Java程序国际化的关键类是ResourceBundle和Locale,ResourceBundle根据不同的Locale加载语言资源文件,在根据指定的key取得语言资源文件中的字符串。
从资源文件中取出的字符串可能包含占位符,可以使用MessageFormat来处理包含占位符的字符串。综上可知,Java程序的国际化主要通过三个类完成:
1)java.util.ResourceBundle: 用来加载国家、语言资源包;
2)java.util.Locale: 用于封装特定的国家/区域、语言环境;
3)java.util.MessageFormat: 用于格式化带占位符的字符串。
下面简单演示如何在Java web程序中集成国际化功能,最后简单总结了ResourceBundle、Locale、MessageFormat这三个类的使用。
1、将resourceBundle放进request域中
public class LoginInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.setAttribute("resourceBundle", Utils.getResourceBundle(request));
}
}
Utils类:
package com.oy;
import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.springframework.web.method.HandlerMethod; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.JSONObject; import com.mysql.jdbc.StringUtils; import amberai.jweb.utils.Config; import amberai.jweb.utils.RedisAccess; import amberai.jweb.utils.UtilFunctions; import redis.clients.jedis.Jedis; public class Utils { public static String getLanguage(HttpServletRequest request) { String language = ""; if (request == null) return language; // priority: url?l=en-us > Cookie:language=zh-cn language = request.getParameter("l"); if (language == null || Config.LANGUAGECONFIG.get(language.toLowerCase()) == null) { language = Utils.getLanguageByCookie(request); } if (language == null || Config.LANGUAGECONFIG.get(language.toLowerCase()) == null) { language = "en-us"; // default "en-us" } return language; } public static String getLanguageByCookie(HttpServletRequest request) { String language = ""; if (request == null) return language; Cookie[] cookies = request.getCookies(); if (cookies == null || cookies.length == 0) { return language; } for (Cookie cookie : cookies) { if ("language".equalsIgnoreCase(cookie.getName())) { language = cookie.getValue(); } } return language; } public static ResourceBundle getResourceBundle(HttpServletRequest request) { String language = Utils.getLanguage(request); String[] languages = language.split("-"); Locale locale = null; if (languages.length >= 2) { locale = new Locale(language.split("-")[0], language.split("-")[1]); } else if (languages.length == 1) { locale = new Locale(language.split("-")[0], "ES"); } return ResourceBundle.getBundle("i18n/MessgesBundle", locale); } }
Config类
public static final Map<String, String> LANGUAGECONFIG = new HashMap<String, String>() { private static final long serialVersionUID = 1L; { put("en-us", "en-US"); put("zh-cn", "zh-CN"); put("es", "es-ES"); put("pt-br", "pt-BR"); } };
2、使用resourceBundle
@IsLogin @RequestMapping(value = "/userlevel", method = RequestMethod.GET) @ResponseBody public JSONObject getUserLevelByUserid(HttpServletRequest request) { Integer uid = (Integer) request.getAttribute("uid"); ResourceBundle resourceBundle = (ResourceBundle) request.getAttribute("resourceBundle"); UserLevel userLevel = userLevelService.getUserLevelByUserid(uid); if (userLevel == null) { String message = UtilFunctions.getMessage(resourceBundle, "USER_LEVEL_NULL"); return new Response(ErrCode.PARAM_INVALID, message).toJson(); } JSONObject response = new JSONObject(); response.put("code", 0); response.put("data", userLevel); return response; }
UtilFunctions.getMessage():资源文件为UTF-8的编码处理
public static String getMessage(ResourceBundle resourceBundle, String key, Object... args) { String msg = ""; if (resourceBundle == null || key == null || key.isEmpty()) return msg; if (args == null || args.length == 0) { msg = resourceBundle.getString(key); try { msg = new String(msg.getBytes("ISO-8859-1"), "UTF-8"); return msg; } catch (UnsupportedEncodingException e) { UtilFunctions.log.error("UtilFunctions getMessage error, msg:{}, exception:{}", e.toString(), e); UtilFunctions.reportError("UtilFunctions getMessage: " + e.toString(), e); return msg; } } msg = MessageFormat.format(resourceBundle.getString(key), args); try { msg = new String(msg.getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { UtilFunctions.log.error("UtilFunctions getMessage error, msg:{}, exception:{}", e.toString(), e); UtilFunctions.reportError("UtilFunctions getMessage: " + e.toString(), e); return msg; } return msg; }
3、资源文件
MessagesBundle_en_US.properties
#Common PARAM_MISS=param: {0} is empty PARAM_INVALID=param: {0} is invalid PARAM_INCORRECT=param: {0} is incorrect PARAM_FORMAT_INCORRECT=param: {0} format is incorrect NO_RECORDS_FOUND=No {0} found SYSTEM_BUSY=The system is busy. Please try again later! PASS_ERROR=Password error PAY_PASS_ERROR=Transaction password error #UserController REPAY_PASS_ERROR=Confirm password error PASS_FORMAT_ERROR=Password format error #OLD_PASS_FORMAT_ERROR=Old password format error NEW_PASS_FORMAT_ERROR=New password format error OLD_PASS_ERROR=Old password error NEW_OLD_PASS_SAME=New password can not be the same as the old one PAY_LOGIN_PASS_SAME=Transaction password can not be the same as login password LOGIN_PAY_PASS_SAME=Login password can not be the same as transaction password NO_SUCH_USER=No such user: {0} ACCOUNT_FROZEN=The account has been frozen: {0} INVITATION_CODE_ERROR=Invitation code is invalid USER_LEVEL_NULL=User level is empty #TradeController PLACE_ORDER_PRICE_ERROR=Price cannot be less than {0} times the current price and more than {1} times the current price PLACE_ORDER_TRIGGER_PRICE_ERROR=Stop price cannot be less than {0} times the price and more than {1} times the price PLACE_ORDER_NUM_ERROR=Trade number can not be less than {0} PLACE_ORDER_NO_ENOUGH_COIN=No enough {0} QUERY_ORDER_NULL=Query order failed, hashId is invalid QUERY_USER_VALIDATION_ERROR=Can not query orders that are not your own CANCEL_ORDER_NULL=Cancel order failed, hashId is invalid CANCEL_USER_VALIDATION_ERROR=Cancel order failed. Can not cancel orders that are not your own CANCEL_TYPE_ERROR=Market order can not be cancelled CANCEL_STATUS_ERROR=Order with status {0} can not be cancelled
4、国际化相关API
Locale
Locale defaultLocale = Locale.getDefault(); System.out.print("country=" + defaultLocale.getCountry());// country=CN System.out.println(", language=" + defaultLocale.getLanguage());// language=zh Locale locale1 = Locale.CHINA; System.out.print("country=" + locale1.getCountry());// country=CN System.out.println(", language=" + locale1.getLanguage());// language=zh Locale locale2 = Locale.CHINESE; System.out.print("country=" + locale2.getCountry());// country= System.out.println(", language=" + locale2.getLanguage());// language=zh Locale locale3 = Locale.TRADITIONAL_CHINESE; System.out.print("country=" + locale3.getCountry());// country=TW System.out.println(", language=" + locale3.getLanguage());// language=zh Locale locale4 = Locale.SIMPLIFIED_CHINESE; System.out.print("country=" + locale4.getCountry());// country=CN System.out.println(", language=" + locale4.getLanguage());// language=zh
ResourceBundle
// 创建ResourceBundle:根据指定的国家a、语言A 加载资源文件 baseName_a_A.properties ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n/baseName", new Locale("a", "A")); // 打印从资源文件获取的值 System.out.println(resourceBundle.getString("HELLO")); resourceBundle = ResourceBundle.getBundle("i18n/baseName", new Locale("b", "B")); System.out.println(resourceBundle.getString("HELLO")); // 资源文件是UTF-8编码。这里打印结果乱码 // 处理乱码 String msg = resourceBundle.getString("HELLO"); try { msg = new String(msg.getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println(msg);
测试上面的代码之前,在src下新建文件夹i18n,然后再i8n文件夹内新建baseName_a_A.properties和baseName_b_B.properties资源文件。资源文件的编码为UTF-8。
baseName_a_A.properties添加:HELLO=hello
baseName_b_B.properties添加:HELLO=您好
MessageFormat
String pattern = "hello {0}"; String message = MessageFormat.format(pattern, "世界"); System.out.println(message); // hello 世界
参考资料
(1)https://www.cnblogs.com/jyh317/p/3608048.html
(2)https://cloud.tencent.com/developer/news/242356
(3)https://blog.csdn.net/deniro_li/article/details/80451866