ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
SwiftUI Appのローカライズ
SwiftUI Appをローカライズして、世界中のユーザが利用できるようにする方法を確認しましょう。スタイルやフォーマットを含む、SwiftUIの文字列をローカライズする方法を確認します。レイアウト、キーボードショートカットなどのタスクをSwiftUIに自動的に処理させることで時間を節約する方法を実演して、Xcode 13のローカリゼーションワークフローを紹介します。 このセッションを最大限に活かしていただく、あるいはMarkdown言語、AttributedStringについて詳しく知りたい方は、WWDC21の「Foundationの新機能」をご確認ください。
リソース
関連ビデオ
WWDC22
WWDC21
-
ダウンロード
私はSwiftUI Macチームの エンジニアのポールです 後で同僚のケイトが加わり SwiftUIアプリをローカ ライズする方法について 話してくれます ご存知の方もいると 思いますがFrutaアプリを サンプルに説明します このアプリによりスムージー のメニューを見たり注文 したりレシピを見て自分で 作ったりできます
ここでは私とケイトの母国語 であるロシア語のローカリ ゼーションをアプリに追加 します 良い練習例 ですのでご自分のアプリ で使ってみて下さい 基本事項としてSwiftUIで 文字列をローカライズし 設計上のリスクを回避 する方法についてお話します 文字列とデータのスタイルと フォーマット及びキーボード ショートカットのローカ ライズの改善点もお話します 最後にケイトがデモを行い Xcodeのワークフローの ”改善”によりアプリの ローカライズが非常に簡単 になったことをお見せします アプリケーションをローカ ライズする上で重要な事は UIの様々な文字列が翻訳者に 公開され実行時に正しく レンダリングされることを 知っておくことです SwiftUIを使うとメインバン ドルでローカライズされた 文字列が自動的に検索される ためこれが簡単になります この例ではロシア語の文字列 ファイルの翻訳に基づき実行 時に自動的にローカライズ される完了ボタンがあります 文字列補間でも機能するため 変数を文字列に埋め込むこと ができエクスポートされた 文字列ファイルとカタログに おいて自動的にフォーマット 指定子に変換されます Xcode 13の新機能は 文字列の変数の型に基づき フォーマット指定子の型を 自動推測することです 制御を強める時テキストには テーブル名とバンドルのオプ ション引数を追加できます この例では材料関連の 文字列を全て”材料” という別のテーブルに 配置しました スムージーの実際の材料とは 別に この文字列テーブルで ”材料”の語に対して バリアントを2つ設け スムージービューと レシピビューの2つの コンテキストに当てました ご覧の通りロシア語では コンテキストに基づき この2つの語を別の語に 訳す必要があるからです 文字列を整理する方法につい て詳しくは”ローカライズさ れた文字列を効率化” の回をご覧ください。 テキストの最初の引数により 全て機能します 文字列リテラルを受け入れる ビューとメソッドがあれば このタイプを利用して ローカライズ可能にできます ビューおよび関数に引数 として渡されたリテラルは Xcodeのローカリゼーション エクスポート中に自動的に 抽出されランタイムにバン ドルからロードされます 先のボタンの例のアプローチ はビューの代わりに テキスト引数を 受け入れさせるものです LocalizedStringKeyを使用し 環境ロケールを指定すると 一度に複数のロケールを プレビューできます NSLocalizedStringでロード した文字列を含むローカ ライズ後の文字列を全て プレビューすると スキームエディタで言語を 変更することができます Xcode 13ではプロジェクトを エクスポートするとターゲ ットを全て作成しローカライ ズ可能な文字列を検出します つまりXcodeはローカライズ 可能なコンテンツを検出し 抽出するという優れた作業 ができるということです 複数行の文字列を含むコード があると想像してください ローカライズ後のコンテンツ の抽出にコンパイラを使用 するため複数行の文字列リテ ラルも正しく解析されます ではSwiftUIを使用し ローカライズに適したレイ アウトでアプリを簡単に作成 してみましょう 文字列検索と同様にSwiftUI のデフォルトのレイアウト はローカリゼーションを 想定して設計されており 追加の作業はほとんど 必要ありません コントロールとテキストは テキストをラップして長い ラベルの言語によるクリップ や切り捨てを防止します この場合 ロシア語で スムージーの名前が長いため 2行目に折り返されています 右から左へ読む言語の場合 レイアウトは自動反転します スクリーンショットでは テーブルセルのレイアウトも タブバーの記号も 反転しています またデフォルトから変更して カスタマイズする場合も 左寄だけでなくVStackから 主要な配置を用いるなど ローカリゼーションに適した オプションを用意しています 次にアプリを作成する際に UIに表示されるローカライズ されたテキストのスタイルを 整えることもあります このためマークダウンを利用 してローカライズ可能な 文字列のスタイルを整える 機能を導入しました このためローカライズされた 文字列へのスタイリングが 大幅に簡略化され翻訳者は 各言語に適したスタイリング を適用することができます 例えばアラビア語には イタリックの概念が ないため 英語の文字列で 強調をした場合 翻訳者は 別の処理で 強調をします この場合 ロシア語の翻訳者は 英語の意図と一致させるため 文字列内の関連する 単語の前後に マークアップを用いました このサポートは基本的に 備わっていますが SwiftUIを使用すると スタイルされた文字列を テキストに直接投げるだけで 簡単に表示できます 詳しくは ”基本事項とSwiftUIの 新機能”の回を チェックしてみて下さい アプリのローカライズでよく 起こる事は言語と地域に 適したフォーマット用いる ということです 使い易くTextとTextFieldと 一体化した新規フォーマット APIを使うと このタスクは 実行可能です FrutaではUIの多くの場所で カロリー数を表示できます 以前はフォーマット値を表示 するために このスライドに 似た測定フォーマッターを 作成する必要がありました 現在は値の表示箇所に 直接インラインで宣言的方法 によりフォーマットを 指定することができます 前のスライドのコードよりも 読み易いだけでなく 効率も良くなります 新規フォーマットAPIの詳細 については”基本事項の 新機能”の回をご覧ください 最後にキーボードショート カットを見てみましょう これを用いると初心者も 熟練者もMacとiPadでの タスクを更に迅速に 遂行できるようになります macOSとiPadOSの新機能に よりSwiftUIアプリで定義 したショートカットが自動 調整されユーザーのアク ティブキーボードレイアウト で入力可能になりました 例えばお気に入りのリストに スムージーを追加したい場合 ”Command plus”と入力 すると追加できます これはコマンドキーと プラスキーの2つを押せば 良い米国レイアウトで 非常に良く機能します リトアニア語のキーボード レイアウトではプラスキーを 押すのは簡単ではありません バッククォートキーと”シフ トイコール”を押しますが この組み合わせはコマンド キーを押している間は 入力できません macOS MontereyとiPadOS 15 の再マッピング機能により リトアニア語のキーボード レイアウトがアクティブな 状況下では このショート カットは”Command ž”に 変更され ショートカットを使って お気に入りにスムージーを 追加出来るようになりました ここがベストな箇所です 開発者は何もしなくても ただ機能してくれるのです それではケイトに代ります Xcode 13のローカリゼー ションワークフローの 改善点に加え 先程説明した 内容と新規APIのデモを 見せてくれます ポール有り難う こんにちは チームの エンジニアのケイトです SwiftUIアプリのローカライ ズの簡潔さを見てみましょう Frutaサンプルアプリです 世界中の人々が母国語で スムージーを注文できるよう にしたいと思います 本日はロシア語のローカリ ゼーションを追加します プロジェクトナビゲーター からプロジェクトに移動し プロジェクトエディターで ”Fruta”を選択し情報 タブからローカリゼーション を追加します macOSに付属するローカリゼ ーションは全てアルファベッ ト順にリストされています Xcode 12.5ではリスト下部の ”その他の言語”サブメニュ ーに数百の言語と方言を 追加してあります ”ロシア語”を選択します Xcode 13はSwiftコンパイラ の新技術によりSwiftコード からの文字列抽出を大幅に 簡素化しました
Frutaのビルド設定で”コン パイラを使用してSwift文字 列を抽出する”が”はい”で あることを確認します 新規Swiftではデフォルトで 有効となっていますが既存の プロジェクトの場合は この設定をオプトインします エクスポート後Xcodeはプロ ジェクト内のターゲットを 全て作成しSwiftUIコードか らLocalizedStringKeysを 抽出します エクスポート前にSwiftUI プレビューで疑似言語を用い ローカライズ可能な文字列 と見逃しを確認します スキームエディターに移動し オプションタブからアプリの 言語をクリックします アプリがサポートする言語は 全てこの上部にリストされて いますが1番下のアクセント 付き疑似言語を選択します
アクセント付き疑似言語は UIのソース文字列に様々な アクセント記号を付与します 全ての材料が疑似 ローカライズされています 計量値はフォーマット化 されているため別ですが StepperViewは疑似 ローカライズされるはずです それではやってみましょう StepperViewはラベル文字列 を取り込みテキストビュー に渡すSwiftUIビューです カスタムSwiftUIビューでは LocalizedStringKeyを使っ てローカライズします 出来ているか見てみましょう
完璧です! ローカライズ可能にな ったので複数形が適切に処理 されるか見てみましょう このコードは英語の ”スムージー”を複数形に しますが全ての単語や 言語には対応していません stringsdictを使いましょう stringsdictファイルを 使うと複数形に様々な訳を 適用することができます Stringsdictの詳しい内容 については”ローカライズ された文字列の効率化” のビデオをご覧ください
ここに準備したファイルを プロジェクトにドラッグして
ローカライズにマークします
エクスポートしてみましょう Xcode 12.5以降製品メニュー からプロジェクトとワーク スペースをインポート・エク スポート可能になりました Export Localizationsを選ん でデスクトップに保存します
XcodeはプロジェクトとXcode ローカライズカタログを作成 してロシア語に翻訳するため ポールに送る準備をします 詳しくはWWDC2018の ”Xcode10の新規ローカリゼ ーションワークフロー” の回をご覧ください
送信前にエクスポート されたものを見てみましょう Xcode 13以降Xcodeローカリ ゼーションカタログは更に 利便性が高くなりました Finderでダブルクリックして Xcodeで開くだけです これは非常に便利でアプリの ローカライズ時 ローカラ イズ用コンテンツ送信前に 文字列やスクリーンショット を確認する時 翻訳の修正時 に使うことができます
エディタではローカライズす る全ファイルを確認できます ファイル選択により翻訳者と 同様に全文字列が見れます キー ソース文字列 翻訳 コメントです 全て良好な状態かどうかを ざっと確認します 問題点が数点見つかりました まず”%lf Calories”の文 字列をエクスポートしました 地域によりカロリーの測定 単位が異なるためこの 文字列はフォーマット化 する必要があります この修正にはコード変更の 必要があります
文字列の代わりに 文字列が抽出された NutritionFactViewで NutritionFacts構造体の 計量型に”formatted”法 を利用します 食品カロリーの測定なので ワイドフォーマットの使用法 を”食品”に設定します これで全地域の単位の フォーマットが処理されます 簡単な修正でした 文字列の確認に戻りましょう
翻訳者は変数名を見れない ので”Buy recipe for %@” のような文字列は混乱させる 可能性があります レシピの購入か友達へのプレ ゼントなのか分かりません 他にも曖昧な文字列がないか 見てみましょう
”Favorite”は動詞とコメン トがありますが”Favorites” は明らかに名詞なので コメントを追加します コードに両方の コメントを追加します
まず”レシピを購入する” の文字列を処理しましょう
出来ました タブバー内の”Favorites” の文字列にコメントします
タブバーはラベルビューです コメント追加にはテキストビ ューでラベルを初期化します
このようなコメントの追加は 高品質なローカリゼーション のために不可欠です 翻訳者を混乱させたり推測 させたりしてはいけません 全て修正出来たと思います 新たなカタログをエクスポー トしてポールに送信します
速かったですね ポールは翻訳者の Appleシリコンです 彼が返信してきたものを ちょっと見てみましょう
ここで翻訳が全てが見れます これは追加したスムージー ステッパのstringsdictです
インポートしてロシア語の 表示を見てみましょう 製品メニューに移動しローカ リゼーションのインポートを 選択しカタログを選択します
全文字列が完了済のはずです macOSのアプリをロシア語で 処理実行してみましょう スキームをmacOSに 言語をロシア語に 変更します
実行してみましょう
ロシア語のアプリは素晴らし い出来です スムージーも どれも美味しそうです 材料と栄養価を全て 見ることができます これを注文してみましょう
素晴らしいサービスです
ローカライズは簡単なので コード記述に集中できます アプリの開発で注意すべき 重要な点をお伝えします LocalizedStringKeyは バンドル内でローカライズ された文字列を検索する SwiftUIの特別な型です カスタムSwiftUIビューで ローカライズの準備をします ”コンパイラを使用して Swift文字列を抽出”を有効 にしてLocalizedStringKeys を抽出します コードを国際化しマークダ ウンでスタイルを設定します
テキストを利用しコンテキス トへのコメントを追加します
ご覧頂き有り難うございます 別のWWDCもお楽しみください
[音楽]
-
-
1:34 - Text() with a string literal
Button(action: done) { Text("Done", comment: "Button title to dismiss rewards sheet") }
-
1:58 - Text() with a string literal and interpolation
// RewardsCard.swift Text("You are \(10 - totalStamps) points away from a free smoothie!")
-
2:06 - Text() with tableName
// RecipeView.swift Text("Ingredients.recipe", tableName: "Ingredients", comment: "Ingredients in a recipe. For languages that have different words for \"Ingredient\" based on semantic context.") Text("Ingredients.menu", tableName: "Ingredients", comment: "Ingredients in a smoothie. For languages that have different words for \"Ingredient\" based on semantic context.")
-
2:52 - Declare localizable attributes in a custom view
struct Card: View { var title: LocalizedStringKey var subtitle: LocalizedStringKey var body: some View { Circle() .fill(BackgroundStyle()) .overlay( VStack(spacing: 16) { Text(title) Text(subtitle) } ) } } Card( title: "Thank you for your order!", subtitle: "We will notify you when your order is ready." )
-
3:47 - Text() with multiline string literal
Text(""" A delicious blend of tropical fruits and blueberries will have you sambaing around like you never knew you could! """, comment: "Tropical Blue smoothie description")
-
4:39 - Customize attributes
VStack(alignment: .leading) { Text(smoothie.title) .font(.headline) Text(ingredients) }
-
5:13 - Using Markdown
// Smoothie.swift Text("A refreshing blend that's a *real kick*!", comment: "Lemonberry smoothie description")
-
6:04 - Create a measurement formatter (prior to iOS 15)
let calories = Measurement<UnitEnergy>( value: nutritionFact.kilocalories, unit: .kilocalories) static let measurementFormatter: MeasurementFormatter = { let formatter = MeasurementFormatter() formatter.unitStyle = .long formatter.unitOptions = .providedUnit return formatter }() Text(Self.measurementFormatter.string(from: calories)) Text("Energy: \(calories, formatter: Self.measurementFormatter)")
-
6:22 - Specify the format in a declarative manner (iOS 15)
let calories = Measurement<UnitEnergy>( value: nutritionFact.kilocalories, unit: .kilocalories) Text(calories.formatted(.measurement(width: .wide, usage: .food))) Text("Energy: \(calories, format: .measurement(width: .wide, usage: .food))")
-
6:53 - Specify a keyboard shortcut
struct SmoothieCommands: Commands { var body: some Commands { CommandMenu(Text("Smoothie", comment: "Menu title for smoothie-related actions")) { SmoothieFavoriteButton(smoothie) .keyboardShortcut("+") } } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。