2024-10-24 08:18:37 -04:00
|
|
|
import fs from 'fs'
|
|
|
|
import Path from 'path'
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import { loadLocale } from './utils.js'
|
|
|
|
|
|
|
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
2023-07-19 04:40:34 -04:00
|
|
|
|
|
|
|
const GLOBALS = ['__appName__']
|
|
|
|
const LOCALES = Path.join(__dirname, '../../locales')
|
2024-10-24 08:18:37 -04:00
|
|
|
const baseLocale = loadLocale('en')
|
2023-07-20 04:55:40 -04:00
|
|
|
const baseLocaleKeys = Object.keys(baseLocale)
|
2023-07-19 04:40:34 -04:00
|
|
|
|
2023-07-20 04:55:40 -04:00
|
|
|
const IGNORE_ORPHANED_TRANSLATIONS = process.argv.includes(
|
|
|
|
'--ignore-orphaned-translations'
|
|
|
|
)
|
2023-07-19 04:40:34 -04:00
|
|
|
|
2023-07-20 04:55:40 -04:00
|
|
|
const IGNORE_NESTING_FOR = {
|
|
|
|
over_x_templates_easy_getting_started: ['__templates__'],
|
|
|
|
all_packages_and_templates: ['__templatesLink__'],
|
|
|
|
}
|
2023-07-19 04:40:34 -04:00
|
|
|
|
|
|
|
function fetchKeys(str) {
|
|
|
|
const matches = str.matchAll(/__.*?__/g)
|
|
|
|
if (matches.length === 0) {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
return Array.from(matches).map(match => match[0])
|
|
|
|
}
|
|
|
|
|
2023-07-20 04:55:40 -04:00
|
|
|
function difference(key, base, target) {
|
|
|
|
const nesting = IGNORE_NESTING_FOR[key] || []
|
|
|
|
const keysInBaseButNotInTarget = base.filter(
|
|
|
|
key => !target.includes(key) && !nesting.includes(key)
|
|
|
|
)
|
2023-07-19 04:40:34 -04:00
|
|
|
const keysInTargetButNotInBase = target.filter(
|
|
|
|
key => !base.includes(key) && !GLOBALS.includes(key)
|
|
|
|
)
|
|
|
|
return {
|
|
|
|
keysInBaseButNotInTarget,
|
|
|
|
keysInTargetButNotInBase,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-20 04:55:40 -04:00
|
|
|
let violations = 0
|
|
|
|
for (const localeName of fs.readdirSync(LOCALES)) {
|
|
|
|
if (localeName === 'README.md') continue
|
2024-10-24 08:18:37 -04:00
|
|
|
const locale = loadLocale(localeName.replace('.json', ''))
|
2023-07-20 04:55:40 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-07-19 04:40:34 -04:00
|
|
|
const keysInTranslation = fetchKeys(locale[key])
|
|
|
|
const keysInBase = fetchKeys(baseLocale[key])
|
|
|
|
const { keysInBaseButNotInTarget, keysInTargetButNotInBase } = difference(
|
2023-07-20 04:55:40 -04:00
|
|
|
key,
|
2023-07-19 04:40:34 -04:00
|
|
|
keysInBase,
|
|
|
|
keysInTranslation
|
|
|
|
)
|
|
|
|
if (keysInBaseButNotInTarget.length) {
|
2023-07-20 04:55:40 -04:00
|
|
|
violations += keysInBaseButNotInTarget.length
|
2023-07-19 04:40:34 -04:00
|
|
|
console.warn(
|
2023-07-20 04:55:40 -04:00
|
|
|
`[${localeName}] Missing variables in key "${key}":`,
|
2023-07-19 04:40:34 -04:00
|
|
|
keysInBaseButNotInTarget
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (keysInTargetButNotInBase.length) {
|
2023-07-20 04:55:40 -04:00
|
|
|
violations += keysInTargetButNotInBase.length
|
2023-07-19 04:40:34 -04:00
|
|
|
console.warn(
|
2023-07-20 04:55:40 -04:00
|
|
|
`[${localeName}] Extra variables in key "${key}":`,
|
2023-07-19 04:40:34 -04:00
|
|
|
keysInTargetButNotInBase
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-20 04:55:40 -04:00
|
|
|
|
|
|
|
if (violations) {
|
|
|
|
console.warn('Variables are not in sync between translations.')
|
|
|
|
process.exit(1)
|
|
|
|
} else {
|
|
|
|
console.log('Variables are in sync.')
|
|
|
|
process.exit(0)
|
|
|
|
}
|