diff --git a/apps/desktop/src/i18n/ar.ts b/apps/desktop/src/i18n/ar.ts new file mode 100644 index 0000000000000..2d61c399998f7 --- /dev/null +++ b/apps/desktop/src/i18n/ar.ts @@ -0,0 +1,2561 @@ +import { defineLocale } from './define-locale' + +export const ar = defineLocale({ + common: { + apply: 'تطبيق', + back: 'رجوع', + save: 'حفظ', + saving: 'جار الحفظ...', + cancel: 'إلغاء', + change: 'تغيير', + choose: 'اختيار', + clear: 'مسح', + close: 'إغلاق', + collapse: 'طي', + confirm: 'تأكيد', + connect: 'اتصال', + connecting: 'جار الاتصال', + continue: 'متابعة', + copied: 'تم النسخ', + copy: 'نسخ', + copyFailed: 'فشل النسخ', + delete: 'حذف', + docs: 'الوثائق', + done: 'تم', + error: 'خطأ', + failed: 'فشل', + free: 'مجاني', + loading: 'جار التحميل...', + notSet: 'غير مضبوط', + refresh: 'تحديث', + remove: 'إزالة', + replace: 'استبدال', + retry: 'إعادة المحاولة', + run: 'تشغيل', + send: 'إرسال', + set: 'ضبط', + skip: 'تخطي', + update: 'تحديث', + on: 'مفعل', + off: 'معطل' + }, + fileMenu: { + revealFinder: 'إظهار في Finder', + revealExplorer: 'إظهار في File Explorer', + revealFileManager: 'فتح المجلد الحاوي', + revealInSidebar: 'إظهار في شجرة الملفات', + copyPath: 'نسخ المسار', + copyRelativePath: 'نسخ المسار النسبي', + rename: 'إعادة تسمية...', + delete: 'حذف', + renameTitle: 'إعادة تسمية', + renameLabel: 'الاسم الجديد', + deleteTitle: name => `حذف ${name}؟`, + deleteBody: 'سيتم نقله إلى سلة المهملات — يمكنك استعادته من هناك.', + pathCopied: 'تم نسخ المسار' + }, + boot: { + ready: 'Hermes Desktop جاهز', + desktopBootFailedWithMessage: message => `فشل تشغيل سطح المكتب: ${message}`, + steps: { + connectingGateway: 'جار الاتصال ببوابة سطح المكتب', + loadingSettings: 'جار تحميل إعدادات Hermes', + loadingSessions: 'جار تحميل الجلسات الأخيرة', + startingDesktopConnection: 'جار بدء اتصال سطح المكتب', + startingHermesDesktop: 'جار تشغيل Hermes Desktop...' + }, + errors: { + backgroundExited: 'خرجت عملية Hermes الخلفية.', + backgroundExitedDuringStartup: 'خرجت عملية Hermes الخلفية أثناء بدء التشغيل.', + backendStopped: 'توقف الخلفية', + desktopBootFailed: 'فشل تشغيل سطح المكتب', + gatewayConnectionLost: 'انقطع الاتصال بالبوابة', + gatewaySignInRequired: 'تسجيل الدخول للبوابة مطلوب', + ipcBridgeUnavailable: 'جسر IPC لسطح المكتب غير متاح.' + }, + failure: { + title: 'تعذر تشغيل Hermes', + description: 'لم تعمل البوابة الخلفية. جرب إحدى خطوات الاسترداد أدناه. لن يحذف ذلك محادثاتك أو إعداداتك.', + remoteTitle: 'تسجيل الدخول للبوابة البعيدة مطلوب', + remoteDescription: 'انتهت جلسة البوابة البعيدة. سجل الدخول مرة أخرى لإعادة الاتصال.', + retry: 'إعادة المحاولة', + repairInstall: 'إصلاح التثبيت', + useLocalGateway: 'استخدام البوابة المحلية', + openLogs: 'فتح السجلات', + repairHint: 'يعيد الإصلاح تشغيل المثبت وقد يستغرق بضع دقائق على جهاز جديد.', + remoteSignInHint: signInLabel => + `يسجّل الخروج من جلسة المتصفح البعيدة المحفوظة، ثم يفتح ${signInLabel}. استخدم البوابة المحلية للتبديل إلى الخلفية المضمنة.`, + signOutAndSignIn: 'تسجيل الخروج وإعادة تسجيل الدخول', + hideRecentLogs: 'إخفاء السجلات الأخيرة', + showRecentLogs: 'إظهار السجلات الأخيرة', + signedInTitle: 'تم تسجيل الدخول', + signedInMessage: 'جار إعادة الاتصال بالبوابة البعيدة...', + signInIncompleteTitle: 'تسجيل الدخول غير مكتمل', + signInIncompleteMessage: 'أغلقت نافذة تسجيل الدخول قبل اكتمال المصادقة.', + signInFailed: 'فشل تسجيل الدخول', + signInToRemoteGateway: 'تسجيل الدخول للبوابة البعيدة', + signInWithProvider: provider => `تسجيل الدخول عبر ${provider}`, + identityProvider: 'مزود الهوية' + } + }, + notifications: { + region: 'الإشعارات', + hide: 'إخفاء', + show: 'إظهار', + more: count => `${count} إشعار إضافي`, + clearAll: 'مسح الكل', + dismiss: 'إغلاق الإشعار', + details: 'التفاصيل', + copyDetail: 'نسخ التفاصيل', + copyDetailFailed: 'تعذر نسخ تفاصيل الإشعار', + backendOutOfDateTitle: 'الخلفية قديمة', + backendOutOfDateMessage: 'خلفية Hermes أقدم من إصدار سطح المكتب الحالي وقد لا تعمل كما يجب. حدثهما ليتوافقا.', + updateHermes: 'تحديث Hermes', + updateReadyTitle: 'التحديث جاهز', + updateReadyMessage: count => `${count} تغيير جديد متاح.`, + seeWhatsNew: 'عرض الجديد', + errors: { + elevenLabsNeedsKey: 'يتطلب ElevenLabs STT المفتاح ELEVENLABS_API_KEY.', + elevenLabsRejectedKey: 'رفض ElevenLabs مفتاح API (401).', + methodNotAllowed: 'رفضت خلفية سطح المكتب هذا الطلب (405 Method Not Allowed). جرب إعادة تشغيل Hermes Desktop.', + microphonePermission: 'تم رفض إذن الميكروفون.', + openaiRejectedApiKey: 'رفض OpenAI مفتاح API.', + openaiRejectedApiKeyWithStatus: status => `رفض OpenAI مفتاح API (${status} invalid_api_key).`, + openaiTtsNeedsKey: 'يتطلب OpenAI TTS المفتاح VOICE_TOOLS_OPENAI_KEY أو OPENAI_API_KEY.' + }, + voice: { + configureSpeechToText: 'اضبط تحويل الكلام إلى نص لاستخدام وضع الصوت.', + couldNotStartSession: 'تعذر بدء جلسة الصوت', + microphoneAccessDenied: 'تم رفض الوصول إلى الميكروفون.', + microphoneConstraintsUnsupported: 'قيود الميكروفون غير مدعومة على هذا الجهاز.', + microphoneFailed: 'فشل الميكروفون', + microphoneInUse: 'الميكروفون مستخدم من تطبيق آخر.', + microphonePermissionDenied: 'تم رفض إذن الميكروفون.', + microphoneStartFailed: 'تعذر بدء تسجيل الميكروفون.', + microphoneUnsupported: 'هذا المتصفح لا يدعم تسجيل الميكروفون.', + noMicrophone: 'لم يتم العثور على ميكروفون.', + noSpeechDetected: 'لم يتم اكتشاف كلام', + playbackFailed: 'فشل تشغيل الصوت', + recordingFailed: 'فشل التسجيل', + transcriptionFailed: 'فشل التفريغ النصي', + transcriptionUnavailable: 'التفريغ النصي غير متاح.', + tryRecordingAgain: 'حاول التسجيل مرة أخرى.', + unavailable: 'الصوت غير متاح' + }, + native: { + approvalTitle: 'مطلوب موافقة', + approveAction: 'موافقة', + rejectAction: 'رفض', + inputTitle: 'مطلوب إدخال', + inputBody: 'ينتظر Hermes ردّك.', + turnDoneTitle: 'أنهى Hermes', + turnDoneBody: 'الرد جاهز.', + turnErrorTitle: 'فشلت الجولة', + backgroundDoneTitle: 'انتهت المهمة في الخلفية', + backgroundFailedTitle: 'فشلت المهمة في الخلفية' + } + }, + remoteDisplayBanner: { + message: reason => `العرض البرمجي نشط — تم اكتشاف شاشة بعيدة (${reason}). تم تعطيل تسريع GPU لمنع الوميض.` + }, + titlebar: { + hideSidebar: 'إخفاء الشريط الجانبي', + showSidebar: 'إظهار الشريط الجانبي', + search: 'بحث', + searchTitle: 'البحث في الجلسات والعروض والإجراءات', + swapSidebarSides: 'تبديل جانبي الأشرطة', + swapSidebarSidesTitle: 'تبديل موضعي شريط الجلسات ومستكشف الملفات', + hideRightSidebar: 'إخفاء الشريط الأيمن', + showRightSidebar: 'إظهار الشريط الأيمن', + muteHaptics: 'كتم الاهتزازات', + unmuteHaptics: 'تفعيل الاهتزازات', + openSettings: 'فتح الإعدادات', + openStarmap: 'فتح خريطة الذاكرة', + openKeybinds: 'اختصارات لوحة المفاتيح', + layoutEditor: 'محرر التخطيط', + layoutEditorTitle: 'محرر التخطيط — انقر مع ⌘ لإعادة ضبط التخطيط' + }, + keybinds: { + title: 'اختصارات لوحة المفاتيح', + subtitle: open => `انقر على اختصار لإعادة تعيينه · ${open} يعيد فتح هذه اللوحة.`, + search: 'ابحث في الاختصارات...', + rebind: 'إعادة تعيين', + reset: 'إعادة إلى الافتراضي', + resetAll: 'إعادة تعيين الكل', + pressKey: 'اضغط مفتاحا...', + set: 'مضبوط', + conflictWith: label => `مرتبط أيضا بـ “${label}”`, + categories: { + composer: 'المحرّر', + profiles: 'الملفات الشخصية', + session: 'الجلسة', + navigation: 'التنقل', + view: 'العرض' + }, + actions: { + 'keybinds.openPanel': 'فتح اختصارات لوحة المفاتيح', + 'nav.commandPalette': 'فتح لوحة الأوامر', + 'nav.commandCenter': 'فتح مركز الأوامر', + 'nav.settings': 'فتح الإعدادات', + 'nav.profiles': 'فتح الملفات الشخصية', + 'nav.skills': 'فتح المهارات', + 'nav.messaging': 'فتح المراسلة', + 'nav.artifacts': 'فتح العناصر', + 'nav.cron': 'فتح المهام المجدولة', + 'nav.agents': 'فتح الوكلاء', + 'session.new': 'جلسة جديدة', + 'session.newTab': 'علامة تبويب جلسة جديدة', + 'session.newWindow': 'جلسة جديدة في نافذة', + 'session.next': 'الجلسة التالية', + 'session.prev': 'الجلسة السابقة', + 'session.slot.1': 'الانتقال إلى الجلسة الأخيرة 1', + 'session.slot.2': 'الانتقال إلى الجلسة الأخيرة 2', + 'session.slot.3': 'الانتقال إلى الجلسة الأخيرة 3', + 'session.slot.4': 'الانتقال إلى الجلسة الأخيرة 4', + 'session.slot.5': 'الانتقال إلى الجلسة الأخيرة 5', + 'session.slot.6': 'الانتقال إلى الجلسة الأخيرة 6', + 'session.slot.7': 'الانتقال إلى الجلسة الأخيرة 7', + 'session.slot.8': 'الانتقال إلى الجلسة الأخيرة 8', + 'session.slot.9': 'الانتقال إلى الجلسة الأخيرة 9', + 'session.focusSearch': 'البحث في الجلسات', + 'session.togglePin': 'تثبيت / إلغاء تثبيت الجلسة الحالية', + 'workspace.newWorktree': 'worktree جديد', + 'composer.focus': 'التركيز على المحرّر', + 'composer.modelPicker': 'فتح منتقي النموذج', + 'composer.voice': 'بدء / إيقاف المحادثة الصوتية', + 'view.toggleSidebar': 'تبديل الشريط الجانبي للجلسات', + 'view.toggleRightSidebar': 'تبديل متصفح الملفات', + 'view.toggleReview': 'تبديل لوحة المراجعة', + 'view.showFiles': 'إظهار متصفح الملفات', + 'view.showTerminal': 'إظهار الطرفية', + 'view.closeTab': 'إغلاق علامة التبويب', + 'view.reopenTab': 'إعادة فتح علامة التبويب المغلقة', + 'view.terminalSelection': 'إرسال تحديد الطرفية إلى المحرّر', + 'view.closePreviewTab': 'إغلاق علامة تبويب المعاينة', + 'view.flipPanes': 'تبديل جانبي الشريط الجانبي', + 'appearance.toggleMode': 'تبديل الفاتح / الداكن', + 'profile.default': 'الانتقال إلى الملف الشخصي الافتراضي', + 'profile.switch.1': 'الانتقال إلى الملف الشخصي 1', + 'profile.switch.2': 'الانتقال إلى الملف الشخصي 2', + 'profile.switch.3': 'الانتقال إلى الملف الشخصي 3', + 'profile.switch.4': 'الانتقال إلى الملف الشخصي 4', + 'profile.switch.5': 'الانتقال إلى الملف الشخصي 5', + 'profile.switch.6': 'الانتقال إلى الملف الشخصي 6', + 'profile.switch.7': 'الانتقال إلى الملف الشخصي 7', + 'profile.switch.8': 'الانتقال إلى الملف الشخصي 8', + 'profile.switch.9': 'الانتقال إلى الملف الشخصي 9', + 'profile.switch.10': 'الانتقال إلى الملف الشخصي 10', + 'profile.switch.11': 'الانتقال إلى الملف الشخصي 11', + 'profile.switch.12': 'الانتقال إلى الملف الشخصي 12', + 'profile.switch.13': 'الانتقال إلى الملف الشخصي 13', + 'profile.switch.14': 'الانتقال إلى الملف الشخصي 14', + 'profile.switch.15': 'الانتقال إلى الملف الشخصي 15', + 'profile.switch.16': 'الانتقال إلى الملف الشخصي 16', + 'profile.switch.17': 'الانتقال إلى الملف الشخصي 17', + 'profile.switch.18': 'الانتقال إلى الملف الشخصي 18', + 'profile.next': 'الملف الشخصي التالي', + 'profile.prev': 'الملف الشخصي السابق', + 'profile.toggleAll': 'تبديل عرض كل الملفات الشخصية', + 'profile.create': 'إنشاء ملف شخصي', + 'composer.send': 'إرسال الرسالة', + 'composer.newline': 'إدراج سطر جديد', + 'composer.steer': 'توجيه الدور الجاري', + 'composer.sendQueued': 'إرسال الدور التالي في الطابور', + 'composer.mention': 'الإشارة إلى الملفات والمجلدات وعناوين URL', + 'composer.slash': 'لوحة الأوامر المائلة', + 'composer.help': 'مساعدة سريعة', + 'composer.history': 'التنقل في النافذة المنبثقة / السجل', + 'composer.cancel': 'إغلاق النافذة المنبثقة · إلغاء التشغيل' + } + }, + language: { + label: 'اللغة', + description: 'اختر لغة واجهة سطح المكتب.', + saving: 'جار حفظ اللغة...', + saveError: 'تعذر تحديث اللغة', + switchTo: 'تغيير اللغة', + searchPlaceholder: 'ابحث عن لغة...', + noResults: 'لا توجد لغة مطابقة' + }, + settings: { + closeSettings: 'إغلاق الإعدادات', + exportConfig: 'تصدير الإعدادات', + importConfig: 'استيراد الإعدادات', + resetToDefaults: 'إعادة الافتراضيات', + resetConfirm: 'هل تريد إعادة كل الإعدادات إلى افتراضيات Hermes؟', + exportFailed: 'فشل التصدير', + resetFailed: 'فشلت إعادة الضبط', + nav: { + providers: 'المزودون', + providerAccounts: 'الحسابات', + providerApiKeys: 'مفاتيح API', + gateway: 'البوابة', + apiKeys: 'الأدوات والمفاتيح', + keysTools: 'الأدوات', + keysSettings: 'الإعدادات', + mcp: 'MCP', + archivedChats: 'المحادثات المؤرشفة', + about: 'حول', + notifications: 'الإشعارات', + keybinds: 'اختصارات لوحة المفاتيح', + plugins: 'الإضافات' + }, + plugins: { + title: 'إضافات سطح المكتب', + blurb: + 'امتدادات واجهة تُحمّل داخل هذا التطبيق — إما مضمّنة مع البناء، أو موضوعة في مجلد desktop-plugins (بما فيها التي يكتبها Hermes). تعطيل الإضافة يفرغها مباشرة ويبقى بعد إعادة التشغيل.', + count: n => `${n} مثبتة`, + openFolder: 'فتح مجلد الإضافات', + rescan: 'إعادة الفحص', + reveal: 'إظهار في مدير الملفات', + enable: 'تفعيل', + disable: 'تعطيل', + failed: 'فشل', + empty: 'لا توجد إضافات سطح مكتب مثبتة بعد.', + kinds: { bundled: 'مضمّنة', disk: 'على القرص', runtime: 'وقت التشغيل' } + }, + notifications: { + title: 'الإشعارات', + intro: + 'إشعارات سطح المكتب الأصلية، منفصلة عن التنبيهات داخل التطبيق. هذه محلية على الجهاز — كل حاسوب يحتفظ بإعداداته الخاصة.', + enableAll: 'تفعيل الإشعارات', + enableAllDesc: 'مفتاح رئيسي. أوقفه لإسكات كل الإشعارات أدناه.', + focusedHint: 'تنبيهات الاكتمال تظهر فقط عندما يكون Hermes في الخلفية.', + kinds: { + approval: { + label: 'يلزم الموافقة', + description: 'هناك أمر ينتظر موافقتك أو رفضك له.' + }, + input: { + label: 'يلزم إدخال', + description: 'طرح Hermes سؤالا أو يحتاج إلى كلمة مرور أو سر.' + }, + turnDone: { + label: 'الرد جاهز', + description: 'انتهى دور بينما كان Hermes في الخلفية.' + }, + turnError: { + label: 'فشل الدور', + description: 'انتهى دور بخطأ.' + }, + backgroundDone: { + label: 'اكتملت مهمة الخلفية', + description: 'اكتمل أمر طرفية يعمل في الخلفية.' + } + }, + test: 'إرسال إشعار تجريبي', + testTitle: 'Hermes', + testBody: 'الإشعارات تعمل.', + testSent: 'تم إرسال التجربة. إذا لم يظهر شيء، تحقق من أذونات الإشعارات في نظام التشغيل ووضع التركيز/عدم الإزعاج.', + testUnsupported: 'هذا النظام لا يدعم الإشعارات الأصلية.', + completionSoundTitle: 'صوت الاكتمال', + completionSoundDesc: 'يُشغّل عند انتهاء دور الوكيل. اختر إعدادا مسبقا وعاينه هنا.', + completionSoundPreview: 'معاينة' + }, + sections: { + model: 'النموذج', + chat: 'المحادثة', + appearance: 'المظهر', + workspace: 'مساحة العمل', + safety: 'الأمان', + memory: 'الذاكرة والسياق', + voice: 'الصوت', + advanced: 'متقدم' + }, + searchPlaceholder: { + about: 'حول Hermes Desktop', + config: 'ابحث في الإعدادات...', + gateway: 'اتصال البوابة...', + keys: 'ابحث في مفاتيح API...', + mcp: 'ابحث في خوادم MCP...', + sessions: 'ابحث في المحادثات المؤرشفة...' + }, + modeOptions: { + light: { + label: 'فاتح', + description: 'أسطح سطح مكتب ساطعة' + }, + dark: { + label: 'داكن', + description: 'مساحة عمل منخفضة الوهج' + }, + system: { + label: 'النظام', + description: 'اتباع مظهر نظام التشغيل' + } + }, + appearance: { + title: 'المظهر', + intro: 'خصص مظهر Hermes Desktop.', + colorMode: 'نمط الألوان', + colorModeDesc: 'اختر الوضع الفاتح أو الداكن أو اتبع النظام.', + toolViewTitle: 'عرض الأدوات', + toolViewDesc: 'تحكم في كيفية عرض نشاط الأدوات داخل المحادثة.', + translucencyTitle: 'شفافية النافذة', + translucencyDesc: 'إظهار سطح المكتب من خلال النافذة بالكامل. متاح على macOS وWindows فقط.', + backdropTitle: 'خلفية النافذة', + backdropDesc: 'اختيار مقدار مزج خلفية سطح المكتب مع سطح Hermes.', + embedsTitle: 'التضمينات المضمّنة', + embedsDesc: + 'تُحمّل المعاينات الغنية من مواقع طرف ثالث (YouTube، X، …). "اسأل" يعرض عنصرا نائبا حتى تسمح لكل واحد؛ "دائما" يحمّلها تلقائيا؛ "إيقاف" يبقي الروابط عادية.', + embedsAsk: 'اسأل', + embedsAlways: 'دائما', + embedsOff: 'إيقاف', + embedsReset: count => `إعادة تعيين ${count} ${count === 1 ? 'خدمة مسموح بها' : 'خدمة مسموح بها'}`, + product: 'مبسط', + productDesc: 'عرض أنظف يركز على النتيجة.', + technical: 'تقني', + technicalDesc: 'يعرض تفاصيل أكثر عن الأدوات والتنفيذ.', + themeTitle: 'الثيم', + themeDesc: 'اختر ثيم سطح المكتب.', + themeProfileNote: profile => `سيطبق هذا الثيم على الملف الشخصي ${profile}.`, + installTitle: 'تثبيت ثيم', + installDesc: 'ألصق رابط ثيم أو اسمه لتثبيته.', + installPlaceholder: 'رابط أو اسم الثيم', + installButton: 'تثبيت', + installing: 'جار التثبيت...', + installError: 'فشل تثبيت الثيم', + installed: name => `تم تثبيت ${name}`, + removeTheme: 'إزالة الثيم', + importedBadge: 'مستورد', + pet: { + title: 'حيوان أليف', + intro: + 'تبنَّ تعويذة petdex متحركة تطفو فوق التطبيق وتتفاعل مع ما يفعله Hermes — تجري أثناء تنفيذ الأدوات، وتحتفل عند النجاح، وتعبس عند الأخطاء.', + restartHint: + 'تحتاج الحيوانات الأليفة إلى إعادة تشغيل سريعة — بدأ التطبيق العامل قبل إضافة هذه الميزة. أغلق Hermes وأعد فتحه، ثم ارجع إلى هنا.', + on: 'تشغيل', + off: 'إيقاف', + scaleTitle: 'الحجم', + scaleDesc: 'غيّر حجم التعويذة الطافية. يُطبّق في كل مكان فورا.', + chooseTitle: 'اختر حيوانا أليفا', + chooseDesc: 'اختياره يثبّته (إن لزم) ويجعله نشطا.', + searchPlaceholder: 'البحث عن حيوانات أليفة...', + unreachable: 'تعذّر الوصول إلى معرض petdex. تحقق من اتصالك وأعد فتح هذه الصفحة.', + noMatch: query => `لا توجد حيوانات أليفة تطابق "${query}".`, + installedTag: 'مثبّت', + generatedTag: 'مُولّد', + countCapped: (cap, total) => `عرض ${cap} من ${total} — اكتب لتضييق النتائج.`, + count: n => `${n} ${n === 1 ? 'حيوان أليف' : 'حيوان أليف'}.`, + uninstall: name => `إلغاء تثبيت ${name}`, + delete: name => `حذف ${name}`, + deleteTitle: name => `حذف ${name}؟`, + deleteBody: 'هذا يحذف الحيوان الأليف نهائيا — لا يمكن إعادة تثبيته.', + deleteConfirm: 'حذف', + rename: name => `إعادة تسمية ${name}`, + renameTitle: 'إعادة تسمية الحيوان الأليف', + renamePlaceholder: 'سمِّ حيوانك الأليف', + renameSave: 'حفظ', + exportPet: name => `تصدير ${name}`, + adoptFailed: slug => `تعذّر تبني ${slug}`, + uninstallFailed: slug => `تعذّر إلغاء تثبيت ${slug}`, + renameFailed: slug => `تعذّرت إعادة تسمية ${slug}`, + exportFailed: slug => `تعذّر تصدير ${slug}`, + noneAvailable: 'لا توجد حيوانات أليفة متاحة للتشغيل الآن.', + turnOnFailed: 'تعذّر تشغيل الحيوان الأليف.', + turnOffFailed: 'تعذّر إيقاف الحيوان الأليف.' + } + }, + fieldLabels: { + model: 'النموذج الافتراضي', + modelContextLength: 'نافذة السياق', + fallbackProviders: 'النماذج الاحتياطية', + toolsets: 'مجموعات الأدوات المفعلة', + timezone: 'المنطقة الزمنية', + 'display.personality': 'أسلوب المساعد', + 'display.showReasoning': 'إظهار التفكير', + 'agent.maxTurns': 'الحد الأقصى لخطوات الوكيل', + 'agent.imageInputMode': 'مرفقات الصور', + 'agent.apiMaxRetries': 'محاولات API', + 'agent.serviceTier': 'مستوى الخدمة', + 'agent.toolUseEnforcement': 'فرض استخدام الأدوات', + 'terminal.cwd': 'مجلد العمل', + 'terminal.backend': 'خلفية التنفيذ', + 'terminal.timeout': 'مهلة الأوامر', + 'terminal.persistentShell': 'صدفة مستمرة', + 'terminal.envPassthrough': 'تمرير متغيرات البيئة', + 'terminal.dockerImage': 'صورة Docker', + 'terminal.singularityImage': 'صورة Singularity', + 'terminal.modalImage': 'صورة Modal', + 'terminal.daytonaImage': 'صورة Daytona', + fileReadMaxChars: 'حد قراءة الملفات', + 'toolOutput.maxBytes': 'حد مخرجات الطرفية', + 'toolOutput.maxLines': 'حد صفحات الملفات', + 'toolOutput.maxLineLength': 'حد طول السطر', + 'codeExecution.mode': 'نمط تنفيذ الكود', + 'approvals.mode': 'نمط الموافقات', + 'approvals.timeout': 'مهلة الموافقة', + 'approvals.mcpReloadConfirm': 'تأكيد إعادة تحميل MCP', + commandAllowlist: 'قائمة الأوامر المسموحة', + 'security.redactSecrets': 'إخفاء الأسرار', + 'security.allowPrivateUrls': 'السماح بالروابط الخاصة', + 'browser.allowPrivateUrls': 'روابط المتصفح الخاصة', + 'browser.autoLocalForPrivateUrls': 'متصفح محلي للروابط الخاصة', + 'checkpoints.enabled': 'نقاط حفظ الملفات', + 'checkpoints.maxSnapshots': 'حد نقاط الحفظ', + 'voice.recordKey': 'اختصار الصوت', + 'voice.maxRecordingSeconds': 'أقصى مدة للتسجيل', + 'voice.autoTts': 'قراءة الردود صوتياً', + 'stt.enabled': 'تحويل الكلام إلى نص', + 'stt.provider': 'مزود تحويل الكلام إلى نص', + 'stt.local.model': 'نموذج التفريغ المحلي', + 'stt.local.language': 'لغة التفريغ', + 'stt.openai.model': 'نموذج OpenAI STT', + 'stt.groq.model': 'نموذج Groq STT', + 'stt.mistral.model': 'نموذج Mistral STT', + 'stt.elevenlabs.modelId': 'نموذج ElevenLabs STT', + 'stt.elevenlabs.languageCode': 'لغة ElevenLabs', + 'stt.elevenlabs.tagAudioEvents': 'وسم أحداث الصوت', + 'stt.elevenlabs.diarize': 'تمييز المتحدثين', + 'tts.provider': 'مزود تحويل النص إلى كلام', + 'tts.edge.voice': 'صوت Edge', + 'tts.openai.model': 'نموذج OpenAI TTS', + 'tts.openai.voice': 'صوت OpenAI', + 'tts.elevenlabs.voiceId': 'صوت ElevenLabs', + 'tts.elevenlabs.modelId': 'نموذج ElevenLabs', + 'tts.xai.voiceId': 'صوت xAI (Grok)', + 'tts.xai.language': 'لغة xAI', + 'tts.minimax.model': 'نموذج MiniMax TTS', + 'tts.minimax.voiceId': 'صوت MiniMax', + 'tts.mistral.model': 'نموذج Mistral TTS', + 'tts.mistral.voiceId': 'صوت Mistral', + 'tts.gemini.model': 'نموذج Gemini TTS', + 'tts.gemini.voice': 'صوت Gemini', + 'tts.neutts.model': 'نموذج NeuTTS', + 'tts.neutts.device': 'جهاز NeuTTS', + 'tts.kittentts.model': 'نموذج KittenTTS', + 'tts.kittentts.voice': 'صوت KittenTTS', + 'tts.piper.voice': 'صوت Piper', + 'memory.memoryEnabled': 'الذاكرة المستمرة', + 'memory.userProfileEnabled': 'ملف المستخدم', + 'memory.memoryCharLimit': 'ميزانية الذاكرة', + 'memory.userCharLimit': 'ميزانية الملف الشخصي', + 'memory.provider': 'مزود الذاكرة', + 'context.engine': 'محرك السياق', + 'compression.enabled': 'الضغط التلقائي', + 'compression.threshold': 'عتبة الضغط', + 'compression.targetRatio': 'هدف الضغط', + 'compression.protectLastN': 'الرسائل الأخيرة المحمية', + 'delegation.model': 'نموذج الوكيل الفرعي', + 'delegation.provider': 'مزود الوكيل الفرعي', + 'delegation.maxIterations': 'حد دورات الوكيل الفرعي', + 'delegation.maxConcurrentChildren': 'الوكلاء الفرعيون المتوازيون', + 'delegation.childTimeoutSeconds': 'مهلة الوكيل الفرعي', + 'delegation.reasoningEffort': 'جهد تفكير الوكيل الفرعي', + 'updates.nonInteractiveLocalChanges': 'تغييرات التحديث داخل التطبيق' + }, + fieldDescriptions: { + model: 'يستخدم في المحادثات الجديدة ما لم تختر نموذجاً مختلفاً من محرر الرسائل.', + modelContextLength: 'اتركه 0 لاستخدام نافذة السياق المكتشفة للنموذج المحدد.', + fallbackProviders: 'إدخالات احتياطية بصيغة provider:model لتجربتها إذا فشل النموذج الافتراضي.', + 'display.personality': 'أسلوب المساعد الافتراضي للجلسات الجديدة.', + 'display.showReasoning': 'يعرض أقسام التفكير عندما توفرها الخلفية.', + timezone: 'تستخدم عندما يحتاج Hermes إلى سياق الوقت المحلي. اتركها فارغة لاستخدام منطقة النظام.', + 'agent.imageInputMode': 'يتحكم في طريقة إرسال مرفقات الصور إلى النموذج.', + 'agent.maxTurns': 'الحد الأعلى لدورات استدعاء الأدوات قبل أن يوقف Hermes التشغيل.', + 'terminal.cwd': 'مجلد المشروع الافتراضي لعمل الأدوات والطرفية.', + 'terminal.persistentShell': 'يحافظ على حالة الصدفة بين الأوامر عندما تدعمها الخلفية.', + 'terminal.envPassthrough': 'متغيرات البيئة التي تمرر إلى تنفيذ الأدوات.', + 'terminal.dockerImage': 'صورة الحاوية المستخدمة عند اختيار Docker كخلفية تنفيذ.', + 'terminal.singularityImage': 'الصورة المستخدمة عند اختيار Singularity.', + 'terminal.modalImage': 'الصورة المستخدمة عند اختيار Modal.', + 'terminal.daytonaImage': 'الصورة المستخدمة عند اختيار Daytona.', + 'codeExecution.mode': 'مدى تقييد تنفيذ الكود بالمشروع الحالي.', + fileReadMaxChars: 'أقصى عدد أحرف يستطيع Hermes قراءته من ملف واحد في الطلب.', + 'approvals.mode': 'كيف يتعامل Hermes مع الأوامر التي تحتاج موافقة صريحة.', + 'approvals.timeout': 'مدة انتظار طلبات الموافقة قبل انتهاء المهلة.', + 'security.redactSecrets': 'يخفي الأسرار المكتشفة من المحتوى المرئي للنموذج قدر الإمكان.', + 'checkpoints.enabled': 'ينشئ لقطات رجوع قبل تعديلات الملفات.', + 'memory.memoryEnabled': 'يحفظ ذكريات دائمة يمكن أن تساعد الجلسات القادمة.', + 'memory.userProfileEnabled': 'يحافظ على ملف مختصر لتفضيلات المستخدم.', + 'context.engine': 'استراتيجية إدارة المحادثات الطويلة قرب حد السياق.', + 'compression.enabled': 'يلخص السياق الأقدم عندما تكبر المحادثات.', + 'voice.autoTts': 'ينطق ردود المساعد تلقائياً.', + 'tts.xai.voiceId': 'معرف صوت xAI مثل eve أو معرف صوت مخصص.', + 'tts.xai.language': 'رمز لغة النطق، مثل en.', + 'tts.neutts.device': 'جهاز الاستدلال المحلي لـ NeuTTS.', + 'stt.enabled': 'يفعل التفريغ الصوتي المحلي أو عبر مزود.', + 'stt.elevenlabs.languageCode': 'رمز لغة ISO-639-3 اختياري. اتركه فارغاً للاكتشاف التلقائي.', + 'updates.nonInteractiveLocalChanges': + 'عندما يحدّث Hermes نفسه من التطبيق دون موجه طرفية، احتفظ بتعديلات المصدر المحلية أو تجاهلها.' + }, + about: { + heading: 'حول Hermes', + version: value => `الإصدار ${value}`, + versionUnavailable: 'الإصدار غير متاح', + updates: 'التحديثات', + checkNow: 'التحقق الآن', + checking: 'جار التحقق...', + seeWhatsNew: 'عرض الجديد', + updateNow: 'تحديث الآن', + releaseNotes: 'ملاحظات الإصدار', + onLatest: 'أنت على أحدث إصدار', + installing: 'جار التثبيت...', + cantUpdate: 'تعذر التحديث', + cantReach: 'تعذر الوصول لخدمة التحديث', + tapCheck: 'اضغط للتحقق من التحديثات.', + updateReady: count => `${count} تحديث متاح`, + lastChecked: age => `آخر تحقق ${age}`, + justNowSuffix: 'الآن', + automaticUpdates: 'التحديثات التلقائية', + automaticUpdatesDesc: 'اسمح لـ Hermes بالتحقق من التحديثات وتثبيتها.', + branchCommit: (branch, commit) => `${branch} عند ${commit}`, + never: 'أبدا', + justNow: 'الآن', + minAgo: count => `قبل ${count} دقيقة`, + hoursAgo: count => `قبل ${count} ساعة`, + daysAgo: count => `قبل ${count} يوم` + }, + config: { + none: 'لا شيء', + noneParen: '(لا شيء)', + notSet: 'غير مضبوط', + commaSeparated: 'قيم مفصولة بفواصل', + loading: 'جار تحميل إعدادات Hermes...', + emptyTitle: 'لا توجد إعدادات', + emptyDesc: 'لا يحتوي هذا القسم على إعدادات قابلة للتعديل.', + failedLoad: 'فشل تحميل الإعدادات', + autosaveFailed: 'فشل الحفظ التلقائي', + imported: 'تم استيراد الإعدادات', + invalidJson: 'JSON غير صالح' + }, + credentials: { + pasteKey: 'لصق المفتاح', + pasteLabelKey: label => `لصق مفتاح ${label}`, + optional: 'اختياري', + enterValueFirst: 'أدخل قيمة أولا.', + couldNotSave: 'تعذّر حفظ بيانات الاعتماد.', + remove: 'إزالة', + getKey: 'احصل على مفتاح', + saving: 'جار الحفظ' + }, + envActions: { + actionsFor: label => `إجراءات ${label}`, + credentialActions: 'إجراءات بيانات الاعتماد', + docs: 'الوثائق', + hideValue: 'إخفاء القيمة', + revealValue: 'إظهار القيمة', + replace: 'استبدال', + set: 'ضبط', + clear: 'مسح' + }, + gateway: { + loading: 'جار تحميل إعدادات البوابة...', + unavailableTitle: 'إعدادات البوابة غير متاحة', + unavailableDesc: 'جسر IPC في سطح المكتب لا يوفّر إعدادات البوابة.', + title: 'اتصال البوابة', + envOverride: 'تجاوز من البيئة', + intro: + 'يشغّل Hermes Desktop بوابة محلية خاصة افتراضياً. استخدم بوابة بعيدة عندما تريد أن يتحكم هذا التطبيق بخلفية Hermes تعمل مسبقاً على جهاز آخر أو خلف وكيل موثوق.', + appliesTo: 'ينطبق على', + allProfiles: 'كل الملفات الشخصية', + defaultConnection: 'الاتصال الافتراضي لكل ملف شخصي لا يملك تجاوزاً خاصاً.', + profileConnection: profile => + `الاتصال المستخدم فقط عندما يكون "${profile}" هو الملف الشخصي النشط. اضبطه على محلي ليرث الافتراضي.`, + envOverrideTitle: 'متغيرات البيئة تتحكم في جلسة سطح المكتب هذه.', + envOverrideDesc: 'أزل HERMES_DESKTOP_REMOTE_URL و HERMES_DESKTOP_REMOTE_TOKEN لاستخدام الإعداد المحفوظ أدناه.', + localTitle: 'بوابة محلية', + localDesc: 'تشغيل خلفية Hermes خاصة على localhost. هذا هو الافتراضي ويعمل دون اتصال.', + remoteTitle: 'بوابة بعيدة', + remoteDesc: + 'صل واجهة سطح المكتب هذه بخلفية Hermes بعيدة. البوابات المستضافة تستخدم OAuth أو اسم مستخدم وكلمة مرور، والبوابات الذاتية قد تستخدم رمز جلسة.', + remoteUrlTitle: 'رابط البوابة البعيدة', + remoteUrlDesc: 'الرابط الأساسي لخلفية لوحة التحكم البعيدة. يمكن استخدام بادئات مسار مثل /hermes.', + probing: 'جار فحص طريقة مصادقة هذه البوابة...', + probeError: 'تعذر الوصول إلى هذه البوابة الآن. تحقق من الرابط وستظهر طريقة المصادقة عند الاستجابة.', + signedIn: 'تم تسجيل الدخول', + signIn: 'تسجيل الدخول', + signOut: 'تسجيل الخروج', + signInWith: provider => `تسجيل الدخول عبر ${provider}`, + authTitle: 'المصادقة', + authSignedInPassword: 'هذه البوابة تستخدم اسم مستخدم وكلمة مرور. أنت مسجل الدخول والجلسة تتجدد تلقائياً.', + authSignedInOauth: 'هذه البوابة تستخدم OAuth. أنت مسجل الدخول والجلسة تتجدد تلقائياً.', + authNeedsPassword: 'هذه البوابة تستخدم اسم مستخدم وكلمة مرور. سجل الدخول لتفويض تطبيق سطح المكتب.', + authNeedsOauth: provider => `هذه البوابة تستخدم OAuth. سجل الدخول عبر ${provider} لتفويض تطبيق سطح المكتب.`, + tokenTitle: 'رمز الجلسة', + tokenDesc: 'رمز جلسة لوحة التحكم المستخدم لطلبات REST و WebSocket. اتركه فارغاً للإبقاء على الرمز المحفوظ.', + existingToken: value => `رمز موجود ${value}`, + savedToken: 'محفوظ', + pasteSessionToken: 'ألصق رمز الجلسة', + testRemote: 'اختبار البعيد', + saveForRestart: 'حفظ للتشغيل القادم', + saveAndReconnect: 'حفظ وإعادة الاتصال', + diagnostics: 'التشخيصات', + diagnosticsDesc: 'اعرض desktop.log في مدير الملفات، وهذا مفيد عند فشل تشغيل البوابة.', + openLogs: 'فتح السجلات', + incompleteTitle: 'إعداد البوابة البعيدة غير مكتمل', + incompleteSignIn: 'أدخل رابط البوابة البعيدة وسجل الدخول قبل التبديل إلى البعيد.', + incompleteToken: 'أدخل رابط البوابة البعيدة ورمز الجلسة قبل التبديل إلى البعيد.', + incompleteSignInTest: 'أدخل رابط البوابة البعيدة وسجل الدخول قبل الاختبار.', + incompleteTokenTest: 'أدخل رابط البوابة البعيدة ورمز الجلسة قبل الاختبار.', + enterUrlFirst: 'أدخل رابط البوابة البعيدة أولاً.', + restartingTitle: 'جار إعادة تشغيل اتصال البوابة', + savedTitle: 'تم حفظ إعدادات البوابة', + restartingMessage: 'سيعيد Hermes Desktop الاتصال باستخدام الإعدادات المحفوظة.', + savedMessage: 'تم الحفظ للتشغيل القادم.', + connectedTo: (baseUrl, version) => `متصل بـ ${baseUrl}${version ? ` · Hermes ${version}` : ''}`, + reachableTitle: 'البوابة البعيدة قابلة للوصول', + signedOutTitle: 'تم تسجيل الخروج', + signedOutMessage: 'تم مسح جلسة البوابة البعيدة.', + failedLoad: 'فشل تحميل إعدادات البوابة', + signInFailed: 'فشل تسجيل الدخول', + signOutFailed: 'فشل تسجيل الخروج', + testFailed: 'فشل اختبار البوابة البعيدة', + applyFailed: 'تعذر تطبيق إعدادات البوابة', + saveFailed: 'تعذر حفظ إعدادات البوابة' + }, + keys: { + loading: 'جار تحميل مفاتيح API وبيانات الاعتماد...', + failedLoad: 'فشل تحميل مفاتيح API', + empty: 'لا يوجد شيء مضبوط في هذه الفئة بعد.' + }, + mcp: { + loading: 'جار تحميل خوادم MCP...', + failedLoad: 'فشل تحميل إعدادات MCP', + nameRequiredTitle: 'الاسم مطلوب', + nameRequiredMessage: 'أعط هذا الخادم مفتاح إعداد.', + objectRequired: 'يجب أن تكون إعدادات الخادم كائن JSON', + invalidJson: 'JSON الخاص بـ MCP غير صالح', + saveFailed: 'فشل الحفظ', + removeFailed: 'فشلت الإزالة', + gatewayUnavailableTitle: 'البوابة غير متاحة', + gatewayUnavailableMessage: 'أعد الاتصال بالبوابة قبل إعادة تحميل MCP.', + reloadedTitle: 'تمت إعادة تحميل أدوات MCP', + reloadedMessage: 'مخططات الأدوات الجديدة تطبق على الأدوار الجديدة.', + reloadFailed: 'فشلت إعادة تحميل MCP', + savedTitle: 'تم حفظ خادم MCP', + savedMessage: name => `سيطبق ${name} بعد إعادة تحميل MCP.`, + newServer: 'خادم جديد', + reload: 'إعادة تحميل MCP', + reloading: 'جار إعادة التحميل...', + emptyTitle: 'لا توجد خوادم MCP', + emptyDesc: 'أضف خادم stdio أو HTTP لإتاحة أدوات MCP.', + disabled: 'معطل', + editServer: 'تحرير الخادم', + name: 'الاسم', + serverJson: 'JSON الخادم', + remove: 'إزالة', + saveServer: 'حفظ الخادم' + }, + model: { + loading: 'جار تحميل إعدادات النموذج...', + appliesDesc: 'ينطبق على الجلسات الجديدة. استخدم منتقي النموذج في صندوق الإنشاء لتبديل المحادثة النشطة فورا.', + provider: 'المزوّد', + model: 'النموذج', + applying: 'جار التطبيق...', + defaultsLabel: 'الافتراضيات', + reasoning: 'الاستدلال', + reasoningOff: 'إيقاف', + defaultsFailed: 'فشل حفظ افتراضيات النموذج', + auxiliaryTitle: 'النماذج المساعدة', + resetAllToMain: 'إعادة تعيين الكل إلى النموذج الرئيسي', + auxiliaryDesc: 'تعمل المهام المساعدة على النموذج الرئيسي افتراضيا. عيّن نموذجا مخصصا لأي مهمة لتجاوز ذلك.', + setToMain: 'ضبط على الرئيسي', + change: 'تغيير', + autoUseMain: 'تلقائي · استخدام النموذج الرئيسي', + providerDefault: '(افتراضي المزوّد)', + tasks: { + vision: { + label: 'الرؤية', + hint: 'تحليل الصور' + }, + web_extract: { + label: 'استخراج الويب', + hint: 'تلخيص الصفحات' + }, + compression: { + label: 'الضغط', + hint: 'ضغط السياق' + }, + skills_hub: { + label: 'مركز المهارات', + hint: 'بحث المهارات' + }, + approval: { + label: 'الموافقة', + hint: 'موافقة تلقائية ذكية' + }, + mcp: { + label: 'MCP', + hint: 'توجيه أدوات MCP' + }, + title_generation: { + label: 'توليد العناوين', + hint: 'عناوين الجلسات' + }, + curator: { + label: 'المنسّق', + hint: 'مراجعة استخدام المهارات' + } + } + }, + providers: { + connectAccount: 'ربط حساب', + haveApiKey: 'لديك مفتاح API بدلاً من ذلك؟', + intro: 'سجل الدخول باشتراكك دون نسخ مفتاح API. يشغّل Hermes تسجيل الدخول من المتصفح لك داخل التطبيق.', + connected: 'متصل', + collapse: 'طي', + connectAnother: 'ربط مزود آخر', + otherProviders: 'مزودون آخرون', + disconnect: 'قطع الاتصال', + disconnectInTerminal: 'قطع الاتصال (يشغّل أمر الإزالة في الطرفية)', + removeConfirm: provider => `إزالة ${provider}؟`, + removeExternalGeneric: provider => `${provider} يُدار عبر CLI خاص به — أزله من هناك.`, + removeKeyManaged: provider => `${provider} مُعدّ من مفتاح API. أزله من مفاتيح API.`, + removeTerminalConfirm: (provider, command) => + `قطع اتصال ${provider}؟ هذا يشغّل "${command}" في الطرفية لمسح بيانات الاعتماد.`, + removeTerminalRunning: provider => `جار تشغيل قطع اتصال ${provider} في الطرفية…`, + removedTitle: 'تمت إزالة الحساب', + removedMessage: provider => `تمت إزالة ${provider}.`, + failedRemove: provider => `تعذّرت إزالة ${provider}`, + noProviderKeys: 'لا توجد مفاتيح API متاحة للمزودين.', + searchKeys: 'البحث عن مزوّدين...', + noKeysMatch: 'لا يوجد مزوّدون يطابقون بحثك.', + localEndpoint: { + title: 'نقطة نهاية محلية', + description: 'استخدم خادما محليا أو نقطة نهاية متوافقة مع OpenAI لهذا المزود.' + }, + loading: 'جار تحميل المزودين...' + }, + sessions: { + loading: 'جار تحميل الجلسات المؤرشفة...', + archivedTitle: 'الجلسات المؤرشفة', + archivedIntro: + 'تُخفى المحادثات المؤرشفة من الشريط الجانبي مع الاحتفاظ بكل رسائلها. اضغط Ctrl/⌘ مع النقر على محادثة في الشريط الجانبي لأرشفتها.', + emptyArchivedTitle: 'لا توجد محادثات مؤرشفة', + emptyArchivedDesc: 'أرشف محادثة لإخفائها هنا.', + unarchive: 'إلغاء الأرشفة', + deletePermanently: 'حذف نهائي', + messages: count => `${count} ${count === 1 ? 'رسالة' : 'رسائل'}`, + restored: 'تمت الاستعادة', + deleteConfirm: title => `حذف "${title}" نهائياً؟ لا يمكن التراجع عن هذا.`, + defaultDirTitle: 'مجلد المشروع الافتراضي', + defaultDirDesc: 'تبدأ الجلسات الجديدة في هذا المجلد ما لم تختر غيره. اتركه غير مضبوط لاستخدام مجلدك الرئيسي.', + defaultDirUpdated: 'تم تحديث مجلد المشروع الافتراضي، ابدأ محادثة جديدة (Ctrl/⌘+N) ليطبق التغيير', + defaultsTo: label => `الافتراضي هو ${label}.`, + change: 'تغيير', + choose: 'اختيار', + clear: 'مسح', + notSet: 'غير مضبوط', + failedLoad: 'تعذر تحميل الجلسات المؤرشفة', + unarchiveFailed: 'فشل إلغاء الأرشفة', + deleteFailed: 'فشل الحذف', + updateDirFailed: 'تعذر تحديث المجلد الافتراضي', + clearDirFailed: 'تعذر مسح المجلد الافتراضي' + }, + toolsets: { + loadingConfig: 'جار تحميل الإعدادات', + savedTitle: 'تم حفظ بيانات الاعتماد', + savedMessage: key => `تم تحديث ${key}.`, + removedTitle: 'تمت إزالة بيانات الاعتماد', + removedMessage: key => `تمت إزالة ${key}.`, + failedSave: key => `فشل حفظ ${key}`, + failedRemove: key => `فشل إزالة ${key}`, + failedReveal: key => `فشل إظهار ${key}`, + removeConfirm: key => `إزالة ${key} من .env؟`, + set: 'ضبط', + notSet: 'غير مضبوط', + selectedTitle: 'تم اختيار المزوّد', + selectedMessage: provider => `${provider} نشط الآن.`, + failedSelect: provider => `فشل اختيار ${provider}`, + failedLoad: 'فشل تحميل إعدادات الأدوات', + noProviderOptions: 'لا تحتوي مجموعة الأدوات هذه على خيارات مزوّد — فعّلها لتعمل مع إعدادك الحالي.', + noProviders: 'لا يوجد مزوّدون متاحون لمجموعة الأدوات هذه الآن.', + ready: 'جاهز', + nousIncluded: 'مُضمّن مع اشتراك Nous — سجّل الدخول إلى Nous Portal للتفعيل.', + noApiKeyRequired: 'لا يلزم مفتاح API.', + postSetupHint: step => + `تحتاج هذه الخلفية إلى تثبيت لمرة واحدة (${step}). يعمل على هذا الجهاز — قد يستغرق بضع دقائق.`, + postSetupRun: 'تشغيل الإعداد', + postSetupRunning: 'جار التثبيت…', + postSetupStarting: 'جار البدء…', + postSetupCompleteTitle: 'اكتمل الإعداد', + postSetupCompleteMessage: step => `تم تثبيت ${step}.`, + postSetupErrorTitle: 'انتهى الإعداد بأخطاء', + postSetupErrorMessage: step => `تحقق من سجل ${step}.`, + postSetupFailed: step => `فشل تشغيل إعداد ${step}` + } + }, + skills: { + tabSkills: 'المهارات', + tabToolsets: 'مجموعات الأدوات', + all: 'الكل', + searchSkills: 'البحث في المهارات', + searchToolsets: 'البحث في مجموعات الأدوات', + refresh: 'تحديث', + refreshing: 'جار التحديث...', + loading: 'جار التحميل...', + noSkillsTitle: 'لا توجد مهارات', + noSkillsDesc: 'ستظهر المهارات المثبتة هنا.', + noToolsetsTitle: 'لا توجد مجموعات أدوات', + noToolsetsDesc: 'ستظهر مجموعات الأدوات المتاحة هنا.', + noDescription: 'لا يوجد وصف', + configured: 'مضبوط', + needsKeys: 'يحتاج مفاتيح', + toolsetsEnabled: (enabled, total) => `${enabled} من ${total} مفعلة`, + configureToolset: label => `ضبط ${label}`, + toggleToolset: label => `تبديل ${label}`, + skillsLoadFailed: 'فشل تحميل المهارات', + toolsetsRefreshFailed: 'فشل تحديث مجموعات الأدوات', + skillEnabled: 'تم تفعيل المهارة', + skillDisabled: 'تم تعطيل المهارة', + toolsetEnabled: 'تم تفعيل مجموعة الأدوات', + toolsetDisabled: 'تم تعطيل مجموعة الأدوات', + appliesToNewSessions: name => `ينطبق على الجلسات الجديدة في ${name}`, + failedToUpdate: name => `فشل تحديث ${name}` + }, + agents: { + close: 'إغلاق الوكلاء', + title: 'شجرة التوليد', + subtitle: 'نشاط الوكلاء الفرعيين المباشر للدور الحالي.', + emptyTitle: 'لا يوجد وكلاء فرعيون مباشرون', + emptyDesc: 'عندما يفوّض دور ما عملا، يبث الوكلاء الأبناء تقدّمهم هنا.', + running: 'قيد التشغيل', + failed: 'فشل', + done: 'تم', + streaming: 'جار البث', + files: 'الملفات', + moreFiles: count => `+${count} ملفات إضافية`, + delegation: index => `التفويض ${index}`, + workers: count => `${count} عامل`, + workersActive: count => `${count} نشط`, + agentsCount: count => `${count} ${count === 1 ? 'وكيل' : 'وكلاء'}`, + activeCount: count => `${count} نشط`, + failedCount: count => `${count} فشل`, + toolsCount: count => `${count} أداة`, + filesCount: count => `${count} ملف`, + updatedAgo: age => `تم التحديث ${age}`, + ageNow: 'الآن', + ageSeconds: seconds => `قبل ${seconds} ث`, + ageMinutes: minutes => `قبل ${minutes} د`, + ageHours: hours => `قبل ${hours} س`, + durationSeconds: seconds => `${seconds} ث`, + durationMinutes: (minutes, seconds) => `${minutes} د ${seconds} ث`, + tokens: value => `${value} رمز` + }, + commandCenter: { + close: 'إغلاق', + paletteTitle: 'لوحة الأوامر', + back: 'رجوع', + searchPlaceholder: 'ابحث عن أمر أو إعداد...', + goTo: 'انتقال إلى', + goToSession: 'الانتقال إلى الجلسة', + branches: 'الفروع', + startInBranch: branch => `محادثة جديدة في ${branch}`, + commandCenter: 'مركز الأوامر', + appearance: 'المظهر', + settings: 'الإعدادات', + changeTheme: 'تغيير الثيم', + changeColorMode: 'تغيير نمط الألوان', + pets: { + title: 'الحيوانات الأليفة', + placeholder: 'البحث في الحيوانات الأليفة...', + loading: 'جار تحميل معرض petdex...', + error: 'تعذّر الوصول إلى معرض petdex.', + staleBackend: 'أعد تشغيل Hermes لاستخدام الحيوانات الأليفة — الخادم الخلفي أقدم من هذه الميزة.', + empty: 'لا توجد حيوانات أليفة مطابقة.', + turnOff: 'إيقاف التشغيل', + turnOn: 'تشغيل', + installed: 'مثبّت', + generatedTag: 'مُولّد', + adoptFailed: 'تعذّر تبنّي ذلك الحيوان الأليف.', + toggleFailed: 'تعذّر تبديل الحيوان الأليف.', + noneAvailable: 'لا توجد حيوانات أليفة متاحة — اختر واحدا أدناه لتثبيته.' + }, + generatePet: { + title: 'توليد حيوان أليف', + placeholder: 'صف حيوانا أليفا لتوليده...', + promptHint: 'اكتب وصفا، ثم اضغط Enter لرسم أربعة مظاهر.', + readyHint: 'اضغط Enter لرسم أربعة مظاهر من وصفك.', + generate: 'توليد', + generating: 'جار التوليد...', + retry: 'إعادة المحاولة', + hatch: 'تفقيس', + spawning: 'جار الإنشاء...', + hatching: 'جار تفقيس حيوانك الأليف...', + hatchingSub: 'جار بثّ الحياة فيه...', + hatched: 'تم التفقيس!', + hatchRow: (_state, done, total) => `جار رسم الإطار ${done} من ${total}...`, + hatchComposing: 'جار تجميع الأجزاء...', + hatchSaving: 'أوشكنا على الانتهاء...', + namePlaceholder: 'سمِّ حيوانك الأليف', + staleBackend: 'حدّث Hermes لتوليد الحيوانات الأليفة.', + backgroundHint: 'يمكنك إغلاق هذا — سيُعلِمك Hermes عند الانتهاء.', + slowProviderHint: 'قد يستغرق هذا عدة دقائق', + remix: 'إعادة مزج', + remixConfirmTitle: 'إعادة مزج هذا المظهر؟', + remixConfirmBody: 'يولّد هذا مجموعة جديدة من المسوّدات باستخدام هذا كنقطة بداية. قد يستغرق عدة دقائق.', + genericError: 'فشل التوليد — حاول مجددا أو اختر اقتراحا.', + referenceImageTooLarge: 'صورة المرجع كبيرة جدا. استخدم واحدة أقل من 16 MB.', + referenceImageInvalid: 'تعذّرت قراءة صورة المرجع تلك. جرّب PNG أو JPG أو WebP أو GIF.', + adopt: 'تبنّي', + startOver: 'البدء من جديد' + }, + installTheme: { + title: 'تثبيت سمة...', + placeholder: 'البحث في VS Code Marketplace...', + loading: 'جار البحث في Marketplace...', + error: 'تعذّر الوصول إلى Marketplace.', + empty: 'لا توجد سمات مطابقة.', + install: 'تثبيت', + installing: 'جار التثبيت...', + installed: 'مثبّت', + installs: count => `${count} عملية تثبيت` + }, + settingsFields: 'حقول الإعدادات', + mcpServers: 'خوادم MCP', + archivedChats: 'المحادثات المؤرشفة', + commands: 'الأوامر', + sections: { + sessions: 'الجلسات', + system: 'النظام', + usage: 'الاستخدام' + }, + sectionDescriptions: { + sessions: 'البحث في الجلسات وإدارتها', + system: 'الحالة والسجلات وإجراءات النظام', + usage: 'نشاط الرموز والتكلفة والمهارات عبر الزمن' + }, + nav: { + newChat: { + title: 'جلسة جديدة', + detail: 'بدء جلسة جديدة' + }, + settings: { + title: 'الإعدادات', + detail: 'تكوين Hermes desktop' + }, + skills: { + title: 'المهارات والأدوات', + detail: 'تفعيل المهارات ومجموعات الأدوات والمزوّدين' + }, + messaging: { + title: 'المراسلة', + detail: 'إعداد Telegram وSlack وDiscord والمزيد' + }, + artifacts: { + title: 'العناصر', + detail: 'استعراض المخرجات المولّدة' + } + }, + sectionEntries: { + sessions: { + title: 'لوحة الجلسات', + detail: 'البحث في الجلسات وتثبيتها وإدارتها' + }, + system: { + title: 'لوحة النظام', + detail: 'حالة البوابة والسجلات وإعادة التشغيل/التحديث' + }, + usage: { + title: 'لوحة الاستخدام', + detail: 'نشاط الرموز والتكلفة والمهارات' + } + }, + providerNavigate: 'فتح المزود', + providerSessions: 'جلسات المزود', + refresh: 'تحديث', + refreshing: 'جار التحديث...', + noResults: 'لا توجد نتائج', + pinSession: 'تثبيت الجلسة', + unpinSession: 'إلغاء تثبيت الجلسة', + exportSession: 'تصدير الجلسة', + deleteSession: 'حذف الجلسة', + noSessions: 'لا توجد جلسات', + gatewayRunning: 'البوابة تعمل', + gatewayStopped: 'البوابة متوقفة', + hermesActiveSessions: (version, count) => `Hermes ${version} لديه ${count} جلسة نشطة`, + restartGateway: 'إعادة تشغيل البوابة', + gatewayRestartFailed: 'فشل إعادة تشغيل البوابة.', + updateHermes: 'تحديث Hermes', + actionRunning: 'الإجراء قيد التشغيل', + actionDone: 'اكتمل الإجراء', + actionFailed: 'فشل الإجراء', + actionStartedWaiting: 'بدأ الإجراء، جار الانتظار...', + loadingStatus: 'جار تحميل الحالة', + recentLogs: 'السجلات الأخيرة', + noLogs: 'لا توجد سجلات', + days: count => `${count} يوم`, + statSessions: 'الجلسات', + statApiCalls: 'نداءات API', + statTokens: 'الرموز', + statCost: 'التكلفة', + actualCost: cost => `التكلفة الفعلية ${cost}`, + loadingUsage: 'جار تحميل الاستخدام', + noUsage: period => `لا يوجد استخدام خلال ${period} يوم`, + retry: 'إعادة المحاولة', + dailyTokens: 'الرموز اليومية', + input: 'إدخال', + output: 'إخراج', + noDailyActivity: 'لا يوجد نشاط يومي', + topModels: 'أكثر النماذج استخداما', + noModelUsage: 'لا يوجد استخدام نماذج', + topSkills: 'أكثر المهارات استخداما', + noSkillActivity: 'لا يوجد نشاط مهارات', + actions: count => `${count} إجراء` + }, + messaging: { + search: 'بحث', + loading: 'جار التحميل...', + loadFailed: 'فشل التحميل', + states: { + connected: 'متصل', + connecting: 'جار الاتصال', + disabled: 'معطّل', + fatal: 'خطأ', + gateway_stopped: 'تم إيقاف بوابة المراسلة', + not_configured: 'يحتاج إعدادا', + pending_restart: 'يلزم إعادة التشغيل', + retrying: 'جار إعادة المحاولة', + startup_failed: 'فشل بدء التشغيل' + }, + unknown: 'غير معروف', + hintPendingRestart: 'تحتاج إعادة تشغيل لتطبيق التغييرات.', + hintGatewayStopped: 'البوابة متوقفة.', + credentialsSet: 'بيانات الاعتماد مضبوطة', + needsSetup: 'يحتاج إعدادا', + gatewayStopped: 'البوابة متوقفة', + getCredentials: 'الحصول على بيانات الاعتماد', + openSetupGuide: 'فتح دليل الإعداد', + required: 'مطلوب', + recommended: 'موصى به', + advanced: count => `${count} إعدادات متقدمة`, + noTokenNeeded: 'لا يحتاج رمز', + enabled: 'مفعل', + disabled: 'معطل', + unsavedChanges: 'تغييرات غير محفوظة', + saving: 'جار الحفظ...', + saveChanges: 'حفظ التغييرات', + saved: 'تم الحفظ', + replaceValue: 'استبدال القيمة', + openDocs: 'فتح الوثائق', + clearField: key => `مسح ${key}`, + enableAria: name => `تفعيل ${name}`, + disableAria: name => `تعطيل ${name}`, + platformEnabled: name => `تم تفعيل ${name}`, + platformDisabled: name => `تم تعطيل ${name}`, + restartToApply: 'أعد التشغيل لتطبيق التغييرات.', + setupSaved: name => `تم حفظ إعداد ${name}`, + restartToReconnect: 'أعد التشغيل لإعادة الاتصال.', + keyCleared: key => `تم مسح ${key}`, + setupUpdated: name => `تم تحديث إعداد ${name}`, + failedUpdate: name => `فشل تحديث ${name}`, + failedSave: name => `فشل حفظ ${name}`, + failedClear: key => `فشل مسح ${key}`, + fieldCopy: { + TELEGRAM_BOT_TOKEN: { + label: 'رمز البوت (token)', + help: 'أنشئ بوتا عبر @BotFather، ثم الصق الرمز الذي يمنحك إياه.', + placeholder: 'الصق رمز بوت Telegram' + }, + TELEGRAM_ALLOWED_USERS: { + label: 'معرّفات مستخدمي Telegram المسموح بهم', + help: 'موصى به. معرّفات رقمية مفصولة بفواصل من @userinfobot. بدون ذلك، يمكن لأي شخص مراسلة بوتك مباشرة.' + }, + TELEGRAM_PROXY: { + label: 'رابط الـ Proxy', + help: 'مطلوب فقط على الشبكات التي يكون فيها Telegram محجوبا.' + }, + DISCORD_BOT_TOKEN: { + label: 'رمز البوت (token)', + help: 'أنشئ تطبيقا في Discord Developer Portal، وأضف بوتا، ثم الصق رمزه.' + }, + DISCORD_ALLOWED_USERS: { + label: 'معرّفات مستخدمي Discord المسموح بهم', + help: 'موصى به. معرّفات مستخدمي Discord مفصولة بفواصل.' + }, + DISCORD_REPLY_TO_MODE: { + label: 'نمط الرد', + help: 'first أو all أو off.' + }, + DISCORD_ALLOW_ALL_USERS: { + label: 'السماح لكل مستخدمي Discord', + help: 'للتطوير فقط. عند التفعيل، يمكن لأي شخص مراسلة البوت مباشرة دون قائمة سماح.' + }, + DISCORD_HOME_CHANNEL: { + label: 'معرّف القناة الرئيسية', + help: 'القناة التي يرسل فيها البوت الرسائل الاستباقية (مخرجات cron، التذكيرات).' + }, + DISCORD_HOME_CHANNEL_NAME: { + label: 'اسم القناة الرئيسية', + help: 'الاسم المعروض للقناة الرئيسية في السجلات ومخرجات الحالة.' + }, + BLUEBUBBLES_ALLOW_ALL_USERS: { + label: 'السماح لكل مستخدمي iMessage', + help: 'عند التفعيل، يتم تخطي قائمة سماح BlueBubbles.' + }, + MATTERMOST_ALLOW_ALL_USERS: { + label: 'السماح لكل مستخدمي Mattermost' + }, + MATTERMOST_HOME_CHANNEL: { + label: 'القناة الرئيسية' + }, + QQ_ALLOW_ALL_USERS: { + label: 'السماح لكل مستخدمي QQ' + }, + QQBOT_HOME_CHANNEL: { + label: 'قناة QQ الرئيسية', + help: 'القناة أو المجموعة الافتراضية لتسليم cron.' + }, + QQBOT_HOME_CHANNEL_NAME: { + label: 'اسم قناة QQ الرئيسية' + }, + SLACK_BOT_TOKEN: { + label: 'رمز بوت Slack', + help: 'استخدم رمز البوت من OAuth & Permissions بعد تثبيت تطبيق Slack الخاص بك.', + placeholder: 'الصق رمز بوت Slack' + }, + SLACK_APP_TOKEN: { + label: 'رمز تطبيق Slack', + help: 'استخدم الرمز على مستوى التطبيق المطلوب لـ Socket Mode.', + placeholder: 'الصق رمز تطبيق Slack' + }, + SLACK_ALLOWED_USERS: { + label: 'معرّفات مستخدمي Slack المسموح بهم', + help: 'موصى به. معرّفات مستخدمي Slack مفصولة بفواصل.' + }, + MATTERMOST_URL: { + label: 'رابط الخادم', + placeholder: 'https://mattermost.example.com' + }, + MATTERMOST_TOKEN: { + label: 'رمز البوت (token)' + }, + MATTERMOST_ALLOWED_USERS: { + label: 'معرّفات المستخدمين المسموح بهم', + help: 'موصى به. معرّفات مستخدمي Mattermost مفصولة بفواصل.' + }, + MATRIX_HOMESERVER: { + label: 'رابط Homeserver', + placeholder: 'https://matrix.org' + }, + MATRIX_ACCESS_TOKEN: { + label: 'رمز الوصول' + }, + MATRIX_USER_ID: { + label: 'معرّف مستخدم البوت', + placeholder: '@hermes:example.org' + }, + MATRIX_ALLOWED_USERS: { + label: 'معرّفات مستخدمي Matrix المسموح بهم', + help: 'موصى به. معرّفات مستخدمين مفصولة بفواصل بصيغة @user:server.' + }, + SIGNAL_HTTP_URL: { + label: 'رابط جسر Signal', + placeholder: 'http://127.0.0.1:8080', + help: 'رابط جسر signal-cli REST قيد التشغيل.' + }, + SIGNAL_ACCOUNT: { + label: 'رقم الهاتف', + help: 'الرقم المسجّل مع جسر signal-cli الخاص بك.' + }, + SIGNAL_ALLOWED_USERS: { + label: 'مستخدمو Signal المسموح بهم', + help: 'موصى به. معرّفات Signal مفصولة بفواصل.' + }, + WHATSAPP_ENABLED: { + label: 'تفعيل جسر WhatsApp', + help: 'يُضبط تلقائيا عبر المفتاح أدناه. اتركه دون تغيير ما لم تكن متأكدا من حاجتك إليه.' + }, + WHATSAPP_MODE: { + label: 'وضع الجسر' + }, + WHATSAPP_ALLOWED_USERS: { + label: 'مستخدمو WhatsApp المسموح بهم', + help: 'موصى به. أرقام هواتف أو معرّفات WhatsApp مفصولة بفواصل.' + } + }, + platformIntro: {} + }, + profiles: { + close: 'إغلاق', + nameHint: 'اسم الملف الشخصي', + title: 'الملفات الشخصية', + count: count => `${count} ملف شخصي`, + loading: 'جار التحميل...', + newProfile: 'ملف شخصي جديد', + allProfiles: 'كل الملفات الشخصية', + showAllProfiles: 'إظهار كل الملفات الشخصية', + switchToProfile: name => `التبديل إلى ${name}`, + manageProfiles: 'إدارة الملفات الشخصية', + actionsFor: name => `إجراءات ${name}`, + color: 'اللون', + colorFor: name => `لون ${name}`, + setColor: color => `ضبط اللون ${color}`, + autoColor: 'لون تلقائي', + noProfiles: 'لا توجد ملفات شخصية', + selectPrompt: 'اختر ملفا شخصيا', + refresh: 'تحديث', + refreshing: 'جار التحديث...', + default: 'الافتراضي', + skills: count => `${count} مهارة`, + env: 'البيئة', + defaultBadge: 'افتراضي', + rename: 'إعادة تسمية', + copySetup: 'نسخ الإعداد', + copying: 'جار النسخ...', + modelLabel: 'النموذج', + skillsLabel: 'المهارات', + notSet: 'غير مضبوط', + soulDesc: 'الموجّه (prompt) النظامي وتعليمات الشخصية المضمّنة في هذا الملف الشخصي.', + soulOptional: 'اختياري', + soulPlaceholder: mode => + `الموجّه (prompt) النظامي / الشخصية لهذا الملف الشخصي.\nاتركه فارغا للإبقاء على افتراضي ${mode}.`, + soulPlaceholderCloned: 'مستنسخ', + soulPlaceholderEmpty: 'فارغ', + unsavedChanges: 'تغييرات غير محفوظة', + loadingSoul: 'جار تحميل SOUL.md...', + emptySoul: 'SOUL.md فارغ — ابدأ بكتابة الشخصية...', + saving: 'جار الحفظ...', + saveSoul: 'حفظ التعليمات', + deleteTitle: 'حذف الملف الشخصي', + deleteDescPrefix: 'سيؤدي هذا إلى حذف ', + deleteDescMid: ' وإزالة ', + deleteDescSuffix: ' الخاص به. لا يمكن التراجع عن هذا.', + deleting: 'جار الحذف...', + createDesc: 'أنشئ ملفا شخصيا بإعدادات منفصلة.', + nameLabel: 'الاسم', + cloneFrom: 'استنساخ من', + cloneFromNone: 'لا شيء (فارغ)', + cloneFromDesc: 'ينسخ الإعدادات والمهارات وSOUL.md من الملف الشخصي المصدر المحدد.', + cloneFromDefault: 'نسخ إعداد الافتراضي', + cloneFromDefaultDesc: 'ابدأ من إعدادات الملف الافتراضي.', + invalidName: hint => `اسم غير صالح: ${hint}`, + nameRequired: 'الاسم مطلوب', + creating: 'جار الإنشاء...', + createAction: 'إنشاء ملف شخصي', + renameTitle: 'إعادة تسمية الملف الشخصي', + renameDescPrefix: 'تؤدي إعادة التسمية إلى تحديث دليل الملف الشخصي وأي سكربتات تغليف في ', + renameDescSuffix: '.', + newNameLabel: 'الاسم الجديد', + renaming: 'جار إعادة التسمية...', + created: 'تم إنشاء الملف الشخصي', + renamed: 'تمت إعادة التسمية', + deleted: 'تم الحذف', + setupCopied: 'تم نسخ الإعداد', + soulSaved: 'تم حفظ التعليمات', + failedLoad: 'فشل تحميل الملفات الشخصية', + failedDelete: 'فشل الحذف', + failedCopy: 'فشل النسخ', + failedLoadSoul: 'فشل تحميل التعليمات', + failedSaveSoul: 'فشل حفظ التعليمات', + failedCreate: 'فشل الإنشاء', + failedRename: 'فشل إعادة التسمية' + }, + cron: { + close: 'إغلاق', + search: 'بحث', + loading: 'جار التحميل...', + states: { + enabled: 'مُفعّل', + scheduled: 'مجدول', + running: 'قيد التشغيل', + paused: 'متوقف مؤقتا', + disabled: 'معطّل', + error: 'خطأ', + completed: 'مكتمل' + }, + deliveryLabels: { + local: 'سطح المكتب هذا', + telegram: 'Telegram', + discord: 'Discord', + slack: 'Slack', + email: 'البريد الإلكتروني' + }, + scheduleLabels: { + daily: 'يوميا', + weekdays: 'أيام الأسبوع', + weekly: 'أسبوعيا', + monthly: 'شهريا', + hourly: 'كل ساعة', + 'every-15-minutes': 'كل 15 دقيقة', + custom: 'مخصص' + }, + scheduleHints: { + daily: 'كل يوم في الساعة 9:00 صباحا', + weekdays: 'من الاثنين إلى الجمعة في الساعة 9:00 صباحا', + weekly: 'كل اثنين في الساعة 9:00 صباحا', + monthly: 'أول يوم من كل شهر في الساعة 9:00 صباحا', + hourly: 'في بداية كل ساعة', + 'every-15-minutes': 'كل 15 دقيقة', + custom: 'صياغة cron أو لغة طبيعية' + }, + days: { + '0': 'الأحد', + '1': 'الاثنين', + '2': 'الثلاثاء', + '3': 'الأربعاء', + '4': 'الخميس', + '5': 'الجمعة', + '6': 'السبت', + '7': 'الأحد' + }, + dayFallback: value => `اليوم ${value}`, + everyDayAt: time => `كل يوم في ${time}`, + weekdaysAt: time => `أيام الأسبوع في ${time}`, + everyDayOfWeekAt: (day, time) => `كل ${day} في ${time}`, + monthlyOnDayAt: (dayOfMonth, time) => `شهريا في اليوم ${dayOfMonth} في ${time}`, + topOfHour: 'في بداية كل ساعة', + everyHourAt: minute => `كل ساعة عند :${minute}`, + newCron: 'مهمة مجدولة جديدة', + emptyDescNew: 'أنشئ مهمة مجدولة لتشغيل Hermes تلقائيا.', + emptyDescSearch: 'لا توجد مهام تطابق البحث.', + emptyTitleNew: 'لا توجد مهام مجدولة', + emptyTitleSearch: 'لا توجد نتائج', + last: 'آخر تشغيل', + next: 'التالي', + noRuns: 'لا توجد تشغيلات', + manage: 'إدارة', + showRuns: 'إظهار التشغيلات', + hideRuns: 'إخفاء التشغيلات', + runHistory: 'سجل التشغيل', + actionsFor: title => `إجراءات ${title}`, + actionsTitle: 'الإجراءات', + resume: 'استئناف', + pause: 'إيقاف مؤقت', + resumeTitle: 'استئناف المهمة', + pauseTitle: 'إيقاف المهمة مؤقتا', + triggerNow: 'تشغيل الآن', + edit: 'تحرير', + deleteTitle: 'حذف المهمة', + deleteDescPrefix: 'سيؤدي هذا إلى إزالة ', + deleteDescSuffix: ' نهائيا. سيتوقف عن العمل فورا.', + deleting: 'جار الحذف...', + resumed: 'تم الاستئناف', + paused: 'تم الإيقاف مؤقتا', + triggered: 'تم التشغيل', + deleted: 'تم الحذف', + created: 'تم الإنشاء', + updated: 'تم التحديث', + failedLoad: 'فشل تحميل المهام', + failedUpdate: 'فشل التحديث', + failedTrigger: 'فشل التشغيل', + failedDelete: 'فشل الحذف', + failedSave: 'فشل الحفظ', + editTitle: 'تحرير المهمة المجدولة', + createTitle: 'إنشاء مهمة مجدولة', + editDesc: 'عدل الجدول والرسالة.', + createDesc: 'اضبط مهمة يشغلها Hermes تلقائيا.', + nameLabel: 'الاسم', + namePlaceholder: 'مثال: الملخص الصباحي', + promptLabel: 'الرسالة', + promptPlaceholder: 'ماذا تريد من Hermes أن يفعل؟', + frequencyLabel: 'التكرار', + deliverLabel: 'التسليم', + customScheduleLabel: 'جدول مخصص', + customPlaceholder: 'تعبير cron', + customHint: 'استخدم صيغة cron القياسية.', + optional: 'اختياري', + promptScheduleRequired: 'الرسالة والجدول مطلوبان', + saveChanges: 'حفظ التغييرات', + createAction: 'إنشاء' + }, + artifacts: { + search: 'بحث', + refresh: 'تحديث', + refreshing: 'جار التحديث...', + indexing: 'جار الفهرسة...', + tabAll: 'الكل', + tabImages: 'الصور', + tabFiles: 'الملفات', + tabLinks: 'الروابط', + noArtifactsTitle: 'لا توجد عناصر', + noArtifactsDesc: 'ستظهر الصور والملفات والروابط من محادثاتك هنا.', + failedLoad: 'فشل تحميل العناصر', + openFailed: 'فشل الفتح', + itemsImage: 'صور', + itemsLink: 'روابط', + itemsFile: 'ملفات', + itemsGeneric: 'عناصر', + zero: 'صفر', + rangeOf: (start, end, total) => `${start}-${end} من ${total}`, + goToPage: (itemLabel, page) => `الانتقال إلى صفحة ${page} من ${itemLabel}`, + colTitleLink: 'الرابط', + colTitleFile: 'الملف', + colTitleDefault: 'العنوان', + colLocationLink: 'الموقع', + colLocationFile: 'الموقع', + colLocationDefault: 'الموقع', + colSession: 'الجلسة', + kindImage: 'صورة', + kindFile: 'ملف', + kindLink: 'رابط', + chat: 'المحادثة', + copyUrl: 'نسخ الرابط', + copyPath: 'نسخ المسار' + }, + sidebar: { + nav: { + 'new-session': 'جلسة جديدة', + skills: 'المهارات', + messaging: 'المراسلة', + artifacts: 'العناصر', + chat: 'المحادثة', + settings: 'الإعدادات', + cron: 'المهام المجدولة', + agents: 'الوكلاء' + }, + searchAria: 'البحث في الجلسات', + searchPlaceholder: 'البحث في الجلسات...', + clearSearch: 'مسح البحث', + noMatch: query => `لا توجد جلسات تطابق "${query}"`, + results: 'النتائج', + pinned: 'المثبتة', + sessions: 'الجلسات', + cronJobs: 'المهام المجدولة', + groupAriaGrouped: 'الجلسات مجمعة حسب مساحة العمل', + groupAriaUngrouped: 'الجلسات غير مجمعة', + showProjects: 'عرض المشاريع', + showSessions: 'عرض الجلسات', + groupTitleGrouped: 'مجمعة حسب مساحة العمل', + groupTitleUngrouped: 'كل الجلسات', + allPinned: 'كل الجلسات مثبتة', + shiftClickHint: 'استخدم Shift للتحديد المتعدد', + noWorkspace: 'بدون مساحة عمل', + noProject: 'لا يوجد مشروع', + projectEmpty: 'لا توجد جلسات بعد', + noSessions: 'لا توجد جلسات بعد', + projects: { + sectionLabel: 'المشاريع', + newButton: 'مشروع جديد', + createTitle: 'مشروع جديد', + createDesc: 'سمِّ مساحة العمل وأضف مجلدا أو أكثر.', + renameTitle: 'إعادة تسمية المشروع', + addFolderTitle: 'إضافة مجلد', + namePlaceholder: 'مثال: Skunkworks', + foldersLabel: 'المجلدات', + ideaLabel: 'الفكرة', + ideaPlaceholder: 'ما موضوع هذا المشروع؟ (يُحفظ في IDEA.md)', + ideaGenerate: 'توليد فكرة', + ideaGenerating: 'جار التوليد...', + ideaShuffle: 'خلط القوالب', + noFolders: 'لم تتم إضافة أي مجلدات بعد.', + addFolder: 'إضافة مجلد', + primaryBadge: 'أساسي', + removeFolder: 'إزالة', + create: 'إنشاء', + menu: 'إجراءات المشروع', + menuRename: 'إعادة تسمية', + menuAppearance: 'المظهر', + noColor: 'بلا لون', + menuAddFolder: 'إضافة مجلد', + menuSetActive: 'تعيين كنشط', + menuDelete: 'حذف', + reveal: 'إظهار في المجلد', + copyPath: 'نسخ المسار', + removeFromSidebar: 'إخفاء من الشريط الجانبي', + createFailed: 'تعذّر إنشاء المشروع', + deleteConfirm: 'هذا يزيل المشروع المحفوظ من Hermes. تبقى الملفات ومستودعات git وأشجار العمل دون تغيير.', + startWork: 'شجرة عمل جديدة', + newWorktreeTitle: 'شجرة عمل جديدة', + newWorktreeDesc: 'سمِّ الفرع لشجرة العمل هذه.', + branchPlaceholder: 'مثال: my-feature', + startWorkFailed: 'تعذّر إنشاء شجرة العمل', + convertBranch: 'تحويل فرع...', + convertBranchTitle: 'تحويل فرع', + convertBranchDesc: 'افتح الفروع المسحوبة، أو أنشئ شجرة عمل لفرع حر.', + convertBranchPlaceholder: 'البحث في الفروع...', + convertBranchInstead: 'تحويل فرع موجود', + branchOpenExisting: 'فتح', + branchSwitchHome: 'تبديل الموطن', + branchCreateWorktree: 'شجرة عمل جديدة', + branchesLoading: 'جار تحميل الفروع...', + noBranches: 'لم يتم العثور على فروع', + removeWorktree: 'إزالة شجرة العمل', + removeWorktreeFailed: 'تعذّر إزالة شجرة العمل (تغييرات غير مُودعة؟)', + removeWorktreeConfirm: + 'أزِلها من git (يحذف مجلد شجرة العمل؛ يبقى الفرع)، أو فقط أخفِ المسار من الشريط الجانبي واترك شجرة العمل على القرص.', + removeWorktreeDirty: + 'تحتوي شجرة العمل هذه على تغييرات غير مُودعة. أزِلها بالقوة (يتجاهل تلك التغييرات)، أو فقط أخفِ المسار واحتفظ بها على القرص.', + forceRemove: 'إزالة بالقوة', + enter: label => `فتح ${label}`, + reorder: label => `إعادة ترتيب ${label}`, + toggle: label => `تبديل جلسات ${label}`, + back: 'كل المشاريع' + }, + newSessionIn: label => `جلسة جديدة في ${label}`, + showMoreIn: (count, label) => `إظهار ${count} أخرى في ${label}`, + loading: 'جار التحميل...', + loadMore: 'تحميل المزيد', + loadCount: step => `تحميل ${step} أخرى`, + row: { + pin: 'تثبيت', + unpin: 'إلغاء التثبيت', + copyId: 'نسخ المعرف', + export: 'تصدير', + branchFrom: 'فرع', + rename: 'إعادة تسمية', + archive: 'أرشفة', + newWindow: 'فتح في نافذة جديدة', + copyIdFailed: 'فشل نسخ المعرف', + actionsFor: title => `إجراءات ${title}`, + sessionActions: 'إجراءات الجلسة', + sessionRunning: 'الجلسة تعمل', + needsInput: 'تحتاج إدخالا', + waitingForAnswer: 'بانتظار إجابة', + backgroundRunning: 'تعمل في الخلفية', + finishedUnread: 'اكتملت وفيها جديد', + hideTabBar: 'إخفاء شريط التبويبات', + openInNewTab: 'فتح في تبويب جديد', + openInSplit: 'فتح في تقسيم', + ownedByProfile: profile => `مملوكة للملف الشخصي ${profile}`, + untitledChat: id => `محادثة ${id}`, + handoffOrigin: platform => `قادمة من ${platform}`, + renamed: 'تمت إعادة التسمية', + renameFailed: 'فشلت إعادة التسمية', + renameTitle: 'إعادة تسمية الجلسة', + renameDesc: 'اختر اسما جديدا لهذه الجلسة.', + untitledPlaceholder: 'جلسة بلا عنوان', + ageNow: 'الآن', + ageDay: 'يوم', + ageHour: 'ساعة', + ageMin: 'دقيقة' + } + }, + composer: { + message: 'الرسالة', + wakingProfile: profile => `جار إيقاظ ${profile}`, + placeholderStarting: 'جار بدء Hermes...', + placeholderReconnecting: 'جار إعادة الاتصال...', + placeholderFollowUp: 'اكتب متابعة...', + newSessionPlaceholders: ['اسأل Hermes عن شيء...', 'اطلب من Hermes تنفيذ مهمة...', 'ابدأ محادثة جديدة...'], + followUpPlaceholders: ['اكتب متابعة...', 'أضف توجيها...', 'اسأل سؤالا آخر...'], + startVoice: 'بدء الصوت', + queueMessage: 'إضافة الرسالة للطابور', + steer: 'توجيه', + stop: 'إيقاف', + send: 'إرسال', + speaking: 'يتحدث', + transcribing: 'جار التفريغ', + thinking: 'يفكر', + muted: 'مكتوم', + listening: 'يستمع', + muteMic: 'كتم الميكروفون', + unmuteMic: 'إلغاء كتم الميكروفون', + stopListening: 'إيقاف الاستماع', + stopShort: 'إيقاف', + endConversation: 'إنهاء المحادثة', + endShort: 'إنهاء', + stopDictation: 'إيقاف الإملاء', + transcribingDictation: 'جار تفريغ الإملاء', + voiceDictation: 'إملاء صوتي', + lookupLoading: 'جار البحث...', + lookupNoMatches: 'لا توجد نتائج', + lookupTry: 'جرب', + lookupOr: 'أو', + commonCommands: 'الأوامر الشائعة', + hotkeys: 'الاختصارات', + helpFooter: 'استخدم الأسهم للتنقل و Enter للاختيار.', + commandDescs: { + '/help': 'قائمة كاملة بالأوامر + اختصارات لوحة المفاتيح', + '/clear': 'بدء جلسة جديدة', + '/resume': 'استئناف جلسة سابقة', + '/details': 'التحكم في مستوى تفاصيل النص', + '/copy': 'نسخ التحديد أو آخر رسالة من المساعد', + '/quit': 'الخروج من hermes' + }, + hotkeyDescs: { + 'composer.mention': 'الإشارة إلى الملفات والمجلدات والروابط وgit', + 'composer.slash': 'لوحة أوامر الشرطة المائلة', + 'composer.help': 'هذه المساعدة السريعة (احذف للإخفاء)', + 'composer.sendNewline': 'إرسال · Shift+Enter لسطر جديد', + 'composer.sendQueued': 'إرسال الدور التالي في قائمة الانتظار', + 'keybinds.openPanel': 'كل اختصارات لوحة المفاتيح', + 'composer.cancel': 'إغلاق النافذة المنبثقة · إلغاء التشغيل', + 'composer.history': 'التنقل في النافذة المنبثقة / السجل' + }, + attachUrlTitle: 'إرفاق رابط', + attachUrlDesc: 'أضف رابطا إلى الرسالة.', + urlPlaceholder: 'https://example.com', + urlHintPre: 'سيقرأ Hermes الرابط ضمن السياق.', + attach: 'إرفاق', + queued: count => `${count} في الطابور`, + attachmentOnly: 'إرفاق فقط', + emptyTurn: 'اكتب رسالة أو أرفق ملفا.', + attachments: count => `${count} مرفق`, + editingInComposer: 'جار التحرير في صندوق الكتابة', + editingQueuedInComposer: 'جار تحرير رسالة في الطابور', + queueEdit: 'تحرير الرسالة المجدولة', + queueSendNext: 'إرسالها تاليا', + queueSend: 'إرسالها الآن', + queueDelete: 'حذف من الطابور', + queueStuckTitle: 'لم تُرسل الرسالة في قائمة الانتظار', + queueStuckBody: 'ظل دور في قائمة الانتظار يفشل في الإرسال. ما زال في قائمة الانتظار — حاول إرساله مرة أخرى.', + previewUnavailable: 'المعاينة غير متاحة', + previewLabel: label => `معاينة ${label}`, + couldNotPreview: label => `تعذرت معاينة ${label}`, + removeAttachment: label => `إزالة ${label}`, + dictating: 'جار الإملاء', + preparingAudio: 'جار تجهيز الصوت', + speakingResponse: 'جار قراءة الرد', + readingAloud: 'جار القراءة بصوت عال', + themeSuggestions: 'اقتراحات سمات سطح المكتب', + noMatchingThemes: 'لا توجد سمات مطابقة.', + themeTryPre: 'جرّب ', + themeTryPost: '.', + attachLabel: 'إرفاق', + files: 'ملفات', + folder: 'مجلد', + images: 'صور', + pasteImage: 'لصق صورة', + url: 'رابط', + promptSnippets: 'مقتطفات جاهزة', + tipPre: 'نصيحة: اكتب ', + tipPost: ' للإشارة إلى الملفات ضمن النص.', + snippetsTitle: 'مقتطفات الموجّهات', + snippetsDesc: 'اختر موجّهًا أوليًا لإدراجه في المحرّر.', + dropFiles: 'أفلت الملفات للإرفاق', + dropSession: 'أفلت الجلسة للفتح', + snippets: { + codeReview: { + label: 'مراجعة الكود', + description: 'دقّق التغيير الحالي بحثًا عن الانحدارات والحالات الطرفية المُسقطة والاختبارات المفقودة.', + text: 'يرجى مراجعة هذا بحثًا عن الأخطاء والانحدارات والاختبارات المفقودة.' + }, + implementationPlan: { + label: 'خطة التنفيذ', + description: 'حدّد نهجًا قبل لمس الكود حتى يبقى الفرق مركّزًا.', + text: 'يرجى وضع خطة تنفيذ موجزة قبل تغيير الكود.' + }, + explainThis: { + label: 'اشرح هذا', + description: 'اشرح كيفية عمل الكود المحدد واربطه بالملفات الرئيسية.', + text: 'يرجى شرح كيفية عمل هذا وإرشادي إلى الملفات الرئيسية.' + } + } + }, + statusStack: { + agents: 'الوكلاء', + background: count => `${count} في الخلفية`, + subagents: count => `${count} ${count === 1 ? 'وكيل فرعي' : 'وكيل فرعي'}`, + todos: (done, total) => `المهام ${done}/${total}`, + running: 'قيد التشغيل', + stop: 'إيقاف', + dismiss: 'تجاهل', + exit: code => `خروج ${code}`, + coding: { + title: 'شجرة العمل', + noBranch: 'لا يوجد فرع', + detached: 'منفصل', + clean: 'نظيف', + changed: count => `${count} مُغيَّر`, + ahead: count => `${count} متقدم`, + behind: count => `${count} متأخر`, + review: 'مراجعة', + close: 'إغلاق', + openChanges: 'فتح التغييرات', + openFile: 'فتح الملف', + stage: 'إدراج', + unstage: 'إلغاء الإدراج', + stageAll: 'إدراج الكل', + viewAsTree: 'عرض كشجرة', + viewAsList: 'عرض كقائمة', + revert: 'تراجع', + revertAll: 'التراجع عن الكل', + revertConfirm: 'هل تريد تجاهل التغييرات على هذا الملف واستعادته إلى الحالة المُودعة؟ لا يمكن التراجع عن هذا.', + revertAllConfirm: 'هل تريد تجاهل كل التغييرات واستعادة الملفات إلى الحالة المُودعة؟ لا يمكن التراجع عن هذا.', + staged: 'مُدرَج', + noChanges: 'لا توجد تغييرات', + notRepo: 'ليس مستودع git', + noDiff: 'لا يوجد فرق لعرضه', + scopeUncommitted: 'غير مُودَع', + scopeBranch: 'فرع', + scopeLastTurn: 'آخر دور', + commit: 'إيداع', + commitAndPush: 'إيداع ودفع', + commitPlaceholder: 'رسالة (⌘↵ للإيداع)', + generateCommitMessage: 'توليد رسالة الإيداع', + stopGenerating: 'إيقاف التوليد', + createPr: 'إنشاء PR', + openPr: 'فتح PR', + ghMissing: 'ثبّت GitHub CLI (gh) وسجّل الدخول لفتح طلبات السحب', + agentShip: 'اطلب من Hermes فتح PR', + agentShipPrompt: 'راجع التغييرات الحالية، وأودعها برسالة إيداع تقليدية واضحة، وادفع الفرع، وافتح طلب سحب.', + newBranch: 'فرع جديد', + branchOffFrom: base => `فرع جديد من ${base}`, + switchTo: branch => `التبديل إلى ${branch}`, + switchFailed: branch => `تعذّر التبديل إلى ${branch}`, + worktrees: 'أشجار العمل' + } + }, + updates: { + stages: { + idle: 'جار التحضير...', + prepare: 'جار التحضير...', + fetch: 'جار التنزيل...', + pull: 'أوشكنا على الانتهاء...', + pydeps: 'جار الإنهاء...', + update: 'جار تحديث Hermes...', + rebuild: 'جار إعادة بناء تطبيق سطح المكتب...', + restart: 'جار إعادة تشغيل Hermes...', + done: 'اكتمل التحديث', + manual: 'التحديث من الطرفية', + guiSkew: 'تحديث تطبيق سطح المكتب', + error: 'تم إيقاف التحديث مؤقتا' + }, + checking: 'جار البحث عن تحديثات...', + checkFailedTitle: 'تعذّر التحقق من التحديثات', + tryAgain: 'إعادة المحاولة', + notAvailableTitle: 'التحديث غير متاح', + unsupportedMessage: 'لا يمكن لهذا الإصدار من Hermes تحديث نفسه من داخل التطبيق.', + connectionRetry: 'تحقق من اتصالك وأعد المحاولة.', + latestBody: 'أنت تستخدم أحدث إصدار.', + latestBodyBackend: 'الواجهة الخلفية تعمل بأحدث إصدار.', + allSetTitle: 'كل شيء جاهز', + availableTitle: 'يتوفر تحديث جديد', + availableBody: 'إصدار جديد من Hermes جاهز للتثبيت.', + availableTitleBackend: 'يتوفر تحديث للواجهة الخلفية', + availableBodyBackend: 'إصدار أحدث من واجهة Hermes الخلفية المتصلة جاهز للتثبيت.', + availableBodyNoChangelog: 'إصدار أحدث جاهز. ملاحظات الإصدار غير متاحة لنوع التثبيت هذا.', + updateNow: 'التحديث الآن', + maybeLater: 'ربما لاحقا', + moreChanges: count => `+ ${count} تغيير${count === 1 ? '' : 'ات'} إضافي مُضمَّن.`, + manualTitle: 'التحديث من الطرفية', + manualBody: 'لقد ثبّتت Hermes من سطر الأوامر، لذا تُجرى التحديثات من هناك أيضا. الصق هذا في طرفيتك:', + manualPickedUp: 'سيلتقط Hermes الإصدار الجديد في المرة التالية التي تشغّله فيها.', + guiSkewTitle: 'تحديث تطبيق سطح المكتب', + guiSkewBody: + 'تم تحديث الواجهة الخلفية، لكن حزمة تطبيق سطح المكتب هذه لم تتغير. حدّث أو أعد تثبيت تطبيق Hermes لسطح المكتب (ملف AppImage / ‎.deb / ‎.rpm) لمطابقته.', + copy: 'نسخ', + copied: 'تم النسخ', + done: 'تم', + applyingBody: + 'يتولّى مُحدِّث Hermes المهمة في نافذته الخاصة ويعيد فتح Hermes تلقائيا عند الانتهاء. الرجاء عدم إعادة فتح Hermes بنفسك أثناء التحديث.', + applyingBodyBackend: + 'تطبّق الواجهة الخلفية البعيدة التحديث وستعيد التشغيل. يعيد Hermes الاتصال تلقائيا عند عودتها.', + applyingClose: 'ستُغلق هذه النافذة أثناء تشغيل التحديث، ثم يعيد Hermes فتح نفسه تلقائيا.', + errorTitle: 'لم يكتمل التحديث', + errorBody: 'لا داعي للقلق — لم يُفقد شيء. يمكنك إعادة المحاولة الآن.', + notNow: 'ليس الآن', + applyStatus: { + preparing: 'جار تحديث الواجهة الخلفية...', + pulling: 'جار تحديث الواجهة الخلفية...', + restarting: 'تعيد الواجهة الخلفية التشغيل لتحميل التحديث...', + notAvailable: 'التحديث غير متاح لهذه الواجهة الخلفية.', + failed: 'فشل تحديث الواجهة الخلفية.', + noReturn: 'لم تعد الواجهة الخلفية إلى الاتصال. قد لا يكون التحديث قد اكتمل — تحقق من مضيف الواجهة الخلفية.' + } + }, + install: { + stageStates: { + pending: 'قيد الانتظار', + running: 'جار التثبيت', + succeeded: 'تم', + skipped: 'تم التخطي', + failed: 'فشل' + }, + oneTimeTitle: 'يحتاج Hermes إلى تثبيت لمرة واحدة', + unsupportedDesc: platform => + `التثبيت التلقائي عند أول تشغيل غير متاح على ${platform} بعد. افتح الطرفية وشغّل الأمر أدناه، ثم أعد تشغيل هذا التطبيق. ستتخطى عمليات التشغيل اللاحقة هذه الخطوة.`, + installCommand: 'أمر التثبيت', + copyCommand: 'نسخ الأمر', + viewDocs: 'عرض مستندات التثبيت', + installTo: 'سيتم التثبيت في', + retryAfterRun: 'لقد شغّلته -- إعادة المحاولة', + failedTitle: 'فشل التثبيت', + settingUpTitle: 'جار إعداد وكيل Hermes', + finishingTitle: 'جار الإنهاء', + failedDesc: + 'فشلت إحدى خطوات التثبيت. على Windows، قد يحدث هذا إذا كان هناك نسخة أخرى من Hermes CLI أو تطبيق سطح المكتب قيد التشغيل. أوقف أي نسخ Hermes قيد التشغيل، ثم أعد المحاولة. تحقق من التفاصيل أدناه أو من سجل سطح المكتب للحصول على النص الكامل.', + activeDesc: + 'هذا إعداد لمرة واحدة. يقوم مثبّت Hermes بتنزيل التبعيات وتهيئة جهازك. ستتخطى عمليات التشغيل اللاحقة هذه الخطوة.', + progress: (completed, total) => `اكتملت ${completed} من ${total} خطوة`, + currentStage: stage => ` -- الآن: ${stage}`, + fetchingManifest: 'جار جلب بيان المثبّت...', + error: 'خطأ', + hideOutput: 'إخفاء مخرجات المثبّت', + showOutput: 'إظهار مخرجات المثبّت', + lines: count => `${count} سطر`, + noOutput: 'لا توجد مخرجات بعد.', + cancelling: 'جار الإلغاء...', + cancelInstall: 'إلغاء التثبيت', + transcriptSaved: 'تم حفظ النص الكامل في', + copiedOutput: 'تم النسخ!', + copyOutput: 'نسخ المخرجات', + reloadRetry: 'إعادة التحميل وإعادة المحاولة' + }, + onboarding: { + headerTitle: 'لنُعِدّ لك Hermes Agent', + headerDesc: 'اربط مزوّد نماذج لبدء المحادثة. معظم الخيارات تتطلب نقرة واحدة.', + preparingInstall: 'يُكمل Hermes التثبيت. عادة ما يستغرق ذلك أقل من دقيقة في أول تشغيل.', + starting: 'جار بدء Hermes...', + lookingUpProviders: 'جار البحث عن المزوّدين...', + collapse: 'طي', + otherProviders: 'مزودون آخرون', + haveApiKey: 'لديك مفتاح API', + chooseLater: 'سأختار مزوّدا لاحقا', + recommended: 'موصى به', + connected: 'متصل', + featuredPitch: 'اشتراك واحد، أكثر من 300 نموذج متقدم — الطريقة الموصى بها لتشغيل Hermes', + fireworksPitch: 'نماذج مفتوحة سريعة مع استضافة Fireworks.', + openRouterPitch: 'مفتاح واحد لمئات النماذج — خيار افتراضي جيد', + apiKeyOptions: { + openrouter: { + short: 'مفتاح واحد، نماذج كثيرة', + description: 'يستضيف مئات النماذج خلف مفتاح واحد. خيار افتراضي جيد للتثبيتات الجديدة.' + }, + openai: { + short: 'نماذج من فئة GPT', + description: 'وصول مباشر إلى نماذج OpenAI.' + }, + gemini: { + short: 'نماذج Gemini', + description: 'وصول مباشر إلى نماذج Google Gemini.' + }, + xai: { + short: 'نماذج Grok', + description: 'وصول مباشر إلى نماذج xAI Grok.' + }, + local: { + short: 'مستضاف ذاتيا', + description: + 'وجّه Hermes إلى نقطة نهاية محلية أو مستضافة ذاتيا متوافقة مع OpenAI (vLLM، llama.cpp، Ollama، إلخ).' + } + }, + backToSignIn: 'العودة إلى تسجيل الدخول', + getKey: 'الحصول على مفتاح', + replaceCurrent: 'استبدال القيمة الحالية', + pasteApiKey: 'ألصق مفتاح API', + localApiKeyPlaceholder: 'مفتاح API (اختياري — فقط إذا كانت نقطة النهاية تتطلبه)', + couldNotSave: 'تعذر حفظ بيانات الاعتماد.', + connecting: 'جار الاتصال', + update: 'تحديث', + flowSubtitles: { + pkce: 'يفتح المتصفح لتسجيل الدخول ثم يتابع هنا', + device_code: 'يفتح صفحة تحقق في المتصفح — يتصل Hermes تلقائياً', + loopback: 'يفتح المتصفح لتسجيل الدخول — يتصل Hermes تلقائياً', + external: 'سجل الدخول مرة واحدة في الطرفية ثم عد إلى المحادثة' + }, + startingSignIn: provider => `جار بدء تسجيل الدخول لـ ${provider}...`, + verifyingCode: provider => `جار التحقق من الرمز عبر ${provider}...`, + connectedProvider: provider => `تم ربط ${provider}`, + connectedPicking: provider => `تم ربط ${provider}. جار اختيار نموذج افتراضي...`, + signInFailed: 'فشل تسجيل الدخول. حاول مرة أخرى.', + pickDifferentProvider: 'اختر مزوداً آخر', + signInWith: provider => `تسجيل الدخول عبر ${provider}`, + openedBrowser: provider => `فتحنا ${provider} في المتصفح.`, + authorizeThere: 'صرّح لـ Hermes هناك.', + copyAuthCode: 'انسخ رمز التفويض وألصقه أدناه.', + pasteAuthCode: 'ألصق رمز التفويض', + reopenAuthPage: 'إعادة فتح صفحة التفويض', + autoBrowser: provider => `فتحنا ${provider} في المتصفح. صرّح لـ Hermes هناك وسيتم الاتصال تلقائياً دون نسخ أو لصق.`, + reopenSignInPage: 'إعادة فتح صفحة تسجيل الدخول', + waitingAuthorize: 'بانتظار التفويض...', + externalPending: provider => + `${provider} يسجل الدخول عبر أداة سطر الأوامر الخاصة به. شغّل هذا الأمر في الطرفية، ثم عد واختر "سجلت الدخول":`, + signedIn: 'سجلت الدخول', + deviceCodeOpened: provider => `فتحنا ${provider} في المتصفح. أدخل هذا الرمز هناك:`, + reopenVerification: 'إعادة فتح صفحة التحقق', + copy: 'نسخ', + defaultModel: 'النموذج الافتراضي', + freeTier: 'الطبقة المجانية', + pro: 'مدفوع', + free: 'مجاني', + price: (input, output) => `${input} إدخال / ${output} إخراج لكل مليون رمز`, + change: 'تغيير', + startChatting: 'ابدأ', + docs: provider => `وثائق ${provider}` + }, + modelPicker: { + title: 'اختيار النموذج', + current: 'الحالي', + unknown: 'غير معروف', + search: 'البحث عن نموذج...', + noModels: 'لا توجد نماذج', + addProvider: 'إضافة مزود', + loadFailed: 'فشل تحميل النماذج', + noAuthenticatedProviders: 'لا توجد مزودات مصادق عليها', + pro: 'Pro', + proNeedsSubscription: 'يتطلب اشتراكا', + free: 'مجاني', + freeTier: 'طبقة مجانية', + priceTitle: 'السعر' + }, + modelVisibility: { + title: 'النماذج', + search: 'بحث في النماذج', + noAuthenticatedProviders: 'لا يوجد مزوّدون مصادق عليهم.', + addProvider: 'إضافة مزوّد…' + }, + shell: { + windowControls: 'تحكم النافذة', + paneControls: 'تحكم اللوحات', + appControls: 'تحكم التطبيق', + modelMenu: { + search: 'البحث عن نموذج...', + noModels: 'لا توجد نماذج', + editModels: 'تحرير النماذج', + refreshModels: 'تحديث النماذج', + fast: 'سريع', + medium: 'متوسط' + }, + modelOptions: { + noOptions: 'لا توجد خيارات لهذا النموذج', + options: 'الخيارات', + thinking: 'التفكير', + fast: 'سريع', + effort: 'الجهد', + minimal: 'أدنى', + low: 'منخفض', + medium: 'متوسط', + high: 'عالٍ', + max: 'أقصى', + updateFailed: 'فشل تحديث خيار النموذج', + fastFailed: 'فشل تحديث الوضع السريع' + }, + gatewayMenu: { + gateway: 'البوابة', + connected: 'متصل', + connecting: 'جار الاتصال', + offline: 'غير متصل', + inferenceReady: 'الاستدلال جاهز', + inferenceNotReady: 'الاستدلال غير جاهز', + checkingInference: 'جار فحص الاستدلال', + disconnected: 'منقطع', + openSystem: 'فتح النظام', + connection: label => `الاتصال: ${label}`, + recentActivity: 'النشاط الأخير', + viewAllLogs: 'عرض كل السجلات', + messagingPlatforms: 'منصات المراسلة' + }, + statusbar: { + unknown: 'غير معروف', + restart: 'إعادة تشغيل', + update: 'تحديث', + updateInProgress: 'التحديث جار', + commitsBehind: (count, branch) => `${count} commits خلف ${branch}`, + desktopVersion: version => `سطح المكتب ${version}`, + backendVersion: version => `الخلفية ${version}`, + clientLabel: version => `العميل ${version}`, + backendLabel: version => `الخلفية ${version}`, + commit: sha => `commit ${sha}`, + branch: branch => `الفرع ${branch}`, + closeCommandCenter: 'إغلاق مركز الأوامر', + openCommandCenter: 'فتح مركز الأوامر', + showTerminal: 'إظهار الطرفية', + hideTerminal: 'إخفاء الطرفية', + gateway: 'البوابة', + gatewayReady: 'البوابة جاهزة', + gatewayNeedsSetup: 'البوابة تحتاج إعدادا', + gatewayChecking: 'جار فحص البوابة', + gatewayConnecting: 'جار اتصال البوابة', + gatewayOffline: 'البوابة غير متصلة', + gatewayRestarting: 'جار إعادة التشغيل...', + gatewayTitle: 'حالة البوابة', + agents: 'الوكلاء', + closeAgents: 'إغلاق الوكلاء', + openAgents: 'فتح الوكلاء', + subagents: count => `${count} وكيل فرعي`, + failed: count => `${count} فشل`, + running: count => `${count} يعمل`, + cron: 'المهام', + openCron: 'فتح المهام المجدولة', + turnRunning: 'الدور يعمل', + currentTurnElapsed: 'وقت الدور الحالي', + contextUsage: 'استخدام السياق', + session: 'الجلسة', + runtimeSessionElapsed: 'وقت الجلسة', + yoloOn: 'YOLO مفعل', + yoloOff: 'YOLO معطل', + modelNone: 'لا نموذج', + noModel: 'لا يوجد نموذج', + switchModel: 'تبديل النموذج', + openModelPicker: 'فتح اختيار النموذج', + modelPinned: 'النموذج مثبت', + modelTitle: (provider, model) => `${provider}: ${model}`, + providerModelTitle: (provider, model) => `${provider}: ${model}` + } + }, + rightSidebar: { + aria: 'الشريط الجانبي الأيمن', + panelsAria: 'لوحات الشريط الأيمن', + files: 'الملفات', + terminal: 'الطرفية', + noFolderSelected: 'لم يتم اختيار مجلد', + changeCwdTitle: 'تغيير مجلد العمل', + remotePickerTitle: 'اختر مجلدا بعيدا', + remotePickerDescription: 'استعرض المجلدات على الخادم الخلفي المتصل.', + remotePickerSelect: 'تحديد المجلد', + folderTip: cwd => `المجلد الحالي: ${cwd}`, + openFolder: 'فتح مجلد', + refreshTree: 'تحديث الشجرة', + collapseAll: 'طي الكل', + previewUnavailable: 'المعاينة غير متاحة', + couldNotPreview: path => `تعذرت معاينة ${path}`, + noProjectTitle: 'لا يوجد مشروع', + noProjectBody: 'اختر مجلد عمل لعرض الملفات.', + noProjectOpen: 'لا يوجد مشروع مفتوح', + noDiffs: 'لا توجد فروقات', + unreadableTitle: 'تعذر قراءة المجلد', + unreadableBody: error => `السبب: ${error}`, + emptyTitle: 'المجلد فارغ', + emptyBody: 'لا توجد ملفات للعرض.', + treeErrorTitle: 'فشل تحميل شجرة الملفات', + treeErrorBody: 'حاول التحديث أو اختر مجلدا آخر.', + tryAgain: 'حاول مرة أخرى', + loadingTree: 'جار تحميل الشجرة...', + loadingFiles: 'جار تحميل الملفات...', + terminalHide: 'إخفاء الطرفية', + addToChat: 'إضافة للمحادثة' + }, + preview: { + tab: 'معاينة', + closeTab: label => `إغلاق ${label}`, + closeOthers: 'إغلاق الأخرى', + closeToRight: 'إغلاق ما على اليمين', + closeAll: 'إغلاق الكل', + closePane: 'إغلاق جزء المعاينة', + loading: 'جار تحميل المعاينة', + unavailable: 'المعاينة غير متاحة', + opening: 'جار الفتح...', + hide: 'إخفاء', + openPreview: 'فتح المعاينة', + openInBrowser: 'فتح في المتصفح', + linkHint: '⌘/Ctrl-نقر لجزء المعاينة', + sourceLineTitle: 'انقر للتحديد · shift-نقر للتوسيع · اسحب إلى المُنشئ', + source: 'المصدر', + renderedPreview: 'المعاينة', + diff: 'الفرق', + unknownSize: 'حجم غير معروف', + binaryTitle: 'يبدو هذا ملفا ثنائيا', + binaryBody: label => `قد تعرض معاينة ${label} نصا غير قابل للقراءة.`, + largeTitle: 'هذا الملف كبير', + largeBody: (label, size) => `حجم ${label} هو ${size}. سيعرض Hermes أول 512 KB فقط.`, + previewAnyway: 'معاينة على أي حال', + truncated: 'عرض أول 512 KB.', + noInlineTitle: 'لا توجد معاينة مضمّنة', + noInlineBody: mimeType => `${mimeType || 'هذا النوع من الملفات'} لا يزال بالإمكان إرفاقه كسياق.`, + edit: 'تحرير', + editing: 'جار التحرير', + unsavedChanges: 'تغييرات غير محفوظة', + saveFailed: message => `تعذّر الحفظ: ${message}`, + diskChangedTitle: 'تغيّر الملف على القرص', + diskChangedBody: 'تغيّر هذا الملف منذ أن فتحته. هل تريد الكتابة فوقه بنسختك، أم تجاهل تعديلاتك وإعادة التحميل؟', + overwrite: 'الكتابة فوقه', + discardReload: 'تجاهل وإعادة التحميل', + console: { + deselect: 'إلغاء تحديد الإدخال', + select: 'تحديد الإدخال', + copyFailed: 'تعذّر نسخ مخرجات الكونسول', + copyEntry: 'نسخ هذا الإدخال', + sendEntry: 'إرسال هذا الإدخال إلى المحادثة', + messages: count => `${count} رسائل كونسول`, + resize: 'تغيير حجم كونسول المعاينة', + title: 'كونسول المعاينة', + selected: count => `${count} محدد`, + sendToChat: 'إرسال إلى المحادثة', + copySelected: 'نسخ المحدد إلى الحافظة', + copyAll: 'نسخ الكل إلى الحافظة', + copy: 'نسخ', + clear: 'مسح', + empty: 'لا توجد رسائل كونسول بعد.', + promptHeader: 'كونسول المعاينة:', + sentTitle: 'تم الإرسال إلى المحادثة', + sentMessage: count => `أُضيف ${count} ${count === 1 ? 'إدخال سجل' : 'إدخالات سجل'} إلى المُنشئ` + }, + web: { + appFailedToBoot: 'فشل إقلاع تطبيق المعاينة', + serverNotFound: 'الخادم غير موجود', + failedToLoad: 'فشل تحميل المعاينة', + tryAgain: 'إعادة المحاولة', + restarting: 'جار إعادة تشغيل Hermes...', + askRestart: 'اطلب من Hermes إعادة تشغيل الخادم', + lookingRestart: taskId => `يبحث Hermes عن خادم معاينة لإعادة تشغيله (${taskId})`, + restartingTitle: 'جار إعادة تشغيل خادم المعاينة', + restartingMessage: 'يعمل Hermes في الخلفية. راقب كونسول المعاينة لمتابعة التقدم.', + startRestartFailed: message => `تعذّر بدء إعادة تشغيل الخادم: ${message}`, + restartFailed: 'فشلت إعادة تشغيل الخادم', + hideConsole: 'إخفاء كونسول المعاينة', + showConsole: 'إظهار كونسول المعاينة', + hideDevTools: 'إخفاء DevTools المعاينة', + openDevTools: 'فتح DevTools المعاينة', + finishedRestarting: message => `أنهى Hermes إعادة تشغيل خادم المعاينة${message ? `: ${message}` : ''}`, + failedRestarting: message => `فشلت إعادة تشغيل الخادم: ${message}`, + unknownError: 'خطأ غير معروف', + restartedTitle: 'تمت إعادة تشغيل خادم المعاينة', + reloadingNow: 'جار إعادة تحميل المعاينة الآن.', + restartFailedTitle: 'فشلت إعادة تشغيل المعاينة', + restartFailedMessage: 'تعذّر على Hermes إعادة تشغيل الخادم.', + stillWorking: + 'لا يزال Hermes يعمل، لكن لم تصل نتيجة إعادة التشغيل بعد. قد يكون أمر الخادم قيد التشغيل في المقدمة.', + workspaceReloading: 'تغيّرت مساحة العمل، جار إعادة تحميل المعاينة', + fileChanged: url => `تغيّر الملف، جار إعادة تحميل المعاينة: ${url}`, + filesChanged: (count, url) => `${count} تغييرات ملفات، جار إعادة تحميل المعاينة: ${url}`, + watchFailed: message => `تعذّر مراقبة ملف المعاينة: ${message}`, + moduleMimeDescription: + 'يتم تقديم نصوص الوحدات بنوع MIME خاطئ. عادة ما يعني هذا أن خادم ملفات ثابتة يقدّم تطبيق Vite/React بدلا من خادم تطوير المشروع.', + loadFailedConsole: (code, message) => `فشل التحميل${code ? ` (${code})` : ''}: ${message}`, + unreachableDescription: 'تعذّر الوصول إلى صفحة المعاينة.', + openTarget: url => `فتح ${url}`, + fallbackTitle: 'معاينة' + } + }, + zones: { + showHeader: 'إظهار الرأس', + hideHeader: 'إخفاء الرأس', + minimize: 'تصغير', + restore: 'استعادة', + closeRunningTitle: 'إغلاق تبويب يعمل؟', + closeRunningBody: + 'هذه المحادثة ما زالت تعمل (أو تنتظر إدخالك). إغلاق التبويب يخفيها فقط — ستحتفظ الجلسة بتقدمها ويمكن إعادة فتحها من الشريط الجانبي.', + closeRunningConfirm: 'إغلاق التبويب', + closeOthers: 'إغلاق الأخرى', + closeToRight: 'إغلاق ما على اليمين', + closeAll: 'إغلاق الكل', + split: dir => `تقسيم ${dir}`, + move: dir => `نقل ${dir}`, + dirUp: 'للأعلى', + dirDown: 'للأسفل', + dirLeft: 'لليسار', + dirRight: 'لليمين', + pluginDisabled: pluginId => `الإضافة "${pluginId}" معطلة`, + pluginDisabledBody: 'أعد تفعيلها من الإعدادات ← الإضافات لإرجاع اللوحة.', + missingPane: paneId => `لوحة مفقودة: ${paneId}`, + editTitle: 'التخطيطات', + editHint: 'اختر تخطيطا، أو اسحب اللوحات بين المناطق. انقر بزر الفأرة الأيمن على منطقة لتقسيمها.', + reset: 'إعادة ضبط', + templates: 'القوالب', + custom: 'مخصص', + newGridLayout: 'تخطيط شبكة جديد', + saveCurrentAs: 'حفظ الترتيب الحالي كقالب', + nameLayoutPlaceholder: 'سم هذا التخطيط...', + deletePreset: name => `حذف ${name}`, + zoneEditorTitle: 'محرر المناطق', + editorHintPre: 'انقر للتقسيم · ', + editorHintPost: ' يعكس الخط · اسحب عبر المناطق للدمج · اسحب الحواف المشتركة لتغيير الحجم', + templateColumns: 'أعمدة', + templateRows: 'صفوف', + templateGrid: 'شبكة', + templatePriority: 'أولوية', + zoneTag: index => `منطقة ${index}`, + mergeZones: count => `دمج ${count} مناطق`, + customZoneName: count => `مخصص من ${count} مناطق`, + layoutNamePlaceholder: fallback => `اسم التخطيط (${fallback})`, + saveApply: 'حفظ وتطبيق', + notExpressible: 'هذا الترتيب متشابك — لا يمكن تمثيله كتقسيمات متداخلة بعد', + zoneCount: count => `${count} مناطق` + }, + assistant: { + thread: { + loadingSession: 'جار تحميل الجلسة...', + showEarlier: 'عرض الرسائل الأقدم', + loadingResponse: 'جار تحميل الرد...', + resumeWhenBackgroundDone: count => + count === 1 ? 'سيُستأنف عند انتهاء المهمة الخلفية' : `سيُستأنف عند انتهاء ${count} مهام خلفية`, + thinking: 'يفكر...', + today: time => `اليوم ${time}`, + yesterday: time => `أمس ${time}`, + copy: 'نسخ', + refresh: 'تحديث', + moreActions: 'إجراءات إضافية', + branchNewChat: 'تفريع إلى محادثة جديدة', + dismissError: 'تجاهل الخطأ', + readAloudFailed: 'فشلت القراءة بصوت عال', + preparingAudio: 'جار تجهيز الصوت', + stopReading: 'إيقاف القراءة', + readAloud: 'قراءة بصوت عال', + editMessage: 'تحرير الرسالة', + scrollToBottom: 'التمرير إلى الأسفل', + stop: 'إيقاف', + restorePrevious: 'استعادة السابق', + restoreCheckpoint: 'استعادة النقطة', + restoreFromHere: 'استعادة نقطة التحقق — إعادة التشغيل من هذا الموجّه', + restoreTitle: 'الاستعادة إلى نقطة التحقق هذه؟', + restoreBody: 'يُزال كل ما يلي هذا الموجّه من المحادثة، ويُعاد تشغيل الموجّه من هنا.', + restoreConfirm: 'استعادة وإعادة تشغيل', + restoreNext: 'استعادة التالي', + goForward: 'تقدم', + sendEdited: 'إرسال التعديل', + attachingFile: 'جار إرفاق الملف' + }, + approval: { + gatewayDisconnected: 'البوابة غير متصلة', + sendFailed: 'فشل الإرسال', + run: 'تشغيل', + command: 'الأمر', + moreOptions: 'خيارات إضافية', + allowSession: 'السماح لهذه الجلسة', + alwaysAllowMenu: 'السماح دائما', + jumpToApproval: 'الموافقة مطلوبة', + reject: 'رفض', + alwaysTitle: 'السماح دائما', + alwaysDescription: pattern => `السماح دائما بالأوامر المطابقة لـ ${pattern}`, + alwaysAllow: 'السماح دائما' + }, + clarify: { + notReady: 'غير جاهز', + gatewayDisconnected: 'البوابة غير متصلة', + sendFailed: 'فشل الإرسال', + loadingQuestion: 'جار تحميل السؤال...', + other: 'غير ذلك', + placeholder: 'اكتب إجابتك...', + skip: 'تخطي', + continueLabel: 'متابعة' + }, + tool: { + code: 'الكود', + copyCode: 'نسخ الكود', + renderingImage: 'جار عرض الصورة...', + copyOutput: 'نسخ الإخراج', + copyCommand: 'نسخ الأمر', + copyContent: 'نسخ المحتوى', + copyUrl: 'نسخ الرابط', + copyResults: 'نسخ النتائج', + copyQuery: 'نسخ الاستعلام', + copyFile: 'نسخ الملف', + copyPath: 'نسخ المسار', + outputAlt: 'إخراج الأداة', + rawResponse: 'الرد الخام', + copyActivity: 'نسخ النشاط', + recoveredOne: 'تم الاسترداد', + recoveredMany: count => `تم استرداد ${count}`, + failedOne: 'فشل', + failedMany: count => `فشل ${count}`, + statusRunning: 'يعمل', + statusError: 'خطأ', + statusRecovered: 'تم الاسترداد', + statusDone: 'تم', + actions: { + read: 'قراءة', + reading: 'جار القراءة', + opened: 'تم الفتح', + opening: 'جار الفتح', + searched: 'تم البحث', + searching: 'جار البحث', + ran: 'تم التشغيل', + running: 'جار التشغيل', + ranCode: 'تم تشغيل الكود', + runningCode: 'جار البرمجة' + }, + prefixes: { + browser: 'المتصفح', + web: 'الويب' + }, + titleTemplates: { + actionCommand: (action, command) => `${action} ${command}`, + actionQuoted: (action, value) => `${action} “${value}”`, + actionTarget: (action, target) => `${action} ${target}`, + prefixedDone: (prefix, action) => `${prefix} ${action}`, + runningPrefixedTool: (prefix, action) => `جار تشغيل ${prefix.toLowerCase()} ${action.toLowerCase()}`, + runningTool: action => `جار تشغيل ${action.toLowerCase()}` + }, + titles: { + browser_click: { + done: 'تم النقر على عنصر الصفحة', + pending: 'جار النقر على عنصر الصفحة', + pendingAction: 'جار النقر' + }, + browser_fill: { + done: 'تم ملء حقل النموذج', + pending: 'جار ملء حقل النموذج', + pendingAction: 'جار الملء' + }, + browser_navigate: { + done: 'تم فتح الصفحة', + pending: 'جار فتح الصفحة', + pendingAction: 'جار الفتح' + }, + browser_snapshot: { + done: 'تم التقاط لقطة الصفحة', + pending: 'جار التقاط لقطة الصفحة', + pendingAction: 'جار الالتقاط' + }, + browser_take_screenshot: { + done: 'تم التقاط لقطة الشاشة', + pending: 'جار التقاط لقطة الشاشة', + pendingAction: 'جار الالتقاط' + }, + browser_type: { + done: 'تمت الكتابة على الصفحة', + pending: 'جار الكتابة على الصفحة', + pendingAction: 'جار الكتابة' + }, + clarify: { + done: 'تم طرح سؤال', + pending: 'جار طرح سؤال', + pendingAction: 'جار السؤال' + }, + cronjob: { + done: 'مهمة مجدولة', + pending: 'جار جدولة المهمة', + pendingAction: 'جار الجدولة' + }, + edit_file: { + done: 'تم تحرير الملف', + pending: 'جار تحرير الملف', + pendingAction: 'جار التحرير' + }, + execute_code: { + done: 'تم تشغيل الكود', + pending: 'جار البرمجة', + pendingAction: 'جار البرمجة' + }, + image_generate: { + done: 'تم إنشاء الصورة', + pending: 'جار إنشاء الصورة', + pendingAction: 'جار الإنشاء' + }, + list_files: { + done: 'تم سرد الملفات', + pending: 'جار سرد الملفات', + pendingAction: 'جار السرد' + }, + patch: { + done: 'تم تصحيح الملف', + pending: 'جار تصحيح الملف', + pendingAction: 'جار التصحيح' + }, + read_file: { + done: 'تمت قراءة الملف', + pending: 'جار قراءة الملف', + pendingAction: 'جار القراءة' + }, + search_files: { + done: 'تم البحث في الملفات', + pending: 'جار البحث في الملفات', + pendingAction: 'جار البحث' + }, + session_search_recall: { + done: 'تم البحث في سجل الجلسة', + pending: 'جار البحث في سجل الجلسة', + pendingAction: 'جار البحث' + }, + terminal: { + done: 'تم تشغيل الأمر', + pending: 'جار تشغيل الأمر', + pendingAction: 'جار التشغيل' + }, + todo: { + done: 'تم تحديث المهام', + pending: 'جار تحديث المهام', + pendingAction: 'جار التحديث' + }, + vision_analyze: { + done: 'تم تحليل الصورة', + pending: 'جار تحليل الصورة', + pendingAction: 'جار التحليل' + }, + web_extract: { + done: 'تمت قراءة صفحة الويب', + pending: 'جار قراءة صفحة الويب', + pendingAction: 'جار القراءة' + }, + web_search: { + done: 'تم البحث في الويب', + pending: 'جار البحث في الويب', + pendingAction: 'جار البحث' + }, + write_file: { + done: 'تم تحرير الملف', + pending: 'جار تحرير الملف', + pendingAction: 'جار التحرير' + } + } + } + }, + prompts: { + gatewayDisconnected: 'البوابة غير متصلة', + sudoSendFailed: 'فشل إرسال كلمة مرور sudo', + secretSendFailed: 'فشل إرسال السر', + sudoTitle: 'مطلوب sudo', + sudoDesc: 'أدخل كلمة المرور لمتابعة الأمر.', + sudoPlaceholder: 'كلمة المرور', + secretTitle: 'مطلوب سر', + secretDesc: 'أدخل القيمة المطلوبة لمتابعة المهمة.', + secretPlaceholder: 'القيمة السرية' + }, + desktop: { + audioReadFailed: 'فشلت قراءة الصوت', + sessionUnavailable: 'الجلسة غير متاحة', + createSessionFailed: 'فشل إنشاء الجلسة', + promptFailed: 'فشل إرسال الرسالة', + providerCredentialRequired: 'مطلوب اعتماد المزود', + emptySlashCommand: 'أمر slash فارغ', + desktopCommands: 'أوامر سطح المكتب', + skillCommandsAvailable: count => `${count} أمر مهارة متاح`, + warningLine: message => `تحذير: ${message}`, + yoloArmed: 'YOLO مفعل', + yoloOff: 'YOLO معطل', + yoloSystem: active => (active ? 'YOLO مفعل للنظام' : 'YOLO معطل للنظام'), + yoloTitle: 'وضع YOLO', + yoloToggleFailed: 'فشل تبديل YOLO', + profileStatus: current => `الملف الحالي: ${current}`, + unknownProfile: 'ملف شخصي غير معروف', + noProfileNamed: (target, available) => `لا يوجد ملف باسم ${target}. المتاح: ${available}`, + newChatsProfile: name => `المحادثات الجديدة تستخدم ${name}`, + setProfileFailed: 'فشل ضبط الملف الشخصي', + sttDisabled: 'تحويل الكلام إلى نص معطل', + stopFailed: 'فشل الإيقاف', + regenerateFailed: 'فشلت إعادة التوليد', + editFailed: 'فشل التحرير', + resumeFailed: 'فشل الاستئناف', + resumeStrandedTitle: 'تعذّر تحميل هذه الجلسة', + resumeStrandedBody: + 'فشل الاتصال بهذه الجلسة وتوقفت إعادة المحاولة التلقائية. تأكد من تشغيل البوابة، ثم حاول مجددا.', + resumeRetry: 'إعادة المحاولة', + nothingToBranch: 'لا يوجد ما يمكن تفريعه', + branchNeedsChat: 'يحتاج التفريع إلى محادثة', + sessionBusy: 'الجلسة مشغولة', + branchStopCurrent: 'أوقف الدور الحالي قبل التفريع', + branchNoText: 'لا يوجد نص للتفريع', + branchTitle: n => `مسودة: تفريع #${n}`, + branchFailed: 'فشل التفريع', + deleteFailed: 'فشل الحذف', + archived: 'تمت الأرشفة', + archiveFailed: 'فشلت الأرشفة', + cwdChangeFailed: 'فشل تغيير مجلد العمل', + cwdStagedTitle: 'تم تجهيز مجلد العمل', + cwdStagedMessage: 'سيطبق مجلد العمل على الرسالة التالية.', + modelSwitchFailed: 'فشل تبديل النموذج', + sessionExported: 'تم تصدير الجلسة', + sessionExportFailed: 'فشل تصدير الجلسة', + imageSaved: 'تم حفظ الصورة', + downloadStarted: 'بدأ التنزيل', + restartToUseSaveImage: 'أعد التشغيل لاستخدام حفظ الصور', + restartToSaveImages: 'أعد التشغيل لحفظ الصور', + imageDownloadFailed: 'فشل تنزيل الصورة', + openImage: 'فتح الصورة', + downloadImage: 'تنزيل الصورة', + savingImage: 'جار حفظ الصورة', + imagePreviewFailed: 'فشلت معاينة الصورة', + imageAttach: 'إرفاق الصورة', + imageWriteFailed: 'فشل كتابة الصورة', + imageAttachFailed: 'فشل إرفاق الصورة', + attachImages: 'إرفاق الصور', + clipboard: 'الحافظة', + noClipboardImage: 'لا توجد صورة في الحافظة', + clipboardPasteFailed: 'فشل اللصق من الحافظة', + dropFiles: 'أفلت الملفات هنا', + handoff: { + pickPlatform: 'اختر وجهة', + success: platform => `تم التسليم إلى ${platform}. استأنف هنا في أي وقت.`, + systemNote: platform => `↻ تم التسليم إلى ${platform} — استأنف هنا في أي وقت.`, + failed: error => `فشل التسليم: ${error}`, + timedOut: 'انتهت المهلة في انتظار البوابة. هل `hermes gateway` قيد التشغيل؟' + } + }, + errors: { + genericFailure: 'حدث خطأ', + boundaryTitle: 'تعطل جزء من الواجهة', + boundaryDesc: 'يمكنك إعادة تحميل النافذة أو فتح السجلات لمعرفة التفاصيل.', + reloadWindow: 'إعادة تحميل النافذة', + openLogs: 'فتح السجلات' + }, + ui: { + search: { + clear: 'مسح البحث' + }, + pagination: { + label: 'ترقيم الصفحات', + previous: 'السابق', + previousAria: 'الصفحة السابقة', + next: 'التالي', + nextAria: 'الصفحة التالية' + }, + sidebar: { + title: 'الشريط الجانبي', + description: 'تنقل التطبيق', + toggle: 'تبديل الشريط الجانبي' + } + } +}) diff --git a/apps/desktop/src/i18n/catalog.ts b/apps/desktop/src/i18n/catalog.ts index 19556cb45c491..f35c957076db2 100644 --- a/apps/desktop/src/i18n/catalog.ts +++ b/apps/desktop/src/i18n/catalog.ts @@ -1,3 +1,4 @@ +import { ar } from './ar' import { en } from './en' import { ja } from './ja' import type { Locale, Translations } from './types' @@ -8,5 +9,6 @@ export const TRANSLATIONS: Record = { en, zh, 'zh-hant': zhHant, - ja + ja, + ar } diff --git a/apps/desktop/src/i18n/context.test.tsx b/apps/desktop/src/i18n/context.test.tsx index 3028c86ffa07d..729ced7a4da49 100644 --- a/apps/desktop/src/i18n/context.test.tsx +++ b/apps/desktop/src/i18n/context.test.tsx @@ -209,6 +209,24 @@ describe('I18nProvider', () => { expect(screen.getByTestId('locale').textContent).toBe('ja') }) + it('applies RTL direction for Arabic and restores LTR on switch back', async () => { + render( + + + + ) + + expect(screen.getByTestId('locale').textContent).toBe('ar') + expect(document.documentElement.dir).toBe('rtl') + expect(document.documentElement.lang).toBe('ar') + + fireEvent.click(screen.getByRole('button', { name: 'switch' })) + + await waitFor(() => expect(screen.getByTestId('locale').textContent).toBe('en')) + expect(document.documentElement.dir).toBe('ltr') + expect(document.documentElement.lang).toBe('en') + }) + it('rolls back the visible locale when saving fails', async () => { const configClient: I18nConfigClient = { getConfig: vi.fn().mockResolvedValue({ display: { language: 'en' } }), diff --git a/apps/desktop/src/i18n/context.tsx b/apps/desktop/src/i18n/context.tsx index 103a63047e77b..67f335826192a 100644 --- a/apps/desktop/src/i18n/context.tsx +++ b/apps/desktop/src/i18n/context.tsx @@ -55,6 +55,17 @@ function toError(error: unknown): Error { return error instanceof Error ? error : new Error(String(error)) } +const RTL_LOCALES = new Set(['ar']) + +function applyDocumentLocale(locale: Locale) { + if (typeof document === 'undefined') { + return + } + + document.documentElement.lang = locale + document.documentElement.dir = RTL_LOCALES.has(locale) ? 'rtl' : 'ltr' +} + export interface I18nContextValue { configLoadError: Error | null isLoadingConfig: boolean @@ -92,6 +103,7 @@ export function I18nProvider({ children, configClient = defaultConfigClient, ini useEffect(() => { localeRef.current = locale setRuntimeI18nLocale(locale) + applyDocumentLocale(locale) }, [locale]) useEffect(() => { diff --git a/apps/desktop/src/i18n/languages.test.ts b/apps/desktop/src/i18n/languages.test.ts index 792aad5f586b2..fa6a8a4c22de1 100644 --- a/apps/desktop/src/i18n/languages.test.ts +++ b/apps/desktop/src/i18n/languages.test.ts @@ -15,6 +15,9 @@ describe('desktop i18n languages', () => { expect(normalizeLocale('zh_HK')).toBe('zh-hant') expect(normalizeLocale('ja')).toBe('ja') expect(normalizeLocale('ja-JP')).toBe('ja') + expect(normalizeLocale('ar')).toBe('ar') + expect(normalizeLocale('AR-SA')).toBe('ar') + expect(normalizeLocale(' ar_eg ')).toBe('ar') }) it('falls back to English for empty or unsupported values', () => { @@ -32,6 +35,7 @@ describe('desktop i18n languages', () => { expect(isLocale('zh')).toBe(true) expect(isLocale('zh-hant')).toBe(true) expect(isLocale('ja')).toBe(true) + expect(isLocale('ar')).toBe(true) }) it('returns the persisted config value for supported locales', () => { @@ -39,5 +43,6 @@ describe('desktop i18n languages', () => { expect(localeConfigValue('zh')).toBe('zh') expect(localeConfigValue('zh-hant')).toBe('zh-hant') expect(localeConfigValue('ja')).toBe('ja') + expect(localeConfigValue('ar')).toBe('ar') }) }) diff --git a/apps/desktop/src/i18n/languages.ts b/apps/desktop/src/i18n/languages.ts index 96daf9b598dd9..e4a1fb1e02eb4 100644 --- a/apps/desktop/src/i18n/languages.ts +++ b/apps/desktop/src/i18n/languages.ts @@ -28,6 +28,12 @@ export const LOCALE_OPTIONS = [ name: '日本語', englishName: 'Japanese', configValue: 'ja' + }, + { + id: 'ar', + name: 'العربية', + englishName: 'Arabic', + configValue: 'ar' } ] as const satisfies readonly { configValue: string; englishName: string; id: Locale; name: string }[] @@ -64,7 +70,16 @@ const LOCALE_ALIASES: Record = { zh_hant_hk: 'zh-hant', ja: 'ja', 'ja-jp': 'ja', - ja_jp: 'ja' + ja_jp: 'ja', + ar: 'ar', + 'ar-sa': 'ar', + ar_sa: 'ar', + 'ar-ae': 'ar', + ar_ae: 'ar', + 'ar-eg': 'ar', + ar_eg: 'ar', + arabic: 'ar', + العربية: 'ar' } export function isLocale(value: unknown): value is Locale { diff --git a/apps/desktop/src/i18n/types.ts b/apps/desktop/src/i18n/types.ts index 3957d668a8242..58836148a45df 100644 --- a/apps/desktop/src/i18n/types.ts +++ b/apps/desktop/src/i18n/types.ts @@ -5,7 +5,7 @@ // partial locales should use `defineLocale()` so missing desktop-only strings // fall back to English while new keys remain type-checked. -export type Locale = 'en' | 'zh' | 'zh-hant' | 'ja' +export type Locale = 'en' | 'zh' | 'zh-hant' | 'ja' | 'ar' export type ToolTitleKey = | 'browser_click'