本文介绍了Java的MessageFormat没有以小写形式在日期中本地化葡萄牙语月份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 月份名称以大写字母而不是小写字母开头,他们应该 。 我在本地机器上运行的一些示例代码: 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 =今天是{0,日期,长}!; 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(葡萄牙结果:+ ptResult.toString()); System.out.println(巴西结果:+ brResult.toString()); System.out.println(法国结果:+ frResult.toString()); 这就是我得到的: 葡萄牙结果:今天是10 de Julho de 2018! 巴西结果:今天是10 de Julho de 2018! 法国结果:今天是2018年10月1日! 所以法语是正确的,但由于某种原因,两种葡萄牙语变体不是。 甚至更奇怪,我尝试添加与 IDEAONE代码段,它根本不会本地化。 我在这里误解了什么?解决方案 tl; dr Java的不同实现可能在本地化规则上有所不同。 不同版本的实现Java的本地化规则可能有所不同。 对于Oracle JDK& OpenJDK项目,版本9及更高版本在其自己的规则集和由 Unicode CLDR (参见维基百科)。请参阅发行说明和请参阅 OpenJDK JEP 252 。 运行以下代码: Month.JULY.getDisplayName(TextStyle.FULL,new Locale(pt)) 在Java 8,Oracle JDK中,默认使用自己的本地化规则,我们得到了初始值-cap。 In Java 10,Oracle JDK,默认情况下使用Unicode CLDR 规则,我们得到小写。在Java 10中,设置VM选项后的Oracle JDK -Djava.locale.providers = COMPAT,SPI 要恢复遗留行为而不是使用Unicode CLDR,我们会获得初始上限。 详细信息 文化规范定义的格式规则可能因 JVM 实施和版本。 IdeOne.com中的//en.wikipedia.org/wiki/Java_virtual_machine\"rel =nofollow noreferrer> JVM 拒绝本地化。只有美国英语。 查看证明。 您使用的是错误的课程。 使用 java.time 进行所有日期时间处理。 代码。 ZonedDateTime //从特定时区看一下现代课程。 .now()//使用JVM的当前默认时区捕获当前时刻。最好明确指定区域。 .format(//生成一个`String`表示我们的`ZonedDateTime`对象的值。 DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL) .withLocale(new Locale(pt, BR)))//返回一个`String`对象。 文化规范 决定诸如月份名称的大写等问题取决于文化的规范。当然,这些规范可以有所不同,合理的人可以不同意。 但在某些时候,必须作出决定。 Java实现必须具有一组用于制定这些本地化规则的规则。 Unicode CLDR 也许您使用的是Java 8或更早版本。我在本答案中的代码是用Java 10生成的。 一个重要的区别是,从Java 9开始,对于Oracle JDK和OpenJDK项目,默认来源本地化规则已更改使用 Unicode CLDR (参见维基百科)。在Java 8及更早版本中,每个JVM都提供了自己的一套规则。 另外,请注意Unicode CLDR会不时更新,有些规则可能会更改。 因此,您可能会看到不同的本地化结果,具体取决于正在使用的Java版本以及正在使用的Java实现。 演示语境 这里的问题或许是上下文之一。在某些文化中,格式规则(例如月份名称的大小写)会因月份是单独呈现还是嵌入日期而有所不同。 让我们试试translate.Google.com: 7月收益 Julho 7月初收益率noiníciodomêsdejulho 2018年7月12日收益率 12 de julho de 2018 所以Google似乎有所不同通过上下文,但我不确定第一个案例是初始上限是怎么回事。 这个上下文可以通过使用 TextStyle enum用于 Month :: getDisplayName 方法。该枚举提供 ... STANDALONE 变体。 Month.JULY.getDisplayName( TextStyle.FULL, new Locale(pt)) Month.JULY.getDisplayName( TextStyle.FULL_STANDALONE,新区域设置(pt)) julho 所以不,在使用Java 10时,上下文似乎不是问题。 java.time 您正在使用现在由 java.time classes。 使用 java代替 java.util.Date 。 time.Instant 。两者都代表UTC的时刻。现代 Instant 类使用更精细的分辨率纳秒而不是毫秒。 即时瞬间= Instant.now(); //以UTC格式捕获当前时刻。 从UTC调整到该地区人员使用您所需的特定挂钟时间的时区。应用 ZoneId 来获取 ZonedDateTime 对象。时区与区域设置完全正交。一个涉及当下的内容,另一个仅影响用于生成字符串以表示该内容的本地化。例如,您可以使用带有葡萄牙语语言环境的日本时区。 ZoneId z = ZoneId.of(Pacific / Auckland); ZonedDateTime zdt = instant.atZone(z); 现在,我们想要生成代表那一刻的字符串。首先,在标准 ISO 8601 ISO 8601中生成 String a>格式通过在方括号中附加时区名称来扩展。 String output = zdt.toString(); //生成ISO 8601格式字符串。 您想要本地化生成的 String 对象。使用 DateTimeFormatter 控制要生成的 String 的格式。指定 FormatStyle 控制多长或缩短。 区域设置l_pt =新区域设置(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)); 为了好玩,让我们试试 FormatStyle.LONG 而不是 FULL 。 IdeOne拒绝本地化 我喜欢使用IdeOne.com来演示Java代码。不幸的是,它的JVM拒绝使用除美国英语之外的任何 Locale 。所以,不要去上面的代码。 关于 java.time java.time 框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,例如 java.util.Date , 日历 ,& SimpleDateFormat 。 Joda-Time 项目,现已进入维护模式 ,建议迁移到 java.time classes。 要了解更多信息,请参阅 Oracle Tutorial 。并搜索Stack Overflow以获取许多示例和解释。规范是 JSR 310 。 您可以直接与数据库交换 java.time 对象。使用符合 JDBC驱动程序 / jeps / 170rel =nofollow noreferrer> JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql。* 类。 从哪里获取java.time班? Java SE 8 , Java SE 9 , Java SE 10 ,以及之后 内置。 带有捆绑实现的标准Java API的一部分。 Java 9添加了一些小功能和修复。 Java SE 6 和 Java SE 7 大部分java.time功能都被反向移植到Java 6& 7 ThreeTen-Backport 。 Android java.time 类的Android捆绑包实现的更高版本。 对于早期的Android(< 26), ThreeTenABP 项目适应 ThreeTen- Backport (如上所述)。请参阅 如何使用ThreeTenABP ...... 。 ThreeTen-Extra 项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在这里找到一些有用的课程,例如 Interval , YearWeek , YearQuarter ,更多。 简短的时间历史 回应对此答复的评论...... 时间表: Sun Microsystems 推出 Java 1.0 ,带有一些日期时间cl IBM捐赠的asses( java.util.Date 等)/ Taligent公司。不幸的是,它们设计糟糕,有缺陷,令人困惑和麻烦。 Sun在Java 1.1中添加了更多类( java.util.Calendar 等)试图改善日期时间处理。但是这些设计也很糟糕而且令人困惑,而不是真正的改进。 多年后,一个男人 Stephen Colebourne 创建了 Joda-Time 项目,创建了一个全面复杂的日期时间处理库,这是IT行业中的第一个。巨大的成功。最受欢迎的Java库之一,经常添加到许多开发人员的项目中。 Sun,然后是Oracle,以及 JCP社区最终认识到最早版本的Java附带的旧日期时间类是不够的。这种认可为同样的Stephen Colebourne打开了大门,推出了 JSR 310 ,一个全新的日期时间API,作为Java平台的一部分。这个项目基于Joda-Time的概念,但是是一个全新的重写。新的重写基于创建Joda-Time的经验,询问如果我们知道我们现在知道什么,我们将如何设计Joda-Time?。 JSR 310的实现是作为 java.time 包构建的,包含在即将到来的Java 8中。 为了确保更广泛地接受 java.time API,Stephen Colebourne启动了开源 ThreeTen-Backport 项目,模仿与 java.time 中几乎相同的API,但能够在Java 6和Java 7上运行。并不是全部 java.time 功能,但大多数。目标是使早期Java上的开发人员能够开始使用API。然后,当转移到更高版本的Java时,他们只需要更改 org.threeten.bp中的 import 语句。* 到 java.time。* 。 随着Java 8的成功发售,Stephen Colebourne等人。将Joda-Time项目转变为维护模式,仍然使用 tzdata 更改和错误修复,但没有其他功能可以完成。他们建议从Joda-Time迁移到 java.time 类。 Stephen Colebourne还启动了开源 ThreeTen-Extra 项目,以处理可能会或可能不会在以后提交的其他功能JSR 310的版本(成为附加的 java.time 类)。同时,这些额外的功能, java.time 功能的扩展,作为一个库提供给那些发现它们有用的开发人员。 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? 解决方案 tl;drDifferent 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.In Java 10, Oracle JDK, by default using Unicode CLDR rules, we get lowercase.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.DetailsThe 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.Cultural normsDeciding 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 CLDRPerhaps 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 presentationPerhaps 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 yields JulhoEarly in the month of July yields no início do mês de julho12th of July, 2018 yields 12 de julho de 2018So 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" ))Month.JULY.getDisplayName( TextStyle.FULL_STANDALONE , new Locale( "pt" ))So no, context seems to not be an issue here when using Java 10.java.timeYou 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.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.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 ) ) ;For fun, let’s try FormatStyle.LONG instead of FULL.IdeOne refuses to localizeI 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.timeThe 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 laterBuilt-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 7Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.AndroidLater 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 timeResponding 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 from org.threeten.bp.* to java.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. 这篇关于Java的MessageFormat没有以小写形式在日期中本地化葡萄牙语月份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 08-01 12:48