はじめに
本記事は 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) です。