zammad-detect-translatable-string.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. /**
  3. * @fileoverview Detect unmarked translatable strings
  4. * @author Martin Gruner
  5. */
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. /**
  10. * @type {import('eslint').Rule.RuleModule}
  11. */
  12. module.exports = {
  13. meta: {
  14. type: 'problem',
  15. docs: {
  16. description: 'Detect unmarked translatable strings',
  17. category: 'Layout & Formatting',
  18. recommended: true,
  19. url: null,
  20. },
  21. fixable: 'code',
  22. schema: [],
  23. },
  24. create(context) {
  25. const IGNORE_STRING_PATTERNS = [
  26. /^[^A-Z]/, // Only look at strings starting with upper case letters
  27. /\$\{/, // Ignore strings with interpolation
  28. ]
  29. const IGNORE_METHODS = ['__']
  30. const IGNORE_OBJECTS = ['log', 'console', 'i18n']
  31. return {
  32. Literal(node) {
  33. if (typeof node.value === 'string') {
  34. string = node.value
  35. // Ignore strings with less than two words.
  36. if (string.split(' ').length < 2) return
  37. for (const pattern of IGNORE_STRING_PATTERNS) {
  38. if (string.match(pattern)) return
  39. }
  40. // Ignore strings used for comparison
  41. const tokenBefore = context.getTokenBefore(node)
  42. if (
  43. tokenBefore &&
  44. tokenBefore.type === 'Punctuator' &&
  45. ['==', '==='].includes(tokenBefore.value)
  46. ) {
  47. return
  48. }
  49. const { parent } = node
  50. if (parent.type === 'CallExpression') {
  51. if (IGNORE_METHODS.includes(parent.callee.name)) return
  52. if (parent.callee.type === 'MemberExpression') {
  53. if (IGNORE_OBJECTS.includes(parent.callee.object.name)) return
  54. }
  55. }
  56. // console.log(node, parent)
  57. context.report({
  58. node,
  59. message:
  60. 'This string looks like it should be marked as translatable via __(...)',
  61. fix(fixer) {
  62. return fixer.replaceText(node, `__(${node.raw})`)
  63. },
  64. })
  65. }
  66. },
  67. }
  68. },
  69. }