はじめに
本記事は Swift Advent Calendar 2022 の1日目の記事です。
遅くなりましたが、誰も埋めていなかったので埋めます。
ローカライズの文字列を取得する方法を紹介します。
環境
- OS:macOS Ventura 13.0.1
- Xcode:14.1 (14B47b)
- Swift:5.7.1
今まで: NSLocalizedStringを使う
ローカライズの文字列を取得するとき、今までは NSLocalizedString(_:tableName:bundle:value:comment:)
を使っていました。
func NSLocalizedString(
_ key: String,
tableName: String? = nil,
bundle: Bundle = Bundle.main,
value: String = "",
comment: String
) -> String
引用: https://developer.apple.com/documentation/foundation/1418095-nslocalizedstring
Swift Packages上にあるSwiftUIのViewから呼び出す場合、以下のように使うことが多いと思います。
import SwiftUI
struct FooView: View {
var body: some View {
Text("Foo")
.navigationTitle(NSLocalizedString("Foo", bundle: .module, comment: ""))
}
}
これから: String(localized:)を使う
たまたま apple/sample-food-truckのソースコード を見ていて、 String(localized:table:bundle:locale:comment:)
なる String
のイニシャライザがあることに気づきました。
init(
localized keyAndValue: String.LocalizationValue,
table: String? = nil,
bundle: Bundle? = nil,
locale: Locale = .current,
comment: StaticString? = nil
)
引用: https://developer.apple.com/documentation/swift/string/init(localized:table:bundle:locale:comment:)
iOS 15.0+で使えること以外、公式ドキュメントには説明がありません。「No overview available.」すら書いてありません。
先ほどの NSLocalizedString
を使った例を String(localized:)
で置き換えてみます。
import SwiftUI
struct FooView: View {
var body: some View {
Text("Foo")
- .navigationTitle(NSLocalizedString("Foo", bundle: .module, comment: ""))
+ .navigationTitle(String(localized: "Foo", bundle: .module)
}
}
いろいろ試したところ、iOS 15.0+からはこちらのAPIを使ったほうがいいと判断したので、この記事で紹介することにしました。
String(localized:)のメリット
String(localized:table:bundle:locale:comment:)
のメリットを紹介します。
Stringを返すことがわかりやすい
定義を見るとわかりますが、 NSLocalizedString()
の実態は String
を返す関数です。
String
のイニシャライザを使うことで、 String
であることがわかりやすくなります。
commentを省略できる
NSLocalizedString
では comment
が String
型なのに対し、 String(localized:)
では StaticString?
型と、オプショナル型になっています。
しかもデフォルトで nil
が指定されているので、呼び出しを省略できます。
今まで comment: ""
と書くことが多かったので、省略できるとスッキリして嬉しいです。
String Interpolationに対応している
「String Interpolation(文字列補間)」とは、文字列リテラル内に埋め込まれたプレースホルダーを、実行時に実際の値へ置き換える処理のことです。
iOSのローカライズでは、以下のようにフォーマット指定子を使って実現できます。
"Set %lld" = "%lldセット目";
NSLocalizedString
はString Interpolationに対応していないのに対し、 String(localized:)
は対応しています。
import SwiftUI
struct FooView: View {
var body: some View {
VStack {
Text(NSLocalizedString("Set \(Int(3) + 1)", bundle: .module, comment: "")) // "Set 4"
Text(String(localized: "Set \(Int(3) + 1)", bundle: .module)) // "4セット目"
}
}
}
これは String(localized:)
に渡すキーの型が String
でなく String.LocalizationValue
になっているためです。
逆に言うと String
を渡せないので、ローカライズしたい文字列がすでに String
の場合は、何かしら工夫しないと使えません。
おまけ: Textはもっとスッキリ書ける
Text
は LocalizedStringKey
と Bundle
の両方を渡せるイニシャライザが用意されているので、上記の記述はもっとスッキリ書けます。
詳細は以下の記事をご参照ください。
おわりに
String(localized:)
は NSLocalizedString
の上位互換と言っても過言ではないので、ぜひ使っていきましょう
逆にデメリットがあればコメントなどで教えていただきたいです。
以上 Swift Advent Calendar 2022 の1日目の記事でした。
明日も私で LocalizedStringKeyの簡単な説明(Swift) です。