feat(i18n): implement internationalization framework and update UI components for language support

This commit is contained in:
HouYunFei
2026-08-05 14:08:03 +08:00
parent 9bccd0ff1a
commit 0f6809251a
116 changed files with 3269 additions and 1870 deletions
@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
import { ArrowUp, LoaderCircle, Square } from "lucide-react";
import { Button } from "antd";
import { useTranslation } from "react-i18next";
import { ModelPicker } from "@/components/model-picker";
import { defaultConfig, resolveModelForCapability, useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store";
@@ -30,6 +31,7 @@ type CanvasNodePromptPanelProps = {
};
export function CanvasNodePromptPanel({ node, isRunning, onPromptChange, onConfigChange, onGenerate, onStop, mentionReferences = [], onImageSettingsOpenChange, modeOverride }: CanvasNodePromptPanelProps) {
const { t } = useTranslation();
const globalConfig = useEffectiveConfig();
const openConfigDialog = useConfigStore((state) => state.openConfigDialog);
const theme = canvasThemes[useThemeStore((state) => state.theme)];
@@ -73,7 +75,7 @@ export function CanvasNodePromptPanel({ node, isRunning, onPromptChange, onConfi
onSubmit={submit}
className="thin-scrollbar h-40 w-full cursor-text resize-none rounded-xl px-3 py-2 text-sm leading-5 outline-none"
style={{ background: "transparent", color: theme.node.text }}
placeholder={promptPlaceholder(mode, hasImageContent, hasTextContent)}
placeholder={t(`canvas.promptPanel.${mode === "image" && hasImageContent ? "editImage" : mode === "text" && hasTextContent ? "editText" : mode}`)}
/>
<div className="mt-2 flex min-w-0 items-center justify-between gap-2">
@@ -114,14 +116,14 @@ export function CanvasNodePromptPanel({ node, isRunning, onPromptChange, onConfi
danger={isRunning}
disabled={!isRunning && !prompt.trim()}
onClick={() => (isRunning ? onStop(node.id) : submit())}
aria-label={isRunning ? "停止生成" : "生成"}
aria-label={t(isRunning ? "canvas.promptPanel.stopGeneration" : "canvas.promptPanel.generate")}
>
<span className="flex items-center gap-1.5">
{isRunning ? (
<>
<LoaderCircle className="size-4 animate-spin" />
<Square className="size-3.5 fill-current" />
<span className="text-xs font-medium"></span>
<span className="text-xs font-medium">{t("canvas.promptPanel.stop")}</span>
</>
) : (
<ArrowUp className="size-4" />
@@ -157,13 +159,6 @@ function buildNodeConfig(globalConfig: AiConfig, node: CanvasNodeData, mode: Can
};
}
function promptPlaceholder(mode: CanvasNodeGenerationMode, hasImageContent: boolean, hasTextContent: boolean) {
if (mode === "video") return "描述要生成的视频内容";
if (mode === "audio") return "描述要生成的音频内容";
if (mode === "image") return hasImageContent ? "请输入你想要把这张图修改成什么" : "描述要生成的图片内容";
return hasTextContent ? "请输入你想要将本段文本修改成什么" : "请输入你想要生成的文本内容";
}
function videoConfigPatch(key: keyof AiConfig, value: string) {
if (key === "videoSeconds") return { seconds: value };
if (key === "videoGenerateAudio") return { generateAudio: value };