Skip to content

Commit be80838

Browse files
committed
✨ feat: add i18n
1 parent 201af32 commit be80838

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+986
-138
lines changed

.prettierrc.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
"trailingComma": "all",
44
"tabWidth": 2,
55
"semi": true,
6-
"printWidth": 100
6+
"printWidth": 80
77
}

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ English | [简体中文](./README.zh-CN.md)
1111
<br />
1212
<br />
1313
<img src="https://s1.ax1x.com/2023/07/20/pCHnLLt.png" alt="demo"/>
14-
</div>
14+
</div>
1515

1616
## 👀 Demo
1717

README.zh-CN.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<br />
1212
<br />
1313
<img src="https://s1.ax1x.com/2023/07/20/pCHnLLt.png" alt="demo"/>
14-
</div>
14+
</div>
1515

1616
## 👀 Demo
1717

app/app.vue

+21-6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
const config = useRuntimeConfig();
3434
const statusStore = useStatusStore();
3535
36+
const { setLocale } = useI18n();
37+
3638
// 加载状态
3739
const siteLoaded = ref<boolean>(false);
3840
@@ -56,26 +58,39 @@ const siteScroll = (e: Event) => {
5658
statusStore.scrollTop = scrollTop;
5759
};
5860
61+
// 更改站点语言
62+
const setSiteLang = (lang: string) => {
63+
setLocale(lang);
64+
useHead({ htmlAttrs: { lang } });
65+
};
66+
5967
// 监听站点状态
6068
watch(
6169
() => statusStore.siteStatus,
6270
(status) => {
6371
const { siteTitle } = config.public;
64-
// 错误总数
72+
// 错误数据
73+
const isError = status === "error" || status === "warn";
6574
const error = statusStore.siteData?.status?.error || 0;
6675
const unknown = statusStore.siteData?.status?.unknown || 0;
6776
// 更改信息
6877
useHead({
6978
// 更改标题
70-
title:
71-
status === "error" || status === "warn"
72-
? `${error + unknown} 异常 | ` + siteTitle
73-
: siteTitle,
79+
title: isError ? `( ${error + unknown} ) ` + siteTitle : siteTitle,
7480
});
81+
// 更改图标
82+
useFavicon(isError ? "/favicon-error.ico" : "/favicon.ico");
7583
},
7684
);
7785
78-
onMounted(checkSite);
86+
// 语言更改
87+
watch(() => statusStore.siteLang, setSiteLang);
88+
89+
onBeforeMount(checkSite);
90+
91+
onMounted(() => {
92+
setSiteLang(statusStore.siteLang);
93+
});
7994
</script>
8095

8196
<style lang="scss" scoped>

app/assets/data/text.ts

+20-16
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
// 全站状态文本
2-
export const siteGlobalText: { [key: string]: string } = {
3-
loading: "站点状态加载中",
4-
unknown: "站点状态未知",
5-
normal: "站点运行正常",
6-
error: "全部站点出现异常",
7-
warn: "部分站点出现异常",
8-
};
1+
import type { SelectOption } from "naive-ui";
92

103
// 站点监控类型
114
export const siteType: { [key: number]: { tag: string; text?: string } } = {
@@ -28,11 +21,22 @@ export const siteType: { [key: number]: { tag: string; text?: string } } = {
2821
},
2922
};
3023

31-
// 站点状态类型
32-
export const siteStatus: { [key: number]: { text: string; type: string } } = {
33-
0: { text: "暂停检测", type: "unknown" },
34-
1: { text: "还未检查", type: "unknown" },
35-
2: { text: "正常访问", type: "normal" },
36-
8: { text: "站点异常", type: "error" },
37-
9: { text: "无法访问", type: "error" },
38-
};
24+
// 语言数据
25+
export const langData: SelectOption[] = [
26+
{
27+
label: "简体中文",
28+
value: "zh-CN",
29+
},
30+
{
31+
label: "English",
32+
value: "en",
33+
},
34+
{
35+
label: "日本語",
36+
value: "ja-JP",
37+
},
38+
{
39+
label: "한국어",
40+
value: "ko-KR",
41+
},
42+
];

app/assets/icons/language.svg

+1
Loading

app/assets/icons/logout.svg

+1
Loading

app/components.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ declare module 'vue' {
2525
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
2626
NP: typeof import('naive-ui')['NP']
2727
NPopover: typeof import('naive-ui')['NPopover']
28+
NPopselect: typeof import('naive-ui')['NPopselect']
2829
NResult: typeof import('naive-ui')['NResult']
2930
NScrollbar: typeof import('naive-ui')['NScrollbar']
3031
NSpin: typeof import('naive-ui')['NSpin']

app/components/GlobalProvider.vue

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<!-- 全局配置 -->
22
<template>
33
<n-config-provider
4-
:locale="zhCN"
5-
:date-locale="dateZhCN"
4+
:locale="siteLang.locale"
5+
:date-locale="siteLang.date"
66
:theme="theme"
77
:theme-overrides="themeOverrides"
88
abstract
@@ -41,6 +41,14 @@ import {
4141

4242
const osTheme = useOsTheme();
4343
const colorMode = useColorMode();
44+
const statusStore = useStatusStore();
45+
46+
// 站点语言
47+
const siteLang = computed(() =>
48+
statusStore.siteLang === "zh-CN"
49+
? { locale: zhCN, date: dateZhCN }
50+
: { locale: undefined, date: undefined },
51+
);
4452

4553
// 获取明暗模式
4654
const theme = computed(() => {

app/components/SiteCards.vue

+65-20
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
<n-popover>
1717
<template #trigger>
1818
<n-tag :bordered="false" size="small" round>
19-
{{ siteType[site.type]?.tag || "HTTP" }} /
19+
{{ siteTypeMap[site.type]?.tag || "HTTP" }} /
2020
{{ formatInterval(site?.interval) }}
2121
</n-tag>
2222
</template>
2323
<n-text>
2424
{{
25-
`每间隔 ${formatInterval(site?.interval)},` + siteType[site.type]?.text ||
26-
"30s" + ",来判断段站点是否运行正常"
25+
$t("card.type.tip", {
26+
interval: formatInterval(site?.interval) || "30s",
27+
type: siteTypeMap[site.type]?.text,
28+
})
2729
}}
2830
</n-text>
2931
</n-popover>
@@ -43,19 +45,27 @@
4345
</n-flex>
4446
<n-flex
4547
:style="{
46-
'--bg-color': `var(--${siteStatus[site.status]?.type || 'unknown'}-color)`,
48+
'--bg-color': `var(--${siteStatusMap[site.status]?.type || 'unknown'}-color)`,
4749
}"
4850
class="status"
4951
align="center"
5052
>
5153
<div v-if="site.status !== 0" class="point" />
5254
<Icon v-else name="icon:pause" />
53-
<n-text>{{ siteStatus[site.status]?.text }}</n-text>
55+
<n-text>{{ siteStatusMap[site.status]?.text }}</n-text>
5456
</n-flex>
5557
</n-flex>
5658
<!-- 每日数据 -->
57-
<n-flex v-if="site?.days?.length" :size="2" class="timeline" justify="space-between">
58-
<n-popover v-for="(day, dayIndex) in site.days" :key="day?.date || dayIndex">
59+
<n-flex
60+
v-if="site?.days?.length"
61+
:size="2"
62+
class="timeline"
63+
justify="space-between"
64+
>
65+
<n-popover
66+
v-for="(day, dayIndex) in site.days"
67+
:key="day?.date || dayIndex"
68+
>
5969
<template #trigger>
6070
<div
6171
:style="{
@@ -66,18 +76,22 @@
6676
</template>
6777
<div class="day-data">
6878
<n-text class="date" depth="3">
69-
{{ day?.date ? formatTime(day.date) : "未知日期" }}
79+
{{ day?.date ? formatTime(day.date) : $t("card.unknownDate") }}
7080
</n-text>
7181
<!-- 详细 -->
7282
<n-text v-if="day?.percent >= 100">
73-
{{ `当日可用率 ${day?.percent}%` }}
83+
{{ $t("card.percent", { percent: day?.percent }) }}
7484
</n-text>
7585
<n-text v-else-if="day?.percent > 0 && day?.percent < 100">
7686
{{
77-
`故障 ${day?.down?.times} 次,累计故障时长 ${formatDuration(day?.down?.duration)},当日可用率 ${day?.percent}%`
87+
$t("card.percentData", {
88+
times: day?.down?.times,
89+
duration: formatDuration(day?.down?.duration),
90+
percent: day?.percent,
91+
})
7892
}}
7993
</n-text>
80-
<n-text v-else>当日无数据</n-text>
94+
<n-text v-else>{{ $t("card.unknownData") }}</n-text>
8195
</div>
8296
</n-popover>
8397
</n-flex>
@@ -88,13 +102,22 @@
88102
</n-text>
89103
<n-text v-if="site?.down?.times" depth="3">
90104
{{
91-
`最近 ${site?.days?.length} 天内故障 ${site?.down?.times} 次,累计故障时长 ${formatDuration(site?.down?.duration)},平均可用率 ${site?.percent}%`
105+
$t("card.summaryData", {
106+
times: site?.down?.times,
107+
duration: formatDuration(site?.down?.duration),
108+
percent: site?.percent,
109+
})
92110
}}
93111
</n-text>
94112
<n-text v-else depth="3">
95-
{{ `最近 ${site?.days?.length} 天内可用率 ${site.percent}%` }}
113+
{{
114+
$t("card.summary", {
115+
days: site?.days?.length,
116+
percent: site?.percent,
117+
})
118+
}}
96119
</n-text>
97-
<n-text class="date" depth="3">今日</n-text>
120+
<n-text class="date" depth="3">{{ $t("meta.today") }}</n-text>
98121
</n-flex>
99122
</n-card>
100123
</div>
@@ -109,11 +132,13 @@
109132
<n-result
110133
v-else
111134
status="error"
112-
title="出错啦"
113-
description="接口调用超限或请求错误,请稍后重试"
135+
:title="$t('card.error')"
136+
:description="$t('card.errorText')"
114137
>
115138
<template #footer>
116-
<n-button tertiary round @click="refresh"> 重试 </n-button>
139+
<n-button tertiary round @click="refresh">
140+
{{ $t("meta.refresh") }}
141+
</n-button>
117142
</template>
118143
</n-result>
119144
</Transition>
@@ -124,12 +149,32 @@
124149

125150
<script setup lang="ts">
126151
import type { SiteStatusType, SiteType } from "~~/types/main";
127-
import { siteType, siteStatus } from "~/assets/data/text";
128152

153+
const { t } = useI18n();
129154
const statusStore = useStatusStore();
130155

156+
// 站点类型
157+
const siteStatusMap = computed(() => ({
158+
0: { text: t("card.status.stop"), type: "unknown" },
159+
1: { text: t("card.status.unknown"), type: "unknown" },
160+
2: { text: t("card.status.normal"), type: "normal" },
161+
8: { text: t("card.status.error"), type: "error" },
162+
9: { text: t("card.status.down"), type: "error" },
163+
}));
164+
165+
// 请求类型
166+
const siteTypeMap = computed(() => ({
167+
1: { tag: "HTTP", text: t("card.type.HTTP") },
168+
2: { tag: "KEYWORD", text: t("card.type.KEYWORD") },
169+
3: { tag: "PING", text: t("card.type.PING") },
170+
4: { tag: "PORT", text: t("card.type.PORT") },
171+
5: { tag: "HEARTBEAT", text: t("card.type.HEARTBEAT") },
172+
}));
173+
131174
// 全部站点数据
132-
const siteData = computed<SiteStatusType[] | undefined>(() => statusStore.siteData?.data);
175+
const siteData = computed<SiteStatusType[] | undefined>(
176+
() => statusStore.siteData?.data,
177+
);
133178

134179
// 当天站点状态
135180
const getDayStatus = (percent: number): SiteType => {
@@ -209,7 +254,7 @@ onMounted(getSiteData);
209254
margin: 15px 0 10px;
210255
.day {
211256
height: 26px;
212-
flex-grow: 1;
257+
flex: 1;
213258
border-radius: 25px;
214259
background-color: var(--normal-color);
215260
transition: transform 0.3s;

app/components/SiteFooter.vue

+15-5
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,28 @@
1616
</n-flex>
1717
<n-flex :size="4" class="text" align="center" vertical>
1818
<n-p depth="3">
19-
<n-text depth="3" @click="jumpLink(linkData.github)">SiteStatus</n-text>
19+
<n-text depth="3" @click="jumpLink(linkData.github)">
20+
SiteStatus
21+
</n-text>
2022
Version {{ version }}
2123
</n-p>
2224
<n-p depth="3">
23-
基于
24-
<n-text depth="3" @click="jumpLink('https://uptimerobot.com/')"> UptimeRobot </n-text>
25-
接口 | 检测频率 5 分钟
25+
{{ $t("footer.basedOn") }}
26+
<n-text depth="3" @click="jumpLink('https://uptimerobot.com/')">
27+
{{ $t("uptimeRobot") }}
28+
</n-text>
29+
{{ $t("footer.interface") }} |
30+
{{ $t("footer.checkFrequency") }}
31+
{{ $t("footer.fiveMinutes") }}
2632
</n-p>
2733
<n-p depth="3">
2834
Copyright &copy; 2020 - {{ new Date().getFullYear() }}
2935
<n-text depth="3" @click="jumpLink(linkData.home)"> IMSYY </n-text>
30-
<n-text v-if="siteIcp" depth="3" @click="jumpLink('https://beian.miit.gov.cn/')">
36+
<n-text
37+
v-if="siteIcp"
38+
depth="3"
39+
@click="jumpLink('https://beian.miit.gov.cn/')"
40+
>
3141
| {{ siteIcp }}
3242
</n-text>
3343
</n-p>

0 commit comments

Comments
 (0)