Automatically scans your Next.js project's source files to manage internationalization (i18n) translation keys. It keeps your translation dictionaries up-to-date by extracting new keys, removing unused ones, and optionally partitioning keys into separate client and server dictionaries.
Note
Primarily designed for use with next-intl, this plugin can technically be adapted for other i18n libraries or frameworks that share a similar dictionary structure and access pattern in code.
- Automatic Extraction: Scans your project's source code for i18n keys.
- Namespace Support: Handles nested i18n keys organized into namespaces for structured translations.
- Dictionary Syncing: Automatically updates JSON dictionaries with new translation keys.
- Unused Keys Handling: Warns or removes unused keys.
- Client/Server Partitioning: Separates translation keys into client-side and server-side bundles.
- Debounced Scanning: Efficiently handles rapid file changes.
- Suppression Escape Hatch: Silence warnings for specific unsupported expression kinds while native support is pending.
Install the package via npm, yarn or pnpm:
npm install intl-watcher
# or
yarn add intl-watcher
# or
pnpm add intl-watcherWrap your Next.js configuration with the provided createIntlWatcher function:
// next.config.ts
import { createIntlWatcher } from 'intl-watcher'
const withIntlWatcher = createIntlWatcher({
dictionaryPaths: ['./i18n/en.json', './i18n/de.json'],
})
export default withIntlWatcher({
reactStrictMode: true,
// other Next.js config options...
})For use cases where you need to perform a one-time sync without file watching (e.g., in CI/CD pipelines, custom build scripts, or pre-commit hooks), use the syncTranslationKeys function:
// scripts/sync-translations.ts
import { syncTranslationKeys } from 'intl-watcher'
syncTranslationKeys({
dictionaryPaths: ['./i18n/en.json', './i18n/de.json'],
// ... other options
})Run this script manually or as part of your build process:
# Using ts-node
npx ts-node scripts/sync-translations.ts
# Using tsx
npx tsx scripts/sync-translations.ts
# In package.json scripts
{
"scripts": {
"sync-translations": "tsx scripts/sync-translations.ts"
}
}- CI/CD Validation: Ensure translation keys are synchronized before deployment
- Pre-commit Hooks: Automatically update dictionaries when committing changes
- Custom Build Steps: Integrate into existing build pipelines
- Testing: Programmatically verify translation coverage
The following options apply to both createIntlWatcher and syncTranslationKeys:
- Type:
string[] - Description: Paths to JSON dictionary files for each language. These files will be managed and kept in sync with your source.
- Type:
(key: string) => string - Default:
(key) => `[NYT: ${key}]`
- Description: Function that generates a default translation for new keys.
- Type:
boolean - Default:
false - Description: When true, removes keys no longer found in source files; otherwise emits warnings.
- Type:
number - Default:
500 - Description: Delay in milliseconds before re‑scanning after file changes.
- Type:
string - Default:
tsconfig.json - Description: Path to
tsconfig.jsonfor project file resolution.
- Type:
string[] - Default:
['./src'] - Description: Paths that the plugin watches to trigger rescans.
This does not change which files belong to your TypeScript project; that is controlled by
tsconfig.jsonviatsConfigFilePath.
- Type:
boolean - Default:
true - Description: Use tab characters for indentation. When
false, spaces will be used instead (seetabWidth).
- Type:
number - Default:
4 - Description: Number of spaces per indentation level. Only applies when
useTabsisfalse.
- Type:
string[] - Default:
[] - Description: Expression kind names for which the unsupported-expression diagnostic is silenced.
Each entry must match a kind name as reported in the warning — for example
'ConditionalExpression'or'CallExpression'. Any entry that does not suppress at least one warning during a scan will itself emit a warning, prompting you to remove the stale entry.
Note
This option is intended as a temporary escape hatch while native support for a given expression kind is pending. Before adding a kind here, consider opening a feature request so that support can be added properly.
- Type:
false - Default:
false - Description: Default mode where keys are not split.
- Type:
string[] - Default:
['useTranslations', 'getTranslations'] - Description: Translation function name(s) to scan for keys.
- Type:
true - Description: Enables splitting translation keys into separate client and server bundles.
- Type:
{ clientFunction?: string; serverFunction?: string } - Default:
{ clientFunction: 'useTranslations', serverFunction: 'getTranslations' }
- Description: Function names to use for extracting client vs server translation keys.
When applyPartitioning is enabled, the plugin generates separate dictionaries for client and server bundles.
For example:
locales/
├── en.json
├── en.client.json
└── en.server.json
This enables optimized bundle sizes and clearer separation of translations by environment.
See .github/CONTRIBUTING.md, then .github/DEVELOPMENT.md.
Thanks! 💖
Christian Ivicevic 💻 🖋 📖 🤔 🚇 🚧 📆 🔧 |
Mark Lenser 🤔 |
