iOS SDKでローカライゼーションとロケールコードを使用する

なぜこれが重要なのか

ロケールコードは、Adapty がフローやオンボーディングのローカライズを選択するときや、カスタムペイウォール向けにリモートコンフィグを読み取るときに機能します。

ロケールコードはプラットフォームごとに異なる場合があり複雑なため、Adapty はサポートするすべてのプラットフォームにわたって1つの内部標準に依存しています。この標準を理解することで、ユーザーがどのローカライズを受け取るかを予測できます。

Adaptyのロケールコード標準

ロケールコードについて、Adaptyはわずかに変更した BCP 47標準 を使用しています。各コードはハイフンで区切られた小文字のサブタグで構成されています。例:en(英語)、pt-br(ポルトガル語(ブラジル))、zh(簡体字中国語)、zh-hant(繁体字中国語)。

ロケールコードのマッチング

SDK v4では、フローとオンボーディングのロケールコードのマッチング方法が異なります。フローはデバイス上でSDKによってローカライズされ、オンボーディングはAdaptyサーバーによってローカライズされます。

フローとペイウォールビルダーのペイウォール

ペイウォールビルダーで作成されたペイウォールは SDK v4 ではフローとして配信されるため、以下のルールは両方に適用されます。

マッチングは完全一致です。SDK は渡されたコードとフローのローカライゼーションコードを1文字ずつ比較します。大文字・小文字の変換、アンダースコア(_)とハイフン(-)の置き換え、言語サブタグへのフォールバックは行いません。pt-br というローカライゼーションを持つフローの場合、一致するのは pt-br だけです。pt-BRpt_BRpt-PT はいずれも一致しません。

コードがどのローカリゼーションにも一致しない場合、フローはデフォルトのデフォルトロケールで表示されます。SDKはエラーを返さず、警告もログに記録しません。

コードが一致した場合、Adaptyはそのローカリゼーションをデフォルトのローカリゼーションとマージします。一致したローカリゼーションで定義されていない文字列やアセットは、デフォルトのローカリゼーションから取得されます。

ロケールコードを省略することは、フローのデフォルトローカライゼーションを要求することとは異なります。SDK は固定の en を代わりに使用します。デフォルトロケールが de のフローでも、en ローカライゼーションが存在する場合は en で表示され、存在しない場合にのみ de にフォールバックします。

Warning

ダッシュボードで設定されているとおりに、小文字のサブタグをハイフンで区切ったロケールコードを渡してください。システムのロケール識別子をそのまま渡さないでください。Locale.current.identifierpt_BR を返し、Locale.current.identifier(.bcp47)pt-BR を返しますが、どちらもデフォルトのローカライズにフォールバックします。アプリ内で値を変換してから渡してください。

オンボーディング

オンボーディングはサーバー側でローカライズされており、サーバーのルールは他のフォーマットも許容します。getOnboardinglocale を渡すと、以下の処理が行われます:

  1. ロケール文字列が小文字に変換され、アンダースコア(_)がすべてハイフン(-)に置換されます
  2. Adapty は完全に一致するロケールコードのローカライゼーションを検索します
  3. 一致するものが見つからない場合、Adapty は最初のハイフンより前の部分文字列(pt-br であれば pt)を取り出し、一致するローカライゼーションを検索します
  4. それでも一致するものが見つからない場合、Adapty はオンボーディングのデフォルトロケールのコンテンツを返します

これにより、pt_BRpt-BRpt-br はすべて同じオンボーディングのローカライゼーションに解決されます。

ローカライゼーションの実装

SDK v4 では、フローを取得する際にロケールコードを渡す必要はありません。getFlow はすべてのローカライゼーションを含むフローを返します。

  • ビルダーで作成したフロー: SDK はデバイスのロケールを読み取らないため、アプリ側でロケールを解決し、AdaptyUI.getFlowConfiguration(forFlow:locale:) に渡してください。このパラメータはオプションです。省略するとフローは en でレンダリングされます。フローに en のローカライズがない場合は、デフォルトのロケールが使用されます。
  • カスタム(リモートコンフィグ)ペイウォール: getFlow は設定済みのすべてのローカライズを flow.remoteConfigs に返します。各エントリには locale コードと設定内容(jsonString、またはパース済みの dictionary)が含まれます。ユーザーに合ったエントリを選択し、独自のフォールバックを設定してください:
do {
    let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")
    let config = flow.remoteConfigs.first(where: { $0.locale == "en" })
        ?? flow.remoteConfigs.first
    // read your values from config?.dictionary
} catch {
    // handle the error
}

Adapty は locale コードを Adapty のロケールコード標準 に記載のフォーマットで保存します。SDK はリモートコンフィグをロケールと照合しないため、どのエントリを適用するかはアプリ側で決定します。

なぜ重要なのか

ロケールコードが関係するシナリオはいくつかあります。たとえば、アプリの現在のローカライズに合ったペイウォールを取得しようとする場合などです。

ロケールコードはプラットフォームによって複雑に異なるため、Adapty ではサポートするすべてのプラットフォームに共通する内部標準を採用しています。ただし、コードが複雑であるため、サーバーに送信している内容と、その後に何が起こるかをきちんと理解しておくことが非常に重要です。そうすることで、常に期待通りの結果を受け取ることができます。

Adapty でのロケールコード規格

ロケールコードには、Adapty は BCP 47 標準 を少し改変したものを採用しています。各コードは小文字のサブタグをハイフンで区切って構成されます。例: en(英語)、pt-br(ポルトガル語(ブラジル))、zh(簡体字中国語)、zh-hant(繁体字中国語)。

ロケールコードのマッチング

Adapty がクライアントサイド SDK からロケールコードを含む呼び出しを受け取り、対応するペイウォールのローカライズを検索する際、以下の処理が行われます:

  1. 受け取ったロケール文字列を小文字に変換し、アンダースコア(_)をすべてハイフン(-)に置き換えます
  2. 完全一致するロケールコードのローカライズを検索します
  3. 一致するものが見つからない場合、最初のハイフンより前の部分文字列(pt-br なら pt)を取り出し、一致するローカライズを検索します
  4. それでも一致するものが見つからない場合、ペイウォールのデフォルトロケールのコンテンツを返します

これにより、'pt_BR'を送信したiOSデバイス、pt-BRを送信したAndroidデバイス、pt-brを送信した別のデバイスは、すべて同じ結果を受け取ります。

ローカライゼーションについて検討しているなら、すでにプロジェクト内のローカライズされた文字列ファイルを扱っているでしょう。その場合、各ローカライゼーションに対応するファイルに、意図したAdaptyロケールコードをキーと値のペアとして配置することをお勧めします。そして、次のようにSDKを呼び出す際にそのキーの値を取得します:

// 1. Modify your Localizable.strings files

/*
Localizable.strings - Spanish
*/
adapty_paywalls_locale = "es";
/*
Localizable.strings - Portuguese (Brazil)
*/
adapty_paywalls_locale = "pt-br";
// 2. Extract and use the locale code
let locale = NSLocalizedString("adapty_paywalls_locale", comment: "")
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

これにより、アプリのすべてのユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。

ローカライゼーションの実装:別の方法

ロケールコードをすべてのローカライゼーションに明示的に定義しなくても、類似した(ただし同一ではない)結果を得ることができます。その場合、プラットフォームが提供する他のオブジェクトからロケールコードを抽出することになります。例:

let locale = Locale.current.identifier
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

いくつかの理由から、このアプローチは推奨しません:

  1. iOSでは、優先言語と現在のロケールは同一ではありません。ローカライゼーションを正しく選択したい場合、Appleのロジックに依存するか(ローカライズされた文字列ファイルを使用する推奨アプローチでは自動的に機能します)、それを再現する必要があります。
  2. Adaptyのサーバーが何を受け取るかを予測するのが難しいです。たとえばiOSでは、デバイスからar_OM@numbers='latn'のようなロケールを取得してサーバーに送信することがあります。この場合、期待していたar-omローカライゼーションではなく、arが返ってくる可能性があり、意図しない結果になることがあります。

この方法を使用する場合は、すべての関連するユースケースに対応していることを確認してください。