🍁
Swift: 指定した言語のStringを取得する
まず、SwiftUIのPreviewで多言語対応の動作確認をするのは簡単です。
#Preview {
ForEach(["en_US", "ja_JP"], id: \.self) { id in
SomeView().environment(\.locale, Locale(identifier: id))
}
}
のように書けば言語ごとのプレビューを確認できます。
ただし、Previewではなくアプリ実行中にプログラムによって動的に言語を指定して文言を取得したい場合には、場面によって仕様をよく理解して取得方法を変える必要があります。
文言をアプリTarget内(Bundle.main)に設置してある場合
SwiftUIのViewで直接指定する場合
Text("文言のキー")
.environment(\.locale, Locale(identifier: "ja_JP"))
のように.environment()
でLocaleを指定するだけで意図した言語の文言が表示されます。
Viewでないロジック層で指定する場合
String
にlocale
が指定できそうなAPIがあるのでそれを使ってみると
String(localized: "文言のキー", locale: Locale(identifier: "ja_JP"))
プライマリー言語の文言しか取得できません。この件についてはDeveloper Forumsで議論されています。
このAPIはlocalized
に指定されたフォーマット込みの文字列に埋め込まれる変数にDate
などローカライズ要素のあるものが含まれていた際に指定したLocaleが活用される仕様らしいです。
では、強制的に指定した言語の文言を直接取得するにはどうすればいいでしょうか。
Stack Overflowに答えがありました。
Bundleは言語によって異なるパスを示すため、指定言語のBundleを取得してその中にある文言を拾ってくるようにすればいいようです。
import Foundation
extension String {
init(localized: LocalizationValue, lang: String) {
let path = Bundle.main.path(forResource: lang, ofType: "lproj")
self.init(localized: localized, bundle: Bundle(path: path!))
}
}
String(localized: "文言のキー", lang: "ja")
のようにすれば、直接意図した言語の文言を取得できます。
文言をローカルPackage内(Bundle.module)に設置してある場合
まず、異なるモジュールのリソースを扱う場合、現状かなりクセがつよいので仕様を理解する必要があります。
SwiftUIのViewで直接指定する場合
結論から言うと、モジュール側にその文言を利用するためのインタフェースを実装し、利用側でenvironment(\.locale)
指定するのが一番安定します。
モジュール内
public enum SomeModule {
public static let mongonText = Text("文言のキー", bundle: .module)
}
アプリ側
import SomeModule
SomeModule.mongonText
.environment(\.locale, Locale(identifier: "ja_JP"))
Viewでないロジック層で指定する場合
基本的にはアプリTarget内に設置してある場合と同じです。Bundleを指定してStringを拾うextensionをモジュール側に置けばよいです。
モジュール内
import Foundation
extension String {
init(localized: LocalizationValue, lang: String) {
+ let path = Bundle.module.path(forResource: lang, ofType: "lproj")
self.init(localized: localized, bundle: Bundle(path: path!))
}
}
public enum SomeModule {
public static let mongon = String(localized: "文言のキー", lang: "ja")
}
アプリ側
import SomeModule
let mongon = SomeModule.mongon
Discussion