Як отримати Locale з його представлення String на Java?


109

Чи є акуратний спосіб отримати екземпляр Locale з його "програмного імені", поверненого методом Locale toString()? Очевидним і потворним рішенням буде розбір String, а потім побудова нового екземпляра Locale відповідно до цього, але, можливо, є кращий спосіб / готове рішення для цього?

Необхідність полягає в тому, що я хочу зберігати деякі параметри, визначені для місцевості, в базі даних SQL, включаючи самі Locales, але було б неприємно розміщувати туди серіалізовані локальні об’єкти. Я вважаю за краще зберігати їхні строкові уявлення, які, як видається, є досить адекватними у деталях.

Відповіді:


34

Дивіться Locale.getLanguage(), Locale.getCountry()... Зберігайте цю комбінацію в базі даних замість "programatic name"...
Коли ви хочете зібрати Локальну систему назад, використовуйтеpublic Locale(String language, String country)

Ось зразок коду :)

// 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
Це навіть не складеться.
Адріан

1
@raj навіщо використовувати токенізатор, якщо Java дає вам готові методи? наприклад, toLocale (String str). Дивіться приклади у відповідь
VdeX

9
Ви повинні використовувати Locale.forLanguageTag (String)
Rian

126

Метод, який повертає локаль із рядка, існує в бібліотеці commons-lang: LocaleUtils.toLocale(localeAsString)


2
LocaleUtils.toLocale не підтримує рядки типу "zh-Hans", "pt-PT" тощо.
Hans van Dodewaard,

10
Якщо у вас є дефіс -між локальними частинами, ви маєте справу з тегом IETF BCP 47, якщо ви використовуєте Java 7, ви можете використовуватиLocale.forLanguageTag
Jaime Hablutzel

59

З Java 7 існує заводський метод Locale.forLanguageTagта метод екземпляра, що Locale.toLanguageTagвикористовує теги мови IETF .


8
Просто хочу підкреслити, що Locale.forLanguageTagпрацює рядки локалі IETF (тобто en-US) і не працюють з рядками en_US
Fabian

34
  1. Java забезпечує багато речей, при правильній реалізації можна уникнути багатьох складностей. Це повертає ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons має LocaleUtilsдопомогти розібрати представлення рядків. Це поверне en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Також можна використовувати локальні конструктори.

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

Перевірте цей LocaleUtils та цей Locale, щоб вивчити інші методи.


1
LocaleUtils.toLocale (localeStringRepresentation) виконує роботу акуратно. Також якщо ви бачите реалізацію цього методу, він цілком всебічний!
Блюдо

15

Варіант 1:

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

Варіант 2:

Locale.forLanguageTag("en-US")

Зверніть увагу, що варіант 1 - "підкреслення" між мовою та країною, а варіант 2 - "тире".


Для виклику потрібен рівень 21 (поточний хв. 17): java.util.Locale # forLanguageTag
Влад

12

Ця відповідь може трохи пізно, але виявляється, що розбір рядка не такий потворний, як припускав ОП. Я вважав це досить простим і стислим:

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

Я перевірив це (на Java 7) з усіма прикладами, наведеними в документації Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Хант-х-джава "та" th_TH_TH_ # у-ну-тай ".

ВАЖЛИВО ОНОВЛЕННЯ : Це не рекомендується використовувати в Java 7+ відповідно до документації :

Зокрема, клієнти, які розбирають вихід ToString на мови, країну та варіанти варіантів, можуть продовжувати це робити (хоча це сильно не рекомендується ), хоча поле варіанта буде в ньому додатковою інформацією, якщо присутні скрипт або розширення.

Використовуйте Locale.forLanguageTag та Locale.toLanguageTag замість цього, або якщо потрібно, Locale.Builder.


5
Java 7 Locale.forLanguageTagзастосовується лише до мовних тегів, кодованих, як зазначено в BCP 47 IETF, з дефісом ( -), а не підкресленням ( _), як у відповідь на метод Locale'toString
Jaime Hablutzel

1
Ти маєш рацію. Існує ще якийсь спосіб перетворити існуючі представлення локалів у формат BCP47. Мій намір полягав у тому, щоб запропонувати, що йти вперед Localeне слід зберігати їх у toStringформі, а у тому toLanguageTagвигляді, який можна конвертувати назад у Localeбільш легкий та точний спосіб.
andy

Чи не було б у цього методу ряд крайових випадків, які можуть викликати індекс поза межами?
користувач2524908

@ user2524908: Я не думаю, що він завжди перевіряє довжину масиву, перш ніж отримати доступ до його елементів. У рішенні може бути безліч кращих випадків, коли воно не працює належним чином, але не "індексується поза межами"
MestreLion

9

Якщо ви використовуєте Spring Framework у своєму проекті, ви також можете використовувати:

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

Документація :

Проаналізуйте задане представлення String на Locale


Документи з цього приводу говорять, що це конкретно зворотне Locale#toString()- ідеально! :)
jocull


3

Здається, для цього не існує статичного valueOfметоду, що трохи дивно.

Один з досить некрасивих, але простих способів - це повторити Locale.getAvailableLocales(), порівнюючи їхні toStringзначення з вашою цінністю.

Не дуже приємно, але розбір рядків не потрібен. Ви можете заздалегідь заповнити Mapрядки для локальних знаків і шукати рядок бази даних на цій карті.


А, ітерація може бути цілком розумним рішенням. Дійсно, що Locale не має статичного методу для цього.
Joonas Pulakka

Заздалегідь встановлені Localeекземпляри представляють дуже малий підмножину лише дійсних локалів . Це аж ніяк не повно.
BetaRide

3

Ви можете використовувати це на Android. Добре працює для мене.

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

Ну, я б зберігати замість строкової конкатенації Locale.getISO3Language(), getISO3Country()і getVariant () в якості ключа, який дозволив би мені останнім викликом Locale(String language, String country, String variant)конструктора.

Дійсно, посилання на displayLanguage передбачає використання мови локалі для його відображення, що робить його локальним залежним, всупереч коду iso мови.

Наприклад, ключ en locale може зберігатися як

en_EN
en_US

і так далі ...


1

Тому що я щойно це здійснив:

В Groovy/ Grailsбуло б:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.