Swift Digest

Locale.preferredLocales

Locale.preferredLocales

Proposal
SF-0026
Authors
करन मिश्र · Karan Miśra
Status
Accepted

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

01 何が問題だったのか

ユーザーが Language & Region 設定で並べた優先言語のリストを取得する API として、Foundation には従来から Locale.preferredLanguages がありました。

let languages: [String] = Locale.preferredLanguages

ただし、戻り値は [Locale] ではなく [String] です。これは +[NSLocale preferredLanguages] から続く仕様で、実体は "en-US""ja-JP" のような言語識別子の文字列です。

呼び出し側でこの情報を扱おうとすると、文字列のまま比較したり、必要に応じて Locale(identifier:)Locale に変換したりすることになります。とくに、アプリ内の言語選択メニューで「ユーザーが優先する言語と一致するもの」を上位に並べたい場合のように、言語識別子としての等価性を見たいユースケースでは、文字列処理だけで正しく扱うのは難しく、誤りが入り込みやすくなります。

Locale 型には既に Locale.Language.isEquivalent(to:) のように言語識別子としての等価判定を行う API が用意されているにもかかわらず、preferredLanguages の戻り値が [String] のままなので、これらの API へつなぐためにわざわざ変換する必要がありました。

02 どのように解決されるのか

Locale に、preferredLanguages と同じ情報を [Locale] として返す static プロパティ preferredLocales が追加されます。

public struct Locale: Hashable, Equatable, Sendable {

    /// Returns a list of the user's preferred locales, as specified in
    /// Language & Region settings, taking into account any per-app language overrides.
    @available(FoundationPreview 6.2, *)
    public static var preferredLocales: [Locale]
}

返される値は、Language & Region 設定でユーザーが指定した優先言語のリストに対応するもので、アプリごとの言語上書き設定があればそれも反映されます。情報の中身は preferredLanguages と同じですが、要素が Locale になっているため、Locale の API をそのまま使って扱えます。

たとえば、利用可能な Locale のリストから言語選択メニューを構築し、ユーザーの優先言語に一致するものを上位に並べる、といった処理が次のように書けます。

// 利用可能な Locale を、ユーザーの優先言語と一致するものとそれ以外に分ける
var matchedLocales: [Locale] = []
var otherLocales: [Locale] = []
let availableLocales: [Locale] = // ... 利用可能な Locale のリスト ...

for locale in availableLocales {
    var foundMatch = false
    for preferredLocale in Locale.preferredLocales {
        if locale.language.isEquivalent(to: preferredLocale.language) {
            matchedLocales.append(locale)
            foundMatch = true
            break
        }
    }
    if !foundMatch {
        otherLocales.append(locale)
    }
}

Locale.Language.isEquivalent(to:) のような既存 API に直接渡せるため、preferredLanguages を使っていたときのように文字列をパースしたり Locale(identifier:) で変換したりする必要がなくなります。

preferredLanguages は引き続き残るので、新規コードで preferredLocales を使うかどうかはケースバイケースで選べます。

03 今後の見通し

言語選択 UI を組み立てるユースケースをさらに支援するために、いくつかの拡張が構想として挙げられています。いずれも将来の構想であり、その実現を約束するものではありません。

利用可能な Locale をソート・分割する API

利用可能な Locale のリストを、ユーザーの優先言語に一致するものとそれ以外に分けて返す便利関数を Locale に追加する案が示されています。

public static func sorted(_ available: [Locale]) -> (preferred: [Locale], remaining: [Locale])

これがあれば、preferredLocales と利用可能な Locale のリストを突き合わせる処理を呼び出し側で書かなくても、戻り値の preferredremaining をそのまま UI に流し込むことができます。

Locale.Language を扱うバリアント

ユースケースによっては、Locale の付加情報までは必要なく、言語識別子としての Locale.Language だけ扱えれば十分な場合もあります。そこで、Locale.Language を入出力とする同種の API を追加することも将来の方向性として検討されています。

preferredLanguages の deprecated 化

preferredLocalespreferredLanguages は同じ情報を返しますが、String は言語識別子の入れ物として適切ではなく、誤った使い方を誘発しがちです。そのため、preferredLanguages を deprecated 化していくという方向性も挙げられています。