Skip to content

fix(channels): show real i18n label for single-variant types like opencode_go#1734

Merged
looplj merged 1 commit into
looplj:unstablefrom
qinkangdeid:fix/i18n-opencode-channel-type-key
May 28, 2026
Merged

fix(channels): show real i18n label for single-variant types like opencode_go#1734
looplj merged 1 commit into
looplj:unstablefrom
qinkangdeid:fix/i18n-opencode-channel-type-key

Conversation

@qinkangdeid

Copy link
Copy Markdown
Contributor

Bug

On the Channels page, the filter tab for the only opencode_go channel renders as the raw i18n key channels.types.opencode (instead of "OpenCode Go"), even though frontend/src/locales/{en,zh-CN}/channels.json already define channels.types.opencode_go = "OpenCode Go". The right-hand provider tag on the row itself renders correctly:

screenshot

Root cause

channels-type-tabs.tsx groupTypesByPrefix always splits the channel type on _ and groups by the bare prefix:

const prefix = type.split('_')[0];

This is by design — it collapses e.g. deepseek + deepseek_anthropic into a single deepseek tab. But the design assumes the bare prefix is itself a registered channel type with its own i18n entry.

opencode_go has no sibling opencode. After splitting, the tab is keyed on opencode, 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 sibling opencode) → group key stays opencode_go → uses existing channels.types.opencode_go = "OpenCode Go"
  • deepseek + deepseek_anthropic (both present) → both fold to deepseek → existing behaviour preserved ✅
  • anthropic + anthropic_aws + anthropic_gcp + anthropic_fake → all fold to anthropic → existing behaviour preserved ✅

One-file, eight-line change in frontend/src/features/channels/components/channels-type-tabs.tsx.

Test plan

  • Verified the i18n entries for channels.types.opencode_go are already present in both en and zh-CN (no locale changes needed)
  • Manually traced the grouping logic with the new rule against the 52 channel types in 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_*)
  • CI green

…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-apps

greptile-apps Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a tab-label i18n regression on the Channels page where single-variant underscore types like opencode_go (with no sibling bare opencode type) were rendered with the raw key channels.types.opencode rather than the already-defined translation "OpenCode Go".

  • Root cause fixed: groupTypesByPrefix in channels-type-tabs.tsx previously always split on _ and used the bare prefix as the group key; the new logic builds a Set of all known types first and only folds prefix_suffix under prefix when prefix itself is present, so opencode_go stays as its own group key and picks up the correct i18n entry.
  • No regressions: All existing multi-variant groups (anthropic_*, deepseek_*, openai_*, etc.) still fold correctly because their bare prefix (e.g., anthropic, deepseek) is always present in the batch; icon lookup via CHANNEL_CONFIGS['opencode_go'] and the parent's startsWith-based tab filter both work correctly with the new full-type-name key.

Confidence Score: 5/5

Safe to merge — one small, well-reasoned function change with no API or schema impact.

The change is tightly scoped to the grouping heuristic inside groupTypesByPrefix. The new knownTypes set is built once per call from the same input array, so there is no performance concern. All pre-existing multi-variant groups retain their existing behavior because their bare prefix is always present in the batch. The icon lookup via CHANNEL_CONFIGS['opencode_go'] resolves correctly since that key exists. The parent's startsWith-based tab filter works correctly with the full type name as the tab value.

No files require special attention.

Important Files Changed

Filename Overview
frontend/src/features/channels/components/channels-type-tabs.tsx Fixes i18n label fallback for single-variant underscore types (e.g. opencode_go) by only folding prefix_suffix under prefix when prefix itself is a known channel type in the current batch; icon lookup, tab filtering, and all existing multi-variant groups are unaffected.

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 ✅"]
Loading

Reviews (1): Last reviewed commit: "fix(channels): show real i18n label for ..." | Re-trigger Greptile

@looplj looplj merged commit ea31f44 into looplj:unstable May 28, 2026
4 checks passed
ldm0206 added a commit to ldm2060/axonhub that referenced this pull request May 29, 2026
…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>
junjiangao pushed a commit to junjiangao/axonhub that referenced this pull request May 30, 2026
…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>
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