Lovableがi18nルールを読み込む場所は3つあります。常にコンテキストに入るワークスペース/プロジェクトのKnowledge、プロンプトが説明文に一致したときだけ読み込まれるスキル、そして接続したリポジトリ内の指示ファイルです。リポジトリのルート直下にあるAGENTS.mdは、会話がどれだけ長くなっても読み込まれます。ルールを置く場所を間違えると、先週翻訳したアプリが、次の機能では英語のまま出荷されることになります。globalize.nowはAI搭載のローカライズ基盤であり、こうしたミスの結果を多くのLovableリポジトリで目にしてきました。対処の要点は、どの経路がいつ読まれるのかを把握することです。
翻訳済みのLovableアプリが英語に逆戻りしてしまうのはなぜ?
アプリを多言語対応にした指示が、エージェントが次のコンポーネントを書く時点でコンテキストに入っていなかったからです。Lovableは目の前のプロンプトを解くだけです。そのプロンプトが「お客様の声セクションを追加して」で、コンテキストのどこにも「ユーザーに表示される文字列はすべて<Trans>を通す」と書かれていなければ、見出しは新規プロジェクトのときと同じようにリテラルのまま書き込まれます。
これは、コードにカタログが追いついていないという同期の問題(Lovableアプリの翻訳がデプロイのたびに壊れる理由で解説しています)とは別の問題です。同期は、ラップされた文字列をロケールファイルへ移すだけで、ラップされなかった文字列は移せません。そもそもの問いは、Lovableがコードを書いた瞬間に何を読んでいたかであり、これについてLovableのドキュメントは異例なほど具体的に記述しています。
Lovableは編集の前に、実際に何を読んでいる?
Knowledgeのドキュメントによると、プロジェクトKnowledge、ワークスペースKnowledge、そしてGitリポジトリ内のAGENTS.mdやCLAUDE.mdといった指示ファイルが、いずれもプロジェクトのコードと並んでエージェントをガイドします。スキルは別枠で、必要に応じて読み込まれます。
これらには、i18nの観点で重要な3つの違いがあります。
いつ読み込まれるか。 Knowledgeは毎回のメッセージに含まれます。スキルは、リクエストが説明文に一致したときだけ含まれます。ルート直下のAGENTS.mdは、Lovableの表現を借りれば、セッションの長さに関係なく常に読み込まれます。
長いチャットでどれだけ持続するか。 Lovableのドキュメントには、コンテキストの多い非常に長い会話では、Knowledgeの指示が常に一貫して守られるとは限らないという注意書きがあります。同じページでルート直下のAGENTS.mdについては逆の説明がなされています。この非対称性こそが、この記事を書いた理由のすべてです。
誰が編集できるか。 ワークスペースKnowledgeを編集できるのは、オーナーと管理者だけです。プロジェクトKnowledgeは、そのプロジェクトの編集権限を持つ人なら誰でも編集できます。リポジトリのファイルは、pushできる人なら誰でも編集でき、これにはLovableのエージェント自身も含まれます。
Knowledgeの各レベルには1万文字まで書き込めます。ポインタを置くには十分ですが、アーキテクチャのメモ、データベーススキーマ、ブランドボイスまで一緒に書こうとすると、ルール一式を入れるには到底足りません。
では、i18nルールはどこに置くべき?
リポジトリに置き、Knowledgeには短いポインタを書きます。理由は上で見てきた違いから導けます。
リポジトリ直下のAGENTS.mdに、ルールの全文を書きます。 毎回のメッセージでセッションの長さに関係なく読み込まれ、Gitで管理されるため新しいチャットや新しいメンバー、別のエージェントへの乗り換えでも失われず、他のプロジェクトコンテキストと競合する文字数上限もありません。lovable-i18nスキルがセットアップを実行すると、第3フェーズでまさにこのファイルを書き出します。<!-- lovable-i18n:rules:start -->と<!-- lovable-i18n:rules:end -->のマーカーで囲んだLinguiルールのブロックを、ファイルがなければ新規作成し、あれば追記し、再実行時はマーカー間を置き換えるので、重複は発生しません。
プロジェクトKnowledgeには2行のポインタを書きます。 たとえば次のようなものです。
Localization
- This app is localized with Lingui. Every user-visible string is wrapped
(<Trans>, t``, msg``) and new strings are appended to src/locales/*/messages.po.
- The full rules are in AGENTS.md at the repo root. Follow them on every edit.
このポインタは、ドキュメントが警告しているケースへの備えです。長い会話でKnowledgeブロックの効きが薄れても、エージェントの手元にはリポジトリのファイルがあります。逆に、何らかの理由でリポジトリのファイルがコンテキストに入っていなくても、ポインタが制約を示してくれます。経路は2つ、ルールは1つです。
ワークスペースKnowledgeは、全プロジェクトが同じライブラリを使っている場合だけ。 ワークスペースKnowledgeはワークスペース内の全プロジェクトに適用され、1つしか存在しません。プロジェクトの半分がLinguiで、残り半分が別のライブラリなら、ワークスペースレベルのLinguiルールは半分のプロジェクトにとって誤りです。しかも、競合時にはLovableがプロジェクトKnowledgeを優先するよう促されています。ワークスペースKnowledgeには、どのプロジェクトでも共通して成り立つルールだけを書きましょう。たとえば、ボタンは文頭のみ大文字、console.logは使わない、コードコメントは英語、などです。
スキルはルールの置き場所ではありません。 インポートしたばかりの人は、ここで意外に感じます。スキルはプロンプトが説明文に一致したときに読み込まれるので、lovable-i18nは、i18nのセットアップを依頼したときにはコンテキストにありますが、決済ページを依頼したときにはありません。これは設計どおりの動作です。毎回のメッセージで読み込まれるスキルなら、それはただのKnowledgeです。スキルの役割は、永続するルールを一度だけリポジトリに書き込み、あとは退くことです。
AGENTS.mdのルールには何が書かれている?
単に「i18nを使って」と指示されただけのエージェントが間違えやすい点に、あらかじめ答えが書かれています。スキルが書き込むブロックは6つのパートで構成されています。
どのマクロを使うか。 判断リストになっています。数値によって変化するテキストは<Plural>またはICUのpluralを使います。JSX内のテキストには<Trans>を使います。属性値や、トーストのようなイベントハンドラー内の文字列には、useLingui()が返すtを使います。モジュールスコープの定数にはmsgを使い、コンポーネント内で解決します。ルールにはそれぞれのimportパスも明記されています。誤ったtをimportすると、アプリが読み込まないグローバルインスタンスに紐づいてしまうためです。
補間。 抽出されるメッセージ内で自分のスロット名を持てるのは、素の変数だけです。それ以外の式は{0}として抽出され、翻訳者には扱えません。そのため、ルールではph()を使って名前を付けることを必須にしています。
複数形。 otherは常に必須で、カテゴリーはCLDRに従い、2つの文字列を切り替える三項演算子は禁止です。英語の複数形ルールをコンポーネントに埋め込んでしまうためです。背景を知りたい場合は、ICU MessageFormatとはで、複数形がコンパイルされる構文を解説しています。
数値と日付。 i18n.number()とi18n.date()を使い、toFixed()や、値に連結した通貨記号は使いません。Lovable自身のワークスペースKnowledgeのサンプルには、日付形式とヨーロッパ式の数値表記を指定するローカライズ項目が含まれており、良い発想ですが、これはフォーマットのルールであってラップのルールではありません。このルールを完璧に守っていても、見出しがすべて英語のまま出荷されることはあり得ます。
翻訳者向けコメント。 複数の解釈ができる短い文字列、単独のアクションラベル、専門用語には、その文字列が表示される場所を説明するcomment=を付けます。context=は、同じテキストでも場所によって訳し分けが必要な場合にのみ使います。
カタログの維持。 新しい文字列はすべてラップし、各src/locales/*/messages.poに空のmsgstrを付けて追記します。これにより、翻訳が届くまではLinguiがソーステキストにフォールバックします。エージェントはlingui extractを実行しません。Lovableにはターミナルがないため、同期後にGitHub Actionが実行します。また、既存エントリの#.と#:のコメント行は、抽出時に再生成されるため、エージェントは編集しません。
この最後のパートが、このルールをLovable専用たらしめています。CursorやClaude Codeのルールファイルなら「最後にリンターを実行すること」で締められますが、Lovableのルールファイルにはそれができません。代わりに、手作業で何をすべきか、そしてCIに任せるべきことは何かを書く必要があります。
Lovableが何も実行できないとき、ルールは誰が強制するのでしょうか?
GitHubワークフローだけです。Lovableにはターミナルがないため、エージェントがリテラルを書いてから変更がリポジトリに同期されるまでの間に、lintステップが入る余地はありません。ここが、ハードコードされた文字列に対してCIのlintルールがビルドを失敗させるIDEエージェントとの構造的な違いです。
セットアップ時にオプトインすると、スキルはGitHub Actionsのワークフローを追加します。このワークフローは、Lovableの同期が反映されるデフォルトブランチへのpush時に実行され、ラップ済みの文字列をカタログに抽出し、カタログの同期結果をコミットして戻します。GitHubアプリにworkflowsの権限がない場合は、スキルがGitHub上でファイルを手動追加するよう案内します。これでエージェントがラップしたものについては、ループが完結します。しかし、エージェントがラップしなかった文字列には何も効果がありません。抽出が認識するのはマクロだけだからです。
実情はこうです。AGENTS.mdのルールがラップ漏れのリテラルの発生頻度を下げ、Knowledgeのポインタが長いチャットでそれを補強し、残りはGitHubのdiffで検出します。残りを機械に検出させたいなら、同じワークフローのステップとしてeslint-plugin-i18nextのno-literal-stringルールを追加してください。これはリポジトリ上で実行されます。Lovableプロジェクトで何かを実行できる場所は、そこしかありません。
ラップされた文字列は、その後どうなるのでしょうか?
翻訳が必要になります。そして、プロンプトをやり直すのではなく自動化する価値があるのは、まさにこの部分です。変換は一度きりで、アプリ上で行います。リポジトリを接続すると、globalize.nowがコードベースを一度だけ変換し、カタログをレビュー用のプルリクエストとして届けます。それ以降は、pushジョブが新しいカタログユニットを到着するたびに翻訳するため、火曜日にLovableが書いた<Trans>は、水曜日までに翻訳入りのプルリクエストになります。ダッシュボードでの操作も、エクスポートも、承認キューもありません。このやり方を詳しく論じた記事がダッシュボードなしでLovableアプリをローカライズするにあり、GitHub連携やglobalizeコネクターを含む具体的なセットアップ手順はLovable連携ページにあります。
ちょっとした補足です。この問題を新しく感じるLovableビルダーがいる理由がここにあります。Lovalingoはブラウザ上でLovableアプリをランタイム翻訳していたため、新しく生成された英語のコンポーネントも読み込み時に再翻訳され、この問題が表面化することはありませんでした。同サービスは2026年8月31日に終了し、移行ガイドに従ってコミット済みのカタログへ移行したアプリは、この上流の問いに初めて向き合っています。カタログ方式は正しいトレードオフです。翻訳済みのマークアップは自分のものになり、インデックスもされます。ただし、エージェントに翻訳可能なコードを書かせる必要があり、そのためにはルールの置き場所を教えなければなりません。
Lovableが読む場所にルールを置きましょう
スキルを一度実行してAGENTS.mdにルール全文を書き込み、2行のポインタをプロジェクトKnowledgeに貼り付け、エディタにはできない抽出をGitHubワークフローに任せましょう。Lovableで開発していて、カタログに載るすべての翻訳を自分で保守するのではなく任せたいなら、概要はバイブコーダー向けページに、料金は別ページの料金プランにあります。
globalize.nowは、ハードコードされたアプリ内テキストを翻訳可能なロケールファイルに変換し、リリースのたびに自動で最新の状態を保ちます。
globalize.nowを無料で試す