I'm trying to format a date in a Scala template in Play. So far I've written this:
<p>#DateFormat.getInstance().format(deadline)</p>
Where deadline is the date I'm outputting to the web page. However, this uses the JVM's locale and not the one selected by the user.
My app currently supports two locales, Norwegian (no) and English (en). This works well for messages, but not for Dates. So I tried adding a GlobalSettings to intercept each request as shown below, but apparently it's never invoked:
import java.lang.reflect.Method;
import java.util.Locale;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.LocaleContextHolder;
import play.GlobalSettings;
import play.i18n.Lang;
import play.mvc.Action;
import play.mvc.Http.Request;
public class Global extends GlobalSettings {
#SuppressWarnings("rawtypes")
#Override
public Action onRequest(final Request request, final Method actionMethod) {
LocaleContextHolder.setLocaleContext(new LocaleContext() {
public Locale getLocale() {
Lang preferred = Lang.preferred(request.acceptLanguages());
return preferred.toLocale();
}
});
return super.onRequest(request, actionMethod);
}
}
Does someone have a solution to this problem? Is it a known bug in Play? I'm using version 2.0.4.
Thanks!
I tried estmatic's solution, but it didn't discriminate properly between country variants of the same language, for example if my browser's preferred languages were "en_AU" and "en_US" in that order, then it would only use the "en" part, which resulted in a US-style date (with the month first) rather than an Aussie-style one (with the date first, as is right and proper).
My solution was to create a helper class as follows:
public class Formatter extends Controller {
private static final int DATE_STYLE = LONG;
private static final int TIME_STYLE = SHORT;
/**
* Formats the given Date as a date and time, using the locale of the current
* request's first accepted language.
*
* #param date the date to format (required)
* #return the formatted date
* #see play.mvc.Http.Request#acceptLanguages()
*/
public static String formatDateTime(final Date date) {
final Locale locale = getPreferredLocale();
return DateFormat.getDateTimeInstance(
DATE_STYLE, TIME_STYLE, locale).format(date);
}
private static Locale getPreferredLocale() {
final List<Lang> acceptedLanguages = request().acceptLanguages();
final Lang preferredLanguage = acceptedLanguages.isEmpty() ?
Lang.preferred(acceptedLanguages) : acceptedLanguages.get(0);
return new Locale(preferredLanguage.language(), preferredLanguage.country());
}
}
Then in my Scala templates, all I had to do was use (for example):
#import my.package.Formatter
...
Date = #Formatter.formatDateTime(someDate)
This seems cleaner to me than having a lot of Locale construction logic in the templates.
Well you need to provide the locale when you get your DateFormat instance; otherwise it'll just use the system default locale instead of what Play is getting from the browser.
Something like this seems to work:
#DateFormat.getDateInstance(DateFormat.LONG, (implicitly[Lang]).toLocale).format(deadline)
That implicitly[Lang] bit is basically calling Lang.preferred(request.acceptLanguages() just like you were doing in your onRequest() method.
Related
Java.util.date package is auto correcting date. For ex: if we pass date as "2018-02-35", it automatically changes it to "2018-03-07", which is a valid date.
Basically, the requirement is to validate the user entered date but as the date is getting auto corrected the module was never able to find an incorrect date. (Note: UI validation can't be done due to some special restrictions so the validation has to be done by the middleware system).
Is there a way i can handle this with the same util package or can this be handled through any 3rd party jar? pls advise
Even i faced same issue. But after some research i found that there is method (setLenient()) in the DateFormat class to disable this behaviour.
DateFormat df = new SimpleDateFormat(DATE_FORMAT);
df.setLenient(false);
Java Docs:
Specify whether or not date/time parsing is to be lenient. With lenient parsing, the parser may use heuristics to interpret inputs that do not precisely match this object's format. With strict parsing, inputs must match this object's format.
you can write DateDeserializer
public class DateDeserializer extends JsonDeserializer<Date> {
#Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", getLocale());
format.setLenient(false); // if true, will auto correct the date
// to the next possible valid date
String date = jp.getText();
try {
return format.parse(date);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
private Locale getLocale() {
Locale locale = (LocaleContextHolder.getLocale() != null) ? LocaleContextHolder.getLocale() : Locale.getDefault();
return locale;
}
}
And then annotate your date property in the media class with this DateDeserializer. You can also use dateSerializer to serialize the object back to Json format. Example below
#JsonSerialize(using=DateSerializer.class)
#JsonDeserialize(using=DateDeserializer.class)
private Date startDate;
Here's my problem. I need to generate PDF in particular language chosen by user. Some informations are in language.properties files and I cannot manage to read other files than the current site language.
For example current language is Spanish and User select German. I'd like to read language_de.properties.
I've tried to use:
String Lang=LanguageUtil.get(LanguageUtil.getLocale('de'), "Mykey");
but without sucess, it always returns "Mykey"
If I use :
String Lang=LanguageUtil.get(HttpServletRequest, "Mykey");
It works, but It's the site language and not the one I want.
Any Ideas?
One option is that you have forgotten to define de_DE in your portal-ext.properties for locales.enabled:
#
# Specify the locales that are enabled by default.
#
locales.enabled=en_US,de_DE,es_ES
Another possibility is that the locale is not enabled for your portal instance. You should check that in the admin UI of your instance.
In both cases LanguageUtil.getLocale('de') will return null - and this will return the given key from LanguageUtil.get. You can verify that by printing the result of LanguageUtil.getLocale('de') and LanguageUtil.getLocale('de_DE') (should both be null). Just add the locale to the enabled ones and you are good.
A third option applies, if you have defined the messages in the resource bundle of your portlet (usually you define the messages in a hook or OSGI bundle to use them in more than one portlet). In that case LanguageUtil.get(Locale, String) doesn't know which portlet you are in and can't access the resource bundle of that portlet. That's the difference to LanguageUtil.get(HttpServletRequest, String), which retrieves the portlet from the request.
In that case you have to retrieve the resource bundle from the config given to your Portlet.init(PortletConfig) method. Or you mimic the implementation of LanguageUtil.get(HttpServletRequest, String) with a locale specific parameter:
public class MyLanguageUtil {
public static String get(HttpServletRequest request, Locale locale, String key) {
if (request == null) {
return key;
}
PortletConfig portletConfig = (PortletConfig) request.getAttribute("javax.portlet.config");
if (portletConfig != null) {
ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
if (resourceBundle.containsKey(key)) {
return LanguageUtil.get(resourceBundle, key, key);
}
}
return LanguageUtil.get(locale, key);
}
}
ok got it to work.
I added a class for each language in my module language
import java.util.Enumeration;
import java.util.ResourceBundle;
import org.osgi.service.component.annotations.Component;
import com.liferay.portal.kernel.language.UTF8Control;
#Component(
property = { "language.id=es_ES" },
service = ResourceBundle.class
)
public class EsResourceBundle extends ResourceBundle {
#Override
protected Object handleGetObject(String key) {
return _resourceBundle.getObject(key);
}
#Override
public Enumeration<String> getKeys() {
return _resourceBundle.getKeys();
}
private final ResourceBundle _resourceBundle = ResourceBundle.getBundle(
"content.Language_es_ES", UTF8Control.INSTANCE);}
thanks for help
For those who need this to be a little more generic.
Add a small class to your portlet that accesses the portlets ResourceBundle:
public class [MyPortlet]LanguageUtil {
public static String get (Locale locale, String key) {
ResourceBundle resourceBundle = ResourceBundle.getBundle("content.Language", locale, UTF8Control.INSTANCE);
return LanguageUtil.get(resourceBundle, key);
}
public static String format (Locale locale, String pattern, Object[] arguments) {
ResourceBundle resourceBundle = ResourceBundle.getBundle("content.Language", locale, UTF8Control.INSTANCE);
return LanguageUtil.format(resourceBundle, pattern, arguments);
}
}
and export it with the help of the bnd.bnd file of the portlet like:
Export-Package: [path.to.my.util]
This way it can be used in OSGI modules and regular JAVA classes for example like this:
[MyPortlet]LanguageUtil.get(serviceContext.getLocale(), "my-language-string");
Problem: Native queries with Spring Data returning dates return java.sql.Date not java.time.LocalDate, despite the setup.
Context: A new project with Spring Boot 2.0.0.M5 (the latest), Hibernate 5.2.11, Hibernate-Java8 5.2.12 (which gives support for JSR310 classes as long as it's on the classpath).
Anonymized example below (the app is not really about birthdays):
public interface BirthdayRepository<T, ID extends Serializable> extends Repository<T, ID> {
#Query(value = "select day from birthdays", nativeQuery = true)
Iterable<java.sql.Date> getBirthdays(); //the return type should ideally be java.time.LocalDate
}
In the database (SQL Server), the day field is DATE and values are like 2017-10-24.
The problem is that at runtime, the Spring Data repository (whose implementation I cannot control, or is there a way?) returns java.sql.Date not java.time.LocalDate (Clarification: the return type appears to be decided by Spring Data and remains java.sql.Date even if I change the return type to be java.time.LocalDate, which is how I started to).
Isn't there a way to get LocalDate directly? I can convert it later, but (1) that's inefficient and (2) the repository methods have to return the old date/time classes, which is something I'd like to avoid. I read the Spring Data documentation, but there's nothing about this.
EDIT: for anyone having the same question, below is the solution, the converter suggested by Jens.
public class LocalDateTypeConverter {
#Converter(autoApply = true)
public static class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
#Nullable
#Override
public Date convertToDatabaseColumn(LocalDate date) {
return date == null ? null : new Date(LocalDateToDateConverter.INSTANCE.convert(date).getTime());
}
#Nullable
#Override
public LocalDate convertToEntityAttribute(Date date) {
return date == null ? null : DateToLocalDateConverter.INSTANCE.convert(date);
}
}
It looks like you found a gap in the converters. Spring Data converts out of the box between java.util.Date and java.time.LocalDate but not between java.time.LocalDate and java.sql.Date and other date and time-related types in the java.sql package.
You can create your own converter to do that. You can use Jsr310JpaConverters as a template.
Also, you might want to create a feature request and if you build a converter for your use, you might even submit a pull request.
I know this is an older question, but my solution to this problem does not require a custom converter.
public interface BirthdayRepository<T, ID extends Serializable> extends Repository<T, ID> {
#Query(value = "select cast(day as date) from birthdays", nativeQuery = true)
Iterable<java.time.LocalDate> getBirthdays();
}
The CAST tells JPQL to use available java date\time types rather than java.sql.Date
All INET Nordic FIX protocols will be enhanced by extending to nanosecond granularity timestamps on 16.oktober 2015 (see notification and section 3.1.1 in the spec).
The timestamps will look like this: 20150924-10:35:20.840117690
quickfix currently rejects messages that contain fields with this new format with the error: Incorrect data format for value
Are there any plans to support this new format? Or maybe some workaround?
You can first try modifying your data dictionary. For example if you are using fix42.xml that comes with QuickFIX, you can change the affected timestamp fields from type='UTCTIMESTAMP' to type='STRING'.
If that isn't enough, you should instead write a patch against QuickFIX in C++, which should be somewhat straightforward once you know where to patch it, which I think is UtcTimeStampConvertor, around here: https://github.com/quickfix/quickfix/blob/master/src/C%2B%2B/FieldConvertors.h#L564
I think you need to add a case 27: above case 21: near the top, because your format has six extra digits. It looks like the rest of the function doesn't care about the total field length.
Of course if you want to actually inspect the sub-millisecond precision part of these timestamps, you'll need to do more.
No plans in QF/n, but only because this is the first I've heard of this.
I'll need to write some tests to see what the repercussions are. It may be that the time/date parser just truncates the extra nano places when it converts the string to a DateTime.
I've opened an issue: https://github.com/connamara/quickfixn/issues/352
This change is as far as I know kind of breaking the fix protocol definition of timestamps but that's another story.
There is a static class in QuickFixn called DateTimeConverter under QuickFix/Fields/Converters.
To get this to work correctly you would need to add format strings in lines in that class.
Add "yyyyMMdd-HH:mm:ss.fffffff" to DATE_TIME_FORMATS and "HH:mm:ss.fffffff" to TIME_ONLY_FORMATS so that it would look like this.
/// <summary>
/// Convert DateTime to/from String
/// </summary>
public static class DateTimeConverter
{
public const string DATE_TIME_FORMAT_WITH_MILLISECONDS = "{0:yyyyMMdd-HH:mm:ss.fff}";
public const string DATE_TIME_FORMAT_WITHOUT_MILLISECONDS = "{0:yyyyMMdd-HH:mm:ss}";
public const string DATE_ONLY_FORMAT = "{0:yyyyMMdd}";
public const string TIME_ONLY_FORMAT_WITH_MILLISECONDS = "{0:HH:mm:ss.fff}";
public const string TIME_ONLY_FORMAT_WITHOUT_MILLISECONDS = "{0:HH:mm:ss}";
public static string[] DATE_TIME_FORMATS = { "yyyyMMdd-HH:mm:ss.fffffff", "yyyyMMdd-HH:mm:ss.fff", "yyyyMMdd-HH:mm:ss" };
public static string[] DATE_ONLY_FORMATS = { "yyyyMMdd" };
public static string[] TIME_ONLY_FORMATS = { "HH:mm:ss.fffffff", "HH:mm:ss.fff", "HH:mm:ss" };
public static DateTimeStyles DATE_TIME_STYLES = DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal;
public static CultureInfo DATE_TIME_CULTURE_INFO = CultureInfo.InvariantCulture;
I have properties files oriented for specific language only (page_ru_RU.prop and page_en_GB.prop). Where on this page came user with locale en US - he got exception, because no proper locale found.
Can i in this way make somwhere check to manual set locale if user dont have any aviable locale without make default locale (page.prop)
If I am not clear about, please tell me.
If you create a properties file with just the language only, it will be used for all variants: so instead of page_en_GB.properties, you can have a page_en.properties, which will be used for all en_* sublocales.
You can also have a plain page.peroperties, which will be used for everyone who doesn't fit into a more specific category.
Update: Take two, how to take control of Locale selection completely.
Locale in Wicket is stored in the Session object, it can be manipulated using the getLocale() and setLocale() method. This alone might give you a solution, but you can also intercept calls to these methods to override locale selection automaticlly.
//this is your application class
public class MyApplication extends WebApplication {
#Override
public Session newSession( Request req, Response res ) {
return new MySession( req )
}
}
//this is your session class
public class MySession extends WebSession {
public MySession( Request req ) {
super( req );
}
#Override
public void setLocale( Locale locale ) {
// your locale substitution code goes here, for example:
if( locale.getLanguage().equals( "en" ) ) {
super.setLocale( new Locale( "en", "GB" ) );
}
}
}
Is this the sort of thing you're after?