Files
paseo/docs/website-i18n.md
T
Mohamed Boudra bd15e40e94 Serve paseo.sh in Simplified Chinese (#7373)
* feat(website): serve paseo.sh in Simplified Chinese

Every page of the website now has a Simplified Chinese version under
/zh-CN: the interface, docs, blog posts, comparison pages, legal pages,
all changelog releases and the homepage mockup. English URLs are unchanged.

The URL alone decides the language. There is no browser-language redirect
and no stored preference, because either would have to redirect the
unprefixed English URLs that people share and search engines index.
Internal links carry the page's language instead, and hreflang alternates
point Chinese search results at /zh-CN.

Translated headings pin the English anchor with {#id}, so section links
work in both languages. content-translations.test.ts fails when a page
has no translation or a translation's headings drift from the English.
Changelog releases and plugin listings without a translation render
whole in English under a notice, so a release never waits on one.

Plugin manifests and the registry gain optional translations and
OVERVIEW.zh-CN.md fields; older clients and registries ignore them.

* feat(website): replace the native language select with an EN/ZH menu

The header showed an OS-native select whose popup did not match the site.
The trigger now shows the language abbreviated (EN, ZH) and opens a menu in
the app's dropdown style that names each language in itself, with its name
in the page language underneath. Rows are real links to the same page in
that language; arrows, Escape, outside presses and taps behave as a menu
button, and the menu keeps itself on screen when a narrow header pushes the
trigger toward an edge.

Also drops the stray space after the full-width comma in the Chinese
homepage subtitle.

* docs(website): translate main's new docs and 0.12.0 release notes

Main added Keep run workspaces to the schedules docs, rewrote plugin icons
around inline SVG, and promoted 0.12.0 with new entries. Bring the Chinese
pages and changelog in line so no section falls back to English.

* fix(server): leave plugin listing translations to the registry

The daemon rejected manifests whose translations the registry would refuse,
so a plugin main installs could fail to load here. Paseo never reads
translations; the registry validates them at publish. Docs now say which
checks are automated at publish and which are human review.

* docs(plugins): describe the registry's final overview translation discovery

* style(server): format manifest test

* test(app): measure sidebar rows one at a time

After a reload the developer error toast appears while expectVerticalOrder
measures every row at once. Each concurrent boundingBox runs the toast
locator handler, and only one of them resumes, so the poll timed out on
every attempt since #7424. Measuring sequentially keeps one action in flight.

* test(app): return sidebar row measuring to main

#7480 hides the developer toast instead of running a locator handler, so
measuring the rows concurrently no longer races it. Reverts 41ac23016.

* test(app): wait for the compact shell before opening compact Changes

The shell survives the breakpoint, so right after the resize the wide
Explorer could still be visible: the test skipped the Explorer toggle and
the tab then disappeared, or toggled at the wrong time. Wait for the
compact-shell marker, as the composer helpers do since #7424.

* docs(website): translate main's plugin file panel docs

* test(app): edit the code font size after the font family remount

A committed appearance change remounts the settings screen through
AppearanceStyleBoundary, and the new form starts from the stored size.
Filling the size before that remount lost the edit in CI.

* docs(website): translate main's client/ui import docs

Follows #7474: one /client/ui entry, StreamedText instead of useRevealedText,
SettingsGroup dropped from the settings table, and the new
'UI imports in v0.13' migration section.

* test(app): wait for the previous layout's file panel picker to leave

After a resize the old layout's picker animates out while the new one is
already mounted, so the Use button matched two elements and the strict
locator failed. Wait for the shell's layout and a single picker first.
2026-10-21 13:13:03 +07:00

5.5 KiB

Website translations

paseo.sh is served in English and Simplified Chinese (zh-CN). This doc covers the website in packages/website. App UI translations are in i18n.md.

URLs own the language

  • English pages keep their unprefixed paths. Every other language lives under its tag: /docs/cli and /zh-CN/docs/cli are the same page. /en/... is not a page.
  • The server renders the language in the URL. There is no browser-language detection or redirect, so a shared link always opens in the language it was shared in.
  • The language selector moves to the same page in the other language and keeps the query and hash. Every internal link on a page carries the page's language, so the choice sticks while the reader navigates. An explicit English URL always renders English.
  • The choice is not stored. A stored choice could only take effect by redirecting unprefixed URLs, which are the English pages. First-party links into the site carry the reader's language instead: README.zh-CN.md links to /zh-CN/....
  • Routes live under src/routes/{-$locale}/. Build internal links with localizePath or useLocalizePath from ~/i18n. Links inside Markdown are localized by DocsMarkdown. Files, .md sources, llms.txt and API endpoints keep one path for every language (isPagePath).
  • Give each page's head the language-neutral path through pageMeta (src/meta.ts). It writes the self canonical, the hreflang alternates with English as x-default, and og:locale. The sitemap in vite.config.ts lists the same alternates.

Where copy lives

Content English Chinese
Interface copy src/i18n/resources/en.json src/i18n/resources/zh-CN.json
Docs public-docs/<page>.md public-docs/<page>.zh-CN.md
Blog posts posts/<slug>.md posts/<slug>.zh-CN.md
Comparison pages src/content/alternatives/<slug>.md src/content/alternatives/<slug>.zh-CN.md
Legal pages legal/<page>.md legal/<page>.zh-CN.md
Changelog CHANGELOG.md CHANGELOG.zh-CN.md, see release.md
Plugin listings the plugin's paseo-plugin.json and OVERVIEW.md translations and OVERVIEW.zh-CN.md, see public-docs/plugins/publishing.md

en.json types the keys, so typecheck fails when zh-CN.json misses one. A translation file is grouped with its English original by name (src/markdown-content.ts). A translation without an English original fails the build.

Every first-party page has a translation. The changelog and plugin listings are the exceptions: a release or listing without one renders whole in English under a notice. Pages never mix languages paragraph by paragraph. Navigation order, categories and slugs always come from the English file's frontmatter.

Editing a translated doc

Edit the English file and its .zh-CN.md in the same PR, and add the .zh-CN.md with any new page. Code blocks, commands, flags, config keys and links are copied verbatim, so code-only changes are a copy. Never delete a translation to get around an edit, and never leave one that describes behavior the English no longer has.

Translated headings pin the English anchor with a trailing {#id}, so /zh-CN/docs/cli#running-agents lands on the same section as the English link:

## 运行 Agent {#running-agents}

:::example[回复 Slack 提及 {#answer-a-slack-mention}]

When you rename an English heading, change the {#id} in the translation to the new slug. src/content-translations.test.ts fails when a docs, blog, comparison or legal page has no translation, and when a translation's headings differ from the English in count, level, order or anchor. It cannot tell whether the prose under a heading is current. The .md source endpoints serve files verbatim, so {#id} shows there as written.

Chinese style

  • Keep code, commands, file paths, IDs, brand and product names, and command output in English.
  • Keep these terms in English: Agent, worktree, daemon, Provider, PR, diff, Composer, Hub, workflow, heartbeat, slug.
  • Translate these: workspace 工作区, host 主机, relay 中继, plugin 插件, skill 技能, review 审查, schedule 定时任务, orchestration 编排, configuration 配置, prompt 提示词, subagent 子 Agent.
  • Quote app UI labels with the app's Chinese wording from packages/app/src/i18n/resources/zh-CN.ts, such as 设置 → 插件. Labels the app has not translated stay in English, as do labels in Hub, GitHub, Slack and Discord. Add the English label in parentheses only where readers search for it, such as an error message.
  • Put a space between Chinese and Latin text or numbers: 启动 Agent, 共 3 个.
  • Bold that ends in full-width punctuation does not render when Chinese text follows it directly: **注意:**这里 shows the asterisks. Move the punctuation outside the bold (**注意**:这里).