Panduan untuk ResourceBundle

1. Ikhtisar

Banyak pengembang perangkat lunak, selama karir profesional mereka, menghadapi peluang untuk mengembangkan sistem atau aplikasi multibahasa. Ini biasanya ditujukan untuk pengguna akhir dari berbagai wilayah atau wilayah bahasa yang berbeda.

Selalu menantang untuk memelihara dan memperluas aplikasi ini. Kemampuan untuk beroperasi dengan berbagai data spesifik lokalisasi pada waktu yang sama biasanya sangat penting. Modifikasi data aplikasi harus sesederhana mungkin tanpa perlu kompilasi ulang. Itulah mengapa kami biasanya menghindari label hardcode atau nama tombol.

Untungnya, kami dapat mengandalkan Java yang menyediakan kelas ini, yang membantu kami menyelesaikan semua masalah yang disebutkan di atas.

Sederhananya, ResourceBundle memungkinkan aplikasi kita memuat data dari file berbeda yang berisi data khusus lokal.

1.1. ResourceBundles

Hal pertama yang harus kita ketahui adalah bahwa semua file dalam satu bundel sumber daya harus berada dalam paket / direktori yang sama dan memiliki nama dasar yang sama . Mereka mungkin memiliki sufiks khusus lokal yang menunjukkan bahasa, negara, atau platform yang dipisahkan oleh simbol garis bawah.

Penting bagi kami untuk menambahkan kode negara jika sudah ada kode bahasa, atau platform jika kode bahasa dan negara ada.

Mari kita lihat contoh nama file:

  • ExampleResource
  • ExampleResource_en
  • ExampleResource_en_US
  • ExampleResource_en_US_UNIX

File default untuk setiap paket data selalu satu tanpa sufiks - ExampleResource . Karena ada dua subclass ResourceBundle : PropertyResourceBundle dan ListResourceBundle , kita dapat menyimpan data secara bergantian dalam file properti serta file java.

Setiap file harus memiliki nama khusus lokal dan ekstensi file yang sesuai , misalnya, properti ExampleResource_en_US . atau Example_en.java .

1.2. File Properti - PropertyResourceBundle

File properti diwakili oleh PropertyResourceBundle. Mereka menyimpan data dalam bentuk pasangan nilai kunci yang peka huruf besar / kecil.

Mari menganalisis contoh file properti:

# Buttons continueButton continue cancelButton=cancel ! Labels helloLabel:hello 

Seperti yang bisa kita lihat, ada tiga gaya berbeda untuk menentukan pasangan nilai kunci.

Semuanya setara, tetapi yang pertama mungkin yang paling populer di kalangan programmer Java . Perlu diketahui bahwa kami juga dapat memberikan komentar di file properti. Komentar selalu dimulai dengan # atau ! .

1.3. File Java - ListResourceBundle

Pertama-tama, untuk menyimpan data khusus bahasa kita, kita perlu membuat kelas yang memperluas ListResourceBundle dan mengganti metode getContents () . Konvensi nama kelas sama dengan untuk file properti.

Untuk setiap Lokal, kita perlu membuat kelas Java terpisah.

Berikut adalah contoh kelasnya:

public class ExampleResource_pl_PL extends ListResourceBundle { @Override protected Object[][] getContents() { return new Object[][] { {"currency", "polish zloty"}, {"toUsdRate", new BigDecimal("3.401")}, {"cities", new String[] { "Warsaw", "Cracow" }} }; } }

File Java memiliki satu keunggulan utama dibandingkan file properti yang memungkinkan untuk menampung objek apa pun yang kita inginkan - tidak hanya Strings.

Di sisi lain, setiap modifikasi atau pengenalan kelas java khusus lokal baru memerlukan kompilasi ulang aplikasi sedangkan file properti dapat diperpanjang tanpa upaya tambahan.

2. Gunakan Kumpulan Sumber Daya

Kita sudah tahu bagaimana mendefinisikan bundel sumber daya, jadi kita siap menggunakannya.

Mari pertimbangkan cuplikan kode singkat:

Locale locale = new Locale("pl", "PL"); ResourceBundle exampleBundle = ResourceBundle.getBundle("package.ExampleResource", locale); assertEquals(exampleBundle.getString("currency"), "polish zloty"); assertEquals(exampleBundle.getObject("toUsdRate"), new BigDecimal("3.401")); assertArrayEquals(exampleBundle.getStringArray("cities"), new String[]{"Warsaw", "Cracow"});

Pertama, kita dapat menentukan Lokal kita , kecuali kita tidak ingin menggunakan yang default.

Setelah itu, panggil metode pabrik statis ResourceBundle . Kita perlu melewatkan nama bundel dengan paket / direktori dan lokal sebagai parameter.

Ada juga metode pabrik yang hanya memerlukan nama bundel jika lokal default baik-baik saja. Segera setelah kita memiliki objeknya, kita dapat mengambil nilai dengan kuncinya.

Selain itu, contoh tersebut menunjukkan bahwa kita dapat menggunakan getString (String key) , getObject (String key), dan getStringArray (String key) untuk mendapatkan nilai yang kita inginkan.

3. Memilih Sumber Daya Bundel yang Tepat

Jika kita ingin menggunakan sumber daya bundel, penting untuk mengetahui bagaimana Java memilih berkas bundel.

Mari kita bayangkan bahwa kita bekerja dengan aplikasi yang membutuhkan label dalam bahasa Polandia tetapi lokal JVM default Anda adalah Locale.US .

Pada awalnya, aplikasi akan mencari file di classpath yang sesuai untuk lokal yang Anda minta. Ini dimulai dengan nama yang paling spesifik, yaitu yang berisi platform, negara, dan bahasa.

Kemudian, itu berlanjut ke yang lebih umum. Jika tidak ada yang cocok, kali ini akan kembali ke lokal default tanpa pemeriksaan platform.

Jika tidak ada yang cocok, itu akan mencoba membaca bundel default. Semuanya harus jelas saat kita melihat urutan nama file yang dipilih:

  • Label_pl_PL_UNIX
  • Label_pl_PL
  • Label_pl
  • Label_en_US
  • Label_en
  • Label

Kita harus ingat bahwa setiap nama mewakili file .java dan .properties , tetapi yang pertama lebih diutamakan daripada yang terakhir. Jika tidak ada file yang sesuai, MissingResourceException akan muncul.

4. Warisan

Another advantage of the resource bundle concept is property inheritance. It means that key-values pairs included in less specific files are inherited by those which are higher in the inheritance tree.

Let's assume that we have three property files:

#resource.properties cancelButton = cancel #resource_pl.properties continueButton = dalej #resource_pl_PL.properties backButton = cofnij

Resource bundle retrieved for Locale(“pl”, “PL”) would return all three keys/values in the result. It's worth to mention, there's no fall back to default locale bundle as far as property inheritance is considered.

What is more, ListResourceBundles and PropertyResourceBundles aren't in the same hierarchy.

So if a property file is found in the classpath then key-value pairs are inherited only from property files. The same rule applies to Java files.

5. Customization

All we've learned above was about the default implementation of ResourceBundle. However, there's a way we can modify its behavior.

We do this by extending ResourceBoundle.Control and overriding its methods.

For example, we can change the time of keeping values in cache or determine the condition when the cache should be reloaded.

For a better understanding, let's prepare a short method as an example:

public class ExampleControl extends ResourceBundle.Control { @Override public List getCandidateLocales(String s, Locale locale) { return Arrays.asList(new Locale("pl", "PL")); } }

The purpose of this method is to change a manner of selecting files in the classpath. As we can see, ExampleControl will return only polish Locale, no matter what the default or defined Locale is.

6. UTF-8

Since there're still many applications using JDK 8 or older versions, it's worth to know that prior to Java 9ListResourceBundles had one more advantage over PropertyResourceBundles. As Java files can store String objects, they are able to hold any character supported by UTF-16 encoding.

On the contrary, PropertyResourceBundle loads files by default using ISO 8859-1 encoding, which has fewer characters than UTF-8 (causing problems for our Polish language examples).

In order to save characters which are beyond UTF-8, we can use the Native-To-ASCII converter – native2ascii. It converts all characters that aren't compliant with ISO 8859-1 by encoding them to \uxxxx notation.

Here's an example command:

native2ascii -encoding UTF-8 utf8.properties nonUtf8.properties

And let's see how properties look like before and after a change of encoding:

#Before polishHello=cześć #After polishHello=cze\u015b\u0107

Fortunately, this inconvenience exists no longer in Java 9. JVM reads property files in UTF-8 encoding, and there's no problem in using non-Latin characters.

7. Conclusion

BundleResource contains much of what we need to develop a multilingual application. The features we've covered make manipulation of different locales pretty straightforward.

Kami juga menghindari nilai pengkodean keras, yang memungkinkan kami memperluas Lokal yang didukung hanya dengan menambahkan file Lokal baru yang memungkinkan aplikasi kami dimodifikasi dan dipelihara dengan lancar.

Seperti biasa, kode sampel tersedia di lebih dari GitHub.