Double translating using the AngularJS angular-translate library
For those of us who're still working with applications using AngularJS 1.x (it's still in long-term support for nearly 2 years so plenty of time to plan a migration!), localising strings in the user interface using the angular-translate library seems to be the way to go, or at least it's the library I've have exposure to anyway!
One problem I've recently needed to solve is injecting the localised names of fields into validation messages that are also localised. These messages are fairly generic, e.g. You must enter at least 3 characters for the field 'Some Field', with the same messages used throughout the application with differing minimum numbers of characters and field names plugged in as appropriate. It turns out that there is a way to do this! Starting with the assumption that your application already has angular-translate plugged in and running, a simple example of the markup in question would look a little like this:
<div translate="FIELD_LBL"></div> <ul> <li translate="VALIDATION_MESSAGE" translate-values="{'field': 'The field'}"></li> </ul>
That markup uses two translations to substitute in the text for FIELD_LBL and VALIDATION_MESSAGE, which are defined as:
app.config(function ($translateProvider) { $translateProvider.translations('en', { FIELD_LBL: 'Field Label', VALIDATION_MESSAGE: 'The value entered into \'{{field}}\' is not valid' });; $translateProvider.preferredLanguage('en'); });
With that done, running up the app shows:
So, both of the translations are being substituted which is just what we're after, but at the moment the string that's interpolated is static based on the value defined in the markup. It's a small step to convert this markup to:
<div> <div translate="FIELD_LBL"></div> <h1> {{ vm.Something }} </h1> <ul> <li translate="VALIDATION_MESSAGE" translate-values="{'field': '{{ vm.label | translate }}'}"></li> </ul> </div>
And then add a little to the controller:
controller: [function () { var vm = this; vm.label = 'FIELD_LBL'; }],
Of course, in a production app vm.label wouldn't be hard-coded in the controller, it'd be passed in, but with this in place we do get the desired output which is a translated string interpolated into another translated string: