|
|
@ -11,7 +11,11 @@ import { $settings } from "../settings/stores";
|
|
|
|
import { enGB } from "date-fns/locale/en-GB";
|
|
|
|
import { enGB } from "date-fns/locale/en-GB";
|
|
|
|
import { useStore } from "@nanostores/solid";
|
|
|
|
import { useStore } from "@nanostores/solid";
|
|
|
|
import type { Locale } from "date-fns";
|
|
|
|
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(
|
|
|
|
async function synchronised(
|
|
|
|
name: string,
|
|
|
|
name: string,
|
|
|
@ -34,29 +38,35 @@ export function autoMatchLangTag() {
|
|
|
|
return match(Array.from(navigator.languages), SUPPORTED_LANGS, DEFAULT_LANG);
|
|
|
|
return match(Array.from(navigator.languages), SUPPORTED_LANGS, DEFAULT_LANG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const DateFnLocaleCx = /* __@PURE__ */createContext<Accessor<Locale>>(() => enGB);
|
|
|
|
const DateFnLocaleCx = /* __@PURE__ */ createContext<Accessor<Locale>>(
|
|
|
|
|
|
|
|
() => enGB,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const cachedDateFnLocale: Record<string, Locale> = {
|
|
|
|
const cachedDateFnLocale: Record<string, Locale> = {
|
|
|
|
enGB,
|
|
|
|
enGB,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
export function autoMatchRegion() {
|
|
|
|
export function autoMatchRegion() {
|
|
|
|
const regions = navigator.languages
|
|
|
|
const specifiers = navigator.languages.map((x) => x.split("-"));
|
|
|
|
.map((x) => {
|
|
|
|
|
|
|
|
const parts = x.split("_");
|
|
|
|
for (const s of specifiers) {
|
|
|
|
if (parts.length > 1) {
|
|
|
|
if (s.length === 1) {
|
|
|
|
return parts[1];
|
|
|
|
const lang = s[0];
|
|
|
|
|
|
|
|
for (const available of SUPPORTED_REGIONS) {
|
|
|
|
|
|
|
|
if (available.toLowerCase().startsWith(lang.toLowerCase())) {
|
|
|
|
|
|
|
|
return available;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
} else if (s.length === 2) {
|
|
|
|
})
|
|
|
|
const [lang, region] = s[1];
|
|
|
|
.filter((x): x is string => !!x);
|
|
|
|
for (const available of SUPPORTED_REGIONS) {
|
|
|
|
for (const r of regions) {
|
|
|
|
if (available.toLowerCase() === `${lang}_${region}`.toLowerCase()) {
|
|
|
|
for (const available of SUPPORTED_REGIONS) {
|
|
|
|
return available;
|
|
|
|
if (available.toLowerCase().endsWith(r.toLowerCase())) {
|
|
|
|
}
|
|
|
|
return available;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return "en_GB";
|
|
|
|
return "en_GB";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -148,14 +158,17 @@ export function useLanguage() {
|
|
|
|
return () => settings().language || autoMatchLangTag();
|
|
|
|
return () => settings().language || autoMatchLangTag();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type ImportFn<T> = (name: string) => Promise<{default: T}>
|
|
|
|
type ImportFn<T> = (name: string) => Promise<{ default: T }>;
|
|
|
|
|
|
|
|
|
|
|
|
type ImportedModule<F> = F extends ImportFn<infer T> ? T: never
|
|
|
|
type ImportedModule<F> = F extends ImportFn<infer T> ? T : never;
|
|
|
|
|
|
|
|
|
|
|
|
type MergedImportedModule<T> =
|
|
|
|
type MergedImportedModule<T> = T extends []
|
|
|
|
T extends [] ? {} :
|
|
|
|
? {}
|
|
|
|
T extends [infer I] ? ImportedModule<I> :
|
|
|
|
: T extends [infer I]
|
|
|
|
T extends [infer I, ...infer J] ? ImportedModule<I> & MergedImportedModule<J> : never
|
|
|
|
? ImportedModule<I>
|
|
|
|
|
|
|
|
: T extends [infer I, ...infer J]
|
|
|
|
|
|
|
|
? ImportedModule<I> & MergedImportedModule<J>
|
|
|
|
|
|
|
|
: never;
|
|
|
|
|
|
|
|
|
|
|
|
export function createStringResource<
|
|
|
|
export function createStringResource<
|
|
|
|
T extends ImportFn<Record<string, string | Template<any> | undefined>>[],
|
|
|
|
T extends ImportFn<Record<string, string | Template<any> | undefined>>[],
|
|
|
@ -170,9 +183,11 @@ export function createStringResource<
|
|
|
|
return cache[nlang];
|
|
|
|
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<T> = Object.assign({}, ...results)
|
|
|
|
const merged: MergedImportedModule<T> = Object.assign({}, ...results);
|
|
|
|
|
|
|
|
|
|
|
|
cache[nlang] = merged;
|
|
|
|
cache[nlang] = merged;
|
|
|
|
|
|
|
|
|
|
|
@ -181,8 +196,10 @@ export function createStringResource<
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function createTranslator<T extends ImportFn<Record<string, string | Template<any> | undefined>>[],>(...importFns: T) {
|
|
|
|
export function createTranslator<
|
|
|
|
const res = createStringResource(...importFns)
|
|
|
|
T extends ImportFn<Record<string, string | Template<any> | undefined>>[],
|
|
|
|
|
|
|
|
>(...importFns: T) {
|
|
|
|
|
|
|
|
const res = createStringResource(...importFns);
|
|
|
|
|
|
|
|
|
|
|
|
return [translator(res[0], resolveTemplate), res] as const
|
|
|
|
return [translator(res[0], resolveTemplate), res] as const;
|
|
|
|
}
|
|
|
|
}
|
|
|
|