0%

国际化

Java Web 国际化(i18n):多语言应用的实现方案

国际化(Internationalization,简称 i18n,因 “internationalization” 首尾字母中间有 18 个字母而得名)是指应用程序能根据用户的语言或地区自动适配内容,提供本地化(Localization,简称 l10n)体验。在 Java Web 中,通过 Locale 类、资源束(ResourceBundle)及格式化工具,可轻松实现多语言支持。本文将详细介绍国际化的核心概念、实现步骤及最佳实践。

国际化的核心概念

区域设置(Locale)

Locale 类代表特定的语言和地区,由语言代码(如 zh 表示中文,en 表示英文)和国家 / 地区代码(如 CN 表示中国,US 表示美国)组成,格式为 语言代码_国家/地区代码(如 zh_CNen_US)。

常用 Locale 实例

1
2
3
Locale china = Locale.CHINA; // 等同于 new Locale("zh", "CN")
Locale us = Locale.US; // 等同于 new Locale("en", "US")
Locale japan = new Locale("ja", "JP"); // 日语(日本)

Locale 核心方法

方法 作用描述
getLanguage() 获取语言代码(如 zhen
getCountry() 获取国家 / 地区代码(如 CNUS
getDisplayLanguage() 获取本地化的语言名称(如 Locale.CHINA 下返回 “中文”)
getDisplayCountry() 获取本地化的国家 / 地区名称(如 Locale.US 下返回 “美国”)

资源束(ResourceBundle)

资源束是存储多语言文本的配置文件集合,通过 ResourceBundle 类加载,根据 Locale 自动匹配对应的语言资源。

命名规则
资源文件以基础名开头,后跟 _语言代码_国家代码.properties,默认文件(无区域后缀)作为 fallback:

  • messages.properties(默认,当找不到匹配的区域文件时使用)
  • messages_zh_CN.properties(中文 - 中国)
  • messages_en_US.properties(英文 - 美国)

格式化工具

针对日期、时间、货币等需要本地化的内容,Java 提供了专用格式化工具:

  • DateFormat:日期 / 时间格式化;
  • NumberFormat:数字 / 货币格式化;
  • MessageFormat:带占位符的字符串格式化(支持动态参数)。

字符串国际化:基于资源束的实现

创建资源文件

src/main/resources 目录下创建以下文件:

(1)默认资源文件(messages.properties
1
2
3
4
5
# 默认英文(当无匹配区域时使用)
welcome=Welcome
greeting=Hello, {0}!
login.button=Login
logout.button=Logout
(2)中文资源文件(messages_zh_CN.properties
1
2
3
4
welcome=欢迎
greeting=你好,{0}!
login.button=登录
logout.button=退出
(3)英文(美国)资源文件(messages_en_US.properties
1
2
3
4
welcome=Welcome
greeting=Hello, {0}!
login.button=Login
logout.button=Logout

注意:中文资源文件需确保编码正确。若使用 IDE(如 IDEA),可自动处理 Unicode 编码;手动编辑时,需用 native2ascii 工具转换(JDK 自带):

1
native2ascii messages_zh_CN.txt messages_zh_CN.properties

加载资源束并获取字符串

通过 ResourceBundle.getBundle() 加载资源束,根据 Locale 获取对应语言的字符串:

1
2
3
4
5
6
7
8
9
// 获取客户端区域(从请求中获取)
Locale clientLocale = request.getLocale();

// 加载基础名为 "messages" 的资源束
ResourceBundle bundle = ResourceBundle.getBundle("messages", clientLocale);

// 获取字符串
String welcome = bundle.getString("welcome");
String greeting = bundle.getString("greeting"); // 带占位符的字符串

处理带占位符的字符串

使用 MessageFormat 格式化带参数的字符串(如 greeting=你好,{0}! 中的 {0} 为占位符):

1
2
3
4
// 格式化带参数的字符串
String username = "张三";
String formattedGreeting = MessageFormat.format(bundle.getString("greeting"), username);
// 输出:"你好,张三!"(中文环境)或 "Hello, 张三!"(英文环境)

日期与货币的国际化

日期 / 时间格式化(DateFormat

DateFormat 会根据 Locale 自动适配日期格式(如中文为 “2023 年 10 月 1 日”,英文为 “Oct 1, 2023”):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 获取客户端区域
Locale locale = request.getLocale();

// 格式化日期(短格式:年月日)
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale);
String formattedDate = dateFormat.format(new Date());
// 中文环境:"23-10-1" 或 "2023/10/01"(因地区而异)
// 英文环境:"10/01/23"

// 格式化时间(包含时分)
DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
String formattedTime = timeFormat.format(new Date());
// 中文环境:"14:30:45"
// 英文环境:"2:30:45 PM"

货币格式化(NumberFormat

NumberFormat 可根据 Locale 适配货币符号和数字格式(如人民币 “¥1,234.56”,美元 “$1,234.56”):

1
2
3
4
5
6
7
8
9
Locale locale = request.getLocale();

// 获取货币格式化器
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);
double price = 1234.56;
String formattedCurrency = currencyFormat.format(price);
// 中文环境:"¥1,234.56"
// 英文(美国)环境:"$1,234.56"
// 英文(英国)环境:"£1,234.56"

Web 应用中的国际化实践

获取客户端区域

在 Web 应用中,客户端的 Locale 可通过以下方式获取:

1
2
3
4
5
6
7
8
// 方式 1:从请求中获取(基于浏览器的 Accept-Language 头)
Locale clientLocale = request.getLocale();

// 方式 2:从用户会话中获取(用户手动选择的语言,优先级更高)
Locale userLocale = (Locale) session.getAttribute("userLocale");
if (userLocale == null) {
userLocale = request.getLocale(); // 若未选择,使用浏览器默认
}

在 JSP 中使用国际化

通过 JSTL 标签库(fmt 标签)可简化 JSP 中的国际化操作:

(1)引入 JSTL 依赖
1
2
3
4
5
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>1.2.2</version>
</dependency>
(2)JSP 页面中使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!-- 设置区域(从会话或请求中获取) -->
<fmt:setLocale value="${sessionScope.userLocale}" scope="session"/>

<!-- 加载资源束 -->
<fmt:setBundle basename="messages" var="bundle"/>

<!-- 输出字符串 -->
<fmt:message key="welcome" bundle="${bundle}"/><br>
<fmt:message key="greeting" bundle="${bundle}">
<fmt:param value="${username}"/> <!-- 填充占位符 -->
</fmt:message><br>

<!-- 格式化日期 -->
<fmt:formatDate value="${now}" type="date" style="short"/><br>

<!-- 格式化货币 -->
<fmt:formatNumber value="${price}" type="currency"/>

允许用户切换语言

提供语言切换功能,将用户选择的 Locale 存储在会话中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@WebServlet("/change-language")
public class LanguageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String lang = request.getParameter("lang"); // 如 "zh_CN" 或 "en_US"
Locale newLocale = null;
if ("zh_CN".equals(lang)) {
newLocale = Locale.CHINA;
} else if ("en_US".equals(lang)) {
newLocale = Locale.US;
}
// 存储到会话
request.getSession().setAttribute("userLocale", newLocale);
// 重定向回原页面
response.sendRedirect(request.getHeader("Referer"));
}
}

在页面中添加切换链接:

1
2
<a href="/change-language?lang=zh_CN">中文</a>
<a href="/change-language?lang=en_US">English</a>

最佳实践与注意事项

  1. 资源文件管理
    • 按模块拆分资源文件(如 user_messages.propertiesorder_messages.properties),避免单个文件过大;
    • 使用版本控制工具管理资源文件,便于多语言团队协作翻译。
  2. 默认资源文件
    始终提供默认资源文件(messages.properties),确保在无匹配区域时应用仍能正常运行。
  3. 动态内容处理
    数据库中的动态内容(如用户生成的文本)需单独设计国际化方案(如多语言字段)。
  4. 性能优化
    ResourceBundle 会缓存资源文件,避免频繁创建实例;在 JSP 中通过 fmt:setBundlescope 属性设置缓存范围

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10