Back

軽量な国際化:ライブラリをIntl APIで置き換える

軽量な国際化:ライブラリをIntl APIで置き換える

JavaScriptバンドルにMoment.jsが含まれていませんか?日付フォーマットだけで280KBです。ネイティブのJavaScript Intl APIなら?0キロバイトです。この大きな違いは、帯域幅コストで数千ドル、読み込み時間で数秒の差を生み、コンバージョン率に直接影響します。

現代のWebアプリケーションには重い国際化ライブラリは必要ありません。JavaScript Intl APIは、日付フォーマット、数値フォーマット、通貨フォーマット、複数形処理、文字列ソートを提供し、すべてブラウザに組み込まれています。この記事では、Moment.js、date-fns、numeral.jsなどのライブラリをネイティブソリューションで置き換え、パフォーマンスを向上させ、複雑さを軽減する方法を説明します。

重要なポイント

  • Intl APIはバンドルサイズを0キロバイトに抑える一方、Moment.jsなどのライブラリは280KBを追加
  • ネイティブブラウザサポートは99.5%以上のユーザーをカバー—ポリフィルは不要
  • 日付フォーマット、数値フォーマット、複数形処理を組み込みAPIで置き換え
  • 本番環境での最適なパフォーマンスのためにフォーマッターインスタンスをキャッシュ

重いライブラリをJavaScript Intl APIで置き換える理由

バンドルサイズの問題

人気の国際化ライブラリはアプリケーションに大きな負荷を加えます:

  • Moment.js:280KB(gzip圧縮で67KB)
  • date-fns:一般的な機能で75KB(gzip圧縮で17KB)
  • numeral.js:72KB(gzip圧縮で18KB)

これらの数値は、ロケールデータを含めるとさらに増加します。JavaScript Intl APIは追加バイト数ゼロ—すでにブラウザに組み込まれています。

2025年のネイティブブラウザサポート

ブラウザ互換性はもはや懸念事項ではありません。Intl APIはすべての現代ブラウザで汎用的にサポートされています。Internet ExplorerとOpera Miniのみがサポートを欠いており、これらは世界的使用率の0.5%未満を占めるブラウザです。あなたのユーザーはすでにこれらのAPIを持っています。

Intl.DateTimeFormatによる日付と時刻のフォーマット

基本的な日付フォーマット

Moment.jsの日付フォーマットを置き換える:

// 以前:Moment.js
moment().format('MMMM DD, YYYY'); // "October 3, 2025"

// 以後:ネイティブIntl
new Intl.DateTimeFormat('en-US', {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
}).format(new Date()); // "October 3, 2025"

高度なオプション

ネイティブAPIはタイムゾーンと複雑なフォーマットを処理します:

new Intl.DateTimeFormat('en-GB', {
  dateStyle: 'full',
  timeStyle: 'short',
  timeZone: 'Europe/London'
}).format(new Date()); // "Friday, 3 October 2025 at 15:30"

ライブラリなしの相対時間フォーマット

moment.fromNow()をネイティブ相対時間で置き換える:

// 以前:Moment.js
moment().subtract(2, 'hours').fromNow(); // "2 hours ago"

// 以後:ネイティブIntl
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
rtf.format(-2, 'hour'); // "2 hours ago"
rtf.format(1, 'day'); // "tomorrow"

このAPIは複数形処理と多言語対応のローカライゼーションを自動的に処理します。

シンプルな数値と通貨のフォーマット

数値フォーマット

numeral.jsをネイティブ数値フォーマットで置き換える:

// 以前:numeral.js
numeral(1234567.89).format('0,0.00'); // "1,234,567.89"

// 以後:ネイティブIntl
new Intl.NumberFormat('en-US').format(1234567.89); // "1,234,567.89"
new Intl.NumberFormat('de-DE').format(1234567.89); // "1.234.567,89"

通貨フォーマット

ネイティブ通貨フォーマットは外部依存関係を排除します:

const formatter = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
});
formatter.format(1234.5); // "$1,234.50"

// 日本円(小数点なし)
new Intl.NumberFormat('ja-JP', {
  style: 'currency',
  currency: 'JPY'
}).format(1234); // "¥1,234"

Intl.PluralRulesによるスマートな複数形処理

複雑な条件ロジックをネイティブ複数形処理で置き換える:

const pr = new Intl.PluralRules('en-US', { type: 'ordinal' });
const suffixes = { one: 'st', two: 'nd', few: 'rd', other: 'th' };

function ordinal(n) {
  const rule = pr.select(n);
  return `${n}${suffixes[rule]}`;
}

ordinal(1); // "1st"
ordinal(22); // "22nd"
ordinal(103); // "103rd"

Intl.Collatorによるロケール対応文字列ソート

カスタムソートをネイティブロケール対応照合で置き換える:

// 数値対応ソート
const collator = new Intl.Collator('en', { numeric: true });
['item2', 'item10', 'item1'].sort(collator.compare);
// ["item1", "item2", "item10"]

// ドイツ語ソート(äはaの後に来る)
const germanCollator = new Intl.Collator('de');
['Müller', 'Mueller', 'Maler'].sort(germanCollator.compare);
// ["Maler", "Mueller", "Müller"]

本番環境でのベストプラクティス

フォーマッターキャッシング

フォーマッターを一度作成して再利用する:

// パフォーマンスのためにフォーマッターをキャッシュ
const formatters = new Map();

function getCurrencyFormatter(locale, currency) {
  const key = `${locale}-${currency}`;
  if (!formatters.has(key)) {
    formatters.set(key, new Intl.NumberFormat(locale, {
      style: 'currency',
      currency
    }));
  }
  return formatters.get(key);
}

エラーハンドリング

無効な入力に対するフォールバックを実装する:

function safeFormat(date, locale = 'en-US', options = {}) {
  try {
    return new Intl.DateTimeFormat(locale, options).format(date);
  } catch (error) {
    console.warn(`ロケール${locale}でのフォーマットに失敗しました`, error);
    return new Intl.DateTimeFormat('en-US', options).format(date);
  }
}

制限と将来の考慮事項

Intl APIはフォーマットに優れていますが、日付の算術演算は処理しません。日数の追加や日付間の差分を求めるような計算には、今後のTemporal APIまたは軽量な計算ライブラリが必要です。

以下が必要な場合のみライブラリの保持を検討してください:

  • 複雑な日付算術演算
  • 任意の日付文字列の解析
  • IE11以下のレガシーブラウザサポート

まとめ

JavaScript Intl APIは国際化をバンドルサイズの負担からゼロコスト機能へと変革します。Moment.js、date-fns、numeral.jsをネイティブAPIで置き換えることで、依存関係を排除し、パフォーマンスを向上させ、メンテナンスを簡素化できます。

今日から移行を開始しましょう:これらのライブラリのフォーマットのみの使用を特定し、Intlで置き換えてください。ユーザーはより高速な読み込み時間を体験し、アプリケーションはより保守しやすくなります。最良のコードは、出荷する必要のないコードです。

よくある質問

Intl APIはフォーマットを処理しますが、日数の追加や差分の計算などの日付算術演算は処理しません。これらの操作には、ネイティブDateメソッドを使用するか、Temporal APIを待つ必要があります。ほとんどのアプリケーションはフォーマットのためだけにライブラリを使用するため、Intlは完璧な置き換えとなります。

Moment.jsを削除するだけで280KBを節約でき、低速接続では読み込み時間を1-3秒短縮できます。ネイティブAPIはブラウザレベルで最適化されているため、ランタイムパフォーマンスも向上し、JavaScriptライブラリより2-3倍高速に動作することがよくあります。

すべての現代ブラウザがIntl APIをサポートしています。Internet ExplorerとOpera Miniのみがサポートを欠いており、ユーザーの0.5%未満を占めています。これらのブラウザをサポートする必要がある場合は、すべてのユーザーに重いライブラリを出荷するのではなく、それらのユーザーにのみポリフィルを使用してください。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay