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

i18next-auto-keys

v4.0.1

Published

Automatic translation key generation for i18next

Readme

i18next-auto-keys

npm version Build Status License: MIT

Automatic translation key generation for i18next - No more manual key management!

✨ Features

  • 🔄 Automatic key generation - No manual key management required
  • 📍 Colocated translations - Text strings live next to the components that use them
  • 📦 Framework agnostic - Works with React, Vue, Angular, or vanilla JS
  • 🔒 Typesafe by default - Full TypeScript support with AST transformation
  • Multiple bundler support - Works with Webpack, Vite, and Rollup

🎯 Why this over other i18next libraries?

Traditional i18next libraries like react-i18next force you to:

  • Manually manage translation keys - tedious and error-prone
  • Rewrite your entire codebase to use their APIs (t('some.key') everywhere)
  • Buy into their ecosystem - change how you write and organize code
  • Separate translations from code - hunt through .json files to find text strings

With i18next-auto-keys, you:

  • Keep writing normal TypeScript - no special APIs to learn
  • Stay library-agnostic - developers don't even know what i18n library powers translations
  • Easy migration - switch translation systems with minimal changes to application code

i18next-auto-keys automatically extracts strings from your code and replaces them with i18next.t() calls using auto-generated hash keys at build time.

📋 Requirements

  • Node.js 18+
  • TypeScript 5+ (We use a TypeScript transformer)
  • One of the following bundlers:
    • Webpack 5+ (Webpack loader + plugin)
    • Vite (Rollup plugin, works in dev and build)
    • Rollup 4+ (Rollup plugin)

📦 Installation

npm install --save-dev i18next-auto-keys

# Your project will also need these dependencies if you don't already have them
npm install --save i18next i18next-icu

🚀 Quick Start

1. Write your messages in regular Typescript

You should use the ICU format for plurals and formatting.

// src/components/LoginForm.messages.ts
export const LoginMessages = {
  errorInvalid: (email: string): string => "Invalid email: {email}",

  // ICU pluralization examples
  loginAttempts: (count: number): string =>
    "{count, plural, one {# login attempt} other {# login attempts}} remaining",
};

2. Import and use the Messages

Convert this:

// src/components/LoginForm.tsx
function LoginForm(props) {
  return (
    <div>
      <div>Invalid email: {props.email}</div>
      <div>
      {props.loginAttemptsRemaining} login {props.loginAttemptsRemaining === 1 ? "attempt" : "attempts"} remaining
      </div>
    </div>
  );
}

Into this:

// src/components/LoginForm.tsx
import { LoginMessages } from "./LoginForm.messages.ts";

function LoginForm(props) {
  return (
    <div>
      <div>{LoginMessages.errorInvalid(props.email)}</div>
      <div>{LoginMessages.loginAttempts(props.loginAttemptsRemaining)}</div>
    </div>
  );
}

3. Configure your bundler

→ Full Vite & Rollup documentation

// webpack.config.js
const { I18nextAutoKeyEmitPlugin } = require('i18next-auto-keys');

module.exports = {
  module: {
    rules: [
      {
        test: /\.messages\.(ts|tsx)$/, // Only process message files
        exclude: /node_modules/,
        enforce: 'pre', // Ensure this runs before actual TS -> JS compilation
        use: {
          loader: 'i18next-auto-keys',
          options: {
            setDefaultValue: process.env.NODE_ENV === 'development', // For HMR support
          }
        }
      }
    ]
  },
  plugins: [
    new I18nextAutoKeyEmitPlugin({
      jsonOutputPath: 'locales/en.json', // path to your i18next JSON resources
    })
  ]
};
// vite.config.js
import { defineConfig } from 'vite';
import { i18nextAutoKeyRollupPlugin } from 'i18next-auto-keys';

export default defineConfig({
  plugins: [
    i18nextAutoKeyRollupPlugin({
      jsonOutputPath: 'locales/en.json',
      setDefaultValue: process.env.NODE_ENV === 'development',
    }),
  ],
});
// rollup.config.js
import { i18nextAutoKeyRollupPlugin } from 'i18next-auto-keys';
import typescript from '@rollup/plugin-typescript';

export default {
  input: 'src/index.ts',
  output: { dir: 'dist', format: 'esm' },
  plugins: [
    typescript(),
    i18nextAutoKeyRollupPlugin({
      jsonOutputPath: 'locales/en.json',
      setDefaultValue: process.env.NODE_ENV === 'development',
    }),
  ],
};

4. Profit!

The loader automatically transforms your code:

// After transformation
import i18next from "i18next";

export const LoginMessages = {
  errorInvalid: (email: string): string => i18next.t("p6q7r8s9t0", { email }),
  loginAttempts: (count: number): string => i18next.t("u8v9w0x1y2", { count }),
};

And generates translation files:

// dist/locales/en.json
{
  "p6q7r8s9t0": "Invalid email: {email}",
  "u8v9w0x1y2": "{count, plural, one {# login attempt} other {# login attempts}} remaining",
}

🎯 Usage Patterns

Pluralization

Since keys are auto-generated, we can't use i18next's default key-based pluralization (_zero, _one, etc.). Instead we use the ICU message format which handles plurals and inline formatting:

  • Pluralization: {count, plural, one {# item} other {# items}}
  • Number/Date formatting: {price, number, currency}{date, date, short}
  • Conditional text: {status, select, online {Connected} offline {Disconnected}}

Learn more about ICU format →

Parameter Handling

[!WARNING] Do NOT use JavaScript string interpolation (${}) in your message functions!

// ❌ WRONG - Creates unstable hashes
greeting: (name: string): string => `Hello ${name}!`

// ✅ CORRECT - Use ICU format
greeting: (name: string): string => "Hello {name}!"
status: (count: number): string => "{count, plural, one {# item} other {# items}}"

Message Files Organization

Create dedicated message files for better organization:

// src/pages/auth/auth.messages.ts
export const AuthMessages = {
  // Simple messages
  title: (): string => "Authentication",
  subtitle: (): string => "Please sign in to continue",

  // Messages with ICU interpolation
  welcome: (name: string): string => "Welcome back, {name}!",

  // ICU pluralization
  attemptsLeft: (count: number): string =>
    "{count, plural, one {# attempt} other {# attempts}} remaining",
};

Supports Different Function Syntax

Supports arrow functions, function expressions, and method shorthand:

export const Messages = {
  // Arrow functions
  arrowStyle: (name: string): string => "Hello {name}",

  // Function expressions
  functionStyle: function(count: number): string {
    return "{count, plural, one {# item} other {# items}}";
  },

  // Method shorthand
  methodStyle(status: string): string {
    return "Status: {status}";
  },
};

JSDoc Parameter Extraction for Translators

When using the CLI to generate PO files, JSDoc comments are automatically extracted to provide context for translators, especially useful with ICU indexed mode:

/**
 * User account summary message
 * @param userName The user's display name
 * @param accountType Type of account (free, premium, enterprise)
 * @param daysSince Days since account creation
 * @translationContext user-account-summary
 */
userSummary: (userName: string, accountType: string, daysSince: number): string =>
  "User {userName} has {accountType} account (active for {daysSince, number} days)"

Generated PO file with translator context:

#. User account summary message
#. {0} userName: string - The user's display name
#. {1} accountType: string - Type of account (free, premium, enterprise)
#. {2} daysSince: number - Days since account creation
msgctxt "user-account-summary"
msgid "User {userName} has {accountType} account (active for {daysSince, number} days)"
msgstr ""

Parameter Modes

Named (Default): Use parameter names in ICU format

greeting: (name: string): string => "Hello {name}!"
// Transforms to: i18next.t("abc123", { name })

Indexed: Use numbered placeholders

greeting: (name: string): string => "Hello {0}!"
// Transforms to: i18next.t("abc123", { "0": name })

Excluding Messages from Translation

Use JSDoc comments to exclude specific functions:

/** @noTranslate */
debugInfo: (): string => "Debug: Component mounted"

Translation Context for Message Disambiguation

Use @translationContext in JSDoc comments to provide context for identical strings that may need different translations:

export const Messages = {
  /** @translationContext gaming */
  playGame: (): string => "Play",

  /** @translationContext music */
  playMusic: (): string => "Play",
};

This helps translators distinguish between contexts. For example, in Spanish:

  • Gaming context: "Jugar" (to play a game)
  • Music context: "Reproducir" (to play music)

Generated PO file with context:

#. Play button for games
msgctxt "gaming"
msgid "Play"
msgstr ""

#. Play button for music
msgctxt "music"
msgid "Play"
msgstr ""

setDefaultValue Option

Includes original strings as fallback values. Useful for development mode or HMR:

// Source
message: (name: string): string => "Hello {name}"

// Transformed to
message: (name: string): string => i18next.t("abc123def4", { defaultValue: "Hello {name}", name })

Use in development to keep production bundles small, or if you don't want to load your default language from a JSON resource.

Debug Mode

Wrap transformed strings with ~~ markers to easily identify which strings are using the translation system in your running application.

This is particularly useful when gradually migrating an existing codebase to use i18next-auto-keys. The wrapped strings will be visually distinct, making it easy to spot which strings have been migrated vs which are still hardcoded. It also helps developers consider the spacial requirements of other languages, especially more verbose languages which might require more space.

Configuration:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.messages\.(ts|tsx)$/,
        use: {
          loader: 'i18next-auto-keys',
          options: {
            debug: process.env.NODE_ENV === 'development',
          }
        }
      }
    ]
  }
};

Example transformation:

// Source
greeting: (): string => "Hello world"

// Transformed in development with debug: true
greeting: (): string => `~~${i18next.t("abc123def4")}~~`

// Result in browser: "~~Hello world~~"

🛠️ CLI Tools

Extract translation keys from source files:

npx i18next-auto-keys extract --include "**/*.messages.ts" --output ./i18n/messages.pot

Sync existing PO files with new strings:

npx i18next-auto-keys sync --template ./i18n/messages.pot --po-files "./i18n/*.po" --backup

Convert PO files to JSON:

npx i18next-auto-keys convert --input "./i18n/*.po" --output ./public/locales --batch

Status - Show translation progress for PO files:

npx i18next-auto-keys status

Full CLI documentation →

⚙️ Configuration

Project Configuration File

Optional config file for project-wide settings. Supports multiple formats: i18next-auto-keys.config.js, .i18next-auto-keysrc.json, or package.json.

// i18next-auto-keys.config.js
module.exports = {
  poOutputDirectory: "locales",
  poTemplateName: "messages.pot",
  hashLength: 12,
  argMode: "named",
  topLevelKey: "common",
  projectId: "my-app v2.1.0", // Optional: defaults to package.json name + version
  jsonIndentSpaces: 2,
};

Configuration Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | poOutputDirectory | string | "i18n" | Directory where PO template files are output | | poTemplateName | string | "messages.pot" | Name of the PO template file | | hashLength | number | 10 | Length of generated hash keys (minimum 10) | | argMode | 'indexed' \| 'named' | 'named' | How to pass parameters to i18next.t() | | topLevelKey | string | undefined | Wrap translations under a top-level key | | projectId | string | package.json name + version (fallback: "app 1.0") | Project ID for PO file headers | | jsonIndentSpaces | number | 2 | JSON indentation spaces for output files |

Webpack Loader Options

These options override configuration file settings when specified:

| Option | Type | Default | Description | |--------|------|---------|-------------| | include | RegExp \| RegExp[] | * | Pattern(s) to match files for processing | | hashLength | number | From config | Length of generated hash keys (minimum 10) | | argMode | 'indexed' \| 'named' | From config | How to pass parameters to i18next.t() | | sourcemap | boolean | false | Generate source maps | | setDefaultValue | boolean | false | Include original strings as defaultValue in i18next calls | | debug | boolean | false | Wrap transformed strings with ~~ markers for visual debugging |

Webpack Plugin Options

These options override configuration file settings when specified:

| Option | Type | Default | Description | |--------|------|---------|-------------| | jsonOutputPath | string | Required | Path for JSON translation file | | topLevelKey | string | From config | Wrap translations under a top-level key |

🧪 Development

Setup

git clone https://github.com/username/i18next-auto-keys.git
cd i18next-auto-keys
npm install

Scripts

npm run build    # Build the package
npm test         # Run tests
npm run test:watch # Watch mode testing

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.