npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-i18next-scanner

v0.1.10

Published

CLI tool to scan React projects for missing and unused react-i18next translation keys

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-scanner

or

yarn add -D react-i18next-scanner

2. Create config

npx react-i18next-scanner init

This will create a config file for your project.

Supported config formats:

i18n-scanner.config.js
i18n-scanner.config.cjs
i18n-scanner.config.mjs

.ts config is not supported yet.


3. Run scan

npx react-i18next-scanner scan

The 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 init

scan

Scans your project and creates reports.

npx react-i18next-scanner scan

With custom config:

npx react-i18next-scanner scan --config ./i18n-scanner.config.mjs

The 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-missing

Missing keys are added with empty values.

Example:

{
  "common": {
    "Save": ""
  }
}

sort

Sorts translation JSON files alphabetically.

npx react-i18next-scanner sort

If 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.json

Report 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.json

Unused Translation Reports

Folder:

reports/unused-translations/

These reports contain translation keys that look unused after deep verification.

Example:

reports/unused-translations/unused.translations.en.json

Example 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.json

This 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 Number

Example 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
.tsx

Config files

.js
.cjs
.mjs

.ts config 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 scan

2. 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 scan

or:

npx react-i18next-scanner sync-missing

3. 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 scan

Before 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

  • syncMissing does not translate values automatically.
  • removeUnused should be used carefully.
  • Possibly dynamic keys are not removed automatically.
  • Config paths are resolved relative to the config file location.
  • .ts config is not supported yet.

Development

Build the project:

yarn build

Run scanner in development:

yarn dev scan

Sort JSON files:

yarn sort

Sync missing keys:

yarn sync

License

ISC