I'm using angular-translate and angular-translate-loader-partial to translate an AngularJS application. angular-translate provides directives, filters and a service to get texts translated. It provides a few ways to load translation files. angular-translate-loader-partial is one loader that allows you to load the necessary translation files when you need them. This is what I'm using right now. The document from https://angular-translate.github.io/ covers all of them. But there's a gap in the end to end scenario. The translation fails.
Here's the summary of what need to be done from the document:
-
- Tell the translate provider to use the partial loader and the translation file path pattern.
$translateProvider.useLoader('$translatePartialLoader', { urlTemplate: '/i18n/{part}/{lang}.json' });
urlTemplate tells the loader how to find the translation file. In this example, it's in /i18n/ directory. {part} will be provided later. {lang} is the language you use. It's set later too.
- Set the preferred language and fall back languages in your module configuration function. e.g.
$translateProvider.preferredLanguage('zh_CN').fallbackLanguage('en_US');
That tells the translate provider to look for translation for Simplified Chinese, and fall back to English if it's not found. This will set the {lang} for the loader.
- Load the translation file and refresh translation tables. This is done by
$translatePartialLoader.addPart('contact'); $translate.refresh();
The translation file for 'contact' will be loaded. It sets the {part} in urlTemplate. So the translation file path is /i18n/contact/zh_CN.json.
$translate.refresh() must be called every time a part is added. The document also suggests to refresh translation tables in event $translatePartialLoaderStructureChanged.
app.run(function ($rootScope, $translate) { $rootScope.$on('$translatePartialLoaderStructureChanged', function () { $translate.refresh(); }); });
- Tell the translate provider to use the partial loader and the translation file path pattern.
That seems straightforward. Everyone can add those code and start to use directives, filters or the service to translate their own applications. But that won't just work.
Both $translatePartialLoader.addPart() and $translate.refresh() are asynchronous. When you use directives, filters or the service to ask for translation for a given id, the translation table may not be loaded! This is what happens in my application. The document doesn't warn it, and doesn't present a solution either. The solution is simple, however. Both loadPart() and refresh() return promises. You have to ask $translate to get the translation after the promise refresh() is resolved. So you can do something similar to:
$translate.refresh().then(function() {
$translate('TRANSLATE_ID').then(function(data) {
$scope.SomeLabel = data;
});
});
This is tedious. Every time when you try to translate something, you have to double check whether the translation table is ready. And you cannot use directives and filters. Because when the translation table becomes ready, it won't update the directives and filters. Here's an example to demonstrate the solution: http://plnkr.co/edit/MrliEBMed17f3yqeRqz3
angular-translate is flexible in loaders and how to do translation (directives, filters or services). But there are some undocumented limitations (or bugs). When you use partial loader, you cannot use directives and filters. But at least, there's always another way of doing it. angular-translate still doesn't fail at getting the work done.