i18n: optimize performance

* createCurrentLanguage: caching result with memo
* createStringResource: use useAppLocale
This commit is contained in:
thislight 2024-11-25 15:22:25 +08:00
parent 6df5c2e216
commit b1812392cb
No known key found for this signature in database
GPG key ID: FCFE5192241CCD4E

View file

@ -25,12 +25,22 @@ const DEFAULT_LANG = "en";
/**
* Decide the using language for the user.
*
* **Performance**: This function is costy, make sure you cache the result.
* In the app, you should use {@link useAppLocale} instead.
*
* @returns the selected language tag
*/
export function autoMatchLangTag() {
return match(Array.from(navigator.languages), SUPPORTED_LANGS, DEFAULT_LANG);
}
/**
* Decide the using region for the user.
*
* **Performance**: This function is costy, make sure you cache the result.
* In the app, you should use {@link useAppLocale} instead.
*/
export function autoMatchRegion() {
const specifiers = navigator.languages.map((x) => x.split("-"));
@ -99,7 +109,7 @@ export function useDateFnLocale(): Accessor<Locale> {
export function createCurrentLanguage() {
const settings = useStore($settings);
return () => settings().language || autoMatchLangTag();
return createMemo(() => settings().language || autoMatchLangTag());
}
type ImportFn<T> = (name: string) => Promise<{ default: T }>;
@ -114,10 +124,30 @@ type MergedImportedModule<T> = T extends []
? ImportedModule<I> & MergedImportedModule<J>
: never;
/**
* Create a resource that combines all I18N strings into one object.
*
* The result is combined in the order of the argument functions.
* The formers will be overrided by the latter.
*
* @param importFns a series of functions imports the string modules
* based on the specified language code.
*
* **Context**: This function must be used under {@link AppLocaleProvider}.
*
* @example ````ts
* const [strings] = createStringResource(
* async (code) => await import(`./i18n/${code}.json`), // Vite can handle the bundling
* async () => import("./i18n/generic.json"), // You can also ignore the code.
* );
* ````
*
* @see {@link createTranslator} if you need a Translator from "@solid-primitives/i18n"
*/
export function createStringResource<
T extends ImportFn<Record<string, string | Template<any> | undefined>>[],
>(...importFns: T) {
const language = createCurrentLanguage();
const { language } = useAppLocale();
const cache: Record<string, MergedImportedModule<T>> = {};
return createResource(
@ -140,6 +170,18 @@ export function createStringResource<
);
}
/**
* Create the Translator from "@solid-primitives/i18n" based on
* the {@link createStringResource}.
*
* @param importFns same to {@link createStringResource}
*
* @returns the first element is the translator, the second is the result from
* {@link createStringResource}.
*
* @see {@link translator} for the translator usage
* @see {@link createStringResource} for the raw strings
*/
export function createTranslator<
T extends ImportFn<Record<string, string | Template<any> | undefined>>[],
>(...importFns: T) {