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

@@ -1,6 +1,18 @@
import type { EChartsOption } from 'echarts';
import type { AdminLocale } from '../i18n/admin-messages';
import { formatAmount, formatAmountFull } from './format-amount';
export type ChartI18n = {
locale?: AdminLocale;
betCountSeries: string;
axisAmount: string;
axisCount: string;
countSuffix: string;
pieTooltip: string;
noData: string;
pieEmpty: string;
};
const tooltipBase = {
backgroundColor: '#141414',
borderColor: '#2a2a2a',
@@ -110,7 +122,10 @@ export function buildMultiLineChartOption(
export function buildPieChartOption(
title: string,
segments: PieSegment[],
i18n?: Partial<ChartI18n>,
): EChartsOption {
const loc = i18n?.locale;
const noData = i18n?.noData ?? '暂无数据';
const data = segments.map((s) => ({
name: s.label,
value: s.value,
@@ -122,7 +137,7 @@ export function buildPieChartOption(
tooltip: {
...tooltipBase,
trigger: 'item',
formatter: '{b}{c}{d}%',
formatter: i18n?.pieTooltip ?? '{b}{c}{d}%',
},
legend: {
orient: 'vertical',
@@ -151,14 +166,15 @@ export function buildPieChartOption(
label: { fontSize: 12, fontWeight: 'bold' },
scaleSize: 6,
},
data: data.length ? data : [{ name: '暂无数据', value: 1, itemStyle: { color: '#333' } }],
data: data.length ? data : [{ name: noData, value: 1, itemStyle: { color: '#333' } }],
},
],
};
}
function fmtCount(v: number) {
return v.toLocaleString('zh-CN', { maximumFractionDigits: 0 });
function fmtCount(v: number, locale?: AdminLocale) {
const tag = locale ?? 'zh-CN';
return v.toLocaleString(tag, { maximumFractionDigits: 0 });
}
/** 7 日金额折线 + 注单柱(双 Y 轴),一图看清趋势 */
@@ -166,7 +182,11 @@ export function buildCombinedTrendOption(
labels: string[],
amountSeries: ChartSeries[],
betCounts: number[],
i18n: ChartI18n,
): EChartsOption {
const loc = i18n.locale;
const betCountName = i18n.betCountSeries;
const countSuffix = i18n.countSuffix;
return {
backgroundColor: 'transparent',
color: [...amountSeries.map((s) => s.color), '#fb923c'],
@@ -178,9 +198,10 @@ export function buildCombinedTrendOption(
return items
.map((p) => {
const v = Number(p.value ?? 0);
const isCount = p.seriesName === '注单笔数';
const val = isCount ? `${fmtCount(v)}` : formatAmountFull(v);
return `${p.marker ?? ''}${p.seriesName}${val}`;
const isCount = p.seriesName === betCountName;
const val = isCount ? `${fmtCount(v, loc)} ${countSuffix}` : formatAmountFull(v, loc);
const sep = loc?.startsWith('zh') ? '' : ': ';
return `${p.marker ?? ''}${p.seriesName}${sep}${val}`;
})
.join('<br/>');
},
@@ -202,16 +223,16 @@ export function buildCombinedTrendOption(
yAxis: [
{
type: 'value',
name: '金额',
name: i18n.axisAmount,
nameTextStyle: { color: '#666', fontSize: 10 },
axisLabel: { ...axisLabel, formatter: (v: number) => formatAmount(v) },
axisLabel: { ...axisLabel, formatter: (v: number) => formatAmount(v, 2, loc) },
splitLine,
},
{
type: 'value',
name: '笔数',
name: i18n.axisCount,
nameTextStyle: { color: '#666', fontSize: 10 },
axisLabel: { ...axisLabel, formatter: (v: number) => fmtCount(v) },
axisLabel: { ...axisLabel, formatter: (v: number) => fmtCount(v, loc) },
splitLine: { show: false },
},
],
@@ -228,7 +249,7 @@ export function buildCombinedTrendOption(
lineStyle: { color: s.color, width: 2 },
})),
{
name: '注单笔数',
name: betCountName,
type: 'bar',
yAxisIndex: 1,
data: betCounts,
@@ -242,7 +263,10 @@ export function buildCombinedTrendOption(
/** 三个饼图并排,占一张图 */
export function buildTriplePieOption(
blocks: { title: string; segments: PieSegment[] }[],
i18n?: Partial<ChartI18n>,
): EChartsOption {
const pieEmpty = i18n?.pieEmpty ?? '暂无';
const pieTooltip = i18n?.pieTooltip ?? '{b}{c}{d}%';
const slots = [
{ center: ['18%', '58%'] as [string, string], titleLeft: '14%' },
{ center: ['50%', '58%'] as [string, string], titleLeft: '46%' },
@@ -254,7 +278,7 @@ export function buildTriplePieOption(
tooltip: {
...tooltipBase,
trigger: 'item',
formatter: '{b}{c}{d}%',
formatter: pieTooltip,
},
graphic: blocks.map((b, i) => ({
type: 'text' as const,
@@ -283,7 +307,7 @@ export function buildTriplePieOption(
labelLine: { show: false },
data: data.length
? data
: [{ name: '暂无', value: 1, itemStyle: { color: '#333' } }],
: [{ name: pieEmpty, value: 1, itemStyle: { color: '#333' } }],
};
}),
};