jsp页面自动国际化工具+js文件自动国际化工具--懒人的解决方案

   公司的应用要求都做国际化,jsp页面中有大量的中文,需要将它们使用spring 的国际化标签实现国际化;一个一个手工去查找中文、再转换为spring国际化标签、并生成中英文的国际化资源文件,这是个重复且无聊的工作,页面少还好,如果页面多,会让人发狂,所以写了一个提取jsp页面中的中文,将它们替换为国际化标签,并生成国际化资源文件的小工具;


主要代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fanyti.ChineseToPinyin;

/**
 * 扫描jsp文件中的中文,提取出中文,生成i18n的properties文件和jsp国际化后的文件;
 * 
 * 使用方式:
 * 1. 需要国际化的文件放在JSP_SOURCE_PATH路径下,生成的国际化文件放在JSP_CREATE_PATH路径下,项目已经存在的国际化资源文件(只要中文的)放到EXIST_I18n_ZH_CN_FILE_PATH路径下
 * 2. 生成的国际化文件放在I18N_FILE_SAVE_PATH目录下,生成的国际化文件名称为PROP_NAME_ENG(英文资源文件)、PROP_NAME_GBK(中文资源文件);
 * 3. 根据上面的配置修改JSP_SOURCE_PATH、JSP_CREATE_PATH、EXIST_I18n_ZH_CN_FILE_PATH、I18N_FILE_SAVE_PATH这四个常量路径的值;
 * 4. 生成的国际化文件中,key的前缀为I18N_KEY_PREFIX变量指定;
 * 
 * 注意:需要国际化的文件只要将项目中jsp文件所在父文件夹拷贝过来即可,应用会自动遍历各级子目录下的文件,并按照同样的目录结构去生成国际化好的jsp文件
 * @author zqz
 */
public class Il8nJspTool {
	
	/**国际化文件中国际化key的前缀**/
	private static final String I18N_KEY_PREFIX = "com.newsys";
	
	/**
	 * 请先配置好以下路径
	 */
	// 要国际化的jsp文件存放路径
	private static final String JSP_SOURCE_PATH = "E:\\newsysi18n";
	// 国际化后生成的文件的存储路径
	private static final String JSP_CREATE_PATH = "E:\\newsysi18n_";
	// 已经存在的国际化文件请放在这个目录下,防止对已经国际化的中文再生成重复的国际化文件,这个目录下只存放中文国际化文件即可;
	private static final String EXIST_I18n_ZH_CN_FILE_PATH = "E:\\newsysi18n_\\i18n_source";
	
	/**
	 * 请配置要生成的国际化文件的文件名
	 */
	// 生成的国际化文件名称,生成的文件保存在当前classpath目录下,重复执行会覆盖之前的执行结果
	private static final String I18N_FILE_SAVE_PATH = "E:\\newsysi18n_\\i18n_create\\"; 
	private static final String PROP_NAME_ENG$ = "$autocreate_i18n_en.properties";
	private static final String PROP_NAME_ENG = "autocreate_i18n_en.properties";
	private static final String PROP_NAME_GBK = "autocreate_i18n_zh_CN.properties";
	// 文件编码utf-8
	private static final String ENCODING = "utf-8";
	
	public static final int BUFF_SIZE = 10240;
	
	// 配置中文
	private static final Pattern CHINESE_PATTERN = Pattern
			.compile("[\\w\\ufe30-\\uffa0\\u4e00-\\u9fa5]*([\\u4e00-\\u9fa5]+[\\P{Punct}-,]{0,1})+[ \\w\\ufe30-\\uffa0\\u4e00-\\u9fa5]*\\P{Punct}{0,1}");
	// html注释<!-- XXXX -->
	private static String regEx_html = "<!--.*?-->";
	private static Pattern p_html = Pattern.compile(regEx_html, Pattern.DOTALL);
	// jsp的注释<%-- XXXXX --%>
	private static String regEx_jsp = "<%--.*?--%>";
	private static Pattern p_jsp = Pattern.compile(regEx_jsp, Pattern.DOTALL);
	// js注释/* XXXX */
	private static String regEx_js1 = "/\\*.*?\\*/";
	private static Pattern p_js1 = Pattern.compile(regEx_js1, Pattern.DOTALL);
	// js注释 // XXXXX
	private static String regEx_js2 = "//[\\s\\S]*?\n";
	private static java.util.regex.Pattern p_js2 = Pattern.compile(regEx_js2, Pattern.CASE_INSENSITIVE);
	
	// jsp中的java代码 ${XXXX}
	private static String regEx_java = "\\$\\{.*?\\}";
	private static Pattern p_java = Pattern.compile(regEx_java, Pattern.DOTALL);
	// jsp代码<% XXXX %>
	private static String regEx_jsp2 = "<%.*?%>";
	private static Pattern p_jsp2 = Pattern.compile(regEx_jsp2, Pattern.DOTALL);
	// 已经国际化的kv
	private static Map<String, String> existMap ;

	// 不匹配的中文缓存
	private static Map<String, String> noReplace = new HashMap<String, String>();
	
	// 需要被国际化的jsp文件列表
	private static List<File> fileList = new ArrayList<File>(); 
	
	// 被匹配的中文内容 key为匹配到的中文 ,value为Il8NBean
	private static Map<String, IL8NBean> i18nMatchCache = new HashMap<String, IL8NBean>();
	
	private final static String IL8N_TAGLIB_FMT = "<%@ taglib prefix=\"fmt\" uri=\"http://java.sun.com/jsp/jstl/fmt\" %>\r\n";
	private final static String IL8N_TAGLIB_FMT_CHECK = "uri=\"http://java.sun.com/jsp/jstl/fmt\"";
	private final static String IL8N_TAGLIB_CHECK = "file=\"../include/taglibs.jsp\"%>";
	
	/**
	 * @Description: TODO
	 * @param args
	 * @throws 
	 * @author  zhuqz
	 */
	public static void main(String[] args) {
		// 初始化
		init();
		// 获取要国际化的中文,并在当前classpath下生成properties文件;
		getChinereWord(JSP_SOURCE_PATH);
		// 生成将中文替换为国际化key的jsp文件;
		replace(JSP_SOURCE_PATH, JSP_CREATE_PATH);
	}
	
	//初始化
	private static void init() {
		// 不做国际化的内容,例如html页面上css中的字体
		noReplace.put("微软雅黑", "");
		noReplace.put("宋体", "");
		// 缓存已经做过国际化的key和value;
		existMap = loadExistI18nFiles();
		// 获取需要被国际化的jsp文件列表
		fileList = getJsps(new File(JSP_SOURCE_PATH));
	}


	/**
	 * 获取到当前已经国际化的key和value
	 * @return
	 */
	private static Map<String, String> loadExistI18nFiles() {
		File baseDir = new File(EXIST_I18n_ZH_CN_FILE_PATH);
		if(!baseDir.exists()){
			return new HashMap<String,String>(0);
		}
		File[] files = baseDir.listFiles();
		Map<String,String> existI18n  = new HashMap<String,String>(3000);
		for (File file : files)
			if (file.isDirectory() && !file.isHidden())
				continue;
			else if (file.getName().toLowerCase().endsWith(".properties"))
				existI18n.putAll(loadProperties(file));
		return existI18n;
	}


	/**
	 * Map<value,key>
	 * @Description:  载入已经存在的国际化文件
	 * @param fileName
	 * @return
	 * @throws 
	 * @author zhuqz
	 */
	private static Map<String, String> loadProperties(File file) {
		Map<String, String> map = new HashMap<String, String>();
		Properties prop = new Properties();
		InputStream in = null;
		try {
			in = new FileInputStream(file);
			prop.load(new InputStreamReader(in, "UTF-8"));
			System.out.println("加载已经存在的国际化文件:"+file);
		} catch (IOException e) {
			e.printStackTrace();
		}
		for (Map.Entry<Object, Object> e : prop.entrySet()) {
			map.put(String.valueOf(e.getValue()), String.valueOf(e.getKey()));
		}
		return map;
	}

	/**
	 * 
	 * @param sourcePath
	 * @param targetPath
	 */
	private static void replace(String sourcePath, String targetPath) {
		System.out.println("共有文件:" + fileList.size());
		for (File file : fileList) {
			// 查找当前要替换的字符
			String content = file2String(file, "utf-8");
			content = p_html.matcher(content).replaceAll("\n");
			content = p_jsp2.matcher(content).replaceAll("\n");
			content = p_js1.matcher(content).replaceAll("\n");
			content = p_js2.matcher(content).replaceAll("\n");
			content = p_java.matcher(content).replaceAll("\n");
			// 获取国际化后的文件内容
			content = getI18nContent(file, content);
			// 生成国际化文件
			File newFile = new File(file.getAbsolutePath().replace(sourcePath, targetPath));
			File dir = new File(newFile.getPath().substring(0, newFile.getPath().lastIndexOf("\\")));
			if (!dir.exists()) {
				dir.mkdirs();
			}
			string2File(content, newFile);
		}
	}

	
	/**
	 * 获取文件国际化后的内容
	 * @param file
	 * @param content
	 * @return
	 */
	private static String getI18nContent( File file, String content) {
		// System.out.println(content);
		/** 本页面匹配到的中文 */
		Matcher ma = CHINESE_PATTERN.matcher(content);
		// 缓存当前页面需要被匹配中文和生成的key Map<中文,匹配到的key>
		Map<String, String> selfMap = new HashMap<String, String>();
		//用来标记是否有匹配的中文
		boolean isMatch = false;
		while (ma.find()) {
			String pipei = ma.group().trim();
			// 忽略需要被排除的中文
			if (noReplace.get(pipei) != null) {
				continue;
			}
			IL8NBean i18nBean = i18nMatchCache.get(pipei);
			if(i18nBean != null){
				String key = i18nBean.getKey();
				if (key != null) {
					selfMap.put(pipei, key);
				}
				isMatch = true;
			}
		}
		/** 开始替换 **/
		content = file2String(file, "utf-8");
		StringBuffer sb = new StringBuffer();
		ma = CHINESE_PATTERN.matcher(content);
		while (ma.find()) {
			if (noReplace.get(ma.group().trim()) != null) {
				continue;
			}
			String key = selfMap.get(ma.group().trim());
			//替换
			ma.appendReplacement(sb, key == null ? ma.group() : getI18nString(key));
		}
		ma.appendTail(sb);
		/** 判断是否已经添加国际化标签,没有则添加 */
		if (isMatch && sb.indexOf(IL8N_TAGLIB_CHECK) < 0 && sb.indexOf(IL8N_TAGLIB_FMT_CHECK) < 0) {
			return new StringBuilder(IL8N_TAGLIB_FMT).append(sb.toString()).toString();
		}
		return sb.toString();
	}
	
	/**
	 * 返回国际化标签
	 * @param str
	 * @return
	 */
	private static String getI18nString(String str) {
		return "<fmt:message key=\"" + str + "\"/>";
	}

	/**
	 * @Description: 扫描jsp,提取中文,并翻译,生成国际化资源文件
	 * @param path        		要国际化的jsp文件存储路径
	 * @param i18nKeyPrefix     国际化key的前缀
	 * @throws 
	 * @author  zhuqz
	 */
	private static void getChinereWord(String path) {
		for (File file : fileList) {
			String content = file2String(file, "utf-8");
			// 预处理
			// 去掉html注释 <!--.*?-->
			content = p_html.matcher(content).replaceAll("\n");
			// 去掉jsp注释 <%--.*?--%>
			content = p_jsp.matcher(content).replaceAll("\n");
			// 去掉jsp注释2 /* */
			content = p_js1.matcher(content).replaceAll("\n");
			// 去掉jsp注释3 //
			content = p_js2.matcher(content).replaceAll("\n");
			content = p_java.matcher(content).replaceAll("\n");

			// 匹配中文
			Matcher ma = CHINESE_PATTERN.matcher(content);
			boolean has = false;
			while (ma.find()) {
				// 获取到匹配的中文
				String pipei = ma.group().trim();
				// 过滤掉不需要匹配的中文内容
				if (noReplace.get(ma.group().trim()) != null) {
					continue;
				}
				has = true;
				IL8NBean il8 = i18nMatchCache.get(pipei);
				if (il8 == null)
					il8 = new IL8NBean();
				//查找key是否已经被国际化
				String pinyinValueKey = existMap.get(pipei);
				il8.setChinese(pipei);
				il8.setKey(pinyinValueKey == null ? 
						new StringBuffer(I18N_KEY_PREFIX)
						.append(".")
						.append(ChineseToPinyin.getAll(pipei))
						.toString() : pinyinValueKey);
				il8.setFile(file.getAbsolutePath().replace(JSP_SOURCE_PATH, ""));
				i18nMatchCache.put(pipei, il8);
				System.out.println(ma.group());
			}
			if (has) {
				System.out.println("文件:" + file.getPath());
				// break;
			}
		}

		// 打印出全部的中文和生成的key;
		for (Map.Entry<String, IL8NBean> e : i18nMatchCache.entrySet()) {
			System.out.println(e.getValue().getChinese() + ":::" + e.getValue().getKey());
		}
		System.out.println(i18nMatchCache.size());
		// 翻译
		translate(i18nMatchCache);
		// 生成i18n文件
		createIL8NFile(i18nMatchCache);
	}

	/**
	 *
	 * @Description:  翻译中文为英文,这里都用"english"字符串代替,可以在这里调用翻译工具自动翻译;
	 * @param map
	 * @throws 
	 * @author zhuqz
	 */
	private static void translate(Map<String, IL8NBean> map) {
		int i = 0;
		for (Map.Entry<String, IL8NBean> e : map.entrySet()) {
			try {
				e.getValue().setEnglish("english");
			} catch (Exception ex) {
				// TODO Auto-generated catch block
				ex.printStackTrace();
			}
			System.out.println(
					e.getValue().getChinese() + ":::" + e.getValue().getEnglish() + ":::" + e.getValue().getKey());
			System.out.println(map.size() + "--" + (++i));
		}
	}

	/**
	 * @Description: 生成国际化文件
	 * @param map
	 * @throws 
	 * @author zhuqz
	 */
	private static void createIL8NFile(Map<String, IL8NBean> map) {
		Writer osw_eng = null, osw_gbk = null, osw_eng$ = null;
		try {
			osw_eng = new OutputStreamWriter(new FileOutputStream(I18N_FILE_SAVE_PATH+PROP_NAME_ENG), ENCODING);
			osw_gbk = new OutputStreamWriter(new FileOutputStream(I18N_FILE_SAVE_PATH+PROP_NAME_GBK), ENCODING);
			osw_eng$ = new OutputStreamWriter(new FileOutputStream(I18N_FILE_SAVE_PATH+PROP_NAME_ENG$), ENCODING);
			int  existCount = 0;
			for (Map.Entry<String, IL8NBean> entry : map.entrySet()) {
				// 已经被国际化的key就不再处理了;
				if(existMap.get(entry.getKey()) != null){
					existCount++;
					continue;
				}
				osw_eng$.write(
						"#" + entry.getValue().getChinese() + "--->" + entry.getValue().getFiles().toString() + "\n");
				osw_eng$.write(entry.getValue().getKey() + "=$" + entry.getValue().getEnglish() + "$\n");
				osw_eng$.write("\n");
				osw_eng.write(
						"#" + entry.getValue().getChinese() + "--->" + entry.getValue().getFiles().toString() + "\n");
				osw_eng.write(entry.getValue().getKey() + "=" + entry.getValue().getEnglish() + "\n");
				osw_eng.write("\n");
				osw_gbk.write("#" + entry.getValue().getFiles().toString() + "\n");
				osw_gbk.write(entry.getValue().getKey() + "=" + entry.getKey() + "\n");
				osw_gbk.write("\n");
			}
			System.out.println("\n\r\n\r生成国际化资源文件");
			System.out.println(I18N_FILE_SAVE_PATH+PROP_NAME_GBK);
			System.out.println(I18N_FILE_SAVE_PATH+PROP_NAME_ENG);
			System.out.println("共有"+map.size()+"个key,"+existCount+"个key已经存在,"+ (map.size() - existCount)+"个key已写入国际化文件");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (osw_eng != null) {
				try {
					osw_eng.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (osw_eng$ != null) {
				try {
					osw_eng$.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (osw_gbk != null) {
				try {
					osw_gbk.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}


	/**
	 * 将文本写入到文件
	 * @param content
	 * @param file
	 */
	public static void string2File(String content, File file) {
		try {
			Writer osw = new OutputStreamWriter(new FileOutputStream(file), ENCODING);
			osw.write(content);
			osw.close();
			System.out.println("生成国际化jsp文件:"+file.getAbsolutePath());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 遍历path目录,获取全部的jsp文件,并将其放入到fileList列表里面;
	 * @param path
	 * @param fileList
	 */
	private static List<File> getJsps(File path) {
		List<File> fileList = new ArrayList<File>();
		File[] files = path.listFiles();
		for (File file : files)
			if (file.isDirectory() && !file.isHidden()){
				fileList.addAll(getJsps(file));
			}else if (file.getName().toLowerCase().endsWith(".jsp")){
				fileList.add(file);
				System.out.println("需国际化的jsp文件:"+file.getAbsolutePath());
			}
		return fileList;
	}

	/**
	 * 读取文件内容,返回字符串;
	 * @param file
	 * @param encoding
	 * @return
	 */
	public static String file2String(File file, String encoding) {
		StringWriter writer = new StringWriter();
		try {
			InputStreamReader reader = new InputStreamReader(new FileInputStream(file), encoding);
			char[] buffer = new char[BUFF_SIZE];
			int n;
			while (-1 != (n = reader.read(buffer))) {
				writer.write(buffer, 0, n);
			}
			reader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return writer.toString();
	}

	static class ComparatorStrLength implements Comparator<String> {
		public int compare(String str1, String str2) {
			int length1 = str1 == null ? 0 : str1.length();
			int length2 = str2 == null ? 0 : str2.length();
			return length2 - length1;
		}
	}

}


辅助类

import java.util.HashSet;
import java.util.Set;

/**
 * 国际化辅助类
 * @author zqz
 */
public class IL8NBean {

	/**
	 * 国际化文件中的key
	 */
	private String key;
	
	/**
	 *  需要被国际化的中文
	 */
	private String chinese;
	
	/**
	 * 中文翻译后的英文
	 */
	private String english;
	
	/**
	 * 记录哪些文件包含有这个中文
	 */
	private Set<String> files = new  HashSet<String>(5);
	
	public void setFile(String file){
		files.add(file);
	}
	
	public StringBuilder getFiles(){
		StringBuilder sb =new StringBuilder();
		for(String str:files){
			sb.append(str).append(";");
		}
		return sb;
	}
	
	public String getKey() {
		return key;
	}
	public void setKey(String key) {
		this.key = key;
	}
	public String getEnglish() {
		return english;
	}
	public void setEnglish(String english) {
		this.english = english;
	}
	public String getChinese() {
		return chinese;
	}
	public void setChinese(String chinese) {
		this.chinese = chinese;
	}

	@Override
	public String toString() {
		return "IL8NBean [key=" + key + ", chinese=" + chinese + ", english=" + english + ", files=" + files + "]";
	}
}


获取汉字拼音的工具类


import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;


/**
 * 将中文转换为拼音
 * @author zqz
 *
 */
public class ChineseToPinyin {
	
	/**
	 * 获取全拼拼音,如果长度大于40,那么就取每个汉字开头拼音字母;
	 * @param src
	 * @return
	 */
	public static String getAll(String src){
		String result= getPingYin(src).replaceAll("\\W", "");
		if(result.length()>40){
			result = getPinYinHeadChar(src).replaceAll("\\W", "");
		}
		return result;
	}
	
	public static String get(String src){
		String result = null;
		boolean isHeader = false;
		if(src.length()>7){
			result = getPinYinHeadChar(src);
			isHeader = true;
		}else{
			result = getPingYin(src);
		}
		result = result.replaceAll("\\W", "");
		if(isHeader && result.length()<6){
			result=getPingYin(src).replaceAll("\\W", "");
		}
		return result;
	}
	
	 /**
	  * 首字母转大写
	  * @param s
	  * @return
	  */
    public static String toUpperCaseFirstOne(String s){
        if(Character.isUpperCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
    }
	
	 /**
	  *  将汉字转换为全拼  
	  * @param src
	  * @return
	  */
    public static String getPingYin(String src) {  
        char[] t1 = null;  
        t1 = src.toCharArray();  
        String[] t2 = new String[t1.length];  
        HanyuPinyinOutputFormat t3 = new HanyuPinyinOutputFormat();  
        t3.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
        t3.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
        t3.setVCharType(HanyuPinyinVCharType.WITH_V);  
        String t4 = "";  
        int t0 = t1.length;  
        try {  
        	boolean first = false;
            for (int i = 0; i < t0; i++) {  
                // 判断是否为汉字字符  
                if (java.lang.Character.toString(t1[i]).matches(  
                        "[\\u4E00-\\u9FA5]+")) {  
                    t2 = PinyinHelper.toHanyuPinyinStringArray(t1[i], t3);  
                    t4 += first?toUpperCaseFirstOne(t2[0]):t2[0];
                    first = true;
                } else  
                    t4 += java.lang.Character.toString(t1[i]);  
            }  
            // System.out.println(t4);  
            return t4;  
        } catch (BadHanyuPinyinOutputFormatCombination e1) {  
            e1.printStackTrace();  
        }  
        return t4;  
    }  
  
    /**
     *  返回中文的首字母  
     * @param str
     * @return
     */
    public static String getPinYinHeadChar(String str) {  
  
        String convert = "";  
        for (int j = 0; j < str.length(); j++) {  
            char word = str.charAt(j);  
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);  
            if (pinyinArray != null) {  
                convert += pinyinArray[0].charAt(0);  
            } else {  
                convert += word;  
            }  
        }  
        return convert;  
    }  
  
    /**
     *  将字符串转移为ASCII码  
     * @param cnStr
     * @return
     */
    public static String getCnASCII(String cnStr) {  
        StringBuffer strBuf = new StringBuffer();  
        byte[] bGBK = cnStr.getBytes();  
        for (int i = 0; i < bGBK.length; i++) {  
            strBuf.append(Integer.toHexString(bGBK[i] & 0xff));  
        }  
        return strBuf.toString();  
    }  
  
    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {  
        System.out.println(getPingYin("綦江1_qq县").replaceAll("\\W", ""));  
        System.out.println(getPinYinHeadChar("綦江县"));  
        System.out.println(getCnASCII("綦江县"));
        System.out.println(getAll("綦江县"));
        System.out.println(getPingYin("綦江县"));
    }  
}

依赖的jar包


<!-- https://mvnrepository.com/artifact/com.belerweb/pinyin4j -->
<dependency>
    <groupId>com.belerweb</groupId>
    <artifactId>pinyin4j</artifactId>
    <version>2.5.0</version>
</dependency>


2018-05-02

又搞了一个对js文件做国际化的工具类:


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fanyti.ChineseToPinyin;

/**
 * javascript文件国际化
 * js国际化原理就是根据语言加载不同js国际化文件,js国际化文件里面有一个对象,这个对象是当前语言的一个map;
 * @author zqz
 *
 */
public class Il8nJavascriptTool {

	/**文件编码*/
	private static final String ENCODING = "utf-8";
	/** 文件缓冲大小*/
	public static final int BUFF_SIZE = 10240;
	
	/**js国际化资源对象名称,全部的国际化key都会放在这个对象里面;*/
	private final static String GLOBAL_VARIABLE_NAME = "message_source_i18n";
	/** 现有的国际化文件,只需要中文 **/
	private static final String EXIST_I18n_FILES = "E:\\newsysi18n_\\js_i18n_source\\";
    
	/**需要被国际化的js文件,将需要国际化的js文件,按照js文件存放的目录结构,放在这个目录下即可*/
	private static final String sourcePath = "E:\\newsysi18n\\";
	/**国际化后生成的js文件**/
	private static final String targetPath = "E:\\newsysi18n_\\";

	/**
	 * 国际化后生成的key和value文件,将文件中的内容拷贝到一个GLOBAL_VARIABLE_NAME参数指定的名称的js对象中即可
	 * 例如GLOBAL_VARIABLE_NAME=message_source_i18n, 则生成文件:
	 1. js_autocreate_i18n_zh_CN.properties文件内容:
	 com_zqz_bianJi:"编辑",
	 com_zqz_shanChu:"删除",
	 com_zqz_add:"添加",
	 2. js_autocreate_i18n_en.properties文件内容:
	 com_zqz_bianJi:"edit",
	 com_zqz_shanChu:"delete",
	 com_zqz_add:"add",
	 
	 那么把这些内容分别放到两个js文件中
	 
	 js_autocreate_i18n_zh_CN.js文件内容:
	 
	 var message_source_i18n = {
	 	com_zqz_bianJi:"编辑",
	 	com_zqz_shanChu:"删除",
	 	com_zqz_add:"添加"
	 }
	 
	 js_autocreate_i18n_en.js文件内容:
	 
	 var js_autocreate_i18n_en = {
	 	com_zqz_bianJi:"edit",
	 	com_zqz_shanChu:"delete",
	 	com_zqz_add:"add"
	 }
	 
	 然后在页面上如果是中文则载入js_autocreate_i18n_zh_CN.js,如果是英文则载入js_autocreate_i18n_en.js文件
	 * 
	 * */
	private static final String PROP_NAME_ENG$ = "$js_autocreate_i18n_en.properties";
	private static final String PROP_NAME_ENG = "js_autocreate_i18n_en.properties";
	private static final String PROP_NAME_GBK = "js_autocreate_i18n_zh_CN.properties";

	/** 缓存现有国际化文件中国际化了的ket和value(只有中文)Entyty<中文,国际化key> **/
	private static Map<String, String> existI18nWord = new HashMap<String, String>();
	
	/** 用来存储需要被国际化的key和value,Entyty<中文,IL8NBean> **/
	private static final Map<String, IL8NBean> needToI18n = new HashMap<String, IL8NBean>();

	private static final Pattern CHINESE_PATTERN = Pattern
			.compile("[ \\w\\ufe30-\\uffa0\\u4e00-\\u9fa5]*[\\u4e00-\\u9fa5]+[\\w\\ufe30-\\uffa0\\u4e00-\\u9fa5!。!?]*");
	private static final Pattern CHINESE_PATTERN2 = Pattern.compile(
			"[\"']?[ \\w\\ufe30-\\uffa0\\u4e00-\\u9fa5]*[\\u4e00-\\u9fa5]+[ \\w\\ufe30-\\uffa0\\u4e00-\\u9fa5!。!?]*[\"']?");

	// html注释<!-- XXXX -->
	private static String regEx_html = "<!--.*?-->";
	private static Pattern p_html = Pattern.compile(regEx_html, Pattern.DOTALL);
	// js注释/* XXXX */
	private static String regEx_js1 = "/\\*.*?\\*/";
	private static Pattern p_js1 = Pattern.compile(regEx_js1, Pattern.DOTALL);
	// js注释 // XXXXX
	private static String regEx_js2 = "//[\\s\\S]*?\n";
	private static Pattern p_js2 = Pattern.compile(regEx_js2, Pattern.CASE_INSENSITIVE);


	public static void main(String[] args) {
		getExistI18nJsFile();
		getChinereWord(sourcePath, "com_lens_");
		replace(sourcePath, targetPath);
	}

	/**
	 * 获取已经做过国际化的中文及其key
	 */
	private static void getExistI18nJsFile() {
		File[] files = new File(EXIST_I18n_FILES).listFiles();
		for (File file : files) {
			if (file.getName().endsWith(".js"))
				readExistI18nJsFile(file);
		}
	}

	/**
	 * 按行读取文件内容
	 * 
	 * @param file
	 */
	private static void readExistI18nJsFile(File file) {
		FileInputStream inputStream = null;
		BufferedReader bufferedReader = null;
		try {
			inputStream = new FileInputStream(file);
			bufferedReader = new BufferedReader(new InputStreamReader(inputStream,ENCODING));
			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				praiseLine(str.trim());
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				inputStream.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			try {
				bufferedReader.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/** 匹配js国际化行 **/
	private final static String JS_I18N_LINE_PATTERN = "^\\w+:\\s{0,3}[\"\'].+[\"\'],?$";

	/**
	 * 解析国际化行,并放入缓存
	 * 
	 * @param str
	 */
	private static void praiseLine(String str) {
		if (str == null || "".equals(str)) {
			return;
		}
		if (Pattern.matches(JS_I18N_LINE_PATTERN, str)) {
			String key = str.substring(0, str.indexOf(":")).trim();
			String value = null;
			int startIndex = -1;
			if ((startIndex = str.indexOf("\"")) > -1) {
				value = str.substring(startIndex + 1, str.lastIndexOf("\""));
			} else if ((startIndex = str.indexOf("\'")) > -1) {
				value = str.substring(startIndex + 1, str.lastIndexOf("\'"));
			}
			existI18nWord.put(value, key);
		}
	}

	/**
	 * 扫描js文件,提取中文,并翻译,生成国际化资源文件
	 * 
	 * @Description: TODO
	 * @param path
	 * @param appName
	 * @author zhuqz
	 */
	private static void getChinereWord(String path, String appName) {
		List<File> files = new ArrayList<File>();
		getJsFiles(new File(path), files);
		int fileSize = 0;
		for (File file : files) {
			String content = file2String(file, "utf-8");
			content = p_html.matcher(content).replaceAll("");
			content = p_js1.matcher(content).replaceAll("");
			content = p_js2.matcher(content).replaceAll("");
			Matcher ma = CHINESE_PATTERN.matcher(content);
			boolean has = false;
			while (ma.find()) {
				has = true;
				String pipei = ma.group().trim();
				IL8NBean il8;
				if (existI18nWord.get(pipei) != null) {
					il8 = new IL8NBean();
					il8.setKey(existI18nWord.get(pipei));
				} else {
					il8 = needToI18n.get(pipei);
					if (il8 == null)
						il8 = new IL8NBean();
					il8.setKey(new StringBuffer(appName).append(ChineseToPinyin.getAll(pipei)).toString());
					
				}
				il8.setFile(file.getAbsolutePath().replace(sourcePath, ""));
				il8.setChinese(pipei);
				needToI18n.put(pipei, il8);
				System.out.println(il8.getChinese() + ":::::" + il8.getKey() + "::::");
				
			}
			if (has) {
				fileSize++;
				System.out.println("文件:" + file.getPath());
			}
		}
		System.out.println(needToI18n.size() + ":::" + fileSize);
		translate();
		createIL8NFile();
	}


	private static void replace(String sourcePath, String targetPath) {
		/** 国际化map<中文,替换的key> **/
		List<File> files = new ArrayList<File>();
		getJsFiles(new File(sourcePath), files);
		System.out.println("共有文件:" + files.size());
		for (File file : files) {
			// 查找当前要替换的字符
			String content = file2String(file, "utf-8");
			content = p_html.matcher(content).replaceAll("");
			content = p_js1.matcher(content).replaceAll("");
			content = p_js2.matcher(content).replaceAll("");
			content = tihuanWithYinHao(needToI18n, file, content);
			// 生成国际化文件
			File newFile = new File(file.getAbsolutePath().replace(sourcePath, targetPath));
			File dir = new File(newFile.getPath().substring(0, newFile.getPath().lastIndexOf("\\")));
			if (!dir.exists()) {
				dir.mkdirs();
			}
			string2File(content, newFile);
		}
	}

	/**
	 * 替换带引号的js代码中的中文 “中文” ,'中文'
	 * 
	 * @param map
	 * @param file
	 * @param content
	 * @return
	 * @throws 
	 * @author zhuqz
	 */
	private static String tihuanWithYinHao(Map<String, IL8NBean> map, File file, String content) {
		// System.out.println(content);
		/** 本页面匹配到的中文 */
		Matcher ma = CHINESE_PATTERN.matcher(content);
		Map<String, String> selfMap = new HashMap<String, String>();
		while (ma.find()) {
			String pipei = ma.group().trim();
			String key = map.get(pipei).getKey();
			if (key != null) {
				selfMap.put(pipei, key);
			}
		}
		/** 开始替换 **/
		content = file2String(file, "utf-8");
		StringBuffer sb = new StringBuffer();
		ma = CHINESE_PATTERN2.matcher(content);
		while (ma.find()) {
			String pipei = ma.group().trim();
			System.out.println(pipei);

			String key = null;
			if ((pipei.startsWith("'") && pipei.endsWith("'")) || (pipei.startsWith("\"") && pipei.endsWith("\""))) {
				System.out.println(pipei.substring(1, pipei.length() - 1));
				key = selfMap.get(pipei.substring(1, pipei.length() - 1));
			} else
				key = selfMap.get(pipei);
			ma.appendReplacement(sb, key == null ? ma.group() : getI18nString(pipei, key));
		}
		ma.appendTail(sb);
		return sb.toString();
	}


	/**
	 * @Description: js国际化替换
	 * @param str
	 * @param key
	 * @return
	 * @throws 
	 * @author zhuqz
	 */
	private static String getI18nString(String str, String key) {
		if (str.startsWith("'") && str.endsWith("'")) {
			return new StringBuilder(GLOBAL_VARIABLE_NAME).append(".").append(key).toString();
		} else if (str.startsWith("\"") && str.endsWith("\"")) {
			return new StringBuilder(GLOBAL_VARIABLE_NAME).append(".").append(key).toString();
		} else {
			return new StringBuilder("'+").append(GLOBAL_VARIABLE_NAME).append(".").append(key).append("+'").toString();
		}
	}

	/**
	 * 生成国际化文件
	 * 
	 * @Description: TODO
	 * @param map
	 * @throws 
	 * @author zhuqz
	 */
	private static void createIL8NFile() {
		Writer osw_eng = null, osw_gbk = null, osw_eng$ = null;
		try {
			osw_eng = new OutputStreamWriter(new FileOutputStream(PROP_NAME_ENG), ENCODING);
			osw_gbk = new OutputStreamWriter(new FileOutputStream(PROP_NAME_GBK), ENCODING);
			osw_eng$ = new OutputStreamWriter(new FileOutputStream(PROP_NAME_ENG$), ENCODING);
			for (Map.Entry<String, IL8NBean> entry : needToI18n.entrySet()) {
				if (existI18nWord.get(entry.getKey()) != null) {
					continue;
				}
				osw_eng$.write("/**" + entry.getValue().getChinese() + "--->" + entry.getValue().getFiles().toString()
						+ "**/\n");
				osw_eng$.write(entry.getValue().getKey() + ":\"$" + entry.getValue().getEnglish() + "$\",\n");
				osw_eng$.write("\n");

				osw_eng.write("/**" + entry.getValue().getChinese() + "--->" + entry.getValue().getFiles().toString()
						+ "**/\n");
				osw_eng.write(entry.getValue().getKey() + ":\"" + entry.getValue().getEnglish() + "\",\n");
				osw_eng.write("\n");
				osw_gbk.write("/**" + entry.getValue().getFiles().toString() + "**/\n");
				osw_gbk.write(entry.getValue().getKey() + ":\"" + entry.getKey() + "\",\n");
				osw_gbk.write("\n");
			}
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			if (osw_eng != null) {
				try {
					osw_eng.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (osw_eng$ != null) {
				try {
					osw_eng$.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (osw_gbk != null) {
				try {
					osw_gbk.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 翻译
	 * 
	 * @Description: TODO
	 * @param map
	 * @throws 
	 * @author zhuqz
	 */
	private static void translate() {
		int i = 0;
		for (Map.Entry<String, IL8NBean> e : needToI18n.entrySet()) {
			try {
				// e.getValue().setEnglish(TranslateUtil.translate(e.getValue().getChinese(),TranslateUtil.CHINA,
				// TranslateUtil.ENGLISH));
				e.getValue().setEnglish("english");
			} catch (Exception ex) {
				// TODO Auto-generated catch block
				ex.printStackTrace();
			}
			System.out.println(
					e.getValue().getChinese() + ":::" + e.getValue().getEnglish() + ":::" + e.getValue().getKey());
			System.out.println(needToI18n.size() + "--" + (++i));
		}
	}

	private static void getJsFiles(File path, List<File> fileList) {
		File[] files = path.listFiles();
		for (File file : files)
			if (file.isDirectory() && !file.isHidden())
				getJsFiles(file, fileList);
			else if (file.getName().toLowerCase().endsWith(".js"))
				fileList.add(file);
	}

	public static String file2String(File file, String encoding) {

		StringWriter writer = new StringWriter();
		try {
			InputStreamReader reader = new InputStreamReader(new FileInputStream(file), encoding);
			char[] buffer = new char[BUFF_SIZE];
			int n;
			while (-1 != (n = reader.read(buffer))) {
				writer.write(buffer, 0, n);
			}
			reader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return writer.toString();
	}

	public static void string2File(String content, File file) {
		try {
			Writer osw = new OutputStreamWriter(new FileOutputStream(file), ENCODING);
			osw.write(content);
			osw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值