i18n-l10n-readiness-review
Audit frontend code for internationalization readiness — externalized ICU MessageFormat strings, Intl-based date/number/currency/plural formatting, correct lang/dir attribute propagation, and RTL-safe CSS logical properties — before translation vendor engagement, with CLDR plural
Install
npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/frontend/i18n-l10n-readiness-review
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
git clone https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vincentchuwaichow/vanguard-frontier-agentic collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
i18n/l10n Readiness Review
Purpose
Teams routinely discover — after paying a translation vendor — that string concatenation
can't express another language's word order, pluralization breaks outside English's
one/other split, or RTL layouts mirror visually but not functionally. Fixing these after
translation means re-engineering already-translated strings, re-running the vendor
pipeline, and eating the schedule slip. This skill audits pluralization architecture
(ICU MessageFormat / CLDR plural categories), Intl-based formatting, lang/dir
attribute propagation, and RTL-safe layout so the codebase is structurally
translation-ready before any string reaches a translator. It does not translate
anything itself.
When to use
Use this skill when the user asks to:
- audit a codebase for hardcoded/non-externalized user-facing strings,
- review pluralization logic against CLDR plural categories for target locales,
- review date/number/currency formatting for
IntlAPI usage vs manual string-building, - review layout/CSS for RTL-market readiness,
- assess overall i18n/l10n readiness before a new-market launch or vendor engagement.
Lean operating rules
- First establish the target locale list, including at least one locale with more than two CLDR plural categories (e.g., Arabic: 6, Polish: 4, Russian: 4) if any countable strings exist — English's one/other split hides most pluralization bugs. If the user has not named target locales, ask; do not assume English-only is sufficient for a "readiness" review.
- Flag string concatenation for user-facing countable/orderable/gendered content as a
structural defect, not a style nit —
"You have " + count + " items"cannot be correctly localized without ICU MessageFormat ({count, plural, ...}) or an equivalent, because plural-category counts and word order both vary by locale. - Verify date/number/currency/plural values use
Intl.DateTimeFormat,Intl.NumberFormat, orIntl.PluralRules(or a library wrapping them, e.g. FormatJS/react-intl,next-intl,i18nextwith ICU) rather than manual string building, hardcoded separators, or naiveMath.round/string concatenation for currency. - Check that the
dirattribute (andlang) actually reach the rendered document root (<html lang dir>) and stay in sync with the active locale, and that layout uses CSS logical properties (margin-inline-start,padding-inline-end,inset-inline-start) instead of physical properties (margin-left,padding-right,left) wherever an RTL-market launch is on the roadmap, even if RTL isn't shipped yet — retrofitting physical properties across a whole codebase later is expensive. - Do not treat the presence of a language switcher, an
i18next/next-intldependency, or alocales/translation-file structure as proof of readiness — a library being installed does not mean it is used correctly everywhere. Verify the underlying formatting/pluralization/layout mechanics independently, file by file. - Never author, insert, or "helpfully" translate actual copy into another language; that is the translation vendor's job. Only flag strings for extraction and hand off the inventory to whoever owns translation.
- Verify icons/imagery conveying directionality (arrows, forward/back/next controls, progress indicators) have a documented RTL-mirroring plan when RTL is in scope — logical CSS properties fix layout flow but do not auto-flip iconography.
- Treat ICU plural-category coverage as version/library-sensitive: verify the exact syntax and category set against current FormatJS/ECMA-402/CLDR references rather than assuming a fixed one/few/many split applies to every language.
Context7 Documentation Protocol
Before making any claim about ICU MessageFormat syntax, Intl API behavior, or a
specific i18n library's plural/formatting API, ground it via Context7:
- Call
resolve-library-idfor the library in scope (e.g.,formatjs,next-intl,react-intl,i18next) or the runtime spec area (ECMA-402/Intl). - Call
query-docsfor the specific syntax or API behavior before citing it (plural category names,selectordinalsyntax,Intl.PluralRulesoptions, locale-matching behavior). - Prefer official docs (FormatJS docs, TC39 ECMA-402 spec, MDN
Intl, Unicode CLDR) over memory — plural rule sets andIntloption names are locale- and spec-version-sensitive. - If Context7 has no coverage for a library in scope, fall back to the official docs
listed below and mark the claim
documentation-based (uncertain — no Context7 coverage). - Never invent ICU syntax,
Intlconstructor options, or CLDR plural-category names. Verified from Context7 (FormatJS docs) for this skill: the canonical CLDR plural categories arezero,one,two,few,many,other(not every language uses every category — e.g. English uses onlyone/other; Arabic uses all six), and ICU MessageFormat also supports exact-value matches via=N(e.g.=0 {No items}) layered alongside category matches.
References
Load these only when needed:
- Pluralization and ICU MessageFormat audit
— use only when auditing countable/orderable strings against CLDR plural categories
or reviewing ICU MessageFormat/
Intl.PluralRulesusage. - Intl formatting audit — use only when
reviewing date, number, currency, or list formatting for manual-string-building
defects vs correct
IntlAPI usage. - RTL and logical-property layout audit
— use only when reviewing
lang/dirattribute propagation, CSS logical properties, or directional-iconography readiness for RTL markets.
Response minimum
Return, at minimum:
- the target locale list driving the review (including any RTL or multi-plural-category locale considered),
- hardcoded-string inventory with file:line for user-facing countable/orderable/ concatenated content,
- pluralization audit against the actual CLDR categories required for the target locale(s), not just one/other,
- RTL/logical-CSS-property findings if RTL is in scope or roadmapped, including
lang/dirpropagation status, - explicit statement that translation itself was not performed by this skill and that findings are a structural-readiness audit, not a translation deliverable.
Files (vanguard-frontier-agentic)
-
references
-
intl-formatting-audit.md 5.5 KB
# Intl Formatting Audit Use this reference only when reviewing date, number, currency, or list formatting for manual-string-building defects versus correct `Intl` API usage. > Version note: `Intl` constructor options are ECMA-402-spec-version-sensitive and > browser/runtime-support-sensitive. Verify option names (e.g., `Intl.NumberFormat` > `style`/`currencyDisplay`/`notation`) against the current ECMA-402 spec or MDN before > asserting a given option is safe to use, and check the project's minimum supported > runtime for coverage gaps. ## What people get wrong The common bad assumption is: > "Formatting a date or currency amount is just string interpolation with the right > separators for each locale." That undercounts the problem. Locale-correct formatting is not just comma-vs-period-for-decimals — it includes: 1. **Digit systems** — not every locale uses Western Arabic numerals (0-9); some use native digit systems, which `Intl.NumberFormat` handles automatically when correctly invoked and manual formatting will not. 2. **Currency symbol placement and spacing** — varies by locale independent of the currency itself (e.g., `$100` vs `100 $` vs `100$`); hardcoding a symbol-prefix pattern breaks for locales that place it differently. 3. **Date component order and calendar system** — month/day/year order is not universal, and some locales/config combinations use non-Gregorian calendars. 4. **Grouping separators** — thousands separators vary (`,` / `.` / space / none) and are not simply swappable via find-and-replace on a fixed pattern. 5. **List formatting** ("A, B, and C" vs "A, B и C") — conjunction/list-joining rules are locale-specific and easy to miss because they're rarely tested. ## Non-negotiable review rules 1. **Any manually-constructed date string** (`` `${month}/${day}/${year}` ``, string-padding a day/month) is a structural defect for any codebase with more than one target locale — flag it regardless of whether the current output happens to look correct for the developer's own locale. 2. **Any manually-formatted currency/number string** (custom thousands-separator insertion, hardcoded `$` prefix, `toFixed(2)` treated as "locale-safe currency formatting") is a defect. `toFixed(2)` produces a numeric string with no locale awareness at all — flag it explicitly, since it is a very common false-safe pattern. 3. **Verify the locale passed into `Intl.*Format` constructors is the actual active application locale**, not a hardcoded `'en-US'` left over from initial development or scaffolding — a codebase can use `Intl.NumberFormat` correctly and still be non-localized if the locale argument is hardcoded. 4. **Currency formatting must specify `currency` explicitly and correctly per transaction/display context** (`Intl.NumberFormat(locale, { style: 'currency', currency: 'USD' })`) — do not accept a numeric-only format with a manually concatenated currency symbol as equivalent. 5. **Check for `Intl` availability assumptions on server vs client** — if locale/currency data availability differs between the runtime's `Intl` implementation and what's expected (e.g., a minimal/embedded runtime lacking full CLDR data), flag it as a verification item rather than assuming full coverage. ## Minimal safe audit flow 1. Grep for manual date-building patterns (string concatenation with `/`, `-`, month names arrays indexed by number) and manual currency/number formatting (`toFixed`, manual separator insertion, hardcoded currency symbols). 2. Grep for `Intl.DateTimeFormat`, `Intl.NumberFormat`, `Intl.ListFormat`, `Intl.PluralRules`, `Intl.RelativeTimeFormat` usage and confirm the locale argument is dynamic (sourced from application locale state), not a hardcoded literal. 3. For currency displays, confirm `style: 'currency'` and an explicit `currency` code are present, not a generic number format with a bolted-on symbol. 4. For any library wrapping `Intl` (FormatJS, `next-intl`, `i18next`), confirm it is actually invoked at the display sites in scope rather than assumed present because it exists in `package.json`. 5. Record each finding as file:line, the specific manual-formatting pattern found, and which `Intl` API should replace it. ## Adversarial checklist Before clearing formatting as "ready," answer these: - Is the locale argument passed to every `Intl.*Format` call dynamic, or is any of them hardcoded to a default locale? - Does currency formatting specify an explicit currency code per context, or is a single currency assumed globally? - Are there any `toFixed()` calls being treated as currency-safe? - Does date formatting handle non-Gregorian calendar locales if any target locale requires one, or is Gregorian assumed unconditionally? - Is list-joining ("A, B, and C") formatted with `Intl.ListFormat` or hardcoded English conjunction rules? If you cannot answer these, the formatting audit is incomplete — say so rather than declaring readiness. ## When to push back Push back if the user asks to: - "just add a locale-to-symbol lookup table instead of `Intl.NumberFormat`" — that reimplements a subset of CLDR data by hand and will drift from the real locale rules over time. - treat visual correctness in one locale (usually the developer's own) as proof of correctness for all target locales. - skip verifying the locale argument is dynamic because "it works in dev" — dev environments frequently default to a single hardcoded locale, masking the defect. -
pluralization-icu-messageformat.md 6.8 KB
# Pluralization and ICU MessageFormat Audit Use this reference only when auditing countable or orderable strings against CLDR plural categories, or reviewing ICU MessageFormat / `Intl.PluralRules` usage. > Version note: ICU MessageFormat syntax and the exact `Intl.PluralRules` option set > are spec/library-version-sensitive. Verify plural-category coverage and syntax > against current FormatJS docs, the TC39 ECMA-402 spec, and Unicode CLDR before > flagging or clearing a finding. ## What people get wrong The common bad assumption is: > "Pluralization is `count === 1 ? singular : plural`. Ship it." That is an English-only mental model, and it silently breaks every language that isn't English (and even breaks English's `zero` case: "0 items" reads oddly next to "no items" depending on style guide). Unicode CLDR defines up to **six** plural categories per locale — `zero`, `one`, `two`, `few`, `many`, `other` — and which subset a language uses is not predictable from English intuition: - English: `one`, `other` only. - Chinese, Japanese, Korean: `other` only (no grammatical number at all). - Arabic: all six categories (`zero`, `one`, `two`, `few`, `many`, `other`). - Polish, Russian: `one`, `few`, `many`, `other` (four categories, with nontrivial numeric-range rules for `few` vs `many`). - Welsh: all six categories, with different numeric boundaries than Arabic. A codebase hardcoded to a binary singular/plural split cannot express any of the non-English cases correctly, no matter how good the translation is — the *structure* is the defect, not the wording. ## Officially grounded ICU MessageFormat shape (verified via Context7 / FormatJS docs) ICU MessageFormat's `plural` argument type matches a numeric value against plural categories, with an escape hatch for exact-value overrides: ``` {itemCount, plural, =0 {You have no items.} one {You have # item.} other {You have # items.} } ``` - `=0`, `=1`, etc. match an exact numeric value regardless of plural category — use this for language-independent special cases like "no items" rather than relying on `zero` (which many languages, including English, do not use as a grammatical category). - `#` inside a plural branch is replaced with the formatted number itself; prefer it over re-interpolating the same variable, per the FormatJS `prefer-pound-in-plural` lint rule — re-interpolating `{itemCount}` inside the branch instead of `#` is a correctness/consistency smell to flag. - `selectordinal` uses the same category set for ordinal forms (1st/2nd/3rd/4th in English maps to `one`/`two`/`few`/`other`); do not conflate `plural` and `selectordinal` — ordinal and cardinal plural rules differ per locale. - `select` (non-numeric) is the correct construct for gendered or enumerated branching (e.g., `{gender, select, female {She} male {He} other {They}}`), not further string-concatenation hacks. ## Non-negotiable review rules 1. **Any string containing a runtime count and user-facing text is a plural-format candidate.** Concatenation (`count + " item" + (count !== 1 ? "s" : "")`) or template-literal interpolation of a raw count into a fixed-plurality string is a structural defect — flag it with file:line, not as a nit. 2. **Do not accept "we only ship English" as an exemption** if the readiness review's stated target locale list includes any non-English locale, or if the user is asking about vendor-readiness generically. Ask for the target locale list if it wasn't given — a plural defect invisible in English (one/other) can be a shipped-breaking bug in Arabic or Polish. 3. **Check that the plural/selectordinal library in use actually enforces locale-correct category resolution** (e.g., `Intl.PluralRules(locale).select(n)`, or a library — FormatJS/`react-intl`, `next-intl`, `i18next` with an ICU plugin — that delegates to it) rather than a hand-rolled category function. A hand-rolled `n === 1` check anywhere in the pipeline defeats CLDR-correct pluralization even if the message strings themselves use ICU syntax. 4. **Verify translators, not developers, control the plural branches per locale.** If the plural-branch structure is hardcoded per-language in application code instead of in the externalized message file, translators cannot add/remove categories for their locale (e.g., adding `few`/`many` branches for Polish) without a code change — flag this as a translation-workflow blocker, not just a formatting nit. 5. **selectordinal and plural must not be conflated** even when the surface English text looks similar; verify the intended semantics (count vs rank) match the ICU argument type used. ## Minimal safe audit flow 1. Grep for user-facing string literals interpolating a numeric variable directly (`` `${count} item` ``, `count + ' item'`, template literals with a count and no plural handling). 2. For each hit, confirm whether it flows through an ICU-aware formatter (`FormatMessage`/`t()` with a `plural` argument, `Intl.PluralRules`) or is raw concatenation. 3. For every ICU `plural`/`selectordinal` message found, confirm branch coverage against the CLDR categories actually required for the stated target locale list — not just whether `one`/`other` exist. 4. Confirm the count value passed in is a plain number (or correctly extracted from a formatted value) — passing an already-formatted string (`"1,000"`) into a plural selector breaks category resolution. 5. Record findings as file:line plus the specific CLDR category gap (e.g., "Polish requires `few`/`many` branches; message defines only `one`/`other`"). ## Adversarial checklist Before clearing a pluralization implementation as "ready," answer these: - What locale(s) actually need more than `one`/`other`, and does the target locale list include any of them? - Is the plural-category selection delegated to `Intl.PluralRules`/an ICU library, or hand-rolled? - Can a translator add a missing CLDR category for their locale without an engineering change? - Are ordinal (`selectordinal`) and cardinal (`plural`) uses distinguished correctly? - Does any message pass a pre-formatted (comma-grouped, localized) number into the plural selector instead of the raw numeric value? If you cannot answer these, the pluralization audit is incomplete — say so rather than declaring readiness. ## When to push back Push back if the user asks to: - "just ship one/other, we'll fix it if a translator complains" — that defers a structural defect into the vendor pipeline, which is exactly the expensive rework this skill exists to prevent. - treat a passing English-only test suite as proof of pluralization correctness — it cannot exercise categories English doesn't have. - hardcode per-locale plural logic in application code "to save time" — that blocks translators from being able to fix their own locale's grammar without a release. -
rtl-logical-properties-audit.md 7.2 KB
# RTL and Logical-Property Layout Audit Use this reference only when reviewing `lang`/`dir` attribute propagation, CSS logical properties, or directional-iconography readiness for RTL markets. > Version note: CSS logical-property support and the exact `dir="auto"` / `unicode-bidi` > interaction are spec/browser-support-sensitive. Verify current support and behavior > against the W3C Internationalization Techniques guidance and current MDN CSS logical > properties documentation before asserting a given property is safe to rely on. ## What people get wrong The common bad assumption is: > "RTL support means flipping the whole page with `dir="rtl"` on `<html>`, and CSS > `transform: scaleX(-1)` or a mirrored stylesheet handles the rest." That is incomplete in two directions: 1. **Physical CSS properties don't flip automatically.** `margin-left`, `padding-right`, `left`, `text-align: left` are all physical — they do not reverse when `dir` changes. A layout built entirely from physical properties will have `dir="rtl"` applied but visually remain LTR-positioned (padding stays on the same physical side), which is often worse than doing nothing, because it looks half-implemented. 2. **Not everything should mirror.** Numerals, code snippets, logos, and some icon families (e.g., a play button) are directionally invariant and should *not* flip; only directionally-meaningful content (arrows indicating navigation direction, "next/back" chevrons, progress bars implying forward motion) should mirror. A blanket `scaleX(-1)` on the whole page over-mirrors and under-mirrors simultaneously (it flips text glyphs and logos it shouldn't, while CSS engines already handle text shaping/bidi separately from that transform). ## Officially grounded shape (W3C Internationalization guidance) - The `dir` attribute belongs on `<html>` at minimum, and should be set from the active locale's script directionality, not hardcoded — the W3C guidance on the `dir` attribute and the CSS `direction` property covers this split: `dir` is the HTML-level semantic direction; `direction`/logical properties are the CSS-level mechanism that responds to it. - CSS logical properties (`margin-inline-start`, `margin-inline-end`, `padding-block-start`, `inset-inline-start`, `border-inline-end`, `text-align: start`/`end`) are defined relative to the *flow direction*, so a single stylesheet written in logical properties adapts to `dir="ltr"` or `dir="rtl"` without a mirrored stylesheet or a JS-driven layout flip. - Bidi (bidirectional text) isolation matters even in an LTR-primary UI that embeds RTL user content (e.g., a name or comment in Arabic inside an English UI) — unisolated bidi runs can visually corrupt adjacent punctuation/numbers. Use `dir` scoping or Unicode bidi-isolation characters/CSS `unicode-bidi: isolate` around user-generated content of unknown directionality, not just at the page root. ## Non-negotiable review rules 1. **Verify `dir` is set dynamically from the active locale's script, and actually reaches the rendered `<html>` element** — not just passed as a prop to a component that never forwards it to the DOM root. A `dir` value trapped in application state without reaching `<html dir>` does nothing for native browser bidi/text-alignment behavior. 2. **Grep for physical CSS properties in layout-critical rules** (`margin-left`, `margin-right`, `padding-left`, `padding-right`, `left`, `right`, `text-align: left`, `text-align: right`, `float: left`, `float: right`, `border-left`, `border-right`) — each is a candidate defect if RTL is in scope or roadmapped. Flag with file:line; do not silently "fix" — this skill reviews, it doesn't rewrite the codebase. 3. **Distinguish directionally-meaningful icons from directionally-invariant ones.** Flag navigation/progression icons (back/forward chevrons, "next step" arrows) that lack any RTL-mirroring mechanism (a `dir`-aware icon variant, CSS `transform: scaleX(-1)` scoped narrowly to that icon under `[dir="rtl"]`, or an icon library with built-in bidi awareness). Do not flag logos, brand marks, or numerals as needing mirroring. 4. **Check bidi isolation for embedded user-generated or mixed-direction content** (usernames, free-text fields, search queries) rendered inside a primarily single-direction UI — flag missing isolation (`unicode-bidi: isolate`, `dir="auto"` on the specific element, or equivalent) as a defect distinct from the page-level `dir` question. 5. **Do not accept a single manually-mirrored RTL stylesheet as a substitute for logical properties** if the codebase is under active development — a parallel mirrored stylesheet requires ongoing double-maintenance and drifts; flag it as a maintainability/regression risk even if it currently renders correctly, and recommend migration to logical properties as the structural fix. ## Minimal safe audit flow 1. Confirm where `dir` is set (locale config, i18n library, manual state) and trace whether it reaches `<html dir>` in the actual rendered output (grep component tree / root layout, not just the i18n config). 2. Grep CSS/CSS-in-JS/Tailwind classes for physical directional properties in layout-critical files; note density (a handful of instances vs. pervasive use) since that changes remediation scope and urgency. 3. Grep for directional icon usage (chevron/arrow component names, icon library imports for "next"/"back"/"forward"/"previous") and check for any `dir`-aware handling. 4. Grep for free-text/user-generated-content rendering sites and check for bidi isolation handling. 5. Record findings as file:line, the specific physical-property or missing-isolation instance, and whether RTL is currently shipped, roadmapped, or out of scope (which changes finding severity but not whether it's recorded). ## Adversarial checklist Before clearing layout as "RTL-ready," answer these: - Does `dir` actually reach `<html>`, or only live in component props/i18n state? - What fraction of layout-critical CSS uses physical vs. logical properties? - Which icons are directionally meaningful, and do any of them lack a mirroring mechanism? - Is there any user-generated or mixed-direction text rendered without bidi isolation? - Is RTL support implemented via a parallel mirrored stylesheet (maintenance/drift risk) or via logical properties (structural fix)? If you cannot answer these, the RTL audit is incomplete — say so rather than declaring readiness. ## When to push back Push back if the user asks to: - "just flip the whole page with `transform: scaleX(-1)` and call it RTL support" — that over-mirrors text/logos and under-addresses logical layout flow; it is not a substitute for `dir` + logical properties. - defer `dir`/logical-property work indefinitely because "we're not launching RTL markets yet" while simultaneously claiming full i18n/l10n readiness — readiness claims should state RTL scope explicitly (in scope, roadmapped, or explicitly out of scope) rather than being silently omitted. - treat a manually-mirrored RTL stylesheet as a permanent solution rather than a stopgap, when the codebase is under active development and will keep drifting.
-
-
metadata.json 1.1 KB
{ "id": "i18n-l10n-readiness-review", "name": "i18n/l10n Readiness Review", "type": "skill", "provider": "frontend", "harnesses": [ "codex", "claude-code", "cursor", "gemini", "kiro", "other" ], "summary": "Skill for auditing i18n architecture (ICU MessageFormat, Intl-based formatting, CLDR pluralization, RTL layout) so a frontend is structurally translation-ready before any translation vendor engagement.", "source_type": "adapted", "official_docs": [ "https://www.w3.org/International/", "https://cldr.unicode.org/", "https://tc39.es/ecma402/", "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl", "https://www.w3.org/International/articles/article-text-direction" ], "security_notes": "Static review only; never fabricates or inserts translated strings (that is a human/vendor task). Does not process real user-submitted locale/PII data.", "last_verified": "2026-07-02", "path": "skills/frontend/i18n-l10n-readiness-review", "author": "github: VincentChuWaiChow", "version": "0.1.0" } -
SKILL.md 6.9 KB
--- name: i18n-l10n-readiness-review description: Audit frontend code for internationalization readiness — externalized ICU MessageFormat strings, Intl-based date/number/currency/plural formatting, correct lang/dir attribute propagation, and RTL-safe CSS logical properties — before translation vendor engagement, with CLDR plural-rule detail loaded only when auditing countable strings. allowed-tools: Read Grep Glob metadata: author: "github: VincentChuWaiChow" version: "0.1.0" updated: "2026-07-02" category: compliance --- # i18n/l10n Readiness Review ## Purpose Teams routinely discover — after paying a translation vendor — that string concatenation can't express another language's word order, pluralization breaks outside English's one/other split, or RTL layouts mirror visually but not functionally. Fixing these after translation means re-engineering already-translated strings, re-running the vendor pipeline, and eating the schedule slip. This skill audits pluralization architecture (ICU MessageFormat / CLDR plural categories), `Intl`-based formatting, `lang`/`dir` attribute propagation, and RTL-safe layout so the codebase is structurally translation-ready *before* any string reaches a translator. It does not translate anything itself. ## When to use Use this skill when the user asks to: - audit a codebase for hardcoded/non-externalized user-facing strings, - review pluralization logic against CLDR plural categories for target locales, - review date/number/currency formatting for `Intl` API usage vs manual string-building, - review layout/CSS for RTL-market readiness, - assess overall i18n/l10n readiness before a new-market launch or vendor engagement. ## Lean operating rules - First establish the target locale list, including at least one locale with more than two CLDR plural categories (e.g., Arabic: 6, Polish: 4, Russian: 4) if any countable strings exist — English's one/other split hides most pluralization bugs. If the user has not named target locales, ask; do not assume English-only is sufficient for a "readiness" review. - Flag string concatenation for user-facing countable/orderable/gendered content as a structural defect, not a style nit — `"You have " + count + " items"` cannot be correctly localized without ICU MessageFormat (`{count, plural, ...}`) or an equivalent, because plural-category counts and word order both vary by locale. - Verify date/number/currency/plural values use `Intl.DateTimeFormat`, `Intl.NumberFormat`, or `Intl.PluralRules` (or a library wrapping them, e.g. FormatJS/`react-intl`, `next-intl`, `i18next` with ICU) rather than manual string building, hardcoded separators, or naive `Math.round`/string concatenation for currency. - Check that the `dir` attribute (and `lang`) actually reach the rendered document root (`<html lang dir>`) and stay in sync with the active locale, and that layout uses CSS logical properties (`margin-inline-start`, `padding-inline-end`, `inset-inline-start`) instead of physical properties (`margin-left`, `padding-right`, `left`) wherever an RTL-market launch is on the roadmap, even if RTL isn't shipped yet — retrofitting physical properties across a whole codebase later is expensive. - Do not treat the presence of a language switcher, an `i18next`/`next-intl` dependency, or a `locales/` translation-file structure as proof of readiness — a library being installed does not mean it is used correctly everywhere. Verify the underlying formatting/pluralization/layout mechanics independently, file by file. - Never author, insert, or "helpfully" translate actual copy into another language; that is the translation vendor's job. Only flag strings for extraction and hand off the inventory to whoever owns translation. - Verify icons/imagery conveying directionality (arrows, forward/back/next controls, progress indicators) have a documented RTL-mirroring plan when RTL is in scope — logical CSS properties fix layout flow but do not auto-flip iconography. - Treat ICU plural-category coverage as version/library-sensitive: verify the exact syntax and category set against current FormatJS/ECMA-402/CLDR references rather than assuming a fixed one/few/many split applies to every language. ## Context7 Documentation Protocol Before making any claim about ICU MessageFormat syntax, `Intl` API behavior, or a specific i18n library's plural/formatting API, ground it via Context7: 1. Call `resolve-library-id` for the library in scope (e.g., `formatjs`, `next-intl`, `react-intl`, `i18next`) or the runtime spec area (`ECMA-402`/`Intl`). 2. Call `query-docs` for the specific syntax or API behavior before citing it (plural category names, `selectordinal` syntax, `Intl.PluralRules` options, locale-matching behavior). 3. Prefer official docs (FormatJS docs, TC39 ECMA-402 spec, MDN `Intl`, Unicode CLDR) over memory — plural rule sets and `Intl` option names are locale- and spec-version-sensitive. 4. If Context7 has no coverage for a library in scope, fall back to the official docs listed below and mark the claim `documentation-based (uncertain — no Context7 coverage)`. 5. Never invent ICU syntax, `Intl` constructor options, or CLDR plural-category names. Verified from Context7 (FormatJS docs) for this skill: the canonical CLDR plural categories are `zero`, `one`, `two`, `few`, `many`, `other` (not every language uses every category — e.g. English uses only `one`/`other`; Arabic uses all six), and ICU MessageFormat also supports exact-value matches via `=N` (e.g. `=0 {No items}`) layered alongside category matches. ## References Load these only when needed: - [Pluralization and ICU MessageFormat audit](references/pluralization-icu-messageformat.md) — use only when auditing countable/orderable strings against CLDR plural categories or reviewing ICU MessageFormat/`Intl.PluralRules` usage. - [Intl formatting audit](references/intl-formatting-audit.md) — use only when reviewing date, number, currency, or list formatting for manual-string-building defects vs correct `Intl` API usage. - [RTL and logical-property layout audit](references/rtl-logical-properties-audit.md) — use only when reviewing `lang`/`dir` attribute propagation, CSS logical properties, or directional-iconography readiness for RTL markets. ## Response minimum Return, at minimum: - the target locale list driving the review (including any RTL or multi-plural-category locale considered), - hardcoded-string inventory with file:line for user-facing countable/orderable/ concatenated content, - pluralization audit against the actual CLDR categories required for the target locale(s), not just one/other, - RTL/logical-CSS-property findings if RTL is in scope or roadmapped, including `lang`/`dir` propagation status, - explicit statement that translation itself was not performed by this skill and that findings are a structural-readiness audit, not a translation deliverable.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.