The static analyze tool for finding, marking and removing unused and missing i18n translations in your JavaScript project.
With npm:
npm install --save-dev i18n-unused
With yarn:
yarn add --dev i18n-unused
Add config i18n-unused.config.js to your root folder:
/** @type {import('i18n-unused').RunOptions} */
module.exports = {
localesPath: 'src/locales',
srcPath: 'src',
};
For ES-Modules (esm) use i18n-unused.config.cjs. You can also use the .json with no support for callbacks.
| Option name | Description |
Required | Type | Default value |
|---|---|---|---|---|
| localesPath | path to search for locales | yes | string | - |
| localesExtensions | allowed file extensions for locales | no | string[] | if not set localeNameResolver: ['json'] |
| localeNameResolver | file name resolver for locales | no | RegExp, (name: string) => boolean | - |
| customChecker | function to check if a key is used, if so the key should be removed from translationsKeys | no | fn, (matchedKeys: Set<string>, translationsKeys: string[] => void) | A defined validations will be applied |
| localeFileParser | resolve locale imports, for example if you use named imports from locales files, just wrap it to your own resolver | no | (module) => module | fn, return module.default or module |
| localeFileLoader | load the locale file manually (e.g. for using your own parser) | no | (filePath) => object | - |
| srcPath | path to search for translations | no | string | '' (same as run folder) |
| srcExtensions | allowed file extensions for translations | no | string[] | ['js', 'ts', 'jsx', 'tsx', 'vue'] |
| ignorePaths | ignored paths, eg: ['src/ignored-folder'], should start similarly srcPath |
no | string[] | - |
| translationKeyMatcher | matcher to search for translation keys in files | no | RegExp | RegExp, match $_, $t, t, $tc, tc and i18nKey |
| excludeKey | doesn't process translations that include passed key(s), for example if you set excludeKey: '.props.', script will ignore Button.props.value. |
no | string, string[] | - |
| ignoreComments | Ignore code comments in src files. | no | boolean | false |
| marker | special string to mark unused translations, it'll added via mark-unused |
no | string | '[UNUSED]' |
| gitCheck | show git state change tree | no | boolean | false |
| context | use i18n context, (eg: plurals) | no | boolean | true |
| flatTranslations | use flat translations, (eg: Flat JSON) | no | boolean | false |
| translationSeparator | separator for translations using in code | no | string | '.' |
| translationContextSeparator | separator for i18n context (see context option) |
no | string | '_' |
| translationContextMatcher | matcher to search for context endings | no | RegExp | RegExp, match zero, one, two, few, many, other, male, female, 0, 1, 2, 3, 4, 5, plural, 11 and 100 |
| missedTranslationParser | parser for ejecting value from translationKeyMatcher matches |
no | RegExp, (v: string) => string | RegExp, match value inside rounded brackets |
| localeJsonStringifyIndent | json indent value for writing json file, either a number of spaces, or a string to indent with. (i.e. 2, 4, \t) |
no | string , number | 2 |
Get help:
i18n-unused -h
Display unused translations:
i18n-unused display-unused
Display unused translations for mashpie/i18n-node:
i18n-unused display-unused --translation-key-matcher '/(?:[$ .](__))\(.*?\)/gi'
Mark unused translations via [UNUSED] or marker from config (works only with json for now):
i18n-unused mark-unused
Remove unused translations (works only with json for now):
i18n-unused remove-unused
Sync translations (works only with json for now):
i18n-unused sync <source> <target>
Display missed translations:
i18n-unused display-missed
If you use tool in code, you can run async function collectUnusedTranslations:
import { collectUnusedTranslations } from 'i18n-unused';
const handleTranslations = async () => {
const unusedTranslations = await collectUnusedTranslations(
localesPaths, // paths to locale files
srcFilesPaths, // paths to src files
{
localeFileParser: (module) => module, // optional, resolver for module
excludeTranslationKey: ['.props.'], // optional, special string or sting[] to exclude flat translations
},
);
};
It'll return to you follow collect:
{
translations: [
{
localePath: 'locale_file_path',
keys: ['unused_key'],
count: 1,
},
],
totalCount: 1,
}
If you use tool in code, you can run async function collectMissedTranslations:
import { collectMissedTranslations } from 'i18n-unused';
const handleTranslations = async () => {
const missedTranslations = await collectMissedTranslations(
localesPaths, // paths to locale files
srcFilesPaths, // paths to src files
{
localeFileParser: (module) => module, // optional, resolver for module
excludeTranslationKey: ['.props.'], // optional, special string or sting[] to exclude flat translations
translationKeyMatcher: /(?:[$ .](_|t|tc))\(.*?\)/ig, // optional, match translation keys in files
},
);
};
You'll get the following collection:
{
translations: [
{
filePath: 'src_file_path',
staticKeys: ['missed_key'], // keys without ${} syntax
dynamicKeys: ['missed_key'], // keys with ${} syntax
staticCount: 1,
dynamicCount: 1,
},
],
totalStaticCount: 1,
totalDynamicCount: 1,
}
Available as async function generateFilesPaths:
import { generateFilesPaths } from 'i18n-unused';
const handleFilesPaths = async () => {
// return array of full paths to files
const filesPaths = await generateFilesPaths(
srcPath, // path where search files, example: 'src/locales'
{
srcExtensions, // allowed file extensions, example: ['js', 'ts']
fileNameResolver, // resolver for file name, see more info about 'localeNameResolver' option
},
);
};
Next actions return unusedTranslations:
displayUnusedTranslationsremoveUnusedTranslationsmarkUnusedTranslationsNext actions return missedTranslations:
displayMissedTranslationsIf the tool helped you, please rate it on github, thx. I'll be glad to your PRs =)
MIT License. Maxim Vishnevsky