はじめに
iOSの言語設定を取得するベストプラクティスを紹介します。
環境
PC
- OS:macOS Big Sur 11.0.1
- Xcode:12.2 (12B45b)
- Swift:5.3.1
シミュレータ
- 機種:iPhone SE (2nd generation)
- OS:iOS 14.2
結論
- アプリがローカライズされていない
-
Locale.current
ではうまく取得できないので、Locale.preferredLanguages
からLocale
を生成し直す
-
- アプリがローカライズされている
- アプリ単位で優先する言語を指定できるので、「おまけ」に書いたようにローカライズの設定を使うのがベター
- OS単位の言語設定を取得したい場合は、ローカライズされていないときと同様の方法でいい
言語設定の取得を試す
結論に至るまでにいろいろ試したので、過程を紹介します。
PREFERRED LANGUAGE ORDER(使用する言語の優先順序): English > 日本語 (アメリカ)
地域: United States(アメリカ合衆国)
まずはシミュレータのデフォルト設定で試してみます。
Language & Region(言語と地域) |
---|
プロパティ | 戻り値 |
---|---|
Locale.preferredLanguages |
["en", "ja-US"] |
Locale.current.description |
en (current) |
Locale.current.languageCode |
en |
Locale.current.regionCode |
nil |
ほぼ予想通りの結果ですが、 ja-US
という表記を初めて見たのと、 regionCode
が nil
なのは意外でした。
使用する言語の優先順序: 日本語 > English
地域: アメリカ合衆国
次に、使用する言語の優先順序を入れ替えます。
地域は英語→日本語表記になったので変わったように見えますが、変えていません。
Language & Region(言語と地域) |
---|
プロパティ | 戻り値 |
---|---|
Locale.preferredLanguages |
["ja-US", "en"] |
Locale.current.description |
en_US (current) |
Locale.current.languageCode |
en |
Locale.current.regionCode |
US |
Locale.preferredLanguages
が入れ替わったのは予想通りでしたが、他は私の中では予想外でした。
優先順序を入れ替えたことによって「iPhoneの使用言語」が 日本語
に変わったので、 Locale.current.○○
のプロパティも日本になると思いました。
使用する言語の優先順序: 日本語 > English
地域: 日本
使用する言語の優先順序をそのままに、地域を日本に変えます。
Language & Region(言語と地域) |
---|
プロパティ | 戻り値 |
---|---|
Locale.preferredLanguages |
["ja-JP", "en-JP"] |
Locale.current.description |
en_JP (current) |
Locale.current.languageCode |
en |
Locale.current.regionCode |
JP |
なんかいろいろおかしい気がしますw
シミュレータだからなのか、言語や地域の変更後に再起動していないからなのか、原因はわかりません。
正しい挙動という可能性ももちろんあります。
おわりに
いろいろ試してもよくわかりませんでした。
何となくわかったのが、 preferredLanguages
の要素は {languageCode}-{regionCode}
で構成されているということです。
iOSの言語と地域について詳しい方がいたら、コメントなどで教えていただけると嬉しいです
追記:
Twitter でAppleの公式ドキュメントを教えていただきました。
言語IDやロケールIDについて詳しく書いてあるので、こちらを読めば深く理解できそうです。
https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15
おまけ:言語設定の取得をローカライズ文字列に任せる
iOSの言語設定がうまく取得できなかったので、代替案を考える必要があります。
Localizable.string
に "languageCode" = "en";
のようなキーと値を持たせ、言語設定の取得をローカライズ文字列に任せる方法を思いつきましたw
他にいい方法があれば教えてください
みなさんはアプリ内でなくサーバーから言語設定に応じた文字列を取得する場合、どのように言語設定をサーバーに渡しているのだろう…
追記:
@k_katsumi さんにTwitterでいろいろ教えていただきました
当てになるのはpreferredLanguagesで、そこから言語コードだけ、とか分解して取りたいならその値からLocaleを作り直すといいっすよ。
— kishikawa katsumi (@k_katsumi) November 18, 2020
let locale = Locale(identifier:Locale.preferredLanguages[0])
print(locale.languageCode)
print(locale.regionCode)
print(locale.scriptCode)
実際に preferredLanguages
から Locale
を作り直し、各プロパティを確認しました。
print(Locale.preferredLanguages) // ["ja-JP", "en-JP"]
let language = Locale.preferredLanguages.first!
print(language) // ja-JP
let locale = Locale(identifier: language)
print(locale.description) // ja-JP (fixed)
print(locale.languageCode ?? "nil") // ja
print(locale.regionCode ?? "nil") // JP
print(locale.scriptCode ?? "nil") // nil
適切に languageCode
や regionCode
を取得できました。
自分で生成した Locale
だと description
の括弧内が (current)
でなく (fixed)
になるようです。
その上で、ケースバイケースで難しいんですけどたいていの場合はユーザーが指定した(望んでいる)ローカライズの設定に従うようにLocalizable.stringを当てにするっていうのはかなりベターな方法だと思います。
— kishikawa katsumi (@k_katsumi) November 18, 2020
ローカライズされているアプリは、OS単位でなくアプリ単位でも優先する言語を指定できるので、ローカライズの設定に従うのはベターな方法でした。
おまけとして書きましたが、こちらの方法を採用するのがよさそうです。
@treastrain さんも採用しているとのことです。
完全に出遅れてしまったけど、私も各 Localizable.strings に
— treastrain / Tanaka.R (@treastrain) November 18, 2020
"key" = "ja";
"key" = "en";
"key" = "zh-HK";
を書いて、それを拾って判定してる。 https://t.co/2B0BiEZllv
参考リンク
- Locale | Apple Developer Documentation
- NSLocale | Apple Developer Documentation
- current | Apple Developer Documentation
- preferredLanguages | Apple Developer Documentation
- description | Apple Developer Documentation
- languageCode | Apple Developer Documentation
- regionCode | Apple Developer Documentation
- [iOS]中国語対応のために端末の言語環境の値を取得したときにハマったこと - Qiita
- 言語設定を取得したい場合はLocale.prefferedLanguagesを使う - Qiita