dsh-arabic
Đã xác minhdsh-arabic · v0.4.2 · MIT · Giao diện web
Arabic experience for DeepSeek Harness: bidi-safe RTL rendering for mixed Arabic/English content plus a full Arabic UI language pack registered through the official locale service.
Cài đặt
dsh plugin add dsh-arabic Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Thẻ
Tác giả
Readme
dsh-arabic
العربية · English
العربية لتطبيق DeepSeek Harness — عرض RTL سليم تقنياً، وحزمة تعريب كاملة للواجهة، وخطّ ثمانية للواجهة.
DSH لا يدعم RTL ولا يوفّر لغة عربية. خلط النص العربي بأسماء المتغيّرات والمسارات والأكواد داخل الواجهة يجعل الكلام مبعثراً، وكل القوائم إنجليزية. هذا البلاقن يحل المشكلتين دون تعديل التطبيق نفسه.
ما الذي يفعله
١) عرض RTL آمن ثنائي الاتجاه (يعمل بأي لغة واجهة)
الاتجاه يُحسم لكل كتلة بهيمنة الكلمات، لا بأول حرف قوي. والتقسيم على
المسافات فقط، فـ@deepseek-ai/dsh تُحسب كلمة واحدة لا ثلاثاً:
| المحتوى | الاتجاه | السبب |
|---|---|---|
كيف حالك Hello |
RTL | الكلمات العربية غالبَة |
Hello كيف حالك |
RTL | ما زالت جملة عربية — وdir="auto" يخطئ هنا |
Error: فشل الاتصال بالخادم |
RTL | الجملة عربية والبادئة ليست كذلك |
npm install ثم أعد التشغيل |
RTL | ٣ كلمات عربية مقابل ٢ لاتينية |
شغّل npx @deepseek-ai/dsh web |
RTL | الرمز التقني يلصق npx … web في وحدة واحدة: عربية ١ مقابل لاتينية ١ |
راجع commit a4c1025b قبل النشر |
RTL | البصمة المجرّدة لا تُصوِّت |
نسبة النجاح 15/15 |
RTL | النسبة محايدة |
افتح src/index.ts ثم عدّل الدالة |
RTL | المسار لا يُصوِّت |
"C:\Users\…\الخطوط\thmanyahseriftext" |
بلا تغيير | مسار ويندوز رمز تقني ولو كان أحد مجلداته عربيًا |
@deepseek-ai/dsh مهم جدًا |
RTL | المُعرِّف الواحد = وحدة واحدة |
Hello نص |
RTL | التعادل يُحسم RTL |
The build failed while parsing سلام in the file |
بلا تغيير | نص إنجليزي يقتبس كلمة يبقى LTR |
شغّل "git status" |
RTL | الاقتباس وحدة واحدة: يُحتسب مرة لا مرتين |
pre وcode والكود المضمّن |
LTR دائماً | الكود لا يُحكم عليه ولا يُقلب |
| مربّع الكتابة والبحث | يتبع ما تكتبه | RTL حين تغلب العربية، وإلا auto الأصلي |
القواعد الأربع خلف الجدول:
١. الرموز الشبيهة بالكود لا تُصوِّت — الروابط، المسارات (بما فيها شرطة ويندوز
المائلة الخلفية)، @scope/name، البصمات، 15/15، أسماء الملفات المنقوطة؛
فرابط واحد أو بصمة واحدة قد ترجّح على جملة عربية كاملة، والرمز التقني يلصق
الكلمات اللاتينية حوله في وحدة تقنية واحدة. والمسار الذي يحمل مجلدًا عربيًا
يبقى مسارًا: احتسابه نصًّا عربيًا هو ما كان يقلب كتلة مسارات إلى RTL، فيُعاد
ترتيب مقاطعها اللاتينية حول تلك الكلمة.
٢. الكلمات هي الوحدة لا الحروف — فالمصطلح اللاتيني أطول حروفاً وأقل كلمات.
والتعادل يُحسم للعربية، والكتلة التي لا كلمة عربية فيها تُحرَّر.
٣. تثبيت أثناء البثّ (hysteresis) — الكتلة التي صارت RTL تبقى كذلك حتى يصير
النص لاتينياً بوضوح (ضعف عدد الكلمات العربية)، فلا يتذبذب الرد المتدرّج.
٤. الاقتباس وحدة واحدة — "git status" نصٌّ مقتبس (أمر، عنوان، جملة) يُحتسب
مرة واحدة لا مرتين؛ فيُقرأ شغّل "git status" جملةً عربية كما هي، بينما
الكلمتان نفسهما بلا اقتباس تبقى LTR (انظر الحدود أدناه). وعلامة اقتباس غير
مغلقة — ردٌّ يتدفّق والاقتباس لم يُغلق بعد — تمتدّ إلى آخر النص، وهي الوحدة
نفسها التي سينتجها الاقتباس المغلق، فلا تذبذب لحظةَ الإغلاق.
كتل النص وحدها تُقلب — والهيكل لا يُقلب أبداً. حاوية flex أو grid تُعيد
ترتيب أبنائها عند القلب، والصف الذي يملك أزراراً هو شريط أدوات: كلاهما مُستثنى،
فيبقى زر الإرسال في مكانه رغم أن وسم الصلاحية العربي في الصف نفسه. والنص العربي
داخل ذلك الصف يعيش في كتلة نصية خاصة به فيُعالَج عادةً.
وشكلان احتاجا أكثر من قرار كتلة عادية، وكلٌّ منهما مُثبَّت باختبار وبـdata/card-pins.json:
- خلية نصّية جعلها CSS كتلةً. بطاقة السؤال التي يسأل بها المساعد ترسم كل خيار
buttonبـflex، ووسمها ووصفهاspanداخله. الـspanالمضمّن فعلاً جزء من التدفّق حوله، أما عنصرflexفهو كتلة نصية قائمة بذاتها: كل خلية تأخذ RTL، فيُقرأادفع fix/rust-flake كما هوبترتيبه لا مقلوباً، ويبقى رقم الصف في مكانه؛ <header>/<footer>بطاقة المحتوى. DSH يضع نص السؤال داخل<header>(وheaderوfooterعلامتان للهيكل وتبقيان LTR). وإطار البطاقة يحملdata-question-key— وهو المُعرِّف الوحيد الذي يقرأه هذا البلاقن من التطبيق — فعلامة داخل البطاقة جزء من البطاقة، وسؤالها محتوى كأي فقرة. وscripts/check-card-pins.mjs <app.asar>يفشل مسمّياً الفرق إذا تغيّر هذا المُعرِّف أو لم يعد صف الخيارات صفflex؛- وما لا يتحرك: رقم الخيار، وعناصر التحكّم نفسها. الصف الذي يملك زراً لا يُقلب،
وعنصر التحكّم لا يُمنح اتجاهاً خاصاً به — فزر
flexيعكس ترتيب أيقونته ووسمه، والوسم المتوسّط يقفز إلى حافة عند تجاوز المحاذاة. فيبقى الرقم حيث وضعه التصميم، وتبقى أزرار البطاقة بتخطيطها، ويبدأ النص العربي بجانبها — البطاقة لا تُقلب، بل نصّها.

مُصيَّرة بـChromium بمحرّك bidi الحقيقي: الترميز والنصوص نفسها في اللوحين، مع خصائص dir التي يكتبها البلاقن في اللوح الأيمن. ورقم الخيار يبقى في اليسار في الحالتين. المصدر: docs/question-card.html.
وإذا كان اتجاه كتلة ما مضبوطاً من التطبيق أو منك (dir="ltr" في الترميز)، فلا
نلمسه أبداً — وهذا هو المخرج الاحتياطي لأي كتلة يُخطئ فيها المُقدِّر.
حدود معروفة (مُثبَّتة في الاختبارات لا مخفية)
- الكلمات اللاتينية المجرّدة تُصوِّت.
شغّل git statusيبقى LTR: كلمتان لاتينيتان عاديتان ترجّحان على كلمة عربية، ولا فاصل تقني يلصقهما. وقد جُرِّب اعتبار كل تتابع لاتيني وحدة واحدة فرُفض — لأنه يقلب فقرات إنجليزية تقتبس كلمة عربية. والاقتباس هو العلاج بيد القارئ:شغّل "git status"ينقلب. - المسار المختلط داخل الجملة العربية يتبع خوارزمية bidi. الكتلة عربية وتبقى
RTL، فتترتّب مقاطع المسار اللاتينية حول مقطعه العربي. وكتابة المسار داخل
علامتَي الكود الخلفيتين هي الصيغة الموثوقة: الورقة تعزل
codeمن اليسار إلى اليمين، فيُقرأ المسار بترتيبه (مُتحقَّق منه في Chromium). - طرفية الشريط الجانبي لا تصل الحروف. طرفية DSH مبنية على xterm.js ولا تصل
الحروف العربية (
ا ل ع ر ب ي ة). هذا قيد في المصدر، نوثّقه ولا نتظاهر بإصلاحه. - صيغ الجمع. قواميس DSH سلاسل مسطّحة، فالجملة العربية التي تعدّ الأشياء لا تستطيع اختيار الصيغة الصحيحة لـ ١ و٢ و٣–١٠ و١١+؛ وحيث يهمّ ذلك نصوغ الجملة بحيث لا تتأثر بالعدد.
- الهيكل يبقى LTR. القوائم والشريط الجانبي تتبع اتجاه الهيكل لا اللغة المختارة؛
فقلبها بالحقن يكسر تخطيطاً كُتب بخصائص CSS فيزيائية. وللسبب نفسه تُستثنى حاويات
flex/gridوالصفوف التي تملك أزراراً من قرار الاتجاه — فيُقرأ وسم الصلاحية العربي في شريط المُحرِّر من اليمين دون أن ينتقل زر الإرسال. الخطة المعتمدة تعتمد المصدر أولاً — انظر docs/roadmap.md.
نهج هيمنة الكلمات، وقاعدة «المُعرِّف الواحد كلمة واحدة»، وفكرة حذف الرموز الشبيهة بالكود قبل العدّ — كلها تتبع الإجماع المجتمعي الذي بدأه haythamat/dsh-client-ui-rtl وkfirsch/dsh-hebrew-rtl (رخصة MIT لكلٍّ منهما)؛ وهذا التنفيذ مستقل، ويضيف طبقة مربّع الكتابة والمفتاح والتثبيت أثناء البثّ، ومغطّى باختباراته.

مُصيَّرة بمتصفح Chromium بمحرّك bidi الحقيقي: العمودان يحملان الأسطر الخمسة نفسها، وكلٌّ منها يبدأ بمُعرِّف لاتيني. المصدر: docs/direction.html.
لا يقلب الواجهة كلها إلى RTL. واجهات المطوّرين ثنائية اللغة بطبيعتها، واتجاه كل كتلة على حدة هو ما يُبقي اللغتين مقروءتين.
٢) حزمة تعريب الواجهة
مُسجَّلة عبر خدمة الترجمة الرسمية (ctx.locale.addLanguage + ctx.locale.register)
— أي بالنفس الآلية التي يستخدمها التطبيق نفسه، بلا استبدال نصوص في DOM وبلا
تعديل دوال قائمة:
- 60 نطاقاً · 3,307 نصاً مأخوذة من مصدر DSH الرسمي
- أي مفتاح غير مترجم يعود تلقائياً إلى الإنجليزية (
fallback: 'en') - اختر العربية من الإعدادات ← عام ← Language
التغطية وكل قرار ترجمة غير بديهي قابلة للتدقيق في
data/en-catalog.json (مجموعة المفاتيح الإنجليزية الرسمية)،
وlocales/ar.json (الحزمة العربية)،
وdata/overrides.json (توحيد الصيغ بين الدفعات).
٣) الخيار بيدك لا بيدنا
العربية تُضاف كخيار ولا تُفرض أبداً:
- الإعدادات ← عام ← Language تُدرج العربية بجانب اللغات المدمجة، ويحفظ التطبيق اختيارك عبر خدمة اللغة الرسمية — فمن يفضّل الواجهة الإنجليزية يحتفظ بها.
- الإعدادات ← عام ← اتجاه النص من اليمين إلى اليسار يُشغّل طبقة الاتجاه
ويوقفها فوراً ويتذكّر اختيارك (
localStorage). عند الإيقاف لا تُوسَم أي كتلة ولا يُضبط اتجاه أي خانة كتابة — تتصرّف الواجهة تماماً كما لو لم يكن البلاقن موجوداً.
٤) طباعة الواجهة
ثلاث قطع من ثمانية، كلٌّ في الدور الذي رُسم له:
| الدور | القطع | أين يظهر |
|---|---|---|
| الواجهة | ثمنية سانس | الافتراضي: الوسوم والأزرار والهيكل والنصوص الصغيرة |
| القراءة | ثمنية سيريف تيكست | فقرات الماركداون وعناصر القوائم والاقتباسات |
| العناوين | ثمنية سيريف ديسپلاي | h1–h6 |
وسطر واحد يحمل دور الواجهة — البلاقن يعيد تعريف --dsw-font-family، المتغيّر الذي
تمرّ منه كل رموز الطباعة في سمة التطبيق — وقاعدتان للعناصر تحملان الدورين
الآخرين. وتبقى حزمة خطوط التطبيق خلف كل عائلة في التعريف نفسه، وخطّ الكود لا
يُلمس، وكل دور يصمت إن غابت ملفاته.
ومنذ DSH 0.2.1 صار ذلك المتغيّر وسيطاً داخلياً عند التطبيق نفسه: يحمل على body
قيمة --dsh-font-family-text — الخط الذي تختاره من الإعدادات ← عام — قبل
حزمة خطوطه المدمجة. فصار البلاقن يسمّي قطعه احتياطياً لذلك المتغيّر لا قيمةً
له: خطٌّ تختاره في حقل التطبيق يتقدّم على قطعنا في الواجهة والفقرات والعناوين
جميعاً، وحقلٌ فارغ — وحينها لا يكتب التطبيق شيئاً — يُبقي ثمانية في مكانها.
والمتغيّر يُقرأ ولا يُعرَّف أبداً، وهذا ما يحفظ ذلك الترتيب.
والأوزان في fonts/ — مجلد فرعي لا جذر المستودع — ومعه
نصّا الرخصة (والعربية هي الحاكمة)، ويخدمها البلاقن من /dsh-arabic/fonts/ على
خادم التطبيق نفسه: نسخة الديسكتوب تحمّل صفحتها من http://127.0.0.1:<port>
فيعمل الرابط نفسه في الوجهين، وتحمل الصفحة تسع قواعد @font-face قصيرة بدل نحو
ميغابايت من base64. ووجّه DSH_ARABIC_FONTS إلى مجلد بالبنية نفسها لتُزوّد نسخةً
أخرى، أو إلى مجلد فارغ لتُبقي خط التطبيق الأصلي — الطبقة تصمت، لا تتعطّل.
لا يتغيّر شيء في الواجهة حتى تختاره أنت.
التثبيت
# من npm
dsh plugin --profile desktop add dsh-arabic
# أو من نسخة محلية (للتطوير)
dsh plugin --profile desktop add link:/المسار/الكامل/dsh-arabic
أو من داخل التطبيق: الإعدادات ← Plugins ← Plugin Manager.
أعد تشغيل DSH بعد التثبيت. جدول الحقن في نسخة الديسكتوب يُجمَع مرة واحدة عند إقلاع المضيف، فتحديث الصفحة وحده لا يكفي.
ثم لتفعيل الواجهة العربية: الإعدادات ← عام ← Language ← العربية. طبقة RTL تعمل مع أي لغة بمجرد تحميل البلاقن.
كيف يعمل
index.js النصف المضيف
└── صفوف webserver/index-inject
├── { kind: 'style', text: <CSS الاتجاه> }
└── { kind: 'script', placement: 'body', text: <سكربت الوسم> }
lib/client.js النصف البرمجي في المتصفح (مُولَّد)
└── window.__ModuleLoader__.load({ id, factory })
├── ctx.locale.addLanguage({ id: 'ar', label: 'العربية', fallback: 'en' })
│ ctx.locale.register(namespace, 'ar', dictionary) × 59
└── ctx.slots.inject('settings.general.item', …)
└── صف Switch واحد → window.__dshArabic.setEnabled()
لا اعتماديات خارجية على مستوى التحميل: react والمكوّنات الرسمية تُطلَب فقط عند
وجود مقعد الإعدادات، وذاك التسجيل محروس بحيث لا يُسقط تغيير مستقبلي في المواقع
حزمةَ اللغة معه.
بنية المستودع
| المسار | الغرض |
|---|---|
index.js |
النصف المضيف: صفوف حقن الاتجاه |
lib/client.js |
النصف البرمجي المُولَّد: حزمة اللغة العربية |
locales/ar.json |
القواميس المترجمة |
data/en-catalog.json |
مجموعة المفاتيح الإنجليزية الرسمية المستخرجة من مصادر DSH |
data/en-catalog.meta.json |
مرجع/بصمة upstream التي قيست عليها المجموعة |
data/glossary.yml |
المسرد الآلي (المصطلح، العربية، ما يُتجنّب، ما لا يُترجم) |
data/overrides.json |
توحيد الصيغ حيث اختلفت الدفعات المتوازية |
data/term-map.json |
تطبيع المصطلحات المُطبَّق على كل قيمة في الخط |
data/bidi-decisions.json |
كل عزل في عائلة سطر الحالة — وكل قيمة مختلطة — بسببها |
data/shimmer-pins.json |
أسماء الفئات والـkeyframes المُجزأة التي قيست عليها مرآة الوميض |
scripts/extract-catalog.mjs |
يعيد توليد data/en-catalog.json من المصادر الرسمية (npm run extract) |
scripts/status.mjs |
نسبة التغطية مقابل مرجع upstream المسجَّل (npm run status) |
scripts/build-client.mjs |
يتحقق من الحزمة ويعيد توليد lib/client.js (--check لـ CI) |
scripts/assemble-translations.mjs |
يدمج دفعات الترجمة في locales/ar.json |
scripts/lint-consistency.mjs |
يكشف ترجمة النص الإنجليزي الواحد بصيغتين |
scripts/check-bidi-family.mjs |
يفشل — بتسمية المفتاح — على أي عزل غير مسجَّل في عائلة سطر الحالة |
scripts/check-shimmer-pins.mjs |
يعيد التحقق من أسماء مرآة الوميض مقابل app.asar مثبَّت (خطوة إصدار) |
tests/golden-direction.mjs |
٤٥ نصاً ذهبياً مع الاتجاه الواجب لكلٍّ منها |
fonts/ |
قطع ثمنية الثلاث (سانس · سيريف تيكست · سيريف ديسپلاي) بأوزان 400/500/700 + نصّا الرخصة (العربي حاكم)، والمجلد فرعي لا جذر للمستودع |
docs/roadmap.md |
الطبقات الثلاث، وطلبات المصدر، وما لا ننوي فعله |
AUDIT.md |
كيف بُني المشروع: كل خطوة وأمر ونتيجة بوابة |
CONTRIBUTING.md |
كيف تضيف ترجمة أو تصلحها، والفحوص التي يشغّلها CI |
tests/verify-rtl.mjs |
٦٧ اختباراً سلوكياً لطبقة الاتجاه على محاكي DOM |
tests/verify-locales.mjs |
سلامة الكتالوج وعقد الملف وتسجيل اللغة |
data/card-pins.json |
شكل بطاقة السؤال (المُعرِّف والعلامات وصفّ flex)، يُعاد التحقق منه من app.asar المثبَّت (خطوة إصدار) |
التطوير
npm test # الاتجاه (67) + الترجمة (32) + المصفوفة الذهبية (45) + الخطوط (28)
npm run check # الاكتمال + تدقيق الاتساق + المصفوفة الذهبية
npm run build # إعادة توليد lib/client.js
npm run status # التغطية مقابل مرجع upstream المسجَّل
مواكبة التحديثات الرسمية
سير عمل أسبوعي (.github/workflows/upstream-sync.yml)
يعيد استخراج مجموعة المفاتيح الرسمية ويفتح PR بالمفاتيح الجديدة وحدها، فيصل
الانحراف كفرق قابل للمراجعة لا كمفاجأة:
GITHUB_TOKEN=$(gh auth token) npm run extract # تحديث data/en-catalog.json
node scripts/build-client.mjs --check # سرد كل مفتاح غير مترجم
npm run status # التغطية + مرجع upstream
المفاتيح الناقصة تعود للإنجليزية وقت التشغيل — فتحديث جزئي لا يكسر الواجهة أبداً. انظر CONTRIBUTING.md وخطة الطريق.
التوافق
مُختبَر على DSH 0.2.0-rc.2 (تطبيق الديسكتوب) و0.2.1-alpha.2 (نسخة ويب
مخدومة بـdsh web). الوجهان يستخدمان التقاطعين الداخليين الموثّقين نفسهما — الحدث
webserver/index-inject وخدمة locale في العميل — ويتدهور البلاقن بأمان إن تغيّر
أحدهما: طبقة الاتجاه مُغلَّفة فلا تكسر أبداً عرض الفهرس، وحزمة اللغة تتوقف عن
التسجيل فحسب. وفي نسخة الديسكتوب يُجمَع جدول الحقن مرة واحدة عند إقلاع المضيف،
فالمطلوب إعادة تشغيل لا تحديث صفحة.
ومنذ 0.2.1 صار للتطبيق دور خطوط يختاره المستخدم (نص الواجهة، الكود، طرفية
الشريط الجانبي): يكتب التطبيق ما تختاره في --dsh-font-family-text على body،
فتُسمّى قطعنا احتياطياً لذلك المتغيّر — خطٌّ تختاره يتقدّم، وقطعنا يرسم ما لا
يرسمه (العربية عادةً)، وحقلٌ فارغ يُبقي ثمانية في المقدّمة. والمتغيّر يُقرأ ولا
يُعرَّف أبداً، وهذا الترتيب مُثبَّت في tests/verify-fonts.mjs.
التفاعل مع بلاقنز عربية/RTL أخرى. بلاقننا وdsh-client-ui-rtl أو
dsh-rtl-fix كلاهما يضبط dir على كتل المحتوى؛ وتثبيت اثنين معاً يعني تناوبهما
ويفوز آخر كاتب. مفتاح الإعدادات في «عام» يوقف طبقتنا، وهو الطريق النظيف للجمع
بينهما. وكذلك تسجيل لغتين بالمعرّف ar (يفعله @mimateinn/dsh-i18n بتغطية
مختلفة) سيتنازع على المعرّف نفسه — اختر واحداً.
المصطلح. «بلاقن» اختيار واعٍ: هي الصيغة التي يستخدمها المطوّرون العرب في
كلامهم، بينما يبقى plugin في النطاقات التقنية (أسماء الحزم، المسارات، مخرجات
الطرفية). وإن فضّلت الكلمة اللاتينية في الواجهة فالقاموس على بعد تعديل واحد —
انظر CONTRIBUTING.md.
الشكر والتوثيق
- نصوص الواجهة وأسماء المفاتيح من deepseek-ai/deepseek-harness (رخصة MIT).
- نهج هيمنة الكلمات وقاعدة «المُعرِّف الواحد كلمة واحدة» يتبعان الإجماع المجتمعي الذي بدأه haythamat/dsh-client-ui-rtl (رخصة MIT)، وهذا التنفيذ مستقل.
- الترجمات العربية في هذا المستودع عمل أصلي، منشورة تحت رخصة MIT.
الرخصة
MIT — انظر LICENSE.