/** * Copyright (c) 2011-2012, James Zhan 詹波 (jfinal@126.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jfinal.i18n; import java.util.Enumeration; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import com.jfinal.core.Const; /** * I18N support. * * 1: Config parameters in JFinalConfig * 2: Init I18N in JFinal * 3: I18N support text with Locale * 4: ActionContext use I18N.getText(...) with Local setting in I18nInterceptor * 5: The resource file in WEB-INF/classes * * important: Locale can create with language like new Locale("xxx"); * * need test * Using String get Locale was learned from Strus2 */ public class I18N { private static String baseName; private static Locale defaultLocale = Locale.getDefault(); private static int i18nMaxAgeOfCookie = Const.DEFAULT_I18N_MAX_AGE_OF_COOKIE; private static final NullResourceBundle NULL_RESOURCE_BUNDLE = new NullResourceBundle(); private static final ConcurrentMap<String, ResourceBundle> bundlesMap = new ConcurrentHashMap<String, ResourceBundle>(); private static volatile I18N me; private I18N() { } public static I18N me() { if (me == null) synchronized (I18N.class) { if (me == null) me = new I18N(); } return me; } public static void init(String baseName, Locale defaultLocale, Integer i18nMaxAgeOfCookie) { I18N.baseName = baseName; if (defaultLocale != null) I18N.defaultLocale = defaultLocale; if (i18nMaxAgeOfCookie != null) I18N.i18nMaxAgeOfCookie = i18nMaxAgeOfCookie; } public static Locale getDefaultLocale() { return defaultLocale; } final static public int getI18nMaxAgeOfCookie() { return i18nMaxAgeOfCookie; } private static ResourceBundle getResourceBundle(Locale locale) { String resourceBundleKey = getresourceBundleKey(locale); ResourceBundle resourceBundle = bundlesMap.get(resourceBundleKey); if (resourceBundle == null) { try { resourceBundle = ResourceBundle.getBundle(baseName, locale); bundlesMap.put(resourceBundleKey, resourceBundle); } catch (MissingResourceException e) { resourceBundle = NULL_RESOURCE_BUNDLE; } } return resourceBundle; } /** * 将来只改这里就可以了: resourceBundleKey的生成规则 */ private static String getresourceBundleKey(Locale locale) { // return baseName + "_" + locale.toString(); // "_" 貌似与无关, 为了提升性能, 故去掉 return baseName + locale.toString(); } public static String getText(String key) { return getResourceBundle(defaultLocale).getString(key); } public static String getText(String key, String defaultValue) { String result = getResourceBundle(defaultLocale).getString(key); return result != null ? result : defaultValue; } public static String getText(String key, Locale locale) { return getResourceBundle(locale).getString(key); } public static String getText(String key, String defaultValue, Locale locale) { String result = getResourceBundle(locale).getString(key); return result != null ? result : defaultValue; } // public static Locale localeFromString(String localeStr, Locale defaultLocale) { public static Locale localeFromString(String localeStr) { if ((localeStr == null) || (localeStr.trim().length() == 0) || ("_".equals(localeStr))) { // return (defaultLocale != null) ? defaultLocale : Locale.getDefault(); // 原实现被注掉 return defaultLocale; } int index = localeStr.indexOf('_'); if (index < 0) { return new Locale(localeStr); } String language = localeStr.substring(0, index); if (index == localeStr.length()) { return new Locale(language); } localeStr = localeStr.substring(index + 1); index = localeStr.indexOf('_'); if (index < 0) { return new Locale(language, localeStr); } String country = localeStr.substring(0, index); if (index == localeStr.length()) { return new Locale(language, country); } localeStr = localeStr.substring(index + 1); return new Locale(language, country, localeStr); } private static class NullResourceBundle extends ResourceBundle { public Enumeration<String> getKeys() { return null; // dummy } protected Object handleGetObject(String key) { return null; // dummy } } // 可惜的是使用Local可以被 new 出来, 造成了无法判断相等,后来测试,可以使用 equals方法来判断是否相等 public static void main(String[] args) { // Locale.getDefault(); // Locale en = Locale.US; // Locale us = Locale.US; // System.out.println(l.toString()); // System.out.println(en == us); // System.out.println(en.equals(us)); // 下面的 taiwan.getLanguage()值仍为 zh,所以可以确定i18n实现有缺陷,即 language不能唯一确定Local对象 // 造成了无法通过 language不好还原 System.out.println(Locale.CHINESE.getLanguage()); System.out.println(Locale.CHINA.getLanguage()); System.out.println(Locale.SIMPLIFIED_CHINESE.getLanguage()); System.out.println(Locale.TRADITIONAL_CHINESE.getLanguage()); System.out.println(Locale.TAIWAN.getLanguage()); Locale shoudong = new Locale("en"); System.out.println(shoudong.getLanguage().equals(Locale.US.getLanguage())); System.out.println(shoudong.getLanguage().equals(Locale.ENGLISH.getLanguage())); System.out.println(shoudong.getLanguage().equals(Locale.CANADA.getLanguage())); System.out.println(shoudong.getLanguage().equals(Locale.UK.getLanguage())); System.out.println(shoudong.getLanguage().equals(Locale.CANADA_FRENCH.getLanguage())); } }