Skip to content

feat(hub-ui): translate the hub UI and add a language setting - #415

Open
antfubot wants to merge 2 commits into
mainfrom
feat/hub-ui-i18n
Open

antfubot wants to merge 2 commits into
mainfrom
feat/hub-ui-i18n

Conversation

@antfubot

@antfubot antfubot commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Refs #398

What

  • Every user-facing string in @devframes/hub-ui renders through a small in-house t() (src/client/i18n) with typed keys from en.json. Ten locales ship: en, zh-CN, zh-TW, ja, ko, es, fr, de, pt-BR, ru. English is the fallback.
  • Settings > Appearance gets a Language select (native <select>, so it works inside the shadow root). The pick persists per browser under devframes-locale, like the color scheme. Auto follows the host default, then navigator.languages.
  • createUi({ locale }) publishes a host default as ConnectionMeta.configs.ui.locale. The running UI writes the language it resolved back into the connection it publishes on its window (__DEVFRAME_CONNECTION__ / __DEVFRAME_CONNECTION_META__), so a same-origin frame reads the effective language from connectionMeta.configs.ui.locale at boot.
  • devframe/client exports storeConnection so the hub UI can refresh the published connection after mutating its meta.
  • Storybook gets a Language toolbar toggle. Docs: locale option and how to add a language in the hub-initiate guide; a t() rule in .agents/06-design-system.md.

Translations

The non-English files are machine quality and marked for native review. The i18n test keeps every file in lockstep with en.json (same keys, same {slot} placeholders), so a missing or renamed key fails CI.

Deferred


Created with the help of an agent.

Every hub-ui string now goes through a small in-house t() with ten
locales (en, zh-CN, zh-TW, ja, ko, es, fr, de, pt-BR, ru) and English as
the fallback. A Language select in Settings > Appearance persists the
visitor's pick per browser; createUi({ locale }) seeds the default via
ConnectionMeta.configs.ui.locale, and the running UI writes the effective
language back into the connection it publishes so same-origin frames read
it at boot.

refs #398
@coldtea-pr-lens

coldtea-pr-lens Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

◈ PR Lens

Note

This drawing shows 0fadd97, and the branch has new commits since. Tick Redraw to draw the latest one

  • Redraw

🟢 +2 new · 🟠 ~3 changed · 🔴 -0 removed · 1 flow · 14 files · commit 0fadd97


Architecture

Architecture diagram for devframes/devframe at 0fadd97

5 components touched across 2 lanes.

Play the interactive walkthrough


Inside the changed components — 2 views

Component view — Hub UI Localization Engine

Internal localization engine, message catalogs, and UI translation integration

Architecture view of Component view — Hub UI Localization Engine in devframes/devframe

Component view — Locale State & Connection Publishing

Reactive locale watcher and cross-frame connection storage synchronization

Architecture view of Component view — Locale State & Connection Publishing in devframes/devframe

Data flow

Data flow diagram for devframes/devframe at 0fadd97

Changing UI language and synchronizing frames

Follow each request, response and payload


View

  • Architecture lens
  • Data flow lens
  • Expand every detail

Tip

Untick Architecture lens or Data flow lens under View to hide a diagram, or tick Expand every detail to open every section. The comment redraws in a few seconds

🪧 More tips
  • Run npx skills add coldteadotai/pr-lens, then tell your coding agent: "Diagram the change you just made with PR Lens and attach it to the pull request."
  • Run npx @coldtea/pr-lens-cli analyze --base origin/main on a branch, then npx @coldtea/pr-lens-cli render .pr-lens/graph.json. Same lenses, your own model key, before the pull request exists
  • Click the link under each diagram to open it on a canvas you can zoom, pan and step through
  • The diagrams are links. Click one to open it on the canvas, then press W or click play to walk through the change
  • Open a diagram on the canvas, then press W or click play to walk through the change one step at a time
  • The CLI's render reads .github/pr-lens.yml and applies your renames, exclusions and lane pins at draw time
  • Set github.comment.collapsed: true in .github/pr-lens.yml to fold the comment behind one View architecture and data flow row. Drawing still runs as before
  • Set github.draw: on-demand in .github/pr-lens.yml and PR Lens stops drawing pull requests on its own. Comment @pr-lens draw on a pull request when you want that one drawn
  • Add .github/workflows/pr-lens.yml with coldteadotai/pr-lens/packages/action@v0 and your model provider's key as its api-key to run PR Lens from your own CI. Any /chat/completions endpoint works
  • Push a commit and the drawing stays, with a note that it is out of date. Tick Redraw in the note to draw the new head
  • Switch GitHub to dark mode and the diagrams follow. The moving dots are this pull request's data in motion

Thanks for using PR Lens! It's built by Coldtea, free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

@vercel

vercel Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
devframe Skipped Skipped Oct 1, 2026 12:58am UTC

@antfu

antfu commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

👁️‍🗨️ Review this pull request with grouped, summarized diffs at:
👉 https://pulls.review/gh/devframes/devframe/415?from=antfu

raw result

💭 analyzed by vercel-ai-gateway/anthropic/claude-sonnet-5
🕰️ 2026-10-01 00:28 UTC
🔗 head 0fadd97
🤖 automated by pulls.review

{
  "headSha": "0fadd97ad8d2937b797442bb9a158a4df8bf7505",
  "result": {
    "overallSummary": "Introduces a lightweight `t()` i18n system for `@devframes/hub-ui`: every user-facing string now routes through typed keys with 10 shipped locales, a new Settings → Appearance language picker persists the visitor's choice, and `createUi({ locale })` plus a republished connection let a same-origin frame inherit the resolved language at boot. Supporting changes cover Storybook/playground locale toggling, docs, and generated API snapshots.",
    "groups": [
      {
        "key": "i18n-infra",
        "label": "i18n infrastructure",
        "category": "core",
        "filePaths": [],
        "children": [
          {
            "key": "locale-resolution",
            "label": "Locale resolution & t()",
            "summary": "Defines the supported locale list, BCP-47 matching, the `t()`/`tAround()` helpers and the `locale` ref that resolves visitor pick → host default → browser language → English.",
            "category": "core",
            "filePaths": [
              "packages/hub-ui/src/locales.ts",
              "packages/hub-ui/src/client/i18n/index.ts",
              "packages/hub-ui/src/client/i18n/i18n.test.ts",
              "packages/hub-ui/src/client/state/locale.ts",
              "packages/hub-ui/src/client/state/locale.test.ts"
            ]
          },
          {
            "key": "connection-publishing",
            "label": "Publish locale on connection",
            "summary": "Exposes `storeConnection` from `devframe/client` and wires `setupLocale` into the embedded and standalone entry points so the resolved language is written back into the published connection for same-origin frames to inherit at boot.",
            "category": "api",
            "filePaths": [
              "packages/devframe/src/client/connection-storage.ts",
              "packages/devframe/src/client/index.ts",
              "packages/hub-ui/src/client/embedded/index.ts",
              "packages/hub-ui/src/client/standalone/main.ts"
            ]
          },
          {
            "key": "create-ui-option",
            "label": "createUi locale option",
            "summary": "Adds `createUi({ locale })` to seed the host's default UI language as `ConnectionMeta.configs.ui.locale`.",
            "category": "api",
            "filePaths": [
              "packages/hub-ui/src/index.ts",
              "packages/hub-ui/src/index.test.ts"
            ]
          }
        ]
      },
      {
        "key": "component-translations",
        "label": "Translate hub-ui components",
        "category": "ui",
        "filePaths": [],
        "children": [
          {
            "key": "command-palette",
            "label": "Command palette",
            "summary": "Replaces hardcoded command-palette strings (placeholder, empty/no-results states, footer hints, server badge) with `t()`/`tAround()`.",
            "category": "ui",
            "filePaths": [
              "packages/hub-ui/src/client/components/command-palette/CommandPalette.vue",
              "packages/hub-ui/src/client/components/command-palette/CommandPaletteItem.vue"
            ]
          },
          {
            "key": "display",
            "label": "Display components",
            "summary": "Translates the confirm dialog's default buttons and the OTP input's ARIA labels.",
            "category": "ui",
            "filePaths": [
              "packages/hub-ui/src/client/components/display/Confirm.vue",
              "packages/hub-ui/src/client/components/display/OtpInput.vue"
            ]
          },
          {
            "key": "dock",
            "label": "Dock chrome",
            "summary": "Translates dock labels, tooltips and context-menu entries, and sets `lang` on the color-scheme root so hyphenation, fonts and screen readers match the resolved locale.",
            "category": "ui",
            "filePaths": [
              "packages/hub-ui/src/client/components/dock/ColorSchemeRoot.vue",
              "packages/hub-ui/src/client/components/dock/Dock.vue",
              "packages/hub-ui/src/client/components/dock/DockContextMenu.ts",
              "packages/hub-ui/src/client/components/dock/DockEdge.vue",
              "packages/hub-ui/src/client/components/dock/DockGroupPopover.vue",
              "packages/hub-ui/src/client/components/dock/DockGroupSidebar.vue",
              "packages/hub-ui/src/client/components/dock/DockOverflowButton.vue"
            ]
          },
          {
            "key": "views-builtin",
            "label": "Settings & built-in views",
            "summary": "Translates the Settings tabs, Advanced/Docks/Shortcuts panes and the auth notice, and adds the new Appearance language `<select>` that persists the visitor's pick under `devframes-locale`.",
            "category": "ui",
            "filePaths": [
              "packages/hub-ui/src/client/components/views-builtin/SettingsAdvanced.vue",
              "packages/hub-ui/src/client/components/views-builtin/SettingsAppearance.vue",
              "packages/hub-ui/src/client/components/views-builtin/SettingsDocks.vue",
              "packages/hub-ui/src/client/components/views-builtin/SettingsShortcuts.vue",
              "packages/hub-ui/src/client/components/views-builtin/ViewBuiltinClientAuthNotice.vue",
              "packages/hub-ui/src/client/components/views-builtin/ViewBuiltinSettings.vue"
            ]
          },
          {
            "key": "views",
            "label": "Iframe & launcher views",
            "summary": "Translates loading/error/retry copy, iframe toolbar tooltips and launcher button states.",
            "category": "ui",
            "filePaths": [
              "packages/hub-ui/src/client/components/views/ViewAssetsError.vue",
              "packages/hub-ui/src/client/components/views/ViewDockRenderer.vue",
              "packages/hub-ui/src/client/components/views/ViewEntry.vue",
              "packages/hub-ui/src/client/components/views/ViewIframe.vue",
              "packages/hub-ui/src/client/components/views/ViewIframeLoading.vue",
              "packages/hub-ui/src/client/components/views/ViewLauncher.vue"
            ]
          },
          {
            "key": "state",
            "label": "Command & category labels",
            "summary": "Re-registers built-in commands reactively so their titles follow locale changes, and maps dock category keys through `t()` instead of a static English label table.",
            "category": "core",
            "filePaths": [
              "packages/hub-ui/src/client/state/context.ts",
              "packages/hub-ui/src/client/state/dock-settings.ts"
            ]
          }
        ]
      },
      {
        "key": "locale-files",
        "label": "Locale message files",
        "summary": "Adds the 151-key message file per shipped locale, `en.json` as the authoritative source and fallback; the non-English files are machine translations flagged for native review, kept in lockstep with `en.json` by the i18n test.",
        "category": "i18n",
        "filePaths": [
          "packages/hub-ui/src/client/i18n/locales/en.json",
          "packages/hub-ui/src/client/i18n/locales/zh-CN.json",
          "packages/hub-ui/src/client/i18n/locales/zh-TW.json",
          "packages/hub-ui/src/client/i18n/locales/ja.json",
          "packages/hub-ui/src/client/i18n/locales/ko.json",
          "packages/hub-ui/src/client/i18n/locales/es.json",
          "packages/hub-ui/src/client/i18n/locales/fr.json",
          "packages/hub-ui/src/client/i18n/locales/de.json",
          "packages/hub-ui/src/client/i18n/locales/pt-BR.json",
          "packages/hub-ui/src/client/i18n/locales/ru.json"
        ]
      },
      {
        "key": "storybook-playground",
        "label": "Storybook & playground locale",
        "summary": "Adds a Storybook toolbar language toggle and wires locale setup into the playground entry so both dev surfaces exercise the new i18n.",
        "category": "config",
        "filePaths": [
          "packages/hub-ui/.storybook/preview.ts",
          "packages/hub-ui/playground/main.ts"
        ]
      },
      {
        "key": "docs",
        "label": "Docs",
        "summary": "Documents the `locale` createUi option, how the resolved language propagates to same-origin frames, how to add a new language, and codifies the `t()`-only rule for hub-ui strings.",
        "category": "docs",
        "filePaths": [
          ".agents/06-design-system.md",
          "docs/content/1.guide/18.hub-initiate.md"
        ]
      },
      {
        "key": "snapshots",
        "label": "Generated API snapshots",
        "summary": "Regenerated public API snapshots reflecting `HUB_UI_LOCALES`, `CreateUiOptions.locale` and the newly exported `storeConnection`.",
        "category": "tests",
        "filePaths": [
          "tests/__snapshots__/tsnapi/@devframes/hub-ui/index.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/@devframes/hub-ui/index.snapshot.js",
          "tests/__snapshots__/tsnapi/devframe/client.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/devframe/client.snapshot.js"
        ]
      }
    ],
    "schemaVersion": 1,
    "source": "llm",
    "generatedAt": "2026-10-01T00:28:37.229Z",
    "model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
    "locale": "en"
  }
}

This branch was previously deployed

1 inactive deployment
Preview — 836a016f Deployed Oct 1, 2026 by vercel[bot]
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.

2 participants