问题
The month names start with an uppercase letter instead of lowercase, as they should.
Some sample code I ran on my local machine:
Locale portugal = new Locale("pt");
Locale brazil = new Locale("pt", "BR");
Locale france = new Locale("fr", "FR");
Object[] params = new Object[] { new Date() };
String pattern = "Today is {0,date,long}!";
MessageFormat ptFormat = new MessageFormat(pattern, portugal);
MessageFormat brFormat = new MessageFormat(pattern, brazil);
MessageFormat frFormat = new MessageFormat(pattern, france);
StringBuffer ptResult = ptFormat.format(params, new StringBuffer(), new FieldPosition(0));
StringBuffer brResult = brFormat.format(params, new StringBuffer(), new FieldPosition(0));
StringBuffer frResult = frFormat.format(params, new StringBuffer(), null);
System.out.println("Portugal result: " + ptResult.toString());
System.out.println("Brazil result: " + brResult.toString());
System.out.println("France result: " + frResult.toString());
And this is what I got:
Portugal result: Today is 10 de Julho de 2018!
Brazil result: Today is 10 de Julho de 2018!
France result: Today is 10 juillet 2018!
So the French is correct, but for some reason the two Portuguese variants are not.
Even weirder, I tried adding the exact same code as an IDEAONE snippet, and it wouldn't localize at all.
What am I misunderstanding here?
回答1:
tl;dr
- Different implementations of Java may vary in their rules for localization.
- Different versions of an implementation of Java may vary in their rules for localization.
For the Oracle JDK & OpenJDK projects, version 9 and later switched between its own set of rules and the set of rules defined by the Unicode CLDR (see Wikipedia). See Release Notes and see OpenJDK JEP 252.
Run this code:
Month.JULY.getDisplayName( TextStyle.FULL , new Locale( "pt" ) )
In Java 8, Oracle JDK, by default using its own localization rules, we get initial-cap.
Julho
In Java 10, Oracle JDK, by default using Unicode CLDR rules, we get lowercase.
julho
In Java 10, Oracle JDK after setting the VM option -Djava.locale.providers=COMPAT,SPI
to revert to legacy behavior rather than using Unicode CLDR, we get initial-cap.
Julho
Details
- The formatting rules defined by cultural norms may vary by JVM implementation and version.
- The JVM in IdeOne.com refuses to localize. Only US English. See proof.
- You are using the wrong classes. Use java.time for all date-time handling.
Code.
ZonedDateTime // Use modern class for a moment seen from a particular time zone.
.now() // Capture the current moment, using the JVM’s current default time zone. Better to specify a zone explicitly.
.format( // Generate a `String` representing the value of our `ZonedDateTime` object.
DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( new Locale( "pt" , "BR" ) )
) // Returns a `String` object.
11 de julho de 2018 17:57:36 NZST
Cultural norms
Deciding an issue such as capitalization of a month name depends on a culture’s norms. Of course, those norms can vary, and reasonable people can disagree.
But at some point, decisions have to be made. A Java implementation must have a set of rules for making these localization rules.
Unicode CLDR
Perhaps you are using Java 8 or earlier. My code in this Answer was produced with Java 10.
One important difference is that as of Java 9, for the Oracle JDK and OpenJDK projects, the default source of localization rules changed to using the Unicode CLDR (see Wikipedia). In Java 8 and earlier, each JVM provided their own set of rules.
Also, note that the Unicode CLDR is updated from time-to-time, and some rules may change.
So, you may well see different results for localization depending on which version of Java is in use, and on which implementation of Java is in use.
Context of presentation
Perhaps the issue here is one of context. In some cultures, the formatting rules such as capitalization of a month name vary by whether the month is being presented alone or embedded within a date.
Let’s try translate.Google.com:
July
yieldsJulho
Early in the month of July
yieldsno início do mês de julho
12th of July, 2018
yields12 de julho de 2018
So Google seems to vary by context, but I am not certain what is going on with that first case being initial-cap.
This context can be indicated by the use of the TextStyle enum used in Month::getDisplayName method. That enum offers …STANDALONE
variations.
Month.JULY.getDisplayName(
TextStyle.FULL ,
new Locale( "pt" )
)
julho
Month.JULY.getDisplayName(
TextStyle.FULL_STANDALONE ,
new Locale( "pt" )
)
julho
So no, context seems to not be an issue here when using Java 10.
java.time
You are using the troublesome old classes now supplanted by the java.time classes.
Instead of java.util.Date
, use java.time.Instant
. Both represent a moment in UTC. The modern Instant
class uses a finer resolution of nanoseconds instead of milliseconds.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
instant.toString(): 2018-07-11T05:57:36.446917Z
Adjust from UTC to the time zone where the people of that region use a particular wall-clock time you desire. Apply a ZoneId
to get a ZonedDateTime
object. Time zone is completely orthogonal to locale. One relates to the content of the moment, the other affects only the localization used in generating a String to represent that content. You could, for example, use a Japan time zone with a Portuguese locale.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Now, we want to generate strings representing that moment. First, generate a String
in standard ISO 8601 format extended by appending the name of the time zone in square brackets.
String output = zdt.toString() ; // Generate ISO 8601 format string.
2018-07-11T17:57:36.446917+12:00[Pacific/Auckland]
You want to localize the generated String
objects. Use DateTimeFormatter to control the formatting of the String
to be generated. Specify a FormatStyle to control how long or abbreviated.
Locale l_pt = new Locale( "pt" ) ;
Locale l_ptBR = new Locale( "pt" , "BR" ) ;
Locale l_FR = Locale.FRANCE ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ) ;
String output_pt = zdt.format( f.withLocale( l_pt ) ) ;
String output_ptBR = zdt.format( f.withLocale( l_ptBR ) ) ;
String output_FR = zdt.format( f.withLocale( l_FR ) ) ;
quarta-feira, 11 de julho de 2018 17:57:36 Horário Padrão da Nova Zelândia
quarta-feira, 11 de julho de 2018 17:57:36 Horário Padrão da Nova Zelândia
mercredi 11 juillet 2018 à 17:57:36 heure normale de la Nouvelle-Zélande
For fun, let’s try FormatStyle.LONG instead of FULL
.
11 de julho de 2018 17:57:36 NZST
11 de julho de 2018 17:57:36 NZST
11 juillet 2018 à 17:57:36 NZSTe
IdeOne refuses to localize
I enjoy using IdeOne.com to demo Java code. Unfortunately, its JVM refuses to use any Locale
except US English. So, no go for the code above.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, Java SE 10, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
A brief history of time
Responding to comments on this Answer…
Timeline:
- Sun Microsystems launches Java 1.0 with some date-time classes (
java.util.Date
etc.) donated by IBM/Taligent. Unfortunately, they are poorly-designed and flawed, confusing and troublesome. - Sun adds more classes in Java 1.1 (
java.util.Calendar
etc.) in an attempt to improve the date-time handling. But these too turn out to be poorly-designed and confusing, not a real improvement. - Years later, a man Stephen Colebourne founds the Joda-Time project, to make a comprehensive sophisticated date-time handling library, a first in the IT industry afaik. Huge success. One of the most popular Java libraries, added routinely to many developers’ projects.
- Sun, then Oracle, and the JCP community finally recognize that the old date-time classes shipped with the earliest versions of Java are not adequate. This recognition opens the door for that same Stephen Colebourne to launch JSR 310, a specification for an all-new date-time API for inclusion as part of the Java platform. This project is based on concepts from Joda-Time, but is an entirely new rewrite. The new rewrite builds on the experience of having created Joda-Time, asking “If we knew then what we know now, how would we have designed Joda-Time?”.
- The implementation of JSR 310 is built as the java.time package to be included with the then-upcoming Java 8.
- To ensure wider acceptance of the java.time API, Stephen Colebourne launches the open-source ThreeTen-Backport project, mimicking nearly the same API as in java.time but capable of running on Java 6 and Java 7. Not quite all of the java.time functionality, but most of it. The goal is to enable a developer on earlier Java to start using the API. Then when moving to later versions of Java they need do little more than change their
import
statements fromorg.threeten.bp.*
tojava.time.*
. - With Java 8 successfully shipping, Stephen Colebourne et al. shift the Joda-Time project into maintenance-mode, still actively updated with tzdata changes and bug fixes, but no further feature work to be done. They advise migration away from Joda-Time and on to the java.time classes.
- Stephen Colebourne also launches the open-source ThreeTen-Extra project to work on additional features that may or may not eventually be submitted to later versions of JSR 310 (to become additional java.time classes). Meanwhile, these extra features, extensions to the java.time functionality, are provided as a library to the public for those developers who find them useful.
来源:https://stackoverflow.com/questions/51275322/javas-messageformat-not-localizing-portuguese-months-in-dates-in-lowercase