Java Localization - Formatering af beskeder

1. Introduktion

I denne vejledning overvejer vi, hvordan vi kan lokaliser og formater meddelelser baseret på Lokal.

Vi bruger begge Java'er MessageFormat og tredjepartsbiblioteket, ICU.

2. Brugssag for lokalisering

Når vores applikation erhverver et bredt publikum af brugere fra hele verden, vil vi naturligvis gerne vise forskellige meddelelser baseret på brugerens præferencer.

Det første og vigtigste aspekt er det sprog, som brugeren taler. Andre kan omfatte valuta-, antal- og datoformater. Sidst men ikke mindst er kulturelle præferencer: hvad der er acceptabelt for brugere fra et land, kan være utåleligt for andre.

Antag, at vi har en e-mail-klient, og vi vil vise underretninger, når en ny besked ankommer.

Et simpelt eksempel på en sådan besked kan være denne:

Alice har sendt dig en besked.

Det er fint for engelsktalende brugere, men ikke-engelsktalende er måske ikke så glade. F.eks. Foretrækker fransktalende brugere at se denne meddelelse:

Alice vous en udsending og besked. 

Mens polske folk ville være glade for at se denne:

Alice wysłała ci wiadomość. 

Hvad hvis vi vil have en korrekt formateret besked, selv i tilfælde hvor Alice ikke kun sender en besked, men kun få beskeder?

Vi kan blive fristet til at løse problemet ved at sammenkæde forskellige stykker i en enkelt streng som denne:

String message = "Alice har sendt" + antal + "beskeder"; 

Situationen kan let komme ud af kontrol, når vi har brug for meddelelser i tilfælde, hvor ikke kun Alice, men også Bob måske sender beskederne:

Bob har sendt to beskeder. Bob en udsending deux beskeder. Bob wysłał dwie wiadomości.

Bemærk, hvordan verbet ændres i tilfælde af polsk (wysłała vs. wysłał) Sprog. Det illustrerer det faktum, at sammenkædning af banale strenge er sjældent acceptabelt til lokalisering af meddelelser.

Som vi ser, får vi to typer problemer: den ene er relateret til oversættelser og den anden er relateret til formater. Lad os adressere dem i de følgende afsnit.

3. Beskedlokalisering

Vi kan definere lokalisering eller l10naf en applikation som processen til at tilpasse applikationen til brugerens komfort. Nogle gange udtrykket internalisering, eller i18n, bruges også.

For at lokalisere applikationen, lad os først fjerne alle hardkodede meddelelser ved at flytte dem ind i vores ressourcer folder:

Hver fil skal indeholde nøgleværdipar med meddelelserne på det tilsvarende sprog. For eksempel fil beskeder_da.egenskaber skal indeholde følgende par:

label = Alice har sendt dig en besked.

messages_pl.egenskaber skal indeholde følgende par:

label = Alice wysłała ci wiadomość.

Tilsvarende tildeler andre filer passende værdier til nøglen etiket. Nu, for at afhente den engelske version af underretningen, kan vi bruge ResourceBundle:

ResourceBundle bundle = ResourceBundle.getBundle ("meddelelser", Locale.UK); Strengmeddelelse = bundle.getString ("label");

Værdien af ​​variablen besked vil være "Alice har sendt dig en besked."

Java'er Lokal klasse indeholder genveje til ofte anvendte sprog og lande.

I tilfælde af det polske sprog skriver vi måske følgende:

ResourceBundle bundle = ResourceBundle.getBundle ("meddelelser", Locale.forLanguageTag ("pl-PL")); Strengmeddelelse = bundle.getString ("label");

Lad os bare nævne, at hvis vi ikke giver nogen landestandarder, så bruger systemet en standard. Vi kan få flere detaljer om dette emne i vores artikel “Internationalisering og lokalisering i Java 8“. Blandt de tilgængelige oversættelser vælger systemet derefter den, der ligner mest det aktuelle sted.

Placering af meddelelserne i ressourcefilerne er et godt skridt i retning af at gøre applikationen mere brugervenlig. Det gør det lettere at oversætte hele applikationen af ​​følgende årsager:

  1. en oversætter behøver ikke at gennemse applikationen på jagt efter meddelelserne
  2. en oversætter kan se hele sætningen, som hjælper med at forstå konteksten og dermed letter en bedre oversættelse
  3. vi behøver ikke at kompilere hele applikationen igen, når en oversættelse til et nyt sprog er klar

4. Beskedformat

Selvom vi har flyttet meddelelserne fra koden til et separat sted, indeholder de stadig nogle hardkodede oplysninger. Det ville være rart at kunne tilpasse navnene og numrene i meddelelserne på en sådan måde, at de forbliver grammatisk korrekte.

Vi kan definere formateringen som en proces til gengivelse af strengskabelonen ved at erstatte pladsholderne med deres værdier.

I de følgende afsnit overvejer vi to løsninger, der giver os mulighed for at formatere beskederne.

4.1. Java'er MessageFormat

For at formatere strenge definerer Java adskillige formatmetoder i java.lang.Streng. Men vi kan få endnu mere support via java.text.format.MessageFormat.

For at illustrere, lad os oprette et mønster og føde det til et MessageFormat eksempel:

Strengmønster = "På {0, dato} sendte {1} dig" + "{2, valg, 0 # ingen beskeder | 1 # en besked | 2 # to beskeder | 2 <{2, antal, heltal} beskeder} . "; MessageFormat formatter = ny MessageFormat (mønster, Locale.UK); 

Mønsterstrengen har slots til tre pladsholdere.

Hvis vi leverer hver værdi:

Strengmeddelelse = formatter.format (nyt objekt [] {dato, "Alice", 2});

Derefter MessageFormat udfylder skabelonen og gengiver vores besked:

Den 27. april 2019 sendte Alice dig to beskeder.

4.2. MessageFormat Syntaks

Fra eksemplet ovenfor ser vi, at meddelelsesmønsteret:

mønster = "Den {...} sendte {..} dig {...}.";

indeholder pladsholdere, der er de krøllede parenteser {…} med et krævet argument indeks og to valgfri argumenter, type og stil:

{index} {index, type} {index, type, style}

Pladsholderens indeks svarer til placeringen af ​​et element fra den række af objekter, som vi vil indsætte.

Når det er til stede, type og stil kan tage følgende værdier:

typestil
nummerheltal, valuta, procent, brugerdefineret format
datokort, mellemlang, lang, fuld, brugerdefineret format
tidkort, mellemlang, lang, fuld, brugerdefineret format
valgbrugerdefineret format

Navnene på typerne og stilarterne taler stort set for sig selv, men vi kan se den officielle dokumentation for flere detaljer.

Lad os dog se nærmere på brugerdefineret format.

I eksemplet ovenfor brugte vi følgende formatudtryk:

{2, valg, 0 # ingen beskeder | 1 # en besked | 2 # to beskeder | 2 <{2, antal, heltal} beskeder}

Generelt har valgstilen form af muligheder adskilt af den lodrette bjælke (eller rør):

Inde i indstillingerne er matchværdien kjeg og strengen vjeg er adskilt med # bortset fra den sidste mulighed. Bemærk, at vi muligvis nest andre mønstre i strengen vjeg som vi gjorde det for den sidste mulighed:

{2, valg, ... | 2 <{2, antal, heltal} meddelelser}

Valgtypen er en numerisk baseret, så der er en naturlig rækkefølge for matchværdierne kjeg der deler en numerisk linje i intervaller:

Hvis vi giver en værdi k der hører til intervallet [kjeg, ki + 1) (den venstre ende er inkluderet, den højre er udelukket), derefter værdi vjeg er valgt.

Lad os i flere detaljer overveje intervallerne for den valgte stil. Til dette formål tager vi dette mønster:

mønster = "Du har" + "{0, valg, 0 # ingen beskeder | 1 # en besked | 2 # to beskeder | 2 <{0, antal, heltal} beskeder}.";

og videregive forskellige værdier for sin unikke pladsholder:

nbesked
-1, 0, 0.5Du har ingen beskeder.
1, 1.5Du har en besked.
2Du har to beskeder.
2.5Du har to beskeder.
5Du har 5 beskeder.

4.3. Gør ting bedre

Så vi formaterer nu vores meddelelser. Men selve meddelelsen forbliver hårdkodet.

Fra det foregående afsnit ved vi, at vi skal udtrække strengemønstrene til ressourcerne. For at adskille vores bekymringer, lad os oprette en ny flok ressourcefiler kaldet formater:

I disse opretter vi en nøgle kaldet etiket med sprogspecifikt indhold.

For eksempel i den engelske version lægger vi følgende streng:

label = Den {0, dato, fuld} {1} har sendt dig + {2, valg, 0 # intet | 1 # en besked | 2 # to beskeder | 2 <{2, antal, heltal} beskeder}.

Vi bør ændre den franske version en smule på grund af tilfældet med nul meddelelser:

label = {0, date, short}, {1} 0 <vous a envoyé + {2, choice, 0 # aucun message | 1 # un message | 2 # deux messages | 2 <{2, number, integer} messages} .

Og vi bliver også nødt til at foretage lignende ændringer i den polske og italienske version.

Faktisk viser den polske version endnu et problem. I henhold til grammatikken på det polske sprog (og mange andre) skal verbet være enig i køn med emnet. Vi kunne løse dette problem ved hjælp af valgstypen, men lad os overveje en anden løsning.

4.4. ICU'er MessageFormat

Lad os bruge Internationale komponenter til Unicode (ICU) bibliotek. Vi har allerede nævnt det i vores Konverter en streng til titel sag tutorial. Det er en moden og udbredt løsning, der giver os mulighed for at tilpasse applikationen til forskellige sprog.

Her vil vi ikke udforske det i detaljer. Vi begrænser os bare til, hvad vores legetøjsapplikation har brug for. For at få den mest omfattende og opdaterede information bør vi tjekke ICU's officielle side.

I skrivende stund blev den seneste version af ICU til Java (ICU4J) er 64,2. For at begynde at bruge det skal vi som sædvanlig tilføje det som en afhængighed af vores projekt:

 com.ibm.icu icu4j 64.2 

Antag, at vi vil have en korrekt dannet meddelelse på forskellige sprog og for forskellige antal meddelelser:

NengelskPolere
0Alice har ikke sendt dig nogen beskeder.

Bob har ikke sendt dig nogen beskeder.

Alice nie wysłała ci żadnej wiadomości.

Bob nie wysłał ci żadnej wiadomości.

1Alice har sendt dig en besked.

Bob har sendt dig en besked.

Alice wysłała ci wiadomość.

Bob wysłał ci wiadomość.

> 1Alice har sendt dig N-beskeder.

Bob har sendt dig N-beskeder.

Alice wysłała ci N wiadomości.

Bob wysłał ci N wiadomości.

Først og fremmest skal vi oprette et mønster i de landespecifikke ressourcefiler.

Lad os genbruge filen formats.properties og tilføj der en nøgle label-icu med følgende indhold:

label-icu = {0} har sendt dig + {2, flertal, = 0 {ingen beskeder} = 1 {en besked} + andre {{2, antal, heltal} beskeder}}.

Den indeholder tre pladsholdere, som vi fodrer ved at give der et tre-element array:

Objekt [] data = nyt objekt [] {"Alice", "kvinde", 0}

Vi ser, at den kønsvurderede pladsholder i den engelske version ikke nytter, mens den i den polske:

label-icu = {0} {2, flertal, = 0 {nie} andet {}} + {1, vælg, mand {wysłał} kvinde {wysłała} andet {wysłało}} + ci {2, flertal, = 0 { żadnych wiadomości} = 1 {wiadomość} + andet {{2, nummer, heltal} wiadomości}}.

vi bruger det til at skelne mellem wysłał / wysłała / wysłało.

5. Konklusion

I denne vejledning overvejede vi, hvordan vi kunne lokalisere og formatere de meddelelser, som vi demonstrerer for brugerne af vores applikationer.

Som altid er kodestykkerne til denne tutorial i vores GitHub-lager.


$config[zx-auto] not found$config[zx-overlay] not found