fable-review
Use when asked for a full codebase review, health check, quality audit, or scorecard of this repo, or for a "fable review" /…
Use when adding a new interface language (locale) to the app, or when asked to translate the UI into another language. Covers the translation file, the i18n resources, the plural forms the language needs, and the user doc that names the available languages.
$ npx -y skills add ZoneMinder/zmNinjaNg --skill add-language --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/add-languageContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when adding a new interface language (locale) to the app, or when asked to translate the UI into another language. Covers the translation file, the i18n resources, the plural forms the language needs, and the user doc that names the available languages.
name: add-language description: Use when adding a new interface language (locale) to the app, or when asked to translate the UI into another language. Covers the translation file, the i18n resources, the plural forms the language needs, and the user doc that names the available languages.
The app bundles translations at build time. Adding a locale means touching three code locations plus two prose locations. Miss any one and the failure is silent: i18next falls back to English mid-screen, or the new locale ships with no key-parity coverage.
Run all npm commands from `app/`.
Below, `{code}` is the ISO code (`it`) and `{Name}` is the language's own name for itself (`Italiano`).
mkdir -p app/src/locales/{code}
cp app/src/locales/en/translation.json app/src/locales/{code}/translation.jsonTranslate every value in `app/src/locales/{code}/translation.json`. Do not change, add, or drop keys. The key-parity test in step 5 fails if the shape drifts from `en`.
Labels must fit 320px (project rule in `AGENTS.project.md`), so prefer the concise translation where two options exist.
The `languages` section of each locale lists all languages, so the picker reads correctly whatever language the UI is currently in. Add `"{code}": "{Name}"` to the `languages` section of every `translation.json` under `app/src/locales/`, the new one included. List them first rather than working from memory:
ls app/src/locales
Use the same string `{Name}` in all of them. Language names are not translated.
In `app/src/locales/resources.ts`, add the import alongside the others and the entry in `LANGUAGE_RESOURCES`:
import {code}Translation from './{code}/translation.json';export const LANGUAGE_RESOURCES = {
// ...
{code}: { translation: {code}Translation },
};Both pickers and i18next read this map, so nothing else registers a locale.
Both of them, Settings → Appearance and the sidebar globe dropdown, render `useLanguageOptions` (`app/src/hooks/useLanguageOptions.ts`), which reads the codes registered in step 4 and orders them English first, then by label. The order is covered by `app/src/components/layout/__tests__/LanguageSwitcher.test.tsx`, which pins the expected sequence, so add the new code there.
`docs/user-guide/settings.md`, Appearance table, Language row, names the available languages in English. Add the new one.
Also add the code to the Localization contract's list in `AGENTS.project.md`. `app/src/tests/agents-contracts.test.ts` fails until the list matches `LANGUAGE_CODES`.
English declares `_one` and `_other`. A language with more plural categories needs the rest, or i18next finds no key for those counts and silently renders English: Russian showed "2 monitors" until `_few` and `_many` were added. The parity test checks every category `Intl.PluralRules` reports for counts up to 100, so it tells you which keys are missing.
node -e "console.log(new Intl.PluralRules('{code}').resolvedOptions().pluralCategories)"These already take the active locale as data, so none of them needs a per-locale entry:
`Intl.RelativeTimeFormat`.
prompt and asks the model to answer in the user's language.
directories on disk, so the new one is key-checked against `en` with no edit.
npm test npx tsc -b npm run build npm run test:e2e -- settings.feature
`settings.feature` has a language-change scenario, so it is the relevant e2e run for this change.
Then check the UI by hand: Settings → Appearance → Language, and the sidebar globe dropdown. Both should list the new language, and selecting it should change the visible text.
Documentation A ZoneMinder client for web, desktop, iOS, and Android. It shows live camera feeds, a montage of many cameras at once, and events on a timeline, and has an AI chat agent you can ask about your cameras.
Use when asked for a full codebase review, health check, quality audit, or scorecard of this repo, or for a "fable review" /…
Use when asked to mine the commit history for lessons the agent instruction files have not captured, to audit whether…