iOSアプリのローカライズにあたって必要な情報をまとめました。
まずはアプリ側の対応についてです。
※ストア側は別途まとめる予定
ローカライズ対応ですべき事
まずローカライズ対応に必要な事をリストアップします。
- プロジェクト設定
- ローカライズ用テキストの作成
- コード側からのテキストの読み込み
- 画像のローカライズ
- コード内での分岐
おおよそこの5つに分けられると思います。
追記
Info.plsitのローカライズが抜けていました。
アプリ名やATTダイアログなどはこちらで設定します。
別記事になっているのでこちらをご覧ください。
プロジェクト設定
プロジェクトのLocalizationsを設定します。
Project→Info→Localizationsを確認しましょう

デフォルトはBaseとEnglishがあります。
今回は日本語と英語の対応とするのでJapaneseを追加します。

既にお気づきだとは思いますが、ここにJapaneseなかったからと言ってストアページで英語になっている訳ではありません。
ローカライズしない時はそのままEnglishとBaseのみですがストアの言語はJAになっています。

また、この状態ではローカライズ対応外の国ではEnglishとなります。
プレビューと実行環境
実際のローカライズ作業に入っていく前にpreviewと実行環境についてです
previewする
先程の設定でDevelopment LocalizationがEnglishになっていました。
この状態ではpreviewが英語になります。
それぞれの言語でpreviewしたい場合はpreviewにlocaleを設定します。
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.locale, .init(identifier: "ja"))
ContentView()//.environment(\.locale, .init(identifier: "en"))
}
}


この様にenvironmentで設定する事で言語毎のpreviewができます。
今回は2つ並べて書いたのでタブを切り替える事でそれぞれの言語で確認できます。
実行環境
実行環境も言語設定をしなければなりません。
現在のiOSは本体の言語設定を変えなくてもアプリ毎に言語設定が可能です。
設定アプリの下部のアプリ毎の設定から変更が可能です。
ここからはプロジェクトで設定したものが選択できます。



プロジェクトで設定していない言語についてどうなるかを確認したい場合は本体設定を変更しましょう。
設定アプリの一般の言語と地域から変更しましょう。
初めての場合は言語を追加で変更できます。
既に追加されている場合は設定したい言語を一番上に並び変えて下さい。


ローカライズテキストを用意する(Localizable.strings)
ローカライズ用のテキストを用意します。
その際、Localizable.stringsというファイルに書いて行きます。
ファイルを新規作成してStrings Fileを選択して下さい。
名前はそのままLocalizableを推奨します。
他の名前にするとコード内でファイル名指定が必要になるので面倒です。
特に必要がなければデフォルト名のままにして下さい。




次に左側のLocalizationのLocalize…を選択して下さい。
Englishが選択されていますがJapaneseは後で追加出来るのでそのままLocalizeを押して下さい。


するとLocalize…があった場所に言語のチェックボックスができます。
ここでJapaneseをチェックするとLocalizableがEnglishとJapaneseの二つになります。


ここにKey-Value形式でテキストを記述していく事ができます。
stringsファイルではセミコロンが必要なので忘れない様にして下さい。
"Key" = "Value";
"TitleKey" = "タイトル";
実際に書いていく際は、以下の様に2つのファイルに1つのKeyに対してそれぞれのValueを記述して行きます。
//Localizable(ja)
"TitleKey" = "タイトル";
//Localizable(en)
"TitleKey" = "Title";
コード側からテキストを読み込む
Textに表示する
実際に先程のテキストをアプリ内で使って行きましょう。
使い方は簡単でTextの引数に先程のKeyを使用するだけです。
struct ContentView: View {
var body: some View {
VStack {
Text("TitleKey")
}
.padding()
}
}


Textの引数に渡した”TitleKey”ではなく、対応したValueが表示されています。
StringsファイルをLocalizable以外の名前にした場合は以下の形で指定します。
Text("LocalizedStringKey" ,tableName: "FileName") //.stringsは不要
長文を扱う場合や数が多くなってしまった場合に、Stringsファイルを分割する時に使うと良いでしょう。
変数を含める
テキスト内に変数を埋め込みたい場合は多々あります。
Localizable.stringsに%@を含める事で文字列を埋め込む事ができます。
数値の場合は先に文字列に変換しておきましょう。
//
"Hello %@" = "こんにちは %@!!";
//
struct ContentView: View {
let text = "SwiftUI"
var body: some View {
VStack {
Text("Hello \(text)")
}
.padding()
}
}

もちろん複数の変数を埋め込む事も出来ます。
//
"TestKey %@,%@" = "こんにちは %@、こんにちは %@";
//
struct ContentView: View {
let text = "SwiftUI"
let text2 = "Xcode"
var body: some View {
VStack {
Text("TestKey \(text2),\(text)")
}
.padding()
}
}

テキストをそのまま表示する
Keyをしっかり管理すれば問題ありませんが、
万が一表示したいテキストとKeyが被ってしまった場合にも、
そのままテキストを表示する方法があります。
Textのverbatim引数を使用しましょう。
この引数を使う事でLocalizable.stringsを無視してそのまま表示する事ができます。
//
"TitleKey" = "タイトル";
//
struct ContentView: View {
var body: some View {
VStack {
Text("TitleKey")
Text(verbatim: "TitleKey")
}
}
}

String変数内のテキストは翻訳されない
String変数内のテキストはLocalizable.stringsの影響を受けません
先程までの使用方法では特に区別していませんが、実はKeyはString型ではありません。
LocalizedStringKeyという型が存在し、Localizableで変換されるのはこちらになります。
従ってString型の変数を使用しても変換されません。
//
"TitleKey" = "タイトル";
//
struct ContentView: View {
let titleString = "TitleKey"
let titleKey:LocalizedStringKey = "TitleKey"
var body: some View {
VStack {
Text("TitleKey")
Text(titleString)
Text(titleKey)
//Text(verbatim:titleKey) //エラー
}
}
}
通常はString型で扱う為、処理した文字列やユーザー入力の文字列は変換される事がありません。
変換したい文字列を扱う場合はLocalizedStringKeyで扱うことを意識しなければなりません。
例えば、これはenumのrawValueを表示する場合です。
//enum Tabs:String,CaseIterable{
enum Tabs:LocalizedStringKey,CaseIterable{
case tab1 = "Tab1"
case tab2 = "Tab2"
case tab3 = "Tab3"
}
struct SampleTabView: View {
@State var selection = Tabs.tab1
var body: some View {
VStack {
Picker("", selection: $selection) {
ForEach(Tabs.allCases, id:\.self){ tab in
Text(tab.rawValue).tag(tab)
}
}.pickerStyle(.segmented)
TabView(selection: $selection){
ForEach(Tabs.allCases, id:\.self){ tab in
Text(tab.rawValue)
}
}
}
}
}


この様にStringとLocalizedStringKeyの使い分けが必要になる場合もあります。
画像の出し分け
画像などのリソースに言語毎の違いが必要な場合は分岐が必要になります。
Assetsにもローカライズの項目があるのでしっかり活用しましょう。
今回はImageを追加してローカライズして行きます。
Localizable.stringsと同様に右にLocalizeボタンがあるのでこれを押し、
チェックを入れる事でlocale毎に設定出来る様になります。




表示する方法はいつも通りImageで表示するだけでOKです。
struct ContentView: View {
var body: some View {
VStack {
Image("Image")
}
}
}


なお、今回私がテストしている途中、previewでLocalizeが反映されなかったので注意して下さい。
シミュレータでアプリの言語を変更すると問題なく表示が変わりました。
コード内での分岐
他がうまく出来ていると余り必要はないかもしれませんが、
アプリの内容によっては必要になるかもしれません。
previewの時点でおおよそ予想がついているかもしれませんが、
EnvironmentValueでlocaleを指定する事で取得出来ます。
struct ContentView: View {
@Environment(\.locale) var locale
var body: some View {
VStack {
Text("Locale : \(locale.identifier)")
}
.padding()
}
}


最後に
以上がアプリ側で行うローカライズ対応でした。
案外全てがいい感じにまとまっている記事がなかった為、自分でまとめました。
Info.plsitのローカライズは別記事になっているのでこちらをご覧ください。
今後ストア公開にあたって必要な対応についても記事にする予定です。
コメント
[…] 【SwiftUI】iOSアプリのローカライズiOSアプリのローカライズにあたって必要…SwiftUI開発全般AppTrackingTransparencyInfo.plistLocalizeSwiftUIXcodeシェアする Twitter Facebook はてブ Pocket LINE コピーthwork.devをフォローする thwork.dev thwork […]
[…] 【SwiftUI】iOSアプリのローカライズiOSアプリのローカライズにあたって必要…開発全般AppStoreAppStoreConnectシェアする Twitter Facebook はてブ Pocket LINE コピーthwork.devをフォローする thwork.dev thwork […]