2013-12-10 11 views
11

एक PHP लाइब्रेरी लिखने पर विचार करें, जो पैकगिस्ट या नाशपाती के माध्यम से प्रकाशित हो जाएगा। यह मनमाने ढंग से सेटिंग्स में इसका उपयोग कर सहकर्मी डेवलपर्स को संबोधित किया जाता है।एक PHP तृतीय-पक्ष लाइब्रेरी को अंतर्राष्ट्रीयकरण कैसे करें

इस पुस्तकालय में ग्राहक के लिए निर्धारित कुछ स्थिति संदेश होंगे। मैं इस कोड को अंतर्राष्ट्रीय कैसे बना सकता हूं, ताकि लाइब्रेरी का उपयोग करने वाले डेवलपर्स को अपनी स्थानीयकरण विधि में प्लग करने की उच्चतम स्वतंत्रता हो? मैं कुछ भी नहीं मानना ​​चाहता, खासकर गेटटेक्स्ट का उपयोग करने के लिए देव को मजबूर नहीं करना चाहता।

एक उदाहरण पर काम करने के लिए, के इस वर्ग डालें:

class Example { 

    protected $message = "I'd like to be translated in your client's language."; 

    public function callMe() { 
     return $this->message; 
    } 

    public function callMeToo($user) { 
     return sprintf('Hi %s, nice to meet you!', $user); 
    } 

} 

वहाँ दो समस्याओं यहाँ हैं: मैं अनुवाद के लिए निजी $message कैसे चिह्नित करते हैं, और कैसे मैं डेवलपर के अंदर स्ट्रिंग स्थानीय बनाना करने की अनुमति है callMeToo()?

एक (अत्यधिक असुविधाजनक) विकल्प होगा, इसलिए जैसे निर्माता में कुछ i18n विधि के लिए पूछना,:

public function __construct($i18n) { 
    $this->i18n = $i18n; 
    $this->message = $this->i18n($this->message); 
} 

public function callMeToo($user) { 
    return sprintf($this->i18n('Hi %s, nice to meet you!'), $user); 
} 

लेकिन मैं महंगा एक और अधिक सुरुचिपूर्ण समाधान के लिए उम्मीद है।

संपादित करें 1: सरल स्ट्रिंग प्रतिस्थापन के अलावा i18n का क्षेत्र एक विस्तृत है। आधार यह है कि मैं अपनी लाइब्रेरी के साथ किसी भी i18n समाधान को पैक नहीं करना चाहता हूं या उपयोगकर्ता को विशेष रूप से मेरे कोड को पूरा करने के लिए चुनने के लिए मजबूर नहीं करना चाहता हूं।

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

उत्तर

7

सबसे अधिक उपयोग किया जाने वाला समाधान एक स्ट्रिंग फ़ाइल है। जैसे जैसे निम्नलिखित:

# library 
class Foo { 
    public function __construct($lang = 'en') { 
    $this->strings = require('path/to/langfile.' . $lang . '.php'); 
    $this->message = $this->strings['callMeToo']; 
    } 

    public function callMeToo($user) { 
    return sprintf($this->strings['callMeToo'], $user); 
    } 
} 

# strings file 
return Array(
    'callMeToo' => 'Hi %s, nice to meet you!' 
); 

आप $this->message काम से बचने के लिए कर सकते हैं, यह भी जादू ही टिककर खेल के साथ काम:

# library again 
class Foo { 
    # … code from above 

    function __get($name) { 
    if(!empty($this->strings[$name])) { 
     return $this->strings[$name]; 
    } 

    return null; 
    } 
} 

तुम भी एक loadStrings विधि है जो उपयोगकर्ता से तार की एक सरणी लेता है जोड़ सकते हैं और मर्ज कर सकते हैं यह आपके आंतरिक तार तालिका के साथ।

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

दिनांक स्थानीयकरण कोई समस्या नहीं है। लोकेल सेट करना आपके पुस्तकालय का उपयोग करने वाले सॉफ़्टवेयर का विषय है। प्रारूप स्वयं एक स्थानीय स्ट्रिंग है, उदा। $this->translate('%Y-%m-%d') दिनांक स्वरूप स्ट्रिंग का एक स्थानीय संस्करण लौटाएगा।

सही लोकेल सेट करके और sprintf() जैसे कार्यों का उपयोग करके स्थानीयकरण किया जाता है।

मुद्रा स्थानीयकरण एक समस्या है, हालांकि।मुझे लगता है कि सबसे अच्छा तरीका एक मुद्रा अनुवाद फ़ंक्शन (और, शायद बेहतर लचीलापन, एक और संख्या स्वरूपण फ़ंक्शन भी) जोड़ना होगा, जो एक डेवलपर ओवरराइट कर सकता है यदि वह मुद्रा प्रारूप बदलना चाहता है। वैकल्पिक रूप से आप मुद्राओं के लिए प्रारूप तारों को भी कार्यान्वित कर सकते हैं। उदाहरण के लिए %CUR %.02f - इस उदाहरण में आप मुद्रा चिह्न के साथ %CUR को प्रतिस्थापित करेंगे। मुद्रा प्रतीक स्वयं भी स्थानीय तार हैं।

संपादित करें 2: आप setlocale का उपयोग नहीं करना चाहते हैं तो आप बहुत काम करना है ... मूल रूप से आप strftime() और sprintf() के पुनर्लेखन के लिए स्थानीय दिनांक और संख्या प्राप्त करने के लिए किया है। बेशक संभव है, लेकिन बहुत सारे काम।

+0

धन्यवाद, दिलचस्प। असल में, सुझाए गए 'लोडस्ट्रिंग्स' मेरी ज़रूरतों के लिए एक अच्छा मैच प्रतीत होता है। क्या आप जंगली में किसी भी परियोजना के बारे में जानते हैं, वे इससे कैसे निपटते हैं? (ज़ेंड को छूट दी गई है, हालांकि उनके पास अपना खुद का i18n lib है।) – Boldewyn

+0

@ बोल्डविन मैं इसे बंद करने वाली कुछ बंद स्रोत परियोजनाओं को जानता हूं, लेकिन मुझे ओपन सोर्स प्रोजेक्ट के बारे में कड़ी मेहनत करनी है। अधिकांश स्थानीयकरण नहीं किए जाते हैं और यदि वे हैं, तो वे गेटटेक्स्ट का उपयोग करते हैं ... – ckruse

+0

हां, यह वास्तव में मेरी समस्या है, दुर्भाग्य से ... – Boldewyn

2

बुनियादी दृष्टिकोण उपभोक्ता को मैपिंग को परिभाषित करने के लिए कुछ विधि प्रदान करना है। यह तब तक कोई भी फॉर्म ले सकता है, जब तक कि उपयोगकर्ता एक जैविक मैपिंग को परिभाषित कर सके।

उदाहरण के लिए, मैंटिस बग ट्रैकर एक सरल globals file उपयोग करता है:

<?php 
    require_once "strings_$language.txt"; 
    echo $s_actiongroup_menu_move; 

उनकी विधि बुनियादी है, लेकिन ठीक काम करता है। एक वर्ग में लपेट यदि आप पसंद:

<?php 
    $translator = new Translator(Translator::ENGLISH); // or make it a singleton 
    echo $translator->translate('actiongroup_menu_move'); 

बजाय एक XML फ़ाइल का उपयोग करें, या एक INI फ़ाइल, या एक CSV फ़ाइल ... अपनी पसंद के किसी भी प्रारूप है, वास्तव में।


उत्तर देना आपके बाद में संपादन/टिप्पणियों

हाँ, इसके बाद के संस्करण अन्य समाधान से बहुत अलग नहीं है। लेकिन मेरा मानना ​​है कि वहाँ कुछ और कहा जा रहा है:

  • अनुवाद केवल (मानचित्रण रूपों में से एक अनंत संख्या लग सकता है)
  • स्वरूपण संख्या और दिनांक आपकी चिंता से कोई भी है स्ट्रिंग प्रतिस्थापन के माध्यम से प्राप्त किया जा सकता। यह प्रस्तुति परत की जिम्मेदारी है, और तुम सिर्फ कच्चे संख्या (या DateTime या टाइम स्टांप) लौटना चाहिए, (जब तक अपनी लाइब्रेरी के उद्देश्य स्थानीयकरण है;)
+0

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

2

वहाँ एक मुख्य समस्या यहाँ है। आप कोड बनाना नहीं चाहते हैं क्योंकि यह अभी अंतर्राष्ट्रीयकरण के लिए आपके प्रश्न में है।

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

तो मैं इसका प्रस्ताव करता हूं: अज्ञेय प्रारूप में अपने स्रोत वाक्य (अंग्रेज़ी) को रखें, ताकि सभी के लिए यह समझना आसान हो। यह एक एक्सएमएल फ़ाइल, एक डेटाबेस या कोई अन्य रूप हो सकता है जिसे आप देखते हैं। फिर अपने अनुवादों का उपयोग करें जहां आपको उनकी आवश्यकता है। इसके अलावा, आप एक small translation script I did उपयोग करना चाहते हैं यदि आप इसे इसके अलावा सरल बना सकते हैं

class Example { 
    // Fetch them as you prefer and store them in $messages. 
    protected $messages = array(
    'en' => array(
     "message" => "I'd like to be translated in your client's language.", 
     "greeting" => "Hi %s, nice to meet you!" 
    ) 
    ); 

    public function __construct($lang = 'en') { 
    $this->lang = $lang; 
    } 

    protected function get($key, $args = null) { 
    // Store the string 
    $message = $this->messages[$this->lang][$key]; 
    if ($args == null) 
     return $this->translator($message); 
    else { 
     $string = $this->translator($message); 
     // Merge the two arrays so they can be passed as values 
     $sprintf_args = array_merge(array($string), $args); 
     return call_user_func_array('sprintf', $sprintf_args); 
     } 
    } 

    public function callMe() { 
    return $this->get("message"); 
    } 

    public function callMeToo($user) { 
    return $this->get("greeting", $user); 
    } 
} 

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

class Example { 
    protected $translator; 

    // Translator already knows the language to translate the text to 
    public function __construct($Translator) { 
    $this->translator = $Translator; 
    } 

    public function callMe() { 
    return $this->translator("I'd like to be translated in your client's language."); 
    } 

    public function callMeToo($user) { 
    return sprintf($this->translator("Hi %s, nice to meet you!"), $user)); 
    } 
} 

इसे आसानी से एक्सएमएल फ़ाइल या अनुवादित तारों के लिए किसी अन्य स्रोत का उपयोग करने के लिए संशोधित किया जा सकता है।

नोट्स दूसरी विधि के लिए:

  • यह आपके प्रस्तावित समाधान से अलग है, क्योंकि यह काम उत्पादन में नहीं बल्कि प्रारंभ की तुलना में है, इसलिए कोई ट्रैक रखने के लिए की जरूरत है क्या कर रहा है, हर स्ट्रिंग का।

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

  • कॉन: यह एक पुरानी कक्षा है। मैं तब बहुत कुछ नहीं जानता था। अब मैं कुछ चीजें बदलूंगा: en, es इत्यादि के बजाय language फ़ील्ड बनाना, यहां कुछ और अपवाद फेंकना और मैंने किए गए कुछ परीक्षण अपलोड किए।

+0

उत्तर के लिए धन्यवाद। मैंने गीथूब पर भी कोड देखा। दुर्भाग्यवश यह समाधान मेरे लिए काम नहीं करता है। मैं अपनी आवश्यकताओं को जितना संभव हो सके प्रतिबंधित करना चाहता हूं, जबकि उपभोक्ता उपयोगकर्ता को मेरे कोड द्वारा उत्सर्जित करने के लिए पूरी तरह से स्थानीयकरण करने की इजाजत देता है।मैंने डेट स्वरूपण जैसी चीजों को शामिल करने के लिए प्रश्न भी अपडेट किया। मुझे डर है कि आउटपुट या प्रारंभिकरण के दौरान अनुवाद करना है या नहीं। – Boldewyn

+0

आपके अपडेट के साथ, मुझे लगता है कि यह वास्तव में एसओ के लिए बहुत व्यापक है। या तो कोड को सैकड़ों लाइनों की आवश्यकता होगी या यह एक वैचारिक प्रश्न है जो [प्रोग्रामर] (http://programmers.stackexchange.com/) में बेहतर पूछा जाता है। हालांकि, बेहतर स्थानीयकरण को संभालने के लिए मैंने जिस कक्षा को इंगित किया है, उसे विस्तारित करने के लिए स्वतंत्र महसूस करें (और यदि आप चाहते हैं तो जिथब पर वापस धक्का दें)। –

+0

एक और दिलचस्प सवाल यह है कि आपने मुद्रा को कैसे संभाला? चूंकि यह समय के साथ परिवर्तनीय है, इसलिए आपको बाहरी एपीआई का उपयोग करने की आवश्यकता होगी, इसलिए यह आपकी सभी आवश्यकताओं को करने के लिए अधिक से अधिक असुविधाजनक हो जाता है और यह * सरल * नहीं होगा। –

संबंधित मुद्दे