SPMでモジュール分割したらString Catalogが効かなかった問題に対処した
前回の記事もSPMでのモジュール分割ネタでしたが、今回も関連情報です。
対象読者は前回と同じ。
問題の説明と、対処法について書きます。
なお対処法を最初見つけた後にアドバイスいただいて、もっといい方法があったので、それも書きます。
問題
タイトルの通りではあるのですが、SPMでモジュール分割したらString Catalogが効きませんでした。
メインは最小限にして、実際のロジックはパッケージ化されたモジュール内で書いており、String Catalogもパッケージ内に持っておりました。
SPMのパッケージはBundleがmainではなく、Bundle.moduleという別バンドルなのですが、そこはケアできていました。
こんな実装を入れてました。
import Foundation
extension Bundle {
static var current: Bundle {
#if SWIFT_PACKAGE
return Bundle.module
#else
return Bundle.main
#endif
}
}
extension String {
public var localized: String {
String(localized: String.LocalizationValue(self), bundle: Bundle.current)
}
}
想定ではここさえケアできていれば、"Followers".localized と書けばローカライズされるはずでした。
String Catalogには英語・日本語の設定を入れていて、端末の言語設定に応じて変わってくれる想定でした。
しかし実際はプロジェクトのデフォルト言語で表示されるだけで、切り替えが機能しませんでした。
実際のissueです。
対処法
この問題、String Catalogの設定ではなく、SPMモジュールに対して、プロジェクトの設定が渡せていないことが原因でした。
SPMモジュールの中にブレイクポイントを仕込んで、preferredLocalizationsを見てみます。
(lldb) po Bundle.current.preferredLocalizations
▿ 1 element
- 0 : "en"
プロジェクトの言語設定は英語(デフォルト)と日本語にしていたので、デフォルト言語しか渡っていないことがわかりました。
こちらのスクラップを参考に、SPMモジュールだけでなく、メインのディレクトリに対してもString Catalogを設定して、ダミーの変換文字を設定したところ、ちゃんと渡るようになりました。
どうやらメインにString Catalogがない場合、プロジェクトのデフォルト言語しか渡さないようです。
ベターな対処法
一応これで解決ですが、ダミーxcstringを置かないといけないのが嫌だなあと思っていたところ、aphanantheさんからTwitterでアドバイスをいただきました。
info.plistにCFBundleAllowMixedLocalizations(Localized resources can be mixed)という設定があり、これをYESにすると、ちゃんとプロジェクトの言語設定が渡りました。
またinfo.plist自体をローカライズしたいときに使うInfoPlist.xcstringsを設置しても、同じく解決できます。
今回は検証プロジェクトだったので、CFBundleAllowMixedLocalizationsで対応しましたが、ストア公開までするちゃんとしたアプリであれば、こっちがいいと思います。
(了)
Discussion