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

[web] flag mismatching translations variables in CI

GitOrigin-RevId: 33bfda0975258a18a07db5057bd3a57ee9ad4b6b
This commit is contained in:
Jakob Ackermann 2023-07-20 10:55:40 +02:00 committed by Copybot
parent f010acb135
commit c7c77d0851
2 changed files with 46 additions and 18 deletions

View file

@ -8,6 +8,9 @@ node scripts/translations/sort.js --check
# Ensure all locales are still in use # Ensure all locales are still in use
node scripts/translations/cleanupUnusedLocales.js --check 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 # Ensure all locales used in the frontend are tracked
OUTPUT=data/dumpFolder/i18next-scanner OUTPUT=data/dumpFolder/i18next-scanner
trap "rm -rf $OUTPUT" EXIT trap "rm -rf $OUTPUT" EXIT

View file

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