import "minimal-polyfills/Object.fromEntries"; import * as fs from "fs"; import { join as pathJoin, relative as pathRelative, dirname as pathDirname, sep as pathSep } from "path"; import { crawl } from "../src/bin/tools/crawl"; import { downloadBuiltinKeycloakTheme } from "../src/bin/shared/downloadBuiltinKeycloakTheme"; import { getThisCodebaseRootDirPath } from "../src/bin/tools/getThisCodebaseRootDirPath"; import { getLogger } from "../src/bin/tools/logger"; import { rmSync } from "../src/bin/tools/fs.rmSync"; // NOTE: To run without argument when we want to generate src/i18n/generated_kcMessages files, // update the version array for generating for newer version. //@ts-ignore const propertiesParser = require("properties-parser"); const isSilent = true; const logger = getLogger({ isSilent }); async function main() { const keycloakVersion = "24.0.4"; const thisCodebaseRootDirPath = getThisCodebaseRootDirPath(); const tmpDirPath = pathJoin(thisCodebaseRootDirPath, "tmp_xImOef9dOd44"); rmSync(tmpDirPath, { "recursive": true, "force": true }); fs.mkdirSync(tmpDirPath); fs.writeFileSync(pathJoin(tmpDirPath, ".gitignore"), Buffer.from("/*\n!.gitignore\n", "utf8")); await downloadBuiltinKeycloakTheme({ keycloakVersion, "destDirPath": tmpDirPath, "buildOptions": { "cacheDirPath": pathJoin(thisCodebaseRootDirPath, "node_modules", ".cache", "keycloakify"), "npmWorkspaceRootDirPath": thisCodebaseRootDirPath } }); type Dictionary = { [idiomId: string]: string }; const record: { [typeOfPage: string]: { [language: string]: Dictionary } } = {}; { const baseThemeDirPath = pathJoin(tmpDirPath, "base"); const re = new RegExp(`^([^\\${pathSep}]+)\\${pathSep}messages\\${pathSep}messages_([^.]+).properties$`); crawl({ "dirPath": baseThemeDirPath, "returnedPathsType": "relative to dirPath" }).forEach(filePath => { const match = filePath.match(re); if (match === null) { return; } const [, typeOfPage, language] = match; (record[typeOfPage] ??= {})[language.replace(/_/g, "-")] = Object.fromEntries( Object.entries(propertiesParser.parse(fs.readFileSync(pathJoin(baseThemeDirPath, filePath)).toString("utf8"))).map( ([key, value]: any) => [key, value.replace(/''/g, "'")] ) ); }); } rmSync(tmpDirPath, { "recursive": true }); Object.keys(record).forEach(themeType => { const recordForPageType = record[themeType]; if (themeType !== "login" && themeType !== "account") { return; } const baseMessagesDirPath = pathJoin(thisCodebaseRootDirPath, "src", themeType, "i18n", "baseMessages"); const languages = Object.keys(recordForPageType); const generatedFileHeader = [ `//This code was automatically generated by running ${pathRelative(thisCodebaseRootDirPath, __filename)}`, "//PLEASE DO NOT EDIT MANUALLY" ].join("\n"); languages.forEach(language => { const filePath = pathJoin(baseMessagesDirPath, `${language}.ts`); fs.mkdirSync(pathDirname(filePath), { "recursive": true }); fs.writeFileSync( filePath, Buffer.from( [ generatedFileHeader, "", "/* spell-checker: disable */", `const messages= ${JSON.stringify(recordForPageType[language], null, 2)};`, "", "export default messages;", "/* spell-checker: enable */" ].join("\n"), "utf8" ) ); logger.log(`${filePath} wrote`); }); fs.writeFileSync( pathJoin(baseMessagesDirPath, "index.ts"), Buffer.from( [ generatedFileHeader, `import * as en from "./en";`, "", "export async function getMessages(currentLanguageTag: string) {", " const { default: messages } = await (() => {", " switch (currentLanguageTag) {", ` case "en": return en;`, ...languages .filter(language => language !== "en") .map(language => ` case "${language}": return import("./${language}");`), ' default: return { "default": {} };', " }", " })();", " return messages;", "}" ].join("\n"), "utf8" ) ); }); } if (require.main === module) { main(); }