Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Currency formatting is wrong with RTL layout and dollar sign #20394

Closed
mehmetf opened this issue Aug 9, 2018 · 16 comments
Closed

Currency formatting is wrong with RTL layout and dollar sign #20394

mehmetf opened this issue Aug 9, 2018 · 16 comments
Labels
a: internationalization Supporting other languages or locales. (aka i18n) customer: mulligan (g3)

Comments

@mehmetf
Copy link
Contributor

mehmetf commented Aug 9, 2018

Posting on behalf of mulligan:

When formatting currency values in RTL (Arabic), the formatted values are getting reordered in unexpected ways.

$ 100.50 (Arabic) is displayed as 100.50 $ (incorrect?)
SR 100.50 (Arabic, Saudi Riyals) is displayed as SR 100.50 (correct?)
$100.50 (Hebrew) is displayed as $100.50 (correct?)
$ 2.57 ألف (Arabic, $2.57K) is displayed as squiggle 2.57 $ (¯_(ツ)_/¯)

Note that we are using NumberFormat.compactFormatCurrency() which does generally localize numbers properly.

Adding textDirection: TextDirection.ltr, seems to generally fix things, but also seems like the wrong solution. It looks like maybe the standalone dollar sign symbol is getting treated specially and moved about in ways that regular letters aren't when the text direction is RTL?

Here is a simplified snippet of our code:

Blockquote
new Text(
new NumberFormat.compactSimpleCurrency(name: 'USD').format(257000))
)
Blockquote

@amirh
Copy link
Contributor

amirh commented Aug 10, 2018

FWIW as a native Hebrew speaker placing the sign on either side "feels" reasonable to me.
I've asked the Academy of the Hebrew Language what is the correct position, their answer was that they have not discussed this issue, but that it feels more natural to read when the sign is to the left of the digits.

So at least for the Hebrew formatting I think we should keep it as-is (sign is to the left of the digits).

@mehmetf
Copy link
Contributor Author

mehmetf commented Aug 11, 2018

As a native turkish speaker, I can also say that currency symbols being on the right feels more natural to us even though Turkish is a LTR language. Now I am used to it but when I first came here, it felt weird that in English you say: "Four dollars" but you write "$4". We say "Dort turk lirasi" (Four turkish lira) and we write "4 TL".

This is true for foreign currency as well. Taken from Volkswagen turkish site with the price of Golf R listen in Euros and the euro symbol is on the right:
image

@egramond
Copy link
Contributor

There needs to be a standard answer for each language. Otherwise our charts end up displaying the formatted String one way, the Flutter text block ends up displaying it another way, and the UI looks inconsistent. Then people start filing bugs.

For reference, I believe the CDLR is what the Dart NumberFormat class ultimately relies on.
https://www.unicode.org/cldr/charts/latest/summary/ar.html#4217
(that doesn't necessarily mean it's always right, but at the very least that's where our formatted numbers are coming from)

FWIW the Hebrew version isn't giving us any trouble. (I think because in Hebrew, NumberFormat does not put a space between the $-sign and the amount, so the order doesn't get flipped)

@Hixie
Copy link
Contributor

Hixie commented Aug 14, 2018

This seems like a problem with intl: it's presumably assuming that the result is always in an LTR context. cc @alan-knight

@Hixie
Copy link
Contributor

Hixie commented Aug 14, 2018

(Assuming I'm right, that means that short-term the answer is probably to put TextDirection.ltr on the text span.)

@alan-knight
Copy link
Contributor

This doesn't really specify very well what was done, but assuming that the locale is plain "ar", the code that's listed looks like
"$ 257 ألف"
in a web browser, and the same when run on a Mac command line, but displays with the dollar sign at the end when printing to an IntelliJ console. I think the Arabic part is the same, and just displayed at the front, but I may not be noticing subtle differences. I don't know enough to reproduce in Flutter. The runes it produces, in any setting, are (36, 160, 50, 53, 55, 160, 1571, 1604, 1601)

So Intl does not insert any BiDi markers in the text. The surrounding context might auto-detect it, and generally seems to in web browsers, but might not in others. It sounds like Flutter might not autodetect it at all, or might autodetect it for the letters, but that the space in between resets the direction, even for a non-breaking space?

@alan-knight
Copy link
Contributor

Note that there are a number of useful Bidi-related methods in Intl which might be helpful. I really haven't used them in practice much, but https://github.com/dart-lang/intl/blob/1771fd26af88dd4b22c3c177fd8e86ad37fcc56e/lib/src/intl/bidi_formatter.dart#L130 might be useful if you want to automatically wrap a formatted number in RTL when it looks like it contains RTL text. Or https://github.com/dart-lang/intl/blob/1771fd26af88dd4b22c3c177fd8e86ad37fcc56e/lib/src/intl/bidi_utils.dart#L166 to check on a per-locale basis

@Hixie
Copy link
Contributor

Hixie commented Aug 15, 2018

The question is what is the context that that format assumes? Does it assume that that string will be rendered with the paragraph directionality set to RTL or LTR?

@alan-knight
Copy link
Contributor

Since the data does not indicate, I would think the assumption is that it will be rendered according to the conventions of the thing that is displaying it. But I'm not a domain expert, and we're just trying to do the same thing as ICU/CLDR for numbers.

Does Flutter attempt to detect and render RTL strings appropriately?

@Hixie
Copy link
Contributor

Hixie commented Aug 15, 2018

You can't really "detect" RTL, you have to know ahead of time what the directionality is. We do support that (so if you're in an arabic localization, e.g., everything will be RTL).

@alan-knight
Copy link
Contributor

In a RTL rendering of the number formatted for a RTL locale, I would expect the number to be formatted correctly. The numeric format for "ar" has the currency symbol before the number, i.e. I would expect it to be on the right in RTL.

According to Unicode, these are the correct formats for Arabic. http://www.unicode.org/cldr/charts/latest/verify/numbers/ar.html

However, I find it very peculiar that in that chart the currency symbol is on the left when we're not compacting the numbers, but switches to the right when we do compact. The chart has an explicit RTL marker around the compact values, but not the regular ones.

@Hixie
Copy link
Contributor

Hixie commented Aug 16, 2018

Based on that page and on http://www.unicode.org/cldr/charts/latest/verify/numbers/he.html, it looks to me like the description in the first comment here is what is expected.

@alan-knight
Copy link
Contributor

So, in a web browser, the behavior appears to be as follows. In a RTL context.

Numbers with Arabic words after them are rendered RTL.
Numbers with a $ in front of them and no whitespace are rendered LTR.
Numbers with a $ in front of them and a non-breaking space are rendered RTL.
Numbers with Latin characters plus $ in front of them and a non-breaking space (e.g. "US$ 1.23") are rendered LTR.

I don't know how this compares to Flutter behavior. It sounds consistent with what's described except for the last one. I don't know if "squiggle" is intended to mean that it rendered correctly RTL, or if it means that it was rendered RTL but the Arabic characters were garbled.

I tried out AdWords in an "ar" locale, to see what they're doing, and I noticed that in one place they had "$1.23", which renders LTR because they didn't format it to locale conventions, omitting the space. In most other places that had non-compacted currency amounts they wrote "US$ 1.23".

This does seem rather awkward to use. The information we produce is identical to ICU. It's not clear to me if there's a recommended way to use this in order to get the correct renderings. I also notice that in the Unicode chart above there is no space between the currency symbol and the number, which does not seem to be consistent with the data.

@alan-knight
Copy link
Contributor

Flutter appears to behave more or less like the browser. When wrapped in

  new Directionality(textDirection: TextDirection.rtl

r'$ 3' renders LTR
r'$3' renders RTL
r'$ 3 ألف' renders RTL

So it may not be possible to detect orientation, but something seems to be trying. Since this is the same as the browser it may be a feature rather than a bug.

@Hixie
Copy link
Contributor

Hixie commented Aug 16, 2018

I've received confirmation that the CLDR is designed so that the formatting for RTL locales will work correctly when rendered with the right directionality for that locale. That means that what is described in the first comment is correct behaviour, and there's no bug here.

I'm going to close this issue. Please don't hesitate to file a new bug if you find another potential error in the localizing. Thanks!

@Hixie Hixie closed this as completed Aug 16, 2018
@github-actions
Copy link

github-actions bot commented Sep 2, 2021

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: internationalization Supporting other languages or locales. (aka i18n) customer: mulligan (g3)
Projects
None yet
Development

No branches or pull requests

5 participants