Lingo.devのCLIは、設定済みのローカライゼーションエンジンを通じて、XcodeのString Catalogs(.xcstrings)を翻訳します。String Catalogsは、Xcode 15で導入されたAppleの最新ローカライズ形式で、すべての言語を1つのJSONファイルにまとめて管理できます。CLIはこのファイルを直接更新するため、ロケールごとのディレクトリは必要ありません。
このガイドでは、CLIの設定からローカルでの翻訳、GitHub Actionsによる自動化まで、iOSアプリのローカライズを一通り紹介します。プッシュのたびに翻訳を反映できるようになります。
デモリポジトリ
一緒に試しながら進めるには、lingodotdev/ios-app-localization-exampleをクローンまたはフォークしてください。このリポジトリには、動作するXcodeプロジェクト、String Catalogs、Lingo.dev CLIの設定、GitHub Actionsのワークフローが含まれています。
String Catalogsの仕組み#
Xcode 15以前のiOSローカライズでは、[locale].lproj/ディレクトリごとに分かれた.stringsや.stringsdictファイルを個別に管理する必要がありました。String Catalogsでは、これがXcodeによって自動管理される1つのLocalizable.xcstringsファイルに置き換わります。
SwiftUIまたはUIKitで文字列をローカライズ対象として指定すると、Xcodeがビルド時にそれを検出し、String Catalogにエントリを追加します。各エントリには、ソース文字列、設定された各ロケール向けの翻訳、そして翻訳者に文脈を伝える任意のコメント欄が含まれます。
| 項目 | 従来の.strings | String Catalogs .xcstrings |
|---|---|---|
| ファイル数 | テーブルごと・ロケールごとに1つ | 1ファイルですべてのロケール |
| 形式 | キーと値のテキスト形式 | 構造化JSON |
| 複数形対応 | 別途.stringsdictファイルが必要 | 複数形ルールを標準サポート |
| Xcode連携 | 手動でエクスポート/インポート | 自動検出 |
| 翻訳者向けメモ | 非対応 | エントリごとのコメント欄 |
CLIのxcode-xcstringsバケットタイプはこのJSON構造を解析し、各エントリをローカライゼーションエンジン経由で翻訳して、コメント、複数形ルール、メタデータを保持したまま同じファイルに書き戻します。
前提条件#
ローカライゼーションエンジンを作成する
CLIを実行するたびに、コンテンツはローカライゼーションエンジンを通じて送信されます。これは、使用するLLMモデル、glossary、ブランドボイス、instructionsを決める設定です。Lingo.dev dashboardで作成し、API keyを生成してください。
Node.jsを確認する
CLIの利用には、Node.js 18以上が必要です。
node -vXcodeでローカライズを有効にする
Xcodeプロジェクトで Project Settings > Info > Localizations に移動し、対象言語を追加してください。追加した各ロケールに対して、XcodeがString Catalogのエントリを作成します。詳しくはAppleのlocalization documentationを参照してください。
CLIを設定する#
プロジェクトのルートにi18n.jsonファイルを作成します。xcode-xcstringsバケットを指定すると、CLIがString Catalog形式を解析し、その場でファイルを更新します。
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de", "ja"]
},
"buckets": {
"xcode-xcstrings": {
"include": ["MyApp/Localizable.xcstrings"]
}
}
}String Catalogsはすべてのロケールを1つのファイルに格納するため、includeパターンに[locale]プレースホルダーは必要ありません。CLIはソース言語のエントリを読み取り、翻訳し、すべての対象言語を同じ.xcstringsファイルに書き戻します。
複数のString Catalogを使う場合
プロジェクトで複数のString Catalogファイルを使っている場合(たとえばフレームワークターゲットごとに1つずつある場合)は、include配列にそれらをすべて列挙してください。
{
"buckets": {
"xcode-xcstrings": {
"include": [
"MyApp/Localizable.xcstrings",
"MyAppWidgets/Localizable.xcstrings"
]
}
}
}ローカルで翻訳する#
API keyを設定して、CLIを実行します。
export LINGO_API_KEY="your-api-key"
npx lingo.dev@latest runCLIはString Catalogを読み込み、lockfileを使って未翻訳のエントリを特定し、差分だけをローカライゼーションエンジン経由で翻訳して、結果を同じ.xcstringsファイルに書き戻します。Xcodeでそのファイルを開けば、設定済みの各ロケールに翻訳が反映されていることを確認できます。
開発中に特定のロケールだけを対象にするには、次のようにします。
npx lingo.dev@latest run --target-locale es翻訳者向けメモ#
String Catalogsでは、各エントリにコメント欄を持たせることができ、CLIはそのコメントを翻訳リクエストに含めます。これらのコメントはローカライゼーションエンジンに文脈を伝え、用語の曖昧さを解消したり、トーンを指定したり、文字列がUIのどこに表示されるかを説明したりするのに役立ちます。
Xcodeでは、String Catalogエディタで文字列を選択し、インスペクタパネルでコメントを追加できます。コメントは.xcstringsJSONに保存されます。
{
"sourceLanguage": "en",
"strings": {
"Set": {
"comment": "Refers to a collection of items, not the verb",
"localizations": { }
}
}
}CLIはこのコメントを文字列と一緒に送信することで、モデルを正しい解釈へ導きます。たとえば文脈のない"Set"は、多くの言語で動詞として訳される可能性がありますが、コメントがあればその曖昧さを解消できます。さらに多くのパターンについては、Translator Notesを参照してください。
複数形#
String Catalogsは、CLDR plural rulesを使って複数形をネイティブに処理します。Xcodeで複数形バリエーションを定義すると、String Catalogには対象言語で必要な各複数形カテゴリ(zero、one、two、few、many、other)のルールが保存されます。
CLIは翻訳時にもこの構造を維持し、各対象ロケールに対して正しい複数形カテゴリを生成します。英語で使うカテゴリは2つ(oneとother)ですが、アラビア語では6つ、ポーランド語では4つ、日本語では1つ必要です。こうした違いは、ローカライゼーションエンジンが自動的に処理します。
GitHub Actionsで自動化する#
プッシュのたびに翻訳を実行するには、.github/workflows/translate.ymlにワークフローファイルを追加します。
翻訳をそのままmainにコミットします。手間が少なく、小規模チームに最適です。
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lingo.dev
uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}API keyは、GitHubリポジトリの Settings > Secrets and variables > Actions でLINGODOTDEV_API_KEYとして保存してください。
デプロイ前に確認する#
未翻訳の文字列が本番環境に出ないようにするため、デプロイゲートとして--frozenフラグを使います。翻訳が必要なエントリが1つでもある場合、CLIは非ゼロステータスで終了します。
npx lingo.dev@latest run --frozenこれをビルド前の独立したCIステップとして追加してください。
- name: Verify translations
run: npx lingo.dev@latest run --frozen