Java国际化工具实现

                                                                              Java国际化工具详解,国际化工具实现


本工具具有很强的实用性,可以拷贝代码直接使用

1.MessageFormatter

这是一个字符串格式化工具,主要完成两个功能

1.对于字符串“ hello {0}, {1}“在转换过程中会将{0}替换为所传参数数组下标为0的参数值,{1}则替换为下标为1的参数值。好处是支持任意的下标值,而jdk自带的MessageFormatter下标值只能是0-9

调用方式MessageFormatter.formatter(str, params);

2.将字符串中${xx},替换为一个外部的值,比如默认的MessageFormatter遇到${xx}后会试图通过System.getProperty(xx)获取值,然后将${xx}替换为获取之后的值,外部值获取主要通过PropertySource来取,构造器可以传入PropertySource的实现类。

看代码:

/**
 * 
 * @author zhaoming
 *
 */
public class MessageFormatter {
	
	private PropertySource source;
	
	private static final char DELIM_START = '{';
	
	private static final char DELIM_START_LEN = 1;
	
	private static final char DELIM_END = '}';
	
	private static final char DELIM_END_LEN = 1;
	
    private static final char ESCAPE_CHAR = '\\';
    
    private static final char REF_CHAR = '$';
    
    public MessageFormatter(PropertySource source) {
    	if (source == null) {
    		source = new SystemPropertySource();
    	} else {
    		this.source = source;
    	}
	}
    
	public MessageFormatter() {
		source = new SystemPropertySource();
	}
	
	public String format(String pattern) {
		return this.format(pattern, null);
	}
	
	public String format(String pattern, Object[] args) {
		return this.format(pattern, args, 0);
	}

	private String format(String pattern, Object[] args, int argIdx) {
    	try {
			if (pattern == null) {
				return pattern;
			}
			if (args == null) {
				args = new Object[0];
			}
			StringBuilder sb = new StringBuilder(pattern.length() + 20);
			int start = 0;
			int sidx = -1;
			int eidx = -1;
			String argStr = "";
			while (start < pattern.length() && (sidx = pattern.indexOf(DELIM_START, start)) >= 0) {
				if (hasEscapeChar(pattern, sidx)) {
					if (hasDoubleEscapeChar(pattern, sidx)) {
						sb.append(pattern, start, sidx - 1);
					} else {
						sb.append(pattern, start, sidx - 1).append(DELIM_START);
						start = sidx + DELIM_START_LEN;
						continue;
					}
				} else {
					sb.append(pattern, start, sidx);
				}
				eidx = pattern.indexOf(DELIM_END, sidx);
				if (eidx == -1) {
					sb.append(pattern, sidx, pattern.length());
					start = pattern.length();
				} else {
					argStr = pattern.substring(sidx + DELIM_START_LEN, eidx).trim();
					if (argStr.isEmpty() || isNumeric(argStr)) {
						appendIndexParam(sb, getArgInt(argStr, argIdx++), args, argStr);
					} else {
						appendRefParam(sb, argIdx, args, argStr);
					}
					start = eidx + DELIM_END_LEN;
				}
				
			}
			if (start < pattern.length()) {
				sb.append(pattern, start, pattern.length());
			}
			return sb.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return pattern;
    }
    
	private boolean isNumeric(String s) {
		int len = s.length();
		for (int i = 0; i < len; i++) {
			if (!Character.isDigit(s.charAt(i))) {
				return false;
			}
		}
		return true;
	}
	
    private int getArgInt(String param, int v) {
    	try {
    		if ("".equals(param)) {
    			return v;
    		}
			return Integer.parseInt(param);
		} catch (NumberFormatException e) {
		}
    	return -1;
    }
    
    private void appendRefParam(StringBuilder sb, int argIdx, Object[] args, String orgParam) {
    	int len = sb.length();
    	boolean isRef = true;
    	if (len == 0 || sb.charAt(len - 1) != REF_CHAR) {
    		isRef = false;
    	}
    	if (hasEscapeChar(sb, len - 1) && !hasDoubleEscapeChar(sb, len - 1)) {
    		isRef = false;
    	}
    	if (isRef) {
    		String v = source.getProperty(orgParam);
    		if (v != null) {
    			sb.setLength(len - 1);
    			sb.append(this.format(v, args, argIdx));
    			return;
    		}
    	}
    	sb.append(DELIM_START).append(orgParam).append(DELIM_END);
    }
    
    private void appendIndexParam(StringBuilder sb, int argIdx, Object[] args, String orgParam) {
    	if (argIdx < 0 || argIdx >= args.length) {
    		sb.append(DELIM_START).append(orgParam).append(DELIM_END);
    	} else {
    		deeplyAppendParam(sb, args[argIdx], new HashMap<Object[], Object>());
    	}
    }
    
    private void deeplyAppendParam (StringBuilder sb, Object o, Map<Object[], Object> seenMap) {
    	if (o == null) {
            sb.append("null");
            return;
        }
        if (!o.getClass().isArray()) {
        	appendToString(sb, o);
        } else {
        	if (o.getClass() == Object[].class) {
        		objectArrayAppend(sb,  (Object[]) o, seenMap);
        	} else {
        		int len = Array.getLength(o);
        		sb.append("[");
        		for (int i = 0; i < len; i++) {
        			appendToString(sb, Array.get(o, i));
        			if (i != len - 1) {
        				sb.append(", ");
        			}
        		}
        		sb.append(']');
        	}
        }
    }
    
    private void objectArrayAppend(StringBuilder sb, Object[] a, Map<Object[], Object> seenMap) {
    	sb.append('[');
        if (!seenMap.containsKey(a)) {
            seenMap.put(a, null);
            final int len = a.length;
            for (int i = 0; i < len; i++) {
            	deeplyAppendParam(sb, a[i], seenMap);
                if (i != len - 1)
                    sb.append(", ");
            }
            seenMap.remove(a);
        } else {
            sb.append("...");
        }
        sb.append(']');
    }
    
    private void appendToString(StringBuilder sb, Object o) {
    	try {
			if(o == null) {
				sb.append("null");
			} else {
				sb.append(o.toString());
			}
		} catch (Exception e) {
			sb.append("[failed toString]");
		}
    }
    
    private boolean hasEscapeChar(StringBuilder pattern, int idx) {
    	if (idx > 0 && pattern.charAt(idx - 1) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    private boolean hasEscapeChar(String pattern, int idx) {
    	if (idx > 0 && pattern.charAt(idx - 1) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    private boolean hasDoubleEscapeChar(StringBuilder pattern, int idx) {
    	if (idx >= 2 && pattern.charAt(idx - 2) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    private boolean hasDoubleEscapeChar(String pattern, int idx) {
    	if (idx >= 2 && pattern.charAt(idx - 2) == ESCAPE_CHAR) {
    		return true;
    	}
    	return false;
    }
    
    class SystemPropertySource implements PropertySource {

		@Override
		public String getProperty(String key) {
			try {
				return System.getProperty(key);
			} catch (Exception e) {
			}
			return null;
		}
    	
    }
}

PropertySource接口声明:

public interface PropertySource {
	
	public String getProperty(String key);
	
}

2.ResourceBundleManager国际化字符串查找工具类:

/**
 * 
 * @author zhaoming
 *
 */
public class ResourceBundleManager {
	
	private Locale locale;
	
	private ResourceBundle bundler;
	
	private MessageFormatter mf = new MessageFormatter(new BundlePropertySource());
	
	private static Map<String, Map<Locale, ResourceBundleManager>> mgts = Collections
			.synchronizedMap(new HashMap<String, Map<Locale, ResourceBundleManager>>());
	
	
	
	private ResourceBundleManager(String baseName, Locale locale) {
		ResourceBundle bd = null;
		try {
			bd = ResourceBundle.getBundle(baseName, locale);
		} catch (Exception e) {
			LogUtil.getLogger().error(e.getMessage(), e);
			try {
				bd = ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader());
			} catch (Exception e1) {
			}
		}
		bundler = bd;
		if (bundler != null) {
			this.locale = bundler.getLocale();
			if (Locale.ROOT.equals(this.locale)) {
				locale = Locale.ENGLISH;
			}
		}
	}
	
	public static ResourceBundleManager getManager(String baseName, Locale locale) {
		Map<Locale, ResourceBundleManager> map = mgts.get(baseName);
		if (map == null) {
			map = new HashMap<Locale, ResourceBundleManager>();
			mgts.put(baseName, map);
		}
		ResourceBundleManager mgt = map.get(locale);
		if (mgt == null) {
			mgt = new ResourceBundleManager(baseName, locale);
			map.put(locale, mgt);
		}
		return mgt;
	}
	
	private String getValue(String key) {
		try {
			if (key != null) {
				if (bundler != null) {
					return bundler.getString(key);
				}
			}
		} catch (Exception e) {
		}
		return null;
	}
	
	public String getString(String key) {
		String v = getValue(key);
		if (v != null) {
			return mf.format(v);
		}
		return key;
	}
	
	public String getString(String key, String defaultV) {
		String v = getValue(key);
		if (v != null) {
			return mf.format(v);
		}
		return defaultV;
	}
	
	public String getString(String key, Object... params) {
		try {
			String v = getValue(key);
			if (v != null) {
				return mf.format(v, params);
			}
		} catch (Exception e) {
		}
		return key;
	}
	
	public String getString(String key, String defaultV, Object... params) {
		try {
			String v = getValue(key);
			if (v != null) {
				return mf.format(v, params);
			} else {
				return defaultV;
			}
		} catch (Exception e) {
		}
		return key;
	}
	
	class BundlePropertySource implements PropertySource {

		@Override
		public String getProperty(String key) {
			try {
				return getValue(key);
			} catch (Exception e) {
			}
			return null;
		}
    }
}

直接使用ResourceBundleManager比较不方便,因为首先必须先调用ResourceBundleManager.getManager(baseName, locale),并传入资源文件基名称和Locale对象才能调用getString(String key)去获取相应资源文件的key的值。实际项目中我们一般会有一个默认的资源文件基名称,同时Locale对象一般也是通过浏览器访问,后端服务器自动为我们创建。因此引入最终的一个工具类,支持默认资源名称,和传递线程上下文的Locale对象。

3.I18nManager:

/**
 * 
 * @author zhaoming
 *
 */
public class I18nManager {
	//这里是默认的资源文件名称,可以配死也可以读取配置文件动态获取
	private final static String DEFAULT_BASE_NAME = "com.test.myresource"; 
	
	private static ThreadLocal<Locale> local = new ThreadLocal<Locale>();
	
	public static String getString(String key) {
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, getLocale());
		return mgt.getString(key);
	}
	
	public static String getString(String key, String defaultV) {
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, getLocale());
		return mgt.getString(key, defaultV);
	}
	
	public static String getString(String key, Object... params) {
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, getLocale());
		return mgt.getString(key, params);
	}
	
	public static String getString(String key, String defaultV, Object... params) {
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, getLocale());
		return mgt.getString(key, defaultV, params);
	}
	
	public static String getString(Locale locale, String key) {
		if (locale == null) {
			locale = getLocale();
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, locale);
		return mgt.getString(key);
	}
	
	public static String getString(Locale locale, String key, String defaultV) {
		if (locale == null) {
			locale = getLocale();
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, locale);
		return mgt.getString(key, defaultV);
	}
	
	public static String getString(Locale locale, String key, Object... params) {
		if (locale == null) {
			locale = getLocale();
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, locale);
		return mgt.getString(key, params);
	}
	
	public static String getString(Locale locale, String key, String defaultV, Object... params) {
		if (locale == null) {
			locale = getLocale();
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(DEFAULT_BASE_NAME, locale);
		return mgt.getString(key, defaultV, params);
	}
	
	public static String getStringBy(String baseName, String key) {
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, getLocale());
		return mgt.getString(key);
	}
	
	public static String getStringBy(String baseName, String key, String defaultV) {
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, getLocale());
		return mgt.getString(key, defaultV);
	}
	
	public static String getStringBy(String baseName, String key, Object... params) {
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, getLocale());
		return mgt.getString(key, params);
	}
	
	public static String getStringBy(String baseName, String key, String defaultV, Object... params) {
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, getLocale());
		return mgt.getString(key, defaultV, params);
	}

	public static String getStringBy(Locale locale, String baseName, String key) {
		if (locale == null) {
			locale = getLocale();
		}
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, locale);
		return mgt.getString(key);
	}
	
	public static String getStringBy(Locale locale, String baseName, String key, String defaultV) {
		if (locale == null) {
			locale = getLocale();
		}
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, locale);
		return mgt.getString(key, defaultV);
	}
	
	public static String getStringBy(Locale locale, String baseName, String key, Object... params) {
		if (locale == null) {
			locale = getLocale();
		}
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, locale);
		return mgt.getString(key, params);
	}
	
	public static String getStringBy(Locale locale, String baseName, String key, String defaultV, Object... params) {
		if (locale == null) {
			locale = getLocale();
		}
		if (baseName == null) {
			baseName = DEFAULT_BASE_NAME;
		}
		ResourceBundleManager mgt = ResourceBundleManager.getManager(baseName, locale);
		return mgt.getString(key, defaultV, params);
	}
	public static void setThreadLocale(Locale locale) {
		if (locale != null) {
			local.set(locale);
		}
	}

	private static Locale getLocale() {
		Locale l = local.get();
		if (l != null) {
			return l;
		}
		return Locale.getDefault();
	}
}

4.使用:

以structs为例,在action构造器中使用如下代码设置线程上下文的Locale对象
I18nManager.setThreadLocale(this.getLocale());
String s = I18nManager.getString("a", "Tom", "Cat");//结果: hello Jerry my name is Tom Cat

资源文件内容:

a=hello ${b} my name is {0} {1}

b=Jerry

猜你喜欢

转载自blog.csdn.net/zhaomin_g/article/details/81538595