@yaos-git/i18n-kit
v226.0.1
Published
Universal i18n linting CLI and TUI workspace editor
Downloads
74
Maintainers
Readme
Table of Contents
Getting Started
Features
Development
Overview
i18n-kit treats internationalization as a data-integrity problem. Instead of just checking "key exists", it parses ICU MessageFormat strings from your base locale, extracts grammatical contracts (variables, plural branches, string length), and validates every translation against those contracts.
What Makes This Project Unique
- Contract-Based Validation: Extracts variables, plural branches, and length buckets from the base locale — translations must satisfy the same grammatical contract
- CLDR-Aware Plural Checking: Uses
Intl.PluralRulesto validate that Arabic has all 6 categories, not justone/other - Expansion Guard: Detects translations that are too long for their UI context based on configurable thresholds per length bucket
- Dual Binary: Lean CLI for CI/CD pipelines + full React/Ink TUI for interactive editing
Installation
# Install globally from npm
npm install -g @yaos-git/i18n-kit
# Or install as a dev dependency
npm install -D @yaos-git/i18n-kitFrom Source
# Clone the repository
git clone https://github.com/YAOSGit/i18n-kit.git
cd i18n-kit
# Install dependencies
npm install
# Build the project
npm run build
# Link globally (optional)
npm linkQuick Start
# Initialize a config file
i18n-kit init
# Lint your locale files
i18n-kit check
# View per-locale health scores
i18n-kit health
# Generate a pseudo-locale file
i18n-kit pseudoCLI Usage
i18n-kit check [--config <path>] [--fix] Lint locale files against grammatical contracts
i18n-kit health [--config <path>] Show per-locale health scores
i18n-kit pseudo [--config <path>] [-o <path>] Generate pseudo-localized locale file
i18n-kit init Scaffold an i18n-kit.config.ts file
i18n-kit --help, -h Show help message
i18n-kit --version, -v Show version informationExit Codes
| Code | Meaning |
|------|---------|
| 0 | No errors found |
| 1 | Errors found in locale files |
| 2 | Config loading failed |
Examples
# Check with default config (i18n-kit.config.ts)
i18n-kit check
# Check with custom config path
i18n-kit check --config ./config/i18n.config.ts
# Auto-fix ghost keys
i18n-kit check --fix
# Output health as bar chart
i18n-kit health
# Generate pseudo-locale to custom path
i18n-kit pseudo -o ./locales/pseudo.json6 Built-in Rules
| Rule | Default | Description |
|------|---------|-------------|
| variable-parity | error | Ensures all {variables} from the base locale appear in translations |
| icu-syntax | error | Validates ICU MessageFormat syntax is parseable |
| plural-completeness | error | Checks all CLDR-required plural categories are present per locale |
| expansion-guard | warning | Detects translations that exceed length thresholds for their bucket |
| ghost-keys | warning | Finds keys in translations that don't exist in the base locale |
| missing-keys | info | Reports base locale keys missing from translations |
Three-Tier Severity Cascade
Severity is resolved with three tiers of precedence:
- Per-key override —
overrides['key'].severity['rule'] - Global rule config —
rules['rule'] - Rule default — hardcoded in the rule definition
export default defineConfig({
baseLocale: 'en',
locales: './locales/*.json',
rules: {
'ghost-keys': 'error', // Global: promote to error
},
overrides: {
'legacy.key': {
severity: { 'ghost-keys': 'off' }, // Per-key: suppress
},
},
});Grammatical Contracts
For each key in the base locale, i18n-kit extracts a grammatical contract:
- Variables:
{name},{count}— the ICU arguments the message expects - Plural Branches:
one,other,few,many— the categories the message defines - Length Bucket:
short(≤10 chars),medium(≤40),long(>40) — for expansion thresholds
Translations are validated against these contracts, not just checked for existence.
Pseudo-Localization
The pseudo command generates a pseudo-locale file that transforms all base strings using a Normalize → Transliterate → Replace pipeline:
English: "Welcome, {name}!" → "[~ ₩3|(0₥3, {name}! ~]"
French: "Bienvenue, {name}!" → "[~ 813ñ√3ñµ3, {name}! ~]"
Japanese: "ようこそ" → "【~ @8( ~】"- ICU variables and plural/select structures are never transformed
- Script-aware wrappers:
[~ ~]for Latin,«~ ~»for RTL,【~ ~】for CJK
Health Scoring
Per-locale health scores are computed from weighted diagnostics:
| Severity | Penalty |
|----------|---------|
| error | 5 points |
| warning | 2 points |
| info | 0.5 points |
Score = max(0, 100 - total penalty)
i18n-kit health
# Output:
# de ████████████████████████████░░ 95.0%
# pt ████████████████████░░░░░░░░░░ 83.5%
# ar ██████████████░░░░░░░░░░░░░░░░ 62.0%TypeScript Config
i18n-kit uses a TypeScript config file with a defineConfig helper for type-safe configuration:
import { defineConfig } from '@yaos-git/i18n-kit';
export default defineConfig({
baseLocale: 'en',
locales: './locales/*.json',
rules: {
'variable-parity': 'error',
'expansion-guard': 'warning',
'ghost-keys': 'off',
},
expansion: {
short: { maxChars: 10, threshold: 1.0 },
medium: { maxChars: 40, threshold: 0.4 },
long: { threshold: 0.15 },
},
overrides: {
'marketing.hero': { expansion: 'ignore' },
},
});Also supports JSON and YAML config files (i18n-kit.config.json, i18n-kit.config.yaml).
Available Scripts
Development Scripts
| Script | Description |
|--------|-------------|
| npm run dev | Run TypeScript checking + test watcher concurrently |
| npm run dev:typescript | Run TypeScript type checking in watch mode |
| npm run dev:test | Run Vitest in watch mode |
Build Scripts
| Script | Description |
|--------|-------------|
| npm run build | Bundle CLI and TUI with esbuild |
Lint Scripts
| Script | Description |
|--------|-------------|
| npm run lint | Run type checking, linting, formatting, and audit |
| npm run lint:check | Check code for linting issues with Biome |
| npm run lint:fix | Check and fix linting issues with Biome |
| npm run lint:format | Format all files with Biome |
| npm run lint:types | Run TypeScript type checking only |
| npm run lint:audit | Run npm audit |
Testing Scripts
| Script | Description |
|--------|-------------|
| npm test | Run all tests (unit, react, types, e2e) |
| npm run test:unit | Run unit tests |
| npm run test:react | Run React component tests |
| npm run test:types | Run type-level tests |
| npm run test:e2e | Build and run end-to-end tests |
Tech Stack
Core
- React 19 — UI component library
- Ink 6 — React for CLIs
- TypeScript 5 — Type-safe JavaScript
- @formatjs/icu-messageformat-parser — ICU MessageFormat parsing
- Zod — Runtime schema validation
- Commander — CLI argument parsing
- picomatch — Glob pattern matching
Build & Development
UI
- Chalk — Terminal string styling
- @yaos-git/toolkit — Shared TUI components and build config
Project Structure
i18n-kit/
├── src/
│ ├── app/ # Application entry points
│ │ ├── cli.ts # CLI entry point (Commander)
│ │ ├── tui.tsx # TUI entry point (Ink)
│ │ ├── app.tsx # Main TUI layout
│ │ ├── theme.ts # TUI theme
│ │ └── commands.ts # TUI command definitions
│ ├── commands/ # CLI commands
│ │ ├── check.ts # i18n-kit check
│ │ ├── health.ts # i18n-kit health
│ │ ├── pseudo.ts # i18n-kit pseudo
│ │ └── init.ts # i18n-kit init
│ ├── core/ # Business logic (shared CLI + TUI)
│ │ ├── ConfigLoader/ # TypeScript config loading via jiti
│ │ ├── FileDiscovery/ # Glob-based locale file resolution
│ │ ├── Parser/ # JSON → ICU AST parsing + flatten
│ │ ├── ContractExtractor/ # Base locale → grammatical contracts
│ │ ├── RuleEngine/ # Rule registry + severity cascade
│ │ │ └── rules/ # 6 built-in rules
│ │ ├── Validator/ # Pipeline orchestrator
│ │ ├── Reporter/ # Terminal + JSON output
│ │ ├── HealthScorer/ # Weighted diagnostic scoring
│ │ └── PseudoLocalizer/ # Script-aware pseudo-localization
│ ├── types/ # Core type definitions
│ │ ├── Severity/ # Severity + DiagnosticSeverity
│ │ ├── Config/ # I18nKitConfig + ResolvedConfig
│ │ ├── Workspace/ # Workspace + LocaleData + LocaleEntry
│ │ ├── Contract/ # GrammaticalContract + PluralBranch
│ │ ├── Diagnostic/ # Diagnostic + AutoFix
│ │ └── Rule/ # Rule + RuleContext
│ ├── components/ # TUI React components
│ │ ├── StatusBar/ # Header bar with diagnostics summary
│ │ ├── KeyTree/ # Filterable key list
│ │ ├── FilterPanel/ # Diagnostic filter selector
│ │ ├── KeyDetail/ # Per-key translation cards
│ │ ├── TranslationCard/ # Single locale translation display
│ │ ├── IcuEditor/ # ICU structure viewer
│ │ ├── FakerLab/ # Variable faker preview
│ │ ├── PseudoPreview/ # Pseudo-localization preview
│ │ └── HealthDashboard/ # Per-locale health bar chart
│ ├── providers/ # React context providers
│ │ ├── WorkspaceProvider/ # Validation state
│ │ ├── NavigationProvider/ # Key selection + tab state
│ │ ├── EditorProvider/ # Dirty entry tracking
│ │ └── FakerProvider/ # Variable generation
│ └── hooks/ # Re-exported provider hooks
├── e2e/ # End-to-end CLI tests
│ ├── fixtures/ # Test locale fixtures
│ └── *.e2e.ts # CLI command tests
├── examples/ # Usage examples
│ ├── basic/ # Minimal setup
│ ├── custom/ # Custom rules and overrides
│ └── integration/ # CI/CD integration
└── dist/ # Built output
├── cli.js # Headless CLI binary
└── tui.js # React/Ink TUI binary