fix(i18n): localize special tab titles at render time (#66)

* fix(i18n): localize special tab titles at render time

Special tabs (settings/scheduled/traces) carry a stored title that was
captured at the locale active when the tab was first opened. That title
is persisted to localStorage by saveTabs() and restored verbatim by
restoreTabs(), so a user who first opened Settings in English and then
switched to Chinese kept seeing 'Settings' in the tab bar forever.

The label is also already retrievable from i18n at render time
(sidebar.settings, sidebar.scheduled, trace.list.title) — these keys
exist in all locales. Compute displayTitle from tab.type in TabItem
and ignore the stored title for special tabs. Session/terminal/trace
tabs still use the stored title as before.

The fix is localStorage-state agnostic: existing users with the stale
'Settings' title see the corrected zh label on next render, no migration
or storage cleanup needed.

* ci: trigger rerun with allow-missing-tests label

---------

Co-authored-by: 你的姓名 <you@example.com>
This commit is contained in:
小橙子 2026-06-17 01:06:17 +08:00 committed by GitHub
parent 59b7b124fa
commit 257a8f9fa2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -551,6 +551,18 @@ const TabItem = forwardRef<HTMLDivElement, {
onContextMenu: (e: React.MouseEvent) => void
onMouseDown: (event: React.MouseEvent) => void
}>(({ tab, isRunning, isActive, isDragOver, isDragging, dragOffsetX, runningLabel, onClick, onClose, onContextMenu, onMouseDown }, ref) => {
const t = useTranslation()
// Special tabs (settings/scheduled/traces) carry a stored title from when
// they were first opened; that title is frozen at the locale active at the
// time and persists across locale switches via localStorage. Always derive
// the label from i18n at render time so the current locale wins.
const displayTitle = tab.type === 'settings'
? t('sidebar.settings')
: tab.type === 'scheduled'
? t('sidebar.scheduled')
: tab.type === 'traces'
? t('trace.list.title')
: (tab.title || 'Untitled')
return (
<div
ref={ref}
@ -596,12 +608,12 @@ const TabItem = forwardRef<HTMLDivElement, {
)}
<span className={`flex-1 truncate text-xs ${isActive ? 'text-[var(--color-text-primary)] font-medium' : 'text-[var(--color-text-secondary)]'}`}>
{tab.title || 'Untitled'}
{displayTitle}
</span>
<button
type="button"
aria-label={`Close ${tab.title || 'Untitled'}`}
aria-label={`Close ${displayTitle}`}
onMouseDown={(e) => { e.stopPropagation() }}
onClick={(e) => { e.stopPropagation(); onClose() }}
className="flex-shrink-0 -mr-0.5 inline-flex h-3 w-3 items-center justify-center bg-transparent p-0 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-[opacity,color] text-[var(--color-text-tertiary)] hover:text-[var(--color-text-secondary)] focus-visible:outline-none"