Skip to content

feat(plotly): add per-chart locale support#6428

Open
BABTUNA wants to merge 1 commit intoreflex-dev:mainfrom
BABTUNA:feat-6101-plotly-locale
Open

feat(plotly): add per-chart locale support#6428
BABTUNA wants to merge 1 commit intoreflex-dev:mainfrom
BABTUNA:feat-6101-plotly-locale

Conversation

@BABTUNA
Copy link
Copy Markdown
Contributor

@BABTUNA BABTUNA commented Apr 30, 2026

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

New Feature Submission:

  • Does your submission pass the tests?
  • Have you linted your code locally prior to submission?

Changes To Core Features:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your core changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Description

Adds first-pass Plotly locale support on
x.plotly and plotly dist variants via a new locale prop.

What changed:

  • Added locale prop to Plotly.
  • Added plotly.js-locales@3.5.0 dependency/import.
  • Added locale helpers that resolve locale data and merge it into config (locale + locales) at render time.
  • Kept locale handling internal to config (the raw locale prop is excluded from direct component props).
  • Added unit coverage for both
    x.plotly(...) and
    x.plotly.basic(...) locale flow.
  • Added docs section showing localized usage.
  • Updated pyi_hashes.json for packages/reflex-components-plotly/src/reflex_components_plotly/plotly.pyi.

Validation:

  • uv run --no-sync ruff check packages/reflex-components-plotly/src/reflex_components_plotly/plotly.py tests/units/components/graphing/test_plotly.py
  • uv run --no-sync pytest tests/units/components/graphing/test_plotly.py -q
  • uv run --no-sync pytest tests/units/components/graphing -q

Closes #6101

@BABTUNA BABTUNA requested review from a team and Alek99 as code owners April 30, 2026 17:01
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 30, 2026

Merging this PR will not alter performance

✅ 9 untouched benchmarks


Comparing BABTUNA:feat-6101-plotly-locale (cd39149) with main (5496439)

Open in CodSpeed

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 30, 2026

Greptile Summary

This PR adds a locale prop to rx.plotly that resolves locale data from plotly.js-locales at render time and merges it into the Plotly config object, enabling per-chart number/date formatting and modebar label localisation.

  • Missing plotlyLocales import in dist-variant subclasses (PlotlyBasic, PlotlyCartesian, etc.): each subclass overrides add_imports without calling super(), so the plotly.js-locales binding added in Plotly.add_imports() may never reach those components. The inherited custom code always references plotlyLocales, which would cause a ReferenceError in the browser if Reflex resolves imports per-class rather than across the full MRO.
  • plotly.js-locales and the two helper functions are bundled unconditionally, adding overhead for every app using rx.plotly regardless of whether locale is set.

Confidence Score: 3/5

Not safe to merge without verifying that dist-variant subclasses receive the plotlyLocales import.

A P1 finding (missing import in subclass overrides) could cause a silent runtime ReferenceError for all users of the dist variants when locale is set. The existing tests only validate the Python render output, not the browser-side import map, so the bug would not be caught by CI.

packages/reflex-components-plotly/src/reflex_components_plotly/plotly.py — specifically the add_imports overrides in PlotlyBasic and all other dist-variant subclasses.

Important Files Changed

Filename Overview
packages/reflex-components-plotly/src/reflex_components_plotly/plotly.py Adds locale prop, locale helper JS functions, and plotly.js-locales import; dist-variant subclasses override add_imports without calling super, risking a missing plotlyLocales binding at runtime.
tests/units/components/graphing/test_plotly.py Adds two locale tests that verify the Python-side render output; does not verify that the plotly.js-locales import is present in the generated import map for dist variants.
docs/library/graphing/other-charts/plotly.md Adds a "Locale Configuration" section with a working demo snippet; prose is clear and accurate.
pyi_hashes.json Hash updated for plotly.pyi to reflect the new locale prop; mechanical change.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["rx.plotly(data=fig, locale='de')"] --> B["Plotly._render()"]
    B --> C{self.locale is not None?}
    C -- No --> D["Return tag as-is"]
    C -- Yes --> E["Resolve config Var\n(self.config or empty dict)"]
    E --> F["Inject config prop:\n_rxGetPlotlyLocaleConfig(config, locale, plotlyLocales)"]
    F --> G["Browser: _rxResolvePlotlyLocaleData\nlooks up locale in plotlyLocales bundle"]
    G --> H{Locale found?}
    H -- Yes --> I["Set config.locale = localeData.name\nSet config.locales[name] = localeData"]
    H -- No --> J["Set config.locale = String(locale)\n(fallback — no locale dict injected)"]
    I --> K["React Plot renders with locale"]
    J --> K

    subgraph Import side
        L["Plotly.add_imports()\n→ plotly.js-locales@3.5.0 (always)"]
        M["PlotlyBasic.add_imports()\n→ CREATE_PLOTLY_COMPONENT only\n⚠️ no super() call"]
    end
Loading

Comments Outside Diff (1)

  1. packages/reflex-components-plotly/src/reflex_components_plotly/plotly.py, line 386-392 (link)

    P1 plotlyLocales import missing in dist-variant subclasses

    PlotlyBasic.add_imports() (and every other dist variant — PlotlyCartesian, PlotlyGeo, PlotlyGl3d, PlotlyGl2d, PlotlyMapbox, PlotlyFinance, PlotlyStrict) overrides add_imports and returns only CREATE_PLOTLY_COMPONENT, without calling super().add_imports(). The inherited add_custom_code() always emits _rxResolvePlotlyLocaleData and _rxGetPlotlyLocaleConfig, both of which close over the plotlyLocales binding that is introduced solely in Plotly.add_imports().

    If Reflex dispatches add_imports() only on the most-derived class (standard Python MRO behaviour), plotlyLocales will never be imported for these variants. Calling rx.plotly.basic(data=fig, locale="fr") would compile fine on the Python side (the test confirms this) but throw a ReferenceError: plotlyLocales is not defined in the browser.

    The test test_plotly_basic_locale_option_merges_into_config only checks that the generated string contains _rxGetPlotlyLocaleConfig and "fr" — it does not verify that the plotly.js-locales import is actually present in the component's import map.

    To fix, either have each subclass return a list that includes the parent imports:

    def add_imports(self) -> ImportDict | list[ImportDict]:
        return [super().add_imports(), CREATE_PLOTLY_COMPONENT]

    or guard the custom code so it only references plotlyLocales when it is actually imported.

Reviews (1): Last reviewed commit: "feat(plotly): add per-chart locale suppo..." | Re-trigger Greptile

Comment on lines 188 to 196
return {
# For merging plotly data/layout/templates.
"mergician@v2.0.2": "mergician"
"mergician@v2.0.2": "mergician",
# For locale dictionaries injected into plot config.locales.
"plotly.js-locales@3.5.0": ImportVar(
tag="plotlyLocales",
is_default=True,
),
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Locale bundle always included regardless of usage

plotly.js-locales@3.5.0 is unconditionally added to the import map, and add_custom_code() always emits the two helper functions that reference it. This means every app that uses rx.plotly (even with no locale prop) will bundle all 70+ locale definitions and include the helper code, adding unnecessary weight for users who never touch the locale feature.

A conditional approach would require add_imports and add_custom_code to only emit locale-related output when the component is actually configured with a locale, which isn't easy at the class level. At minimum, the trade-off should be noted in the docstring or changelog so users are aware of the bundle size impact.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree. see how we handle it in moment.py when the user supplies the tz prop. the import should be added conditionally based on the locale prop being provided

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern from moment.py is clear. Here's how to apply it to the plotly add_imports:

Suggested change
return {
# For merging plotly data/layout/templates.
"mergician@v2.0.2": "mergician"
"mergician@v2.0.2": "mergician",
# For locale dictionaries injected into plot config.locales.
"plotly.js-locales@3.5.0": ImportVar(
tag="plotlyLocales",
is_default=True,
),
}
def add_imports(self) -> ImportDict:
"""Add imports for the plotly component.
Returns:
The imports for the plotly component.
"""
imports: ImportDict = {
# For merging plotly data/layout/templates.
"mergician@v2.0.2": "mergician",
}
if self.locale is not None:
# For locale dictionaries injected into plot config.locales.
imports["plotly.js-locales@3.5.0"] = ImportVar(
tag="plotlyLocales",
is_default=True,
)
return imports

Same idea applies to add_custom_code — it should also gate the locale helper functions behind if self.locale is not None so the helper code is only emitted when a locale is actually used.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support locale config for rx.plotly

2 participants