Skip to content

Commit 47f0929

Browse files
authored
feat(I18n): Add multiple languages ​​(zh-CN/zh-TW/en/it) (#8)
1 parent 5850fe7 commit 47f0929

Some content is hidden

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

44 files changed

+1138
-366
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@
3232
"class-variance-authority": "^0.7.0",
3333
"clsx": "^2.1.1",
3434
"cmdk": "^1.0.0",
35+
"i18next": "^24.0.2",
3536
"jotai-zustand": "^0.6.0",
3637
"lucide-react": "^0.454.0",
3738
"next-themes": "^0.3.0",
3839
"react": "^18.3.1",
3940
"react-dom": "^18.3.1",
4041
"react-hook-form": "^7.53.1",
42+
"react-i18next": "^15.1.2",
4143
"react-router-dom": "^6.27.0",
4244
"react-use-websocket": "^4.10.1",
4345
"react-virtuoso": "^4.12.0",

src/components/action-button-group.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,16 @@ import {
1313
import { KeyedMutator } from "swr";
1414
import { buttonVariants } from "@/components/ui/button"
1515

16+
import { useTranslation } from "react-i18next";
17+
1618
interface ButtonGroupProps<E, U> {
1719
className?: string;
1820
children: React.ReactNode;
1921
delete: { fn: (id: E[]) => Promise<void>, id: E, mutate: KeyedMutator<U> };
2022
}
2123

2224
export function ActionButtonGroup<E, U>({ className, children, delete: { fn, id, mutate } }: ButtonGroupProps<E, U>) {
25+
const { t } = useTranslation();
2326
const handleDelete = async () => {
2427
await fn([id]);
2528
await mutate();
@@ -30,18 +33,18 @@ export function ActionButtonGroup<E, U>({ className, children, delete: { fn, id,
3033
{children}
3134
<AlertDialog>
3235
<AlertDialogTrigger asChild>
33-
<IconButton variant="outline" icon="trash" />
36+
<IconButton variant="destructive" icon="trash" />
3437
</AlertDialogTrigger>
3538
<AlertDialogContent className="sm:max-w-lg">
3639
<AlertDialogHeader>
37-
<AlertDialogTitle>Confirm Deletion?</AlertDialogTitle>
40+
<AlertDialogTitle>{t("ConfirmDeletion")}</AlertDialogTitle>
3841
<AlertDialogDescription>
39-
This operation is unrecoverable!
42+
{t("Results.ThisOperationIsUnrecoverable")}
4043
</AlertDialogDescription>
4144
</AlertDialogHeader>
4245
<AlertDialogFooter>
43-
<AlertDialogCancel>Cancel</AlertDialogCancel>
44-
<AlertDialogAction className={buttonVariants({ variant: "destructive" })} onClick={handleDelete}>Confirm</AlertDialogAction>
46+
<AlertDialogCancel>{t("Close")}</AlertDialogCancel>
47+
<AlertDialogAction className={buttonVariants({ variant: "destructive" })} onClick={handleDelete}>{t("Confirm")}</AlertDialogAction>
4548
</AlertDialogFooter>
4649
</AlertDialogContent>
4750
</AlertDialog>

src/components/alert-rule.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import { Textarea } from "./ui/textarea"
4343
import { useNotification } from "@/hooks/useNotfication"
4444
import { Combobox } from "./ui/combobox"
4545

46+
import { useTranslation } from "react-i18next";
47+
4648
interface AlertRuleCardProps {
4749
data?: ModelAlertRule;
4850
mutate: KeyedMutator<ModelAlertRule[]>;
@@ -83,6 +85,7 @@ const alertRuleFormSchema = z.object({
8385
});
8486

8587
export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) => {
88+
const { t } = useTranslation();
8689
const form = useForm<z.infer<typeof alertRuleFormSchema>>({
8790
resolver: zodResolver(alertRuleFormSchema),
8891
defaultValues: data ? {
@@ -133,7 +136,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
133136
<ScrollArea className="max-h-[calc(100dvh-5rem)] p-3">
134137
<div className="items-center mx-1">
135138
<DialogHeader>
136-
<DialogTitle>New Alert Rule</DialogTitle>
139+
<DialogTitle>{data ? t("EditAlertRule") : t("CreateAlertRule")}</DialogTitle>
137140
<DialogDescription />
138141
</DialogHeader>
139142
<Form {...form}>
@@ -143,7 +146,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
143146
name="name"
144147
render={({ field }) => (
145148
<FormItem>
146-
<FormLabel>Name</FormLabel>
149+
<FormLabel>{t("Name")}</FormLabel>
147150
<FormControl>
148151
<Input
149152
{...field}
@@ -158,7 +161,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
158161
name="rules_raw"
159162
render={({ field }) => (
160163
<FormItem>
161-
<FormLabel>Rules</FormLabel>
164+
<FormLabel>{t("Rules")}</FormLabel>
162165
<FormControl>
163166
<Textarea
164167
className="resize-y"
@@ -174,7 +177,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
174177
name="notification_group_id"
175178
render={({ field }) => (
176179
<FormItem>
177-
<FormLabel>Notifier Group</FormLabel>
180+
<FormLabel>{t("NotifierGroup")}</FormLabel>
178181
<FormControl>
179182
<Combobox
180183
placeholder="Search..."
@@ -192,7 +195,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
192195
name="trigger_mode"
193196
render={({ field }) => (
194197
<FormItem>
195-
<FormLabel>Trigger Mode</FormLabel>
198+
<FormLabel>{t("TriggerMode")}</FormLabel>
196199
<Select onValueChange={field.onChange} defaultValue={`${field.value}`}>
197200
<FormControl>
198201
<SelectTrigger>
@@ -214,7 +217,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
214217
name="fail_trigger_tasks"
215218
render={({ field }) => (
216219
<FormItem>
217-
<FormLabel>Tasks to trigger on an alarm (Separate with comma)</FormLabel>
220+
<FormLabel>{t("TasksToTriggerOnAlert") + t("SeparateWithComma")}</FormLabel>
218221
<FormControl>
219222
<Input
220223
placeholder="1,2,3"
@@ -235,7 +238,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
235238
name="recover_trigger_tasks"
236239
render={({ field }) => (
237240
<FormItem>
238-
<FormLabel>Tasks to trigger after recovery (Separate with comma)</FormLabel>
241+
<FormLabel>{t("TasksToTriggerAfterRecovery") + t("SeparateWithComma")}</FormLabel>
239242
<FormControl>
240243
<Input
241244
placeholder="1,2,3"
@@ -262,7 +265,7 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
262265
checked={field.value}
263266
onCheckedChange={field.onChange}
264267
/>
265-
<Label className="text-sm">Enable</Label>
268+
<Label className="text-sm">{t("Enable")}</Label>
266269
</div>
267270
</FormControl>
268271
<FormMessage />
@@ -272,10 +275,10 @@ export const AlertRuleCard: React.FC<AlertRuleCardProps> = ({ data, mutate }) =>
272275
<DialogFooter className="justify-end">
273276
<DialogClose asChild>
274277
<Button type="button" className="my-2" variant="secondary">
275-
Close
278+
{t("Close")}
276279
</Button>
277280
</DialogClose>
278-
<Button type="submit" className="my-2">Submit</Button>
281+
<Button type="submit" className="my-2">{t("Confirm")}</Button>
279282
</DialogFooter>
280283
</form>
281284
</Form>

src/components/cron.tsx

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ import { useNotification } from "@/hooks/useNotfication"
4242
import { MultiSelect } from "./xui/multi-select"
4343
import { Combobox } from "./ui/combobox"
4444

45+
import { useTranslation } from "react-i18next";
46+
4547
interface CronCardProps {
4648
data?: ModelCron;
4749
mutate: KeyedMutator<ModelCron[]>;
@@ -59,6 +61,7 @@ const cronFormSchema = z.object({
5961
});
6062

6163
export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
64+
const { t } = useTranslation();
6265
const form = useForm<z.infer<typeof cronFormSchema>>({
6366
resolver: zodResolver(cronFormSchema),
6467
defaultValues: data ? data : {
@@ -109,7 +112,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
109112
<ScrollArea className="max-h-[calc(100dvh-5rem)] p-3">
110113
<div className="items-center mx-1">
111114
<DialogHeader>
112-
<DialogTitle>New Task</DialogTitle>
115+
<DialogTitle>{data?t("EditTask"):t("CreateTask")}</DialogTitle>
113116
<DialogDescription />
114117
</DialogHeader>
115118
<Form {...form}>
@@ -119,7 +122,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
119122
name="name"
120123
render={({ field }) => (
121124
<FormItem>
122-
<FormLabel>Name</FormLabel>
125+
<FormLabel>{t("Name")}</FormLabel>
123126
<FormControl>
124127
<Input
125128
placeholder="My Task"
@@ -135,7 +138,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
135138
name="task_type"
136139
render={({ field }) => (
137140
<FormItem>
138-
<FormLabel>Task Type</FormLabel>
141+
<FormLabel>{t("Type")}</FormLabel>
139142
<Select onValueChange={field.onChange} defaultValue={`${field.value}`}>
140143
<FormControl>
141144
<SelectTrigger>
@@ -157,7 +160,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
157160
name="scheduler"
158161
render={({ field }) => (
159162
<FormItem>
160-
<FormLabel>Cron expression</FormLabel>
163+
<FormLabel>{t("CronExpression") }</FormLabel>
161164
<FormControl>
162165
<Input
163166
placeholder="0 0 0 3 * * (At 3 AM)"
@@ -173,7 +176,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
173176
name="command"
174177
render={({ field }) => (
175178
<FormItem>
176-
<FormLabel>Command</FormLabel>
179+
<FormLabel>{t("Command")}</FormLabel>
177180
<FormControl>
178181
<Textarea
179182
className="resize-y"
@@ -189,7 +192,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
189192
name="cover"
190193
render={({ field }) => (
191194
<FormItem>
192-
<FormLabel>Coverage</FormLabel>
195+
<FormLabel>{t("Coverage")}</FormLabel>
193196
<Select onValueChange={field.onChange} defaultValue={`${field.value}`}>
194197
<FormControl>
195198
<SelectTrigger>
@@ -211,7 +214,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
211214
name="servers"
212215
render={({ field }) => (
213216
<FormItem>
214-
<FormLabel>Specific Servers</FormLabel>
217+
<FormLabel>{t("SpecificServers")}</FormLabel>
215218
<FormControl>
216219
<MultiSelect
217220
options={serverList}
@@ -231,7 +234,7 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
231234
name="notification_group_id"
232235
render={({ field }) => (
233236
<FormItem>
234-
<FormLabel>Notifier Group ID</FormLabel>
237+
<FormLabel>{t("NotifierGroup")}</FormLabel>
235238
<FormControl>
236239
<Combobox
237240
placeholder="Search..."
@@ -247,10 +250,10 @@ export const CronCard: React.FC<CronCardProps> = ({ data, mutate }) => {
247250
<DialogFooter className="justify-end">
248251
<DialogClose asChild>
249252
<Button type="button" className="my-2" variant="secondary">
250-
Close
253+
{t("Close")}
251254
</Button>
252255
</DialogClose>
253-
<Button type="submit" className="my-2">Submit</Button>
256+
<Button type="submit" className="my-2">{t("Confirm")}</Button>
254257
</DialogFooter>
255258
</form>
256259
</Form>

0 commit comments

Comments
 (0)