LC_MESSSAGES को प्रभावी होने के लिए macOS homebrew bash पर निर्यात करने की आवश्यकता क्यों है?


4

MacOS पर, होमब्रे से इंस्टॉल किए गए बैश के साथ, मैंने देखा कि सेटिंग LC_MESSAGESको वर्तमान शेल के लोकेल सेटिंग्स पर कुछ प्रभाव पड़ता है, लेकिन LC_MESSAGESनिर्यात होने तक संदेश वास्तव में नहीं बदलते हैं :

परेशान LANGऔर LC_MESSAGES, मुझे उम्मीद के मुताबिक एक अंग्रेजी त्रुटि संदेश मिला:

bash-4.4$ unset LANG LC_MESSAGES
bash-4.4$ if :;  fi
bash: syntax error near unexpected token `fi'

LC_MESSAGESगलत मान पर सेट करने से त्रुटि होती है setlocale:

bash-4.4$ LC_MESSAGES=foo
bash: warning: setlocale: LC_MESSAGES: cannot change locale (foo): No such file or directory

जब मैं सेट करता हूं तो कुछ बदल जाता है LC_MESSAGES। लेकिन इसे उचित मूल्य पर सेट करने से कोई प्रभाव नहीं पड़ता है:

bash-4.4$ LC_MESSAGES=ja_JP.UTF-8
bash-4.4$ if :;  fi
bash: syntax error near unexpected token `fi'

जब तक मैं इसे निर्यात नहीं करता:

bash-4.4$ export LC_MESSAGES
bash-4.4$ if :;  fi
bash: 予期しないトークン `fi' 周辺に構文エラーがあります

(यह सब के लिए भी जाता है LANG, ऐसा लगता है)

बैश वेरिएबल्स पर बाश मैनुअल का खंड निर्यात नहीं करता है LC_MESSAGESया LANGनिर्यात नहीं किया जाता है (और वहां सूचीबद्ध अधिकांश अन्य चर निर्यात नहीं किए जाते हैं)।

ऐसा क्यों है?



1
@ स्टीफनचेलजैस बैश के आंतरिक गेटटेक्स्ट लाइब्रेरी में कॉल करने के लिए स्विच होता है getenv()यदि setlocale()उपलब्ध नहीं है। यह है , हालांकि MacOS पर उपलब्ध ... लेकिन शायद Homebrew निर्माण स्क्रिप्ट यह उठा are't, या जो भी कारण के लिए यह अनदेखी कर रहे हैं।
Kusalananda

1
@ कुसलानंद, मैं FreeBSD पर एक सरल प्रोग्राम के साथ पुन: पेश कर सकता हूं जो setlocale("fr_FR.UTF-8", LC_ALL)इसके बाद कॉल करता है dgettext()। संदेशों को अनुवाद की गई भाषा में अनुवादित नहीं किया जाता है setlocale()(हालांकि trussपता चलता है कि संबंधित .moफ़ाइल LC_*पर्यावरण में कोई चर नहीं है) खुला है , लेकिन इसके बजाय LC_ * चर द्वारा संदर्भित भाषा में। स्रोत को देखने की आवश्यकता होगी कि क्यों, लेकिन यह बहुत बग की तरह दिखता है।
स्टीफन चेज़लस

1
मैंने केवल FreeBSD में परीक्षण किया है (अधिकांश macOS FreeBSD पर आधारित है, हालांकि मैं यह नहीं बता सकता कि क्या उस विशेष मामले पर लागू होता है)।
स्टीफन चेज़लस

1
@JohnDoea OpenBSD पर समान व्यवहार।
Kusalananda

जवाबों:


2

आप सही हैं कि LC_*शेल वेरिएबल्स को असाइन bashकरने से POSIX setlocale()को वैरिएबल के मान के साथ संबंधित श्रेणी के लिए कॉल किया जा सकता है , चाहे वे निर्यात किए गए हों या नहीं। के लिए LANG, यह कॉल setlocale(LC_ALL, thevalue)का पालन setlocale(LC_*)सभी के लिए फिर से LC_*चर। के लिए LANGUAGE, यह कुछ भी नहीं करता है।

अब, bashजीएनयू परियोजना का खोल है। पाठ के स्थानीयकरण के लिए, यह GNU का उपयोग करता है gettext, जिसे रूप में भी जाना जाता है libintl। यहां तक ​​कि यह अपने स्वयं के संस्करण के साथ आता है जो स्रोत के साथ बंडल होता है जिसे आप स्क्रिप्ट के साथ bashकॉल करने पर संकलित कर सकते हैं ।configure--with-included-gettext

gettextप्रति भाषा डेटाबेस में संदेश अनुवाद दिखता है। यह किस भाषा की LC_MESSAGESश्रेणी के मूल्य से निर्धारित होता है, हालांकि $LANGUAGEपर्यावरण चर द्वारा इसे ओवरराइड किया जा सकता है ।

गेटटेक्स्ट डॉक्यूमेंटेशन के अनुसार, पिछला कॉल वह setlocale()होना चाहिए जो श्रेणी के लिए मूल्य निर्धारित करता है, लेकिन कुछ जटिलताएं हैं:

Multithreaded अनुप्रयोगों के लिए, वर्तमान में कोई मानक API नहीं है जो गेटटेक्स्ट उस मान को पुनः प्राप्त करने के लिए उपयोग कर सकता हैbashएक बहुपरत आवेदन नहीं है, लेकिन यहां तक ​​कि क्या setlocale(category, NULL)रिटर्न कार्यान्वयन को परिभाषित किया गया है और व्यवहार में हमेशा उपयोग करने योग्य नहीं है

तो व्यवहार में, gettext केवल का उपयोग करता है setlocale()जब जीएनयू libc का हिस्सा है या एक प्रणाली है जहाँ libc जीएनयू libc (के साथ बनाया गया एक की तरह है पर बनाया गया भाषा नाम को पुनः प्राप्त करने bashके साथ --with-included-gettextएक जीएनयू सिस्टम पर), क्योंकि यह जानता है कि यह पर भरोसा कर सकते यह।

अन्य प्रणालियों पर, यह getenv()स्थानीय को निर्धारित करने के लिए उपयोग करता है, भले ही setlocale()पहले कैसे लागू किया गया था, यही कारण है कि आप उस व्यवहार को देख रहे हैं।

उन चरों को निर्यात करना एक आसान काम है। कोई यह तर्क दे सकता है कि यदि वे निर्यात नहीं किए जाते हैं, तो वे वैसे भी पर्यावरण का हिस्सा नहीं हैं। उस पर POSIX बहुत स्पष्ट नहीं है। इसे देखने का एक और तरीका यह है कि अनुवाद bashकिसी तीसरे पक्ष के तंत्र द्वारा नहीं किया जाता है , इसलिए जैसे अन्य आदेशों को निष्पादित करते समय , हमें दो सॉफ्टवेयर (यहां bashऔर gettext) के बीच स्थानीय जानकारी को पारित करने के लिए पर्यावरण चर का उपयोग करने की आवश्यकता होती है ।

अब, GNU सिस्टम पर, यह वास्तव में खराब हो जाता है।

जैसा कि ऊपर देखा गया है, गेटटेक्स्ट को जीएनयू परिवाद में शामिल किया गया है। $LANGUAGEपूर्वता लेता है, $LC_MESSAGEलेकिन $LANGUAGEPOSIX लोकेल एपीआई का हिस्सा नहीं है, यह उसके ऊपर एक विस्तार है।

एक GNU सिस्टम पर रहते हुए, gettext setlocale(LC_MESSAGES, NULL)LC_MESSAGES श्रेणी के लिए नाम प्राप्त करने के लिए उपयोग करेगा LANGUAGE, इसके लिए , यह हमेशा उपयोग होता है getenv(), LANGUAGEएक स्थानीय श्रेणी नहीं है।

समस्या यह है कि bashअपने चर हैंडलिंग के हिस्से के रूप में पर्यावरण को प्रबंधित करता है, जो कि libc के environ[]एरे से डिस्कनेक्ट किया गया है । इसका getenv()अपना स्वयं का संस्करण है जो पर्यावरण के अपने स्वयं के संस्करण को क्वेरी करता है, लेकिन जब gettextयह libc के भाग के रूप में बनाया गया है, और bashयह libc से गतिशील रूप से जुड़ा हुआ dgettext()कॉल है, getenv()क्योंकि यह libc के भीतर एक आंतरिक कॉल है bash, ऐसा नहीं है , इसलिए होगा केवल $LANGUAGEउस समय से मूल्य प्राप्त bashकरना शुरू किया गया था।

जीएनयू सिस्टम पर, जब तक कि bashइसे वैधानिक रूप से नहीं जोड़ा गया या इसके साथ नहीं बनाया गया , तब तक उत्पन्न होने वाले संदेशों के लिए --with-included-gettextकिसी भी परिवर्तन को $LANGUAGEअनदेखा किया जाएगा bash, चाहे वह चर निर्यात किया गया हो या नहीं। अन्य सिस्टम पर, वह ठीक (जब तक है $LANGUAGEनिर्यात किया जाता है) gettext libc का हिस्सा नहीं है के रूप में, तो यह कॉल करता bashहै getenv()

डेबियन पर:

$ LANGUAGE=fr bash -c 'LANGUAGE=es; eval fi'
bash: eval: ligne 0: erreur de syntaxe près du symbole inattendu « fi »
bash: eval: ligne 0: `fi'

(फ्रेंच में संदेश, $LANGUAGEउस समय bashका मूल्य लागू किया गया था, न कि स्पेनिश)।

वास्तव में यह अन्य गोले के साथ ज्यादा बेहतर नहीं है।

zshअन्य भाषाओं में अनुवादित नहीं है, लेकिन वह उपयोग करता है strerror()जो gettextGNU सिस्टम पर आंतरिक रूप से उपयोग करता है:

$ LANGUAGE=fr zsh -c 'LANGUAGE=es; true</x; LANGUAGE=en; true</a; true < /etc/shadow'
zsh:1: no existe el archivo o el directorio: /x
zsh:1: no existe el archivo o el directorio: /a
zsh:1: permission denied: /etc/shadow

LANGUAGE=esसम्मानित लेकिन देखते हैं कि कैसे ENOENT के लिए दूसरा संदेश अंग्रेजी में दिखाया गया है नहीं किया गया है (शायद किसी भी तरह gettext द्वारा कैश, जब कि कैश अमान्य हो जाना चाहिए था गया था $LANGUAGEबदल लेकिन स्थिति कुछ भिन्न है)।


वाह, यह एक मुश्किल पहेली है जिसे आपने सुलझाया है!

0

शेल चर और पर्यावरण चर के बीच अंतर के स्पष्टीकरण के लिए इस उत्तर पर एक नज़र डालें । संक्षेप में:

शेल चर सेट करना:

LANG=en_US.UTF-8

एक पर्यावरण चर सेट करना:

export LANG=en_US.UTF-8

आप स्थानीय चर के लिए पर्यावरण चर सेट करना चाहते हैं, क्योंकि शेल चर शेल के लिए निजी हैं और इसे बाल प्रक्रियाओं में पारित नहीं किया जाएगा।


1
यहाँ अलग बात है। exportकेवल निष्पादित किए जा रहे आदेशों के व्यवहार को प्रभावित करने के लिए आवश्यक है। यहाँ, हम आंतरिक रूप से शेल द्वारा उत्पन्न संदेशों की बात कर रहे हैं।
स्टीफन चेजलस

हालांकि यहां कोई बाल प्रक्रिया नहीं है। इसलिए मैंने विशेष रूप से इस if :; fiकमांड का उपयोग किया , जो शेल से ही एक सिंटैक्स त्रुटि उत्पन्न करता है।

यह असाइनमेंट है जो समस्या पैदा करता है। एक चर का असाइनमेंट एक कमांड है जो बंद हो जाता है। सेटलोकेले चाइल्ड प्रक्रिया शेल चर असाइनमेंट को नहीं देखती है और यह बताती है कि यह काम नहीं किया। बैश ने बताया कि असाइनमेंट काम नहीं करता है, और आपको बताया कि आपका प्रयास असाइनमेंट क्या था।
रिचर्ड बार्बर

इसका कोई अर्थ नही बन रहा है। सरल चर असाइनमेंट किसी भी शेल में एक नई प्रक्रिया को कांटा नहीं करता है जो मुझे पता है। और setlocaleबैश को यह बताने के लिए कि यह काम नहीं करता है, यहां दो असाइनमेंट हैं, और setlocaleउनमें से केवल एक के बारे में शिकायत की गई है। अपने तर्क से, यह दोनों के बारे में शिकायत करनी चाहिए थी।

यह "सरल" चर असाइनमेंट नहीं है, हालांकि, यह है? आप उसे पृष्ठभूमि में चला रहे हैं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.