add i18n support - #6796
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
Greptile SummaryThis PR introduces a full internationalization (i18n) system for Reflex as a new Key additions:
Confidence Score: 5/5Safe to merge; all previously raised issues have been addressed and no new blocking defects were found. The core mechanics — event-scope locale injection, implicit dependency tracking via bytecode scanning, catalog compilation, and client-side provider — are all well-designed with solid unit and integration test coverage. The two remaining findings are quality/developer-experience concerns that do not affect production correctness. Files Needing Attention: runtime.py (stale translation cache on hot-reload) and state.py (set_locale no-op with URL routing) are worth a second look before GA, but neither blocks production correctness.
|
| Filename | Overview |
|---|---|
| packages/reflex-i18n/src/reflex_i18n/plugin.py | New plugin wiring i18n into compilation: catalog emission, route expansion per locale, hreflang injection. Well-structured with clean separation of static/dynamic catalog concerns. |
| packages/reflex-i18n/src/reflex_i18n/runtime.py | Server-side gettext helpers and locale formatting via Babel. Module-level _translations cache is not cleared on hot-reload, causing server/client translation divergence during development. |
| packages/reflex-i18n/src/reflex_i18n/state.py | I18nState holds locale cookie; _locale_scope registers per-event locale context. set_locale() is silently a no-op with URL routing due to _switchLocale=null in that mode. |
| packages/reflex-i18n/src/reflex_i18n/_web/i18n.js | Client runtime: I18nProvider, lazy catalog loading, Intl formatter caching, URL routing helpers. Secure cookie attribute conditionally added. Promise rejection caught. RTL detection included. |
| packages/reflex-base/src/reflex_base/event/processor/scope.py | New per-event ambient context mechanism with ExitStack-based cleanup. Mid-loop exception safety correctly handled with try/except in aenter. |
| packages/reflex-base/src/reflex_base/vars/dep_tracking.py | Adds implicit dependency tracking for LOAD_GLOBAL/LOAD_DEREF bytecode instructions, enabling gettext-family calls to imply a dep on I18nState.locale without explicit annotation. |
| packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py | Wraps both handler execution and delta resolution in event_scope so locale contextvar is active during computed-var recomputation. No-op fast path when no providers are registered. |
| packages/reflex-i18n/src/reflex_i18n/catalog.py | Compiles .po catalogs to JS modules. Plural expression whitelisted via regex before embedding in generated code. Missing translations warned with truncation at 10. |
| packages/reflex-i18n/src/reflex_i18n/routing.py | Locale routing strategy abstraction with PathPrefixRouting implementation. Correctly handles default-at-root, delocalization, and locale_of path detection. |
| reflex/state.py | Refactors reload_state_module to accumulate removed state names and purge dangling dep-graph edges, fixing stale dependency crashes on hot-reload. |
| reflex/reflex.py | Adds _add_plugin_cli_commands() to load click.Command entry points from installed packages. Correctly guards against non-Command objects and failed loads. |
| packages/reflex-i18n/pyproject.toml | New package manifest with a TODO noting the reflex-base/reflex dependencies must be pinned to released versions before publishing. |
| packages/reflex-i18n/src/reflex_i18n/vars.py | rx.t() translation var: validates literal message at call site, registers to compile-time message registry, and emits JS calls to useTranslation hook. |
| reflex/init.py | Adds lazy-loaded i18n symbols (I18nConfig, I18nPlugin, I18nState, gettext, ngettext, pgettext, set_locale, t) to the rx.* namespace via _MAPPING. |
Reviews (13): Last reviewed commit: "Merge remote-tracking branch 'upstream/m..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6b9a5f5342
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| "reflex-base >= 0.9.7.dev0", | ||
| "reflex >= 0.9.7.dev0", |
There was a problem hiding this comment.
Remove development pins before publishing reflex-i18n
With the new dispatch-release option, selecting reflex-i18n will create a release and trigger .github/workflows/publish.yml, whose publish job runs scripts/check_min_deps.py --check-dev-pins "$PACKAGE" and explicitly rejects published dependencies containing *.dev pins. Because these two requirements are part of reflex-i18n's published metadata, the publish workflow for any reflex-i18n release will fail at that gate until they are pinned to released versions.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
I'll leave this open for the maintainers
|
@masenf could you please take a brief look at this from an architectural design and DX perspective? it's totally okay if you have smth completly different in mind |
masenf
left a comment
There was a problem hiding this comment.
@benedikt-bartscher thanks for adding this and sorry for the review back-up. i did an initial look and i think the added extension points make sense and the API feels nice.
one potential issue i see affects SEO performance of the SSG static versions of the site -- since the translation depends on state, other languages might not be indexable by crawlers.
e68fb65 to
3e540c0
Compare
1559ee7 to
1f506d7
Compare
1f506d7 to
a5025c7
Compare
closes #2339