Làm cách nào để lấy Ngôn ngữ từ biểu diễn Chuỗi của nó trong Java?


109

Có cách nào gọn gàng để lấy một phiên bản Locale từ "tên có lập trình" của nó như được trả về bởi phương toString()thức của Locale không? Một giải pháp rõ ràng và xấu xí sẽ là phân tích cú pháp Chuỗi và sau đó xây dựng một cá thể Ngôn ngữ mới theo đó, nhưng có thể có một cách tốt hơn / giải pháp sẵn sàng cho điều đó?

Nhu cầu là tôi muốn lưu trữ một số cài đặt ngôn ngữ cụ thể trong cơ sở dữ liệu SQL, bao gồm cả bản thân Địa phương, nhưng sẽ rất tệ nếu đặt các đối tượng Ngôn ngữ tuần tự ở đó. Tôi muốn lưu trữ các biểu diễn Chuỗi của họ, có vẻ như khá đầy đủ về chi tiết.

Câu trả lời:


34

Xem Locale.getLanguage(), Locale.getCountry()... Lưu trữ tổ hợp này trong cơ sở dữ liệu thay vì "programatic name"...
Khi bạn muốn xây dựng lại Ngôn ngữ, hãy sử dụngpublic Locale(String language, String country)

Đây là một mã mẫu :)

// 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
Điều này thậm chí sẽ không biên dịch.
Adrian

1
@raj tại sao phải sử dụng tokenizer, Nếu Java cung cấp cho bạn các phương thức sẵn sàng? ví dụ toLocale (String str). Hãy xem các ví dụ trong câu trả lời
VdeX

9
Bạn nên sử dụng Locale.forLanguageTag (String)
Rian

126

Phương thức trả về ngôn ngữ từ chuỗi tồn tại trong thư viện commons-lang: LocaleUtils.toLocale(localeAsString)


2
LocaleUtils.toLocale không hỗ trợ chuỗi như 'zh-Hans', 'pt-PT', vv
Hans van dodewaard

10
Nếu bạn có một gạch nối -giữa các bộ phận miền địa phương bạn đang đối phó với một thẻ IETF BCP 47, nếu bạn đang sử dụng Java 7 bạn có thể sử dụngLocale.forLanguageTag
Jaime Hablutzel

59

Vì Java 7 có phương thức gốc Locale.forLanguageTagvà phương thức phiên bản Locale.toLanguageTagsử dụng thẻ ngôn ngữ IETF .


8
Chỉ muốn nhấn mạnh rằng Locale.forLanguageTaghoạt động với chuỗi ngôn ngữ IETF (tức là en-US) và không hoạt động với chuỗi ngôn ngữ ISO (ví dụ en_US)
Fabian

34
  1. Java cung cấp rất nhiều thứ với việc triển khai phù hợp nên có thể tránh được nhiều phức tạp. Điều này trả về ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons LocaleUtilsphải giúp phân tích cú pháp một biểu diễn chuỗi. Điều này sẽ trả về en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Bạn cũng có thể sử dụng các hàm tạo ngôn ngữ.

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

Vui lòng kiểm tra LocaleUtils này và Locale này để khám phá thêm các phương pháp.


1
LocaleUtils.toLocale (localeStringRepresentation) thực hiện công việc một cách gọn gàng. Ngoài ra nếu bạn thấy việc thực hiện phương pháp này, nó là khá toàn diện!
Món ăn

15

Lựa chọn 1 :

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

Lựa chọn 2 :

Locale.forLanguageTag("en-US")

Xin lưu ý Tùy chọn 1 là "gạch dưới" giữa ngôn ngữ và quốc gia và Tùy chọn 2 là "gạch ngang".


Cuộc gọi yêu cầu API cấp 21 (tối thiểu hiện tại là 17): java.util.Locale # forLanguageTag
Vlad

12

Câu trả lời này có thể hơi muộn, nhưng hóa ra việc phân tích cú pháp chuỗi không xấu như OP đã giả định. Tôi thấy nó khá đơn giản và ngắn gọn:

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

Tôi đã kiểm tra điều này (trên Java 7) với tất cả các ví dụ được đưa ra trong tài liệu Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Hant-x-java ", và" th_TH_TH_ # u-nu-thai ".

CẬP NHẬT QUAN TRỌNG : Điều này không được khuyến nghị sử dụng trong Java 7+ theo tài liệu :

Đặc biệt, những khách hàng phân tích cú pháp đầu ra của toString thành các trường ngôn ngữ, quốc gia và biến thể có thể tiếp tục làm như vậy (mặc dù điều này rất không được khuyến khích ), mặc dù trường biến thể sẽ có thêm thông tin nếu có tập lệnh hoặc phần mở rộng.

Thay vào đó, hãy sử dụng Locale.forLanguageTag và Locale.toLanguageTag, hoặc nếu bạn phải, Locale.Builder.


5
Java 7 Locale.forLanguageTagchỉ áp dụng cho thẻ ngôn ngữ mã hóa như đã nêu trong IETF của BCP 47 tuổi, với một dấu gạch ngang ( -), không phải là một dấu gạch dưới ( _) như trong sự trở lại của Locale's toStringphương pháp
Jaime Hablutzel

1
Bạn đúng. Vẫn cần có một số cách để chuyển đổi các biểu diễn Ngôn ngữ hiện có sang định dạng BCP47. Ý định của tôi là gợi ý rằng trong tương lai, Localecác s không nên được lưu trữ ở toStringdạng của chúng, mà ở toLanguageTagdạng của chúng, có thể chuyển đổi trở lại Localedễ dàng và chính xác hơn.
andy

Phương pháp này sẽ không có một số trường hợp cạnh có thể gây ra chỉ mục ngoài giới hạn?
user2524908

@ user2524908: Tôi không nghĩ vậy, vì anh ấy luôn kiểm tra độ dài mảng trước khi truy cập các phần tử của nó. Giải pháp có thể có nhiều trường hợp
phức tạp

9

Nếu bạn đang sử dụng Spring framework trong dự án của mình, bạn cũng có thể sử dụng:

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

Tài liệu :

Phân tích cú pháp biểu diễn Chuỗi đã cho thành Ngôn ngữ


Các tài liệu về điều này nói rằng nó đặc biệt là nghịch đảo của Locale#toString()- hoàn hảo! :)
jocull


3

Có vẻ như không có một valueOfphương thức tĩnh nào cho việc này, điều này hơi ngạc nhiên.

Một cách khá xấu xí, nhưng đơn giản, là lặp đi lặp lại Locale.getAvailableLocales(), so sánh toStringgiá trị của chúng với giá trị của bạn.

Không đẹp lắm, nhưng không cần phân tích chuỗi. Bạn có thể điền trước một Maptrong các Chuỗi tới Địa phương và tra cứu chuỗi cơ sở dữ liệu của mình trong Bản đồ đó.


Ah, lặp lại có thể là một giải pháp khá hợp lý. Thật vậy, thật đáng ngạc nhiên là Locale không có một phương thức tĩnh nào cho việc này.
Joonas Pulakka

Các phiên bản dự đoán chỉ Localeđại diện cho một tập hợp con rất nhỏ của các ngôn ngữ hợp lệ. Nó không có nghĩa là hoàn thành.
BetaRide

3

Bạn có thể sử dụng điều này trên Android. Hoạt động tốt cho tôi.

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

Vâng, tôi sẽ lưu trữ thay vì một chuỗi nối của Locale.getISO3Language(), getISO3Country()và getVariant () như chìa khóa, mà sẽ cho phép tôi gọi sau Locale(String language, String country, String variant)constructor.

thực sự, việc dựa vào displayLanguage ngụ ý sử dụng ngôn ngữ ngôn ngữ để hiển thị nó, điều này làm cho nó phụ thuộc vào ngôn ngữ, trái với mã ngôn ngữ iso.

Ví dụ: khóa địa phương sẽ được lưu trữ như

en_EN
en_US

và như thế ...


1

Bởi vì tôi vừa thực hiện nó:

Trong Groovy/ Grailsnó sẽ là:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.