Merge pull request #303 from Coffey-Labs/contributor-notes-in-contributing
Move the translation and UI-verification notes into CONTRIBUTING
This commit is contained in:
@@ -7,5 +7,3 @@ server/data/
|
||||
.vite/
|
||||
coverage/
|
||||
|
||||
# Worktrees used by parallel agents; never part of a commit.
|
||||
.claude/worktrees/
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
# Notes for Claude
|
||||
|
||||
**Scope: translations and verifying UI work. Nothing else.**
|
||||
|
||||
This file covers exactly two things — the nine translation catalogues, and
|
||||
what it takes to confirm a visible change actually works. Do not add sections
|
||||
for anything else: no build, deploy, architecture, style or workflow notes,
|
||||
however useful they seem. `CONTRIBUTING.md` is the style guide, and everything
|
||||
else belongs in the code, the docs, or a commit message.
|
||||
|
||||
## Translations
|
||||
|
||||
Nine languages ship alongside English: German, Spanish, French, Dutch,
|
||||
Portuguese (Brazil), Russian, Ukrainian, Simplified Chinese and Japanese, in
|
||||
`web/src/locales/`. A missing key renders its English source rather than
|
||||
failing, so an untranslated string is invisible until somebody reading that
|
||||
language finds it.
|
||||
|
||||
**Any change that adds or alters a user-visible string adds work in all nine
|
||||
catalogues.** Say so explicitly when reporting the change — how many keys, and
|
||||
the fallback count before and after — and say so just as explicitly when a
|
||||
change adds none, so it is never left to be inferred.
|
||||
|
||||
### The catalogue key for a plural is the `other` form
|
||||
|
||||
`plural()` looks the entry up by `forms.other`, so a call site written as
|
||||
|
||||
```ts
|
||||
plural(n, { one: "Deleted {n} contact", other: "Deleted {n} contacts" })
|
||||
```
|
||||
|
||||
is keyed on **`"Deleted {n} contacts"`**. Keying the catalogue on the `one`
|
||||
form type-checks, builds, passes every test, and silently falls back to English
|
||||
in all nine languages. Nothing errors. The only signal is the fallback count
|
||||
going up, so read it:
|
||||
|
||||
```sh
|
||||
npm run i18n:check # literals wrapped, and catalogue health
|
||||
node scripts/i18n-catalog-check.mjs # per-language: translated / used / falling back
|
||||
```
|
||||
|
||||
Compare the "falling back to English" number against `main` before and after.
|
||||
It should not rise. Do not read the percentage instead — adding keys moves the
|
||||
denominator, so it can hold steady while new strings go untranslated.
|
||||
|
||||
Plural forms are per language, from `Intl.PluralRules`: `one`/`other` for most,
|
||||
`one`/`few`/`many`/`other` for Russian and Ukrainian, `other` alone for Japanese
|
||||
and Chinese. Supplying a form a language does not draw is inventing a
|
||||
distinction, not being thorough.
|
||||
|
||||
## Verifying UI work
|
||||
|
||||
Store tests do not exercise the component. At least one bug in this repo's
|
||||
history — a shift-click range measured inside a `setState` updater, which React
|
||||
runs after the anchor ref has already moved — passed every store assertion and
|
||||
failed the moment the built app was driven. If a change is visible on screen,
|
||||
run it: `npm run dev:mock` (mock Stalwart, credentials printed on start), then
|
||||
drive the real thing. Add a component test for what you find; there are
|
||||
examples in `web/src/views/*/__tests__/`.
|
||||
+54
-6
@@ -48,12 +48,10 @@ For larger changes, please open an issue to discuss the approach **before** subm
|
||||
- Related issue number(s), if any
|
||||
- Screenshots/GIFs for UI changes
|
||||
- Any manual testing you performed
|
||||
8. **Add translations** for any new user-visible string. Nine languages ship
|
||||
alongside English in `web/src/locales/`, and a missing key renders its
|
||||
English source rather than failing — so an untranslated string is invisible
|
||||
until somebody reading that language finds it. `npm run i18n:check` and
|
||||
`node scripts/i18n-catalog-check.mjs` report where you stand; the catalogue
|
||||
key for a plural is the `other` form. See [CLAUDE.md](CLAUDE.md).
|
||||
8. **Add translations** for any new user-visible string — see
|
||||
[Translations](#translations) below — and **drive the built app** for any
|
||||
change that is visible on screen, as described in
|
||||
[Verifying UI work](#verifying-ui-work).
|
||||
|
||||
`main` is protected. A change reaches it through a pull request whose **build**
|
||||
check has passed — not afterwards — and the branch cannot be force-pushed or
|
||||
@@ -67,6 +65,56 @@ waiting for one.
|
||||
- Prefer clarity over cleverness — this is a mail client people rely on for their inbox.
|
||||
- Comment non-obvious JMAP interactions, especially around state/`changes` handling, since JMAP's delta-sync model can be easy to get subtly wrong.
|
||||
|
||||
### Translations
|
||||
|
||||
Nine languages ship alongside English: German, Spanish, French, Dutch,
|
||||
Portuguese (Brazil), Russian, Ukrainian, Simplified Chinese and Japanese, in
|
||||
`web/src/locales/`. A missing key renders its English source rather than
|
||||
failing, so an untranslated string is invisible until somebody reading that
|
||||
language finds it.
|
||||
|
||||
**Any change that adds or alters a user-visible string adds work in all nine
|
||||
catalogues.** Say so explicitly in the PR — how many keys, and the fallback
|
||||
count before and after — and say so just as explicitly when a change adds none,
|
||||
so it is never left to be inferred.
|
||||
|
||||
#### The catalogue key for a plural is the `other` form
|
||||
|
||||
`plural()` looks the entry up by `forms.other`, so a call site written as
|
||||
|
||||
```ts
|
||||
plural(n, { one: "Deleted {n} contact", other: "Deleted {n} contacts" })
|
||||
```
|
||||
|
||||
is keyed on **`"Deleted {n} contacts"`**. Keying the catalogue on the `one`
|
||||
form type-checks, builds, passes every test, and silently falls back to English
|
||||
in all nine languages. Nothing errors. The only signal is the fallback count
|
||||
going up, so read it:
|
||||
|
||||
```sh
|
||||
npm run i18n:check # literals wrapped, and catalogue health
|
||||
node scripts/i18n-catalog-check.mjs # per-language: translated / used / falling back
|
||||
```
|
||||
|
||||
Compare the "falling back to English" number against `main` before and after.
|
||||
It should not rise. Do not read the percentage instead — adding keys moves the
|
||||
denominator, so it can hold steady while new strings go untranslated.
|
||||
|
||||
Plural forms are per language, from `Intl.PluralRules`: `one`/`other` for most,
|
||||
`one`/`few`/`many`/`other` for Russian and Ukrainian, `other` alone for Japanese
|
||||
and Chinese. Supplying a form a language does not draw is inventing a
|
||||
distinction, not being thorough.
|
||||
|
||||
### Verifying UI work
|
||||
|
||||
Store tests do not exercise the component. At least one bug in this repo's
|
||||
history — a shift-click range measured inside a `setState` updater, which React
|
||||
runs after the anchor ref has already moved — passed every store assertion and
|
||||
failed the moment the built app was driven. If a change is visible on screen,
|
||||
run it: `npm run dev:mock` (mock Stalwart, credentials printed on start), then
|
||||
drive the real thing. Add a component test for what you find; there are
|
||||
examples in `web/src/views/*/__tests__/`.
|
||||
|
||||
### Development Setup
|
||||
|
||||
1. Clone your fork:
|
||||
|
||||
Reference in New Issue
Block a user