/** * @file Lit Localize build script. * * @remarks * Determines if all the Xliff translation source files are present and if the Typescript source files generated from those sources are up-to-date. * * If they are not, it runs the locale building script, * intercepting the long spew of "this string is not translated" and replacing it with a * summary of how many strings are missing with respect to the source locale. * * @import { ConfigFile } from "@lit/localize-tools/lib/types/config" */ import { PackageRoot } from "@goauthentik/web/paths"; import { spawnSync } from "node:child_process"; import { readFileSync, statSync } from "node:fs"; import path from "node:path"; /** * @type {ConfigFile} */ const localizeRules = JSON.parse( readFileSync(path.join(PackageRoot, "lit-localize.json"), "utf-8"), ); /** * * @param {string} loc * @returns {boolean} */ function generatedFileIsUpToDateWithXliffSource(loc) { const xliff = path.join("./xliff", `${loc}.xlf`); const gened = path.join("./src/locales", `${loc}.ts`); // Returns false if: the expected XLF file doesn't exist, The expected // generated file doesn't exist, or the XLF file is newer (has a higher date) // than the generated file. The missing XLF file is important enough it // generates a unique error message and halts the build. try { var xlfStat = statSync(xliff); } catch (_error) { console.error(`lit-localize expected '${loc}.xlf', but XLF file is not present`); process.exit(1); } // If the generated file doesn't exist, of course it's not up to date. try { var genedStat = statSync(gened); } catch (_error) { return false; } // if the generated file is the same age or newer (date is greater) than the xliff file, it's // presumed to have been generated by that file and is up-to-date. return genedStat.mtimeMs >= xlfStat.mtimeMs; } // For all the expected files, find out if any aren't up-to-date. const upToDate = localizeRules.targetLocales.reduce( (acc, loc) => acc && generatedFileIsUpToDateWithXliffSource(loc), true, ); if (!upToDate) { const status = spawnSync("npm", ["run", "build-locales:build"], { encoding: "utf8" }); // Count all the missing message warnings const counts = status.stderr.split("\n").reduce((acc, line) => { const match = /^([\w-]+) message/.exec(line); if (!match) { return acc; } acc.set(match[1], (acc.get(match[1]) || 0) + 1); return acc; }, new Map()); const locales = Array.from(counts.keys()); locales.sort(); const report = locales .map((locale) => `Locale '${locale}' has ${counts.get(locale)} missing translations`) .join("\n"); console.log(`Translation tables rebuilt.\n${report}\n`); } console.log("Locale ./src is up-to-date");