locale对象需配合resourcebundle、dateformat等类使用才生效;推荐用locale.forlanguagetag("zh-cn")创建,避免构造函数的大小写和分隔符错误。

Locale对象怎么创建才真正生效
Java里Locale本身只是语言/地区标识,不自动切换资源或格式化行为。必须配合ResourceBundle、DateFormat、NumberFormat等类使用,否则new Locale("zh", "CN")只是个空壳。
- 推荐用
Locale.forLanguageTag("zh-CN")而非构造函数,避免大小写和分隔符错误(比如"zh_cn"或"ZH-CN"可能被忽略) - 系统默认
Locale由JVM启动时确定,运行中调用Locale.setDefault()会影响全局——但多数Web应用(如Spring)会为每个请求单独设置,不该全局改 - Servlet容器(如Tomcat)通常从HTTP
Accept-Language头解析出Locale,别硬编码new Locale("en_US")去覆盖它
ResourceBundle加载不到properties文件的常见原因
名字匹配规则严格:假设ResourceBundle.getBundle("messages", locale),实际查找顺序是messages_zh_CN.properties → messages_zh.properties → messages.properties(后备)。任意环节路径、编码、命名错都会静默回退到默认。
- 文件必须在classpath下,且名称区分大小写:
Messages_zh_CN.properties≠messages_zh_CN.properties - properties文件默认ISO-8859-1编码,中文需用
native2ascii转义(如\u4f60\u597d),或改用ResourceBundle.Control支持UTF-8(Java 9+) - Spring Boot项目若用
@PropertySource加载,它不走ResourceBundle机制,得用MessageSource接口
日期/数字格式化为什么没按Locale变化
直接调new SimpleDateFormat("yyyy-MM-dd")用的是默认Locale,跟当前线程Locale无关。必须显式传入:
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, new Locale("ja", "JP"));
// 或
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.withLocale(new Locale("ko", "KR"));
-
SimpleDateFormat非线程安全,多线程场景必须每次新建或用ThreadLocal缓存 -
java.time类(如DateTimeFormatter)是不可变的,可复用,但withLocale()必须调用,否则仍用系统默认 - Android上
Locale.getDefault()可能返回Locale.ROOT,导致格式化异常,需显式检查
Spring Boot里MessageSource配置容易漏的关键点
Spring默认用ResourceBundleMessageSource,但几个配置项不设就失效:
立即学习“Java免费学习笔记(深入)”;
-
spring.messages.basename必须指定基础名(如messages),不能只写路径;多个用逗号分隔:messages,validation -
spring.messages.encoding=UTF-8必须显式声明,否则读取中文properties会乱码(尤其Windows开发机) - 如果用
ReloadableResourceBundleMessageSource实现热更新,cacheSeconds要设为正数(如10),否则仍走默认缓存逻辑 - Thymeleaf模板中
#{key}依赖Spring的MessageSource,若Controller里手动newResourceBundle,不会触发Spring的占位符解析
国际化不是配个Locale就完事,核心是资源加载链路(basename→文件名→编码→缓存)和格式化工具链(Date/Number/Message)两处必须全部对齐,任一环节断开,就会静默回退到默认行为,而这种问题在线上环境最难排查。










