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

@spaced-out/eslint-plugin-i18n

v3.1.1

Published

ESLint plugin for i18n with TypeScript support

Downloads

1,344

Readme

eslint-plugin-i18n

ESLint Rules for Translation and Internationalization:

This repository introduces ESLint rules designed to enforce best practices for internationalization (i18n) in your codebase. These rules ensure that static labels are replaced with translation functions and that all translation keys are defined in the corresponding en.json(source of truth).

Note: This plugin has been migrated to ESLint 9 with full functionality restored using the new scope analysis API and now includes comprehensive TypeScript support.

Features

  • Full TypeScript Support: Works seamlessly with .ts and .tsx files
  • Backward Compatibility: Maintains full support for .js and .jsx files
  • ESLint 9 Compatible: Uses modern ESLint 9 scope analysis API
  • Auto-fix Support: Many rules include automatic fixes
  • Type-aware Analysis: Enhanced type checking for better accuracy

Rules overview

1. no-static-labels

Description:

This rule identifies and prevents the use of static labels (hardcoded strings) in JSX code. It enforces wrapping all static labels with a translation function (e.g., t('key', 'defaultValue')).

Key Features:

  • Detects static strings in JSX elements, attributes, and variables.
  • Identifies template literals, binary expressions, logical expressions, and conditional expressions containing static strings.
  • Supports dynamic attribute checks, including menu, options, tooltip, and more.
  • Auto-fix functionality to wrap detected static labels in a translation function.
  • TypeScript Support: Works with TypeScript interfaces, types, and type annotations.

Why Use It?

Ensures that all user-facing text is localized, improving the scalability and maintainability of your application for internationalization.

2. missing-translation

Description:

This rule checks if the translation keys used in your t function are present in your source translation JSON file (e.g., en.json,). It warns developers about missing keys, ensuring translation files remain consistent with the codebase.

Key Features:

  • Verifies translation keys passed to the t function.
  • Supports t as a standalone function and as a method (e.g., this.t()).
  • Helps maintain completeness of translation files.
  • Warns developers if keys are missing from the source of truth JSON file (en.json).
  • TypeScript Support: Works with TypeScript function signatures and type definitions.

Why Use It?

Ensures all user-facing text is properly localized and prevents runtime issues due to missing translations.

3. invalid-translation-key-format

Description:

This rule enforces a strict naming convention for translation keys used in the t('key', 'defaultValue') function to ensure consistency and predictability across translation files.

Convention Rules:

  • All spaces in the fallback value must be replaced by underscores (_) in the key.
  • The key must preserve the exact casing of the fallback string (no forced lowercase).
  • No special characters allowed in the key, except a single apostrophe (').

4. no-react-i18next-import

Description:

This rule disallows the use of the useTranslation hook from react-i18next in your codebase. It enforces a centralized approach to translation using the t('key', 'fallback') pattern, instead of dynamically obtaining t via hooks. (rule specifically for sense repo)

Key Features:

  • Detects imports of useTranslation from react-i18next.
  • Reports any invocation of useTranslation() in the code.
  • TypeScript Support: Works with TypeScript import statements and type declarations.

5. no-dynamic-labels

Description:

This rule enforces wrapping dynamic labels (variables, expressions, and computed values) in translation functions using the makeKey wrapper. It ensures that all dynamic content that could be user-facing is properly localized.

Key Features:

  • Detects dynamic expressions in JSX that should be translated
  • Enforces the use of makeKey() function for dynamic translation keys
  • Supports various dynamic contexts: variables, member expressions, function calls, conditional expressions, logical expressions, and template literals
  • Auto-fix functionality to wrap detected dynamic labels in t(makeKey(dynamicValue), dynamicValue) format
  • Handles array method calls (map, filter, flatMap, reduce) and their callbacks
  • Supports styled-components template expressions
  • TypeScript Support: Enhanced type checking for better accuracy in identifying string vs non-string expressions

Why Use It?

Ensures that all dynamic content (variables, computed values, expressions) that could be user-facing is properly internationalized using the standardized makeKey pattern for dynamic translation keys.

6. i18n-enforce-makeKey-wrapper

Description:

This rule enforces that dynamic variables used as translation keys must be wrapped with the makeKey() function from the useLabelTranslation hook. It ensures consistent handling of dynamic translation keys across the codebase.

Key Features:

  • Detects dynamic variables used directly as translation keys
  • Enforces wrapping with makeKey() function from useLabelTranslation hook
  • Validates proper hook usage and destructuring
  • Auto-fix functionality to wrap dynamic keys with makeKey()
  • Supports both direct function calls and method calls
  • Configurable translation function names and hook names
  • TypeScript Support: Works with TypeScript interfaces, types, and function signatures

Why Use It?

Ensures consistent and safe handling of dynamic translation keys by enforcing the use of the makeKey wrapper function, which provides proper key generation and validation.

TypeScript Support

This plugin now includes comprehensive TypeScript support, making it suitable for both JavaScript and TypeScript projects.

TypeScript Features:

  • File Extension Detection: Automatically detects .ts and .tsx files
  • Type Annotation Support: Understands TypeScript type annotations and interfaces
  • Enhanced Type Checking: Better accuracy in identifying string vs non-string expressions
  • TypeScript Pragma Support: Recognizes TypeScript-specific pragmas (@ts-check, @ts-nocheck, etc.)
  • Interface and Type Support: Works with TypeScript interfaces, types, and type aliases
  • Generic Support: Handles TypeScript generics and complex type expressions

TypeScript Configuration:

// .eslintrc.js
module.exports = {
  extends: [
    // other configurations...
  ],
  plugins: ["@spaced-out"],
  overrides: [
    {
      files: ["*.ts", "*.tsx"],
      parser: "@typescript-eslint/parser",
      parserOptions: {
        ecmaVersion: 2020,
        sourceType: "module",
        ecmaFeatures: {
          jsx: true,
        },
      },
      rules: {
        "@spaced-out/i18n/no-static-labels": "error",
        "@spaced-out/i18n/missing-translation": "warn",
        "@spaced-out/i18n/invalid-translation-key-format": "error",
        "@spaced-out/i18n/no-react-i18next-import": "error",
        "@spaced-out/i18n/no-dynamic-labels": "error",
        "@spaced-out/i18n/i18n-enforce-makeKey-wrapper": "error",
      },
    },
    {
      files: ["*.js", "*.jsx"],
      rules: {
        "@spaced-out/i18n/no-static-labels": "error",
        "@spaced-out/i18n/missing-translation": "warn",
        "@spaced-out/i18n/invalid-translation-key-format": "error",
        "@spaced-out/i18n/no-react-i18next-import": "error",
        "@spaced-out/i18n/no-dynamic-labels": "error",
        "@spaced-out/i18n/i18n-enforce-makeKey-wrapper": "error",
      },
    },
  ],
};

TypeScript Usage Examples:

// TypeScript interface example
interface User {
  name: string;
  email: string;
}

// TypeScript component with proper translations
const UserProfile: React.FC<{ user: User }> = ({ user }) => {
  return (
    <div>
      <h1>{t('user_profile_title', 'User Profile')}</h1>
      <p>{t('welcome_message', 'Welcome, {name}!', { name: user.name })}</p>
    </div>
  );
};

// TypeScript with type annotations
const getMessage = (type: 'success' | 'error'): string => {
  return t(`message_${type}`, type === 'success' ? 'Success!' : 'Error occurred');
};

ESLint 9 Compatibility

This plugin has been successfully migrated to support ESLint 9 with full functionality restored using the new scope analysis API.

Changes Made:

  • Updated scope analysis: Replaced context.getScope() with ESLint 9's context.sourceCode.scopeManager API
  • Restored all rules: All rules now work with full functionality using the new scope analysis
  • Enhanced error handling: Added fallback mechanisms for scope analysis failures
  • Updated ESLint dependency: Upgraded from ESLint 8.35.0 to ESLint 9.x
  • TypeScript support: Added comprehensive TypeScript parsing and analysis capabilities

Impact:

  • All rules are fully functional: No functionality has been lost in the migration
  • Enhanced compatibility: Better error handling and fallback mechanisms
  • Future-proof: Uses ESLint 9's modern scope analysis API
  • TypeScript ready: Full support for TypeScript syntax and type checking

Installation

1. Install ESLint and the plugin:

npm install @spaced-out/eslint-plugin-i18n --save-dev

2. For TypeScript projects, install additional dependencies:

npm install @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript --save-dev

3. Add the rules to your .eslintrc.js configuration:

For JavaScript projects:

module.exports = {
  extends: [
    // other configurations...
  ],
  plugins: ["@spaced-out"],
  rules: {
    "@spaced-out/i18n/no-static-labels": "error",
    "@spaced-out/i18n/missing-translation": "warn",
    "@spaced-out/i18n/invalid-translation-key-format": "error",
    "@spaced-out/i18n/no-react-i18next-import": "error",
    "@spaced-out/i18n/no-dynamic-labels": "error",
    "@spaced-out/i18n/i18n-enforce-makeKey-wrapper": "error",
  },
};

For TypeScript projects:

module.exports = {
  extends: [
    // other configurations...
  ],
  plugins: ["@spaced-out"],
  overrides: [
    {
      files: ["*.ts", "*.tsx"],
      parser: "@typescript-eslint/parser",
      // ... rest of TypeScript configuration
    }
  ]
};

Using the provided configurations:

module.exports = {
  extends: [
    "plugin:@spaced-out/i18n/recommended", // For JavaScript
    // OR
    "plugin:@spaced-out/i18n/typescript", // For TypeScript
  ],
};

4. Configure your translation files:

Place your translation files (e.g., en.json, fr.json) in the translations folder inside your i18n directory. The rules will automatically pick up these files to validate translation keys.

How It Works

Rule: no-static-labels

The rule inspects your code for hardcoded static strings. For example:

Input:

<div>Hello, World!</div>;
const message = "Welcome!";
<h1>{message}</h1>;

Output: The rule suggests wrapping the strings in a translation function:

<div>{t("Hello_World", "Hello, World!")}</div>;
const message = t("Welcome", "Welcome!");
<h1>{message}</h1>;

Supported Contexts:

  • JSX Text (<div>Static Text</div>)
  • JSX Attributes (<button label="Click me" />)
  • JavaScript Variables (const label = "Static text";)
  • Template Literals, Binary Expressions, Logical Expressions, Conditional Expressions, and Object Properties.
  • TypeScript: Interfaces, types, and type annotations

Rule: missing-translation

The rule checks translation keys used in the t function. If a key is missing in the JSON files, a warning is displayed:

Input:

const message = t("NonExistentKey", "Default Message");

Warning Message:

Translation key "NonExistentKey" is missing in the config translations JSON file.

Supported Function Usages:

  • t('key', 'defaultValue')
  • TypeScript: Type-safe function calls with proper type checking

Rule: invalid-translation-key-format

This rule checks that the key passed to t() matches the fallback string (with underscores for spaces, identical casing, and only apostrophes allowed as special characters).

Input:

t("youre cute", "You're cute");

Output: The rule suggests fixing the key of wrapped translation function:

Translation key "youre_cute" is invalid. It should be "You're_cute".

Supported Contexts:

  • JSX Text (<div>Static Text</div>)
  • JSX Attributes (<button label="Click me" />)
  • JavaScript Variables (const label = "Static text";)
  • Template Literals, Binary Expressions, Logical Expressions, Conditional Expressions, and Object Properties.
  • TypeScript: Type-safe key validation

Rule: no-dynamic-labels

This rule detects dynamic expressions that should be wrapped in translation functions using the makeKey pattern.

Input:

const userName = "John";
const items = [{ name: "Item 1" }, { name: "Item 2" }];

<div>Hello, {userName}!</div>
<div>{items.map(item => item.name)}</div>
<div>{getLabel()}</div>

Output: The rule suggests wrapping dynamic expressions in translation functions:

const userName = "John";
const items = [{ name: "Item 1" }, { name: "Item 2" }];

<div>Hello, {t(makeKey(userName), userName)}!</div>
<div>{items.map(item => t(makeKey(item.name), item.name))}</div>
<div>{t(makeKey(getLabel()), getLabel())}</div>

Supported Contexts:

  • Dynamic variables ({userName})
  • Member expressions ({item.name})
  • Function calls ({getLabel()})
  • Logical expressions ({value || "default"})
  • Template literals with expressions
  • Array method callbacks (items.map(item => item.name))
  • Styled-components template expressions
  • TypeScript: Enhanced type checking for better accuracy

Rule: i18n-enforce-makeKey-wrapper

This rule ensures that dynamic variables used as translation keys are properly wrapped with the makeKey() function.

Input:

const label = getLabel();
const message = t(makeKey(label), label);

Output: The rule enforces wrapping dynamic keys with makeKey():

Required Setup:

// Must import and use the hook (specific to Sensehq(ui-server) usecase)
import { useLabelTranslation } from 'path/to/hook';

function Component() {
  const { t, makeKey } = useLabelTranslation();
  
  const label = getLabel();
  return <div>{t(makeKey(label), label)}</div>;
}

Error Messages:

  • Missing makeKey wrapper: "Dynamic Variable translation key must be wrapped with makeKey() from useLabelTranslation"
  • Missing hook call: "useLabelTranslation hook must be called in this component to use makeKey"
  • Missing destructuring: "makeKey must be destructured from useLabelTranslation hook call"

Fix Suggestions and Workflow

Auto-Fix for rules that support it:

  • Rules that supports auto-fix functionality. Run ESLint with the --fix flag to automatically wrap static labels in the t function.
npx eslint . --fix

Handling Missing Translations

  1. Run the linter to identify missing keys:
npx eslint .
  1. Use a script to generate the missing keys in your translation files. For example:
yarn generate-translations

This script should:

  • Parse all translation keys from the codebase.
  • Compare the keys with existing translation JSON files.
  • Append missing keys with default values.

Migration Guide

From JavaScript to TypeScript

If you're migrating your project from JavaScript to TypeScript:

  1. Install TypeScript dependencies:
npm install @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript --save-dev
  1. Update your ESLint configuration:
// .eslintrc.js
module.exports = {
  overrides: [
    {
      files: ["*.ts", "*.tsx"],
      parser: "@typescript-eslint/parser",
      // ... rest of TypeScript configuration
    }
  ]
};
  1. Add TypeScript pragmas to your files:
// @ts-check
import React from 'react';
  1. Run ESLint to check for any issues:
npx eslint . --ext .ts,.tsx

Backward Compatibility

The plugin maintains full backward compatibility with JavaScript files. All existing configurations will continue to work without any changes.

Contributing

When contributing to this plugin, please ensure:

  1. TypeScript Support: All new features should work with both JavaScript and TypeScript
  2. Backward Compatibility: Changes should not break existing JavaScript functionality
  3. Type Safety: Use TypeScript for new development when possible
  4. Testing: Test with both .js/.jsx and .ts/.tsx files

License

ISC