Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOSDC2019 多言語対応と戦う2019年版

iOSDC2019 多言語対応と戦う2019年版

多言語対応と戦う2019年版 (2019/09/07 14:20〜 Track B)

スライド: https://speakerdeck.com/matsuokah/iosdc2019-duo-yan-yu-dui-ying-tozhan-u2019nian-ban

サンプルコード: https://github.com/matsuokah/GetBetterLocalize
サンプルコードはXcode11でも動きます

#iosdc #b

Hideki Matsuoka

September 07, 2019
Tweet

More Decks by Hideki Matsuoka

Other Decks in Technology

Transcript

  1. ネームスペース “top.description.label.text” = “こんにちは、世界!”; top description text / title 画⾯

    / コンポーネント 役割 句読点あり→ text 句読点なし → title label UI
  2. • OK, NG, YES, NO, 了解, 完了などコンポーネント 化で利⽤されやすいものがおすすめ • 抜き出した単語を組み合わせて⽂章を作るのはNG

    • キーの接頭辞に”common”をつけて、組み合わせ NGというルールを作ったりすればいい 共通の単語を抜き出す
  3. ネームスペース “top.description.label.text” = “こんにちは、世界!”; top description text / title 画⾯

    / コンポーネント 役割 句読点あり→ text 句読点なし → title label UI ① キーのコンフリクト対策 ② キーから⽤途を明確に
  4. 書き出し結果 enum L10n { enum Auth { enum PasswordReset {

    static let title = L10n.tr(…) } } } path/to/Gens/Strings.swift “auth.password_reset.title” = “Ϧηοτ”; Localizable.strings
  5. 書き出し結果 enum L10n { enum Auth { enum PasswordReset {

    static let title = L10n.tr(…) } } } path/to/Gens/Strings.swift “auth.password_reset.title” = “Ϧηοτ”; Localizable.strings L n.Auth.PasswordRest.title で、「パスワードリセット」を解決できる
  6. デバッグ⽂⾔を.strings化 Localizable+Debug.strings swiftgen.yml “debug.login.title” = “σόοάϩάΠϯ”; strings: ɹ- inputs: Base.lproj/Localizable+Debug.strings

    outputs: - templateName: structured-swift4 output: path/to/Gens/Localizable+Debug.swift ファイルを分けてコンパイル対象外にしやすくする
  7. 書き出し結果 “debug.login.title” = “σόοάϩάΠϯ”; Localizable+Debug.strings enum L10n { enum Debug

    { enum Login { static let title = L10n.tr(…) } } } Localizable+Debug.swift
  8. 書き出し結果 “debug.login.title” = “σόοάϩάΠϯ”; Localizable+Debug.strings enum L10n { enum Debug

    { enum Login { static let title = L10n.tr(…) } } } Localizable+Debug.swift enumが競合する
  9. ベースのL nを定義 enum L10n { static func tr(…) -> String

    { let format = NSLocalizedString(…) return String(format: format, …) } } Strings.swift
  10. ベースのL nを定義 enum L10n { static func tr(…) -> String

    { let format = NSLocalizedString(…) return String(format: format, …) } } Strings.swift ⽂⾔を解決する関数
  11. プリセットをコピーする {% set enumName %}{{param.enumName|default:"L10n"}}{% endset %} {{accessModifier}} enum {{enumName}}

    { {% set enumName %}{{param.enumName|default:"L10n"}}{% endset %} {{accessModifier}} extension {{enumName}} { structured-swift .stencil strings.stencil structured-swift .stencilをコピーして、 extensionに変更
  12. strings: - inputs: Base.lproj/Localizable.strings outputs: - templatePath: strings.stencil output: path/to/Gens/Strings.swift

    strings: - inputs: Base.lproj/Localizable.strings outputs: - templateName: structured-swift4 output: path/to/Gens/Strings.swift swiftgen.yml(Before) stencilのパスを指定 swiftgen.yml(After)
  13. 書き出し結果 extension L10n { enum Debug { enum Login {

    … } } } extension L10n { enum Auth { enum PasswordReset { … } } } Strings+Localizable+Debug.swift Strings+Localizable.swift
  14. • 取得 UserDefault.standard.array(forKey: “AppleLanguages”) [String]で定義されている。[“en”, “ja-JP”]のような形。 定義されている⾔語は設定アプリで追加されている⾔語 配列の先頭の⾔語コードが起動時に適⽤される • 変更

    [“ja-JP”, “en”]に変更すれば、強制的に⽇本語に切り替え可能に。 [“zh-Hans”, “ja-JP”, “en”]のように、新たな⾔語を追加すれば、それも適⽤される • リセット UserDefaults.standard.removeObject(forKey: “AppleLanguages") アプリの⾔語を変更する
  15. コード @IBAction func applyEnglish(_ sender: Any) { applyLanguage(code: "en") }

    @IBAction func applyJapanese(_ sender: Any) { applyLanguage(code: "ja") } @IBAction func applyChinese(_ sender: Any) { applyLanguage(code: "zh-Hans") } @IBAction func applyDeviceDependency(_ sender: Any) { UserDefaults.standard.removeObject(forKey: "AppleLanguages") } func applyLanguage(code: String) { let language = Locale.preferredLanguages.filter { $0.contains(code) }.first guard let selectedLanguage = language else { UserDefaults.standard.set([code] + Locale.preferredLanguages, forKey: "AppleLanguages") return } let other = Locale.preferredLanguages.filter { $0 != selectedLanguage } UserDefaults.standard.set([selectedLanguage] + other, forKey: "AppleLanguages") }
  16. let text = L10n.Top.Apples.text(apples) // Alias to stringsdict "top.apples.text" =

    "You have %d apples"; SwiftGenで enumだけ作っておく Localizable.strings Swift
  17. // Alias to stringsdict "top.apples.text" = "You have %d apples";

    Localizable.strings Localizable.stringsdict
  18. // Alias to stringsdict "top.apples.text" = "You have %d apples";

    Localizable.strings Localizable.stringsdict キーが⼀致してれば stringsdictの⽅が採⽤さ れる
  19. "top.apples.text" = "͋ͳͨ͸ϦϯΰΛ%dݸ͍࣋ͬͯ·͢ɻ"; "top.apples.text.decoration" = "%dݸ"; "top.apples.text" = "You have

    %d apples"; "top.apples.text.decoration" = "%d apples"; English Japanese text.range(of:decoration) で装飾範囲を解決する
  20. • 多⾔語対応のススメ( , ikkan_chin) • Strings Dict Format(Apple) • i

    n and L n videos(Apple) • Internationalization(Apple) • SwiftGen(GitHub) • サンプルプロジェクト(GitHub, matsuokah) • Crowdin(ローカライズSaaS, Crowdin) 参考⽂献, リンク