diff --git a/src/App.tsx b/src/App.tsx
index 8f7ba44..e7ca588 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,4 @@
-import { Route, Router } from "@solidjs/router";
+import { Route } from "@solidjs/router";
import { ThemeProvider } from "@suid/material";
import {
Component,
@@ -17,7 +17,12 @@ import {
} from "./masto/clients.js";
import { $accounts, updateAcctInf } from "./accounts/stores.js";
import { useStore } from "@nanostores/solid";
-import { DateFnScope, useLanguage } from "./platform/i18n.jsx";
+import {
+ AppLocaleProvider,
+ createCurrentLanguage,
+ createCurrentRegion,
+ createDateFnLocaleResource,
+} from "./platform/i18n.jsx";
import { useRegisterSW } from "virtual:pwa-register/solid";
import {
isJSONRPCResult,
@@ -67,7 +72,9 @@ const Routing: Component = () => {
const App: Component = () => {
const theme = useRootTheme();
const accts = useStore($accounts);
- const lang = useLanguage();
+ const lang = createCurrentLanguage();
+ const region = createCurrentRegion();
+ const dateFnLocale = createDateFnLocaleResource(region);
const [serviceWorker, setServiceWorker] = createSignal<
ServiceWorker | undefined
>(undefined, { name: "serviceWorker" });
@@ -150,7 +157,13 @@ const App: Component = () => {
}}
>
-
+
{
-
+
);
diff --git a/src/platform/i18n.tsx b/src/platform/i18n.tsx
index ade3868..b64b920 100644
--- a/src/platform/i18n.tsx
+++ b/src/platform/i18n.tsx
@@ -1,12 +1,12 @@
import {
- ParentComponent,
+ catchError,
createContext,
createMemo,
createResource,
useContext,
} from "solid-js";
import { match } from "@formatjs/intl-localematcher";
-import { Accessor, createEffect, createSignal } from "solid-js";
+import { Accessor } from "solid-js";
import { $settings } from "../settings/stores";
import { enGB } from "date-fns/locale/en-GB";
import { useStore } from "@nanostores/solid";
@@ -17,13 +17,6 @@ import {
type Template,
} from "@solid-primitives/i18n";
-async function synchronised(
- name: string,
- callback: () => Promise | void,
-): Promise {
- await navigator.locks.request(name, callback);
-}
-
export const SUPPORTED_LANGS = ["en", "zh-Hans"] as const;
export const SUPPORTED_REGIONS = ["en_US", "en_GB", "zh_CN"] as const;
@@ -38,14 +31,6 @@ export function autoMatchLangTag() {
return match(Array.from(navigator.languages), SUPPORTED_LANGS, DEFAULT_LANG);
}
-const DateFnLocaleCx = /* __@PURE__ */ createContext>(
- () => enGB,
-);
-
-const cachedDateFnLocale: Record = {
- enGB,
-};
-
export function autoMatchRegion() {
const specifiers = navigator.languages.map((x) => x.split("-"));
@@ -70,7 +55,7 @@ export function autoMatchRegion() {
return "en_GB";
}
-export function useRegion() {
+export function createCurrentRegion() {
const appSettings = useStore($settings);
return createMemo(
@@ -100,53 +85,6 @@ async function importDateFnLocale(tag: string): Promise {
}
}
-/**
- * Provides runtime values and fetch dependencies for date-fns locale
- */
-export const DateFnScope: ParentComponent = (props) => {
- const [dateFnLocale, setDateFnLocale] = createSignal(enGB, {
- name: "dateFnLocale",
- });
- const region = useRegion();
-
- createEffect(() => {
- const dateFnLocaleName = region();
-
- if (cachedDateFnLocale[dateFnLocaleName]) {
- setDateFnLocale(cachedDateFnLocale[dateFnLocaleName]);
- } else {
- synchronised("i18n-wrapper-load-date-fns-locale", async () => {
- if (cachedDateFnLocale[dateFnLocaleName]) {
- setDateFnLocale(cachedDateFnLocale[dateFnLocaleName]);
- return;
- }
- const target = `date-fns/locale/${dateFnLocaleName}`;
- try {
- const mod = await importDateFnLocale(dateFnLocaleName);
- cachedDateFnLocale[dateFnLocaleName] = mod;
- setDateFnLocale(mod);
- } catch (reason) {
- console.error(
- {
- act: "load-date-fns-locale",
- stat: "failed",
- reason,
- target,
- },
- "failed to load date-fns locale",
- );
- }
- });
- }
- });
-
- return (
-
- {props.children}
-
- );
-};
-
/**
* Get the {@link Locale} object for date-fns.
*
@@ -155,11 +93,11 @@ export const DateFnScope: ParentComponent = (props) => {
* @returns Accessor for Locale
*/
export function useDateFnLocale(): Accessor {
- const cx = useContext(DateFnLocaleCx);
- return cx;
+ const { dateFn } = useAppLocale();
+ return dateFn;
}
-export function useLanguage() {
+export function createCurrentLanguage() {
const settings = useStore($settings);
return () => settings().language || autoMatchLangTag();
}
@@ -179,7 +117,7 @@ type MergedImportedModule = T extends []
export function createStringResource<
T extends ImportFn | undefined>>[],
>(...importFns: T) {
- const language = useLanguage(); // TODO: this function costs to much, provide a global cache
+ const language = createCurrentLanguage();
const cache: Record> = {};
return createResource(
@@ -209,3 +147,38 @@ export function createTranslator<
return [translator(res[0], resolveTemplate), res] as const;
}
+
+export type AppLocale = {
+ dateFn: () => Locale;
+ language: () => string;
+ region: () => string;
+};
+
+const AppLocaleContext = /* @__PURE__ */ createContext();
+
+export const AppLocaleProvider = AppLocaleContext.Provider;
+
+export function useAppLocale() {
+ const l = useContext(AppLocaleContext);
+ if (!l) {
+ throw new TypeError("app locale not found");
+ }
+ return l;
+}
+
+export function createDateFnLocaleResource(region: () => string) {
+ const [localeUncaught] = createResource(
+ region,
+ async (region) => {
+ return await importDateFnLocale(region);
+ },
+ { initialValue: enGB },
+ );
+
+ return createMemo(
+ () =>
+ catchError(localeUncaught, (reason) => {
+ console.error("fetch date-fns locale", reason);
+ }) ?? enGB,
+ );
+}