diff --git a/.gitignore b/.gitignore index b5ffcaa..bfd59aa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .internationalizer/ dist/ /*.tgz +/.env diff --git a/.internationalizer.example.yml b/.internationalizer.example.yml index 9efb008..b611c43 100644 --- a/.internationalizer.example.yml +++ b/.internationalizer.example.yml @@ -15,10 +15,6 @@ llm: api_key_env: GOOGLE_AI_STUDIO_API_KEY # env var containing your API key # base_url: https://api.openai.com # for OpenAI-compatible endpoints locale_overrides: # optional provider/model settings by target locale - ja: - provider: openrouter - model: sakana/sakana-namazu - api_key_env: OPENROUTER_API_KEY yue: provider: openrouter model: deepseek/deepseek-v4-flash-0731 diff --git a/.internationalizer.yml b/.internationalizer.yml index b710d5b..cd216de 100644 --- a/.internationalizer.yml +++ b/.internationalizer.yml @@ -44,10 +44,6 @@ llm: model: gemini-3.8-flash api_key_env: GOOGLE_AI_STUDIO_API_KEY locale_overrides: - ja: - provider: openrouter - model: sakana/sakana-namazu - api_key_env: OPENROUTER_API_KEY yue: provider: openrouter model: deepseek/deepseek-v4-flash-0731 diff --git a/README.md b/README.md index 179dbf7..442f7a3 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Internationalizer is different. It's a **CLI pipeline** that combines LLM transl - **Per-language glossaries** — enforce consistent terminology across your app - **Per-language style guides** — control tone, formality, pluralization, and typography - **Translation memory** — skip unchanged strings, save money on API calls -- **Key validation** — catch missing translations and interpolation mismatches before they ship +- **Deterministic validation** — catch missing or extra keys, protected-structure drift, glossary issues, and plural or ICU errors before they ship ## Installation @@ -115,7 +115,7 @@ internationalizer validate ### `translate` -Find missing keys and translate them via an LLM. +Find missing or stale keys and translate them via an LLM. ```bash internationalizer translate # translate all locales @@ -262,10 +262,6 @@ llm: # global provider inherits unspecified global settings. A different provider # uses that provider's defaults for unspecified settings. locale_overrides: - ja: - provider: openrouter - model: sakana/sakana-namazu - api_key_env: OPENROUTER_API_KEY yue: provider: openrouter model: deepseek/deepseek-v4-flash-0731 @@ -306,6 +302,8 @@ validation: Locale identifiers must be well-formed BCP 47 tags such as `fr`, `pt-BR`, or `sr-Latn-RS`. Canonical-equivalent target locales are rejected as duplicates, and locale-specific provider overrides match canonical-equivalent spelling. +In the example above, locales without an override—including Japanese—inherit +the global Gemini configuration. ICU MessageFormat values are parsed structurally. Simple arguments, `select`, `plural`, `selectordinal`, `number`, `date`, and `time` are supported, including @@ -371,12 +369,16 @@ findings; it does not exempt a longer value merely containing `API`. Translation memory is stored as a JSONL file (one JSON record per line). Each record contains: -- The source key and value -- The translated value -- A SHA-256 hash of the source value +- The bundle, key, source value, translated value, and canonical target locale +- Source and translation-policy hashes +- The provider and model that produced the translation - A timestamp -On subsequent runs, unchanged strings are served from the TM cache without calling the LLM, saving both time and API costs. The TM file is git-friendly and can be committed alongside your locale files. +On subsequent runs, strings with the same source and policy hashes are served +from the cache without calling the LLM. The default path is under the ignored +`.internationalizer/` directory, so it remains a local cache. Set `tm_path` to a +tracked location if your project intentionally shares translation memory. The +reviewable `.internationalizer.lock` manifest is versioned separately. ## Supported Formats @@ -410,6 +412,8 @@ internal/ OpenRouter uses openai.go with custom base_url locale/ BCP 47 identity and CLDR plural categories message/ ICU MessageFormat parser and structural comparison + policy/ Stable translation-policy hashing + state/ Versioned translation manifest styleguide/ Style guide loader tm/ JSONL translation memory translate/ Translation orchestrator diff --git a/docs/i18n/ja.md b/docs/i18n/ja.md index a0428f3..fb73950 100644 --- a/docs/i18n/ja.md +++ b/docs/i18n/ja.md @@ -9,46 +9,52 @@ ソフトウェアプロジェクト向けのAIネイティブな国際化パイプラインです。LLMを使用してi18nファイルの翻訳、検証、管理を行います。 [![CI](https://github.com/Tom-R-Main/Internationalizer/actions/workflows/ci.yml/badge.svg)](https://github.com/Tom-R-Main/Internationalizer/actions/workflows/ci.yml) -[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) +[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](../../LICENSE) -## なぜ Internationalizer なのか? +

+العربية · বাংলা · Čeština · Dansk · Deutsch · Ελληνικά · Español · Suomi · Français · עברית · हिन्दी · Indonesia · Italiano · 日本語 · 한국어 · Bahasa Melayu
Nederlands · ਪੰਜਾਬੀ · Polski · Português · Română · Русский · Svenska · తెలుగు · ไทย · Türkçe · Українська · Tiếng Việt · 粵語 · 简体中文 · 繁體中文 +

+ +--- -ほとんどのi18nツールは、ランタイムライブラリ(i18next、react-intl)か、キー管理SaaSプラットフォーム(Crowdin、Lokalise)のいずれかです。しかし、どれも実際の翻訳問題をうまく解決できていません。 +## Internationalizerを選ぶ理由 -- **手動翻訳**は、少数の言語を超えるとスケールしません。 -- **機械翻訳API**(Google Translate、DeepL)は、専門用語、トーン、UIの規則を無視します。 -- **一般的なLLM翻訳**はより良く機能しますが、用語集やスタイルガイドがないと、一貫性のない結果になります。 +一般的なi18nツールの多くは、ランタイムライブラリ(i18next、react-intl)か、キー管理SaaSプラットフォーム(Crowdin、Lokalise)のいずれかです。しかし、実際の翻訳課題を適切に解決できているツールはありません。 -Internationalizerは違います。LLM翻訳と以下を組み合わせた**CLIパイプライン**です。 +- **手動翻訳**は、数言語を超えると対応しきれなくなります +- **機械翻訳API**(Google翻訳、DeepL)は、専門用語、トーン、UIの規則を無視します +- **汎用LLM翻訳**は精度が高いものの、用語集やスタイルガイドがなければ出力結果にばらつきが生じます -- **言語ごとの用語集** — アプリ全体で一貫した専門用語を強制します。 -- **言語ごとのスタイルガイド** — トーン、フォーマルさ、複数形、タイポグラフィを制御します。 -- **翻訳メモリ** — 変更されていない文字列をスキップし、API呼び出しのコストを節約します。 -- **キーの検証** — リリース前に、翻訳の欠落や補間の不一致を検出します。 +Internationalizerは異なります。LLM翻訳と以下の機能を組み合わせた**CLIパイプライン**です。 + +- **言語ごとの用語集** — アプリケーション全体で一貫した用語を適用 +- **言語ごとのスタイルガイド** — トーン、丁寧さの度合い、複数形、タイポグラフィを制御 +- **翻訳メモリ** — 変更のない文字列をスキップし、API呼び出しコストを削減 +- **決定論的な検証** — リリース前にキーの欠落や余分なキー、保護対象の構造の差異、用語集違反、複数形やICUのエラーを検出 ## インストール -npmからのインストール: +npmでのインストール ```bash npm install -g internationalizer ``` -または、グローバルインストールせずに実行する場合: +グローバルインストールせずに実行 ```bash npx internationalizer --help ``` -npmパッケージは、プラットフォーム固有のオプションの依存関係を介して、npmから一致するビルド済みバイナリをインストールします。 +npmパッケージは、プラットフォーム固有のオプション依存関係を介して、対応するビルド済みバイナリをnpmから自動的にインストールします。 -Goでのインストール: +Goでのインストール ```bash go install github.com/Tom-R-Main/Internationalizer/cmd/internationalizer@latest ``` -または、ソースからのビルド: +ソースからのビルド ```bash git clone https://github.com/Tom-R-Main/Internationalizer.git @@ -58,20 +64,24 @@ go build -o internationalizer ./cmd/internationalizer ## npmパッケージ -- Gitタグとnpmパッケージのバージョンは一致している必要があります(例: `v0.1.0` と `0.1.0`)。 -- ルートの `internationalizer` パッケージは、`internationalizer-darwin-arm64` などのプラットフォームパッケージに依存しています。 -- サポートされているnpmターゲット: macOS arm64/x64、Linux arm64/x64、Windows x64 -- CIでの公開には、`NPM_TOKEN` という名前のGitHubシークレットが必要です。 +- Gitタグとnpmパッケージのバージョンは一致している必要があります(例:`v0.1.0`と`0.1.0`) +- ルートの`internationalizer`パッケージは、`internationalizer-darwin-arm64`などのプラットフォーム別パッケージに依存します +- サポート対象のnpmターゲット:macOS arm64/x64、Linux arm64/x64、Windows x64 +- CIでのパッケージ公開には、`NPM_TOKEN`という名前のGitHubシークレットが必要です ## クイックスタート -1. プロジェクトのルートに設定ファイルを作成します: +1. プロジェクトのルートに設定ファイルを作成します。 ```yaml # .internationalizer.yml source_locale: en target_locales: [fr, de, es, ja] -source_path: locales/en.json +bundles: + - id: app + source: locales/en.json + target: locales/{locale}.json + format: json llm: provider: gemini @@ -79,25 +89,25 @@ llm: api_key_env: GOOGLE_AI_STUDIO_API_KEY ``` -2. APIキーを設定します: +2. APIキーを設定します。 ```bash export GOOGLE_AI_STUDIO_API_KEY=your-ai-studio-key ``` -3. 翻訳される内容をプレビューします: +3. 翻訳対象をプレビューします。 ```bash internationalizer translate --dry-run ``` -4. 翻訳を実行します: +4. 翻訳を実行します。 ```bash internationalizer translate ``` -5. すべてのロケールを検証します: +5. すべてのロケールを検証します。 ```bash internationalizer validate @@ -107,39 +117,67 @@ internationalizer validate ### `translate` -欠落しているキーを見つけ、LLMを介して翻訳します。 +欠落しているキーや古くなったキーを検出し、LLM経由で翻訳します。 ```bash internationalizer translate # すべてのロケールを翻訳 internationalizer translate -l fr # フランス語のみ翻訳 internationalizer translate --dry-run # APIを呼び出さずにプレビュー -internationalizer translate --batch-size 20 # バッチサイズを小さくする -internationalizer translate --concurrency 2 # 並行呼び出しを減らす +internationalizer translate --adopt-existing # APIを呼び出さずに既存の翻訳をベースライン化 +internationalizer translate --refresh-policy # プロンプト/スタイル/モデルの変更により古くなったエントリを更新 +internationalizer translate --batch-size 20 # より小さいバッチサイズで実行 +internationalizer translate --concurrency 2 # 並行呼び出し数を抑えて実行 ``` +翻訳状態は、欠落(missing)、ソース変更(source-stale)、ポリシー変更(policy-stale)、最新(current)、手動編集済み(manually edited)の状態を個別にレポートするため、手動編集によってソースやポリシーの変更が覆い隠されることはありません。ポリシー変更によって古くなった値はレポートされますが、`--refresh-policy`を指定した場合にのみ再翻訳されます。手動編集された値が自動的に上書きされることは決してありません。レビュー済みの翻訳にマニフェストを導入する場合や、レビュー済みの手動編集を新しいベースラインとして明示的に受け入れる場合は、`--adopt-existing`を使用してください。 + ### `validate` -すべてのロケールファイルをチェックし、キーの欠落、余分なキー、補間の不一致がないか確認します。 +すべてのロケールファイルをソースバンドルと照合します。デフォルトでは、必須ターゲットキーの充足率を検査し、余分なキーを警告として報告します。キーの欠落、補間パラメータの不一致、ICU MessageFormatの構文エラーがある場合は失敗します。 ```bash -internationalizer validate # 人間が読める形式で出力 +internationalizer validate # 人間が読みやすい形式で出力 internationalizer validate --json # 機械可読なJSON形式で出力 internationalizer validate -q # 終了コードのみ出力 +internationalizer validate --strict # 翻訳品質に関する規則を適用 +internationalizer validate --require-state # マニフェストが最新であることを必須化 ``` +`--strict`では翻訳済みの割合も報告します。言語表現としての値がソースと同一の場合、用語集にその値全体についてソースとターゲットが完全に同じ項目がない限り、未翻訳と判定されます。`ignore_case`は考慮されますが、長い値の一部に用語集の語が含まれるだけでは除外されません。strictモードでは、余分なキー、ソースと同一の値、補間・HTML・コード・Markdownリンクの構造変更、用語集違反、設定された複数形の不足があると失敗します。 + +`--require-state`は、各ターゲットを`.internationalizer.lock`と照合します。キーが未記録の場合や、記録されたソース、翻訳ポリシー、ターゲットのハッシュが古い場合は失敗します。`--strict`と併用できます。 + +人間向けレポートとJSONレポートでは、次の安定した検出コードを使用します。 + +| コード | 意味 | +| --- | --- | +| `missing_key` / `extra_key` | ソースとターゲットのキー集合が一致していない | +| `blank_translation` | 空でないソースに対するstrictモードのターゲットが空 | +| `source_identical` | 言語表現としての値がstrictモードでもソースと同一 | +| `protected_structure_mismatch` | 補間、HTML、コード、リンクの構造が変更されている | +| `glossary_violation` | 承認済みのターゲット用語または異表記が見つからない | +| `plural_form_missing` | 設定されたロケールの複数形が不足している | +| `icu_message_syntax` | ソースまたはターゲットのICUメッセージが不正 | +| `icu_argument_mismatch` | ICUの引数名、種類、フォーマッタースタイルが一致していない | +| `icu_selector_mismatch` | セレクターが一致していない、または複数形カテゴリーがターゲットロケールで無効 | +| `untracked` | ターゲットに対応するマニフェストレコードがない | +| `source_stale` | 記録後にソースの内容が変更された | +| `policy_stale` | 生成プロンプトまたはモデル設定が変更された | +| `target_modified` | ターゲットの内容がマニフェストの記録と異なる | + ### `detect` -i18nフレームワークを自動検出し、設定を提案します。 +使用中のi18nフレームワークを自動検出し、推奨設定を提案します。 ```bash internationalizer detect ``` -サポート対象: react-i18next、next-intl、vue-i18n、プレーンなJSON、Markdownドキュメント。 +サポート対象:react-i18next、next-intl、vue-i18n、プレーンなJSON、Markdownドキュメント。 ### `glossary` -翻訳時に強制される言語ごとの用語集を管理します。 +翻訳時に適用される言語ごとの用語集を管理します。 ```bash internationalizer glossary list --locale fr @@ -149,11 +187,11 @@ internationalizer glossary remove --locale fr --source "Dashboard" ### `tm` -翻訳メモリ(過去に翻訳された文字列のJSONLキャッシュ)を管理します。 +翻訳メモリ(過去に翻訳された文字列を保存するJSONLキャッシュ)を管理します。 ```bash internationalizer tm stats # レコード数を表示 -internationalizer tm export # JSONとしてダンプ +internationalizer tm export # JSON形式でダンプ出力 internationalizer tm clear --force # すべてのレコードを削除 ``` @@ -162,52 +200,100 @@ internationalizer tm clear --force # すべてのレコードを削 ```yaml # .internationalizer.yml -# ソース言語(デフォルト: en) +# ソース言語(デフォルト:en) source_locale: en -# 翻訳先の言語(必須) -target_locales: [fr, de, es, ja, zh-CN, ar] - -# ソースロケールファイルへのパス(必須) -source_path: locales/en.json - -# LLMプロバイダーの設定 +# 翻訳先言語(必須) +target_locales: [fr, de, es, ja, yue, zh-CN, zh-TW, ar] + +# 1つ以上のソースからターゲットへのマッピング(必須)。 +# {locale}は設定された各ターゲットロケールに置換されます。 +bundles: + - id: app + source: locales/en.json + target: locales/{locale}.json + format: json + - id: docs + source: README.md + target: docs/i18n/{locale}.md + format: markdown + +# 下位互換性:source_pathも引き続きlocales/fr.jsonなどの兄弟ファイルへターゲットをマッピングします。 +# 新規プロジェクトではbundlesの使用を推奨します。 +# source_path: locales/en.json + +# LLMプロバイダー設定 llm: - # プロバイダー: "anthropic"、"openai"、"gemini"、または "openrouter"(デフォルト: gemini) + # プロバイダー:「anthropic」、「openai」、「gemini」、または「openrouter」(デフォルト:gemini) provider: gemini - # プロバイダーごとのデフォルトモデル名: + # プロバイダーごとのデフォルトモデル名 # anthropic: claude-opus-5 - # openai: gpt-5.6-luna + # openai: gpt-5.6-luna(推論強度のデフォルトはmax) # gemini: gemini-3.8-flash # openrouter: deepseek/deepseek-v4-pro-0813 model: gemini-3.8-flash - # APIキーを含む環境変数 + # APIキーを格納した環境変数名 api_key_env: GOOGLE_AI_STUDIO_API_KEY # OpenAI互換エンドポイントのベースURL(オプション) # base_url: https://api.openai.com -# LLM呼び出しあたりのキー数(デフォルト: 40) + # OpenAI GPT-5シリーズ Responses APIの推論強度 + # (OpenAIプロバイダーのデフォルト:max) + reasoning_effort: max + + # 特定のターゲットロケールに対するオプションのLLM設定。 + # グローバル設定と同一のプロバイダーを使用する言語オーバーライドは、未指定の項目にグローバル設定を継承します。 + # 異なるプロバイダーを指定した場合、未指定の項目にはそのプロバイダーのデフォルト値が適用されます。 + locale_overrides: + yue: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + zh-CN: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + zh-TW: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + +# LLM呼び出しあたりのキー数(デフォルト:40) batch_size: 40 -# 並行LLM呼び出し数(デフォルト: 4) +# LLMの並行呼び出し数(デフォルト:4) concurrency: 4 -# 言語ごとのスタイルガイドMarkdownファイルを含むディレクトリ(デフォルト: style-guides) +# ロケール別スタイルガイドMarkdownファイルを格納するディレクトリ(デフォルト:style-guides) style_guides_dir: style-guides -# 言語ごとの用語集JSONファイルを含むディレクトリ(デフォルト: glossary) +# ロケール別用語集JSONファイルを格納するディレクトリ(デフォルト:glossary) glossary_dir: glossary -# 翻訳メモリファイルへのパス(デフォルト: .internationalizer/tm.jsonl) +# 翻訳メモリファイルへのパス(デフォルト:.internationalizer/tm.jsonl) tm_path: .internationalizer/tm.jsonl + +# ソース、ポリシー、ターゲット、および来歴情報のバージョン管理状態 +# (デフォルト:.internationalizer.lock。このファイルをコミットしてください) +manifest_path: .internationalizer.lock + +# 翻訳とstrict検証に関するオプション規則 +validation: + plural_style: i18next-v4 # ターゲットロケールの複数形を生成して検証 ``` +ロケール識別子には、`fr`、`pt-BR`、`sr-Latn-RS`など、正しい形式のBCP 47タグを指定してください。正規化すると同一になるターゲットロケールは重複として拒否され、ロケール別のプロバイダーオーバーライドも正規化後の表記で照合されます。上の例では、日本語を含むオーバーライドのないロケールは、グローバルなGemini設定を継承します。 + +ICU MessageFormatの値は構造として解析されます。単純な引数のほか、`select`、`plural`、`selectordinal`、`number`、`date`、`time`に対応し、メッセージのネスト、複数形のオフセット、数値セレクター、`#`も使用できます。検証では、構文、引数の種類とフォーマッタースタイル、複数形のオフセット、selectの分岐、ターゲットロケールのCLDR複数形カテゴリーを確認します。これらの条件を破るプロバイダー出力は、ロケールファイルや翻訳メモリへ書き込まれる前に拒否されます。 + +`i18next-v4`を指定すると、認識されたソースの複数形ファミリーが、翻訳時にターゲットロケールのCLDRカテゴリーへ展開されます。ターゲットにしかないカテゴリーでは、ソースファミリーの`_other`値を翻訳テンプレートとして使用します。strict検証ではターゲットに必要なカテゴリーを必須とし、ターゲットロケールで使用しないソース側だけのカテゴリーは任意として扱います。 + ## スタイルガイド -スタイルガイドは、LLMの翻訳プロンプトに注入されるMarkdownファイルです。トーン、フォーマルさ、タイポグラフィ、その他の言語固有の規則を制御します。 +スタイルガイドは、LLMの翻訳プロンプトに挿入されるMarkdownファイルです。トーン、丁寧さの度合い、タイポグラフィ、その他の言語固有の規則を制御します。 ``` style-guides/ @@ -217,98 +303,105 @@ style-guides/ ar.md # アラビア語固有のルール ``` -### 共通の規則 (`_conventions.md`) +### 共通規則 (`_conventions.md`) -すべての言語に適用されるルールを定義します。補間構文、HTMLの保持、文字列タイプの規則(ボタン、ラベル、エラーなど)が含まれます。 +すべての言語に適用されるルールを定義します。補間構文、HTMLの保持、文字列種別ごとの規則(ボタン、ラベル、エラーメッセージなど)を指定します。 -### 言語ごとのガイド (`{locale}.md`) +### 言語別ガイド (`{locale}.md`) -言語固有のルールを定義します。フォーマルさのレベル(tu と vous など)、句読点(ギュメ、逆疑問符など)、複数形、日付/数値のフォーマット、専門用語の用語集が含まれます。 +言語固有のルールを定義します。丁寧さの度合い(「tu」と「vous」の使い分けなど)、句読点(ギュメ、逆疑問符など)、複数形、日付や数値の書式、用語集を指定します。 -実際の例については、[`examples/react-app/style-guides/`](examples/react-app/style-guides/) を参照してください。 +実際の構成例については、[`examples/react-app/style-guides/`](../../examples/react-app/style-guides/)を参照してください。 -## 用語集のフォーマット +## 用語集の形式 -用語集ファイルは、`{glossary_dir}/{locale}.json` に保存されるJSON配列です: +用語集ファイルは、`{glossary_dir}/{locale}.json`に配置するJSON配列です。 ```json [ { "source": "Dashboard", "target": "Tableau de bord", + "variants": ["Panneau de contrôle"], + "enforcement": "error", "ignore_case": false, "whole_word": true } ] ``` -用語は用語表としてLLMプロンプトに注入され、アプリケーション全体で重要な用語が一貫して翻訳されるようにします。 +`variants`には、承認済みの別表記を指定します。`enforcement`には`error`または`warning`を指定でき、省略時は`error`です。用語は対照表としてLLMプロンプトに挿入され、アプリケーション全体で一貫した翻訳に使用されます。`{"source":"API","target":"API"}`のようにソースとターゲットが完全に同じ項目を登録すると、その値全体はstrict検証の未翻訳判定から除外されます。長い値の一部に`API`が含まれるだけでは除外されません。 ## 翻訳メモリ -翻訳メモリはJSONLファイル(1行に1つのJSONレコード)として保存されます。各レコードには以下が含まれます: +翻訳メモリはJSONLファイル(1行につき1件のJSONレコード)として保存されます。各レコードには以下の情報が含まれます。 -- ソースのキーと値 -- 翻訳された値 -- ソース値のSHA-256ハッシュ +- バンドル、キー、ソース値、翻訳後の値、正規化されたターゲットロケール +- ソースと翻訳ポリシーのハッシュ +- 翻訳に使用したプロバイダーとモデル - タイムスタンプ -次回以降の実行では、変更されていない文字列はLLMを呼び出すことなくTMキャッシュから提供されるため、時間とAPIコストの両方を節約できます。TMファイルはGitと相性が良く、ロケールファイルと一緒にコミットできます。 +次回以降の実行時には、ソースとポリシーのハッシュが同じ文字列がLLMを呼び出さずにキャッシュから取得されます。デフォルトの保存先はGit管理から除外された`.internationalizer/`ディレクトリ内なので、ローカルキャッシュとして扱われます。翻訳メモリを意図的に共有する場合は、`tm_path`をGit管理対象のパスへ変更してください。レビュー可能な`.internationalizer.lock`マニフェストは別途バージョン管理されます。 -## サポートされているフォーマット +## サポート対象の形式 -| フォーマット | 拡張子 | モード | +| 形式 | 拡張子 | 処理モード | |--------|-----------|------| -| JSON | `.json` | キーバリュー(ネスト、ドット記法によるフラット化) | -| YAML | `.yml`, `.yaml` | キーバリュー(コメントと順序を保持) | +| JSON | `.json` | キーバリュー(ネスト対応、ドット記法による平坦化) | +| YAML | `.yml`, `.yaml` | キーバリュー(コメントと記述順序を保持) | | Markdown | `.md`, `.mdx` | ドキュメント全体の翻訳 | ## プロジェクトタイプの検出 -`internationalizer detect` は以下をチェックしてi18nの設定を特定します: +`internationalizer detect`は、以下の項目を検査してi18n構成を特定します。 -- `package.json` の依存関係(react-i18next、next-intl、vue-i18n) -- 一般的なロケールパターンに一致するディレクトリ構造 -- ファイルの拡張子と命名規則 +- `package.json`内のreact-i18next、next-intl、vue-i18nなどの依存関係 +- 一般的なロケール配置パターンに一致するディレクトリ構造 +- ファイル拡張子および命名規則 ## アーキテクチャ ``` -cmd/internationalizer/ CLIエントリポイントとコマンド定義 +cmd/internationalizer/ CLIエントリポイントと各コマンドの定義 internal/ - config/ デフォルト値付きのYAML設定の読み込み + config/ デフォルト値を適用したYAML設定の読み込み detect/ プロジェクトタイプの自動検出 formats/ フォーマットパーサー(JSON、YAML、Markdown) - glossary/ 言語ごとの用語集管理 + glossary/ ロケール別用語集の管理 llm/ LLMプロバイダーのインターフェースと実装 anthropic.go Anthropic Claudeバックエンド - openai.go OpenAI / 互換バックエンド - gemini.go AI Studio経由のGoogle Geminiバックエンド - OpenRouterはカスタムbase_urlでopenai.goを使用 - styleguide/ スタイルガイドローダー - tm/ JSONL翻訳メモリ - translate/ 翻訳オーケストレーター - validate/ ロケールの検証と差分確認 + openai.go OpenAI / 互換エンドポイントバックエンド + gemini.go Google AI Studio経由のGeminiバックエンド + OpenRouterはカスタムbase_urlを指定してopenai.goを使用 + locale/ BCP 47ロケールIDとCLDR複数形カテゴリー + message/ ICU MessageFormatのパーサーと構造比較 + policy/ 安定した翻訳ポリシーのハッシュ化 + state/ バージョン管理される翻訳マニフェスト + styleguide/ スタイルガイドの読み込み + tm/ JSONL形式の翻訳メモリ + translate/ 翻訳処理のオーケストレーター + validate/ ロケールの検証と差分抽出 ``` ## 代替ツールとの比較 -| 機能 | Internationalizer | i18next | Crowdin | 一般的なLLM | +| 機能 | Internationalizer | i18next | Crowdin | 汎用LLM | |---------|------------------|---------|---------|-------------| -| LLMによる翻訳 | はい | いいえ | 一部 | はい | +| LLMを活用した翻訳 | はい | いいえ | 一部対応 | はい | | 言語ごとのスタイルガイド | はい | いいえ | いいえ | いいえ | -| 用語集の強制 | はい | いいえ | はい | いいえ | +| 用語集の強制適用 | はい | いいえ | はい | いいえ | | 翻訳メモリ | はい | いいえ | はい | いいえ | -| CLI / ローカル実行 | はい | N/A | いいえ | 手動 | -| Gitと相性の良いファイル | はい | はい | 一部 | 手動 | -| SaaS依存なし | はい | はい | いいえ | ツールによる | -| オープンソース (AGPL-3.0) | はい | はい | いいえ | ツールによる | +| CLI / ローカル環境での実行 | はい | 該当なし | いいえ | 手動 | +| Git管理に適したファイル形式 | はい | はい | 一部対応 | 手動 | +| SaaSへの依存なし | はい | はい | いいえ | ツールによる | +| オープンソース(AGPL-3.0) | はい | はい | いいえ | ツールによる | ## ライセンス -[AGPL-3.0](LICENSE) +[AGPL-3.0](../../LICENSE) -## コントリビューション +依存関係に関する通知は、[THIRD_PARTY_NOTICES.md](../../THIRD_PARTY_NOTICES.md)を参照してください。 -開発のセットアップとガイドラインについては、[CONTRIBUTING.md](CONTRIBUTING.md) を参照してください。すべてのコントリビューションにはDCOの署名が必要です。 +## コントリビューション +開発環境のセットアップおよびガイドラインについては、[CONTRIBUTING.md](../../CONTRIBUTING.md)を参照してください。すべてのコントリビューションにはDCO(開発者原産性証明)への署名(サインオフ)が必須です。 diff --git a/docs/i18n/zh-CN.md b/docs/i18n/zh-CN.md index 5e10d2d..1ea86bf 100644 --- a/docs/i18n/zh-CN.md +++ b/docs/i18n/zh-CN.md @@ -1,30 +1,34 @@ -> [English (original)](../../README.md) -

Internationalizer

# Internationalizer -面向软件项目的 AI 原生国际化流水线。使用 LLM 翻译、验证和管理 i18n 文件。 +面向软件项目的 AI 原生国际化流水线。基于大语言模型(LLM)实现 i18n 文件的翻译、校验与管理。 [![CI](https://github.com/Tom-R-Main/Internationalizer/actions/workflows/ci.yml/badge.svg)](https://github.com/Tom-R-Main/Internationalizer/actions/workflows/ci.yml) -[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) +[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](../../LICENSE) + +

+العربية · বাংলা · Čeština · Dansk · Deutsch · Ελληνικά · Español · Suomi · Français · עברית · हिन्दी · Indonesia · Italiano · 日本語 · 한국어 · Bahasa Melayu
Nederlands · ਪੰਜਾਬੀ · Polski · Português · Română · Русский · Svenska · తెలుగు · ไทย · Türkçe · Українська · Tiếng Việt · 粵語 · 简体中文 · 繁體中文 +

+ +--- ## 为什么选择 Internationalizer? -大多数 i18n 工具要么是运行时库(i18next、react-intl),要么是键值管理 SaaS 平台(Crowdin、Lokalise)。它们都没有很好地解决实际的翻译问题: +多数 i18n 工具要么属于运行时库(如 i18next、react-intl),要么属于翻译键管理 SaaS 平台(如 Crowdin、Lokalise)。它们均未能从根本上解决实际翻译问题: -- **人工翻译** 在语言数量增加后难以扩展 -- **机器翻译 API**(Google Translate、DeepL)会忽略你的术语、语调和 UI 约定 -- **通用 LLM 翻译** 效果更好,但如果没有术语表和样式指南,翻译结果会不一致 +- **人工翻译**:支持语言一旦增多便难以扩展 +- **机器翻译 API**(Google Translate、DeepL):无视术语库、语气要求与 UI 规范 +- **通用 LLM 翻译**:效果虽有提升,但缺少术语表与样式指南时,译文风格容易脱节 -Internationalizer 则不同。它是一个 **CLI 流水线**,将 LLM 翻译与以下功能结合: +Internationalizer 则另辟蹊径。它是一套 **CLI 流水线**,将 LLM 翻译与以下能力深度结合: -- **单语言术语表** — 确保整个应用中的术语一致 -- **单语言样式指南** — 控制语调、正式程度、复数形式和排版 -- **翻译记忆库** — 跳过未更改的字符串,节省 API 调用成本 -- **键值验证** — 在发布前捕获缺失的翻译和插值不匹配问题 +- **各语言术语表** — 确保全系统专业术语统一 +- **各语言风格指南** — 规范语气、正式程度、复数规则及排版格式 +- **翻译记忆库** — 自动跳过未修改字段,节省 API 调用开销 +- **确定性校验** — 在发布前发现翻译键缺失或多余、受保护结构变更、术语表违规,以及复数或 ICU 错误 ## 安装 @@ -34,21 +38,21 @@ Internationalizer 则不同。它是一个 **CLI 流水线**,将 LLM 翻译与 npm install -g internationalizer ``` -或者不进行全局安装直接运行: +无需全局安装直接运行: ```bash npx internationalizer --help ``` -npm 包会通过特定平台的预构建可选依赖项,从 npm 安装匹配的预构建二进制文件。 +npm 包会借助对应平台的可选依赖,从 npm 拉取并安装匹配的预构建二进制文件。 -通过 Go 安装: +使用 Go 安装: ```bash go install github.com/Tom-R-Main/Internationalizer/cmd/internationalizer@latest ``` -或者从源码构建: +从源码编译: ```bash git clone https://github.com/Tom-R-Main/Internationalizer.git @@ -56,22 +60,26 @@ cd Internationalizer go build -o internationalizer ./cmd/internationalizer ``` -## npm 包 +## npm 软件包 -- Git 标签和 npm 包版本必须匹配,例如 `v0.1.0` 和 `0.1.0` -- 根 `internationalizer` 包依赖于平台包,例如 `internationalizer-darwin-arm64` +- Git 标签版本必须与 npm 包版本严格一致,例如 `v0.1.0` 与 `0.1.0` +- 顶层 `internationalizer` 包依赖各平台分发包,例如 `internationalizer-darwin-arm64` - 支持的 npm 目标平台:macOS arm64/x64、Linux arm64/x64、Windows x64 -- CI 发布需要一个名为 `NPM_TOKEN` 的 GitHub secret +- CI 发布流水线需在 GitHub Secret 中配置 `NPM_TOKEN` -## 快速开始 +## 快速上手 -1. 在项目根目录创建一个配置文件: +1. 在项目根目录下创建配置文件: ```yaml # .internationalizer.yml source_locale: en target_locales: [fr, de, es, ja] -source_path: locales/en.json +bundles: + - id: app + source: locales/en.json + target: locales/{locale}.json + format: json llm: provider: gemini @@ -79,67 +87,95 @@ llm: api_key_env: GOOGLE_AI_STUDIO_API_KEY ``` -2. 设置你的 API 密钥: +2. 配置 API 密钥: ```bash export GOOGLE_AI_STUDIO_API_KEY=your-ai-studio-key ``` -3. 预览将要翻译的内容: +3. 预览待翻译内容: ```bash internationalizer translate --dry-run ``` -4. 运行翻译: +4. 执行翻译: ```bash internationalizer translate ``` -5. 验证所有语言环境: +5. 校验所有语言环境文件: ```bash internationalizer validate ``` -## 命令 +## 命令列表 ### `translate` -查找缺失的键值并通过 LLM 进行翻译。 +检索缺失或已过期的键,并通过 LLM 自动完成翻译。 ```bash -internationalizer translate # 翻译所有语言环境 +internationalizer translate # 翻译全部语言环境 internationalizer translate -l fr # 仅翻译法语 -internationalizer translate --dry-run # 预览但不调用 API -internationalizer translate --batch-size 20 # 较小的批处理大小 -internationalizer translate --concurrency 2 # 较少的并发调用 +internationalizer translate --dry-run # 预览变更,不产生 API 调用 +internationalizer translate --adopt-existing # 将现有翻译纳为基线,不产生 API 调用 +internationalizer translate --refresh-policy # 重新翻译因提示词/样式指南/模型变更而过期的条目 +internationalizer translate --batch-size 20 # 减小批处理大小 +internationalizer translate --concurrency 2 # 降低并发请求数 ``` +翻译状态会分别独立跟踪缺失(missing)、源文过期(source-stale)、策略过期(policy-stale)、最新(current)以及手动修改(manually edited)等情况,手动编辑不会掩盖源文本或策略的变动。策略过期的词条会被列出,但仅在传入 `--refresh-policy` 时才会触发重新翻译。系统绝不会自动覆盖手动编辑的内容。初次为已审校的译文引入清单文件,或明确将人工修改确认采纳为新基线时,请使用 `--adopt-existing`。 + ### `validate` -检查所有语言环境文件是否存在缺失键、多余键以及插值不匹配的问题。 +将所有语言环境文件与源文件包进行比对。默认校验会计算必需目标翻译键的覆盖率,将多余翻译键列为警告,并在翻译键缺失、插值变量不匹配或 ICU MessageFormat 结构无效时失败。 ```bash -internationalizer validate # 人类可读的输出 -internationalizer validate --json # 机器可读的 JSON -internationalizer validate -q # 仅返回退出码 +internationalizer validate # 人类可读文本输出 +internationalizer validate --json # 机器可读 JSON 输出 +internationalizer validate -q # 静默模式,仅返回退出码 +internationalizer validate --strict # 强制执行翻译质量规则 +internationalizer validate --require-state # 要求清单中的溯源状态为最新 ``` +`--strict` 还会报告实际翻译覆盖率。语言内容若与源文完全相同,会被视为未翻译;只有术语表为完整值明确配置了源文与译文相同的精确条目时才会豁免。校验会遵守 `ignore_case`,但较长文本中仅包含某个术语表词条并不能获得豁免。严格模式会在存在多余翻译键、与源文相同的值、插值/HTML/代码/Markdown 链接结构变更、术语表违规或缺少已配置复数形式时失败。 + +`--require-state` 会将每个目标值与 `.internationalizer.lock` 比对。翻译键未被跟踪,或清单记录的源文、翻译策略、目标哈希已过期时,校验都会失败。该选项可与 `--strict` 同时使用。 + +人工可读报告与 JSON 报告使用以下稳定的问题代码: + +| 代码 | 含义 | +| --- | --- | +| `missing_key` / `extra_key` | 源文件与目标文件的翻译键集合不一致 | +| `blank_translation` | 非空源文对应的严格模式译文为空 | +| `source_identical` | 严格模式下语言内容仍与源文相同 | +| `protected_structure_mismatch` | 插值、HTML、代码或链接结构发生变化 | +| `glossary_violation` | 未找到获准使用的目标术语或变体 | +| `plural_form_missing` | 缺少为该语言配置的复数形式 | +| `icu_message_syntax` | 源文或译文的 ICU 消息格式有误 | +| `icu_argument_mismatch` | ICU 参数名、参数类型或格式化样式不一致 | +| `icu_selector_mismatch` | 选择器不一致,或复数类别不适用于目标语言 | +| `untracked` | 清单中没有对应的目标记录 | +| `source_stale` | 清单记录生成后源文发生变化 | +| `policy_stale` | 生成提示词或模型设置发生变化 | +| `target_modified` | 目标内容与清单记录不一致 | + ### `detect` -自动检测 i18n 框架并建议配置。 +自动检测项目使用的 i18n 框架并生成推荐配置。 ```bash internationalizer detect ``` -支持:react-i18next、next-intl、vue-i18n、原生 JSON、Markdown 文档。 +现已支持:react-i18next、next-intl、vue-i18n、纯 JSON 及 Markdown 文档。 ### `glossary` -管理在翻译过程中强制执行的单语言术语表。 +管理在翻译期间强制遵循的单语言术语表。 ```bash internationalizer glossary list --locale fr @@ -149,12 +185,12 @@ internationalizer glossary remove --locale fr --source "Dashboard" ### `tm` -管理翻译记忆库(先前翻译字符串的 JSONL 缓存)。 +管理翻译记忆库(基于 JSONL 存储的历史翻译缓存)。 ```bash -internationalizer tm stats # 显示记录数 -internationalizer tm export # 导出为 JSON -internationalizer tm clear --force # 删除所有记录 +internationalizer tm stats # 查看记录统计 +internationalizer tm export # 导出为 JSON 格式 +internationalizer tm clear --force # 清空全部记录 ``` ## 配置参考 @@ -165,150 +201,205 @@ internationalizer tm clear --force # 删除所有记录 # 源语言(默认:en) source_locale: en -# 目标翻译语言(必填) -target_locales: [fr, de, es, ja, zh-CN, ar] - -# 源语言环境文件路径(必填) -source_path: locales/en.json - -# LLM 提供商设置 +# 目标翻译语言列表(必填) +target_locales: [fr, de, es, ja, yue, zh-CN, zh-TW, ar] + +# 一个或多个源到目标的映射绑定(必填)。 +# 占位符 {locale} 会被自动替换为各个已配置的目标语言标识。 +bundles: + - id: app + source: locales/en.json + target: locales/{locale}.json + format: json + - id: docs + source: README.md + target: docs/i18n/{locale}.md + format: markdown + +# 向后兼容配置:source_path 仍可将目标映射至同级文件, +# 例如 locales/fr.json。新项目建议优先使用 bundles。 +# source_path: locales/en.json + +# LLM 服务商配置 llm: - # 提供商:"anthropic"、"openai"、"gemini" 或 "openrouter"(默认:gemini) + # 服务商选项:"anthropic"、"openai"、"gemini" 或 "openrouter"(默认:gemini) provider: gemini - # 各提供商的默认模型名称: + # 各服务商的默认模型: # anthropic: claude-opus-5 - # openai: gpt-5.6-luna + # openai: gpt-5.6-luna(思考力度默认设为 max) # gemini: gemini-3.8-flash # openrouter: deepseek/deepseek-v4-pro-0813 model: gemini-3.8-flash - # 包含 API 密钥的环境变量 + # 存储 API 密钥的环境变量名称 api_key_env: GOOGLE_AI_STUDIO_API_KEY - # 兼容 OpenAI 的端点基础 URL(可选) + # OpenAI 兼容接口的 Base URL(可选) # base_url: https://api.openai.com -# 每次 LLM 调用的键数量(默认:40) + # OpenAI GPT-5 系列 Responses API 的思考力度(reasoning effort) + #(OpenAI 服务商默认值:max) + reasoning_effort: max + + # 针对特定目标语言的独立 LLM 设置(可选)。覆盖配置若沿用全局服务商, + # 会自动继承全局中未显式指定的参数;若切换为其他服务商, + # 未指定项则回退至该服务商的默认设置。 + locale_overrides: + yue: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + zh-CN: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + zh-TW: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + +# 每次 LLM 请求包含的键数量(默认:40) batch_size: 40 -# 并行 LLM 调用数(默认:4) +# 并行 LLM 请求数(默认:4) concurrency: 4 -# 包含各语言环境样式指南 Markdown 文件的目录(默认:style-guides) +# 各语言风格指南 Markdown 文件存放目录(默认:style-guides) style_guides_dir: style-guides -# 包含各语言环境术语表 JSON 文件的目录(默认:glossary) +# 各语言术语表 JSON 文件存放目录(默认:glossary) glossary_dir: glossary # 翻译记忆库文件路径(默认:.internationalizer/tm.jsonl) tm_path: .internationalizer/tm.jsonl + +# 记录源文、策略、目标及版本溯源状态的清单文件 +#(默认:.internationalizer.lock;请将此文件提交至版本控制) +manifest_path: .internationalizer.lock + +# 可选的翻译及严格校验规则 +validation: + plural_style: i18next-v4 # 生成并校验目标语言的复数形式 ``` -## 样式指南 +语言标识必须是格式正确的 BCP 47 标签,例如 `fr`、`pt-BR` 或 `sr-Latn-RS`。规范化后等价的目标语言会被判定为重复项;各语言专属的服务商覆写配置也会按规范化形式匹配。上述示例中,日语等没有单独覆写配置的语言均继承全局 Gemini 设置。 + +ICU MessageFormat 内容会按结构解析。系统支持简单参数、`select`、`plural`、`selectordinal`、`number`、`date` 和 `time`,并支持嵌套消息、复数偏移量、精确数字选择器以及 `#`。校验会检查语法、参数类型与格式化样式、复数偏移量、select 分支标识,以及目标语言适用的 CLDR 复数类别。若服务商返回的内容破坏这些约束,系统会在写入语言文件或翻译记忆库前拒绝该结果。 + +启用 `i18next-v4` 后,系统会在翻译期间将识别到的源复数词族扩展为目标语言所需的 CLDR 类别。仅目标语言需要的类别会使用源词族的 `_other` 值作为翻译模板。严格校验要求目标语言所需的类别齐全,但不会强制保留目标语言不使用的源语言专属类别。 + +## 风格指南 -样式指南是注入到 LLM 翻译提示词中的 Markdown 文件。它们控制语调、正式程度、排版以及其他特定语言的约定。 +风格指南是以 Markdown 格式编写的文件,会在翻译时直接注入 LLM 提示词中。借此可精准把控译文的语调、正式程度、排版规范以及特定语言的行文习惯。 ``` style-guides/ - _conventions.md # 适用于所有语言的共享规则 - fr.md # 法语特定规则 - ja.md # 日语特定规则 - ar.md # 阿拉伯语特定规则 + _conventions.md # 面向所有语言的通用规范 + fr.md # 法语专属规则 + ja.md # 日语专属规则 + ar.md # 阿拉伯语专属规则 ``` -### 共享约定 (`_conventions.md`) +### 通用规范(`_conventions.md`) -定义适用于所有语言的规则:插值语法、HTML 保留、字符串类型约定(按钮 vs 标签 vs 错误)等。 +用于定义适用于所有语言的全局规则,包括:插值语法、HTML 标签保护策略、不同文案类型的表述规范(如按钮、表单标签与错误提示)等。 -### 单语言指南 (`{locale}.md`) +### 各语言指南(`{locale}.md`) -定义特定语言的规则:正式程度(如 tu 与 vous)、标点符号(如法文引号、倒问号)、复数形式、日期/数字格式以及术语表。 +用于定义特定语言的细分规则,包括:正式程度(如法语 tu 与 vous)、特定标点规范(如法文引号 « »、西班牙语倒问号 ¿)、复数形式定义、日期/数字格式化及特定术语表。 -有关实际示例,请参阅 [`examples/react-app/style-guides/`](examples/react-app/style-guides/)。 +完整可运行范例参见 [`examples/react-app/style-guides/`](../../examples/react-app/style-guides/)。 ## 术语表格式 -术语表文件是存储在 `{glossary_dir}/{locale}.json` 中的 JSON 数组: +术语表以 JSON 数组形式保存在 `{glossary_dir}/{locale}.json` 中: ```json [ { "source": "Dashboard", "target": "Tableau de bord", + "variants": ["Panneau de contrôle"], + "enforcement": "error", "ignore_case": false, "whole_word": true } ] ``` -术语会作为术语表注入到 LLM 提示词中,以确保整个应用程序中关键术语的翻译保持一致。 +`variants` 用于列出其他获准使用的译法。`enforcement` 可设为 `error` 或 `warning`;省略时默认为 `error`。这些词条会作为术语对照表注入 LLM 提示词,确保整个应用中的术语保持一致。对于 `{"source":"API","target":"API"}` 这类源文与译文完全相同的精确条目,严格校验不会将完整值判定为未翻译;较长文本中仅包含 `API` 则不会获得豁免。 ## 翻译记忆库 -翻译记忆库存储为 JSONL 文件(每行一个 JSON 记录)。每条记录包含: +翻译记忆库采用 JSONL 文件格式存储(每行对应一条独立 JSON 记录)。各记录包含以下字段: -- 源键和值 -- 翻译后的值 -- 源值的 SHA-256 哈希 +- 文件包、翻译键、源文、译文及规范化后的目标语言 +- 源文哈希与翻译策略哈希 +- 生成译文的服务商与模型 - 时间戳 -在后续运行中,未更改的字符串将直接从 TM 缓存中提供,而无需调用 LLM,从而节省时间和 API 成本。TM 文件对 Git 友好,可以与你的语言环境文件一起提交。 +后续翻译时,源文哈希与策略哈希均相同的文本会直接从缓存复用,无需调用 LLM。默认路径位于已被忽略的 `.internationalizer/` 目录中,因此它是本地缓存。如需由项目成员共享翻译记忆库,请将 `tm_path` 明确设为受版本控制的路径。可审查的 `.internationalizer.lock` 清单则单独纳入版本控制。 -## 支持的格式 +## 支持的文件格式 -| 格式 | 扩展名 | 模式 | +| 格式 | 文件扩展名 | 处理模式 | |--------|-----------|------| -| JSON | `.json` | 键值对(嵌套、点号表示法扁平化) | -| YAML | `.yml`, `.yaml` | 键值对(保留注释和顺序) | -| Markdown | `.md`, `.mdx` | 全文档翻译 | +| JSON | `.json` | 键值对(支持深层嵌套,按点号表示法扁平化) | +| YAML | `.yml`、`.yaml` | 键值对(完整保留注释与键序) | +| Markdown | `.md`、`.mdx` | 整篇文档全文翻译 | -## 项目类型检测 +## 项目类型检测机制 -`internationalizer detect` 通过检查以下内容来识别你的 i18n 设置: +执行 `internationalizer detect` 时,工具将通过检查以下特征定位您的 i18n 环境: -- `package.json` 中对 react-i18next、next-intl 或 vue-i18n 的依赖 -- 匹配常见语言环境模式的目录结构 -- 文件扩展名和命名约定 +- `package.json` 中的 react-i18next、next-intl 或 vue-i18n 依赖 +- 符合通用规范的语言目录架构 +- 文件扩展名与命名约定 -## 架构 +## 系统架构 ``` -cmd/internationalizer/ CLI 入口点和命令定义 +cmd/internationalizer/ CLI 入口点与命令定义 internal/ - config/ 带默认值的 YAML 配置加载 + config/ YAML 配置加载与默认值填充 detect/ 项目类型自动检测 formats/ 格式解析器(JSON、YAML、Markdown) glossary/ 单语言术语表管理 - llm/ LLM 提供商接口 + 实现 + llm/ LLM 服务商通用接口与后端实现 anthropic.go Anthropic Claude 后端 - openai.go OpenAI / 兼容后端 - gemini.go 通过 AI Studio 的 Google Gemini 后端 - OpenRouter 使用带有自定义 base_url 的 openai.go - styleguide/ 样式指南加载器 - tm/ JSONL 翻译记忆库 - translate/ 翻译编排器 - validate/ 语言环境验证和差异对比 + openai.go OpenAI 及兼容后端 + gemini.go 基于 Google AI Studio 的 Gemini 后端 + OpenRouter 复用 openai.go 并指定自定义 base_url + locale/ BCP 47 语言标识与 CLDR 复数类别 + message/ ICU MessageFormat 解析器与结构比对 + policy/ 稳定的翻译策略哈希 + state/ 受版本控制的翻译清单 + styleguide/ 风格指南加载器 + tm/ JSONL 翻译记忆库实现 + translate/ 翻译流水线核心编排器 + validate/ 语言包校验与差异分析 ``` -## 与替代方案的比较 +## 与其他方案对比 -| 功能 | Internationalizer | i18next | Crowdin | 通用 LLM | +| 功能特性 | Internationalizer | i18next | Crowdin | 通用 LLM | |---------|------------------|---------|---------|-------------| -| LLM 驱动翻译 | 是 | 否 | 部分 | 是 | -| 单语言样式指南 | 是 | 否 | 否 | 否 | -| 强制执行术语表 | 是 | 否 | 是 | 否 | -| 翻译记忆库 | 是 | 否 | 是 | 否 | -| CLI / 本地执行 | 是 | 不适用 | 否 | 手动 | -| Git 友好文件 | 是 | 是 | 部分 | 手动 | -| 无 SaaS 依赖 | 是 | 是 | 否 | 视情况而定 | -| 开源 (AGPL-3.0) | 是 | 是 | 否 | 视情况而定 | +| 基于 LLM 驱动翻译 | 是 | 否 | 部分 | 是 | +| 支持各语言风格指南 | 是 | 否 | 否 | 否 | +| 强制约束专业术语表 | 是 | 否 | 是 | 否 | +| 内置翻译记忆库 | 是 | 否 | 是 | 否 | +| 支持 CLI / 本地直接执行 | 是 | 不适用 | 否 | 需手动操作 | +| 生成 Git 友好文件 | 是 | 是 | 部分 | 需手动操作 | +| 摆脱商业 SaaS 依赖 | 是 | 是 | 否 | 视情况而定 | +| 完全开源(AGPL-3.0) | 是 | 是 | 否 | 视情况而定 | ## 许可证 -[AGPL-3.0](LICENSE) +本项目遵循 [AGPL-3.0](../../LICENSE) 协议开源。 -## 贡献 +第三方依赖声明请参阅 [THIRD_PARTY_NOTICES.md](../../THIRD_PARTY_NOTICES.md)。 -有关开发设置和指南,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。所有贡献都需要 DCO 签名。 +## 参与贡献 +本地开发环境搭建与贡献指引请参阅 [CONTRIBUTING.md](../../CONTRIBUTING.md)。所有代码提交均需包含 DCO 签署。 diff --git a/docs/i18n/zh-TW.md b/docs/i18n/zh-TW.md index 8e7f7f3..6b504e9 100644 --- a/docs/i18n/zh-TW.md +++ b/docs/i18n/zh-TW.md @@ -1,30 +1,34 @@ -> [English (original)](../../README.md) -

Internationalizer

# Internationalizer -專為軟體專案打造的 AI 原生國際化管線。使用 LLM 來翻譯、驗證和管理 i18n 檔案。 +專為軟體專案打造的 AI 原生國際化管線。使用 LLM 來翻譯、驗證與管理 i18n 檔案。 [![CI](https://github.com/Tom-R-Main/Internationalizer/actions/workflows/ci.yml/badge.svg)](https://github.com/Tom-R-Main/Internationalizer/actions/workflows/ci.yml) -[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](LICENSE) +[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](../../LICENSE) + +

+العربية · বাংলা · Čeština · Dansk · Deutsch · Ελληνικά · Español · Suomi · Français · עברית · हिन्दी · Indonesia · Italiano · 日本語 · 한국어 · Bahasa Melayu
Nederlands · ਪੰਜਾਬੀ · Polski · Português · Română · Русский · Svenska · తెలుగు · ไทย · Türkçe · Українська · Tiếng Việt · 粵語 · 简体中文 · 繁體中文 +

+ +--- ## 為什麼選擇 Internationalizer? -大多數的 i18n 工具不是執行階段函式庫 (i18next, react-intl),就是金鑰管理 SaaS 平台 (Crowdin, Lokalise)。它們都沒有妥善解決實際的翻譯問題: +大多數的 i18n 工具不是執行階段函式庫(i18next、react-intl),就是翻譯鍵管理 SaaS 平台(Crowdin、Lokalise)。它們都無法妥善解決核心的翻譯問題: - **手動翻譯**在語言數量增加後難以擴展 -- **機器翻譯 API** (Google Translate, DeepL) 會忽略您的術語、語氣和 UI 慣例 -- **通用 LLM 翻譯**效果較好,但如果沒有詞彙表和風格指南,翻譯結果會不一致 +- **機器翻譯 API**(Google Translate、DeepL)會忽略您的專屬術語、語氣與 UI 慣例 +- **通用 LLM 翻譯**效果較佳,但若缺乏詞彙表與風格指南,產出的結果容易前後不一 -Internationalizer 與眾不同。它是一個結合了 LLM 翻譯與以下功能的 **CLI 管線**: +Internationalizer 截然不同。它是一個結合了 LLM 翻譯與下列功能的 **CLI 管線**: -- **各語言專屬詞彙表** — 確保應用程式中的術語保持一致 -- **各語言專屬風格指南** — 控制語氣、正式程度、複數形式和排版 -- **翻譯記憶庫** — 略過未變更的字串,節省 API 呼叫費用 -- **金鑰驗證** — 在發布前捕捉遺漏的翻譯和插值不符的問題 +- **各語言專屬詞彙表** — 確保整個應用程式中的術語維持一致 +- **各語言專屬風格指南** — 精確控制語氣、正式程度、複數規則與文字排版 +- **翻譯記憶庫** — 自動跳過未變更的字串,節省 API 呼叫費用 +- **確定性驗證** — 在發布前找出翻譯鍵遺漏或多餘、受保護結構變更、詞彙表違規,以及複數或 ICU 錯誤 ## 安裝 @@ -34,13 +38,13 @@ Internationalizer 與眾不同。它是一個結合了 LLM 翻譯與以下功能 npm install -g internationalizer ``` -或在不全域安裝的情況下執行: +或者無需全域安裝,直接執行: ```bash npx internationalizer --help ``` -npm 套件會透過特定平台的選用相依性,從 npm 安裝相符的預先建置二進位檔。 +npm 套件會藉由平台專屬的選用相依性,從 npm 安裝相對應的預先建置二進位檔。 透過 Go 安裝: @@ -58,20 +62,24 @@ go build -o internationalizer ./cmd/internationalizer ## npm 套件 -- Git 標籤和 npm 套件版本必須相符,例如 `v0.1.0` 和 `0.1.0` -- 根目錄的 `internationalizer` 套件相依於平台套件,例如 `internationalizer-darwin-arm64` +- Git 標籤與 npm 套件版本必須完全一致,例如 `v0.1.0` 與 `0.1.0` +- 根目錄的 `internationalizer` 套件相依於各平台套件,例如 `internationalizer-darwin-arm64` - 支援的 npm 目標平台:macOS arm64/x64、Linux arm64/x64、Windows x64 -- CI 發布需要名為 `NPM_TOKEN` 的 GitHub secret +- CI 發布流程需要名為 `NPM_TOKEN` 的 GitHub secret ## 快速入門 -1. 在您的專案根目錄建立設定檔: +1. 在專案根目錄建立設定檔: ```yaml # .internationalizer.yml source_locale: en target_locales: [fr, de, es, ja] -source_path: locales/en.json +bundles: + - id: app + source: locales/en.json + target: locales/{locale}.json + format: json llm: provider: gemini @@ -97,7 +105,7 @@ internationalizer translate --dry-run internationalizer translate ``` -5. 驗證所有地區設定: +5. 驗證所有語系: ```bash internationalizer validate @@ -107,39 +115,67 @@ internationalizer validate ### `translate` -尋找遺漏的金鑰並透過 LLM 進行翻譯。 +找出遺漏或已過期的翻譯鍵並透過 LLM 進行翻譯。 ```bash -internationalizer translate # 翻譯所有地區設定 +internationalizer translate # 翻譯所有語系 internationalizer translate -l fr # 僅翻譯法文 -internationalizer translate --dry-run # 預覽而不呼叫 API -internationalizer translate --batch-size 20 # 較小的批次 -internationalizer translate --concurrency 2 # 較少的平行呼叫 +internationalizer translate --dry-run # 預覽翻譯內容,不呼叫 API +internationalizer translate --adopt-existing # 將現有翻譯設為基準,不呼叫 API +internationalizer translate --refresh-policy # 重新整理因提示詞/風格/模型變更而過期的項目 +internationalizer translate --batch-size 20 # 縮小每批次翻譯量 +internationalizer translate --concurrency 2 # 降低平行呼叫數 ``` +翻譯狀態會獨立回報遺漏、來源過期、政策過期、最新與手動編輯等情況,因此手動編輯不會掩蓋來源或政策的變更。政策過期的內容會被列出回報,但僅在附加 `--refresh-policy` 旗標時才會重新翻譯。系統絕不會自動覆寫手動編輯的內容。初次將資訊清單(manifest)導入已審核的翻譯,或明確要將審核後的手動編輯採納為新基準時,請使用 `--adopt-existing`。 + ### `validate` -檢查所有地區設定檔案是否有遺漏的金鑰、多餘的金鑰以及插值不符的情況。 +將所有語系檔案與來源套件進行比對。預設驗證會計算必要目標翻譯鍵的涵蓋率,將多餘的翻譯鍵列為警告,並在翻譯鍵遺漏、插值不符或 ICU MessageFormat 結構無效時失敗。 ```bash internationalizer validate # 人類可讀的輸出 internationalizer validate --json # 機器可讀的 JSON -internationalizer validate -q # 僅輸出結束代碼 +internationalizer validate -q # 僅傳回結束代碼 +internationalizer validate --strict # 強制執行翻譯品質規則 +internationalizer validate --require-state # 要求資訊清單中的來源追溯狀態為最新 ``` +`--strict` 也會回報實際翻譯涵蓋率。語言內容若與來源完全相同,便會視為未翻譯;只有詞彙表針對完整值明確設定來源與譯文相同的精確項目時才會豁免。驗證會遵守 `ignore_case`,但較長內容中只包含某個詞彙表項目並不會獲得豁免。嚴格模式會在出現多餘翻譯鍵、與來源相同的值、插值/HTML/程式碼/Markdown 連結結構變更、詞彙表違規或缺少已設定的複數形式時失敗。 + +`--require-state` 會將每個目標值與 `.internationalizer.lock` 比對。翻譯鍵未受追蹤,或資訊清單記錄的來源、翻譯政策、目標雜湊已過期時,驗證都會失敗。此選項可與 `--strict` 同時使用。 + +人類可讀報告與 JSON 報告使用下列穩定的問題代碼: + +| 代碼 | 含義 | +| --- | --- | +| `missing_key` / `extra_key` | 來源與目標的翻譯鍵集合不一致 | +| `blank_translation` | 非空來源所對應的嚴格模式譯文為空 | +| `source_identical` | 嚴格模式下語言內容仍與來源相同 | +| `protected_structure_mismatch` | 插值、HTML、程式碼或連結結構發生變更 | +| `glossary_violation` | 找不到獲准使用的目標術語或變體 | +| `plural_form_missing` | 缺少為該語言設定的複數形式 | +| `icu_message_syntax` | 來源或譯文的 ICU 訊息格式有誤 | +| `icu_argument_mismatch` | ICU 引數名稱、類型或格式樣式不一致 | +| `icu_selector_mismatch` | 選擇器不一致,或複數類別不適用於目標語言 | +| `untracked` | 資訊清單中沒有對應的目標記錄 | +| `source_stale` | 資訊清單記錄建立後來源內容發生變更 | +| `policy_stale` | 產生提示詞或模型設定發生變更 | +| `target_modified` | 目標內容與資訊清單記錄不一致 | + ### `detect` -自動偵測 i18n 框架並建議設定。 +自動偵測 i18n 框架並提供建議設定。 ```bash internationalizer detect ``` -支援:react-i18next、next-intl、vue-i18n、原生 JSON、Markdown 文件。 +支援:react-i18next、next-intl、vue-i18n、純 JSON、Markdown 文件。 ### `glossary` -管理在翻譯期間強制執行的各語言專屬詞彙表術語。 +管理在翻譯期間強制套用的各語言專屬詞彙表術語。 ```bash internationalizer glossary list --locale fr @@ -149,10 +185,10 @@ internationalizer glossary remove --locale fr --source "Dashboard" ### `tm` -管理翻譯記憶庫 (先前翻譯字串的 JSONL 快取)。 +管理翻譯記憶庫(儲存先前翻譯字串的 JSONL 快取)。 ```bash -internationalizer tm stats # 顯示記錄數量 +internationalizer tm stats # 顯示記錄總數 internationalizer tm export # 匯出為 JSON internationalizer tm clear --force # 刪除所有記錄 ``` @@ -162,70 +198,118 @@ internationalizer tm clear --force # 刪除所有記錄 ```yaml # .internationalizer.yml -# 來源語言 (預設:en) +# 來源語言(預設:en) source_locale: en -# 要翻譯成的目標語言 (必填) -target_locales: [fr, de, es, ja, zh-CN, ar] - -# 來源地區設定檔案的路徑 (必填) -source_path: locales/en.json +# 要翻譯成的目標語言(必填) +target_locales: [fr, de, es, ja, yue, zh-CN, zh-TW, ar] + +# 一或多個來源到目標的對應設定(必填)。 +# {locale} 會替換為每個設定的目標語言代碼。 +bundles: + - id: app + source: locales/en.json + target: locales/{locale}.json + format: json + - id: docs + source: README.md + target: docs/i18n/{locale}.md + format: markdown + +# 向後相容設定:source_path 仍可將目標對應至同層檔案, +# 例如 locales/fr.json。新專案建議優先使用 bundles。 +# source_path: locales/en.json # LLM 供應商設定 llm: - # 供應商:"anthropic"、"openai"、"gemini" 或 "openrouter" (預設:gemini) + # 供應商:"anthropic"、"openai"、"gemini" 或 "openrouter"(預設:gemini) provider: gemini # 各供應商的預設模型名稱: # anthropic: claude-opus-5 - # openai: gpt-5.6-luna + # openai: gpt-5.6-luna(推理程度預設為 max) # gemini: gemini-3.8-flash # openrouter: deepseek/deepseek-v4-pro-0813 model: gemini-3.8-flash - # 包含 API 金鑰的環境變數 + # 存放 API 金鑰的環境變數名稱 api_key_env: GOOGLE_AI_STUDIO_API_KEY - # 相容於 OpenAI 端點的基礎 URL (選填) + # 相容於 OpenAI 端點的基礎 URL(選填) # base_url: https://api.openai.com -# 每次 LLM 呼叫的金鑰數量 (預設:40) + # OpenAI GPT-5 系列 Responses API 的推理程度 + #(OpenAI 供應商預設值:max) + reasoning_effort: max + + # 個別目標語言的選用 LLM 設定。若覆寫時沿用全域供應商, + # 未指定的項目將繼承全域設定;若改用其他供應商, + # 未指定的項目則採用該供應商的預設值。 + locale_overrides: + yue: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + zh-CN: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + zh-TW: + provider: openrouter + model: deepseek/deepseek-v4-flash-0731 + api_key_env: OPENROUTER_API_KEY + +# 單次 LLM 呼叫處理的鍵數量(預設:40) batch_size: 40 -# 平行 LLM 呼叫數量 (預設:4) +# 平行 LLM 呼叫數量(預設:4) concurrency: 4 -# 包含各語言專屬風格指南 Markdown 檔案的目錄 (預設:style-guides) +# 存放各語言風格指南 Markdown 檔案的目錄(預設:style-guides) style_guides_dir: style-guides -# 包含各語言專屬詞彙表 JSON 檔案的目錄 (預設:glossary) +# 存放各語言詞彙表 JSON 檔案的目錄(預設:glossary) glossary_dir: glossary -# 翻譯記憶庫檔案的路徑 (預設:.internationalizer/tm.jsonl) +# 翻譯記憶庫檔案路徑(預設:.internationalizer/tm.jsonl) tm_path: .internationalizer/tm.jsonl + +# 來源、政策、目標及來源追溯資訊的版本化狀態 +#(預設:.internationalizer.lock;請將此檔案提交至版本控制) +manifest_path: .internationalizer.lock + +# 選用的翻譯及嚴格驗證規則 +validation: + plural_style: i18next-v4 # 產生並驗證目標語言的複數形式 ``` +語言識別碼必須是格式正確的 BCP 47 標籤,例如 `fr`、`pt-BR` 或 `sr-Latn-RS`。正規化後等價的目標語言會被判定為重複項目;各語言專屬的供應商覆寫設定也會依正規化形式比對。上述範例中,日文等沒有個別覆寫設定的語言都會繼承全域 Gemini 設定。 + +ICU MessageFormat 內容會依結構解析。系統支援簡單引數、`select`、`plural`、`selectordinal`、`number`、`date` 與 `time`,以及巢狀訊息、複數偏移量、精確數字選擇器和 `#`。驗證會檢查語法、引數類型與格式樣式、複數偏移量、select 分支識別,以及目標語言適用的 CLDR 複數類別。若供應商回傳的內容破壞這些條件,系統會在寫入語系檔案或翻譯記憶庫前拒絕該結果。 + +啟用 `i18next-v4` 後,系統會在翻譯期間將辨識出的來源複數詞組擴充為目標語言需要的 CLDR 類別。只有目標語言需要的類別會使用來源詞組的 `_other` 值作為翻譯範本。嚴格驗證要求目標語言所需的類別齊全,但不強制保留目標語言不使用的來源語言專屬類別。 + ## 風格指南 -風格指南是注入到 LLM 翻譯提示中的 Markdown 檔案。它們控制語氣、正式程度、排版以及其他特定語言的慣例。 +風格指南是會直接注入到 LLM 翻譯提示詞中的 Markdown 檔案。可用來控制語氣、正式程度、文字排版與其他語言專屬的慣例。 ``` style-guides/ - _conventions.md # 所有語言的共用規則 + _conventions.md # 適用於所有語言的共用規則 fr.md # 法文專屬規則 ja.md # 日文專屬規則 ar.md # 阿拉伯文專屬規則 ``` -### 共用慣例 (`_conventions.md`) +### 共用慣例(`_conventions.md`) -定義適用於所有語言的規則:插值語法、HTML 保留、字串類型慣例 (按鈕 vs. 標籤 vs. 錯誤) 等。 +定義通用於所有語言的規範:變數插值語法、HTML 標籤保留、字串類型慣例(按鈕、標籤與錯誤訊息)等。 -### 各語言專屬指南 (`{locale}.md`) +### 各語言專屬指南(`{locale}.md`) -定義特定語言的規則:正式程度 (tu vs. vous)、標點符號 (法文引號、倒問號)、複數形式、日期/數字格式以及術語詞彙表。 +定義特定語言的細部規則:正式程度(例如 tu 與 vous)、標點符號規範(法文引號、倒問號)、複數形式、日期/數字格式,以及術語對照清單。 -請參閱 [`examples/react-app/style-guides/`](examples/react-app/style-guides/) 以取得實際範例。 +實際運作範例請參閱 [`examples/react-app/style-guides/`](../../examples/react-app/style-guides/)。 ## 詞彙表格式 @@ -236,79 +320,86 @@ style-guides/ { "source": "Dashboard", "target": "Tableau de bord", + "variants": ["Panneau de contrôle"], + "enforcement": "error", "ignore_case": false, "whole_word": true } ] ``` -術語會作為術語表注入到 LLM 提示中,確保應用程式中關鍵術語的翻譯保持一致。 +`variants` 用來列出其他獲准使用的譯法。`enforcement` 可設為 `error` 或 `warning`;省略時預設為 `error`。這些項目會以術語對照表的形式注入 LLM 提示詞,確保整個應用程式中的術語維持一致。對於 `{"source":"API","target":"API"}` 這類來源與譯文完全相同的精確項目,嚴格驗證不會將完整值判定為未翻譯;較長內容中只包含 `API` 則不會獲得豁免。 ## 翻譯記憶庫 -翻譯記憶庫儲存為 JSONL 檔案 (每行一筆 JSON 記錄)。每筆記錄包含: +翻譯記憶庫儲存為 JSONL 格式(每行一筆 JSON 記錄)。每筆記錄包含: -- 來源金鑰和值 -- 翻譯後的值 -- 來源值的 SHA-256 雜湊 +- 套件、翻譯鍵、來源值、譯文及正規化後的目標語言 +- 來源雜湊與翻譯政策雜湊 +- 產生譯文的供應商與模型 - 時間戳記 -在後續執行時,未變更的字串會從 TM 快取中提供,而無需呼叫 LLM,從而節省時間和 API 成本。TM 檔案對 Git 友善,可以與您的地區設定檔案一起提交。 +後續執行時,來源雜湊與政策雜湊都相同的內容會直接從快取重複使用,不必呼叫 LLM。預設路徑位於已被忽略的 `.internationalizer/` 目錄中,因此它是本機快取。如需讓專案成員共用翻譯記憶庫,請將 `tm_path` 明確設為受版本控制的路徑。可供審查的 `.internationalizer.lock` 資訊清單則另行納入版本控制。 ## 支援的格式 | 格式 | 副檔名 | 模式 | |--------|-----------|------| -| JSON | `.json` | 鍵值對 (巢狀、點記號扁平化) | -| YAML | `.yml`, `.yaml` | 鍵值對 (保留註解和順序) | -| Markdown | `.md`, `.mdx` | 整份文件翻譯 | +| JSON | `.json` | 鍵值對(支援巢狀、以點號表示法扁平化) | +| YAML | `.yml`、`.yaml` | 鍵值對(保留註解與欄位順序) | +| Markdown | `.md`、`.mdx` | 全文件翻譯 | ## 專案類型偵測 -`internationalizer detect` 會透過檢查以下項目來識別您的 i18n 設定: +執行 `internationalizer detect` 時,會透過檢查下列項目來識別您的 i18n 架構: -- `package.json` 中 react-i18next、next-intl 或 vue-i18n 的相依性 -- 符合常見地區設定模式的目錄結構 -- 副檔名和命名慣例 +- `package.json` 中對 react-i18next、next-intl 或 vue-i18n 的相依性 +- 符合常見語系結構的目錄配置 +- 檔案副檔名與命名慣例 ## 架構 ``` -cmd/internationalizer/ CLI 進入點和指令定義 +cmd/internationalizer/ CLI 進入點與指令定義 internal/ - config/ 載入 YAML 設定與預設值 + config/ YAML 設定載入與預設值處理 detect/ 專案類型自動偵測 - formats/ 格式解析器 (JSON、YAML、Markdown) + formats/ 格式解析器(JSON、YAML、Markdown) glossary/ 各語言專屬詞彙表管理 llm/ LLM 供應商介面與實作 anthropic.go Anthropic Claude 後端 - openai.go OpenAI / 相容後端 - gemini.go 透過 AI Studio 的 Google Gemini 後端 - OpenRouter 使用帶有自訂 base_url 的 openai.go + openai.go OpenAI/相容端點後端 + gemini.go Google Gemini(透過 AI Studio 後端) + OpenRouter 採用自訂 base_url 的 openai.go + locale/ BCP 47 語言識別與 CLDR 複數類別 + message/ ICU MessageFormat 解析器與結構比對 + policy/ 穩定的翻譯政策雜湊 + state/ 受版本控制的翻譯資訊清單 styleguide/ 風格指南載入器 tm/ JSONL 翻譯記憶庫 - translate/ 翻譯協調器 - validate/ 地區設定驗證與差異比對 + translate/ 翻譯流程協調器 + validate/ 語系驗證與差異比對 ``` ## 與替代方案的比較 | 功能 | Internationalizer | i18next | Crowdin | 通用 LLM | |---------|------------------|---------|---------|-------------| -| LLM 驅動翻譯 | 是 | 否 | 部分 | 是 | +| LLM 驅動翻譯 | 是 | 否 | 部分支援 | 是 | | 各語言專屬風格指南 | 是 | 否 | 否 | 否 | -| 強制執行詞彙表 | 是 | 否 | 是 | 否 | +| 強制套用詞彙表 | 是 | 否 | 是 | 否 | | 翻譯記憶庫 | 是 | 否 | 是 | 否 | -| CLI / 本機執行 | 是 | 不適用 | 否 | 手動 | -| 對 Git 友善的檔案 | 是 | 是 | 部分 | 手動 | -| 無 SaaS 相依性 | 是 | 是 | 否 | 視情況而定 | -| 開源 (AGPL-3.0) | 是 | 是 | 否 | 視情況而定 | +| CLI/本機執行 | 是 | 不適用 | 否 | 手動處理 | +| 對 Git 友善的檔案 | 是 | 是 | 部分支援 | 手動處理 | +| 無需依賴 SaaS | 是 | 是 | 否 | 視情況而定 | +| 開放原始碼(AGPL-3.0) | 是 | 是 | 否 | 視情況而定 | ## 授權條款 -[AGPL-3.0](LICENSE) +[AGPL-3.0](../../LICENSE) -## 貢獻 +第三方相依套件聲明請參閱 [THIRD_PARTY_NOTICES.md](../../THIRD_PARTY_NOTICES.md)。 -請參閱 [CONTRIBUTING.md](CONTRIBUTING.md) 以了解開發設定和指南。所有貢獻都需要 DCO 簽署。 +## 貢獻指南 +開發環境設定與規範請參閱 [CONTRIBUTING.md](../../CONTRIBUTING.md)。所有貢獻均需完成 DCO 簽署。