Skip to content

i18n: audience-scoped catalogs + branded scaffold title (#248, #249) - #251

Merged
antosubash merged 2 commits into
mainfrom
fix/i18n-audience-and-scaffold-title
Aug 7, 2026
Merged

i18n: audience-scoped catalogs + branded scaffold title (#248, #249)#251
antosubash merged 2 commits into
mainfrom
fix/i18n-audience-and-scaffold-title

Conversation

@antosubash

Copy link
Copy Markdown
Owner

Fixes #248 and #249 — the two framework-level findings from the globalcanopyatlas perf pass (the module-level ones moved to smpy_modules and are fixed in antosubash/smpy_modules#18).

#248 — stop shipping admin catalogs to anonymous visitors

Measured on a public content page: 9.4 KB of i18n in every full-page payload, ~85% of it admin-only strings (permissions 2.6 KB, settings 2 KB, branding 1.3 KB, file_storage 1.3 KB, dashboard 0.7 KB) an anonymous visitor can never render — and it grows with every installed module.

Design (option 1 from the issue — module-declared audience):

  • ModuleMeta.i18n_audience: "public" (default — ships to everyone, fully backward compatible) or "admin" (ships only to authenticated users).
  • I18nRegistry: add_source(..., audience=...); load() precomputes a public snapshot next to the full one, so the request hot path stays a precomputed-dict lookup either way. messages_snapshot(locale, include_admin=False) is the anonymous variant. Server-side Translator lookups are unaffected — every namespace stays visible.
  • build_i18n_block picks the snapshot by is_authenticated and tracks the served audience in the session alongside the locale. The subtle case is covered: login mid-session re-ships messages even on an Inertia partial (which normally sends messages: None), so a freshly-authenticated client isn't stuck with the anonymous catalog until a hard reload. Logout likewise.
  • The in-repo admin modules (settings, permissions, dashboard, file_storage, audit_log, feature_flags, background_tasks, branding) now declare "admin". auth/users/keycloak stay public — their flows render for anonymous users. Docs: docs/framework/i18n.md § Audience.

#249 — scaffold title

create-host's index.html still hardcoded <title>SimpleModule</title>; the branding_head() Jinja global (the #175 fix) existed but nothing scaffolded called it. The template now renders the branded title + theme-color, matching the in-repo dev host. Verified in a consuming host (iiasa/globalcanopyatlas#5).

Verification

  • framework/core + framework/hosting i18n suites extended: public-snapshot exclusion, default-audience passthrough, anonymous vs authenticated payloads, the login-partial re-ship, and the unchanged-audience skip (40 i18n tests green).
  • Full make test-py: 1,721 passed, 2 skipped. make test-js: 48 passed. ruff/format, biome, ty check framework/core framework/hosting, and the 300-line cap all clean.
  • Pre-existing, unrelated: ty flags framework/cli/tests/test_cli_package_update.py (typer._click.exceptions import, from feat: pluggable auth — AuthProvider contract + Keycloak OIDC module + bearer tokens #184) in my local env; untouched by this PR.

https://claude.ai/code/session_01LHXd7LmearTryWpnf4ksKD

Fixes #248: every module's locale catalog shipped in every Inertia
payload — an anonymous visitor on a public content page downloaded
~8 KB of admin form labels (permissions, settings, branding, ...) per
full page load, growing linearly with installed modules.

- ModuleMeta gains i18n_audience ("public" default, "admin" opt-in).
- I18nRegistry.add_source() takes the audience; load() precomputes a
  public snapshot alongside the full one, so the hot path stays a dict
  lookup either way. messages_snapshot(locale, include_admin=False)
  returns the anonymous variant; server-side Translator lookups always
  see every namespace.
- build_i18n_block() picks the snapshot by auth state and tracks the
  served audience in the session next to the locale: a login (or
  logout) mid-session re-ships the messages even on an Inertia
  partial, so a freshly-authenticated client is never left holding
  the anonymous catalog.
- The framework's admin modules (settings, permissions, dashboard,
  file_storage, audit_log, feature_flags, background_tasks, branding)
  declare i18n_audience="admin". auth/users/keycloak stay public —
  anonymous visitors see their login flows.

Fixes #249: the create-host scaffold hardcoded <title>SimpleModule</title>
even though branding_head() — added for exactly this in #175 — was
already registered as a Jinja global. The scaffold now renders the
branded title and theme-color the same way the in-repo dev host does.

Claude-Session: https://claude.ai/code/session_01LHXd7LmearTryWpnf4ksKD
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4a427b4
Status: ✅  Deploy successful!
Preview URL: https://2c0a939f.simple-module-python.pages.dev
Branch Preview URL: https://fix-i18n-audience-and-scaffo.simple-module-python.pages.dev

View logs

@antosubash
antosubash merged commit bd80e95 into main Aug 7, 2026
12 checks passed
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.

[hosting/i18n] Every module's full locale catalog ships in every page payload — including admin-only strings on anonymous public pages

1 participant