Denetleyicilerde açısal çeviri için doğru kullanım


121

Bir AngularJS uygulamasında i18n için angular-translate kullanıyorum .

Her uygulama görünümü için özel bir denetleyici vardır. Aşağıdaki kontrolörlerde sayfa başlığı olarak gösterilecek değeri ayarladım.

kod

HTML

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

JavaScript

.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';
    }])

Angular-translate-loader-url uzantısını kullanarak çeviri dosyalarını yüklüyorum .

Sorun

İlk sayfa yüklemesinde, bu anahtarın çevirisi yerine çeviri anahtarı gösterilir. Tercüme Hello, World!, ama görüyorum HELLO_WORLD.

Sayfaya ikinci kez gittiğimde her şey yolunda ve çevrilmiş versiyon gösteriliyor.

Sorunun, denetleyici değeri atarken çeviri dosyasının henüz yüklenmemiş olması gerçeğiyle ilgili olduğunu varsayıyorum $scope.pageTitle.

düşünce

Kullanırken <h1>{{ pageTitle | translate }}</h1>ve $scope.pageTitle = 'HELLO_WORLD';çeviri eserler ilk andan itibaren mükemmel. Bununla ilgili sorun, her zaman çevirileri kullanmak istemememdir (örneğin, ikinci denetleyici için sadece bir ham dizge geçmek istiyorum).

Soru

Bu bilinen bir sorun / sınırlama mı? Bu nasıl çözülebilir?

Yanıtlar:


69

DÜZENLEME : Daha iyi bir çözüm için lütfen PascalPrecht'in (angular-translate yazarı) yanıtına bakın.


Yüklemenin asenkron doğası soruna neden olur. Gördüğünüz gibi {{ pageTitle | translate }}, Angular ifadeyi izleyecek; yerelleştirme verileri yüklendiğinde, ifadenin değeri değişir ve ekran güncellenir.

Yani, bunu kendiniz yapabilirsiniz:

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

Ancak bu, izlenen ifadeyi her sindirim döngüsünde çalıştıracaktır. Bu yetersizdir ve gözle görülür bir performans düşüşüne neden olabilir veya olmayabilir. Her neyse, Angular'ın yaptığı gibi, o kadar da kötü olamaz ...


Teşekkür ederim! Görünümde veya bir Denetleyicide bir filtre kullanmanın tamamen aynı şekilde davranmasını beklerdim. Burada durum böyle görünmüyor.
ndequeker

$scope.$watchAngular Translate'in denetleyicilerde kullanılmak üzere bir Hizmet sunduğu için a kullanmanın oldukça fazla olduğunu söyleyebilirim . Aşağıdaki cevabıma bakın.
Robin van Baalen

1
$translate.instant()Bir hizmetle aynı şeyi sunduğundan, Açısal Çeviri filtresi gerekli değildir . Bunun yanında lütfen Pascal'ın cevabına dikkat edin.
knalli

Katılıyorum, $ watch kullanmanın abartılı olduğunu düşünüyorum. Aşağıdaki cevaplar daha uygun kullanımlardır.
jpblancoder

141

Önerilen: kontrolörde tercüme etmeyin, kendi görüşünüzde tercüme edin

Denetleyicinizi çeviri mantığından uzak tutmanızı ve dizelerinizi doğrudan şu şekilde görünümünüzün içine çevirmenizi öneririm:

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

Sağlanan hizmeti kullanmak

Angular Translate, $translateKontrol Cihazlarınızda kullanabileceğiniz hizmeti sağlar .

$translateHizmetin örnek bir kullanımı şunlar olabilir:

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

Çeviri hizmeti ayrıca bir sözü yerine getirmeye gerek kalmadan dizeleri doğrudan çevirmek için bir yönteme sahiptir $translate.instant():

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

Kullanmanın dezavantajı, $translate.instant()eşzamansız olarak yüklüyorsanız, dil dosyasının henüz yüklenmemiş olması olabilir.

Sağlanan filtreyi kullanma

Sözleri bu şekilde halletmek zorunda olmadığım için bu benim tercih ettiğim yoldur. Filtrenin çıktısı doğrudan bir kapsam değişkenine ayarlanabilir.

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

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

Sağlanan yönergeyi kullanarak

@PascalPrecht bu harika kütüphanenin yaratıcısı olduğu için, onun tavsiyesine uymanızı (aşağıdaki cevaba bakın) ve çevirileri çok akıllıca işleyen sağlanan yönergeyi kullanmanızı öneririm .

Yönerge, eşzamansız yürütme ile ilgilenir ve ayrıca çevirinin dinamik değerleri yoksa kapsamdaki çeviri kimliklerini geri almak için yeterince akıllıdır.


O ilgisiz yorumu yazmak yerine deneseydiniz, şimdiye kadar cevabı biliyor olurdunuz. Kısa cevap: evet. Bu mümkün.
Robin van Baalen

1
denetleyicideki filtre ile örneğinizde: instant () ile olduğu gibi, dil dosyası yüklenmemişse, bu doğru çalışmayacaktır? Bu durumda saat kullanmamalı mıyız? Ya da 'filtreyi yalnızca çevirilerin yüklendiğini biliyorsanız kullanın' demek istiyorsunuz?
Bombinosh

@Bombinosh Çevirilerin yüklendiğini biliyorsanız filtre yöntemini kullanın derim. Kişisel olarak, mecbur değilseniz çevirileri dinamik olarak yüklememenizi bile tavsiye ederim. Bu, uygulamanızın zorunlu bir parçasıdır, bu nedenle kullanıcının onu beklemesini istemeseniz iyi olur. Ama bu kişisel bir görüş.
Robin van Baalen

Çevirilerin amacı, kullanıcı tercihlerine ve hatta kullanıcı eylemlerine göre değişebilmeleridir. Dolayısıyla, genel olarak bunları dinamik olarak yüklemeniz gerekir. En azından çevrilecek dizelerin sayısı önemliyse ve / veya çok sayıda çeviriniz varsa.
PhiLho

4
Çeviri HTML'de yapıldığında, özet döngüsü iki kez çalıştırılır, ancak denetleyicide yalnızca bir kez çalıştırılır. Vakaların% 99'u bu muhtemelen önemli olmayacak, ancak birçok hücredeki çevirilerle birlikte açısal bir kullanıcı arabiriminde korkunç performansla ilgili bir sorun yaşadım. Kesinlikle uç bir durum, sadece dikkat edilmesi gereken bir şey
tykowale

123

Aslında, bunun yerine translate direktifini kullanmalısınız.

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

Yönerge, eşzamansız yürütme ile ilgilenir ve ayrıca çevirinin dinamik değerleri yoksa kapsamdaki çeviri kimliklerini geri almak için yeterince akıllıdır.

Orada etrafında bir yolu yoktur ve eğer gerçekten Ancak, gerek kullanım $translatedenetleyicisi hizmet, bir aramayı yerleştirilmeli $translateChangeSuccesskullanarak olayı $rootScopeile birlikte $translate.instant()böyle:

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

Öyleyse neden $rootScopeve değil $scope? Bunun nedeni, angular-translate'de olayların , tüm kapsam hiyerarşisi boyunca yayın yapmamız gerekmediğinden , üzerinde $emiteditörlük yapmaktan $rootScopeziyade, $broadcastüzerine $scopeyazılmış olmasıdır.

Neden $translate.instant()ve sadece eşzamansız değil $translate()? Ne zaman $translateChangeSuccessolay tetiklenir, bu nedenle biz sadece kullanabilirsiniz, gerekli çeviri veri yoktur ve hiçbir zaman uyumsuz yürütme (örneğin asenkron yükleyici yürütülmesi için) oluyor emin olduğu $translate.instant()senkron olan ve sadece çeviriler mevcut olduğunu varsayar.

2.8.0 sürümünden beri $translate.onReady(), çeviriler hazır olur olmaz çözülen bir söz veren bir söz de var. Değişiklik günlüğüne bakın .


Filtre yerine çeviri yönergesini kullanırsam herhangi bir performans sorunu olabilir mi? Ayrıca dahili olarak, instant () dönüş değerini izlediğine inanıyorum. Peki mevcut kapsam ortadan kalktığında saatleri kaldırır mı?
Nilesh

Önerinizi kullanmayı denedim, ancak kapsam değişkeninin değeri dinamik olarak değiştiğinde çalışmıyor.
Nilesh

10
Aslında, her zaman yeni saatler ayarladıkları için uygulamanızı yavaşlattıkları için filtrelerden mümkün olduğunca kaçınmak her zaman daha iyidir. Ancak yönerge biraz daha ileri gidiyor. Bir çeviri kimliğinin değerini izlemesinin gerekip gerekmediğini kontrol eder. Bu, uygulamanızı daha iyi gerçekleştirmenizi sağlar. Biraz daha derinlemesine bakabilmem için beni ona bağlar mısın?
Pascal Precht

Plunk: plnkr.co/edit/j53xL1EdJ6bT20ldlhxr Muhtemelen benim örneğimde , yönerge değeri izlememeye karar veriyor. Ayrıca ayrı bir sorun olarak, özel hata işleyicim anahtar bulunmazsa çağrılır, ancak döndürülen dizeyi göstermez. Onun için başka bir şey yapacağım.
Nilesh

2
@PascalPrecht Sadece bir soru, çeviri ile bir kez bağlama kullanmak iyi bir uygulama mı? Bunun gibi {{::'HELLO_WORLD | translate}}'.
Zunair Zubair

5

Denetleyicide çeviri yapmak için $translatehizmeti kullanabilirsiniz :

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

Bu ifade yalnızca denetleyici etkinleştirildiğinde çeviriyi yapar, ancak dildeki çalışma zamanı değişikliğini algılamaz. Bu davranışı başarmak için $rootScopeolayı dinleyebilir $translateChangeSuccessve aynı çeviriyi orada yapabilirsiniz:

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

Elbette, $translatehizmeti bir yöntemde sarmalayabilir ve onu denetleyicide ve $translateChangeSucessdinleyicide çağırabilirsiniz .


1

Olan şu ki, Angular-translate ifadeyi olay tabanlı bir sistemle izliyor ve diğer herhangi bir bağlama veya iki yönlü bağlama durumunda olduğu gibi, veriler alındığında bir olay tetikleniyor ve değer değişiyor. açıkçası çeviri için çalışmıyor. Sayfadaki diğer dinamik verilerden farklı olarak çeviri verileri, elbette, kullanıcıya hemen gösterilmelidir. Sayfa yüklendikten sonra içeri giremez.

Bu sorunu başarılı bir şekilde ayıklayabilseniz bile, daha büyük sorun, içerilen geliştirme çalışmalarının çok büyük olmasıdır. Bir geliştiricinin sitedeki her dizeyi manuel olarak çıkarması, bir .json dosyasına koyması, dize koduyla manuel olarak referans vermesi gerekir (örn. Bu durumda 'pageTitle'). Çoğu ticari site, bunun olması gereken binlerce diziye sahiptir. Ve bu sadece başlangıç. Artık bazılarında temel metin değiştiğinde çevirileri senkronize tutmak için bir sisteme, çeviri dosyalarını çeşitli çevirmenlere göndermek, bunları yapıya yeniden entegre etmek, çevirmenlerin görebilmesi için siteyi yeniden dağıtmak için bir sisteme ihtiyacınız var. bağlamdaki değişiklikleri ve devam ediyor.

Ayrıca, bu 'bağlayıcı', olay tabanlı bir sistem olduğundan, sayfadaki her bir dize için bir olay tetikleniyor, bu yalnızca sayfayı dönüştürmenin daha yavaş bir yolu olmakla kalmıyor, aynı zamanda sayfadaki tüm eylemleri de yavaşlatabiliyor. çok sayıda olay eklemeye başlarsanız.

Her neyse, işlem sonrası çeviri platformu kullanmak bana daha mantıklı geliyor. Örneğin, GlobalizeIt kullanarak, bir çevirmen sitedeki bir sayfaya gidebilir ve metni doğrudan sayfadaki dilleri için düzenlemeye başlayabilir ve işte bu: https://www.globalizeit.com/HowItWorks . Programlamaya gerek yok (programla genişletilebilir olsa da), Angular ile kolayca entegre olur: https://www.globalizeit.com/Translate/Angular , sayfanın dönüşümü tek seferde gerçekleşir ve her zaman çevrilmiş metni sayfanın ilk görüntüsü.

Tam açıklama: Ben bir kurucu ortağım :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.