6

The function below results in "10.000". Where I live this means "ten thousand".

format!("{:.3}", 10.0);

I would like the output to be "10,000".

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
roeland
  • 6,058
  • 7
  • 50
  • 67
  • Possible duplicate of [Rust: print/format number with thousand separator](https://stackoverflow.com/questions/26998485/rust-print-format-number-with-thousand-separator) – ljedrz Jun 15 '17 at 20:10
  • @ljedrz No, the OP clearly ask for floating number. Your question is about integer. – Stargateur Jun 15 '17 at 20:12
  • The answer to that question covers floats too, but you're right; this question is not exactly a duplicate. – ljedrz Jun 15 '17 at 20:24
  • 1
    cf. https://github.com/rust-lang/rust/issues/19752#issuecomment-66684082 – ArtemGr Jun 15 '17 at 21:10
  • 1
    @Stargateur: When evaluating duplicates, answers count as much as questions. In this case however, I would not mark it as duplicate, as one is talking about thousand separators (nigh exclusively) without any code sample and the other about decimal separators. – Matthieu M. Jun 16 '17 at 06:59

3 Answers3

7

There is no support for internationalization (i18n) or localization (l10n) baked in the Rust standard library.


There are several reasons, in no particular order:

  1. a locale-dependent output should be a conscious choice, not a default,
  2. i18n and l10n are much more complicated than just formatting numbers,
  3. the Rust std aims at being small.

The format! machinery is going to be used to write JSON or XML files. You really do NOT want to end up with a differently formatted file depending on the locale of the machine that encoded it. It's a recipe for disaster.

The detection of locale at run-time is also optimization unfriendly. Suddenly you cannot pre-compute things at compile-time (even partially), you cannot even know which size of buffer to allocate at compile-time.

And this ties in with a dubious usefulness. Dates and numbers are arguably important, however this American vs English formatting war is ultimately a drop in the ocean. A French grammar schooler will certainly appreciate that the number is formatted in the typical French format... but it will be of no avail to her if the surrounding text is in English (we French are notoriously bad at teaching/learning foreign languages). Locale should influence language selection, sorting order, etc... merely changing the format of numbers is pointless, everything should switch with it, and this requires much more serious support (check gettext for a C library that provides a good base).

Basing the detection of the locale on the host locale, and it being global to the whole process, is also a very dubious architectural choice in this age of multi-threaded web servers. Imagine if Facebook was served in Swedish in Europe just because its datacenter is running there.

Finally, all this language/date/... support requires a humongous amount of data. ICU has several dozens (or is it hundreds?) of MBs of such data embedded inside it. This would make the size of the std explode, and make it completely unsuitable for embedded development; which probably do not care about this anyway.

Of course, you could cut down on this significantly if you only chose to support a handful of languages... which is yet another argument for putting this outside the standard library.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • 3
    Sure, but OP does not speak about `std`: there could be some official extern crate for internationalization, baked by the rust team. You are right IMO about *not* putting this stuff in `std`, but to develop in a modern language, this must exist somewhere. – Boiethios Jun 16 '17 at 07:38
  • 3
    @Boiethios: I hear you... but the SO format just doesn't lend itself well to recommending libraries unfortunately. Most notably because of inertia in the answers which means that 2 years from now the top answer may refer to a dead library (which is the reason questions asking for such references are closed, btw). Thus I prefer to limit myself to the explanation of why the standard library doesn't provide it; and this frees the OP to shop around rather than try and wait for the std solution (search for "locale" on crates.io, ask questions on IRC/Reddit/the users forum/...). – Matthieu M. Jun 16 '17 at 07:45
  • Mmh you are right. I will think about that when I answer something. – Boiethios Jun 16 '17 at 07:48
  • Thanks. Is there a usable crate for this at the moment? (I understand why you don't mention it in your answer, but maybe a comment is ok) – roeland Jun 16 '17 at 09:45
  • @r03: Stargateur suggested one, I have no idea how good or bad it is. If this is important to you, I really advise searching/asking the community (not on SO) about it. – Matthieu M. Jun 16 '17 at 11:13
5

Since the standard library doesn't have this functionality (localization of number format), you can just replace the dot with a comma:

fn main() {
    println!("{}", format!("{:.3}", 10.0).replacen(".", ",", 1));
}

There are other ways of doing this, but this is probably the most straightforward solution.

ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • 2
    I hate this solution, but I guess I have no choice at the moment :-) – roeland Jun 16 '17 at 09:47
  • I first forgot that it existed and attempted to implement it myself and believe me - this one is actually pretty pleasant ;). – ljedrz Jun 16 '17 at 10:09
  • For proper i18n support, see https://crates.io/crates/num-format and https://crates.io/crates/gettext – Mikko Rantalainen Aug 02 '22 at 15:11
  • If you don't want to use gettext because of the LGPL license, try https://mozilla-l10n.github.io/localizer-documentation/tools/fluent/basic_syntax.html#selectors-and-plurals instead – Mikko Rantalainen Aug 02 '22 at 15:16
1

This is not the role of the macro format!. This option should be handle by Rust. Unfortunately, my search lead me to the conclusion that Rust don't handle locale (yet ?).

There is a library rust-locale, but they are still in alpha.

Stargateur
  • 24,473
  • 8
  • 65
  • 91