パーセント記号を使用したパーセンテージのフォーマット方法

Intl.NumberFormatのパーセントスタイルを使用して、ロケールに適したフォーマットでパーセンテージとして数値を表示する

はじめに

パーセンテージは、完了進捗の表示から金利や割引額の表示まで、多くのアプリケーションに登場します。数字とパーセント記号を連結するような単純なアプローチは基本的なケースでは機能しますが、異なる言語や地域でのパーセンテージのフォーマット方法を考慮していません。トルコ語では、パーセント記号は数字の前に表示され、%50のようになります。フランス語では、数字とパーセント記号の間にスペースが入り、50 %となります。アラビア語では、標準的な%記号の代わりに特別なパーセント文字を使用します。

JavaScriptのIntl.NumberFormat APIは、これらのフォーマットの違いを自動的に処理します。styleオプションを"percent"に設定することで、ロケール固有のコードを書くことなく、どのロケールでも正しくフォーマットされたパーセンテージを取得できます。

パーセンテージのフォーマットがロケールによって異なる理由

パーセント記号の位置とスペースのルールはロケールによって異なります。英語ではパーセント記号を数字の直後にスペースなしで配置します。フランス語ではパーセント記号の前にスペースを追加します。トルコ語ではパーセント記号を数字の前に配置します。これらのバリエーションは、各言語の自然な読み方とルールを反映しています。

フォーマットの違いは記号の配置だけにとどまりません。一部のロケールではパーセント記号に異なる文字を使用します。アラビア語ではASCIIパーセント記号の代わりに٪(U+066A)を使用します。小数点区切り文字と桁区切り文字も、通常の数値フォーマットと同様にロケールによって異なります。

文字列連結でパーセンテージのフォーマットをハードコードすると、すべてのユーザーに単一のロケールのフォーマットを強制することになります。フランス語のユーザーが50 %ではなく50%を見ると不自然なフォーマットを体験することになります。トルコ語のユーザーが%50を期待しているのに50%を見ると同じ問題に直面します。IntlAPIはこの問題を解決し、各ロケールに対して正しいフォーマットルールを適用します。

数値をパーセンテージとしてフォーマットする

Intl.NumberFormatstyleオプションは、数値を通常の数値、通貨、パーセンテージ、または単位としてフォーマットするかを制御します。style"percent"に設定すると、数値をパーセンテージとしてフォーマットします。

const formatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(formatter.format(0.75));
// 出力: "75%"

console.log(formatter.format(0.05));
// 出力: "5%"

console.log(formatter.format(1.5));
// 出力: "150%"

フォーマッターは自動的に入力値を100倍し、パーセント記号を追加します。つまり、フォーマッターには小数値を渡します。0.75の値は75%になります。1.5の値は150%になります。

この小数入力の規則は、数学やほとんどのプログラミング計算におけるパーセンテージの扱い方と一致しています。成長率や完了率などのパーセンテージを計算する場合、結果は通常0から1の間の小数値になります。この値を最初にパーセンテージに変換せずに、直接フォーマッターに渡すことができます。

小数入力値の理解

パーセンテージフォーマッターは、1.0が100%を表す小数入力を想定しています。この設計選択は、コード内でパーセンテージが計算される方法と一致しています。

const formatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

// 完了率の計算
const completed = 75;
const total = 100;
const ratio = completed / total;

console.log(formatter.format(ratio));
// 出力: "75%"

// 成長率の計算
const oldValue = 1000;
const newValue = 1250;
const growth = (newValue - oldValue) / oldValue;

console.log(formatter.format(growth));
// 出力: "25%"

completed を total で割ると、0.75 が得られます。これを直接フォーマッターに渡すと、75%と表示されます。変化量を元の値で割って成長率を計算すると、0.25が得られます。フォーマッターはこれを25%と表示します。

このアプローチにより、開発者がフォーマット前に100を掛けて、75%ではなく7500%のような値になるという一般的なエラーを防ぎます。フォーマッターが乗算を処理するため、コード内では自然な小数表現で作業できます。

0~1の範囲外の値の処理

パーセンテージは0%から100%の間の値に限定されません。ゼロ未満の値は負のパーセンテージを表します。1.0を超える値は100%を超えるパーセンテージを表します。

const formatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(formatter.format(-0.15));
// 出力: "-15%"

console.log(formatter.format(2.5));
// 出力: "250%"

console.log(formatter.format(0.0025));
// 出力: "0%"

負の値はマイナス記号付きでフォーマットされます。これは減少、損失、または負の成長率を表示する際に役立ちます。1.0より大きい値は100%を超えるパーセンテージとしてフォーマットされ、これは前年比成長率や新しい値がベースラインを超える比較を表示する際によく使用されます。

非常に小さい値はデフォルトの精度設定により0%に丸められることがあります。0.0025という値は0.25%を表しますが、パーセンテージのデフォルトの最大小数桁数が0であるため、0%と表示されます。次のレッスンでは、これらの小さなパーセンテージを正確に表示するための小数点以下の桁数の制御について説明します。

異なるロケールでのパーセンテージのフォーマット

パーセンテージのフォーマットは指定したロケールに適応します。各ロケールは記号の配置、スペース、シンボルに独自のルールを適用します。

const enFormatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(enFormatter.format(0.5));
// 出力: "50%"

const frFormatter = new Intl.NumberFormat("fr-FR", {
  style: "percent"
});

console.log(frFormatter.format(0.5));
// 出力: "50 %"

const trFormatter = new Intl.NumberFormat("tr-TR", {
  style: "percent"
});

console.log(trFormatter.format(0.5));
// 出力: "%50"

const arFormatter = new Intl.NumberFormat("ar-SA", {
  style: "percent"
});

console.log(arFormatter.format(0.5));
// 出力: "٪50"

英語では、パーセント記号は数字の直後に配置されます。フランス語ではパーセント記号の前にスペースが追加されます。トルコ語ではパーセント記号が数字の前に配置されます。アラビア語ではアラビア語のパーセント記号が使用され、右から左への文字方向に従います。

これらの違いはロケールパラメータに基づいて自動的に発生します。異なるロケールを処理するための条件付きロジックを記述する必要はありません。ユーザーのロケールでフォーマッタを作成すれば、そのロケールに適した正しい出力が生成されます。

パーセンテージの小数点以下の桁数を制御する

デフォルトでは、パーセンテージのフォーマットは小数点以下の桁数を表示しません。0.755のような値は四捨五入されて76%と表示されます。minimumFractionDigitsmaximumFractionDigitsオプションを使用して、小数点以下の桁数を制御できます。

const defaultFormatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(defaultFormatter.format(0.755));
// 出力: "76%"

const oneDecimalFormatter = new Intl.NumberFormat("en-US", {
  style: "percent",
  minimumFractionDigits: 1,
  maximumFractionDigits: 1
});

console.log(oneDecimalFormatter.format(0.755));
// 出力: "75.5%"

const twoDecimalFormatter = new Intl.NumberFormat("en-US", {
  style: "percent",
  minimumFractionDigits: 2,
  maximumFractionDigits: 2
});

console.log(twoDecimalFormatter.format(0.755));
// 出力: "75.50%"

minimumFractionDigitsオプションは、フォーマッタが少なくともその桁数の小数点以下を表示することを保証し、必要に応じて末尾にゼロを追加します。maximumFractionDigitsオプションは小数点以下の桁数を制限し、必要に応じて値を四捨五入します。

両方を同じ値に設定することで、すべてのパーセンテージで一貫したフォーマットを確保できます。これは、すべてのパーセンテージを視覚的に揃えたい表やグラフで役立ちます。

次のレッスンでは、末尾のゼロの処理や非常に小さなパーセンテージを正確に表示する方法など、小数点の制御についてより詳しく説明します。

パーセンテージと符号表示の組み合わせ

パーセンテージのフォーマットはsignDisplayオプションと連携して、正のパーセンテージにプラス記号を明示的に表示できます。これは、符号が方向を示す変化や成長率を表示する際に役立ちます。

const formatter = new Intl.NumberFormat("en-US", {
  style: "percent",
  signDisplay: "always",
  minimumFractionDigits: 1,
  maximumFractionDigits: 1
});

console.log(formatter.format(0.0523));
// 出力: "+5.2%"

console.log(formatter.format(-0.0341));
// 出力: "-3.4%"

console.log(formatter.format(0));
// 出力: "+0.0%"

signDisplayオプションは前のレッスンで説明しました。パーセンテージのフォーマットと組み合わせると、パーセンテージが増加を表すのか減少を表すのかが明確になります。明示的なプラス記号がなければ、増加と減少の両方が表示されるコンテキストでは、正のパーセンテージがあいまいになる可能性があります。

パーセンテージとしてのゼロのフォーマット

ゼロはデフォルトで0%としてフォーマットされます。ゼロの扱い方は、ゼロが変化なし、値なし、または意味のある測定値を表すかによって異なります。

const formatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(formatter.format(0));
// 出力: "0%"

const withSignFormatter = new Intl.NumberFormat("en-US", {
  style: "percent",
  signDisplay: "exceptZero"
});

console.log(withSignFormatter.format(0.05));
// 出力: "+5%"

console.log(withSignFormatter.format(0));
// 出力: "0%"

signDisplay: "exceptZero"を使用すると、正と負のパーセンテージには符号が表示されますが、ゼロには符号が省略されます。これにより、ゼロが変化なしなどの中立状態を表す場合に視覚的に区別できます。

パーセンテージフォーマットを使用するタイミング

比率、レート、または自然にパーセンテージとして表現される割合を表示する場合は、パーセンテージフォーマットを使用してください。一般的な使用例には、完了進捗、金利、割引額、成長率、成功率、確率値などがあります。

ロケールに関係なくパーセント記号が特定の位置に表示される必要がある場合は、パーセンテージフォーマットを使用しないでください。デザイン上、パーセント記号が視覚的な一貫性のために常に右側に表示される必要がある場合は、代わりに文字列連結を使用してください。ただし、これは国際化の正確性を犠牲にします。

また、すでに100を掛けた値を扱う場合もパーセンテージフォーマットを避けてください。データが75が75%を意味するような整数としてパーセンテージを保存している場合は、フォーマット前に100で割るか、パーセント記号を手動で追加した通常の数値フォーマットを使用してください。

パーセンテージフォーマッタの精度を理解する

パーセンテージフォーマットのデフォルト精度は小数点以下0桁です。これは入力値に基づいて精度を調整する通常の数値フォーマットとは異なります。パーセンテージフォーマッタは、小数点以下の桁数オプションを明示的に設定しない限り、値を整数パーセンテージに丸めます。

const formatter = new Intl.NumberFormat("en-US", {
  style: "percent"
});

console.log(formatter.format(0.755));
// 出力: "76%"

console.log(formatter.format(0.754));
// 出力: "75%"

console.log(formatter.format(0.001));
// 出力: "0%"

値は最も近い整数パーセンテージに丸められます。0.755の値は76%に丸められます。0.754の値は75%に丸められます。0.001のような非常に小さい値は0%に丸められます。

小さなパーセンテージや小数点以下のパーセンテージを表示する必要がある場合は、最大小数点以下桁数を増やしてください。次のレッスンでは精度制御について詳しく説明します。