Author:
    Creation:2026-10-03Last update:2026-10-03

    ICU MessageFormat जावास्क्रिप्ट के लिए क्यों नहीं बना है

    youtube.com

    ICU MessageFormat एक बेहतरीन मानक है। यह पूरी तरह से परिपूर्ण है, अनुवादक इसे अच्छी तरह समझते हैं, और अधिकांश अनुवाद प्रबंधन प्रणालियाँ (TMS) इसे पढ़ सकती हैं। समस्या उस रनटाइम परिवेश में है जिसके लिए इसे तैयार किया गया था। ICU का जन्म C++ और Java की दुनिया में हुआ था, जहाँ पूरे एप्लिकेशन के आकार की तुलना में एक संपूर्ण संदेश पार्सर और फॉर्मेटर का आकार नगण्य होता है। लेकिन ब्राउज़र बंडल में यह अतिरिक्त लागत हर पेज लोड पर चुकानी पड़ती है।

    यह लेख विश्लेषण करता है कि ICU कहाँ से आया, बहुवचन रूपों के लिए इसका सिंटैक्स इतना भारी क्यों है, और पूर्ण संगतता किसी भी जावास्क्रिप्ट i18n लाइब्रेरी के बंडल आकार को क्यों बढ़ा देती है। यदि आपको सीधे इसके सिंटैक्स को समझना है, तो पहले ICU Message Format संदर्भ गाइड पढ़ें।

    IBM से यूनिकोड कंसोर्टियम तक

    ICU का पूरा नाम International Components for Unicode है। इसके संदेश सिंटैक्स की शुरुआत जावा से हुई: Apple और IBM के एक संयुक्त उद्यम Taligent ने JDK 1.1 (1997) की अंतर्राष्ट्रीयकरण क्लासें लिखीं, जिसमें java.text.MessageFormat शामिल था। IBM ने इन्हें ICU4J के रूप में विकसित करना जारी रखा, C/C++ के लिए ICU4C के रूप में पोर्ट किया और 1999 में इसे ओपन-सोर्स किया। 2016 में, ICU यूनिकोड कंसोर्टियम के अधीन आ गया, जो उस CLDR लोकेल डेटा का प्रबंधन भी करता है जिस पर ICU निर्भर है।

    इसका प्रारंभिक उपयोग

    इसका प्राथमिक लक्ष्य सर्वर और डेस्कटॉप सॉफ़्टवेयर थे: जावा एंटरप्राइज एप्लिकेशन, आईबीएम उत्पाद और बाद में ऑपरेटिंग सिस्टम। संदेश ResourceBundle के माध्यम से लोड की जाने वाली जावा .properties फ़ाइलों में या C/C++ के लिए ICU के अपने संसाधन बंडल प्रारूप में रखे जाते थे:

    messages_fr.properties
    inbox.unread={count, plural, one {# message non lu} other {# messages non lus}}
    
    java
    String pattern = bundle.getString("inbox.unread");
    String text = new MessageFormat(pattern, Locale.FRENCH)
        .format(Map.of("count", 5)); // "5 messages non lus"
    

    मूल JDK संस्करण में plural कीवर्ड नहीं था। इसमें संख्यात्मक श्रेणियों के साथ choice ({0,choice,0#no files|1#one file|1<{0} files}) का उपयोग किया जाता था, जो केवल अंग्रेजी जैसी बहुवचन संरचना वाली भाषाओं के अनुकूल था। ICU ने 2008 (ICU 4.0) में CLDR नियमों पर आधारित plural को जोड़ा और 2010 (ICU 4.4) में select पेश किया।

    .po से अंतर

    अक्सर लोग ICU को gettext समझने की भूल कर बैठते हैं, लेकिन ये दोनों अलग-अलग परंपराएँ हैं। .po फ़ाइलें GNU gettext (C, Linux, बाद में PHP और Python) से आती हैं। एक .po प्रविष्टि में सीधे msgid / msgstr जोड़े होते हैं, और बहुवचन का निर्धारण फ़ाइल हेडर में दिए गए C एक्सप्रेशन (Plural-Forms: nplurals=2; plural=(n > 1);) द्वारा होता है। संदेश के भीतर कोई ब्रांचिंग नहीं होती। इसके विपरीत, ICU ब्रांचिंग को सीधे स्ट्रिंग के भीतर रखता है, जिससे एक ही संदेश में plural, select और संख्या स्वरूपण को एक साथ जोड़ा जा सकता है।

    आज ICU कहाँ काम करता है

    ICU4C आज Android, iOS, macOS, Windows, Node.js और Chrome तथा Firefox के जावास्क्रिप्ट इंजनों में मूल रूप से मौजूद है। ब्राउज़र के मानक Intl API काफी हद तक इसी पर बने हैं। इसलिए, ब्राउज़र में ICU के बहुवचन नियम और दिनांक तथा संख्या स्वरूपण पहले से मौजूद हैं। ब्राउज़र के पास जो नहीं है, वह है इसका संदेश पार्सर: Intl.MessageFormat अभी भी TC39 प्रस्ताव के शुरुआती चरण में है, जो नए MessageFormat 2 सिंटैक्स पर आधारित है और ICU MessageFormat 1 के साथ संगत नहीं है।

    यह इतिहास इसके डिज़ाइन निर्णयों को स्पष्ट करता है:

    • यह सर्वर और डेस्कटॉप रनटाइम को लक्षित करता है। रनटाइम पर स्ट्रिंग पार्स करना वहाँ बहुत सस्ता है, और लाइब्रेरी ऑपरेटिंग सिस्टम स्तर पर एक बार स्थापित होती है, जिसे हर आगंतुक द्वारा नेटवर्क से डाउनलोड नहीं किया जाता।
    • यह स्ट्रिंग के अंदर एक DSL है। ब्रांचिंग, संख्याओं और तिथियों का स्वरूपण और नेस्टिंग सभी एक ही सिंटैक्स में रहते हैं जिसे अनुवादक कोड छुए बिना संपादित कर सकते हैं।
    • यह पूर्णता का लक्ष्य रखता है। अनुवादक को जिस भी व्याकरणिक स्थिति की आवश्यकता हो सकती है, उसके लिए एक विशिष्ट ऑपरेटर मौजूद है।

    इनमें से कोई भी निर्णय ग़लत नहीं है। वे केवल ऐसे परिवेश को मानकर चले थे जो ब्राउज़र नहीं है।

    बहुवचन सिंटैक्स अत्यधिक जटिल है

    ICU की सबसे आम संरचना ही सबसे अधिक जटिल भी है। शून्य की स्थिति वाले काउंट को इस प्रकार लिखा जाता है:

    text
    {count, plural,
      =0 {No unread messages}
      one {# unread message}
      other {# unread messages}
    }
    

    इसके लिए तर्क का नाम, कीवर्ड plural, प्रत्येक शाखा के लिए एक केस लेबल, नेस्टेड कर्ली ब्रैकेट और # को एक विशेष टोकन के रूप में उपयोग करना पड़ता है जो केवल बहुवचन शाखाओं के अंदर मान्य होता है। यदि लिंग (gender) भी जोड़ दिया जाए, तो संरचना और अधिक गहरी हो जाती है:

    text
    {gender, select,
      female {{count, plural,
        one {She has # unread message}
        other {She has # unread messages}
      }}
      male {{count, plural,
        one {He has # unread message}
        other {He has # unread messages}
      }}
      other {{count, plural,
        one {They have # unread message}
        other {They have # unread messages}
      }}
    }
    

    पंद्रह में से नौ पंक्तियाँ केवल सिंटैक्स के ढाँचे के लिए हैं। पोलिश जैसी भाषा को इन तीन लिंग शाखाओं में से प्रत्येक में चार बहुवचन शाखाओं की आवश्यकता होती है, जिससे अनुवादित स्ट्रिंग कोष्ठकों का एक घना जंगल बन जाती है जहाँ एक भी छूटा हुआ } पूरे संदेश को क्रैश कर देता है, और अक्सर इसका पता केवल रनटाइम में चलता है।

    जावास्क्रिप्ट में इसी संरचना को शुद्ध डेटा के रूप में व्यक्त किया जा सकता है: एक ऐसा ऑब्जेक्ट जिसकी कुंजियाँ बहुवचन श्रेणियों से मेल खाती हैं, जिसे टाइप सिस्टम और कोड एडिटर द्वारा जाँचा जा सकता है, बिना फ़ाइल और मान के बीच किसी पार्सर की आवश्यकता के।

    पूर्णता की भारी कीमत

    ICU बहुत से फीचर्स को कवर करता है:

    • सटीक मिलान (=0) और ऑफ़सेट (offset:) के साथ plural
    • अपनी अलग CLDR क्रमिक तालिका के साथ selectordinal
    • असीमित गहराई तक नेस्ट होने वाला select
    • पारंपरिक शैली (number, currency) और स्केलेटन (::currency/EUR compact-short) में number, date और time तर्क
    • एस्केप और उद्धरण नियम ('{', '')
    • कुछ कार्यान्वयनों में रिच-टेक्स्ट टैग (<b>…</b>)

    ICU के साथ 1:1 पूर्ण संगतता का दावा करने वाली लाइब्रेरी को यह सब कुछ बंडल में शामिल करना पड़ता है, क्योंकि वह बिल्ड-टाइम पर यह अनुमान नहीं लगा सकती कि आपके संदेश किन सुविधाओं का उपयोग करेंगे। व्यावहारिक रूप से इसका अर्थ है:

    1. एक पार्सर जो स्ट्रिंग को AST में बदलता है और त्रुटिपूर्ण कोष्ठकों को संभालता है।
    2. संख्या और दिनांक के :: सिंटैक्स के लिए एक स्केलेटन पार्सर, जो अपने आप में एक छोटी भाषा है।
    3. एक फॉर्मेटर जो AST को पार करता है और प्रत्येक नोड को Intl.PluralRules, Intl.NumberFormat और Intl.DateTimeFormat से जोड़ता है।

    तीसरा भाग बहुत हल्का है क्योंकि आधुनिक जावास्क्रिप्ट में CLDR लॉजिक पहले से ही Intl में अंतर्निहित है। पहले दो घटक केवल स्ट्रिंग सिंटैक्स को पढ़ने के लिए मौजूद हैं। FormatJS के intl-messageformat में (जो react-intl और next-intl का आधार है) इसका अर्थ है लगभग 10 KB संपीड़ित जावास्क्रिप्ट कोड जो आपके अपने संदेश लोड होने से पहले हर उपयोगकर्ता को भेजा जाता है।

    अधिकांश एप्लिकेशन इसके एक छोटे से हिस्से का उपयोग करते हैं: {name} प्रतिस्थापन और कुछ plural ब्लॉक। फिर भी वे स्केलेटन, क्रमिक संख्याओं और ऑफ़सेट के पूरे पार्सर को डाउनलोड करते हैं, क्योंकि रनटाइम पर पार्स की गई स्ट्रिंग बंडलर को यह नहीं बता सकती कि क्या हटाया जा सकता है।

    next-intl को भी इसी समस्या का सामना करना पड़ा

    यह केवल सैद्धांतिक चिंता नहीं है। next-intl, जो सबसे लोकप्रिय ICU-आधारित पुस्तकालयों में से एक है, इसी निष्कर्ष पर पहुँचा। संस्करण 4.8 (जनवरी 2026) में इसने एक प्रायोगिक precompile विकल्प जोड़ा जो बिल्ड समय पर ICU संदेशों को एक कॉम्पैक्ट AST में पार्स करता है और रनटाइम पार्सर को एक छोटे मूल्यांकनकर्ता से बदल देता है। इस विकल्प को चालू करने पर लगभग 9 KB संपीड़ित जावास्क्रिप्ट कम होने की जानकारी दी गई है।

    लेकिन यह समझौता इस दृष्टिकोण की सीमाओं को भी उजागर करता है: प्रीकंपाइलेशन के साथ t.raw काम नहीं करता, क्योंकि कच्ची ICU स्ट्रिंग रनटाइम पर मौजूद नहीं रहती। जैसे ही आप ब्राउज़र में पार्स करना बंद करते हैं, आप वास्तव में ICU वितरित नहीं कर रहे होते। आप इसका संकलित रूप भेज रहे होते हैं, और स्ट्रिंग सिंटैक्स केवल लिखने का माध्यम बनकर रह जाता है।

    उस बिंदु पर यह प्रश्न स्वाभाविक है: यदि ब्राउज़र कभी उस स्ट्रिंग को सीधे पढ़ता ही नहीं है, तो डेवलपर्स और अनुवादकों को इसे इस जटिल रूप में क्यों लिखना चाहिए?

    जावास्क्रिप्ट-नेटिव दृष्टिकोण कैसा दिखता है

    जावास्क्रिप्ट सबसे जटिल हिस्से को पहले ही मूल रूप से हल कर चुका है। Intl.PluralRules जानता है कि पोलिश में चार बहुवचन श्रेणियाँ हैं और अंग्रेजी में चार क्रमिक श्रेणियाँ हैं। Intl.NumberFormat और Intl.DateTimeFormat मुद्राओं, इकाइयों, संक्षिप्त नोटेशन और कैलेंडर को संभालते हैं। शेष काम केवल एक शाखा चुनना और मान डालना है, जिसमें संरचना के डेटा होने पर कोड की कुछ ही पंक्तियाँ लगती हैं।

    यही मॉडल Intlayer उपयोग करता है। ब्रांचिंग एक टाइप किए गए सामग्री घोषणा में एक फ़ंक्शन है, और प्रत्येक लोकेल केवल उन्हीं श्रेणियों को घोषित करता है जिनकी उसके व्याकरण को आवश्यकता होती है:

    **/*.content.ts
    import { gender, plural, t, type Dictionary } from "intlayer";
    
    const inboxContent = {
      key: "inbox",
      content: {
        unread: t({
          hi: plural({
            one: "{{count}} बिना पढ़ा संदेश",
            other: "{{count}} बिना पढ़े संदेश",
          }),
          en: plural({
            one: "{{count}} unread message",
            other: "{{count}} unread messages",
          }),
          pl: plural({
            one: "{{count}} nieprzeczytana wiadomość",
            few: "{{count}} nieprzeczytane wiadomości",
            many: "{{count}} nieprzeczytanych wiadomości",
            other: "{{count}} nieprzeczytanej wiadomości",
          }),
        }),
      },
    } satisfies Dictionary;
    
    export default inboxContent;
    
    **/*.tsx
    const { unread } = useIntlayer("inbox");
    
    unread(5); // पोलिश लोकेल → "5 nieprzeczytanych wiadomości"
    

    ICU की तुलना में मुख्य अंतर:

    • बंडल में कोई पार्सर नहीं। ब्राउज़र तक पहुँचने पर संरचना पहले से ही एक जावास्क्रिप्ट ऑब्जेक्ट होती है। plural ब्राउज़र में मौजूद Intl.PluralRules की सहायता से कुंजी चुनता है।
    • बिल्ड समय पर त्रुटि पहचान। छूटी हुई शाखा या गलत स्पेलिंग वाली कुंजी TypeScript टाइप त्रुटि बन जाती है, जिससे प्रोडक्शन में होने वाली विफलताएं रुकती हैं।
    • स्वरूपण संदेश से बाहर रहता है। संख्याएँ, तारीखें और मुद्राएँ फॉर्मेटर हुक के माध्यम से संसाधित होती हैं जो सीधे Intl का उपयोग करते हैं, जिससे स्केलेटन पार्सर की आवश्यकता नहीं रहती।
    • अप्रयुक्त सुविधाओं की कोई लागत नहीं। यदि कोई संदेश gender का उपयोग नहीं करता है, तो बंडलर इसे tree-shaking द्वारा हटा देता है।

    • फॉर्मेटर हुक

    निश्चित रूप से इसके अपने पहलू हैं: एक बिल्ड चरण की आवश्यकता होती है, सामग्री फ़ाइलें सादे पाठ के बजाय कोड होती हैं, और कुछ टीएमएस उपकरण जो पूरी तरह से आईसीयू स्ट्रिंग्स पर निर्भर हैं, सीधे टाइपस्क्रिप्ट घोषणा फ़ाइलों को नहीं पढ़ पाते हैं।

    जब ICU अभी भी सही विकल्प है

    ICU इन स्थितियों में बेहतर विकल्प बना हुआ है:

    • आपकी अनुवाद पाइपलाइन पूरी तरह से इस पर आधारित है। कई TMS उपकरण ICU स्ट्रिंग्स का आयात और निर्यात करते हैं, और अनुवादक इस सिंटैक्स में प्रशिक्षित होते हैं।
    • संदेश कई प्लेटफ़ॉर्मों पर साझा किए जाते हैं। एक ही कैटलॉग का उपयोग iOS ऐप, Android ऐप और वेब ऐप के लिए करना एक मानक प्रारूप बनाए रखने का एक ठोस कारण है।
    • आपके पास पहले से ही ICU संदेशों का एक विशाल संग्रह है। हज़ारों संदेशों को दोबारा लिखना अकेले शायद ही कभी व्यावहारिक होता है।

    अंतिम मामले में, आपको पूरे कोड को दोबारा लिखने या भारी पार्सर बनाए रखने के बीच चयन करने की आवश्यकता नहीं है। Intlayer का react-intl कम्पैटिबिलिटी एडेप्टर मौजूदा ICU स्ट्रिंग्स (plural, select, selectordinal, #, पारंपरिक number / date / time) को पढ़ सकता है, जिससे आप धीरे-धीरे माइग्रेट कर सकते हैं और ICU की लागत केवल वहीं तक सीमित रख सकते हैं जहाँ पुराने संदेशों को इसकी आवश्यकता है।

    निष्कर्ष

    ICU MessageFormat ने एक वास्तविक समस्या को हल किया: व्याकरण अनुवादकों का काम है, न कि एप्लिकेशन कोड में if (count === 1) जैसी शर्तों का। इसने उन परिवेशों के लिए इसे पूरी तरह हल किया जहाँ स्ट्रिंग आधारित DSL को पार्स करने में कोई अतिरिक्त लागत नहीं आती थी। लेकिन वेब ब्राउज़र में पूर्ण संगतता का अर्थ है ऐसे पार्सर कोड को भेजना जिसकी अधिकांश ऐप्स को कभी आवश्यकता नहीं होती, और अब ICU-आधारित लाइब्रेरी भी इससे बचने के लिए अपने संदेशों को पहले से संकलित कर रही हैं।

    जावास्क्रिप्ट में पहले से ही Intl के माध्यम से CLDR नियम मौजूद हैं। आधुनिक i18n प्रारूप से जो अपेक्षित है वह केवल ब्रांचिंग संरचना है, और उसे टाइप किए गए डेटा के रूप में बहुत सरलता और कुशलता से व्यक्त किया जा सकता है।

    आगे पढ़ें

    टिप्पणियाँ

    अभी तक कोई टिप्पणी नहीं। अपने विचार साझा करने वाले पहले व्यक्ति बनें।

    संबंधित पोस्ट

    नवीनतम पोस्ट