Skip to content

Instantly share code, notes, and snippets.

@rvillars
Last active February 25, 2020 09:26
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rvillars/6422287 to your computer and use it in GitHub Desktop.
Save rvillars/6422287 to your computer and use it in GitHub Desktop.
[Angular Translate Bunlde] Spring bundle based translations (i18n) for AngularJS applications with angular-translate

angular-translate with Spring bundles

Synopsis

AngularJS itself doesn't provide any features to translate the texts of your application to different languages and switching the language right on the page. Fornutalty there is now another open-source project called angular-translate that implements the needed functionalities.

AnularJS proposes a technologiy where as much as possible application behevior is exeuted on the client (the browser). So it makes sense to hold translated texts clientside and enrich the static templates with the transalted texts there.

Spring message bundles in the opposite are a collection of serverside key=value files that hold the translated texts each for one language. A well known and widly used pattern.

The following short examples show, how your application can be configured so that angular-translate can asynchronly get the serialized Spring message bundles from the server as JSON code and use them as clientside transaltion sources.

If you want so see a full fletched project example where this is implemented please see: https://github.com/rvillars/bookapp-rest/tree/angular-translate.

Technologies used:

  • SpringMVC
  • AngularJS
  • angular-translate

Details

Unfortunatly the default implementation of the message source of Spring doesn't provide a method to get all properties of a given locale. To correct this we have to write or own by deriving from ReloadableResourceBundleMessageSource and add the following method:

public Properties getAllProperties(Locale locale) {
    clearCacheIncludingAncestors();
    PropertiesHolder propertiesHolder = getMergedProperties(locale);
    Properties properties = propertiesHolder.getProperties();
    return properties;
}

angular-translate will get the translations automatically and asynchronly by by using an url loader:

$translateProvider.useUrlLoader('/rest/messageBundle');

The url will be called by anguar-translate with the request query parameter ?lang=LANGUAGE where LANGUAGE is the language identifier given in the $translate.uses(LANGUAGE) service of angular-translate. As serverside part for this request we will implement a very simple controller that returns the propperties for the given locale code by using our new message bundle source.

@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public Properties list(@RequestParam String lang) {
    return messageBundle.getAllProperties(new Locale(lang));
}

If Jakson is in the classpath the SpringMVC controller will automatically convert the properties to a JSON format that can be understood by angular-translate.

You can use the local or cookie storages provided by angular-translate to save the language for a given session. If you like a more SpringMVC driven approch you can and the current language to the url as query parameter by using a custom storage like this:

$scope.changeLanguage = function (locale) {
    $translate.uses(locale);
    $location.search('lang', locale);
};

services.factory('UrlLanguageStorage', ['$location', function($location) {
    return {
        set: function (name, value) {},
        get: function (name) {
            return $location.search()['lang']
        }
    };
}]);
var bookapp = angular.module('bookapp', ['controllers', 'services','directives', 'pascalprecht.translate']);
bookapp.config(function ($translateProvider) {
$translateProvider.useUrlLoader('/rest/messageBundle');
$translateProvider.useStorage('UrlLanguageStorage');
$translateProvider.preferredLanguage('en');
$translateProvider.fallbackLanguage('en');
});
<legend translate>book.edit.current</legend>
controllers.controller('LanguageController', ['$scope','$translate','$location', function($scope, $translate, $location) {
$scope.changeLanguage = function (locale) {
$translate.uses(locale);
$location.search('lang', locale);
//window.location.href = $location.absUrl();
//window.location.reload();
};
}]);
<ul ng-controller="LanguageController">
<li><a href="" ng-click="changeLanguage('en')">en</a>
<li><a href="" ng-click="changeLanguage('de')">de</a>
</ul>
book.edit.current=Current Book
<mvc:annotation-driven/>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"/>
</bean>
</mvc:interceptors>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en" />
</bean>
<bean id="messageSource" class="ch.bfh.swos.bookapp.rest.common.SerializableResourceBundleMessageSource">
<property name="basename">
<value>classpath:/messages</value>
</property>
</bean>
@Controller
@RequestMapping("/messageBundle")
public class SerializableMessageBundleController {
@Inject
SerializableResourceBundleMessageSource messageBundle;
/**
* ReadAll
*/
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
public Properties list(@RequestParam String lang) {
return messageBundle.getAllProperties(new Locale(lang));
}
}
public class SerializableResourceBundleMessageSource extends ReloadableResourceBundleMessageSource {
public Properties getAllProperties(Locale locale) {
clearCacheIncludingAncestors();
PropertiesHolder propertiesHolder = getMergedProperties(locale);
Properties properties = propertiesHolder.getProperties();
return properties;
}
}
services.factory('UrlLanguageStorage', ['$location', function($location) {
return {
set: function (name, value) {},
get: function (name) {
return $location.search()['lang']
}
};
}]);
@ThomasVanThillo
Copy link

How can you change your inputfields text with i18n??
I have and input field with this code??

@mayurihiwale
Copy link

hu

@fernaspiazu
Copy link

The example has been helpful for me, even if it's a little bit over-engineered :-)
I'd correct controller.js, $translate.use(locale) instead $translate.uses(locale)

@mariofink
Copy link

This was really helpful! Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment