feat(i18n): 管理端与玩家端三语支持(中/英/马来语)

- 管理后台 adminT 文案库、结算与代理端页面、表单校验
- 玩家端 vue-i18n 补全首页/公告/串关与 ms 文案
- Element Plus ms 语言包与共享 locale 工具
This commit is contained in:
2026-06-03 15:05:36 +08:00
parent 80adc0e928
commit cbfa18d1d3
63 changed files with 3081 additions and 1038 deletions

View File

@@ -0,0 +1,65 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import LocaleFlag from './LocaleFlag.vue';
import { useAppLocale } from '../composables/useAppLocale';
withDefaults(
defineProps<{
compact?: boolean;
}>(),
{ compact: false },
);
const { locale } = useI18n();
const { locales, setLocale } = useAppLocale();
async function onChange(code: string) {
await setLocale(code);
}
</script>
<template>
<div class="locale-switch" :class="{ compact }">
<LocaleFlag :locale="locale" :size="compact ? 16 : 18" />
<select
:value="locale"
class="locale-select"
:aria-label="compact ? 'Language' : undefined"
@change="onChange(($event.target as HTMLSelectElement).value)"
>
<option v-for="l in locales" :key="l.code" :value="l.code">
{{ l.label }}
</option>
</select>
</div>
</template>
<style scoped>
.locale-switch {
display: flex;
align-items: center;
gap: 5px;
height: 36px;
padding: 0 8px 0 6px;
border: 1px solid var(--border);
border-radius: 6px;
background: #0d0d0d;
box-sizing: border-box;
}
.locale-switch.compact {
height: auto;
padding: 2px 5px;
}
.locale-select {
background: transparent;
color: var(--primary-light);
border: none;
padding: 2px 2px 2px 0;
font-size: 11px;
font-weight: 700;
outline: none;
max-width: 120px;
}
</style>