Come ottenere Locale dalla sua rappresentazione in stringa in Java?


109

Esiste un modo semplice per ottenere un'istanza Locale dal suo "nome programmatico" restituito dal toString()metodo Locale ? Una soluzione ovvia e brutta sarebbe analizzare la stringa e quindi costruire una nuova istanza Locale in base a ciò, ma forse c'è un modo migliore / soluzione pronta per questo?

La necessità è che io voglia memorizzare alcune impostazioni specifiche della locale in un database SQL, comprese le impostazioni locali stesse, ma sarebbe brutto mettere lì oggetti localizzati serializzati. Preferisco memorizzare le loro rappresentazioni String, che sembrano essere abbastanza adeguate nei dettagli.

Risposte:


34

Vedere Locale.getLanguage(), Locale.getCountry()... Memorizza questa combinazione nel database invece di "programatic name"...
Quando si desidera ricostruire le impostazioni locali, utilizzarepublic Locale(String language, String country)

Ecco un codice di esempio :)

// 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);
}

3
Questo non si compilerebbe nemmeno.
Adrian

1
@raj perché usare tokenizer, se Java ti fornisce metodi pronti? ad esempio toLocale (String str). Vedi esempi nella risposta
VdeX

9
Dovresti usare Locale.forLanguageTag (String)
Rian

126

Il metodo che restituisce la lingua dalla stringa esiste nella libreria commons-lang: LocaleUtils.toLocale(localeAsString)


2
LocaleUtils.toLocale non supporta stringhe come 'zh-Hans', 'pt-PT', ecc.
Hans van Dodewaard

10
Se hai un trattino -tra le parti locali hai a che fare con un tag IETF BCP 47, se stai usando Java 7 puoi usareLocale.forLanguageTag
Jaime Hablutzel

59

A partire da Java 7 esiste un metodo di fabbrica Locale.forLanguageTage un metodo di istanza che Locale.toLanguageTagutilizza i tag del linguaggio IETF .


8
Voglio solo sottolineare che Locale.forLanguageTagfunziona con le stringhe locali IETF (cioè en-US) e non funziona con le stringhe locali ISO (cioè en_US)
Fabian

34
  1. Java fornisce molte cose con una corretta implementazione, molte complessità possono essere evitate. Ciò restituisce ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons deve LocaleUtilsaiutare ad analizzare una rappresentazione di stringa. Questo restituirà en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. È inoltre possibile utilizzare i costruttori di impostazioni locali.

    // 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)

Controlla questo LocaleUtils e questo Locale per esplorare altri metodi.


1
LocaleUtils.toLocale (localeStringRepresentation) fa il lavoro in modo ordinato. Inoltre, se vedi l'implementazione di questo metodo, è abbastanza completo!
Piatto

15

Opzione 1 :

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

Opzione 2 :

Locale.forLanguageTag("en-US")

Tieni presente che l' opzione 1 è "trattino basso" tra lingua e paese e l' opzione 2 è "trattino".


La chiamata richiede il livello API 21 (il minimo attuale è 17): java.util.Locale # forLanguageTag
Vlad

12

Questa risposta potrebbe essere un po 'in ritardo, ma risulta che l'analisi della stringa non è così brutta come ipotizzato dall'OP. L'ho trovato abbastanza semplice e conciso:

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]);
}

L'ho testato (su Java 7) con tutti gli esempi forniti nella documentazione Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Hant-x-java "e" th_TH_TH_ # u-nu-thai ".

AGGIORNAMENTO IMPORTANTE : questo non è consigliato per l'uso in Java 7+ secondo la documentazione :

In particolare, i client che analizzano l'output di toString nei campi lingua, paese e variante possono continuare a farlo (sebbene ciò sia fortemente sconsigliato ), sebbene il campo variante disporrà di informazioni aggiuntive se sono presenti script o estensioni.

Utilizza invece Locale.forLanguageTag e Locale.toLanguageTag o, se necessario, Locale.Builder.


5
Java 7 Locale.forLanguageTagsi applica solo per la lingua tag codificati come indicato in BCP di IETF 47, con un trattino ( -), non un carattere di sottolineatura ( _), come nel ritorno del Locale's toStringmetodo
Jaime Hablützel

1
Hai ragione. È ancora necessario un modo per convertire le rappresentazioni locali esistenti nel formato BCP47. La mia intenzione era di suggerire che andando avanti, Localei messaggi di posta elettronica non dovrebbero essere memorizzati nella loro toStringforma, ma nella loro toLanguageTagforma, che è convertibile di nuovo in una Localepiù facilmente e accuratamente.
andy

Questo metodo non avrebbe un numero di casi limite che potrebbero causare l'indice fuori dai limiti?
user2524908

@ user2524908: Non credo, poiché verifica sempre la lunghezza dell'array prima di accedere ai suoi elementi. La soluzione potrebbe avere molti casi limite in cui non funziona correttamente, ma non "indice fuori limite"
MestreLion

9

Se stai usando Spring framework nel tuo progetto puoi anche usare:

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

Documentazione :

Analizza la rappresentazione String data in una Locale


I documenti su questo dicono che è specificamente l'inverso di Locale#toString()- perfetto! :)
jocull


3

Non sembra esserci un valueOfmetodo statico per questo, il che è un po 'sorprendente.

Un modo piuttosto brutto, ma semplice, sarebbe quello di iterare Locale.getAvailableLocales(), confrontando i loro toStringvalori con il tuo valore.

Non molto carino, ma non è richiesta l'analisi delle stringhe. È possibile precompilare una Mapdelle stringhe in Impostazioni locali e cercare la stringa del database in quella mappa.


Ah, l'iterazione potrebbe essere una soluzione abbastanza ragionevole. In effetti è sorprendente che Locale non abbia un metodo statico per questo.
Joonas Pulakka

Le Localeistanze predefinite rappresentano solo un piccolo sottoinsieme di impostazioni locali valide. Non è affatto completo.
BetaRide

3

Puoi usarlo su Android. Funziona bene per me.

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;
}

1

Beh, vorrei conservare invece una concatenazione di stringhe di Locale.getISO3Language(), getISO3Country()e getVariant () come la chiave, che mi permetterebbe di chiamata quest'ultimo Locale(String language, String country, String variant)costruttore.

infatti, affidarsi a displayLanguage implica usare la lingua di locale per visualizzarlo, il che lo rende dipendente dalla locale, contrariamente al codice della lingua iso.

Ad esempio, la chiave en locale sarebbe memorizzabile come

en_EN
en_US

e così via ...


1

Perché l'ho appena implementato:

In Groovy/ Grailssarebbe:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.