Claude
Skills
Sign in
Back

software-localisation

Included with Lifetime
$97 forever

Production-grade i18n/l10n for React, Vue, Angular, and Next.js with ICU format and RTL support. Use when setting up or debugging localisation.

Web Devassets

What this skill does


# Software Localisation - Quick Reference

Production patterns for internationalisation (i18n) and localisation (l10n) in modern web applications. Covers library selection, translation management, ICU message format, RTL support, and CI/CD workflows.

**Snapshot (2026-02)**: i18next 25.x, react-i18next 16.x, react-intl 8.x, vue-i18n 11.x, next-intl 4.x, @angular/localize 21.x. Always verify current versions in the target repo (see Currency Check Protocol).

**Authoritative References**:
- [i18next Documentation](https://www.i18next.com/)
- [FormatJS/react-intl](https://formatjs.github.io/)
- [ICU Message Format](https://unicode-org.github.io/icu/userguide/format_parse/messages/)
- [MDN Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl)

## Quick Reference

| Task | Tool/Library | Command | When to Use |
|------|--------------|---------|-------------|
| React i18n | react-i18next | `npm i i18next react-i18next` | Most React apps, flexibility |
| React i18n (ICU) | react-intl (FormatJS) | `npm i react-intl` | ICU-first message catalog + tooling |
| Vue i18n | vue-i18n | `npm i vue-i18n` | Vue 3 apps |
| Angular i18n | @angular/localize | `ng add @angular/localize` | Angular apps |
| Next.js i18n | next-intl | `npm i next-intl` | Next.js App Router |
| Minimal bundle | LinguiJS | `npm i @lingui/core @lingui/react` | Bundle size critical |
| Type-safe | typesafe-i18n | `npm i typesafe-i18n` | TypeScript-first projects |
| String extraction | i18next-parser | `npx i18next-parser` | Extract keys from code |
| ICU linting | @formatjs/cli | `npx formatjs extract` | Validate ICU messages |

## Decision Tree: Library Selection

```text
Project requirements:
    │
    ├─ React/Next.js project?
    │   ├─ ICU-first message catalogs + FormatJS tooling?
    │   │   └─ react-intl (FormatJS)
    │   │
    │   ├─ Flexibility, plugins, lazy loading?
    │   │   └─ react-i18next
    │   │
    │   ├─ Bundle size critical?
    │   │   └─ LinguiJS (ICU syntax)
    │   │
    │   └─ TypeScript-first, compile-time safety?
    │       └─ typesafe-i18n
    │
    ├─ Vue/Nuxt project?
    │   └─ vue-i18n (Composition API)
    │
    ├─ Angular project?
    │   ├─ Built-in solution preferred?
    │   │   └─ @angular/localize (first-party, AOT support)
    │   │
    │   └─ Need i18next ecosystem?
    │       └─ angular-i18next (wrapper)
    │
    └─ Framework-agnostic / Node.js?
        └─ i18next core (works everywhere)
```

## Library Comparison

| Library | ICU Support | Lazy Loading | TypeScript | Best For |
|---------|-------------|--------------|------------|----------|
| react-i18next | Plugin/optional | Native | Good | Flexible, popular React choice |
| react-intl | Native | Manual | Good | ICU-first catalogs + tooling |
| LinguiJS | Native | Native | Excellent | Bundle-conscious apps |
| typesafe-i18n | Limited | Manual | Excellent | Compile-time key safety |
| vue-i18n | Native | Native | Good | Vue 3 apps |
| @angular/localize | Native | AOT | Native | Angular apps |

## Core Concepts

### Character Encoding (Critical)

**Always use UTF-8** across your entire stack to prevent text corruption:

```text
PASS Required: UTF-8 everywhere
- Database: utf8mb4 (MySQL) or UTF-8 (PostgreSQL)
- HTML: <meta charset="UTF-8">
- HTTP headers: Content-Type: text/html; charset=utf-8
- File encoding: Save all source files as UTF-8
- API responses: JSON with UTF-8 encoding
```

UTF-8 supports all Unicode characters including emojis, mathematical symbols, and all language scripts. Inconsistent encoding causes: corrupted characters (�), failed searches for accented names, and rejected international input.

### Translation Key Patterns

```typescript
// Flat keys (simple)
"welcome": "Welcome to our app"
"user.greeting": "Hello, {name}"

// Nested keys (organised)
{
  "user": {
    "greeting": "Hello, {name}",
    "profile": {
      "title": "Your Profile"
    }
  }
}

// Namespace separation (scalable)
// common.json, auth.json, dashboard.json
```

### ICU Message Format Essentials

```text
// Simple interpolation
"Hello, {name}!"

// Pluralisation
"{count, plural, one {# item} other {# items}}"

// Select (gender, category)
"{gender, select, male {He} female {She} other {They}} liked your post"

// Number formatting
"Price: {price, number, currency}"

// Date formatting
"Posted: {date, date, medium}"
```

### Locale Detection Strategy

```text
Priority order:
1. User preference (stored in profile/localStorage)
2. URL parameter or path (/en/about, ?lang=de)
3. Cookie (NEXT_LOCALE, i18next)
4. Accept-Language header
5. Default locale fallback
```

## Locale Quality Gates (SEO/AEO-Safe)

Use these gates for locale-routed, indexable pages (for example `/vi/*`, `/de/*`):

- Do not ship mixed-language content on a single locale route.
- Do not silently fall back to English for indexable page content.
- Keep metadata, breadcrumbs, and JSON-LD in the same locale as visible content.
- Prefer explicit missing-key handling in CI over runtime fallback in production SEO pages.
- If fallback is unavoidable, use locale-safe neutral copy and track missing keys.

### Missing Translation Decision Rule

- Marketing/SEO pages: block publish or replace with locale-safe copy; never inject English fragments.
- Product UI (non-indexed surfaces): fallback is acceptable with telemetry and follow-up fix.

## EN/RU Mixed-Language Regression Protocol

Use this when users report locale mixing (for example RU screens showing EN fragments).

### 1) Key-Parity Diff (Base vs Target Locale)

Compare key sets between source and target locale files; treat missing keys as release blockers on user-facing pages.

```bash
jq -r 'paths(scalars) | join(".")' app/src/messages/en/*.json | sort -u > /tmp/en.keys
jq -r 'paths(scalars) | join(".")' app/src/messages/ru/*.json | sort -u > /tmp/ru.keys
comm -23 /tmp/en.keys /tmp/ru.keys   # present in EN, missing in RU
```

### 2) Hardcoded-String Sweep in UI

Search for user-visible literals in components/pages that should use i18n keys.

```bash
rg -n '>[A-Za-z][^<]{2,}<' app/src -g '*.tsx'
rg -n '"[A-Za-z][^"]{2,}"' app/src -g '*.tsx' -g '*.ts'
```

### 3) Route-Level Locale Smoke Check

For target locale routes, verify rendered text is consistently localized and no fallback EN fragments appear in critical UI regions.

### 4) Engine Text Audit

Ensure computed/engine-driven messages (not just static labels) pass through translation mapping instead of returning raw EN strings.

### 5) CI Gate

Add a lightweight gate that fails when:
- required target-locale keys are missing,
- newly added UI literals bypass the i18n layer,
- locale-routed smoke pages include mixed-language sentinel terms.

### Runtime Constraint Note

If an agent runtime has no external translation connector, do not block on auto-translation tools. Enforce key completeness + placeholder strategy, then backfill approved translations in a separate tracked pass.

## Engine Output i18n (`_i18n` Metadata Pattern)

Server-generated engine content (astrology calculations, ML outputs, computed reports) needs localisation without making the engine locale-aware.

### Pattern

- Engine attaches `_i18n: { key: "transits.neptune_trine.description", params: { planet: "Neptune" } }` alongside the English string
- Client resolves: `_i18n ? t(_i18n.key, _i18n.params) : englishFallback`
- Backward-compatible: old cached responses without `_i18n` gracefully degrade to English
- Server caches once; every locale resolves on the client
- Use `t.has(key)` before `t(key)` for graceful fallback

| Pattern | Status | Why |
|---------|--------|-----|
| `{ text: "Neptune trine Jupiter", _i18n: { key: "transits.neptune_trine", params: { p1: "Neptune", p2: "Jupiter" } } }` | PASS | Client resolves per locale; server caches once |
| `{ text_en: "...", text_ru: "...", text_de: "..." }` | FAIL | Server bloat, cache per locale |
| `t(meaning.theme)` | FAIL | Using raw engine output as translation key |
| `t.

Related in Web Dev