仕組み
@lingo.dev/compilerは、インテリジェントなコード解析とAI翻訳により、ビルド時にReactアプリケーションを多言語アプリに変換します。
ビルド時変換
従来のランタイムi18nライブラリ(i18next、react-intl)はランタイムで動作します。つまり、アプリの実行中に翻訳を読み込み、値を補間し、メッセージをフォーマットします。これにより、バンドルサイズ、ランタイムオーバーヘッド、複雑さが増加します。
@lingo.dev/compilerは異なる動作をします。ビルドプロセス中にコードを変換します。Reactコンポーネントはクリーンなままで、翻訳は最適化されたバンドルに事前コンパイルされます。
結果: ランタイムオーバーヘッドゼロ、バンドルサイズの削減、手動での翻訳キー管理が不要。
プロセス
1. AST解析
コンパイラはBabelを使用してReactコードを抽象構文木(AST)に解析します。JSXを走査し、翻訳可能なコンテンツを識別します。
- テキストノード(
<p>Hello</p>) - 文字列属性(
<img alt="Logo" />) - テンプレート式内のテキスト(
<p>Hello {name}</p>)
コンパイラはReactコンポーネントの境界を理解し、正確な翻訳のためのコンテキスト情報を維持します。技術的な識別子、コードスニペット、翻訳不要な要素は自動的にフィルタリングされます。
2. コンテンツ抽出
翻訳可能な各文字列に対して、コンパイラは以下を実行します。
- 安定したハッシュベースの識別子を生成
- コンポーネントコンテキスト(ファイル、位置、周囲の要素)を保持
- リッチテキスト構造を抽出(
<strong>や<em>などのネストされた要素を処理) - 補間プレースホルダーを維持
このメタデータは.lingo/metadata.jsonに保存されます。これは、アプリ内のすべての翻訳可能なコンテンツを追跡するバージョン管理されたファイルです。
3. 翻訳生成
開発中、翻訳サーバーがオンデマンド翻訳を処理します。
- 疑似翻訳モード(デフォルト): 即座に偽の翻訳を生成します。APIコストをかけずに何が翻訳されるかを確認するのに便利です。
- 実翻訳モード: 設定されたLLMプロバイダー(Lingo.dev EngineまたはダイレクトLLM)を呼び出します。
翻訳サービスはステートレスであり、部分的な障害を適切に処理します。一部の翻訳が失敗した場合でも、キャッシュされた翻訳は引き続き使用されます。
4. コードインジェクション
コンパイラは翻訳ルックアップをJSXに注入します。
// Your source code
<p>Hello {name}</p>
// Transformed code (simplified)
<p>{t('abc123', { name })}</p>
t()関数は最適化され、自動的に注入されます。事前にロードされた翻訳辞書でハッシュベースのルックアップを実行します。
5. バンドル最適化
ビルド時に以下が実行されます。
- ロケールごとのバンドルが作成されます
- 使用されている翻訳のみが含まれます
- デッドコード除去により未使用の翻訳が削除されます
- 辞書はコンポーネントごとにツリーシェイキングされます
開発ワークフロー
開発モード
{
dev: {
usePseudotranslator: true,
}
}
npm run devを実行すると以下が行われます。
- コンパイラが翻訳サーバーを起動します(ポート60000-60099を自動検索)
- アプリが翻訳をサーバーにリクエストします
- 疑似翻訳機能が即座に偽の翻訳を生成します
- 翻訳は
.lingo/metadata.jsonにキャッシュされます - HMRは通常通り動作し、状態は保持されます
開発ウィジェット(有効な場合)を使用すると、ブラウザ内で翻訳を編集し、変更をリアルタイムで確認できます。
本番モード
{
buildMode: "cache-only",
}
npm run buildを実行すると以下が行われます。
- 翻訳サーバーは起動しません
.lingo/metadata.jsonからのキャッシュされた翻訳のみが使用されます- 翻訳が不足している場合、明確なエラーでビルドが失敗します
- API呼び出しは行われず、APIキーは不要です
なぜキャッシュのみなのか? 本番環境では、決定論的なビルドが必要です。翻訳は本番ビルド中ではなく、CI(APIキーがある場所)で生成する必要があります。
推奨ワークフロー
ローカル開発:
- 疑似翻訳機能を使用
- 高速なフィードバックループ
- APIコストなし
CI/CD:
{
buildMode: "translate",
dev: {
usePseudotranslator: false,
}
}
- 実際の翻訳を生成
- デプロイごとに1回実行
.lingo/の変更をコミット
本番ビルド:
{
buildMode: "cache-only",
}
- 事前生成された翻訳を使用
- APIキー不要
- 高速で決定論的なビルド
アーキテクチャ
コンパイラは明確な関心の分離を中心に構成されています:
メタデータマネージャー
.lingo/metadata.jsonのCRUD操作- ファイルロックによるスレッドセーフ
- 翻訳用のハッシュベース識別子
翻訳サービス
- 翻訳ワークフローのオーケストレーション
- キャッシュ戦略の処理
- 部分的な失敗の管理
- 成功した翻訳とエラーの両方を返却
トランスレーター(ステートレス)
- Pseudotranslator: 即座の疑似翻訳
- LCP Translator: Lingo.dev Engineとの統合
- LLM Translators: プロバイダーとの直接統合
- 組み込みキャッシュなし—サービス層が処理
翻訳サーバー
- 開発用HTTPサーバー
- リアルタイムウィジェット更新のためのWebSocketサポート
- 自動ポート管理
- バッチリクエスト処理
実装の詳細については、ソースコードアーキテクチャドキュメントを参照してください。
フレームワーク統合
Next.js
コンパイラはwithLingo()ラッパー経由で統合されます:
- WebpackとTurbopackの両方をサポート
- React Server Componentsと連携
- 遅延プラグイン読み込みのための非同期設定
- 自動ロケールベースルーティング(設定されている場合)
Vite
コンパイラはlingoCompilerPlugin経由で統合されます:
- Unpluginベース(Vite、Webpack、Rollupで動作)
- 完全なHMRサポート
- 効率的な開発サーバー統合
- 自動仮想モジュール生成
よくある質問
Server Componentsで動作しますか? はい。Next.jsでは、コンパイラはServerとClient Componentsの両方を変換します。翻訳の検索はアイソモーフィックに動作します。
コード分割はどうなりますか? 翻訳はコンポーネントと一緒に自動的に分割されます。各チャンクには必要な翻訳のみが含まれます。
翻訳はどのようにキャッシュされますか?
すべての翻訳は.lingo/metadata.jsonに保存されます。このファイルはバージョン管理され、翻訳キャッシュとして機能します。コンパイラはコンテンツハッシュを使用し、新しいテキストまたは変更されたテキストのみが再翻訳をトリガーします。
翻訳が失敗した場合はどうなりますか? サービスは部分的な結果を返します。成功した翻訳はキャッシュされて使用され、エラーはデバッグ用のコンテキストと共にログに記録されます。アプリは壊れません。キャッシュされた翻訳またはソーステキストにフォールバックします。
変換されたコードを確認できますか?
はい。ビルド出力で変換されたファイルを確認できます。変換は最小限です。ハッシュベースのルックアップを使用した t() 関数呼び出しのみです。