plotly / plotly/plotly.py

Add support for internationalization of multilingual figures

Offen
#2,475 2 Kommentare 2 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

@T4rk1n arbeitet bereits daran.

Seit 08.7.2024.

feature P3
Vorherrschende Sprache
Python
Sterne
18.8k
Forks
2.8k
Ø Merge
16 Std. 26 Min.
Gemergte PRs (30 T.)
21

Beschreibung

Hello! This feature request comes from a project that uses Dash, but the problems/changes are in plotly modules so I opened the ticket here.

Context: The goal is to render a dashboard with various figures (graphs and maps) in different languages. At the moment, it is required to build 4 Dash layouts to serve 4 languages, making development less convenient (can’t use standard translation tools) and requiring 4 times the memory for hosting (this was profiled). I am not the author of the project, but for a hackathon I looked at using the Flask i18n extension, and found out that Dash is not directly compatible; then after finding a compat trick, I found out that it wasn‘t enough.

Details:
This is a Dash app https://github.com/jeremymoreau/covid19mtl/blob/master/app/__init__.py viewable at https://covid19mtl.ca/en . (It’s not using latest plotly or dash for stability or familiarity I suppose.)

1) I looked for Flask i18n guides and tried to add Flask-i18n which uses a classic gettext approach with a LazyString class that is rendered to a localized string at request time.

https://github.com/jeremymoreau/covid19mtl/pull/21/files#diff-1f9f743421417fb2794c88447083a031R12-R27

LazyString was rejected during JSON encoding. I looked at this method https://github.com/plotly/plotly.py/blob/v4.6.0/packages/python/plotly/_plotly_utils/utils.py#L100 which led me to define as_plotly_json https://github.com/jeremymoreau/covid19mtl/pull/21/files#diff-828aeb2697b4cf1e4ba7120b38810cccR5-R9 to be compatible, and it worked for Dash HTML components (example https://github.com/jeremymoreau/covid19mtl/pull/21/files#diff-4599052b1ffcd344c72d72ce59a64186R399 — this is in template.py file that github hides by default even if there is a line link ☹️)

Now, how to upstream this? plotly doesn’t know about flask, but dash itself doesn’t transform to JSON, that code is in _plotly_utils and is not extensible, so I couldn’t send a quick PR. «Not extensible» I mean that a list of conversion functions is hard-coded and tried in order. Other approaches like Pyramid’s adapters or https://pypi.org/project/json-encoder/ based on single-dispatch can be extended from downstream code. But these rely on types (object class), whereas the existing approach checks for the presence of attributes (special method like tolist) or special values (pandas funky NaN and such).

Would you be open to reworking this? I think a hybrid approach could work (detect special methods like as_plotly_json or fancy scipy stack objects first, then delegate to a single-dispatched function that checks types to handle datetime, decimal, etc, and expose that function so that Dash can register a conversion function for the LazyString type.

2) The LazyString class is rejected by checks in plotly figure classes, so we can’t translate all the labels. This blocked my efforts. I didn’t try to make a str subclass because built-in classes often have shortcuts in codebases (starting with CPython itself!) so your overriden methods are not getting called when you expect and it’s a dead end. We didn’t try applying translations using JavaScript because it would require to write more gettext integration, and some of the labels are inside SVG sub-documents which wouldn’t be easy to get.

How can we satisfy plotly type checks when passing a custom class that should be transformed (i.e. call str) at render time?

Thanks for reading and considering this! I am sure more than one person would like to make multilingual plots and dashboards, so it would be great if I could contribute some useful code upstream.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.