Xcode15以降のローカライゼーション(多言語対応)

<!-- 記述ルールは画面下部にあります。(コメントは削除して問題ありません) -->

# 概要

iOSアプリのローカライゼーション(多言語対応)の効率的な開発方法を調べていたら、WWDC2023で発表されていた[Discover String Catalogs](https://developer.apple.com/videos/play/wwdc2023/10155)の内容が良さそうに見えたので自分用のメモも兼ねて投稿します。

なお、今までの多言語対応の方法は[こちら](https://developer.apple.com/documentation/Xcode/localization)に記載されています。

- - -
# 詳細

Xcode15よりも前のバージョンでローカライゼーションを対応しようと考えたとき、`String`ファイルと`STRINGDICT`ファイルに対応するワードを記載し、手作業で翻訳を追加する方法がメインでした。
この方法だと翻訳の抜け漏れがあるのをチェックするのが手間だというデメリットがありました。

2023年9月にリリースされたXcode15からは`String Catalogs`という新しい仕組みが導入されました。
この仕組みにより、1箇所でローカライゼーションしたいワードを管理できるため、これまでよりも効率的にローカライゼーションができるようになりました。

例えば、以下のようなViewがあり、`Text("Hello world!")`をローカライゼーションの対象としたい場合、後述の手順に従うことで対応が可能です。

```swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello world!")
        }
        .padding()
    }
}
```


## 手順

### 1.プロジェクトに言語を追加する

下記の画像のように**PROJECT>Info>Locakizationsタブの＋ボタン**を押下し、ローカライゼーションを行う言語を選択する。

この記事では英語に対応する日本語を追加するため、**Japanese**を選択しています。

![スクリーンショット 2023-11-21 8.08.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/b003c1af-9927-6ae9-90ce-2b1f679630a8.png)


### 2.`String Catalog`をプロジェクトに追加する

プロジェクト内に新規ファイルとして`String Catalog`を追加します。

この記事ではデフォルトの`Localizable.xcstrings`という名前を使用します。

![スクリーンショット 2023-11-27 19.22.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/697a625b-471f-0d9a-c3a1-321618a67a09.png)

### 3.Localizable.xcstringsにKeyと翻訳を追加する

今回は`Hello world!`をローカライゼーションするため、以下のように**English**を選択し、Keyの欄に`Hello world!`と入力します。

なお、今回は意図的に追加する箇所を手順に加えましたが、**プロジェクト内に宣言されている文字列をXcodeが検知し、勝手にString CatalogのKeyとして追加してくれる**という仕様です。


![スクリーンショット 2023-11-27 19.23.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/9b98a752-d014-b729-062f-2c0e2ebbb08f.png)

Englishに`Hello world!`を追加したことで、以下のように**Japanese**の一覧にも自動的に`Hello world!`が追加されています。

![スクリーンショット 2023-11-27 19.23.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/441e4531-c26a-057d-746f-1cc289d665bd.png)

今回は例として`こんにちは　世界！`という翻訳を追加してみます。

これで`Hello world!`の日本語へのローカライゼーションが完了です。

![スクリーンショット 2023-11-27 19.23.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/dc778071-4fa5-d04b-e429-e2b0a830e9ac.png)

### 4.ローカライゼーションが適用されているか確認する

実際に適用されているかをシミュレーターで確認してみましょう。

まず、iPhoneの使用言語を日本語に設定し、アプリを起動してみます。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/c519198b-1920-a9c1-a10b-bad1602bc2d3.png">

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/55ed85b7-0f65-ad29-6d00-57f4bf4b6142.png">

日本語に翻訳されていますね。

次にiPhoneの使用言語を英語に設定し、アプリを起動してみます。

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/f6501a4c-fe40-b3e3-4dfe-67f12f3ff7fd.png">


<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/f8dc1b59-6120-c546-e83e-72ee56d4a449.png">



こちらも想定していたように、英語が表示されています。






### 余談：デバイスごとに表示するワードを切り替える

上記の翻訳はデバイスごとに設定することも可能です。
例えば、以下のような`Tap me`というボタンがあったとしましょう。


<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/c7a88cb1-3e3b-5364-a89d-5c8933680cf7.png">

これはiPhoneやiPadであればユーザーに正しく受け取られます。しかし、Macで同様のアプリを起動した時、タップという動きは存在しないため、ユーザーは違和感を覚えるかもしれません。
一般的にはiPhoneなどのデバイスでは`Tap me`、Macでは`Click me`というように自動で切り替わることが望ましいでしょう。
そういった機種ごとに表示する翻訳を切り替えることも`String Catalogs`では可能です。


事前準備として、先ほどの`Hello world!`を`Tap me`に書き換えてみます。

```
struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Tap me")
        }
        .padding()
    }
}
```

`Localizable.xcstrings`を確認すると、Xcodeに検知された`Tap me`が`Localizable.xcstrings`に自動で追加されています。

![スクリーンショット 2023-11-27 20.03.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/f0fc7ad5-6bb9-b775-0d17-1d55e3afe193.png)

デバイスごとに表示するワードを切り替える場合、ワードの上で右クリックを行い、`Vary by Device`にカーソルを合わせるとデバイスの一覧が表示されます。

今回はデモの都合上、iPadを選択します。

![スクリーンショット 2023-11-27 20.05.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/0621fa7c-b201-fb29-3bc2-eaea29a3354d.png)

すると、以下のように機種ごとに表示するワードを設定することが可能です。
今回はiPhoneで起動したときには`Tap me`,iPadで起動した場合には`Click me`と表示するように設定しました。

![スクリーンショット 2023-11-27 20.22.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/d963e353-10a2-9eb8-29ae-6bcf68cf6b5d.png)


起動した時のイメージは以下のようになります。

iPhone
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/7fd9f0eb-b491-1193-f103-6ed7773e9c81.png">

iPad
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3576326/e5a1893e-6e7d-9efe-6d03-b708d70ba16c.png">

機種ごとに表示するワードを切り替えられていますね。

ローカライゼーションは今までの方法だと抜け漏れのチェックに手間がかかっていましたが、この方法を導入すればTextなどを自動で検知してくれてかなり楽になりそうです。