Capacitor 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 で表示され、en のローカライズが存在しない場合にのみ de にフォールバックします。

Warning

ダッシュボードで設定された通りのロケールコードをそのまま渡してください。ハイフン区切りの小文字サブタグ形式で渡す必要があります。システムのロケール識別子をそのまま渡さないでください。navigator.languagept-BR を返し、デフォルトのローカライズにフォールバックします。アプリ内で値を変換してから渡してください。

オンボーディング

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

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

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

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

SDK v4 では、フローを取得する際にロケールコードを渡す必要はありません。getFlow はすべてのローカライゼーションを含むフローを返し、フロービューが構築される際に Adapty が適切なものを適用します。

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

    import { createFlowView } from '@adapty/capacitor';
    
    const view = await createFlowView(flow, { locale: 'es' });

view.locale は、ビューが構築されたローカライゼーションを報告します。locale オプションと view.locale はどちらも Capacitor SDK 4.0.1-beta.1 が必要で、それより古いバージョンでは view.localeundefined になります。onAppeared ハンドラー も同じ値を報告します。

  • カスタム(リモートコンフィグ)ペイウォール: getFlow は設定されたすべてのローカライゼーションを flow.remoteConfigs に返します。各エントリには lang コードと data オブジェクトが含まれます。ユーザーに合ったエントリを、独自のフォールバックロジックで選択してください。

const flow = await adapty.getFlow({ placementId: 'placement_id' });
const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0];
// read your values from config?.data

Adapty は lang コードを 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 localization files (e.g., using react-i18next)

/*
en.json
*/
{
  "adapty_paywalls_locale": "en"
}

/*
es.json
*/
{
  "adapty_paywalls_locale": "es"
}

/*
pt-BR.json
*/
{
  "adapty_paywalls_locale": "pt-br"
}

// 2. Extract and use the locale code

const MyComponent = () => {
  const { t } = useTranslation();
  
  const fetchPaywall = async () => {
    const locale = t('adapty_paywalls_locale');
    // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
    const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
  };
};

That way you can ensure you’re in full control of what localization will be retrieved for every user of your app.

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

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


const getLocaleCode = () => {
  if (Capacitor.getPlatform() === 'ios') {
    return navigator.language || 'en';
  } else {
    return navigator.language || 'en';
  }
};

const fetchPaywall = async () => {
  const locale = getLocaleCode();
  // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method
  const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale);
};

この方法はいくつかの理由からお勧めしません:

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