From b44d093f0871c8c649928b4a39a608140655a621 Mon Sep 17 00:00:00 2001 From: thislight Date: Mon, 4 Nov 2024 00:13:21 +0800 Subject: [PATCH] autoMatchRegion: improved matching algorithm --- src/platform/i18n.tsx | 67 +++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/src/platform/i18n.tsx b/src/platform/i18n.tsx index ff03e14..70db7f3 100644 --- a/src/platform/i18n.tsx +++ b/src/platform/i18n.tsx @@ -11,7 +11,11 @@ import { $settings } from "../settings/stores"; import { enGB } from "date-fns/locale/en-GB"; import { useStore } from "@nanostores/solid"; import type { Locale } from "date-fns"; -import { resolveTemplate, translator, type Template } from "@solid-primitives/i18n"; +import { + resolveTemplate, + translator, + type Template, +} from "@solid-primitives/i18n"; async function synchronised( name: string, @@ -34,29 +38,35 @@ export function autoMatchLangTag() { return match(Array.from(navigator.languages), SUPPORTED_LANGS, DEFAULT_LANG); } -const DateFnLocaleCx = /* __@PURE__ */createContext>(() => enGB); +const DateFnLocaleCx = /* __@PURE__ */ createContext>( + () => enGB, +); const cachedDateFnLocale: Record = { enGB, }; export function autoMatchRegion() { - const regions = navigator.languages - .map((x) => { - const parts = x.split("_"); - if (parts.length > 1) { - return parts[1]; + const specifiers = navigator.languages.map((x) => x.split("-")); + + for (const s of specifiers) { + if (s.length === 1) { + const lang = s[0]; + for (const available of SUPPORTED_REGIONS) { + if (available.toLowerCase().startsWith(lang.toLowerCase())) { + return available; + } } - return undefined; - }) - .filter((x): x is string => !!x); - for (const r of regions) { - for (const available of SUPPORTED_REGIONS) { - if (available.toLowerCase().endsWith(r.toLowerCase())) { - return available; + } else if (s.length === 2) { + const [lang, region] = s[1]; + for (const available of SUPPORTED_REGIONS) { + if (available.toLowerCase() === `${lang}_${region}`.toLowerCase()) { + return available; + } } } } + return "en_GB"; } @@ -148,14 +158,17 @@ export function useLanguage() { return () => settings().language || autoMatchLangTag(); } -type ImportFn = (name: string) => Promise<{default: T}> +type ImportFn = (name: string) => Promise<{ default: T }>; -type ImportedModule = F extends ImportFn ? T: never +type ImportedModule = F extends ImportFn ? T : never; -type MergedImportedModule = - T extends [] ? {} : - T extends [infer I] ? ImportedModule : - T extends [infer I, ...infer J] ? ImportedModule & MergedImportedModule : never +type MergedImportedModule = T extends [] + ? {} + : T extends [infer I] + ? ImportedModule + : T extends [infer I, ...infer J] + ? ImportedModule & MergedImportedModule + : never; export function createStringResource< T extends ImportFn | undefined>>[], @@ -170,9 +183,11 @@ export function createStringResource< return cache[nlang]; } - const results = await Promise.all(importFns.map(x => x(nlang).then(v => v.default))) + const results = await Promise.all( + importFns.map((x) => x(nlang).then((v) => v.default)), + ); - const merged: MergedImportedModule = Object.assign({}, ...results) + const merged: MergedImportedModule = Object.assign({}, ...results); cache[nlang] = merged; @@ -181,8 +196,10 @@ export function createStringResource< ); } -export function createTranslator | undefined>>[],>(...importFns: T) { - const res = createStringResource(...importFns) +export function createTranslator< + T extends ImportFn | undefined>>[], +>(...importFns: T) { + const res = createStringResource(...importFns); - return [translator(res[0], resolveTemplate), res] as const + return [translator(res[0], resolveTemplate), res] as const; }