Skip to content

add i18n support#6796

Open
benedikt-bartscher wants to merge 16 commits into
reflex-dev:mainfrom
benedikt-bartscher:add-i18n
Open

add i18n support#6796
benedikt-bartscher wants to merge 16 commits into
reflex-dev:mainfrom
benedikt-bartscher:add-i18n

Conversation

@benedikt-bartscher

@benedikt-bartscher benedikt-bartscher commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

closes #2339

@codspeed-hq

codspeed-hq Bot commented Jul 17, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing benedikt-bartscher:add-i18n (9496723) with main (f79d011)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces reflex-i18n, a new optional package providing i18n support for Reflex apps, along with supporting changes in reflex-base and the core reflex package. The implementation covers client-side static translation (rx.t), server-side dynamic translation (gettext/ngettext/pgettext), locale-aware Intl number/date formatting, a reflex i18n CLI for catalog management, and a per-event locale contextvar scope that keeps computed vars reactive to locale changes.

  • Client side: An I18nProvider React context wraps the app; locale preference is stored in a cookie with a conditional secure attribute; catalog chunks are dynamically imported per locale (code-split) with proper .catch() error surfacing.
  • Server side: _EventScope enters a use_locale context around both handler execution and delta resolution, so gettext calls in computed vars automatically retranslate when the cookie changes. A new register_implicit_dependency mechanism in dep_tracking.py teaches the bytecode scanner to emit a I18nState.locale dependency whenever gettext-family functions appear in a computed var getter.
  • Bug fix: reload_state_module is refactored to accumulate and then purge dangling _var_dependencies/_potentially_dirty_states edges left behind when i18n (or any package-level) state is dropped during hot-reload.

Confidence Score: 5/5

Safe to merge. The new i18n package is well-isolated behind an opt-in plugin; apps not using i18n are unaffected by all changes except the reload_state_module refactor, which fixes a crash.

The implementation is thorough — previous review threads (cookie security, q=0 exclusion, __aenter__ cleanup, set_locale mapping, CLI guard) have all been addressed. The only remaining observations are about ExitStack.close() not forwarding exception info to context managers (safe for the current use_locale provider) and the server-side translation cache not being cleared during hot-reload (a developer UX detail, not a runtime correctness issue).

packages/reflex-base/src/reflex_base/event/processor/scope.py — the __aexit__ pattern is worth revisiting before new event-scope providers are added.

Important Files Changed

Filename Overview
packages/reflex-i18n/src/reflex_i18n/runtime.py New file: server-side gettext translation with locale contextvar, PO catalog loading, and Babel number/date formatting. negotiate_locale correctly excludes q=0 entries per RFC 7231. Translation cache (_translations) is lazily populated but not cleared on hot-reload.
packages/reflex-i18n/src/reflex_i18n/state.py New file: I18nState substate holding locale cookie, set_locale module-level function that dispatches both client-side switchLocale script and server-side state update, and _locale_scope event-scope provider registering the active locale per event.
packages/reflex-base/src/reflex_base/event/processor/scope.py New file: _EventScope async context manager entering all registered per-event providers. __aenter__ correctly cleans up on mid-loop failure. __aexit__ uses ExitStack.close() which calls context managers' __exit__ with (None, None, None) regardless of whether an exception is active.
packages/reflex-i18n/src/reflex_i18n/_web/i18n.js New file: React context provider, switchLocale global for Reflex script calls, cookie with conditional secure attribute, cancellable locale loader with .catch() error logging, and Intl-backed formatters with bounded LRU cache.
packages/reflex-base/src/reflex_base/vars/dep_tracking.py Modified: adds register_implicit_dependency mechanism and LOAD_GLOBAL/LOAD_DEREF handlers so computed vars that call gettext-family functions automatically gain a dependency on I18nState.locale. LOAD_FAST (local imports inside function bodies) is intentionally not handled.
packages/reflex-i18n/src/reflex_i18n/catalog.py New file: compiles .po catalogs to per-locale JS modules. Plural expression is whitelisted against an allowlist regex before embedding in generated JS. Only used messages are emitted (tree-shaking).
reflex/state.py Modified: refactors reload_state_module into _reload_state_module + _purge_dependencies_on_states to fix dangling edges in _var_dependencies and _potentially_dirty_states when i18n (or any package-level) state is hot-reloaded.
reflex/reflex.py Modified: adds _add_plugin_cli_commands() to attach reflex.cli entry points. Non-click.Command objects are guarded against with a warning, so a bad plugin can't crash the CLI.
packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py Modified: wraps both non-background event processing and delta resolution in event_scope, so the locale contextvar is active during both handler execution and computed-var resolution. Background tasks get a separate scope for processing.
packages/reflex-i18n/src/reflex_i18n/plugin.py New file: I18nPlugin that wires configuration, ships the client runtime, and compiles per-locale JS catalog modules. State is lazily imported in __post_init__ to avoid registering I18nState unless the plugin is actually used.

Reviews (8): Last reviewed commit: "greptile" | Re-trigger Greptile

Comment thread packages/reflex-base/src/reflex_base/event/processor/scope.py
Comment thread packages/reflex-i18n/src/reflex_i18n/runtime.py
Comment thread packages/reflex-i18n/src/reflex_i18n/_web/i18n.js
Comment thread packages/reflex-i18n/src/reflex_i18n/_web/i18n.js
Comment thread reflex/__init__.py
@benedikt-bartscher
benedikt-bartscher marked this pull request as ready for review July 18, 2026 11:09
@benedikt-bartscher
benedikt-bartscher requested review from a team and Alek99 as code owners July 18, 2026 11:09
@benedikt-bartscher benedikt-bartscher changed the title first i18n wip add basic i18n support Jul 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment on lines +12 to +13
"reflex-base >= 0.9.7.dev0",
"reflex >= 0.9.7.dev0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll leave this open for the maintainers

Comment thread reflex/reflex.py
@benedikt-bartscher benedikt-bartscher changed the title add basic i18n support add i18n support Jul 18, 2026
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.

Internationalization (I18N) and localization (L10N) (Feature Request)

1 participant