環境
- Xcode 10.1
- Swift 4.2.1
目的
分割されたEmbedded Framework毎にLocalizable.stringsを持ち、横断的に文字列を取得する。
課題
- どうやってEmbedded Framework毎にLocalizable.stringsを持つのか?
- Embedded Framework間で連動するNSLocalizedStringの使い方とは?
どうやってEmbedded Framework毎にLocalizable.stringsを持つのか?
単純に「File」メミューから「File...」を選んで、さらに「Strings File」を選んでプロジェクト(ターゲット)に追加してください。名前はスタンダードな「Localizable.strings」で構いません。
これはEmbedded Frameworkでは名前空間が異なるためです。
問題は、この新たな「Localizable.strings」をどうやって呼び出すかです。
下記の例ではCommonUtilクラス(クラス名は何でも良い)を、先ほどLocalizable.stringsを作成したEmbedded Framework内に作成します。
public class CommonUtil
{
public static let shared = CommonUtil()
private init(){
bundle = Bundle(for: type(of: self))
}
public let bundle: Bundle
}
上記のコードで、Embedded FrameworkのBundleを取得できるようになります。
そして、Bundleがとファイル名(Localizable.strings)が分かればNSLocalizedString()を使うことができます。
extension String
{
public var localized: String
{
let bundle = CommonUtil.shared.bundle
let result = NSLocalizedString(self, tableName: "Localizable", bundle: bundle, value: "", comment: self)
return result
}
}
上記のコードは、Stringクラスのextension内でlocalizedプロパティを定義しています。
このlocalizedプロパティは先ほどの CommonUtil.shared.bundle
を使ってEmbedded FrameworkのBundleを取得し、Localizable.stringsを指定しています。
Embedded Framework間で連動するNSLocalizedStringの使い方とは?
ところで、NSLocalizedString()は非常に使いにくい関数です。それは、Localizable.stringsにキーがない場合は、キーを返り値として戻してくることです。
例えば、
/*
Localizable.strings
*/
"確定" = "確定";
"キャンセル" = "キャンセル";
というようなLocalizable.stringsがあったとして、
let val = NSLocalizedString("もどる")
とすると、"もどる"が返ってきてしまいます。
つまり、Localizable.stringsにそのキーが無いことが判定できません。
この場合、複数のLocalizable.stringsから単語を検索できなくなり、大変不便です。
そこで、Localizable.stringsにあるルールを付加することでこれを解決します。
/*
Localizable.strings
*/
"_確定" = "確定";
"_キャンセル" = "キャンセル";
上記のアンスコは例ですが、取得する単語とキーは一致させない、というルールです。
これによって、
extension String
{
public var localized: String
{
let result = NSLocalizedString(self, value: "", comment: "")
if result == self
{
// 無かった
}
return result
}
}
というように書くことができます。
結論
まとめると、下記のように書くことで、Mainバンドルに無かったキーを、Embedded FrameworkのLocalizable.stringsから検索して取得することができるようになります。
import Foundation
extension String
{
public var localized: String
{
let result = NSLocalizedString(self, value: "", comment: "")
if result == self
{
return embedded_localized
}
return result
}
public var embedded_localized: String
{
let bundle = CommonUtil.shared.bundle
let result = NSLocalizedString(self, tableName: "Localizable", bundle: bundle, value: "", comment: self)
return result
}
}
基本的な単語で、どのプロジェクトでも変わらないような物は、こちらに集めることで、少し便利かもしれません。また、Embedded Framework内でLocalizable.stringsを使ってUIViewを表示したりする場合も有効かもしれません。