Skip to content

Commit e80e441

Browse files
committed
feat(i18n): add i18n files for enhancement
1 parent 87316e7 commit e80e441

File tree

15 files changed

+350
-152
lines changed

15 files changed

+350
-152
lines changed

frontend/src/api/system.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
22
import { toast } from "sonner";
33
import { API_QUERY_KEYS, VALUECELL_BACKEND_URL } from "@/constants/api";
4+
import i18n from "@/i18n";
45
import { type ApiResponse, apiClient } from "@/lib/api-client";
56
import { useLanguage } from "@/store/settings-store";
67
import { useSystemStore } from "@/store/system-store";
@@ -111,7 +112,7 @@ export const usePublishStrategy = () => {
111112
);
112113
},
113114
onSuccess: () => {
114-
toast.success("Strategy published successfully");
115+
toast.success(i18n.t("strategy.toast.published"));
115116
queryClient.invalidateQueries({
116117
queryKey: API_QUERY_KEYS.SYSTEM.strategyList([]),
117118
});

frontend/src/app/agent/components/strategy-items/modals/create-strategy-modal.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useStore } from "@tanstack/react-form";
22
import { AlertCircleIcon } from "lucide-react";
33
import type { FC, RefObject } from "react";
4-
import { memo, useImperativeHandle, useState } from "react";
4+
import { memo, useImperativeHandle, useMemo, useState } from "react";
55
import { useTranslation } from "react-i18next";
66
import { useGetModelProviderDetail } from "@/api/setting";
77
import {
@@ -29,9 +29,9 @@ import { TradingStrategyForm } from "@/components/valuecell/form/trading-strateg
2929
import { StepIndicator } from "@/components/valuecell/step-indicator";
3030
import { TRADING_SYMBOLS } from "@/constants/agent";
3131
import {
32-
aiModelSchema,
33-
exchangeSchema,
34-
tradingStrategySchema,
32+
createAiModelSchema,
33+
createExchangeSchema,
34+
createTradingStrategySchema,
3535
} from "@/constants/schema";
3636
import { useAppForm } from "@/hooks/use-form";
3737
import { tracker } from "@/lib/tracker";
@@ -50,6 +50,9 @@ const CreateStrategyModal: FC<CreateStrategyModalProps> = ({
5050
children,
5151
}) => {
5252
const { t } = useTranslation();
53+
const aiModelSchema = useMemo(() => createAiModelSchema(t), [t]);
54+
const exchangeSchema = useMemo(() => createExchangeSchema(t), [t]);
55+
const tradingStrategySchema = useMemo(() => createTradingStrategySchema(t), [t]);
5356
const [open, setOpen] = useState(false);
5457
const [currentStep, setCurrentStep] = useState(1);
5558
const [error, setError] = useState<string | null>(null);

frontend/src/app/agent/components/strategy-items/modals/share-portfolio-modal.tsx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
useRef,
1212
useState,
1313
} from "react";
14+
import { useTranslation } from "react-i18next";
1415
import { toast } from "sonner";
1516
import { Button } from "@/components/ui/button";
1617
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
@@ -38,6 +39,7 @@ export interface SharePortfolioCardRef {
3839
const SharePortfolioModal: FC<{
3940
ref?: RefObject<SharePortfolioCardRef | null>;
4041
}> = ({ ref }) => {
42+
const { t } = useTranslation();
4143
const cardRef = useRef<HTMLDivElement>(null);
4244
const [isDownloading, setIsDownloading] = useState(false);
4345

@@ -84,18 +86,21 @@ const SharePortfolioModal: FC<{
8486
await writeFile(path, new Uint8Array(arrayBuffer));
8587

8688
setOpen(false);
87-
toast.success("Image downloaded successfully", {
89+
toast.success(t("sharePortfolio.toast.downloaded"), {
8890
action: {
89-
label: "open file",
91+
label: t("sharePortfolio.toast.openFile"),
9092
onClick: async () => {
9193
return await openPath(path);
9294
},
9395
},
9496
});
9597
} catch (err) {
96-
toast.error(`Failed to download image: ${JSON.stringify(err)}`, {
97-
duration: 6 * 1000,
98-
});
98+
toast.error(
99+
t("sharePortfolio.toast.downloadFailed", {
100+
error: JSON.stringify(err),
101+
}),
102+
{ duration: 6 * 1000 },
103+
);
99104
} finally {
100105
setIsDownloading(false);
101106
}
@@ -116,7 +121,9 @@ const SharePortfolioModal: FC<{
116121
className="h-[600px] w-[434px] overflow-hidden border-none bg-transparent p-0 shadow-none"
117122
showCloseButton={false}
118123
>
119-
<DialogTitle className="sr-only">Share Portfolio</DialogTitle>
124+
<DialogTitle className="sr-only">
125+
{t("sharePortfolio.title")}
126+
</DialogTitle>
120127

121128
{/* Card to be captured */}
122129
<div
@@ -161,10 +168,10 @@ const SharePortfolioModal: FC<{
161168
{formatChange(data.total_pnl, "", 2)}
162169
</span>
163170

164-
<p>Model</p>
171+
<p>{t("sharePortfolio.fields.model")}</p>
165172
<span>{data.llm_model_id}</span>
166173

167-
<p>Exchange</p>
174+
<p>{t("sharePortfolio.fields.exchange")}</p>
168175
<span className="ml-auto flex items-center gap-1">
169176
<PngIcon
170177
src={
@@ -177,7 +184,7 @@ const SharePortfolioModal: FC<{
177184
{data.exchange_id}
178185
</span>
179186

180-
<p>Strategy</p>
187+
<p>{t("sharePortfolio.fields.strategy")}</p>
181188
<span>{data.strategy_type}</span>
182189
</div>
183190

@@ -202,7 +209,7 @@ const SharePortfolioModal: FC<{
202209
className="h-12 flex-1 rounded-xl border-gray-200 bg-white font-medium text-base hover:bg-gray-50"
203210
onClick={() => setOpen(false)}
204211
>
205-
Cancel
212+
{t("strategy.action.cancel")}
206213
</Button>
207214

208215
<Button
@@ -215,7 +222,7 @@ const SharePortfolioModal: FC<{
215222
) : (
216223
<Download className="mr-2 size-5" />
217224
)}
218-
Download
225+
{t("sharePortfolio.action.download")}
219226
</Button>
220227
</div>
221228
</DialogContent>

frontend/src/app/setting/general.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,16 @@ export default function GeneralPage() {
9696
<SelectValue />
9797
</SelectTrigger>
9898
<SelectContent>
99-
<SelectItem value="en">English (United States)</SelectItem>
100-
<SelectItem value="zh_CN">简体中文</SelectItem>
101-
<SelectItem value="zh_TW">繁體中文</SelectItem>
102-
<SelectItem value="ja">日本語</SelectItem>
99+
<SelectItem value="en">
100+
{t("general.language.options.en")}
101+
</SelectItem>
102+
<SelectItem value="zh_CN">
103+
{t("general.language.options.zh_CN")}
104+
</SelectItem>
105+
<SelectItem value="zh_TW">
106+
{t("general.language.options.zh_TW")}
107+
</SelectItem>
108+
<SelectItem value="ja">{t("general.language.options.ja")}</SelectItem>
103109
</SelectContent>
104110
</Select>
105111
</Field>

frontend/src/components/valuecell/app/app-sidebar.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
type ReactNode,
66
useMemo,
77
} from "react";
8+
import { useTranslation } from "react-i18next";
89
import { NavLink, useLocation } from "react-router";
910
import { useGetAgentList } from "@/api/agent";
1011
import {
@@ -131,6 +132,7 @@ const SidebarMenuItem: FC<SidebarItemProps> = ({
131132
};
132133

133134
const AppSidebar: FC = () => {
135+
const { t } = useTranslation();
134136
const pathArray = useLocation().pathname.split("/");
135137

136138
const prefix = useMemo(() => {
@@ -149,38 +151,38 @@ const AppSidebar: FC = () => {
149151
{
150152
id: "home",
151153
icon: Logo,
152-
label: "Home",
154+
label: t("nav.home"),
153155
to: "/home",
154156
},
155157
{
156158
id: "strategy",
157159
icon: StrategyAgent,
158-
label: "Strategy",
160+
label: t("nav.strategy"),
159161
to: "/agent/StrategyAgent",
160162
},
161163
{
162164
id: "ranking",
163165
icon: Ranking,
164-
label: "Ranking",
166+
label: t("nav.ranking"),
165167
to: "/ranking",
166168
},
167169
{
168170
id: "market",
169171
icon: Market,
170-
label: "Market",
172+
label: t("nav.market"),
171173
to: "/market",
172174
},
173175
],
174176
config: [
175177
{
176178
id: "setting",
177179
icon: Setting,
178-
label: "Setting",
180+
label: t("nav.setting"),
179181
to: "/setting",
180182
},
181183
],
182184
};
183-
}, []);
185+
}, [t]);
184186

185187
const { data: agentList } = useGetAgentList({ enabled_only: "true" });
186188
const agentItems = useMemo(() => {

frontend/src/components/valuecell/app/backend-health-check.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { AnimatePresence, motion } from "framer-motion";
22
import type React from "react";
33
import { useEffect, useState } from "react";
4+
import { useTranslation } from "react-i18next";
45
import { useBackendHealth } from "@/api/system";
56
import ValuecellLogo from "@/assets/png/logo/valuecell-logo.webp";
67
import { Progress } from "@/components/ui/progress";
@@ -10,6 +11,7 @@ export function BackendHealthCheck({
1011
}: {
1112
children: React.ReactNode;
1213
}) {
14+
const { t } = useTranslation();
1315
const { isError, isSuccess } = useBackendHealth();
1416
const [showError, setShowError] = useState(false);
1517
const [progress, setProgress] = useState(0);
@@ -92,7 +94,7 @@ export function BackendHealthCheck({
9294
className="space-y-4"
9395
>
9496
<p className="text-lg text-muted-foreground leading-relaxed">
95-
Setting up environment...
97+
{t("common.settingUpEnvironment")}
9698
</p>
9799
</motion.div>
98100

@@ -106,7 +108,7 @@ export function BackendHealthCheck({
106108
<div className="max-w-lg space-y-2">
107109
<Progress value={progress} className="h-2 w-full bg-muted/50" />
108110
<div className="flex justify-between font-medium text-muted-foreground text-xs uppercase tracking-wider">
109-
<span>Loading</span>
111+
<span>{t("common.loading")}</span>
110112
<span>{Math.round(progress)}%</span>
111113
</div>
112114
</div>

frontend/src/components/valuecell/modal/copy-strategy-modal.tsx

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useStore } from "@tanstack/react-form";
22
import { AlertCircleIcon } from "lucide-react";
33
import type { FC, RefObject } from "react";
4-
import { memo, useImperativeHandle, useState } from "react";
4+
import { memo, useImperativeHandle, useMemo, useState } from "react";
5+
import { useTranslation } from "react-i18next";
56
import { useGetModelProviderDetail } from "@/api/setting";
67
import {
78
useCreateStrategy,
@@ -27,9 +28,9 @@ import {
2728
import { StepIndicator } from "@/components/valuecell/step-indicator";
2829
import { TRADING_SYMBOLS } from "@/constants/agent";
2930
import {
30-
aiModelSchema,
31-
copyTradingStrategySchema,
32-
exchangeSchema,
31+
createAiModelSchema,
32+
createCopyTradingStrategySchema,
33+
createExchangeSchema,
3334
} from "@/constants/schema";
3435
import { useAppForm } from "@/hooks/use-form";
3536
import { tracker } from "@/lib/tracker";
@@ -45,22 +46,32 @@ interface CopyStrategyModalProps {
4546
callback?: () => void;
4647
}
4748

48-
const STEPS = [
49-
{ step: 1, title: "AI Models" },
50-
{ step: 2, title: "Exchanges" },
51-
{ step: 3, title: "Trading strategy" },
52-
];
53-
5449
const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
5550
ref,
5651
children,
5752
callback,
5853
}) => {
54+
const { t } = useTranslation();
55+
const aiModelSchema = useMemo(() => createAiModelSchema(t), [t]);
56+
const exchangeSchema = useMemo(() => createExchangeSchema(t), [t]);
57+
const copyTradingStrategySchema = useMemo(
58+
() => createCopyTradingStrategySchema(t),
59+
[t],
60+
);
5961
const [open, setOpen] = useState(false);
6062
const [currentStep, setCurrentStep] = useState(1);
6163
const [defaultValues, setDefaultValues] = useState<CopyStrategy>();
6264
const [error, setError] = useState<string | null>(null);
6365

66+
const STEPS = useMemo(
67+
() => [
68+
{ step: 1, title: t("strategy.create.steps.aiModels") },
69+
{ step: 2, title: t("strategy.create.steps.exchanges") },
70+
{ step: 3, title: t("strategy.create.steps.tradingStrategy") },
71+
],
72+
[t],
73+
);
74+
6475
const { data: strategies = [] } = useGetStrategyList();
6576
const { mutateAsync: createStrategy, isPending: isCreatingStrategy } =
6677
useCreateStrategy();
@@ -201,7 +212,7 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
201212
<DialogTitle className="flex flex-col gap-4 px-1">
202213
<div className="flex items-center justify-between">
203214
<h2 className="font-semibold text-lg">
204-
Duplicate trading strategy
215+
{t("strategy.copy.title")}
205216
</h2>
206217
<CloseButton onClick={resetAll} />
207218
</div>
@@ -230,7 +241,7 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
230241
{error && (
231242
<Alert variant="destructive">
232243
<AlertCircleIcon />
233-
<AlertTitle>Error Duplicating Strategy</AlertTitle>
244+
<AlertTitle>{t("strategy.copy.error")}</AlertTitle>
234245
<AlertDescription>{error}</AlertDescription>
235246
</Alert>
236247
)}
@@ -241,7 +252,9 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
241252
onClick={currentStep === 1 ? resetAll : handleBack}
242253
className="border-gray-100 py-4 font-semibold text-base"
243254
>
244-
{currentStep === 1 ? "Cancel" : "Back"}
255+
{currentStep === 1
256+
? t("strategy.action.cancel")
257+
: t("strategy.action.back")}
245258
</Button>
246259
<Button
247260
type="button"
@@ -261,7 +274,9 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
261274
className="relative py-4 font-semibold text-base text-white hover:bg-gray-800"
262275
>
263276
{isCreatingStrategy && <Spinner className="absolute left-4" />}
264-
{currentStep === 3 ? "Confirm" : "Next"}
277+
{currentStep === 3
278+
? t("strategy.action.confirm")
279+
: t("strategy.action.next")}
265280
</Button>
266281
</div>
267282
</DialogFooter>

0 commit comments

Comments
 (0)