Jak uzyskać Locale z jego reprezentacji String w Javie?


109

Czy istnieje zgrabny sposób na pobranie instancji Locale z jej „nazwy programowej” zwróconej przez toString()metodę Locale ? Oczywistym i brzydkim rozwiązaniem byłoby przeanalizowanie ciągu znaków, a następnie skonstruowanie nowej instancji Locale zgodnie z tym, ale może jest na to lepszy sposób / gotowe rozwiązanie?

Potrzeba jest taka, że ​​chcę przechowywać pewne ustawienia regionalne w bazie danych SQL, w tym same ustawienia regionalne, ale byłoby brzydko umieszczać tam zserializowane obiekty Locale. Wolałbym raczej przechowywać ich reprezentacje String, które wydają się być dość szczegółowe w szczegółach.

Odpowiedzi:


34

Zobacz Locale.getLanguage(), Locale.getCountry()... Przechowuj tę kombinację w bazie danych zamiast "programatic name"...
Jeśli chcesz przywrócić ustawienia regionalne, użyjpublic Locale(String language, String country)

Oto przykładowy kod :)

// 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
To się nawet nie skompiluje.
— Adrian

1
@raj po co używać tokenizera, skoro Java daje gotowe metody? np. toLocale (String str). Zobacz przykłady w odpowiedzi
— VdeX,

9
Powinieneś używać Locale.forLanguageTag (String)
— Rian,

126

Metoda zwracająca locale z stringa istnieje w bibliotece commons-lang: LocaleUtils.toLocale(localeAsString)


2
LocaleUtils.toLocale nie obsługuje ciągów, takich jak „zh-Hans”, „pt-PT” itp.
— Hans van Dodewaard

10
Jeśli masz łącznik -między częściami lokalnymi, masz do czynienia ze znacznikiem IETF BCP 47, jeśli używasz Java 7, możesz użyćLocale.forLanguageTag
— Jaime Hablutzel

59

Od wersji Java 7 istnieje metoda fabryczna Locale.forLanguageTagi metoda instancji Locale.toLanguageTagwykorzystująca znaczniki języka IETF .


8
Chcę tylko podkreślić, że Locale.forLanguageTagdziała z łańcuchami ustawień regionalnych IETF (tj. en-US) I nie działa z ciągami ustawień regionalnych ISO (tj. en_US)
— Fabian

34
  1. Java zapewnia wiele rzeczy przy prawidłowej implementacji, dzięki czemu można uniknąć wielu złożoności. Zwraca ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons musi LocaleUtilspomóc przeanalizować reprezentację ciągu. To zwróci en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Możesz także użyć konstruktorów ustawień regionalnych.

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

Sprawdź to LocaleUtils i to Locale, aby poznać więcej metod.


1
LocaleUtils.toLocale (localeStringRepresentation) robi to starannie. Również jeśli widzisz implementację tej metody, jest ona dość wszechstronna!
— Danie

15

Opcja 1 :

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

Opcja 2 :

Locale.forLanguageTag("en-US")

Pamiętaj, że opcja 1 to „podkreślenie” między językiem a krajem, a opcja 2 to „myślnik”.


Wywołanie wymaga interfejsu API na poziomie 21 (obecnie minimum to 17): java.util.Locale # forLanguageTag
— Vlad,

12

Ta odpowiedź może być trochę spóźniona, ale okazuje się, że analiza ciągu nie jest tak brzydka, jak zakładał OP. Wydało mi się to dość proste i zwięzłe:

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

Przetestowałem to (na Javie 7) ze wszystkimi przykładami podanymi w dokumentacji Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Hant-x-java ”i„ th_TH_TH_ # u-nu-thai ”.

WAŻNA AKTUALIZACJA : Nie jest to zalecane do użytku w Javie 7+ zgodnie z dokumentacją :

W szczególności klienci, którzy analizują dane wyjściowe metody toString na pola języka, kraju i wariantu, mogą nadal to robić (chociaż jest to zdecydowanie odradzane ), chociaż pole wariantu będzie zawierało dodatkowe informacje, jeśli obecny jest skrypt lub rozszerzenia.

Zamiast tego użyj Locale.forLanguageTag i Locale.toLanguageTag lub, jeśli musisz, Locale.Builder.


5
Java 7 Locale.forLanguageTagstosuje się tylko do języka znaczników kodowanych, jak wskazano w IETF BCP 47, z łącznikiem ( -), nie podkreślenia ( _), jak w zwrocie Locale„s toStringmetody
— Jaime Hablutzel

1
Masz rację. Nadal musi być jakiś sposób na przekonwertowanie istniejących reprezentacji ustawień regionalnych do formatu BCP47. Chciałem zasugerować, że idąc dalej, Locales nie powinny być przechowywane w ich toStringformie, ale w toLanguageTagformie, którą można zamienić z powrotem na Localełatwiejszą i dokładniejszą.
— andy

Czy ta metoda nie miałaby wielu przypadków skrajnych, które mogłyby spowodować przekroczenie granic indeksu?
— user2524908

@ user2524908: Nie sądzę, ponieważ zawsze testuje długość tablicy przed uzyskaniem dostępu do jej elementów. Rozwiązanie może mieć wiele
— skrajnych

9

Jeśli korzystasz z Spring Framework w swoim projekcie, możesz również użyć:

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

Dokumentacja :

Przeanalizuj podaną reprezentację String w locale


Dokumenty na ten temat mówią, że jest to dokładnie odwrotność Locale#toString()- idealnie! :)
— żartobliwy


3

Wydaje się, że nie ma na to statycznej valueOfmetody, co jest nieco zaskakujące.

Jednym raczej brzydkim, ale prostym sposobem byłoby powtórzenie Locale.getAvailableLocales()i porównanie ich toStringwartości z wartością.

Niezbyt ładne, ale nie jest wymagane analizowanie ciągu. Możesz wstępnie wypełnić Mapciągi znaków na lokalizacje i wyszukać łańcuch bazy danych w tej mapie.


Ach, ta iteracja może być całkiem rozsądnym rozwiązaniem. Rzeczywiście jest zaskakujące, że Locale nie ma na to statycznej metody.
— Joonas Pulakka

Predefiniowane Localeinstancje reprezentują tylko niewielki podzbiór prawidłowych ustawień regionalnych. To wcale nie jest kompletne.
— BetaRide

3

Możesz tego użyć na Androidzie. U mnie działa dobrze.

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

Cóż, chciałbym przechowywać zamiast konkatenacji ciąg Locale.getISO3Language(), getISO3Country()i getVariant () jako klucz, który pozwoliłby mnie do ostatniego wywołania Locale(String language, String country, String variant)konstruktora.

w rzeczywistości poleganie na displayLanguage implikuje użycie języka locale do jego wyświetlenia, co czyni go zależnym od locale, w przeciwieństwie do kodu języka ISO.

Na przykład klucz en locale mógłby być przechowywany jako

en_EN
en_US

i tak dalej ...


1

Ponieważ właśnie to zaimplementowałem:

W Groovy/ Grailsto byłoby:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.