Claude Cursor GitHub Copilot Skill

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

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download vincentchuwaichow-vanguard-frontier-agentic-skills_frontend_i18n-l10n-readiness-review-febe32a.zip · 12 KB
Part of vincentchuwaichow/vanguard-frontier-agentic — 293 skills

Install

skills CLI npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/frontend/i18n-l10n-readiness-review
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
Git 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 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 — use only when auditing countable/orderable strings against CLDR plural categories or reviewing ICU MessageFormat/Intl.PluralRules usage.
  • Intl formatting audit — 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 — 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.
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.

No comments yet.

Reviews (0)

No reviews yet.

Related