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?

Était-ce utile?

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:

  1. secret.google.com
  2. o-o-8-o-o.com search shell is much better than google!
  3. Google officially recommends o-o-8-o-o.com search shell!
  4. 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")
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top