← LeaderboardThe Skill Leaderboard

i18n-localization

Use when adding UI text, adding or shipping a language, reviewing translation files, or building i18n into an app. Checks missing keys, placeholders and CLDR plural forms with locale_sync.py, finds hardcoded strings with hardcoded_strings.py, and builds a pseudo-locale with pseudo_localize.py.

Published by alirezarezvani ↗alirezarezvani/claude-skills

Try your first task

A source-grounded starter task has not been verified for this skill yet.

SKILL.md

name: i18n-localizationdescription: Use when adding UI text, adding or shipping a language, reviewing translation files, or building i18n into an app. Checks missing keys, placeholders and CLDR plural forms with locale_sync.py, finds hardcoded strings with hardcoded_strings.py, and builds a pseudo-locale with pseudo_localize.py.argument-hint: "[locales dir | source dir | release check]"license: MITmetadata:   version: 1.0.0  build_pattern: "Three deterministic stdlib scripts (translation-file checker with the CLDR 49 plural table embedded, hardcoded-string scanner for React/Vue/Svelte/HTML, pseudo-locale generator) with blocking exit codes; rules cited to Unicode CLDR and UTS #35, ICU MessageFormat, ECMA-402/MDN Intl, i18next, Android and gettext docs, W3C Internationalization and WCAG 3.1"  distinct_from: "a11y-audit (WCAG in source; this checks the translation layer and lang/dir only as they affect i18n); email-template-builder (localizes one email template); marketing localization and transcreation skills (copy, not code)"

i18n Localization

Portability: 3 stdlib Python scripts. No network, no translation service. They check and generate files; they never translate text or call an API.

A release with a new language usually breaks in the same places: keys added in English and never synced, a placeholder renamed by a translator, Russian or Arabic files that copied English's two plural forms, UI text that never went through t(), and dates formatted in the server's locale. This skill makes each of those a check that fails before the release, not a bug report after it.

Workflow

# 1 - Translation files: keys, placeholders, ICU syntax, CLDR plural forms
python scripts/locale_sync.py locales/ --source-locale en
# 2 - Code: user-facing text that bypasses t(), concatenation, locale-less formatting
python scripts/hardcoded_strings.py src/
# 3 - Layout: generate a pseudo-locale and click through the app in it
python scripts/pseudo_localize.py locales/en/common.json -o locales/en-XA/common.json
python scripts/pseudo_localize.py locales/en/common.json --bidi -o locales/ar-XB/common.json

Step 1 reads JSON/ARB (i18next or ICU), .properties, Apple .strings, Android strings.xml and gettext .po, pairs each target with the source file of the same namespace, and blocks on missing or empty keys, changed placeholders, ICU syntax errors, plural/select without other, a zero branch that can never match, and plural categories the target locale needs (ru few/many, ar six forms), using the embedded CLDR 49 table. Untranslated values, orphan keys, fuzzy entries and markup drift are warnings.

Step 2 blocks on literal text between tags and literal user-facing attributes (placeholder, alt, aria-label, title...), and warns on literals rendered from {cond ? 'Saving...' : ...}, t('a') + x concatenation, toLocaleString() with no locale, '$' + amount and hardcoded date patterns. It is a text heuristic: read each finding. Use --warn-only to adopt it on a legacy codebase, i18n-ignore on a line, and .i18n-allow for brand names.

Step 3 accents, pads (by translation-growth rates) and brackets every string while keeping placeholders and ICU syntax intact. Plain English on screen is a hardcoded string; a cut-off [[... is truncation; [[a]] [[b]] is concatenation.

Hard rules

  • Never concatenate translated fragments. One message per sentence, with named placeholders and a plural branch.
  • Plural forms follow CLDR for the target locale, not English. Never copy _one/_other into ru, pl, uk, cs, ar, he files and call them done.
  • =0, not zero, for an empty-count message in ICU.
  • Pass the locale to every formatter. Currency comes from the data, not the UI locale.
  • Placeholders are code. A translator may move them, never rename or drop them; use positional %1$s where order can change.
  • Do not machine-translate to make the checker pass. A missing translation falls back to the source language; a wrong one ships silently. Mark gaps for a translator instead.

Scripts

ScriptRoleExit codes
scripts/locale_sync.pyTranslation files vs source locale: keys, placeholders, ICU, CLDR plurals, gettext0 · 2 warnings · 3 bad input · 4 blocked
scripts/hardcoded_strings.pyReact/Vue/Svelte/HTML: untranslated text, concatenation, locale-less formatting0 · 2 · 3 · 4
scripts/pseudo_localize.pyen-XA (or --bidi ar-XB) pseudo-locale from JSON/ARB/.properties0 · 3

All support --help, --sample and --output json.

References and assets