From a5e25a3e822fc19698ad8055ed0229c64da7060b Mon Sep 17 00:00:00 2001 From: Raycoi <415187499@qq.com> Date: Thu, 14 May 2026 01:23:20 +0800 Subject: [PATCH] feat(i18n): add Simplified Chinese translations and update existing locales - Added Simplified Chinese (cn) translations for all relevant keys in the i18n system. - Updated existing translations in English, German, Spanish, French, Arabic, and Hebrew to include new keys for input types and hotkey descriptions. --- src/components/CadenceInput.tsx | 721 +++++++++++++------------- src/components/KeyCaptureInput.tsx | 10 +- src/components/panels/SimplePanel.tsx | 4 +- src/i18n.ts | 5 +- src/locales/ar.json | 49 +- src/locales/cn.json | 315 +++++++++++ src/locales/de.json | 12 +- src/locales/en.json | 23 +- src/locales/es.json | 38 +- src/locales/fr.json | 38 +- src/locales/he.json | 23 +- 11 files changed, 819 insertions(+), 419 deletions(-) create mode 100644 src/locales/cn.json diff --git a/src/components/CadenceInput.tsx b/src/components/CadenceInput.tsx index e2d24ac..15e70ec 100644 --- a/src/components/CadenceInput.tsx +++ b/src/components/CadenceInput.tsx @@ -10,117 +10,116 @@ import type { RateInputMode, Settings } from "../store"; import { useTranslation } from "../i18n"; import { AdvDropdown } from "./panels/advanced/shared"; import type { ClickInterval } from "../settingsSchema"; - -// TODO: This should really be split up into what is in the advanced panel and what is in the simple panel. Having both in one feels kinda off i feel like. - -interface Props { - settings: Settings; - update: (patch: Partial) => void; - variant: "simple" | "advanced"; - showInfo?: boolean; -} - -const INTERVAL_OPTIONS = [ - { value: "s", label: "Second" }, - { value: "m", label: "Minute" }, - { value: "h", label: "Hour" }, - { value: "d", label: "Day" }, -] as const; - -const SIMPLE_RATE_INPUT_MODE_OPTIONS = [ - { value: "rate", label: "Rate" }, - { value: "duration", label: "Delay" }, -] as const; - -function parseIntegerRaw(raw: string) { - const normalized = normalizeIntegerRaw(raw); - return normalized === "" || normalized === "-" ? 0 : Number(normalized); -} - -function clamp(value: number, min: number, max?: number) { - const minClamped = Math.max(min, value); - return max === undefined ? minClamped : Math.min(max, minClamped); -} - -function dynamicChWidth(value: number, min = 1, max = 3) { - return `${clamp(String(Math.abs(value)).length, min, max)}ch`; -} - -function handleWheelStep( - event: WheelEvent, - current: number, - min: number, - max: number | undefined, - apply: (next: number) => void, -) { - event.preventDefault(); - event.stopPropagation(); - event.currentTarget.blur(); - const delta = event.deltaY < 0 ? 1 : -1; - apply(clamp(current + delta, min, max)); -} - -function handleNumberChange( - event: ChangeEvent, - apply: (next: number) => void, -) { - const normalized = normalizeIntegerRaw(event.target.value); - if (normalized !== event.target.value) { - event.target.value = normalized; - } - apply(parseIntegerRaw(normalized)); -} - -function handleNumberBlur( - event: FocusEvent, - min: number, - max: number | undefined, - apply: (next: number) => void, -) { - const normalized = normalizeIntegerRaw(event.target.value); - if (normalized !== event.target.value) { - event.target.value = normalized; - } - apply(clamp(parseIntegerRaw(normalized), min, max)); -} - -function DurationField({ - value, - min, - max, - onChange, - style, - unit, - className, -}: { - value: number; - min: number; - max?: number; - onChange: (next: number) => void; - style?: CSSProperties; - unit: string; - className?: string; -}) { - return ( -
- handleNumberChange(event, onChange)} - onBlur={(event) => handleNumberBlur(event, min, max, onChange)} - onWheel={(event) => handleWheelStep(event, value, min, max, onChange)} - style={style} - /> - {unit} -
- ); -} - + +// TODO: This should really be split up into what is in the advanced panel and what is in the simple panel. Having both in one feels kinda off i feel like. + +interface Props { + settings: Settings; + update: (patch: Partial) => void; + variant: "simple" | "advanced"; + showInfo?: boolean; +} + +function parseIntegerRaw(raw: string) { + const normalized = normalizeIntegerRaw(raw); + return normalized === "" || normalized === "-" ? 0 : Number(normalized); +} + +function clamp(value: number, min: number, max?: number) { + const minClamped = Math.max(min, value); + return max === undefined ? minClamped : Math.min(max, minClamped); +} + +function dynamicChWidth(value: number, min = 1, max = 3) { + return `${clamp(String(Math.abs(value)).length, min, max)}ch`; +} + +function handleWheelStep( + event: WheelEvent, + current: number, + min: number, + max: number | undefined, + apply: (next: number) => void, +) { + event.preventDefault(); + event.stopPropagation(); + event.currentTarget.blur(); + const delta = event.deltaY < 0 ? 1 : -1; + apply(clamp(current + delta, min, max)); +} + +function handleNumberChange( + event: ChangeEvent, + apply: (next: number) => void, +) { + const normalized = normalizeIntegerRaw(event.target.value); + if (normalized !== event.target.value) { + event.target.value = normalized; + } + apply(parseIntegerRaw(normalized)); +} + +function handleNumberBlur( + event: FocusEvent, + min: number, + max: number | undefined, + apply: (next: number) => void, +) { + const normalized = normalizeIntegerRaw(event.target.value); + if (normalized !== event.target.value) { + event.target.value = normalized; + } + apply(clamp(parseIntegerRaw(normalized), min, max)); +} + +function DurationField({ + value, + min, + max, + onChange, + style, + unit, + className, +}: { + value: number; + min: number; + max?: number; + onChange: (next: number) => void; + style?: CSSProperties; + unit: string; + className?: string; +}) { + return ( +
+ handleNumberChange(event, onChange)} + onBlur={(event) => handleNumberBlur(event, min, max, onChange)} + onWheel={(event) => handleWheelStep(event, value, min, max, onChange)} + style={style} + /> + {unit} +
+ ); +} + export default function CadenceInput({ settings, update, variant }: Props) { const { t } = useTranslation(); + const INTERVAL_OPTIONS = [ + { value: "s", label: t("options.interval.s") }, + { value: "m", label: t("options.interval.m") }, + { value: "h", label: t("options.interval.h") }, + { value: "d", label: t("options.interval.d") }, + ] as const; + + const SIMPLE_RATE_INPUT_MODE_OPTIONS = [ + { value: "rate", label: t("options.rateInputMode.rate") }, + { value: "duration", label: t("options.rateInputMode.duration") }, + ] as const; const switchMode = (mode: RateInputMode) => { if (mode === settings.rateInputMode) return; @@ -164,18 +163,18 @@ export default function CadenceInput({ settings, update, variant }: Props) { ...(converted ?? {}), }); }; - - if (variant === "simple") { - return ( -
- {settings.rateInputMode === "rate" ? ( -
- + {settings.rateInputMode === "rate" ? ( +
+ handleNumberChange(event, (next) => @@ -193,11 +192,11 @@ export default function CadenceInput({ settings, update, variant }: Props) { ) } /> -
- - {t("advanced.clicksPer")} - -
+
+ + {t("advanced.clicksPer")} + +
-
- switchMode(value as RateInputMode)} - /> -
- ) : ( -
-
+
+ switchMode(value as RateInputMode)} + /> +
+ ) : ( +
+
+ }} + unit={t("options.timeUnits.h")} + /> + }} + unit={t("options.timeUnits.m")} + /> + }} + unit={t("options.timeUnits.s")} + /> -
-
- Per Click -
- switchMode(value as RateInputMode)} - /> -
- )} -
- ); - } - - const modeToggle = ( -
- {RATE_INPUT_MODE_OPTIONS.map((mode) => ( - - ))} -
- ); - - return ( -
-
-
- {settings.rateInputMode === "rate" ? ( -
-
- - handleNumberChange(event, (next) => - update({ clickSpeed: next }), - ) - } - onBlur={(event) => - handleNumberBlur(event, 1, 500, (next) => - update({ clickSpeed: next }), - ) - } - onWheel={(event) => - handleWheelStep( - event, - settings.clickSpeed, - 1, - 500, - (next) => update({ clickSpeed: next }), - ) - } - /> -
-
- {t("advanced.clicksPer")} -
-
- - update({ clickInterval: v as ClickInterval }) - } - /> -
-
- ) : ( -
-
- - handleNumberChange(event, (next) => - update({ durationHours: next }), - ) - } - onBlur={(event) => - handleNumberBlur(event, 0, 999, (next) => - update({ durationHours: next }), - ) - } - onWheel={(event) => - handleWheelStep( - event, - settings.durationHours, - 0, - 999, - (next) => update({ durationHours: next }), - ) - } - /> - h -
-
-
- - handleNumberChange(event, (next) => - update({ durationMinutes: next }), - ) - } - onBlur={(event) => - handleNumberBlur(event, 0, 59, (next) => - update({ durationMinutes: next }), - ) - } - onWheel={(event) => - handleWheelStep( - event, - settings.durationMinutes, - 0, - 59, - (next) => update({ durationMinutes: next }), - ) - } - /> - m -
-
-
- - handleNumberChange(event, (next) => - update({ durationSeconds: next }), - ) - } - onBlur={(event) => - handleNumberBlur(event, 0, 59, (next) => - update({ durationSeconds: next }), - ) - } - onWheel={(event) => - handleWheelStep( - event, - settings.durationSeconds, - 0, - 59, - (next) => update({ durationSeconds: next }), - ) - } - /> - s -
-
-
- - handleNumberChange(event, (next) => - update({ durationMilliseconds: next }), - ) - } - onBlur={(event) => - handleNumberBlur(event, 0, 999, (next) => - update({ durationMilliseconds: next }), - ) - } - onWheel={(event) => - handleWheelStep( - event, - settings.durationMilliseconds, - 0, - 999, - (next) => update({ durationMilliseconds: next }), - ) - } - /> - ms -
-
- )} -
- {modeToggle} -
-
- ); -} + }} + unit={t("options.timeUnits.ms")} + /> +
+
+ {t("advanced.perClick")} +
+ switchMode(value as RateInputMode)} + /> +
+ )} +
+ ); + } + + const modeToggle = ( +
+ {RATE_INPUT_MODE_OPTIONS.map((mode) => ( + + ))} +
+ ); + + return ( +
+
+
+ {settings.rateInputMode === "rate" ? ( +
+
+ + handleNumberChange(event, (next) => + update({ clickSpeed: next }), + ) + } + onBlur={(event) => + handleNumberBlur(event, 1, 500, (next) => + update({ clickSpeed: next }), + ) + } + onWheel={(event) => + handleWheelStep( + event, + settings.clickSpeed, + 1, + 500, + (next) => update({ clickSpeed: next }), + ) + } + /> +
+
+ {t("advanced.clicksPer")} +
+
+ + update({ clickInterval: v as ClickInterval }) + } + /> +
+
+ ) : ( +
+
+ + handleNumberChange(event, (next) => + update({ durationHours: next }), + ) + } + onBlur={(event) => + handleNumberBlur(event, 0, 999, (next) => + update({ durationHours: next }), + ) + } + onWheel={(event) => + handleWheelStep( + event, + settings.durationHours, + 0, + 999, + (next) => update({ durationHours: next }), + ) + } + /> + h +
+
+
+ + handleNumberChange(event, (next) => + update({ durationMinutes: next }), + ) + } + onBlur={(event) => + handleNumberBlur(event, 0, 59, (next) => + update({ durationMinutes: next }), + ) + } + onWheel={(event) => + handleWheelStep( + event, + settings.durationMinutes, + 0, + 59, + (next) => update({ durationMinutes: next }), + ) + } + /> + m +
+
+
+ + handleNumberChange(event, (next) => + update({ durationSeconds: next }), + ) + } + onBlur={(event) => + handleNumberBlur(event, 0, 59, (next) => + update({ durationSeconds: next }), + ) + } + onWheel={(event) => + handleWheelStep( + event, + settings.durationSeconds, + 0, + 59, + (next) => update({ durationSeconds: next }), + ) + } + /> + s +
+
+
+ + handleNumberChange(event, (next) => + update({ durationMilliseconds: next }), + ) + } + onBlur={(event) => + handleNumberBlur(event, 0, 999, (next) => + update({ durationMilliseconds: next }), + ) + } + onWheel={(event) => + handleWheelStep( + event, + settings.durationMilliseconds, + 0, + 999, + (next) => update({ durationMilliseconds: next }), + ) + } + /> + ms +
+
+ )} +
+ {modeToggle} +
+
+ ); +} diff --git a/src/components/KeyCaptureInput.tsx b/src/components/KeyCaptureInput.tsx index 7c61a7c..97530d8 100644 --- a/src/components/KeyCaptureInput.tsx +++ b/src/components/KeyCaptureInput.tsx @@ -14,6 +14,7 @@ import { } from "../hotkeys"; import { isAlphabeticKeyboardKey } from "../keyboardKeyCase"; import type { KeyboardKeyCase, MouseButton } from "../store"; +import { useTranslation } from "../i18n"; interface Props { value: string; @@ -52,6 +53,7 @@ export default function KeyCaptureInput({ keyboardKeyCase, onMouseButtonCapture, }: Props) { + const { t } = useTranslation(); const [listening, setListening] = useState(false); const inputRef = useRef(null); const rightClickStartedWhileListeningRef = useRef(false); @@ -69,14 +71,14 @@ export default function KeyCaptureInput({ }, []); const displayText = useMemo(() => { - if (listening) return "Press a key..."; - if (!value) return "Select key"; + if (listening) return t("hotkey.pressKey"); + if (!value) return t("hotkey.selectKey"); return applyKeyboardKeyCase( value, formatHotkeyForDisplay(value, layoutMap), keyboardKeyCase, ); - }, [keyboardKeyCase, layoutMap, listening, value]); + }, [keyboardKeyCase, layoutMap, listening, value, t]); const handleKeyDown = (event: KeyboardEvent) => { event.preventDefault(); @@ -163,7 +165,7 @@ export default function KeyCaptureInput({ onKeyDown={handleKeyDown} onContextMenu={handleContextMenu} spellCheck={false} - title="Right click input to clear" + title={t("hotkey.rightClickToClear")} style={{ cursor: "pointer", textAlign: "center", diff --git a/src/components/panels/SimplePanel.tsx b/src/components/panels/SimplePanel.tsx index 3434633..f727452 100644 --- a/src/components/panels/SimplePanel.tsx +++ b/src/components/panels/SimplePanel.tsx @@ -143,8 +143,8 @@ export default function SimplePanel({ settings, update }: SimplePanelProps) { })); const inputTypeOptions = [ - { value: "mouse", label: "Mouse" }, - { value: "keyboard", label: "Key" }, + { value: "mouse", label: t("options.inputType.mouse") }, + { value: "keyboard", label: t("options.inputType.keyboard") }, ] as const; const canToggleKeyboardKeyCase = isAlphabeticKeyboardKey( settings.keyboardKey, diff --git a/src/i18n.ts b/src/i18n.ts index 7f52c6c..2fdd5c1 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -15,8 +15,9 @@ import es from "./locales/es.json"; import fr from "./locales/fr.json"; import de from "./locales/de.json"; import he from "./locales/he.json"; +import cn from "./locales/cn.json"; -export const LANGUAGE_CODES = ["en", "es", "fr", "ar", "de", "he"] as const; +export const LANGUAGE_CODES = ["en", "es", "fr", "ar", "de", "he", "cn"] as const; export type Language = (typeof LANGUAGE_CODES)[number]; export const DEFAULT_LANGUAGE: Language = "en"; @@ -27,6 +28,7 @@ export const LANGUAGE_OPTIONS: readonly { code: Language; label: string }[] = [ { code: "ar", label: "العربية" }, { code: "de", label: "Deutsch"}, { code: "he", label: "עברית"}, + { code: "cn", label: "简体中文"}, ]; type TranslationTree = typeof en; @@ -44,6 +46,7 @@ const translations: Record = { ar, de, he, + cn, }; type I18nContextValue = { diff --git a/src/locales/ar.json b/src/locales/ar.json index 291f5fe..991a1ff 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -5,7 +5,8 @@ "fr": "Français", "ar": "العربية", "de": "Deutsch", - "he": "עברית" + "he": "עברית", + "cn": "简体中文" }, "common": { "on": "تشغيل", @@ -64,13 +65,13 @@ "runOnStartupDescription": "بدء تشغيل BlurAutoClicker تلقائياً مع Windows، مصغراً إلى شريط المهام.", "sectionAppearance": "المظهر", "sectionAppearanceDescription": "تفضيلات السمة ولون التمييز.", - "theme": "السمة", - "themeDescription": "التبديل بين السمات الداكنة والفاتحة.", - "advancedLayout": "تخطيط الوضع المتقدم", - "advancedLayoutDescription": "اختر ما إذا كان النقر التسلسلي يظهر بجانب عناصر التحكم المتقدمة الأخرى أو أسفل النقر المزدوج.", - "advancedLayoutWide": "عريض", - "advancedLayoutTall": "طويل", - "accentColor": "لون التمييز", + "theme": "السمة", + "themeDescription": "التبديل بين السمات الداكنة والفاتحة.", + "advancedLayout": "تخطيط الوضع المتقدم", + "advancedLayoutDescription": "اختر ما إذا كان النقر التسلسلي يظهر بجانب عناصر التحكم المتقدمة الأخرى أو أسفل النقر المزدوج.", + "advancedLayoutWide": "عريض", + "advancedLayoutTall": "طويل", + "accentColor": "لون التمييز", "accentColorDescription": "تخصيص لون التمييز الأساسي المستخدم للحالات النشطة.", "sectionPresets": "الإعدادات المسبقة", "sectionPresetsDescription": "حفظ أو تحديث أو إعادة تسمية أو حذف تكوينات النقر القابلة لإعادة الاستخدام.", @@ -115,12 +116,12 @@ "cadenceDescription": "يتحكم في سرعة توليد النقرات: إما كنقرات لكل فترة (المعدل) أو كتأخير ثابت بين النقرات (التأخير).", "clicksPer": "نقرات لكل", "hotkey": "اختصار لوحة المفاتيح", - "hotkeyDescription": "اختر مجموعة المفاتيح التي تبدأ وتوقف النقر. استخدم التبديل للضغط للتشغيل/الإيقاف، أو الاستمرار للنقر فقط أثناء الضغط.", - "mouseButton": "زر الماوس", - "mouseButtonDescription": "اختر زر الماوس الذي سيضغط عليه النقر في كل حدث نقر.", - "keyboardKey": "مفتاح لوحة المفاتيح", - "keyboardKeyDescription": "اختر مفتاح لوحة المفاتيح الذي سيضغط عليه النقر في كل حدث نقر.", - "dutyCycle": "مدة النقر", + "hotkeyDescription": "اختر مجموعة المفاتيح التي تبدأ وتوقف النقر. استخدم التبديل للضغط للتشغيل/الإيقاف، أو الاستمرار للنقر فقط أثناء الضغط.", + "mouseButton": "زر الماوس", + "mouseButtonDescription": "اختر زر الماوس الذي سيضغط عليه النقر في كل حدث نقر.", + "keyboardKey": "مفتاح لوحة المفاتيح", + "keyboardKeyDescription": "اختر مفتاح لوحة المفاتيح الذي سيضغط عليه النقر في كل حدث نقر.", + "dutyCycle": "مدة النقر", "dutyCycleDescription": "اختر مدة الضغط على زر الماوس خلال كل نقرة. 50% عند نقرة واحدة في الثانية = 0.5 ثانية ضغط، 0.5 ثانية تحرير", "speedVariation": "تباين السرعة", "speedVariationDescription": "يعشوّي سرعة النقر بالنسبة المئوية المحددة.", @@ -168,7 +169,8 @@ "sequenceAddingIn": "سيتم الإضافة خلال", "sequenceCapturing": "جارٍ الالتقاط...", "customStopZoneAddingIn": "سيتم التعيين خلال", - "customStopZoneCapturing": "جارٍ التعيين..." + "customStopZoneCapturing": "جارٍ التعيين...", + "perClick": "لكل نقرة" }, "options": { "interval": { @@ -197,6 +199,20 @@ "Middle": "نقر وسط", "Right": "نقر أيمن" }, + "inputType": { + "mouse": "ماوس", + "keyboard": "لوحة مفاتيح" + }, + "rateInputMode": { + "rate": "معدل", + "duration": "تأخير" + }, + "timeUnits": { + "h": "س", + "m": "د", + "s": "ث", + "ms": "مللي ث" + }, "timeUnitShort": { "s": "ث", "m": "د", @@ -205,7 +221,10 @@ }, "hotkey": { "pressKeys": "اضغط على المفاتيح...", + "pressKey": "اضغط على مفتاح...", "empty": "انقر واضغط على المفاتيح", + "selectKey": "اختر مفتاح", + "rightClickToClear": "انقر بزر الماوس الأيمن لحذف", "key": { "up": "أعلى", "down": "أسفل", diff --git a/src/locales/cn.json b/src/locales/cn.json new file mode 100644 index 0000000..4822f66 --- /dev/null +++ b/src/locales/cn.json @@ -0,0 +1,315 @@ +{ + "language": { + "en": "English", + "es": "Español", + "fr": "Français", + "ar": "العربية", + "de": "Deutsch", + "he": "עברית", + "cn": "简体中文" + }, + "common": { + "on": "开", + "off": "关", + "enabled": "已启用", + "disabled": "已禁用", + "reset": "重置", + "resetting": "重置中...", + "notAvailable": "不可用", + "dark": "深色", + "light": "浅色" + }, + "titleBar": { + "simple": "简洁模式", + "advanced": "高级模式", + "zones": "区域", + "settings": "设置", + "enableAlwaysOnTop": "开启窗口置顶", + "disableAlwaysOnTop": "关闭窗口置顶", + "minimize": "最小化", + "close": "关闭" + }, + "settings": { + "sectionAbout": "关于", + "sectionAboutDescription": "版本和项目链接。", + "supportMe": "支持我", + "version": "版本", + "sectionUsage": "使用情况", + "sectionUsageDescription": "本地运行总计和历史控制。", + "usageData": "您的使用数据", + "usageDataDescription": "您的个人点击器统计数据,存储在本地。", + "totalClicks": "总点击次数", + "totalTimeClicking": "总点击时长", + "averageCpu": "平均 CPU 使用率", + "sessions": "会话次数", + "noRuns": "尚未记录运行", + "clearStats": "清除统计数据", + "clearStatsDescription": "永久删除所有本地存储的使用数据。", + "sectionBehavior": "窗口与提醒", + "sectionBehaviorDescription": "影响应用窗口行为和停止反馈的控制项。", + "alwaysOnTop": "窗口置顶", + "alwaysOnTopDescription": "让应用固定在其他窗口之上。", + "stopHitboxOverlay": "停止区域叠加显示", + "stopHitboxOverlayDescription": "切换是否显示停止区域的叠加框。", + "stopReasonAlert": "停止原因提醒", + "stopReasonAlertDescription": "在标题栏中显示点击器停止的原因。", + "strictHotkeyModifiers": "严格模式", + "strictHotkeyModifiersDescription": "开启:仅在完全匹配时触发。关闭:忽略额外按下的按键。", + "sectionStartup": "启动", + "sectionStartupDescription": "控制 Windows 启动或窗口关闭时的行为。", + "language": "语言", + "languageDescription": "选择应用显示语言。", + "minimizeToTray": "最小化到系统托盘", + "minimizeToTrayDescription": "启用后,关闭窗口会将其隐藏到系统托盘而不是退出应用。", + "runOnStartup": "开机自启", + "runOnStartupDescription": "Windows 启动时自动运行 BlurAutoClicker,并最小化到托盘。", + "sectionAppearance": "外观", + "sectionAppearanceDescription": "主题和强调色偏好。", + "theme": "主题", + "themeDescription": "在深色和浅色主题之间切换。", + "advancedLayout": "高级布局", + "advancedLayoutDescription": "选择“序列点击”是放在其他高级控件旁边,还是放在“双击”下方。", + "advancedLayoutWide": "宽布局", + "advancedLayoutTall": "高布局", + "accentColor": "强调色", + "accentColorDescription": "自定义用于激活状态的主强调色。", + "sectionPresets": "预设", + "sectionPresetsDescription": "保存、更新、重命名或删除可复用的点击器配置。", + "presets": "预设", + "presetsDescription": "保存并复用命名的点击器配置。", + "presetNamePlaceholder": "预设名称", + "saveNewPreset": "保存新预设", + "presetLimitReached": "已达预设数量上限。请先删除一个再保存。", + "presetActionsDisabled": "点击器运行时无法使用预设操作。", + "noPresets": "尚未保存预设。从当前点击器设置中保存一个。", + "presetActive": "当前激活", + "presetSave": "保存", + "presetCancel": "取消", + "presetConfirmDelete": "确认删除?", + "presetApply": "应用", + "presetUpdate": "更新", + "presetRename": "重命名", + "presetDelete": "删除", + "sectionReset": "重置", + "sectionResetDescription": "恢复默认或清除本地数据(包括预设)的破坏性操作。", + "resetAll": "重置所有设置", + "resetAllDescription": "将所有输入字段、设置和预设重置为默认值。", + "resetDialogTitle": "重置所有设置?", + "resetDialogMessage": "所有输入项、热键、偏好设置和预设都将恢复为默认值。此操作无法撤销。", + "resetDialogConfirm": "重置", + "clearStatsDialogTitle": "清除使用数据?", + "clearStatsDialogMessage": "您的总点击次数、会话次数、点击总时长和 CPU 平均值将被永久清除。", + "clearStatsDialogConfirm": "清除" + }, + "simple": { + "changeClickInterval": "更改点击间隔", + "switchRateInputMode": "在频率和间隔输入模式间切换", + "switchMode": "在热键切换和保持模式间切换", + "selectMouseButton": "选择要点击的鼠标按键", + "hold": "点击持续时间", + "holdDescription": "每次点击过程中鼠标按键按下的时长", + "randomization": "速度变化", + "randomizationDescription": "在设定 CPS 的百分比范围内随机改变点击速度" + }, + "advanced": { + "cadence": "节奏", + "cadenceDescription": "控制生成点击的速度:可以是每次间隔的点击次数(频率),也可以是两次点击之间的固定间隔(间隔)。", + "clicksPer": "次", + "hotkey": "热键", + "hotkeyDescription": "选择启动和停止点击器的按键组合。使用“切换”模式实现按一下开/按一下关,或使用“保持”模式仅在按住时点击。", + "mouseButton": "鼠标按键", + "mouseButtonDescription": "选择点击器每次点击事件要按下的鼠标按键。", + "keyboardKey": "键盘按键", + "keyboardKeyDescription": "选择点击器每次点击事件要按下的键盘按键。", + "dutyCycle": "点击持续时间", + "dutyCycleDescription": "选择每次点击过程中鼠标按键按下的时长。50% 在每秒 1 次点击时 = 按下 0.5 秒,松开 0.5 秒", + "speedVariation": "速度变化", + "speedVariationDescription": "按给定百分比随机化点击速度。", + "doubleClick": "双击", + "doubleClickDescription": "每次点击时以给定的间隔连续点击两次所选按键。仅在低于 50cps 时可用。", + "limits": "限制", + "clickLimit": "次数限制", + "clickLimitDescription": "达到设定的点击次数后自动停止。", + "timeLimit": "时间限制", + "timeLimitDescription": "达到设定的持续时间后自动停止。", + "cornerStop": "角落停止", + "cornerStopDescription": "当光标进入屏幕角落时停止点击器。作为安全开关使用。", + "edgeStop": "边缘停止", + "edgeStopDescription": "当光标到达屏幕边缘时停止点击器。作为安全开关使用。", + "position": "固定位置", + "positionDescription": "启用后,每次点击前将光标移动到保存的位置点。", + "delay": "间隔", + "clicksUnit": "次点击", + "pick": "拾取", + "picking": "拾取中...", + "pickingIn": "{seconds} 秒后拾取", + "sequenceClicking": "序列点击", + "sequenceClickingDescription": "按轮询顺序循环遍历保存的光标位置,在每个位置应用当前的全局计时和点击设置。", + "sequenceEmpty": "尚未保存序列点。", + "sequenceMoveUp": "上移", + "sequenceMoveDown": "下移", + "sequenceDelete": "删除", + "sequenceAddCurrentCursor": "添加当前光标位置", + "customStopZone": "自定义停止区域", + "customStopZoneDescription": "当光标进入此矩形区域时停止点击器。使用可跨多显示器的绝对屏幕坐标。", + "customStopZoneSetTopLeft": "设置左上角", + "customStopZoneSetBottomRight": "设置右下角", + "speedVariationUnavailable": "请启用“速度变化”以编辑应用随机化点击时间的程度。", + "doubleClickUnavailable": "在 {cps} 次点击/秒下无法使用“双击”。请将有效点击频率降低到 50 次点击/秒以下以启用它。", + "doubleClickContentUnavailable": "请启用“双击”以调整第一次和第二次点击之间的间隔。", + "clickLimitUnavailable": "请启用“点击次数限制”以在达到设定次数后自动停止。", + "timeLimitUnavailable": "请启用“时间限制”以在达到设定时长后自动停止。", + "cornerStopUnavailable": "请启用“角落停止”以编辑角落安全开关区域。", + "edgeStopUnavailable": "请启用“边缘停止”以编辑边缘安全开关区域。", + "positionUnavailable": "请启用“固定位置”以在每次点击前编辑或拾取固定的光标目标。", + "dutyCycleUnavailable": "请启用“点击持续时间”以编辑每次点击的按下时长。", + "pickInProgressUnavailable": "位置捕获已在进行中。请等待当前拾取完成。", + "pickCountdownUnavailable": "{seconds} 秒后开始捕获位置。将光标移到目标位置并等待其被保存。", + "pickCountdownSingularUnavailable": "1 秒后开始捕获位置。将光标移到目标位置并等待其被保存。", + "sequenceAddingIn": "将在", + "sequenceCapturing": "捕获中...", + "customStopZoneAddingIn": "将在", + "customStopZoneCapturing": "设置中...", + "perClick": "每次" + }, + "options": { + "interval": { + "s": "每秒", + "m": "每分钟", + "h": "每小时", + "d": "每天" + }, + "intervalShort": { + "s": "秒", + "m": "分", + "h": "时", + "d": "天" + }, + "mode": { + "Toggle": "切换", + "Hold": "按住" + }, + "mouseButton": { + "Left": "左键", + "Middle": "中键", + "Right": "右键" + }, + "mouseClick": { + "Left": "左键单击", + "Middle": "中键单击", + "Right": "右键单击" + }, + "inputType": { + "mouse": "鼠标", + "keyboard": "键盘" + }, + "rateInputMode": { + "rate": "频率", + "duration": "间隔" + }, + "timeUnits": { + "h": "时", + "m": "分", + "s": "秒", + "ms": "毫秒" + }, + "timeUnitShort": { + "s": "秒", + "m": "分", + "h": "时" + } + }, + "hotkey": { + "pressKeys": "按下按键...", + "pressKey": "按下一个按键...", + "empty": "点击并按下按键", + "selectKey": "选择按键", + "rightClickToClear": "右键单击输入框以清空", + "key": { + "up": "上箭头", + "down": "下箭头", + "left": "左箭头", + "right": "右箭头", + "pageup": "Page Up", + "pagedown": "Page Down", + "backspace": "Backspace", + "delete": "Delete", + "insert": "Insert", + "home": "Home", + "end": "End", + "enter": "Enter", + "tab": "Tab", + "space": "空格", + "escape": "Esc", + "esc": "Esc", + "capslock": "Caps Lock", + "numlock": "Num Lock", + "scrolllock": "Scroll Lock", + "printscreen": "Print Screen", + "pause": "Pause", + "menu": "Menu", + "mouseleft": "左键", + "mouseright": "右键", + "mousemiddle": "滚轮", + "mouse4": "鼠标侧键后", + "mouse5": "鼠标侧键前", + "scrollup": "向上滚动", + "scrolldown": "向下滚动", + "numpad0": "小键盘 0", + "numpad1": "小键盘 1", + "numpad2": "小键盘 2", + "numpad3": "小键盘 3", + "numpad4": "小键盘 4", + "numpad5": "小键盘 5", + "numpad6": "小键盘 6", + "numpad7": "小键盘 7", + "numpad8": "小键盘 8", + "numpad9": "小键盘 9", + "numpadadd": "小键盘 +", + "numpadsubtract": "小键盘 -", + "numpadmultiply": "小键盘 *", + "numpaddivide": "小键盘 /", + "numpaddecimal": "小键盘 .", + "numpadenter": "小键盘 Enter" + }, + "modifier": { + "ctrl": "Ctrl", + "alt": "Alt", + "shift": "Shift", + "super": "Win" + } + }, + "update": { + "to": "到", + "preparing": "正在准备更新...", + "notAvailable": "更新已不可用。", + "downloading": "正在下载更新...", + "installing": "正在安装更新...", + "installingButton": "安装中...", + "installedRestart": "更新已安装。请重启以应用。", + "installFailed": "更新安装失败。", + "restartFailed": "重启失败。请手动重新打开应用。", + "restartToApply": "重启以应用更新", + "downloadAndInstall": "下载并安装", + "installAlreadyInstalling": "更新已在安装中。请等待完成后再试。", + "installAlreadyDownloading": "更新已在下载中。请等待当前安装完成。", + "installAlreadyPreparing": "更新已在准备中。请等待完成后再试。" + }, + "stopReason": { + "stoppedFromUi": "已通过界面停止", + "stoppedFromToggle": "已通过切换开关停止", + "stoppedFromHotkey": "已通过热键停止", + "stoppedFromHoldHotkey": "已通过保持热键停止", + "stopped": "已停止", + "topLeftCornerFailsafe": "左上角安全开关", + "topRightCornerFailsafe": "右上角安全开关", + "bottomLeftCornerFailsafe": "左下角安全开关", + "bottomRightCornerFailsafe": "右下角安全开关", + "topEdgeFailsafe": "上边缘安全开关", + "rightEdgeFailsafe": "右边缘安全开关", + "bottomEdgeFailsafe": "下边缘安全开关", + "leftEdgeFailsafe": "左边缘安全开关", + "clickLimitReached": "已达到点击次数限制 ({count})", + "timeLimitReached": "已达到时间限制 ({time})" + } +} \ No newline at end of file diff --git a/src/locales/de.json b/src/locales/de.json index 481ecf7..7bd7b2c 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -5,7 +5,8 @@ "fr": "Français", "ar": "العربية", "de": "Deutsch", - "he": "עברית" + "he": "עברית", + "cn": "简体中文" }, "common": { "on": "An", @@ -168,7 +169,8 @@ "sequenceAddingIn": "Hinzugefügt in", "sequenceCapturing": "Erfassung...", "customStopZoneAddingIn": "Setzen in", - "customStopZoneCapturing": "Wird gesetzt..." + "customStopZoneCapturing": "Wird gesetzt...", + "perClick": "Pro Klick" }, "options": { "interval": { "s": "Sekunde", "m": "Minute", "h": "Stunde", "d": "Tag" }, @@ -176,11 +178,17 @@ "mode": { "Toggle": "Umschalten", "Hold": "Halten" }, "mouseButton": { "Left": "Links", "Middle": "Mitte", "Right": "Rechts" }, "mouseClick": { "Left": "Linksklick", "Middle": "Mittelklick", "Right": "Rechtsklick" }, + "inputType": { "mouse": "Maus", "keyboard": "Tastatur" }, + "rateInputMode": { "rate": "Rate", "duration": "Verzögerung" }, + "timeUnits": { "h": "h", "m": "m", "s": "s", "ms": "ms" }, "timeUnitShort": { "s": "s", "m": "m", "h": "h" } }, "hotkey": { "pressKeys": "Tasten drücken...", + "pressKey": "Eine Taste drücken...", "empty": "Klicken und Tasten drücken", + "selectKey": "Taste auswählen", + "rightClickToClear": "Rechtsklick zum Löschen", "key": { "up": "Oben", "down": "Unten", "left": "Links", "right": "Rechts", "pageup": "Bild auf", "pagedown": "Bild ab", "backspace": "Rücktaste", diff --git a/src/locales/en.json b/src/locales/en.json index a196c99..0f60e7c 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -5,7 +5,8 @@ "fr": "Français", "ar": "العربية", "de": "Deutsch", - "he": "עברית" + "he": "עברית", + "cn": "简体中文" }, "common": { "on": "On", @@ -168,7 +169,8 @@ "sequenceAddingIn": "Adding in", "sequenceCapturing": "Capturing...", "customStopZoneAddingIn": "Setting in", - "customStopZoneCapturing": "Setting..." + "customStopZoneCapturing": "Setting...", + "perClick": "Per Click" }, "options": { "interval": { @@ -197,6 +199,20 @@ "Middle": "Middle Click", "Right": "Right Click" }, + "inputType": { + "mouse": "Mouse", + "keyboard": "Key" + }, + "rateInputMode": { + "rate": "Rate", + "duration": "Delay" + }, + "timeUnits": { + "h": "h", + "m": "m", + "s": "s", + "ms": "ms" + }, "timeUnitShort": { "s": "s", "m": "m", @@ -205,7 +221,10 @@ }, "hotkey": { "pressKeys": "Press keys...", + "pressKey": "Press a key...", "empty": "Click and press keys", + "selectKey": "Select key", + "rightClickToClear": "Right click input to clear", "key": { "up": "Up", "down": "Down", diff --git a/src/locales/es.json b/src/locales/es.json index 004b3f3..261088a 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -5,7 +5,8 @@ "fr": "Français", "ar": "العربية", "de": "Deutsch", - "he": "עברית" + "he": "עברית", + "cn": "简体中文" }, "common": { "on": "Activado", @@ -64,13 +65,13 @@ "runOnStartupDescription": "Inicia BlurAutoClicker con Windows, minimizado en la bandeja.", "sectionAppearance": "Apariencia", "sectionAppearanceDescription": "Preferencias de tema y color de acento.", - "theme": "Tema", - "themeDescription": "Cambia entre tema oscuro y claro.", - "advancedLayout": "Diseño avanzado", - "advancedLayoutDescription": "Elige si Secuencia de clics aparece junto a los otros controles avanzados o debajo de Doble clic.", - "advancedLayoutWide": "Ancho", - "advancedLayoutTall": "Alto", - "accentColor": "Color de acento", + "theme": "Tema", + "themeDescription": "Cambia entre tema oscuro y claro.", + "advancedLayout": "Diseño avanzado", + "advancedLayoutDescription": "Elige si Secuencia de clics aparece junto a los otros controles avanzados o debajo de Doble clic.", + "advancedLayoutWide": "Ancho", + "advancedLayoutTall": "Alto", + "accentColor": "Color de acento", "accentColorDescription": "Personaliza el color principal usado en los estados activos.", "sectionPresets": "Preajustes", "sectionPresetsDescription": "Guarda, actualiza, renombra o elimina configuraciones reutilizables.", @@ -115,12 +116,12 @@ "cadenceDescription": "Controla la rapidez con la que se generan los clics: ya sea como clics por intervalo (tasa) o como un retraso fijo entre clics (demora).", "clicksPer": "Clics por", "hotkey": "Tecla rápida", - "hotkeyDescription": "Elige la combinación de teclas que inicia y detiene el clicker. Usa Alternar para pulsar para activar/desactivar, o Mantener para hacer clic solo mientras se mantiene pulsado.", - "mouseButton": "Botón del mouse", - "mouseButtonDescription": "Selecciona qué botón del mouse pulsará el clicker en cada evento de clic.", - "keyboardKey": "Tecla", - "keyboardKeyDescription": "Selecciona qué tecla pulsará el clicker en cada evento de clic.", - "dutyCycle": "Duración del clic", + "hotkeyDescription": "Elige la combinación de teclas que inicia y detiene el clicker. Usa Alternar para pulsar para activar/desactivar, o Mantener para hacer clic solo mientras se mantiene pulsado.", + "mouseButton": "Botón del mouse", + "mouseButtonDescription": "Selecciona qué botón del mouse pulsará el clicker en cada evento de clic.", + "keyboardKey": "Tecla", + "keyboardKeyDescription": "Selecciona qué tecla pulsará el clicker en cada evento de clic.", + "dutyCycle": "Duración del clic", "dutyCycleDescription": "Elige cuánto tiempo se mantiene pulsado el botón del mouse en cada clic. 50% a 1 clic por segundo = 0.5 seg pulsado, 0.5 seg liberado", "speedVariation": "Variación de velocidad", "speedVariationDescription": "Aleatoriza la velocidad de clic por el porcentaje dado.", @@ -168,7 +169,8 @@ "sequenceAddingIn": "Añadiendo en", "sequenceCapturing": "Capturando...", "customStopZoneAddingIn": "Configurando en", - "customStopZoneCapturing": "Configurando..." + "customStopZoneCapturing": "Configurando...", + "perClick": "Por clic" }, "options": { "interval": { "s": "Segundo", "m": "Minuto", "h": "Hora", "d": "Día" }, @@ -176,11 +178,17 @@ "mode": { "Toggle": "Alternar", "Hold": "Mantener" }, "mouseButton": { "Left": "Izquierdo", "Middle": "Central", "Right": "Derecho" }, "mouseClick": { "Left": "Clic izquierdo", "Middle": "Clic central", "Right": "Clic derecho" }, + "inputType": { "mouse": "Ratón", "keyboard": "Teclado" }, + "rateInputMode": { "rate": "Tasa", "duration": "Retraso" }, + "timeUnits": { "h": "h", "m": "min", "s": "s", "ms": "ms" }, "timeUnitShort": { "s": "s", "m": "min", "h": "h" } }, "hotkey": { "pressKeys": "Pulsa teclas...", + "pressKey": "Pulsa una tecla...", "empty": "Haz clic y pulsa teclas", + "selectKey": "Seleccionar tecla", + "rightClickToClear": "Haz clic derecho para limpiar", "key": { "up": "Arriba", "down": "Abajo", "left": "Izquierda", "right": "Derecha", "pageup": "Re Pág", "pagedown": "Av Pág", "backspace": "Retroceso", "delete": "Supr", diff --git a/src/locales/fr.json b/src/locales/fr.json index 7534ccc..20ac8c1 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -5,7 +5,8 @@ "fr": "Français", "ar": "العربية", "de": "Deutsch", - "he": "עברית" + "he": "עברית", + "cn": "简体中文" }, "common": { "on": "Activé", @@ -64,13 +65,13 @@ "runOnStartupDescription": "Lance BlurAutoClicker avec Windows, réduit dans la zone de notification.", "sectionAppearance": "Apparence", "sectionAppearanceDescription": "Préférences de thème et de couleur d'accent.", - "theme": "Thème", - "themeDescription": "Basculer entre les thèmes sombre et clair.", - "advancedLayout": "Disposition avancée", - "advancedLayoutDescription": "Choisissez si Séquence de clics apparaît à côté des autres contrôles avancés ou sous Double clic.", - "advancedLayoutWide": "Large", - "advancedLayoutTall": "Haute", - "accentColor": "Couleur d'accent", + "theme": "Thème", + "themeDescription": "Basculer entre les thèmes sombre et clair.", + "advancedLayout": "Disposition avancée", + "advancedLayoutDescription": "Choisissez si Séquence de clics apparaît à côté des autres contrôles avancés ou sous Double clic.", + "advancedLayoutWide": "Large", + "advancedLayoutTall": "Haute", + "accentColor": "Couleur d'accent", "accentColorDescription": "Personnalise la couleur principale utilisée pour les états actifs.", "sectionPresets": "Préréglages", "sectionPresetsDescription": "Enregistrez, mettez à jour, renommez ou supprimez des configurations réutilisables.", @@ -115,12 +116,12 @@ "cadenceDescription": "Contrôle la rapidité de génération des clics : soit en clics par intervalle (Taux), soit sous forme de délai fixe entre les clics (Délai).", "clicksPer": "Clics par", "hotkey": "Raccourci", - "hotkeyDescription": "Choisissez la combinaison de touches qui démarre et arrête le clicker. Utilisez Alterner pour appuyer pour activer/désactiver, ou Maintenir pour cliquer uniquement lorsqu'il est maintenu.", - "mouseButton": "Bouton de souris", - "mouseButtonDescription": "Sélectionnez le bouton de souris que le clicker pressera à chaque événement de clic.", - "keyboardKey": "Touche clavier", - "keyboardKeyDescription": "Sélectionnez la touche clavier que le clicker pressera à chaque événement de clic.", - "dutyCycle": "Durée du clic", + "hotkeyDescription": "Choisissez la combinaison de touches qui démarre et arrête le clicker. Utilisez Alterner pour appuyer pour activer/désactiver, ou Maintenir pour cliquer uniquement lorsqu'il est maintenu.", + "mouseButton": "Bouton de souris", + "mouseButtonDescription": "Sélectionnez le bouton de souris que le clicker pressera à chaque événement de clic.", + "keyboardKey": "Touche clavier", + "keyboardKeyDescription": "Sélectionnez la touche clavier que le clicker pressera à chaque événement de clic.", + "dutyCycle": "Durée du clic", "dutyCycleDescription": "Choisissez la durée pendant laquelle le bouton de souris reste enfoncé à chaque clic. 50 % à 1 clic par seconde = 0,5 s enfoncé, 0,5 s relâché", "speedVariation": "Variation de vitesse", "speedVariationDescription": "Randomise la vitesse de clic selon le pourcentage donné.", @@ -168,7 +169,8 @@ "sequenceAddingIn": "Ajout dans", "sequenceCapturing": "Capture...", "customStopZoneAddingIn": "Définition dans", - "customStopZoneCapturing": "Définition..." + "customStopZoneCapturing": "Définition...", + "perClick": "Par clic" }, "options": { "interval": { "s": "Seconde", "m": "Minute", "h": "Heure", "d": "Jour" }, @@ -176,11 +178,17 @@ "mode": { "Toggle": "Alterner", "Hold": "Maintenir" }, "mouseButton": { "Left": "Gauche", "Middle": "Milieu", "Right": "Droit" }, "mouseClick": { "Left": "Clic gauche", "Middle": "Clic milieu", "Right": "Clic droit" }, + "inputType": { "mouse": "Souris", "keyboard": "Clavier" }, + "rateInputMode": { "rate": "Taux", "duration": "Délai" }, + "timeUnits": { "h": "h", "m": "min", "s": "s", "ms": "ms" }, "timeUnitShort": { "s": "s", "m": "min", "h": "h" } }, "hotkey": { "pressKeys": "Appuyez sur des touches...", + "pressKey": "Appuyez sur une touche...", "empty": "Cliquez et appuyez sur des touches", + "selectKey": "Sélectionner une touche", + "rightClickToClear": "Cliquez droit pour effacer", "key": { "up": "Haut", "down": "Bas", "left": "Gauche", "right": "Droite", "pageup": "Page préc.", "pagedown": "Page suiv.", "backspace": "Retour arrière", diff --git a/src/locales/he.json b/src/locales/he.json index d25928c..21a0d53 100644 --- a/src/locales/he.json +++ b/src/locales/he.json @@ -5,7 +5,8 @@ "fr": "Français", "ar": "العربية", "de": "Deutsch", - "he": "עברית" + "he": "עברית", + "cn": "简体中文" }, "common": { "on": "פועל", @@ -168,7 +169,8 @@ "sequenceAddingIn": "מוסיף בעוד", "sequenceCapturing": "לוכד...", "customStopZoneAddingIn": "מגדיר בעוד", - "customStopZoneCapturing": "מגדיר..." + "customStopZoneCapturing": "מגדיר...", + "perClick": "לכל לחיצה" }, "options": { "interval": { @@ -197,6 +199,20 @@ "Middle": "לחיצה אמצעית", "Right": "לחיצה ימנית" }, + "inputType": { + "mouse": "עכבר", + "keyboard": "מקלדת" + }, + "rateInputMode": { + "rate": "קצב", + "duration": "השהיה" + }, + "timeUnits": { + "h": "שע׳", + "m": "דק׳", + "s": "שנ׳", + "ms": "מ״ש" + }, "timeUnitShort": { "s": "שנ׳", "m": "דק׳", @@ -205,7 +221,10 @@ }, "hotkey": { "pressKeys": "לחץ על מקשים...", + "pressKey": "לחץ על מקש...", "empty": "לחץ כאן ואז הקש מקשים", + "selectKey": "בחר מקש", + "rightClickToClear": "לחץ עם כפתור ימני כדי למחוק", "key": { "up": "חץ למעלה", "down": "חץ למטה",