如何从Java的String表示中获取Locale?


109

是否有一种巧妙的方法可以从Locale 方法返回的“程序名称” 中获取Locale实例toString()?一个明显且丑陋的解决方案是解析String,然后根据该字符串构造一个新的Locale实例,但是也许有一种更好的方法/现成的解决方案?

我需要将一些特定于语言环境的设置(包括语言环境本身)存储在SQL数据库中,但是将序列化的语言环境对象放在那里是很难的。我宁愿存储它们的String表示形式,在细节上似乎也足够了。

Answers:


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为什么要使用tokenizer,如果Java为您提供了现成的方法?例如toLocale(String str)。请查看答案示例
VdeX

9
您应该使用Locale.forLanguageTag(String)
Rian

126

commons-lang库中存在从字符串返回语言环境的方法: LocaleUtils.toLocale(localeAsString)


2
LocaleUtils.toLocale不支持像'ZH-汉斯', 'PT-PT'等字符串
汉斯面包车Dodewaard

10
如果您要-处理的是IETF BCP 47标签,则在语言环境部分之间使用连字符,如果您使用的是Java 7,则可以使用Locale.forLanguageTag
Jaime Hablutzel,2013年

59

从Java 7开始,有使用IETF语言标签的工厂方法Locale.forLanguageTag和实例方法。Locale.toLanguageTag


8
只是想强调一下,它Locale.forLanguageTag可以使用IETF语言环境字符串(即en-US),而不能用于ISO语言环境字符串(即en_US
Fabian

33
  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是“破折号”。


调用需要API级别21(当前最小值为17):java.util.Locale#forLanguageTag
Vlad

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

我使用Locale.toString()文档中给出的所有示例对此进行了测试(在Java 7上):“ 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仅适用于在IETF的BCP 47所示,用连字符(编码语言标签-),而不是下划线(_)在返回LocaletoString方法
海梅Hablutzel

1
你是对的。仍然需要某种方法将现有的语言环境表示形式转换为BCP47格式。我的意图是建议今后,Locales不应以其toString形式存储,而应以其形式存储,这种形式toLanguageTag可以Locale更轻松,更准确地转换回去。
andy

此方法是否不会存在许多可能导致索引超出范围的边缘情况?
user2524908

@ user2524908:我不这么认为,因为他总是在访问数组元素之前测试数组长度。该解决方案可能在很多情况下无法正常运行,但无法“超出范围”
MestreLion

9

如果您在项目中使用Spring框架,则还可以使用:

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

说明文件

将给定的String表示形式解析为语言环境


有关此文档的文档说这与Locale#toString()-完美相反!:)
jocull


3

似乎没有静态valueOf方法,这有点令人惊讶。

一种相当丑陋但简单的方法是迭代Locale.getAvailableLocales(),将它们的toString值与您的值进行比较。

不是很好,但是不需要字符串解析。您可以预填充Map“字符串到语言环境”,然后在该Map中查找数据库字符串。


嗯,迭代可能是一个非常合理的解决方案。实际上,令人惊讶的是Locale没有静态方法。
乔纳斯·普拉卡

预先定义的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

等等 ...


1

因为我刚刚实现了它:

Groovy/ Grails它将是:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.