This question already has answers here:
Acquiring a country's currency code
(4 answers)
Closed 6 years ago.
Suppose I have country name as USA .So I want to convert to USD.I have only country name from webservice.
I have tried this code but how to convert country name into Locale object. Can anybody suggest in this problem?
String countryName=jsonObject.getString("country");
Provide country code instead of country name
public static void main(String[] args) throws InterruptedException {
Map<String, String> countries = new HashMap<>();
for (String iso : Locale.getISOCountries()) {
Locale l = new Locale("", iso);
countries.put(l.getDisplayCountry(), iso);
}
System.out.println(countries.get("Switzerland"));
System.out.println(countries.get("Andorra"));
System.out.println(countries.get("Japan"));
}
You can also use https://github.com/TakahikoKawasaki/nv-i18n library this is specifically designed for this purpose.
From its GitHub page,
Package to support internationalization, containing ISO 3166-1 country
code enum, ISO 639-1 language code enum, etc.
Example specific to this question
String countryName = jsonObject.getString("country");
List<CurrencyCode> codes = CurrencyCode.getByCountry(countryName, false)
Simple example to see available list (from Github page),
// List all the currency codes.
for (CurrencyCode code : CurrencyCode.values())
{
System.out.format("[%s] %03d %s\n", code, code.getNumeric(), code.getName());
}
// List all the country codes.
for (CountryCode code : CountryCode.values())
{
System.out.format("[%s] %s\n", code, code.getName());
}
Related
I wanted to use enum class to assign book formats to book object. Issue that I have encountered is that some books have 1 format and other have several.
public enum Format {
HARD_COVER, PAPERBACK, E_BOOK, AUDIOBOOK
}
Let's say that first book have only 1 format while second book have all formats. How can I solve it with getters/setters?
How can I solve it with getters/setters?
I wouldn't do this since in my experience, getters and setters are for setting single properties. If I have a class that requires a collection of property, then I'd have the class contain a List for this:
List<Format> formats = new ArrayList<>();
and then:
public void addFormat(Format format) {
formats.add(format); // add to the ArrayList of Format
}
and similarly a removeFormat(Format format) method for removing from the List.
Edit: as correctly stated by Dorian Gray in comments, it would be better that the collection of Formats be a Set<Format> initialized as an EnumSet` since this would prevent duplicate Formats being added to the collection.
Set<Format> formatSet = EnumSet.noneOf(Format.class);
You could work with Bitwise Operators to have one property with the possibility of having multiple values.
Have Enums with int values like this:
public enum Format {
HARD_COVER(1),
PAPERBACK(2),
E_BOOK(4),
AUDIOBOOK(8);
public final int value;
Format(int value) {
this.value = value;
}
}
In your Book class add an int property called format instead of a Format property. Also create a method called isFormat that returns a boolean value according to its Format parameter:
class Book {
private int format;
public Book(int format) {
this.format = format;
}
public boolean isFormat(Format format) {
return format.value == (this.format & format.value); // &: bitwise and
}
}
Finally create a book adding formats separated by | (bitwise or):
Book book = new Book(Format.E_BOOK.value | Format.HARD_COVER.value | Format.AUDIOBOOK.value);
And check its formats like this:
System.out.println("Is paperback?: " + book.isFormat(Format.PAPERBACK));
System.out.println("Is hard cover?: " + book.isFormat(Format.HARD_COVER));
System.out.println("Is audio book?: " + book.isFormat(Format.AUDIOBOOK));
System.out.println("Is E-book?: " + book.isFormat(Format.E_BOOK));
The result of this execution is this:
Is paperback?: false
Is hard cover?: true
Is audio book?: true
Is E-book?: true
I am writing a Date-Time wrapper for my project using Java8 java.time package in which user will pass me a pattern,language and his timezone id (eg. Asia/Kolkatta, etc) on the basis of which i will output the LocalDateTime object(as String) as per his preferred timezone.So basically I have this method signature in mind
public static String getDateTime(String pattern, String language, String timezone){}
For getting timezone preffered time i have used ZonedDateTime which is working fine but I am facing a strange behaviour for getting language plus pattern specific format. I am using
public static DateTimeFormatter ofPattern(String pattern, Locale locale) I just tried with basic example to go ahead before writing any concrete structure but I am getting different results for same operation. Check below mentioned 2 programs-
public static void main(String[] args) {
String lang = "hi";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy,HH:mm", new Locale("hi","IN"));
System.out.println("Date:"+ LocalDateTime.now().format(dateTimeFormatter));
}
Output:
Date:16-अगस्त-2016,14:30
Now here I am getting the expected output for Locale in (Hindi,India) but now when I thought of optimising it by using the already available locale objects rather than using new Locale(String language, String country) I am not getting the result, I did something like this:
public class App2 {
// using map to act as a cache for the Key:Language and Value: Locale
private static Map<String,Locale> localeMap = new HashMap<String, Locale>();
public static void main(String[] args) {
String lang = "hi";
if (localeMap.get(lang) == null) {
for (Locale locale1 : Locale.getAvailableLocales()) {
if (locale1.getLanguage().equals(lang)) {
System.out.println("Lang:"+locale1.getLanguage()+",Country:"+locale1.getCountry());
localeMap.put(lang, locale1);
}
}
}
DateTimeFormatter.ofPattern("dd-MMM-yyyy,HH:mm", localeMap.get(lang));
System.out.println("Date:"+ LocalDateTime.now().format(dateTimeFormatter));
}
}
Output:
Lang:hi,Country:IN
Lang:hi,Country:
Date:16-Aug-2016,15:18
Note:
Locale corresponding to "hi" is already present in
for (Locale locale1 : Locale.getAvailableLocales()) {
if (locale1.getLanguage().equals("hi")) is not null
}
Questions:
Any reason why different output for above mentioned methods ? - Resolved [there were multiple entries for locales where lang is:"hi"]
I also wants to know why I am not getting numbers in that language. I am getting month name in hindi(for new Locale("hi","IN")) but not the numbers in date and time.(eg. I want numbers in ०,१,२,३,४,५,६,७,८,९,१० - this is hindi version of 0,1,2,3,4..10)
I also observed if I log locale1.getLanguage and locale1.getCountry(), 2 entries are there lang:hi and Country:IN and lang:hi and country:" "(empty string) and same for other locales too I observe this behaviour(language is there but no country). Any reasons ?
Edit1:
After putting sopln while insertion in map, I see there are two locales for which language is hindi if put an additional check in that for loop !locale1.getCountry().isEmpty() && locale1.getLanguage().equals(lang) ; I am getting the expected output. Now in Locale class there is constructor for Locale(String language) also. It also doesn't seem to work for "hi" but for "zh" - which is for CHINESE it works which gives multiple entries for zh and locale objects and for last insertion country has empty value which is similar to "hi" behaviour but yet I get an output in Chinese. Basically,this points to 3 in questions to ask.
Lang:zh,Country:TW
Lang:zh,Country:HK
Lang:zh,Country:SG
Lang:zh,Country:CN
Lang:zh,Country:
Date:16-八月-2016,17:14
I have a class called Info, and i have a bunch of static String variables described in it.
public class Info{
public static stringOne= "Hello";
public static stringTwo = "world";
}
and i'm hoping to access these variables as Info.stringTwo from other classes.
1.) I need to know if this is java-Internationalization that i have applied here ? (I have all the messages that i will display in the application assigned in this class. And, i am hoping to have different languages support to the app as well)
Have a look at Resource bundle
A copy paste from the documentation:
When your program needs a locale-specific object, it loads the ResourceBundle class using the getBundle method:
ResourceBundle myResources =
ResourceBundle.getBundle("MyResources", currentLocale);
Resource bundles contain key/value pairs. The keys uniquely identify a locale-specific object in the bundle.
Here's an example of a ListResourceBundle that contains two key/value pairs:
public class MyResources extends ListResourceBundle {
protected Object[][] getContents() {
return new Object[][] {
// LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
{"OkKey", "OK"},
{"CancelKey", "Cancel"},
// END OF MATERIAL TO LOCALIZE
};
}
}
Keys are always Strings. In this example, the keys are "OkKey" and "CancelKey". In the above example, the values are also Strings--"OK" and "Cancel"--but they don't have to be. The values can be any type of object.
You retrieve an object from resource bundle using the appropriate getter method. Because "OkKey" and "CancelKey" are both strings, you would use getString to retrieve them:
button1 = new Button(myResources.getString("OkKey"));
button2 = new Button(myResources.getString("CancelKey"));
Here is an example from here:-
import java.util.*;
public class InternationalizationDemo {
public static void main(String[] args) {
String language;
String country;
Locale locale;
ResourceBundle rb;
if (args.length != 2) {
language = new String("en");
country = new String("US");
}
else {
language = new String(args[0]);
country = new String(args[1]);
}
locale = new Locale(language, country);
rb = ResourceBundle.getBundle("MessagesBundle", locale);
System.out.println(rb.getString("localeInfo") + " ( " +
locale.getDisplayLanguage() + "," + locale.getDisplayCountry() + ").\n");
System.out.println(rb.getString("welcome"));
System.out.println(rb.getString("sayThanks"));
}
}
Though using a ResourceBundle is the traditional and most well-known approach to internationalization in Java, it is possible to make internationalization data available as class members, somewhat similar to the way you seek.
You can further put your strings for some message in different languages in a Map, indexed by language. And make this Map a static member of some class. Thus you get the ability to reference these string collections for messages by their class member names in a compiler-checked manner. And next, if you have a way to select preferred user language at run time (you have to have it), you just pick the right string from an appropriate collection using its language key, boiling down to something like this:
logger.info (MyClassWithMessages.MY_MULTILANGUAGE_MESSAGE.s ());
And the s() method to be added to your Map subclass can be made resposible for dealing with user preferences and selection from Map by language key.
That said, the remaining task is just to formulate a convenient API for all this... You are welcome to have a look at such an implementation on my blog page Look Ma, no ResourceBundle :) ..., and the next page that goes ahead with message formatting arguments.
For internationalization of Java and other applications I implemented a Message Compiler, which creates the resource bundle files and constant definitions as Java enum or static final strings for the keys from one single source file. So the constants can be used in the Java source code, which is a much safer way than using plain string constants. The message compiler cannot only be used for Java. It creates also resource files and constants for Objective-C or Swift and can be extended for other programming environments.
Is there any String replacement mechanism in Java, where I can pass objects with a text, and it replaces the string as it occurs?
For example, the text is:
Hello ${user.name},
Welcome to ${site.name}.
The objects I have are user and site. I want to replace the strings given inside ${} with its equivalent values from the objects. This is same as we replace objects in a velocity template.
Use StringSubstitutor from Apache Commons Text.
Dependency import
Import the Apache commons text dependency using maven as bellow:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
Example
Map<String, String> valuesMap = new HashMap<String, String>();
valuesMap.put("animal", "quick brown fox");
valuesMap.put("target", "lazy dog");
String templateString = "The ${animal} jumped over the ${target}.";
StringSubstitutor sub = new StringSubstitutor(valuesMap);
String resolvedString = sub.replace(templateString);
Take a look at the java.text.MessageFormat class, MessageFormat takes a set of objects, formats them, then inserts the formatted strings into the pattern at the appropriate places.
Object[] params = new Object[]{"hello", "!"};
String msg = MessageFormat.format("{0} world {1}", params);
My preferred way is String.format() because its a oneliner and doesn't require third party libraries:
String message = String.format("Hello! My name is %s, I'm %s.", name, age);
I use this regularly, e.g. in exception messages like:
throw new Exception(String.format("Unable to login with email: %s", email));
Hint: You can put in as many variables as you like because format() uses Varargs
I threw together a small test implementation of this. The basic idea is to call format and pass in the format string, and a map of objects, and the names that they have locally.
The output of the following is:
My dog is named fido, and Jane Doe owns him.
public class StringFormatter {
private static final String fieldStart = "\\$\\{";
private static final String fieldEnd = "\\}";
private static final String regex = fieldStart + "([^}]+)" + fieldEnd;
private static final Pattern pattern = Pattern.compile(regex);
public static String format(String format, Map<String, Object> objects) {
Matcher m = pattern.matcher(format);
String result = format;
while (m.find()) {
String[] found = m.group(1).split("\\.");
Object o = objects.get(found[0]);
Field f = o.getClass().getField(found[1]);
String newVal = f.get(o).toString();
result = result.replaceFirst(regex, newVal);
}
return result;
}
static class Dog {
public String name;
public String owner;
public String gender;
}
public static void main(String[] args) {
Dog d = new Dog();
d.name = "fido";
d.owner = "Jane Doe";
d.gender = "him";
Map<String, Object> map = new HashMap<String, Object>();
map.put("d", d);
System.out.println(
StringFormatter.format(
"My dog is named ${d.name}, and ${d.owner} owns ${d.gender}.",
map));
}
}
Note: This doesn't compile due to unhandled exceptions. But it makes the code much easier to read.
Also, I don't like that you have to construct the map yourself in the code, but I don't know how to get the names of the local variables programatically. The best way to do it, is to remember to put the object in the map as soon as you create it.
The following example produces the results that you want from your example:
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
Site site = new Site();
map.put("site", site);
site.name = "StackOverflow.com";
User user = new User();
map.put("user", user);
user.name = "jjnguy";
System.out.println(
format("Hello ${user.name},\n\tWelcome to ${site.name}. ", map));
}
I should also mention that I have no idea what Velocity is, so I hope this answer is relevant.
Here's an outline of how you could go about doing this. It should be relatively straightforward to implement it as actual code.
Create a map of all the objects that will be referenced in the template.
Use a regular expression to find variable references in the template and replace them with their values (see step 3). The Matcher class will come in handy for find-and-replace.
Split the variable name at the dot. user.name would become user and name. Look up user in your map to get the object and use reflection to obtain the value of name from the object. Assuming your objects have standard getters, you will look for a method getName and invoke it.
There are a couple of Expression Language implementations out there that does this for you, could be preferable to using your own implementation as or if your requirments grow, see for example JUEL and MVEL
I like and have successfully used MVEL in at least one project.
Also see the Stackflow post JSTL/JSP EL (Expression Language) in a non JSP (standalone) context
Handlebars.java might be a better option in terms of a Velocity-like syntax with other server-side templating features.
http://jknack.github.io/handlebars.java/
Handlebars handlebars = new Handlebars();
Template template = handlebars.compileInline("Hello {{this}}!");
System.out.println(template.apply("Handlebars.java"));
I use GroovyShell in java to parse template with Groovy GString:
Binding binding = new Binding();
GroovyShell gs = new GroovyShell(binding);
// this JSONObject can also be replaced by any Java Object
JSONObject obj = new JSONObject();
obj.put("key", "value");
binding.setProperty("obj", obj)
String str = "${obj.key}";
String exp = String.format("\"%s\".toString()", str);
String res = (String) gs.evaluate(exp);
// value
System.out.println(str);
I created this utility that uses vanilla Java. It combines two formats... {} and %s style from String.format.... into one method call. Please note it only replaces empty {} brackets, not {someWord}.
public class LogUtils {
public static String populate(String log, Object... objects) {
log = log.replaceAll("\\{\\}", "%s");
return String.format(log, objects);
}
public static void main(String[] args) {
System.out.println(populate("x = %s, y ={}", 5, 4));;
}
}
Since Java 15 you have the method String.formatted() (see documentation).
str.formatted(args) is the equivalent of String.format(str, args) with less ceremony.
For the example mentioned in the question, the method could be used as follows:
"Hello %s, Welcome to %s.".formatted(user.getName(), site.getName())
Good news. Java is most likely going to have string templates (probably from version 21).
See the string templates proposal (JEP 430) here.
It will be something along the lines of this:
String name = "John";
String info = STR."I am \{name}";
System.out.println(info); // I am John
P.S. Kotlin is 100% interoperable with Java. It supports cleaner string templates out of the box:
val name = "John"
val info = "I am $name"
println(info) // I am John
Combined with extension functions, you can achieve the same thing the Java template processors (e.g. STR) will do.
There is nothing out of the box that is comparable to velocity since velocity was written to solve exactly that problem. The closest thing you can try is looking into the Formatter
http://cupi2.uniandes.edu.co/site/images/recursos/javadoc/j2se/1.5.0/docs/api/java/util/Formatter.html
However the formatter as far as I know was created to provide C like formatting options in Java so it may not scratch exactly your itch but you are welcome to try :).
E.g. eng, spa, ita, ger
I could iterate all locales and compare the codes, but I wonder whether there is a more elegant & performant way to achieve this....
Thanks a lot for any hints :)
I don't know if there's an easy way to convert the 3-letter to the 2-letter versions, but in a worse case scenario, you could create a Map of them, like so:
String[] languages = Locale.getISOLanguages();
Map<String, Locale> localeMap = new HashMap<String, Locale>(languages.length);
for (String language : languages) {
Locale locale = new Locale(language);
localeMap.put(locale.getISO3Language(), locale);
}
Now you can look up locales using things like localeMap.get("eng");
Edit: Modified the way the map is created. Now there should be one object per language.
Edit 2: It's been a while, but changed the code to use the actual length of the languages array when initializing the Map.
You can use constructor Locale(String language), where language is the 2 letter ISO-639-1 code. I think the easiest way to convert ISO-639-2 to ISO-639-1 would be to create HashMap<String,String> constant.
Some modified code from my project, which has a similar requirement. We have our own historical timezone format so we can't use standard libraries.
public class MyProjectTimeZoneFactory {
private static Map timeZoneDb;
/**
* Set up our timezone id mappings; call this from any constructor
* or static method that needs it.
*/
private static void init() {
if(null == TimeZoneDb) {
timeZoneDb = new HashMap(); // Maybe a TreeMap would be more appropriate
timeZoneDb.put(" ","GMT+00");
timeZoneDb.put("EAD ","GMT+10");
timeZoneDb.put("JST ","GMT+9");
// etc.
}
}
public static TimeZone getTimeZone(String id)
throws CommandFormatException {
init();
TimeZone tz;
if(timeZoneDb.containsKey(id)) {
tz = TimeZone.getTimeZone((String)timeZoneDb.get(id));
} else {
throw new CommandFormatException("Invalid Timezone value");
}
return tz;
}
}
You could argue that it would be better to have the map in configuration rather than code - perhaps in a properties file. That may be true - but do remember the Pragmatic Programmers' rule 'Your not going to need it'.