दिलचस्प पोस्ट
ऑरेकल में चुनिंदा क्वेरी के लिए डिफ़ॉल्ट पंक्ति क्रम क्या एक धागा को अनिश्चित रूप से रोकना है? एसक्यूएल – एक तालिका से रिकॉर्ड खोजें जो दूसरे में मौजूद नहीं है सभी ब्राउज़रों के लिए मैं डिफ़ॉल्ट समयबाह्य सेटिंग्स कहां प्राप्त करूं? यूनिकोडएएनकोड त्रुटि: 'charmap' कोडेक अक्षरों को एन्कोड नहीं कर सकता जावा बहुलाइन स्ट्रिंग एंड्रॉइड 4.2 ने मेरे एन्क्रिप्ट / डिक्रिप्ट कोड को तोड़ दिया और प्रदान किए गए समाधान काम नहीं करते सिंटेक्स त्रुटि: सख्त मोड में const का उपयोग करें पांडा के साथ डाटाफ्रेम के माध्यम से लूप का सबसे कारगर तरीका क्या है? एंड्रॉइड: एक बटन या छवि बटन पर पाठ और छवि का संयोजन कैसे पीएचपी में सरल एक को एक "बहु-आयामी सरणी" को "समतल" करना है? ndk {} DSL में LOCAL_SRC_FILES को परिभाषित करें गैर-स्थिर विधि के लिए एक स्थिर संदर्भ नहीं बना सकते जावा में एक विभाजक (विभाजन के विपरीत) के साथ सरणी तत्वों में शामिल होने का एक त्वरित और आसान तरीका कैसे कोड हटना – डेक में 65k विधि सीमा

सर्वश्रेष्ठ अभ्यास बहु भाषा वेबसाइट

मैं इस प्रश्न के साथ काफी कुछ महीनों के लिए संघर्ष कर रहा हूं, लेकिन मैं एक ऐसे हालात में नहीं हूं, जिसे मुझे पहले सभी संभावित विकल्पों का पता लगाने की जरूरत थी। अभी, मुझे लगता है कि यह संभावनाएं जानने के लिए समय है और मेरी आगामी परियोजनाओं में उपयोग करने के लिए मेरी अपनी व्यक्तिगत वरीयता बनाना है।

मुझे पहले उस स्थिति का स्केच करें जो मैं देख रहा हूं

मैं एक ऐसी सामग्री प्रबंधन प्रणाली को अपग्रेड / पुन: विकसित करने के बारे में हूं जो मैं कुछ समय के लिए उपयोग कर रहा हूं हालांकि, मुझे लगता है कि बहु भाषा इस प्रणाली में एक महान सुधार है। इससे पहले कि मैं किसी भी चौखटे का उपयोग नहीं किया लेकिन मैं आगामी परियोजना के लिए Laraval4 का उपयोग करने जा रहा हूँ। Laravel कोड को PHP के क्लीनर का सबसे अच्छा विकल्प लगता है Sidenote: Laraval4 should be no factor in your answer । मैं सामान्य रूप से अनुवाद के तरीकों की तलाश कर रहा हूं जो मंच / फ्रेमवर्क स्वतंत्र हैं

क्या अनुवाद किया जाना चाहिए

चूंकि मैं जिस सिस्टम को तलाश रहा हूं वह उतना उपयोगकर्ता के अनुकूल होने की जरूरत है जितनी संभव हो कि अनुवाद को प्रबंधित करने की विधि सीएमएस के अंदर होनी चाहिए। अनुवाद फ़ाइलों या किसी भी HTML / php पार्स किए गए टेम्पलेट को संशोधित करने के लिए कोई एफ़टीपी कनेक्शन शुरू करने की कोई आवश्यकता नहीं होनी चाहिए।

इसके अलावा, मैं अतिरिक्त टेबल बनाने की आवश्यकता के बिना कई डेटाबेस तालिकाओं का अनुवाद करने का सबसे आसान तरीका तलाश रहा हूं

मैं खुद के साथ क्या आया था

जैसा कि मैंने खोज की है, पढ़ने और चीजों को स्वयं से पहले ही कोशिश कर रहा हूं मेरे पास कुछ विकल्प हैं I लेकिन मुझे अभी भी ऐसा नहीं लगता है कि मैं वास्तव में क्या खोज रहा हूं, इसके लिए मैं एक सर्वोत्तम अभ्यास पद्धति पर पहुंच गया हूं। अभी, यह है कि मैं इसके साथ आया हूं, लेकिन इस पद्धति में इसके दुष्प्रभाव भी हैं।

  1. PHP पार्स टेम्पलेट : टेम्पलेट सिस्टम को PHP द्वारा पार्स किया जाना चाहिए इस तरह मैं टेम्पलेट खोलने और उन्हें संशोधित किए बिना अनुवादित पैरामीटर को HTML में सम्मिलित करने में सक्षम हूं। इसके अलावा, PHP पार्स किए गए टेम्पलेट मुझे प्रत्येक भाषा (जो मैंने पहले किया था) के लिए सबफ़ोल्डर होने के बजाय पूरी वेबसाइट के लिए 1 टेम्पलेट की क्षमता देता है। इस लक्ष्य तक पहुंचने की विधि या तो स्मार्टली, टेम्पलेटपावर, लारेजल ब्लेड या कोई अन्य टेम्पलेट पार्सर हो सकती है। जैसा कि मैंने कहा कि यह लिखित समाधान से स्वतंत्र होना चाहिए।
  2. डेटाबेस संचालित : शायद मुझे इसे दोबारा उल्लेख करने की आवश्यकता नहीं है। लेकिन समाधान डेटाबेस संचालित होना चाहिए। सीएमएस का उद्देश्य उद्देश्य उन्मुख और एमवीसी होना है, इसलिए मुझे स्ट्रिंग के लिए एक तार्किक डेटा संरचना के बारे में सोचने की आवश्यकता होगी। चूंकि मेरे टेम्प्लेट संरचित होंगे: टेम्पलेट / नियंत्रक / व्यू.एफ़पीपी शायद यह संरचना सबसे ज्यादा समझदारी होगी: Controller.View.parameter । दृश्य। पैरामीटर डेटाबेस तालिका में इन फ़ील्ड्स को value फ़ील्ड के साथ लंबा होगा। टेम्पलेट्स के अंदर हम कुछ प्रकार की विधि का उपयोग कर सकते हैं जैसे echo __('Controller.View.welcome', array('name', 'Joshua'))Welcome, :name echo __('Controller.View.welcome', array('name', 'Joshua')) और पैरामीटर में Welcome, :name इस प्रकार परिणाम का Welcome, Joshua जा रहा है Welcome, Joshua । यह ऐसा करने का एक अच्छा तरीका है, क्योंकि पैरामीटर जैसे: नाम संपादक द्वारा समझना आसान है।
  3. निम्न डेटाबेस लोड : बेशक उपरोक्त सिस्टम डाटा लोड होने का कारण होगा यदि इन तारों को जाने पर लोड किया जा रहा है इसलिए मुझे एक कैशिंग सिस्टम की आवश्यकता होगी जो भाषा फ़ाइलों को फिर से प्रस्तुत करती है जैसे ही वे प्रशासन परिवेश में संपादित / सहेजे जाते हैं। क्योंकि फ़ाइलें उत्पन्न होती हैं, एक अच्छी फ़ाइल सिस्टम लेआउट भी आवश्यक है। मुझे लगता है कि हम languages/en_EN/Controller/View.php या languages/en_EN/Controller/View.php साथ जा सकते हैं, जो आपकी सबसे अच्छी बात है संभवतः अंत में एक। आई भी जल्दी पर्सेड है इस ढांचे में format parameter=value; में डेटा होना चाहिए format parameter=value; । मुझे लगता है कि यह करने का सबसे अच्छा तरीका है, क्योंकि प्रत्येक दृश्य जो प्रस्तुत किया गया है, वह स्वयं की भाषा फाइल शामिल कर सकता है यदि यह मौजूद है तब भाषा के पैरामीटर को एक विशिष्ट दृश्य में लोड किया जाना चाहिए और एक दूसरे को ओवरराइट करने से पैरामीटर को रोकने के लिए वैश्विक परिदृश्य में नहीं होना चाहिए।
  4. डाटाबेस तालिका अनुवाद : यह वास्तव में यह बात है कि मैं सबसे ज्यादा चिंतित हूं। मैं समाचार / पृष्ठ / आदि के अनुवाद बनाने का एक तरीका तलाश रहा हूं। जितना जल्दी हो सके। प्रत्येक मॉड्यूल (उदाहरण के लिए News और News_translations ) के लिए दो तालिकाओं का एक विकल्प होता है लेकिन ऐसा लगता है कि अच्छा सिस्टम प्राप्त करने के लिए बहुत काम करना है। मैं जिन चीजों के साथ आया हूं उनमें से एक data versioning प्रणाली पर आधारित है मैंने लिखा है: एक डेटाबेस तालिका नाम Translations , इस तालिका में language का एक अनूठा संयोजन है, primarykey और primarykey । उदाहरण के लिए: en_En / News / 1 (आईडी = 1 के साथ समाचार आइटम के अंग्रेजी संस्करण का जिक्र करना) लेकिन इस पद्धति में 2 बड़े नुकसान हैं: इस तालिका में से पहले डेटाबेस में बहुत सारे डेटा के साथ बहुत लंबा हो जाता है और दूसरी बात यह है कि मेज पर खोज करने के लिए इस सेटअप का उपयोग करना नौकरी का एक नरक होगा। उदाहरण के लिए आइटम की एसईओ स्लग के लिए खोज एक पूर्ण पाठ खोज होगी, जो बहुत गूंगा है। लेकिन दूसरी तरफ: यह हर तालिका में अनुवाद करने योग्य सामग्री को बहुत तेज़ बनाने का एक त्वरित तरीका है, लेकिन मुझे विश्वास नहीं है कि इस समर्थक ओवरवेट्स को कॉन है।
  5. फ्रंट-एंड कार्य : इसके अलावा फ्रंट एंड को कुछ सोचने की आवश्यकता होगी बेशक हम एक डेटाबेस में उपलब्ध भाषाओं को स्टोर कर देंगे और (डी) हम लोगों को सक्रिय कर सकेंगे। इस प्रकार स्क्रिप्ट एक भाषा का चयन करने के लिए एक ड्रॉपडाउन उत्पन्न कर सकता है और बैक-एंड स्वचालित रूप से यह तय कर सकता है कि सीएमएस का उपयोग करके कौन से अनुवाद किए जा सकते हैं। चुनी गई भाषा (जैसे एन_एन) तब तब इस्तेमाल की जाएगी जब किसी दृश्य के लिए भाषा फाइल प्राप्त हो रही हो या वेबसाइट पर सामग्री आइटम के लिए सही अनुवाद प्राप्त करने के लिए।

तो, वहां वे हैं मेरे विचार अब तक वे यहां तक ​​कि तिथियों के लिए स्थानीयकरण विकल्प भी शामिल नहीं करते हैं, लेकिन जैसा कि मेरा सर्वर PHP5.3.2 + का समर्थन करता है + सबसे अच्छा विकल्प यह है कि यहां विस्तार से बताया गया है: http://devzone.zend.com/1500/internationalization-in -php-53 / – लेकिन यह विकास के किसी भी बाद के स्टेडियम में उपयोग की जाएगी। अब के लिए मुख्य मुद्दा यह है कि किसी वेबसाइट में सामग्री के अनुवाद के सर्वोत्तम अभ्यास कैसे करें।

मैं यहाँ समझाया सब कुछ के अलावा, मेरे पास अब एक और चीज है जो मैंने अभी तक तय नहीं की है, यह एक साधारण सवाल है, लेकिन वास्तव में यह मुझे सिरदर्द दे रहा है:

यूआरएल अनुवाद? हमें यह करना चाहिए या नहीं? और किस तरह से?

इसलिए .. अगर मेरे पास यह यूआरएल है: http://www.domain.com/about-us और अंग्रेजी मेरी डिफ़ॉल्ट भाषा है क्या यह यूआरएल http://www.domain.com/over-ons में अनुवाद किया जाना चाहिए जब मैं अपनी भाषा के रूप में डच का चयन करता हूं? या हमें आसान रास्ते पर जाना चाहिए और बस /about दृश्यमान पृष्ठ की सामग्री को बदलना चाहिए। आखिरी बात एक वैध विकल्प नहीं लगता है क्योंकि वह उसी यूआरएल के कई संस्करणों को उत्पन्न करेगा, यह अनुक्रमित सामग्री सही तरीके से असफल हो जाएगी।

एक और विकल्प http://www.domain.com/nl/about-us का उपयोग कर रहा है यह प्रत्येक सामग्री के लिए कम से कम एक अद्वितीय यूआरएल उत्पन्न करता है। इसके अलावा यह अन्य भाषा में जाना आसान होगा, उदाहरण के लिए http://www.domain.com/en/about-us और यूआरएल प्रदान किया गया है Google और मानव दोनों आगंतुकों के लिए समझना आसान है। इस विकल्प का उपयोग करना, हम डिफ़ॉल्ट भाषाओं के साथ क्या करते हैं? क्या डिफ़ॉल्ट भाषा डिफ़ॉल्ट रूप से चयनित भाषा को हटाना चाहिए? इसलिए http://www.domain.com/en/about-us को http://www.domain.com/about-us पुनर्निर्देशित करना … मेरी आँखों में यह सबसे अच्छा समाधान है, क्योंकि जब सीएमएस के लिए सेटअप होता है केवल एक ही भाषा में URL में इस भाषा की पहचान करने की कोई आवश्यकता नहीं है।

और एक तिहाई विकल्प दोनों विकल्पों से एक संयोजन है: मुख्य भाषा के लिए "भाषा-पहचान-कम" -URL ( http://www.domain.com/about-us ) का उपयोग करना और sublanguages ​​के लिए एक अनुवादित एसईओ स्लग के साथ यूआरएल का प्रयोग करें: http://www.domain.com/nl/over-ons और http://www.domain.com/de/uber-uns

मुझे उम्मीद है कि मेरा सवाल आपके सिर टूटना हो जाता है, उन्होंने मुझे यकीन दिलाया! यह पहले से ही एक प्रश्न के रूप में काम करने के लिए मुझे पहले ही मदद करता है मुझे मेरे द्वारा उपयोग किए जाने वाले विधियों की समीक्षा करने की संभावना है और यह विचार मेरे आने वाले सीएमएस के लिए है I

पाठ के इस गुच्छा को पढ़ने के लिए समय निकालने के लिए मैं आपको पहले से धन्यवाद देना चाहता हूं!

// Edit #1 :

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

वेब के समाधान से एकत्रित समाधान "सर्वश्रेष्ठ अभ्यास बहु भाषा वेबसाइट"

विषय का आधार

एक बहुभाषी साइट में तीन विशिष्ट पहलू हैं:

  • इंटरफ़ेस अनुवाद
  • सामग्री
  • यूआरएल रूटिंग

जबकि वे सभी अलग-अलग तरीकों से जुड़े रहते हैं, सीएमएस बिंदु दृश्य से वे अलग-अलग UI तत्वों का उपयोग कर प्रबंधित करते हैं और अलग तरह से संग्रहीत होते हैं। आप अपने कार्यान्वयन और पहले दो को समझने में भरोसा रखते हैं। प्रश्न बाद के पहलू के बारे में था – "यूआरएल अनुवाद, क्या हमें ऐसा करना चाहिए या नहीं? और किस तरह?"

यूआरएल का क्या बनाया जा सकता है?

एक बहुत ही महत्वपूर्ण बात यह है, आईडीएन के साथ फैंसी न करें इसके बजाय लिप्यंतरण (भी: प्रतिलेखन और रोमनकरण) पर ध्यान दें। जबकि पहली नज़र में आईएनडीएन अंतरराष्ट्रीय यूआरएल के लिए व्यवहार्य विकल्प है, यह वास्तव में दो कारणों से विज्ञापित नहीं है:

  • कुछ ब्राउज़रों में गैर-एएससीआईआई अक्षर बदल जाएंगे जैसे कि 'ч' या 'ž' में '%D1%87' और '%C5%BE'
  • अगर उपयोगकर्ता कस्टम थीम हैं, तो थीम का फ़ॉन्ट उन अक्षरों के प्रतीक नहीं होने की संभावना है

मैं वास्तव में एक Yii आधारित परियोजना (भयानक ढांचा, आईएमएचओ) में कुछ साल पहले आईडीएन दृष्टिकोण की कोशिश की थी उस समाधान को स्क्रैप करने से पहले मैंने उपर्युक्त सभी समस्याओं का सामना किया। इसके अलावा, मुझे संदेह है कि यह एक हमला वेक्टर हो सकता है

उपलब्ध विकल्पों … जैसा कि मैं उन्हें देख रहा हूँ

असल में आपके पास दो विकल्प हैं, जिन्हें इस रूप में समझा जा सकता है:

  • http://site.tld/[:query] : जहां [:query] दोनों भाषा और सामग्री विकल्प निर्धारित करती है

  • http://site.tld/[:language]/[:query] : जहां [:language] यूआरएल का हिस्सा [:language] की पसंद को परिभाषित करता है और [:query] का उपयोग केवल सामग्री की पहचान करने के लिए किया जाता है

प्रश्न Α और Ω है ..

कहें कि आप http://site.tld/[:query]

उस मामले में आपके पास भाषा का एक प्राथमिक स्रोत है: [:query] सेगमेंट की सामग्री; और दो अतिरिक्त स्रोत:

  • उस विशेष ब्राउज़र के लिए मूल्य $_COOKIE['lang']
  • HTTP स्वीकृत-भाषा (1) , (2) शीर्ष लेख में भाषाओं की सूची

सबसे पहले, आपको परिभाषित राइटिंग पैटर्न में से किसी एक को क्वेरी से मिलान करना होगा (यदि आपकी पसंद लारवेल है, तो यहां पढ़ें )। पैटर्न के सफल मिलान पर आपको भाषा खोजना होगा।

आपको पैटर्न के सभी हिस्सों के माध्यम से जाना होगा उन सभी खंडों के लिए संभावित अनुवाद खोजें और पता करें कि किस भाषा का उपयोग किया गया था। दो अतिरिक्त स्रोत (कुकी और हेडर) का उपयोग रूटिंग टकराव को हल करने के लिए किया जाएगा, जब वे उत्पन्न होते हैं ("नहीं")।

उदाहरण के लिए लें: http://site.tld/blog/novinka

यही "блог, новинка" लिप्यंतरण "блог, новинка" का अनुवाद है "блог, новинка" अंग्रेज़ी अर्थ लगभग "blog", "latest"

जैसा कि आप पहले ही नोट कर सकते हैं, रूसी "ब्लॉग" में "ब्लॉग" के रूप में लिप्यंतरण किया जाएगा। इसका अर्थ है कि [:query] के पहले भाग के लिए आप ( सर्वोत्तम मामले परिदृश्य में ) संभव भाषाओं की ['en', 'ru'] सूची के साथ समाप्त हो जाएंगे। फिर आप अगले सेगमेंट – "नवचिका" ले सकते हैं। इसकी संभावनाओं की सूची में केवल एक ही भाषा हो सकती है: ['ru']

जब सूची में एक आइटम होता है, तो आपने सफलतापूर्वक भाषा पाई है

लेकिन अगर आप 2 (उदाहरण: रूसी और यूक्रेनी) या अधिक संभावनाओं के साथ समाप्त होते हैं .. या 0 संभावनाएं, जैसा कोई मामला हो सकता है। आपको सही विकल्प खोजने के लिए कुकी और / या हेडर उपयोग करना होगा।

और अगर सब कुछ विफल हो जाता है, तो आप साइट की डिफ़ॉल्ट भाषा चुनते हैं।

पैरामीटर के रूप में भाषा

वैकल्पिक यूआरएल का उपयोग करना है, जिसे http://site.tld/[:language]/[:query] रूप में परिभाषित किया जा सकता है। इस मामले में, क्वेरी का अनुवाद करते समय, आपको भाषा का अनुमान लगाने की आवश्यकता नहीं है, क्योंकि उस बिंदु पर आप पहले से जानते हैं कि किसका उपयोग करना है।

भाषा का एक द्वितीयक स्त्रोत भी है: कुकी मूल्य। लेकिन यहाँ स्वीकार-भाषा हैडर के साथ गड़बड़ करने का कोई मतलब नहीं है, क्योंकि आप "ठंड शुरू" के मामले में संभावित भाषाओं की अज्ञात राशि से निपटने नहीं कर रहे हैं (जब उपयोगकर्ता पहली बार कस्टम क्वेरी के साथ साइट खोलता है)।

इसके बजाय आपके पास 3 सरल, प्राथमिकता वाले विकल्प हैं:

  1. यदि [:language] सेगमेंट सेट है, तो इसका इस्तेमाल करें
  2. यदि $_COOKIE['lang'] सेट है, तो इसका उपयोग करें
  3. डिफ़ॉल्ट भाषा का उपयोग करें

जब आपके पास भाषा होती है, तो आप बस क्वेरी का अनुवाद करने का प्रयास करते हैं, और यदि अनुवाद विफल रहता है, तो उस विशेष सेगमेंट के लिए "डिफ़ॉल्ट मान" का उपयोग करें (रूटिंग परिणामों पर आधारित)।

यहां एक तीसरा विकल्प नहीं है?

हां, तकनीकी रूप से आप दोनों तरीकों से गठजोड़ कर सकते हैं, लेकिन यह प्रक्रिया को जटिल बना देगा और केवल उन लोगों को समायोजित कर सकता है जो मैन्युअल रूप से http://site.tld/en/news का यूआरएल http://site.tld/en/news पर बदलना चाहते हैं। न्यूज़ पेज को जर्मन में बदलने की उम्मीद है

लेकिन यहां तक ​​कि इस केस को कुकी मूल्य (जो कि भाषा की पिछली पसंद के बारे में जानकारी होती है) का उपयोग करने के लिए कम हो सकता है, कम जादू और आशा के साथ कार्यान्वित करने के लिए।

उपयोग करने के लिए कौन सी दृष्टिकोण?

जैसा कि आप पहले से ही अनुमान लगा सकते हैं, मैं http://site.tld/[:language]/[:query] को अधिक समझदार विकल्प के रूप में http://site.tld/[:language]/[:query]

साथ ही वास्तविक शब्द की स्थिति में आपके पास यूआरएल में तीसरा प्रमुख भाग होगा: "शीर्षक" ऑनलाइन शॉप में उत्पाद के नाम या समाचार साइट में लेख की शीर्षक के अनुसार।

उदाहरण: http://site.tld/en/news/article/121415/EU-as-global-reserve-currency

इस मामले में '/news/article/121415' क्वेरी होगी, और 'EU-as-global-reserve-currency' शीर्षक है। शुद्ध रूप से एसईओ प्रयोजनों के लिए

क्या यह लैरवेल में किया जा सकता है?

थोड़े, लेकिन डिफ़ॉल्ट रूप से नहीं

मैं इसके बारे में भी परिचित नहीं हूँ, लेकिन मैंने जो कुछ देखा है, से लैरवेल सरल पैटर्न-आधारित रूटिंग तंत्र का उपयोग करता है। बहुभाषी यूआरएल को लागू करने के लिए आपको संभवतः कोर क्लास (एसई) का विस्तार करना होगा, क्योंकि बहुभाषी रूटिंग को विभिन्न प्रकार के भंडारण (डेटाबेस, कैश और / या कॉन्फ़िगरेशन फाइलों) तक पहुंच की आवश्यकता है।

यह मार्गबद्ध है अब क्या?

सभी के परिणामस्वरूप आप दो महत्वपूर्ण जानकारी के साथ समाप्त होंगे: वर्तमान भाषा और क्वेरी के अनुवादित खंड ये मूल्य तब क्लास (एसए) को प्रेषित करने के लिए इस्तेमाल किया जा सकता है जो नतीजे उत्पन्न करेगा।

असल में, निम्न यूआरएल: http://site.tld/ru/blog/novinka (या '/ru' बिना संस्करण) कुछ की तरह बदल जाता है

 $parameters = [ 'language' => 'ru', 'classname' => 'blog', 'method' => 'latest', ]; 

जो आप अभी प्रेषण के लिए उपयोग करते हैं:

 $instance = new {$parameter['classname']}; $instance->{'get'.$parameters['method']}( $parameters ); 

.. या इसके कुछ बदलाव, विशेष कार्यान्वयन के आधार पर।

थॉमस ब्ली ने सुझाव दिया है कि प्री-प्रोसेसर का इस्तेमाल करते हुए प्रदर्शन के बिना i18n को कार्यान्वित करना

काम पर, हमने हाल ही में हमारे कुछ सम्पत्तियों में आई 18 एन के कार्यान्वयन के माध्यम से कार्य किया, और हम जिन चीज़ों के साथ संघर्ष कर रहे थे उनमें से एक पर-फ्लाई अनुवाद से निपटने का प्रदर्शन हिट था, फिर मैं थॉमस ब्लेले द्वारा इस महान ब्लॉग पोस्ट की खोज की जो जिस तरह से हम कम प्रदर्शन समस्याओं के साथ बड़े यातायात भार को नियंत्रित करने के लिए I18n का उपयोग कर रहे हैं प्रेरित।

हर अनुवाद ऑपरेशन के लिए फ़ंक्शन बुलाए जाने के बजाय, जो कि हम PHP में जानते हैं वह महंगा है, हम अपनी बेस फाइलों को प्लेसहोल्डर्स के साथ परिभाषित करते हैं, फिर उन फाइलों को कैश करने के लिए पूर्व-प्रोसेसर का उपयोग करें (हम फ़ाइल संशोधन समय को संचित करते हैं ताकि हम सेवा दे रहे हैं हर समय नवीनतम सामग्री)

अनुवाद टैग

थॉमस {tr} और {/tr} टैग का प्रयोग परिभाषित करने के लिए करता है जहां अनुवाद प्रारंभ और अंत होता है तथ्य यह है कि हम TWIG का उपयोग कर रहे हैं, हम भ्रम से बचने के लिए { का उपयोग नहीं करना चाहते हैं, इसलिए हम इसके बजाय [%tr%] और [%/tr%] उपयोग करते हैं। असल में, यह इस तरह दिखता है:

 `return [%tr%]formatted_value[%/tr%];` 

ध्यान दें कि थॉमस फाइल में मूल अंग्रेजी का उपयोग करने का सुझाव देता है। हम ऐसा नहीं करते क्योंकि हम सभी अनुवाद फ़ाइलों को संशोधित नहीं करना चाहते हैं, अगर हम अंग्रेजी में मान बदलते हैं।

INI फ़ाइलें

फिर, हम प्रत्येक भाषा के लिए INI फ़ाइल बनाते हैं, प्रारूप में placeholder = translated :

 // lang/fr.ini formatted_value = number_format($value * Model_Exchange::getEurRate(), 2, ',', ' ') . '€' // lang/en_gb.ini formatted_value = '£' . number_format($value * Model_Exchange::getStgRate()) // lang/en_us.ini formatted_value = '$' . number_format($value) 

यह एक उपयोगकर्ता को सीएमएस के अंदर संशोधित करने की अनुमति देने के लिए क्षुद्र होगा, बस एक preg_split द्वारा \n या = पर कीपैर प्राप्त करें और सीआईएमएस को आईएनआई फाइलों में लिखने में सक्षम बनाते हैं।

प्री-प्रोसेसर घटक

अनिवार्य रूप से, थॉमस ने अपनी अनुवाद फ़ाइलों को ले जाने और डिस्क पर स्थैतिक PHP फाइल बनाने के लिए एक ऐसा समय-समय 'संकलक' (हालांकि, सच्चाई में, यह एक प्रीप्रोसेसर है) का उपयोग करने का सुझाव दिया है। इस तरह, हम मूल रूप से फ़ाइल में प्रत्येक स्ट्रिंग के लिए अनुवाद फ़ंक्शन कॉल करने के बजाय हमारी अनुवादित फ़ाइलों को कैश करते हैं:

 // This function was written by Thomas Bley, not by me function translate($file) { $cache_file = 'cache/'.LANG.'_'.basename($file).'_'.filemtime($file).'.php'; // (re)build translation? if (!file_exists($cache_file)) { $lang_file = 'lang/'.LANG.'.ini'; $lang_file_php = 'cache/'.LANG.'_'.filemtime($lang_file).'.php'; // convert .ini file into .php file if (!file_exists($lang_file_php)) { file_put_contents($lang_file_php, '<?php $strings='. var_export(parse_ini_file($lang_file), true).';', LOCK_EX); } // translate .php into localized .php file $tr = function($match) use (&$lang_file_php) { static $strings = null; if ($strings===null) require($lang_file_php); return isset($strings[ $match[1] ]) ? $strings[ $match[1] ] : $match[1]; }; // replace all {t}abc{/t} by tr() file_put_contents($cache_file, preg_replace_callback( '/\[%tr%\](.*?)\[%\/tr%\]/', $tr, file_get_contents($file)), LOCK_EX); } return $cache_file; } 

नोट: मैंने यह सत्यापित नहीं किया कि regex काम करता है, मैंने इसे हमारी कंपनी सर्वर से कॉपी नहीं किया था, लेकिन आप देख सकते हैं कि ऑपरेशन कैसे काम करता है।

इसे कैसे कॉल करें

फिर, यह उदाहरण थॉमस ब्ले से है, न कि मेरे से:

 // instead of require("core/example.php"); echo (new example())->now(); // we write define('LANG', 'en_us'); require(translate('core/example.php')); echo (new example())->now(); 

हम एक कुकी में भाषा को स्टोर करते हैं (या सत्र चर अगर हम कोई कुकी नहीं प्राप्त कर सकते हैं) और उसके बाद प्रत्येक अनुरोध पर इसे पुनः प्राप्त करें आप इस भाषा को ओवरराइड करने के लिए एक वैकल्पिक $_GET पैरामीटर के साथ गठजोड़ कर सकते हैं, लेकिन मैं उपडोमेन-प्रति-भाषा या पेज-प्रति-भाषा का सुझाव नहीं देता क्योंकि यह यह देखना कठिन है कि कौन से पृष्ठ लोकप्रिय हैं और मूल्य कम करेगा इनबाउंड लिंक के रूप में आप उन्हें और अधिक शायद ही प्रसार करेंगे।

इस पद्धति का उपयोग क्यों करें?

हमें तीन कारणों के लिए प्रीप्रोसेसिंग की इस विधि पसंद है:

  1. सामग्री के लिए पूरी तरह से काम करने वाले कार्यों को नहीं बुलाते हुए, जो शायद ही कभी बदलते हैं (इस प्रणाली के साथ, फ्रांसीसी में 100k आगंतुक अभी भी केवल एक बार अनुवाद प्रतिस्थापन को समाप्त कर देंगे)।
  2. यह हमारे डेटाबेस में कोई लोड नहीं जोड़ता, क्योंकि यह सरल फ्लैट-फाइल का उपयोग करता है और शुद्ध-PHP समाधान है।
  3. हमारे अनुवादों में PHP अभिव्यक्तियों का उपयोग करने की क्षमता

अनुवादित डाटाबेस सामग्री प्राप्त करना

हम सिर्फ अपने डेटाबेस में सामग्री के लिए एक कॉलम जोड़ते हैं जिसे language कहा जाता language , फिर हम LANG निरंतर के लिए एक LANG विधि का उपयोग करते हैं जिसे हम पहले परिभाषित करते थे, इसलिए हमारे एसक्यूएल कॉल (ज़ेडएफ 1 का प्रयोग करके, दुख की बात है) इस तरह दिखते हैं:

 $query = select()->from($this->_name) ->where('language = ?', User::getLang()) ->where('id = ?', $articleId) ->limit(1); 

हमारे लेखों में id और language पर एक प्राथमिक प्राथमिक कुंजी है, इसलिए सभी भाषाओं में अनुच्छेद 54 मौजूद हो सकते हैं। यदि हमारे द्वारा निर्दिष्ट नहीं किया गया है तो हमारे LANG डिफ़ॉल्ट को en_US

यूआरएल स्लग अनुवाद

मैं यहां दो चीजों को जोड़ता हूं, एक आपके बूटस्ट्रैप में एक फ़ंक्शन होता है जो भाषा के लिए $_GET पैरामीटर को स्वीकार करता है और कुकी चर को ओवरराइड करता है, और दूसरा रूटिंग जो कई स्लग को स्वीकार करता है तो आप अपने रूटिंग में ऐसा कुछ कर सकते हैं:

 "/wilkommen" => "/welcome/lang/de" ... etc ... 

इन्हें एक फ्लैट फ़ाइल में संग्रहीत किया जा सकता है जो आसानी से आपके व्यवस्थापक पैनल से लिखा जा सकता है। JSON या XML उन्हें समर्थन के लिए एक अच्छा ढांचा प्रदान कर सकता है।

कुछ अन्य विकल्पों के बारे में नोट्स

पीएचपी आधारित ऑन-द-फ्लाई अनुवाद

मुझे नहीं पता है कि ये पूर्व-संसाधित अनुवाद पर कोई लाभ प्रदान करते हैं।

फ्रंट-एंड बेस्ड अनुवाद

मुझे ये दिलचस्प मिल गया है, लेकिन कुछ चेतावनियां हैं उदाहरण के लिए, आपको उपयोगकर्ता को अपनी वेबसाइट पर वाक्यांशों की संपूर्ण सूची उपलब्ध कराई जा सकती है, जिसका आप अनुवाद करना चाहते हैं, यदि समस्याग्रस्त हो रही साइट के क्षेत्र हैं या उनको एक्सेस करने की अनुमति नहीं है, तो यह समस्याग्रस्त हो सकता है

आपको यह भी मानना ​​पड़ेगा कि आपके सभी उपयोगकर्ता अपनी साइट पर जावास्क्रिप्ट का उपयोग करने में सक्षम हैं, लेकिन मेरे आँकड़ों से, इसके लगभग 2.5% यूज़र्स इसके बिना चल रहे हैं (या हमारी साइटों को इसे इस्तेमाल करने से रोकने के लिए एनस्क्रिप्ट का उपयोग कर रहे हैं) ।

डेटाबेस-प्रेरित अनुवाद

पीएचपी की डाटाबेस कनेक्टिविटी गति के बारे में घर लिखने के लिए कुछ नहीं है, और यह अनुवाद करने के लिए प्रत्येक वाक्यांश पर फ़ंक्शन को कॉल करने के पहले ही उच्च ओवरहेड को जोड़ता है। इस दृष्टिकोण के साथ प्रदर्शन और स्केलेबिलिटी मुद्दों को भारी लगता है

मैं सुझाव देता हूं कि आप एक पहिया का आविष्कार न करें और गेटटेक्स्ट और आईएसओ भाषाएं Abbrevs सूची का उपयोग करें। क्या आपने देखा है कि लोकप्रिय सीएमएस या फ्रेमवर्क में आई -18 एन / एल 10 एन कैसे कार्यान्वित हुआ है?

Gettext का उपयोग करने पर आपके पास एक शक्तिशाली टूल होगा जहां कई केस पहले से कार्यान्वित किए गए हैं जैसे संख्याओं के बहुवचन रूप। अंग्रेजी में आपके पास केवल 2 विकल्प हैं: एकवचन और बहुवचन लेकिन रूसी में उदाहरण के तौर पर 3 रूप होते हैं और इसका अंग्रेजी में जितना सरल नहीं है

इसके अलावा कई अनुवादकों को पहले से ही gettext के साथ काम करने का अनुभव है।

केकपीएचपी या ड्रुपल को देखें दोनों बहुभाषी सक्षम केपीपीएचपी इंटरफ़ेस स्थानीयकरण और ड्रुपल के उदाहरण के रूप में सामग्री अनुवाद के उदाहरण के रूप में।

डेटाबेस के उपयोग से एल 10 एन के लिए बिल्कुल मामला नहीं है। प्रश्नों पर यह बहुत कम होगा मानक दृष्टिकोण प्रारंभिक चरण में स्मृति में सभी एल 10 एन डेटा प्राप्त करना है (या यदि आप आलसी लोडिंग पसंद करते हैं तो i10n फ़ंक्शन के दौरान)। यह। Po फ़ाइल से या एक बार में डीबी सभी डेटा से पढ़ा जा सकता है। और सिर्फ सरणी से अनुरोधित स्ट्रिंग पढ़ा।

यदि आप इंटरफ़ेस का अनुवाद करने के लिए ऑनलाइन टूल को लागू करने की आवश्यकता है, तो आप डीबी में वह डेटा प्राप्त कर सकते हैं, लेकिन अभी भी सभी डेटा को इसके साथ काम करने के लिए फ़ाइल से बचा सकते हैं। स्मृति में डेटा की मात्रा को कम करने के लिए आप अपने सभी अनुवादित संदेशों / स्ट्रिंग्स को समूहों में विभाजित कर सकते हैं और केवल उन समूहों को लोड करने की आवश्यकता कर सकते हैं, जिनके लिए संभव होगा।

तो आप अपने # 3 में पूरी तरह से सही एक अपवाद के साथ: आमतौर पर यह एक बड़ी फाइल है, प्रति-नियंत्रक फ़ाइल या ऐसा नहीं है क्योंकि एक फ़ाइल खोलने के लिए प्रदर्शन के लिए सबसे अच्छा है आप शायद जानते हैं कि कुछ हाई लोड किए गए वेब ऐप्स सभी फाइलों को एक फाइल में संकलित करते हैं, जिसमें फाइल संचालन से बचने के लिए कहा जाता है / शामिल होने की आवश्यकता है।

यूआरएल के बारे में Google परोक्ष रूप से अनुवाद का सुझाव देता है:

स्पष्ट रूप से फ्रांसीसी सामग्री का संकेत: http://example.ca/fr/vélo-de-montagne.html

इसके अलावा मुझे लगता है कि आपको उपयोगकर्ता को डिफ़ॉल्ट भाषा उपसर्ग जैसे http://www.examlpe.com/about-us पर पुनर्निर्देशित करने की आवश्यकता है http://examlpe.com/en/about-us पर यदि आपकी साइट केवल एक ही भाषा का उपयोग करती है तो आप सभी को उपसर्गों की आवश्यकता नहीं है।

देखें: http://www.audiomicro.com/trailer-hit-impact-sychodrama-sound-effects-836925 http://nl.audiomicro.com/aanhangwagen-hit-effect-psychodrama-geluidseffecten-836925 http: / /de.audiomicro.com/anhanger-hit-auswirkungen-psychodrama-sound-effekte-836925

सामग्री का अनुवाद करना अधिक मुश्किल काम है। मुझे लगता है कि यह विभिन्न प्रकार की सामग्री जैसे लेख, मेनू आइटम आदि के साथ कुछ अंतर होगा। लेकिन # 4 में आप सही तरीके से हैं अधिक विचार करने के लिए Drupal में एक नज़र डालें। इसके पास पर्याप्त पर्याप्त डीबी स्कीमा और अनुवाद के लिए अच्छा अंतरफलक है। जैसे आप लेख बनाते हैं और इसके लिए भाषा चुनें और आप बाद में इसे अन्य भाषाओं में भी अनुवाद कर सकते हैं।

Drupal अनुवाद इंटरफ़ेस

मुझे लगता है कि यह URL स्लग के साथ समस्या नहीं है आप केवल स्लग के लिए अलग तालिका बना सकते हैं और यह सही फैसला होगा। सही अनुक्रमित का उपयोग करके भी डेटा की बड़ी मात्रा के साथ तालिका क्वेरी करने में समस्या नहीं है और यह पूर्ण पाठ खोज नहीं था, लेकिन स्ट्रिंग मैच अगर स्लोग के लिए varchar डेटा प्रकार का उपयोग करेगा और आप उस क्षेत्र का सूचक भी बना सकते हैं

पी एस क्षमा करें, मेरी अंग्रेजी अभी तक सही से है।

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

मान लें कि आपका यह पाठ है:

 Welcome! 

आप इसे अनुवाद के साथ एक डेटाबेस में इनपुट कर सकते हैं, लेकिन आप यह भी कर सकते हैं:

 $welcome = array( "English"=>"Welcome!", "German"=>"Willkommen!", "French"=>"Bienvenue!", "Turkish"=>"Hoşgeldiniz!", "Russian"=>"Добро пожаловать!", "Dutch"=>"Welkom!", "Swedish"=>"Välkommen!", "Basque"=>"Ongietorri!", "Spanish"=>"Bienvenito!" "Welsh"=>"Croeso!"); 

अब, यदि आपकी वेबसाइट कुकी का उपयोग करती है, तो आपके पास यह उदाहरण है:

 $_COOKIE['language']; 

इसे आसान बनाने के लिए इसे एक कोड में बदलना जो आसानी से उपयोग किया जा सकता है:

 $language=$_COOKIE['language']; 

यदि आपकी कुकी भाषा वेल्श है और आपके पास यह कोड का टुकड़ा है:

 echo $welcome[$language]; 

इसका परिणाम निम्न होगा:

 Croeso! 

यदि आपको अपनी वेबसाइट के लिए बहुत सारे अनुवाद जोड़ना पड़ता है और एक डाटाबेस बहुत उपभोक्ता है, तो एक सरणी का उपयोग करना एक आदर्श समाधान हो सकता है।

मैं आपको सुझाव देता हूं कि अनुवाद के लिए वास्तव में डेटाबेस पर निर्भर न हो, यह वास्तव में एक गन्दा काम हो सकता है और डेटा एन्कोडिंग के मामले में एक अत्यधिक समस्या हो सकती है।

मेरी समस्या का समाधान करने के लिए मेरे पास पहले समान समस्या थी और निम्नलिखित वर्ग को लिखा था

ऑब्जेक्ट: लोकेल \ लोकेल

 <?php namespace Locale; class Locale{ // Following array stolen from Zend Framework public $country_to_locale = array( 'AD' => 'ca_AD', 'AE' => 'ar_AE', 'AF' => 'fa_AF', 'AG' => 'en_AG', 'AI' => 'en_AI', 'AL' => 'sq_AL', 'AM' => 'hy_AM', 'AN' => 'pap_AN', 'AO' => 'pt_AO', 'AQ' => 'und_AQ', 'AR' => 'es_AR', 'AS' => 'sm_AS', 'AT' => 'de_AT', 'AU' => 'en_AU', 'AW' => 'nl_AW', 'AX' => 'sv_AX', 'AZ' => 'az_Latn_AZ', 'BA' => 'bs_BA', 'BB' => 'en_BB', 'BD' => 'bn_BD', 'BE' => 'nl_BE', 'BF' => 'mos_BF', 'BG' => 'bg_BG', 'BH' => 'ar_BH', 'BI' => 'rn_BI', 'BJ' => 'fr_BJ', 'BL' => 'fr_BL', 'BM' => 'en_BM', 'BN' => 'ms_BN', 'BO' => 'es_BO', 'BR' => 'pt_BR', 'BS' => 'en_BS', 'BT' => 'dz_BT', 'BV' => 'und_BV', 'BW' => 'en_BW', 'BY' => 'be_BY', 'BZ' => 'en_BZ', 'CA' => 'en_CA', 'CC' => 'ms_CC', 'CD' => 'sw_CD', 'CF' => 'fr_CF', 'CG' => 'fr_CG', 'CH' => 'de_CH', 'CI' => 'fr_CI', 'CK' => 'en_CK', 'CL' => 'es_CL', 'CM' => 'fr_CM', 'CN' => 'zh_Hans_CN', 'CO' => 'es_CO', 'CR' => 'es_CR', 'CU' => 'es_CU', 'CV' => 'kea_CV', 'CX' => 'en_CX', 'CY' => 'el_CY', 'CZ' => 'cs_CZ', 'DE' => 'de_DE', 'DJ' => 'aa_DJ', 'DK' => 'da_DK', 'DM' => 'en_DM', 'DO' => 'es_DO', 'DZ' => 'ar_DZ', 'EC' => 'es_EC', 'EE' => 'et_EE', 'EG' => 'ar_EG', 'EH' => 'ar_EH', 'ER' => 'ti_ER', 'ES' => 'es_ES', 'ET' => 'en_ET', 'FI' => 'fi_FI', 'FJ' => 'hi_FJ', 'FK' => 'en_FK', 'FM' => 'chk_FM', 'FO' => 'fo_FO', 'FR' => 'fr_FR', 'GA' => 'fr_GA', 'GB' => 'en_GB', 'GD' => 'en_GD', 'GE' => 'ka_GE', 'GF' => 'fr_GF', 'GG' => 'en_GG', 'GH' => 'ak_GH', 'GI' => 'en_GI', 'GL' => 'iu_GL', 'GM' => 'en_GM', 'GN' => 'fr_GN', 'GP' => 'fr_GP', 'GQ' => 'fan_GQ', 'GR' => 'el_GR', 'GS' => 'und_GS', 'GT' => 'es_GT', 'GU' => 'en_GU', 'GW' => 'pt_GW', 'GY' => 'en_GY', 'HK' => 'zh_Hant_HK', 'HM' => 'und_HM', 'HN' => 'es_HN', 'HR' => 'hr_HR', 'HT' => 'ht_HT', 'HU' => 'hu_HU', 'ID' => 'id_ID', 'IE' => 'en_IE', 'IL' => 'he_IL', 'IM' => 'en_IM', 'IN' => 'hi_IN', 'IO' => 'und_IO', 'IQ' => 'ar_IQ', 'IR' => 'fa_IR', 'IS' => 'is_IS', 'IT' => 'it_IT', 'JE' => 'en_JE', 'JM' => 'en_JM', 'JO' => 'ar_JO', 'JP' => 'ja_JP', 'KE' => 'en_KE', 'KG' => 'ky_Cyrl_KG', 'KH' => 'km_KH', 'KI' => 'en_KI', 'KM' => 'ar_KM', 'KN' => 'en_KN', 'KP' => 'ko_KP', 'KR' => 'ko_KR', 'KW' => 'ar_KW', 'KY' => 'en_KY', 'KZ' => 'ru_KZ', 'LA' => 'lo_LA', 'LB' => 'ar_LB', 'LC' => 'en_LC', 'LI' => 'de_LI', 'LK' => 'si_LK', 'LR' => 'en_LR', 'LS' => 'st_LS', 'LT' => 'lt_LT', 'LU' => 'fr_LU', 'LV' => 'lv_LV', 'LY' => 'ar_LY', 'MA' => 'ar_MA', 'MC' => 'fr_MC', 'MD' => 'ro_MD', 'ME' => 'sr_Latn_ME', 'MF' => 'fr_MF', 'MG' => 'mg_MG', 'MH' => 'mh_MH', 'MK' => 'mk_MK', 'ML' => 'bm_ML', 'MM' => 'my_MM', 'MN' => 'mn_Cyrl_MN', 'MO' => 'zh_Hant_MO', 'MP' => 'en_MP', 'MQ' => 'fr_MQ', 'MR' => 'ar_MR', 'MS' => 'en_MS', 'MT' => 'mt_MT', 'MU' => 'mfe_MU', 'MV' => 'dv_MV', 'MW' => 'ny_MW', 'MX' => 'es_MX', 'MY' => 'ms_MY', 'MZ' => 'pt_MZ', 'NA' => 'kj_NA', 'NC' => 'fr_NC', 'NE' => 'ha_Latn_NE', 'NF' => 'en_NF', 'NG' => 'en_NG', 'NI' => 'es_NI', 'NL' => 'nl_NL', 'NO' => 'nb_NO', 'NP' => 'ne_NP', 'NR' => 'en_NR', 'NU' => 'niu_NU', 'NZ' => 'en_NZ', 'OM' => 'ar_OM', 'PA' => 'es_PA', 'PE' => 'es_PE', 'PF' => 'fr_PF', 'PG' => 'tpi_PG', 'PH' => 'fil_PH', 'PK' => 'ur_PK', 'PL' => 'pl_PL', 'PM' => 'fr_PM', 'PN' => 'en_PN', 'PR' => 'es_PR', 'PS' => 'ar_PS', 'PT' => 'pt_PT', 'PW' => 'pau_PW', 'PY' => 'gn_PY', 'QA' => 'ar_QA', 'RE' => 'fr_RE', 'RO' => 'ro_RO', 'RS' => 'sr_Cyrl_RS', 'RU' => 'ru_RU', 'RW' => 'rw_RW', 'SA' => 'ar_SA', 'SB' => 'en_SB', 'SC' => 'crs_SC', 'SD' => 'ar_SD', 'SE' => 'sv_SE', 'SG' => 'en_SG', 'SH' => 'en_SH', 'SI' => 'sl_SI', 'SJ' => 'nb_SJ', 'SK' => 'sk_SK', 'SL' => 'kri_SL', 'SM' => 'it_SM', 'SN' => 'fr_SN', 'SO' => 'sw_SO', 'SR' => 'srn_SR', 'ST' => 'pt_ST', 'SV' => 'es_SV', 'SY' => 'ar_SY', 'SZ' => 'en_SZ', 'TC' => 'en_TC', 'TD' => 'fr_TD', 'TF' => 'und_TF', 'TG' => 'fr_TG', 'TH' => 'th_TH', 'TJ' => 'tg_Cyrl_TJ', 'TK' => 'tkl_TK', 'TL' => 'pt_TL', 'TM' => 'tk_TM', 'TN' => 'ar_TN', 'TO' => 'to_TO', 'TR' => 'tr_TR', 'TT' => 'en_TT', 'TV' => 'tvl_TV', 'TW' => 'zh_Hant_TW', 'TZ' => 'sw_TZ', 'UA' => 'uk_UA', 'UG' => 'sw_UG', 'UM' => 'en_UM', 'US' => 'en_US', 'UY' => 'es_UY', 'UZ' => 'uz_Cyrl_UZ', 'VA' => 'it_VA', 'VC' => 'en_VC', 'VE' => 'es_VE', 'VG' => 'en_VG', 'VI' => 'en_VI', 'VN' => 'vn_VN', 'VU' => 'bi_VU', 'WF' => 'wls_WF', 'WS' => 'sm_WS', 'YE' => 'ar_YE', 'YT' => 'swb_YT', 'ZA' => 'en_ZA', 'ZM' => 'en_ZM', 'ZW' => 'sn_ZW' ); /** * Store the transaltion for specific languages * * @var array */ protected $translation = array(); /** * Current locale * * @var string */ protected $locale; /** * Default locale * * @var string */ protected $default_locale; /** * * @var string */ protected $locale_dir; /** * Construct. * * * @param string $locale_dir */ public function __construct($locale_dir) { $this->locale_dir = $locale_dir; } /** * Set the user define localte * * @param string $locale */ public function setLocale($locale = null) { $this->locale = $locale; return $this; } /** * Get the user define locale * * @return string */ public function getLocale() { return $this->locale; } /** * Get the Default locale * * @return string */ public function getDefaultLocale() { return $this->default_locale; } /** * Set the default locale * * @param string $locale */ public function setDefaultLocale($locale) { $this->default_locale = $locale; return $this; } /** * Determine if transltion exist or translation key exist * * @param string $locale * @param string $key * @return boolean */ public function hasTranslation($locale, $key = null) { if (null == $key && isset($this->translation[$locale])) { return true; } elseif (isset($this->translation[$locale][$key])) { return true; } return false; } /** * Get the transltion for required locale or transtion for key * * @param string $locale * @param string $key * @return array */ public function getTranslation($locale, $key = null) { if (null == $key && $this->hasTranslation($locale)) { return $this->translation[$locale]; } elseif ($this->hasTranslation($locale, $key)) { return $this->translation[$locale][$key]; } return array(); } /** * Set the transtion for required locale * * @param string $locale * Language code * @param string $trans * translations array */ public function setTranslation($locale, $trans = array()) { $this->translation[$locale] = $trans; } /** * Remove transltions for required locale * * @param string $locale */ public function removeTranslation($locale = null) { if (null === $locale) { unset($this->translation); } else { unset($this->translation[$locale]); } } /** * Initialize locale * * @param string $locale */ public function init($locale = null, $default_locale = null) { // check if previously set locale exist or not $this->init_locale(); if ($this->locale != null) { return; } if ($locale == null || (! preg_match('#^[az]+_[a-zA-Z_]+$#', $locale) && ! preg_match('#^[az]+_[a-zA-Z]+_[a-zA-Z_]+$#', $locale))) { $this->detectLocale(); } else { $this->locale = $locale; } $this->init_locale(); } /** * Attempt to autodetect locale * * @return void */ private function detectLocale() { $locale = false; // GeoIP if (function_exists('geoip_country_code_by_name') && isset($_SERVER['REMOTE_ADDR'])) { $country = geoip_country_code_by_name($_SERVER['REMOTE_ADDR']); if ($country) { $locale = isset($this->country_to_locale[$country]) ? $this->country_to_locale[$country] : false; } } // Try detecting locale from browser headers if (! $locale) { if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); foreach ($languages as $lang) { $lang = str_replace('-', '_', trim($lang)); if (strpos($lang, '_') === false) { if (isset($this->country_to_locale[strtoupper($lang)])) { $locale = $this->country_to_locale[strtoupper($lang)]; } } else { $lang = explode('_', $lang); if (count($lang) == 3) { // language_Encoding_COUNTRY $this->locale = strtolower($lang[0]) . ucfirst($lang[1]) . strtoupper($lang[2]); } else { // language_COUNTRY $this->locale = strtolower($lang[0]) . strtoupper($lang[1]); } return; } } } } // Resort to default locale specified in config file if (! $locale) { $this->locale = $this->default_locale; } } /** * Check if config for selected locale exists * * @return void */ private function init_locale() { if (! file_exists(sprintf('%s/%s.php', $this->locale_dir, $this->locale))) { $this->locale = $this->default_locale; } } /** * Load a Transtion into array * * @return void */ private function loadTranslation($locale = null, $force = false) { if ($locale == null) $locale = $this->locale; if (! $this->hasTranslation($locale)) { $this->setTranslation($locale, include (sprintf('%s/%s.php', $this->locale_dir, $locale))); } } /** * Translate a key * * @param * string Key to be translated * @param * string optional arguments * @return string */ public function translate($key) { $this->init(); $this->loadTranslation($this->locale); if (! $this->hasTranslation($this->locale, $key)) { if ($this->locale !== $this->default_locale) { $this->loadTranslation($this->default_locale); if ($this->hasTranslation($this->default_locale, $key)) { $translation = $this->getTranslation($this->default_locale, $key); } else { // return key as it is or log error here return $key; } } else { return $key; } } else { $translation = $this->getTranslation($this->locale, $key); } // Replace arguments if (false !== strpos($translation, '{a:')) { $replace = array(); $args = func_get_args(); for ($i = 1, $max = count($args); $i < $max; $i ++) { $replace['{a:' . $i . '}'] = $args[$i]; } // interpolate replacement values into the messsage then return return strtr($translation, $replace); } return $translation; } } 

प्रयोग

  <?php ## /locale/en.php return array( 'name' => 'Hello {a:1}' 'name_full' => 'Hello {a:1} {a:2}' ); $locale = new Locale(__DIR__ . '/locale'); $locale->setLocale('en');// load en.php from locale dir //want to work with auto detection comment $locale->setLocale('en'); echo $locale->translate('name', 'Foo'); echo $locale->translate('name', 'Foo', 'Bar'); 

यह काम किस प्रकार करता है

{a:1} is replaced by 1st argument passed to method Locale::translate('key_name','arg1') {a:2} is replaced by 2nd argument passed to method Locale::translate('key_name','arg1','arg2')

How detection works

  • By default if geoip is installed then it will return country code by geoip_country_code_by_name and if geoip is not installed the fallback to HTTP_ACCEPT_LANGUAGE header

Just a sub answer: Absolutely use translated urls with a language identifier in front of them: http://www.domain.com/nl/over-ons
Hybride solutions tend to get complicated, so I would just stick with it. क्यूं कर? Cause the url is essential for SEO.

About the db translation: Is the number of languages more or less fixed? Or rather unpredictable and dynamic? If it is fixed, I would just add new columns, otherwise go with multiple tables.

But generally, why not use Drupal? I know everybody wants to build their own CMS cause it's faster, leaner, etc. etc. But that is just really a bad idea!

I had the same probem a while ago, before starting using Symfony framework.

  1. Just use a function __() which has arameters pageId (or objectId, objectTable described in #2), target language and an optional parameter of fallback (default) language. The default language could be set in some global config in order to have an easier way to change it later.

  2. For storing the content in database i used following structure: (pageId, language, content, variables).

    • pageId would be a FK to your page you want to translate. if you have other objects, like news, galleries or whatever, just split it into 2 fields objectId, objectTable.

    • language – obviously it would store the ISO language string EN_en, LT_lt, EN_us etc.

    • content – the text you want to translate together with the wildcards for variable replacing. Example "Hello mr. %%name%%. Your account balance is %%balance%%."

    • variables – the json encoded variables. PHP provides functions to quickly parse these. Example "name: Laurynas, balance: 15.23".

    • you mentioned also slug field. you could freely add it to this table just to have a quick way to search for it.

  3. Your database calls must be reduced to minimum with caching the translations. It must be stored in PHP array, because it is the fastest structure in PHP language. How you will make this caching is up to you. From my experience you should have a folder for each language supported and an array for each pageId. The cache should be rebuilt after you update the translation. ONLY the changed array should be regenerated.

  4. i think i answered that in #2

  5. your idea is perfectly logical. this one is pretty simple and i think will not make you any problems.

URLs should be translated using the stored slugs in the translation table.

Final words

it is always good to research the best practices, but do not reinvent the wheel. just take and use the components from well known frameworks and use them.

take a look at Symfony translation component . It could be a good code base for you.

I am not going to attempt to refine the answers already given. Instead I will tell you about the way my own OOP PHP framework handles translations.

Internally, my framework use codes like en, fr, es, cn and so on. An array holds the languages supported by the website: array('en','fr','es','cn') The language code is passed via $_GET (lang=fr) and if not passed or not valid, it is set to the first language in the array. So at any time during program execution and from the very beginning, the current language is known.

It is useful to understand the kind of content that needs to be translated in a typical application:

1) error messages from classes (or procedural code) 2) non-error messages from classes (or procedural code) 3) page content (usually store in a database) 4) site-wide strings (like website name) 5) script-specific strings

The first type is simple to understand. Basically, we are talking about messages like "could not connect to the database …". These messages only need to be loaded when an error occurs. My manager class receives a call from the other classes and using the information passed as parameters simply goes to relevant the class folder and retrieves the error file.

The second type of error message is more like the messages you get when the validation of a form went wrong. ("You cannot leave … blank" or "please choose a password with more than 5 characters"). The strings need to be loaded before the class runs.I know what is

For the actual page content, I use one table per language, each table prefixed by the code for the language. So en_content is the table with English language content, es_content is for spain, cn_content for China and fr_content is the French stuff.

The fourth kind of string is relevant throughout your website. This is loaded via a configuration file named using the code for the language, that is en_lang.php, es_lang.php and so on. In the global language file you will need to load the translated languages such as array('English','Chinese', 'Spanish','French') in the English global file and array('Anglais','Chinois', 'Espagnol', 'Francais') in the French file. So when you populate a dropdown for language selection, it is in the correct language 😉

Finally you have the script-specific strings. So if you write a cooking application, it might be "Your oven was not hot enough".

In my application cycle, the global language file is loaded first. In there you will find not just global strings (like "Jack's Website") but also settings for some of the classes. Basically anything that is language or culture-dependent. Some of the strings in there include masks for dates (MMDDYYYY or DDMMYYYY), or ISO Language Codes. In the main language file, I include strings for individual classes becaue there are so few of them.

The second and last language file that is read from disk is the script language file. lang_en_home_welcome.php is the language file for the home/welcome script. A script is defined by a mode (home) and an action (welcome). Each script has its own folder with config and lang files.

The script pulls the content from the database naming the content table as explained above.

If something goes wrong, the manager knows where to get the language-dependent error file. That file is only loaded in case of an error.

So the conclusion is obvious. Think about the translation issues before you start developing an application or framework. You also need a development workflow that incorporates translations. With my framework, I develop the whole site in English and then translate all the relevant files.

Just a quick final word on the way the translation strings are implemented. My framework has a single global, the $manager, which runs services available to any other service. So for example the form service gets hold of the html service and uses it to write the html. One of the services on my system is the translator service. $translator->set($service,$code,$string) sets a string for the current language. The language file is a list of such statements. $translator->get($service,$code) retrieves a translation string. The $code can be numeric like 1 or a string like 'no_connection'. There can be no clash between services because each has its own namespace in the translator's data area.

I post this here in the hope it will save somebody the task of reinventing the wheel like I had to do a few long years ago.

I've been asking myself related questions over and over again, then got lost in formal languages… but just to help you out a little I'd like to share some findings:

I recommend to give a look at advanced CMS

Typo3 for PHP (I know there is a lot of stuff but thats the one I think is most mature)

Plone in Python

If you find out that the web in 2013 should work different then, start from scratch. That would mean to put together a team of highly skilled/experienced people to build a new CMS. May be you'd like to give a look at polymer for that purpose.

If it comes to coding and multilingual websites / native language support, I think every programmer should have a clue about unicode. If you don't know unicode you'll most certainly mess up your data. Do not go with the thousands of ISO codes. They'll only save you some memory. But you can do literally everything with UTF-8 even store chinese chars. But for that you'd need to store either 2 or 4 byte chars that makes it basically a utf-16 or utf-32.

If it's about URL encoding, again there you shouldn't mix encodings and be aware that at least for the domainname there are rules defined by different lobbies that provide applications like a browser. eg a Domain could be very similar like:

ьankofamerica.com or bankofamerica.com samesamebutdifferent 😉

Of course you need the filesystem to work with all encodings. Another plus for unicode using utf-8 filesystem.

If its about translations, think about the structure of documents. eg a book or an article. You have the docbook specifications to understand about those structures. But in HTML its just about content blocks. So you'd like to have a translation on that level, also on webpage level or domain level. So if a block doesn't exist its just not there, if a webpage doesn't exist you'll get redirected to the upper navigation level. If a domain should be completely different in navigation structure, then.. its a complete different structure to manage. This can already be done with Typo3.

If its about frameworks, the most mature ones I know, to do the general stuff like MVC(buzzword I really hate it! Like "performance" If you want to sell something, use the word performance and featurerich and you sell… what the hell) is Zend . It has proven to be a good thing to bring standards to php chaos coders. But, typo3 also has a Framework besides the CMS. Recently it has been redeveloped and is called flow3 now. The frameworks of course cover database abstraction, templating and concepts for caching, but have individual strengths.

If its about caching… that can be awefully complicated / multilayered. In PHP you'll think about accellerator, opcode, but also html, httpd, mysql, xml, css, js … any kinds of caches. Of course some parts should be cached and dynamic parts like blog answers shouldn't. Some should be requested over AJAX with generated urls. JSON, hashbangs etc.

Then, you'd like to have any little component on your website to be accessed or managed only by certain users , so conceptually that plays a big role.

Also you'd like to make statistics , maybe have distributed system / a facebook of facebooks etc. any software to be built on top of your over the top cms … so you need different type of databases inmemory, bigdata, xml, whatsoever.

well, I think thats enough for now. If you haven't heard of either typo3 / plone or mentioned frameworks, you have enough to study. On that path you'll find a lot of solutions for questions you haven't asked yet.

If then you think, lets make a new CMS because its 2013 and php is about to die anyway, then you r welcome to join any other group of developers hopefully not getting lost.

सौभाग्य!

And btw. how about people will not having any websites anymore in the future? and we'll all be on google+? I hope developers become a little more creative and do something usefull(to not be assimilated by the borgle)

//// Edit /// Just a little thought for your existing application:

If you have a php mysql CMS and you wanted to embed multilang support. you could either use your table with an aditional column for any language or insert the translation with an object id and a language id in the same table or create an identical table for any language and insert objects there, then make a select union if you want to have them all displayed. For the database use utf8 general ci and of course in the front/backend use utf8 text/encoding. I have used url path segments for urls in the way you already explaned like

domain.org/en/about you can map the lang ID to your content table. anyway you need to have a map of parameters for your urls so you'd like to define a parameter to be mapped from a pathsegment in your URL that would be eg

domain.org/en/about/employees/IT/administrators/

lookup configuration

pageid| url

1 | /about/employees/../..

1 | /../about/employees../../

map parameters to url pathsegment ""

 $parameterlist[lang] = array(0=>"nl",1=>"en"); // default nl if 0 $parameterlist[branch] = array(1=>"IT",2=>"DESIGN"); // default nl if 0 $parameterlist[employertype] = array(1=>"admin",1=>"engineer"); //could be a sql result $websiteconfig[]=$userwhatever; $websiteconfig[]=$parameterlist; $someparameterlist[] = array("branch"=>$someid); $someparameterlist[] = array("employertype"=>$someid); function getURL($someparameterlist){ // todo foreach someparameter lookup pathsegment return path; } 

per say, thats been covered already in upper post.

And to not forget, you'd need to "rewrite" the url to your generating php file that would in most cases be index.php

Database work:

Create Language Table 'languages':

Fields:

language_id(primary and auto increamented)

language_name

created_at

created_by

updated_at

updated_by

Create a table in database 'content':

Fields:

content_id(primary and auto increamented)

main_content

header_content

footer_content

leftsidebar_content

rightsidebar_content

language_id(foreign key: referenced to languages table)

created_at

created_by

updated_at

updated_by

Front End Work:

When user selects any language from dropdown or any area then save selected language id in session like,

$_SESSION['language']=1;

Now fetch data from database table 'content' based on language id stored in session.

Detail may found here http://skillrow.com/multilingual-website-in-php-2/

As a person who live in Quebec where almost all site is french and english… i have try many if not most multilanguage plugin for WP… the one an only usefull solution that work nive with all my site is mQtranslate… i live and die with it !

https://wordpress.org/plugins/mqtranslate/

A really simple option that works with any website where you can upload Javascript is http://www.multilingualizer.com

It lets you put all text for all languages onto one page and then hides the languages the user doesn't need to see. अच्छा काम करता है।

What about WORDPRESS + MULTI-LANGUAGE SITE BASIS (plugin) ? the site will have structure:

  • example.com/ eng /category1/….
  • example.com/ eng /my-page….
  • example.com/ rus /category1/….
  • example.com/ rus /my-page….

The plugin provides Interface for Translation all phrases, with simple logic:

 (ENG) my_title - "Hello user" (SPA) my_title - "Holla usuario" 

then it can be outputed:
echo translate('my_title', LNG); // LNG is auto-detected

ps however, check, if the plugin is still active.