feat(i18n): add Japanese locale catalogs and negotiation (#3841)
Co-authored-by: Y.anbe <yoshitaka.anbe@aot.it.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
This commit is contained in:
+14
-11
@@ -3,8 +3,9 @@
|
||||
Kandev's web UI is internationalized with [i18next](https://www.i18next.com) +
|
||||
[react-i18next](https://react.i18next.com). English is the source locale,
|
||||
European Portuguese (`pt-pt`), Simplified Chinese (`zh-cn`), Traditional Chinese
|
||||
Taiwan (`zh-tw`), and Traditional Chinese Hong Kong (`zh-hk`) are the shipped
|
||||
human locales, and a generated **pseudo-locale** is used for QA. Requirements live in
|
||||
Taiwan (`zh-tw`), Traditional Chinese Hong Kong (`zh-hk`), and Japanese (`ja`,
|
||||
endonym `日本語`) are the shipped human locales, and a generated **pseudo-locale**
|
||||
is used for QA. Requirements live in
|
||||
[`docs/specs/platform/requirements/i18n.md`](specs/platform/requirements/i18n.md). Traditional Chinese
|
||||
catalogs are derived from `zh-cn` via OpenCC plus a product glossary; see
|
||||
[`docs/specs/platform/requirements/traditional-chinese-locales.md`](specs/platform/requirements/traditional-chinese-locales.md)
|
||||
@@ -27,8 +28,8 @@ Two enforcement layers, and it matters which is which:
|
||||
the migration ran; that list is now the migration record, not the bound. See
|
||||
[The guard is scoped](#the-guard-is-scoped-on-purpose) and
|
||||
[Externalizing a path](#externalizing-a-path).
|
||||
- **The four real locales gate the build.** `pt-pt`, `zh-cn`, `zh-hk` and `zh-tw`
|
||||
are complete, and adding an `en` key without translating it fails
|
||||
- **The five real locales gate the build.** `pt-pt`, `zh-cn`, `zh-hk`, `zh-tw`
|
||||
and `ja` are complete, and adding an `en` key without translating it fails
|
||||
`pnpm run i18n:check`. See [Real locales](#real-locale-catalogs-gate).
|
||||
|
||||
## TL;DR for adding a string
|
||||
@@ -1162,8 +1163,9 @@ Do it in its own PR, not inside a copy-only migration.
|
||||
|
||||
## Adding a real language
|
||||
|
||||
Use a canonical lowercase locale id such as `zh-cn`. Locale negotiation accepts
|
||||
case variants such as `zh-CN`, but cookies and `<html lang>` use the canonical id.
|
||||
Use a canonical lowercase locale id such as `zh-cn` or `ja`. Locale negotiation
|
||||
accepts case variants such as `zh-CN` and unambiguous region suffixes such as
|
||||
`ja-JP` (collapsed onto `ja`); cookies and `<html lang>` use the canonical id.
|
||||
|
||||
For Traditional Chinese Taiwan / Hong Kong specifically, prefer converting from
|
||||
`zh-cn` with `node scripts/convert-zh-cn-to-zh-hant.mjs --write` (OpenCC +
|
||||
@@ -1218,11 +1220,12 @@ entries:
|
||||
| zh-hk | 415 | 81 | 1 |
|
||||
| zh-tw | 415 | 81 | 1 |
|
||||
|
||||
None of it visible in a green build. The four catalogs are now complete, so the
|
||||
failure mode has flipped: the risk is no longer "a PR is blocked on a translator"
|
||||
but "a PR silently re-opens the gap". So the pass **gates**, and the cost is that
|
||||
adding user-facing copy means adding it in five languages. That is the real cost
|
||||
of shipping five languages; it was previously being deferred rather than paid.
|
||||
None of it visible in a green build. The four catalogs were completed first, then
|
||||
`ja` joined them, so the failure mode has flipped: the risk is no longer "a PR is
|
||||
blocked on a translator" but "a PR silently re-opens the gap". So the pass
|
||||
**gates**, and the cost is that adding user-facing copy means adding it in six
|
||||
languages (`en` plus five real locales). That is the real cost of shipping those
|
||||
languages; it was previously being deferred rather than paid.
|
||||
|
||||
For `zh-tw` and `zh-hk`, do not hand-translate: run `pnpm run i18n:zh-hant`,
|
||||
which converts `zh-cn` through OpenCC plus the product glossary and emits proper
|
||||
|
||||
Reference in New Issue
Block a user