Como obter Locale de sua representação String em Java?


109

Existe uma maneira simples de obter uma instância do Locale a partir de seu "nome programático" conforme retornado pelo toString()método do Locale ? Uma solução óbvia e feia seria analisar a String e, em seguida, construir uma nova instância Locale de acordo com isso, mas talvez haja uma maneira / solução pronta melhor para isso?

A necessidade é que eu queira armazenar algumas configurações específicas do local em um banco de dados SQL, incluindo os próprios locais, mas seria feio colocar objetos Locale serializados lá. Prefiro armazenar suas representações de String, que parecem ser bastante adequadas em detalhes.

Respostas:


34

Veja o Locale.getLanguage(), Locale.getCountry()... Armazene esta combinação no banco de dados em vez de "programatic name"...
Quando você quiser construir o Locale de volta, usepublic Locale(String language, String country)

Aqui está um exemplo de código :)

// 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
Isso nem mesmo compilava.
Adrian

1
@raj por que usar o tokenizer, se o Java fornece métodos prontos? por exemplo, toLocale (String str). Veja os exemplos de resposta
VdeX

9
Você deve usar Locale.forLanguageTag (String)
Rian

126

Método que retorna a localidade da string existente na biblioteca commons-lang: LocaleUtils.toLocale(localeAsString)


2
LocaleUtils.toLocale não suporta strings como 'zh-Hans', 'pt-PT', etc.
Hans van Dodewaard

10
Se você tiver um hífen -entre as partes do local, você está lidando com uma tag IETF BCP 47, se estiver usando Java 7, você pode usarLocale.forLanguageTag
Jaime Hablutzel

59

Desde o Java 7, há o método de fábrica Locale.forLanguageTage o método de instância Locale.toLanguageTagusando tags de linguagem IETF .


8
Só quero enfatizar que Locale.forLanguageTagfunciona com strings de localidade IETF (isto é en-US) e não funciona com strings de localidade ISO (isto é en_US)
Fabian

34
  1. Java fornece muitas coisas com implementação adequada, muita complexidade pode ser evitada. Isso retorna ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. O Apache Commons tem LocaleUtilsque ajudar a analisar uma representação de string. Isso retornará en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Você também pode usar construtores de localidade.

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

Verifique este LocaleUtils e este Locale para explorar mais métodos.


1
LocaleUtils.toLocale (localeStringRepresentation) faz o trabalho perfeitamente. Além disso, se você vir a implementação desse método, é bastante abrangente!
Prato de

15

Opção 1 :

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

Opção 2 :

Locale.forLanguageTag("en-US")

Observe que a Opção 1 é "sublinhado" entre o idioma e o país, e a Opção 2 é "traço".


A chamada requer API de nível 21 (mínimo atual é 17): java.util.Locale # forLanguageTag
Vlad

12

Esta resposta pode demorar um pouco, mas descobri que analisar a string não é tão feio quanto o OP presumiu. Achei muito simples 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]);
}

Eu testei isso (no Java 7) com todos os exemplos fornecidos na documentação 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 ".

ATUALIZAÇÃO IMPORTANTE : Não é recomendado para uso em Java 7+ de acordo com a documentação :

Em particular, os clientes que analisam a saída de toString em campos de idioma, país e variantes podem continuar a fazê-lo (embora isso seja fortemente desencorajado ), embora o campo variante contenha informações adicionais se script ou extensões estiverem presentes.

Use Locale.forLanguageTag e Locale.toLanguageTag em vez disso ou, se necessário, Locale.Builder.


5
Java 7 Locale.forLanguageTagaplica-se somente para tags de linguagem codificados como indicado no BCP do IETF 47, com um hífen ( -), não um sublinhado ( _) como no retorno de Locale's toStringmétodo
Jaime Hablutzel

1
Você está certo. Ainda precisa haver alguma maneira de converter as representações Locale existentes para o formato BCP47. Minha intenção era sugerir que, daqui para frente, os Locales não deveriam ser armazenados em sua toStringforma, mas em sua toLanguageTagforma, que pode ser convertida de volta para uma forma Localemais fácil e precisa.
Andy

Este método não teria um número de casos extremos que poderiam causar o índice fora dos limites?
user2524908

@ user2524908: Acho que não, pois ele está sempre testando o comprimento do array antes de acessar seus elementos. A solução pode ter muitos casos
extremos

9

Se você estiver usando o framework Spring em seu projeto, também pode usar:

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

Documentação :

Analisa a representação de string fornecida em um local


Os documentos dizem que é especificamente o inverso de Locale#toString()- perfeito! :)
jocull


3

Não parece haver um valueOfmétodo estático para isso, o que é um pouco surpreendente.

Uma maneira bastante feia, mas simples, seria repetir Locale.getAvailableLocales(), comparando seus toStringvalores com o seu valor.

Não é muito bom, mas nenhuma análise de string necessária. Você pode preencher previamente um MapStrings to Locales e procurar a string do banco de dados nesse mapa.


Ah, a iteração pode ser uma solução bastante razoável. Na verdade, é surpreendente que o Locale não tenha um método estático para isso.
Joonas Pulakka

As Localeinstâncias predefinidas representam um subconjunto muito pequeno de apenas localidades válidas. Não está de forma alguma completo.
BetaRide de

3

Você pode usar isso no Android. Funciona bem para mim.

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

Bem, eu armazenaria em vez disso uma concatenação de string de Locale.getISO3Language(), getISO3Country()e getVariant () como chave, o que me permitiria chamar o Locale(String language, String country, String variant)construtor posteriormente .

na verdade, confiar em displayLanguage implica em usar o idioma do locale para exibi-lo, o que o torna dependente do local, ao contrário do código de idioma iso.

Por exemplo, uma chave local seria armazenável como

en_EN
en_US

e assim por diante ...


1

Porque acabei de implementá-lo:

Em Groovy/ Grailsseria:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.