feat(i18n): implement internationalization framework and update UI components for language support
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
import { type ReactNode, useState } from "react";
|
||||
import { ConfigProvider, Switch } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import i18n from "@/i18n";
|
||||
import { type CanvasTheme } from "@/lib/canvas-theme";
|
||||
import type { AiConfig } from "@/stores/use-config-store";
|
||||
|
||||
const qualityOptions = [
|
||||
{ value: "auto", label: "自动" },
|
||||
{ value: "high", label: "高" },
|
||||
{ value: "medium", label: "中" },
|
||||
{ value: "low", label: "低" },
|
||||
{ value: "auto", labelKey: "auto" },
|
||||
{ value: "high", labelKey: "high" },
|
||||
{ value: "medium", labelKey: "medium" },
|
||||
{ value: "low", labelKey: "low" },
|
||||
];
|
||||
const DIMENSION_STEP = 16;
|
||||
|
||||
@@ -28,7 +30,7 @@ const aspectOptions = [
|
||||
{ value: "auto", label: "auto", width: 0, height: 0, icon: "auto" },
|
||||
];
|
||||
|
||||
export const imageQualityOptions = qualityOptions.map((item) => ({ value: item.value, label: item.label }));
|
||||
export const imageQualityOptions = qualityOptions.map((item) => ({ value: item.value, get label() { return i18n.t(`settingsPanels.common.${item.labelKey}`); } }));
|
||||
export const imageAspectOptions = aspectOptions.map((item) => ({ value: item.size || item.value, label: item.label }));
|
||||
|
||||
type ImageSettingsPanelProps = {
|
||||
@@ -42,6 +44,7 @@ type ImageSettingsPanelProps = {
|
||||
};
|
||||
|
||||
export function ImageSettingsPanel({ config, onConfigChange, theme, showTitle = true, className = "w-[320px] space-y-4 rounded-2xl px-1 py-0.5", maxCount = 15, quickCount = 10 }: ImageSettingsPanelProps) {
|
||||
const { t } = useTranslation();
|
||||
const [snapDimensionToStep, setSnapDimensionToStep] = useState(true);
|
||||
const quality = config.quality || "auto";
|
||||
const count = Math.max(1, Math.min(maxCount, Math.floor(Math.abs(Number(config.count)) || 1)));
|
||||
@@ -71,25 +74,25 @@ export function ImageSettingsPanel({ config, onConfigChange, theme, showTitle =
|
||||
if (document.activeElement instanceof HTMLInputElement && event.currentTarget.contains(document.activeElement)) document.activeElement.blur();
|
||||
}}
|
||||
>
|
||||
{showTitle ? <div className="text-lg font-semibold">图像设置</div> : null}
|
||||
{showTitle ? <div className="text-lg font-semibold">{t("settingsPanels.image.title")}</div> : null}
|
||||
<div className="space-y-2.5">
|
||||
<SettingTitle color={theme.node.muted}>质量</SettingTitle>
|
||||
<SettingTitle color={theme.node.muted}>{t("settingsPanels.image.quality")}</SettingTitle>
|
||||
<div className="grid grid-cols-4 gap-2.5">
|
||||
{qualityOptions.map((item) => (
|
||||
<OptionPill key={item.value} selected={quality === item.value} theme={theme} onClick={() => onConfigChange("quality", item.value)}>
|
||||
{item.label}
|
||||
{t(`settingsPanels.common.${item.labelKey}`)}
|
||||
</OptionPill>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<SettingTitle color={theme.node.muted}>尺寸</SettingTitle>
|
||||
<SettingTitle color={theme.node.muted}>{t("settingsPanels.image.size")}</SettingTitle>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-medium" style={{ color: theme.node.muted }}>
|
||||
16倍数对齐
|
||||
{t("settingsPanels.image.align16")}
|
||||
</span>
|
||||
<span title="输入完成后自动向上补成 16 的倍数" onMouseDown={(event) => event.stopPropagation()}>
|
||||
<span title={t("settingsPanels.image.align16Hint")} onMouseDown={(event) => event.stopPropagation()}>
|
||||
<Switch size="small" checked={snapDimensionToStep} onChange={setSnapDimensionToStep} />
|
||||
</span>
|
||||
</div>
|
||||
@@ -101,7 +104,7 @@ export function ImageSettingsPanel({ config, onConfigChange, theme, showTitle =
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2.5">
|
||||
<SettingTitle color={theme.node.muted}>宽高比</SettingTitle>
|
||||
<SettingTitle color={theme.node.muted}>{t("settingsPanels.image.aspectRatio")}</SettingTitle>
|
||||
<div className="grid grid-cols-4 gap-2.5">
|
||||
{aspectOptions.map((item) => (
|
||||
<button
|
||||
@@ -120,9 +123,9 @@ export function ImageSettingsPanel({ config, onConfigChange, theme, showTitle =
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="space-y-0.5">
|
||||
<SettingTitle color={theme.node.muted}>透明背景</SettingTitle>
|
||||
<SettingTitle color={theme.node.muted}>{t("settingsPanels.image.transparent")}</SettingTitle>
|
||||
<div className="text-xs" style={{ color: theme.node.muted, opacity: 0.75 }}>
|
||||
开启后生成无背景的透明图像(仅部分模型可用)
|
||||
{t("settingsPanels.image.transparentHint")}
|
||||
</div>
|
||||
</div>
|
||||
<span onMouseDown={(event) => event.stopPropagation()}>
|
||||
@@ -130,11 +133,11 @@ export function ImageSettingsPanel({ config, onConfigChange, theme, showTitle =
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-2.5">
|
||||
<SettingTitle color={theme.node.muted}>生成张数</SettingTitle>
|
||||
<SettingTitle color={theme.node.muted}>{t("settingsPanels.image.count")}</SettingTitle>
|
||||
<div className="grid grid-cols-4 gap-2.5">
|
||||
{Array.from({ length: quickCount }, (_, index) => index + 1).map((value) => (
|
||||
<OptionPill key={value} selected={count === value} theme={theme} onClick={() => onConfigChange("count", String(value))}>
|
||||
{value} 张
|
||||
{t("settingsPanels.image.images", { count: value })}
|
||||
</OptionPill>
|
||||
))}
|
||||
<CountInput value={count} max={maxCount} theme={theme} onChange={(value) => onConfigChange("count", String(value || 1))} />
|
||||
@@ -159,7 +162,7 @@ export function ImageSettingsTheme({ theme, children }: { theme: CanvasTheme; ch
|
||||
}
|
||||
|
||||
export function imageQualityLabel(value: string) {
|
||||
return ({ auto: "自动", high: "高", medium: "中", low: "低" } as Record<string, string>)[value] || value;
|
||||
return (["auto", "high", "medium", "low"].includes(value) ? i18n.t(`settingsPanels.common.${value}`) : value);
|
||||
}
|
||||
|
||||
export function imageSizeLabel(size: string) {
|
||||
|
||||
Reference in New Issue
Block a user