zammad/zammad

View on GitHub
.eslint-plugin-zammad/lib/rules/zammad-detect-translatable-string.js

Summary

Maintainability
C
7 hrs
Test Coverage
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

/**
 * @fileoverview Detect unmarked translatable strings
 * @author Martin Gruner
 */

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/**
 * @type {import('eslint').Rule.RuleModule}
 */
module.exports = {
  meta: {
    type: 'problem',
    docs: {
      description: 'Detect unmarked translatable strings',
      category: 'Layout & Formatting',
      recommended: true,
      url: null,
    },
    fixable: 'code',
    schema: [],
  },

  create(context) {
    const IGNORE_STRING_PATTERNS = [
      /^[^A-Z]/, // Only look at strings starting with upper case letters
      /\$\{/, // Ignore strings with interpolation
    ]
    const IGNORE_METHODS = ['__']
    const IGNORE_OBJECTS = ['log', 'console', 'i18n']

    return {
      Literal(node) {
        if (typeof node.value !== 'string') {
          return
        }

        const string = node.value

        // Ignore strings with less than two words.
        if (string.split(' ').length < 2) return

        for (const pattern of IGNORE_STRING_PATTERNS) {
          if (string.match(pattern)) return
        }

        // Ignore strings used for comparison
        const tokenBefore = context.getTokenBefore(node)
        if (
          tokenBefore &&
          tokenBefore.type === 'Punctuator' &&
          ['==', '==='].includes(tokenBefore.value)
        ) {
          return
        }

        const { parent } = node

        if (parent.type === 'CallExpression') {
          if (IGNORE_METHODS.includes(parent.callee.name)) return
          if (
            parent.callee.type === 'MemberExpression' &&
            IGNORE_OBJECTS.includes(parent.callee.object.name)
          ) {
            return
          }
        }

        context.report({
          node,
          message:
            'This string looks like it should be marked as translatable via __(...)',
          fix(fixer) {
            return fixer.replaceText(node, `__(${node.raw})`)
          },
        })
      },
    }
  },
}