Skip to content

feat(hub): localize dock, command and launcher titles with titleLocales - #417

Open
antfubot wants to merge 1 commit into
feat/hub-ui-i18nfrom
feat/localized-titles
Open

antfubot wants to merge 1 commit into
feat/hub-ui-i18nfrom
feat/localized-titles

Conversation

@antfubot

@antfubot antfubot commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #415. Refs #398.

What

  • Dock entries, commands and launchers get an optional titleLocales: Record<BCP47 tag, string> next to their plain title. The plain title stays the default, so every existing reader keeps working and a registrant adds languages without a breaking change. DevframeDockDefaults gets the same field so a devframe can localize the dock a hub synthesizes for it.
  • @devframes/hub (and /client) export resolveTitle(titled, locale) and matchLocale(tag, available): exact tag first, then the Traditional Chinese family (zh-HK → zh-TW), then the language prefix (pt-PT → pt-BR, en-GB → en), else the plain title.
  • The reference hub UI resolves every dock entry and command (recursively through children) against its own language setting at its two choke points (entries and commands computeds), so the dock rail, tooltips, settings rows, palette and shortcut rows follow the Language select from feat(hub-ui): translate the hub UI and add a language setting #415 with no per-component change. hub-ui's own matchLocale now delegates to the shared one.
  • Both reference hosts (examples/custom-hub-vite, examples/custom-hub-next) resolve against navigator.language, keeping parity.
  • The playground seeds a localized group and command; docs cover the field in the hub guide, the hub API reference and the build-your-own-hub-UI guide.

Verified in the playground: with the UI set to Japanese the group reads プレイグラウンドツール in the dock rail and the command palette, and an untranslated command still shows its English title.

Design notes

Sidecar field instead of widening title to a union: widening would have broken every entry.title reader (three localeCompare sorts, .toLowerCase() filters, iframe.title assignments the e2e specs select on, the MCP tool title), including third-party hub UI providers. Titles only for now; descriptions and launcher button text can follow the same *Locales pattern if wanted.

The tsnapi snapshots gain the two functions and two types. The declarations are inlined rather than extends DevframeTitled so tsnapi reads the change as additive.


Created with the help of an agent.

A registrant adds translations next to its plain title:
`titleLocales: { 'zh-CN': '构建', ja: 'ビルド' }`. The plain title stays the
default, so a reader that ignores the map keeps working. resolveTitle()
and matchLocale() from @devframes/hub pick the closest tag; the reference
hub UI resolves every entry and command against its own language setting,
and the example hosts resolve against the browser language.

refs #398
@coldtea-pr-lens

coldtea-pr-lens Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

◈ PR Lens

🟢 +0 new · 🟠 ~6 changed · 🔴 -0 removed · 1 flow · 15 files · commit 2de1408


Architecture

Architecture diagram for devframes/devframe at 2de1408

6 components touched across 3 lanes.

Play the interactive walkthrough


Inside the changed components — 2 views

Component view — Locale resolution

The title resolution and BCP 47 matching helpers exported by the client runtime

Architecture view of Component view — Locale resolution in devframes/devframe

Component view — UI title localization

Reactive localization across dock entries, command hierarchies, and launchers in the hub UI

Architecture view of Component view — UI title localization in devframes/devframe

Data flow

Data flow diagram for devframes/devframe at 2de1408

Resolving localized titles

Follow each request, response and payload


View

  • Architecture lens
  • Data flow lens
  • Expand every detail

Tip

The diagrams are links. Click one to open it on the canvas, then press W or click play to walk through the change

🪧 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
  • 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
  • Click the link under each diagram to open it on a canvas you can zoom, pan and step through
  • 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 Oct 1, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
devframe Ready Ready Preview Oct 1, 2026 1:00am 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/417?from=antfu

raw result

💭 analyzed by vercel-ai-gateway/anthropic/claude-sonnet-5
🕰️ 2026-10-01 01:02 UTC
🔗 head 2de1408
🤖 automated by pulls.review

{
  "headSha": "2de14085667434d8da644fbc8c0254f1c551f20f",
  "result": {
    "overallSummary": "Adds an optional `titleLocales` translation map alongside the existing `title` on dock entries, commands and launchers (and `DevframeDockDefaults`), with shared `resolveTitle`/`matchLocale` helpers exported from `@devframes/hub`. The reference hub UI and both example hosts resolve titles through these helpers at their rendering choke points so the dock, palette and settings rows follow the active language, with docs and tsnapi snapshots updated to match.",
    "groups": [
      {
        "key": "core-locale",
        "label": "Shared title localization",
        "summary": "Adds the sidecar `titleLocales` field to dock entries, commands, launchers and `DevframeDockDefaults`, plus the shared `resolveTitle`/`matchLocale` helpers (`@devframes/hub` and `/client`) that pick the closest translation without breaking existing plain-`title` readers.",
        "category": "core",
        "filePaths": [
          "packages/hub/src/index.ts",
          "packages/hub/src/locale.ts",
          "packages/hub/src/locale.test.ts",
          "packages/hub/src/client/index.ts",
          "packages/hub/src/types/commands.ts",
          "packages/hub/src/types/docks.ts",
          "packages/hub/src/types/index.ts",
          "packages/hub/src/types/locale.ts",
          "packages/devframe/src/types/devframe.ts"
        ]
      },
      {
        "key": "hub-ui",
        "label": "hub-ui localized titles",
        "summary": "Wires the reference hub UI to resolve `title` through the shared `matchLocale`/`resolveTitle` at its `entries`/`commands` choke points (recursing through command `children`), so the dock rail, tooltips, palette and shortcut rows follow the Language setting; hub-ui's own `matchLocale` now delegates to the shared one, and the playground seeds a localized group/command to exercise it.",
        "category": "ui",
        "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",
          "packages/hub-ui/src/client/state/commands.ts",
          "packages/hub-ui/src/client/state/context.ts",
          "packages/hub-ui/src/client/components/views/ViewLauncher.vue",
          "packages/hub-ui/playground/seed.ts"
        ]
      },
      {
        "key": "example-hosts",
        "label": "Example hub hosts",
        "summary": "Both reference hosts resolve dock/command titles against `navigator.language` via the new `resolveTitle`, keeping parity with the hub-ui reference implementation.",
        "category": "examples",
        "filePaths": [
          "examples/custom-hub-next/src/client/app/page.tsx",
          "examples/custom-hub-vite/src/client/main.ts"
        ]
      },
      {
        "key": "docs",
        "label": "Docs for titleLocales",
        "summary": "Documents the new `titleLocales` field and `resolveTitle` helper in the hub guide, the build-your-own-hub-UI guide and the hub API reference.",
        "category": "docs",
        "filePaths": [
          "docs/content/1.guide/16.hub.md",
          "docs/content/1.guide/22.build-your-own-hub-ui.md",
          "docs/content/8.references/6.hub-api.md"
        ]
      },
      {
        "key": "tsnapi-snapshots",
        "label": "tsnapi API snapshots",
        "summary": "Updates the public API surface snapshots to reflect the two new functions (`matchLocale`, `resolveTitle`) and two new types (`DevframeTitled`, `DevframeTitleLocales`), inlined rather than via `extends` so the diff reads as purely additive.",
        "category": "tests",
        "filePaths": [
          "tests/__snapshots__/tsnapi/@devframes/hub/client.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/@devframes/hub/client.snapshot.js",
          "tests/__snapshots__/tsnapi/@devframes/hub/index.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/@devframes/hub/index.snapshot.js",
          "tests/__snapshots__/tsnapi/@devframes/hub/types.snapshot.d.ts",
          "tests/__snapshots__/tsnapi/devframe/index.snapshot.d.ts"
        ]
      }
    ],
    "schemaVersion": 1,
    "source": "llm",
    "generatedAt": "2026-10-01T01:02:57.767Z",
    "model": "vercel-ai-gateway/anthropic/claude-sonnet-5",
    "locale": "en"
  }
}

This branch was successfully deployed

1 active deployment
Preview — 2de14085 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