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

问题描述 投票:0回答:3

我遇到了 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
数字并返回
NaN

有人可以解释这种行为的原因以及如何从 NumberFormatter 获得

lt
语言环境的正确减号吗?

javascript php locale number-formatting
3个回答
0
投票

我找到了解决办法。 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
的默认视图转换器,添加特定的减号。

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

需要明确的是,以自定义表单添加的视图转换器比任何其他合并的转换器具有更高的优先级。

它通常不能解决

NumberFormatter
的问题,但可以帮助我解决我的问题。


0
投票

转换为ascii怎么样?

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

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

工作示例

输出

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

参考资料


0
投票

这里真正的问题是,根据给定的语言环境,

NumberFormatter
的输出应该是人类可读的,并且不一定可以解析为数字。

可以通过覆盖符号来解决此特定问题:

$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 解析的单独的机器可读版本。

© www.soinside.com 2019 - 2024. All rights reserved.