नियंत्रकों में कोणीय-अनुवाद के लिए सही उपयोग


121

मैं एक AngularJS एप्लिकेशन में i18n के लिए कोणीय-अनुवाद का उपयोग कर रहा हूं ।

प्रत्येक एप्लिकेशन दृश्य के लिए, एक समर्पित नियंत्रक है। नीचे दिए गए नियंत्रकों में, मैंने पृष्ठ शीर्षक के रूप में दिखाए जाने के लिए मूल्य निर्धारित किया है।

कोड

एचटीएमएल

<h1>{{ pageTitle }}</h1>

जावास्क्रिप्ट

.controller('FirstPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
        $scope.pageTitle = $filter('translate')('HELLO_WORLD');
    }])

.controller('SecondPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
        $scope.pageTitle = 'Second page title';
    }])

मैं कोणीय-अनुवाद-लोडर-यूआरएल एक्सटेंशन का उपयोग करके अनुवाद फाइलें लोड कर रहा हूं ।

संकट

प्रारंभिक पृष्ठ लोड पर, उस कुंजी के लिए अनुवाद के बजाय अनुवाद कुंजी दिखाई गई है। अनुवाद है Hello, World!, लेकिन मैं देख रहा हूं HELLO_WORLD

दूसरी बार जब मैं पृष्ठ पर जाता हूं, तो सब ठीक है और अनुवादित संस्करण दिखाया गया है।

मुझे लगता है कि इस मुद्दे को इस तथ्य के साथ करना है कि शायद अनुवाद फ़ाइल अभी तक लोड नहीं हुई है जब नियंत्रक मूल्य को असाइन कर रहा है $scope.pageTitle

टिप्पणी

उपयोग करते समय <h1>{{ pageTitle | translate }}</h1>और $scope.pageTitle = 'HELLO_WORLD';, अनुवाद पहली बार से सही काम करता है। इसके साथ समस्या यह है कि मैं हमेशा अनुवाद का उपयोग नहीं करना चाहता (उदाहरण के लिए, दूसरे नियंत्रक के लिए मैं सिर्फ एक कच्चा स्ट्रिंग पारित करना चाहता हूं)।

सवाल

क्या यह एक ज्ञात मुद्दा / सीमा है? इसे कैसे हल किया जा सकता है?

जवाबों:


69

संपादित करें : कृपया बेहतर समाधान के लिए पास्कलप्रेच (कोणीय-अनुवाद के लेखक) से उत्तर देखें।


लोडिंग की अतुल्यकालिक प्रकृति समस्या का कारण बनती है। आप देखते हैं, के साथ {{ pageTitle | translate }}, कोणीय अभिव्यक्ति देखेंगे; जब स्थानीयकरण डेटा लोड किया जाता है, तो अभिव्यक्ति का मूल्य बदल जाता है और स्क्रीन अपडेट हो जाती है।

तो, आप खुद ऐसा कर सकते हैं:

.controller('FirstPageCtrl', ['$scope', '$filter', function ($scope, $filter) {
    $scope.$watch(
        function() { return $filter('translate')('HELLO_WORLD'); },
        function(newval) { $scope.pageTitle = newval; }
    );
});

हालांकि, यह हर पाचन चक्र पर देखे गए अभिव्यक्ति को चलाएगा। यह उप-रूपी है और दृश्य प्रदर्शन में गिरावट का कारण हो सकता है या नहीं भी हो सकता है। वैसे भी यह वही है जो कोणीय करता है, इसलिए यह बुरा नहीं हो सकता ...


धन्यवाद! मैं उम्मीद करूंगा कि व्यू में या कंट्रोलर में फ़िल्टर का उपयोग करना बिल्कुल वैसा ही व्यवहार करेगा। यहाँ ऐसा प्रतीत नहीं होता।
ndequeker

मैं कहूंगा कि $scope.$watchएंगुलर ट्रांसलेशन कंट्रोलरों में उपयोग की जाने वाली सेवा की पेशकश के बाद से ए का उपयोग करना अधिक कठिन है। नीचे मेरा जवाब देखें।
रोबिन वैन बालन

1
कोणीय अनुवाद फ़िल्टर की आवश्यकता नहीं है, क्योंकि $translate.instant()यह सेवा के समान है। इसके अलावा, कृपया पास्कल के उत्तर पर ध्यान दें।
नॉली

मैं सहमत हूँ, $ घड़ी का उपयोग ओवरकिल है। नीचे दिए गए उत्तर अधिक उचित उपयोग हैं।
२२

141

अनुशंसित: नियंत्रक में अनुवाद न करें, अपने विचार में अनुवाद करें

मैं आपके नियंत्रक को अनुवाद तर्क से मुक्त रखने की सलाह दूंगा और अपने तार को सीधे आपके दृश्य के अंदर इस तरह अनुवाद करूंगा:

<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1>

प्रदान की गई सेवा का उपयोग करना

कोणीय अनुवाद वह $translateसेवा प्रदान करता है जिसका उपयोग आप अपने नियंत्रकों में कर सकते हैं।

सेवा का एक उदाहरण उपयोग $translateहो सकता है:

.controller('TranslateMe', ['$scope', '$translate', function ($scope, $translate) {
    $translate('PAGE.TITLE')
        .then(function (translatedValue) {
            $scope.pageTitle = translatedValue;
        });
});

अनुवाद सेवा में एक वादे को संभालने की आवश्यकता के बिना सीधे स्ट्रिंग्स का अनुवाद करने की एक विधि भी है $translate.instant():

.controller('TranslateMe', ['$scope', '$translate', function ($scope, $translate) {
    $scope.pageTitle = $translate.instant('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});

उपयोग करने के साथ नकारात्मक पक्ष यह $translate.instant()हो सकता है कि यदि आप इसे async लोड कर रहे हैं तो भाषा फ़ाइल अभी तक लोड नहीं हुई है।

दिए गए फ़िल्टर का उपयोग करना

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

.controller('TranslateMe', ['$scope', '$filter', function ($scope, $filter) {
    var $translate = $filter('translate');

    $scope.pageTitle = $translate('TITLE.DASHBOARD'); // Assuming TITLE.DASHBOARD is defined
});

दिए गए निर्देश का उपयोग करना

चूंकि @PascalPrecht इस भयानक पुस्तकालय का निर्माता है, मैं उसकी सलाह के साथ जाने की सलाह दूंगा (नीचे उसका उत्तर देखें) और दिए गए निर्देश का उपयोग करें जो अनुवादों को बहुत बुद्धिमानी से संभालने के लिए लगता है।

निर्देश अतुल्यकालिक निष्पादन का ख्याल रखता है और यदि अनुवाद में कोई गतिशील मूल्य नहीं है तो गुंजाइश पर अनुवाद आईडी को अनचेक करने के लिए पर्याप्त चतुर है।


यदि आपने उस असंबंधित टिप्पणी को लिखने के बजाय इसे आज़माया, तो आप अब तक इसका जवाब नहीं जान पाएंगे। संक्षिप्त उत्तर: हाँ। यह संभव है।
रॉबिन वैन बालन

1
नियंत्रक में फिल्टर के साथ आपकी छूट में: जैसे कि तत्काल () के साथ, यदि भाषा फ़ाइल लोड नहीं है, तो यह सही काम नहीं करेगा? क्या हमें उस मामले में एक घड़ी का उपयोग नहीं करना चाहिए? या आपके कहने का मतलब है कि 'फ़िल्टर का उपयोग तभी करें जब आपको पता हो कि अनुवाद लोड हैं?
बोम्बिनोश

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

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

4
जब अनुवाद HTML में किया जाता है तो पाचन चक्र दो बार चलाया जाता है, लेकिन नियंत्रक में केवल एक बार ही चलता है। 99% मामलों में यह शायद मायने नहीं रखेगा, लेकिन मुझे कई कोशिकाओं में अनुवाद के साथ कोणीय यूआई ग्रिड में भयानक प्रदर्शन के साथ एक मुद्दा था। सुनिश्चित करने के लिए एक किनारे का मामला, बस कुछ के बारे में पता होना चाहिए
tykowale

123

दरअसल, आपको ऐसे सामान के बदले अनुवाद निर्देश का उपयोग करना चाहिए।

<h1 translate="{{pageTitle}}"></h1>

निर्देश अतुल्यकालिक निष्पादन का ख्याल रखता है और यदि अनुवाद में कोई गतिशील मूल्य नहीं है तो गुंजाइश पर अनुवाद आईडी को अनचेक करने के लिए पर्याप्त चतुर है।

हालांकि, अगर कोई रास्ता नहीं है और आपको वास्तव में नियंत्रक में सेवा का उपयोग $translateकरना है, तो आपको इस तरह से संयोजन में एक $translateChangeSuccessघटना में कॉल को लपेटना चाहिए :$rootScope$translate.instant()

.controller('foo', function ($rootScope, $scope, $translate) {
  $rootScope.$on('$translateChangeSuccess', function () {
    $scope.pageTitle = $translate.instant('PAGE.TITLE');
  });
})

तो क्यों $rootScopeऔर क्यों नहीं $scope? इसका कारण यह है, कि कोणीय-अनुवाद की घटनाओं में $emitएड के $rootScopeबजाय $broadcastएड होते हैं $scopeक्योंकि हमें पूरे स्कोप पदानुक्रम के माध्यम से प्रसारित करने की आवश्यकता नहीं होती है।

क्यों $translate.instant()और सिर्फ async नहीं $translate()? जब $translateChangeSuccessघटना को निकाल दिया जाता है, तो यह सुनिश्चित होता है कि आवश्यक अनुवाद डेटा है और कोई अतुल्यकालिक निष्पादन नहीं हो रहा है (उदाहरण के लिए एसिंक्रोनस लोडर निष्पादन), इसलिए हम केवल उसी का उपयोग कर सकते हैं $translate.instant()जो सिंक्रोनस है और अनुवाद उपलब्ध हैं।

संस्करण 2.8.0 के बाद से $translate.onReady(), वहाँ भी है , जो एक वादा देता है जो अनुवाद तैयार होते ही हल हो जाता है। चैंज देखें


क्या कोई प्रदर्शन समस्या हो सकती है अगर मैं फ़िल्टर के बजाय अनुवाद निर्देश का उपयोग करूं? इसके अलावा, मैं आंतरिक रूप से विश्वास करता हूं, यह तत्काल () का रिटर्न मूल्य देखता है। तो क्या यह उन घड़ियों को हटा देता है जब वर्तमान गुंजाइश नष्ट हो जाती है?
नीलेश

मैंने आपके सुझाव का उपयोग करने की कोशिश की, लेकिन यह तब काम नहीं करता जब स्कोप वैरिएबल का मान गतिशील रूप से बदलता है।
नीलेश

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

प्लंक : plnkr.co/edit/j53xL1EdJ6bT20ldlhxr शायद मेरे उदाहरण में, निर्देश मूल्य नहीं देखने का निर्णय ले रहा है। एक अलग मुद्दे के रूप में, मेरे कस्टम त्रुटि हैंडलर को कॉल किया जाता है यदि कुंजी नहीं मिली है, लेकिन यह लौटे स्ट्रिंग को प्रदर्शित नहीं करता है। मैं इसके लिए एक और डुबकी लगाऊंगा।
नीलेश

2
@PascalPrecht बस एक सवाल है, क्या एक बार अनुवाद के साथ बाइंड का इस्तेमाल करना अच्छा है? इस तरह {{::'HELLO_WORLD | translate}}'
ज़ुबैर ज़ुबैर

5

नियंत्रक में अनुवाद करने के लिए आप $translateसेवा का उपयोग कर सकते हैं :

$translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
    vm.si = translations['COMMON.SI'];
    vm.no = translations['COMMON.NO'];
});

यह कथन केवल नियंत्रक सक्रियण पर अनुवाद करता है, लेकिन यह भाषा में रनटाइम परिवर्तन का पता नहीं लगाता है। उस व्यवहार को प्राप्त करने के लिए, आप इस $rootScopeघटना को सुन सकते हैं : $translateChangeSuccessऔर वहीं अनुवाद करें:

    $rootScope.$on('$translateChangeSuccess', function () {
        $translate(['COMMON.SI', 'COMMON.NO']).then(function (translations) {
            vm.si = translations['COMMON.SI'];
            vm.no = translations['COMMON.NO'];
        });
    });

बेशक, आप $translateएक विधि में सेवा को एन्क्रिप्ट कर सकते हैं और इसे नियंत्रक और $translateChangeSucessश्रोता में कॉल कर सकते हैं ।


1

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

यहां तक ​​कि अगर आप इस मुद्दे पर सफलतापूर्वक बहस कर सकते हैं, तो बड़ी समस्या यह है कि इसमें शामिल विकास कार्य बहुत बड़ा है। एक डेवलपर को साइट पर प्रत्येक स्ट्रिंग को मैन्युअल रूप से निकालना होगा, इसे एक .json फ़ाइल में डालें, मैन्युअल रूप से इसे स्ट्रिंग कोड (यानी इस मामले में 'पेजटेटल') द्वारा संदर्भित करें। अधिकांश वाणिज्यिक साइटों में हजारों तार होते हैं जिनके लिए ऐसा होना आवश्यक है। और यह सिर्फ शुरुआत है। अब आपको अनुवाद को सिंक में रखने की एक प्रणाली की आवश्यकता है जब अंतर्निहित पाठ उनमें से कुछ में बदल जाता है, अनुवाद फ़ाइलों को विभिन्न अनुवादकों को भेजने के लिए एक प्रणाली है, उन्हें बिल्ड में पुनः स्थापित करने, साइट को फिर से तैयार करने के लिए अनुवादकों को देख सकते हैं उनके संदर्भ में परिवर्तन, और पर और पर।

इसके अलावा, चूंकि यह एक 'बाइंडिंग', ईवेंट-आधारित प्रणाली है, पृष्ठ पर हर एक स्ट्रिंग के लिए एक ईवेंट को निकाल दिया जा रहा है, जो न केवल पेज को बदलने का एक धीमा तरीका है, बल्कि पेज पर सभी कार्यों को धीमा कर सकता है, यदि आप इसमें बड़ी संख्या में ईवेंट जोड़ना शुरू करते हैं।

वैसे भी, पोस्ट-प्रोसेसिंग ट्रांसलेशन प्लेटफॉर्म का उपयोग करना मेरे लिए अधिक मायने रखता है। उदाहरण के लिए GlobalizeIt का उपयोग करते हुए, एक अनुवादक सिर्फ साइट पर एक पृष्ठ पर जा सकता है और सीधे अपनी भाषा के लिए पृष्ठ पर पाठ संपादित करना शुरू कर सकता है, और यह है: https://www.globalizeit.com/HowItWorks । किसी भी प्रोग्रामिंग की आवश्यकता नहीं है (हालांकि यह प्रोग्राम एक्स्टेंसिबल हो सकता है), यह आसानी से कोणीय के साथ एकीकृत करता है: https://www.globalizeit.com/Translate/Angular , पृष्ठ का परिवर्तन एक ही बार में होता है, और यह हमेशा अनुवादित पाठ प्रदर्शित करता है पृष्ठ का प्रारंभिक रेंडर।

पूर्ण प्रकटीकरण: मैं एक सह-संस्थापक हूं :)

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