iOSアプリの多言語対応: .xcstrings を XLIFF で言語ごとに分割・統合する

iOSアプリの多言語対応: .xcstrings を XLIFF で言語ごとに分割・統合する

2026.03.13

現在、開発中のアプリで多言語対応を進めている。対応言語が増えるにつれて Localizable.xcstrings の管理に苦労するようになり、翻訳ワークフローの見直しが必要になった。

Xcode 15 で導入された String Catalog(.xcstrings)は全言語・全キーを1つの JSON ファイルに集約する設計になっているため、日本語 + 英語の2言語であればまだ管理できるが、10言語対応ともなるとファイルサイズは一気に膨れ上がり、数千〜数万行の JSON になる。

こうなると問題になるのが 翻訳ワークフローの運用 だ。全言語が混在した巨大な JSON をそのまま翻訳者に渡しても、対象言語以外のデータが大量に含まれているため作業効率が悪く、レビューも困難になる。Git での差分管理も見通しが悪くなり、意図しない変更の混入リスクが高まる。

本記事では、.xcstrings を言語単位に分解し、翻訳作業を安全かつ効率的に回すための実践的なワークフローを紹介する。

検証環境

  • macOS 15.7.3
  • Xcode 26.1.1

なぜ .xcstrings は肥大化するのか

まず .xcstrings の内部構造を確認する。中身は以下のような JSON だ。

{
  "sourceLanguage": "ja",
  "strings": {
    "home_greeting": {
      "comment": "ホーム画面の挨拶",
      "localizations": {
        "en": {
          "stringUnit": {
            "state": "translated",
            "value": "Hello!"
          }
        },
        "ja": {
          "stringUnit": {
            "state": "translated",
            "value": "こんにちは!"
          }
        },
        "zh-Hans": {
          "stringUnit": {
            "state": "translated",
            "value": "你好!"
          }
        }
      }
    }
  }
}

1つのキーに対して、対応言語の数だけ localizations が入れ子になる。つまりファイルサイズは キー数 × 言語数 に比例して肥大化する。

キー数 言語数 おおよその行数 ファイルサイズ目安
100 2 ~800行 ~20KB
100 10 ~3,500行 ~90KB
500 10 ~17,000行 ~450KB
1,000 10 ~35,000行 ~900KB

500キー × 10言語で約17,000行。これだけの規模になると、特定言語の翻訳状況を把握するだけでも一苦労だ。差分レビューで変更箇所を追うのも困難になり、翻訳者に必要な部分だけを渡すことも難しくなる。

XLIFF による言語単位の分割と統合

XLIFF とは

XLIFF(XML Localization Interchange File Format)は、翻訳業界の標準フォーマットだ。Xcode は .xcstrings を XLIFF 形式でエクスポート/インポートする機能を標準で備えている。

最大のポイントは 1言語1ファイル に分かれることである。

エクスポート手順

xcodebuild -exportLocalizations \
  -project MyApp.xcodeproj \
  -localizationPath ./Localizations \
  -exportLanguage en \
  -exportLanguage ja \
  -exportLanguage zh-Hans \
  -exportLanguage es

実行すると、以下のようなディレクトリ構造が生成される。

Localizations/
├── en.xcloc/
│   └── Localized Contents/
│       └── en.xliff
├── ja.xcloc/
│   └── Localized Contents/
│       └── ja.xliff
├── zh-Hans.xcloc/
│   └── Localized Contents/
│       └── zh-Hans.xliff
└── es.xcloc/
    └── Localized Contents/
        └── es.xliff

Finder 上では以下のように表示される。

Localizations ディレクトリの Finder 表示

en.xcloc をダブルクリックで起動すると、XLIFFエディタが起動する。GUIで文字列リソースを操作したい場合はこのエディタで編集することができる。

Xcode の XLIFF エディタ画面

XLIFF の中身

生成された XLIFF はシンプルな XML だ。

<?xml version="1.0" encoding="UTF-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
  <file original="MyApp/Localizable.xcstrings" source-language="ja" target-language="en" datatype="plaintext">
    <header>
      <tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="26.1.1" build-num="17B100"/>
    </header>
    <body>
      <trans-unit id="cart_empty_message" xml:space="preserve">
        <source>カートに商品がありません</source>
        <target state="translated">Your cart is empty</target>
        <note>カート画面の空状態メッセージ</note>
      </trans-unit>
      <trans-unit id="home_greeting" xml:space="preserve">
        <source>こんにちは!</source>
        <target state="translated">Hello!</target>
        <note>ホーム画面の挨拶</note>
      </trans-unit>
      <trans-unit id="settings_title" xml:space="preserve">
        <source>設定</source>
        <target state="new"/>
        <note>設定画面のタイトル</note>
      </trans-unit>
    </body>
  </file>
</xliff>

<source> に原文(日本語)、<target> に翻訳先言語のテキストが入る。state="new" は未翻訳を意味する。

この形式であれば、翻訳者には「<target state="new"/> になっている箇所を翻訳して state="translated" に変えてください」と明確に依頼できる。対象言語のデータしか含まれていないため、作業範囲が一目瞭然だ。

補足:.xcstrings と XLIFF の state 属性値の違い

.xcstrings(JSON)内部と XLIFF(XML)では state 属性の命名規則が異なる。.xcstrings では needs_review(アンダースコア)が使われるが、XLIFF 1.2 仕様では needs-review-translationneeds-review-adaptationneeds-review-l10n(ハイフン区切り)が正式な値となる。Xcode がエクスポート/インポート時に自動変換するため実務上は意識する必要がないが、XLIFF を手動編集する場合やサードパーティツールで処理する場合は注意が必要だ。

インポート手順

翻訳済みの XLIFF を .xcstrings に書き戻すのも1コマンドで完了する。

xcodebuild -importLocalizations \
  -project MyApp.xcodeproj \
  -localizationPath ./Localizations/en.xcloc

これで Localizable.xcstrings の英語部分だけが更新される。他の言語やキーには一切影響しない。

まとめてインポートするオプションは用意されていない。日本語(ja)を更新したい場合は、以下のように個別に実行する。

xcodebuild -importLocalizations \
  -project MyApp.xcodeproj \
  -localizationPath ./Localizations/ja.xcloc

推奨ワークフロー

XLIFF を活用することで、以下のメリットが得られる。

  • 1言語1ファイルなのでサイズが小さく、翻訳対象が明確になる
  • source / target の対が明確で、翻訳箇所を間違えにくい
  • state 属性で未翻訳・翻訳済み・要レビューを機械的に判別できる
  • Xcode 公式のワークフローに乗っているので安定性が高い
  • 翻訳会社に外注する場合も XLIFF はそのまま使える業界標準フォーマットである

これらを踏まえ、最終的に推奨するワークフローは以下の通りだ。

  1. .xcstrings に日本語でキーを追加する。Xcode の String Catalog エディタで編集する
  2. xcodebuild -exportLocalizations で XLIFF に分解し、言語ごとの .xliff ファイルを生成する
  3. 必要に応じて未翻訳キーだけ抽出する。state="new"trans-unit を対象にする
  4. 各言語の XLIFF を翻訳する。翻訳者への外注・社内翻訳・AI ツールの活用など。target を埋めて state"translated" に更新する
  5. xcodebuild -importLocalizations.xcstrings に書き戻す
  6. 未翻訳キー検出とビルド確認を CI で実施する

手順3の未翻訳キー抽出は、たとえば以下のように grep で件数を確認できる。

# 未翻訳キーの件数を確認
grep -c 'state="new"' Localizations/en.xcloc/Localized\ Contents/en.xliff

# 未翻訳キーの id を一覧表示
grep -B1 'state="new"' Localizations/en.xcloc/Localized\ Contents/en.xliff | grep 'trans-unit id'

まとめ

.xcstrings は Xcode の String Catalog として非常に便利な仕組みだが、多言語対応が進むにつれてファイルが肥大化し、管理やレビューが困難になるという課題がある。

XLIFF による言語単位の分割は、翻訳者との協業を円滑にするだけでなく、差分レビューの見通しを良くし、意図しない変更の混入を防ぐ効果もある。「巨大な JSON を丸ごと扱う」のではなく、「構造的に安全な単位に分解してから作業する」という考え方は、多言語対応に限らずファイル管理全般に通じる原則だろう。

多言語対応の運用に悩んでいる方の参考になれば幸いである。

参考リンク

この記事をシェアする

FacebookHatena blogX

関連記事