【SwiftUI】引数から渡されたStringではTextはローカライズしてくれない

2022.10.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

SwiftUIで多言語対応の際に、引数で渡されたStringからではTextはローカライズしてくれないという現象になった為、もう少しTextに寄り添ってみることにしました。

環境

  • Xcode 14

はじめに

今回は多言語対応のためにLocalizable.stringsを作成したりする方法は説明していません。すでに日本語対応用のLocalizable.stringsがある前提で進めていきます。

Text

SwiftUIのTextはUIKitのUILabelに相当するコンポーネントで、表示したい文字列をTextに渡すだけでいい感じに表示してくれます。

import SwiftUI

struct ContentView: View {
    var body: some View { 
        Text("Hello, world!")
    }
}

Textのここが素晴らしい

Textは、渡された値がLocalizable.strings内にあるキーと一致する場合は、そのキーに紐づく値を表示して、一致しない場合は渡された値をそのまま表示するという挙動をしてくれます。

自ら先回りして動いてくれて、本当に素晴らしい。いつもありがとうという気持ちをここに表明します。

素晴らしさを実感

Localizable.strings

まず、日本語用のLocalizable.stringsを用意しました。

/* 
  Localizable.strings
  Localization(Japanese)
*/

"Hello, world!" = "こんにちは、世界!";

ContentView

実際にTextLocalizable.stringsのキーと一致するものがあるTextとキーが存在しないTextを配置してみます。

import SwiftUI

struct ContentView: View {
    var body: some View {

        VStack(spacing: 16) {
            Text("Hello, world!")

            Text("Goodbye, world!")
        }
    }
}

Preview

今回は日本語ローカルでローカライズが反映されるか確認したいので、Locale(identifier: "ja")に設定しています。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.locale, Locale(identifier: "ja"))
    }
}

出力結果

Localizable.stringsにキーが存在するものはその値が表示され、そうではない場合にはそのままの文字列が表示されました!

引数で渡されたStringからはローカライズしてくれない

String型としてTextに設定する値を受け取るカスタムViewを作成して検証してみます。

CustomText

struct CustomText: View {

    let text: String

    var body: some View {
        Text(text)
    }
}

ContentView

import SwiftUI

struct ContentView: View {

    var body: some View {

       CustomText(text: "Hello, world!")
    }
}

出力結果

Localizable.stringsに該当するキーがあるはずなのに、Hello, world!という文字列がそのまま表示されています。

解決策

Apple 公式ドキュメント Textに下記の記載がありました。

変数値でText viewを初期化する場合、Viewは文字列をローカライズしないinit()になります。ただし、最初にLocalizedStringKeyインスタンスを作成することでローカライズをリクエストできます。これにより、代わりにinit(_:tableName:bundle:comment:)がトリガーされます。

// 文字列変数をローカライズしない...
Text(writingImplement)

// ローカライズされた文字列キーに明示的に変換すると、ローカライズされます
Text(LocalizedStringKey(writingImplement))

ということで、変数(定数) :Stringを渡す際には、LocalizedStringKeyに変換する必要があるようです。

TextにLocalizedStringKeyを渡す

作成したCustomTextTextに渡す値をLocalizedStringKeyに変更しました。

struct CustomText: View {

    let text: String

    var body: some View {
        Text(LocalizedStringKey(text))
    }
}

出力結果

実際にビルドをしてみると、無事にローカライズされたものが表示されました。

おわりに

普段は何も言わなくても自分で気づいて良い感じに振る舞ってくれるテキストくん。そんなテキストくんに甘えていたようです。当たり前だった日常が当たり前ではなくなった時に初めてTextくんへの感謝の気持ちが溢れました。

いつもありがとうテキストくん。

参考