Circumstances
I'm using Spring Boot with Thymeleaf for populating my HTML template files and get back the result as a String. For that I used SpringTemplateEngine.
The code looks like this
Context context = new Context();
context.setVariables(myProperties);
return templateEngine.process(htmlTemplateName, context);
The problem
For i18n I have a different approach. My thymeleaf HTML template namings are the following (similar to Freemaker templating):
templatename_default_FOO.html
templatename_en_EN_FOO.html
templatename_de_DE_FOO.html
templatename_default_ANOTHER.html
templatename_en_EN_ANOTHER.html
templatename_de_DE_ANOTHER.html
The convention is:
templatename - is the name of the template
default/en_EN/de_DE - is the locale which I get from an API - The locale may not exists in the templates, in this case I want to use the default template with the matching user parameter
FOO/ANOTHER - different parameter values which the users sets - they exists in atleast one template's name (the default should contain it)
Previously I used ResourceBundles to get the templates by locale if existed, otherwise the default value was automatically chosen. However with Thymeleaf implementation I don't know how to implement the same mechanics, because currently I get the template by providing the full name. If I add a locale which not exists I don't get back the default template.
Question
I know that i18n in Thymeleaf is done through language.properties, but in my case I would need a function where I provide the template name, the locale and the user parameter and I get back the specified HTML file if exists and if not the default HTML file with the matching user parameter.
Something similar:
public String getTemplate(Map<String, Object> myProperties, String templateName, Locale locale, String userParameter) {
Context context = new Context();
context.setVariables(myProperties);
return templateEngine.process(templateName, locale, userParameter context);
}
Is that possible somehow or I should use language.properties? Or I should write custom logic to check if the template not exists go with the default one?
Thanks in advance
Related
What are the approaches to map i18n translated url paths?
For example lets say we talk about the follwing url (for locale en):
www.foo.tld/car/manufacturer
In german (de) this url would be
www.foo.tld/auto/hersteller
What i know about Controller RequestMapping i could use severel values to map these url's for one method like
#GetMapping(value={"/car/manufacturer/", "/auto/hersteller/"})
More seo optimized would be probably something with the current locale in the path like
#GetMapping(value={"/en/car/manufacturer/", "/de/auto/hersteller/"})
...but i dont want to start a discussion what would be the best uri seo wise.
This isn't so bad if to use only a few Locales/Languages but i would like to make this somehow dynamic.
Currently im using messages_xx.properties to map url path parts for generating urls in my application, like:
messages.properties
uri.car=car
uri.manufacturer=manufacturer
messages_de.properties
uri.car=auto
uri.manufacturer=hersteller
Im using them already for building links repecting the user locale which works fine.
What im searching now for is a elegant, less error prune way to map these urls in my controller. If i would change for example a value for the key uri.car and would have a static RequestMapping in my controller like in the example above i also need to change it there (if i dont forget!).
Also if i would like to add support for another language i would need to search in all controller and check if i need to add another value mapping.
Is there a smarter way how to map i18n path parts in Spring controllers, ideally respecting a request locale and resolve the path string with the help of messages_xx.properties?
Or would be a filter the way to go extracting path parts according to the requested locale and use internally only one language for mapping urls?
Supose that you have an EN message.properties and a DE message.properties with the following property:
url.car=/car/manufacturer/ in the EN
url.car=/auto/hersteller/ in the DE
In your #Controller you can get easily this properties configuring your messageSource and using it to get the properties:
Inject your configured MessageSource to allow Spring resolve the messages:
#Autowired
private MessageSource messageSource;
Then you can get all the properties from your message.properties file:
String url= messageSource.getMessage("url.car", put_here_your_locale);
I am working on a Spring 3 project and I need to format a Long field for Turkish currency. The default Locale of the application is en_US. I used the #NumberFormat annotation as below:
#NumberFormat(style=NumberFormat.Style.CURRENCY)
public Long getBudgetLimit() {
return budgetLimit;
}
The annotation works and formats the form field in English locale. However I need to use Turkish locale for this field. Is there a way to set the locale of a single field or a page different than the application's locale?
Edit: I just found the answer myself. Use a custom editor in the controller as below:
NumberFormat numberFormat = NumberFormat.getNumberInstance(new Locale("tr","TR"));
dataBinder.registerCustomEditor(Long.class, new CustomNumberEditor(Long.class,numberFormat, true));
and do not use the #NumberFormat annotation. For same reason it gave an error for me.
There are many ways but you could for example register a custom implementation of AnnotationFormatterFactory<NumberFormat> as a bean which would allow you to handle the formatting manually. This is documentented in the Spring documentation section 6.6. The example in the documentation even handles the use case of adjusting #NumberFormat's behavior.
I have a date format at I wish to set globally for my jsp fmt tag to use.
May I know what is right approach to perform this?
I will wish to configure this value in future
pattern = "dd-MM-yyyy kkm"
I have read the following:
How do I create a global JSP variable that I can access across multiple pages or inside frames/iframes?
I think using applicationContext is right approach. You can set your date format at your "welcomepage.jsp",
String pattern = "dd-MM-yyyy kkm";
application.setAttribute("ApplicationPattern",pattern);
get and use the same format wherever required.
String pattern2 =(String)getServletContext().getAttribute("ApplicationPattern");
If you want to set the default data-format pattern for entire app, you could use ServletContext.setAttribute(), but you need a place to do this work, set it in a jsp page or use a initialize filter for your app.
Or you create a Utlitiy class with a static method(field) definition to get the default pattern, then from your fmt
tag use a method call to reference the default pattern
Is it possible to have the Help Page sample generator ignore certain properties of a particular type?
For example, we use the same DTO for object Request and Response messages, for both POST and PUT requests. When user is POSTing a model (creating a new record) they don't need to provide the ID field.
But once its created and we serialize the new record into the response body, the ID field is included and returned to the client.
So in the POST request sample, I don't want the ID field to be displayed because for post request it doesn't make sense.
But the POST response sample, I do want the ID field displayed...
I am aware that there is the ApiExplorerSettings attribute which can be applied to a Class or Method...but is there anything similar for a Property?
Something like this would be great:
public class MyDTO
{
[ApiExplorerSettings(IgnoreForRequestApi = true, IgnoreForResponseApi = false)]
public int Id { get; set; }
// Other properties omitted for brevity...
}
Using the following annotation I've successfully hidden a property from the generation!
[ApiExplorerSettings(IgnoreApi = true)]
No, there isn't a similar option for a property. HelpPage uses formatter instances configured on the application to serialize the samples and as you can imagine the formatters must not have this knowledge within themselves.
Regarding workarounds:
a. You could explicitly set the raw sample for a particular action's requestsample via the SetSampleRequest extension of HttpRequestMessage. You should be able to see some examples about this in the file at *Areas\HelpPage\App_Start\HelpPageConfig.cs*.
b. In the file Areas\HelpPage\SampleGeneration\HelpPageSampleGenerator.cs, there is a method called WriteSampleObjectUsingFormatter which uses the application's formatter instances to write the samples. Here you would need to create new formatter instances having similar settings as your normal application has(so that they reflect the exact serialization/deserialization semantics that your application would normally react to when actual requests are made) and then try to hide the properties which you want to. We want to create new instances because we do not want to disturb the normal functioning of the application.
Example: In case of Json, you could create a new Json formatter instance and provide a ContractResolver which can hide the properties. Check this link: http://james.newtonking.com/projects/json/help/html/ConditionalProperties.htm
In case of Xml, I am not sure how we can hide properties without using the IgnoreDataMember attribute and also being non-intrusive.
Currently I would prefer option 'a' as its comparatively a simple workaround than 'b'.
ASP.NET WEB API uses Json.NET for JSON and DataContarctSerailizer for XML formatting so if you add [JsonIgnore] annotations over properties that you do not want included in your serialization should work just fine.
Can I rewrite the session attribute WW_TRANS_I18N_LOCALE in Struts2? I want to set locale in cookies, for future use, because by default session have a timeout of 30 minutes, this is to small amount of time for the locale, if user isn't using the site. I am trying to set WW_TRANS_I18N_LOCALE depending on cookies value, but without any luck, the value remains the same as it is.
I found here a question like mine, but all of my jsp's pass through Actions https://stackoverflow.com/questions/5291271/struts-2-internationalisation-problem , and this is not a solution ..
So you want to change a session value in an action? I'm not clear on the last line, but just implement SessionAware then it should be straight forward. The best place to set the value would probably where ever the user logs in (if any).
Something like...
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;
public class MyAction extends ActionSupport implements SessionAware{
Map<String, Object> session;
#Override
public String execute(){
session.put("WW_TRANS_I18N_LOCALE", "fr");
return SUCCESS;
}
#Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
}
should do. There are aware interfaces for most other scopes see the top of this page: http://struts.apache.org/2.0.11/struts2-core/apidocs/org/apache/struts2/interceptor/package-summary.html
Edit:
Thinking about this I can't recommend using cookies to store the language preferences. But if you were to do this... the default i18n interceptor will check if a parameter called "request_locale" exists and set the value on the session to that value. You don't want a value stored on the session. But since this is how struts2 handles this by default you could do something like the following:
create your own i18n interceptor which is a copy of the existing but removes the language data saved into the session (thus the value pushed into the session, really only exists for the request duration).
create a javascript function which is added to every page (probably through some template system), which after the page has loaded looks for all anchor tags and form tags. In the case of anchor tags is adds the "request_local" parameter to the end from the value that it finds in your cookie, and it will add a hidden field to every form which will also set the "request_local" parameter from the cookie.
I'd probably put a language selection drop down on every page too, which sets the cookie value and then would reload the current page. For an idea of creating such a list (although a drop down would be better than links): Tiles2 Struts Switch Locale
For information on the i18n interceptor: http://struts.apache.org/2.1.2/struts2-core/apidocs/com/opensymphony/xwork2/interceptor/I18nInterceptor.html
For the JS function, since I'm partial to jQuery I'd start with either this: http://plugins.jquery.com/project/jsper
or this...
http://plugins.jquery.com/project/Cookie