- अरबी web typography में अक्षरों का जुड़ना, bidirectional text, अंकों और punctuation का प्रबंधन, और line justification एक साथ उलझे हुए rendering infrastructure problem हैं; इसे साधारण CSS bug की तरह संभालना मुश्किल है
- पारंपरिक अरबी typesetting में words के बीच space बढ़ाने के बजाय अक्षरों के भीतर की stroke को बढ़ाकर kashida से full justification किया जाता था, लेकिन आधुनिक browsers का
text-align: justifyज़्यादातर words के बीच space बढ़ाता है - अरबी में एक stored codepoint संदर्भ के अनुसार isolated, initial, medial, final रूपों में बदलता है, और OpenType features तथा shaping engine के बिना अक्षर टूटे हुए रूप में render होते हैं
- Unicode के Arabic Presentation Forms, numeral systems, UAX #9 bidirectional algorithm, और invisible control characters खोज विफल होना, phone number उल्टा दिखना, cursor movement में भ्रम जैसी वास्तविक product समस्याएँ पैदा करते हैं
- HarfBuzz, Amiri, W3C Arabic Layout Requirements जैसी मुख्य बुनियादें बन चुकी हैं, लेकिन browsers में अरबी justification और
jstfका उपयोग अभी भी implementation gap बना हुआ है
शुरुआती बिंदु: अरबी typesetting की समस्या जो “CSS bug” जैसी दिखी
- customer dashboard में mixed-content वाले अरबी paragraph design mockup की तरह justified नहीं थे, और बायाँ किनारा टेढ़ा-मेढ़ा render हो रहा था
- उसी block का Latin version “fine” लग रहा था, लेकिन अरबी में line दाएँ से शुरू होती है, इसलिए uneven edge बाईं तरफ बनता है
text-align: justifyलगाने पर भी text वैसा नहीं भर सका जैसा design team ने approve किया था, यानी words के भीतर की stroke बढ़ाकर line भरना संभव नहीं हुआ- उसी product में पहले भी PDF में नाम के अक्षर टूटना, search index fail होना, legacy Unicode codepoints की समस्या जैसी अरबी handling issues बार-बार आए थे
- समस्या का असली कारण किसी एक stylesheet की कमी नहीं, बल्कि web पर अरबी typography की मौजूदा स्थिति है
वह समस्या जिसे हस्तलिपि परंपरा ने हल किया था
- पारंपरिक अरबी हस्तलिपि में words के बीच space बढ़ाने के बजाय अक्षर रूपों के भीतर के joining stroke को बढ़ाकर lines को दोनों किनारों से align किया जाता था
- इस तरीके को taṭwīl या आधुनिक तकनीकी शब्दों में kashida कहा जाता है, जिसमें कुछ अक्षर-युग्मों के बीच joining stroke लंबा किया जाता है
- 17वीं सदी की Naskh में सजे हुए पन्नों पर दोनों margins बराबर दिखते हैं और word spacing नहीं फैलती, जिससे सघन और नियमित texture बनता है
- Ibn Muqla द्वारा व्यवस्थित al-khaṭṭ al-mansūb ने reed pen की हीरे जैसी dot, alif की ऊँचाई, और arc ratio जैसी इकाइयों से letterforms को व्यवस्थित किया
- इस परंपरा में justification space बाँटने की समस्या नहीं, बल्कि letterform और alternate glyph चुनने की shaping problem थी
एक अक्षर, चार रूप
- अरबी हमेशा cursive तरीके से जुड़कर लिखी जाती है; इसमें print और handwriting के लिए block-letter जैसा अलग रूप नहीं होता
- हर अक्षर अपने पड़ोसी अक्षरों के अनुसार isolated, initial, medial, final रूप लेता है, और छह अक्षर आगे की ओर नहीं जुड़ते, जिससे word के भीतर flow टूट जाता है
- Unicode abstract characters को store करता है, font positional glyphs देता है, और shaping engine
isol,init,medi,fina,rlig,mark,mkmkजैसे OpenType features लागू करता है محمدजैसा word storage में चार codepoints है, लेकिन rendering के समय कई glyph selections और OpenType lookups से होकर एक जुड़ी हुई stroke की तरह दिखता है- अगर HarfBuzz जैसा shaping engine न हो, या PDF generator इस process से न गुज़रे, तो वही codepoints अलग-अलग isolated glyphs की तरह render हो जाते हैं
Unicode के जीवाश्म: Arabic Presentation Forms
- DOS और शुरुआती Windows के 8-bit code pages abstract letters नहीं, बल्कि initial, medial जैसे रूपों को ही अलग characters के रूप में encode करते थे
- Unicode ने round-trip compatibility के लिए इन्हें स्वीकार किया, और वे U+FB50 से U+FEFF तक Arabic Presentation Forms block के रूप में बचे हुए हैं
- नए documents में ये codepoints नहीं आने चाहिए, लेकिन PDF text extractors आज भी इन्हें output कर सकते हैं
- अगर एक ही नाम modern Unicode और Presentation Forms में अलग-अलग store हो, तो screen पर दोनों एक जैसे दिखते हैं, लेकिन string comparison और search में अलग माने जाते हैं
- NFKC normalization लगाने से Presentation Forms abstract letters में fold हो जाते हैं और search miss कम हो सकती है
shaping और bidirectional processing को छोड़ देने वाला software
- जो software shaping engine और bidirectional algorithm को छोड़ देता है, वह अक्षरों को एक-एक isolated form में draw करता है और lines को left-to-right रखता है
- ऐसा output दुकानों के signboard, boarding pass, watermark, और पुरानी फिल्मों से जुड़े अरबी text में वास्तव में देखा जाता है
- पुराना Photoshop, default configuration वाला matplotlib, npm के कई PDF generators, और receipt printers ऐसी समस्या पैदा कर सकते हैं
- Python का आम workaround
arabic_reshaperऔरpython-bidiPresentation Forms block का इस्तेमाल कर pre-shaped forms को string में पहले से पका देता है - यह workaround renderer का काम string में पहले से ठूँस देता है, और मूल रूप से text stack की खामी उजागर करता है
तीन तरह के अंक और punctuation की समस्या
- दुनिया जिसे “Arabic numerals” कहती है, 0–9 वही आकृतियाँ नहीं हैं जिन्हें अधिकतर अरबी पाठक रोज़मर्रा में इस्तेमाल करते हैं
- Egypt, Sudan, Levant, Iraq और Gulf क्षेत्रों में Unicode के ARABIC-INDIC DIGITS
٠١٢٣٤٥٦٧٨٩उपयोग होते हैं - Maghreb में Latin digit glyphs उपयोग होते हैं, जबकि Iran, Afghanistan और Pakistan में EXTENDED ARABIC-INDIC DIGITS
۰۱۲۳۴۵۶۷۸۹उपयोग होते हैं - अंक UAX #9 में strong characters नहीं, बल्कि weak characters माने जाते हैं, और पहले आए strong character की दिशा के अनुसार European digits या Arabic digits की तरह फिर से वर्गीकृत होते हैं
- अरबी शब्द के बाद
010-1234-5678जैसा phone number hyphen के neutral माने जाने से screen पर5678-1234-010जैसा उल्टा दिख सकता है - platform-level solution यह है कि number को
या<bdi>में wrap कर directionality अलग कर दी जाए - अरबी क्षेत्रों में decimal और thousands separators U+066B
٫और U+066C٬हैं; ASCII.और,लगभग समान दिखते हैं, लेकिन उनके codepoints और bidi properties अलग हैं
print से web तक चले आए workaround और simplification
- 1514 में Fano में छपी Kitāb Ṣalāt al-Sawāʿī पहली movable-type अरबी printed book थी, जिसमें अक्षर जुड़ाव टूटने और dot placement की गलतियाँ दिखती हैं
- 1537 की Venice की Paganini Qurʾān typesetting और text errors के कारण व्यावसायिक रूप से असफल रही, और उसकी एक copy 1987 में Venice के एक monastery library में मिली
- Ottoman print ban की कहानी में Bayezid II और Selim I के फरमानों का मूल पाठ उपलब्ध नहीं है, और यह मुख्यतः यूरोपीय यात्रियों के विवरणों पर निर्भर करती है
- Cairo की Bulaq Press 1820 में Muhammad Ali ने स्थापित की, और सैकड़ों type pieces तथा बहुत धैर्य के साथ अरबी metal type की गुणवत्ता सुधारी गई
- 1924 का Cairo Qurʾān Amiria Press में metal type से तैयार किया गया और 20वीं सदी में text तथा typography standardization में योगदान दिया
- 1950 के दशक के उत्तरार्ध में Kamel Mrowa और Linotype ने 90-channel magazine constraints के लिए initial forms को medial में, final forms को isolated में मिलाकर और ligatures घटाकर Simplified Arabic बनाया
- Simplified Arabic ने सस्ता और तेज़ newspaper production संभव बनाया और एक पीढ़ी के भीतर अरबी newsroom पर छा गया
वह kashida जिसे web अब तक नहीं खींच पाया
- CSS Text Module Level 3 के शुरुआती drafts में
text-justifyके लिए kashida value थी, और Internet Explorer 5.5 ने 2000 में इसे implement किया था - IE 5.5 ने
text-kashida-spaceproperty भी दी थी, लेकिन दूसरे browsers ने इसे implement नहीं किया, इसलिए यह value spec से हट गई - आधुनिक Chrome, Firefox और Safari में
text-align: justifyअरबी में words के बीच space बढ़ाकर काम करता है - CSS Working Group में अरबी justification issue कम से कम 2015 से खुला है, और W3C Arabic Layout Requirements पर काम भी उसी साल शुरू हुआ
- kashida justification में stretched glyphs width बदलते हैं, width बदलने से line breaks और required stretch फिर बदलते हैं, इसलिए shaping और layout को line level पर बार-बार negotiate करना पड़ता है
- OpenType में 1990s से
jstftable मौजूद है ताकि fonts justification priorities बता सकें, लेकिन shaping engines इसे लगभग पढ़ते नहीं और font makers भी शायद ही इसे देते हैं - Microsoft Word और InDesign Middle East Edition kashida justification देते हैं, लेकिन जिन browser renderers में लोग सबसे ज़्यादा पढ़ते हैं, वे अब भी अक्षरों को stretch नहीं कर पाते
Tatweel hacks और ligature-vowel mark की समस्या
- web पर आम workaround यह है कि text में U+0640 TATWEEL character डाल दिया जाए ताकि stretched stroke जैसा दिखे
- Tatweel content बदल देता है, इसलिए search matching, copy-paste, screen reader, और column reflow में समस्याएँ आती हैं
- Tatweel से बनी stroke वह kashida नहीं है जो font और character rules के अनुसार लगती है, बल्कि लेखक के अनुमान से डाली गई typewriter-style bar है
- OpenType ligatures
rlig,liga,dligमें बँटी होती हैं;lām-alifजैसे अनिवार्य ligature के टूटने पर text केवल बदसूरत नहीं, बल्कि गलत हो जाता है - अगर अक्षरों के बीच U+200C ZERO WIDTH NON-JOINER डाला जाए, तो stored letters वही रहते हैं लेकिन rendering हर अक्षर को isolated form में मजबूर कर देती है
- Safari
"rlig" 0,"liga" 0को ignore करता है, इसलिए mandatory ligature disable demo वहाँ असर नहीं दिखाता - Amiri, Khaled Hosny द्वारा 2011 में SIL Open Font License के तहत जारी किया गया Naskh font है, और 2022 की 1.0 rewrite के बाद यह curved kashida और refined vowel mark stacking देता है
line-height: 1औरoverflow: hiddenवाले card components fully vocalized अरबी text के ऊपर लगने वाले vowel marks को काट सकते हैं
bidirectional algorithm और झूठ बोलता cursor
- अरबी paragraph के भीतर version numbers, English identifiers, URL, फ्रेंच शब्द आदि Unicode Bidirectional Algorithm यानी UAX #9 को सक्रिय करते हैं
- अरबी letters strong right-to-left characters हैं, Latin letters strong left-to-right, digits weak context-following characters, और spaces तथा punctuation neutral characters माने जाते हैं
- यह algorithm हर character को directional class देता है, weak और neutral characters की चरणबद्ध व्याख्या करता है, फिर embedding levels assign कर same-level runs को reverse करता है
- screen का visual order और memory का logical order अलग होने से cursor movement, mouse click, और selection behavior को इन दोनों orders के बीच लगातार translation करना पड़ता है
- run boundaries पर दो वैध cursor positions होती हैं: logical position और visual position; Chrome, Firefox, Qt, और Outlook इन्हें अलग-अलग तरह से handle कर सकते हैं
- mixed Arabic-English text लिखना 2026 में भी major editors, email clients, और chat applications में default रूप से high cognitive-cost experience बना हुआ है
الصفحات 10-20जैसी range rule W2 और neutral hyphen handling के कारण “20 से 10” जैसी दिख सकती है, और इसे ठीक करने के लिए पहले U+200E LEFT-TO-RIGHT MARK डाला जा सकता है
काम करने वाली बुनियाद और बाकी खाली जगह
- Khaled Hosny ने Amiri बनाया, HarfBuzz command-line tool
hb-shapeलिखा, और HarfBuzz के co-maintainer की भूमिका भी निभाई - Behdad Esfahbod ने Hosny से पहले HarfBuzz का बड़ा हिस्सा लिखा, और आज browsers में अरबी letters को सही draw करने वाले shaping engine में योगदान दिया
- Brill ने अपने Semitics catalog के लिए ज़रूरी सभी transliteration characters शामिल करने हेतु John Hudson से Brill typeface बनवाया, और 2011 में इसे non-commercial use के लिए मुफ्त जारी किया
- Sakhr AX-170 लगभग 1984 का ROM से अरबी दिखाने वाला Saudi-Kuwaiti MSX computer था, और right-to-left लिखे जाने वाले Arabic BASIC identifiers को support करता था
- HarfBuzz, Amiri, Scheherazade, GNU Unifont का Presentation Forms support, Noto Arabic, और W3C Arabic Layout documents कुछ व्यक्तियों, संस्थाओं और volunteers के प्रयासों पर बहुत अधिक निर्भर रहे हैं
- browser vendors ने HarfBuzz को मुफ़्त और तैयार होने के बाद अपना लिया, लेकिन स्क्रीन पर हस्तलिपि-परंपरा वाला justification लाने वाले layout loop में उन्होंने लगभग कोई योगदान नहीं दिया
- बचा हुआ gap कुछ layout engines में implement किए जाने वाले अच्छी तरह समझे जा चुके algorithms का है, और customer dashboard के बाएँ किनारे की यह अनियमितता उसी निवेश की कमी का उपयोगकर्ता-स्तर पर दिखने वाला रूप है
1 टिप्पणियां
Lobste.rs की राय
यह सचमुच कमाल का लेख है
और मुझे यह बात पसंद आई कि यह अक्षर
﷽सिर्फ एक code point है। कॉपी करके देखो तो बड़ा अजीब-सा लगता हैइसका मतलब बताया गया है: “सबसे दयालु और सबसे कृपालु अल्लाह के नाम से”
﷽के बारे में लेख की यह पंक्ति काव्यात्मक है“उस दौर का एक स्मारक, जब rendering engine पर कोई भरोसा नहीं करता था, इसलिए rendering को encoding में ही पका दिया जाता था। जैसे पाठ करती हुई एक मक्खी एम्बर में हमेशा के लिए संरक्षित हो।”
यहाँ दिए गए Wikipedia लिंक के references को आगे खंगालना मजेदार था: https://lobste.rs/c/dq2ucz
संक्षेप में, यह character Unicode में इसलिए आया क्योंकि वह एक Pakistani code page में था, और वहाँ इसलिए था क्योंकि कानूनी दस्तावेज़ों में उस वाक्यांश को शामिल करना एक कानूनी आवश्यकता थी। Urdu एक Indo-European language है, इसलिए उस समय की तकनीक में Basmallah लिखने के लिए Arabic code page में किसी “external call” की तरह switch करना कठिन रहा होगा
दुर्भाग्य से, सारी टिप्पणियाँ उस community की खूबियाँ नहीं दिखातीं
मेटा: इस तरह के लेखों के लिए
typographyटैग चाहिए, इसका यह एक और बढ़िया उदाहरण हैlobste.rs पर टैग मुख्यतः filtering के लिए होते हैं
IE की
text-justifyproperty — उस दौर में कितनी दिलचस्प चीज़ें थीं।text-justify: newspaperभी था, और दशकों बाद कुछ लोगों ने इसे Knuth-Plass या उससे मिलती-जुलती किसी चीज़ के रूप में समझाया, लेकिन मुझे नहीं लगता कि असल में ऐसा थाhttps://mediumwell.com/wp-content/uploads/… दिखाता है कि उस समय
text-justify: newspaperकहे जाने वाला व्यवहार आज की spec केtext-justify: inter-characterसे मेल खाता हैIE के पास सच में बहुत शुरुआती दौर में कई शानदार features थे, और दूसरे browsers ने उन्हें “बहुत मुश्किल” वाली टोकरी में डालकर छोड़ दिया। नतीजा यह हुआ कि वे या तो कभी वापस नहीं आए, या 15 साल, बल्कि 30 साल बाद लौटे। Firefox को
text-justify: inter-character2017 में मिला, Chromium ने इस हिस्से को बस कुछ महीने पहले implement किया, और Safari में अभी भी यह नहीं हैबेहद शानदार और जानकारीपूर्ण लेख। पूरी कहानी को व्यापक संदर्भ देने वाला ऐतिहासिक पृष्ठभूमि वाला हिस्सा खास तौर पर बहुत अच्छा लगा
इतिहास से जुड़ी degree और IT करियर — दोनों रखने वाले व्यक्ति के रूप में, यह लेख मेरी दोनों रुचियों को पूरी तरह छू गया
लेख में कहीं कुछ मेरे LLM detector को ट्रिगर करता है, जो अफ़सोस की बात है। ऐसा इसलिए क्योंकि इसमें गहराई है और modern tech stack के कम documented हिस्सों को कवर किया गया है
जो हिस्सा LLM-जैसा लगता है, उसका एक उदाहरण यह है, और ऐसा एहसास पूरे लेख में है:
“कोई browser यह सुविधा क्यों नहीं देता, इसका कारण संरचनात्मक है, और बाधा के रूप में वह संरचना काफ़ी सुंदर है। Latin justification shaped text को स्थिर मानकर चलती है, शब्दों को मापती है, बची हुई जगह को spacing में उड़ेल देती है, और काम खत्म। Shaping और layout अपने-अपने डिब्बों में रहते हैं, और चलन में मौजूद हर text stack उसी अलगाव को केंद्र में रखकर डिज़ाइन किया गया है। Kashida justification उन डिब्बों को खोलकर रख देती है।”
मैं @lr0 से पूछना चाहूँगा कि क्या इस लेख का मुख्य पाठ LLM से generate, refine, या translate किया गया था। अगर हाँ, तो final output पर LLM के नियंत्रण के स्तर को थोड़ा समायोजित करना अच्छा हो सकता है। पुराने ब्लॉग पोस्ट, जैसे https://lr0.org/blog/p/gpt/ और https://lr0.org/blog/p/linux_new_users/ , कहीं अधिक मानवीय लगे थे