diff options
| author | Adam <[email protected]> | 2026-01-19 15:50:23 -0600 |
|---|---|---|
| committer | Adam <[email protected]> | 2026-01-20 17:58:06 -0600 |
| commit | 0470717c7fbb9ff175b70c6d76ffb2330ef40a1a (patch) | |
| tree | 291cff80dcd40315572893e1c639463fda635001 /packages/app/src/context | |
| parent | 7f50b279962aa76990e2ca2b7eb9bdfd3beafc38 (diff) | |
| download | opencode-0470717c7fbb9ff175b70c6d76ffb2330ef40a1a.tar.gz opencode-0470717c7fbb9ff175b70c6d76ffb2330ef40a1a.zip | |
feat(app): initial i18n stubbing
Diffstat (limited to 'packages/app/src/context')
| -rw-r--r-- | packages/app/src/context/language.tsx | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/packages/app/src/context/language.tsx b/packages/app/src/context/language.tsx new file mode 100644 index 000000000..3178cb6b6 --- /dev/null +++ b/packages/app/src/context/language.tsx @@ -0,0 +1,77 @@ +import * as i18n from "@solid-primitives/i18n" +import { createEffect, createMemo } from "solid-js" +import { createStore } from "solid-js/store" +import { createSimpleContext } from "@opencode-ai/ui/context" +import { Persist, persisted } from "@/utils/persist" +import { dict as en } from "@/i18n/en" +import { dict as zh } from "@/i18n/zh" + +export type Locale = "en" | "zh" + +type RawDictionary = typeof en +type Dictionary = i18n.Flatten<RawDictionary> + +const LOCALES: readonly Locale[] = ["en", "zh"] + +function detectLocale(): Locale { + if (typeof navigator !== "object") return "en" + + const languages = navigator.languages?.length ? navigator.languages : [navigator.language] + for (const language of languages) { + if (!language) continue + if (language.toLowerCase().startsWith("zh")) return "zh" + } + + return "en" +} + +export const { use: useLanguage, provider: LanguageProvider } = createSimpleContext({ + name: "Language", + init: () => { + const [store, setStore, _, ready] = persisted( + Persist.global("language", ["language.v1"]), + createStore({ + locale: detectLocale() as Locale, + }), + ) + + const locale = createMemo<Locale>(() => (store.locale === "zh" ? "zh" : "en")) + + createEffect(() => { + const current = locale() + if (store.locale === current) return + setStore("locale", current) + }) + + const base = i18n.flatten(en) + const dict = createMemo<Dictionary>(() => { + if (locale() === "en") return base + return { ...base, ...i18n.flatten(zh) } + }) + + const t = i18n.translator(dict, i18n.resolveTemplate) + + const labelKey: Record<Locale, keyof Dictionary> = { + en: "language.en", + zh: "language.zh", + } + + const label = (value: Locale) => t(labelKey[value]) + + createEffect(() => { + if (typeof document !== "object") return + document.documentElement.lang = locale() + }) + + return { + ready, + locale, + locales: LOCALES, + label, + t, + setLocale(next: Locale) { + setStore("locale", next) + }, + } + }, +}) |
