Translate (Plane i18n)
Single source of truth for turning English UI strings into every target locale under packages/i18n/src/locales/. Follow this skill exactly — every mistake here ships to every user in that language.
The locale list grows over time. This skill is intentionally generic: rules apply to any locale present now or added later. When you add a locale not explicitly named below, see Adding a locale not documented here at the bottom.
Sources distilled from: Microsoft Localization Style Guides, Mozilla L10n, Unicode CLDR plural rules, W3C i18n, Google developer style guide, Apple HIG, GitHub Primer, MQM error typology, Lokalise/Crowdin/Phrase best-practice docs, and Microsoft's AI/LLM-for-translation guidance.
Source of truth: packages/i18n/src/locales/en/<namespace>.json. Every other locale mirrors English key-for-key. The sync-check.ts script catches missing / stale / collision keys; it does not catch value-quality mistakes. That is what this skill is for.
When to Use
- Adding a new key to any
packages/i18n/src/locales/en/*.json
- Renaming or rewording an English value (every target is now stale)
- Adding a new language (copy from
en/, then translate each file)
- Syncing after
pnpm --filter @plane/i18n run sync:check reports drift
- Reviewing any PR that touches
packages/i18n/src/locales/
Skip only for trivial English-only typo fixes that don't change meaning or length meaningfully.
The Two Iron Rules
- Trademarks, brand marks, plan tier names, third-party product names, acronyms, and code tokens are never translated. Plane's brand marks (Plane, Plane AI, Power K, PQL, Active Cycles, Sticky/Stickies, Intake), plan tiers (Pro, Business, Enterprise), third-party products (GitHub, Slack, Notion, etc.), and acronyms (API, OAuth, etc.) stay Latin in every locale.
- CLDR plural categories are mandatory. Every target locale must include every plural keyword the language requires. Missing a form renders the wrong word at runtime and passes
sync-check silently.
Common feature nouns — Cycle, Module, Epic, Page — are translated into the target language using the canonical glossary further down. They are not brand marks; they are everyday words that belong in the user's language.
The rest of this skill explains how to execute on those rules.
Do-Not-Translate (DNT) Glossary
For each term: the source, the required rendering per script group, and forbidden renderings that have appeared historically and must be reverted when seen.
Plane brand & features
| Source term |
Latin locales (fr, es, it, de, pt-BR, pl, cs, sk, ro, tr-TR, vi-VN, id) |
ja (katakana-default) |
ko (Hangul-default) |
zh-CN / zh-TW |
ru |
ua |
Forbidden (never produce) |
| Plane |
Plane |
Plane |
Plane |
Plane |
Plane |
Plane |
飛行機, 飞机, 비행기, Самолёт, Літак, Avion, Avião, Aereo, Flugzeug |
| Plane AI (formerly PI Chat) |
Plane AI |
Plane AI |
Plane AI |
Plane AI |
Plane AI |
Plane AI |
Чат ИИ, AI 聊天, AIチャット, AI 채팅, Chat IA, AI Çet, PI Chat (legacy) |
| Power K |
Power K |
Power K |
Power K |
Power K |
Power K |
Power K |
Command K, Command Palette, コマンドパレット, 命令面板, Палитра команд |
| PQL |
PQL |
PQL |
PQL |
PQL |
PQL |
PQL |
any expansion of the acronym into the target language |
| Intake (feature name) |
Intake |
Intake |
Intake |
Intake |
Intake |
Intake |
Inbox, 受信箱, 收件箱, Входящие, Triage, Boîte de réception |
| Active Cycles (workspace view) |
Active Cycles |
Active Cycles |
Active Cycles |
Active Cycles |
Active Cycles |
Active Cycles |
Translate as a unit; never split into generic "active" + localized "cycles" |
| Sticky / Stickies |
Sticky / Stickies |
Sticky / Stickies |
Sticky / Stickies |
Sticky / Stickies (Latin inside Chinese text) |
Sticky / Stickies |
Sticky / Stickies |
便签, 便利貼, メモ, 付箋, スティッキー, 메모, 스티키, заметка, Стикер, Note, Nota |
| Pro (plan tier) |
Pro |
Pro |
Pro |
Pro |
Pro |
Pro |
Профессиональный, プロフェッショナル, 专业版, 專業版, Profesional |
| Business (plan tier) |
Business |
Business |
Business |
Business |
Business |
Business |
Бизнес, ビジネス, 商业版, 商務版, Negocios, Negócios |
| Enterprise (plan tier) |
Enterprise |
Enterprise |
Enterprise |
Enterprise |
Enterprise |
Enterprise |
Корпоративный, エンタープライズ, 企业版, 企業版, Empresarial |
Plane feature noun translation glossary (translate, do not preserve)
These are common nouns. Translate them into the target language using the canonical form below. This follows Microsoft, Apple, and Mozilla style guides for product-UI translation: feature common nouns belong in the user's language; only trademarks, brand marks, and acronyms stay Latin. Leaving these in Latin in non-Latin locales reads as half-translated and is a measurable quality defect.
Use the table verbatim — never coin new variants; never leave the Latin form in the locale value.
| Source |
zh-CN |
zh-TW |
ja |
ko |
ru |
ua |
de |
fr |
es |
it |
pt-BR |
pl |
cs |
sk |
ro |
tr-TR |
vi-VN |
id |
| Cycle |
周期 |
週期 |
サイクル |
사이클 |
Цикл |
Цикл |
Zyklus |
Cycle |
Ciclo |
Ciclo |
Ciclo |
Cykl |
Cyklus |
Cyklus |
Ciclu |
Döngü |
Chu kỳ |
Siklus |
| Cycles |
周期 |
週期 |
サイクル |
사이클 |
Циклы |
Цикли |
Zyklen |
Cycles |
Ciclos |
Cicli |
Ciclos |
Cykle |
Cykly |
Cykly |
Cicluri |
Döngüler |
Chu kỳ |
Siklus |
| Module |
模块 |
模組 |
モジュール |
모듈 |
Модуль |
Модуль |
Modul |
Module |
Módulo |
Modulo |
Módulo |
Moduł |
Modul |
Modul |
Modul |
Modül |
Mô-đun |
Modul |
| Modules |
模块 |
模組 |
モジュール |
모듈 |
Модули |
Модулі |
Module |
Modules |
Módulos |
Moduli |
Módulos |
Moduły |
Moduly |
Moduly |
Module |
Modüller |
Mô-đun |
Modul |
| Epic |
史诗 |
史詩 |
エピック |
에픽 |
Эпик |
Епік |
Epic |
Epic |
Epic |
Epic |
Epic |
Epik |
Epik |
Epik |
Epic |
Epik |
Epic |
Epik |
| Epics |
史诗 |
史詩 |
エピック |
에픽 |
Эпики |
Епіки |
Epics |
Epics |
Epics |
Epics |
Epics |
Epiki |
Epiky |
Epiky |
Epice |
Epikler |
Epic |
Epik |
| Page |
页面 |
頁面 |
ページ |
페이지 |
Страница |
Сторінка |
Seite |
Page |
Página |
Pagina |
Página |
Strona |
Stránka |
Stránka |
Pagină |
Sayfa |
Trang |
Halaman |
| Pages |
页面 |
頁面 |
ページ |
페이지 |
Страницы |
Сторінки |
Seiten |
Pages |
Páginas |
Pagine |
Páginas |
Strony |
Stránky |
Stránky |
Pagini |
Sayfalar |
Trang |
Halaman |
Notes:
- Single-form locales (zh-CN, zh-TW, ja, ko, vi-VN, id) use the same form for singular and plural — the column repeats by design.
- Slavic locales (ru, ua, pl, cs, sk) show nominative singular and nominative plural. Inside ICU
{count, plural, ...} blocks, use the case-correct form per CLDR keyword (see the Slavic case-form table further down).
- Some Latin locales (fr, vi-VN, id) have forms identical to English (
Cycle, Module, Page) — that's the natural cognate, not a Latin-preservation rule.
- Epic / Epics: stays Latin in most Latin locales because there's no clean cognate (Spanish
épico is for poetry/film; same for it/pt-BR/de/fr). Slavic locales use phonetic transliteration that's standard in their software industry (Эпик, Епік, Epik). CJK locales use the literal/transliterated form (史诗, エピック, 에픽).
- Generic uses translate normally and don't follow this glossary:
next page (paginator), the page (browser refresh), status page, web page, life cycle, release cycle, rate-limit cycle, cycle of releases — these are not the Plane Cycle/Page feature; translate them as ordinary words in the surrounding prose.
- When editing an existing file, migrate occurrences you are already touching. Do not bulk-rewrite unrelated strings in the same PR — land a separate sweep PR with the
chore(i18n): prefix.
Slavic case forms inside ICU plural blocks
When a Slavic plural block counts a Plane feature noun, use these forms:
| Locale |
Term |
one (nom.sg.) |
few |
many |
other |
| ru |
Цикл |
Цикл |
Цикла |
Циклов |
Цикла |
| ru |
Модуль |
Модуль |
Модуля |
Модулей |
Модуля |
| ru |
Эпик |
Эпик |
Эпика |
Эпиков |
Эпика |
| ru |
Страница |
Страница |
Страницы |
Страниц |
Страницы |
| ua |
Цикл |
Цикл |
Цикла |
Циклів |
Цикла |
| ua |
Модуль |
Модуль |
Модуля |
Модулів |
Модуля |
| ua |
Епік |
Епік |
Епіка |
Епіків |
Епіка |
| ua |
Сторінка |
Сторінка |
Сторінки |
Сторінок |
Сторінки |
| pl |
Cykl |
Cykl |
Cykle |
Cykli |
Cyklu |
| pl |
Moduł |
Moduł |
Moduły |
Modułów |
Modułu |
| pl |
Epik |
Epik |
Epiki |
Epików |
Epika |
| pl |
Strona |
Strona |
Strony |
Stron |
Strony |
| cs |
Cyklus |
Cyklus |
Cykly |
Cyklu |
Cyklů |
| cs |
Modul |
Modul |
Moduly |
Modulu |
Modulů |
| cs |
Epik |
Epik |
Epiky |
Epiku |
Epiků |
| cs |
Stránka |
Stránka |
Stránky |
Stránky |
Stránek |
| sk |
Cyklus |
Cyklus |
Cykly |
Cyklu |
Cyklov |
| sk |
Modul |
Modul |
Moduly |
Modulu |
Modulov |
| sk |
Epik |
Epik |
Epiky |
Epiku |
Epikov |
| sk |
Stránka |
Stránka |
Stránky |
Stránky |
Stránok |
Per CLDR for ru/ua: one fires for 1, 21, 31… (nom.sg.); few for 2–4, 22–24… (gen.sg.); many for 0, 5–20, 25–30… (gen.pl.); other for non-integer counts (gen.sg.). For pl: one (1), few (2–4 not 12–14, nom.pl.), many (0, 5–20, gen.pl.), other (decimals, gen.sg.). cs/sk: one (1), few (2–4, nom.pl.), many (decimals, gen.sg.), other (0, 5+, gen.pl.).
Third-party products & standards (always Latin, every locale)
GitHub, GitLab, Bitbucket, Slack, Discord, Zoom, Microsoft Teams, Jira, Linear, Asana, Notion, Confluence, Trello, Figma, Google, Google Drive, Google Calendar, Google Docs, Google Sheets, Gmail, YouTube, Dropbox, Zapier, Tiptap, ProseMirror, Yjs, Hocuspocus, Socket.IO, React, TypeScript, JavaScript, Python, Django, PostgreSQL, Redis, RabbitMQ.
Also preserve: OAuth, OIDC, SAML, SSO, LDAP, API, REST, GraphQL, URL, URI, ID, UUID, JSON, YAML, CSV, TSV, XML, HTML, PDF, PNG, JPG, SVG, CSS, HTTP, HTTPS, TLS, SSL, IP, CIDR, DNS, ARIA, WCAG.
Inside-string tokens (mechanical — preserve exactly)
- ICU variables:
{count}, {name}, {workspace}, {userName} — never translate, never rename, never move inside {}.
- ICU pluralization / select keywords:
plural, select, one, few, many, other, zero, two, =0, =1, # — never translate.
- HTML & JSX tags:
<b>…</b>, <a href="…">…</a>, <br/>, <code>…</code> — preserve attributes and nesting; translate only the visible text between tags.
- i18next
Trans numbered fragments: <0>…</0>, <1>…</1> — preserve the numbers exactly; only translate the wrapped text. Never renumber.
- Markdown:
**bold**, *italic*, `code`, [text](url) — keep the syntax; translate only human-readable prose.
- Escape sequences:
\n (newline), \t, \", \\ — preserve at the same positions.
- Keyboard keys & modifiers:
Ctrl, Cmd, Shift, Alt, Option, Enter, Return, Esc, Tab, Space, Backspace, arrow glyphs (↑↓←→), and OS glyphs (⌘⌥⌃⇧) — preserve exactly as shown on the physical key.
- File extensions & formats:
.json, .csv, MM/DD/YYYY format strings — preserve.
Per-Script Rules
Apply by target-language script, not by locale list. Adding a new Latin-script locale? It follows the Latin-script rules below. Adding a new Cyrillic locale? It follows the Cyrillic section. Scripts not yet shown here (Arabic, Hebrew, Thai, Greek, Hindi/Devanagari, etc.) — see Adding a locale not documented here.
Latin-script locales
Currently includes fr, es, it, de, pt-BR, pl, cs, sk, ro, tr-TR, vi-VN, id — and any future locale that uses the Latin alphabet (hu, nl, sv, da, nb, fi, hr, bg-using-Latin variants, etc.).
Translate Plane feature nouns (Cycle, Cycles, Module, Modules, Epic, Epics, Page, Pages) using the per-locale form from the glossary above. Keep Latin for Plane brand marks (Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake), plan tier names (Pro, Business, Enterprise), and third-party brands (GitHub, Slack, etc.).
✅ "Créer un Cycle" (fr — natural cognate from glossary, identical to English)
✅ "Crear un nuevo Ciclo" (es — natural Spanish cognate from glossary)
✅ "Archiviare questo Modulo" (it — natural Italian cognate from glossary)
✅ "Nueva Epic" (es — Epic has no clean cognate; stays Latin per glossary)
✅ "Archivieren Sie diesen Zyklus" (de — natural German form from glossary)
✅ "Buat Siklus baru" (id — natural Indonesian form from glossary)
✅ "Buat Sticky baru" (id — Sticky is a Plane brand mark, stays Latin)
✅ "Wechseln Sie zum Pro-Plan" (de — Pro is a plan tier name, stays Latin)
❌ "Créer un Cycle" WRONG when the locale should be `Zyklus` (de). Always use the glossary form.
❌ "Archivieren Sie diesen Cycle" (de — feature noun was left in Latin; use Zyklus per glossary)
❌ "Créer un Cercle" (fr — invented translation; use the glossary form)
❌ "Nueva Saga" (es — translated "Epic" with the wrong cognate)
❌ "Buat Catatan Tempel" (id — translated "Sticky" which is a brand mark; keep Latin)
Generic uses translate normally and do not follow the glossary: a paginator's next page is nächste Seite / página siguiente (generic noun, not the Plane Pages feature). The glossary applies only when EN refers to the Plane product feature.
Japanese (ja) — natural Japanese rendering
Plane feature nouns (Cycle, Module, Epic, Page) use the natural Japanese form per the glossary above (サイクル, モジュール, エピック, ページ — katakana for foreign-origin nouns; native Japanese where one applies, like 付箋 for an Apple/Microsoft-style "sticky note"). Brand marks stay in Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise.
For new katakana coinages and existing translations, the long-vowel mark ー is added for words ending in -er, -or, -ar, -y in English. This is the Microsoft Japanese style-guide convention and the current industry default:
- user → ユーザー (not ユーザ)
- server → サーバー (not サーバ)
- editor → エディター (not エディタ)
- property → プロパティー (kept as プロパティ where the existing codebase already does — match the surrounding file's convention)
Tone: polite form です・ます. Never plain form だ・である. Avoid over-formal 尊敬語・謙譲語 for SaaS product copy — it reads stilted.
Quotation marks: 「」 for primary quotes, 『』 for nested or for titles of works. Full-width punctuation: 。、()・!?.
Korean (ko) — Hangul rendering
Plane feature nouns (Cycle, Module, Epic, Page) use the natural Korean form per the glossary above (사이클, 모듈, 에픽, 페이지 — Hangul transliteration where the term is product-coined; native Korean word where one applies). Brand marks stay in Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise.
For new terms not on the glossary: prefer the native Korean word where one exists (설정 for Settings); use Hangul phonetic transliteration for product-coined nouns with no native equivalent. Do not coerce a phonetic loanword when a natural Korean word exists — 버킷 for "Bucket" reads as a foreign trademark, 장바구니 reads as a Korean noun.
Korean particle agreement: when introducing a consonant-ending noun (사이클, 에픽, 모듈), follow with the consonant-form particle (을/은/이/과), not the vowel-form (를/는/가/와). 사이클을 추가 not 사이클를 추가.
Register:
- System and error messages → 합니다체 (high-formal: 합니다, 됩니다, 입니다). Existing files in this register today:
ko/auth.json, ko/error/*.json.
- Empty states, onboarding microcopy, tooltips → 해요체 acceptable (softer: 해요, 돼요, 이에요) if the existing file uses it. Existing files in this register today:
ko/empty-state.json, ko/tour.json. Always match the surrounding file rather than introducing a new register mid-namespace.
- Never casual 반말.
Punctuation: Western punctuation (. , ? !); straight quotes "…" and '…'.
Simplified Chinese (zh-CN) and Traditional Chinese (zh-TW) — translate feature nouns
Plane feature nouns (Cycle, Module, Epic, Page) translate to natural Chinese per the glossary above (zh-CN: 周期, 模块, 史诗, 页面 — zh-TW: 週期, 模組, 史詩, 頁面). This is what Microsoft's zh-CN style guide and every mainstream zh-localized SaaS product (Notion, Slack, Atlassian) does for common feature nouns.
Brand marks stay Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise — these are trademark-style terms.
Insert a half-width space on each side of embedded Latin tokens — this is Microsoft's zh-CN guideline and required for legibility. Exception: no space between a Latin token and adjacent full-width punctuation (。,;:?!); the punctuation already supplies visual breathing room.
✅ "使用 GitHub 登录" (Latin brand → half-width spaces around)
✅ "创建周期" (zh-CN feature noun translated; no Latin = no spaces)
✅ "归档此史诗" (Plane Epic → 史诗 per glossary)
✅ "添加 Sticky" (Sticky is a brand mark → Latin + half-width space)
✅ "升级到 Pro" (Pro is a plan tier → Latin)
✅ "登录 GitHub。" (no space between Latin token and full-width period)
❌ "使用GitHub登录" (Latin brand without surrounding half-width space)
❌ "创建 Cycle" (feature noun left in Latin — should be 周期)
❌ "创建Cycle" (feature noun in Latin AND missing space)
❌ "登录 GitHub 。" (stray space before full-width period)
❌ "创建赛克" (invented transliteration of Cycle — use the glossary's 周期)
Punctuation is full-width: 。,?!;:. Quotes:
- zh-CN:
"…" (primary) and '…' (nested)
- zh-TW:
「…」 (primary) and 『…』 (nested)
- Work titles (book/movie/app/article names):
《…》
Variant discipline: zh-CN ≠ zh-TW. They differ in script (简体 vs 繁體) and vocabulary (视频 vs 影片; 软件 vs 軟體; 网络 vs 網路). Never mass-copy between the two directories.
Register: 您 (formal polite) in Plane UI — the product is B2B/SaaS. Reserve 你 for consumer/youth contexts (not applicable here).
Cyrillic locales
Currently includes ru, ua — and any future Cyrillic locale (bg-BG, sr-Cyrl, mk, be, kk-Cyrl, etc.).
Plane feature nouns (Cycle, Module, Epic, Page) use the natural Cyrillic form per the glossary above (Цикл/Циклы, Модуль/Модули, Эпик/Эпики, Страница/Страницы in ru — Цикл/Цикли, Модуль/Модулі, Епік/Епіки, Сторінка/Сторінки in ua). Brand marks stay in Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise.
For new terms not on the glossary: prefer the native Cyrillic word where one exists; use phonetic transliteration only when no native word applies (Бакет is wrong for "Bucket" — use Корзина/Кошик).
Slavic case forms inside {count, plural, ...} blocks are case-correct per CLDR keyword (one=nom.sg., few=gen.sg., many=gen.pl., other=gen.sg.). See the case-form table in the glossary section.
Register:
- ru: formal Вы (capitalized) when addressing a single user directly in respectful/formal contexts (onboarding, settings, confirmation dialogs); lowercase вы for plural/general references ("все вы"). Default to capitalized Вы in tooltips/dialogs and lowercase вы in descriptive copy.
- ua: modern Ukrainian software convention is lowercase ви by default; capitalized Ви is reserved for very formal direct address. This is the opposite convention from Russian — do not copy-paste Russian capitalization rules into Ukrainian files.
Punctuation: primary quotes «…», nested „…".
Plural forms — critical: both ru and ua require one / few / many / other. See CLDR section below.
CLDR Plural Rules
Every {count, plural, …} string must contain every keyword the target language's CLDR rule requires. other is always required, even in single-form languages.
Canonical source: Unicode CLDR Language Plural Rules chart — the definitive, versioned list of required categories for every language. Always verify against the current CLDR chart when adding a locale, since rules occasionally shift across CLDR releases. Libraries like Intl.PluralRules can resolve the rule at runtime.
Below are the required keywords for locales currently in the repo. When adding a new locale, look up its categories in CLDR and add the row here.
| Locale |
Required keywords |
Example mapping |
| en, es, de, tr-TR, vi-VN, id, ja, ko, zh-CN, zh-TW |
one, other (single-form locales may use other alone, but always emit other) |
1 → one; 2+ → other |
| fr |
one, many, other |
0, 1 → one; 1 000 000 → many; else other |
| it |
one, many, other |
1 → one; 1 000 000 → many; else other |
| pt-BR |
one, many, other |
0, 1 → one; 1 000 000 → many; else other |
| ro |
one, few, other |
1 → one; 0, 2–19 → few; 20+ → other |
| pl |
one, few, many, other |
1 → one; 2–4 (not 12–14) → few; 0, 5–20, many-digit → many; decimals → other |
| cs |
one, few, many, other |
1 → one; 2–4 → few; decimals → many; 0, 5+ → other |
| sk |
one, few, many, other |
same pattern as cs |
| ru |
one, few, many, other |
1, 21, 31… → one; 2–4, 22–24… → few; 0, 5–20, 25–30… → many; decimals → other |
| ua |
one, few, many, other |
same pattern as ru |
| ar (when added) |
zero, one, two, few, many, other |
Six categories — the maximum any language uses |
Note on the consolidated row. CLDR itself only requires other for tr-TR, vi-VN, id, ja, ko, zh-CN, zh-TW (single-form locales). Emitting both one and other with identical content is a project convention — it keeps tooling and linters consistent across the codebase. It is not a CLDR requirement, and Intl.PluralRules will return only "other" for these locales at runtime.
For any locale not listed: look up the CLDR categories before writing a single plural string. Arabic has six; Welsh has six; most Slavic languages have four; most Romance languages have two or three; CJK / Turkic / Thai have one (still emit other).
Rules in practice:
- Never drop a required form, even when the word is identical across forms — emit each one explicitly.
- Never add a form the target doesn't have. German does not use
few. Any few clause in de/*.json is a bug and must be removed.
- In single-form locales (ja/ko/zh/tr/vi/id), emit
one + other with identical content so tooling and linters stay consistent.
- The
other case is always the fallback — it must render a grammatically complete sentence on its own.
Examples:
// ✅ Correct — Russian (four forms; `other` fires for non-integer counts and takes genitive singular)
"members": "{count, plural, one {# участник} few {# участника} many {# участников} other {# участника}}"
// ✅ Correct — Polish (four forms)
"items": "{count, plural, one {# element} few {# elementy} many {# elementów} other {# elementu}}"
// ✅ Correct — Romanian (three forms)
"days": "{count, plural, one {# zi} few {# zile} other {# de zile}}"
// ✅ Correct — French (three forms; `many` covers 1 000 000, 2 000 000, …)
"members": "{count, plural, one {# membre} many {# membres} other {# membres}}"
// ✅ Correct — Japanese (single form, both keywords emitted)
"label": "{count, plural, one {サイクル} other {サイクル}}"
// ❌ Wrong — German with spurious `few`
"label": "{count, plural, one {Zyklus} few {Zyklen} other {Zyklen}}"
// ❌ Wrong — Russian missing `few` and `many`
"label": "{count, plural, one {Цикл} other {Циклы}}"
Placeholders, HTML, Markdown (preservation checklist)
For every translated string, verify before saving:
Variables may be repositioned for grammatical fit:
en: "Welcome, {name}! You have {count} new work items."
fr: "Bienvenue, {name} ! Vous avez {count} nouveaux work items."
ja: "{name}さん、ようこそ。{count}件の新しい作業項目があります。"
Per-Locale Punctuation & Spacing
Apply in every translated string. These are MQM "Locale Conventions" violations when missed — a measurable quality defect.
Table below covers locales currently in the repo; add a row when you add a locale.
| Locale |
Key rules |
| fr |
Narrow NBSP (U+202F, fallback U+00A0) before :, ;, ?, !, %, » and after «. Primary quotes « » (with NBSPs), nested "…". |
| de |
Primary quotes „…" (low-high); no NBSP before punctuation. Avoid imperatives in system strings; prefer infinitive constructions ("Werkelement erstellen", not "Erstelle ein Werkelement"). |
| es |
Inverted ¿…? and ¡…! at the start of questions/exclamations. Primary quotes «…» or "…". |
| it |
Primary quotes «…» or "…". |
| pt-BR |
Straight quotes "…". |
| pl |
Primary quotes „…". |
| cs / sk |
Primary quotes „…". |
| ro |
Primary quotes „…". |
| tr-TR / vi-VN / id |
Straight quotes "…". Vietnamese diacritics are mandatory — never strip (no bạn → ban). |
| ru / ua |
Primary «…», nested „…". |
| ja |
Full-width 。、()!?・. Primary quotes 「」, nested 『』. Ellipsis … (U+2026), typically doubled as ……. |
| ko |
Western . , ? !; straight quotes "…". |
| zh-CN |
Full-width 。,?!;:. Primary "…", nested '…'. Work titles 《…》. Half-width space around embedded Latin tokens. |
| zh-TW |
Full-width 。,?!;:. Primary 「…」, nested 『…』. Work titles 《…》. Half-width space around embedded Latin tokens. |
Tone & Register (SaaS defaults)
Formality defaults for locales currently in the repo. Add a row for each new locale, consulting the Microsoft Style Guide for that locale as the default authority on product-UI register.
| Locale |
Default "you" |
Notes |
| fr |
vous |
Never "tu" in product UI |
| es |
usted + ustedes |
Neutral Spanish — no "vosotros", no "tú" |
| it |
Lei (formal third-person) |
B2B/enterprise convention |
| de |
Sie |
Use infinitive constructions for system messages |
| pt-BR |
você |
Semi-formal default; never "tu" |
| pl |
Pan/Pani + 3rd-person, or impersonal |
Never "ty" |
| cs / sk |
Vy (formal, 3rd-person plural) |
Never "ty" |
| ro |
dumneavoastră (formal) |
Or impersonal |
| tr-TR |
siz + -iniz endings |
Never "sen" |
| vi-VN |
bạn (safe neutral) |
Never "mày/tao"; consistency > variety |
| id |
Anda (always capitalized) |
Never "kamu" in product UI |
| ja |
です・ます体 |
Never plain form; avoid 尊敬語・謙譲語 |
| ko |
합니다체 for system/errors; 해요체 acceptable for onboarding |
Match surrounding file |
| zh-CN |
您 |
B2B convention; never 你 |
| zh-TW |
您 |
B2B convention; never 你 |
| ru |
Вы (cap.) for singular direct address, вы (lower) for plural/general |
Context-dependent |
| ua |
ви (lowercase, modern convention) |
Capitalized Ви only for very formal |
General writing rules (apply across all locales):
- Sentence case in buttons, headings, tooltips — not Title Case. Only capitalize proper nouns.
- No exclamation marks except in genuine celebrations (first success, milestone).
- No emoji in UI copy.
- No slang, idioms, humor, cultural references — they don't translate.
- Consistent terminology — if "work item" is used once, never switch to "issue" / "ticket" mid-flow.
- Active voice, present tense.
- Write out abbreviations on first use if not on the DNT list.
Text Expansion Budget
Design strings knowing translations will grow. Typical expansion vs. English for locales currently in the repo; lookup values from Andiamo / Eriksen / W3C tables when adding a locale.
| Locale |
Expansion |
Implication |
| de |
+10–35%, single words up to +180% |
Reserve generous space on buttons, tabs, labels |
| fr |
+15–25% |
|
| es |
+15–30% |
|
| it |
+10–25% |
|
| pt-BR |
+15–30% |
|
| pl |
+20–30% |
|
| cs, sk |
+10–20% |
|
| ro |
+15–25% |
|
| ru, ua |
+15% typical, spikes to +30% |
|
| tr-TR |
+10–30% (agglutination) |
|
| vi-VN |
+30–40% |
Diacritic-heavy, many small words |
| id |
+10–20% |
|
| ja |
−10 to −55% character count (similar pixel width) |
|
| ko |
−10 to −15% |
|
| zh-CN, zh-TW |
−40% character count (≈2× char width) |
|
Rule of thumb: any UI surface must absorb +35% without truncation. If a string is length-capped, add a comment or context in the source.
Numbers, Dates, Currency, Units
Never hard-code formats. Use ICU skeletons so the runtime localizes automatically:
"updated_on": "Updated {date, date, medium}",
"percent_done": "{ratio, number, percent} complete",
"item_count": "{count, number} items"
Never write "{date}MM/DD/YYYY" in the source — that guarantees a locale bug.
Decimal/thousands separators (runtime-handled):
- en:
1,234.56 — de/it/es/pt-BR/ru/ua/pl/cs/sk/tr-TR: 1.234,56 or 1 234,56 — fr: 1 234,56 (thin space) — ja/ko/zh: 1,234.56.
Date formats (runtime-handled):
- en-US:
MM/DD/YYYY — most of Europe: `D
…(truncated)
1---2name: translate3description: Translate or update keys in packages/i18n/src/locales. Use whenever adding, changing, or reviewing strings across any target locale — enforces do-not-translate terminology, CLDR plural forms, placeholder/tag preservation, per-locale punctuation/register, and the AI-translation review workflow. Required reading before touching any *.json under src/locales.4---56<!--7 `user_invocable: true` is advisory and follows the same convention as the existing8 `pr-description.md` and `release-notes.md` skills in this repo. No harness behavior9 in this codebase keys off the field today; it documents intent for the Claude Code10 skill registry. The skill is invoked via the slash command (`/translate`) registered11 in `.claude/commands/translate.md`, or by name when an agent infers relevance.12-->1314# Translate (Plane i18n)1516Single source of truth for turning English UI strings into every target locale under `packages/i18n/src/locales/`. Follow this skill exactly — every mistake here ships to every user in that language.1718The locale list grows over time. This skill is intentionally generic: rules apply to any locale present now or added later. When you add a locale not explicitly named below, see **Adding a locale not documented here** at the bottom.1920Sources distilled from: Microsoft Localization Style Guides, Mozilla L10n, Unicode CLDR plural rules, W3C i18n, Google developer style guide, Apple HIG, GitHub Primer, MQM error typology, Lokalise/Crowdin/Phrase best-practice docs, and Microsoft's AI/LLM-for-translation guidance.2122**Source of truth**: `packages/i18n/src/locales/en/<namespace>.json`. Every other locale mirrors English key-for-key. The `sync-check.ts` script catches missing / stale / collision keys; it does **not** catch value-quality mistakes. That is what this skill is for.2324## When to Use2526- Adding a new key to any `packages/i18n/src/locales/en/*.json`27- Renaming or rewording an English value (every target is now stale)28- Adding a new language (copy from `en/`, then translate each file)29- Syncing after `pnpm --filter @plane/i18n run sync:check` reports drift30- Reviewing any PR that touches `packages/i18n/src/locales/`3132Skip only for trivial English-only typo fixes that don't change meaning or length meaningfully.3334## The Two Iron Rules35361. **Trademarks, brand marks, plan tier names, third-party product names, acronyms, and code tokens are never translated.** Plane's brand marks (Plane, Plane AI, Power K, PQL, Active Cycles, Sticky/Stickies, Intake), plan tiers (Pro, Business, Enterprise), third-party products (GitHub, Slack, Notion, etc.), and acronyms (API, OAuth, etc.) stay Latin in every locale.372. **CLDR plural categories are mandatory.** Every target locale must include **every** plural keyword the language requires. Missing a form renders the wrong word at runtime and passes `sync-check` silently.3839Common feature nouns — Cycle, Module, Epic, Page — **are translated** into the target language using the canonical glossary further down. They are not brand marks; they are everyday words that belong in the user's language.4041The rest of this skill explains how to execute on those rules.4243## Do-Not-Translate (DNT) Glossary4445For each term: the source, the required rendering per script group, and **forbidden renderings** that have appeared historically and must be reverted when seen.4647### Plane brand & features4849| Source term | Latin locales (fr, es, it, de, pt-BR, pl, cs, sk, ro, tr-TR, vi-VN, id) | ja (katakana-default) | ko (Hangul-default) | zh-CN / zh-TW | ru | ua | **Forbidden** (never produce) |50| ---------------------------------- | ----------------------------------------------------------------------- | --------------------- | ------------------- | --------------------------------------------- | ----------------- | ----------------- | --------------------------------------------------------------------------------- |51| **Plane** | Plane | Plane | Plane | Plane | Plane | Plane | 飛行機, 飞机, 비행기, Самолёт, Літак, Avion, Avião, Aereo, Flugzeug |52| **Plane AI** (formerly PI Chat) | Plane AI | Plane AI | Plane AI | Plane AI | Plane AI | Plane AI | Чат ИИ, AI 聊天, AIチャット, AI 채팅, Chat IA, AI Çet, PI Chat (legacy) |53| **Power K** | Power K | Power K | Power K | Power K | Power K | Power K | Command K, Command Palette, コマンドパレット, 命令面板, Палитра команд |54| **PQL** | PQL | PQL | PQL | PQL | PQL | PQL | any expansion of the acronym into the target language |55| **Intake** (feature name) | Intake | Intake | Intake | Intake | Intake | Intake | Inbox, 受信箱, 收件箱, Входящие, Triage, Boîte de réception |56| **Active Cycles** (workspace view) | Active Cycles | Active Cycles | Active Cycles | Active Cycles | Active Cycles | Active Cycles | Translate as a unit; never split into generic "active" + localized "cycles" |57| **Sticky** / **Stickies** | Sticky / Stickies | Sticky / Stickies | Sticky / Stickies | Sticky / Stickies (Latin inside Chinese text) | Sticky / Stickies | Sticky / Stickies | 便签, 便利貼, メモ, 付箋, スティッキー, 메모, 스티키, заметка, Стикер, Note, Nota |58| **Pro** (plan tier) | Pro | Pro | Pro | Pro | Pro | Pro | Профессиональный, プロフェッショナル, 专业版, 專業版, Profesional |59| **Business** (plan tier) | Business | Business | Business | Business | Business | Business | Бизнес, ビジネス, 商业版, 商務版, Negocios, Negócios |60| **Enterprise** (plan tier) | Enterprise | Enterprise | Enterprise | Enterprise | Enterprise | Enterprise | Корпоративный, エンタープライズ, 企业版, 企業版, Empresarial |6162### Plane feature noun translation glossary (translate, do not preserve)6364These are common nouns. **Translate them into the target language** using the canonical form below. This follows Microsoft, Apple, and Mozilla style guides for product-UI translation: feature common nouns belong in the user's language; only trademarks, brand marks, and acronyms stay Latin. Leaving these in Latin in non-Latin locales reads as half-translated and is a measurable quality defect.6566Use the table verbatim — never coin new variants; never leave the Latin form in the locale value.6768| Source | zh-CN | zh-TW | ja | ko | ru | ua | de | fr | es | it | pt-BR | pl | cs | sk | ro | tr-TR | vi-VN | id |69| ----------- | ----- | ----- | ---------- | ------ | -------- | -------- | ------ | ------- | ------- | ------ | ------- | ------ | ------- | ------- | ------- | -------- | ------ | ------- |70| **Cycle** | 周期 | 週期 | サイクル | 사이클 | Цикл | Цикл | Zyklus | Cycle | Ciclo | Ciclo | Ciclo | Cykl | Cyklus | Cyklus | Ciclu | Döngü | Chu kỳ | Siklus |71| **Cycles** | 周期 | 週期 | サイクル | 사이클 | Циклы | Цикли | Zyklen | Cycles | Ciclos | Cicli | Ciclos | Cykle | Cykly | Cykly | Cicluri | Döngüler | Chu kỳ | Siklus |72| **Module** | 模块 | 模組 | モジュール | 모듈 | Модуль | Модуль | Modul | Module | Módulo | Modulo | Módulo | Moduł | Modul | Modul | Modul | Modül | Mô-đun | Modul |73| **Modules** | 模块 | 模組 | モジュール | 모듈 | Модули | Модулі | Module | Modules | Módulos | Moduli | Módulos | Moduły | Moduly | Moduly | Module | Modüller | Mô-đun | Modul |74| **Epic** | 史诗 | 史詩 | エピック | 에픽 | Эпик | Епік | Epic | Epic | Epic | Epic | Epic | Epik | Epik | Epik | Epic | Epik | Epic | Epik |75| **Epics** | 史诗 | 史詩 | エピック | 에픽 | Эпики | Епіки | Epics | Epics | Epics | Epics | Epics | Epiki | Epiky | Epiky | Epice | Epikler | Epic | Epik |76| **Page** | 页面 | 頁面 | ページ | 페이지 | Страница | Сторінка | Seite | Page | Página | Pagina | Página | Strona | Stránka | Stránka | Pagină | Sayfa | Trang | Halaman |77| **Pages** | 页面 | 頁面 | ページ | 페이지 | Страницы | Сторінки | Seiten | Pages | Páginas | Pagine | Páginas | Strony | Stránky | Stránky | Pagini | Sayfalar | Trang | Halaman |7879Notes:8081- Single-form locales (zh-CN, zh-TW, ja, ko, vi-VN, id) use the same form for singular and plural — the column repeats by design.82- Slavic locales (ru, ua, pl, cs, sk) show **nominative singular** and **nominative plural**. Inside ICU `{count, plural, ...}` blocks, use the case-correct form per CLDR keyword (see the Slavic case-form table further down).83- Some Latin locales (fr, vi-VN, id) have forms identical to English (`Cycle`, `Module`, `Page`) — that's the natural cognate, not a Latin-preservation rule.84- **Epic / Epics**: stays Latin in most Latin locales because there's no clean cognate (Spanish `épico` is for poetry/film; same for it/pt-BR/de/fr). Slavic locales use phonetic transliteration that's standard in their software industry (Эпик, Епік, Epik). CJK locales use the literal/transliterated form (史诗, エピック, 에픽).85- **Generic uses translate normally and don't follow this glossary:** `next page` (paginator), `the page` (browser refresh), `status page`, `web page`, `life cycle`, `release cycle`, `rate-limit cycle`, `cycle of releases` — these are not the Plane Cycle/Page feature; translate them as ordinary words in the surrounding prose.86- When editing an existing file, migrate occurrences you are already touching. Do not bulk-rewrite unrelated strings in the same PR — land a separate sweep PR with the `chore(i18n):` prefix.8788#### Slavic case forms inside ICU plural blocks8990When a Slavic plural block counts a Plane feature noun, use these forms:9192| Locale | Term | one (nom.sg.) | few | many | other |93| ------ | -------- | ------------- | -------- | -------- | -------- |94| **ru** | Цикл | Цикл | Цикла | Циклов | Цикла |95| **ru** | Модуль | Модуль | Модуля | Модулей | Модуля |96| **ru** | Эпик | Эпик | Эпика | Эпиков | Эпика |97| **ru** | Страница | Страница | Страницы | Страниц | Страницы |98| **ua** | Цикл | Цикл | Цикла | Циклів | Цикла |99| **ua** | Модуль | Модуль | Модуля | Модулів | Модуля |100| **ua** | Епік | Епік | Епіка | Епіків | Епіка |101| **ua** | Сторінка | Сторінка | Сторінки | Сторінок | Сторінки |102| **pl** | Cykl | Cykl | Cykle | Cykli | Cyklu |103| **pl** | Moduł | Moduł | Moduły | Modułów | Modułu |104| **pl** | Epik | Epik | Epiki | Epików | Epika |105| **pl** | Strona | Strona | Strony | Stron | Strony |106| **cs** | Cyklus | Cyklus | Cykly | Cyklu | Cyklů |107| **cs** | Modul | Modul | Moduly | Modulu | Modulů |108| **cs** | Epik | Epik | Epiky | Epiku | Epiků |109| **cs** | Stránka | Stránka | Stránky | Stránky | Stránek |110| **sk** | Cyklus | Cyklus | Cykly | Cyklu | Cyklov |111| **sk** | Modul | Modul | Moduly | Modulu | Modulov |112| **sk** | Epik | Epik | Epiky | Epiku | Epikov |113| **sk** | Stránka | Stránka | Stránky | Stránky | Stránok |114115Per CLDR for ru/ua: `one` fires for 1, 21, 31… (nom.sg.); `few` for 2–4, 22–24… (gen.sg.); `many` for 0, 5–20, 25–30… (gen.pl.); `other` for non-integer counts (gen.sg.). For pl: `one` (1), `few` (2–4 not 12–14, nom.pl.), `many` (0, 5–20, gen.pl.), `other` (decimals, gen.sg.). cs/sk: `one` (1), `few` (2–4, nom.pl.), `many` (decimals, gen.sg.), `other` (0, 5+, gen.pl.).116117### Third-party products & standards (always Latin, every locale)118119GitHub, GitLab, Bitbucket, Slack, Discord, Zoom, Microsoft Teams, Jira, Linear, Asana, Notion, Confluence, Trello, Figma, Google, Google Drive, Google Calendar, Google Docs, Google Sheets, Gmail, YouTube, Dropbox, Zapier, Tiptap, ProseMirror, Yjs, Hocuspocus, Socket.IO, React, TypeScript, JavaScript, Python, Django, PostgreSQL, Redis, RabbitMQ.120121Also preserve: OAuth, OIDC, SAML, SSO, LDAP, API, REST, GraphQL, URL, URI, ID, UUID, JSON, YAML, CSV, TSV, XML, HTML, PDF, PNG, JPG, SVG, CSS, HTTP, HTTPS, TLS, SSL, IP, CIDR, DNS, ARIA, WCAG.122123### Inside-string tokens (mechanical — preserve exactly)124125- **ICU variables**: `{count}`, `{name}`, `{workspace}`, `{userName}` — never translate, never rename, never move inside `{}`.126- **ICU pluralization / select keywords**: `plural`, `select`, `one`, `few`, `many`, `other`, `zero`, `two`, `=0`, `=1`, `#` — never translate.127- **HTML & JSX tags**: `<b>…</b>`, `<a href="…">…</a>`, `<br/>`, `<code>…</code>` — preserve attributes and nesting; translate only the visible text between tags.128- **i18next `Trans` numbered fragments**: `<0>…</0>`, `<1>…</1>` — preserve the numbers exactly; only translate the wrapped text. Never renumber.129- **Markdown**: `**bold**`, `*italic*`, `` `code` ``, `[text](url)` — keep the syntax; translate only human-readable prose.130- **Escape sequences**: `\n` (newline), `\t`, `\"`, `\\` — preserve at the same positions.131- **Keyboard keys & modifiers**: `Ctrl`, `Cmd`, `Shift`, `Alt`, `Option`, `Enter`, `Return`, `Esc`, `Tab`, `Space`, `Backspace`, arrow glyphs (`↑↓←→`), and OS glyphs (`⌘⌥⌃⇧`) — preserve exactly as shown on the physical key.132- **File extensions & formats**: `.json`, `.csv`, `MM/DD/YYYY` format strings — preserve.133134## Per-Script Rules135136Apply by target-language script, not by locale list. Adding a new Latin-script locale? It follows the Latin-script rules below. Adding a new Cyrillic locale? It follows the Cyrillic section. Scripts not yet shown here (Arabic, Hebrew, Thai, Greek, Hindi/Devanagari, etc.) — see **Adding a locale not documented here**.137138### Latin-script locales139140Currently includes fr, es, it, de, pt-BR, pl, cs, sk, ro, tr-TR, vi-VN, id — and any future locale that uses the Latin alphabet (hu, nl, sv, da, nb, fi, hr, bg-using-Latin variants, etc.).141142**Translate Plane feature nouns** (Cycle, Cycles, Module, Modules, Epic, Epics, Page, Pages) using the per-locale form from the glossary above. **Keep Latin** for Plane brand marks (Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake), plan tier names (Pro, Business, Enterprise), and third-party brands (GitHub, Slack, etc.).143144```145✅ "Créer un Cycle" (fr — natural cognate from glossary, identical to English)146✅ "Crear un nuevo Ciclo" (es — natural Spanish cognate from glossary)147✅ "Archiviare questo Modulo" (it — natural Italian cognate from glossary)148✅ "Nueva Epic" (es — Epic has no clean cognate; stays Latin per glossary)149✅ "Archivieren Sie diesen Zyklus" (de — natural German form from glossary)150✅ "Buat Siklus baru" (id — natural Indonesian form from glossary)151✅ "Buat Sticky baru" (id — Sticky is a Plane brand mark, stays Latin)152✅ "Wechseln Sie zum Pro-Plan" (de — Pro is a plan tier name, stays Latin)153❌ "Créer un Cycle" WRONG when the locale should be `Zyklus` (de). Always use the glossary form.154❌ "Archivieren Sie diesen Cycle" (de — feature noun was left in Latin; use Zyklus per glossary)155❌ "Créer un Cercle" (fr — invented translation; use the glossary form)156❌ "Nueva Saga" (es — translated "Epic" with the wrong cognate)157❌ "Buat Catatan Tempel" (id — translated "Sticky" which is a brand mark; keep Latin)158```159160Generic uses translate normally and do not follow the glossary: a paginator's `next page` is `nächste Seite` / `página siguiente` (generic noun, not the Plane Pages feature). The glossary applies only when EN refers to the Plane product feature.161162### Japanese (ja) — natural Japanese rendering163164**Plane feature nouns** (Cycle, Module, Epic, Page) use the natural Japanese form per the glossary above (サイクル, モジュール, エピック, ページ — katakana for foreign-origin nouns; native Japanese where one applies, like 付箋 for an Apple/Microsoft-style "sticky note"). **Brand marks** stay in Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise.165166For new katakana coinages and existing translations, the long-vowel mark `ー` is added for words ending in `-er`, `-or`, `-ar`, `-y` in English. This is the Microsoft Japanese style-guide convention and the current industry default:167168- user → **ユーザー** (not ユーザ)169- server → **サーバー** (not サーバ)170- editor → **エディター** (not エディタ)171- property → **プロパティー** (_kept as_ プロパティ where the existing codebase already does — match the surrounding file's convention)172173Tone: polite form です・ます. Never plain form だ・である. Avoid over-formal 尊敬語・謙譲語 for SaaS product copy — it reads stilted.174175Quotation marks: 「」 for primary quotes, 『』 for nested or for titles of works. Full-width punctuation: 。、()・!?.176177### Korean (ko) — Hangul rendering178179**Plane feature nouns** (Cycle, Module, Epic, Page) use the natural Korean form per the glossary above (사이클, 모듈, 에픽, 페이지 — Hangul transliteration where the term is product-coined; native Korean word where one applies). **Brand marks** stay in Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise.180181For new terms not on the glossary: prefer the native Korean word where one exists (`설정` for Settings); use Hangul phonetic transliteration for product-coined nouns with no native equivalent. Do not coerce a phonetic loanword when a natural Korean word exists — `버킷` for "Bucket" reads as a foreign trademark, `장바구니` reads as a Korean noun.182183**Korean particle agreement**: when introducing a consonant-ending noun (사이클, 에픽, 모듈), follow with the consonant-form particle (을/은/이/과), not the vowel-form (를/는/가/와). `사이클을 추가` not `사이클를 추가`.184185Register:186187- **System and error messages** → 합니다체 (high-formal: 합니다, 됩니다, 입니다). Existing files in this register today: `ko/auth.json`, `ko/error/*.json`.188- **Empty states, onboarding microcopy, tooltips** → 해요체 acceptable (softer: 해요, 돼요, 이에요) if the existing file uses it. Existing files in this register today: `ko/empty-state.json`, `ko/tour.json`. Always match the surrounding file rather than introducing a new register mid-namespace.189- Never casual 반말.190191Punctuation: Western punctuation (`. , ? !`); straight quotes `"…"` and `'…'`.192193### Simplified Chinese (zh-CN) and Traditional Chinese (zh-TW) — translate feature nouns194195**Plane feature nouns** (Cycle, Module, Epic, Page) translate to natural Chinese per the glossary above (zh-CN: 周期, 模块, 史诗, 页面 — zh-TW: 週期, 模組, 史詩, 頁面). This is what Microsoft's zh-CN style guide and every mainstream zh-localized SaaS product (Notion, Slack, Atlassian) does for common feature nouns.196197**Brand marks stay Latin**: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise — these are trademark-style terms.198199**Insert a half-width space on each side of embedded Latin tokens** — this is Microsoft's zh-CN guideline and required for legibility. **Exception**: no space between a Latin token and adjacent full-width punctuation (`。,;:?!`); the punctuation already supplies visual breathing room.200201```202✅ "使用 GitHub 登录" (Latin brand → half-width spaces around)203✅ "创建周期" (zh-CN feature noun translated; no Latin = no spaces)204✅ "归档此史诗" (Plane Epic → 史诗 per glossary)205✅ "添加 Sticky" (Sticky is a brand mark → Latin + half-width space)206✅ "升级到 Pro" (Pro is a plan tier → Latin)207✅ "登录 GitHub。" (no space between Latin token and full-width period)208❌ "使用GitHub登录" (Latin brand without surrounding half-width space)209❌ "创建 Cycle" (feature noun left in Latin — should be 周期)210❌ "创建Cycle" (feature noun in Latin AND missing space)211❌ "登录 GitHub 。" (stray space before full-width period)212❌ "创建赛克" (invented transliteration of Cycle — use the glossary's 周期)213```214215Punctuation is **full-width**: 。,?!;:. Quotes:216217- zh-CN: `"…"` (primary) and `'…'` (nested)218- zh-TW: `「…」` (primary) and `『…』` (nested)219- Work titles (book/movie/app/article names): `《…》`220221Variant discipline: zh-CN ≠ zh-TW. They differ in script (简体 vs 繁體) **and** vocabulary (视频 vs 影片; 软件 vs 軟體; 网络 vs 網路). Never mass-copy between the two directories.222223Register: 您 (formal polite) in Plane UI — the product is B2B/SaaS. Reserve 你 for consumer/youth contexts (not applicable here).224225### Cyrillic locales226227Currently includes ru, ua — and any future Cyrillic locale (bg-BG, sr-Cyrl, mk, be, kk-Cyrl, etc.).228229**Plane feature nouns** (Cycle, Module, Epic, Page) use the natural Cyrillic form per the glossary above (Цикл/Циклы, Модуль/Модули, Эпик/Эпики, Страница/Страницы in ru — Цикл/Цикли, Модуль/Модулі, Епік/Епіки, Сторінка/Сторінки in ua). **Brand marks** stay in Latin: Plane, Plane AI, Power K, PQL, Active Cycles, Sticky, Stickies, Intake, GitHub, Slack, Pro/Business/Enterprise.230231For new terms not on the glossary: prefer the native Cyrillic word where one exists; use phonetic transliteration only when no native word applies (`Бакет` is wrong for "Bucket" — use `Корзина`/`Кошик`).232233**Slavic case forms inside `{count, plural, ...}` blocks** are case-correct per CLDR keyword (one=nom.sg., few=gen.sg., many=gen.pl., other=gen.sg.). See the case-form table in the glossary section.234235Register:236237- **ru**: formal **Вы** (capitalized) when addressing a **single user directly** in respectful/formal contexts (onboarding, settings, confirmation dialogs); lowercase **вы** for plural/general references ("все вы"). Default to capitalized Вы in tooltips/dialogs and lowercase вы in descriptive copy.238- **ua**: modern Ukrainian software convention is lowercase **ви** by default; capitalized **Ви** is reserved for very formal direct address. This is the opposite convention from Russian — do not copy-paste Russian capitalization rules into Ukrainian files.239240Punctuation: primary quotes `«…»`, nested `„…"`.241242**Plural forms — critical**: both ru and ua require `one / few / many / other`. See CLDR section below.243244## CLDR Plural Rules245246Every `{count, plural, …}` string must contain **every** keyword the target language's CLDR rule requires. `other` is always required, even in single-form languages.247248**Canonical source**: Unicode CLDR Language Plural Rules chart — the definitive, versioned list of required categories for every language. Always verify against the current CLDR chart when adding a locale, since rules occasionally shift across CLDR releases. Libraries like `Intl.PluralRules` can resolve the rule at runtime.249250Below are the required keywords for locales currently in the repo. When adding a new locale, look up its categories in CLDR and add the row here.251252| Locale | Required keywords | Example mapping |253| -------------------------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |254| en, es, de, tr-TR, vi-VN, id, ja, ko, zh-CN, zh-TW | `one, other` (single-form locales may use `other` alone, but **always emit `other`**) | 1 → one; 2+ → other |255| fr | `one, many, other` | 0, 1 → one; 1 000 000 → many; else other |256| it | `one, many, other` | 1 → one; 1 000 000 → many; else other |257| pt-BR | `one, many, other` | 0, 1 → one; 1 000 000 → many; else other |258| ro | `one, few, other` | 1 → one; 0, 2–19 → few; 20+ → other |259| pl | `one, few, many, other` | 1 → one; 2–4 (not 12–14) → few; 0, 5–20, many-digit → many; decimals → other |260| cs | `one, few, many, other` | 1 → one; 2–4 → few; decimals → many; 0, 5+ → other |261| sk | `one, few, many, other` | same pattern as cs |262| ru | `one, few, many, other` | 1, 21, 31… → one; 2–4, 22–24… → few; 0, 5–20, 25–30… → many; decimals → other |263| ua | `one, few, many, other` | same pattern as ru |264| ar (when added) | `zero, one, two, few, many, other` | Six categories — the maximum any language uses |265266> **Note on the consolidated row.** CLDR itself only requires `other` for `tr-TR`, `vi-VN`, `id`, `ja`, `ko`, `zh-CN`, `zh-TW` (single-form locales). Emitting both `one` and `other` with identical content is a **project convention** — it keeps tooling and linters consistent across the codebase. It is not a CLDR requirement, and `Intl.PluralRules` will return only `"other"` for these locales at runtime.267268For any locale not listed: look up the CLDR categories before writing a single plural string. Arabic has six; Welsh has six; most Slavic languages have four; most Romance languages have two or three; CJK / Turkic / Thai have one (still emit `other`).269270Rules in practice:2712721. **Never drop a required form**, even when the word is identical across forms — emit each one explicitly.2732. **Never add a form the target doesn't have.** German does **not** use `few`. Any `few` clause in `de/*.json` is a bug and must be removed.2743. In single-form locales (ja/ko/zh/tr/vi/id), emit `one` + `other` with identical content so tooling and linters stay consistent.2754. The `other` case is always the fallback — it must render a grammatically complete sentence on its own.276277Examples:278279```json280// ✅ Correct — Russian (four forms; `other` fires for non-integer counts and takes genitive singular)281"members": "{count, plural, one {# участник} few {# участника} many {# участников} other {# участника}}"282283// ✅ Correct — Polish (four forms)284"items": "{count, plural, one {# element} few {# elementy} many {# elementów} other {# elementu}}"285286// ✅ Correct — Romanian (three forms)287"days": "{count, plural, one {# zi} few {# zile} other {# de zile}}"288289// ✅ Correct — French (three forms; `many` covers 1 000 000, 2 000 000, …)290"members": "{count, plural, one {# membre} many {# membres} other {# membres}}"291292// ✅ Correct — Japanese (single form, both keywords emitted)293"label": "{count, plural, one {サイクル} other {サイクル}}"294295// ❌ Wrong — German with spurious `few`296"label": "{count, plural, one {Zyklus} few {Zyklen} other {Zyklen}}"297298// ❌ Wrong — Russian missing `few` and `many`299"label": "{count, plural, one {Цикл} other {Циклы}}"300```301302## Placeholders, HTML, Markdown (preservation checklist)303304For every translated string, verify before saving:305306- [ ] Identical set of `{variables}` in source and target (character-for-character — `{userName}` is not `{username}`)307- [ ] Identical HTML/JSX tags with identical attributes and nesting308- [ ] Identical i18next `Trans` numbered tags (`<0>…</0>`, `<1>…</1>` — never renumber)309- [ ] Identical Markdown syntax (`**bold**`, `` `code` ``, `[link text](url)`)310- [ ] Identical `\n` positions (layout relies on these)311- [ ] No additions (no extra explanatory words), no omissions (no collapsed clauses)312313Variables **may be repositioned** for grammatical fit:314315```316en: "Welcome, {name}! You have {count} new work items."317fr: "Bienvenue, {name} ! Vous avez {count} nouveaux work items."318ja: "{name}さん、ようこそ。{count}件の新しい作業項目があります。"319```320321## Per-Locale Punctuation & Spacing322323Apply in every translated string. These are MQM "Locale Conventions" violations when missed — a measurable quality defect.324325Table below covers locales currently in the repo; add a row when you add a locale.326327| Locale | Key rules |328| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |329| **fr** | Narrow NBSP (U+202F, fallback U+00A0) **before** `:`, `;`, `?`, `!`, `%`, `»` and **after** `«`. Primary quotes `« »` (with NBSPs), nested `"…"`. |330| **de** | Primary quotes `„…"` (low-high); **no** NBSP before punctuation. Avoid imperatives in system strings; prefer infinitive constructions ("Werkelement erstellen", not "Erstelle ein Werkelement"). |331| **es** | Inverted `¿…?` and `¡…!` at the start of questions/exclamations. Primary quotes `«…»` or `"…"`. |332| **it** | Primary quotes `«…»` or `"…"`. |333| **pt-BR** | Straight quotes `"…"`. |334| **pl** | Primary quotes `„…"`. |335| **cs / sk** | Primary quotes `„…"`. |336| **ro** | Primary quotes `„…"`. |337| **tr-TR / vi-VN / id** | Straight quotes `"…"`. Vietnamese diacritics are mandatory — never strip (no `bạn` → `ban`). |338| **ru / ua** | Primary `«…»`, nested `„…"`. |339| **ja** | Full-width `。、()!?・`. Primary quotes 「」, nested 『』. Ellipsis `…` (U+2026), typically doubled as `……`. |340| **ko** | Western `. , ? !`; straight quotes `"…"`. |341| **zh-CN** | Full-width `。,?!;:`. Primary `"…"`, nested `'…'`. Work titles `《…》`. Half-width space around embedded Latin tokens. |342| **zh-TW** | Full-width `。,?!;:`. Primary `「…」`, nested `『…』`. Work titles `《…》`. Half-width space around embedded Latin tokens. |343344## Tone & Register (SaaS defaults)345346Formality defaults for locales currently in the repo. Add a row for each new locale, consulting the Microsoft Style Guide for that locale as the default authority on product-UI register.347348| Locale | Default "you" | Notes |349| ------- | ---------------------------------------------------------------------------- | ------------------------------------------------ |350| fr | **vous** | Never "tu" in product UI |351| es | **usted** + **ustedes** | Neutral Spanish — no "vosotros", no "tú" |352| it | **Lei** (formal third-person) | B2B/enterprise convention |353| de | **Sie** | Use infinitive constructions for system messages |354| pt-BR | **você** | Semi-formal default; never "tu" |355| pl | **Pan/Pani** + 3rd-person, or impersonal | Never "ty" |356| cs / sk | **Vy** (formal, 3rd-person plural) | Never "ty" |357| ro | **dumneavoastră** (formal) | Or impersonal |358| tr-TR | **siz** + `-iniz` endings | Never "sen" |359| vi-VN | **bạn** (safe neutral) | Never "mày/tao"; consistency > variety |360| id | **Anda** (always capitalized) | Never "kamu" in product UI |361| ja | **です・ます体** | Never plain form; avoid 尊敬語・謙譲語 |362| ko | **합니다체** for system/errors; **해요체** acceptable for onboarding | Match surrounding file |363| zh-CN | **您** | B2B convention; never 你 |364| zh-TW | **您** | B2B convention; never 你 |365| ru | **Вы** (cap.) for singular direct address, **вы** (lower) for plural/general | Context-dependent |366| ua | **ви** (lowercase, modern convention) | Capitalized Ви only for very formal |367368General writing rules (apply across all locales):369370- Sentence case in buttons, headings, tooltips — not Title Case. Only capitalize proper nouns.371- No exclamation marks except in genuine celebrations (first success, milestone).372- No emoji in UI copy.373- No slang, idioms, humor, cultural references — they don't translate.374- Consistent terminology — if "work item" is used once, never switch to "issue" / "ticket" mid-flow.375- Active voice, present tense.376- Write out abbreviations on first use if not on the DNT list.377378## Text Expansion Budget379380Design strings knowing translations will grow. Typical expansion vs. English for locales currently in the repo; lookup values from Andiamo / Eriksen / W3C tables when adding a locale.381382| Locale | Expansion | Implication |383| ------------ | ------------------------------------------------- | ----------------------------------------------- |384| de | +10–35%, single words up to +180% | Reserve generous space on buttons, tabs, labels |385| fr | +15–25% | |386| es | +15–30% | |387| it | +10–25% | |388| pt-BR | +15–30% | |389| pl | +20–30% | |390| cs, sk | +10–20% | |391| ro | +15–25% | |392| ru, ua | +15% typical, spikes to +30% | |393| tr-TR | +10–30% (agglutination) | |394| vi-VN | +30–40% | Diacritic-heavy, many small words |395| id | +10–20% | |396| ja | −10 to −55% character count (similar pixel width) | |397| ko | −10 to −15% | |398| zh-CN, zh-TW | −40% character count (≈2× char width) | |399400Rule of thumb: any UI surface must absorb **+35%** without truncation. If a string is length-capped, add a comment or context in the source.401402## Numbers, Dates, Currency, Units403404**Never hard-code formats.** Use ICU skeletons so the runtime localizes automatically:405406```json407"updated_on": "Updated {date, date, medium}",408"percent_done": "{ratio, number, percent} complete",409"item_count": "{count, number} items"410```411412Never write `"{date}MM/DD/YYYY"` in the source — that guarantees a locale bug.413414Decimal/thousands separators (runtime-handled):415416- en: `1,234.56` — de/it/es/pt-BR/ru/ua/pl/cs/sk/tr-TR: `1.234,56` or `1 234,56` — fr: `1 234,56` (thin space) — ja/ko/zh: `1,234.56`.417418Date formats (runtime-handled):419420- en-US: `MM/DD/YYYY` — most of Europe: `D421422…(truncated)