Flutter SDKでローカリゼーションとロケールコードを使用する

なぜこれが重要なのか

ロケールコードは、Adapty がフローやオンボーディングのローカライゼーションを選択するときや、カスタムペイウォール用のリモートコンフィグを読み取るときに使われます。

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

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にフォールバックします。

ダッシュボードで設定されているとおり、ロケールコードを正確に渡してください。システムのロケール識別子をそのまま渡さないでください。Platform.localeNamept_BR を返し、PlatformDispatcher.instance.locale.toLanguageTag()pt-BR を返しますが、どちらもデフォルトのローカライズにフォールバックします。アプリ内で値を変換してから渡してください。

オンボーディング

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

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

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

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

SDK v4 では、フローを取得する際にロケールコードを渡す必要はありません。getFlow はすべてのローカライゼーションを含むフローを返し、フロービューが構築される際に Adapty が適切なものを適用します。getFlow および getFlowForDefaultAudiencelocale 引数はフローには影響せず、非推奨となっており、警告がログに記録されます。

  • ビルダーで作成したフロー: SDKはデバイスのロケールを読み取らないため、アプリ側でロケールを解決し、createFlowViewまたはAdaptyUIFlowPlatformViewlocale引数として渡してください。この引数は省略可能です。省略した場合、フローはenでレンダリングされます。ただし、フローにenのローカライズがない場合は、デフォルトロケールでレンダリングされます。

AdaptyUIFlowView.locale は、ビューの構築に使用されたローカライゼーションを返します。Flutter SDK 4.0.3(ネイティブ iOS 4.0.2 および Android 4.0.1 以降)が必要で、古いネイティブ SDK では null になります。

  • カスタム(リモートコンフィグ)ペイウォール: getFlow は設定済みのすべてのローカライゼーションを flow.remoteConfigs に返します。各エントリには locale コードと設定コンテンツ(data 文字列、またはパース済みの dictionary)が含まれます。ユーザーに合ったエントリを選択し、必要に応じてフォールバックを実装してください。

final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
final config = flow.remoteConfigs.firstWhereOrNull((c) => c.locale == 'en') ??
    flow.remoteConfig; // the first remote config, if present
// read your values from config?.dictionary

AdaptyはlocaleコードをAdaptyのLocaleコード標準で説明されている形式で保存します。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 app_en.arb, app_es.arb, app_pt_br.arb files

/*
app_en.arb
*/
"adapty_paywalls_locale": "en",

/*
app_es.arb
*/
"adapty_paywalls_locale": "es",

/*
app_pt_br.arb
*/
"adapty_paywalls_locale": "pt-br",

// 2. Extract and use the locale code
final locale = AppLocalizations.of(context)!.adapty_paywalls_locale;
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

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

ローカリゼーションの別の実装方法

ロケールコードをすべてのローカリゼーションに明示的に定義しなくても、同様の(ただし完全に同じではない)結果を得ることができます。その場合、プラットフォームが提供する別のオブジェクトからロケールコードを取得する方法が考えられます。例えば次のようにします。

final locale = Localizations.localeOf(context).languageCode;
// pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method

ただし、この方法はいくつかの理由からお勧めしません。

  1. iOSでは、優先言語と現在のロケールは同一ではありません。ローカライズが正しく選択されるようにするには、ローカライズされた文字列ファイルを使用する推奨のアプローチを利用してAppleのロジックにそのまま任せるか、独自に再実装する必要があります。
  2. Adaptyのサーバーが実際に何を受け取るかを予測するのは困難です。たとえばiOSでは、デバイスから ar_OM@numbers='latn' のようなロケールを取得してサーバーに送信することがあります。この場合、期待していた ar-om ローカライズではなく、ar が返されることになり、予期しない動作となる可能性があります。 万が一このアプローチを採用する場合は、関連するすべてのユースケースを網羅していることを確認してください。