php NumberFormatter:在不同区域设置中带有减号的奇怪行为

qoefvg9y  于 10个月前  发布在  PHP
关注(0)|答案(3)|浏览(90)

我遇到了一个问题,Symfony/Form 在引擎盖下使用NumberFormatter来格式化NumberType字段。我们的项目是多语言的,对于每个国家,我们使用不同的语言环境。
$formatter->format()返回负数的不同负号。举例来说:

$formatter = new \NumberFormatter('en', \NumberFormatter::DECIMAL);
$value = $formatter->format('-150');
var_dump($value); // string(4) "-150"

$formatter = new \NumberFormatter('lt', \NumberFormatter::DECIMAL);
$value = $formatter->format('-150');
var_dump($value); // string(6) "−150" <-- here is the problem

正如您所看到的,NumberFormatter将减号更改为其他符号。
为什么这对我很重要?因为页面上的一些元素是用JavaScript生成的,js无法解析−150 number并返回NaN
有人能解释一下这种行为的原因吗?以及如何从NumberFormatter中为 lt locale获取正确的减号?

eiee3dmh

eiee3dmh1#

我找到解决办法了 Symfony/Form 有一个很棒的功能,就是添加一个view transformers,它会在呈现表单元素之前呈现。
以下是我的FormType

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('amount', NumberType::class, array(
        'required' => true,
        'scale' => 4,
    ));

    $builder->get('amount')->addViewTransformer(new CallbackTransformer(
        function ($forward) {
            // Transform the lithuanian minus sign to the normal minus sign.
            return preg_replace('/\x{2212}/u', '-', $forward);
        },
        function ($reverse) {
            return $reverse;
        }
    ));

    // others form elements...
}

这种方法允许覆盖\Symfony\Component\Form\Extension\Core\Type\NumberType的默认视图Transformer,该转换器添加了特定的减号。

$builder->addViewTransformer(new NumberToLocalizedStringTransformer(
    $options['scale'],
    $options['grouping'],
    $options['rounding_mode'],
    $options['html5'] ? 'en' : null
));

需要说明的是,在自定义表单中添加的view Transformer的优先级高于任何其他合并的transformer。
它不能解决NumberFormatter的问题,但可以帮助我解决我的问题。

pdsfdshx

pdsfdshx2#

如何转换为ascii?

$formatter = new \NumberFormatter('lt', \NumberFormatter::DECIMAL);
$value = $formatter->format('-150');
$valueAsAscii = iconv('utf8', 'ascii//translit', $value);

var_dump($value);
var_dump($valueAsAscii);

正在工作example

输出

string(6) "−150"
string(4) "-150"

参考文献

jhkqcmku

jhkqcmku3#

这里真实的的问题是,根据给定的语言环境,NumberFormatter的输出应该是人类可读的,而不一定是可解析为数字的。\u2212是表示减号的合适Unicode符号,但实际上只有少数地区使用它。
您可以通过覆盖符号来修复此特定问题:

$formatter = new \NumberFormatter('lt', \NumberFormatter::DECIMAL);
$formatter->setSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL, '-');
$value = $formatter->format('-150');
var_dump($value); // string(4) "-150"

然而,考虑千位分隔符或小数分隔符,它们也不一定在JavaScript中解析:

$formatter = new \NumberFormatter('lt', \NumberFormatter::DECIMAL);
$formatter->setSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL, '-');
$value = $formatter->format('-150000.5');
var_dump($value); // string(11) "-150 000,5"

您也可以覆盖这些符号,但这里的要点是,您可能应该根据用户的区域设置提供一个人类可读的版本,并提供一个单独的机器可读版本供JavaScript解析。
如果你仍然想使用NumberFormatter来输出机器可读的版本,你可以使用'en'环境,但你仍然需要覆盖分组分隔符:

$machineFormatter = new \NumberFormatter('en', \NumberFormatter::DECIMAL);
$machineFormatter->setSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL, '');

相关问题