fix(channels): show real i18n label for single-variant types like opencode_go#1734
Conversation
…ncode_go `groupTypesByPrefix` always splits a channel type on `_` and groups by the bare prefix so that e.g. `deepseek` + `deepseek_anthropic` collapse into one `deepseek` tab. That works as long as the bare prefix is itself a registered channel type with an i18n entry. `opencode_go` has no sibling `opencode`, so the tab gets labelled with the fallback raw key `channels.types.opencode` instead of `OpenCode Go`. Same trap would hit any future single-variant `<prefix>_<suffix>` type. Fix: only fold under `<prefix>` when `<prefix>` itself also appears in the batch; otherwise keep the full type name so the existing i18n entry (`channels.types.opencode_go = "OpenCode Go"`) is used.
Greptile SummaryThis PR fixes a tab-label i18n regression on the Channels page where single-variant underscore types like
Confidence Score: 5/5Safe to merge — one small, well-reasoned function change with no API or schema impact. The change is tightly scoped to the grouping heuristic inside No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["typeCounts: ChannelTypeCount[]"] --> B["Build knownTypes Set\n(all type strings)"]
B --> C["For each { type, count }"]
C --> D["candidatePrefix = type.split('_')[0]"]
D --> E{"knownTypes.has(candidatePrefix)?"}
E -- "YES (e.g. 'deepseek' present for 'deepseek_anthropic')" --> F["prefix = candidatePrefix\ne.g. 'deepseek'"]
E -- "NO (e.g. no bare 'opencode' for 'opencode_go')" --> G["prefix = type\ne.g. 'opencode_go'"]
F --> H["Fold into existing group"]
G --> I["Create own group with full type name"]
H --> J["t('channels.types.deepseek') ✅"]
I --> K["t('channels.types.opencode_go') = OpenCode Go ✅"]
Reviews (1): Last reviewed commit: "fix(channels): show real i18n label for ..." | Re-trigger Greptile |
…ge title config, request filter preservation, structured response items Upstream commits merged: - fix: model settings dialog overflow (looplj#1716) - chore: custom page title config after login (looplj#1720) - feat: preserve request log filters on detail navigation (looplj#1723) - feat(llm): support responses websocket sessions (looplj#1730) - chore: add claude-opus-4-7 to claudecode DefaultModels (looplj#1733) - fix(channels): show real i18n label for single-variant types (looplj#1734) - fix(llm): accept structured response item arguments (looplj#1728) Resolved 4 import-path conflicts (looplj -> ldm2060) and adapted session scope integration in auth middleware. Fixed Windows flaky WebSocket test for platform-specific socket error messages. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ncode_go (looplj#1734) `groupTypesByPrefix` always splits a channel type on `_` and groups by the bare prefix so that e.g. `deepseek` + `deepseek_anthropic` collapse into one `deepseek` tab. That works as long as the bare prefix is itself a registered channel type with an i18n entry. `opencode_go` has no sibling `opencode`, so the tab gets labelled with the fallback raw key `channels.types.opencode` instead of `OpenCode Go`. Same trap would hit any future single-variant `<prefix>_<suffix>` type. Fix: only fold under `<prefix>` when `<prefix>` itself also appears in the batch; otherwise keep the full type name so the existing i18n entry (`channels.types.opencode_go = "OpenCode Go"`) is used. Co-authored-by: qinkangdeid <qinkangdeid@gmail.com>
Bug
On the Channels page, the filter tab for the only
opencode_gochannel renders as the raw i18n keychannels.types.opencode(instead of "OpenCode Go"), even thoughfrontend/src/locales/{en,zh-CN}/channels.jsonalready definechannels.types.opencode_go = "OpenCode Go". The right-hand provider tag on the row itself renders correctly:Root cause
channels-type-tabs.tsxgroupTypesByPrefixalways splits the channel type on_and groups by the bare prefix:This is by design — it collapses e.g.
deepseek+deepseek_anthropicinto a singledeepseektab. But the design assumes the bare prefix is itself a registered channel type with its own i18n entry.opencode_gohas no siblingopencode. After splitting, the tab is keyed onopencode, the i18n lookup misses, and the UI falls back to the raw key. Any future single-variant<prefix>_<suffix>type would hit the same trap (e.g. if someone added a_pro-only variant).Fix
Only fold a
<prefix>_<suffix>type under<prefix>when<prefix>is itself present in the same batch as a known channel type. Otherwise keep the full type name as the group key so the existing i18n entry is used.opencode_go(no siblingopencode) → group key staysopencode_go→ uses existingchannels.types.opencode_go = "OpenCode Go"✅deepseek+deepseek_anthropic(both present) → both fold todeepseek→ existing behaviour preserved ✅anthropic+anthropic_aws+anthropic_gcp+anthropic_fake→ all fold toanthropic→ existing behaviour preserved ✅One-file, eight-line change in
frontend/src/features/channels/components/channels-type-tabs.tsx.Test plan
channels.types.opencode_goare already present in bothenandzh-CN(no locale changes needed)frontend/src/locales/zh-CN/channels.json— no regressions in the other multi-variant groups (anthropic_*,deepseek_*,doubao_*,gemini_*,github_*,longcat_*,minimax_*,moonshot_*,nanogpt_*,openai_*,zai_*,zhipu_*,bailian_*)