¿Cómo obtener la configuración regional de su representación de cadena en Java?

109

¿Existe una forma ordenada de obtener una instancia de Locale a partir de su "nombre programático" como lo devuelve el toString()método de Locale ? Una solución obvia y fea sería analizar la Cadena y luego construir una nueva instancia de Locale de acuerdo con eso, pero ¿tal vez haya una mejor manera / solución lista para eso?

La necesidad es que quiero almacenar algunas configuraciones específicas de la configuración regional en una base de datos SQL, incluidas las configuraciones regionales, pero sería feo colocar allí objetos de configuración regional serializados. Preferiría almacenar sus representaciones de cadenas, que parecen ser bastante adecuadas en detalle.

Joonas Pulakka
fuente

Respuestas:

34

Vea Locale.getLanguage(), Locale.getCountry()... Almacene esta combinación en la base de datos en lugar de "programatic name"...
Cuando desee volver a generar la configuración regional, utilicepublic Locale(String language, String country)

Aquí hay un código de muestra :)

// 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
fuente
3
Esto ni siquiera se compilaría.
Adrian
1
@raj ¿por qué usar tokenizer, si Java te ofrece métodos listos? por ejemplo, toLocale (String str). Consulte los ejemplos en la respuesta
VdeX
9
Debería usar Locale.forLanguageTag (String)
Rian
126

El método que devuelve la configuración regional de la cadena existe en la biblioteca commons-lang: LocaleUtils.toLocale(localeAsString)

yurilo
fuente
2
LocaleUtils.toLocale no admite cadenas como 'zh-Hans', 'pt-PT', etc.
Hans van Dodewaard
10
Si usted tiene un guión -entre las partes de la configuración regional que está tratando con una etiqueta de IETF BCP 47, si está utilizando Java 7 se pueden utilizarLocale.forLanguageTag
Jaime Hablutzel
59

Desde Java 7, existe un método de fábrica Locale.forLanguageTagy un método de instancia que Locale.toLanguageTagutiliza etiquetas de lenguaje IETF .

nilskp
fuente
8
Solo quiero enfatizar que Locale.forLanguageTagfunciona con cadenas de configuración regional IETF (es decir en-US) y no funciona con cadenas de configuración regional ISO (es decir en_US)
Fabian
34
  1. Java proporciona muchas cosas con una implementación adecuada y se puede evitar mucha complejidad. Esto devuelve ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons tiene LocaleUtilsque ayudar a analizar una representación de cadena. Esto devolverá en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. También puede utilizar constructores de configuración regional.

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

Consulte este LocaleUtils y este Locale para explorar más métodos.

VdeX
fuente
1
LocaleUtils.toLocale (localeStringRepresentation) hace el trabajo perfectamente. Además, si ve la implementación de este método, ¡es bastante completo!
Plato
15

Opción 1 :

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

Opcion 2 :

Locale.forLanguageTag("en-US")

Tenga en cuenta que la opción 1 es "guión bajo" entre el idioma y el país, y la opción 2 es "guión".

junjun
fuente
La llamada requiere API nivel 21 (el mínimo actual es 17): java.util.Locale # forLanguageTag
Vlad
12

Esta respuesta puede llegar un poco tarde, pero resulta que analizar la cadena no es tan feo como suponía el OP. Lo encontré bastante simple y 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]);
}

Probé esto (en Java 7) con todos los ejemplos dados en la documentación de Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Hant-x-java "y" th_TH_TH_ # u-nu-thai ".

ACTUALIZACIÓN IMPORTANTE : No se recomienda su uso en Java 7+ de acuerdo con la documentación :

En particular, los clientes que analizan la salida de toString en campos de idioma, país y variantes pueden continuar haciéndolo (aunque se desaconseja enfáticamente ), aunque el campo de variantes tendrá información adicional si hay secuencias de comandos o extensiones presentes.

En su lugar, use Locale.forLanguageTag y Locale.toLanguageTag, o si debe hacerlo, Locale.Builder.

Andy
fuente
5
Java 7 se Locale.forLanguageTagaplica solo para las etiquetas de idioma codificadas como se indica en el BCP 47 de IETF, con un guión ( -), no un guión bajo ( _) como en el método de retorno de Locale'toString
Jaime Hablutzel
1
Tienes razón. Todavía es necesario que haya alguna forma de convertir las representaciones locales existentes al formato BCP47. Mi intención era sugerir que, en el futuro, Localelos mensajes de correo electrónico no deben almacenarse en su toStringforma, sino en su toLanguageTagforma, que es convertible de nuevo a una forma Localemás fácil y precisa.
Andy
¿No tendría este método una serie de casos extremos que podrían causar que el índice se salga de los límites?
user2524908
@ user2524908: No lo creo, ya que siempre está probando la longitud de la matriz antes de acceder a sus elementos. La solución puede tener muchos casos
extremos
9

Si está usando Spring Framework en su proyecto, también puede usar:

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

Documentación :

Analizar la representación de cadena dada en una configuración regional

Javad Alimohammadi
fuente
Los documentos sobre esto dicen que es específicamente lo contrario de Locale#toString(): ¡perfecto! :)
jocull
3

No parece haber un valueOfmétodo estático para esto, lo cual es un poco sorprendente.

Una forma bastante fea, pero simple, sería iterar Locale.getAvailableLocales(), comparando sus toStringvalores con el tuyo.

No es muy agradable, pero no se requiere análisis de cadenas. Puede rellenar previamente una Mapde las cadenas a las configuraciones regionales y buscar la cadena de su base de datos en ese mapa.

skaffman
fuente
Ah, la iteración podría ser una solución bastante razonable. De hecho, es sorprendente que Locale no tenga un método estático para esto.
Joonas Pulakka
Las Localeinstancias predefinidas representan solo un subconjunto muy pequeño de configuraciones regionales válidas. De ninguna manera está completo.
BetaRide
3

Puedes usar esto en Android. Funciona bien para mi.

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;
}
Dios mío
fuente
1

Bueno, almacenaría en su lugar una concatenación de cadenas de Locale.getISO3Language(), getISO3Country()y getVariant () como clave, lo que me permitiría llamar al Locale(String language, String country, String variant)constructor.

de hecho, confiar en displayLanguage implica usar el idioma de la configuración regional para mostrarlo, lo que lo hace dependiente de la configuración regional, al contrario del código de idioma iso.

Como ejemplo, la clave en locale sería almacenable como

en_EN
en_US

y así ...

Riduidel
fuente
1

Porque lo acabo de implementar:

En Groovy/ Grailssería:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Martín L.
fuente