Fix specialization of i18n using global

This commit is contained in:
garronej 2022-07-31 20:00:57 +02:00
parent c6dc2377fa
commit 0641151ca1
3 changed files with 14 additions and 16 deletions

View File

@ -9,9 +9,7 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
const fallbackLanguageTag = "en"; const fallbackLanguageTag = "en";
export type BaseMessageKey = keyof typeof baseMessages | keyof typeof keycloakifyExtraMessages[typeof fallbackLanguageTag]; export type I18n<MessageKey extends string> = {
type I18n<MessageKey extends string> = {
msgStr: (key: MessageKey, ...args: (string | undefined)[]) => string; msgStr: (key: MessageKey, ...args: (string | undefined)[]) => string;
msg: (key: MessageKey, ...args: (string | undefined)[]) => JSX.Element; msg: (key: MessageKey, ...args: (string | undefined)[]) => JSX.Element;
/** advancedMsg("${access-denied}") === advancedMsg("access-denied") === msg("access-denied") */ /** advancedMsg("${access-denied}") === advancedMsg("access-denied") === msg("access-denied") */
@ -24,7 +22,7 @@ type I18n<MessageKey extends string> = {
labelBySupportedLanguageTag: Record<string, string>; labelBySupportedLanguageTag: Record<string, string>;
}; };
type KcContextLike = { export type KcContextLike = {
locale?: { locale?: {
currentLanguageTag: string; currentLanguageTag: string;
supported: { languageTag: string; url: string; label: string }[]; supported: { languageTag: string; url: string; label: string }[];
@ -39,12 +37,14 @@ export type I18nProviderProps = {
kcContext: KcContextLike; kcContext: KcContextLike;
}; };
const allExtraMessages: { [languageTag: string]: { [key: string]: string } } = {};
export function createI18nApi<ExtraMessageKey extends string = never>(params: { export function createI18nApi<ExtraMessageKey extends string = never>(params: {
extraMessages: { [languageTag: string]: { [key in ExtraMessageKey]: string } }; extraMessages: { [languageTag: string]: { [key in ExtraMessageKey]: string } };
}) { }) {
const { extraMessages } = params ?? {}; Object.assign(allExtraMessages, params.extraMessages);
type MessageKey = ExtraMessageKey | BaseMessageKey; type MessageKey = ExtraMessageKey | keyof typeof baseMessages | keyof typeof keycloakifyExtraMessages[typeof fallbackLanguageTag];
const context = createContext<I18n<MessageKey> | undefined>(undefined); const context = createContext<I18n<MessageKey> | undefined>(undefined);
@ -81,12 +81,12 @@ export function createI18nApi<ExtraMessageKey extends string = never>(params: {
"fallbackMessages": { "fallbackMessages": {
...fallbackMessages, ...fallbackMessages,
...(keycloakifyExtraMessages[fallbackLanguageTag] ?? {}), ...(keycloakifyExtraMessages[fallbackLanguageTag] ?? {}),
...(extraMessages?.[fallbackLanguageTag] ?? {}), ...(allExtraMessages[fallbackLanguageTag] ?? {}),
} as any, } as any,
"messages": { "messages": {
...messages, ...messages,
...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}), ...((keycloakifyExtraMessages as any)[currentLanguageTag] ?? {}),
...(extraMessages?.[currentLanguageTag] ?? {}), ...(allExtraMessages[currentLanguageTag] ?? {}),
} as any, } as any,
}), }),
currentLanguageTag, currentLanguageTag,

View File

@ -1,5 +1,8 @@
import { createI18nApi } from "./createI18nApi"; import { createI18nApi } from "./createI18nApi";
import type { I18n } from "./createI18nApi";
export const { I18nProvider, useI18n } = createI18nApi({ export const { I18nProvider, useI18n } = createI18nApi({
"extraMessages": {}, "extraMessages": {},
}); });
export type MessageKey = ReturnType<typeof useI18n> extends I18n<infer U> ? U : never;

View File

@ -2,19 +2,18 @@ import "./tools/Array.prototype.every";
import React, { useMemo, useReducer, Fragment } from "react"; import React, { useMemo, useReducer, Fragment } from "react";
import type { KcContextBase, Validators, Attribute } from "./getKcContext/KcContextBase"; import type { KcContextBase, Validators, Attribute } from "./getKcContext/KcContextBase";
import { useI18n } from "./i18n"; import { useI18n } from "./i18n";
import type { KcLanguageTag } from "./i18n"; import type { MessageKey } from "./i18n";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import { id } from "tsafe/id"; import { id } from "tsafe/id";
import type { MessageKey } from "./i18n";
import { emailRegexp } from "./tools/emailRegExp"; import { emailRegexp } from "./tools/emailRegExp";
/** Expect to be used in a component wrapped within a <I18nProvider> */
export function useGetErrors(params: { export function useGetErrors(params: {
kcContext: { kcContext: {
messagesPerField: Pick<KcContextBase.Common["messagesPerField"], "existsError" | "get">; messagesPerField: Pick<KcContextBase.Common["messagesPerField"], "existsError" | "get">;
profile: { profile: {
attributes: { name: string; value?: string; validators: Validators }[]; attributes: { name: string; value?: string; validators: Validators }[];
}; };
locale?: { currentLanguageTag: KcLanguageTag };
}; };
}) { }) {
const { kcContext } = params; const { kcContext } = params;
@ -24,7 +23,7 @@ export function useGetErrors(params: {
profile: { attributes }, profile: { attributes },
} = kcContext; } = kcContext;
const { msg, msgStr, advancedMsg, advancedMsgStr } = getMsg(kcContext); const { msg, msgStr, advancedMsg, advancedMsgStr } = useI18n();
const getErrors = useConstCallback((params: { name: string; fieldValueByAttributeName: Record<string, { value: string }> }) => { const getErrors = useConstCallback((params: { name: string; fieldValueByAttributeName: Record<string, { value: string }> }) => {
const { name, fieldValueByAttributeName } = params; const { name, fieldValueByAttributeName } = params;
@ -313,9 +312,6 @@ export function useFormValidationSlice(params: {
}; };
passwordRequired: boolean; passwordRequired: boolean;
realm: { registrationEmailAsUsername: boolean }; realm: { registrationEmailAsUsername: boolean };
locale?: {
currentLanguageTag: KcLanguageTag;
};
}; };
/** NOTE: Try to avoid passing a new ref every render for better performances. */ /** NOTE: Try to avoid passing a new ref every render for better performances. */
passwordValidators?: Validators; passwordValidators?: Validators;
@ -385,7 +381,6 @@ export function useFormValidationSlice(params: {
"profile": { "profile": {
"attributes": attributesWithPassword, "attributes": attributesWithPassword,
}, },
"locale": kcContext.locale,
}, },
}); });