ロケール識別子から冗長な情報を削除する方法

minimizeメソッドを使用して、意味を失わずにコンパクトなロケール識別子を作成する

はじめに

en-Latn-USzh-Hans-CNのようなロケール識別子には、言語、文字体系、地域を指定する複数のコンポーネントが含まれています。しかし、ロケールを識別するためにこれらのコンポーネントすべてが必要なわけではありません。一部のコンポーネントは、識別子の他の部分から推測できるため冗長です。

minimize()メソッドは、これらの冗長なコンポーネントを削除して、最短の同等のロケール識別子を作成します。これにより、意味を保持しながらストレージサイズを削減し、可読性を向上させるコンパクトな識別子が生成されます。

ロケール識別子における冗長性の理解

ロケール識別子は、他のコンポーネントによってすでに暗示されている情報を明示的に記述している場合に冗長になります。冗長性が発生するのは、各言語に文字体系と地域のデフォルト値が存在する可能性が高いためです。

識別子en-Latn-USを考えてみましょう。この識別子は以下を指定しています。

  • 言語: 英語(en)
  • 文字体系: ラテン文字(Latn)
  • 地域: 米国(US)

英語はラテン文字でのみ書かれ、地域が指定されていない場合、英語は米国がデフォルトになります。文字体系と地域のコンポーネントは、英語のデフォルト値と一致するため冗長です。識別子enは同じ情報を伝えます。

同じ原則が他の言語にも適用されます。韓国語(ko)はハングル文字(Kore)で書かれ、主に韓国(KR)で話されています。識別子ko-Kore-KRは、koだけでこれらのデフォルト値が暗示されるため、冗長な情報を含んでいます。

minimizeメソッドの仕組み

minimize()メソッドはIntl.Localeインスタンスで使用できます。このメソッドはロケール識別子を分析し、デフォルト値と一致するコンポーネントを削除します。

const locale = new Intl.Locale("en-Latn-US");
const minimized = locale.minimize();

console.log(minimized.baseName);
// Output: "en"

このメソッドは、冗長なサブタグを削除した新しいIntl.Localeインスタンスを返します。元のロケールオブジェクトは変更されません。

最小化プロセスは、Unicode CLDRの「Remove Likely Subtags」アルゴリズムに従います。このアルゴリズムは、推定されるサブタグの関連付けデータベースを使用して、情報を失うことなく削除できるコンポーネントを判断します。

minimizeの影響を受けるコンポーネント

minimize()メソッドは、コアロケールコンポーネント(言語、文字体系、地域)にのみ影響します。フォーマット設定を指定するUnicode拡張サブタグは削除または変更されません。

const locale = new Intl.Locale("en-Latn-US-u-ca-gregory-nu-latn");
const minimized = locale.minimize();

console.log(minimized.toString());
// Output: "en-u-ca-gregory-nu-latn"

カレンダー(ca-gregory)と数値体系(nu-latn)の拡張はそのまま保持されます。冗長な文字体系(Latn)と地域(US)のコンポーネントのみが削除されます。

最小化の例

どのコンポーネントが冗長であるかによって、異なるロケール識別子は異なる長さに最小化されます。

文字体系と地域の削除

文字体系と地域の両方がデフォルトと一致する場合、両方とも削除されます。

const english = new Intl.Locale("en-Latn-US");
console.log(english.minimize().baseName);
// Output: "en"

const korean = new Intl.Locale("ko-Kore-KR");
console.log(korean.minimize().baseName);
// Output: "ko"

const japanese = new Intl.Locale("ja-Jpan-JP");
console.log(japanese.minimize().baseName);
// Output: "ja"

デフォルト以外の地域の保持

地域がデフォルトと異なる場合、最小化された識別子に残ります。

const britishEnglish = new Intl.Locale("en-Latn-GB");
console.log(britishEnglish.minimize().baseName);
// Output: "en-GB"

const canadianFrench = new Intl.Locale("fr-Latn-CA");
console.log(canadianFrench.minimize().baseName);
// Output: "fr-CA"

const mexicanSpanish = new Intl.Locale("es-Latn-MX");
console.log(mexicanSpanish.minimize().baseName);
// Output: "es-MX"

文字体系コンポーネントはデフォルトと一致するため削除されますが、地域は言語のデフォルト以外のバリアントを指定するため保持されます。

デフォルト以外の文字体系の保持

文字体系がデフォルトと異なる場合、最小化された識別子に残ります。

const simplifiedChinese = new Intl.Locale("zh-Hans-CN");
console.log(simplifiedChinese.minimize().baseName);
// Output: "zh-Hans"

const traditionalChinese = new Intl.Locale("zh-Hant-TW");
console.log(traditionalChinese.minimize().baseName);
// Output: "zh-Hant"

const serbianCyrillic = new Intl.Locale("sr-Cyrl-RS");
console.log(serbianCyrillic.minimize().baseName);
// Output: "sr-Cyrl"

中国語は簡体字と繁体字のバリアントを区別するために文字体系コンポーネントが必要です。セルビア語はキリル文字とラテン文字を区別するために文字体系コンポーネントが必要です。

すでに最小化された識別子

ロケール識別子がすでに最小化されている場合、メソッドは変更なしで同等のロケールを返します。

const minimal = new Intl.Locale("fr");
console.log(minimal.minimize().baseName);
// Output: "fr"

maximizeとの関係

minimize()メソッドはmaximize()の逆です。maximize()メソッドは推定されるサブタグを追加して完全な識別子を作成しますが、minimize()は冗長なサブタグを削除してコンパクトな識別子を作成します。

これらのメソッドは、完全形式とコンパクト形式の間で双方向変換を可能にするペアを形成します。

const compact = new Intl.Locale("en");
const complete = compact.maximize();
console.log(complete.baseName);
// Output: "en-Latn-US"

const compactAgain = complete.minimize();
console.log(compactAgain.baseName);
// Output: "en"

コンパクト形式から完全形式へ、そして再びコンパクト形式への往復変換により、元の形式が生成されます。

ただし、すべてのロケールが往復変換後に元の形式に正確に戻るわけではありません。このメソッドは、元の構造を保持するのではなく、正規化された最小形式を生成します。

const locale = new Intl.Locale("en-US");
const maximized = locale.maximize();
console.log(maximized.baseName);
// Output: "en-Latn-US"

const minimized = maximized.minimize();
console.log(minimized.baseName);
// Output: "en"

元の識別子en-USには非冗長な地域が含まれていましたが、最大化と最小化の後、enになります。これは、米国が英語のデフォルト地域である可能性が高いために発生します。

minimizeを使用するタイミング

曖昧さを残さないコンパクトなロケール識別子が必要な場合は、minimize()を使用します。いくつかのシナリオで最小化が有効です。

ロケール設定の保存

最小化された識別子は、データベース、ローカルストレージ、または設定ファイルのストレージスペースを削減します。

function saveUserLocale(localeString) {
  const locale = new Intl.Locale(localeString);
  const minimized = locale.minimize().toString();

  localStorage.setItem("userLocale", minimized);
}

saveUserLocale("en-Latn-US");
// Stores "en" instead of "en-Latn-US"

これにより、情報を失うことなく保存データサイズが削減されます。

読みやすいURLの作成

最小化された識別子は、言語選択のためのよりクリーンなURLを生成します。

function createLocalizedURL(path, localeString) {
  const locale = new Intl.Locale(localeString);
  const minimized = locale.minimize().baseName;

  return `/${minimized}${path}`;
}

const url = createLocalizedURL("/products", "en-Latn-US");
console.log(url);
// Output: "/en/products"

URL /en/productsは、/en-Latn-US/productsよりも読みやすくなります。

ロケール識別子の比較

最小化は、2つのロケール識別子が同じロケールを表すかどうかを判断するのに役立ちます。

function areLocalesEquivalent(locale1String, locale2String) {
  const locale1 = new Intl.Locale(locale1String).minimize();
  const locale2 = new Intl.Locale(locale2String).minimize();

  return locale1.toString() === locale2.toString();
}

console.log(areLocalesEquivalent("en", "en-Latn-US"));
// Output: true

console.log(areLocalesEquivalent("en-US", "en-Latn-US"));
// Output: true

console.log(areLocalesEquivalent("en-US", "en-GB"));
// Output: false

最小化により、直接比較を可能にする正規形式が生成されます。

ユーザー入力の正規化

ユーザーまたは外部システムからロケール識別子を受け入れる場合、それらを標準形式に最小化します。

function normalizeLocale(localeString) {
  try {
    const locale = new Intl.Locale(localeString);
    return locale.minimize().toString();
  } catch (error) {
    return null;
  }
}

console.log(normalizeLocale("en-US"));
// Output: "en"

console.log(normalizeLocale("en-Latn-US"));
// Output: "en"

console.log(normalizeLocale("en-GB"));
// Output: "en-GB"

この関数は、同じロケールのさまざまな形式を受け入れ、一貫した表現を返します。

minimizeと他のロケール操作の組み合わせ

minimize()メソッドは、他のIntl.Locale機能と連携して、柔軟なロケール処理を実現します。

ロケールプロパティ変更後の最小化

コンポーネントからロケールを構築する際、不要な部分を削除するために最小化します。

const locale = new Intl.Locale("en", {
  region: "US",
  script: "Latn"
});

const minimized = locale.minimize();
console.log(minimized.baseName);
// Output: "en"

これにより、最終的な識別子が入力コンポーネントで許容される範囲で可能な限りコンパクトになります。

最小化中の拡張の保持

拡張は最小化中も維持されるため、フォーマット設定を保持しながらコアコンポーネントを最小化できます。

function createCompactLocaleWithPreferences(language, region, preferences) {
  const locale = new Intl.Locale(language, {
    region: region,
    ...preferences
  });

  return locale.minimize().toString();
}

const localeString = createCompactLocaleWithPreferences("en", "US", {
  hourCycle: "h23",
  calendar: "gregory"
});

console.log(localeString);
// Output: "en-u-ca-gregory-hc-h23"

コアコンポーネントはenに最小化されますが、カレンダーと時刻表記の拡張は維持されます。