Files
codex-proxy-rs/frontend/src/components/client-profile/ProviderRequestProfilesEditor.vue
T
39b35d46a0 feat(frontend): add reactive localization and refine admin layouts (#501)
* feat(frontend): add English and Traditional Chinese locales

* fix(frontend): capitalize the English login key label

* fix(frontend): capitalize standalone English labels

* feat(frontend): add reactive localization and refine admin layouts

Replace DOM text translation with domain-based Vue I18n resources for English, Simplified Chinese, and Traditional Chinese. Localize shared controls, notifications, charts, and key usage while refining table alignment, menus, and compact labels.

Expose semantic usage-window and trend-metric identifiers from the API. Pin the UI and workbench dependencies to published feature commits and preserve the original font defaults.

Co-authored-by: Codex <noreply@openai.com>

---------

Co-authored-by: Jimbb <14995924+jimbb@users.noreply.github.com>
Co-authored-by: Zyy <zyycn@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
2026-10-23 11:40:38 +08:00

105 lines
3.2 KiB
Vue

<script setup lang="ts">
import type { ClientProfileSelection, ProviderRequestProfile, ProviderRequestProfiles, XaiClientProfileSelection } from '@/api/modules/settings/profiles'
import { ZSegmented } from '@codex-proxy/ui'
import { computed, shallowRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { formatProviderLabel, PROVIDER_IDS, providerIcon } from '@/utils/providers'
import ClientProfileEditor from './ClientProfileEditor.vue'
import XaiClientProfileEditor from './XaiClientProfileEditor.vue'
withDefaults(defineProps<{
active?: boolean
disabled?: boolean
allowInherit?: boolean
}>(), {
active: true,
disabled: false,
allowInherit: false,
})
const { t } = useI18n({ useScope: 'global' })
const model = defineModel<ProviderRequestProfiles>({ required: true })
const provider = shallowRef<(typeof PROVIDER_IDS)[number]>('openai')
const providerOptions = PROVIDER_IDS.map(value => ({
value,
label: formatProviderLabel(value),
icon: providerIcon(value),
}))
const providerSelectorStyle = { width: `${providerOptions.length * 40}px` }
const openai = profileModel<ClientProfileSelection>('openai')
const xai = profileModel<XaiClientProfileSelection>('xai')
function profileModel<T extends object>(providerId: string) {
return computed<T | null>({
get: () => (model.value[providerId] as T | undefined) ?? null,
set: value => updateProfile(providerId, value as ProviderRequestProfile | null),
})
}
function updateProfile(providerId: string, value: ProviderRequestProfile | null) {
const profiles = { ...model.value }
if (value === null)
delete profiles[providerId]
else
profiles[providerId] = value
model.value = profiles
}
</script>
<template>
<div class="grid min-w-0 gap-4">
<div v-if="!allowInherit" class="flex flex-wrap items-start justify-between gap-3">
<slot name="heading" />
<ZSegmented
v-model="provider"
class="ml-auto max-w-full shrink-0"
:aria-label="t('settings.clientProfile.clientIdentityProvider')"
:options="providerOptions"
:disabled="disabled"
:style="providerSelectorStyle"
display="icon"
/>
</div>
<ClientProfileEditor
v-if="provider === 'openai'"
v-model="openai"
:allow-inherit="allowInherit"
:active="active"
:disabled="disabled"
>
<template #source-extra>
<ZSegmented
v-model="provider"
class="max-w-full shrink-0"
:aria-label="t('settings.clientProfile.upstreamIdentityPlatform')"
:options="providerOptions"
:disabled="disabled"
:style="providerSelectorStyle"
display="icon"
/>
</template>
</ClientProfileEditor>
<XaiClientProfileEditor
v-else
v-model="xai"
:allow-inherit="allowInherit"
:active="active"
:disabled="disabled"
>
<template #source-extra>
<ZSegmented
v-model="provider"
class="max-w-full shrink-0"
:aria-label="t('settings.clientProfile.upstreamIdentityPlatform')"
:options="providerOptions"
:disabled="disabled"
:style="providerSelectorStyle"
display="icon"
/>
</template>
</XaiClientProfileEditor>
</div>
</template>