chore(dashboard): Setup test and script for validating i18n (#9799)
**What** - Adds a test that validates that en.json and $schema.json matches, this will help us catch missing translations, and prevent us from forgetting to update the schema when we delete/add new keys. - Adds a script for validating translations against the translation schema. This can be used to validate that community PRs for i18n contain all the required keys. To use the script you can run `yarn i18n:validate <file name>` e.g. `yarn i18n:validate da.json` which will look for a da.json file in the translation folder, and validate it against the schema. We handle this with a script as we don't want to do so through a test. Doing it with a test would mean that if we update the schema, we would also have to update all translations files that we don't maintain ourselves. The purpose of the script is just to allow us to easily review community PRs and also as a tool for people opening PR's to check their translations agains the schema, as it will print missing/additional keys. - Also adds a script to generate a schema from the en.json file. After adding/deleting keys to en.json you should run `yarn i18n:generate`.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
+66
@@ -0,0 +1,66 @@
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import { describe, expect, test } from "vitest"
|
||||
|
||||
import schema from "../$schema.json"
|
||||
|
||||
const translationsDir = path.join(__dirname, "..")
|
||||
|
||||
function getRequiredKeysFromSchema(schema: any, prefix = ""): string[] {
|
||||
const keys: string[] = []
|
||||
|
||||
if (schema.type === "object" && schema.properties) {
|
||||
Object.entries(schema.properties).forEach(([key, value]: [string, any]) => {
|
||||
const newPrefix = prefix ? `${prefix}.${key}` : key
|
||||
if (value.type === "object") {
|
||||
keys.push(...getRequiredKeysFromSchema(value, newPrefix))
|
||||
} else {
|
||||
keys.push(newPrefix)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return keys.sort()
|
||||
}
|
||||
|
||||
function getTranslationKeys(obj: any, prefix = ""): string[] {
|
||||
const keys: string[] = []
|
||||
|
||||
Object.entries(obj).forEach(([key, value]) => {
|
||||
const newPrefix = prefix ? `${prefix}.${key}` : key
|
||||
if (value && typeof value === "object") {
|
||||
keys.push(...getTranslationKeys(value, newPrefix))
|
||||
} else {
|
||||
keys.push(newPrefix)
|
||||
}
|
||||
})
|
||||
|
||||
return keys.sort()
|
||||
}
|
||||
|
||||
describe("translation schema validation", () => {
|
||||
test("en.json should have all keys defined in schema", () => {
|
||||
const enPath = path.join(translationsDir, "en.json")
|
||||
const enTranslations = JSON.parse(fs.readFileSync(enPath, "utf-8"))
|
||||
|
||||
const schemaKeys = getRequiredKeysFromSchema(schema)
|
||||
const translationKeys = getTranslationKeys(enTranslations)
|
||||
|
||||
const missingInTranslations = schemaKeys.filter(
|
||||
(key) => !translationKeys.includes(key)
|
||||
)
|
||||
const extraInTranslations = translationKeys.filter(
|
||||
(key) => !schemaKeys.includes(key)
|
||||
)
|
||||
|
||||
if (missingInTranslations.length > 0) {
|
||||
console.error("\nMissing keys in en.json:", missingInTranslations)
|
||||
}
|
||||
if (extraInTranslations.length > 0) {
|
||||
console.error("\nExtra keys in en.json:", extraInTranslations)
|
||||
}
|
||||
|
||||
expect(missingInTranslations).toEqual([])
|
||||
expect(extraInTranslations).toEqual([])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user