PHP 中的 NumberFormatter 与 JS 中的 NumberFormat
NumberFormatter in PHP vs NumberFormat in JS
我在尝试格式化货币时似乎得到了非常不一致的结果。在 PHP 中,我使用 https://www.php.net/manual/en/class.numberformatter.php。我有以下演示代码:
$number = 5125.99;
echo getInternationallyFormattedCurrency($number, 'tl-PH', 'PHP');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'fil-PH', 'PHP');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'en-US', 'PHP');
echo '<br/>';
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'tl_PH', 'USD');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'fil_PH', 'USD');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'en_US', 'USD');
echo '<br/>';
当我在我的本地主机上 运行 这个(是 PHP 版本 7.3.7,但我更新以匹配我的服务器的 PHP 版本 7.3.12 - ICU 版本 64.2),我明白了:
₱5,125.99
₱5,125.99
PHP 5,125.99
,125.99
,125.99
,125.99
然而,当我 运行 它在我的服务器上时(PHP 版本 7.3.12 - ICU 版本 4.2.1),我得到这个:
₱ 5125.99
₱ 5125.99
₱5,125.99
$ 5125.99
$ 5125.99
,125.99
为什么不一样?哪一个实际上是正确的?由于 ICU 版本较高,我猜是我的本地机器?
我也需要 JS 的完全相同的功能。因此,在 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat 上,我放置了以下等效代码:
var number = 5125.99;
console.log(new Intl.NumberFormat('tl-PH', { style: 'currency', currency: 'PHP' }).format(number));
console.log(new Intl.NumberFormat('fil-PH', { style: 'currency', currency: 'PHP' }).format(number));
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'PHP' }).format(number));
console.log(new Intl.NumberFormat('tl-PH', { style: 'currency', currency: 'USD' }).format(number));
console.log(new Intl.NumberFormat('fil-PH', { style: 'currency', currency: 'USD' }).format(number));
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(number));
我明白了:
> "PHP 5,125.99"
> "₱5,125.99"
> "PHP 5,125.99"
> ",125.99"
> ",125.99"
> ",125.99"
所以 - 这又是一个结果。 我需要一种方法来格式化 PHP 和 JS 之间的货币一致性。我该怎么做?
更新 1:
我本地机器的 ICU 版本是 64.2 而我的服务器是 4.2.1。我会看看我的托管服务提供商是否可以将 ICU 版本更新到最新版本。这可能解释了我的本地机器输出与我的服务器输出之间的差异。
仍然不确定为什么 JS 的行为不同。
更新 2:
我的托管公司说因为 cPanel,我需要坚持使用 ICU 4.2.1 版。虽然 cPanel 有一些关于如何升级 ICU 版本的提示,但显然不建议这样做。
- https://forums.cpanel.net/threads/internationalization-extension-version-upgrade.612607/
- https://forums.cpanel.net/threads/install-php71-php-intl-with-a-more-recent-version-of-icu.620979/
更新 3:
我现在正在考虑让我的 JS 对将处理数字格式的 PHP 方法进行 Ajax 调用,这样我就可以确定我得到相同的格式输出.不过,感觉像是一个缓慢而昂贵的解决方案。
我试过这种方法:
<?php
function process($locale, $value, $currency){
$fmt = numfmt_create($locale, NumberFormatter::CURRENCY );
echo "Locale: $locale, Currency: $currency, Result: " . $fmt->formatCurrency($value, $currency) . "\n";
}
$locales = ["tl_PH","fil_PH", "en_US"];
$currencies = ["USD", "PHP"];
$value = 5125.99;
foreach ($locales as $locale){
foreach ($currencies as $currency){
process($locale, $value, $currency);
}
}
并得到一致的结果:
Locale: tl_PH, Currency: USD, Result: ,125.99
Locale: tl_PH, Currency: PHP, Result: ₱5,125.99
Locale: fil_PH, Currency: USD, Result: ,125.99
Locale: fil_PH, Currency: PHP, Result: ₱5,125.99
Locale: en_US, Currency: USD, Result: ,125.99
Locale: en_US, Currency: PHP, Result: PHP 5,125.99
因此,为了 100% 安全,我建议为格式化目的创建一个小型服务器端组件,这样您就可以传递区域设置、值和货币,并且无论是后端还是前端,都始终具有相同的结果需要格式化的字符串。
另外,请注意 tl-PH
和 tl_PH
是不一样的。始终如一地使用 tl_PH
、fil_PH
和 en_US
。
只是一个想法...但是要在两种不同的语言中获得一致的结果,我建议使用完全相同的库代码。
如果你使用 https://github.com/phpv8/v8js to run Intl.NumberFormat on PHP side? There's also an example here https://github.com/phpv8/v8js/issues/182
我可能会选择这条路来让一切保持一致
从 php 方面来看,由于 php 依赖于底层 C 库,这是不一致的地方(在编译时):
The note about different formatting actually does not depend on the
PHP version but on the version of the icu library that PHP is
compiled against because this library has a database with formatting
rules for the different locales.
https://www.php.net/manual/en/numberformatter.formatcurrency.php#116984
php 无事可做,我们必须格外小心。
以下是自己测试后的一些注意事项!
那些片段 returns 格式的数字(不会 return 科学记数法),而是 四舍五入 ,这是不希望的。它负责分组的数千个,我们可以选择显示或不显示。在我看来,这是一个坏主意,我想避免使用它们。
从javascript,有a lot of options:
var number = 5125.9566654332455556679;
console.log("\n",
number.toLocaleString('fil-PH', {maximumFractionDigits:5, style:'currency', currency:'PHP', useGrouping:true})
,"\n",
number.toLocaleString('fil-PH', {maximumFractionDigits:5, style:'currency', currency:'PHP', useGrouping:false})
,"\n",
number.toLocaleString('fullwide', {maximumFractionDigits:5, style:'currency', currency:'USD', useGrouping:true})
,"\n",
number.toLocaleString('fullwide', {maximumFractionDigits:5, style:'currency', currency:'USD', currencyDisplay:'symbol', useGrouping:false})
)
示例输出:
₱5,125.95667
₱5125.95667
,125.95667
25.95667
从php,为了获得类似的东西,我发现对符号使用关联数组更容易。该代码在任何地方都可以相同地工作。
<?php
$number = 5125.9566654332455556679;
$a = new \NumberFormatter("en-US", \NumberFormatter::CURRENCY);
$a = new \NumberFormatter("tl-PH", \NumberFormatter::CURRENCY);
echo $a->format($number);
echo PHP_EOL;
$symbols = (object)["PHP"=>"₱", "USD"=>"$"];
$precision = 5;
echo number_format($number,$precision,'.','');
echo PHP_EOL;
echo $symbols->PHP . number_format($number,$precision);
echo PHP_EOL;
echo $symbols->USD . number_format($number,$precision,'.','');
echo PHP_EOL;
示例输出。注意使用 NumberFormatter(). It's in most cases unwanted, it's more flexible to use just number_format().
的舍入
₱5,125.96
5125.95667
₱5,125.95667
25.95667
我在尝试格式化货币时似乎得到了非常不一致的结果。在 PHP 中,我使用 https://www.php.net/manual/en/class.numberformatter.php。我有以下演示代码:
$number = 5125.99;
echo getInternationallyFormattedCurrency($number, 'tl-PH', 'PHP');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'fil-PH', 'PHP');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'en-US', 'PHP');
echo '<br/>';
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'tl_PH', 'USD');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'fil_PH', 'USD');
echo '<br/>';
echo getInternationallyFormattedCurrency($number, 'en_US', 'USD');
echo '<br/>';
当我在我的本地主机上 运行 这个(是 PHP 版本 7.3.7,但我更新以匹配我的服务器的 PHP 版本 7.3.12 - ICU 版本 64.2),我明白了:
₱5,125.99
₱5,125.99
PHP 5,125.99
,125.99
,125.99
,125.99
然而,当我 运行 它在我的服务器上时(PHP 版本 7.3.12 - ICU 版本 4.2.1),我得到这个:
₱ 5125.99
₱ 5125.99
₱5,125.99
$ 5125.99
$ 5125.99
,125.99
为什么不一样?哪一个实际上是正确的?由于 ICU 版本较高,我猜是我的本地机器?
我也需要 JS 的完全相同的功能。因此,在 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat 上,我放置了以下等效代码:
var number = 5125.99;
console.log(new Intl.NumberFormat('tl-PH', { style: 'currency', currency: 'PHP' }).format(number));
console.log(new Intl.NumberFormat('fil-PH', { style: 'currency', currency: 'PHP' }).format(number));
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'PHP' }).format(number));
console.log(new Intl.NumberFormat('tl-PH', { style: 'currency', currency: 'USD' }).format(number));
console.log(new Intl.NumberFormat('fil-PH', { style: 'currency', currency: 'USD' }).format(number));
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(number));
我明白了:
> "PHP 5,125.99"
> "₱5,125.99"
> "PHP 5,125.99"
> ",125.99"
> ",125.99"
> ",125.99"
所以 - 这又是一个结果。 我需要一种方法来格式化 PHP 和 JS 之间的货币一致性。我该怎么做?
更新 1:
我本地机器的 ICU 版本是 64.2 而我的服务器是 4.2.1。我会看看我的托管服务提供商是否可以将 ICU 版本更新到最新版本。这可能解释了我的本地机器输出与我的服务器输出之间的差异。
仍然不确定为什么 JS 的行为不同。
更新 2:
我的托管公司说因为 cPanel,我需要坚持使用 ICU 4.2.1 版。虽然 cPanel 有一些关于如何升级 ICU 版本的提示,但显然不建议这样做。
- https://forums.cpanel.net/threads/internationalization-extension-version-upgrade.612607/
- https://forums.cpanel.net/threads/install-php71-php-intl-with-a-more-recent-version-of-icu.620979/
更新 3:
我现在正在考虑让我的 JS 对将处理数字格式的 PHP 方法进行 Ajax 调用,这样我就可以确定我得到相同的格式输出.不过,感觉像是一个缓慢而昂贵的解决方案。
我试过这种方法:
<?php
function process($locale, $value, $currency){
$fmt = numfmt_create($locale, NumberFormatter::CURRENCY );
echo "Locale: $locale, Currency: $currency, Result: " . $fmt->formatCurrency($value, $currency) . "\n";
}
$locales = ["tl_PH","fil_PH", "en_US"];
$currencies = ["USD", "PHP"];
$value = 5125.99;
foreach ($locales as $locale){
foreach ($currencies as $currency){
process($locale, $value, $currency);
}
}
并得到一致的结果:
Locale: tl_PH, Currency: USD, Result: ,125.99
Locale: tl_PH, Currency: PHP, Result: ₱5,125.99
Locale: fil_PH, Currency: USD, Result: ,125.99
Locale: fil_PH, Currency: PHP, Result: ₱5,125.99
Locale: en_US, Currency: USD, Result: ,125.99
Locale: en_US, Currency: PHP, Result: PHP 5,125.99
因此,为了 100% 安全,我建议为格式化目的创建一个小型服务器端组件,这样您就可以传递区域设置、值和货币,并且无论是后端还是前端,都始终具有相同的结果需要格式化的字符串。
另外,请注意 tl-PH
和 tl_PH
是不一样的。始终如一地使用 tl_PH
、fil_PH
和 en_US
。
只是一个想法...但是要在两种不同的语言中获得一致的结果,我建议使用完全相同的库代码。
如果你使用 https://github.com/phpv8/v8js to run Intl.NumberFormat on PHP side? There's also an example here https://github.com/phpv8/v8js/issues/182
我可能会选择这条路来让一切保持一致
从 php 方面来看,由于 php 依赖于底层 C 库,这是不一致的地方(在编译时):
The note about different formatting actually does not depend on the PHP version but on the version of the icu library that PHP is compiled against because this library has a database with formatting rules for the different locales. https://www.php.net/manual/en/numberformatter.formatcurrency.php#116984
php 无事可做,我们必须格外小心。
以下是自己测试后的一些注意事项!
那些片段 returns 格式的数字(不会 return 科学记数法),而是 四舍五入 ,这是不希望的。它负责分组的数千个,我们可以选择显示或不显示。在我看来,这是一个坏主意,我想避免使用它们。
从javascript,有a lot of options:
var number = 5125.9566654332455556679;
console.log("\n",
number.toLocaleString('fil-PH', {maximumFractionDigits:5, style:'currency', currency:'PHP', useGrouping:true})
,"\n",
number.toLocaleString('fil-PH', {maximumFractionDigits:5, style:'currency', currency:'PHP', useGrouping:false})
,"\n",
number.toLocaleString('fullwide', {maximumFractionDigits:5, style:'currency', currency:'USD', useGrouping:true})
,"\n",
number.toLocaleString('fullwide', {maximumFractionDigits:5, style:'currency', currency:'USD', currencyDisplay:'symbol', useGrouping:false})
)
示例输出:
₱5,125.95667
₱5125.95667
,125.95667
25.95667
从php,为了获得类似的东西,我发现对符号使用关联数组更容易。该代码在任何地方都可以相同地工作。
<?php
$number = 5125.9566654332455556679;
$a = new \NumberFormatter("en-US", \NumberFormatter::CURRENCY);
$a = new \NumberFormatter("tl-PH", \NumberFormatter::CURRENCY);
echo $a->format($number);
echo PHP_EOL;
$symbols = (object)["PHP"=>"₱", "USD"=>"$"];
$precision = 5;
echo number_format($number,$precision,'.','');
echo PHP_EOL;
echo $symbols->PHP . number_format($number,$precision);
echo PHP_EOL;
echo $symbols->USD . number_format($number,$precision,'.','');
echo PHP_EOL;
示例输出。注意使用 NumberFormatter(). It's in most cases unwanted, it's more flexible to use just number_format().
的舍入₱5,125.96
5125.95667
₱5,125.95667
25.95667