SPMでマルチマルチモジュール化したプロジェクトにおいて、Localizable.stringsを使って文言管理したいときがあるので、メモとして残しておくためにもこちらの記事にまとめました。
公式Docにも詳しい方法が書かれておりますので、公式を見ていただくのも良い(英語に抵抗がなければその方がいい)と思います。
達成したいこと
- packageに切り出したResourceモジュールの中に
Localizable.stringsを定義したい - 多言語対応もしたい
- SwiftGenを使ってファイルをジェネレートしたい(コマンドを叩くのは手動)
Package.swiftの設定
こちらでやることは1つだけです。
defaultLocalizationの設定が必要で、 defaultLocalization: "ja",を設定してください。
jaの部分はenとかでも大丈夫です。
let package = Package(
name: "AppCommon",
defaultLocalization: "ja",
platforms: [
.iOS(.v15)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
]
)
各言語のディレクトリを作りLocalizable.swiftを配置する
公式Docを日本語翻訳すると、
.lprojで終わるディレクトリにパッケージリソースを配置し、ISO639言語コードを使用することで、Xcodeは自動的に言語を推測できます。
と書かれている通り、ISO639言語コード.lproj形式のディレクトリをPackage内に作成します。

さらにその中に、Localizable.stringsを追加するだけでOKです。
画像は日本語と英語の多言語化対応をする場合のサンプルになります。
Localizable.stringsの中身ですが、
"home.title" = "Home";
のように記述し、各言語のKeyは同一になる必要があります。
プロジェクト内のViewなどから参照する
実際にResourceモジュールと異なるモジュールから参照されることが多いと思いますが、以下のように書くことでResourcePackageにある、各言語のLocalizable.stringsを参照することが可能です。
NSLocalizedString("home.title", bundle: Bundle.module, comment: "ホーム")
SwiftGenを使ってStringファイルを自動生成する
上記のNSLocalizedStringを利用する書き方をViewに直接書いてしまうのは冗長になりますし、タイポなどによるミスの可能性も増えることからSwiftGenを利用します。
SwiftGenについてこの記事では詳しく紹介しませんが、日本語でまとまっている記事が多数出てくるので、ググっていただければいい記事が見つかると思います。
SPMでパッケージ化されたモジュールからファイルをジェネレートしたい場合は、以下のように書いてあげればOKです。
strings:
inputs:
- Resources/Sources/Resources/Strings/ja.lproj
filter: .*\.strings$
outputs:
- templateName: structured-swift5
params:
publicAccess: true
output: Resources/Sources/Resources/Strings/Strings+Generated.swift
ポイントは下記です。
- 多言語化されていたとしても
inputsに入れるディレクトリは、1つの言語のディレクトリを含めれば大丈夫そう -
parmsでpublicAccess: trueを設定すること ← これをやらないと別モジュールから自動ジェネレートされるenumを参照できないため
あとは、文言を追加したときにプロジェクトルートで
Pods/SwiftGen/bin/swiftgen
を叩いてあげるだけで、Strings+Generated.swiftが勝手に生成されます。
使う時はこんな感じです。
L10n.Home.title
おわりに
これで以上です。
意外とステップが少ないので、短時間で終わる作業ということがわかりました。