Trying to create a possibility for admins to change translations on the current page without editing language files directly.
I'm using angular-translate and I want to catch all translated texts on a current page before interpolation. What I need:
translationId: original-value-without-interpolation
First I changed the translate filter and wrote a custom interpolator to return an object instead of just the interpolated value.
interpolate: function (string, interpolateParams) {
return {
string: string,
interpolateParams: interpolateParams,
translated: $translateDefaultInterpolation.interpolate(string, interpolateParams)
};
}
Then inside the translate filter I was able to access both the translationId
and original-value
.
Soon after that I remembered that I had forgotten everything about directives and who knows what else I might have forgotten that use the same interpolator.
Now it feels like it would be safer to find an alternative where I can catch the translationId
and the original-value
without editing filters and directives.
Is there perhaps a function that I can hook myself to that I haven't found yet?
Bear in mind that I only want to catch the translations on the current page and I need to get them before {{values}} are replaced.
Edit: Apparently I can access to the translations table $translateProvider.translations()
where I can get values before interpolation. Then I would only need to track down all the translations used on the current page. (Edit2: Unable to access the $translationTable at runtime)
I found a solution.
First thing I did was to create a custom loader. Which is based on the default one but it also stores all the loaded translations into an object. Which is later passed on.
Secondly I created a translate
filter and directive. Which are also pretty much based on the provided one put with an addition of:
Filter
angular.module('app')
.filter('translate', ['$parse', '$translate', 'TranslationsHandler', function ($parse, $translate, TranslationsHandler) {
var translateFilter = function (translationId, interpolateParams, interpolation) {
if ( ! angular.isObject(interpolateParams)) {
interpolateParams = $parse(interpolateParams)(this);
}
TranslationsHandler.addViewTranslation($translate.use(), translationId);
return $translate.instant(translationId, interpolateParams, interpolation);
};
// Since AngularJS 1.3, filters which are not stateless (depending at the scope)
// have to explicit define this behavior.
translateFilter.$stateful = true;
return translateFilter;
}]);
Directive
angular.module('app')
.directive('translate', ['TranslationsHandler', '$translate', function (TranslationsHandler, $translate) {
return {
link: function (scope, el, attrs) {
TranslationsHandler.addViewTranslation($translate.use(), attrs.translate);
}
};
}]);
Both of these have the addition of TranslationsHandler.addViewTranslation
Since I mentioned that I'm trying to make it possible to change translations on page the translations object looks like this:
var stuff = {
file: {}, // Data loaded from translation files
server: {}, // Already changed & saved translations but not yet merged with files
changed: {}, // Currently changed translations
current: {}, // Current view translations
merged: {} // All together in this order: file + server + changed
}
// When in translation mode, the merged array is the one passed to angular-translate as the translation table
// Also on state change I clear the current object so that I can fill that up again
// And I use $injector.get('$translate').refresh() this after every blur event on the input to change the translation. This way I am able to display the change on the page.