Skip to content

Commit 7ee0e52

Browse files
Merge pull request #43 from Maa-NTE/feature/homepage-i18n
feat(i18n): 首页i18n
2 parents 55fcf62 + 771918a commit 7ee0e52

11 files changed

Lines changed: 545 additions & 172 deletions

File tree

docs/.vuepress/components/HomeAlertBar.vue

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { computed, watchEffect } from 'vue'
33
import { useData } from 'vuepress/client'
4+
import { useLocale } from '../composables/useLocale.js'
45
56
interface TopAlertConfig {
67
enabled?: boolean
@@ -16,6 +17,13 @@ interface TopAlertConfig {
1617
}
1718
1819
const { frontmatter } = useData()
20+
const { currentLocale } = useLocale()
21+
22+
const i18n = computed(() => {
23+
if (currentLocale.value === 'en') return { label: 'Warning', ariaLabel: 'Site Notice' }
24+
if (currentLocale.value === 'ja') return { label: '注意', ariaLabel: 'サイト通知' }
25+
return { label: '警告', ariaLabel: '站点通知' }
26+
})
1927
2028
const homePage = computed(() => frontmatter.value.pageLayout === 'home')
2129
@@ -36,7 +44,7 @@ const enabled = computed(() => {
3644
3745
const text = computed(() => topAlert.value?.text?.trim() ?? '')
3846
const link = computed(() => topAlert.value?.link?.trim() ?? '')
39-
const label = computed(() => topAlert.value?.label?.trim() || '警告')
47+
const label = computed(() => topAlert.value?.label?.trim() || i18n.value.label)
4048
const duration = computed(() => {
4149
const speed = Number(topAlert.value?.speed)
4250
return Number.isFinite(speed) && speed > 0 ? `${speed}s` : '26s'
@@ -67,7 +75,7 @@ watchEffect(() => {
6775
:style="barStyle"
6876
role="status"
6977
aria-live="polite"
70-
aria-label="站点通知"
78+
:aria-label="i18n.ariaLabel"
7179
>
7280
<div class="home-alert-bar__inner">
7381
<div class="home-alert-bar__track" :style="{ '--home-alert-duration': duration }">

docs/.vuepress/components/QQGroupJoin.vue

Lines changed: 104 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,92 @@
11
<script setup lang="ts">
22
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
33
import { withBase } from 'vuepress/client'
4+
import { useLocale } from '../composables/useLocale.js'
5+
6+
const { currentLocale } = useLocale()
7+
8+
interface LocaleStrings {
9+
loading: string
10+
waitingFirstSync: string
11+
unknown: string
12+
unknownError: string
13+
noGroupsTitle: string
14+
noGroupsMsg: (limit: number) => string
15+
lastSync: string
16+
groupId: string
17+
memberCount: string
18+
copyGroupId: string
19+
copied: string
20+
copyFailed: string
21+
viewAllGroups: string
22+
fullOrUnavailable: string
23+
groupName: (id: string) => string
24+
dateLocale: string
25+
numberLocale: string
26+
}
27+
28+
const t = computed<LocaleStrings>(() => {
29+
const strings: Record<import('../composables/useLocale.js').Locale, LocaleStrings> = {
30+
zh: {
31+
loading: '正在获取 QQ 群信息...',
32+
waitingFirstSync: '等待首次更新',
33+
unknown: '未知',
34+
unknownError: '未知错误',
35+
noGroupsTitle: '暂时没有可加入的 QQ 群',
36+
noGroupsMsg: (limit: number) => `当前没有人数低于 ${limit} 的群,或群信息还未完成同步。请稍后再试。`,
37+
lastSync: '最近同步',
38+
groupId: '群号',
39+
memberCount: '当前人数',
40+
copyGroupId: '复制群号',
41+
copied: '已复制',
42+
copyFailed: '复制失败',
43+
viewAllGroups: '查看全部群状态',
44+
fullOrUnavailable: '已满或不可加入',
45+
groupName: (id: string) => `QQ群 ${id}`,
46+
dateLocale: 'zh-CN',
47+
numberLocale: 'zh-CN',
48+
},
49+
en: {
50+
loading: 'Fetching QQ group info...',
51+
waitingFirstSync: 'Waiting for first sync',
52+
unknown: 'Unknown',
53+
unknownError: 'Unknown error',
54+
noGroupsTitle: 'No QQ groups available',
55+
noGroupsMsg: (limit: number) => `No groups with fewer than ${limit} members available, or group data has not synced yet. Please try again later.`,
56+
lastSync: 'Last Sync',
57+
groupId: 'Group ID',
58+
memberCount: 'Members',
59+
copyGroupId: 'Copy Group ID',
60+
copied: 'Copied',
61+
copyFailed: 'Copy Failed',
62+
viewAllGroups: 'View All Groups',
63+
fullOrUnavailable: 'Full or Unavailable',
64+
groupName: (id: string) => `QQ Group ${id}`,
65+
dateLocale: 'en-US',
66+
numberLocale: 'en-US',
67+
},
68+
ja: {
69+
loading: 'QQ グループ情報を取得中...',
70+
waitingFirstSync: '初回同期待ち',
71+
unknown: '不明',
72+
unknownError: '不明なエラー',
73+
noGroupsTitle: '現在参加可能な QQ グループはありません',
74+
noGroupsMsg: (limit: number) => `現在、人数が ${limit} 未満のグループがないか、グループ情報の同期が完了していません。しばらくしてからもう一度お試しください。`,
75+
lastSync: '最終同期',
76+
groupId: 'グループID',
77+
memberCount: '現在の人数',
78+
copyGroupId: 'グループIDをコピー',
79+
copied: 'コピー済み',
80+
copyFailed: 'コピー失敗',
81+
viewAllGroups: '全グループの状態を表示',
82+
fullOrUnavailable: '満員または参加不可',
83+
groupName: (id: string) => `QQグループ ${id}`,
84+
dateLocale: 'ja-JP',
85+
numberLocale: 'ja-JP',
86+
},
87+
}
88+
return strings[currentLocale.value]
89+
})
490
591
interface QQGroup {
692
group_id: string
@@ -41,7 +127,7 @@ const memberLimit = computed(() => groupData.value?.member_limit ?? 2000)
41127
42128
const updatedAt = computed(() => {
43129
const value = groupData.value?.updated_at
44-
return value ? formatDate(value) : '等待首次更新'
130+
return value ? formatDate(value) : t.value.waitingFirstSync
45131
})
46132
47133
onMounted(async () => {
@@ -57,7 +143,7 @@ onMounted(async () => {
57143
58144
groupData.value = await response.json()
59145
} catch (error) {
60-
errorMessage.value = error instanceof Error ? error.message : '未知错误'
146+
errorMessage.value = error instanceof Error ? error.message : t.value.unknownError
61147
} finally {
62148
loading.value = false
63149
}
@@ -67,7 +153,7 @@ function formatDate(value: string): string {
67153
const date = new Date(value)
68154
if (Number.isNaN(date.getTime())) return value
69155
70-
return new Intl.DateTimeFormat('zh-CN', {
156+
return new Intl.DateTimeFormat(t.value.dateLocale, {
71157
year: 'numeric',
72158
month: '2-digit',
73159
day: '2-digit',
@@ -77,15 +163,15 @@ function formatDate(value: string): string {
77163
}
78164
79165
function formatCount(value?: number): string {
80-
return typeof value === 'number' && Number.isFinite(value) ? value.toLocaleString('zh-CN') : '未知'
166+
return typeof value === 'number' && Number.isFinite(value) ? value.toLocaleString(t.value.numberLocale) : t.value.unknown
81167
}
82168
83169
function hasMemberCount(group: QQGroup): boolean {
84170
return typeof group.member_count === 'number' && Number.isFinite(group.member_count)
85171
}
86172
87173
function formatGroupMemberCount(group: QQGroup): string {
88-
if (!hasMemberCount(group)) return '未知'
174+
if (!hasMemberCount(group)) return t.value.unknown
89175
90176
const maxMemberCount = group.max_member_count ?? memberLimit.value
91177
return `${group.member_count}/${maxMemberCount}`
@@ -99,7 +185,7 @@ function hasFewRemainingSlots(group: QQGroup): boolean {
99185
}
100186
101187
function formatGroupName(group: QQGroup): string {
102-
return group.group_name || `QQ群 ${group.group_id}`
188+
return group.group_name || t.value.groupName(group.group_id)
103189
}
104190
105191
async function copyGroupId(groupId: string): Promise<void> {
@@ -161,22 +247,22 @@ function copyTextWithFallback(value: string): void {
161247
}
162248
163249
function copyButtonLabel(groupId: string): string {
164-
if (copiedGroupId.value === groupId) return '已复制'
165-
if (copyErrorGroupId.value === groupId) return '复制失败'
166-
return '复制群号'
250+
if (copiedGroupId.value === groupId) return t.value.copied
251+
if (copyErrorGroupId.value === groupId) return t.value.copyFailed
252+
return t.value.copyGroupId
167253
}
168254
</script>
169255

170256
<template>
171257
<section class="qq-group">
172-
<div v-if="loading" class="qq-group__state">正在获取 QQ 群信息...</div>
258+
<div v-if="loading" class="qq-group__state">{{ t.loading }}</div>
173259

174260
<div v-else-if="!selectedGroup" class="qq-group__empty">
175-
<h2>暂时没有可加入的 QQ 群</h2>
261+
<h2>{{ t.noGroupsTitle }}</h2>
176262
<p>
177-
{{ errorMessage || `当前没有人数低于 ${memberLimit} 的群,或群信息还未完成同步。请稍后再试。` }}
263+
{{ errorMessage || t.noGroupsMsg(memberLimit) }}
178264
</p>
179-
<p class="qq-group__meta">最近同步:{{ updatedAt }}</p>
265+
<p class="qq-group__meta">{{ t.lastSync }}:{{ updatedAt }}</p>
180266
</div>
181267

182268
<div v-else class="qq-group__content">
@@ -185,15 +271,15 @@ function copyButtonLabel(groupId: string): string {
185271

186272
<dl class="qq-group__stats">
187273
<div>
188-
<dt>群号</dt>
274+
<dt>{{ t.groupId }}</dt>
189275
<dd>{{ selectedGroup.group_id }}</dd>
190276
</div>
191277
<div>
192-
<dt>当前人数</dt>
278+
<dt>{{ t.memberCount }}</dt>
193279
<dd>{{ formatCount(selectedGroup.member_count) }} / {{ formatCount(selectedGroup.max_member_count) }}</dd>
194280
</div>
195281
<div>
196-
<dt>最近同步</dt>
282+
<dt>{{ t.lastSync }}</dt>
197283
<dd>{{ updatedAt }}</dd>
198284
</div>
199285
</dl>
@@ -205,7 +291,7 @@ function copyButtonLabel(groupId: string): string {
205291
</div>
206292

207293
<details v-if="groups.length > 1" class="qq-group__details">
208-
<summary>查看全部群状态</summary>
294+
<summary>{{ t.viewAllGroups }}</summary>
209295
<ul>
210296
<li v-for="group in groups" :key="group.group_id">
211297
<span>
@@ -219,7 +305,7 @@ function copyButtonLabel(groupId: string): string {
219305
>
220306
{{ formatGroupMemberCount(group) }}
221307
</strong>
222-
<em v-else>{{ group.error || '已满或不可加入' }}</em>
308+
<em v-else>{{ group.error || t.fullOrUnavailable }}</em>
223309
<button type="button" @click="copyGroupId(group.group_id)">
224310
{{ copyButtonLabel(group.group_id) }}
225311
</button>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { computed } from 'vue'
2+
import { useData } from 'vuepress/client'
3+
4+
export type Locale = 'zh' | 'en' | 'ja'
5+
6+
export function useLocale() {
7+
const { routeLocale } = useData()
8+
9+
const currentLocale = computed<Locale>(() => {
10+
const lp = routeLocale.value
11+
if (lp.startsWith('/en_us')) return 'en'
12+
if (lp.startsWith('/ja_jp')) return 'ja'
13+
return 'zh'
14+
})
15+
16+
return { currentLocale }
17+
}

docs/.vuepress/navigation/genLocales.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export function genThemeLocales(): LocaleConfig<ThemeLocaleData> {
4242
}
4343

4444
themeLocales[`/${locale.name}/`] = {
45+
home: `/${locale.name}/`,
4546
navbar: navigationComponents.navbar,
4647
collections: navigationComponents.collections,
4748
footer: footer[locale.name],
@@ -50,6 +51,7 @@ export function genThemeLocales(): LocaleConfig<ThemeLocaleData> {
5051
// 为根路径 / 添加中文 locale,使首页导航栏能显示语言切换按钮
5152
themeLocales['/'] = {
5253
...themeLocales['/zh_cn/'],
54+
home: '/',
5355
}
5456
return themeLocales
5557
}

0 commit comments

Comments
 (0)