I18N z angular-gettext
I18N aplikacji może być niemałym problemem jeśli się o niej nie pomyśli zawczasu. W tym wpisie dowiesz się jak można przeprowadzić łatwo i przyjemnie proces internacjonalizacji w AngularJS.
Internacjonalizacja to takie przygotowanie aplikacji, aby jej późniejsze przystosowanie dla odbiorców posługujących się innym językiem było jak najłatwiejsze i jak najbardziej ustandaryzowane w ramach aplikacji. Dzięki I18N możemy otworzyć naszą aplikację na użytkowników którzy nie posługują się jej natywnym językiem.
Biblioteka angular-gettext
Biblioteka angular-gettext pozwala w łatwy sposób przystosować treść szablonów, dyrektyw, a nawet komunikatów generowanych w kontrolerach frameworka AngularJS do pracy w wielojęzycznym środowisku.
Instalacja biblioteki
Instalacja biblioteki w projekcie polega na wydaniu kilku poleceń:
bower install --save angular-gettext
npm install grunt-angular-gettext --save-dev
Po ich wydaniu mamy bibliotekę dołączoną do zależności naszego projektu. Należy jeszcze ją odpowiednio skonfigurować.
Konfiguracja biblioteki i narzędzi pomocniczych
Aby dodać przygotowane przez autora biblioteki pomocnicze narzędzia do grunta należy, w pliku Gruntfile.js, wprowadzić następujące zmiany:
grunt.loadNpmTasks('grunt-angular-gettext');
Powyższe polecenie zaimportuje nam zestaw wbudowanych w angular-gettext narzędzi, które także należy skonfigurować:
nggettext_extract: {
pot: {
options: {
attributes: ['placeholder']
},
files: {
'app/locale/en_UK/LC_MESSAGES/ddf.pot': ['app/partials/*.html']
}
},
}
Narzędzie nggettext_compile służy do wyszukiwania w kodzie aplikacji tekstów do przetłumaczenia. W powyższej konfiguracji dodajemy dodatkowy atrybut HTML, którego wartość ma być również brana pod uwagę podczas analizowania kodu (o tym jak oznaczać teksty do tłumaczenia a także o własnych dyrektywach przeczytasz poniżej). Wskazujemy także lokalizację pliku POT, czyli szablonu dla wszystkich tłumaczeń oraz lokalizację, która ma zostać przeszukana pod kątem tekstów oznaczonych jako do przetłumaczenia.
nggettext_compile: {
all: {
files: {
'app/scripts/translations.js': ['app/locale/**/*.po']
}
},
},
Narzędzie nggettext_extract służy do kompilacji przygotowanych plików PO z tłumaczeniami do kodu JS. Wskazujemy tu ścieżkę w której ma zostać utworzony skompilowany plik oraz ścieżkę w której znajdują się pliki z gotowymi tłumaczeniami.
Ponad to, należy w pliku index.html załadować bibliotekę oraz plik z tłumaczeniami, najlepiej przed kodem samej aplikacji:
<script src="bower_components/angular-gettext/dist/angular-gettext.js"></script>
<script src="scripts/translations.js"></script>
Kolejnym krokiem jest wstrzyknięcie modułu do naszej aplikacji, np:
var dependencies = ['gettext', 'ionic', 'ui.router', 'DrugDoseFrameworkControllers'];
var app = angular.module('DrugDoseFrameworkApp', dependencies);
Możemy także uzależnić język aplikacji od ustawień przeglądarki klienta:
app.run(function ($ionicPlatform, gettextCatalog) {
switch (window.navigator.language.substr(0, 2)) {
case 'pl':
gettextCatalog.setCurrentLanguage('pl_PL');
break;
case 'de':
gettextCatalog.setCurrentLanguage('de_DE');
break;
}
};
lub podpiąć metodę setCurrentLanguage pod jakiś element interfejsu umożliwiając tym samym zmianę języka samemu użytkownikowi, wedle jego upodobań.
Przygotowanie tekstów
Biblioteka angular-gettext definiuje kilka sposobów w jaki możemy przygotować teksty do tłumaczeń tak, aby mogły zostać przez nie odnalezione. Pierwszym z nich jest otoczenie tekstu znacznikiem <translate>:
<translate>sentence to translate</translate>
Jeśli nasz tekst znajduje się już w innym znaczniku nie musimy wprowadzać kolejnego, możemy użyć atrybutu translate:
<span translate>sentence to translate</span>
Innym pomysłem może być użycie filtru translate:
{{ 'sentence to translate' | translate }}
Możemy także przygotować własną dyrektywę wspierającą tłumaczenia:
app.directive('placeholder', ['gettextCatalog', function (gettextCatalog) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.attr('placeholder', gettextCatalog.getString(attrs.placeholder));
}
};
}]);
Jeśli chcemy przetłumaczyć coś w kontrolerze to należy do tego wykorzystać metodę getString, jak pokazałem w powyższym przykładzie.
Biblioteka angular-gettext wspiera także takie zaawansowane opcje jak: komentarze do tłumaczeń, kontekst tłumaczeń (rzeczownik, czasownik, itp.), tłumaczenia w liczbie mnogiej, interpolację zmiennych w tłumaczone teksty, lazy-loading tłumaczeń. O tym wszystkim możesz poczytać w bardzo dobrej dokumentacji biblioteki.
Tłumaczenie tekstów
Gdy mamy już oznaczony tekst który chcemy przetłumaczyć, nadchodzi pora aby się za to zabrać. Na szczęście nie musimy go teraz szukać ponownie i przepisywać do plików z tłumaczeniami. Należy wykonać komendę grunt nggettext_extract. W lokalizacji wskazanej w konfiguracji tego narzędzia znajdziemy plik POT, a w nim wszystkie znalezione teksty, wraz z ich lokalizacją w projekcie. W kolejnym kroku należy skopiować szablon, zmieniając mu rozszerzenie na PO, do lokalizacji tłumaczeń które chcemy obsługiwać (nazwa pliku może być dowolna), np:
- app
- locale
- en_UK
- LC_MESSAGES
- ddf.pot
- LC_MESSAGES
- pl_PL
- LC_MESSAGES
- ddf.po
- LC_MESSAGES
- de_DE
- LC_MESSAGES
- ddf.po
- LC_MESSAGES
- en_UK
- locale
Do pliku ddf.po z polskimi tłumaczeniami należy skopiować zawartość szablonu POT. Oprócz samego tłumaczenia możemy także uzupełnić nagłówki tego pliku, zgodnie z dokumentacją formatu PO. Nie jest to wymagane, ale może pomóc przyszłym tłumaczom naszej aplikacji.
Gdy mamy już wszystko przetłumaczone należy skompilować to do pliku JS. Pomoże nam w tym polecenie grunt nggettext_compile. Po jego wykonaniu w pliku translations.js powinno znaleźć się coś podobnego do :
angular.module('gettext').run(['gettextCatalog', function (gettextCatalog) {
/* jshint -W100 */
gettextCatalog.setStrings('de_DE', {
"Type drug name":"Schreiben Sie die Medikamentennamen",
"calculate":"berechnen"
});
gettextCatalog.setStrings('pl_PL', {
"Type drug name":"Wpisz nazwę leku",
"calculate":"oblicz"
});
/* jshint +W100 */
}]);
(linie zostały celowo zwinięte dla lepszej czytelności, normalnie wszystko jest zminimalizowane).
Od teraz tłumaczenia są dostępne dla aplikacji. Jeśli zmiana języka aplikacji oparta jest o window.navigator.language to możemy wszystko łatwo przetestować zmieniając ustawienia języka w opcjach przeglądarki.
Opisana tu procedura została przeze mnie wdrożona w mojej konkursowej aplikacji DDF. Jak to zrobiłem możesz zobaczyć na GitHubie. W razie problemów napisz komentarz - postaram się pomóc.