Comment obtenir des paramètres régionaux à partir de sa représentation String en Java?

109

Existe-t-il un moyen efficace d'obtenir une instance de Locale à partir de son "nom programmatique" tel que renvoyé par la toString()méthode de Locale ? Une solution évidente et laide serait d'analyser la chaîne, puis de construire une nouvelle instance de Locale en fonction de cela, mais peut-être y a-t-il un meilleur moyen / solution prête pour cela?

Le besoin est que je veuille stocker certains paramètres spécifiques aux paramètres régionaux dans une base de données SQL, y compris les paramètres régionaux eux-mêmes, mais il serait moche d'y mettre des objets régionaux sérialisés. Je préférerais stocker leurs représentations String, qui semblent assez détaillées dans le détail.

Joonas Pulakka
la source

Réponses:

34

Voir le Locale.getLanguage(), Locale.getCountry()... Stocker cette combinaison dans la base de données au lieu de "programatic name"...
Lorsque vous souhaitez reconstruire les paramètres régionaux, utilisezpublic Locale(String language, String country)

Voici un exemple de code :)

// May contain simple syntax error, I don't have java right now to test..
// but this is a bigger picture for your algo...
public String localeToString(Locale l) {
    return l.getLanguage() + "," + l.getCountry();
}

public Locale stringToLocale(String s) {
    StringTokenizer tempStringTokenizer = new StringTokenizer(s,",");
    if(tempStringTokenizer.hasMoreTokens())
    String l = tempStringTokenizer.nextElement();
    if(tempStringTokenizer.hasMoreTokens())
    String c = tempStringTokenizer.nextElement();
    return new Locale(l,c);
}
raj
la source
3
Cela ne compilerait même pas.
Adrian
1
@raj pourquoi utiliser tokenizer, si Java vous donne des méthodes prêtes? par exemple toLocale (String str). Veuillez voir les exemples dans la réponse
VdeX
9
Vous devriez utiliser Locale.forLanguageTag (String)
Rian
126

La méthode qui renvoie les paramètres régionaux à partir de la chaîne existe dans la bibliothèque commons-lang: LocaleUtils.toLocale(localeAsString)

yurilo
la source
2
LocaleUtils.toLocale ne prend pas en charge les chaînes comme «zh-Hans», «pt-PT», etc.
Hans van Dodewaard
10
Si vous avez un trait d'union -entre les parties locales, vous avez affaire à une balise IETF BCP 47, si vous utilisez Java 7, vous pouvez l'utiliserLocale.forLanguageTag
Jaime Hablutzel
59

Depuis Java 7, il existe une méthode d'usine Locale.forLanguageTaget une méthode d'instance Locale.toLanguageTagutilisant des balises de langage IETF .

nilskp
la source
8
Je veux juste souligner que Locale.forLanguageTagfonctionne les chaînes locales IETF (ie en-US) et ne fonctionne pas avec les chaînes locales ISO (ie en_US)
Fabian
34
  1. Java fournit beaucoup de choses avec une implémentation appropriée, beaucoup de complexité peut être évitée. Cela renvoie ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons doit LocaleUtilsaider à analyser une représentation sous forme de chaîne. Cela renverra en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Vous pouvez également utiliser des constructeurs de paramètres régionaux.

    // Construct a locale from a language code.(eg: en)
    new Locale(String language)
    // Construct a locale from language and country.(eg: en and US)
    new Locale(String language, String country)
    // Construct a locale from language, country and variant.
    new Locale(String language, String country, String variant)

Veuillez vérifier ce LocaleUtils et ce Locale pour explorer plus de méthodes.

VdeX
la source
1
LocaleUtils.toLocale (localeStringRepresentation) fait parfaitement le travail. Aussi si vous voyez l'implémentation de cette méthode, c'est assez complet!
Plat du
15

Option 1 :

org.apache.commons.lang3.LocaleUtils.toLocale("en_US")

Option 2 :

Locale.forLanguageTag("en-US")

Veuillez noter que l' option 1 est un «trait de soulignement» entre la langue et le pays, et l' option 2 est un «tiret».

junjun
la source
L'appel nécessite le niveau d'API 21 (le minimum actuel est de 17): java.util.Locale # forLanguageTag
Vlad
12

Cette réponse est peut-être un peu tardive, mais il s'avère que l'analyse de la chaîne n'est pas aussi moche que l'OP l'a supposé. Je l'ai trouvé assez simple et concis:

public static Locale fromString(String locale) {
    String parts[] = locale.split("_", -1);
    if (parts.length == 1) return new Locale(parts[0]);
    else if (parts.length == 2
            || (parts.length == 3 && parts[2].startsWith("#")))
        return new Locale(parts[0], parts[1]);
    else return new Locale(parts[0], parts[1], parts[2]);
}

J'ai testé ceci (sur Java 7) avec tous les exemples donnés dans la documentation Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Hant-x-java "et" th_TH_TH_ # u-nu-thai ".

MISE À JOUR IMPORTANTE : Ceci n'est pas recommandé pour une utilisation dans Java 7+ selon la documentation :

En particulier, les clients qui analysent la sortie de toString dans les champs de langue, de pays et de variante peuvent continuer à le faire (bien que cela soit fortement déconseillé ), bien que le champ de variante contienne des informations supplémentaires si un script ou des extensions sont présents.

Utilisez plutôt Locale.forLanguageTag et Locale.toLanguageTag, ou si vous devez le faire, Locale.Builder.

Andy
la source
5
Java 7 Locale.forLanguageTags'applique uniquement aux balises de langue encodées comme indiqué dans le BCP 47 de l'IETF, avec un tiret ( -), pas un trait de soulignement ( _) comme dans le retour de Localela toStringméthode de
Jaime Hablutzel
1
Vous avez raison. Il reste encore un moyen de convertir les représentations locales existantes au format BCP47. Mon intention était de suggérer qu'à l'avenir, les Locales ne devraient pas être stockés sous leur toStringforme, mais sous leur toLanguageTagforme, qui est convertible en une forme Localeplus facile et plus précise.
andy
Cette méthode n'aurait-elle pas un certain nombre de cas extrêmes qui pourraient entraîner un index hors limites?
user2524908
@ user2524908: Je ne pense pas, car il teste toujours la longueur du tableau avant d'accéder à ses éléments. La solution peut avoir de nombreux cas
extrêmes
9

Si vous utilisez Spring Framework dans votre projet, vous pouvez également utiliser:

org.springframework.util.StringUtils.parseLocaleString("en_US");

Documentation :

Analyser la représentation String donnée dans un paramètre régional

Javad Alimohammadi
la source
La documentation à ce sujet dit que c'est spécifiquement l'inverse de Locale#toString()- parfait! :)
jocull
3

Il ne semble pas y avoir de valueOfméthode statique pour cela, ce qui est un peu surprenant.

Une manière plutôt moche, mais simple, serait de répéter Locale.getAvailableLocales(), de comparer leurs toStringvaleurs avec votre valeur.

Pas très agréable, mais aucune analyse de chaîne n'est requise. Vous pouvez pré-remplir une Mapdes chaînes de paramètres régionaux et rechercher votre chaîne de base de données dans cette carte.

skaffman
la source
Ah, l'itération pourrait être une solution tout à fait raisonnable. En effet, il est surprenant que Locale n'ait pas de méthode statique pour cela.
Joonas Pulakka
Les Localeinstances prédéfinies ne représentent qu'un très petit sous-ensemble de paramètres régionaux valides. Ce n'est en aucun cas complet.
BetaRide
3

Vous pouvez l'utiliser sur Android. Fonctionne bien pour moi.

private static final Pattern localeMatcher = Pattern.compile
        ("^([^_]*)(_([^_]*)(_#(.*))?)?$");

public static Locale parseLocale(String value) {
    Matcher matcher = localeMatcher.matcher(value.replace('-', '_'));
    return matcher.find()
            ? TextUtils.isEmpty(matcher.group(5))
                ? TextUtils.isEmpty(matcher.group(3))
                    ? TextUtils.isEmpty(matcher.group(1))
                        ? null
                        : new Locale(matcher.group(1))
                    : new Locale(matcher.group(1), matcher.group(3))
                : new Locale(matcher.group(1), matcher.group(3),
                             matcher.group(5))
            : null;
}
Mon Dieu
la source
1

Eh bien, je stockerais à la place une concaténation de chaînes de Locale.getISO3Language(), getISO3Country()et getVariant () comme clé, ce qui me permettrait d'appeler plus tard le Locale(String language, String country, String variant)constructeur.

en effet, s'appuyer sur displayLanguage implique d'utiliser le langage de la locale pour l'afficher, ce qui la rend dépendante de la locale, contrairement au code de langue iso.

À titre d'exemple, la clé de locale serait stockable comme

en_EN
en_US

etc ...

Riduidel
la source
1

Parce que je viens de l'implémenter:

Dans Groovy/ Grailsce serait:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Martin L.
la source