Een gids voor de ResourceBundle

1. Overzicht

Veel softwareontwikkelaars krijgen tijdens hun professionele carrière de kans om meertalige systemen of applicaties te ontwikkelen. Deze zijn meestal bedoeld voor eindgebruikers uit verschillende regio's of verschillende taalgebieden.

Het is altijd een uitdaging om deze applicaties te onderhouden en uit te breiden. Het vermogen om tegelijkertijd met verschillende lokalisatiegegevens te werken, is meestal cruciaal. Wijziging van de toepassingsgegevens moet zo eenvoudig mogelijk zijn, zonder dat hercompilatie nodig is. Daarom vermijden we over het algemeen het hardcoderen van label- of knopnamen.

Gelukkig kunnen we rekenen op Java dat ons deze klasse biedt, die ons helpt om alle bovengenoemde problemen op te lossen.

Simpel gezegd, de ResourceBundle stelt onze applicatie in staat om gegevens te laden uit verschillende bestanden die landspecifieke gegevens bevatten.

1.1. ResourceBundles

Het eerste dat we moeten weten, is dat alle bestanden binnen één resourcebundel moet zich in hetzelfde pakket / dezelfde map bevinden en een gemeenschappelijke basisnaam hebben. Ze kunnen landspecifieke achtervoegsels hebben die de taal, het land of het platform aangeven, gescheiden door een onderstrepingsteken.

Het is belangrijk dat we een landcode kunnen toevoegen als er al een taalcode is, of een platform als de taal en landcodes aanwezig zijn.

Laten we eens kijken naar voorbeeldbestandsnamen:

  • VoorbeeldResource
  • VoorbeeldResource_nl
  • VoorbeeldResource_en_US
  • VoorbeeldResource_en_US_UNIX

Het standaardbestand voor elke databundel is altijd een bestand zonder achtervoegsels - VoorbeeldResource. Omdat er twee subklassen zijn van ResourceBundle: PropertyResourceBundle en ListResourceBundlekunnen we gegevens onderling uitwisselbaar bewaren in eigenschappenbestanden en in javabestanden.

Elk bestand moet een landspecifieke naam en een juiste bestandsextensie, bijvoorbeeld, VoorbeeldResource_en_US.properties of Voorbeeld_en.java.

1.2. Eigenschappenbestanden - PropertyResourceBundle

Eigenschappenbestanden worden vertegenwoordigd door PropertyResourceBundle. Ze slaan gegevens op in de vorm van hoofdlettergevoelige sleutel / waarde-paren.

Laten we een voorbeeld van een eigenschappenbestand analyseren:

# Knoppen continueButton doorgaan CancelButton = annuleren! Labels hello Label: hallo 

Zoals we kunnen zien, zijn er drie verschillende stijlen om sleutel-waardeparen te definiëren.

Ze zijn allemaal gelijkwaardig, maar de eerste is waarschijnlijk de meest populaire Java programmeurs. Het is de moeite waard om te weten dat we ook opmerkingen in eigenschappenbestanden kunnen plaatsen. Opmerkingen beginnen altijd met # of !.

1.3. Java-bestanden - ListResourceBundle

Om onze taalspecifieke gegevens op te slaan, moeten we allereerst een klasse maken die zich uitbreidt ListResourceBundle en overschrijft de getContents () methode. De klassenaamconventie is hetzelfde als voor eigenschappenbestanden.

Voor elk Land, we moeten een aparte Java-klasse maken.

Hier is een voorbeeldles:

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

Java-bestanden hebben een groot voordeel ten opzichte van eigenschappenbestanden: de mogelijkheid om elk gewenst object vast te houden - niet alleen Snaren.

Aan de andere kant vereist elke wijziging of introductie van een nieuwe locale-specifieke Java-klasse hercompilatie van een applicatie, terwijl eigenschappenbestanden zonder enige extra inspanning kunnen worden uitgebreid.

2. Gebruik bronbundels

We weten al hoe we resourcebundels moeten definiëren, dus we zijn klaar om deze te gebruiken.

Laten we eens kijken naar het korte codefragment:

Locale locale = nieuwe Locale ("pl", "PL"); ResourceBundle exampleBundle = ResourceBundle.getBundle ("package.ExampleResource", locale); assertEquals (exampleBundle.getString ("valuta"), "Poolse zloty"); assertEquals (exampleBundle.getObject ("toUsdRate"), nieuwe BigDecimal ("3.401")); assertArrayEquals (exampleBundle.getStringArray ("steden"), nieuwe String [] {"Warschau", "Krakau"});

Ten eerste kunnen we onze Locale, tenzij we de standaard niet willen gebruiken.

Laten we daarna een statische fabrieksmethode noemen van ResourceBundle. We moeten slagen de bundelnaam met zijn pakket / map en de landinstelling als parameters.

Er is ook een fabrieksmethode die alleen een bundelnaam vereist als de standaardlandinstelling in orde is. Zodra we het object hebben, kunnen we waarden ophalen met hun sleutels.

Bovendien laat het voorbeeld zien dat we getString (String-sleutel), getObject (String-sleutel), en getStringArray (String-sleutel) om waarden te krijgen die we willen.

3. De juiste bundelbron selecteren

Als we een bundelresource willen gebruiken, is het belangrijk om te weten hoe Java selecteert bundelbestanden.

Stel je voor dat we werken met een applicatie die labels in het Pools nodig heeft, maar je standaard JVM locale is Locale.US.

In het begin zal de toepassing zoeken naar de bestanden in het klassenpad die geschikt zijn voor de locale die u vraagt. Het begint met de meest specifieke naam, dat wil zeggen een naam die een platform, een land en taal bevat.

Vervolgens gaat het naar meer algemeen. Als er geen overeenkomst is, valt deze keer terug naar de standaardlandinstelling zonder platformcontrole.

Als er geen overeenkomst is, zal het proberen de standaardbundel te lezen. Alles moet duidelijk zijn als we kijken naar de volgorde van de geselecteerde bestandsnamen:

  • Label_pl_PL_UNIX
  • Label_pl_PL
  • Label_pl
  • Label_en_US
  • Label_en
  • Etiket

We moeten in gedachten houden dat elke naam beide vertegenwoordigt .Java en .eigendommen bestanden, maar de eerste heeft voorrang op de laatste. Als er geen geschikt bestand is, wordt een MissingResourceException wordt gegooid.

4. Overerving

Een ander voordeel van het resourcebundelconcept is de overerving van eigenschappen. Het betekent dat sleutel / waarde-paren die in minder specifieke bestanden zijn opgenomen, worden overgeërfd door de paren die hoger in de overervingsboom staan.

Laten we aannemen dat we drie eigenschappenbestanden hebben:

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

Resourcebundel opgehaald voor Landinstelling ("pl", "PL") zou alle drie de sleutels / waarden in het resultaat retourneren. Het is de moeite waard om te vermelden, er is geen terugval naar de standaard locale bundel voor zover er sprake is van eigendomsvererving.

Wat is meer, ListResourceBundles en PropertyResourceBundles bevinden zich niet in dezelfde hiërarchie.

Dus als een eigenschappenbestand wordt gevonden in het klassepad, worden sleutel / waarde-paren alleen overgenomen van eigenschappenbestanden. Dezelfde regel is van toepassing op Java-bestanden.

5. Maatwerk

Alles wat we hierboven hebben geleerd, ging over de standaardimplementatie van ResourceBundle. Er is echter een manier waarop we zijn gedrag kunnen aanpassen.

Dit doen we door te verlengen ResourceBoundle.Control en het negeren van zijn methoden.

We kunnen bijvoorbeeld de tijd wijzigen waarin waarden in de cache worden bewaard of de toestand bepalen waarin de cache opnieuw moet worden geladen.

Laten we voor een beter begrip een korte methode als voorbeeld voorbereiden:

openbare klasse ExampleControl breidt ResourceBundle.Control uit {@Override openbare lijst getCandidateLocales (String s, locale locale) {return Arrays.asList (nieuwe locale ("pl", "PL")); }}

Het doel van deze methode is om een ​​manier te veranderen om bestanden in het klassenpad te selecteren. Zoals we kunnen zien, VoorbeeldControle zal alleen poetsmiddel retourneren Locale, ongeacht de standaardinstelling of gedefinieerd Locale is.

6. UTF-8

Omdat er nog steeds veel applicaties worden gebruikt JDK 8 of oudere versies, is het de moeite waard om dat te weten vóór Java 9ListResourceBundles had nog een voordeel ten opzichte van PropertyResourceBundles. Omdat Java-bestanden String-objecten kunnen opslaan, kunnen ze elk teken bevatten dat wordt ondersteund door UTF-16 codering.

Integendeel, PropertyResourceBundle laadt bestanden standaard met ISO 8859-1 codering, die minder tekens heeft dan UTF-8 (problemen veroorzaakt voor onze Poolse taalvoorbeelden).

Om karakters op te slaan die verder gaan UTF-8, kunnen we de Systeemeigen naar ASCII omzetter - native2ascii. Het converteert alle tekens die niet voldoen aan ISO 8859-1 door ze te coderen naar \ uxxxx notatie.

Hier is een voorbeeldopdracht:

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

En laten we eens kijken hoe eigenschappen eruit zien voor en na een coderingswijziging:

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

Gelukkig bestaat dit ongemak niet meer in Java 9. JVM leest eigenschappenbestanden in UTF-8 codering, en er is geen probleem bij het gebruik van niet-Latijnse tekens.

7. Conclusie

BundleResource bevat veel van wat we nodig hebben om een ​​meertalige applicatie te ontwikkelen. De functies die we hebben besproken, maken het manipuleren van verschillende landinstellingen vrij eenvoudig.

We vermijden ook hardcoding-waarden, waardoor we het ondersteunde Landinstellingen door simpelweg nieuwe toe te voegen Locale bestanden waardoor onze applicatie soepel kan worden gewijzigd en onderhouden.

Zoals altijd is de voorbeeldcode beschikbaar op GitHub.