Better i18n API

This commit is contained in:
garronej
2023-03-19 14:03:06 +01:00
parent 0608adde89
commit 819f297de8
2 changed files with 100 additions and 97 deletions

View File

@ -69,115 +69,118 @@ export type GenericI18n<MessageKey extends string> = {
export type I18n = GenericI18n<MessageKeyBase>; export type I18n = GenericI18n<MessageKeyBase>;
export function useGenericI18n<ExtraMessageKey extends string = never>(params: { export function createUseI18n<ExtraMessageKey extends string = never>(extraMessages: {
kcContext: KcContextLike; [languageTag: string]: { [key in ExtraMessageKey]: string };
extraMessages: { [languageTag: string]: { [key in ExtraMessageKey]: string } }; }) {
}): GenericI18n<MessageKeyBase | ExtraMessageKey> | null { function useI18n(params: { kcContext: KcContextLike }): GenericI18n<MessageKeyBase | ExtraMessageKey> | null {
const { kcContext, extraMessages } = params; const { kcContext } = params;
const [i18n, setI18n] = useState<GenericI18n<ExtraMessageKey | MessageKeyBase> | undefined>(undefined); const [i18n, setI18n] = useState<GenericI18n<ExtraMessageKey | MessageKeyBase> | undefined>(undefined);
const refHasStartedFetching = useRef(false); const refHasStartedFetching = useRef(false);
useEffect(() => { useEffect(() => {
if (refHasStartedFetching.current) { if (refHasStartedFetching.current) {
return; return;
} }
refHasStartedFetching.current = true; refHasStartedFetching.current = true;
(async () => { (async () => {
const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {}; const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {};
const [fallbackMessages, messages] = await Promise.all([ const [fallbackMessages, messages] = await Promise.all([
import("./generated_messages/18.0.1/login/en"), import("./generated_messages/18.0.1/login/en"),
(() => { (() => {
switch (currentLanguageTag) { switch (currentLanguageTag) {
case "ca": case "ca":
return import("./generated_messages/18.0.1/login/ca"); return import("./generated_messages/18.0.1/login/ca");
case "cs": case "cs":
return import("./generated_messages/18.0.1/login/cs"); return import("./generated_messages/18.0.1/login/cs");
case "da": case "da":
return import("./generated_messages/18.0.1/login/da"); return import("./generated_messages/18.0.1/login/da");
case "de": case "de":
return import("./generated_messages/18.0.1/login/de"); return import("./generated_messages/18.0.1/login/de");
case "en": case "en":
return import("./generated_messages/18.0.1/login/en"); return import("./generated_messages/18.0.1/login/en");
case "es": case "es":
return import("./generated_messages/18.0.1/login/es"); return import("./generated_messages/18.0.1/login/es");
case "fi": case "fi":
return import("./generated_messages/18.0.1/login/fi"); return import("./generated_messages/18.0.1/login/fi");
case "fr": case "fr":
return import("./generated_messages/18.0.1/login/fr"); return import("./generated_messages/18.0.1/login/fr");
case "hu": case "hu":
return import("./generated_messages/18.0.1/login/hu"); return import("./generated_messages/18.0.1/login/hu");
case "it": case "it":
return import("./generated_messages/18.0.1/login/it"); return import("./generated_messages/18.0.1/login/it");
case "ja": case "ja":
return import("./generated_messages/18.0.1/login/ja"); return import("./generated_messages/18.0.1/login/ja");
case "lt": case "lt":
return import("./generated_messages/18.0.1/login/lt"); return import("./generated_messages/18.0.1/login/lt");
case "lv": case "lv":
return import("./generated_messages/18.0.1/login/lv"); return import("./generated_messages/18.0.1/login/lv");
case "nl": case "nl":
return import("./generated_messages/18.0.1/login/nl"); return import("./generated_messages/18.0.1/login/nl");
case "no": case "no":
return import("./generated_messages/18.0.1/login/no"); return import("./generated_messages/18.0.1/login/no");
case "pl": case "pl":
return import("./generated_messages/18.0.1/login/pl"); return import("./generated_messages/18.0.1/login/pl");
case "pt-BR": case "pt-BR":
return import("./generated_messages/18.0.1/login/pt-BR"); return import("./generated_messages/18.0.1/login/pt-BR");
case "ru": case "ru":
return import("./generated_messages/18.0.1/login/ru"); return import("./generated_messages/18.0.1/login/ru");
case "sk": case "sk":
return import("./generated_messages/18.0.1/login/sk"); return import("./generated_messages/18.0.1/login/sk");
case "sv": case "sv":
return import("./generated_messages/18.0.1/login/sv"); return import("./generated_messages/18.0.1/login/sv");
case "tr": case "tr":
return import("./generated_messages/18.0.1/login/tr"); return import("./generated_messages/18.0.1/login/tr");
case "zh-CN": case "zh-CN":
return import("./generated_messages/18.0.1/login/zh-CN"); return import("./generated_messages/18.0.1/login/zh-CN");
default: default:
return { "default": {} }; return { "default": {} };
} }
})() })()
]).then(modules => modules.map(module => module.default)); ]).then(modules => modules.map(module => module.default));
setI18n({ setI18n({
...createI18nTranslationFunctions({ ...createI18nTranslationFunctions({
"fallbackMessages": { "fallbackMessages": {
...fallbackMessages, ...fallbackMessages,
...(keycloakifyExtraMessages[fallbackLanguageTag] ?? {}), ...(keycloakifyExtraMessages[fallbackLanguageTag] ?? {}),
...(extraMessages[fallbackLanguageTag] ?? {}) ...(extraMessages[fallbackLanguageTag] ?? {})
} as any, } as any,
"messages": { "messages": {
...messages, ...messages,
...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}), ...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}),
...(extraMessages[currentLanguageTag] ?? {}) ...(extraMessages[currentLanguageTag] ?? {})
} as any } as any
}), }),
currentLanguageTag, currentLanguageTag,
"changeLocale": newLanguageTag => { "changeLocale": newLanguageTag => {
const { locale } = kcContext; const { locale } = kcContext;
assert(locale !== undefined, "Internationalization not enabled"); assert(locale !== undefined, "Internationalization not enabled");
const targetSupportedLocale = locale.supported.find(({ languageTag }) => languageTag === newLanguageTag); const targetSupportedLocale = locale.supported.find(({ languageTag }) => languageTag === newLanguageTag);
assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`); assert(targetSupportedLocale !== undefined, `${newLanguageTag} need to be enabled in Keycloak admin`);
window.location.href = targetSupportedLocale.url; window.location.href = targetSupportedLocale.url;
assert(false, "never"); assert(false, "never");
}, },
"labelBySupportedLanguageTag": Object.fromEntries( "labelBySupportedLanguageTag": Object.fromEntries(
(kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label]) (kcContext.locale?.supported ?? []).map(({ languageTag, label }) => [languageTag, label])
) )
}); });
})(); })();
}, []); }, []);
return i18n ?? null; return i18n ?? null;
}
return { useI18n };
} }
function createI18nTranslationFunctions<MessageKey extends string>(params: { function createI18nTranslationFunctions<MessageKey extends string>(params: {

View File

@ -5,6 +5,6 @@ export default Fallback;
export { createKeycloakAdapter } from "keycloakify/lib/keycloakJsAdapter"; export { createKeycloakAdapter } from "keycloakify/lib/keycloakJsAdapter";
export { useDownloadTerms } from "keycloakify/lib/useDownloadTerms"; export { useDownloadTerms } from "keycloakify/lib/useDownloadTerms";
export { getKcContext } from "keycloakify/kcContext/getKcContext"; export { getKcContext } from "keycloakify/kcContext/getKcContext";
export { useGenericI18n } from "keycloakify/i18n"; export { createUseI18n } from "keycloakify/i18n";
export type { PageProps } from "keycloakify/pages/PageProps"; export type { PageProps } from "keycloakify/pages/PageProps";