I am looking for help with translating Validation messeges in Play framework 2.2
I have fields that are required:
f.e.
#Required(message = "To pole jest wymagane")
public String miesiac;
#Required
public String miejsce;
#Required
public String oddzial;
But I would to have this message: "To pole jest wymagane" globally.
How can I achive it?
Should I use conf/messagess.pl file for translation To polish language.
Please give me some help
Yes, you should use the conf/messages file for your default/primary language text and then one or more of the conf/messages.xx files for your translations.
The built-in validators are already setup to use the messages files. For example, the Required validator will look for the key error.required in your messages and display that text. So just define that key in your message files with the text you want to use.
If you wanted to use something other than the default then just specify the key with the message attribute (instead of the full text like in your example).
Model class
#Required(message = "my.required.message")
public String miesiac;
conf/messages
my.required.message=Hey, you have to type something here.
Take a look at the documentation for more info:
Externalising messages and internationalization
All what I found out. Here are my current custom messages in
conf/messages
error.required=This field is required
error.invalid=You need to enter a number
constraint.required=Required*
Related
I'm working on a task that's using Velocity to generate an email from a template. One of my requirements is that the email message be localized, based on a Locale submitted by the user. I've got this working for the most part, using Velocity's ResourceTool to pull in a MessageBundle. The other requirement is that I can only have one template - I don't want one template per language or locale because this is difficult to maintain if changes are needed.
As a part of a MessageBundle, I can have what's referred to as "compound messages", which are messages that have variables that are replaced when the message is evaluated. For example:
dear.name=Dear {0}:
My question is this: how do I get Velocity to replace the {0} value with a name that I pass in?
It's not acceptable to simply modify my Velocity template so that I simply replace the name at the template level - in some languages, the greeting word "Dear" comes after the name, so this would yield an incorrect output.
Found the answer: in my velocity template, I can use the Velocity directive:
#evaluate(${msg.dear.name})
And in my message bundle, my message looks like:
dear.name=Dear $name
If I set the name in the Velocity context, it gets replaced as I expect.
I need to validate emails and domains. I just need a formal validation, no whois or other forms of domain lookup needed.
Currently I'm using apache's commons-validator v1.4.0
Unfortunately my customers use the new gTLDs, like .bike or .productions that are not yet supported by the DomainValidator class.
See Apache's Jira issue for more details.
Are there any sound alternatives that I may easily include in my Maven POM?
If you are not concerned about internationalized addresses, you could change last part of address, and continue to use Apache commons.
This approach is based on the fact that whatever the TLD is, the validity of the whole domain name is equivalent to the validity of the same domain name with the TLD replaced with com. For example:
abc.def.com is valid. Similarly abc.def.name, abc.def.xx--kput3i, abc.def.uk are valid.
ab,de.com is not valid. Similarly ab,de.name, ab,de.xx-kput3i, ab,de.uk are not valid.
So instead of calling
return EmailValidator.getInstance().isValid(userEmail);
You can call
if ( userEmail == null ) {
return false;
}
return EmailValidator.getInstance().isValid(userEmail.trim().replaceFirst("\\.\\p{Alpha}[\\p{Alnum}-]*\\p{Alnum}$", ".com"));
Explanation
The regular expression "\\.\\p{Alpha}[\\p{Alnum}-]*\\p{Alnum}$" checks for the TLD part: it's at the end of the string (because of the $), it starts with a dot and contains no other dot, and it conforms to the standards: begins with an ASCII Alpha character, followed by zero or more alphanumerics or dashes, and ends with an alphanumeric character.
I am using trim() because until now, if you used EmailValidator, it allows spaces before and after the address. Removing the spaces just makes it easier to replace the TLD, and it shouldn't matter as far as the validity of the address is concerned.
If the string doesn't have a valid TLD at the end, String.replaceFirst() will return it as is. It could still be valid, because email addresses of the format x#[n.n.n.n] where n.n.n.n. is a valid IP address are valid. So basically, if you didn't find a TLD, you let EmailValidator decide the validity issue itself.
Of course, if the TLD is not an IANA recognized TLD, this validation will not tell you that. An e-mail like david#galaxy.hoopie-frood will be accepted as legal,but IANA doesn't have that TLD as yet.
Checking a domain is similar, without the trim() part:
if (userDomain == null ) {
return false;
}
return DomainValidator.getInstance().isValid(userDomain.replaceFirst("\\.\\p{Alpha}[\\p{Alnum}-]*\\p{Alnum}$"));
I have also tried JavaMail's email address validation, but I don't really like it: it allows completely invalid domain names such as net-name.net- (ending with a dash) or IP addresses (which are not allowed for e-mail without square brackets around them), and it's only good for e-mail addresses, not for domains.
Internationalization
If you need to check for internationalized domains and e-mails, it's a bit different. It's easy to check for internationalized domains (for example 元気。テスト). All you need to do is convert them to ASCII with java.net.IDN.toASCII() (yielding xn--z4qx76d.xn--zckzah for my example domain - this is a valid TLD), and then do the same as I wrote above.
Internationalized e-mails are a different story. If the local part is ASCII, you can convert the domain part to ASCII. If you have to display the email address, you need to use the Unicode version, and if you have to send an email message, you use the ASCII version.
But recently a standard has been introduced for internationalized local parts as well, which also allows sending to the unicode version of the domain name without translating it to ASCII first. Whether you want to support that or not requires some thought, as not many mail servers and mail transfer agents support it at the moment.
Copied the implementation from DomainValidator and replaced the TOP_LABEL_REGEX expression with "\\p{Alpha}[\\p{Alnum}-]*\\p{Alpha}".
In addition, I removed validation against the hard coded list of approved gTLDs. This is, basically, quite weak in that it doesn't validate against the actual domains. But I think it's good enough (catches the gTLDs similar to XN--YGBI2AMMX).
See full list of approved gTLDs here.
// Copied from org.apache.commons.validator.routines.DomainValidator
private static final String DOMAIN_LABEL_REGEX = "\\p{Alnum}(?>[\\p{Alnum}-]*\\p{Alnum})*";
// Changed to include new gTLD - http://data.iana.org/TLD/tlds-alpha-by-domain.txt
private static final String TOP_LABEL_REGEX = "\\p{Alpha}[\\p{Alnum}-]*\\p{Alpha}";
// Copied from org.apache.commons.validator.routines.DomainValidator
private static final String DOMAIN_NAME_REGEX = "^(?:" + DOMAIN_LABEL_REGEX + "\\.)+" + "(" + TOP_LABEL_REGEX + ")$";
private static final RegexValidator domainRegex = new RegexValidator(DOMAIN_NAME_REGEX);
private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator();
public static boolean isValidDomain(String domain) {
String[] groups = domainRegex.match(domain);
return groups != null && groups.length > 0;
}
What I often do in this situation is to checkout the source code for the library in question (it's open source remember?), modify it to suit my requirement, and then contribute the patch back to the project.
Your use case certainly sounds like it would be a useful contribution.
I made you a public suffix list Java API. The method PublicSuffixList.getRegistrableDomain() can be used for Domain validation:
PublicSuffixListFactory factory = new PublicSuffixListFactory();
PublicSuffixList suffixList = factory.build();
assertNull(suffixList.getRegistrableDomain("galaxy.hoopie-frood"));
assertNotNull(suffixList.getRegistrableDomain("example.bike"));
While DomainValidator is missing some of the new TLDs, for me the best solution was to update TLD.
DomainValidator.updateTLDOverride(ArrayType.COUNTRY_CODE_PLUS, new String[]{"someTLD"});
And then initiate EmailValidator Instance
EmailValidator.getInstance(false, true)
Was wondering why the constraints created for a form are not included in the input tag directly when created through the form helper?
Explanation (using Play 2.1):
Model:
public class Account {
#MaxLength(5)
private String id = "";
...
...
view:
#form(action = routes.Application.addAccount()) {
#inputText(accountForm("id"), '_label -> "Enter your id:")
}
renders automatically in html as:
Enter your id:
Maximum length: 5
Should it not render like this (actually constraining the form text field):
Enter your id:
Maximum length: 5
How can I get code that will automatically include constraints such as these in the form? It's just that I do not really think it is a good idea to have a maxlength defined in the form model and a separate one defined in the view.
Thanks
If I've understood you correctly, it sounds like you're looking to implement one of these features:
Highlight an input text field that is overlength before form submission
Clipping text in an input field so that it does not go overlength
Play's HTML templating engine doesn't natively provide this kind of client-side instant form validation. This functionality needs to be implemented via JavaScript, and JavaScript generation is not really a concern for Play.
If you want to progressively enhance your form and provide client-side validation, you'll have to write the JavaScript yourself. Of course there are libraries that you can use to help you with this task. For example, if you are already using jQuery you can use its validation plugin.
As you've mentioned in your question, it would be better to have a maximum length limit declared in one place only, rather than duplicated in your client-side JavaScript code and your server-side Java code. As a suggestion, you could keep the limit declared in Java code, but introduce a new action in your controller tier that returns a JSON response containing this limit. This action could then be called via AJAX when loading your form page.
EDIT
Didn't know about the maxlength attribute, thanks Saad. If you feed in your maximum length limit as an input parameter to your template, you can populate an input element's maxlength attribute as follows:
#(accountForm: Form[Account], maxLength: Int)
...
#form(action = routes.Application.addAccount()) {
...
#inputText(
field = accountForm("id"),
args = '_label -> "Enter your id:", 'maxlength -> maxLength
)
...
}
...
There may be a more elegant way to pass maxLength into your HTML template (e.g use the HTTP context map, or have it as a public field on your Account form object). The above code snippet just demonstrates how to correctly generate the input text field once you can access it in the template.
What's the analogous of
Resources.getMessage(request,"key");
(it's in org.apache.struts.validator package)?
I need to take the right string according to the language in use and put that string in an array.
These strings have a variable part. For example:
The field %s is required
I want to take the The field and is required from the MessageResources
EDIT
I've used
ResourceBundle myResources = ResourceBundle.getBundle("MessageResources");
String msg = MessageFormat.format(myResources.getString("errors.required"),
new Object[] { title });
It works, but only with the default language
You can use a resource bundle for this in idiomatic Java. The bundles are properties files, and they are named according to their locale's.
Here is a link to ResourceBundle in the Java API documentation.
http://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html
Let me know if you need any more info.
Can you do the following with a Java ResourceBundle?
In the properties file...
example.dynamicresource=You currently have {0} accounts.
At runtime...
int accountAcount = 3;
bundle.get("example.dynamicresource",accountCount,param2,...);
To give a result of
"You currently have 3 accounts."
Not without using the MessageFormat class, such as:
String pattern = bundle.getString("example.dynamicresource");
String message = MessageFormat.format(pattern, accountCount);
On their own, ResourceBundle does not support property placeholders. The usual idea is to take the String you get from the bundle, and stick it into a MessageFormat, and then use that to get your parameterized message.
If you're using JSP/JSTL, then you can combine <fmt:message> and <fmt:param> to do this, which uses ResourceBundle and MessageFormat under the covers.
If you happen to be using Spring, then it has the ResourceBundleMessageSource which does something similar, and can be used anywhere in your program. This MessageSource abstraction (combined with MessageSourceAccessor) is much nicer to use than ResourceBundle.
There are various ways, depending on the view technology you're using. If you're using "plain vanilla" Java (e.g. Swing), then use MessageFormat API as answered before. If you're using a webapplication framework (which is true, if I judge your question history here correctly), then the way depends on the view technology and/or MVC framework you're using. If it is for example "plain vanilla" JSP, then you can use JSTL fmt:message for this.
<fmt:message key="example.dynamicresource">
<fmt:param value="${bean.accountCount}">
</fmt:message>
If it is for example JSF, you can use h:outputFormat for this.
<h:outputFormat value="#{bundle['example.dynamicresource']}">
<f:param value="#{bean.accountCount}">
</h:outputFormat>
Best place is to just consult the documentation of the technology/framework you're using (or to tell it here so that we can give better suited and more detailed answers).
Struts have a nice util called MessageResources which does exactly what you ask for....
e.g.
MessageResources resources = getResources(request, "my_resource_bundle"); // Call your bundle exactly like ResourceBundle.getBundle() method
resources.getMessage("example.dynamicresource",accountCount,param2,...);
Limitation
It only allows maximum of 3 parameters (i.e. resource attribute, param1, ..., param3).
I suggest using MessageFormat (if you want to use more than 3 parameter values) as suggested by David Sykes.
PS the getResources method is available only in the Struts Action class.
I don't think you can make this work for Non-English properties file.
My message.properties file has the following line:
info.fomat.log.message.start=Starting to parse log message in {0} format.
And my message_fr_FR.properties file has the following line:
info.fomat.log.message.start=A partir d'analyser le message connecter {0} format.
This code works only for the English one
String.format((String) messages .getString(GlobalConstants.MESSAGE_FORMAT_START), GlobalConstants.STR_JSON));
It does NOT replace the placeholder with the value when my language / locale is French :-(
Even MessageFormat.fomat() is no good
I don't believe ResourceBundle can do that itself, but String can:
String.format(bundle.getString("example.dynamicresource"), accountCount);
Remember that when using MessageFormat.format() you need to use a double quote ('') in your resource bundle if you want to express single quote (').
MessageFormoat#format will work for the case like:
greetingTo=Have Param, saying hello {0}
You can declare two methods like this where RB is a instance of ResourceBundle:
/**This is a method that takes the param to substitute the placeholder**/
public String getString(String key, Object... params ) {
try {
return MessageFormat.format(this.RB.getString(key), params);
} catch (MissingResourceException e) {
return "[" + key + "]";
}
}
/**Without a param, this will derectly delegate to ResourceBundle#getString**/
public String getString(String key) {
try {
return this.RB.getString(key);
} catch (MissingResourceException e) {
return "[" + key + "]";
}
}