summaryrefslogtreecommitdiffhomepage
path: root/packages/web/src/pages
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-02-09 11:34:35 -0600
committerGitHub <[email protected]>2026-02-09 11:34:35 -0600
commitdc53086c1e73d43d3a28fc4cdf161e83d09b1877 (patch)
tree45a1d0e38de958d0886a5120b2806b21db74145b /packages/web/src/pages
parentf74c0339cc6315f7e7743e26b7eab47ce026c239 (diff)
downloadopencode-dc53086c1e73d43d3a28fc4cdf161e83d09b1877.tar.gz
opencode-dc53086c1e73d43d3a28fc4cdf161e83d09b1877.zip
wip(docs): i18n (#12681)
Diffstat (limited to 'packages/web/src/pages')
-rw-r--r--packages/web/src/pages/[...slug].md.ts20
-rw-r--r--packages/web/src/pages/s/[id].astro135
2 files changed, 111 insertions, 44 deletions
diff --git a/packages/web/src/pages/[...slug].md.ts b/packages/web/src/pages/[...slug].md.ts
index 51c63b5a6..dbc11d78e 100644
--- a/packages/web/src/pages/[...slug].md.ts
+++ b/packages/web/src/pages/[...slug].md.ts
@@ -1,13 +1,29 @@
import type { APIRoute } from "astro"
import { getCollection } from "astro:content"
-export const GET: APIRoute = async ({ params }) => {
+function notFoundText(locals: unknown) {
+ if (typeof locals !== "object" || locals === null || !("t" in locals)) {
+ return "share.not_found"
+ }
+ const t = (locals as { t?: unknown }).t
+ if (typeof t !== "function") {
+ return "share.not_found"
+ }
+ const text = t("share.not_found")
+ if (typeof text === "string" && text.length > 0) {
+ return text
+ }
+ return "share.not_found"
+}
+
+export const GET: APIRoute = async ({ params, locals }) => {
const slug = params.slug || "index"
const docs = await getCollection("docs")
const doc = docs.find((d) => d.id === slug)
+ const notFound = notFoundText(locals)
if (!doc) {
- return new Response("Not found", { status: 404 })
+ return new Response(notFound, { status: 404, statusText: notFound })
}
return new Response(doc.body, {
diff --git a/packages/web/src/pages/s/[id].astro b/packages/web/src/pages/s/[id].astro
index df39f0070..7ea42f691 100644
--- a/packages/web/src/pages/s/[id].astro
+++ b/packages/web/src/pages/s/[id].astro
@@ -1,55 +1,112 @@
---
-import { Base64 } from "js-base64";
+import { Base64 } from "js-base64"
+import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"
+import type { Session } from "opencode/session/index"
+import config from "../../../config.mjs"
+import Share from "../../components/Share.tsx"
-import config from '../../../config.mjs'
-import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
-import Share from "../../components/Share.tsx";
+const apiUrl = import.meta.env.VITE_API_URL || ""
+const ta = Astro.locals.t as ((key: string) => string) & {
+ all?: () => Record<string, string>
+}
+const all = typeof ta.all === "function" ? ta.all() : {}
+const locale = Astro.currentLocale || Astro.locals.starlightRoute.locale || "root"
+const formatLocale = locale === "root" ? "en" : locale
+const t = ta
-const apiUrl = import.meta.env.VITE_API_URL;
+function tx(key: string) {
+ const value = all[key]
+ if (typeof value === "string") return value
+ return t(key)
+}
-const { id } = Astro.params;
-const res = await fetch(`${apiUrl}/share_data?id=${id}`);
-const data = await res.json();
+const messages = {
+ locale: formatLocale,
+ link_to_message: tx("share.link_to_message"),
+ copied: tx("share.copied"),
+ copy: tx("share.copy"),
+ show_more: tx("share.show_more"),
+ show_less: tx("share.show_less"),
+ show_results: tx("share.show_results"),
+ hide_results: tx("share.hide_results"),
+ show_details: tx("share.show_details"),
+ hide_details: tx("share.hide_details"),
+ show_preview: tx("share.show_preview"),
+ hide_preview: tx("share.hide_preview"),
+ show_contents: tx("share.show_contents"),
+ hide_contents: tx("share.hide_contents"),
+ show_output: tx("share.show_output"),
+ hide_output: tx("share.hide_output"),
+ error: tx("share.error"),
+ waiting_for_messages: tx("share.waiting_for_messages"),
+ status_connected_waiting: tx("share.status_connected_waiting"),
+ status_connecting: tx("share.status_connecting"),
+ status_disconnected: tx("share.status_disconnected"),
+ status_reconnecting: tx("share.status_reconnecting"),
+ status_error: tx("share.status_error"),
+ status_unknown: tx("share.status_unknown"),
+ error_id_not_found: tx("share.error_id_not_found"),
+ error_api_url_not_found: tx("share.error_api_url_not_found"),
+ error_connection_failed: tx("share.error_connection_failed"),
+ opencode_version: tx("share.opencode_version"),
+ opencode_name: tx("share.opencode_name"),
+ models: tx("share.models"),
+ cost: tx("share.cost"),
+ input_tokens: tx("share.input_tokens"),
+ output_tokens: tx("share.output_tokens"),
+ reasoning_tokens: tx("share.reasoning_tokens"),
+ scroll_to_bottom: tx("share.scroll_to_bottom"),
+ attachment: tx("share.attachment"),
+ thinking: tx("share.thinking"),
+ thinking_pending: tx("share.thinking_pending"),
+ creating_plan: tx("share.creating_plan"),
+ completing_plan: tx("share.completing_plan"),
+ updating_plan: tx("share.updating_plan"),
+ match_one: tx("share.match_one"),
+ match_other: tx("share.match_other"),
+ result_one: tx("share.result_one"),
+ result_other: tx("share.result_other"),
+ debug_key: tx("share.debug_key"),
+}
+
+const id = Astro.params.id || ""
+const res = await fetch(`${apiUrl}/share_data?id=${id}`)
+const data = (await res.json()) as {
+ info?: Session.Info
+ messages: Record<string, { role?: string; modelID?: string }>
+}
if (!data.info) {
return new Response(null, {
status: 404,
- statusText: 'Not found'
- });
+ statusText: tx("share.not_found"),
+ })
}
-const models: Set<string> = new Set();
-const version = data.info.version ? `v${data.info.version}` : "v0.0.1";
+const models: Set<string> = new Set()
+const version = data.info.version ? `v${data.info.version}` : "v0.0.1"
-Object.values(data.messages).forEach((d) => {
+for (const d of Object.values(data.messages)) {
if (d.role === "assistant" && d.modelID) {
- models.add(d.modelID);
+ models.add(d.modelID)
}
-});
+}
const encodedTitle = encodeURIComponent(
Base64.encode(
- // Convert to ASCII
- encodeURIComponent(
- // Truncate to fit S3's max key size
- data.info.title.substring(0, 700),
- )
- )
-);
+ encodeURIComponent(data.info.title.substring(0, 700)),
+ ),
+)
-const modelsArray = Array.from(models);
-let modelParam;
-if (modelsArray.length === 1) {
- modelParam = modelsArray[0];
-}
-else if (modelsArray.length === 2) {
- modelParam = encodeURIComponent(`${modelsArray[0]} & ${modelsArray[1]}`);
-}
-else {
- modelParam = encodeURIComponent(`${modelsArray[0]} & ${modelsArray.length - 1} others`);
-}
+const modelsArray = Array.from(models)
+const modelParam =
+ modelsArray.length === 1
+ ? modelsArray[0]
+ : modelsArray.length === 2
+ ? encodeURIComponent(`${modelsArray[0]} & ${modelsArray[1]}`)
+ : encodeURIComponent(`${modelsArray[0]} & ${modelsArray.length - 1} others`)
-const ogImage = `${config.socialCard}/opencode-share/${encodedTitle}.png?model=${modelParam}&version=${version}&id=${id}`;
+const ogImage = `${config.socialCard}/opencode-share/${encodedTitle}.png?model=${modelParam}&version=${version}&id=${id}`
---
<StarlightPage
hasSidebar={false}
@@ -63,7 +120,7 @@ const ogImage = `${config.socialCard}/opencode-share/${encodedTitle}.png?model=$
tag: "meta",
attrs: {
name: "description",
- content: "opencode - The AI coding agent built for the terminal.",
+ content: tx("share.meta_description"),
},
},
{
@@ -90,13 +147,7 @@ const ogImage = `${config.socialCard}/opencode-share/${encodedTitle}.png?model=$
],
}}
>
- <Share
- id={id}
- api={apiUrl}
- info={data.info}
- messages={data.messages}
- client:only="solid"
- />
+ <Share id={id} api={apiUrl} info={data.info} messages={messages} client:only="solid" />
</StarlightPage>
<style is:global>