Как получить локаль из строкового представления в Java?

109

Есть ли удобный способ получить экземпляр Locale из его «программного имени», возвращенного методом Locale toString()? Очевидным и уродливым решением было бы проанализировать String и затем построить новый экземпляр Locale в соответствии с этим, но, может быть, для этого есть лучший способ / готовое решение?

Я хочу сохранить в базе данных SQL некоторые специфические для локали настройки, включая сами локали, но было бы некрасиво помещать туда сериализованные объекты локали. Я бы предпочел сохранить их строковые представления, которые кажутся достаточно подробными.

Йоонас Пулакка
источник

Ответы:

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 08
9
Вы должны использовать Locale.forLanguageTag (String)
Райан
126

Метод, который возвращает язык из строки, существует в библиотеке commons-lang: LocaleUtils.toLocale(localeAsString)

Юрило
источник
2
LocaleUtils.toLocale не поддерживает такие строки, как 'zh-Hans', 'pt-PT' и т. Д.
Ханс ван Додеваард,
10
Если у вас есть дефис -между частями локали, вы имеете дело с тегом IETF BCP 47, если вы используете Java 7, вы можете использоватьLocale.forLanguageTag
Хайме Хаблутцель
59

Начиная с Java 7, существует фабричный метод Locale.forLanguageTagи метод экземпляра, Locale.toLanguageTagиспользующие языковые теги IETF .

нильскп
источник
8
Просто хочу подчеркнуть, что Locale.forLanguageTagработает со строками языкового стандарта IETF (т.е. en-US) и не работает со строками языкового стандарта ISO (например en_US)
Фабиан
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, чтобы изучить другие методы.

VdeX
источник
1
LocaleUtils.toLocale (localeStringRepresentation) выполняет свою работу аккуратно. Также, если вы видите реализацию этого метода, она довольно обширна!
Блюдо
15

Опция 1 :

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

Вариант 2:

Locale.forLanguageTag("en-US")

Обратите внимание, что в Варианте 1 между языком и страной используется «подчеркивание», а в Варианте 2 - «тире».

Junjun
источник
Для вызова требуется уровень API 21 (текущий мин. 17): java.util.Locale # forLanguageTag
Влад
12

Этот ответ может быть немного запоздалым, но оказывается, что анализ строки не так уродлив, как предполагал OP. Мне это показалось довольно простым и лаконичным:

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_» # Hant-x-java "и" th_TH_TH_ # u-nu-thai ".

ВАЖНОЕ ОБНОВЛЕНИЕ : не рекомендуется использовать в Java 7+ согласно документации :

В частности, клиенты, которые анализируют вывод toString в полях языка, страны и варианта, могут продолжать делать это (хотя это настоятельно не рекомендуется ), хотя поле варианта будет содержать дополнительную информацию, если присутствуют скрипт или расширения.

Вместо этого используйте Locale.forLanguageTag и Locale.toLanguageTag или, если необходимо, Locale.Builder.

Энди
источник
5
Java 7 Locale.forLanguageTagприменяется только для языковых тегов, закодированных, как указано в BCP 47 IETF, с дефисом ( -), а не подчеркиванием ( _), как в return of Locale's toStringmethod
Хайме Хаблутцель
1
Ты прав. По-прежнему должен быть какой-то способ преобразовать существующие представления Locale в формат BCP47. Мое намерение состояло в том, чтобы предложить, чтобы в будущем Locales следует хранить не в их toStringформе, а в их toLanguageTagформе, которая может быть преобразована обратно в Localeболее легкую и точную.
Энди
Разве у этого метода не было бы нескольких крайних случаев, которые могли бы привести к выходу индекса за пределы?
user2524908
@ user2524908: Я так не думаю, потому что он всегда проверяет длину массива перед доступом к его элементам. Решение может иметь много крайних случаев, когда оно не работает должным образом, но не «индекс выходит за пределы»
MestreLion
9

Если вы используете Spring framework в своем проекте, вы также можете использовать:

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

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

Разобрать данное строковое представление в локали

Джавад Алимохаммади
источник
В документации по этому поводу говорится, что это именно обратное Locale#toString()- идеально! :)
jocull
8

Старый вопрос с множеством ответов, но вот и другие решения:

Таурен
источник
Пример java2s довольно хорош и включает в себя также обработку вариантов
Пол Грегуар
Первый URL - это все, что я хотел. Спасибо
KD.
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_EN
en_US

и так далее ...

Riduidel
источник
1

Потому что я только что его реализовал:

В Groovy/ Grailsэто будет:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Мартин Л.
источник