Files
flxn-app/.claude/skills/add-language/SKILL.md
T
yohlo 0a7b5fa00f
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 8s
CI/CD Pipeline / i18n Catalog Check (push) Failing after 10s
CI/CD Pipeline / Build and Push App Docker Image (push) Skipped
CI/CD Pipeline / Deploy to Kubernetes (push) Skipped
i18n
2026-08-08 15:29:40 -07:00

3.0 KiB

name, description
name description
add-language Add or remove a UI language/locale — config, catalog generation, translation agents, SMS/date/meta integration, and verification. Use when asked to add, enable, support, or remove a language.

Adding a language

Example: adding French (fr). Five places name the locale set — update all:

  1. src/lib/i18n/index.tsSUPPORTED_LOCALES + LOCALE_LABELS (label in the language itself, no region clarifier: fr: "Français").
  2. lingui.config.tslocales.
  3. src/lib/mantine/mantine-provider.tsxDAYJS_LOCALE map + the matching import 'dayjs/locale/fr' (calendar month/weekday names come from dayjs; without this, calendars stay English).
  4. src/lib/i18n/meta.tsOG_LOCALE_BY_LOCALE (fr → fr_FR).
  5. src/lib/twilio/index.tsTWILIO_VERIFY_LOCALES ONLY if Twilio Verify supports the code (https://www.twilio.com/docs/verify/supported-languages). Unsupported codes must stay out — the allowlist silently falls back to the service-default English SMS instead of failing the login send.

Then generate + translate:

  1. bun run extract creates src/locales/fr/messages.po (every msgid, empty msgstr).
  2. Translate via a chunked agent workflow (this repo's proven recipe):
    • Split en.po entry blocks (split on blank lines, skip header) into ~60-entry chunks; one sonnet agent per chunk RETURNS translated entries (never let parallel agents edit one .po). Validate each returned chunk by msgid count; retry failures once.
    • Merge by msgid back into the locale .po. Match msgids by exact bytes — watch non-breaking spaces (\xa0) in msgids, which agents normalize away; patch those few by hand.
    • Agent rules: msgstr single-line, ICU placeholders/plural keywords and <0> tags preserved (translate only human words inside branches; plural categories follow the target language's CLDR set), FLXN/Flexxon/Spotify untranslated, casual sporty tone, register decided up front (tú/du/です・ます).
  3. bun run i18n:check must pass (0 missing). Optionally run per-locale native-reviewer agents over the full .po (fidelity, register, glossary consistency, ICU integrity) and apply their FIX lines.
  4. bunx tsc --noEmit && bun run build; confirm the new locale appears as its own lazy messages-*.js chunk in dist/client/assets.
  5. Manual check: switch language in Settings (persists to SuperTokens metadata), confirm UI + calendar + SMS behavior.

Removing a language

Reverse of the above: delete from the five locale-set sites (skip Twilio if it was never listed), rm -rf src/locales/<code>, drop the dayjs import, then bun run i18n:check + tsc. Users with the removed locale saved in metadata fall back to English automatically via resolveLocale.

Fallback semantics: untranslated entries render English (msgid); unauth visitors get Accept-Language detection (SSR first paint on public routes is English, corrected after hydration); authed users get their saved locale server-rendered.