ESLint + Lingui + TypeScript
ESLint 9 + TypeScript

Type-aware i18n
linting for Lingui

8 rules for Lingui best practices — from catching unlocalized strings to enforcing consistent plurals. TypeScript's type system eliminates false positives, no endless whitelists needed.

String detection
Macro validation
Plural formatting
ESLint 9 flat config
example.tsx
// ✅ Automatically ignored — TypeScript knows these
document.createElement("div")
element.addEventListener("click", handler)
fetch(url, { mode: "cors" })

type Status = "idle" | "loading" | "error"
const status: Status = "loading"  // ✅ ignored

// ❌ Reported — actual user text
const message = "Welcome to our app"  // 🚨
<button>Save changes</button>  // 🚨

Smart Detection, Zero Config

TypeScript's type system + intelligent heuristics handle the heavy lifting. Focus on your app, not your linter config.

String Literal Unions

"idle" | "loading" | "error" automatically detected as technical strings.

DOM & Intl APIs

Event names, element types, Intl options — all recognized via TypeScript definitions.

Styling Props

className, backgroundColor, Tailwind classes — auto-ignored.

Numeric Strings

Prices, dates, times like "€99.99" or "12:30" are not user text.

Branded Types

Mark custom loggers, analytics, storage keys as unlocalized with unlocalized().

Package Verification

Verifies t, Trans come from @lingui/* — no false positives.

Custom Ignore Patterns

For loggers, analytics, or any strings that shouldn't be translated — use branded types for type-safe ignore patterns.

UnlocalizedFunction<T> — wrap entire interfaces
unlocalized() — helper for automatic type inference
UnlocalizedEvent, UnlocalizedKey — specific use cases
logger.ts
import { unlocalized } from "eslint-plugin-lingui-typescript/types"

function createLogger(prefix = "[App]") {
  return unlocalized({
    info: (...args) => console.info(prefix, ...args),
    error: (...args) => console.error(prefix, ...args),
  })
}

const logger = createLogger()
logger.info("Server started")   // ✅ ignored
logger.error("Connection failed") // ✅ ignored

Why TypeScript-Aware?

Traditional i18n linters rely on heuristics and manual whitelists. This plugin leverages TypeScript to do the work for you.

Feature Traditional This Plugin
String literal unions Manual whitelist ✓ Auto-detected
DOM API strings Manual whitelist ✓ Auto-detected
Intl method arguments Manual whitelist ✓ Auto-detected
Styling props & constants Manual whitelist ✓ Auto-detected
Numeric/symbolic strings Manual whitelist ✓ Auto-detected
Custom ignore patterns Config arrays ✓ Branded types
Lingui macro verification Name-based only ✓ Package origin

8 Battle-Tested Rules

Comprehensive coverage for Lingui best practices, from unlocalized strings to macro usage.

Quick Start

Get up and running in under a minute.

1

Install the plugin

npm install --save-dev eslint-plugin-lingui-typescript
2

Add to your ESLint config

// eslint.config.ts
import eslint from "@eslint/js"
import tseslint from "typescript-eslint"
import linguiPlugin from "eslint-plugin-lingui-typescript"

export default [
  eslint.configs.recommended,
  ...tseslint.configs.strictTypeChecked,
  linguiPlugin.configs["flat/recommended"],
  {
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    }
  }
]
3

Run ESLint

npx eslint .