Просмотр исходного кода

Merge pull request #13946 from overleaf/jpa-i18n-variable-check-ci

[web] flag mismatching translations variables in CI

GitOrigin-RevId: 33bfda0975258a18a07db5057bd3a57ee9ad4b6b
Jakob Ackermann 3 лет назад
Родитель
Сommit
c7c77d0851
2 измененных файлов с 45 добавлено и 17 удалено
  1. 3 0
      services/web/bin/lint_locales
  2. 42 17
      services/web/scripts/translations/checkVariables.js

+ 3 - 0
services/web/bin/lint_locales

@@ -8,6 +8,9 @@ node scripts/translations/sort.js --check
 # Ensure all locales are still in use
 node scripts/translations/cleanupUnusedLocales.js --check
 
+# Ensure all locales use the same variables
+node scripts/translations/checkVariables.js --ignore-orphaned-translations
+
 # Ensure all locales used in the frontend are tracked
 OUTPUT=data/dumpFolder/i18next-scanner
 trap "rm -rf $OUTPUT" EXIT

+ 42 - 17
services/web/scripts/translations/checkVariables.js

@@ -1,22 +1,20 @@
-// Usage: node checkVariables.js <locale>
-
 const fs = require('fs')
 const Path = require('path')
 
 const GLOBALS = ['__appName__']
 const LOCALES = Path.join(__dirname, '../../locales')
 const baseLocalePath = Path.join(LOCALES, 'en.json')
+const baseLocale = JSON.parse(fs.readFileSync(baseLocalePath, 'utf-8'))
+const baseLocaleKeys = Object.keys(baseLocale)
 
-if (process.argv.length < 3) {
-  console.error('Usage: node checkVariables.js <locale>')
-  process.exit(1)
-}
-
-const localeName = process.argv[2]
-const localePath = Path.join(LOCALES, `${localeName}.json`)
+const IGNORE_ORPHANED_TRANSLATIONS = process.argv.includes(
+  '--ignore-orphaned-translations'
+)
 
-const baseLocale = JSON.parse(fs.readFileSync(baseLocalePath, 'utf-8'))
-const locale = JSON.parse(fs.readFileSync(localePath, 'utf-8'))
+const IGNORE_NESTING_FOR = {
+  over_x_templates_easy_getting_started: ['__templates__'],
+  all_packages_and_templates: ['__templatesLink__'],
+}
 
 function fetchKeys(str) {
   const matches = str.matchAll(/__.*?__/g)
@@ -26,8 +24,11 @@ function fetchKeys(str) {
   return Array.from(matches).map(match => match[0])
 }
 
-function difference(base, target) {
-  const keysInBaseButNotInTarget = base.filter(key => !target.includes(key))
+function difference(key, base, target) {
+  const nesting = IGNORE_NESTING_FOR[key] || []
+  const keysInBaseButNotInTarget = base.filter(
+    key => !target.includes(key) && !nesting.includes(key)
+  )
   const keysInTargetButNotInBase = target.filter(
     key => !base.includes(key) && !GLOBALS.includes(key)
   )
@@ -37,25 +38,49 @@ function difference(base, target) {
   }
 }
 
-for (const key of Object.keys(locale)) {
-  if (Object.prototype.hasOwnProperty.call(baseLocale, key)) {
+let violations = 0
+for (const localeName of fs.readdirSync(LOCALES)) {
+  if (localeName === 'README.md') continue
+  const localePath = Path.join(LOCALES, localeName)
+
+  const locale = JSON.parse(fs.readFileSync(localePath, 'utf-8'))
+
+  for (const key of Object.keys(locale)) {
+    if (!baseLocaleKeys.includes(key)) {
+      if (IGNORE_ORPHANED_TRANSLATIONS) continue
+      violations += 1
+      console.warn(`[${localeName}] Orphaned key "${key}" not found in en.json`)
+      continue
+    }
+
     const keysInTranslation = fetchKeys(locale[key])
     const keysInBase = fetchKeys(baseLocale[key])
     const { keysInBaseButNotInTarget, keysInTargetButNotInBase } = difference(
+      key,
       keysInBase,
       keysInTranslation
     )
     if (keysInBaseButNotInTarget.length) {
+      violations += keysInBaseButNotInTarget.length
       console.warn(
-        `Warning: Missing variables in key ${key}:`,
+        `[${localeName}] Missing variables in key "${key}":`,
         keysInBaseButNotInTarget
       )
     }
     if (keysInTargetButNotInBase.length) {
+      violations += keysInTargetButNotInBase.length
       console.warn(
-        `Warning: Extra variables in key ${key}:`,
+        `[${localeName}] Extra variables in key   "${key}":`,
         keysInTargetButNotInBase
       )
     }
   }
 }
+
+if (violations) {
+  console.warn('Variables are not in sync between translations.')
+  process.exit(1)
+} else {
+  console.log('Variables are in sync.')
+  process.exit(0)
+}