react-i18next-scanner
v0.1.10
Published
CLI tool to scan React projects for missing and unused react-i18next translation keys
Maintainers
Readme
react-i18next-scanner
CLI tool for React / react-i18next projects.
It helps you:
- find missing translation keys
- find unused translation keys
- detect dynamic translation usages
- protect possibly used dynamic keys from removal
- generate reports
- sync missing keys
- remove definitely unused keys
- sort translation JSON files
Quick Start
1. Install
npm install -D react-i18next-scanneror
yarn add -D react-i18next-scanner2. Create config
npx react-i18next-scanner initThis will create a config file for your project.
Supported config formats:
i18n-scanner.config.js
i18n-scanner.config.cjs
i18n-scanner.config.mjs
.tsconfig is not supported yet.
3. Run scan
npx react-i18next-scanner scanThe scanner will check your source files and translation JSON files.
Reports will be created inside:
reports/Example Config
export default {
srcPaths: ["./src/**/*.{js,jsx,ts,tsx}"],
jsonDir: [
"./src/i18n/locales/translations.en.json",
"./src/i18n/locales/translations.es.json",
],
sortJsonFiles: [
"./src/i18n/locales/translations.en.json",
"./src/i18n/locales/translations.es.json",
],
outputDir: "./reports",
syncMissing: false,
removeUnused: false,
sortJson: true,
};Commands
init
Creates config file automatically.
npx react-i18next-scanner initscan
Scans your project and creates reports.
npx react-i18next-scanner scanWith custom config:
npx react-i18next-scanner scan --config ./i18n-scanner.config.mjsThe scan command:
- scans source files
- extracts used translation keys
- compares used keys with translation JSON files
- detects missing keys
- detects unused keys
- detects dynamic translation usages
- writes reports
- optionally syncs missing keys
- optionally removes definitely unused keys
sync-missing
Finds missing keys and adds them to translation JSON files.
npx react-i18next-scanner sync-missingMissing keys are added with empty values.
Example:
{
"common": {
"Save": ""
}
}sort
Sorts translation JSON files alphabetically.
npx react-i18next-scanner sortIf no files are passed, the command uses sortJsonFiles from config.
You can also pass files manually:
npx react-i18next-scanner sort ./src/i18n/locales/translations.en.json ./src/i18n/locales/translations.es.jsonReport Structure
All reports are written inside one root folder:
reports/Each report type has its own folder:
reports/
unused-translations/
unused.translations.en.json
unused.translations.es.json
dynamic-translations/
dynamic-translation-usages.json
possibly-dynamically-used/
possibly-dynamically-used.json
imported-object-usages/
resolved-imported-object-usages.jsonUnused Translation Reports
Folder:
reports/unused-translations/These reports contain translation keys that look unused after deep verification.
Example:
reports/unused-translations/unused.translations.en.jsonExample content:
{
"common": {
"Old button text": "Old button text"
}
}You can review this file before removing keys.
If removeUnused: true, only definitely unused keys will be removed.
Dynamic Translation Report
Folder:
reports/dynamic-translations/This report shows places where the scanner found dynamic translation usage.
Examples:
t(labelKey);
t(getDescription());
t(`${section}.${name}`);
<Trans i18nKey={text} />;
<Trans i18nKey={`account.${text}`} />;Example report:
{
"src/components/Profile.tsx": [
{
"namespaces": ["common"],
"expression": "labelKey",
"reason": "Non-literal translation key",
"suggestion": "Translation key may come from a variable or helper function. Manual or deeper analysis may be required."
}
]
}This report answers:
Where do we use dynamic translation keys in source code?Possibly Dynamically Used Report
Folder:
reports/possibly-dynamically-used/This report shows keys that looked unused at first, but were later detected as possibly used dynamically.
Example:
const titleKey = MODAL_DATA[type].TITLE;
t(String(titleKey));The key may not appear directly as:
t("accountInformation.Account Number");But the scanner can understand that it may come from an object config.
This report answers:
Which unused keys were saved from removal because they may be used dynamically?Imported Object Usages Report
Folder:
reports/imported-object-usages/File:
resolved-imported-object-usages.jsonThis report shows where translation keys from imported object configs are used.
Example config object:
export const MODAL_DATA = {
accountNumber: {
TITLE: "accountInformation.Account Number",
TEXT: "accountInformation.Your Account Number is",
},
};Example usage:
import { MODAL_DATA } from "./modalData";
const additionalInformationData = MODAL_DATA[additionalInformationModalType];
t(String(additionalInformationData.TITLE));The scanner can resolve this as:
additionalInformationData.TITLE
→ MODAL_DATA[*].TITLE
→ accountInformation.Account NumberExample report:
[
{
"key": "accountInformation.Account Number",
"sourceFilePath": "src/components/AdditionalInformationModal.tsx",
"importedFilePath": "src/config/modalData.ts",
"importedObjectName": "MODAL_DATA",
"accessPath": "MODAL_DATA.*.TITLE",
"usageKind": "t"
}
]This report answers:
Where is this imported object translation key used?Supported Translation Patterns
The scanner detects direct translation keys:
t("common.Save");
i18n.t("common.Save");
<Trans i18nKey="common.Save" />;It also supports namespaces:
const { t } = useTranslation("common");
t("Save");Supported Dynamic Patterns
The scanner can detect and report dynamic usages:
t(labelKey);
t(getTitleKey());
t(`${section}.${name}`);
<Trans i18nKey={labelKey} />;
<Trans i18nKey={`account.${name}`} />;It can also resolve some imported object config usages:
t(String(MODAL_DATA[type].TITLE));const data = MODAL_DATA[type];
t(String(data.TITLE));<Trans i18nKey={MODAL_DATA[type].TITLE} />This works not only for MODAL_DATA, but also for similar exported object configs:
export const WARNING_CONFIG = {
deleteAccount: {
TITLE: "settings.Delete account",
TEXT: "settings.This action cannot be undone",
},
};Config Options
srcPaths
Source files to scan.
srcPaths: ["./src/**/*.{js,jsx,ts,tsx}"];jsonDir
Translation JSON files to analyze.
jsonDir: [
"./src/i18n/locales/translations.en.json",
"./src/i18n/locales/translations.es.json",
];sortJsonFiles
JSON files used by the sort command.
sortJsonFiles: [
"./src/i18n/locales/translations.en.json",
"./src/i18n/locales/translations.es.json",
];outputDir
Root folder for scanner reports.
Default:
outputDir: "./reports";Reports will be grouped into subfolders:
reports/
unused-translations/
dynamic-translations/
possibly-dynamically-used/
imported-object-usages/syncMissing
If true, missing keys found in code will be added to translation JSON files.
syncMissing: true;Values are created as empty strings.
removeUnused
If true, definitely unused keys will be removed from translation JSON files.
removeUnused: true;The scanner does not remove keys that are possibly dynamically used.
sortJson
If true, JSON files will be sorted after sync or remove actions.
sortJson: true;Safe Remove Behavior
The scanner tries to avoid removing keys that may still be used dynamically.
For example:
const data = MODAL_DATA[type];
t(String(data.TITLE));If MODAL_DATA[type].TITLE contains:
"accountInformation.Account Number";then this key will not be treated as definitely unused.
It will be moved to a dynamic safety report instead.
Supported Files
Source files
.js
.jsx
.ts
.tsxConfig files
.js
.cjs
.mjs
.tsconfig is not supported yet.
Example Workflow
1. Scan only
Use this when you want reports without modifying translation JSON files.
export default {
srcPaths: ["./src/**/*.{js,jsx,ts,tsx}"],
jsonDir: ["./src/i18n/locales/translations.en.json"],
outputDir: "./reports",
syncMissing: false,
removeUnused: false,
};Run:
npx react-i18next-scanner scan2. Sync missing keys
export default {
srcPaths: ["./src/**/*.{js,jsx,ts,tsx}"],
jsonDir: ["./src/i18n/locales/translations.en.json"],
outputDir: "./reports",
syncMissing: true,
removeUnused: false,
};Run:
npx react-i18next-scanner scanor:
npx react-i18next-scanner sync-missing3. Remove definitely unused keys
export default {
srcPaths: ["./src/**/*.{js,jsx,ts,tsx}"],
jsonDir: ["./src/i18n/locales/translations.en.json"],
outputDir: "./reports",
syncMissing: false,
removeUnused: true,
};Run:
npx react-i18next-scanner scanBefore using removeUnused: true, review reports first.
Limitations
The scanner does not fully support every possible runtime data-flow case.
Currently not fully covered:
const data = getModalData(type);
t(data.TITLE);const key = MODAL_DATA[type].TITLE + ".extra";
t(key);const data = someWrapper(MODAL_DATA[type]);
t(data.TITLE);export default MODAL_DATA;The scanner is designed to be safe. If it is not sure, it reports dynamic usage instead of removing keys automatically.
Notes
syncMissingdoes not translate values automatically.removeUnusedshould be used carefully.- Possibly dynamic keys are not removed automatically.
- Config paths are resolved relative to the config file location.
.tsconfig is not supported yet.
Development
Build the project:
yarn buildRun scanner in development:
yarn dev scanSort JSON files:
yarn sortSync missing keys:
yarn syncLicense
ISC
