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,5 +1,6 @@
import { useEffect, useRef } from "react";
import { ImageIcon, List, Music2, Settings2, Video, X } from "lucide-react";
import { useTranslation } from "react-i18next";
import { canvasThemes } from "@/lib/canvas-theme";
import { useThemeStore } from "@/stores/use-theme-store";
@@ -21,6 +22,7 @@ export function ConnectionCreateMenu({
onClose: () => void;
}) {
const theme = canvasThemes[useThemeStore((state) => state.theme)];
const { t } = useTranslation();
return (
<div
className="absolute z-[120] w-[300px] rounded-[18px] border p-3 shadow-2xl backdrop-blur"
@@ -31,18 +33,18 @@ export function ConnectionCreateMenu({
>
<div className="mb-2 flex items-center justify-between px-1">
<span className="text-sm font-medium" style={{ color: theme.node.muted }}>
引用该节点生成
{t("canvas.createMenu.fromNode")}
</span>
<button type="button" className="grid size-7 place-items-center rounded-lg text-base opacity-55 transition hover:bg-white/10 hover:opacity-100" onClick={onClose} aria-label="关闭">
<button type="button" className="grid size-7 place-items-center rounded-lg text-base opacity-55 transition hover:bg-white/10 hover:opacity-100" onClick={onClose} aria-label={t("canvas.createMenu.close")}>
×
</button>
</div>
<div className="grid gap-1">
<ConnectionCreateOption theme={theme} icon={<List className="size-5" />} title="文本生成" description="脚本、广告词、品牌文案" onClick={() => onCreate(CanvasNodeType.Text)} />
<ConnectionCreateOption theme={theme} icon={<ImageIcon className="size-5" />} title="图片生成" onClick={() => onCreate(CanvasNodeType.Image)} />
<ConnectionCreateOption theme={theme} icon={<Video className="size-5" />} title="视频生成" onClick={() => onCreate(CanvasNodeType.Video)} />
<ConnectionCreateOption theme={theme} icon={<Music2 className="size-5" />} title="音频参考" onClick={() => onCreate(CanvasNodeType.Audio)} />
<ConnectionCreateOption theme={theme} icon={<Settings2 className="size-5" />} title="配置节点" description="模型、尺寸、数量和输入顺序" onClick={() => onCreate(CanvasNodeType.Config)} />
<ConnectionCreateOption theme={theme} icon={<List className="size-5" />} title={t("canvas.createMenu.text")} description={t("canvas.createMenu.textDescription")} onClick={() => onCreate(CanvasNodeType.Text)} />
<ConnectionCreateOption theme={theme} icon={<ImageIcon className="size-5" />} title={t("canvas.createMenu.image")} onClick={() => onCreate(CanvasNodeType.Image)} />
<ConnectionCreateOption theme={theme} icon={<Video className="size-5" />} title={t("canvas.createMenu.video")} onClick={() => onCreate(CanvasNodeType.Video)} />
<ConnectionCreateOption theme={theme} icon={<Music2 className="size-5" />} title={t("canvas.createMenu.audio")} onClick={() => onCreate(CanvasNodeType.Audio)} />
<ConnectionCreateOption theme={theme} icon={<Settings2 className="size-5" />} title={t("canvas.createMenu.config")} description={t("canvas.createMenu.configDescription")} onClick={() => onCreate(CanvasNodeType.Config)} />
</div>
</div>
);
@@ -75,6 +77,7 @@ export function ConnectionCreateOption({ theme, icon, title, description, onClic
export function NodeCreateMenu({ position, onCreate, onClose }: { position: Position; onCreate: (type: string) => void; onClose: () => void }) {
const theme = canvasThemes[useThemeStore((state) => state.theme)];
const { t } = useTranslation();
useNodeRegistryVersion();
const menuRef = useRef<HTMLDivElement>(null);
const definitions = listNodeDefinitions().filter((def) => def.showInCreateMenu !== false);
@@ -96,9 +99,9 @@ export function NodeCreateMenu({ position, onCreate, onClose }: { position: Posi
>
<div className="mb-2 flex items-center justify-between px-1">
<span className="text-sm font-medium" style={{ color: theme.node.muted }}>
选择节点
{t("canvas.createMenu.select")}
</span>
<button type="button" className="grid size-7 place-items-center rounded-lg opacity-55 transition hover:opacity-100" onClick={onClose} aria-label="关闭">
<button type="button" className="grid size-7 place-items-center rounded-lg opacity-55 transition hover:opacity-100" onClick={onClose} aria-label={t("canvas.createMenu.close")}>
<X className="size-4" />
</button>
</div>