
-
Code Along:Xcodeによるローカライズの詳細
Xcodeを使用して、アプリを複数の言語にローカライズする方法を学びます。String Catalogの作成、テキストの翻訳、外部翻訳者とのファイル交換のプロセスについて詳しく説明します。必要なコンテキストを翻訳者に提供するためのベストプラクティスや、Xcodeを使用してこの情報を自動的に提供する方法について解説します。大規模なプロジェクトを対象に、型安全なSwiftコードを使って複雑さに対処し、テキスト管理を合理化する方法についても詳しく説明します。
関連する章
リソース
関連ビデオ
WWDC23
-
このビデオを検索
こんにちは LocalizationチームのAndreasです このセッションでは Xcodeによる ローカリゼーションについて説明します
このセッションに 予備知識は必要ありません ローカリゼーションのためにアプリを 設定する方法を一緒に確認します 次に アプリの翻訳担当者に 適切なコンテキストを 提供する方法について説明します 最後に プロジェクトが大きくなるにつれて 生じる複雑さと その管理に役立つ新機能について お話しします では始めましょう
このセッションはCode Alongです 説明欄にリンクがある サンプルプロジェクトに このビデオの手順を適用できます Landmarksプロジェクトをダウンロードして 一緒にローカライズを始めましょう このプロジェクトをXcodeで開きました このバージョンのLandmarksは 英語では問題なく機能しますが 翻訳は一切されていません まず メニューを使用して String Catalogを追加しましょう
デフォルト名「Localizable」を 使用できますが グループは「Resources」に変更します アセットカタログもここにあります String Catalogが追加されたので プロジェクトをビルドしましょう String Catalogが存在する場合 Xcodeは各ビルド後に ローカライズ可能な文字列を検出し それらを自動的に String Catalogに追加します カタログ内の文字列とコードの 同期を維持するために 特別なことをする必要はありません Xcodeは ローカライズする文字列を どのように見分けるのでしょうか ほとんどのSwiftUI APIでは 文字列が デフォルトでローカライズ可能になります 例えば TextやButtonなどの ビューがこれに当たります コードの残りの部分では String(localized: )でも 文字列がローカライズ可能になります
次にアシスタントエディタを使用して String Catalog内の文字列が どこから抽出されたか見てみます
これは確認ダイアログから抽出されています
この文字列は LabeledContentの タイトルとして使用されています この文字列は navigationTitleとして使用されています そしてこれは 補間変数を使用して Textから抽出されています ご覧のとおり ほとんどのSwiftUI APIが デフォルトでローカライズ可能になります 既にお気づきかもしれませんが この文字列は いくつかのアイテムを表します プレースホルダ%lldは 実行時に ランドマークの数に置き換えられます その数に応じて この文字列を変更する必要があります 例えば 「1 item」 「2 items」となるようにします
これを行うには コンテキストメニューを開いて を選択します
これで 1つの場合と複数の場合の フレーズを指定できます
実行時に 数に応じて 正しい文字列が選択されます 簡単な修正でした
さて ローカリゼーションでは 他の言語が主眼となります 私はたまたまドイツ語を話すので このString Catalogの文字列を いくつか翻訳してみます アシスタントを閉じましょう プロジェクトに言語を追加するために 下部のバーのプラスボタンをクリックして を選択します これでOKです 翻訳をいくつか追加してみましょう
状態がNEWからTRANSLATEDに 変わりました 翻訳の進行状況が 右側の緑のチェックマークで示されます
同時に サイドバーに表示される 全体の翻訳率が 8%に増加しました
私は翻訳者ではなくデベロッパなので 言語の専門家とチームを組みました 残りの翻訳は彼らに任せたいと思います
これまでの作業内容を彼らに送るには Xcodeのメニューで を選択します アプリをドイツ語に翻訳しているので ドイツ語だけをエクスポートします
ローカリゼーションカタログファイルが 生成されます これまでに翻訳した ドイツ語の文字列すべてと まだ翻訳されていない 英語の文字列が含まれています このパッケージファイルには 業界標準のXLIFFファイルが 含まれているため 翻訳サービスとの連携が容易です 翻訳が完了すると 完全に翻訳されたローカリゼーション カタログが返送されてきます
それをプロジェクトにインポートするには またメニューを使用して 今度はを選択します Xcodeによる プロジェクトのビルドが完了すると すべての文字列が翻訳済みとしてマークされ
ドイツ語の翻訳率が100%になります 皆さんも試してみてください サンプルプロジェクトに 完全に翻訳された de.xclocファイルが含まれています それを同じように Xcodeにインポートできます では これを実際にテストしてみましょう アプリをドイツ語で実行してみます スキームエディタを開きます を選択し を選択してに移動します
ここで 次回のデバッグ実行の アプリの言語をドイツ語に変更できます
次に アプリをビルドして Macで実行してみましょう
ドイツ語にローカライズされています 新しい外観も素敵です
このように 新しいアプリを 簡単にローカライズできます 次に 翻訳品質を高めるため 翻訳者に追加のコンテキストを 提供する方法を詳しく見ていきましょう Xcodeでアシスタントエディタを使用すると String Catalogのすぐ横に コードが表示されて便利ですが 翻訳者が文字列を翻訳する時には 多くの場合 コードや実行中のアプリを 見ることはできません 彼らが最良の翻訳を行えるように 追加の コンテキストを提供する必要があります
このコンテキストは コメントの形で追加されます 直接コードに追加することも String Catalogの列に 追加することもできます コメントがないと 文字列がどのように 使用されるかわかりにくい場合があります 例えば「Landmarks」という単語だけでは アプリの名前なのか 地図上のランドマークなのかわかりません また 「%@ is contained in %@」という 文字列キーでは プレースホルダ%@が何を表しているのか 翻訳者にはわかりません これは文字列の翻訳に影響します どのインターフェイス要素で使用される 文字列かを説明する必要があります タブバー、ボタン、サブタイトルなどです
周囲のユーザーインターフェイス要素を 説明するのも役立ちます 例えば 最初の文字列がサイドバーのエントリである ことを追加すると 非常に役立ちます 2番目の文字列は リスト内のランドマークのサブタイトルです これも追加しましょう 最後に 各プレースホルダに 何が表示されるのかを コメントで説明する必要があります この場合 最初のプレースホルダは ランドマークの名前で 2つ目は それが属している コレクションの名前です コメントがなければ これを正しく翻訳することは不可能です だからこそ 良いコメントを提供することが重要なのです
昨年は コードのどの部分から 抽出された文字列かを トラッキングする機能を String Catalogに追加しました 今年は その情報を使用して 皆さんを支援します Xcode 26の コメントの自動生成機能をご紹介しましょう
Xcodeがオンデバイスモデルを使用して コードを分析し あなたのためにコメントを書いてくれます 実際の動作を見てみましょう 現時点でコメントが提供されているのは コード内の一部の文字列のみです コメントがいかに重要であるかわかったので 翻訳者に提供するコンテキストを 改善しましょう ここにコメントなしの文字列があります ボタンで使われているようです コンテキストメニューを開き を選択します この文字列の抽出元が分析され このようなコメントが生成されました 「The text label on a button to cancel the deletion of a collection」 的確なコメントです
この文字列もまだコメントがないので Xcodeに生成してもらいましょう
「A label displayed above the location of a landmark」と生成されました 問題ありません さらに 生成されたコメントは 編集することができます 入力した内容は常に 生成されたコメントよりも優先されます モデルと連携して コンテキストを追加してみましょう この文字列はインスペクタに 表示されることを付け加えます
これは非常に便利な機能なので コードから新たに抽出されたすべての 文字列についてコメントを自動生成しましょう そのためにはを開き
に移動して
を有効にします 今後 コードにローカライズ可能な文字列が 新たに追加されたことをXcodeが検知すると コメントが自動的に生成されます これにより 翻訳者に必要なコンテキストを 非常に簡単に提供できます
翻訳ツールのデベロッパが コメントがXcodeによって 生成されたことを示せるように エクスポートされるXLIFFファイルに 注釈「auto-generated」が付けられます
他のツールとの相互運用性の詳細と String Catalogのその他の機能については 「Discover String Catalogs」を ご覧ください
プロジェクトが大きくなり 複雑になるにつれて 整理された状態を保つのに役立つ 追加のXcode機能と ローカリゼーションAPIがあります 例えば プロジェクトの規模が大きくなり 複数のデベロッパが取り組むようになると コードベースが拡張機能、フレームワーク、 Swiftパッケージに分割されることがあります それぞれに1つ以上のString Catalogが 含まれることもあります このような場合に ローカリゼーションAPIで新たに使用する 必要があるパラメータがbundleです これにより 文字列がどこにあるか 実行時にシステムに通知されます 「bundle: .main」は 常にメインアプリを参照します bundleパラメータを含めない場合 デフォルトで.mainが使用されます
今年の新機能となるのが#bundleマクロです これを使用すると 現在のターゲットの リソースを含むバンドルを参照できます コードがメインアプリで実行される場合は メインアプリが参照され それ以外では自動的にフレームワークや Swiftパッケージのリソースが検索されます 古いバージョンのOSでも動作し 適切な処理が行われます
文字列を整理するもう1つの方法は 関連する文字列のグループ化です 例えば 特定の画面、機能、ユーザーフロー に関連する文字列をグループ化します 文字列のグループを「テーブル」と呼びます 各String Catalogは 1つのテーブルを表します
デフォルトでは すべての文字列が 「Localizable」テーブルに抽出されます String Catalogを作成する時の デフォルトのファイル名と同じです もちろん名前を変えることもできます パラメータtableNameで 文字列を 配置するString Catalogを選択できます 例えば テーブル名「Discover」を使用すると 自動的に 「Discover.xcstrings」に配置されます
このアプリは ランドマークのプライベート コレクションを作成するには便利ですが より多くのコンテンツを発見できる機能を 開発したいと思います フォローしている友人かキュレーション されたフィードからのコンテンツです 新しいフレームワークで その機能の開発を始めましょう
まずメニューを開き 新しいターゲットを追加します 「framework」を検索します
目的は新しいランドマークを 発見することなので 「DiscoverKit」という名前にします
新しい画面をゼロから始めて そのすべての文字列を 別のテーブルに入れたいと思います DiscoverKitに新しいファイルを 追加しましょう
を選択し 「Discover」という名前を付けます
便宜上 画面の右側で コードをエディタで開きます shiftキーとoptionキーを押しながら 新しいSwiftファイルをクリックします
さらにナビゲータを閉じて もう少しスペースを広げます
モデルレイヤで列挙型を使用して この機能の開発を開始します 友人からのコンテンツか キュレーションされたものかを定義します 自身のローカライズされたタイトルを 公開するプロパティがあります 実装しましょう まず String(localized: )を使用して ローカリゼーション用の文字列を公開します 次に 整理を改善するために table引数を使用します フレームワーク内にいるので bundle引数も使用する必要があります もう一方のケースについても 同じようにします
列挙型が完成しました 次にSwiftUIをインポートし コンテンツを 表示するためのビューを追加します
まだビジネスロジックが 用意されていないため 差し当たり 42の新しい投稿があることを 示すプレースホルダを表示します
これで入力は終わりです あとはXcodeに任せましょう スキームを新しいフレームワークに変更して ビルドします
ビルドが完了するとすぐに 新しい文字列がカタログに表示されます
コメントも既に入力されています 素晴らしいですね
残りのUI作業のために Xcode 26の新しいワークフローを ご紹介します String Catalogが導入されて コードから文字列を 抽出できるようになりましたが 今年は コードの記述が さらに簡単になりました 手動で追加した文字列のシンボルが 自動的に生成されます この新しいワークフローを使用して ビューの構築を続けましょう 目標は ナビゲーションのタイトルと サブタイトルを追加することです 現在 このビュー全体はまだ開発中です 文字列のキーを値から分離すると コードを更新することなく 正確な文言を反復処理できます
まず String Catalogのボタンを クリックして 新しい文字列を追加します 多くのプロジェクトでは 大文字のキーを使って 文字列の意味を示す設定が好まれます ここでもそうします キーは「TITLE」とし 値は「Discover Landmarks」とします この文字列は手動で追加したので コメントは自分で書きます
属性インスペクタで この文字列を コードで使用する方法を確認できます これは本当に便利です その通りにしましょう
ナビゲーションバーに タイトルを表示するには ビュー修飾子「.navigationTitle」を 使用します
値については 先頭にドットを入力して テーブル名の入力を開始すると テーブル名が自動補完され このテーブルに含まれるすべての 手動文字列が候補として表示されます
実に簡単でした 今回は バンドル名とテーブル名を 手動で入力する 必要がありませんでした
同じことをナビゲーション サブタイトルで繰り返してみましょう カタログに新しい文字列を追加し 「SUBTITLE」という名前を付けます
友人からの投稿数と キュレーションされた件数を まとめたいと思います そのためにはプレースホルダが必要で それを行うのが書式指定子です まず%を入力すると いくつかの候補が表示されます ここでは数値が必要なので 整数のプレースホルダを選択します
このプレースホルダは 友人からの投稿数を表すため 「friendsPosts」という名前にします
次に キュレーションされた投稿のために プレースホルダをもう1つ追加します
さらにコメントを入力します
これで この文字列を コードで使用する準備が整いました 今回は修飾子 「.navigationSubtitle」を使用します
再び「.Discover」の入力を開始すると 適切なテーブルが検出され 自動補完機能によって候補が表示されます
入力が大幅に削減されました Xcodeが正しい入力内容を 提案してくれることに注目してください この新機能により 手動文字列の操作が非常に簡単になります 自動補完機能とコンパイラに ローカライズされたリソースのロードを 任せることができます 文字列の値を後から変更する場合も String Catalogで簡単に更新できます コードの変更は不要です 過去に入力した様々な綴りの「OK」を 1回の操作ですべて修正できたら 便利だと思いませんか
Swiftでぴったりのシンボル名を 生成するために Xcodeは文字列のキーと値を使用します プレースホルダのない文字列は 他の 静的プロパティと同様にアクセスできます 文字列にプレースホルダが含まれている場合 Xcodeは代わりに関数を生成し プレースホルダ名を 引数ラベルとして使用します 生成されたシンボルは 静的変数または関数で 型はLocalizedStringResourceです これは非常に強力です LocalizedStringResourceが使用される あらゆる場所で使用できるからです 例えば TextやButtonなどの SwiftUIビューや .navigationSubtitle()のような ビュー修飾子で使用できます SwiftUIを使用しない場合 FoundationのString(localized: )でも LocalizedStringResource型を使用できます
LocalizedStringResourceを使用する カスタムビューなどの宣言も 生成されたシンボルを使用して 呼び出せるようになります
デフォルトのテーブル名 「Localizable」を使用している場合は LocalizedStringResourceで 直接シンボルにアクセスできます テーブル名がデフォルト以外の場合 生成されたシンボルは そのテーブルの名前空間にネストされます つまり コードでアクセスする際に 先頭にテーブル名を付けます Xcode 26で作成された新規プロジェクトでは シンボル生成がデフォルトで有効になります 既存のプロジェクトで使用するには ビルド設定「Generate String Catalog Symbols」をオンにします
これで Xcodeで2つの異なる文字列管理ワークフロー が完全にサポートされるようになりました コードからの抽出と タイプセーフなAPIによる参照です どちらのワークフローを 使用するべきでしょうか まず 文字列抽出を 使用することをお勧めします UIを開発する場所で文字列を記述するため コードをよりすばやく読んで 理解できます このワークフローなら Xcodeのコメント生成機能を活用して 入力の手間を省きつつ 翻訳者に有意義なコンテキストを 提供できます プロジェクトが大きくなるにつれて 文字列をより詳細に 整理する必要が生じたら 生成されたシンボルを 使用することをお勧めします これにより キーとその値を分離できるため コードを変更することなく テキストを反復処理できます さらに Xcodeの自動補完機能により すべてのテーブルの文字列を 簡単に参照できます 最後に 生成されたシンボルは フレームワークとパッケージで 定型コードの回避に役立ちます
どちらのアプローチにも長所があります 皆さんのプロジェクトに適したアプローチを 自由に選択してください この2つを簡単に 切り替えられるようにするため 強力なリファクタリング機能を 追加しています DiscoverKitフレームワークで 試してみましょう ナビゲーションスタック内の プレースホルダテキストは シンボルによる参照の 最適な候補だと思います コンテキストメニューを開き > を選択します
プレビューUIが開き 文字列の代わりにシンボルが使用される 正確な場所が示されます ハイライトされたセクションを クリックすると シンボルを 元のコードと比較できます
キーの名前を「feedTitle」に変更して 意味を明確にしましょう Argument 1に名前を付けることもできます 「newPosts」にしましょう これで良さそうです リファクタリングを確定します
両方のアプローチを検討した結果 このテーブルのすべての文字列に 生成 されたシンボルを使用することにしました 残りの2つを選択し
>を選択します
シンボル名に問題はないので をクリックします
このように テーブル全体を一度に 簡単にリファクタリングできます Xcodeのこれらのローカライズ機能を ご自身で試してみることをお勧めします まず 文字列抽出を使用して プロジェクトをローカライズします 翻訳者に有意義なコメントを提供するために コメントを自分で書くか Xcodeのコメント生成機能を使用します プロジェクトが複雑になってきたら 生成されたシンボルを使用して 文字列を正確に制御することを検討します
最後に String Catalogの詳細については 以前のビデオ「Discover String Catalogs」 をご覧ください ありがとうございました これらの新機能をローカリゼーション ワークフローの合理化にお役立てください
-
-
1:34 - Localizable strings
// import SwiftUI Text("Featured Landmark", comment: "Big headline in the hero image of featured landmarks.") Button("Keep") { } // import Foundation String(localized: "New Collection", comment: "Default name for a new user-created collection.")
-
6:00 - Adding a comment
Text("Delete", comment: "Delete button shown in an alert asking for confirmation to delete the collection.") String(localized: "Shared by Friends", comment: "Subtitle of post that was shared by friends.")
-
9:13 - XLIFF file
// Field for automatically generated comments in the XLIFF <trans-unit id="Grand Canyon" xml:space="preserve"> <source>Grand Canyon</source> <target state="new">Grand Canyon</target> <note from="auto-generated">Suggestion for searching landmarks</note> </trans-unit>
-
9:58 - Localized String in the main app and a Swift Package or Framework
// Localized String in the main app: Text("My Collections", comment: "Section title above user-created collections.") // Localized String in a Swift Package or Framework Text("My Collections", bundle: #bundle, comment: "Section title above user-created collections.")
-
10:56 - Localized String with a tableName parameter
// Localized String in the main app: Text("My Collections", tableName: "Discover", comment: "Section title above user-created collections.") // Localized String in a Swift Package or Framework Text("My Collections", tableName: "Discover", bundle: #bundle, comment: "Section title above user-created collections.")
-
17:31 - Symbol usage
// Symbol usage in SwiftUI Text(.introductionTitle) .navigationSubtitle(.subtitle(friendsPosts: 42)) // Symbol usage in Foundation String(localized: .curatedCollection) // Working with generated symbols in your own types struct CollectionDetailEditingView: View { let title: LocalizedStringResource init(title: LocalizedStringResource) { self.title = title } } CollectionDetailEditingView(title: .editingTitle)
-