Skip to main content

At most one i18n library

ab-000235 · ai-slop-code-drift.convention-drift.dual-i18n-library
Severity: infoactive

Why it matters

Two i18n libraries fragment translation keys across two message-catalog formats, double the translation-team workflow, and produce two pluralization strategies that disagree on edge cases (zero counts, languages with dual/trial grammatical number). Translators receive exports from both systems and inevitably miss keys, so some UI strings render in the user's language while others fall back to the source locale. Build output ships both runtimes to every locale bundle.

Severity rationale

Info because the impact is translation-workflow drag and partial-translation bugs, not functional or security failures.

Remediation

Pick one based on your framework: next-intl for Next.js App Router, react-i18next for plain React, @lingui/react if you want compile-time extraction. Migrate call sites with grep -rl "from 'react-i18next'" src/, consolidate message catalogs under src/i18n/messages/ (one file per locale), and remove the loser:

npm uninstall react-i18next i18next i18next-browser-languagedetector

Update your translation export script in scripts/i18n/ to emit a single catalog format.

Detection

  • ID: ai-slop-code-drift.convention-drift.dual-i18n-library

  • Severity: info

  • What to look for: Apply the three-condition rule against this exact i18n allowlist: next-intl, next-i18next, react-i18next, i18next, @lingui/core, @lingui/react, react-intl, formatjs, paraglide-js, @formatjs/intl. Treat i18next + react-i18next as a single unit. Count all i18n libraries that meet the three conditions (at least 3 importing files each).

  • Pass criteria: 0 or 1 i18n libraries from the allowlist actively used. Report even on pass: "Canonical i18n library: [name or 'none'] ([N] importing files)."

  • Fail criteria: 2 or more i18n libraries from the allowlist meet all three conditions (at least 1 non-escape-hatch importing file).

  • Skip (N/A) when: 0 i18n libraries from the allowlist appear in RUNTIME_DEPS.

  • Detail on fail: "2 active i18n libraries: 'next-intl' (4 files) AND 'react-i18next' (3 files). Pick one for translation handling."

  • Remediation: Two i18n libraries means translations split across systems, two key formats, two pluralization rules. Pick one and migrate:

    # Inventory which library each translation key uses
    grep -rl "from 'next-intl'" src/
    grep -rl "from 'react-i18next'" src/
    
    # Pick the one with more usage and convert the rest
    npm uninstall react-i18next i18next
    

Taxons

History