著者:
    作成:2026-08-12最終更新:2026-08-13

    ESLint x OXLint プラグイン

    eslint-plugin-intlayer は、TypeScript では捕捉できない i18n の間違いを検出します:

    1. 辞書に登録されていないハードコードされたテキスト
    2. 型チェックを通過して実行できるものの、Intlayer コンパイラが最適化できない動的な呼び出し
    3. デッドコンテンツ — プロジェクト内のどこからも読み取られていない辞書やフィールド(オプトイン)。

    不明な辞書キー、不明なフィールドパス、欠落しているロケールは既にコンパイルエラーとなるため、プラグインはそれらを重複して指摘しません。

    インストール

    bash
    npm install --save-dev eslint-plugin-intlayer

    ESLint 9 以降(Flat Config)が必要です。ESLint 10 に対応しています。

    使い方

    このプラグインは ESLint と oxlint の両方で動作します — 同じルール、同じオプションです。

    または設定を展開し、重大度を自分で指定します:

    プリセット設定

    設定 no-raw-text static-dictionary-key no-dynamic-field-access enforce-adapter-import no-unused-content
    recommended warn error error off off
    strict error (+ 非JSXリテラル) error error error off
    contract-only off error error off off

    recommended では意図的に no-raw-textwarn に設定しています: 既存のコードベースに適用した際にすべての未翻訳文字列が一斉に検出され、初日からビルドが失敗するのを防ぐためです。

    enforce-adapter-import はデフォルトでオフになっています — 必要な場合は明示的に有効にしてください。

    no-unused-contentstrict を含むすべての設定でオフになっています。これは Intlayer 設定を読み込んでディスクからソースファイルを走査する唯一のルールであるため、プリセットによって自動で有効化されるのではなく、意図的な選択として有効化するべきです。

    ルール

    no-raw-text

    辞書で宣言されていないユーザー向けテキストを報告します。intlayer extract と同じ検出ロジックを使用するため、ブランド名、CSS クラス、技術的識別子は無視されます。

    jsx
    // ✗ 報告される<h1>Welcome to our documentation</h1><input placeholder="Enter your email address" />// ✓ 正常const { title } = useIntlayer("home");<h1>{title}</h1>

    コンテンツ宣言ファイル(*.content.ts など)はスキップされます。

    ファイル全体を一度に修正するには、npx intlayer extract を実行して、コンパイラに文字列を辞書へ移動させてください。

    オプション

    static-dictionary-key

    辞書キーが文字列リテラルであることを要求します。

    コンパイラは呼び出し箇所でキーを直接読み取れる場合にのみ辞書を事前読み込みできます。計算されたキーを使用すると最適化が暗黙的にスキップされ、代わりにすべての辞書がバンドルされます。

    typescript
    // ✗ 報告されるuseIntlayer(dictionaryKey);useIntlayer(`home-${suffix}`);getTranslations({ namespace: page });// ✗ 変数はリテラルではありませんconst key = "home";useIntlayer(key);// ✓ 正常useIntlayer("home");getTranslations({ namespace: "home" });

    これは useIntlayergetIntlayer およびすべての互換アダプター(useTranslationuseTranslationsformatMessage<FormattedMessage id><Trans i18nKey> など)に適用されます。

    no-dynamic-field-access

    辞書から読み取るフィールドが静的に判明していることを要求します。

    コンパイラは使用されていることが確認できないフィールドを削除します。動的なアクセスはコンパイラから見えないため、実行時に読み取りが undefined を返す可能性があります。

    typescript
    // ✗ 報告されるconst content = useIntlayer("home");content[fieldName];const t = useTranslations("home");t(messageKey);// ✓ 正常content.title;content["title"];content.items[0];t("hero.title");

    enforce-adapter-import

    元のパッケージよりも @intlayer/* 互換アダプターを優先します。元のパッケージはバンドラーのエイリアスが設定されている場合にのみ Intlayer に解決されますが、アダプターは常に解決されます。--fix で自動修正可能です。

    typescript
    // ✗ 報告されるimport { useTranslation } from "react-i18next";import { getTranslations } from "next-intl/server";// ✓ 正常import { useTranslation } from "@intlayer/react-i18next";import { getTranslations } from "@intlayer/next-intl/server";

    no-unused-content

    デフォルトではオフです。 プロジェクト内のどこからも読み取られていないコンテンツ、および複数箇所で宣言されている辞書キーを報告します。

    src/home.content.ts
    export default {  key: "home", // ✗ プロジェクト内の呼び出し元がどこからも "home" を要求していない場合に報告  content: {    title: t({ ja: "タイトル", en: "Title" }),    // ✗ `hero` を読み取るものが存在しない場合に報告    hero: {      subtitle: t({ ja: "サブタイトル", en: "Subtitle" }),    },  },};

    他のルールとは異なり、このルールは対象のファイル単体から判断することはできません。フィールドが未使用かどうかはプロジェクト全体との相対関係で決まります。リント実行の最初のコンテンツ宣言時に Intlayer 設定を読み込み、その設定で宣言されているソースファイル(build.traversePatterncompiler.transformPattern)を走査して、@intlayer/lsp や VS Code 拡張機能の「未使用」取り消し線を駆動しているのと同じ使用状況アナライザーを実行します。結果は cacheTtl ミリ秒間キャッシュされるため、ファイルごとではなく1回の実行につき1回のスキャンが行われます。

    オプション

    長時間実行されるエディタサーバーからリントを実行し、編集をすばやく反映させたい場合は cacheTtl を低く設定します。モノレポで1回のリント実行が複数の Intlayer プロジェクトにまたがる場合は baseDir を設定します。

    誤検知を防ぐため静かに動作します。 ここでの誤検知は翻訳の削除につながる可能性があるため、解析が追跡できない方法で辞書が使用されている場合は何も報告されません: コンテンツオブジェクト全体をそのまま渡す、そこからバインドされた翻訳関数(const t = useTranslations("home"))、直接インポートによって到達した宣言(useDictionary(myDictionary))、他の辞書からの nest()、またはスプレッド構文によって網羅的でなくなったフィールドリストなどです。単一ファイルコンポーネント(.vue.svelte.astro)は、ここではスクリプトブロックが解析されないため、言及されている辞書のすべてのフィールドを使用しているものとしてカウントされます。

    reportDuplicateKeys はビルドによって .intlayer/ 配下に書き出された未マージの辞書を読み取るため、プロジェクトが少なくとも1回ビルドされるまでは動作しません。同じキーを共有する2つの宣言はマージされますが、これは正当なパターンです — 両側で定義されたフィールドが暗黙的にどちらか一方の値のみを保持してしまうため、この報告が存在します。

    アナライザーは ESM として提供されている @intlayer/lsp から読み込まれます。そのため、このルールには ES モジュールを require() できる Node バージョン(Node 20.19+ または 22.12+)が必要です。それより古い環境では、リント実行を失敗させるのではなく何も報告しません。

    フレームワーク

    すべてのルールは、Vue、Svelte、Angular テンプレート内を含め、すべての Intlayer 統合で動作します。各ファイルタイプをどのパーサーが読み取るかを ESLint に指定するだけです。

    フレームワーク ファイル パーサー
    React, Preact, Solid, Lit .jsx .tsx typescript-eslint
    Next.js .jsx .tsx typescript-eslint
    Vue, Nuxt .vue vue-eslint-parser
    Svelte, SvelteKit .svelte svelte-eslint-parser
    Angular .ts typescript-eslint
    Angular テンプレート .component.html @angular-eslint/template-parser
    Astro .astro astro-eslint-parser

    プロジェクトに必要なパーサーのみをインストールしてください。

    既知の制限事項。 Vue および Angular テンプレートでは、{{ content[key] }} のような式は no-dynamic-field-access によってチェックされません。スクリプトブロック内に書かれた動的アクセスは通常どおり検出されます。