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

Allow multiple locales. #1652

Closed
wants to merge 9 commits into from
Closed

Allow multiple locales. #1652

wants to merge 9 commits into from

Conversation

mbostock
Copy link
Member

Fixes #750. Code that requires localization is now within a closure that has access to locale-specific strings.

To minimize the degree of isolation required, d3.scale.linear (and other quantitative scales, including d3.time.scale) still default to the en-US locale. However, you can create your own localized formats using locale.numberFormat and locale.timeFormat.

(It would be possible to move these other classes to within d3.locale as well, but that would mean anything that depends on d3.scale.linear would also need to be moved within d3.locale, such as d3.svg.axis. I think it’s cleaner to leave them using a default locale rather and have people localize the formats explicitly, rather than classes that localize anything downstream; you can always reassign d3.format to a different locale if you want to change the default.)

Also introduces locale.timeFormat.multi which can be used to create a multi-scale time format, and improves currency formatting by allowing the currency symbol to appear after the numeric value.

@rbu
Copy link
Contributor

rbu commented Dec 10, 2013

Mike, thanks for taking a shot at this. I'll haven't played around with the branch yet, but the direction you are going to seems right to me. Can you give a quick example how to register a locale at runtime with this?
How do you generate a locale?

Statically loading a js file after d3 has been loaded would be fine for us (similar to what moment.js is doing), however it would be interesting to see if we could generate a d3 locale object from a Globalize.js culture.

By the way, we noticed that d3_time_scaleLocalFormats is not using localized format strings. For example, formatting times as "%I %p" is rather US-specific. Is this something you'd rather tackle in this branch, or should I create an independent bug report against master?

Fixes #750. This isn’t the final implementation, but more of a proof of concept
demonstrating how to scope any code that requires localization within a closure
that has access to locale-specific variables. In the next pass, I can go through
this implementation and more cleanly separate locale-dependent from locale-
independent code, and only put locale-dependent code within the closure.

Also, we may want to use an options object rather than passing a zillion
arguments to d3.locale, because a many-argument method is hard to use and may
make it harder to extend the API in the future. This commit also breaks the
ability to change the default locale during the build process, but this should
be easy to restore.
@mbostock
Copy link
Member Author

mbostock commented Jan 8, 2014

var russian = d3.locale({
  decimal: ",",
  thousands: " ",
  grouping: [3, 3],
  currency: ["", " руб."],
  dateTime: "%A, %e %B %Y г. %X",
  date: "%d.%m.%Y",
  time: "%H:%M:%S",
  periods: ["AM", "PM"],
  days: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
  shortDays: ["вс", "пн", "вт", "ср", "чт", "пт", "сб"],
  months: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"],
  shortMonths: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"]
});

Then:

russian.numberFormat("$,.2f")(1234567.89); // "1 234 567,89 руб."

Note that this doesn’t affect the behavior of the default d3.format:

d3.format("$,.2f")(1234567.89) // "$1,234,567.89"

Edit: this also demonstrates that the currency formatter is now smart enough to put the currency symbol after the number when desired.

@mbostock
Copy link
Member Author

mbostock commented Jan 8, 2014

@rbu If you are pulling in Globalize.js already, wouldn’t you just use Globalize.js to do the number and time formatting? What would be the benefit of creating a d3.locale object from that, given that Globalize.js already provides number and date formatters?

For the U.S.-centric default implementation of locale.timeScaleFormat, I’m not sure what the best solution is here. If you want different behavior, it probably makes more sense to just define your own time format, as in the custom time format example. So by that argument I think I’ll remove the locale.timeScaleFormat, since it’s not properly localized anyway.

It wasn’t really localized anyway, since the set of format strings weren’t
really locale-independent. A better way of localizing this format is to
implement a custom time format using locale.timeFormat, as in the custom time
format example: http://bl.ocks.org/mbostock/4149176
Given an array of format strings and corresponding predicate functions, returns
a time format function that tests the input date against each predicate
function, using the first format that returns true.
This commit allows the currency symbol to appear either at the beginning or end
(or both, but that should be rare).
@wahlatlas
Copy link

Mike, in your russian example you have

thousands: " "

I prefer " " for that because of text wrapping but get issues for tickValues as they don't seem to use innerHTML but Text

@mbostock
Copy link
Member Author

mbostock commented Jan 9, 2014

Can use "\xa0" for that (or embed a non-breaking space directly, and it will get escaped by the build).

@mbostock
Copy link
Member Author

Folded into #1690.

@mbostock mbostock closed this Jan 10, 2014
@mbostock mbostock deleted the locale branch January 10, 2014 00:40
@mbostock mbostock restored the locale branch January 10, 2014 00:41
@mbostock mbostock deleted the locale branch January 10, 2014 00:42
@mbostock
Copy link
Member Author

(In practice I think it might be preferable to use white-space: nowrap rather than hard-coding this behavior into the locale, but maybe either is okay.)

@Yahasana
Copy link

Yahasana commented Feb 8, 2014

d3.time.format.multi is not public but listed in the API Reference wiki

@jasondavies
Copy link
Contributor

Works for me, e.g. http://bl.ocks.org/mbostock/4149176.

@Yahasana
Copy link

Yahasana commented Feb 9, 2014

@jasondavies cool, I's using the older d3. thanks

@coachcheezy
Copy link

Does anybody have any examples of how to change locales on the fly using the D3 library? Still not clear if this is possible with D3, or if we need a custom solution.

@jasondavies
Copy link
Contributor

d3.locale was added in version 3.4.

@rbu
Copy link
Contributor

rbu commented Jun 30, 2014

@mbostock, sorry for dropping the ball earlier. The reason would be that we can still use the d3 api. I assume the time and number formatters are also used internally when creating an axis, for example.
My idea was to reuse an existing catalog of locale data so that we do not have to build a custom set of locales just for d3.

@Monduiz
Copy link

Monduiz commented Jul 28, 2015

I'm tryin to wrap my head around this. Does anyone have an example, say, on how to apply d3.locale to a bar chart to change dot-separated decimals to comma? This would go a long way to help understand how to use it in the most common scenarios.

@wahlatlas
Copy link

Here's how it works

e.g. for spanish

var ES = d3.locale({
decimal: ",",
thousands: ".",
grouping: [3],
currency: ["", " €"],
dateTime: "%A, %e de %B de %Y, %X",
date: "%d/%m/%Y",
time: "%H:%M:%S",
periods: ["AM", "PM"],
days: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes",
"sábado"],
shortDays: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
months: ["enero", "febrero", "marzo", "abril", "mayo", "junio",
"julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
shortMonths: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago",
"sep", "oct", "nov", "dic"]
});

var thsd = ES.numberFormat("n");
thsd(10000);  // 10.000

see here for options
https://github.com/mbostock/d3/wiki/Localization

see it in action here
https://www.destatis.de/bevoelkerungspyramide/

@Monduiz
Copy link

Monduiz commented Jul 29, 2015

Thank you, wahlatlas! It works beautifully. I implemented it today in my app and it saved me a lot of trouble. Thank you Mike for this wonderful functionality. I use more and more D3 now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants