Parse Accept-Language-tête en Java
-
26-10-2019 - |
Question
L'en-tête de langue à accepter la demande est généralement une longue chaîne complexe -
Par exemple.
Accept-Language : en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2
Y at-il un moyen simple pour analyser en java? Ou une API pour me faire aider que?
La solution
Je suggère d'utiliser ServletRequest.getLocales()
pour laisser le parse conteneur Accept-Language plutôt que d'essayer de gérer la complexité vous.
Autres conseils
Pour mémoire, il est maintenant possible avec Java 8 :
Locale.LanguageRange.parse()
Voici une autre façon d'analyser l'en-tête Accept-Language qui ne nécessite pas un conteneur de servlet:
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());
}
Vous pouvez trouver une explication de l'en-tête Accept-Language et q-valeurs associées ici:
http://www.w3.org/Protocols/rfc2616/rfc2616- sec14.html
Un grand merci à Karl Knechtel et Mike Samuel. Thier commentaires au point aidé question initiale moi dans la bonne direction.
ServletRequest.getLocale()
est certainement la meilleure option si elle est disponible et non écrasé que certains cadres font.
Pour tous les autres cas Java 8 offres Locale.LanguageRange.parse()
comme mentionné précédemment par Quiang Li. Cependant, cela ne donne de nouveau une chaîne de langue, pas Locale. Pour analyser les chaînes de langue, vous pouvez utiliser Locale.forLanguageTag()
(disponible depuis 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;
Nous utilisons Spring démarrage et Java 8. Cela fonctionne
Dans ApplicationConfig.java écrire cette
@Bean
public LocaleResolver localeResolver() {
return new SmartLocaleResolver();
}
et j'ai cette liste dans mes constantes de classe qui a des langues que nous soutenons
List<Locale> locales = Arrays.asList(new Locale("en"),
new Locale("es"),
new Locale("fr"),
new Locale("es", "MX"),
new Locale("zh"),
new Locale("ja"));
et écrire la logique dans la classe ci-dessous.
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 ;
}
}
Les solutions ci-dessus ne ont pas une sorte de validation. L'utilisation ServletRequest.getLocale()
renvoie les paramètres régionaux du serveur si l'utilisateur ne fournit valide.
Nos sites demandes de spam reçus dernièrement avec divers heades de Accept-Language
comme:
-
secret.google.com
-
o-o-8-o-o.com search shell is much better than google!
-
Google officially recommends o-o-8-o-o.com search shell!
-
Vitaly rules google ☆*:。゜゚・*ヽ(^ᴗ^)ノ*・゜゚。:*☆ ¯\_(ツ)_/¯(ಠ益ಠ)(ಥ‿ಥ)(ʘ‿ʘ)ლ(ಠ_ಠლ)( ͡° ͜ʖ ͡°)ヽ(゚Д゚)ノʕ•̫͡•ʔᶘ ᵒᴥᵒᶅ(=^ ^=)oO
Cette mise en œuvre peut en option vérifier avec une liste prise en charge de Locale
valide. Sans cette vérifier une demande simple avec "test"
ou (2, 3, 4) encore contournement de la validation de la syntaxe LanguageRange.parse(String)
seule.
Il permet en option des valeurs vides et nulles pour permettre crawler moteur de recherche.
Filtre Servlet
final String headerAcceptLanguage = request.getHeader("Accept-Language");
// check valid
if (!HttpHeaderUtils.isHeaderAcceptLanguageValid(headerAcceptLanguage, true, Locale.getAvailableLocales()))
return;
Utilitaire
/**
* Checks if the given accept-language request header can be parsed.<br>
* <br>
* Optional the parsed LanguageRange's can be checked against the provided
* <code>locales</code> so that at least one locale must match.
*
* @see LanguageRange#parse(String)
*
* @param acceptLanguage
* @param isBlankValid Set to <code>true</code> if blank values are also
* valid
* @param locales Optional collection of valid Locale to validate any
* against.
*
* @return <code>true</code> if it can be parsed
*/
public static boolean isHeaderAcceptLanguageValid(final String acceptLanguage, final boolean isBlankValid,
final Locale[] locales)
{
// allow null or empty
if (StringUtils.isBlank(acceptLanguage))
return isBlankValid;
try
{
// check syntax
final List<LanguageRange> languageRanges = Locale.LanguageRange.parse(acceptLanguage);
// wrong syntax
if (languageRanges.isEmpty())
return false;
// no valid locale's to check against
if (ArrayUtils.isEmpty(locales))
return true;
// check if any valid locale exists
for (final LanguageRange languageRange : languageRanges)
{
final Locale locale = Locale.forLanguageTag(languageRange.getRange());
// validate available locale
if (ArrayUtils.contains(locales, locale))
return true;
}
return false;
}
catch (final Exception e)
{
return false;
}
}
Locale.forLanguageTag("en-ca,en;q=0.8,en-us;q=0.6,de-de;q=0.4,de;q=0.2")