|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在当今全球化的互联网环境中,开发支持多语言的网站已成为一项基本需求。JSP国际化(Internationalization,简称i18n)技术允许开发者构建能够根据用户语言偏好自动调整显示内容的应用程序,从而为不同语言背景的用户提供更好的体验。本文将全面介绍JSP国际化的概念、实现方法和最佳实践,帮助您轻松构建多语言网站。
国际化的基本原理
国际化是指设计和编写应用程序,使其能够适应不同的语言和地区而无需进行工程上的更改。与之相关的本地化(Localization,简称L10n)则是将国际化的应用程序适配到特定语言和地区的过程。
JSP国际化的核心思想是将所有与语言相关的文本从代码中分离出来,存储在外部资源文件中。当用户请求页面时,系统根据用户的语言环境加载相应的资源文件,从而显示对应语言的内容。
这种方法的优点是:
• 无需修改代码即可添加对新语言的支持
• 维护简单,只需翻译资源文件即可更新语言内容
• 代码更加清晰,不包含硬编码的文本
JSP国际化的核心技术
ResourceBundle
ResourceBundle是Java中用于加载特定语言环境资源的类。它允许我们将应用程序中的文本字符串提取到属性文件中,然后根据用户的Locale加载相应的属性文件。
ResourceBundle的基本用法如下:
- // 加载默认的资源包
- ResourceBundle messages = ResourceBundle.getBundle("messages");
- // 加载特定语言环境的资源包
- ResourceBundle messages = ResourceBundle.getBundle("messages", new Locale("zh", "CN"));
- // 从资源包中获取消息
- String greeting = messages.getString("greeting");
复制代码
Locale类
Locale类表示特定的地理、政治或文化区域。它通常用于根据用户的语言、国家/地区和其他文化偏好定制应用程序的行为。
- // 创建表示中文(中国)的Locale对象
- Locale localeZhCN = new Locale("zh", "CN");
- // 创建表示英语(美国)的Locale对象
- Locale localeEnUS = new Locale("en", "US");
- // 获取系统默认的Locale
- Locale defaultLocale = Locale.getDefault();
复制代码
MessageFormat
MessageFormat类提供了一种灵活的方式来格式化包含变量的消息。它允许我们在资源文件中定义带有占位符的消息,然后在运行时替换这些占位符。
- // 在资源文件中定义消息
- // welcome.message=欢迎 {0},今天是 {1}
- // 在Java代码中使用MessageFormat
- String pattern = messages.getString("welcome.message");
- Object[] params = {"张三", new Date()};
- String message = MessageFormat.format(pattern, params);
- System.out.println(message);
- // 输出:欢迎 张三,今天是 2023-11-15
复制代码
JSTL fmt标签库
JSP标准标签库(JSTL)中的fmt标签提供了一套用于国际化的标签,简化了在JSP页面中实现国际化的过程。要使用这些标签,首先需要在JSP页面中引入fmt标签库:
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
复制代码
实现步骤详解
创建资源文件
资源文件是国际化的基础,它们存储了不同语言版本的文本内容。通常,我们会为每种语言创建一个属性文件,文件名格式为basename_language_country.properties。
例如,创建以下资源文件:
messages_en_US.properties(英语 - 美国)
- greeting=Hello
- welcome=Welcome to our website
- login.username=Username
- login.password=Password
- login.button=Login
复制代码
messages_zh_CN.properties(中文 - 中国)
- greeting=你好
- welcome=欢迎访问我们的网站
- login.username=用户名
- login.password=密码
- login.button=登录
复制代码
messages_ja_JP.properties(日语 - 日本)
- greeting=こんにちは
- welcome=私たちのウェブサイトへようこそ
- login.username=ユーザー名
- login.password=パスワード
- login.button=ログイン
复制代码
这些文件应该放在WEB-INF/classes目录下,这样类加载器才能找到它们。如果使用Maven或Gradle构建项目,可以将它们放在src/main/resources目录下。
配置web.xml
在web.xml中,我们可以配置一些与国际化相关的参数,如默认语言环境、支持的字符集等。
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
- http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
- version="4.0">
-
- <!-- 配置字符编码过滤器 -->
- <filter>
- <filter-name>CharacterEncodingFilter</filter-name>
- <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
-
- <filter-mapping>
- <filter-name>CharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
-
- <!-- 配置默认语言环境 -->
- <context-param>
- <param-name>javax.servlet.jsp.jstl.fmt.locale</param-name>
- <param-value>en_US</param-value>
- </context-param>
-
- <!-- 配置资源包的基础名称 -->
- <context-param>
- <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
- <param-value>messages</param-value>
- </context-param>
- </web-app>
复制代码
在JSP页面中使用国际化
使用JSTL的fmt标签,我们可以在JSP页面中轻松实现国际化。以下是一个简单的登录页面示例:
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="greeting"/></title>
- </head>
- <body>
- <h1><fmt:message key="welcome"/></h1>
-
- <form action="login" method="post">
- <div>
- <label for="username"><fmt:message key="login.username"/>:</label>
- <input type="text" id="username" name="username" required>
- </div>
- <div>
- <label for="password"><fmt:message key="login.password"/>:</label>
- <input type="password" id="password" name="password" required>
- </div>
- <div>
- <button type="submit"><fmt:message key="login.button"/></button>
- </div>
- </form>
-
- <!-- 语言选择器 -->
- <div>
- <a href="?lang=en_US">English</a> |
- <a href="?lang=zh_CN">中文</a> |
- <a href="?lang=ja_JP">日本語</a>
- </div>
- </body>
- </html>
复制代码
动态语言切换实现
实现动态语言切换通常需要以下步骤:
1. 创建语言选择器(如下拉菜单或链接)
2. 将用户选择的语言存储在会话或cookie中
3. 在每个页面加载时检查用户选择的语言并设置相应的Locale
下面是一个完整的实现示例:
LocaleFilter.java
- import javax.servlet.*;
- import javax.servlet.annotation.WebFilter;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- import java.util.Locale;
- @WebFilter("/*")
- public class LocaleFilter implements Filter {
- private static final String DEFAULT_LOCALE = "en_US";
- private static final String LOCALE_SESSION_ATTRIBUTE = "userLocale";
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- HttpServletRequest httpRequest = (HttpServletRequest) request;
- HttpSession session = httpRequest.getSession();
-
- // 检查请求参数中是否包含语言设置
- String langParam = httpRequest.getParameter("lang");
- if (langParam != null && !langParam.isEmpty()) {
- // 用户选择了新语言,更新会话中的语言设置
- session.setAttribute(LOCALE_SESSION_ATTRIBUTE, langParam);
- }
-
- // 获取当前语言环境
- String userLocale = (String) session.getAttribute(LOCALE_SESSION_ATTRIBUTE);
- if (userLocale == null) {
- userLocale = DEFAULT_LOCALE;
- }
-
- // 设置请求的语言环境
- String[] localeParts = userLocale.split("_");
- if (localeParts.length == 2) {
- request.setAttribute("userLocale", new Locale(localeParts[0], localeParts[1]));
- }
-
- chain.doFilter(request, response);
- }
- @Override
- public void destroy() {
- }
- }
复制代码
header.jspf(可被所有页面包含的片段)
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <c:if test="${not empty userLocale}">
- <fmt:setLocale value="${userLocale}" scope="session" />
- </c:if>
- <fmt:setBundle basename="messages" scope="session" />
复制代码
index.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="greeting"/></title>
- </head>
- <body>
- <%@ include file="header.jspf" %>
-
- <h1><fmt:message key="welcome"/></h1>
-
- <p><fmt:message key="intro.text"/></p>
-
- <!-- 语言选择器 -->
- <div>
- <a href="?lang=en_US">English</a> |
- <a href="?lang=zh_CN">中文</a> |
- <a href="?lang=ja_JP">日本語</a>
- </div>
- </body>
- </html>
复制代码
高级主题
日期和时间的国际化
不同国家和地区对日期和时间的格式有不同的偏好。使用JSTL的fmt标签,我们可以根据用户的语言环境正确格式化日期和时间。
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <%@ include file="header.jspf" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="date.format.example"/></title>
- </head>
- <body>
- <h1><fmt:message key="date.format.example"/></h1>
-
- <!-- 设置当前日期 -->
- <jsp:useBean id="now" class="java.util.Date" />
-
- <!-- 日期格式示例 -->
- <p><fmt:message key="full.date"/>:
- <fmt:formatDate value="${now}" dateStyle="full" /></p>
-
- <p><fmt:message key="long.date"/>:
- <fmt:formatDate value="${now}" dateStyle="long" /></p>
-
- <p><fmt:message key="medium.date"/>:
- <fmt:formatDate value="${now}" dateStyle="medium" /></p>
-
- <p><fmt:message key="short.date"/>:
- <fmt:formatDate value="${now}" dateStyle="short" /></p>
-
- <!-- 时间格式示例 -->
- <p><fmt:message key="full.time"/>:
- <fmt:formatDate value="${now}" type="time" timeStyle="full" /></p>
-
- <p><fmt:message key="long.time"/>:
- <fmt:formatDate value="${now}" type="time" timeStyle="long" /></p>
-
- <!-- 自定义日期时间格式 -->
- <p><fmt:message key="custom.datetime"/>:
- <fmt:formatDate value="${now}" pattern="yyyy-MM-dd HH:mm:ss" /></p>
- </body>
- </html>
复制代码
数字和货币的国际化
数字和货币的格式也因地区而异。例如,美国使用小数点作为小数分隔符,逗号作为千位分隔符,而许多欧洲国家则相反。同样,货币符号的位置和格式也各不相同。
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <%@ include file="header.jspf" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="number.format.example"/></title>
- </head>
- <body>
- <h1><fmt:message key="number.format.example"/></h1>
-
- <!-- 设置一个数字 -->
- <c:set var="number" value="1234567.89" />
-
- <!-- 数字格式示例 -->
- <p><fmt:message key="default.number"/>:
- <fmt:formatNumber value="${number}" /></p>
-
- <p><fmt:message key="number.without.grouping"/>:
- <fmt:formatNumber value="${number}" groupingUsed="false" /></p>
-
- <p><fmt:message key="number.with.decimals"/>:
- <fmt:formatNumber value="${number}" maxFractionDigits="4" /></p>
-
- <!-- 百分比格式 -->
- <p><fmt:message key="percentage"/>:
- <fmt:formatNumber value="0.85" type="percent" /></p>
-
- <!-- 货币格式 -->
- <p><fmt:message key="currency"/>:
- <fmt:formatNumber value="${number}" type="currency" /></p>
-
- <!-- 设置不同的货币 -->
- <p><fmt:message key="usd.currency"/>:
- <fmt:setLocale value="en_US" />
- <fmt:formatNumber value="${number}" type="currency" /></p>
-
- <p><fmt:message key="eur.currency"/>:
- <fmt:setLocale value="de_DE" />
- <fmt:formatNumber value="${number}" type="currency" /></p>
-
- <p><fmt:message key="jpy.currency"/>:
- <fmt:setLocale value="ja_JP" />
- <fmt:formatNumber value="${number}" type="currency" /></p>
-
- <!-- 恢复用户Locale -->
- <c:if test="${not empty userLocale}">
- <fmt:setLocale value="${userLocale}" />
- </c:if>
- </body>
- </html>
复制代码
处理不同语言的文本方向
某些语言(如阿拉伯语和希伯来语)是从右到左(RTL)书写的。在国际化网站中,我们需要考虑这些语言的文本方向问题。可以通过CSS和HTML的dir属性来控制文本方向。
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <%@ include file="header.jspf" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="rtl.example"/></title>
- <style>
- .ltr {
- direction: ltr;
- text-align: left;
- }
- .rtl {
- direction: rtl;
- text-align: right;
- }
- .container {
- max-width: 800px;
- margin: 0 auto;
- padding: 20px;
- }
- </style>
- </head>
- <body>
- <%-- 根据语言设置文本方向 --%>
- <c:choose>
- <c:when test="${pageContext.response.locale.language == 'ar' || pageContext.response.locale.language == 'he'}">
- <c:set var="textDirection" value="rtl" />
- </c:when>
- <c:otherwise>
- <c:set var="textDirection" value="ltr" />
- </c:otherwise>
- </c:choose>
-
- <div class="container ${textDirection}">
- <h1><fmt:message key="rtl.example"/></h1>
-
- <p><fmt:message key="rtl.description"/></p>
-
- <div>
- <h2><fmt:message key="sample.text"/></h2>
- <p><fmt:message key="sample.paragraph"/></p>
- </div>
-
- <div>
- <h2><fmt:message key="language.switcher"/></h2>
- <p>
- <a href="?lang=en_US">English</a> |
- <a href="?lang=zh_CN">中文</a> |
- <a href="?lang=ar_SA">العربية</a> |
- <a href="?lang=he_IL">עברית</a>
- </p>
- </div>
- </div>
- </body>
- </html>
复制代码
最佳实践和常见问题
最佳实践
1. 始终使用UTF-8编码在所有JSP页面中设置pageEncoding="UTF-8"在HTML中使用<meta charset="UTF-8">在web.xml中配置字符编码过滤器
2. 在所有JSP页面中设置pageEncoding="UTF-8"
3. 在HTML中使用<meta charset="UTF-8">
4. 在web.xml中配置字符编码过滤器
5. 避免在JSP页面中硬编码文本所有用户可见的文本都应该放在资源文件中包括按钮标签、错误消息、提示文本等
6. 所有用户可见的文本都应该放在资源文件中
7. 包括按钮标签、错误消息、提示文本等
8. 使用一致的资源文件命名约定使用有意义的基名,如messages、labels等遵循basename_language_country.properties的命名规则
9. 使用有意义的基名,如messages、labels等
10. 遵循basename_language_country.properties的命名规则
11. 提供完整的翻译确保所有语言版本都包含相同的键对于缺失的翻译,提供默认值或回退机制
12. 确保所有语言版本都包含相同的键
13. 对于缺失的翻译,提供默认值或回退机制
14. 考虑图像和颜色的文化差异避免使用具有特定文化含义的图像注意颜色在不同文化中的象征意义
15. 避免使用具有特定文化含义的图像
16. 注意颜色在不同文化中的象征意义
17. 处理复数形式和性别差异某些语言有复杂的复数形式规则考虑使用ChoiceFormat处理复数形式
18. 某些语言有复杂的复数形式规则
19. 考虑使用ChoiceFormat处理复数形式
始终使用UTF-8编码
• 在所有JSP页面中设置pageEncoding="UTF-8"
• 在HTML中使用<meta charset="UTF-8">
• 在web.xml中配置字符编码过滤器
避免在JSP页面中硬编码文本
• 所有用户可见的文本都应该放在资源文件中
• 包括按钮标签、错误消息、提示文本等
使用一致的资源文件命名约定
• 使用有意义的基名,如messages、labels等
• 遵循basename_language_country.properties的命名规则
提供完整的翻译
• 确保所有语言版本都包含相同的键
• 对于缺失的翻译,提供默认值或回退机制
考虑图像和颜色的文化差异
• 避免使用具有特定文化含义的图像
• 注意颜色在不同文化中的象征意义
处理复数形式和性别差异
• 某些语言有复杂的复数形式规则
• 考虑使用ChoiceFormat处理复数形式
常见问题及解决方案
1. 资源文件加载失败确保资源文件位于正确的位置(WEB-INF/classes或src/main/resources)检查文件名是否正确(区分大小写)验证资源文件的内容格式是否正确
2. 确保资源文件位于正确的位置(WEB-INF/classes或src/main/resources)
3. 检查文件名是否正确(区分大小写)
4. 验证资源文件的内容格式是否正确
5. 中文或其他非ASCII字符显示为乱码确保所有文件使用UTF-8编码保存检查web.xml中是否配置了字符编码过滤器验证数据库连接和表是否使用UTF-8编码
6. 确保所有文件使用UTF-8编码保存
7. 检查web.xml中是否配置了字符编码过滤器
8. 验证数据库连接和表是否使用UTF-8编码
9. 日期/时间/数字格式不正确确保正确设置了Locale检查是否使用了适当的格式样式(full, long, medium, short)考虑使用自定义格式模式
10. 确保正确设置了Locale
11. 检查是否使用了适当的格式样式(full, long, medium, short)
12. 考虑使用自定义格式模式
13. 动态语言切换不生效确保语言参数正确传递和处理检查Locale过滤器是否正确配置和映射验证会话中的Locale设置是否正确保存和检索
14. 确保语言参数正确传递和处理
15. 检查Locale过滤器是否正确配置和映射
16. 验证会话中的Locale设置是否正确保存和检索
资源文件加载失败
• 确保资源文件位于正确的位置(WEB-INF/classes或src/main/resources)
• 检查文件名是否正确(区分大小写)
• 验证资源文件的内容格式是否正确
中文或其他非ASCII字符显示为乱码
• 确保所有文件使用UTF-8编码保存
• 检查web.xml中是否配置了字符编码过滤器
• 验证数据库连接和表是否使用UTF-8编码
日期/时间/数字格式不正确
• 确保正确设置了Locale
• 检查是否使用了适当的格式样式(full, long, medium, short)
• 考虑使用自定义格式模式
动态语言切换不生效
• 确保语言参数正确传递和处理
• 检查Locale过滤器是否正确配置和映射
• 验证会话中的Locale设置是否正确保存和检索
实际案例分析
让我们通过一个完整的示例,展示如何实现一个支持多语言的JSP网站。这个案例将包括用户登录、内容展示和语言切换等功能。
项目结构
- src/
- └── main/
- ├── java/
- │ └── com/
- │ └── example/
- │ ├── filter/
- │ │ └── LocaleFilter.java
- │ ├── servlet/
- │ │ ├── LoginServlet.java
- │ │ └── LogoutServlet.java
- │ └── util/
- │ └── I18nUtil.java
- ├── resources/
- │ ├── messages_en_US.properties
- │ ├── messages_zh_CN.properties
- │ └── messages_ja_JP.properties
- └── webapp/
- ├── WEB-INF/
- │ └── web.xml
- ├── css/
- │ └── style.css
- ├── fragments/
- │ ├── header.jspf
- │ └── footer.jspf
- ├── index.jsp
- ├── login.jsp
- ├── welcome.jsp
- └── error.jsp
复制代码
资源文件
messages_en_US.properties
- greeting=Hello
- welcome=Welcome to our website
- home=Home
- login=Login
- logout=Logout
- username=Username
- password=Password
- submit=Submit
- language=Language
- intro.text=This is a multilingual website example. You can switch between different languages using the language selector.
- login.success=Login successful!
- login.error=Invalid username or password
- welcome.user=Welcome, {0}!
- current.date=Current date and time
复制代码
messages_zh_CN.properties
- greeting=你好
- welcome=欢迎访问我们的网站
- home=首页
- login=登录
- logout=退出
- username=用户名
- password=密码
- submit=提交
- language=语言
- intro.text=这是一个多语言网站示例。您可以使用语言选择器在不同语言之间切换。
- login.success=登录成功!
- login.error=用户名或密码无效
- welcome.user=欢迎,{0}!
- current.date=当前日期和时间
复制代码
messages_ja_JP.properties
- greeting=こんにちは
- welcome=私たちのウェブサイトへようこそ
- home=ホーム
- login=ログイン
- logout=ログアウト
- username=ユーザー名
- password=パスワード
- submit=送信
- language=言語
- intro.text=これは多言語ウェブサイトの例です。言語セレクタを使用して、異なる言語を切り替えることができます。
- login.success=ログインに成功しました!
- login.error=無効なユーザー名またはパスワード
- welcome.user=ようこそ、{0}さん!
- current.date=現在の日付と時刻
复制代码
过滤器和工具类
LocaleFilter.java
- package com.example.filter;
- import javax.servlet.*;
- import javax.servlet.annotation.WebFilter;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- import java.util.Locale;
- @WebFilter("/*")
- public class LocaleFilter implements Filter {
- private static final String DEFAULT_LOCALE = "en_US";
- private static final String LOCALE_SESSION_ATTRIBUTE = "userLocale";
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException {
- HttpServletRequest httpRequest = (HttpServletRequest) request;
- HttpSession session = httpRequest.getSession();
-
- // 检查请求参数中是否包含语言设置
- String langParam = httpRequest.getParameter("lang");
- if (langParam != null && !langParam.isEmpty()) {
- // 用户选择了新语言,更新会话中的语言设置
- session.setAttribute(LOCALE_SESSION_ATTRIBUTE, langParam);
- }
-
- // 获取当前语言环境
- String userLocale = (String) session.getAttribute(LOCALE_SESSION_ATTRIBUTE);
- if (userLocale == null) {
- userLocale = DEFAULT_LOCALE;
- }
-
- // 设置请求的语言环境
- String[] localeParts = userLocale.split("_");
- if (localeParts.length == 2) {
- request.setAttribute("userLocale", new Locale(localeParts[0], localeParts[1]));
- }
-
- chain.doFilter(request, response);
- }
- @Override
- public void destroy() {
- }
- }
复制代码
I18nUtil.java
- package com.example.util;
- import java.util.Locale;
- import java.util.ResourceBundle;
- public class I18nUtil {
-
- private static final String BASE_NAME = "messages";
-
- public static String getMessage(String key, Locale locale) {
- try {
- ResourceBundle bundle = ResourceBundle.getBundle(BASE_NAME, locale);
- return bundle.getString(key);
- } catch (Exception e) {
- return "???" + key + "???";
- }
- }
-
- public static String getMessage(String key, Locale locale, Object... params) {
- try {
- ResourceBundle bundle = ResourceBundle.getBundle(BASE_NAME, locale);
- String pattern = bundle.getString(key);
- return java.text.MessageFormat.format(pattern, params);
- } catch (Exception e) {
- return "???" + key + "???";
- }
- }
- }
复制代码
Servlet类
LoginServlet.java
- package com.example.servlet;
- import com.example.util.I18nUtil;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- import java.util.Locale;
- @WebServlet("/login")
- public class LoginServlet extends HttpServlet {
-
- @Override
- protected void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- String username = request.getParameter("username");
- String password = request.getParameter("password");
-
- // 简单的验证逻辑(实际应用中应该使用数据库验证)
- if ("admin".equals(username) && "password".equals(password)) {
- // 登录成功
- HttpSession session = request.getSession();
- session.setAttribute("user", username);
-
- // 获取当前Locale
- Locale locale = (Locale) request.getAttribute("userLocale");
- if (locale == null) {
- locale = request.getLocale();
- }
-
- // 设置成功消息
- String successMessage = I18nUtil.getMessage("login.success", locale);
- request.setAttribute("message", successMessage);
-
- // 重定向到欢迎页面
- response.sendRedirect("welcome.jsp");
- } else {
- // 登录失败
- Locale locale = (Locale) request.getAttribute("userLocale");
- if (locale == null) {
- locale = request.getLocale();
- }
-
- String errorMessage = I18nUtil.getMessage("login.error", locale);
- request.setAttribute("error", errorMessage);
-
- // 返回登录页面
- request.getRequestDispatcher("login.jsp").forward(request, response);
- }
- }
- }
复制代码
LogoutServlet.java
- package com.example.servlet;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.WebServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import java.io.IOException;
- @WebServlet("/logout")
- public class LogoutServlet extends HttpServlet {
-
- @Override
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- HttpSession session = request.getSession();
- session.invalidate();
-
- response.sendRedirect("index.jsp");
- }
- }
复制代码
JSP页面
fragments/header.jspf
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <c:if test="${not empty userLocale}">
- <fmt:setLocale value="${userLocale}" scope="session" />
- </c:if>
- <fmt:setBundle basename="messages" scope="session" />
复制代码
fragments/footer.jspf
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <div class="footer">
- <p>© 2023 Multilingual Website. All rights reserved.</p>
-
- <div class="language-selector">
- <fmt:message key="language"/>:
- <a href="?lang=en_US">English</a> |
- <a href="?lang=zh_CN">中文</a> |
- <a href="?lang=ja_JP">日本語</a>
- </div>
- </div>
复制代码
index.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="greeting"/></title>
- <link rel="stylesheet" type="text/css" href="css/style.css">
- </head>
- <body>
- <%@ include file="fragments/header.jspf" %>
-
- <div class="container">
- <h1><fmt:message key="welcome"/></h1>
-
- <p><fmt:message key="intro.text"/></p>
-
- <c:if test="${empty sessionScope.user}">
- <div class="login-link">
- <a href="login.jsp"><fmt:message key="login"/></a>
- </div>
- </c:if>
-
- <c:if test="${not empty sessionScope.user}">
- <div class="user-info">
- <p><fmt:message key="welcome.user">
- <fmt:param value="${sessionScope.user}"/>
- </fmt:message></p>
- <a href="logout"><fmt:message key="logout"/></a>
- </div>
- </c:if>
- </div>
-
- <%@ include file="fragments/footer.jspf" %>
- </body>
- </html>
复制代码
login.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="login"/></title>
- <link rel="stylesheet" type="text/css" href="css/style.css">
- </head>
- <body>
- <%@ include file="fragments/header.jspf" %>
-
- <div class="container">
- <h1><fmt:message key="login"/></h1>
-
- <c:if test="${not empty error}">
- <div class="error-message">
- <c:out value="${error}"/>
- </div>
- </c:if>
-
- <form action="login" method="post">
- <div class="form-group">
- <label for="username"><fmt:message key="username"/>:</label>
- <input type="text" id="username" name="username" required>
- </div>
-
- <div class="form-group">
- <label for="password"><fmt:message key="password"/>:</label>
- <input type="password" id="password" name="password" required>
- </div>
-
- <div class="form-group">
- <button type="submit"><fmt:message key="submit"/></button>
- </div>
- </form>
-
- <div class="back-link">
- <a href="index.jsp"><fmt:message key="home"/></a>
- </div>
- </div>
-
- <%@ include file="fragments/footer.jspf" %>
- </body>
- </html>
复制代码
welcome.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
- <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title><fmt:message key="welcome"/></title>
- <link rel="stylesheet" type="text/css" href="css/style.css">
- </head>
- <body>
- <%@ include file="fragments/header.jspf" %>
-
- <div class="container">
- <h1><fmt:message key="welcome.user">
- <fmt:param value="${sessionScope.user}"/>
- </fmt:message></h1>
-
- <p><fmt:message key="current.date"/>:
- <fmt:formatDate value="${now}" type="both" dateStyle="full" timeStyle="medium"/></p>
-
- <div class="actions">
- <a href="index.jsp"><fmt:message key="home"/></a> |
- <a href="logout"><fmt:message key="logout"/></a>
- </div>
- </div>
-
- <%@ include file="fragments/footer.jspf" %>
- </body>
- </html>
复制代码
css/style.css
- body {
- font-family: Arial, sans-serif;
- margin: 0;
- padding: 0;
- background-color: #f5f5f5;
- }
- .container {
- max-width: 800px;
- margin: 0 auto;
- padding: 20px;
- background-color: #fff;
- border-radius: 5px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
- }
- h1 {
- color: #333;
- border-bottom: 2px solid #eee;
- padding-bottom: 10px;
- }
- .form-group {
- margin-bottom: 15px;
- }
- .form-group label {
- display: block;
- margin-bottom: 5px;
- font-weight: bold;
- }
- .form-group input {
- width: 100%;
- padding: 8px;
- border: 1px solid #ddd;
- border-radius: 4px;
- box-sizing: border-box;
- }
- button {
- background-color: #4CAF50;
- color: white;
- padding: 10px 15px;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- }
- button:hover {
- background-color: #45a049;
- }
- .error-message {
- color: #D8000C;
- background-color: #FFD2D2;
- padding: 10px;
- margin-bottom: 20px;
- border-radius: 4px;
- }
- .footer {
- margin-top: 20px;
- padding-top: 20px;
- border-top: 1px solid #eee;
- text-align: center;
- color: #777;
- }
- .language-selector {
- margin-top: 10px;
- }
- .language-selector a {
- margin: 0 5px;
- text-decoration: none;
- color: #4CAF50;
- }
- .language-selector a:hover {
- text-decoration: underline;
- }
- .login-link, .back-link, .actions {
- margin-top: 20px;
- }
- .login-link a, .back-link a, .actions a {
- color: #4CAF50;
- text-decoration: none;
- }
- .login-link a:hover, .back-link a:hover, .actions a:hover {
- text-decoration: underline;
- }
复制代码
web.xml配置
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
- http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
- version="4.0">
-
- <!-- 配置字符编码过滤器 -->
- <filter>
- <filter-name>CharacterEncodingFilter</filter-name>
- <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
-
- <filter-mapping>
- <filter-name>CharacterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
-
- <!-- 配置默认语言环境 -->
- <context-param>
- <param-name>javax.servlet.jsp.jstl.fmt.locale</param-name>
- <param-value>en_US</param-value>
- </context-param>
-
- <!-- 配置资源包的基础名称 -->
- <context-param>
- <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
- <param-value>messages</param-value>
- </context-param>
-
- <!-- 欢迎页面配置 -->
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
复制代码
这个完整的示例展示了一个支持多语言的JSP网站的基本结构和实现方式。用户可以通过语言选择器切换不同的语言,网站会根据用户的选择显示相应语言的内容。同时,示例还包括了用户登录功能,展示了如何在Servlet中处理国际化消息。
总结
JSP国际化是构建多语言网站的关键技术,它允许开发者创建能够适应不同语言和地区的应用程序。通过本文的介绍,我们了解了JSP国际化的基本原理、核心技术、实现步骤以及高级主题。
主要要点包括:
1. 资源文件管理:将所有文本内容提取到属性文件中,按语言环境组织。
2. Locale处理:使用Locale类表示特定的语言环境,并通过过滤器或会话管理用户的语言偏好。
3. JSTL fmt标签:利用JSTL的fmt标签库简化JSP页面中的国际化操作。
4. 动态语言切换:实现允许用户在运行时切换语言的功能。
5. 高级格式处理:处理日期、时间、数字和货币的地区特定格式。
6. 文本方向支持:考虑从右到左语言的特殊需求。
7. 最佳实践:遵循编码标准、避免硬编码文本、提供完整翻译等。
资源文件管理:将所有文本内容提取到属性文件中,按语言环境组织。
Locale处理:使用Locale类表示特定的语言环境,并通过过滤器或会话管理用户的语言偏好。
JSTL fmt标签:利用JSTL的fmt标签库简化JSP页面中的国际化操作。
动态语言切换:实现允许用户在运行时切换语言的功能。
高级格式处理:处理日期、时间、数字和货币的地区特定格式。
文本方向支持:考虑从右到左语言的特殊需求。
最佳实践:遵循编码标准、避免硬编码文本、提供完整翻译等。
通过遵循这些原则和技术,您可以构建出真正国际化、用户体验良好的多语言网站。随着全球化的发展,国际化已成为现代Web应用开发的重要技能,希望本文能帮助您更好地理解和实现JSP国际化。 |
|