Skip to content

Releases: SMSMy/dsh-arabic

v0.4.6

Choose a tag to compare

@SMSMy SMSMy released this 17 Oct 07:47

حزمة اللغة لا تسقط كلها إذا غاب موديول من المضيف

كان نصف العميل في المتصفح يسجّل صفّ الإعدادات في «عام» باستدعاءين بلا حماية
لـ react ومكتبة عناصر DSH (@deepseek-ai/dsh-client-ui-primitives). فلو غاب
أحد الموديولين من نسخة قادمة، أو وُجد لكن بلا Switch صالح، سقط تسجيل الصفّ
وابتلع السياقُ الخطأَ بلا رسالة: يختفي الصفّ من الإعدادات ولا تعرف السبب.

صار الاستدعاءان خلف حماية واحدة:

  • غيابهما لا يمسّ التعريب. اللغة تُسجَّل أولًا ومستقلّةً عن هذا الصفّ،
    فتبقى النطاقات الستون ونصوصها الـ3,307 تعمل كما هي.
  • يسقط صفّ الإعدادات وحده، وتُطبَع رسالة تحذير واحدة في الطرفية
    (console.warn) تحمل نصّ خطأ المحمّل نفسه، فتعرف ما نقص بدل أن تبحث.
  • الموديول الموجود بلا Switch صالح يأخذ المسار نفسه، فلا يتحوّل تغيّر اسم
    عنصر واجهة إلى عطل صامت.

فالعقد الآن: ما غاب من المضيف يكلّف صفّ الإعدادات، ولا يأخذ التعريب معه.

لا تغيير في قواعد الاتجاه ولا في الترجمة ولا في الخطوط.

بيانات الأثبُتات

  • بطاقة السؤال: أُعيد فحصها على DSH المثبَّت 0.2.1-rc.1 فمرّت 9/9،
    وسُجِّل الإصدار الجديد في data/card-pins.json (0.2.1-rc.1 / 2026-10-17).
  • الوميض: سجلّه بقي على 0.2.0-rc.2 (2026-10-05) ولم نُحدّثه، لأن فحصه على
    0.2.1-rc.1 لا ينجح: حزمة العناصر لم تعد تُشحن كمجلد مستقل داخل app.asar
    (صارت تُدمج في أصول الواجهة)، فلا يجد الفحص ملفّ المصدر المثبَّت ويفشل في تلك
    الحالة وحدها (5/6)؛ أما فحوص الأسماء المخدومة في الأنماط والسكربت فتمرّ كلها.
    نذكره بصدق ولا ندّعي تحديثه.

بوابات هذا الإصدار: الفهرس 60 نطاقًا / 3,307 نصًا مكتمل (0 مفقود، 0 زائد) —
103 قيمة تحمل {count} مثبَّتة و0 ملاحظة — runtime-peer يقبل 0.2.1-rc.1 —
67/67 اتجاهًا — 32/32 ترجمة — 45/45 ذهبية — 28/28 خطوطًا — bench 1034 ضمن الحد —
browser 10/10 — والملف المولَّد lib/client.js مطابق لمصدره.


English (short): The browser half now loads react and
@deepseek-ai/dsh-client-ui-primitives behind a guard: if either module is
missing — or resolves without a usable Switch — the Arabic pack still installs
all 60 namespaces / 3,307 keys, only the General-settings row is skipped, and a
single console.warn carries the loader's own reason instead of the error being
swallowed. The question-card pins were re-verified on the installed
0.2.1-rc.1 (9/9) and data/card-pins.json now records it. The shimmer record
stays at 0.2.0-rc.2: on 0.2.1-rc.1 the primitives package no longer ships as
its own directory inside app.asar (it is compiled into the frontend assets),
so the pinned module-source check cannot pass — the served-name checks still do.
Direction, translation and font behaviour are unchanged.

v0.4.5

Choose a tag to compare

@SMSMy SMSMy released this 17 Oct 07:15

لا سقف أعلى لنسخة DSH — التحديثات القادمة لن تمنع تشغيل الإضافة

كان نطاق الأقران المعلَن يحمل سقفًا أعلى، فإن انتقل DSH إلى إصدار أحدث —
1.0.0 أو ما بعدها — استُبعدت الإضافة عند التركيب بلا سبب ظاهر، مع أن معظم
تحديثات DSH لا تمسّ نقاط التكامل التي تستعملها هذه الإضافة. هذا الإصدار يرفع
السقف كليًا:

>=0.2.0-0 <0.2.1-0 || >=0.2.1-0

أي أن كل نسخة DSH عند 0.2.0 أو أحدث تُقبل — بما فيها 0.3.0 و1.0.0
و2.5.0 — وما هو أقدم من الأرضية 0.2.0-0 وحده يُرفض.

ما يبقى واقيًا

بوابة check-runtime-peer صارت بوابة أرضية وتنبيه: تفشل فقط تحت الأرضية،
وتُنبّه — من دون أن تمنع — إذا كانت نسخة DSH المشغَّلة أحدث من آخر نسخة مُختبرة
مسجَّلة في data/tested-runtimes.json (أحدثها اليوم 0.2.1-rc.1). فتكون على
علم إن كنت على أرض لم تُختبر، بدل أن يُمنع التشغيل بصمت.

لا تغيير في قواعد الاتجاه ولا في الترجمة ولا في الخطوط — سياسة التثبيت
وحدها تغيّرت، وأُعيد تشغيل البوابات كلها.

بوابات هذا الإصدار: الفهرس 60 نطاقًا / 3,307 نصًا مكتمل — runtime-peer يقبل
0.2.1-rc.1 داخل النطاق المسجَّل — 67/67 اتجاهًا — 32/32 ترجمة — 45/45 ذهبية —
28/28 خطوطًا — bench 1034 ضمن الحد — browser 10/10.


English (short): The declared peer range no longer has an upper ceiling —
>=0.2.0-0 <0.2.1-0 || >=0.2.1-0 accepts every DSH runtime at or above 0.2.0
(0.2.1-rc.1, 0.3.0, 1.0.0, 2.5.0) and refuses only what is below the
floor. check-runtime-peer now fails below the floor and only warns — never
blocks — when the runtime is newer than the newest exercised version recorded in
data/tested-runtimes.json. Direction, translation and font behaviour are
unchanged.

v0.4.4

Choose a tag to compare

@SMSMy SMSMy released this 17 Oct 05:31

نسخ 0.2.1-alpha لم تعد تُستثنى عند التركيب

إن كنت تستخدم DSH من سلسلة 0.2.1-alpha، فقد تعثّرت معك الحزمة بلا سبب ظاهر:
نطاق الأقران المعلَن سابقًا (>=0.2.0-0 <1) لا يقبل تلك النسخ بقاعدة semver
التي يعمل بها npm
، فيستبعدها npm أو pnpm عند التركيب، بينما المضيف نفسه (وهو
يقيّم النطاق بقاعدة أوسع) كان يقبلها — فبدت المشكلة كأن الحزمة «لا تُركَّب» بلا
رسالة مفهومة.

نطاق الأقران صار:

>=0.2.0-0 <0.2.1-0 || >=0.2.1-0 <1

أي أن نسخ 0.2.1-alpha.* صارت داخل النطاق، مع بقاء ما كان مقبولًا من قبل
(0.2.0-rc.2 وما بعدها) وبقاء 1.0.0 خارجًا. لا يتغيّر شيء لمن هو على
0.2.0-rc.2 أو على أي إصدار مستقر: نفس السلوك ونفس البوابات.

لا تغيير في قواعد الاتجاه ولا في الترجمة ولا في الخطوط — هذا إصدار تصحيح
تثبيتٍ، ومع ذلك أُعيد تشغيل البوابات كلها عليه.

للمطوّرين

  • محلّل النطاق في check-runtime-peer صار يفهم || (أي فرعٍ يتحقّق يكفي)،
    ويحكم على النطاق تحت دلالتَي npm والمضيف معًا، فلا يمرّ نطاق يقبله أحدهما
    ويرفضه الآخر.
  • اختباراته الذاتية صارت 13 حالة مسجَّلة تُقاس تحت الحاكمين، و9 صيغ غير مدعومة
    تُرفض، ومقارنة متقاطعة مع semver 7.8.5 على 240 تركيبة نسخة/نطاق/حاكم تتطابق
    تمامًا.
  • screenshots.json جديد في الجذر: صورتان نسبيتان داخل المستودع
    (docs/question-card.png وdocs/direction.png) لبطاقة السوق.
  • وصف المستودع على GitHub صُحّح إلى العدد الحالي: 3,307 نصًا.

بوابات هذا الإصدار: الفهرس 60 نطاقًا / 3,307 نصًا مكتمل — runtime-peer يقبل
0.2.0-rc.2 تحت الحاكمين — 67/67 اتجاهًا — 32/32 ترجمة — 45/45 ذهبية —
28/28 خطوطًا — bench 1034 ضمن الحد — browser 10/10.


English (short): The declared peer range now accepts the 0.2.1 prerelease
line — >=0.2.0-0 <0.2.1-0 || >=0.2.1-0 <1 — so npm and pnpm no longer exclude
the package on 0.2.1-alpha.* installs (the host had always accepted them).
Direction, translation and font rules are unchanged. The runtime-peer guard now
reads ||, judges under both npm and host semantics, and covers 13 recorded
cases under both judges plus a 240-combination cross-check against semver 7.8.5;
screenshots.json was added for the plugin listing, and the repository
description now reads 3,307 strings.

v0.4.3

Choose a tag to compare

@SMSMy SMSMy released this 17 Oct 05:01

الإصدار 0.4.3 — حرّاسٌ تحمي الطبقة، ولا تغيير في شكل النص

هذا إصدار تحصين: لا تتغيّر فيه قواعد الاتجاه التي تعرفها — الجمل والعناوين والقوائم والجداول تُعرض كما كانت — بل تُضاف حرّاس تمنع أن تختفي الطبقة أو تتراجع جودتها بصمت.

الأهمّ لك قبل التحديث

  • الإضافة تعلن الآن أنها تعمل مع DSH من 0.2.0 إلى ما قبل 1.0 — بما في ذلك 0.2.1-alpha.5. إن كان إصدار DSH خارج هذا النطاق يرفض المضيف تشغيل الإضافة، فلا تبدو الصفحة «بلا اتجاه» لسبب مجهول. (في 0.2.1-alpha.5 صار المضيف يطبع سبب الاستبعاد في سجل التشغيل؛ وفي الأقدم منه قد يبقى صامتًا.)
  • لا إعداد جديد: ثبّت وحدّث الصفحة. وإن لم تظهر طبقة الاتجاه بعد التحديث أعِد تشغيل DSH — لأن قرار تحميل الإضافة يُتخذ عند الإقلاع، بخلاف جدول الحقن الذي يُبنى مع كل تحميل للصفحة.

ما الجديد

  • فحص توافق النسخة قبل النشر: يقرأ نسخة التطبيق المثبَّتة من ملفّها الفعلي (app.asar) لا من dsh --version، ويفشل إن كان النطاق المعلَن لا يقبلها.
  • حارس أداء: قياس ثابت لكلفة تمريرة الاتجاه (1034 قراءة نمط) لا يُسمح بتجاوزه، مربوط بسير الفحص الآلي.
  • اختبار متصفح حقيقي: قرارات الاتجاه تُرسم في Chromium وتُقاس مواضع المحارف من التخطيط نفسه، لا من السمة وحدها.
  • حارس صيغ الجمع: كل نص يحمل {count} مُثبَّت صراحةً (103 قيم) كي لا تتسرّب صيغة لا تصحّ لكل الأعداد.
  • متانة في الطبقة بلا تغيير أي قرار اتجاه: بايتات الخطوط تُخدَم من الذاكرة، ولا يُزال إلا الاتجاه الذي كتبناه نحن، ولا تُسقَط كتلة عند ازدحام الطابور، ولا يُعاد وزن النص كله مع كل ضغطة، وأصبح إصدار الطبقة ظاهرًا للتشخيص في window.__dshArabic.version.
  • كُشفت حزمة الترجمة ./locales/* للأدوات التي تريد قراءتها مباشرة.

أرقام هذا الإصدار

60 نطاقًا و3307 نصًا مكتملة · 67/67 فحص اتجاه · 32/32 فحص لغة · 45/45 حالة ذهبية · 28/28 فحص خط · الأداء 1034 ضمن الميزانية · المتصفح 10/10 · فحص نسخة المضيف: مقبول على 0.2.0-rc.2 و0.2.1-alpha.5.


English: the direction rules are unchanged; this release adds guards against a silent plugin exclusion, a deterministic performance gate, a real-Chromium layout test, and a {count} review register. See README.en.md.

v0.4.2 — the app's font choice leads

Choose a tag to compare

@SMSMy SMSMy released this 10 Oct 22:42

The app's font choice leads, and the cuts stay behind it

DSH 0.2.1 gives General settings a font role per surface — interface text, code,
and the sidebar terminal — and turns --dsw-font-family into an indirection of
its own: on body it carries --dsh-font-family-text (the family you chose)
ahead of the built-in stack, and the boot script writes that variable only while
the field is not empty.

This release stops replacing that variable and names its three cuts after it
instead — var(--dsh-font-family-text, var(--dsh-arabic-sans)), var(--dsh-arabic-sans),
the app's own "list then stack" order. A family you choose leads; the shipped cut
still answers for every glyph that family cannot draw (Arabic, usually, when the
choice is a Latin one); an empty field leaves thmanyah in front. The variable is
read and never declared, so an explicit choice is never shadowed. On 0.2.0-rc.2,
where the variable does not exist, every declaration resolves to the cut exactly
as before.

Also in this release:

  • the official key set was re-extracted at d7432673: 60 namespaces / 3,307 keys
    (85 added, 6 removed), and all 85 are translated — the new font rows, the
    work-details collapse setting, the whole cotTranslation namespace of the
    experimental reasoning-translation plugin, and plugin-manager, microphone,
    subagent and workspace strings. Coverage is 3,307/3,307 again.
  • the extractor's cache is keyed by the commit it measures: one cache shared
    across revisions had hidden 47 keys of 0.2.1-alpha.2's restructured
    settings.theme dictionary.
  • verified on a served 0.2.1-alpha.2 instance, not only against published
    assets: the activity mirror's hashed names are unchanged (_sweep_1rdzk_34 …),
    the question card keeps data-question-key, builds its own <header>/<footer>
    and keeps flex option cells — and the layer marks the option's two text cells
    (data-dsh-arabic-bidi, dir="rtl", unicode-bidi: isolate) while leaving the
    option control and its number badge alone. The composer still reports
    dir="auto" kept, our marker set, direction: rtl.

Suites behind this release: 67 bidi + 32 locale + 45 golden + 28 font checks.


بالعربية: صار للتطبيق في DSH 0.2.1 دورُ خطوطٍ يختاره المستخدم — نصُّ الواجهة، والكود، وطرفية الشريط الجانبي — وصار --dsw-font-family وسيطًا داخليًا: يحمل على body قيمة --dsh-font-family-text (الخط الذي اخترته) قبل حزمة التطبيق المدمجة، ولا يكتب التطبيق ذلك المتغيّر إلا إذا كان الحقل غير فارغ.

في هذا الإصدار لم نعد نستبدل ذلك المتغيّر، بل نسمّي قطعنا الثلاث بعده: خطُّك المختار يتقدّم، وقطعنا ترسم كل محرف لا يرسمه (العربية عادةً إن كان اختيارك خطًّا لاتينيًا)، والحقل الفارغ يُبقي ثمانية في المقدّمة. والمتغيّر يُقرأ ولا يُعرَّف، فلا يُظلَّل اختيارٌ صريح أبدًا. وعلى 0.2.0-rc.2 — حيث لا وجود للمتغيّر — تُحلّ تعريفاتنا كلها إلى القطع كما كانت تمامًا.

ومع الإصدار:

  • أُعيد استخراج فهرس المفاتيح الرسمي عند d7432673: 60 نطاقًا · 3,307 نصًا (85 جديدًا و6 محذوفة)، وتُرجمت الخمسة والثمانون كلها — صفوف الخطوط الجديدة، وإعداد طيّ تفاصيل العمل، ونطاق cotTranslation كاملًا لبلاقن ترجمة الاستدلال التجريبي، ونصوص مدير البلاقن والميكروفون والوكلاء الفرعيين ومساحات العمل. والتغطية عادت 3,307/3,307.
  • ذاكرة المُستخرِج صارت مفتاحةً بالالتزام المقيس، بعد أن كانت ذاكرةٌ واحدة مشتركة بين المراجعات تُخفي 47 مفتاحًا من إعادة هيكلة settings.theme في هذا الإصدار.
  • التحقق جرى على نسخة مخدومة من 0.2.1-alpha.2 لا على الأصول المنشورة وحدها: أسماء الوميض المُجزَّأة كما هي (_sweep_1rdzk_34 …)، وبطاقة السؤال محتفظةٌ بعلامتها وبـheader/footer وبصفوفها المرنة، والطبقة تسم خليّتي النص وحدهما وتترك زرّ الخيار وشارة رقمه في مكانهما. ومربّع الكتابة ما زال يُبقي dir="auto" مع علامتنا وdirection: rtl.

المجموعات خلف هذا الإصدار: 67 اتجاهًا + 32 ترجمة + 45 حالة ذهبية + 28 فحصًا للخطوط.

v0.4.1 — the composer's own direction

Choose a tag to compare

@SMSMy SMSMy released this 09 Oct 21:55

The composer's own direction

Lexical writes dir="auto" on every composer paragraph, and auto means "browser, decide by the first strong character". A line that opened with a Latin token or a quotation — "npm install" ثم أعد التشغيل — therefore stayed left-to-right and left-aligned although the sentence is Arabic. The direction layer decides whole blocks, and the block path had been told never to touch a dir the app wrote, so the composer kept its own rule and the earlier quotation fix could not reach it.

auto is not an authored direction — it is a delegation, and this layer exists to decide better than the first strong character. Inside a contenteditable the estimator now takes that decision over: the marker's direction/unicode-bidi beat the attribute, which is only a presentational hint, and the app's own value stays exactly where it was, so restoring the original — or switching the layer off — gives the line back untouched. A paragraph that is already Arabic was RTL before and still is, and an English paragraph in the same composer is untouched.

Measured in a real browser against a running web session with the Arabic UI, typing "npm install" ثم أعد التشغيل بعد التثبيت into the composer reports: dir="auto" (the app's own, kept) · marker set · direction: rtl · unicode-bidi: isolate · text-align: start.

Suites behind this release: 67 bidi + 32 locale + 45 golden + 29 font checks.


بالعربية: كان محرّر المحادثة في DSH يضيف dir="auto" إلى كل فقرة، أي أنّ المتصفح هو من يحدّد اتجاه السطر انطلاقًا من أول حرف واضح الاتجاه. لذلك كان السطر الذي يبدأ بعلامة اقتباس أو بكلمة لاتينية يُعرض من اليسار إلى اليمين وإن كانت جملته عربية.

الآن صار تحديد الاتجاه داخل مربّع الكتابة قائمًا على الكلمات، مع الحفاظ على قيمة dir التي كتبها التطبيق. وعند إيقاف الطبقة أو العودة إلى النص الأصلي يعود السطر إلى حاله الأولى كما كان.

وقد تحققنا من ذلك في متصفح فعلي ضمن جلسة عربية.

v0.4.0 — three thmanyah cuts, and paths that read in order

Choose a tag to compare

@SMSMy SMSMy released this 09 Oct 21:18

Three cuts of thmanyah in the three roles the family is drawn for, and two reading rules the bidi layer had backwards.

Typography. Sans is the interface default, Serif Text carries long-form reading (markdown paragraphs, list items, quotations) and Serif Display takes the headings. The roles ride on --dsw-font-family — the one variable every typography token in the app's theme resolves through — plus one element rule each. The nine weights (400/500/700 per cut) are served from /dsh-arabic/fonts/v0.4.0/… on the app's own web server rather than inlined: the Desktop shell loads its page from http://127.0.0.1:<port>, so one same-origin URL covers both shells and the page carries nine short @font-face rules instead of a megabyte of base64. The fonts ship in fonts/ with both license texts, unmodified; point DSH_ARABIC_FONTS at your own copy, or at an empty directory to keep the app's own stack.

Direction. A Windows path is a code token even when a folder inside it is Arabic: the separator class knew / but not \, and the RTL test ran before the code test, so a listed path counted as Arabic prose — the block flipped to RTL and the bidi algorithm re-ordered the path's own Latin runs around that word, which is what made a list of paths read backwards. Code now votes before prose, and a block of paths stays LTR with every path reading in its own order. A double-quoted span is also one unit now: it cannot outvote the Arabic sentence holding it, and an unclosed quotation (a streamed answer) runs to the end of the text, which is the unit its closed form will produce.

Also. The browser half stops pasting a second copy of the stylesheet the host already injected as an index row (that row carries no id), which with nine embedded faces had been a third of a megabyte duplicated in every page. This repository's README now lands in Arabic, with an English twin at README.en.md.

Confirmed live in the Desktop app after a restart: the three cuts land on their roles, and a quoted Windows path that used to read backwards reads in order.

Suites behind this release: 64 bidi + 32 locale + 45 golden direction + 29 font checks (npm test), plus the completeness, consistency, doc-count, bidi-family and card/shimmer pin gates in npm run check.


بالعربية: ثلاث قطع من خط «ثمانية»، لكلٍّ منها موضعه: «سانس» لواجهة التطبيق، و«سيريف تيكست» لنصوص القراءة، و«سيريف ديسپلاي» للعناوين؛ وتُخدَم من خادم التطبيق نفسه بدل تضمينها داخل الصفحة.

كما صار مسار ويندوز يُعامَل رمزًا تقنيًّا فلا يظهر مقلوبًا، والنص الواقع بين علامتَي اقتباس يُحتسب وحدة واحدة.

وقد تحققنا من ذلك حيًّا في تطبيق الديسكتوب بعد إعادة تشغيله.

dsh-arabic 0.3.2

Choose a tag to compare

@SMSMy SMSMy released this 07 Oct 01:50

The composer's question card reads in order.

The question card the assistant asks with was the one content surface the layer
never reached: it stayed LTR while everything around it was Arabic. Confirmed live
in the Desktop app after a restart — the same question that read backwards in the
report now reads in order, with mixed punctuation and Latin tokens mid-sentence.

  • a blockified text cell now takes a direction of its own. DSH draws each option
    as a flex <button> whose label and description are <span>s, and the walk
    treated every inline-by-default tag as part of the flow around it — landing on the
    button, which is a flex row that owns a control, and giving up. A flex item is a
    text block in its own right: each cell is marked, so ادفع fix/rust-flake كما هو
    reads in order instead of backwards, and the row keeps its number badge where the
    design put it. The probe reads a style only when the walk found nothing usable, so
    prose costs exactly what it did (--bench 1000: 2,031 → 1,031 style reads over
    2,000 elements, against 1,026 before the change);
  • a content card's own <header>/<footer> no longer read as shell chrome. The
    question sits in the card's <header>, so the landmark-tag half of the chrome test
    was suppressing it — the question stayed left-aligned and its mixed runs stayed in
    LTR order. Roles still settle chrome first; the tags now yield inside a card whose
    frame carries data-question-key, the one app marker this layer reads. Every
    landmark outside the card — the session header, the sidebar, the settings panels —
    is unchanged (a shell <header> is asserted untouched in the suite);
  • a control is never given a direction of its own. Exempting the card's
    <footer> exposed the next shape: its action buttons are blockified flex items
    carrying Arabic, so they became candidates — and a marked flex button reverses its
    icon and label, while a centred label jumps to an edge when the alignment is
    overridden. Buttons, selects and role=button/radio/switch/… now stop the walk for
    the text inside them but are never marked themselves. Measured on a regression board
    in Chromium: four text cells gained a direction and no element moved, including
    the composer's send button and the card's pager;
  • data/card-pins.json + scripts/check-card-pins.mjs <app.asar> record what this
    was verified against in the shipped app (the marker, the card's landmark tags, and
    the flex row whose cells are spans) and fail, naming the difference, when a build
    moves any of them — a rename here is otherwise silent, which is how this shipped
    broken. tests/verify-rtl.mjs grows eight checks around the same shapes: 55 → 63.

dsh-arabic 0.3.1

Choose a tag to compare

@SMSMy SMSMy released this 05 Oct 12:28

The activity mirror now reaches the DOM.

The activity light was mirrored in the stylesheet and never in the browser.

  • the mirror reaches the DOM again. The frontend build renames every CSS module
    class, so the app's .sweep ships as _sweep_1rdzk_34: the selectors added in
    0.2.7 matched nothing, and the light kept travelling left to right in Arabic. They
    now take the hashed stem ([class*="_sweep_"]) as well as the plain class, and
    data/shimmer-pins.json records the names this was verified against —
    scripts/check-shimmer-pins.mjs <app.asar> fails, naming the difference, when a
    build renames them, while tests/verify-rtl.mjs fails if the selector shape is
    dropped;
  • the locale gate has an owner. html:lang(ar) depends on the app pointing
    <html lang> at the active locale — it does, and that is the right source. The
    browser half now also writes data-dsh-arabic-locale from the same snapshot and
    removes it on unload, so a change on that internal cannot kill the mirror silently;
  • docs/shimmer-compare.html renders the class names the frontend ships. The old
    figure compared two mock cells, so it would have shown a mirror that did not exist;
    measured now: at a frozen instant the bright band covers 19–56% of the English line
    and 46–82% of the Arabic one;
  • prefers-reduced-motion stays the app's: the mirror only renames an animation, so
    the app's animation: none still owns duration and delay, and a test now forbids
    this plugin from declaring timing of its own. Forced colours is handled neither
    here nor upstream — the Arabic layers behave exactly as the English ones;
  • the live-status comment says the ellipsis keeps to the logical end (the right
    inside an LTR isolate), which is what the isolate actually does.

Gates: npm run check green — 3228/3228 keys · 55/55 direction · 32/32 locale · 30/30 golden · live-status family on record · docs mismatch 0. The activity-mirror names were re-verified against the installed app: 8/8 pins.

dsh-arabic 0.3.0 — the measured performance pass

Choose a tag to compare

@SMSMy SMSMy released this 05 Oct 11:40

The performance pass, measured before it was written.

The harness

node tests/verify-rtl.mjs --bench [blocks] builds a streamed page and reports two numbers for one full pass: wall time, and how many style reads the pass performs. In a browser a style read is a reflow, so the count is the honest metric — the shim's own style read is free, and the unchanged wall clock is exactly what that predicts.

Before and after (2,000 elements)

style reads wall (shim)
before 3,546 ~33 ms
after 2,027 (−43%) ~33 ms

What changed

  • one walk per block: blockInfo() returns the text to weigh and whether the block holds Arabic; two functions used to walk every subtree twice;
  • pass-scoped caches for the computed display and for the interactive-control query — created at the top of a pass and dropped at the end, so nothing can go stale when a class change turns a block into a flex row between passes;
  • inline-by-default tags are walked past without a style read: a page of prose is mostly spans inside blocks, and each read is a reflow;
  • scan() uses a Set instead of a linear indexOf;
  • LATIN_CHAR uses \p{Script=Latin}.

Suites: direction 52, locale 28/28, golden 30 — unchanged, which is the point of a performance change. Published through trusted publishing (OIDC) with a provenance attestation.

بالعربية: قِسْتُ قبل أن أُحسّن: المنظومة تُنشئ 2000 عنصر وتُبلّغ عن قراءات النمط (وكل قراءة إعادة تخطيط في المتصفح). النتيجة: 3546 ← 2027 قراءة (−43%)، والزمن على المحاكاة ثابت لأن قراءة النمط فيها مجانية — وهذا بالضبط ما يتوقّعه القياس. التغيير: جولة نص واحدة بدل اثنتين، ذاكرة بعمر تمريرة واحدة، تجاوز العناصر المضمّنة بلا قراءة نمط، Set بدل indexOf.