next-intl-validator
v1.1.0
Published
CLI tool that validates next-intl translations by detecting mismatches between JSON translation files and actual code usage
Maintainers
Readme
next-intl-validator
CLI tool that validates next-intl translations by detecting mismatches between JSON translation files and actual code usage.
It scans your source code for translation function calls (useTranslations, getTranslations, etc.), compares them against your JSON translation files, and reports:
- Unused keys — defined in JSON but never referenced in code
- Missing keys — used in code but not defined in JSON
- Dynamic keys — template literals like
t(`headers.${id}`)that cover a prefix
Install
npm install -g next-intl-validator
# or run directly
npx next-intl-validator [project-path] [options]Quick Start
# Point it at your project — interactive mode guides you through
npx next-intl-validator ~/my-projectOn first run (no config file), it will:
- Auto-discover namespaces from
global.d.tsor the filesystem - Prompt you to select which namespaces to validate
- Run validation and print results
- Optionally save a
.i18n-validatorrc.jsonconfig file — so next time you can run with--configand skip the prompts entirely
Commands
There is a single command — you run it with a project path (defaults to .):
next-intl-validator [project-path] [options]Options
| Flag | Description |
|------|-------------|
| -c, --config <path> | Use a config file — skips interactive prompts (CI mode) |
| -a, --all | Show all keys with their usage locations, not just mismatches |
| -o, --output <dir> | Save the report to a directory |
| -g, --global-dts <path> | Path to global.d.ts for namespace discovery |
| -t, --tsconfig <path> | Path to tsconfig.json for resolving path aliases |
| -d, --discover | List discovered namespaces and exit (no validation) |
| -V, --version | Print version |
| -h, --help | Print help |
Examples
# Interactive mode — auto-discovers namespaces, prompts for selection
next-intl-validator ~/my-project
# CI mode — uses config file, no prompts
next-intl-validator ~/my-project --config .i18n-validatorrc.json
# Show all keys with their source locations
next-intl-validator ~/my-project --config .i18n-validatorrc.json --all
# Save report to logs/ directory
next-intl-validator ~/my-project --config .i18n-validatorrc.json --output logs
# Just list discovered namespaces (useful for debugging)
next-intl-validator ~/my-project --discover
# Use a custom tsconfig for path alias resolution (monorepo)
next-intl-validator ~/my-project --tsconfig packages/app/tsconfig.jsonOutput
Summary
────────────────────────────────────────
Total keys: 753
Used: 567
Unused: 186
Missing: 0
✓ pages.users: 46 defined, 46 used
⚠ shared: 421 defined, 235 used, 186 unused
✗ common.actions.previous
(unused)
✓ error: 7 defined, 7 usedWith --all, shows where each key is used:
✓ page-header.title
features/dashboard/users/components/pageHeader.tsx:12
✓ delete-user-dialog.success
features/dashboard/users/hooks/useDeleteUser.ts:32Detected Patterns
The code scanner recognizes these translation usage patterns:
- Client-side:
const t = useTranslations('users')→t('key') - Renamed variables:
const tOther = useTranslations('other')→tOther('key')(any variable name is tracked) - Server-side:
const t = await getTranslations('ns')→t('key') - Nested namespaces:
useTranslations('users.table')→ resolves totable.*inusersJSON - Template literals:
t(`headers.${id}`)→ dynamic prefix coversheaders.* - Method calls:
t.rich('key'),t.markup('key'),t.raw('key') - Type annotations:
t: ReturnType<typeof useTranslations<'ns'>> - Type aliases:
type TranslateFn = ReturnType<typeof useTranslations<'ns'>> - Promise callbacks:
getTranslations('ns').then((t) => t('key')) - Destructured params:
({ t }: Props)with typeduseTranslationsproperty
Configuration
Create .i18n-validatorrc.json in your project root:
{
"messagesDir": "src/messages/en",
"srcDir": "src",
"namespaces": [
{ "name": "pages.users", "jsonPath": "pages/users.json" },
{ "name": "shared", "jsonPath": "shared.json" }
],
"defaults": {
"showAll": false,
"outputDir": "logs"
}
}| Field | Type | Default | Description |
|-------|------|---------|-------------|
| projectPath | string | current directory | Absolute or ~/-relative path to the project |
| messagesDir | string | src/messages/en | Path to translation JSON files (relative to project root) |
| srcDir | string | src | Path to source code to scan (relative to project root) |
| namespaces | array | auto-discovered | List of { name, jsonPath } namespace mappings |
| defaults.showAll | boolean | false | Show all keys, not just mismatches |
| defaults.outputDir | string | — | Directory to save reports |
Config files are loaded via cosmiconfig, so you can also use .i18n-validatorrc, .i18n-validatorrc.js, i18n-validator.config.js, or a "i18n-validator" key in package.json.
Without a config file, interactive mode auto-discovers namespaces from global.d.ts (if present) or the filesystem and prompts for selection.
Path Aliases
The tool reads compilerOptions.paths from your tsconfig.json to resolve import aliases in global.d.ts. For example, if your global.d.ts uses @/messages/en/shared.json, and your tsconfig maps @/* to ./src/*, the tool resolves it automatically.
In monorepos where the tsconfig isn't at the project root, use --tsconfig to point to the right file.
CI/CD
Using in CI
# Install and run with a config file (no interactive prompts)
npx next-intl-validator . --config .i18n-validatorrc.jsonThe process exits with code 1 if there are missing or unused keys — use this to fail CI builds.
Limitations
- Does not follow cross-file type aliases (only same-file)
- Dynamic keys with variable interpolation mark the prefix as "used" (conservative)
- No watch mode yet
- No auto-fix capability
License
MIT
