# تقسيم الكلمات وضبط الأسطر

> كيف يقسّم Postext الأسطر ويضبط النص ويتحكم في التباعد بين الكلمات بخوارزمية Knuth-Plass

- نسخة HTML: https://postext.dev/ar/docs/justification
- آخر تحديث: 2026-09-29
- مدة القراءة: 14 دقيقة
- لغات أخرى: [en](https://postext.dev/en/docs/justification.md), [es](https://postext.dev/es/docs/justification.md), [ca](https://postext.dev/ca/docs/justification.md), [zh](https://postext.dev/zh/docs/justification.md)

## باختصار

تشرح هذه الصفحة كيف يوزّع Postext الكلمات على كل سطر. حين تكون حافتا الفقرة مستقيمتين، قد تتسع الفراغات بين الكلمات أكثر من اللازم فيسوء مظهرها. ينظر Postext إلى الفقرة كلها قبل أن يقرر أين ينتهي كل سطر، فتبقى الفراغات متقاربة. ويستطيع أيضًا أن يقسم الكلمات الطويلة بواصلة في الموضع الصحيح. يمكنك أن تحدد إلى أي حد تتسع الفراغات، وأن تميّز الأسطر التي ما زالت فراغاتها واسعة. وتبيّن الصفحة كذلك كيف يجعل Postext الأعمدة تنتهي عند الارتفاع نفسه.

**الفرق بين التنضيد الهاوي والتنضيد المحترف يكمن في المسافات بين الكلمات.**

افتح أي رواية ذات غلاف ورقي. النص مضبوط: حافتا كل فقرة على استقامة واحدة تمامًا. لكن انظر عن قرب. المسافات بين الكلمات متساوية تقريبًا، سطرًا بعد سطر. لا أنهار من البياض تجري على طول الصفحة، ولا أسطر تقف فيها كلمتان منعزلتين يفصل بينهما فراغ شاسع. بلوغ هذا أصعب بكثير مما يبدو، وهو المسألة الواحدة التي استهلكت من جهد الهندسة الطباعية أكثر من أي مسألة أخرى.

يحلّها Postext بالخوارزمية نفسها التي يستعملها TeX منذ 1981: **تقسيم الأسطر الأمثل بخوارزمية Knuth-Plass**. ومع أنماط تقسيم الكلمات بجودة TeX، وحدود قابلة للضبط للتباعد بين الكلمات، ونظام تصحيح مرئي يكشف الأسطر المعيبة، ينتج المحرّك نصًا مضبوطًا يفي بمعايير النشر.

## المشكلة

حين يُنضَّد النص بالإعداد `textAlign: 'justify'`، يجب أن يُمدَّ كل سطر ما عدا الأخير أو يُضغط حتى يملأ عرض العمود بالضبط. يوزّع المحرّك الفرق بين العرض الطبيعي للمحتوى وعرض العمود على المسافات بين الكلمات في ذلك السطر. (يُترك السطر الأخير غير مضبوط بعرضه الطبيعي، مع استثناء واحد يتناوله قسم [السطر الأخير](#السطر-الأخير).)

إن كان في السطر كلمات كثيرة، تمتص كل مسافة تعديلًا ضئيلًا لا يراه القارئ. أما إن كانت كلماته قليلة (لأن كلمة طويلة فرضت قطع السطر مبكرًا)، فلا بد أن تتمدد كل مسافة تمددًا كبيرًا. والنتيجة **سطر متخلخل**: سطر اتسعت فيه المسافات بين الكلمات حتى أربكت إيقاع القراءة وأحدثت فجوات قبيحة للعين.

والمشكلة المعاكسة قائمة أيضًا. فإذا حشر المحرّك في السطر كلمات أكثر من اللازم، انكمشت المسافات دون عرضها الطبيعي، فينتج **سطر مضغوط** تبدو فيه الكلمات متزاحمة.

خوارزمية تقسيم الأسطر الساذجة، من النوع الذي تستعمله CSS، تتخذ قراراتها سطرًا سطرًا. تملأ السطر الحالي بأكبر عدد ممكن من الكلمات، ثم تقطعه وتمضي. ولهذا النهج **الجشع «أول ملاءمة» (greedy first-fit)** ضعف جوهري: لا يستطيع أن يرى ما سيأتي. قرار يبدو أمثل للسطر 5 قد يفرض على السطر 6 قطعًا رديئًا. وحين تصل الخوارزمية إلى السطر 6 يكون الأوان قد فات، فالسطر 5 قد ثُبِّت.

## Knuth-Plass: النظر إلى الفقرة كاملة

خوارزمية Knuth-Plass، التي نشرها Donald Knuth وMichael Plass عام 1981، تسلك طريقًا مختلفًا جذريًا. فبدلًا من قطع سطر واحد في كل مرة، تنظر في **كل الطرق الممكنة لتقسيم الفقرة كلها**، وتختار التركيبة التي تجعل مجموع «الرداءة» (badness) في كل الأسطر في حدّه الأدنى. إنها الخوارزمية التي يقوم عليها TeX، ولهذا ظلت المستندات المنضدة بـTeX المعيار الأعلى للنص المضبوط أكثر من أربعة عقود.

### نموذج الصندوق والغراء والجزاء

لا تفكر Knuth-Plass بمنطق الكلمات والمسافات، بل تمثّل النص سلسلةً من ثلاثة عناصر أولية:

| العنصر الأولي | ما يمثّله | سلوكه |
| --- | --- | --- |
| **الصندوق (box)** | كلمة أو قطعة من النص | له عرض ثابت. لا يُمَدّ ولا يُضغط. لا يُقسَم. |
| **الغراء (glue)** | المسافة بين الكلمات | له عرض *طبيعي* وقدرة على *التمدد* وقدرة على *الانكماش*. يستطيع المحرّك أن يعدّل الغراء ضمن هذه الحدود ليملأ السطر. |
| **الجزاء (penalty)** | موضع محتمل لقطع السطر | له كلفة. جزاء منخفض = قطع رخيص. جزاء مرتفع = قطع باهظ. والجزاء *الموسوم* يعني موضعًا لتقسيم الكلمة (تضيف واصلة مرئية إن استُعملت). |

فتصير الفقرة سلسلة كهذه:

```
[box "The"] [glue] [box "quick"] [glue] [box "brown"] [glue] [box "fox"]
[penalty -∞]  ← forced break at paragraph end
```

وحين يكون تقسيم الكلمات مفعّلًا، تُقسم الكلمات الطويلة إلى قطع تفصل بينها جزاءات:

```
[box "ty"] [penalty 50, flagged] [box "pog"] [penalty 50, flagged] [box "raphy"]
```

كل جزاء موسوم كلفته 50: ليس مجانيًا، لكنه أرخص من إنتاج سطر متخلخل.

> **شكل: العناصر الأولية: الصندوق والغراء والجزاء**
> مفتاح مرئي للعناصر الأولية الثلاثة: الصندوق لقطعة من كلمة، والغراء للمسافة بين الكلمات، والجزاء لموضع محتمل لقطع السطر. وتبيّن الفقرة المثال كيف يصير موضع تقسيم الكلمة جزاءً موسومًا.
>
> *تتحول كل فقرة إلى سلسلة من الصناديق والغراء والجزاءات.*

### كيف تجد الحل الأمثل

تعتمد الخوارزمية البرمجة الديناميكية. فهي تحتفظ بمجموعة من **العُقد النشطة** (active nodes)، أي مواضع القطع المحتملة التي يمكن أن تبدأ منها أسطر جديدة، وتقيّم كل قطع ممكن انطلاقًا من كل عقدة نشطة. ولكل قطع مرشّح تحسب:

1. **نسبة الضبط (r)**: مقدار ما يحتاجه الغراء في هذا السطر من تمدد أو انكماش. `r = 0` تعني أن السطر يتسع تمامًا. `r > 0` تعني تمددًا (متخلخل). `r < 0` تعني انكماشًا (مضغوط).

2. **الرداءة**: مقياس لمدى تفاوت التباعد، يُحسب بالصيغة `100 × |r|³`. النمو التكعيبي يعني أن السطر المتخلخل قليلًا مقبول، أما السطر المتخلخل جدًا فيُعاقَب بشدة. سطر فيه `r = 2` رداءته 800؛ وسطر فيه `r = 0.5` رداءته 12.

3. **فئة الملاءمة** (fitness class): يُصنَّف كل سطر مضغوطًا (`r < -0.5`) أو عاديًا (`-0.5 ≤ r < 0.5`) أو متخلخلًا (`0.5 ≤ r < 1.0`) أو متخلخلًا جدًا (`r ≥ 1.0`). إذا جاور سطرٌ مضغوط سطرًا متخلخلًا جدًا، كان التباين نافرًا، ولذلك تُعاقَب الأسطر المتجاورة التي تتباعد فئاتها أكثر من درجة واحدة.

4. **نقاط الجزاء** (demerits): الكلفة الكلية للقطع في هذا الموضع. على طريقة TeX، تُجمع الرداءة وجزاء موضع القطع في صيغة تربيعية: `demerits = (1 + badness + penalty)²` حين يكون الجزاء غير سالب؛ أما الجزاء السالب (قطع *مرغوب فيه*) فيُطرح مربعه: `(1 + badness)² − penalty²`. ثم تُضاف فوق ذلك نقاط جزاء ثابتة من نوعين:
   - **نقاط جزاء الواصلات المتتالية** (القيمة الافتراضية 3000): تعاقب سطرين متتاليين ينتهي كل منهما بواصلة، لأن تراكم الواصلات يشتت العين.
   - **نقاط جزاء فئة الملاءمة** (القيمة الافتراضية 100): تُضاف حين تبعد فئة ملاءمة هذا السطر أكثر من درجة واحدة عن فئة السطر السابق.

   وجزاء الكلمة المعزولة الموصوف أدناه يدخل هذه الصيغة أيضًا، إذ يُحقن رداءةً إضافية؛ أما جزاءا اليتيمة والأرملة فيعملان في مرحلة لاحقة، حين تنقسم الفقرة بين عمودين.

تختار الخوارزمية سلسلة القطع ذات المجموع الأدنى من نقاط الجزاء في الفقرة كلها، وهذه هي ميزتها كلها على النهج الجشع.

> **شكل: الرداءة دالةً في نسبة الضبط**
> تنمو الرداءة بمقدار 100 ضعف القيمة المطلقة لـ r مرفوعة إلى القوة الثالثة. التمدد أو الانكماش الطفيف رخيص، أما التمدد الشديد فيصير باهظ الكلفة جدًا، ولهذا تتجنبه الخوارزمية.
>
> *تنمو الرداءة نموًا تكعيبيًا: التفاوت الطفيف مقبول، والتفاوت الكبير يُعاقَب بقسوة.*

> **شكل: فئات الملاءمة**
> يُصنَّف كل سطر مضغوطًا أو عاديًا أو متخلخلًا أو متخلخلًا جدًا بحسب نسبة الضبط فيه. وتُعاقَب الأسطر المتجاورة التي تختلف فئاتها بأكثر من درجة واحدة.
>
> *الأسطر المتجاورة التي تفصل بينها أكثر من فئة واحدة تتحمل نقاط جزاء فئة الملاءمة.*

ثم تتتبع الخوارزمية العُقد النشطة رجوعًا لتجد المسار ذا المجموع الأدنى من نقاط الجزاء، أي مجموعة مواضع القطع المثلى على مستوى الفقرة كلها.

#### جزاءات اليتيمة والأرملة والكلمة المعزولة

يوسّع Postext نموذج الكلفة المعتاد بثلاثة جزاءات تحريرية تُبعد المحرّك عن الإخراجات التي تنتهي فيها الفقرات والأعمدة نهايات رديئة المظهر:

- **جزاء اليتيمة** (orphan) يُطبَّق حين يترك تقسيم مرشّح أقل من `orphanMinLines` من الأسطر في أعلى العمود التالي. القيمة الافتراضية لـ`orphanPenalty` هي `1000`.
- **جزاء الأرملة** (widow) يُطبَّق حين يترك التقسيم أقل من `widowMinLines` من الأسطر في أسفل العمود الحالي. القيمة الافتراضية لـ`widowPenalty` هي `1000`.
- **جزاء الكلمة المعزولة في آخر الفقرة** (runt) يُطبَّق حين يكون السطر الأخير من الفقرة أقصر من نحو `runtMinCharacters × normalSpaceWidth` بكسلًا، وهو عدد من مسافات الكلمات لا من الحروف: القيمة الافتراضية 20 تعني سطرًا أخيرًا من نحو 8 إلى 12 حرفًا. القيمة الافتراضية لـ`runtPenalty` هي `1000`، وهي واحدة لكل كلمة معزولة؛ ومع `gradedRuntPenalty` تتدرج بحسب ما ينقص السطر، `runtPenalty × (1 − width / threshold)`، فتكلّف النهاية ذات الكلمتين أقل من النهاية ذات الكلمة الواحدة، وتفوز حين يستطيع سطر فوقها أن يتخلى عن كلمة. وعلى خلاف اليتيمة والأرملة (اللتين تُضافان خطيًا إلى نقاط الجزاء للتقسيم)، تُحقن الكلمة المعزولة *رداءةً* مكافئة داخل الصيغة التربيعية لـKnuth–Plass، فتتنافس على المقياس نفسه الذي تقاس به رداءة السطر (التي تبلغ حدها الأقصى عند 10000) بدلًا من أن تتضاءل أمامها.

وحين يخسر الجزاء رغم ذلك، أي حين يتعذر كل قطع بديل، يلجأ المحرّك إلى ما يفعله المنضّد بيده: ينضد الفقرة أقصر بسطر واحد (`tightenRunts`). تضيق المسافات بين الكلمات في كل سطر، دون أن تنزل عن `minWordSpacing` أبدًا، وحين لا يكفي ذلك وحده لحمل الكلمات العالقة يُضاف قليل من التتبّع السالب، بأصغر خطوة تنجح، ولا يزيد أبدًا عن `maxRuntTracking` جزءًا من الألف من الـem. ويجب أن يحترم النضد الأقصر `maxWordSpacing` أيضًا. فإدخال الكلمات في سطر أقل يضيّق معظم الأسطر، لكنه قد يزحزح موضع قطع فيضطر سطر آخر إلى التمدد كثيرًا. والنضد الذي يمدّ سطرًا إلى ما بعد `maxWordSpacing`، أو إلى ما بعد أوسع سطر في الفقرة إن كان فيها سطر أوسع من ذلك، ليس إصلاحًا، فتبقى الكلمة المعزولة. ولا يُحتسب إلا الأسطر التي تبقى مضبوطة: السطر الذي تنضده الفقرة غير مضبوط لأنه كان سيتمدد إلى أكثر من 3 أضعاف المسافة العادية (انظر [أسطر يعجز مقسِّم الأسطر عن ملئها](#أسطر-يعجز-مقسِّم-الأسطر-عن-ملئها)) لا يرفع الحد، ولا يجوز للنضد الأقصر أن يجعل أسطرًا غير مضبوطة أكثر مما كان في الفقرة. ولا يستبدل الإصلاح بالسطر غير المضبوط أسطرًا مضبوطة تتجاوز ذلك الحد: تحتفظ الفقرة بسطرها غير المضبوط وبكلمتها المعزولة. وموازنة الأعمدة تتبع القاعدة نفسها في الاتجاه المعاكس: الفقرة التي كانت ستطيلها سطرًا لتملأ عمودًا قصيرًا تُترك على حالها إن كان ذلك السطر الإضافي سينتهي بكلمة معزولة، فملء عمود ليس سببًا لترك مقطع وحيد في آخر الفقرة.

يُضاف جزاء الكلمة المعزولة إلى نقاط الجزاء للعقدة المرشحة داخل مقسِّم الأسطر، فيكون للحلّال أن يقايض سطرًا أكثر تخلخلًا بقليل بسطر أخير أطول، لكن ضمن `maxWordSpacing` فقط: السطر الممدود إلى ما بعد هذا الحد يحمل رداءة إضافية أكبر من أي جزاء لكلمة معزولة أو واصلة، فيفضّل مقسِّم الأسطر سطرًا أخيرًا قصيرًا، أو كلمة أخيرة مقسومة بواصلة، على تباعد بين الكلمات يتجاوز الحد. أما جزاءا اليتيمة والأرملة فيدخلان عملية تحسين منفصلة تجري حين تعبر الفقرة حدود عمود: يُقيَّم كل تقسيم مرشّح، بجمع نقاط الفراغ الزائد واليتيمة والأرملة، ويفوز التقسيم الأرخص، فيفضّل المحرّك تلقائيًا التقسيمات التي تتجنبهما معًا كلما أمكن. اضبط هذه الموازنة بتعديل `orphanPenalty` أو `widowPenalty` أو `runtPenalty`؛ واجعل أيًّا منها `0` لتعطيل القاعدة المعنية تمامًا. وتنضم عناصر القوائم إلى هذه القواعد عبر `avoidOrphansInLists` و`avoidWidowsInLists` و`avoidRuntsInLists` (وكلها `true` افتراضيًا).

### لماذا يهمّ ذلك

> **شكل: النهج الجشع «أول ملاءمة» مقابل الحل الأمثل لـKnuth-Plass**
> رسم متقابل: الخوارزمية الجشعة تأخذ أول سطر يتسع وتفسد الأسطر التالية، فتنتج فقرات غير منتظمة متفاوتة التباعد. أما Knuth-Plass فتقيّم الفقرة كلها تقييمًا شاملًا وتنتج أسطرًا متساوية.
>
> *القرار الجشع المحلي يخسر حيث تربح الخطة المثلى الشاملة.*

الفرق العملي ظاهر للعين. ففي الإخراج الجشع تجد فقرات فيها سطر أكثر تخلخلًا من جيرانه بوضوح، وإن دققت النظر رأيت أن ذلك حدث لأن السطر *السابق* أخذ كلمة زائدة. تتجنب Knuth-Plass هذا بقبول سطر حالي أسوأ قليلًا مقابل سطر تالٍ أفضل بكثير، لأنها ترى العواقب.

### التنفيذ في Postext

ينفّذ Postext خوارزمية Knuth-Plass كاملة في الوحدة `knuthPlass/` من الحزمة الأساسية: نواة للبرمجة الديناميكية (العُقد النشطة، ونقاط الجزاء، والتتبع الرجعي) ومساران محوّلان يحوّلان النص إلى نموذج الصندوق والغراء والجزاء:

- **مسار النص العادي**: يستعمل `@chenglou/pretext` لقياس النص دون DOM. توفر Pretext عروض المقاطع وعروض الواصلات الاختيارية؛ ويحوّلها Postext إلى عناصر KP.
- **مسار النص المنسّق**: يعالج المقاطع العريضة والمائلة بقياس قائم على Canvas. تصير كل وحدة منسّقة صندوقًا أو أكثر، وتُدرج مواضع تقسيم الكلمات بينها جزاءات.

يحسب المساران كلاهما لكل سطر `justifiedSpaceRatio`، أي عرض المسافة الفعلي مقسومًا على عرضها الطبيعي، وتغذّي هذه القيمة نظام تصحيح الأسطر المتخلخلة الموصوف أدناه. ولا تُحسب النسبة إلا للأسطر غير الأخيرة؛ أما طريقة نضد السطر الأخير فيتناولها قسم [السطر الأخير](#السطر-الأخير).

وحول مقسِّم الأسطر، يقيم قياس النص في الوحدة `measure/`: مسارا القياس العادي والمنسّق، ومقاييس الحروف في Canvas، ومعالجة سلاسل الخطوط، خلف ذاكرة تخزين مؤقت صريحة للقياس. وتمسح `clearMeasurementCache` أيضًا ذاكرة عروض النص التي تحتها، فتبقى القياسات دقيقة بعد أن ينتهي تحميل خطوط الويب. أما التحليل، وهو المرحلة التي تحوّل النص المصدر إلى كتل ومقاطع سطرية، فيقيم في الوحدة `parse/`. انظر صفحة [البنية](/ar/docs/architecture) لتوزيع ملفات هذه الوحدات.

ويتفاعل تقسيم الأسطر أيضًا مع أنواع المحتوى الأحدث. فالموارد العائمة تحتل الشريط العلوي أو السفلي من عمود أو صفحة، فتقصّر امتدادات الأعمدة التي تستجيب لها جزاءات اليتيمة والأرملة والفراغ الزائد. وتُقاس التعليقات وخلايا الجداول بوصفها مقاطع نص منسّق ملفوفة بخطوط التعليقات والجداول. وأسطر المعادلات المعروضة تتوسط السطر وتبقى وحدة واحدة، فلا تُضبط ولا تُقسم أبدًا. انظر [صيغة المستند › الموارد](/ar/docs/document-format#الموارد) و[الإعدادات › نمط الجدول](/ar/docs/configuration#نمط-الجداول) / [نمط التعليق](/ar/docs/configuration#نمط-التعليقات) للتفاصيل.

**السلوك الاحتياطي**: إذا لم تنتج Knuth-Plass أي مجموعة قطع صالحة (وقد يحدث هذا مع الأعمدة الضيقة جدًا أو الكلمات الطويلة جدًا)، يرجع المحرّك إلى `layoutNextLine()` الجشعة في Pretext. وهذا يضمن أن يكتمل الإخراج دائمًا.

## تقسيم الكلمات بالواصلة

تقسيم الكلمات وضبط الأسطر لا ينفصلان. فمن دون تقسيم الكلمات، لا يملك المحرّك وسيلة لتجنب السطر المتخلخل إلا نقل كلمة إلى السطر التالي، وكثيرًا ما ينقل ذلك المشكلة من مكان إلى آخر فحسب. أما تقسيم الكلمات فيعطي المحرّك مجموعة أكبر بكثير من مواضع القطع ليوازن بينها، فيحسّن جودة النص المضبوط تحسينًا كبيرًا.

> **شكل: نص مضبوط مع تقسيم الكلمات ومن دونه**
> العمود الأيسر بلا تقسيم للكلمات: تتفاوت عروض الأسطر تفاوتًا كبيرًا لأن المحرّك لا يستطيع إلا نقل كلمات كاملة. والعمود الأيمن بتقسيم الكلمات مفعّلًا: عروض الأسطر شبه متساوية، وكلمة واحدة مقسومة بواصلة.
>
> *يقلّل تقسيم الكلمات تفاوت التباعد في النص المضبوط تقليلًا كبيرًا.*

### أنماط بجودة TeX

يستعمل Postext مكتبة **Hypher** (`hypher` v0.2.5) لتقسيم الكلمات، وتعمل بـ**أنماط تقسيم الكلمات لـTeX/Liang**. وهي الأنماط نفسها التي يستعملها TeX منذ 1983: تمثيل موجز لقواعد حدود المقاطع، استخرجته خوارزمية توليد الأنماط التي وضعها Frank Liang من مدوّنات كلمات كبيرة.

تُرمِّز الأنماط مجموعة من القواعد المرقّمة، إذا طُبّقت على كلمة دلّت على المواضع التي يجوز فيها القطع (الأرقام الفردية) والمواضع التي يُمنع فيها (الأرقام الزوجية). ويضمن المعاملان `leftmin` و`rightmin` في ملف أنماط كل لغة حدًا أدنى من الحروف قبل أي موضع قطع وبعده. وفي الإنجليزية (`en-us`) تكون قيمتاهما عادةً 2 و3 على التوالي، فلا بد أن يسبق الواصلةَ حرفان على الأقل وأن يليها 3.

### اللغات المدعومة

| رمز اللغة | اللغة |
| --- | --- |
| `'en-us'` | الإنجليزية (الولايات المتحدة) |
| `'es'` | الإسبانية |
| `'fr'` | الفرنسية |
| `'de'` | الألمانية |
| `'it'` | الإيطالية |
| `'pt'` | البرتغالية |
| `'ca'` | الكتالونية |
| `'nl'` | الهولندية |

تحمّل كل لغة مجموعة أنماطها الخاصة. وتُنشأ نسخ Hypher عند الحاجة وتُخزَّن مؤقتًا: أول استدعاء للغة ما يتحمل كلفة التهيئة، والاستدعاءات التالية فورية. واللغة الموسومة بمنطقة تستعمل أنماط لغتها (`'es-ES'` تُقسَّم بأنماط `'es'`، و`'en-GB'` بأنماط `'en-us'`). واللغة التي لا أنماط لها هنا ترجع إلى `en-us`، ويطبع المحرّك تحذيرًا مرة واحدة في وحدة التحكم (انظر [تقسيم الكلمات](/ar/docs/configuration#تقسيم-الكلمات-بالواصلة) في مرجع الإعدادات). والصينية واليابانية والكورية هي الاستثناء: تُنضَّد بلا تقسيم للكلمات وبلا تحذير، وتنقطع أسطرها بين المحارف (انظر [الصينية واليابانية والكورية](#الصينية-واليابانية-والكورية) أدناه).

تتبع **الكتالونية** قواعد معهد الدراسات الكتالونية (Institut d'Estudis Catalans) في *Llibre d'estil*، الفصل السادس. ويسري هذا منذ postext 1.14:

- يترك القطع حرفين على الأقل في كل جانب (`ter-ra`، `cai-xa`، `plu-ja`).
- تنقطع *ela geminada* بين حرفي *l*، وتحل الواصلة محل النقطة الوسطى: تصير *il·lusió* إلى `il-` | `lusió`. ويُقاس السطر من دون النقطة، فيرى ضبط الأسطر وKnuth–Plass عرضه الحقيقي.
- يبقى حرفا العلة المتواليان في تنافر (hiatus) معًا (`cièn-cia`، `ca-mions`). وحرف *i* أو *u* بين حرفي علة يُعدّ ساكنًا ويفتتح مقطعه (`fe-ia`، `ve-ient`).
- لا قطع بعد الفاصلة العليا (`s'ha-via`، ولا `s'-havia` أبدًا).
- الكلمات الشائعة ذات السوابق تنقطع عند السابقة (`vos-altres`، `cel-obert`، `ben-estar`).
- لإبقاء الكلمات المتصلة بضمائر لاحقة كاملة إلا عند واصلتها (`portar-` | `lo`)، كما يفضّل المعهد، اجعل [`hyphenation.compounds`](/ar/docs/configuration#تقسيم-الكلمات-بالواصلة) بالقيمة `false`.

### لماذا Hypher (وليس خوارزمية خاصة)

استعمل نظام تقسيم الكلمات الأصلي في Postext **قاعدة تقريبية خاصة قائمة على حروف العلة**: كان يكتشف حدود المقاطع بالبحث عن تجمعات حروف العلة، والسوابق الشائعة (`over-`، `under-`، `inter-`)، واللواحق الشائعة (`-tion`، `-ment`، `-sion`). كان بسيطًا وسريعًا، لكنه محدود في جوهره:

| الجانب | القاعدة التقريبية الخاصة | Hypher (أنماط TeX) |
| --- | --- | --- |
| **الدقة** | جيدة في الكلمات الشائعة، وغير موثوقة في الكلمات النادرة. يفوّت اكتشاف حروف العلة كثيرًا من مواضع القطع الصحيحة وينشئ مواضع خاطئة. | شبه كاملة. الأنماط مولَّدة من مدوّنات كبيرة، وما زالت تُنقَّح منذ أكثر من 40 عامًا. |
| **تغطية اللغات** | كان لا بد من تعريف مجموعات حروف العلة والسوابق واللواحق يدويًا لكل لغة، وهو عمل مضنٍ وعرضة للخطأ. | توجد ملفات أنماط لأكثر من 50 لغة، يصونها مجتمع TeX. وإضافة لغة تعني إضافة سطر استيراد واحد. |
| **المعيار المعتمد في الصناعة** | ليست معيارًا معترفًا به. لا أدوات ولا دعم من مجتمع. | الأنماط نفسها التي يستعملها TeX وLibreOffice وFirefox وChrome وكل نظام تنضيد احترافي تقريبًا. |
| **الصيانة** | كل حالة حدّية علّة تُصلَح يدويًا. | ملفات أنماط يصونها المجتمع. وإصلاحات العلل تأتي من المصدر الأصلي. |
| **حجم الحزمة** | نحو 170 سطرًا، بلا اعتماديات. | نواة Hypher نحو 3 KB. وكل ملف أنماط لغة يضيف 20–80 KB (بعد الضغط بـgzip: 5–20 KB). واللغات الثماني المضمّنة كلها تضيف نحو 300 KB (بعد الضغط بـgzip: نحو 80 KB). |
| **الأداء** | سريع جدًا (مسح بسيط للسلاسل). | سريع (بحث في شجرة trie لكل محرف). لا يُذكر عمليًا: تقسيم الكلمات ليس عنق الزجاجة أبدًا. |

الموازنة واضحة: حزمة أكبر في مقابل صحة أفضل بكثير وانعدام عبء الصيانة. ولمحرّك إخراج يستهدف مخرجات بجودة النشر، تفوز الصحة. فتقسيم خاطئ واحد في كتاب مطبوع أغلى من بضعة كيلوبايتات إضافية من الأنماط.

### كيف يندمج تقسيم الكلمات مع Knuth-Plass

قبل أن يدخل النص خوارزمية Knuth-Plass، يعالجه المحرّك مسبقًا بـHypher، فيُدرج **واصلات لينة** (soft hyphens، الرمز `\u00AD` في Unicode) في كل موضع قطع جائز. ثم تُحوَّل هذه المحارف غير المرئية إلى **جزاءات** KP كلفتها 50 مع `flagged: true`.

تعامل الخوارزمية مواضع تقسيم الكلمات خيارًا آخر تقيّمه إلى جانب الحدود الطبيعية بين الكلمات (حيث يسمح الغراء بالقطع). فإن أعطى استعمال الواصلة مجموعًا أدنى من نقاط الجزاء مما يعطيه ترك السطر متخلخلًا، أخذت الخوارزمية الواصلة. وإلا تركت الكلمة سليمة.

وتضمن نقاط جزاء الواصلات المتتالية (القيمة الافتراضية 3000) أن تتجنب الخوارزمية بقوة وضع واصلات في سطرين متجاورين، وهو عرف طباعي تفرضه أدلة الأسلوب كلها تقريبًا.

الواصلة في آخر سطر من عمود أو صفحة ترسل القارئ إلى العمود التالي في منتصف كلمة. والإعداد `bodyText.hyphenateAcrossColumns: false` يُبعدها عن تلك الأسطر: حين ينتهي السطر الذي يختم عمودًا بواصلة، تُقسَّم الفقرة من جديد وتُسعَّر الواصلة هناك كما تُسعَّر الكلمة المعزولة، فينهي مقسِّم الأسطر ذلك السطر بكلمة كاملة كلما استطاعت مسافات الكلمات في الأسطر التي فوقه أن تستوعب الفرق ضمن `maxWordSpacing` و`minWordSpacing`. وحيث لا تستطيع، تبقى الواصلة. ويشمل ذلك أول انقطاع للفقرة بين عمودين، والانقطاعات اللاحقة التي تقع حيث ينتهي عمود ممتلئ. أما الانقطاع اللاحق الذي يقع في موضع آخر (عمود قُصِّر لإبعاد أرملة عنه، أو شريط ختامي قُطع على مستوى واحد) فيحظى بإعادة تقسيم ثانية تبدأ من ذلك العمود: تحتفظ الأسطر المنضدة في الأعمدة السابقة بمواضع قطعها، ولا يُعاد تقسيم إلا بقية الفقرة. وهكذا لا تبقى الواصلة إلا حيث لا يتجنبها أي نضد ضمن الحدود، وذلك عمليًا عند أول انقطاع للفقرة بين عمودين. ولا يميّز مقسِّم الأسطر بين طرق الوصول إلى سطر ما إلا حتى آخر سطر يحرسه، فتكلّف المحاولة الثانية نحو ما يكلّفه القياس الأول: قياس إضافي واحد لكل فقرة يعيد تقسيمها.

لا يُطبَّق تقسيم الكلمات افتراضيًا إلا حين يكون `bodyText.hyphenation.enabled` بالقيمة `true` **و** `bodyText.textAlign` بالقيمة `'justify'`، لأن الحافة الحرّة يُراد لها أن تتفاوت. ويمكن تقسيم الكلمات في النص غير المضبوط أيضًا، بالإعداد `bodyText.hyphenation.ragged: true`. فالسطر غير المضبوط ليس فيه تباعد بين الكلمات يُسوّى، ولذلك تحسم **منطقة التقسيم** (hyphenation zone) الأمر: لا تُقسم الكلمة التي لا تتسع إلا إذا كان نقلها كاملة إلى السطر التالي سيترك فجوة أوسع من `hyphenation.zone` (3 em افتراضيًا). وتنضّد Knuth-Plass النص الجاري غير المضبوط أيضًا (`bodyText.optimalRagged`، مفعّل افتراضيًا): تحتفظ مسافات كلماته بعرضها، ويدفع كل سطر ثمن ما ينقصه عن عرض السطر (measure)، وتحسم المنطقة المقاطع التي يجوز له أن يأخذها؛ ونهايتان متتاليتان بمقطع تكلّفان نقاط جزاء الواصلات المتتالية. وحين يُنضَّد النص سطرًا سطرًا (`optimalRagged: false`)، لا ينتهي أكثر من سطرين متتاليين بمقطع. انظر [النص غير المضبوط](/ar/docs/configuration#النص-غير-المضبوط).

ويوجد موضعان للقطع أيًّا كان هذا الإعداد. **الواصلة الصلبة بين حرفين** (`enseñanza-aprendizaje`، `físico-química`) موضع يجوز أن ينتهي عنده السطر: الكلمة تحمل الواصلة أصلًا، فلا يُضاف شيء. تأخذها Knuth-Plass في كل فقرة مع `bodyText.breakAfterHyphens` (مفعّل افتراضيًا)، وتسعّرها كما تسعّر المقطع؛ وفي الفقرة المضبوطة التي لا تنسيق سطري فيها، لا تأخذها إلا إذا كان على كل جانب من الواصلة حرفان، فلا ينتهي سطر عند `e-` من `e-mail`. وحين يكون معطّلًا، كما كان حتى postext 1.4، لا تنقطع الفقرة المضبوطة التي لا تنسيق سطري فيها بعد مثل هذه الواصلة مباشرة، بينما تنقطع الفقرة نفسها إن كانت فيها كلمة مائلة واحدة في أي موضع؛ والكتب المحفوظة قبل postext 1.5 تُقرأ وهو معطّل. وينتهي السطر بواصلة النص نفسه، ويسجلها السطر بالحقل `hardHyphen` إلى جانب `hyphenated`، فيحتفظ بها القارئ الذي يُسقط الواصلة المضافة (الترويسات، ومؤشر الكتابة في Sandbox). و**الشرطة الطويلة أو المتوسطة** (em dash / en dash) **الملتصقة بين كلمتين** (`say—that’s`، `riddles.—I`، `Hamburg–Berlin`) موضع يجوز أن ينتهي عنده السطر أيضًا، في مقسِّمَي الأسطر كليهما، مع `bodyText.breakAfterDashes` (مفعّل افتراضيًا): ينتهي السطر بالشرطة، ولا يُضاف شيء ولا تُحتسب كلفة. وكذلك الشرطة التي تختم مقطعًا بنمط ما قبل كلمة بنمط آخر (`see—*and*`). ويكون السطر عندئذ `hyphenated`، من دون `hardHyphen`. ولا قطع أبدًا بعد شرطة تفتتح جملة اعتراضية أو سطر حوار (`—dijo`، `said "—Hola`؛ ويجوز أن تسبق الشرطةَ علامةُ تنصيص تختم كلمة، كما في `"no"—and` أو الألمانية `„nein“—und`)، ولا قبل علامة ترقيم، ولا قبل علامة تنصيص أو قوس (`thinking—" and`، `says—“no”`)، ولا داخل سلسلة من الشرطات أو داخل نطاق أرقام (`1914–1918`). و**الكلمة الأعرض من عرض سطرها كله** (خلية جدول ضيقة، أو كلمة مركّبة طويلة في عمود ضيق) لا يُسمح لها أبدًا بتجاوزه: يقسمها المحرّك عند آخر مقطع يتسع، بواصلة، أو عند آخر محرف يتسع حين لا يقدّم القاموس مقطعًا هناك؛ والقطع المجاور لواصلة تحملها الكلمة يقع بعد تلك الواصلة ولا يضيف واصلة، فلا تظهر في الكلمة واصلتان أبدًا. وتحتفظ بقية الكلمة بمواضع قطعها: تواصل الكلمة المركّبة انقطاعها عند واصلاتها، وعنوان الويب عند مفاصله، بينما كانت البقية حتى postext 1.4 تُقسم عند مقاطع القاموس. والفقرة التي لا تنسيق سطري فيها تُقطع عند آخر محرف يتسع، من دون واصلة، ما لم يكن تقسيم الكلمات فيها مفعّلًا. ولا توجد مجموعة قطع ممكنة حول مثل هذه الكلمة في نظر Knuth-Plass، ولذلك تُنضَّد الفقرة المضبوطة التي تحويها سطرًا سطرًا بدلًا من ذلك.

### الكلمات المركّبة

الكلمة المركّبة الموصولة بواصلة (`after-dinner`، `teórico-práctico`) يمكن أن تنقطع في نوعين من المواضع: بعد واصلتها، وعند مقاطع القاموس في أيٍّ من جزأيها (`af-ter-dinner`). أما TeX ودليل شيكاغو للأسلوب (Chicago Manual of Style) فيبقيان الجزأين كاملين ولا يقسمان الكلمة المركّبة إلا عند واصلتها. والإعداد `bodyText.hyphenation.compounds: false` يفعل الشيء نفسه: يترك القاموس كل كلمة فيها واصلة بين حرفين على حالها، فلا تنقطع إلا بعد تلك الواصلة. وتبقى الواصلة اللينة المكتوبة في الكلمة موضع قطع، ويبقى المركّب الأعرض من السطر كله مقسومًا حيث لا بد. والقيمة الافتراضية، `true`، تواصل قسمة الجزأين، وهذا يعطي العمود الضيق المضبوط طرقًا أكثر لملء أسطره.

يطلب الإملاء البرتغالي أن تتكرر واصلة الكلمة المركّبة المقسومة في آخر السطر في بداية السطر التالي (`vencer-` · `-se`)، وكذلك قواعد الأكاديمية الملكية الإسبانية منذ 2010 (`léxico-` · `-semántico`)، ليعرف القارئ أن الواصلة جزء من الكلمة. والإعداد `bodyText.repeatHyphen: true` يفعل ذلك. تُقاس الواصلة المكررة مع سطرها، فيترك لها مقسِّم الأسطر مكانًا، وتُرسم كبقية النص؛ وفي PDF تحمل نصًا بديلًا يُسقطها، فيُقرأ النص المنسوخ أو المستخرج من PDF كلمةً واحدة (`vencer-se`). ويسجلها السطر بالحقل `repeatedHyphen`، ويشير `plainStart` و`sourceStart` فيه إلى ما بعدها، فتقرأ خريطة المصدر والروابط والترويسات الكلمة كما كُتبت. ولا يحظى عنوان الويب بها أبدًا. ويسري ذلك على النص الجاري والعناوين والقوائم والاقتباسات الكتلية والإطارات؛ والفقرة غير المنسّقة التي تحوي كلمة مركّبة يقسمها عندئذ مقسِّم الأسطر الذي ينضد النص المنسّق.

### حيث لا ينكسر السطر أبدًا

بعض المواضع لا تكون أبدًا مواضع قطع، في أيٍّ من مقسِّمَي الأسطر:

- **المسافة غير القابلة للكسر** (no-break space). المحارف U+00A0، والمسافة الضيقة غير القابلة للكسر U+202F، ومسافة الرقم U+2007 تلصق الكلمتين على جانبيها: عددًا ووحدته، أو إحالة إلى صفحة، أو مجموعة من الآلاف. ويصح الأمر نفسه في التعليقات وخلايا الجداول والإطارات ونصوص التصميم (الترويسات وصفحات افتتاح الفصول). وتحتفظ كل منها بعرضها كما قيس؛ ولا يمدّ ضبط الأسطر إلا مسافات الكلمات. والمحرف الذي لا رسم فيه لـU+202F أو U+2007 يأخذ العرض الذي تعطيه إياهما المتصفحات، نصف مسافة كلمة وعرض رقم، في كل المخرجات بما فيها PDF؛ وكل المحارف تقريبًا فيها U+00A0. والمجموعة الملصوقة على هذا النحو إذا كانت أعرض من السطر كله استثناء، سواء كان فيها تنسيق سطري أم لم يكن: تنقطع عند آخر مسافة غير قابلة للكسر فيها، بدلًا من أن تُقطع داخل كلمة. ورابط الكلمات U+2060 (word joiner) يلصق دون أن يأخذ أي حيّز، في النص الصيني أيضًا: رقم المعنى `**①**` إذا تلاه هذا المحرف بقي على سطر المحرف الذي بعده. وكذلك U+FEFF، أي المسافة غير القابلة للكسر الصفرية العرض، وإن كان رابط الكلمات هو المحرف المخصص لذلك.
- **النص المتلاصق**. الكلمة العريضة أو المائلة وعلامة الترقيم التي بعدها (`**osmosis**.`)، والقوسان حول إحالة سطرية (`(:ref{id="fig-3"})`)، والكلمة المنضدة في مقطعين: النص الذي لا مسافة فيه وحدة واحدة كأنه كلمة واحدة. وحين لا تتسع هذه الوحدة لما بقي من السطر، تنزل كاملة. وحين تفتتح سطرًا ولا تتسع مع ذلك، تُقسم كلمتها الأخيرة بواصلة عند مقطع لتنزل علامة الترقيم مع ذيل الكلمة؛ ولا تترك علامة ترقيمها تفتتح السطر التالي إلا الوحدة التي لا مقطع فيها يُقطع عنده.
- **داخل كلمة من كتابة متصلة الحروف**. الكلمة العربية (أو السريانية أو النكوية أو المغولية) لا تُقسم بواصلة أبدًا، ولا حتى عند واصلة لينة مكتوبة فيها، ولا تُقطع بين حروفها أبدًا: حروفها تتصل، والقطعة المنضدة وحدها تأخذ أشكالًا أخرى للحروف وعرضًا آخر. والعربية واللغات الأخرى المكتوبة من اليمين إلى اليسار يكون تقسيم الكلمات فيها معطّلًا افتراضيًا؛ وحين يُفعَّل (للكلمات اللاتينية في كتاب عربي، أو في كتاب إنجليزي يقتبس العربية) يتخطى القاموس مثل هذه الكلمات. والكلمة المنضدة بنمطين (`كتا**ب**`) تبقى كلمة واحدة تُقاس كاملة. والكلمة الأعرض من السطر كله تتجاوز عرض السطر، ويُبلغ البناء عن تحذير محتوى `unbreakableWordOverflow`.

حتى postext 1.4، كانت الفقرة التي فيها تنسيق سطري أو `:ref` يمكن أن تنقطع عند مسافة غير قابلة للكسر، وكان السطر غير المضبوط يمكن أن ينتهي بالقوس `(` الذي يسبق إحالة أو يفتتح بالنقطة التي تلي كلمة عريضة.

## حدود التباعد بين الكلمات

يعطي نموذج الغراء المحرّك حدودًا صريحة لمقدار ما يجوز أن تتمدده المسافات بين الكلمات أو تنكمشه. ويتحكم في هذه الحدود إعدادان في `bodyText`:

| الخاصية | القيمة الافتراضية | الوصف |
| --- | --- | --- |
| `maxWordSpacing` | `2` | الحد الأعلى للتباعد بين الكلمات، مضاعفًا لعرض المسافة العادية. بالقيمة الافتراضية، تتمدد المسافات حتى 200% من عرضها الطبيعي. |
| `minWordSpacing` | `0.6` | الحد الأدنى للتباعد بين الكلمات، مضاعفًا لعرض المسافة العادية. بالقيمة الافتراضية، تنكمش المسافات حتى 60% من عرضها الطبيعي. |

تُترجَم هذه المضاعفات مباشرة إلى قيمتي `stretch` و`shrink` للغراء في نموذج Knuth-Plass:

```
stretchPerSpace = normalSpaceWidth × (maxWordSpacing - 1)
shrinkPerSpace  = normalSpaceWidth × (1 - minWordSpacing)
```

بالقيمتين الافتراضيتين (2 / 0.6)، إذا كان عرض المسافة العادية 4 px:
- تتمدد كل مسافة بمقدار 4 px (من 4 px إلى 8 px)
- تنكمش كل مسافة بمقدار 1.6 px (من 4 px إلى 2.4 px)

**الحدود الأضيق** (مثل `maxWordSpacing: 1.2`) تعطي تباعدًا أكثر انتظامًا، لكنها تترك للخوارزمية مجالًا أقل للمناورة، وقد ينتج عن ذلك تقسيم أكثر للكلمات أو، في الحالات القصوى، تجاوز للعرض. و**الحدود الأوسع** (مثل `maxWordSpacing: 2.5`) تعطي الخوارزمية مرونة أكبر، لكنها تسمح بتباعد متفاوت ظاهر في بعض الأسطر.

القيمتان الافتراضيتان 2 و0.6 تميلان إلى مرونة الخوارزمية: تعطيان Knuth-Plass مجالًا كافيًا لتجنب تجاوز العرض وتقسيم الكلمات والكلمات المعزولة في الأعمدة الضيقة، مع بقائهما ضمن النطاقات التي تعدّها الأدبيات الطباعية مقبولة.

### أسطر يعجز مقسِّم الأسطر عن ملئها

لا تمدّ Knuth-Plass سطرًا إلى ما بعد `maxWordSpacing` حين يكون لها خيار، ولا يفعل ذلك إصلاح الكلمة المعزولة أيضًا (انظر [جزاءات اليتيمة والأرملة والكلمة المعزولة](#جزاءات-اليتيمة-والأرملة-والكلمة-المعزولة)). فالسطر المتجاوز للحد يكلّف أكثر من أي عيب آخر تزنه، سواء كان واصلة أو سطرًا أخيرًا قصيرًا أو سطرًا أكثر تخلخلًا بقليل من جيرانه، منذ اللحظة التي يتجاوز فيها الحد، ثم تنمو الكلفة مع مربع نسبة تمدده، فيفضّل مقسِّم الأسطر أن يقسم كلمة بواصلة، أو يوزع الفراغ الزائد على الأسطر المحيطة، أو ينضد سطرين متخلخلين قليلًا، على أن ينضد سطرًا واحدًا متخلخلًا أكثر مما ينبغي بكثير.

وأحيانًا لا تبقى أي مجموعة قطع ضمن الحدود. فالسطر الذي لا يتسع للكلمة التالية تكون مسافاته أقل من أن تتقاسم الفراغ الزائد: السطر الأول تحت مسافة بادئة للفقرة تليه كلمة أطول من أن تصعد إليه وأقصر من أن تُقسم بواصلة؛ أو سطر من مصطلحات طويلة لا تنقسم؛ أو عنوان URL طويل لا ينقطع إلا عند مفاصله؛ أو عنصر قائمة لا تصعد كلمته الأخيرة بينما يترك كل تقسيم بالواصلة كلمة معزولة. وتعتمد كثرة حدوث ذلك على عرض السطر والمحرف واللغة. ففي عمود عرضه 83 mm من نص إنجليزي بحجم 9.3 pt، تجاوز `maxWordSpacing` من 2 % إلى 8 % من أسطر فصل واحد، بحسب المحرف (وأعرضها أكثرها)؛ أما الفصل نفسه بالإسبانية، التي يقدّم تقسيم الكلمات فيها مواضع قطع أكثر بكثير، فلم يكن فيه سطر واحد منها. عندئذ تقبل Knuth-Plass أقل الأسطر سوءًا، فتتمدد مسافاته إلى ما بعد الحد. وحين تكون ستتمدد إلى أكثر من 3 أضعاف عرض المسافة العادية، ينضد المحرّك السطر **غير مضبوط** بدلًا من ذلك: يُرسم بتباعده الطبيعي وتنحسر حافته اليمنى، كالسطر الأخير من الفقرة. والعتبة هي نفسها التي يستعملها تحذير الأسطر المتخلخلة في Sandbox، فالسطر الذي يتجاوزها يُصلَح بدلًا من أن يُشار إليه. أما الأسطر التي ضمن العتبة فتُترك كما قيست. ويصح الأمر نفسه داخل الإطارات، التي يكثر فيها ذلك لضيق عرض أسطرها؛ وحتى postext 1.4 كان الإطار يبقي مثل هذا السطر مضبوطًا مهما تمددت مسافاته.

وللحصول على عدد أقل من هذه الأسطر، بهذا الترتيب: تحقق من أن تقسيم الكلمات مفعّل ومضبوط على لغة النص؛ وسّع عرض السطر أو صغّر حجم النص؛ اسمح للأسطر بأخذ قليل من التتبّع (القسم التالي)؛ أو ارفع `maxWordSpacing`، فتُعدّ الأسطر نفسها ضمن الحد من دون أن يتغير نضدها.

### التتبّع ملاذًا أخيرًا

يسمح `bodyText.maxJustifyTracking` لمثل هذا السطر بأن يأخذ قليلًا من التتبّع (tracking)، أي تباعد الحروف، بدلًا من مزيد من المسافة بين الكلمات، حتى ذلك العدد من أجزاء الألف من الـem لكل محرف (10 = 0.01 em، وهي وحدة InDesign). ويعمل في الاتجاهين: السطر الذي كانت مسافاته ستتمدد إلى ما بعد `maxWordSpacing` يباعد بين حروفه حتى تعود مسافاته إلى الحد، والسطر الذي لا يتسع إلا بمسافات دون `minWordSpacing` يضيّق حروفه بدلًا من إنزال كلمة. وتزنه Knuth-Plass حين تختار مواضع القطع: السطر المتتبَّع يكلّف أكثر قليلًا من سطر ضمن الحدود وأقل بكثير من سطر يتجاوزها، فلا يؤخذ التتبّع إلا حيث يعجز التباعد بين الكلمات وحده. ولا تأخذ منه شيئًا الأسطرُ التي ضمن الحدود، ولا السطر الأخير من الفقرة (ما لم يتجاوز العرض)، ولا سطر من كلمة واحدة، ولا سطر يحوي شارة (chip). ويسجله السطر في `VDTLine.letterSpacing`، فوق تتبّع كتلته الخاص، وترسمه Canvas وHTML وPDF. وكلمات الكتابات المتصلة الحروف (العربية…) لا تأخذ تتبّعًا أبدًا، لا هذا ولا غيره (`letterSpacing` في نمط ما، أو موازنة الأعمدة، أو إصلاح الكلمة المعزولة): فإبعاد حروفها بعضها عن بعض يقطع اتصالها. ولا يحتسب السطر أيًّا من حروفها، وترسمها المُخرِجات بلا تتبّع؛ والنمط الذي يضبط `letterSpacing` على مثل هذا النص يتلقى تحذير محتوى `joiningScriptLetterSpacing`.

```ts
bodyText: {
  maxWordSpacing: 2,
  maxJustifyTracking: 10, // at most 0.01 em a letter, either way
}
```

وهو معطّل افتراضيًا، فتحتفظ المستندات بأسطرها ما لم تطلبه. وفي الفصل الإنجليزي المذكور أعلاه، خفّضت القيمة 10‰ الأسطر المتجاوزة لـ`maxWordSpacing` إلى سطر واحد أو لا شيء في كل محرف، وخفّضتها 20‰ إلى لا شيء في ثلاثة محارف من أربعة. أبقِه صغيرًا: بعد نحو 20‰ يبدأ التتبّع بالظهور سطرًا أفتح أو أدكن من غيره.

### الكشيدة في النص العربي

السطر العربي المضبوط لا يُباعَد بين حروفه: حروفه تتصل، وإبعادها بعضها عن بعض يقطع اتصالها. بل يُمدّ في موضعين: مسافات كلماته وكشيداته، أي الوصلات الممدودة التي يرسمها الخطاط بين حرفين متصلين (كتاب ← كتـاب). يُدرج Postext الكشيدات محارفَ تطويل (U+0640، ـ) كاملة، يرسمها الخط ضربة واحدة؛ ويحوّل خط Amiri سلسلة من محرف واحد إلى سبعة محارف إلى كشيدة منحنية.

يكون `bodyText.kashida` بالقيمة `'auto'` افتراضيًا في المستند الذي تُكتب لغته بالحرف العربي (`ar`، `fa`، `ur`…) وبالقيمة `'none'` في غيره؛ واجعله `'auto'` لمدّ الكلمات العربية المقتبسة في كتاب بلغة أخرى. يحظى كل سطر، ما عدا السطر الأخير من الفقرة، بتوسيع مسافات كلماته أولًا حتى ربع عرضها، ثم بكشيدات لبقية فراغه الزائد، تطويلًا واحدًا في كل مرة، في أفضل المواضع أولًا، جولةً بعد جولة، مع إعادة قياس كل كلمة كاملةً بتطويلاتها؛ وما يبقى، وهو أقل من تطويل واحد، يعود إلى المسافات. وتحتسب Knuth-Plass ما يمكن أن تُمدّ به كل كلمة قدرةً على التمدد، فتختار مواضع القطع وهي تعلم أن سطرًا من الكلمات العربية يمكن أن يتسع هناك.

أما المواضع التي يجوز أن تقع فيها الكشيدة فتأتي من قواعد [raqim-kashida](https://github.com/aliftype/raqim-kashida) (برخصة MIT): لا تقع إلا بين حرفين متصلين، ولا تقع أبدًا بعد حرف لا يتصل بما بعده (ا د ذ ر ز و ة)، ولا في آخر الكلمة، ولا داخل اللام ألف، وتأتي بعد علامات الحرف الذي قبلها. والإعداد `kashidaPatterns: 'naskh'` يتبع قواعد النسخ الكلاسيكية (مصفوفة بن عطية مع محظورات عفيفي: لا شيء بعد الكاف أو اللام، ولا شيء قبل الصاد أو العين أو الواو، وهاء الضمير في آخر الكلمة يُمدّ ما قبلها مباشرة)؛ و`'simple'` يتبع أولويات Microsoft للخطوط الحديثة البسيطة؛ و`'nastaliq'` يتبع قواعد النسخ مكيّفةً للنستعليق. والقيمة الافتراضية `'auto'` تقرأ خط المتن: لا كشيدة في خط رقعة أو ديواني مثل Aref Ruqaa، وقواعد النستعليق في خط نستعليق، والنسخ فيما عدا ذلك. وتأخذ الكلمة `kashidaPerWord` من التطويلات (1 افتراضيًا) لا يزيد طولها عن `kashidaMaxLength` em (0.6، أي ثلاثة محارف تطويل في Amiri). والكلمة التي فيها تطويل كتبه المؤلف تُمدّ في موضعه. ولا تأخذ أي كشيدة الكلماتُ اللاتينية والأرقام والعناوين والأسطر غير المضبوطة والسطر الأخير من الفقرة.

```ts
bodyText: {
  kashida: 'auto',          // the default in an Arabic book
  kashidaPatterns: 'naskh', // 'auto' picks it from the font
  kashidaMaxLength: 0.6,    // em
}
```

محارف التطويل جزء من النص المرسوم (يسردها كل مقطع في `VDTLineSegment.kashida`، ويعدّها السطر في `VDTLine.kashida`)؛ أما النص العادي وخريطة المصدر والروابط والنص المنسوخ من PDF فتُسقطها.

### السطر الأخير

في نموذج الصندوق والغراء والجزاء، تنتهي كل فقرة بغراء عرضه 0 وقابل للتمدد بلا حد، يليه قطع إلزامي. يمتص ذلك الغراء الختامي كل ما بقي من فراغ في السطر الأخير بلا كلفة، فتخرج الأسطر الأخيرة غير مضبوطة بطبيعتها: تُرسم بعرضها الطبيعي، ولا يُحسب `justifiedSpaceRatio` إلا للأسطر غير الأخيرة.

وثمة استثناء واحد. قد تقبل Knuth-Plass سطرًا أخيرًا محتواه الطبيعي *أعرض* من عرض السطر، على افتراض أن الغراء بين كلماته سينكمش، وهذا هو المعنى المعتاد لضبط الغراء في TeX. وتكتشف المُخرِجات الثلاثة هذه الحالة (حين يتجاوز العرض الطبيعي لمحتوى السطر عرضه الفعلي)، فتضغط المسافات بين كلمات ذلك السطر الأخير ليتسع لعرض السطر بالضبط بدلًا من أن يتجاوزه. ويُطبَّق هذا الفحص بالطريقة نفسها في مُخرِجات Canvas وPDF وHTML.

### تقسيم الأسطر الأمثل والجشع

تتحكم الخاصية `bodyText.optimalLineBreaking` (القيمة الافتراضية: `true`) في خوارزمية تقسيم الأسطر التي يستعملها المحرّك:

- **`true`**: خوارزمية Knuth-Plass القائمة على البرمجة الديناميكية. تقيّم كل مجموعات القطع الممكنة وتختار المثلى على مستوى الفقرة. وهذا هو الإعداد الموصى به لأي نص مضبوط. ويأخذها النص الجاري غير المضبوط أيضًا مع `bodyText.optimalRagged` (مفعّل افتراضيًا): تحتفظ مسافات الكلمات بعرضها، ويزن مقسِّم الأسطر بدلًا من ذلك ما ينقص كل سطر عن عرض السطر، فيكلّف السطر الناقص 3 em ما يكلّفه سطر مضبوط عند `maxWordSpacing`، فتخرج الحافة الحرّة أكثر انتظامًا وتسري قواعد الكلمة المعزولة.
- **`false`**: النهج الجشع «أول ملاءمة»، بالدالة `layoutNextLine()` من Pretext. أسرع لكن نتائجه أدنى جودة. لا تستعمله إلا حين يكون الأداء أهم من الجودة الطباعية (مثل المعاينة الفورية لنصوص كبيرة جدًا).

حين تكون Knuth-Plass مفعّلة ولا تنتج أي مجموعة قطع صالحة (وقد يحدث هذا مع الأعمدة الضيقة جدًا أو الكلمات الأطول من عرض العمود)، يرجع المحرّك تلقائيًا إلى التقسيم الجشع لتلك الفقرة.

### الصينية واليابانية والكورية

الفقرة التي فيها محارف CJK أكثر من مسافات الكلمات ينضدها مُنضِّد CJK، لا Knuth-Plass. فكل فجوة بين محرفين موضع يجوز أن ينقطع عنده السطر (إلا حيث تمنعه قواعد قطع الأسطر في `cjk.lineBreak`)، فلا يبقى ما يزنه بحث عن الحل الأمثل؛ وتُملأ الأسطر واحدًا بعد الآخر. وحين لا يتسع محرف، يحاول السطر أولًا أن يستوعبه بالتخلي عن بياض علامات الترقيم والمسافات (الضغط إلى الداخل، push-in: مسافات الكلمات حتى ربع em، ثم النقاط الوسطى والأقواس وعلامات الوقف القصير والمسافات بين الصينية واللاتينية حتى ثُمن em، ثم علامات الوقف التام، بقدر ما يسمح `cjk.punctuationWidth`)؛ ولا يأخذ المحرفُ الذي لا يجوز أن يفتتح سطرًا المحرفَ الذي قبله معه إلى السطر التالي إلا حين لا يكفي ذلك. انظر [الطباعة في شرق آسيا](/ar/docs/configuration#تنضيد-نصوص-شرق-آسيا) للاطلاع على القواعد. ويتناول قسم [الإخراج الصيني](/ar/docs/chinese-layout) بقية التنضيد الصيني: عروض علامات الترقيم بحسب المنطقة، وشبكة المحارف، والكتابة العمودية.

ويُمدّ السطر المضبوط من مثل هذه الفقرة، ما عدا السطر الأخير، إلى عرض السطر بالترتيب الذي يحدده clreq (§6.2.2.4):

1. المسافات بين الكلمات الغربية، بالتساوي، حتى نصف em لكل منها.
2. المسافات بين المحارف الصينية واللاتينية (`cjk.latinSpacing`)، بالتساوي، حتى نصف em لكل منها.
3. كل فجوة بين المحارف، بالتساوي، والمسافات بين الصينية واللاتينية معها: بين المحارف الصينية، وبين المحرف الصيني وعلامة الترقيم، وبين المحرف الصيني والكلمة اللاتينية. ولا يحدث ذلك أبدًا داخل كلمة لاتينية أو عدد أو شرطة أو نقاط حذف بعرض اثنين em، ولا بجوار رابط (～، –، — المفردة) أو خط مائل. والعلامة المعلّقة بعد نهاية السطر (`cjk.hangingPunctuation`) تبقى خارج عرض السطر.

السطر الأخير من الفقرة يُنضَّد مصمتًا. ويُسجَّل التباعد لكل مقطع من السطر (`VDTLineSegment.tracking`)، فترسم Canvas وHTML وPDF المواضع نفسها، ويضع Sandbox المؤشر على المحرف الذي نُقر عليه.

السطر الذي يحتاج إلى أكثر من نصف em بين محارفه، أو إلى أكثر من `bodyText.maxJustifyTracking` حين يكون مضبوطًا، يُنضَّد بذلك المقدار، ناقصًا عن عرض السطر، ويُبلَغ عنه بتحذير محتوى `cjkLooseLine` (وفي Sandbox: **سطر CJK أقصر من عرضه**). والسبب المعتاد كلمة لاتينية طويلة أو عنوان ويب لم يستطع الصعود إليه. والسطر الذي ليس فيه أي محرف CJK، مثل بداية عنوان ويب طويل، يُنضَّد غير مضبوط بلا تحذير.

ولتمييز الأسطر المتخلخلة، يُعدّ سطر CJK متخلخلًا بحسب تباعده: نسبته 1 زائد تباعده بأثمان الـem، فعند العتبة الافتراضية 3 يُشار إلى السطر الذي تتباعد محارفه بأكثر من ربع em (`lineLooseness(line, fontSizePx)` تعطي النسبة). ويمكن لموازنة الأعمدة أن تطيل فقرة CJK سطرًا: تقطع الأسطر أقصر قليلًا من عرض السطر، ثُمن em في كل مرة حتى اثنين em، ثم تمدّها إليه من جديد.

## كشف الأسطر المتخلخلة

حتى مع Knuth-Plass وتقسيم الكلمات، ستبقى بعض الأسطر أكثر تخلخلًا مما ينبغي، ولا سيما في الأعمدة الضيقة ذات الكلمات الطويلة، أو في اللغات التي تقل فيها فرص تقسيم الكلمات. وتساعدك ميزة التصحيح **تمييز الأسطر المتخلخلة** على العثور على هذه الأسطر المعيبة فورًا.

### كيف يعمل

يحمل كل سطر في شجرة المستند الافتراضية (Virtual Document Tree) القيمة `justifiedSpaceRatio`، أي نسبة عرض المسافة المضبوطة الفعلي إلى العرض الطبيعي للمسافة في الخط. القيمة 1.0 تعني أن المسافات بعرضها الطبيعي. والقيمة 2.5 تعني أن المسافات أعرض من العادية بمقدار 2.5 ضعف.

حين يكون `debug.looseLineHighlight.enabled` بالقيمة `true`، يرسم Sandbox طبقة شبه شفافة فوق معاينة Canvas على كل سطر يتجاوز `justifiedSpaceRatio` فيه العتبة `threshold` المضبوطة. والعتبة الافتراضية 3.0، أي لا تُميَّز إلا الأسطر التي مسافاتها أعرض من العادية ثلاث مرات. وهذا حد مرتفع عن قصد؛ فالأسطر بهذا القدر من التخلخل مشكلات طباعية حقيقية. وهو أيضًا العرض الذي ينضد المحرّك بعده السطر المضبوط غير مضبوط بدلًا من مدّه (انظر [أسطر يعجز مقسِّم الأسطر عن ملئها](#أسطر-يعجز-مقسِّم-الأسطر-عن-ملئها))، فبالقيمة الافتراضية لا يجد التمييز ولا تحذير `looseLines` شيئًا يُذكر في النص الجاري: مثل هذا السطر يُصلَح ولا يُشار إليه. خفّض العتبة إلى 1.5 أو 2 لتجد الأسطر المتخلخلة التي ما زالت مضبوطة.

الطبقة ليست جزءًا من الصفحة، فلا تظهر أبدًا في الصفحات المصدَّرة. ولرسمها على Canvas خاص بك، استدعِ `drawLooseLines(ctx, page, doc, { threshold })` مباشرة بعد `renderPageToCanvas`؛ وتعيد `findLooseLines(doc, { threshold })` الأسطر نفسها بيانات (انظر [الأسطر المتخلخلة في Canvas خاص بك](/ar/docs/configuration#الأسطر-المتخلخلة-في-canvas-خاص-بك)).

### الإعدادات

تمييز الأسطر المتخلخلة جزء من قسم `debug` في `PostextConfig`:

| الخاصية | النوع | القيمة الافتراضية | الوصف |
| --- | --- | --- | --- |
| `looseLineHighlight.enabled` | `boolean` | `false` | هل تُميَّز الأسطر المتخلخلة. |
| `looseLineHighlight.color` | `ColorValue` | `#ff000040` | لون طبقة التمييز. القيمة الافتراضية أحمر شبه شفاف. |
| `looseLineHighlight.threshold` | `number` | `3` | مضاعف عرض المسافة العادية الذي يُعدّ السطر متخلخلًا إذا تجاوزه. القيم الأدنى تلتقط أسطرًا أكثر؛ والقيم الأعلى لا تميّز إلا أسوأ الأسطر. عند 3 أو أكثر، لا يكاد النص الجاري يُظهر شيئًا، لأن الأسطر التي تتجاوز 3 أضعاف تُنضَّد غير مضبوطة. |

```ts
debug: {
  looseLineHighlight: {
    enabled: true,
    threshold: 2.5,
    color: { hex: '#ff660040', model: 'hex' },
  },
}
```

### تفسير النتائج

حين تفعّل تمييز الأسطر المتخلخلة وترى أشرطة حمراء على أسطر معينة، فمعنى ذلك أن المحرّك لم يجد طريقة لنضد تلك الأسطر من دون تباعد مفرط بين الكلمات. ابدأ من الأعلى: الأسباب مرتبة من الأرجح إلى الأقل احتمالًا.

| السبب | الحل |
| --- | --- |
| العمود أضيق مما يناسب حجم الخط | زد عرض العمود، أو صغّر حجم الخط، أو انتقل إلى تخطيط بعمود واحد. |
| كلمات طويلة قليلة مواضع التقسيم | تحقق من أن تقسيم الكلمات مفعّل وأن اللغة الصحيحة مضبوطة. بعض المصطلحات التقنية وأسماء العلم لا مواضع قطع صحيحة فيها. |
| تقسيم الكلمات معطّل | فعّل `bodyText.hyphenation.enabled`. ضبط الأسطر من دون تقسيم الكلمات أسوأ في كل الحالات تقريبًا. |
| بضعة أسطر تبقى متخلخلة أيًّا كان المحرف | اسمح لتلك الأسطر بأخذ قليل من التتبّع: `bodyText.maxJustifyTracking: 10`. انظر [التتبّع ملاذًا أخيرًا](https://postext.dev/ar/docs/justification#التتبّع-ملاذًا-أخيرًا). |
| حدود التباعد بين الكلمات ضيقة أكثر من اللازم | زد `maxWordSpacing` قليلًا (مثلًا من 2 إلى 2.4). هذا يعطي الخوارزمية مجالًا أوسع. |
| اللغة فيها كلمات مركّبة طويلة (مثل الألمانية) | تأكد من ضبط اللغة الصحيحة. أنماط تقسيم الكلمات الألمانية تعالج الكلمات المركّبة جيدًا، لكن بشرط أن يعرف المحرّك أن النص ألماني. |

## الضبط العمودي: موازنة الأعمدة

تحل Knuth-Plass المشكلة *الأفقية*: أين ينقطع كل سطر. وتحل موازنة الأعمدة نظيرتها *العمودية*: أين ينتهي كل عمود. فالناشرون يتوقعون أن يبدأ كل عمود في الصفحة من أعلاها وأن ينتهي محاذيًا لأسفلها تمامًا، سطرًا بسطر عبر الصفحتين المتقابلتين كلتيهما. والقواعد نفسها التي تحمي جودة النص تعمل ضد ذلك: حماية اليتيمة والأرملة، والعناوين ذات `keepWithNext`، والأشكال التي لا تنقسم، كلها تدفع المحتوى إلى العمود التالي قبل أن يمتلئ العمود الحالي تمامًا، فتترك في أسفله سطرًا أو أكثر فارغًا من شبكة خطوط الأساس.

حين يكون `headings.balancing` مفعّلًا (وهو الافتراضي)، يسدّ المحرّك تلك الفجوات كما يفعل المنضّد البشري، فيطبّق رافعاته بترتيب أولوية تحريرية صارم، ولا تعمل كل رافعة إلا على ما عجزت عنه سابقتها:

1. **إطار يختم العمود**. الإطار الذي ينهي عمودًا قصيرًا ينزل بمقدار الحيّز الذي تحت قاعدته بالضبط، فتلتقي حافته السفلى بآخر خط من الشبكة، على مستوى العمود المجاور؛ وقد يكون الحيّز جزءًا من سطر. وتعمل هذه الرافعة أولًا وتأخذ الفجوة كلها ما لم يقضِ `closingBox` بغير ذلك: `'last'` تترك الرافعات التالية تأخذ الأسطر الكاملة أولًا ولا تعطي الإطار إلا ما تتركه، فيبقى الإطار الذي يعلّق على الفقرة التي فوقه قريبًا منها؛ و`'off'` لا تحرّك الإطار أبدًا.
2. **مسافة فوق العناوين**. تُضاف أسطر كاملة من شبكة خطوط الأساس إلى الهامش العلوي للعناوين داخل العمود القصير. وحين تلزم أسطر عدة ويحوي العمود عناوين عدة، تُوزَّع الأسطر بالتناوب بحسب الأهمية، فيأخذ العنوان الأهم دائمًا النصيب الأكبر: 3 أسطر فوق `h2` و`h3` تصير +2 فوق `h2` و+1 فوق `h3`. والعناوين التي في أعلى العمود تمامًا لا تأخذ مسافة إضافية أبدًا (فالأعمدة تظل تبدأ من أعلى الصفحة)، والعنوان الذي في ذيل العمود لا يُدفع أبدًا نحو أسفله.
3. **مسافة بعد نهايات القوائم**. يُضاف سطر من الشبكة حيث تنتهي قائمة أو تعداد، فالفسحة بعد القائمة تُقرأ طبيعية. ولكل نهاية قائمة حد أقصى (`maxLinesAfterList`، القيمة الافتراضية 1). ثم سطر من الشبكة تحت معادلة معروضة أو إطار يستأنف النص بعده، وسطر تحت شكل أو جدول يتصدر العمود (`stretchAfterFloats`، `maxLinesAfterFloat`). وقد يكون النص الذي تحت الشكل بقية فقرة بدأت في الصفحة السابقة؛ فينزل مع ذلك، بمقدار السطر الذي تركته قواعد القطع فارغًا في أسفل العمود (سطر أبقته قاعدة الأرملة فارغًا، أو مسافة فقرة لا مكان بعدها لنص).
4. **الفقرات المرخاة**. ملاذًا أخيرًا، يُعاد تقسيم فقرات من العمود أطول بسطر واحد، على طريقة `\looseness=+1` في TeX، حتى `maxLooseParagraphs` منها (اثنتان افتراضيًا)، بسطر إضافي واحد لكل منها. يعيد مقسِّم الأسطر تشغيل Knuth-Plass طالبًا سطرًا إضافيًا واحدًا بالضبط، ولا يقبل النتيجة إلا حين **يبقى كل سطر من الحل المرخى دون `maxWordSpacing`**: فلا يتجاوز لون النص (type colour) أبدًا الحد الذي ضبطته أنت. ويفضّل المحرّك أطول الفقرات في العمود، حيث يتوزع الحيّز الإضافي على أكبر قدر من الغراء بين الكلمات فلا يُرى. ويتطلب ذلك `optimalLineBreaking` (وهو الافتراضي)؛ وتُستثنى الفقرات المقسومة بين الأعمدة. والفقرة التي نضّدها إصلاح الكلمة المعزولة أقصر بسطر تحسب سطرها الإضافي بدءًا من ذلك النضد: يجوز أن تستعيد السطر الذي أخذه الإصلاح، لكن بنضد لا كلمة معزولة فيه ولا سطر يتجاوز `maxWordSpacing` (حتى postext 1.4 كان يمكن أن تعود بسطر يتجاوز الحد كثيرًا).

   وحين لا يستطيع التباعد بين الكلمات وحده كسب السطر، يجوز للفقرة أيضًا أن تأخذ قليلًا من **التتبّع** الموجب، وهو الإصلاح الكلاسيكي لدى المنضّد. يجرّب المحرّك أصغر مقدار أولًا (نصف `maxTracking`، ثم `maxTracking`، بأجزاء الألف من الـem لكل محرف؛ 10 = 0.01 em افتراضيًا) ويحتفظ بأول مقدار يكسب السطر، تحت شرط التباعد بين الكلمات نفسه. ويُقاس التتبّع ضمن أسطر الفقرة وترسمه كل المُخرِجات (`letterSpacing` في Canvas، و`letter-spacing` في CSS، وتباعد المحارف في PDF). عطّله بالإعداد `trackParagraphs: false`.

### لماذا يبقى الإصلاح موضعيًا

انقطاعات الأعمدة *مقيّدة بالعناصر*: العنصر الذي يفتتح العمود التالي موجود هناك لأنه لم يتسع في الفجوة. فدفع ذيل العمود إلى الأسفل بما لا يزيد عن فجوته لا ينقل أي محتوى إلى العمود أو الصفحة التالية أبدًا، فيثبت كل عمود في مكانه، من دون إعادة تدفق متسلسلة. ومع ذلك يتحقق المحرّك من هذا تجريبيًا: يعيد تشغيل التوزيع بالتعديلات المقترحة (حتى 8 جولات)، ويقيس مجموع الفجوات المتبقية، ويحتفظ دائمًا بأفضل إخراج وجده. والفقرة المرخاة التي تعجز عن كسب سطرها ضمن حد التباعد، بأي مقدار من التتبّع، توضع في القائمة السوداء ويُجرَّب المرشح التالي.

### متى يُترك العمود القصير على حاله

العمود القصير هو أحيانًا المخرج *الصحيح*، والموازنة تعرف متى تتنحى:

- **العمود الأخير من الصفحة** لا يُوازَن إلا حين تتدفق الصفحة بطبيعتها إلى التالية. أما الصفحات التي تنتهي بـ`:::pagebreak`، أو بـ`breakBefore` لعنوان، أو بصفحة افتتاح فصل، فتحتفظ بعمودها الأخير القصير، إذ يجوز أن ينتهي الفصل في منتصف الصفحة.
- **الصفحة الأخيرة من المستند** لا تُوازَن أبدًا.
- العمود الذي **لا موضع تمدد صالحًا فيه** (لا عنوان مؤهلًا، ولا نهاية قائمة، ولا فقرة يمكن إرخاؤها) يحتفظ بفجوته بدلًا من أن يفسد الطباعة.

```js
const doc = buildDocument(content, {
  headings: {
    balancing: {
      enabled: true,            // default
      maxLinesPerHeading: 4,    // cap per heading
      stretchAfterLists: true,  // lever 3
      maxLinesAfterList: 1,     // cap per list end
      looseParagraphs: true,    // lever 4 — bounded by bodyText.maxWordSpacing
      maxLooseParagraphs: 2,    // loose paragraphs per short column
      trackParagraphs: true,    // let a loose paragraph take a little tracking
      maxTracking: 10,          // ‰ em per character (0.01 em)
      closingBox: 'first',      // lever 1: 'first' | 'last' | 'off'
    },
  },
});
```

في Sandbox تجد هذه الإعدادات في قسم *العناوين* من **التصميم › العناوين والمحتويات** («موازنة الأعمدة»، وتحته «التمديد بعد القوائم» و«التمديد تحت الأشكال» و«إطار يختم عمودًا» و«الفقرات المرخاة»). فعّل شبكة خطوط الأساس (**التصميم › متقدّم › أدوات مساعدة على الشاشة**) وانظر إلى عرض Canvas لترى الأثر: حين تكون الموازنة معطّلة، تنتهي الأعمدة القصيرة فوق آخر خط من الشبكة؛ وحين تكون مفعّلة، ينتهي كل عمود قابل للموازنة على الخط نفسه. انظر صفحة [الإعدادات](/ar/docs/configuration#موازنة-الأعمدة) للمرجع الكامل للخيارات.

## مثال كامل

إعدادات كاملة تعرض كل إعدادات تقسيم الكلمات وضبط الأسطر:

```ts
import { buildDocument } from 'postext';

const vdt = buildDocument(content, {
  bodyText: {
    fontFamily: 'EB Garamond',
    fontSize: { value: 9, unit: 'pt' },
    textAlign: 'justify',

    // Knuth-Plass optimal line breaking (default: true)
    optimalLineBreaking: true,

    // Hyphenation
    hyphenation: {
      enabled: true,
      locale: 'es',
    },

    // Word spacing bounds (multipliers of normal space width)
    maxWordSpacing: 2,     // spaces stretch up to 200%
    minWordSpacing: 0.6,   // spaces shrink down to 60%
  },

  // Debug: highlight lines with excessive spacing
  debug: {
    looseLineHighlight: {
      enabled: true,
      threshold: 2.5,
      color: { hex: '#ff000040', model: 'hex' },
    },
  },
});
```

للاطلاع على القائمة الكاملة لخيارات إعدادات نص المتن، انظر صفحة [الإعدادات](/ar/docs/configuration#نص-المتن). ولمعرفة كيف يستعمل مسار الإخراج هذه الإعدادات أثناء قياس النص، انظر صفحة [البنية](/ar/docs/architecture).
