Parse Accept-Language header in Java

2019-02-04 00:25发布

The accept-language header in request is usually a long complex string -

Eg.

Accept-Language : en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2

Is there a simple way to parse it in java? Or a API to help me do that?

7条回答
ら.Afraid
2楼-- · 2019-02-04 01:00
Locale.forLanguageTag("en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2")
查看更多
干净又极端
3楼-- · 2019-02-04 01:04

Here's an alternative way to parse the Accept-Language header which doesn't require a servlet container:

String header = "en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2";
for (String str : header.split(",")){
    String[] arr = str.trim().replace("-", "_").split(";");

  //Parse the locale
    Locale locale = null;
    String[] l = arr[0].split("_");
    switch(l.length){
        case 2: locale = new Locale(l[0], l[1]); break;
        case 3: locale = new Locale(l[0], l[1], l[2]); break;
        default: locale = new Locale(l[0]); break;
    }

  //Parse the q-value
    Double q = 1.0D;
    for (String s : arr){
        s = s.trim();
        if (s.startsWith("q=")){
            q = Double.parseDouble(s.substring(2).trim());
            break;
        }
    }

  //Print the Locale and associated q-value
    System.out.println(q + " - " + arr[0] + "\t " + locale.getDisplayLanguage());
}

You can find an explanation of the Accept-Language header and associated q-values here:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Many thanks to Karl Knechtel and Mike Samuel. Thier comments to the original question helped point me in the right direction.

查看更多
老娘就宠你
4楼-- · 2019-02-04 01:11

ServletRequest.getLocale() is certainly the best option if it is available and not overwritten as some frameworks do.

For all other cases Java 8 offers Locale.LanguageRange.parse() as previously mentioned by Quiang Li. This however only gives back a Language String, not a Locale. To parse the language strings you can use Locale.forLanguageTag() (available since Java 7):

    final List<Locale> acceptedLocales = new ArrayList<>();
    final String userLocale = request.getHeader("Accept-Language");
    if (userLocale != null) {
        final List<LanguageRange> ranges = Locale.LanguageRange.parse(userLocale);

        if (ranges != null) {
            ranges.forEach(languageRange -> {
                final String localeString = languageRange.getRange();
                final Locale locale = Locale.forLanguageTag(localeString);
                acceptedLocales.add(locale);
            });
        }
    }
    return acceptedLocales;
查看更多
Juvenile、少年°
5楼-- · 2019-02-04 01:16

For the record, now it is possible with Java 8:

Locale.LanguageRange.parse()
查看更多
老娘就宠你
6楼-- · 2019-02-04 01:21

We are using Spring boot and Java 8. This works

In ApplicationConfig.java write this

@Bean

public LocaleResolver localeResolver() {
    return new SmartLocaleResolver();
}

and I have this list in my constants class that has languages that we support

List<Locale> locales = Arrays.asList(new Locale("en"),
                                         new Locale("es"),
                                         new Locale("fr"),
                                         new Locale("es", "MX"),
                                         new Locale("zh"),
                                         new Locale("ja"));

and write the logic in the below class.

public class SmartLocaleResolver extends AcceptHeaderLocaleResolver {
          @Override
         public Locale resolveLocale(HttpServletRequest request) {
            if (StringUtils.isBlank(request.getHeader("Accept-Language"))) {
            return Locale.getDefault();
            }
            List<Locale.LanguageRange> ranges = Locale.LanguageRange.parse("da,es-MX;q=0.8");
            Locale locale = Locale.lookup(ranges, locales);
            return locale ;
        }
}
查看更多
倾城 Initia
7楼-- · 2019-02-04 01:22

I would suggest using ServletRequest.getLocales() to let the container parse Accept-Language rather than trying to manage the complexity yourself.

查看更多
登录 后发表回答