123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- // 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.sourceCode.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})`)
- },
- })
- },
- }
- },
- }
|