आम भूलें¶
यह साइट पैंतीस भाषाओं में अनुवादित है, और उनमें से हर एक उसी लूप को चलाकर बनी है जो यह दस्तावेज़ीकरण सिखाता है। उद्योग के मानकों से यह छोटा corpus है, और फिर भी उन अधिकांश जालों में फँसने के लिए काफ़ी था जो i18n को दिखने से कहीं ज़्यादा कठिन बनाते हैं।
नीचे का हर खंड कुछ ऐसा है जो यहाँ सचमुच ग़लत हुआ — उस समय वह कैसा दिखा, और वह रेखा कहाँ पड़ती है जो लाइब्रेरी की जाँच को आपके अपने विवेक से अलग करती है।
वेरिएबल का नाम बदलना पूरे वाक्य का दोबारा अनुवाद करा देता है¶
msgid ही कैटलॉग की key है, और interpolate किया गया नाम उसके भीतर होता है।
एक स्थिरांक को module scope में ले जाकर उसे Python शैली की माँग के अनुसार
बड़े अक्षरों में लिखना — author से AUTHOR — ने
Copyright © 2026 {author} · MIT License को ऐसे संदेश में बदल दिया जिसे
किसी कैटलॉग ने कभी देखा ही नहीं था। उस लाइन का हर अनुवाद, हर भाषा में, फिर
से fuzzy चक्र से गुज़रता — ऐसे नाम-परिवर्तन के लिए जिसने पाठक को दिखने वाला
कुछ भी नहीं बदला।
लाइब्रेरी आपको रोकेगी नहीं: दोनों वर्तनियाँ वैध placeholder नाम हैं। वह जो करती है वह यह है कि नाम को सहेजने लायक बनाती है — interpolation को एक नंगा नाम होना ही चाहिए, इसलिए कैटलॉग key में जो चीज़ बैठती है वह एक शब्द है जिसे अनुवादक पढ़ सकता है, कोई expression नहीं।
इसका उल्टा मामला रचना से ही सुरक्षित है। conversion और format spec msgid का
हिस्सा नहीं हैं, इसलिए {amount:,.2f} को कसकर {amount:,.0f} करना किसी key
को नहीं बदलता और कहीं किसी अनुवाद को अमान्य नहीं करता।
nplurals=2 का मतलब दो अलग स्ट्रिंग नहीं है¶
तुर्की, हंगेरियाई, फ़ारसी और बांग्ला — चारों दो बहुवचन रूप घोषित करती हैं,
और चारों में गिनती वाले संदेश के दोनों रूप वैध रूप से एक ही स्ट्रिंग होते
हैं — संख्यावाचक के बाद संज्ञा एकवचन ही रहती है, इसलिए {n} sayfa एक पेज के
लिए भी सही है और दस के लिए भी। जो समीक्षक इस दोहराव को "ठीक" कर देता है, वह
अनुवाद तोड़ देता है।
उलटी ग़लती भी उतनी ही आसान है। लातवियाई का तीसरा रूप केवल शून्य के लिए
है; स्लोवेनियाई का दूसरा द्विवचन है, ठीक दो के लिए; रोमानियाई के अंतिम
रूप को वह शब्द de चाहिए जो उसके पहले दो रूपों में होना ही नहीं चाहिए। इन
ख़ानों को एक एकवचन और एक बहुवचन से भर देना ऐसा कैटलॉग बनाता है जो केवल उन्हीं
गिनतियों के लिए ग़लत है जिन्हें कोई जाँचता ही नहीं।
इससे भी बुरा: ख़ानों का क्रम अर्थपूर्ण नहीं है। वेल्श अपने पाँच रूपों को इस
तरह अनुक्रमित करती है कि msgstr[0] सामान्य स्थिति है और msgstr[1]
एकवचन। उन्हें स्पष्ट दिखने वाले क्रम में भरना एकवचन को ठीक वहीं रख देता है
जहाँ हर बिना-गिनती वाला संदेश उसे पा लेगा।
लाइब्रेरी इसमें से कुछ भी अपने ऊपर नहीं लेती, और यही तो बात है: लक्ष्य भाषा का बहुवचन नियम उसी के अपने कैटलॉग हेडर में रहता है, और union/intersection नियम अनुवाद को स्रोत से ज़्यादा रूप रखने देता है, या कम। वह जो जाँचती है वह इकलौती चीज़ है जिसे भाषा जाने बिना जाँचा जा सकता है — कि हर रूप उन placeholders को बनाए रखे जो उसे चाहिए।
दो रूप एक कारण से एक जैसे हो सकते हैं¶
आयरिश में पाँच बहुवचन रूप हैं, और इस साइट की बिल्ड रिपोर्ट में उनमें से कई
एक जैसे ही लिखे गए हैं। यह copy-paste की चूक नहीं है: leathanach l से
शुरू होता है, और आयरिश के संख्यावाचक जिन दो आदि-विकारों को जगाते हैं उनमें
से कोई भी l पर लिखा नहीं जाता। रूप फिर भी असली काम करते हैं — धातु
leathanach और leathanaigh के बीच बदलती रहती है, और दस से ऊपर की गिनतियाँ
एकवचन पर लौट आती हैं — पर "पेज" के अर्थ वाली कोई भी संज्ञा यह अंतर दिखाती ही
नहीं।
कोई भी जाँच जो एक जैसे रूपों को संदिग्ध बताती है, सही आयरिश को भी पकड़ लेगी। इसके लिए इकलौता समीक्षक वह इंसान है जो भाषा जानता है।
एक संदेश केवल एक ही गिनती से मेल खा सकता है¶
इस साइट की बिल्ड रिपोर्ट बताती है कि कितने पेज रेंडर हुए और कितना समय लगा।
इसे "Rendered {n} pages in {seconds} seconds" की तरह लिखना निर्दोष दिखता है
और अनुवाद्य नहीं है: gettext एक गिनती से एक रूप चुनता है, और वह गिनती n
है। शब्द seconds को ऐसी संख्या से मेल खाना पड़ता जिसे बहुवचन तंत्र कभी
देखता ही नहीं।
उपाय यह है कि दूसरी मात्रा को शब्द की बजाय इकाई-संकेत बनाया जाए, और
इकाई-संकेत ख़ुद भी स्थानीयकृत होते हैं: इस साइट के कैटलॉग s, с, ث,
שנ׳ और mp रखते हैं, और फ़्रेंच, स्पैनिश तथा स्वीडिश टाइपोग्राफ़ी संकेत से
पहले एक स्पेस चाहती है जहाँ अंग्रेज़ी नहीं चाहती। इसमें से कुछ भी लाइब्रेरी
का काम नहीं — पर यह ध्यान देना कि किसी संदेश को दो मेलों की ज़रूरत है, ज़रूर
उसका काम है, और उसका इकलौता औज़ार है संदेश को अलग तरह से लिखना।
अंग्रेज़ी वाक्य का संपादन विदेशी व्याकरण का संपादन है¶
होम पेज पहले कहता था "all ten language editions"। संख्या हटाना — अंग्रेज़ी में एक शब्द का संपादन, इसलिए किया गया क्योंकि संख्या बार-बार पुरानी पड़ जाती थी — ने बहुवचन कर्ता को एकवचन बना दिया। स्पैनिश, इतालवी, पुर्तगाली, रूसी, यूक्रेनी, ग्रीक, डच और हिब्रू — सबको क्रिया का मेल फिर से बिठाना पड़ा; कइयों में कृदंत भी बदलना पड़ा।
स्रोत का जो संपादन अंग्रेज़ी में मामूली पढ़ा जाता है, वह आगे की धारा में
मामूली नहीं होता। उसे fuzzy चिह्नित करना — जो pybabel update करता ही है —
वही तंत्र है जो हर अनुवादक को ध्यान देने का मौक़ा देता है।
अदृश्य अंतर हर copy-paste से बच निकलते हैं¶
गाइड एक ऐसे निदान को उद्धृत करती है जिसमें (nаme) है — एक जान-बूझकर किया
गया escape, क्योंकि जिस अक्षर का वह नाम लेता है वह सिरिलिक а है जिसे
कोई पाठक लातिन वाले से अलग बता ही नहीं सकता। इस साइट के अनुवादकों ने उस
escape को असली अक्षर में पाँच अलग-अलग बार बदल दिया, पाँच अलग भाषाओं में,
और हर बार ऐसा पेज बना जो सही दिखता था और ग़लत था।
यह वाली लाइब्रेरी सचमुच पकड़ लेती है, और यही वजह है कि निदान जिस आकार के हैं उसी आकार के हैं: जिस placeholder के अक्षर लिपियाँ मिला देते हैं, उसे दो बार बताया जाता है — एक बार पढ़ने योग्य रूप में और एक बार escaped, क्योंकि escaped रूप ही इकलौती वर्तनी है जो दोनों को अलग करती है। ब्रेसों के भीतर का no-break space इसी वजह से code point के रूप में छापा जाता है। कैटलॉग checker उस संदेश को शिप होने से पहले ही अस्वीकार कर देता है।
ख़ाली न होना अनुवादित होना नहीं है¶
ऐसा कैटलॉग जिसके msgid ही msgstr में कॉपी करके ढाँचा खड़ा किया गया हो, हर भोली जाँच पास कर जाता है: कुछ भी ख़ाली नहीं, कुछ भी fuzzy नहीं, संदेश-समुच्चय बिल्कुल मेल खाता है। इस साइट का एक संस्करण कई घंटों तक इसी तरह शिप रहा। और वैसे ही एक दूसरे संस्करण के आठ पेज, जो अंग्रेज़ी स्रोत की बाइट-दर-बाइट नक़ल थे — जो दोनों के बीच code blocks की तुलना करने वाली जाँच पास कर जाते हैं, क्योंकि वे एक ही फ़ाइल हैं।
इनमें से कोई भी ऐसी चीज़ नहीं जिसे कोई अनुवाद लाइब्रेरी देख सके। दोनों की
जाँच सस्ती है, पर हर एंट्री का अपने स्रोत से भिन्न होना अनिवार्य करके नहीं:
OK, उत्पादों के नाम, व्यक्तिवाचक नाम, संक्षिप्ताक्षर और code identifiers —
सब अपने आप में ही अनुवादित होते हैं, और इसे मना करने वाली जाँच हमेशा के लिए
झूठे अलार्म देती रहती है।
इसके बजाय पूरे कैटलॉग या पूरे पेज पर दर मापिए, और बाहरी छोरों को किसी मनुष्य के पास भेजिए। इस साइट का अपना टेस्ट ठीक यही करता है — वह हर संस्करण की गद्य पंक्तियों की तुलना अंग्रेज़ी स्रोत से करता है और 25% से अधिक समान होने पर विफल हो जाता है। नक़ली संस्करण 87% पर था; हर असली अनुवाद 4% से 8% के बीच रहता है, जो उन पंक्तियों की छोटी-सी पूँछ है जो वाजिब वजहों से मेल खाती हैं, जैसे URL और उद्धृत प्रोग्राम-आउटपुट। दोनों समुच्चय इतने दूर हैं कि थ्रेशोल्ड को सटीक होने की ज़रूरत नहीं।
कैटलॉग ही इकलौती अनुवादित चीज़ नहीं है¶
यहाँ की दो विफलताओं का gettext से कोई लेना-देना नहीं था।
किसी शीर्षक का अनुवाद उससे बनने वाले anchor को बदल देता है, इसलिए उस खंड की ओर जाने वाली हर अंतर-पृष्ठ कड़ी टूट जाती है — चुपचाप, केवल उसी भाषा में। यह साइट हर शीर्षक पर अंग्रेज़ी anchor जड़ देती है, और एक टेस्ट अपेक्षित सूची अंग्रेज़ी पेज से निकालता है।
और साइट जनरेटर अड़सठ भाषाओं के लिए इंटरफ़ेस अनुवाद भेजता है, जिनमें स्वाहिली या आयरिश नहीं हैं। इनके बिना बिल्ड अंग्रेज़ी पर उतर नहीं आता; टेम्पलेट का include विफल हो जाता है और वह संस्करण बन ही नहीं पाता। इस रिपॉज़िटरी की अपनी दो फ़ाइलें उसी खाई को भरने के लिए मौजूद हैं।
आपके औज़ारों में भी बग होते हैं¶
बासी कैटलॉग पकड़ने के लिए यह दस्तावेज़ीकरण जिस CI चरण की सिफ़ारिश करता है,
pybabel update --check, वह किसी भी ऐसे प्रोजेक्ट के लिए वह काम नहीं कर
सकता जो pgettext या npgettext उपयोग करता है। Babel 2.18.0 पर वह
msgctxt वाले हर कैटलॉग को, हर बार, पुराना बता देता है। तुलना
Catalog.is_identical से होकर जाती है, जो हर संदेश को उसी key से ढूँढ़ती है
जिसके नीचे वह रखा गया है — और contextual संदेश के लिए वह key (id, context)
जोड़ी है, जिसे Catalog.get स्वीकार नहीं करता। खोज कुछ नहीं लौटाती, और
कैटलॉग कभी बराबर नहीं निकलते:
>>> from babel.messages.catalog import Catalog
>>> c = Catalog(locale="ja")
>>> c.add("Guide", "ガイド", context="navigation")
<Message 'Guide' (flags: [])>
>>> c.is_identical(c)
False
यह यहीं, उसे उपयोग करने की कोशिश में मिला, upstream रिपोर्ट किया गया, और इसकी जगह लेने वाली जाँच production पेज पर है।
आम सबक़ असहज वाला है: जो गेट हमेशा लाल रहता है वह गेट न होने से बुरा है, क्योंकि टीम उसे बंद कर देती है। अपनी CI जाँच पर विफल होने का भरोसा करने से पहले पक्का कर लीजिए कि वह सचमुच पास भी हो सकती है।
लाइब्रेरी किस लिए है, एक पंक्ति में¶
इस पेज का ज़्यादातर हिस्सा ऐसा विवेक है जिसे कोई औज़ार अपने ज़िम्मे नहीं ले सकता। औज़ार जो कर सकता है वह यह है: गारंटी दे कि कोई अनुवाद उस वाक्य की संरचना नहीं बदल सकता जिसका वह अनुवाद है — न कोई value गिरा सकता है, न गढ़ सकता है, न उसका स्वरूप बदल सकता है, न आपके objects के भीतर हाथ डाल सकता है — और यह बात ऐसे वाक्य में कह सके जिस पर उसे ठीक करने वाला व्यक्ति कार्रवाई कर सके। यही सब कुछ है जो यह लाइब्रेरी वादा करती है, और इस साइट का बाक़ी हिस्सा यह है कि वह उसे निभाती कैसे है।