I have to detect user country and language automatically in Java Servlet using request details (IP address, browser information etc.). Is it possible to detect these settings for the most of users (~90%)?
2 Answers
Detecting the language
Detecting the correct language is easy. Web browsers tend to send AcceptLanguage header and Java Servlet API is so nice to actually convert it contents to Locale object(s). All you would have to do, is just access this information and implement fall-back mechanism. To do that you actually need a list of Locales your application is going to support (you could think of creating some sort of Properties file that would contain supported locales along with default one). Example below shows such implementation:
public class LousyServlet extends HttpServlet {
private Properties supportedLanguages;
private Locale requestLocale = (Locale) supportedLanguages.get("DEFAULT");
public LousyServlet() {
supportedLanguages = new Properties();
// Just for demonstration of the concept
// you would probably load it from i.e. XML
supportedLanguages.put("DEFAULT", Locale.US);
// example mapping of "de" to "de_DE"
supportedLanguages.put("de-DEFAULT", Locale.GERMANY);
supportedLanguages.put("de_AT", new Locale("de", "AT"));
supportedLanguages.put("de_CH", new Locale("de", "CH"));
supportedLanguages.put("ja_JP", Locale.JAPAN);
}
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
detectLocale(request);
super.doGet(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
detectLocale(request);
super.doPost(request, response);
}
private void detectLocale(HttpServletRequest request) {
Enumeration locales = request.getLocales();
while (locales.hasMoreElements()) {
Locale locale = (Locale) locales.nextElement();
if (supportedLanguages.contains(locale)) {
requestLocale = locale;
break;
}
}
}
public String getLanguage() {
// get English name of the language
// For native call requestLocale.getDisplayName(requestLocale)
return requestLocale.getDisplayLanguage();
}
}
Mind you, that you would need to list all the countries for given language, as it won't fall back in this case. That is for the reason. Local users tend to have non-specific Locale either way (for example my web browser sends pl_PL, pl, en_US, en in that order). And the reason is, there are some languages that differs substantially depending on the country, for example Brazilian Portuguese is different than Portuguese and Chinese Traditional (Taiwan, Hong Kong) is different than Chinese Simplified (China, Singapore) and it won't be appropriate to fall back to one of them.
Detecting country
Depending on what you need this information for, it might or might not be straightforward. If end user's web browser is configured correctly, it will give you the hint of end user's preferred location - that would be the part of Locale. If you only need that information to decide on which localized page to load, that would be probably the best option. Of course if Locale object is not specific (country-less) you may want to assign "default" country for each supported non-specific Locale. In both cases, you should provide end user with some means of switching country (i.e. through "Other countries" combo box). The list could be obtained like this:
public String[] getOtherCountries() {
Set<String> countries = new HashSet<String>();
Set<Object> keys = supportedLanguages.keySet();
for (Object key : keys) {
Locale other = (Locale) supportedLanguages.get(key);
if (other != requestLocale) {
countries.add(other.getDisplayCountry(requestLocale));
}
}
return countries.toArray(new String[0]);
}
If however, you need this to restrict the access to the contents based on location, the problem is harder. You may think of checking the IP. You would need to prepare some Database with address classes that belongs to given country. This data could be found on the Internet. The only problem with that solution is, user may configure a web proxy and fool your web site on his real location. Also, corporate users might appear as if they connect from USA where in fact they connect from UK or Ireland. Either way, it is your best shot.
There was some question on GeoLocation before and I believe you may find it useful. Here you are.

- 1
- 1

- 18,366
- 7
- 57
- 79
-
1AFAIK there will only be 1 instance of the servlet, so the given code will eventually be problematic. – AndrewBourgeois May 23 '12 at 14:16
-
@AndrewBourgeois: I can't see your point. If you care about the performance, I would suggest to profile the code rather than pre-mature optimize it. If you mean there will be problems with detected Locales, mind you that each request is different and this code cares about each of them ***separately***. If you want to handle it per session, you might want to `getSession()` and save detected `Locale` object to it (although for this, I would use Filter rather than Servlet, and honestly I wouldn't write it myself but use Spring instead). – Paweł Dyda May 23 '12 at 17:56
-
2All I'm saying is that you're saving the Locale in an instance variable of a servlet whose instance is shared by multiple requests from multiple people (= 1 servlet instance for all requests). So a French person may set the Locale to French, after which an American may put English into the Locale. If the request of the French user hasn't finished, he'll have an Enlgish Locale for the rest of his request... – AndrewBourgeois May 24 '12 at 06:11
use getlocale from request object.

- 2,036
- 13
- 12
-
provided user has not changed locale setting in browser before sending request. – sudmong May 13 '11 at 07:31
-
See this [GettingLocaleInformationfromReques](http://www.java2s.com/Code/Java/Servlets/GetLocaleInformationfromRequest.htm) – sudmong May 13 '11 at 07:33