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.

Joonas Pulakka
fonte

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);
}
raj
fonte
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)

yurilo
fonte
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 .

nilskp
fonte
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.

VdeX
fonte
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".

Junjun
fonte
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.

Andy
fonte
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

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

Pergunta antiga com muitas respostas, mas aqui estão mais soluções:

Tauren
fonte
O exemplo do java2s é muito bom e também inclui a manipulação de variantes
Paul Gregoire,
O primeiro URL é tudo que eu queria .. Obrigado
KD.
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.

skaffman
fonte
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;
}
Meu Deus
fonte
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 ...

Riduidel
fonte
1

Porque acabei de implementá-lo:

Em Groovy/ Grailsseria:

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