Merge pull request #529 from i1Zeus/arabic-support
feat: add Arabic localization support for editor, launch, settings, s…
This commit is contained in:
+6
-2
@@ -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<string, unknown>;
|
||||
|
||||
@@ -31,6 +33,7 @@ const messages: Record<Locale, Record<Namespace, MessageMap>> = {
|
||||
"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;
|
||||
}
|
||||
|
||||
+91
-23
@@ -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
|
||||
? [
|
||||
{
|
||||
|
||||
@@ -1045,7 +1045,9 @@ export function SettingsPanel({
|
||||
{cursorHighlight && onCursorHighlightChange && (
|
||||
<div className="p-2 rounded-lg bg-white/5 border border-white/5 mt-2 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-[10px] font-medium text-slate-300">Cursor highlight</div>
|
||||
<div className="text-[10px] font-medium text-slate-300">
|
||||
{t("effects.cursorHighlight.title")}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
@@ -1060,7 +1062,7 @@ export function SettingsPanel({
|
||||
: "bg-white/5 border-white/10 text-slate-400"
|
||||
}`}
|
||||
>
|
||||
{cursorHighlight.enabled ? "On" : "Off"}
|
||||
{cursorHighlight.enabled ? t("effects.on") : t("effects.off")}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
@@ -1077,13 +1079,15 @@ export function SettingsPanel({
|
||||
: "bg-white/5 border-white/10 text-slate-300 hover:border-white/20"
|
||||
}`}
|
||||
>
|
||||
{style}
|
||||
{t(`effects.cursorHighlight.${style}`)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className={cursorHighlight.enabled ? "" : "opacity-40 pointer-events-none"}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="text-[10px] text-slate-400">Size</div>
|
||||
<div className="text-[10px] text-slate-400">
|
||||
{t("effects.cursorHighlight.size")}
|
||||
</div>
|
||||
<span className="text-[10px] text-slate-500 font-mono">
|
||||
{cursorHighlight.sizePx}px
|
||||
</span>
|
||||
@@ -1091,7 +1095,10 @@ export function SettingsPanel({
|
||||
<Slider
|
||||
value={[cursorHighlight.sizePx]}
|
||||
onValueChange={(values) =>
|
||||
onCursorHighlightChange({ ...cursorHighlight, sizePx: values[0] })
|
||||
onCursorHighlightChange({
|
||||
...cursorHighlight,
|
||||
sizePx: values[0],
|
||||
})
|
||||
}
|
||||
min={10}
|
||||
max={36}
|
||||
@@ -1103,19 +1110,27 @@ export function SettingsPanel({
|
||||
<div
|
||||
className={`flex items-center justify-between ${cursorHighlight.enabled ? "" : "opacity-40 pointer-events-none"}`}
|
||||
>
|
||||
<div className="text-[10px] text-slate-400">Only on clicks</div>
|
||||
<div className="text-[10px] text-slate-400">
|
||||
{t("effects.cursorHighlight.onlyOnClicks")}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
const turningOn = !cursorHighlight.onlyOnClicks;
|
||||
if (turningOn) {
|
||||
try {
|
||||
const result = await window.electronAPI.requestAccessibilityAccess();
|
||||
if (!result.granted) {
|
||||
toast.message("Accessibility permission needed", {
|
||||
description:
|
||||
"Open System Settings → Privacy & Security → Accessibility, enable Openscreen, then restart the app.",
|
||||
});
|
||||
const result =
|
||||
await window.electronAPI?.requestAccessibilityAccess?.();
|
||||
if (!result?.granted) {
|
||||
toast.message(
|
||||
t("effects.cursorHighlight.accessibilityPermissionTitle"),
|
||||
{
|
||||
description: t(
|
||||
"effects.cursorHighlight.accessibilityPermissionDescription",
|
||||
),
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("Accessibility request failed:", err);
|
||||
@@ -1132,12 +1147,14 @@ export function SettingsPanel({
|
||||
: "bg-white/5 border-white/10 text-slate-400"
|
||||
}`}
|
||||
>
|
||||
{cursorHighlight.onlyOnClicks ? "On" : "Off"}
|
||||
{cursorHighlight.onlyOnClicks ? t("effects.on") : t("effects.off")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className={cursorHighlight.enabled ? "" : "opacity-40 pointer-events-none"}>
|
||||
<div className="text-[10px] text-slate-400 mb-1">Color</div>
|
||||
<div className="text-[10px] text-slate-400 mb-1">
|
||||
{t("effects.cursorHighlight.color")}
|
||||
</div>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
@@ -1166,7 +1183,10 @@ export function SettingsPanel({
|
||||
colorPalette: t("background.colorPalette"),
|
||||
}}
|
||||
onUpdateColor={(color) =>
|
||||
onCursorHighlightChange({ ...cursorHighlight, color })
|
||||
onCursorHighlightChange({
|
||||
...cursorHighlight,
|
||||
color,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</PopoverContent>
|
||||
@@ -1174,7 +1194,9 @@ export function SettingsPanel({
|
||||
</div>
|
||||
<div className={cursorHighlight.enabled ? "" : "opacity-40 pointer-events-none"}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="text-[10px] text-slate-400">Offset X (window recordings)</div>
|
||||
<div className="text-[10px] text-slate-400">
|
||||
{t("effects.cursorHighlight.offsetX")}
|
||||
</div>
|
||||
<span className="text-[10px] text-slate-500 font-mono">
|
||||
{(cursorHighlight.offsetXNorm * 100).toFixed(1)}%
|
||||
</span>
|
||||
@@ -1195,7 +1217,9 @@ export function SettingsPanel({
|
||||
</div>
|
||||
<div className={cursorHighlight.enabled ? "" : "opacity-40 pointer-events-none"}>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="text-[10px] text-slate-400">Offset Y</div>
|
||||
<div className="text-[10px] text-slate-400">
|
||||
{t("effects.cursorHighlight.offsetY")}
|
||||
</div>
|
||||
<span className="text-[10px] text-slate-500 font-mono">
|
||||
{(cursorHighlight.offsetYNorm * 100).toFixed(1)}%
|
||||
</span>
|
||||
|
||||
@@ -8,6 +8,7 @@ export const SUPPORTED_LOCALES = [
|
||||
"tr",
|
||||
"ko-KR",
|
||||
"ja-JP",
|
||||
"ar",
|
||||
] as const;
|
||||
export const I18N_NAMESPACES = [
|
||||
"common",
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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": "جميع الملفات"
|
||||
}
|
||||
}
|
||||
@@ -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": "تم رفض إذن التسجيل. يرجى السماح بتسجيل الشاشة."
|
||||
}
|
||||
}
|
||||
@@ -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": "الاحتفاظ باللغة الحالية"
|
||||
}
|
||||
}
|
||||
@@ -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": "اللغة"
|
||||
}
|
||||
}
|
||||
@@ -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": "إطار للأمام"
|
||||
}
|
||||
}
|
||||
@@ -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}} اقتراحات تكبير بناءً على المؤشر"
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user