ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
グローバルAppをビルドする:事例を挙げてローカライズ化
世界中のデバイスでAppを実行する方法や、言語に関係なく、すべてのユーザーに素晴らしいエクスペリエンスをもたらす方法をご覧ください。多様なユーザー向けのAppを作成する際に、AppleのAPIにより強固な基盤が実現する仕組みをはじめ、経験則に基づく事例、問題点、ベストプラクティスを紹介します。
リソース
- Expanding Your App to New Markets
- Internationalization and Localization Guide
- Localization
- Localizing package resources
関連ビデオ
WWDC23
WWDC22
WWDC21
WWDC20
-
ダウンロード
こんにちは WWDCへようこそ Appleローカライズチームの Andreasです 本日は高品質なローカライズ Appの構築方法について いくつかの例を ご紹介したいと思います
国際化とは世界中の デバイスで動作するように Appを 準備することです ローカライズがうまくいけば 話す言語に関係なく 誰もが同じように素晴らしい体験と 効用を享受することができます Appleが提供する APIを使用すれば Appのほとんどの 部分がすぐに 国際化に対応できます 本トークではAppleのAppを 多様なユーザーにアピール するために私たちが どのような課題に取り組み どのように解決して いったかをご紹介します まずローカライズされたテキストの 宣言と読込みから説明します 文字列の中に書式化された日付や 時間などを簡単に含められます いくつかのオプションに注目し 洗練された例を見てみましょう ご自身のSwiftパッケージにもローカライズ されたテキストがあるかもしれません ローカライズワークフローの改善に ついても学ぶことができます 最後にレイアウトとSwiftUIの 素晴らしい新機能について話します Appleでは私たちのAppが世界中の ユーザーに素晴らしい体験を 提供できているかどうかを 常に確認しています そして「天気」Appは その一例です 毎日 何百万人ものユーザーが 予報を確認するために開いています 世界のどこにいても彼らにとって Appはこのように見えます UIが彼らの好みに合わせて 調整されている事にご注目ください 現在の天候の説明を ローカライズしたり 数字を現地に合わせてフォーマット化 したりしています また言語が左から右か 右から左かによって UIを適切に最適化しています 私たちがカスタマイズしている ものを まずは翻訳から 詳しく見ていきましょう 英語で「風が涼しく感じさせてくれる」 と書かれています そして他の言語では このようになります これらを適切に サポートするためには String(localized)を使って文字列を 宣言すればよいのです Xcodeはローカライズのために エクスポートする時にそれを検出し 私たちはその結果を 翻訳者に送ることができます その際にMacのメールAppを 使用することにしています ついでに 見せたいものがあります メールのコンテキスト メニューを開くと 「アーカイブ」という特別なフォルダに 移動させることができます サイドバーに 設置されています どちらも英語で「アーカイブ」を意味する 言葉であることに注目ください しかしスペイン語など 他の言語では アクションとフォルダー名を 表す単語が異なっています 同じ英単語でも 文脈が異なれば 他の言語では異なる 単語が使われる こともあります この場合コードで2つの文字列を 使用する必要があります そのため文字列イニシャライザーに 新しいAPIを今年追加しました これで英語の文字列に使用できる デフォルト値を取得可能に そして翻訳者が区別を 明確にできるように ローカライズされた 文字列のキーを変更する こうすることで英語でAppを 実行すると同じ単語が表示され スペイン語の翻訳者は異なる単語を 提供出来るようになります 昨年のトーク「ローカライズ 文字列の効率化」では 文字列管理の基本を 理解し さらにローカライズプロセスに 踏み込んだ内容となっています この例から同じ英単語あるいは 文章全体がUI上では異なる文脈で 表示されることがあることを 感じ取ってほしいのです このような場合コード内で2つの異なる 文字列を使用するようにしてください 天気はAppだけ ではありません システムとの 連携も万全です ここでは現在地の天気を 確認するためにAppを開くことを 提案するユーザー アクティビティを表示しています それがどのように 実現されるか見ていきましょう 文字列はこのように 宣言して読み込み 文字列補間を使って任意の 場所の名前を挿入できます この名前は都市名であったり 現在地を表す言葉であったりします 英語ではうまくいきます それぞれ 「Show weather in Cupertino」 「Show weather in my location」です しかし他の言語では文法的な 問題にぶつかることがあります 例えばドイツ語では 都市名を表す前置詞は有効だが 現在地を表す言葉を 挿入する場合は間違っていて 代わりに別の訳語を 用意する必要があります ここでの解決策は簡単です 2種類の文字列を 使用するだけです 都市名の挿入は 最初のものでよく 現在地は別の文字列を 使っています これにより翻訳者はその言語に 合った正しい文法を 使用することが できるようになります そして英語とドイツ語どちらでも うまく機能します この例は変数を 挿入することで文章 全体に影響があることを 示すために作りました 文字列の結合は他の言語では 意外な結果をもたらします 文法に抑揚が必要だったり 大文字 小文字の使い分けが必要な場面も しかしコードを書く時に それを事前に知ることは難しいものです その言語を話す人が Appをテストすることは ワークフローの中でかなり 重要なパートです プログラムでの文字列作成時は このことを覚えておいてください
さて文字列がどのようにコードで 宣言されるかをよく理解した所で そのコメントについて 説明しましょう もう一度先ほどの例の文字列を 適切なコメント付きで見ましょう 翻訳者にとってコメントは 本当に大切なものです 文字列を宣言した時と 同じ意図で 翻訳に必要な文脈を 与えるようにする必要があります 素晴らしいコメントでは 文字列がラベルやボタンなど どのUI要素に 表示されるかを説明します またUI要素の文脈や画面のどこに 表示されるかを説明します セクションヘッダー コンテキスト- メニュー ユーザーアクティビティなどです 文字列に変数が 含まれている場合は その値を実行時に 説明しましょう これは例文で 見たように文法を 一致させるために 非常に重要なことです 翻訳者がコンテンツを 翻訳する際に ランタイムのAppを見ない 可能性も留意ください しかしこれらのヒントにより 文字列の宣言と翻訳の間に 共通の理解を得ることができ それがあなたのAppで どのような役割を果たすかを 理解できるようになるはずです さて今まで思いもよらなかった かもしれませんが「天気」Appは 実際に天気をコントロール しているわけではありません その代わりデータは サーバーからダウンロードされています 世界のどこかどの言語で コンテンツを 送ればいいのかさえ わからないかもしれません コンテンツがデバイスに ダウンロードされる時 常にユーザーが好む言語で 表示される必要があります Appの一部だけローカライズすると かえって混乱することがあります ここではサーバーから 読込んだ悪天候のアラートを 「天気」Appで 表示しています これは本当に深刻で もし私の言語に 翻訳されていなかったら 後で困るかもしれませんね ここではユーザーが常に リモートコンテンツを 読めるようにするために できることを見ていきましょう
サーバーからAppに 対応言語リストを送信できます これは言語IDの配列で ユーザーが どの言語を好むかについては デバイスがすべて把握しているので 自分でチェックしたり 比較したりする必要はないのです Bundle.preferredLocalizationsを 呼び出すことで Appleのフレームワークを 利用することができます 候補となる言語を ユーザーが選択した言語に どれだけ近いかで ソートした配列を返します 最初の言語が大抵一番しっくりくる のでこれを使うことになります その言語は後のサーバーへの リクエストに使用しましょう それを使いユーザーが 理解できる言語で書かれた 内容のレスポンスを 生成します このテクニックを使えば サーバーから送られてくる文字列が UIを更新したりユーザーに アラートを表示したりするための 準備が整っていることを 確認できます そこでリモートコンテンツを 表示する際にユーザーを イライラさせないために 利用可能な言語をダウンロードし それをユーザーの好みの言語と 照らし合わせてみましょう その結果をユーザー向けコンテンツを 読み込むリクエストに使用します いい天気に戻りましょう 雨の日も晴れの日も「天気」Appは 非常に豊富なデータを持ち 多くの面で数字や カウントを含んでいます そのうちのひとつに 焦点をあててみましょう 「降水量」の下に「過去6時間 で0mm」と表示されています 同じようなものを作りたいと 仮定してここでは 「1時間」と綴ることに しましょう このようにコードで文字列を 宣言することができます 英語では1時間より 大きい場合は two hoursのように 複数形を使う必要があります ウクライナ語では別の 変種を使用する場合の ルールはさらに複雑です そのロジックを自分のコードで 実装したくないからこそ Appleのフレームワークを 活用するのです コード内で文字列を宣言し 複数形のルールをエンコードした stringsdictファイルを 用意するだけでよいのです また 自動文法一致機能を 利用するのも一つの方法です この2つのテクニックに ついては昨年のトーク 「ローカライズ文字列の効率化」で 詳しくご紹介しています 簡単とはいえすべての 文字列に対して常に複数形の ルールを適用するべき ではありません 例えば文章が何も数えておらず 数字も含まれていない場合 その文章に複数形の規則を 使うべきではありません この「この都市をお気に入りから- 削除する」は 番号がないため不要であり 複数の都市でも同様です しかし文字列に数字が 含まれている場合は 複数形のバリエーションを 検討する必要があります 先ほどの文字列は何時間後にどれだけの 雨が降るかを数えるものでしたが 1より大きな数に対しても簡単に 最適化できることを学びました しかし文中に期間 時間 割合などの単位がある場合は フォーマッタの使用を 検討する必要があります では次にフォーマッタに ついて説明します 「天気」はこのビューで現在の 湿度をパーセントで表示します SwiftUIでこれを行うには 1行のコードを書くだけです 値をText()で囲み 数値の書式を 指定するだけです そしてそれに相当する Swiftのコードもシンプルです 値に対して'.formatted'を 呼び出すだけです
本当にそれだけです あとはフォーマッタが 全部やってくれます パーセント記号を 数字の前や後に置いたり スペースを加えたり するだけでなく ユーザーの好みの番号付けに 対応しアラビア語や ヒンディー語のユーザーが 期待するものになっています しかしこれはフォーマットできる データ種類の一握りにすぎません ほぼ全てにフォーマッタがあるので セッションを振り返ってください 「フォーマッタ:データを ヒューマンフレンドリーに 」です
これまで見てきたように 天気はいつも晴れとは限らず 雨の日もあります もちろんこれは「天気」Appに 欠かすことはできない 「雨量」のところに「今後24時間で- 50ミリの予想」とありますが 今いるところは大雨でない ので本当によかったです 英語ではシンプルです 「今後24時間で50ミリの予想」 と言います しかしスペイン語では もっと複雑です 降水量が単数の場合と 複数の場合で 訳語を変える 必要があります 解決するにはフォーマッタと 複数形ルールの両方を組み合わせます 「2mm 」という文字列は フォーマッタによって生成され スペイン語で複数形を変化させる 必要のある文に埋め込まれています ではその方法をコードで 見てみましょう まず降水量をミリメートル単位で 表すパラメータを 受け取る関数を 宣言することから始めます おそらくサーバーから ダウンロードされたのでしょう まずユーザーの設定を 暗号化したUnitLengthを システムに要求し 雨量を表示する場合に 適切なものを選びます ユーザーが単位を使用するよう システムを構成していない場合 測定タイプは簡単に 希望の単位に変換できます
次にフォーマットAPIに より1行のコードで値の フォーマットされた 文字列を生成できます preferredUnitには すでに降雨を 表示させたいという情報が 入っています そこでフォーマットする際 使用方法をasProvidedに設定します 1ミリや1インチ以上の 雨が降る場合は 複数形のケースを使いたいですね それを確認できるように 値を整数に変換しています 次にローカライズされた 文字列を指定された キーでロードし デフォルトの値も提供します そこでは 文字列補間を 用いて整数値 フォーマットされた値 および数字24を含んでいます 常に24時間となるため ここではコードで定義します 文字列補間を 使用すると自動的に 正しい番号付けが 行われるようになります キーはstringsdictファイルで 宣言されます それを見てみましょう stringsdictは先ほどコードで 使用したキーから始まります 英語では複数形のために 文字列を変化させる必要はないので 「other」という カテゴリーで対応します 最初のパラメータは実行時にどの カテゴリが選択されるか定義しています 整数値でしたね パラメータ番号2と3はフォーマット された文字列の中にあります これは実行時にどのような 文になるかを定義します スペイン語のstringsdictも 同じ構造で 単数形と複数形の両方で 翻訳を提供しています
これでコードのデータをフォーマットし 文中に配置しました stringsdictファイルには スペイン語翻訳が正しい文法を 使用するように複数形の ルールが含まれています すべての言語で正常に動作する 完全なローカライズされた UIを提供することは 時に困難です 文字列の結合は 英語では有効でも他の言語では 意外な結果をもたらす可能性が あることをここでも学びましたね これを行うには包括的なコードが 必要になるかもしれませんが 全ユーザーに対応するための 方法が分かったかと思います 文字列が従属関係に あったりAppが使用する モジュールに含まれて いることもあります あるいはSwiftパッケージを 使って自分のコードも 他のデベロッパに配布して いるかもしれません それではローカライズにあたっての 新機能を紹介しましょう Swiftパッケージの定義では Swift自身を使用して 構造とビルド構成を 宣言します ユーザー向けの コンテンツがある場合 defaultLocalization パラメータを使用すると コンテンツが主要言語として英語を 使用している事を宣言できます Appのプロジェクトで開発言語を 指定するのと似ています Xcodeはそのパラメータを読み ローカライズされた体験を 提供することに興味があることを 認識するようになりました Productメニューに「Export Localizatins」 のオプションが追加されました この機能はメインAppで 使い慣れたものでしょうが 今回Swiftパッケージでも 使えるようになりました 「Export」をクリックするとXcodeが コードを読み全文字列を抽出します これらは翻訳者に送る .xclocファイル内に配置されます そしてローカライズされた コンテンツをパッケージに インポートし直すには 「Import Localization」を使用します Xcodeはローカライズされたファイルを パッケージ内の正しいファイルパスに配置します Swiftパッケージのワークフローは Appのローカライズと同じになりました
しかしSwiftパッケージで 文字列を読み込むには 'bundle'引数を指定する必要が ある点を留意ください 「Swiftパッケージ:リソースと- ローカリゼーション」という トークで詳しく 説明しています Swiftパッケージとして配布されている ライブラリの作者であれば プロジェクトの更新と ローカリゼーションをワークフローの 一部として簡単に 行うことができます せっかく苦労して作った プロジェクトですから ローカライズすることでクライアントの 時間を大幅に短縮できます 本当に効果的です ソフトウエアで最高の 体験を提供するために 努力をしていることを 認識してもらい アピールできますね どの言語をサポートして いるのかオープンにすること App開発者は コード品質の観点だけでなく 信頼性についても 特別な配慮をする 必要があります 使用するコンポーネントは Appの他の部分と 同じ言語と高品質の翻訳を サポートする必要があります サードパーティーのコードが 必要な言語に ローカライズされていない 場合でもパッケージの ローカルコピーを作成しそこで ローカライズを更新できます Appをくまなく対応する 言語で必ずテストしてください こうすることでユーザーの 言語に適応していない UI要素が存在しないことを 確認できます 翻訳された文字列は ほとんどの場合 英語の相当値よりも 長かったり短かったりするので Appのレイアウトに 常に影響を及ぼします 「天気」Appでどういう事か 確認しましょう これは英語で 動作しているAppで 右側はアラビア語で 動作しているのがわかります 翻訳だけでなく レイアウトも適切な 方向性に沿っている ことがわかります すべての言語に対応する レイアウトの作成方法 ローカライズされた シンボルの種類 右横書き言語での 考慮事項などについて 詳しく知りたい場合は ぜひトーク 「Get it right... to left」を ご覧ください
ここでは右側でヒンディー語で Appが動作しています ズームしましょう この言語のスクリプトは 一般に背が高くなる傾向があり そしてよく見ると その分ラベルの高さが 調整されているのです システムが自動的に行います UI要素に固定の高さを 与えないように すればいいのです 英語の文字列に合う 高さだからといって すべてが44ポイントに収まる とは思わないでください 状況に応じて常に背が伸びた 文章になることを留意ください
メイン画面に戻って スクロールすると 10日間の天気予報が 表示されるので 次の1週間をチェック するのに最適です
この画面で注目すべきは 長いラベルに合わせて エレメントの位置を ダイナミックに調整している点です 英語では"Today "は平日の 略称より長いです しかしスペイン語では 3文字なのに ギリシャ語では 「今日」という訳語がほぼ2倍の 大きさになります ただしどの言語でも天気予報の アイコンは縦に並んでいます つまり隣接する要素との 間隔が固定されておらず 最長曜日ラベルに 従って流れています 国際化に対応した レイアウトを作る場合ラベルは 常にフレキシブルであることを 意識しておく必要があります 縦方向に柔軟に対応させる事が重要な点は お分かりいただけたと思いますが ラベルは翻訳が長くなると横にも 伸びることが予想されます この例のように 特定のレイアウトで それに対応するのは 大変ですが 今年はSwiftUIがGridをサポートし この種のレイアウトを簡単に 構築できる新しいビューを 追加しています それではGridの使い方を 詳しく見ていきましょう まずGridをalignment: leadingで宣言します つまりUI要素は左から右の 言語では画面の左側から 右から左の言語では 画面の右側から 始まるということです そして水平方向のグループ ごとにGridRowを追加します そして最後に 行の内容を宣言します これだけでかなり高度な レイアウトが完成するのです ラベルにスペースが 必要な場合カプセルは 最も柔軟な要素であるため サイズを縮めることができます SwiftUIは測定 サイズ調整 ビューの位置決めなどの 重い作業をすべて完全に 自動で行います またApple Watchのように 限られたスペースで 長い訳語を持つビューを 機能させることも課題です ここでは「Tip Function」の ドイツ語訳が長すぎて 1行に収まらないので 例を紹介します 解決するためテキストの横にある アイコンを削除することはありません 解決策は必要に応じて2行以上の テキストを使用することで これはデフォルトの動作です 十分なスペースがない場合 それを変更したり インターフェイスの要素を 隠すことは推奨していません 通常レイアウトを 調整する方法があり 言語のニーズに対応する ことができます メールAppはこれを独創的な 方法で実現しています
こちらではアクションのための 4つのボタンが用意されています ボタンタイトルの 翻訳が長すぎる場合 テキストは切り取らず 改行もしません それでは アンバランスに見えてしまいます その代わり全体のレイアウトは 横長のスタックから 2列の縦長のスタックに 移行しています
今年SwiftUIにはダイナミック- レイアウトの作成を容易にする もう一つの素晴らしい ツールが追加されました ViewThatFitsです 要するにスペースに制約があり ビューが収まらない場合に 代替レイアウトを提供する ことができるのです
ビューをそれぞれ 独立して宣言し 'ViewThatFits' に 配置するだけです SwiftUIがカットしないと 収まらないことを 自動的に検出し次に 提供されるビューに遷移します レイアウトを入れ替える 程度にとどめておきましょう 翻訳が長すぎるという理由だけで ビューを非表示にするのは悪い習慣です UIの中でのユーザーが 居場所を見つけ辛くなります 柔軟なレイアウトでまず全ての インターフェイスの要素を収納する スペースを確保するように 心がけましょう
これはローカライズに 役立つだけではありません このレイアウトはユーザーがより 小サイズのものを好む場合に有効です または文字が大きくするなど いろいろな工夫ができます 今年のSwiftUIの新しい レイアウト機能については 「SwiftUIでカスタムレイアウト を構成する」トークをご覧ください 異なるアクセシビリティ設定や ローカライズされたテキストを持つことは レイアウトの課題でもあります インターフェイスの高さ 幅を拡張できます それに対応するためにレイアウトを 調整するのは大変なことですが SwiftUIを使えば 今年はかなり楽になります
今回のトークでは他の言語を サポートする際にコードで 文字列を構成することが困難なことを 汲み取っていただきたいです 海外のユーザーやテスターからの フィードバックに耳を傾け 誰にとっても素晴らしい作品に なるようにしましょう Swiftで値をフォーマット するのは簡単で 多くの場合1行の コードで済みます そしてそうすることで フォーマットされた値が 尊重されます
Swift パッケージを提供 する場合 新しい Xcode ローカリゼーション ワークフローを使用して クライアントに完全に ローカライズされた体験を提供します さてSwiftUIを使うか 使わないかにかかわらず レイアウトは翻訳されたテキストと アクセシビリティ設定に 対応できるように する必要があります レイアウトツールを使って インターフェイスの要素を隠すことなく 柔軟にレイアウトする ことができます ユーザーは 自分たちの生活にAppが フィットすることを 望んでいるので 最終的には 感謝されるでしょう さて今週は晴天続きで 楽しみです 残りのWWDCを お楽しみください ご視聴ありがとうございます
-
-
1:59 - Declare strings using String(localized)
let windPerceptionLabelText = String( localized: "Wind is making it feel cooler", comment: "Explains the wind is lowering the apparent temperature" )
-
2:46 - Translation example 1
let filter = String(localized: "Archive.label", defaultValue: "Archive", comment: "Name of the Archive folder in the sidebar") let filter = String(localized: "Archive.menuItem", defaultValue: "Archive", comment: "Menu item title for moving the email into the Archive folder")
-
3:40 - Translation example 2
String(localized: "Show weather in \(locationName)", comment: "Title for a user activity to show weather at a specific city") String(localized: "Show weather in My Location", comment: "Title for a user activity to show weather at the user's current location")
-
4:58 - Comment example
String(localized: "Show weather in \(locationName)", comment: "Title for a user activity to show weather at a specific city")
-
6:40 - Localized remote content example
let allServerLanguages = ["bg", "de", "en", "es", "kk", "uk"] let language = Bundle.preferredLocalizations(from: allServerLanguages).first
-
7:56 - Numbers in a string example 1
String(localized: "\(amountOfRain) in last \(numberOfHours) hour", comment: "Label showing how much rain has fallen in the last number of hours") String(localized: "\(amountOfRain) in last ^[\(numberOfHours) hour](inflect: true)", comment: "Label showing how much rain has fallen in the last number of hours")
-
8:40 - Numbers in a string example 2
if selectedCount == 1 { return String(localized: "Remove this city from your favorites") } else { return String(localized: "Remove these cities from your favorites") }
-
9:00 - Numbers in a string example 3
String(localized: "\(amountOfRain) in last ^[\(numberOfHours) hour](inflect: true).", comment: "Label showing how much rain has fallen in the last number of hours")
-
9:29 - Formatter example
let humidity = 54 // In a SwiftUI view Text(humidity, format: .percent) // In Swift code humidity.formatted(.percent)
-
10:03 - Formatter example 2
date.formatted( .dateTime.year() .month() ) // Jun 2022 whatToExpect.formatted() // New features, exciting API, and advanced tips amountOfRain.formatted( .measurement( width: .narrow, usage: .rainfall)) // 12mm (date...<later).formatted( .components( style: .wide ) ) // 24 minutes, 18 Seconds date.formatted( .relative( presentation: .numeric ) ) // 2 minutes ago let components = PersonNameComponents() … nameComponentsFormatter .string(from: components) // Andreas Neusüß or 田中陽子 excitementLevel.formatted( .number .precision( .fractionLength(2) ) ) // 1,001.42 price.formatted( .currency( code: "EUR" ) ) // $20.99 distance.formatted( .measurement( width: .wide, usage: .road) ) // 500 feet bytesCopied.formatted( .byteCount( style: .file )) // 42.23 MB
-
11:10 - Combine a formatter with text
func expectedPrecipitationIn24Hours(for valueInMillimeters: Measurement<UnitLength>) -> String { // Use user's preferred measures let preferredUnit = UnitLength(forLocale: .current, usage: .rainfall) let valueInPreferredSystem = valueInMillimeters.converted(to: preferredUnit) // Format the amount of rainfall let formattedValue = valueInPreferredSystem .formatted(.measurement(width: .narrow, usage: .asProvided)) let integerValue = Int(valueInPreferredSystem.value.rounded()) // Load and use formatting string return String(localized: "EXPECTED_RAINFALL", defaultValue: "\(integerValue) \(formattedValue) expected in next \(24)h.", comment: "Label - How much precipitation (2nd formatted value, in mm or Inches) is expected in the next 24 hours (3rd, always 24).") }
-
12:22 - Stringsdict examples in English and Spanish
Localizable.stringsdict English: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EXPECTED_RAINFALL</key> <dict> <key>NSStringLocalizedFormatKey</key> <string>%#@next_expected_precipitation_amount_24h@</string> <key>next_expected_precipitation_amount_24h</key> <dict> <key>NSStringFormatSpecTypeKey</key> <string>NSStringPluralRuleType</string> <key>NSStringFormatValueTypeKey</key> <string>d</string> <key>other</key> <string>%2$@ expected in next %3$dh.</string> </dict> </dict> </dict> </plist> Localizable.stringsdict Spanish: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EXPECTED_RAINFALL</key> <dict> <key>NSStringLocalizedFormatKey</key> <string>%#@next_expected_precipitation_amount_24h@</string> <key>next_expected_precipitation_amount_24h</key> <dict> <key>NSStringFormatSpecTypeKey</key> <string>NSStringPluralRuleType</string> <key>NSStringFormatValueTypeKey</key> <string>d</string> <key>one</key> <string>Se prevé %2$@ en las próximas %3$d h.</string> <key>other</key> <string>Se prevén %2$@ en las próximas %3$d h.</string> </dict> </dict> </dict> </plist>
-
13:40 - Swift Package localization example
let package = Package( name: "FoodTruckKit", defaultLocalization: "en", products: [ .library( name: "FoodTruckKit", targets: ["FoodTruckKit"]), ], … )
-
14:41 - Loading a string in a Swift Package
let title = String(localized: "Wind", bundle: .module, comment: "Title for section that shows data about wind.")
-
18:19 - Grid example
// Requires data types "Row" and "row" to be defined struct WeatherTestView: View { var rows: [Row] var body: some View { Grid(alignment: .leading) { ForEach(rows) { row in GridRow { Text(row.dayOfWeek) Image(systemName: row.weatherCondition) .symbolRenderingMode(.multicolor) Text(row.minimumTemperature) .gridColumnAlignment(.trailing) Capsule().fill(Color.orange).frame(height: 4) Text(row.maximumTemperature) } .foregroundColor(.white) } } } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。