WWDC Quick Look 💓 By SwiftGGTeam
Build global apps: Localization by example

Build global apps: Localization by example

元の動画を見る

ハイライト

Apple のローカリゼーション チームの Andreas は、天気アプリケーションを中心的な事例として取り上げ、文字列の宣言、書式設定からレイアウトの適応まで、高品質の多言語アプリケーションを構築する方法を体系的に説明しました。


主要内容

天気アプリは非常に普通に見えます。風速、降水量、10 日間の予報シートを説明する行が表示されます。

多言語環境に置くと、これらは 3 つのエンジニアリング上の問題になります。

文脈によっては、同じ英語の単語がスペイン語では 2 つの単語になる場合があります。文中に都市名を挿入すると、ドイツ語の前置詞が変わる場合があります。高さ 44 ポイントのラベルは、ヒンディー語のテキストに適合しない可能性があります。

このセッションでは、天気予報アプリを使用して完全なリンクをつなぎ合わせます。最初に文字列を翻訳可能なリソースに書き込み、次にシステム API を使用してリモート コンテンツ言語を選択し、次に書式設定 API を使用して数字、単位、および複数形を処理し、最後に SwiftUI レイアウトで長く、背が高く、さまざまな方向のテキストを処理します。

詳細

文字列にはコードからコンテキストを与える必要があります

(01:59) ローカリゼーションの最初のステップは、String(localized:)ユーザーに表示されるテキストを宣言します。 Xcode は、ローカライズされたコンテンツをエクスポートするときにこれらの文字列を検出し、処理のためにトランスレーターに渡します。

let windPerceptionLabelText = String(
    localized: "Wind is making it feel cooler", 
    comment: "Explains the wind is lowering the apparent temperature"
)

キーポイント:

  • String(localized:)このテキストをマークするには、ローカライズ プロセスを開始する必要があります。 -localizedの英語は開発言語で表示されるテキストです。 -commentこの文は風によって体がどのように涼しく感じられるかを説明していると翻訳者に伝えてください。
  • コメントは翻訳コンテキストに属し、ユーザーには表示されません。

(02:46) 問題は同じ英単語で表示されます。メールの「アーカイブ」は、サイドバーのフォルダー名またはメニュー アクションのいずれかになります。英語では同じですが、スペイン語では別の翻訳が必要です。

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")

キーポイント:

  • Archive.labelそしてArchive.menuItemは 2 つの異なるローカリゼーション キーです。 -defaultValue英語のランタイムには同じ「アーカイブ」が表示されるようにします。
  • 初めcommentサイドバーのフォルダーの名前であることを指定します。
  • 2番目commentこれがメッセージをアーカイブ フォルダーに移動するメニュー項目であることを示します。
  • 翻訳者は、他の言語で名詞と動作を別々に扱うことができます。

(03:40) 文字列補間も注意して使用する必要があります。Show weather in CupertinoそしてShow weather in My Locationこれは英語では当てはまりますが、ドイツ語では異なる文法が必要になる場合があります。

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")

キーポイント:

  • 最初の段落は、特定の都市名を挿入するためにのみ使用されます。 -locationNameの実行時の意味はコメントに明確に記載されています。
  • 「現在地」は変数として使用されるのではなく、別の文字列に分割され、同じ文に詰め込まれます。
  • これにより、翻訳者は現在のターゲティング シナリオに対して別の構文を選択できるようになります。

リモート コンテンツもユーザーの言語と一致する必要があります

(06:40) 気象警報はサーバーから送信されます。サーバーは複数の言語をサポートする場合がありますが、デバイスが認識しているのはユーザーの言語設定のみです。 Apple は、サーバーがサポートされている言語 ID を返し、クライアントがその言語 ID を呼び出すことができるようにすることを推奨しています。Bundle.preferredLocalizations(from:)マッチを作ります。

let allServerLanguages = ["bg", "de", "en", "es", "kk", "uk"]
let language = Bundle.preferredLocalizations(from: allServerLanguages).first

キーポイント:

  • allServerLanguagesサーバーがコンテンツを返すことができる言語のリストを表します。
  • 言語 ID はシステム フレームワークによって処理されるため、ユーザーの設定を自分で比較する必要はありません。 -Bundle.preferredLocalizations(from:)一致度によってソートされた候補言語を返します。 -.first通常は、現在のユーザー設定に最も適した言語です。
  • 後続のリクエストでは、この言語を使用してユーザーに表示されるコンテンツをロードする必要があります。

この詳細は見落としがちです。アプリ シェルはローカライズされており、サーバー側のアラートは別の言語で表示され、ユーザーは重要な瞬間に情報を読むことができません。

数値、単位、および複数形の書式設定をシステムに任せる

(07:56) 降雨量などのコピーライティングには数字が含まれることがよくあります。英語では「1 時間」と「2 時間」はもはや同じではなく、ウクライナ語などの言語ではより複雑な複数規則があります。セッションでは 2 つの方向性が示されます。stringsdict複数ルール、または自動文法一致。

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")

キーポイント:

  • 最初の段落numberOfHours英語の文章を直接挿入します。
  • 2 番目の段落について^[...](inflect: true)量によって変形する必要があるセグメントにマークを付けます。 -amountOfRainそしてnumberOfHoursどちらも文字列補間を通じてローカライズされた文字列を入力します。
  • 注: これは、過去数時間の降雨量を示すラベルです。

(09:29) 値に単位、パーセンテージ、日付、または時間が含まれる場合は、書式設定 API を優先して使用します。シンボルの配置、間隔、およびユーザーの好みの番号体系を処理します。

let humidity = 54

// In a SwiftUI view
Text(humidity, format: .percent)

// In Swift code
humidity.formatted(.percent)

キーポイント:

  • humidity元の値を保存します。
  • SwiftUIで使用されますText(_:format:)パーセント形式を直接指定します。
  • 通常の Swift コードで使用されます.formatted(.percent)フォーマットされた結果を取得します。
  • パーセント記号の位置と数値システムは、ユーザー設定に基づいてシステムによって処理されます。

(11:10) より複雑な例は、今後 24 時間の降雨量です。このコードは、まずサーバーから返されたミリメートル値をユーザーの優先単位に変換し、次にフォーマットされた値をローカライズ可能な文に入れます。

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).")
}

キーポイント:

  • 関数パラメータMeasurement<UnitLength>サーバーから渡された降雨量を示します。 -UnitLength(forLocale: .current, usage: .rainfall)降雨量を表示するために現在のユーザーが希望する単位を選択します。 -converted(to:)ミリメートル値をユーザー単位に変換します。 -.formatted(.measurement(width: .narrow, usage: .asProvided))幅の狭い単位テキストを生成します。 -integerValue複数のルールをトリガーするために使用されます。 -EXPECTED_RAINFALL対応するstringsdictキーを入力します。 -defaultValue複雑な判定値や書式設定された降雨量、24時間固定も挿入します。 -comment翻訳者が語順を処理しやすいように、各補間パラメータの意味を明確に説明します。

12:22stringsdictそして彼は言語の複数形の分野を担当します。英語のみother、スペイン語でoneそしてotherさまざまな文を提供します。

<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>

キーポイント:

  • EXPECTED_RAINFALLSwift コードのキーに対応します。 -NSStringLocalizedFormatKey複数のルールエントリを指します。 -NSStringPluralRuleType言語の複数規則に従った分岐の選択を表します。 -NSStringFormatValueTypeKey使用d、Swift で渡される整数値に対応します。 -oneスペイン語の単数形の分派です。 -other他の量的分岐です。 -%2$@書式設定された降雨量テキストを使用します。 -%3$d固定の時間を使用します。

Swift パッケージも Xcode ローカリゼーション プロセスに入ります

(13:40) ユーザーに表示されるテキストが Swift パッケージ内にある場合、デフォルトのローカリゼーション言語をパッケージ マニフェストで宣言する必要があります。 Xcode 2022 はこのパラメーターを読み取り、[製品] メニューのパッケージにローカリゼーションのエクスポート/ローカリゼーションのインポート ワークフローを提供します。

let package = Package(
    name: "FoodTruckKit",

    defaultLocalization: "en",

    products: [
       .library(
            name: "FoodTruckKit",
            targets: ["FoodTruckKit"]),
    ],

)

キーポイント:

  • PackageSwift パッケージの構造について説明します。 -defaultLocalization: "en"パッケージ内のユーザーに表示されるコンテンツの開発言語が英語であることを宣言します。
  • Xcode がこの設定を認識すると、ローカライズされたエクスポートおよびインポート プロセスにパッケージが含まれます。
  • ローカリゼーション ファイルは渡されます.xclocそれを翻訳者に渡し、パッケージ内の正しいパスにリダイレクトして戻します。

(14:41) パッケージに文字列をロードするときは、以下も指定する必要がありますbundle: .module

let title = String(localized: "Wind",
                      bundle: .module, 
                     comment: "Title for section that
                               shows data about wind.")

キーポイント:

  • localized: "Wind"ユーザーに表示されるパッケージのタイトルです。 -bundle: .module現在の Swift パッケージのリソース バンドルからローカライズされたコンテンツを探すようにシステムに指示します。 -comment説明 このタイトルは、風に関するデータを表示するエリアに使用されます。

レイアウトでは、テキストの長さ、高さ、方向を変更できる必要があります。

(16:37) 翻訳するとテキストが長くなる可能性があります。あるいは、より高度な書記体系が原因である可能性があります。セッションは、英語が 44 ポイント高いからといって、すべての言語に固定の高さを与えないでくださいとはっきりと思い出させます。

(18:19) SwiftUIGrid天気予報などの列配置のインターフェイスに適しています。最長の曜日ラベルによって列の幅が決まり、天気アイコンは垂直方向の配置を維持します。

// 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)
            }
        }
    }
}

キーポイント:

  • Grid(alignment: .leading)先頭の位置合わせを使用します。左から右に記述する言語は左側に揃えられ、右から左に記述する言語は右側に揃えられます。 -ForEach(rows)毎日 1 行を生成します。 -GridRow水平方向のコンテンツのセットを定義します。 -Text(row.dayOfWeek)曜日ラベルを表示します。列幅は最長テキストの影響を受けます。 -Image(systemName:)天気記号を表示します。 -.gridColumnAlignment(.trailing)最低温度の列を尾部に合わせます。 -Capsule()これは最も柔軟な要素であり、テキストが長くなると縮小する可能性があります。 -foregroundColor(.white)インラインの前景色を均一に設定します。

(19:53) 十分なスペースがない場合、SwiftUI はまた、ViewThatFits。逐語的な草稿でのアプローチは、複数のレイアウトを用意してそれらを配置することです。ViewThatFits、トリミングされない最初のバージョンを選択するように SwiftUI に指示します。 Apple はまた、レイアウトを切り替えるだけであり、翻訳が長すぎるためにインターフェイス要素を非表示にしないことも強調しています。


重要ポイント

1. 既存のプロジェクトの文字列コンテキスト監査を実施します。

  • 何をすべきか: 異なるインターフェイスの場所で同じ英語のテキストが再利用されている場所を見つけます。
  • 実行する価値がある理由: セッションの「アーカイブ」の例は、同じ英語の単語でも他の言語では異なる翻訳が必要になる可能性があることを示しています。
  • 開始方法: 再利用された文字列を異なるキーに分割し、次を使用します。String(localized:defaultValue:comment:)、存在するcommentコントロールの種類とそれが配置されているインターフェイスを明確に書き留めます。

2. サーバー側のコピーライティングに言語ネゴシエーションを追加する

  • 内容: ユーザーの言語設定に基づいて、クライアントがサーバー側のコンテンツ言語を選択できるようにします。
  • 実行する価値がある理由: 気象警報などのリモート コンテンツがローカライズされていない場合、ユーザーは重要なプロンプトを読むことができない可能性があります。
  • 開始方法: サーバーがサポートされている言語 ID 配列を返し、クライアントが呼び出します。Bundle.preferredLocalizations(from:)、後続のリクエストには最初の候補言語を使用します。

3. デジタル コピーライティングを文字列の連結からフォーマット API に変更する

  • 内容: パーセンテージ、日付、単位、ファイル サイズ、距離、降雨量の表示ロジックを確認します。
  • 価値がある理由: 書式設定 API は、単位、記号の配置、およびユーザーの好みの数値体系を処理します。
  • 開始方法: SwiftUI で使用しますText(value, format:)、通常の Swift コードで使用されますvalue.formatted(...)、複数形の文が追加されますstringsdict

4. Swift パッケージにローカライズされたリソースを公開させます

  • 内容: ユーザーに表示されるテキストを含む Swift パッケージのローカリゼーション設定を完了します。
  • 実行する価値がある理由: Xcode はパッケージを直接エクスポートおよびインポートできます.xcloc、ライブラリの作成者は、通常のリリース プロセスにローカリゼーションを組み込むことができます。
  • 開始方法:Package.swiftの設定defaultLocalization、パッケージ内の文字列をロードするときに指定されますbundle: .module

5. 実際の言語でレイアウトの柔軟性をテストする

  • 何をすべきか: アラビア語、スペイン語、ギリシャ語、ヒンディー語、その他の言語でコア インターフェイスを実行します。
  • 価値がある理由: この草案は、方向の変更、長いテキスト、より高いテキストがレイアウトにどのような影響を与えるかを示しています。
  • 開始方法: 固定高度の仮定を削除します。 10日間の予報などのテーブルインターフェースを試してみるGrid;スペースが限られた操作エリア用に複数のレイアウトを準備し、それらを担当者に引き渡します。ViewThatFits選ぶ。

関連セッション

  • 右から左へ — 右から左へ記述する言語でのレイアウトの方向、シンボル、インターフェイスの適応について引き続き説明します。
  • アラビア語向けデザイン - アラビア語インターフェイスのタイポグラフィ、テキスト、および文化的詳細をデザイン レベルから補足します。
  • SwiftUI でカスタム レイアウトを作成する — SwiftUI グリッド、カスタム レイアウト、およびさまざまなコンテンツ サイズに適応するレイアウト機能について詳しく説明します。

コメント

GitHub Issues · utterances