From b13c269162e6c858acbce6cc792636cd4cb921a9 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Tue, 20 Jan 2026 15:00:46 -0600 Subject: wip(app): i18n --- packages/enterprise/src/app.tsx | 68 +++++++++++++++++++++++++++++++- packages/enterprise/src/entry-server.tsx | 48 ++++++++++++++-------- 2 files changed, 98 insertions(+), 18 deletions(-) (limited to 'packages/enterprise') diff --git a/packages/enterprise/src/app.tsx b/packages/enterprise/src/app.tsx index 0fd3a009c..1d408ac94 100644 --- a/packages/enterprise/src/app.tsx +++ b/packages/enterprise/src/app.tsx @@ -4,10 +4,72 @@ import { Font } from "@opencode-ai/ui/font" import { MetaProvider } from "@solidjs/meta" import { MarkedProvider } from "@opencode-ai/ui/context/marked" import { DialogProvider } from "@opencode-ai/ui/context/dialog" -import { Suspense } from "solid-js" +import { I18nProvider, type UiI18nParams } from "@opencode-ai/ui/context" +import { dict as uiEn } from "@opencode-ai/ui/i18n/en" +import { dict as uiZh } from "@opencode-ai/ui/i18n/zh" +import { createEffect, createMemo, Suspense, type ParentProps } from "solid-js" +import { getRequestEvent } from "solid-js/web" import "./app.css" import { Favicon } from "@opencode-ai/ui/favicon" +function resolveTemplate(text: string, params?: UiI18nParams) { + if (!params) return text + return text.replace(/{{\s*([^}]+?)\s*}}/g, (_, rawKey) => { + const key = String(rawKey) + const value = params[key] + return value === undefined ? "" : String(value) + }) +} + +function detectLocaleFromHeader(header: string | null | undefined) { + if (!header) return + for (const item of header.split(",")) { + const value = item.trim().split(";")[0]?.toLowerCase() + if (!value) continue + if (value.startsWith("zh")) return "zh" as const + if (value.startsWith("en")) return "en" as const + } +} + +function detectLocale() { + const event = getRequestEvent() + const header = event?.request.headers.get("accept-language") + const headerLocale = detectLocaleFromHeader(header) + if (headerLocale) return headerLocale + + if (typeof document === "object") { + const value = document.documentElement.lang?.toLowerCase() ?? "" + if (value.startsWith("zh")) return "zh" as const + if (value.startsWith("en")) return "en" as const + } + + if (typeof navigator === "object") { + const languages = navigator.languages?.length ? navigator.languages : [navigator.language] + for (const language of languages) { + if (!language) continue + if (language.toLowerCase().startsWith("zh")) return "zh" as const + } + } + + return "en" as const +} + +function UiI18nBridge(props: ParentProps) { + const locale = createMemo(() => detectLocale()) + const t = (key: keyof typeof uiEn, params?: UiI18nParams) => { + const value = locale() === "zh" ? uiZh[key] ?? uiEn[key] : uiEn[key] + const text = value ?? String(key) + return resolveTemplate(text, params) + } + + createEffect(() => { + if (typeof document !== "object") return + document.documentElement.lang = locale() + }) + + return {props.children} +} + export default function App() { return ( - {props.children} + + {props.children} + diff --git a/packages/enterprise/src/entry-server.tsx b/packages/enterprise/src/entry-server.tsx index 989c3c088..b61448c95 100644 --- a/packages/enterprise/src/entry-server.tsx +++ b/packages/enterprise/src/entry-server.tsx @@ -1,23 +1,39 @@ // @refresh reload import { createHandler, StartServer } from "@solidjs/start/server" +import { getRequestEvent } from "solid-js/web" export default createHandler(() => ( ( - - - - - OpenCode - - - {assets} - - -
{children}
- {scripts} - - - )} + document={({ assets, children, scripts }) => { + const lang = (() => { + const event = getRequestEvent() + const header = event?.request.headers.get("accept-language") + if (!header) return "en" + for (const item of header.split(",")) { + const value = item.trim().split(";")[0]?.toLowerCase() + if (!value) continue + if (value.startsWith("zh")) return "zh" + if (value.startsWith("en")) return "en" + } + return "en" + })() + + return ( + + + + + OpenCode + + + {assets} + + +
{children}
+ {scripts} + + + ) + }} /> )) -- cgit v1.2.3