I've searched a bit on the web but haven't really found a concrete solution to internationalize an application running ExtJS & Spring MVC. Currently (for testing), I define global javascript variables in the JSP's & assign the string literals using JSTL tags.
Has anyone had any success in coming up w/ a clear/clean/flexible solution on this?
Any thoughts are really appreciated. TIA.
There are 3 types of strings that you should translate in an application
Static strings on you page -> as Adam said using a template is a good idea. MVC can solve the problem. So you keep all your strings in a db or a properties file.
Error messages strings that are send to Ext J.S -> Here you have two solutions, either you allow Ext J.S to handle them , so this means that you have js files with the translations loaded
OR
on the MVC before you send the reply you add the translation on your response
Values from a db table that must be translated, e.g car parts. In this case you keep the key in you car_parts table and the translations in a properties file or on a translation table in db.
On my current app I perform the translation on the MVC level and I keep the translations on the db. The advantage are
1. The translation logic is one place the MVC and not split.
2. Your translations are in one place and whenever you make an error on a translation you do not have to make a new release, you just update the db OR you provide a form on the application admins to do it on their own. Backup of the translation table is required!!!
This is how it is done in my application, which is using Pylons, Ext JS and a template engine called Mako.
I'm treating JavaScript files as templates. I keep each class in a separate file and use a defined by me function require() to handle dependencies. My server processes these templates, handles dependencies, joins them together and compresses. Those templates contain calls to gettext-like function "_" e.g.:
window.setTitle("${_('My title')}");
These templates are regular Mako templates and can be preprocessed by a gettext-like utility to create .po files. The .po generator I'm using (Babel) puts positions of found strings as comments inside a .po file, which is convenient for me, because I know where the string appeared.
Take a look at the Spring MVC Ajax example frpm Spring.
if you use JSP views, you can use fmt tag library and resource bundles.
If you use Velocity views, use #springMessage('my.key') as explained in Spring documentation.
Related
A website I am currently developing with Neos / Flow includes a self-developed shop system implemented as a Flow Plugin. The products, variants and vouchers are kept as domain models.
Since the customer wants to provide their website in different languages I need to find a way to manage translations for the domain objects.
I cannot find a way which is baked into Neos/Flow so my first thought was to simply insert translation identifiers inside the translatable fields (description & stuff like that) which are then used inside the view with the translation viewhelper. This would work totally fine if the customer would not want to edit those fields by themselves.
My next idea was to just implement an extra field for each language-dimension and each translatable field (like description_en; description_es, …). But this would be the worst approach in terms of maintainability and changeability.
I usually worked on TYPO3 projects where translation of domain objects is really easy and working out of the box. So this experience inside Neos is very frustrating.
Does anybody came across a similar problem or even has found a solution to this?
whenever we've got the requirement to have multi-language content so far, we've solved that, by storing the data within the Neos Content Repository. This way language handling aka dimensions work out of the box. Also, building a UI for that records is very easy by using inline editing or the inspector of the content module.
Note, that storing data in the CR does not necessarily means, that you have to store it under the /site root node. You could also add a new root node /products to store your products.
You could have a look at https://github.com/neos/metadata-contentrepositoryadapter where meta data is stored under its own root.
Hope that helps,
Cheers, Daniel
For the record, something like that could also be achieved with the Doctrine Translateable extension in pure Flow:
https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/translatable.md
See http://flowframework.readthedocs.io/en/stable/TheDefinitiveGuide/PartIII/Persistence.html#on-the-doctrine-event-system on how to activate the extension in Flow.
However, the cleaner aproach indeed is to actually separate domain model and content (unless you build a CMS and the content is your domain ;)
I'd like to set up a simple server with a DB containing keys and translations for different messages. My different other applications would request this server, which would give them only the list of messages concerning them in, let's say, JSON. The different apps would then "compile" this list into several classic i18n .properties files they could use.
The advantage is that translation service is decorrelated from the different applications nofile has to be re-deployed or even updated on the applications servers. I could even set up a GUI to siplify operations on the messages.
Moreover, I found in the different projects I worked on that the manual maintenance of properties files can get really messy overtime (labels missing for one locale and it's really hard to find which one when the files get big, we used to use a central excel file to manage and generate .properties files but it's just a giant mess).
Anyway, do you think it's a good / feasable idea? Any insight on how to do it? How can I transform JSON into .properties easily? (is there tools for that?) (or should I use another format than JSON?). Thanks for any comment :)
To be blunt, I don't know why you want to reinvent the wheel and make it a bit more square-like.
Is it feasible? Yes it is.
Should you do it? No.
That is, you may serve translations with JSON, there is nothing wrong with that. It often makes sense.
What does not, is to put all the translations in a database. If you do that, I wish the localizers all the best.
It is just way easier to fix the translation in the standard text file (especially if it is UTF-8 encoded...) than in the database.
Talking about translations, you may want to (or be forced) to hire Translation Service Providers. These guys have there own Translation Memory systems as well as Machine Translation systems and guess what? They don't care about your database, nor GUI. They want to handle translations the standard way, that is using typical file formats. Java properties files happens to be one of them. Database scripts are not...
Now, on how to convert Java properties files to JSON. Assuming you are using Java, it's fairly straightforward. What you need first is to read your properties file:
// you somehow need to detect a Locale
ResourceBundle messages = ResourceBundle.getBundle("messages", locale);
The way you detect a Locale depends on the context. For instance, you may want to assign one in a user profile (allowing users to change their regional preferences), or you may want to create a web service that take language tag as a parameter. In both cases it would probably go down to this:
Locale locale = Locale.forLanguageTag(langTag);
Where langTag is a String containing your desired language tag (either read from user profile, which is recommended, or read as a parameter of a call to the web service).
When you have your resource file read, all you need to do is to take a desired portion and put it to the map:
Map<String, String> keyToTranslation = new HashMap<>();
for (String key : messages.keySet()) {
// filter the key somehow, for example:
// if (key.startsWith(moduleName))
keyToTranslation.put(key, messages.getString(key));
}
Then you can use Jackson to convert the map into JSON. Actually, any JAX-RS compatible library like RESTEasy would use it internally to perform the conversion.
It is of course possible to do this kind of conversion using completely different technology stack, i.e. using Node.js. However, there are few things to keep in mind:
Users may have a list of their preferred languages, which they advertise in a HTTP Accept-Language header. It is desirable to return a translation based on this list.
There is something called resource loading fallback. For instance, you may have no translations for Canadian version of French, but you may have regular French translations, which you may want to return to a user. ResourceBundle handles this for you, if you want to use something else, it is good to keep this in a back of your head.
You can use the i18n Maven Plugin to handle internationalization. It's very simple to configure your project. You render different output format files.
JSON
XML
Properties
Check out the sample i18n resource files.
I would develop my CakePHP application in the most reusable way. I'd like to treat it as webservices, so I don't want to strictly bind controller with view. My idea is: controller just returns json info, the view calls the controller and get the json and make html output.
How can I realize that? Could be a good approch, developing pages rather than views, and inside that pages call the webservices previously developed.
You can even forget about creating view files, using $this->set('_serialize', array('people')); in your PeopleController::show()
Well Cake is kinda' works like this "out of the box". You can use Router::parseExtensions(); to define what type of data you would like to serve. For example in app/Config/routes.php:
Router::parseExtensions('xml','json');
This will make it possible to detect what kind of request is incoming. For example if someone requests:
www.example.com/people/list.json or www.example.com/people/list.xml, in your PeopleController's list() method you'd be able to detect what kind of resource is being requested - json or xml, or of course any other
extension you define. This is what the RequestHandlerComponent is used for. You can check if it is xml for example:
if($this->RequestHandler->isXml()) {
//Some code
}
The different extensions are only different representation of the data, so it shouldn't matter what exactly you're serving. From v2.1 Cake will automatically switch the view class when it sees a JSON or XML request, which takes us to the new JSON and XML views.
All you will have to do is provide the views in the appropriate places.
In View/People (as for this example) you would have:
..View/People/
list.ctp
xml/
list.ctp - XML view
json/
list.ctp - JSON view
I'm new in Spring MVC, I just started my first project and I'm doing some research to be sure to set it up in a proper way (should work in the long-term!).
I already know that for a part of the project, I will need to manually change small fragments of the page through Ajax. I know it's possible to change part of the page (using Tiles). What I really need, though, is for example to change a single line in a table containing dynamically generated data (i.e. data coming from the database).
Can you suggest anything?
I don't want to use JSF or Spring JS.
Thank you.
You have at least two choices:
render on the server, send the update html snippet to the brower and use JavaScript to replace them
send an AJAX request to the server, but this time return only the data (JSON) and the "render" the table line in the browser (or just update some pices of text)
For the fist choice you need a dedicated jsp file (and tiles configuration) to render only a single line. As fare as I know, there is no technical support.
What you can do, to reduce the amount of duplicated code is to use that single line rendering jsp in like in include in the one that renders the complete table.
Of course instead of using JSP to render the single line you can also use the Java Method that handles the request, and make it returning the html string.
In my application, I have both html and JSP files.
I need them both to pass through the controller.
But it is not possible to use multiple internalViewResolvers in an application . Chaining is not possible in the case of internalViewResolvers since even if specify the "Order" values, this will be ignored and this resolver will always come up last.
There are two options:
1)To use a ResourceBundleViewResolver and have a properties file explicitly mapping each of the request. This involves the overhead of reading from properties file.
2)Rename the html files as ".jsp" (i.e) though they are simple HTML pages rename it as .jsp to fix this. - This will involve the overhead of "JSP" to servlet conversion . Though pages does not have dynamic content, marking them as "JSP" seems an overhead for me
Please advise which is going to be a better solution.
Actually, you don't need to run both through the controller if the HTML files are static. If that is the case, you can use the mvs:resources tag to optimize retrievel. See my post on this topic. In your case, you would just add *.html to the resources list.
I wouldn't worry about the overhead. Neither of these options would take a lot of cpu or memory.
I would go with the second option as then you won't have to keep the resourcebundle updated when adding new html files.