Bagaimana cara mendapatkan Lokal dari representasi String-nya di Jawa?

109

Apakah ada cara yang rapi untuk mendapatkan instance Lokal dari "nama programatik" -nya seperti yang dikembalikan oleh toString()metode Locale ? Solusi yang jelas dan jelek akan mengurai String dan kemudian membuat instance Lokal baru sesuai dengan itu, tetapi mungkin ada cara / solusi yang lebih baik untuk itu?

Kebutuhannya adalah bahwa saya ingin menyimpan beberapa pengaturan khusus lokal dalam database SQL, termasuk Lokal itu sendiri, tetapi akan jelek untuk meletakkan objek Lokal berseri di sana. Saya lebih suka menyimpan representasi String mereka, yang tampaknya cukup memadai secara detail.

Joonas Pulakka
sumber

Jawaban:

34

Lihat Locale.getLanguage(), Locale.getCountry()... Simpan kombinasi ini dalam database dan bukan "programatic name"...
Saat Anda ingin membangun kembali Lokal, gunakanpublic Locale(String language, String country)

Ini contoh kode :)

// 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);
}
raj
sumber
3
Ini bahkan tidak bisa dikompilasi.
Adrian
1
@raj mengapa menggunakan tokenizer, Jika Java memberi Anda metode yang siap? misalnya toLocale (String str). Silakan lihat contoh dalam jawaban
VdeX
9
Anda harus menggunakan Locale.forLanguageTag (String)
Rian
126

Metode yang mengembalikan lokal dari string ada di perpustakaan commons-lang: LocaleUtils.toLocale(localeAsString)

yurilo
sumber
2
LocaleUtils.toLocale tidak mendukung string seperti 'zh-Hans', 'pt-PT', dll.
Hans van Dodewaard
10
Jika Anda memiliki tanda hubung -antara bagian lokal, Anda berurusan dengan tag IETF BCP 47, jika Anda menggunakan Java 7 Anda dapat menggunakanLocale.forLanguageTag
Jaime Hablutzel
59

Sejak Java 7 ada metode pabrik Locale.forLanguageTagdan metode contoh Locale.toLanguageTagmenggunakan tag bahasa IETF .

nilskp
sumber
8
Hanya ingin menekankan bahwa Locale.forLanguageTagbekerja dengan string lokal IETF (yaitu en-US) dan tidak bekerja dengan string lokal ISO (yaitu en_US)
Fabian
34
  1. Java menyediakan banyak hal dengan implementasi yang tepat sehingga banyak kerumitan dapat dihindari. Ini mengembalikan ms_MY .

    String key = "ms-MY";
    Locale locale = new Locale.Builder().setLanguageTag(key).build();
  2. Apache Commons harus LocaleUtilsmembantu mengurai representasi string. Ini akan mengembalikan en_US

    String str = "en-US";
    Locale locale =  LocaleUtils.toLocale(str);
    System.out.println(locale.toString());
  3. Anda juga dapat menggunakan konstruktor lokal.

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

Silakan periksa LocaleUtils ini dan Lokal ini untuk menjelajahi lebih banyak metode.

VdeX
sumber
1
LocaleUtils.toLocale (localeStringRepresentation) melakukan pekerjaan dengan rapi. Juga jika Anda melihat penerapan metode ini, itu cukup komprehensif!
Hidangan
15

Pilihan 1 :

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

Pilihan 2 :

Locale.forLanguageTag("en-US")

Harap diperhatikan Opsi 1 adalah "garis bawah" antara bahasa dan negara, dan Opsi 2 adalah "tanda hubung".

junjun
sumber
Panggilan memerlukan API level 21 (min saat ini 17): java.util.Locale # forLanguageTag
Vlad
12

Jawaban ini mungkin sedikit terlambat, tapi ternyata mengurai string tidak seburuk yang diasumsikan OP. Saya merasa cukup sederhana dan ringkas:

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

Saya menguji ini (di Java 7) dengan semua contoh yang diberikan dalam dokumentasi Locale.toString (): "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "zh_CN_ # Hans", "zh_TW_ # Hant-x-java ", dan" th_TH_TH_ # u-nu-thai ".

PEMBARUAN PENTING : Ini tidak disarankan untuk digunakan di Java 7+ menurut dokumentasi :

Secara khusus, klien yang mengurai keluaran toString ke dalam bidang bahasa, negara, dan varian dapat terus melakukannya (meskipun hal ini sangat tidak disarankan ), meskipun bidang varian akan memiliki informasi tambahan di dalamnya jika ada skrip atau ekstensi.

Gunakan Locale.forLanguageTag dan Locale.toLanguageTag sebagai gantinya, atau jika Anda harus, Locale.Builder.

andy
sumber
5
Java 7 Locale.forLanguageTaghanya berlaku untuk tag bahasa dikodekan seperti yang ditunjukkan dalam IETF BCP 47, dengan tanda hubung ( -), bukan garis bawah ( _) seperti pada kembalinya Locale's toStringmetode
Jaime Hablutzel
1
Kamu benar. Masih perlu ada cara untuk mengubah representasi Lokal yang ada ke format BCP47. Maksud saya adalah untuk menyarankan agar ke depan, Locales tidak boleh disimpan dalam toStringbentuknya, tetapi dalam toLanguageTagbentuknya, yang dapat diubah kembali menjadi Localelebih mudah dan akurat.
andy
Bukankah metode ini memiliki sejumlah kasus tepi yang dapat menyebabkan indeks di luar batas?
pengguna2524908
@ user2524908: Saya kira tidak, karena dia selalu menguji panjang array sebelum mengakses elemennya. Solusinya mungkin memiliki banyak kasus tepi yang tidak berfungsi dengan baik, tetapi tidak "membuat indeks
melampaui
9

Jika Anda menggunakan kerangka Spring dalam proyek Anda, Anda juga dapat menggunakan:

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

Dokumentasi :

Parsing representasi String yang diberikan menjadi Lokal

Javad Alimohammadi
sumber
Dokumen tentang ini secara khusus mengatakan kebalikan dari Locale#toString()- sempurna! :)
jocull
8

Pertanyaan lama dengan banyak jawaban, tetapi berikut lebih banyak solusi:

Tauren
sumber
Contoh java2s cukup bagus dan juga menyertakan penanganan varian
Paul Gregoire
URL pertama adalah semua yang saya inginkan .. Terima kasih
KD.
3

Sepertinya tidak ada valueOfmetode statis untuk ini, yang agak mengejutkan.

Salah satu cara yang agak jelek, tetapi sederhana, adalah mengulangi Locale.getAvailableLocales(), membandingkan toStringnilai - nilai mereka dengan nilai Anda.

Tidak terlalu bagus, tetapi tidak diperlukan penguraian string. Anda bisa mengisi Mapstring ke lokal, dan mencari string database Anda di peta itu.

skaffman
sumber
Ah, iterasi mungkin solusi yang cukup masuk akal. Memang mengherankan bahwa Lokal tidak memiliki metode statis untuk ini.
Joonas Pulakka
Instance yang telah ditentukan sebelumnya hanya Localemewakili subset lokal yang valid. Itu belum lengkap.
BetaRide
3

Anda dapat menggunakan ini di Android. Bekerja dengan baik untuk saya.

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;
}
Tuhanku
sumber
1

Nah, saya akan menyimpan sebagai gantinya rangkaian string Locale.getISO3Language(), getISO3Country()dan getVariant () sebagai kunci, yang akan memungkinkan saya untuk memanggil Locale(String language, String country, String variant)konstruktor.

memang, mengandalkan displayLanguage berarti menggunakan bahasa lokal untuk menampilkannya, yang membuatnya bergantung pada lokal, berlawanan dengan kode bahasa iso.

Sebagai contoh, kunci en locale dapat disimpan sebagai

en_EN
en_US

dan seterusnya ...

Riduidel
sumber
1

Karena saya baru saja menerapkannya:

Dalam Groovy/ Grailsitu akan menjadi:

def locale = Locale.getAvailableLocales().find { availableLocale ->
      return availableLocale.toString().equals(searchedLocale)
}
Martin L.
sumber