Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
82 changes: 82 additions & 0 deletions .github/workflows/docs-locale-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: docs-locale-sync

on:
push:
branches:
- dev
paths:
- packages/web/src/content/docs/*.mdx

jobs:
sync-locales:
if: github.actor != 'opencode-agent[bot]'
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
id-token: write
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Bun
uses: ./.github/actions/setup-bun

- name: Setup git committer
id: committer
uses: ./.github/actions/setup-git-committer
with:
opencode-app-id: ${{ vars.OPENCODE_APP_ID }}
opencode-app-secret: ${{ secrets.OPENCODE_APP_SECRET }}

- name: Compute changed English docs
id: changes
run: |
FILES=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" -- 'packages/web/src/content/docs/*.mdx' || true)
if [ -z "$FILES" ]; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
echo "No English docs changed in push range"
exit 0
fi
echo "has_changes=true" >> "$GITHUB_OUTPUT"
{
echo "files<<EOF"
echo "$FILES"
echo "EOF"
} >> "$GITHUB_OUTPUT"

- name: Sync locale docs with OpenCode
if: steps.changes.outputs.has_changes == 'true'
uses: sst/opencode/github@latest
env:
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
with:
model: opencode/gpt-5.2
agent: docs
prompt: |
Update localized docs to match the latest English docs changes.

Changed English doc files:
<changed_english_docs>
${{ steps.changes.outputs.files }}
</changed_english_docs>

Requirements:
1. Update all relevant locale docs under packages/web/src/content/docs/<locale>/ so they reflect these English page changes.
2. Preserve frontmatter keys, internal links, code blocks, and existing locale-specific metadata unless the English change requires an update.
3. Keep locale docs structure aligned with their corresponding English pages.
4. Do not modify English source docs in packages/web/src/content/docs/*.mdx.
5. If no locale updates are needed, make no changes.

- name: Commit and push locale docs updates
if: steps.changes.outputs.has_changes == 'true'
run: |
if [ -z "$(git status --porcelain)" ]; then
echo "No locale docs changes to commit"
exit 0
fi
git add -A
git commit -m "docs(i18n): sync locale docs from english changes"
git pull --rebase --autostash origin "$GITHUB_REF_NAME"
git push origin HEAD:"$GITHUB_REF_NAME"
122 changes: 118 additions & 4 deletions bun.lock

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions packages/console/app/src/routes/docs/[...path].ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { APIEvent } from "@solidjs/start/server"
import { LOCALE_HEADER, localeFromCookieHeader, parseLocale, tag } from "~/lib/language"
import { localeFromRequest, tag } from "~/lib/language"

async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://docs.opencode.ai${url.pathname}${url.search}`

const headers = new Headers(req.headers)
const locale = parseLocale(req.headers.get(LOCALE_HEADER)) ?? localeFromCookieHeader(req.headers.get("cookie"))
if (locale) headers.set("accept-language", tag(locale))
headers.set("accept-language", tag(localeFromRequest(req)))

const response = await fetch(targetUrl, {
method: req.method,
Expand Down
5 changes: 2 additions & 3 deletions packages/console/app/src/routes/docs/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { APIEvent } from "@solidjs/start/server"
import { LOCALE_HEADER, localeFromCookieHeader, parseLocale, tag } from "~/lib/language"
import { localeFromRequest, tag } from "~/lib/language"

async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://docs.opencode.ai${url.pathname}${url.search}`

const headers = new Headers(req.headers)
const locale = parseLocale(req.headers.get(LOCALE_HEADER)) ?? localeFromCookieHeader(req.headers.get("cookie"))
if (locale) headers.set("accept-language", tag(locale))
headers.set("accept-language", tag(localeFromRequest(req)))

const response = await fetch(targetUrl, {
method: req.method,
Expand Down
14 changes: 7 additions & 7 deletions packages/console/app/src/routes/download/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ export default function Download() {
</span>
<span>VS Code</span>
</div>
<a href="https://opencode.ai/docs/ide/" data-component="action-button">
<a href="/docs/ide/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand All @@ -318,7 +318,7 @@ export default function Download() {
</span>
<span>Cursor</span>
</div>
<a href="https://opencode.ai/docs/ide/" data-component="action-button">
<a href="/docs/ide/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand All @@ -335,7 +335,7 @@ export default function Download() {
</span>
<span>Zed</span>
</div>
<a href="https://opencode.ai/docs/ide/" data-component="action-button">
<a href="/docs/ide/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand All @@ -352,7 +352,7 @@ export default function Download() {
</span>
<span>Windsurf</span>
</div>
<a href="https://opencode.ai/docs/ide/" data-component="action-button">
<a href="/docs/ide/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand All @@ -369,7 +369,7 @@ export default function Download() {
</span>
<span>VSCodium</span>
</div>
<a href="https://opencode.ai/docs/ide/" data-component="action-button">
<a href="/docs/ide/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand All @@ -393,7 +393,7 @@ export default function Download() {
</span>
<span>GitHub</span>
</div>
<a href="https://opencode.ai/docs/github/" data-component="action-button">
<a href="/docs/github/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand All @@ -410,7 +410,7 @@ export default function Download() {
</span>
<span>GitLab</span>
</div>
<a href="https://opencode.ai/docs/gitlab/" data-component="action-button">
<a href="/docs/gitlab/" data-component="action-button">
{i18n.t("download.action.install")}
</a>
</div>
Expand Down
5 changes: 2 additions & 3 deletions packages/console/app/src/routes/s/[id].ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { APIEvent } from "@solidjs/start/server"
import { LOCALE_HEADER, localeFromCookieHeader, parseLocale, tag } from "~/lib/language"
import { localeFromRequest, tag } from "~/lib/language"

async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://docs.opencode.ai/docs${url.pathname}${url.search}`

const headers = new Headers(req.headers)
const locale = parseLocale(req.headers.get(LOCALE_HEADER)) ?? localeFromCookieHeader(req.headers.get("cookie"))
if (locale) headers.set("accept-language", tag(locale))
headers.set("accept-language", tag(localeFromRequest(req)))

const response = await fetch(targetUrl, {
method: req.method,
Expand Down
154 changes: 154 additions & 0 deletions packages/web/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,99 @@ export default defineConfig({
solidJs(),
starlight({
title: "OpenCode",
defaultLocale: "root",
locales: {
root: {
label: "English",
lang: "en",
dir: "ltr",
},
ar: {
label: "العربية",
lang: "ar",
dir: "rtl",
},
bs: {
label: "Bosanski",
lang: "bs-BA",
dir: "ltr",
},
da: {
label: "Dansk",
lang: "da-DK",
dir: "ltr",
},
de: {
label: "Deutsch",
lang: "de-DE",
dir: "ltr",
},
es: {
label: "Espa\u00f1ol",
lang: "es-ES",
dir: "ltr",
},
fr: {
label: "Fran\u00e7ais",
lang: "fr-FR",
dir: "ltr",
},
it: {
label: "Italiano",
lang: "it-IT",
dir: "ltr",
},
ja: {
label: "日本語",
lang: "ja-JP",
dir: "ltr",
},
ko: {
label: "한국어",
lang: "ko-KR",
dir: "ltr",
},
nb: {
label: "Norsk Bokm\u00e5l",
lang: "nb-NO",
dir: "ltr",
},
pl: {
label: "Polski",
lang: "pl-PL",
dir: "ltr",
},
"pt-br": {
label: "Portugu\u00eas (Brasil)",
lang: "pt-BR",
dir: "ltr",
},
ru: {
label: "Русский",
lang: "ru-RU",
dir: "ltr",
},
th: {
label: "ไทย",
lang: "th-TH",
dir: "ltr",
},
tr: {
label: "T\u00fcrk\u00e7e",
lang: "tr-TR",
dir: "ltr",
},
"zh-cn": {
label: "简体中文",
lang: "zh-CN",
dir: "ltr",
},
"zh-tw": {
label: "繁體中文",
lang: "zh-TW",
dir: "ltr",
},
},
favicon: "/favicon-v3.svg",
head: [
{
Expand Down Expand Up @@ -89,11 +182,51 @@ export default defineConfig({
"1-0",
{
label: "Usage",
translations: {
en: "Usage",
ar: "الاستخدام",
"bs-BA": "Korištenje",
"da-DK": "Brug",
"de-DE": "Nutzung",
"es-ES": "Uso",
"fr-FR": "Utilisation",
"it-IT": "Utilizzo",
"ja-JP": "使い方",
"ko-KR": "사용",
"nb-NO": "Bruk",
"pl-PL": "Użycie",
"pt-BR": "Uso",
"ru-RU": "Использование",
"th-TH": "การใช้งาน",
"tr-TR": "Kullanım",
"zh-CN": "使用",
"zh-TW": "使用",
},
items: ["tui", "cli", "web", "ide", "zen", "share", "github", "gitlab"],
},

{
label: "Configure",
translations: {
en: "Configure",
ar: "الإعداد",
"bs-BA": "Podešavanje",
"da-DK": "Konfiguration",
"de-DE": "Konfiguration",
"es-ES": "Configuración",
"fr-FR": "Configuration",
"it-IT": "Configurazione",
"ja-JP": "設定",
"ko-KR": "구성",
"nb-NO": "Konfigurasjon",
"pl-PL": "Konfiguracja",
"pt-BR": "Configuração",
"ru-RU": "Настройка",
"th-TH": "การกำหนดค่า",
"tr-TR": "Yapılandırma",
"zh-CN": "配置",
"zh-TW": "設定",
},
items: [
"tools",
"rules",
Expand All @@ -114,13 +247,34 @@ export default defineConfig({

{
label: "Develop",
translations: {
en: "Develop",
ar: "التطوير",
"bs-BA": "Razvoj",
"da-DK": "Udvikling",
"de-DE": "Entwicklung",
"es-ES": "Desarrollo",
"fr-FR": "Développement",
"it-IT": "Sviluppo",
"ja-JP": "開発",
"ko-KR": "개발",
"nb-NO": "Utvikling",
"pl-PL": "Rozwój",
"pt-BR": "Desenvolvimento",
"ru-RU": "Разработка",
"th-TH": "การพัฒนา",
"tr-TR": "Geliştirme",
"zh-CN": "开发",
"zh-TW": "開發",
},
items: ["sdk", "server", "plugins", "ecosystem"],
},
],
components: {
Hero: "./src/components/Hero.astro",
Head: "./src/components/Head.astro",
Header: "./src/components/Header.astro",
Footer: "./src/components/Footer.astro",
SiteTitle: "./src/components/SiteTitle.astro",
},
plugins: [
Expand Down
4 changes: 2 additions & 2 deletions packages/web/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default {
github: "https://github.com/anomalyco/opencode",
discord: "https://opencode.ai/discord",
headerLinks: [
{ name: "Home", url: "/" },
{ name: "Docs", url: "/docs/" },
{ name: "app.header.home", url: "/" },
{ name: "app.header.docs", url: "/docs/" },
],
}
Loading
Loading