Files
openchamber/packages/docs/CONTRIBUTING.md
T
eb051f969e Add Japanese locale (ja) support (#1810)
* Add Japanese locale (ja) support

- New: ja.ts with 2624 UI translation keys
- New: ja.settings.ts with 1789 settings translation keys
- Registered ja in runtime.ts (Locale type, LOCALES, LOCALE_LABEL_KEYS, normalizeLocale)
- Added ja-JP BCP-47 mapping in intl.ts
- Added JA_MESSAGES in bootstrap.ts
- Added ja to lazy-load dictionary map in store.ts
- Updated messages.test.ts with ja dictionary
- Added common.language.japanese to all 8 existing locale files

* fix(i18n): complete Japanese locale updates

* test(i18n): enforce locale key parity

* docs: add Japanese documentation

---------

Co-authored-by: yuchi0531 <yuchi0531@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
2026-06-27 01:00:05 +03:00

324 lines
11 KiB
Markdown

# Docs Authoring Guide
This package is docs content source-of-truth for OpenChamber.
## Voice & style
Write for someone trying to get something done — not for an engineer reading a
spec. Assume the reader may be non-technical. A page should feel quick to read,
never like a separate chore just to get through one screen.
These rules describe how we already write the docs. Follow them so the style
stays the same no matter who is writing.
### Who you're writing for
- Assume curiosity, not expertise. The reader knows what they want to do, not
how OpenChamber works inside.
- One page = one job. If a page is answering two unrelated questions, split it.
### Keep it short
- Lead with the task, not background. The first line should say what the page is
for ("Use `openchamber tunnel` to expose a running OpenChamber instance.").
- Cut anything that doesn't change what the reader does next.
- A basic page should fit in a screen or two. Long, dense reference pages (like
Reverse Proxy) are the exception — and they say so in their first line ("Use
this page if you run OpenChamber behind...").
### Steps
- Number sequential actions; use bullets for options or unordered notes.
- Start each step with a verb: "Run", "Open", "Pick".
- End a procedure by telling the reader what success looks like, so they know
they did it right.
```mdx
3. Run `openchamber --ui-password be-creative-here`.
4. Open the printed URL (usually `http://localhost:3000`).
You should land on the OpenChamber session list. If you see it, the server is
running.
```
### Plain language
- Explain a term the first time it appears, in parentheses, in everyday words:
- good: start a tunnel (a public link to your local OpenChamber)
- bad: start a tunnel — the reader doesn't know what that is yet
- Prefer common words over internal ones. "App", "version", "page" beat
"surface", "instance", "route" when the meaning is the same. If an internal
term is unavoidable, define it once.
- Don't reach for `SSE`, `WebSocket`, `buffering`, or header names unless the
page is explicitly an advanced/operator page.
### Bullets and sentences
- Be consistent within a single list. Either all short fragments (lowercase, no
period) or all full sentences (capital letter, period) — don't mix the two in
one list.
- Use fragments for quick option lists; use full sentences for rules, warnings,
or anything the reader must not misread.
### Link out instead of re-explaining
- Where a step can realistically fail, link to
[Troubleshooting](/troubleshooting/) right there, not only at the bottom.
- Don't re-document something another page owns — link to it. (Quickstart points
at Install for the actual install command instead of copying it.)
### Show, don't only tell
- A screenshot beats a paragraph for anything visual (where a button is, what a
screen looks like). See [Images](#images) for how to add one.
- Always pair a screenshot with one line of text — the image supports the step,
it isn't the whole step.
### Commands and code
- Make code blocks copy-paste-ready: real, working values. Only use a
`<placeholder>` when the value is genuinely user-specific, and make that
obvious (e.g. `app.example.com`, `~/.secrets/cf-token`).
- One command per idea. Don't chain unrelated commands just to look compact.
## Add a new docs page
1. Create a new file in `packages/docs/content/docs/`.
- Example: `packages/docs/content/docs/remote-access.mdx`
2. Add frontmatter at top:
```mdx
---
title: Remote Access
description: Access OpenChamber from outside your local network.
---
```
3. Use route-safe naming:
- `foo.mdx` -> `/foo/`
- `folder/index.mdx` -> `/folder/`
- `folder/bar.mdx` -> `/folder/bar/`
4. Add translations for the page — see [Localization](#localization). New pages
must include translated files for every supported locale before they ship.
5. If the page is linked from the sidebar, add its localized labels too — see
[Translate the sidebar](#translate-the-sidebar).
6. Run validation:
```bash
bun run docs:validate
```
## Add a new sidebar section
Edit `packages/docs/sidebar.config.json`.
Example:
```json
{
"label": "Advanced",
"items": [{ "label": "Remote Access", "link": "/remote-access/" }]
}
```
Rules:
- use trailing slash in links (`/page/`)
- every sidebar link must map to an existing MDX file
- keep section labels short and task-oriented
## Images
Images live inside the docs content tree so they sync to the website with the
pages (the sync copies all of `content/docs/`, not just `.mdx`). Reference them
with a **relative path**; Astro optimizes them at build time.
```
content/docs/
install.mdx -> ![Desktop app](./images/desktop.png)
images/
desktop.png
```
Rules:
- co-locate images under `content/docs/` (e.g. `content/docs/images/`); a
relative `./images/...` reference is resolved and optimized at build
- always set meaningful `alt` text (and translate it in localized pages)
- do **not** put docs images in the website repo's `public/` — it is not the
source of truth and the sync will not pick them up
- keep originals reasonably sized; the build generates responsive variants
For translations, reuse the same shared image when it carries no text. If a
screenshot contains localized UI text, add a per-locale copy under that locale's
folder (e.g. `uk/images/...`) and point the translated page at it.
`docs:validate` only checks `.mdx`, so images never block validation.
### Light / dark variants
To show a different screenshot per theme, add a `-light` / `-dark` pair and tag
each with `oc-light-only` / `oc-dark-only`. The website ships CSS for these
classes (keyed on Starlight's `data-theme`), so the right one shows and follows
the in-page theme toggle.
Use the `<Image>` component so the images stay optimized while taking a class.
Add the imports right under the frontmatter:
```mdx
---
title: Install
description: ...
---
import { Image } from "astro:assets";
import desktopLight from "./images/desktop-light.png";
import desktopDark from "./images/desktop-dark.png";
<Image src={desktopLight} alt="Desktop app" class="oc-light-only" />
<Image src={desktopDark} alt="Desktop app" class="oc-dark-only" />
```
Notes:
- both files live under `content/docs/` like any other image and sync normally
- give both the same `alt` (and translate it in localized pages)
- if you only have one image, just use the normal `![alt](./path.png)` form
## Localization
The docs are translated into the same languages the OpenChamber app ships in.
English is the source of truth and lives at the root of `content/docs/`. Every
other language mirrors the English files under a locale folder.
### Supported locales
| Language | Content folder | Sidebar `translations` key |
| --- | --- | --- |
| English | _(root, no folder)_ | `en` |
| Ukrainian | `uk/` | `uk` |
| Chinese (Simplified) | `zh-cn/` | `zh-CN` |
| Spanish | `es/` | `es` |
| Brazilian Portuguese | `pt-br/` | `pt-BR` |
| Korean | `ko/` | `ko` |
| Polish | `pl/` | `pl` |
| French | `fr/` | `fr` |
| Japanese | `ja/` | `ja` |
> [!IMPORTANT]
> The **content folder** uses the lowercase locale key (`zh-cn`, `pt-br`); the
> **sidebar `translations`** key uses the BCP-47 language tag (`zh-CN`, `pt-BR`).
> They look similar but are not interchangeable — Starlight resolves them with
> different rules. Everything else (`uk`, `es`, `ko`, `pl`, `fr`, `ja`, `en`) is identical
> in both columns.
This locale set is mirrored in the website at
`openchamber-website/apps/docs/astro.config.mjs` (`locales`). If a language is
added or removed, update both places.
### Translate a page
Mirror the English file under each locale folder, keeping the **exact same
filename and path**. Starlight matches a translation to its English page by path.
```
content/docs/
install.mdx # English (source of truth)
uk/install.mdx # Ukrainian
zh-cn/install.mdx # Chinese (Simplified)
es/install.mdx # Spanish
pt-br/install.mdx # Brazilian Portuguese
ko/install.mdx # Korean
pl/install.mdx # Polish
fr/install.mdx # French
ja/install.mdx # Japanese
guides/tunnels.mdx # nested English page
uk/guides/tunnels.mdx # its Ukrainian translation
```
Each translated file needs its **own translated frontmatter** (`title` and
`description` are required by validation):
```mdx
---
title: Встановлення
description: Встановіть OpenChamber для десктопа, вебу або VS Code.
---
```
Every new page must include translated files for all supported locales before it
ships. Starlight can fall back to English when a translation is missing, but do
not rely on that fallback for new docs pages.
### Translate the sidebar
Do **not** create separate sidebar entries per language and do **not** add a
locale prefix to `link` — Starlight prefixes the active locale automatically.
Instead, add a `translations` map (keyed by the BCP-47 tag from the table above)
to each section and item in `sidebar.config.json`:
```json
{
"label": "Start here",
"translations": {
"uk": "Почніть тут",
"zh-CN": "从这里开始",
"es": "Empieza aquí",
"pt-BR": "Comece aqui",
"ko": "여기서 시작",
"pl": "Zacznij tutaj",
"fr": "Commencer ici",
"ja": "ここから開始"
},
"items": [
{
"label": "Install",
"link": "/install/",
"translations": {
"uk": "Встановлення",
"zh-CN": "安装",
"es": "Instalación",
"pt-BR": "Instalação",
"ko": "설치",
"pl": "Instalacja",
"fr": "Installation",
"ja": "インストール"
}
}
]
}
```
A label with no translation for the active locale falls back to the English
`label`.
### What not to translate
- brand and product nouns: OpenChamber, OpenCode, VS Code, PWA, GitHub, Discord,
macOS, SSH
- code blocks, shell commands, file paths, flags, and config keys
- the page filename and the sidebar `link` (these stay identical across locales)
### Validate
`bun run docs:validate` walks every `.mdx` under `content/docs/` — **including
translations** — and fails if any page is missing `title` or `description`
frontmatter, or if a sidebar `link` does not resolve to an English page. Run it
after adding or translating pages.
## Sync into openchamber-website
`openchamber-website` renders/deploys docs via Starlight in `apps/docs`.
After docs content updates here:
1. copy `packages/docs/content/docs/*` -> `openchamber-website/apps/docs/src/content/docs/*`
(this is recursive, so locale folders like `uk/` and `zh-cn/` carry over with
no extra steps)
2. map `packages/docs/sidebar.config.json` into `openchamber-website/apps/docs/astro.config.mjs` sidebar
(the `translations` maps carry over as-is)
3. run docs checks/build in website repo
Automation support exists in `.github/workflows/docs-source.yml` (release/manual packaging of docs source artifact).