fix(i18n): 运行模式/权限/沙箱菜单选项改用 labelKey 动态渲染,切语言即时生效

state.ts 四个选项数组此前在模块顶层用 t() 固化翻译字符串,切换语言后不更新、需刷新页面。改为存 labelKey/descriptionKey,渲染处动态求值(模板 $t / computed t(matched.labelKey)),与 PersonalizationDrawer 既有规范模式对齐。tsc/build/i18n 审计均通过。
This commit is contained in:
JOJO 2026-08-29 10:09:08 +08:00
parent a2cf547400
commit 4aac18f7bb
4 changed files with 40 additions and 39 deletions

View File

@ -51,13 +51,13 @@ export const permissionMethods = {
void currentLocale.value; void currentLocale.value;
const options = Array.isArray(this.permissionModeOptions) ? this.permissionModeOptions : []; const options = Array.isArray(this.permissionModeOptions) ? this.permissionModeOptions : [];
const hit = options.find((item) => item.value === mode); const hit = options.find((item) => item.value === mode);
return hit ? hit.label : mode || t('appUi.unknown'); return hit ? t(hit.labelKey) : mode || t('appUi.unknown');
}, },
getExecutionModeLabel(mode) { getExecutionModeLabel(mode) {
void currentLocale.value; void currentLocale.value;
const options = Array.isArray(this.executionModeOptions) ? this.executionModeOptions : []; const options = Array.isArray(this.executionModeOptions) ? this.executionModeOptions : [];
const hit = options.find((item) => item.value === mode); const hit = options.find((item) => item.value === mode);
return hit ? hit.label : mode || t('appUi.unknown'); return hit ? t(hit.labelKey) : mode || t('appUi.unknown');
}, },
async changePermissionMode(mode) { async changePermissionMode(mode) {
const target = String(mode || '') const target = String(mode || '')

View File

@ -11,7 +11,7 @@ export const workModeMethods = {
void currentLocale.value; void currentLocale.value;
const options = Array.isArray(this.workModeOptions) ? this.workModeOptions : []; const options = Array.isArray(this.workModeOptions) ? this.workModeOptions : [];
const hit = options.find((item) => item.value === mode); const hit = options.find((item) => item.value === mode);
return hit ? hit.label : mode || t('appUi.unknown'); return hit ? t(hit.labelKey) : mode || t('appUi.unknown');
}, },
async fetchWorkMode() { async fetchWorkMode() {
try { try {

View File

@ -196,13 +196,13 @@ export function dataState() {
networkPermissionOptions: [ networkPermissionOptions: [
{ {
value: 'restricted', value: 'restricted',
label: t('appUi.networkRestricted'), labelKey: 'appUi.networkRestricted',
description: t('appCore.networkRestrictedDesc') descriptionKey: 'appCore.networkRestrictedDesc'
}, },
{ {
value: 'full', value: 'full',
label: t('appUi.networkFull'), labelKey: 'appUi.networkFull',
description: t('appCore.networkFullDesc') descriptionKey: 'appCore.networkFullDesc'
} }
], ],
workModeMenuOpen: false, workModeMenuOpen: false,
@ -210,18 +210,18 @@ export function dataState() {
workModeOptions: [ workModeOptions: [
{ {
value: 'plan', value: 'plan',
label: t('appUi.workModePlan'), labelKey: 'appUi.workModePlan',
description: t('appCore.workModePlanDesc') descriptionKey: 'appCore.workModePlanDesc'
}, },
{ {
value: 'ask', value: 'ask',
label: t('appUi.workModeAsk'), labelKey: 'appUi.workModeAsk',
description: t('appCore.workModeAskDesc') descriptionKey: 'appCore.workModeAskDesc'
}, },
{ {
value: 'execute', value: 'execute',
label: t('appUi.workModeExecute'), labelKey: 'appUi.workModeExecute',
description: t('appCore.workModeExecuteDesc') descriptionKey: 'appCore.workModeExecuteDesc'
} }
], ],
pathAuthorizationDialogOpen: false, pathAuthorizationDialogOpen: false,
@ -256,35 +256,35 @@ export function dataState() {
permissionModeOptions: [ permissionModeOptions: [
{ {
value: 'readonly', value: 'readonly',
label: t('personalization.permissionReadonly'), labelKey: 'personalization.permissionReadonly',
description: t('appCore.permissionReadonlyDesc') descriptionKey: 'appCore.permissionReadonlyDesc'
}, },
{ {
value: 'approval', value: 'approval',
label: t('appCore.permissionApproval'), labelKey: 'appCore.permissionApproval',
description: t('appCore.permissionApprovalDesc') descriptionKey: 'appCore.permissionApprovalDesc'
}, },
{ {
value: 'auto_approval', value: 'auto_approval',
label: t('appCore.permissionAutoApproval'), labelKey: 'appCore.permissionAutoApproval',
description: t('appCore.permissionAutoApprovalDesc') descriptionKey: 'appCore.permissionAutoApprovalDesc'
}, },
{ {
value: 'unrestricted', value: 'unrestricted',
label: t('appCore.permissionUnrestricted'), labelKey: 'appCore.permissionUnrestricted',
description: t('appCore.permissionUnrestrictedDesc') descriptionKey: 'appCore.permissionUnrestrictedDesc'
} }
], ],
executionModeOptions: [ executionModeOptions: [
{ {
value: 'sandbox', value: 'sandbox',
label: t('input.executionSandbox'), labelKey: 'input.executionSandbox',
description: t('appCore.executionSandboxDesc') descriptionKey: 'appCore.executionSandboxDesc'
}, },
{ {
value: 'direct', value: 'direct',
label: t('input.executionFullAccess'), labelKey: 'input.executionFullAccess',
description: t('appCore.executionDirectDesc') descriptionKey: 'appCore.executionDirectDesc'
} }
], ],
pendingToolApprovals: [], pendingToolApprovals: [],

View File

@ -375,8 +375,8 @@
:class="{ 'is-active': option.value === currentWorkMode }" :class="{ 'is-active': option.value === currentWorkMode }"
@click.stop="$emit('change-work-mode', option.value)" @click.stop="$emit('change-work-mode', option.value)"
> >
<span class="agent-type-switcher__menu-label">{{ option.label }}</span> <span class="agent-type-switcher__menu-label">{{ $t(option.labelKey) }}</span>
<span class="agent-type-switcher__menu-desc">{{ option.description }}</span> <span class="agent-type-switcher__menu-desc">{{ $t(option.descriptionKey) }}</span>
</button> </button>
</div> </div>
</div> </div>
@ -546,8 +546,8 @@
:disabled="permissionLockedByPlan" :disabled="permissionLockedByPlan"
@click="$emit('change-permission-mode', option.value)" @click="$emit('change-permission-mode', option.value)"
> >
<span class="permission-switcher__item-label">{{ option.label }}</span> <span class="permission-switcher__item-label">{{ $t(option.labelKey) }}</span>
<span class="permission-switcher__item-desc">{{ option.description }}</span> <span class="permission-switcher__item-desc">{{ $t(option.descriptionKey) }}</span>
</button> </button>
</div> </div>
<div <div
@ -572,9 +572,9 @@
<span <span
class="permission-switcher__item-label" class="permission-switcher__item-label"
:class="{ 'permission-switcher__item-label--warn': option.value === 'direct' }" :class="{ 'permission-switcher__item-label--warn': option.value === 'direct' }"
>{{ option.label }}</span >{{ $t(option.labelKey) }}</span
> >
<span class="permission-switcher__item-desc">{{ option.description }}</span> <span class="permission-switcher__item-desc">{{ $t(option.descriptionKey) }}</span>
</button> </button>
</div> </div>
<div <div
@ -595,9 +595,9 @@
<span <span
class="permission-switcher__item-label" class="permission-switcher__item-label"
:class="{ 'permission-switcher__item-label--warn': option.value === 'full' }" :class="{ 'permission-switcher__item-label--warn': option.value === 'full' }"
>{{ option.label }}</span >{{ $t(option.labelKey) }}</span
> >
<span class="permission-switcher__item-desc">{{ option.description }}</span> <span class="permission-switcher__item-desc">{{ $t(option.descriptionKey) }}</span>
</button> </button>
</div> </div>
</div> </div>
@ -756,13 +756,13 @@ const props = defineProps<{
blockConversationReview?: boolean; blockConversationReview?: boolean;
currentPermissionMode: 'readonly' | 'approval' | 'auto_approval' | 'unrestricted'; currentPermissionMode: 'readonly' | 'approval' | 'auto_approval' | 'unrestricted';
permissionMenuOpen: boolean; permissionMenuOpen: boolean;
permissionOptions: Array<{ value: string; label: string; description: string }>; permissionOptions: Array<{ value: string; labelKey: string; descriptionKey: string }>;
executionModeEnabled?: boolean; executionModeEnabled?: boolean;
currentExecutionMode?: 'sandbox' | 'direct'; currentExecutionMode?: 'sandbox' | 'direct';
executionModeOptions?: Array<{ value: string; label: string; description: string }>; executionModeOptions?: Array<{ value: string; labelKey: string; descriptionKey: string }>;
networkPermissionEnabled?: boolean; networkPermissionEnabled?: boolean;
currentNetworkPermission?: 'restricted' | 'full'; currentNetworkPermission?: 'restricted' | 'full';
networkPermissionOptions?: Array<{ value: string; label: string; description: string }>; networkPermissionOptions?: Array<{ value: string; labelKey: string; descriptionKey: string }>;
currentContextTokens: number; currentContextTokens: number;
versioningEnabled?: boolean; versioningEnabled?: boolean;
runtimeQueuedMessages?: Array<{ id: string; text: string }>; runtimeQueuedMessages?: Array<{ id: string; text: string }>;
@ -790,7 +790,7 @@ const props = defineProps<{
/** 运行模式菜单是否展开 */ /** 运行模式菜单是否展开 */
workModeMenuOpen?: boolean; workModeMenuOpen?: boolean;
/** 运行模式选项 */ /** 运行模式选项 */
workModeOptions?: Array<{ value: string; label: string; description: string }>; workModeOptions?: Array<{ value: string; labelKey: string; descriptionKey: string }>;
/** host/docker 项目模式下的工作区列表(/菜单「切换工作区」数据源) */ /** host/docker 项目模式下的工作区列表(/菜单「切换工作区」数据源) */
hostWorkspaces?: Array<{ hostWorkspaces?: Array<{
workspace_id: string; workspace_id: string;
@ -3320,10 +3320,11 @@ const triggerQuickUpload = () => {
}; };
const currentPermissionLabel = computed(() => { const currentPermissionLabel = computed(() => {
void currentLocale.value;
const matched = (props.permissionOptions || []).find( const matched = (props.permissionOptions || []).find(
(item) => item.value === props.currentPermissionMode (item) => item.value === props.currentPermissionMode
); );
return matched ? matched.label : props.currentPermissionMode; return matched ? t(matched.labelKey) : props.currentPermissionMode;
}); });
/** 对话类型选择器:选项定义(响应式:随语言切换刷新) */ /** 对话类型选择器:选项定义(响应式:随语言切换刷新) */
@ -3364,7 +3365,7 @@ const workModeLabel = computed(() => {
const matched = (props.workModeOptions || []).find( const matched = (props.workModeOptions || []).find(
(item) => item.value === props.currentWorkMode (item) => item.value === props.currentWorkMode
); );
return matched ? matched.label : props.currentWorkMode || t('input.workModePlanFallback'); return matched ? t(matched.labelKey) : props.currentWorkMode || t('input.workModePlanFallback');
}); });
/** 计划模式下权限被锁定为只读UI 禁用 + 后端强制) */ /** 计划模式下权限被锁定为只读UI 禁用 + 后端强制) */