diff --git a/electron/i18n.ts b/electron/i18n.ts index 4222741..7856357 100644 --- a/electron/i18n.ts +++ b/electron/i18n.ts @@ -1,6 +1,8 @@ // Lightweight i18n for the Electron main process. // Imports the same JSON translation files used by the renderer. +import commonAr from "../src/i18n/locales/ar/common.json"; +import dialogsAr from "../src/i18n/locales/ar/dialogs.json"; import commonEn from "../src/i18n/locales/en/common.json"; import dialogsEn from "../src/i18n/locales/en/dialogs.json"; import commonEs from "../src/i18n/locales/es/common.json"; @@ -18,7 +20,7 @@ import dialogsZh from "../src/i18n/locales/zh-CN/dialogs.json"; import commonZhTw from "../src/i18n/locales/zh-TW/common.json"; import dialogsZhTw from "../src/i18n/locales/zh-TW/dialogs.json"; -type Locale = "en" | "zh-CN" | "zh-TW" | "es" | "fr" | "ja-JP" | "ko-KR" | "tr"; +type Locale = "en" | "zh-CN" | "zh-TW" | "es" | "fr" | "ja-JP" | "ko-KR" | "tr" | "ar"; type Namespace = "common" | "dialogs"; type MessageMap = Record; @@ -31,6 +33,7 @@ const messages: Record> = { "ja-JP": { common: commonJa, dialogs: dialogsJa }, "ko-KR": { common: commonKo, dialogs: dialogsKo }, tr: { common: commonTr, dialogs: dialogsTr }, + ar: { common: commonAr, dialogs: dialogsAr }, }; let currentLocale: Locale = "en"; @@ -44,7 +47,8 @@ export function setMainLocale(locale: string) { locale === "fr" || locale === "ja-JP" || locale === "ko-KR" || - locale === "tr" + locale === "tr" || + locale === "ar" ) { currentLocale = locale; } diff --git a/electron/main.ts b/electron/main.ts index 0b90b89..c2bee86 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -136,15 +136,30 @@ function setupApplicationMenu() { template.push({ label: app.name, submenu: [ - { role: "about" }, + { + role: "about", + label: mainT("common", "actions.about") || "About OpenScreen", + }, { type: "separator" }, - { role: "services" }, + { + role: "services", + label: mainT("common", "actions.services") || "Services", + }, { type: "separator" }, - { role: "hide" }, - { role: "hideOthers" }, - { role: "unhide" }, + { + role: "hide", + label: mainT("common", "actions.hide") || "Hide OpenScreen", + }, + { + role: "hideOthers", + label: mainT("common", "actions.hideOthers") || "Hide Others", + }, + { + role: "unhide", + label: mainT("common", "actions.unhide") || "Show All", + }, { type: "separator" }, - { role: "quit" }, + { role: "quit", label: mainT("common", "actions.quit") || "Quit" }, ], }); } @@ -168,40 +183,89 @@ function setupApplicationMenu() { accelerator: "CmdOrCtrl+Shift+S", click: () => sendEditorMenuAction("menu-save-project-as"), }, - ...(isMac ? [] : [{ type: "separator" as const }, { role: "quit" as const }]), + ...(isMac + ? [] + : [ + { type: "separator" as const }, + { + role: "quit" as const, + label: mainT("common", "actions.quit") || "Quit", + }, + ]), ], }, { label: mainT("common", "actions.edit") || "Edit", submenu: [ - { role: "undo" }, - { role: "redo" }, + { role: "undo", label: mainT("common", "actions.undo") || "Undo" }, + { role: "redo", label: mainT("common", "actions.redo") || "Redo" }, { type: "separator" }, - { role: "cut" }, - { role: "copy" }, - { role: "paste" }, - { role: "selectAll" }, + { role: "cut", label: mainT("common", "actions.cut") || "Cut" }, + { role: "copy", label: mainT("common", "actions.copy") || "Copy" }, + { role: "paste", label: mainT("common", "actions.paste") || "Paste" }, + { + role: "selectAll", + label: mainT("common", "actions.selectAll") || "Select All", + }, ], }, { label: mainT("common", "actions.view") || "View", submenu: [ - { role: "reload" }, - { role: "forceReload" }, - { role: "toggleDevTools" }, + { + role: "reload", + label: mainT("common", "actions.reload") || "Reload", + }, + { + role: "forceReload", + label: mainT("common", "actions.forceReload") || "Force Reload", + }, + { + role: "toggleDevTools", + label: mainT("common", "actions.toggleDevTools") || "Toggle Developer Tools", + }, { type: "separator" }, - { role: "resetZoom" }, - { role: "zoomIn" }, - { role: "zoomOut" }, + { + role: "resetZoom", + label: mainT("common", "actions.actualSize") || "Actual Size", + }, + { + role: "zoomIn", + label: mainT("common", "actions.zoomIn") || "Zoom In", + }, + { + role: "zoomOut", + label: mainT("common", "actions.zoomOut") || "Zoom Out", + }, { type: "separator" }, - { role: "togglefullscreen" }, + { + role: "togglefullscreen", + label: mainT("common", "actions.toggleFullScreen") || "Toggle Full Screen", + }, ], }, { label: mainT("common", "actions.window") || "Window", submenu: isMac - ? [{ role: "minimize" }, { role: "zoom" }, { type: "separator" }, { role: "front" }] - : [{ role: "minimize" }, { role: "close" }], + ? [ + { + role: "minimize", + label: mainT("common", "actions.minimize") || "Minimize", + }, + { role: "zoom" }, + { type: "separator" }, + { role: "front" }, + ] + : [ + { + role: "minimize", + label: mainT("common", "actions.minimize") || "Minimize", + }, + { + role: "close", + label: mainT("common", "actions.close") || "Close", + }, + ], }, ); @@ -232,7 +296,11 @@ function getTrayIcon(filename: string, size: number) { function updateTrayMenu(recording: boolean = false) { if (!tray) return; const trayIcon = recording ? recordingTrayIcon : defaultTrayIcon; - const trayToolTip = recording ? `Recording: ${selectedSourceName}` : "OpenScreen"; + const trayToolTip = recording + ? mainT("common", "actions.recordingStatus", { + source: selectedSourceName, + }) || `Recording: ${selectedSourceName}` + : "OpenScreen"; const menuTemplate = recording ? [ { diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index 1ffa0f4..76ff762 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -1045,7 +1045,9 @@ export function SettingsPanel({ {cursorHighlight && onCursorHighlightChange && (
-
Cursor highlight
+
+ {t("effects.cursorHighlight.title")} +
- {style} + {t(`effects.cursorHighlight.${style}`)} ))}
-
Size
+
+ {t("effects.cursorHighlight.size")} +
{cursorHighlight.sizePx}px @@ -1091,7 +1095,10 @@ export function SettingsPanel({ - onCursorHighlightChange({ ...cursorHighlight, sizePx: values[0] }) + onCursorHighlightChange({ + ...cursorHighlight, + sizePx: values[0], + }) } min={10} max={36} @@ -1103,19 +1110,27 @@ export function SettingsPanel({
-
Only on clicks
+
+ {t("effects.cursorHighlight.onlyOnClicks")} +
)}
-
Color
+
+ {t("effects.cursorHighlight.color")} +
-
Offset X (window recordings)
+
+ {t("effects.cursorHighlight.offsetX")} +
{(cursorHighlight.offsetXNorm * 100).toFixed(1)}% @@ -1195,7 +1217,9 @@ export function SettingsPanel({
-
Offset Y
+
+ {t("effects.cursorHighlight.offsetY")} +
{(cursorHighlight.offsetYNorm * 100).toFixed(1)}% diff --git a/src/i18n/config.ts b/src/i18n/config.ts index 788a315..cf0b34c 100644 --- a/src/i18n/config.ts +++ b/src/i18n/config.ts @@ -8,6 +8,7 @@ export const SUPPORTED_LOCALES = [ "tr", "ko-KR", "ja-JP", + "ar", ] as const; export const I18N_NAMESPACES = [ "common", diff --git a/src/i18n/locales/ar/common.json b/src/i18n/locales/ar/common.json new file mode 100644 index 0000000..3591a29 --- /dev/null +++ b/src/i18n/locales/ar/common.json @@ -0,0 +1,50 @@ +{ + "actions": { + "cancel": "الغاء", + "save": "حفظ", + "delete": "حذف", + "close": "اغلاق", + "share": "مشاركة", + "done": "تم", + "open": "فتح", + "upload": "رفع", + "export": "تصدير", + "showInFolder": "عرض في المجلد", + "file": "ملف", + "edit": "تعديل", + "view": "عرض", + "window": "نافذة", + "quit": "خروج", + "stopRecording": "إيقاف التسجيل", + "undo": "تراجع", + "redo": "إعادة", + "cut": "قص", + "copy": "نسخ", + "paste": "لصق", + "selectAll": "تحديد الكل", + "minimize": "تصغير", + "reload": "إعادة تحميل", + "forceReload": "إعادة تحميل إجبارية", + "toggleDevTools": "أدوات المطور", + "actualSize": "الحجم الفعلي", + "zoomIn": "تكبير", + "zoomOut": "تصغير", + "toggleFullScreen": "ملء الشاشة", + "recordingStatus": "جاري التسجيل: {{source}}", + "about": "حول OpenScreen", + "services": "خدمات", + "hide": "إخفاء OpenScreen", + "hideOthers": "إخفاء الآخرين", + "unhide": "إظهار الكل" + }, + "playback": { + "play": "تشغيل", + "pause": "ايقاف مؤقت", + "fullscreen": "ملء الشاشة", + "exitFullscreen": "خروج من ملء الشاشة" + }, + "locale": { + "name": "عربي", + "short": "AR" + } +} diff --git a/src/i18n/locales/ar/dialogs.json b/src/i18n/locales/ar/dialogs.json new file mode 100644 index 0000000..2263f60 --- /dev/null +++ b/src/i18n/locales/ar/dialogs.json @@ -0,0 +1,70 @@ +{ + "export": { + "complete": "اكتمل التصدير", + "yourFormatReady": "{{format}} الخاص بك جاهز", + "showInFolder": "عرض في المجلد", + "finalizingVideo": "جاري إنهاء تصدير الفيديو...", + "compilingGifProgress": "جاري تجميع GIF... {{progress}}%", + "compilingGifWait": "جاري تجميع GIF... قد يستغرق هذا بعض الوقت", + "takeMoment": "قد يستغرق هذا لحظة...", + "failed": "فشل التصدير", + "tryAgain": "يرجى المحاولة مرة أخرى", + "finalizingVideoTitle": "إنهاء الفيديو", + "compilingGif": "تجميع GIF", + "exportingFormat": "تصدير {{format}}", + "compiling": "تجميع", + "renderingFrames": "تصيير الإطارات", + "processing": "جاري المعالجة...", + "finalizing": "جاري الإنهاء...", + "compilingStatus": "جاري التجميع...", + "status": "الحالة", + "format": "الصيغة", + "frames": "الإطارات", + "cancelExport": "إلغاء التصدير", + "savedSuccessfully": "تم حفظ {{format}} بنجاح!" + }, + "tutorial": { + "triggerLabel": "كيف يعمل القص", + "title": "كيف يعمل القص", + "description": "فهم كيفية قص الأجزاء غير المرغوب فيها من الفيديو الخاص بك.", + "explanationBefore": "تعمل أداة القص من خلال تحديد المقاطع التي تريد", + "remove": "إزالتها", + "explanationMiddle": " — أي شيء", + "covered": "مغطى", + "explanationAfter": "بمقطع قص أحمر سيتم قصه عند التصدير.", + "visualExample": "مثال مرئي", + "removed": "مُزال", + "kept": "مُحتفظ به", + "part1": "الجزء 1", + "part2": "الجزء 2", + "part3": "الجزء 3", + "finalVideo": "الفيديو النهائي", + "step1Title": "1. إضافة قص", + "step1DescriptionBefore": "اضغط على ", + "step1DescriptionAfter": " أو انقر على أيقونة المقص لتحديد قسم لإزالته.", + "step2Title": "2. تعديل", + "step2Description": "اسحب حواف المنطقة الحمراء لتغطي بالضبط ما تريد قصه." + }, + "unsavedChanges": { + "title": "تغييرات غير محفوظة", + "message": "لديك تغييرات غير محفوظة.", + "detail": "هل تريد حفظ مشروعك قبل الإغلاق؟", + "saveAndClose": "حفظ وإغلاق", + "discardAndClose": "تجاهل وإغلاق", + "loadProject": "تحميل مشروع...", + "saveProject": "حفظ المشروع...", + "saveProjectAs": "حفظ المشروع باسم..." + }, + "fileDialogs": { + "saveGif": "حفظ GIF المصدر", + "saveVideo": "حفظ الفيديو المصدر", + "selectVideo": "حدد ملف فيديو", + "saveProject": "حفظ مشروع OpenScreen", + "openProject": "فتح مشروع OpenScreen", + "gifImage": "صورة GIF", + "mp4Video": "فيديو MP4", + "videoFiles": "ملفات فيديو", + "openscreenProject": "مشروع OpenScreen", + "allFiles": "جميع الملفات" + } +} diff --git a/src/i18n/locales/ar/editor.json b/src/i18n/locales/ar/editor.json new file mode 100644 index 0000000..a246f01 --- /dev/null +++ b/src/i18n/locales/ar/editor.json @@ -0,0 +1,45 @@ +{ + "newRecording": { + "title": "العودة إلى المسجل", + "description": "تم حفظ جلستك الحالية.", + "cancel": "إلغاء", + "confirm": "تأكيد" + }, + "loadingVideo": "جاري تحميل الفيديو...", + "errors": { + "noVideoLoaded": "لم يتم تحميل أي فيديو", + "videoNotReady": "الفيديو غير جاهز", + "unableToDetermineSourcePath": "تعذر تحديد مسار الفيديو المصدر", + "failedToSaveGif": "فشل حفظ GIF", + "gifExportFailed": "فشل تصدير GIF", + "failedToSaveVideo": "فشل حفظ الفيديو", + "exportFailed": "فشل التصدير", + "exportFailedWithError": "فشل التصدير: {{error}}", + "exportBackgroundLoadFailed": "فشل التصدير: تعذر تحميل صورة الخلفية ({{url}})", + "failedToSaveExport": "فشل حفظ التصدير", + "failedToSaveExportedVideo": "فشل حفظ الفيديو المُصدَّر", + "failedToRevealInFolder": "خطأ في الكشف في المجلد: {{error}}" + }, + "export": { + "canceled": "تم إلغاء التصدير", + "exportedSuccessfully": "تم تصدير {{format}} بنجاح" + }, + "project": { + "saveCanceled": "تم إلغاء حفظ المشروع", + "failedToSave": "فشل حفظ المشروع", + "savedTo": "تم حفظ المشروع في {{path}}", + "failedToLoad": "فشل تحميل المشروع", + "invalidFormat": "تنسيق ملف المشروع غير صالح", + "loadedFrom": "تم تحميل المشروع من {{path}}" + }, + "recording": { + "failedCameraAccess": "فشل طلب الوصول إلى الكاميرا.", + "cameraBlocked": "الوصول إلى الكاميرا محظور. قم بتمكينه في إعدادات النظام لاستخدام كاميرا الويب.", + "systemAudioUnavailable": "صوت النظام غير متوفر. يتم التسجيل بدون صوت النظام.", + "microphoneDenied": "تم رفض الوصول إلى الميكروفون. سيستمر التسجيل بدون صوت.", + "cameraDenied": "تم رفض الوصول إلى الكاميرا. سيستمر التسجيل بدون كاميرا الويب.", + "cameraDisconnected": "تم فصل كاميرا الويب.", + "cameraNotFound": "لم يتم العثور على كاميرا.", + "permissionDenied": "تم رفض إذن التسجيل. يرجى السماح بتسجيل الشاشة." + } +} diff --git a/src/i18n/locales/ar/launch.json b/src/i18n/locales/ar/launch.json new file mode 100644 index 0000000..19da8fb --- /dev/null +++ b/src/i18n/locales/ar/launch.json @@ -0,0 +1,43 @@ +{ + "tooltips": { + "hideHUD": "إخفاء واجهة العرض", + "closeApp": "إغلاق التطبيق", + "restartRecording": "إعادة تشغيل التسجيل", + "cancelRecording": "إلغاء التسجيل", + "pauseRecording": "إيقاف التسجيل مؤقتاً", + "resumeRecording": "استئناف التسجيل", + "openVideoFile": "فتح ملف فيديو", + "openProject": "فتح مشروع" + }, + "audio": { + "enableSystemAudio": "تفعيل صوت النظام", + "disableSystemAudio": "تعطيل صوت النظام", + "enableMicrophone": "تفعيل الميكروفون", + "disableMicrophone": "تعطيل الميكروفون", + "defaultMicrophone": "الميكروفون الافتراضي" + }, + "webcam": { + "enableWebcam": "تفعيل كاميرا الويب", + "disableWebcam": "تعطيل كاميرا الويب", + "defaultCamera": "الكاميرا الافتراضية", + "searching": "جاري البحث...", + "noneFound": "لم يتم العثور على كاميرا", + "unavailable": "الكاميرا غير متوفرة" + }, + "sourceSelector": { + "loading": "جاري تحميل المصادر...", + "screens": "الشاشات ({{count}})", + "windows": "النوافذ ({{count}})", + "defaultSourceName": "الشاشة" + }, + "recording": { + "selectSource": "يرجى تحديد مصدر للتسجيل" + }, + "language": "اللغة", + "systemLanguagePrompt": { + "title": "هل تريد استخدام لغة نظامك؟", + "description": "اكتشفنا أن {{language}} هي لغة نظامك. هل تريد تبديل OpenScreen إلى {{language}}؟", + "switch": "التبديل إلى {{language}}", + "keepDefault": "الاحتفاظ باللغة الحالية" + } +} diff --git a/src/i18n/locales/ar/settings.json b/src/i18n/locales/ar/settings.json new file mode 100644 index 0000000..2d250b1 --- /dev/null +++ b/src/i18n/locales/ar/settings.json @@ -0,0 +1,194 @@ +{ + "zoom": { + "level": "مستوى التكبير", + "selectRegion": "حدد منطقة التكبير للتعديل", + "deleteZoom": "حذف التكبير", + "focusMode": { + "title": "وضع التركيز", + "manual": "يدوي", + "auto": "تلقائي", + "autoDescription": "الكاميرا تتبع موضع المؤشر المسجل" + } + }, + "speed": { + "playbackSpeed": "سرعة التشغيل", + "selectRegion": "حدد منطقة السرعة للتعديل", + "deleteRegion": "حذف منطقة السرعة", + "customPlaybackSpeed": "سرعة تشغيل مخصصة", + "maxSpeedError": "لا يمكن للسرعة أن تتجاوز 16×" + }, + "trim": { + "deleteRegion": "حذف منطقة القص" + }, + "layout": { + "title": "التخطيط", + "preset": "الإعداد المسبق", + "selectPreset": "حدد إعدادًا مسبقًا", + "pictureInPicture": "صورة داخل صورة", + "verticalStack": "تكدس عمودي", + "dualFrame": "إطار مزدوج", + "webcamShape": "شكل الكاميرا", + "webcamSize": "حجم كاميرا الويب" + }, + "effects": { + "title": "تأثيرات الفيديو", + "blurBg": "تمويه الخلفية", + "motionBlur": "ضبابية الحركة", + "off": "إيقاف", + "on": "تشغيل", + "shadow": "ظل", + "roundness": "الاستدارة", + "padding": "المسافة البادئة", + "cursorHighlight": { + "title": "تمييز المؤشر", + "style": "النمط", + "dot": "نقطة", + "ring": "حلقة", + "size": "الحجم", + "onlyOnClicks": "عند النقر فقط", + "color": "اللون", + "offsetX": "إزاحة X (لتسجيلات النوافذ)", + "offsetY": "إزاحة Y", + "accessibilityPermissionTitle": "مطلوب إذن الوصول", + "accessibilityPermissionDescription": "افتح إعدادات النظام ← الخصوصية والأمان ← إمكانية الوصول، وقم بتفعيل Openscreen، ثم أعد تشغيل التطبيق." + } + }, + "background": { + "title": "الخلفية", + "image": "صورة", + "color": "لون", + "gradient": "تدرج لوني", + "uploadCustom": "رفع صورة مخصصة", + "gradientLabel": "تدرج لوني {{index}}", + "colorWheel": "عجلة الألوان", + "colorPalette": "لوحة الألوان" + }, + "crop": { + "title": "اقتصاص", + "cropVideo": "اقتصاص الفيديو", + "dragInstruction": "اسحب من كل جانب لضبط منطقة الاقتصاص", + "ratio": "النسبة", + "free": "حر", + "done": "تم", + "lockAspectRatio": "قفل نسبة العرض إلى الارتفاع", + "unlockAspectRatio": "إلغاء قفل نسبة العرض إلى الارتفاع" + }, + "exportFormat": { + "mp4": "MP4", + "gif": "GIF", + "mp4Video": "فيديو MP4", + "mp4Description": "ملف فيديو عالي الجودة", + "gifAnimation": "صورة GIF متحركة", + "gifDescription": "صورة متحركة للمشاركة" + }, + "exportQuality": { + "title": "جودة التصدير", + "low": "منخفضة", + "medium": "متوسطة", + "high": "عالية" + }, + "gifSettings": { + "frameRate": "معدل إطارات GIF", + "size": "حجم GIF", + "loop": "تكرار GIF" + }, + "project": { + "save": "حفظ المشروع", + "load": "تحميل المشروع" + }, + "export": { + "videoButton": "تصدير الفيديو", + "gifButton": "تصدير GIF", + "chooseSaveLocation": "اختيار موقع الحفظ" + }, + "links": { + "reportBug": "الإبلاغ عن خطأ", + "starOnGithub": "إعطاء نجمة على GitHub" + }, + "imageUpload": { + "invalidFileType": "نوع ملف غير صالح", + "jpgOnly": "يرجى رفع ملف صورة JPG أو JPEG.", + "uploadSuccess": "تم رفع الصورة المخصصة بنجاح!", + "failedToUpload": "فشل رفع الصورة", + "errorReading": "حدث خطأ أثناء قراءة الملف." + }, + "annotation": { + "title": "إعدادات الشروح", + "active": "نشط", + "typeText": "نص", + "typeImage": "صورة", + "typeArrow": "سهم", + "typeBlur": "تمويه", + "textContent": "محتوى النص", + "textPlaceholder": "أدخل النص هنا...", + "fontStyle": "نمط الخط", + "selectStyle": "حدد النمط", + "size": "الحجم", + "customFonts": "خطوط مخصصة", + "textColor": "لون النص", + "background": "الخلفية", + "none": "بدون", + "color": "لون", + "colorWheel": "عجلة الألوان", + "colorPalette": "لوحة الألوان", + "clearBackground": "مسح الخلفية", + "uploadImage": "رفع صورة", + "supportedFormats": "الصيغ المدعومة: JPG, PNG, GIF, WebP", + "arrowDirection": "اتجاه السهم", + "strokeWidth": "عرض الخط: {{width}}px", + "arrowColor": "لون السهم", + "blurType": "نوع التمويه", + "blurTypeBlur": "تمويه", + "blurTypeMosaic": "فسيفساء", + "blurColor": "لون التمويه", + "blurColorWhite": "أبيض", + "blurColorBlack": "أسود", + "blurShape": "شكل التمويه", + "blurIntensity": "كثافة التمويه", + "mosaicBlockSize": "حجم كتلة الفسيفساء", + "blurShapeRectangle": "مستطيل", + "blurShapeOval": "بيضاوي", + "blurShapeFreehand": "رسم حر", + "deleteAnnotation": "حذف الشرح", + "shortcutsAndTips": "اختصارات ونصائح", + "tipMovePlayhead": "انقل رأس التشغيل إلى قسم الشروح المتداخلة وحدد عنصرًا.", + "tipTabCycle": "استخدم Tab للتنقل بين العناصر المتداخلة.", + "tipShiftTabCycle": "استخدم Shift+Tab للتنقل للخلف.", + "invalidImageType": "نوع ملف غير صالح", + "imageFormatsOnly": "يرجى رفع ملف صورة JPG أو PNG أو GIF أو WebP.", + "imageUploadSuccess": "تم رفع الصورة بنجاح!", + "failedImageUpload": "فشل في رفع الصورة" + }, + "fontStyles": { + "classic": "كلاسيكي", + "editor": "محرر", + "strong": "قوي", + "typewriter": "آلة كاتبة", + "deco": "ديكو", + "simple": "بسيط", + "modern": "حديث", + "clean": "نظيف" + }, + "customFont": { + "dialogTitle": "إضافة خط Google", + "urlLabel": "رابط استيراد خطوط Google", + "urlPlaceholder": "https://fonts.googleapis.com/css2?family=Roboto&display=swap", + "urlHelp": "احصل على هذا من خطوط Google: حدد خطًا → انقر على \"احصل على الخط\" → انسخ رابط `@import`", + "nameLabel": "اسم العرض", + "namePlaceholder": "خطي المخصص", + "nameHelp": "هكذا سيظهر الخط في محدد الخطوط", + "addButton": "إضافة خط", + "addingButton": "جاري الإضافة...", + "errorEmptyUrl": "يرجى إدخال رابط استيراد لخطوط Google", + "errorInvalidUrl": "يرجى إدخال رابط صحيح لخطوط Google", + "errorEmptyName": "يرجى إدخال اسم الخط", + "errorExtractFailed": "تعذر استخراج عائلة الخط من الرابط", + "successMessage": "تم إضافة الخط \"{{fontName}}\" بنجاح", + "failedToAdd": "فشل في إضافة الخط", + "errorTimeout": "استغرق تحميل الخط وقتًا طويلاً. يرجى التحقق من الرابط والمحاولة مرة أخرى.", + "errorLoadFailed": "تعذر تحميل الخط. يرجى التحقق من صحة رابط خطوط Google." + }, + "language": { + "title": "اللغة" + } +} diff --git a/src/i18n/locales/ar/shortcuts.json b/src/i18n/locales/ar/shortcuts.json new file mode 100644 index 0000000..a560c06 --- /dev/null +++ b/src/i18n/locales/ar/shortcuts.json @@ -0,0 +1,37 @@ +{ + "title": "اختصارات لوحة المفاتيح", + "customize": "تخصيص", + "configurable": "قابل للتكوين", + "fixed": "ثابت", + "pressKey": "اضغط على مفتاح...", + "clickToChange": "انقر للتغيير", + "pressEscToCancel": "اضغط على Esc للإلغاء", + "helpText": "انقر على اختصار ثم اضغط على مجموعة المفاتيح الجديدة. اضغط على Esc للإلغاء.", + "resetToDefaults": "إعادة تعيين إلى الافتراضيات", + "alreadyUsedBy": "مستخدم بالفعل بواسطة {{action}}", + "swap": "تبديل", + "reservedShortcut": "هذا الاختصار محجوز لـ \"{{label}}\" ولا يمكن إعادة تعيينه.", + "savedToast": "تم حفظ اختصارات لوحة المفاتيح", + "resetToast": "إعادة تعيين إلى الاختصارات الافتراضية — انقر فوق حفظ للتطبيق", + "actions": { + "addZoom": "إضافة تكبير", + "addTrim": "إضافة قص", + "addSpeed": "إضافة سرعة", + "addAnnotation": "إضافة شرح", + "addBlur": "إضافة تمويه", + "addKeyframe": "إضافة إطار رئيسي", + "deleteSelected": "حذف المحدد", + "playPause": "تشغيل / إيقاف مؤقت" + }, + "fixedActions": { + "undo": "تراجع", + "redo": "إعادة", + "cycleAnnotationsForward": "التنقل بين الشروح للأمام", + "cycleAnnotationsBackward": "التنقل بين الشروح للخلف", + "deleteSelectedAlt": "حذف المحدد (alt)", + "panTimeline": "تحريك المخطط الزمني", + "zoomTimeline": "تكبير المخطط الزمني", + "frameBack": "إطار للخلف", + "frameForward": "إطار للأمام" + } +} diff --git a/src/i18n/locales/ar/timeline.json b/src/i18n/locales/ar/timeline.json new file mode 100644 index 0000000..09d55c4 --- /dev/null +++ b/src/i18n/locales/ar/timeline.json @@ -0,0 +1,55 @@ +{ + "buttons": { + "addZoom": "إضافة تكبير (Z)", + "suggestZooms": "اقتراح تكبير من المؤشر", + "addTrim": "إضافة قص (T)", + "addAnnotation": "إضافة شرح (A)", + "addBlur": "إضافة تمويه (B)", + "addSpeed": "إضافة سرعة (S)" + }, + "hints": { + "pressZoom": "اضغط Z لإضافة تكبير", + "pressTrim": "اضغط T لإضافة قص", + "pressAnnotation": "اضغط A لإضافة شرح", + "pressBlur": "اضغط B لإضافة منطقة تمويه", + "pressSpeed": "اضغط S لإضافة سرعة" + }, + "labels": { + "pan": "تحريك", + "zoom": "تكبير", + "trim": "قص", + "speed": "سرعة", + "zoomItem": "تكبير {{index}}", + "trimItem": "قص {{index}}", + "speedItem": "سرعة {{index}}", + "annotationItem": "شرح", + "blurItem": "تمويه {{index}}", + "imageItem": "صورة", + "emptyText": "نص فارغ" + }, + "emptyState": { + "noVideo": "لم يتم تحميل أي فيديو", + "dragAndDrop": "اسحب وأفلت مقطع فيديو لبدء التعديل" + }, + "errors": { + "cannotPlaceZoom": "لا يمكن وضع التكبير هنا", + "zoomExistsAtLocation": "يوجد تكبير بالفعل في هذا الموقع أو لا توجد مساحة كافية متاحة.", + "zoomSuggestionUnavailable": "معالج اقتراح التكبير غير متوفر", + "noCursorTelemetry": "لا تتوفر بيانات قياس المؤشر", + "noCursorTelemetryDescription": "قم بتسجيل الشاشة أولاً لإنشاء اقتراحات بناءً على المؤشر.", + "noUsableTelemetry": "لا توجد بيانات قياس مؤشر قابلة للاستخدام", + "noUsableTelemetryDescription": "التسجيل لا يتضمن بيانات حركة مؤشر كافية.", + "noDwellMoments": "لم يتم العثور على لحظات توقف واضحة للمؤشر", + "noDwellMomentsDescription": "جرب تسجيلاً مع توقفات مؤشر أبطأ عند الإجراءات المهمة.", + "noAutoZoomSlots": "لا تتوفر خانات تكبير تلقائي", + "noAutoZoomSlotsDescription": "نقاط التوقف المكتشفة تتداخل مع مناطق التكبير الحالية.", + "cannotPlaceTrim": "لا يمكن وضع القص هنا", + "trimExistsAtLocation": "يوجد قص بالفعل في هذا الموقع أو لا توجد مساحة كافية متاحة.", + "cannotPlaceSpeed": "لا يمكن وضع السرعة هنا", + "speedExistsAtLocation": "توجد منطقة سرعة بالفعل في هذا الموقع أو لا توجد مساحة كافية متاحة." + }, + "success": { + "addedZoomSuggestions": "تمت إضافة {{count}} اقتراح تكبير بناءً على المؤشر", + "addedZoomSuggestionsPlural": "تمت إضافة {{count}} اقتراحات تكبير بناءً على المؤشر" + } +} diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index cdefe84..f60a402 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -15,7 +15,27 @@ "view": "View", "window": "Window", "quit": "Quit", - "stopRecording": "Stop Recording" + "stopRecording": "Stop Recording", + "undo": "Undo", + "redo": "Redo", + "cut": "Cut", + "copy": "Copy", + "paste": "Paste", + "selectAll": "Select All", + "minimize": "Minimize", + "reload": "Reload", + "forceReload": "Force Reload", + "toggleDevTools": "Toggle Developer Tools", + "actualSize": "Actual Size", + "zoomIn": "Zoom In", + "zoomOut": "Zoom Out", + "toggleFullScreen": "Toggle Full Screen", + "recordingStatus": "Recording: {{source}}", + "about": "About OpenScreen", + "services": "Services", + "hide": "Hide OpenScreen", + "hideOthers": "Hide Others", + "unhide": "Show All" }, "playback": { "play": "Play", diff --git a/src/i18n/locales/en/settings.json b/src/i18n/locales/en/settings.json index d926709..557fb14 100644 --- a/src/i18n/locales/en/settings.json +++ b/src/i18n/locales/en/settings.json @@ -43,9 +43,23 @@ "blurBg": "Blur BG", "motionBlur": "Motion Blur", "off": "off", + "on": "on", "shadow": "Shadow", "roundness": "Roundness", - "padding": "Padding" + "padding": "Padding", + "cursorHighlight": { + "title": "Cursor highlight", + "style": "Style", + "dot": "Dot", + "ring": "Ring", + "size": "Size", + "onlyOnClicks": "Only on clicks", + "color": "Color", + "offsetX": "Offset X (window recordings)", + "offsetY": "Offset Y", + "accessibilityPermissionTitle": "Accessibility permission needed", + "accessibilityPermissionDescription": "Open System Settings → Privacy & Security → Accessibility, enable Openscreen, then restart the app." + } }, "background": { "title": "Background",