Refactor of the i18n download mechanism
This commit is contained in:
parent
aaac1f54e8
commit
a3fd376b24
4
.gitignore
vendored
4
.gitignore
vendored
@ -49,4 +49,6 @@ jspm_packages
|
|||||||
.idea
|
.idea
|
||||||
|
|
||||||
/keycloak_email
|
/keycloak_email
|
||||||
/build_keycloak
|
/build_keycloak
|
||||||
|
/src/login/i18n/baseMessages/
|
||||||
|
/src/account/i18n/baseMessages/
|
@ -7,5 +7,6 @@ node_modules/
|
|||||||
/src/tools/types/
|
/src/tools/types/
|
||||||
/sample_react_project
|
/sample_react_project
|
||||||
/build_keycloak/
|
/build_keycloak/
|
||||||
/src/i18n/generated_messages/
|
|
||||||
/.vscode/
|
/.vscode/
|
||||||
|
/src/login/i18n/baseMessages/
|
||||||
|
/src/account/i18n/baseMessages/
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"postinstall": "yarn generate-i18n-messages",
|
||||||
"build": "rimraf dist/ && tsc -p src/bin && tsc -p src/tsconfig.json && tsc-alias -p src/tsconfig.json && yarn grant-exec-perms && yarn copy-files dist/",
|
"build": "rimraf dist/ && tsc -p src/bin && tsc -p src/tsconfig.json && tsc-alias -p src/tsconfig.json && yarn grant-exec-perms && yarn copy-files dist/",
|
||||||
"build:watch": "tsc -p src/tsconfig.json && (concurrently \"tsc -p src/tsconfig.json -w\" \"tsc-alias -p src/tsconfig.json\")",
|
"build:watch": "tsc -p src/tsconfig.json && (concurrently \"tsc -p src/tsconfig.json -w\" \"tsc-alias -p src/tsconfig.json\")",
|
||||||
"build:test": "rimraf dist_test/ && tsc -p test/tsconfig.json && tsc-alias -p test/tsconfig.json && yarn copy-files dist_test/src",
|
"build:test": "rimraf dist_test/ && tsc -p test/tsconfig.json && tsc-alias -p test/tsconfig.json && yarn copy-files dist_test/src",
|
||||||
|
@ -17,76 +17,101 @@ const { isSilent } = getCliOptions(process.argv.slice(2));
|
|||||||
const logger = getLogger({ isSilent });
|
const logger = getLogger({ isSilent });
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
for (const keycloakVersion of ["11.0.3", "15.0.2", "18.0.1", "21.0.1"]) {
|
const keycloakVersion = "21.0.1";
|
||||||
logger.log(JSON.stringify({ keycloakVersion }));
|
|
||||||
|
|
||||||
const tmpDirPath = pathJoin(getProjectRoot(), "tmp_xImOef9dOd44");
|
const tmpDirPath = pathJoin(getProjectRoot(), "tmp_xImOef9dOd44");
|
||||||
|
|
||||||
fs.rmSync(tmpDirPath, { "recursive": true, "force": true });
|
fs.rmSync(tmpDirPath, { "recursive": true, "force": true });
|
||||||
|
|
||||||
await downloadBuiltinKeycloakTheme({
|
await downloadBuiltinKeycloakTheme({
|
||||||
keycloakVersion,
|
keycloakVersion,
|
||||||
"destDirPath": tmpDirPath,
|
"destDirPath": tmpDirPath,
|
||||||
isSilent
|
isSilent
|
||||||
});
|
});
|
||||||
|
|
||||||
type Dictionary = { [idiomId: string]: string };
|
type Dictionary = { [idiomId: string]: string };
|
||||||
|
|
||||||
const record: { [typeOfPage: string]: { [language: string]: Dictionary } } = {};
|
const record: { [typeOfPage: string]: { [language: string]: Dictionary } } = {};
|
||||||
|
|
||||||
{
|
{
|
||||||
const baseThemeDirPath = pathJoin(tmpDirPath, "base");
|
const baseThemeDirPath = pathJoin(tmpDirPath, "base");
|
||||||
|
|
||||||
crawl(baseThemeDirPath).forEach(filePath => {
|
crawl(baseThemeDirPath).forEach(filePath => {
|
||||||
const match = filePath.match(/^([^/]+)\/messages\/messages_([^.]+)\.properties$/);
|
const match = filePath.match(/^([^/]+)\/messages\/messages_([^.]+)\.properties$/);
|
||||||
|
|
||||||
if (match === null) {
|
if (match === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, typeOfPage, language] = match;
|
const [, typeOfPage, language] = match;
|
||||||
|
|
||||||
(record[typeOfPage] ??= {})[language.replace(/_/g, "-")] = Object.fromEntries(
|
(record[typeOfPage] ??= {})[language.replace(/_/g, "-")] = Object.fromEntries(
|
||||||
Object.entries(propertiesParser.parse(fs.readFileSync(pathJoin(baseThemeDirPath, filePath)).toString("utf8"))).map(
|
Object.entries(propertiesParser.parse(fs.readFileSync(pathJoin(baseThemeDirPath, filePath)).toString("utf8"))).map(
|
||||||
([key, value]: any) => [key, value.replace(/''/g, "'")]
|
([key, value]: any) => [key, value.replace(/''/g, "'")]
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.rmSync(tmpDirPath, { recursive: true, force: true });
|
|
||||||
|
|
||||||
Object.keys(record).forEach(themeType => {
|
|
||||||
const recordForPageType = record[themeType];
|
|
||||||
|
|
||||||
Object.keys(recordForPageType).forEach(language => {
|
|
||||||
if (themeType !== "login") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filePath = pathJoin(getProjectRoot(), "src", themeType, "i18n", "generated_messages", keycloakVersion, `${language}.ts`);
|
|
||||||
|
|
||||||
fs.mkdirSync(pathDirname(filePath), { "recursive": true });
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
filePath,
|
|
||||||
Buffer.from(
|
|
||||||
[
|
|
||||||
`//This code was automatically generated by running ${pathRelative(getProjectRoot(), __filename)}`,
|
|
||||||
"//PLEASE DO NOT EDIT MANUALLY",
|
|
||||||
"",
|
|
||||||
"/* 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.rmSync(tmpDirPath, { recursive: true, force: true });
|
||||||
|
|
||||||
|
Object.keys(record).forEach(themeType => {
|
||||||
|
const recordForPageType = record[themeType];
|
||||||
|
|
||||||
|
if (themeType !== "login") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseMessagesDirPath = pathJoin(getProjectRoot(), "src", themeType, "i18n", "baseMessages");
|
||||||
|
|
||||||
|
const languages = Object.keys(recordForPageType);
|
||||||
|
|
||||||
|
const generatedFileHeader = [
|
||||||
|
`//This code was automatically generated by running ${pathRelative(getProjectRoot(), __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,
|
||||||
|
"export async function getMessages(currentLanguageTag: string) {",
|
||||||
|
" const { default: messages } = await (() => {",
|
||||||
|
" switch (currentLanguageTag) {",
|
||||||
|
...languages.map(language => ` case "${language}": return import("./${language}");`),
|
||||||
|
' default: return { "default": {} };',
|
||||||
|
" }",
|
||||||
|
" })();",
|
||||||
|
" return messages;",
|
||||||
|
"}"
|
||||||
|
].join("\n"),
|
||||||
|
"utf8"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import "minimal-polyfills/Object.fromEntries";
|
import "minimal-polyfills/Object.fromEntries";
|
||||||
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
|
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
|
||||||
import { useEffect, useState, useRef } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
import type baseMessages from "./generated_messages/18.0.1/login/en";
|
import fallbackMessages from "./baseMessages/en";
|
||||||
|
import { getMessages } from "./baseMessages";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import type { KcContext } from "../kcContext/KcContext";
|
import type { KcContext } from "../kcContext/KcContext";
|
||||||
import { Markdown } from "keycloakify/tools/Markdown";
|
import { Markdown } from "keycloakify/tools/Markdown";
|
||||||
@ -17,7 +18,7 @@ export type KcContextLike = {
|
|||||||
|
|
||||||
assert<KcContext extends KcContextLike ? true : false>();
|
assert<KcContext extends KcContextLike ? true : false>();
|
||||||
|
|
||||||
export type MessageKey = keyof typeof baseMessages | keyof (typeof keycloakifyExtraMessages)[typeof fallbackLanguageTag];
|
export type MessageKey = keyof typeof fallbackMessages | keyof (typeof keycloakifyExtraMessages)[typeof fallbackLanguageTag];
|
||||||
|
|
||||||
export type GenericI18n<MessageKey extends string> = {
|
export type GenericI18n<MessageKey extends string> = {
|
||||||
/**
|
/**
|
||||||
@ -89,60 +90,6 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|||||||
(async () => {
|
(async () => {
|
||||||
const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {};
|
const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {};
|
||||||
|
|
||||||
const [fallbackMessages, messages] = await Promise.all([
|
|
||||||
import("./generated_messages/18.0.1/login/en"),
|
|
||||||
(() => {
|
|
||||||
switch (currentLanguageTag) {
|
|
||||||
case "ca":
|
|
||||||
return import("./generated_messages/18.0.1/login/ca");
|
|
||||||
case "cs":
|
|
||||||
return import("./generated_messages/18.0.1/login/cs");
|
|
||||||
case "da":
|
|
||||||
return import("./generated_messages/18.0.1/login/da");
|
|
||||||
case "de":
|
|
||||||
return import("./generated_messages/18.0.1/login/de");
|
|
||||||
case "en":
|
|
||||||
return import("./generated_messages/18.0.1/login/en");
|
|
||||||
case "es":
|
|
||||||
return import("./generated_messages/18.0.1/login/es");
|
|
||||||
case "fi":
|
|
||||||
return import("./generated_messages/18.0.1/login/fi");
|
|
||||||
case "fr":
|
|
||||||
return import("./generated_messages/18.0.1/login/fr");
|
|
||||||
case "hu":
|
|
||||||
return import("./generated_messages/18.0.1/login/hu");
|
|
||||||
case "it":
|
|
||||||
return import("./generated_messages/18.0.1/login/it");
|
|
||||||
case "ja":
|
|
||||||
return import("./generated_messages/18.0.1/login/ja");
|
|
||||||
case "lt":
|
|
||||||
return import("./generated_messages/18.0.1/login/lt");
|
|
||||||
case "lv":
|
|
||||||
return import("./generated_messages/18.0.1/login/lv");
|
|
||||||
case "nl":
|
|
||||||
return import("./generated_messages/18.0.1/login/nl");
|
|
||||||
case "no":
|
|
||||||
return import("./generated_messages/18.0.1/login/no");
|
|
||||||
case "pl":
|
|
||||||
return import("./generated_messages/18.0.1/login/pl");
|
|
||||||
case "pt-BR":
|
|
||||||
return import("./generated_messages/18.0.1/login/pt-BR");
|
|
||||||
case "ru":
|
|
||||||
return import("./generated_messages/18.0.1/login/ru");
|
|
||||||
case "sk":
|
|
||||||
return import("./generated_messages/18.0.1/login/sk");
|
|
||||||
case "sv":
|
|
||||||
return import("./generated_messages/18.0.1/login/sv");
|
|
||||||
case "tr":
|
|
||||||
return import("./generated_messages/18.0.1/login/tr");
|
|
||||||
case "zh-CN":
|
|
||||||
return import("./generated_messages/18.0.1/login/zh-CN");
|
|
||||||
default:
|
|
||||||
return { "default": {} };
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
]).then(modules => modules.map(module => module.default));
|
|
||||||
|
|
||||||
setI18n({
|
setI18n({
|
||||||
...createI18nTranslationFunctions({
|
...createI18nTranslationFunctions({
|
||||||
"fallbackMessages": {
|
"fallbackMessages": {
|
||||||
@ -151,7 +98,7 @@ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessa
|
|||||||
...(extraMessages[fallbackLanguageTag] ?? {})
|
...(extraMessages[fallbackLanguageTag] ?? {})
|
||||||
} as any,
|
} as any,
|
||||||
"messages": {
|
"messages": {
|
||||||
...messages,
|
...(await getMessages(currentLanguageTag)),
|
||||||
...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}),
|
...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}),
|
||||||
...(extraMessages[currentLanguageTag] ?? {})
|
...(extraMessages[currentLanguageTag] ?? {})
|
||||||
} as any
|
} as any
|
||||||
|
Loading…
x
Reference in New Issue
Block a user