summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/context
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-01-19 15:50:23 -0600
committerAdam <[email protected]>2026-01-20 17:58:06 -0600
commit0470717c7fbb9ff175b70c6d76ffb2330ef40a1a (patch)
tree291cff80dcd40315572893e1c639463fda635001 /packages/app/src/context
parent7f50b279962aa76990e2ca2b7eb9bdfd3beafc38 (diff)
downloadopencode-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.tsx77
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)
+ },
+ }
+ },
+})