🙌

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には英語・日本語の設定を入れていて、端末の言語設定に応じて変わってくれる想定でした。
しかし実際はプロジェクトのデフォルト言語で表示されるだけで、切り替えが機能しませんでした。

https://github.com/0si43/GitHubUsers/issues/14

実際のissueです。

対処法

この問題、String Catalogの設定ではなく、SPMモジュールに対して、プロジェクトの設定が渡せていないことが原因でした。
SPMモジュールの中にブレイクポイントを仕込んで、preferredLocalizationsを見てみます。

(lldb) po Bundle.current.preferredLocalizations
▿ 1 element
  - 0 : "en"

プロジェクトの言語設定は英語(デフォルト)と日本語にしていたので、デフォルト言語しか渡っていないことがわかりました。

https://zenn.dev/link/comments/f32f3d7a35118c

こちらのスクラップを参考に、SPMモジュールだけでなく、メインのディレクトリに対してもString Catalogを設定して、ダミーの変換文字を設定したところ、ちゃんと渡るようになりました。
どうやらメインにString Catalogがない場合、プロジェクトのデフォルト言語しか渡さないようです。

ベターな対処法

一応これで解決ですが、ダミーxcstringを置かないといけないのが嫌だなあと思っていたところ、aphanantheさんからTwitterでアドバイスをいただきました。

https://x.com/aphananthe42/status/1941765419016257859

info.plistにCFBundleAllowMixedLocalizations(Localized resources can be mixed)という設定があり、これをYESにすると、ちゃんとプロジェクトの言語設定が渡りました。

またinfo.plist自体をローカライズしたいときに使うInfoPlist.xcstringsを設置しても、同じく解決できます。
今回は検証プロジェクトだったので、CFBundleAllowMixedLocalizationsで対応しましたが、ストア公開までするちゃんとしたアプリであれば、こっちがいいと思います。

(了)

Discussion