國際化工具:properties屬性文件以及json文件的讀取、修改值內容、保存。
讀取和修改都是基於key-value的:方便理解和修改;具備properties文件<->json文件互相轉換的能力。
在實際項目中還用到properties屬性文件或json文件和excel文件的相互轉換的。
關於國際化,還需要考慮去重(一個詞條在系統中多種不同的翻譯會顯得很不專業,一個詞條重複翻譯浪費翻譯費用),考慮專業術語的維護,詞條的合理複用,不同語言的條目的一致性,字符寬度檢測(避免界面變形),語法的一致性等。
一、屬性文件properties的讀取、修改值內容、保存
package tool.i18n;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
/**
* 屬性文件properties的讀取、修改值內容、保存
* @author 陳小穩 csdn ID:ccxw1983
*
*/
public class PropertyFileModify {
public static void main(String[] args) throws IOException {
String currentFilePath = "D:\\workspace123\\demo.json\\test_files\\unicode.properties";
String saveFilePath = "D:\\workspace123\\demo.json\\test_files\\unicode_new.properties";
HashMap<String, String> modifyKeyVals = new HashMap<String, String>();
{
modifyKeyVals.put("a.b.c", "newval");
}
modifyAndNewFile(currentFilePath, saveFilePath, modifyKeyVals, "【有待翻譯】");
}
public static void modifyAndNewFile(String currentFilePath, String saveFilePath,
HashMap<String, String> modifyKeyVals, String defaultVal) throws IOException {
File file = new File(currentFilePath);
ArrayList<String> lines = FileUtils2.readFile2Lines(file, FileUtils2.encoding);
HashMap<String, String> currentMap = getCurrentKeyVals(lines);
Boolean setDefaultVal = StringUtils.isNotBlank(defaultVal);
if (currentMap.size() > modifyKeyVals.size()) {
System.out.println("json文件key-val數目:" + currentMap.size() + "> 修改條目:" + modifyKeyVals.size());
// 設置默認值
if (setDefaultVal) {
for (Iterator iterator = currentMap.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
if (!modifyKeyVals.containsKey(key)) {
// System.out.println("沒有條目的翻譯:" + key);
modifyKeyVals.put(key, defaultVal);
}
}
}
}
// 修改文件
StringBuffer newcontent = new StringBuffer();
for (int i = 0; i < lines.size(); i++) {
String line = StringUtils.trimToEmpty(lines.get(i));
if (line.startsWith("#")) {
newcontent.append(line);
newcontent.append("\r\n");
continue;
} else {
String[] keyvalarr = line.split("=");
String key = StringUtils.trimToEmpty(keyvalarr[0]);
if(modifyKeyVals.containsKey(key)){
String val = modifyKeyVals.get(key);
val = utf82unicode(val);
newcontent.append(key);
newcontent.append("=");
newcontent.append(val);
newcontent.append("\r\n");
}else{
newcontent.append(line);
newcontent.append("\r\n");
}
}
}
// 保存爲文件
File newfile = new File(saveFilePath);
if (newfile.exists()) {
newfile.delete();
}
FileUtils.writeStringToFile(newfile, newcontent.toString(), "UTF-8");
}
private static HashMap<String, String> getCurrentKeyVals(ArrayList<String> lines) {
HashMap<String, String> currentKeyVals = new HashMap<String, String>();
for (int i = 0; i < lines.size(); i++) {
String line = StringUtils.trimToEmpty(lines.get(i));
if (line.startsWith("#")) {
continue;
} else {
String[] keyvalarr = line.split("=");
String key = StringUtils.trimToEmpty(keyvalarr[0]);
String val = StringUtils.trimToEmpty(keyvalarr[1]);
val = unicode2utf8(val);
currentKeyVals.put(key, val);
}
}
return currentKeyVals;
}
private static String utf82unicode(String val) {
return Native2AsciiUtils.native2Ascii(val);
}
private static String unicode2utf8(String val) {
return Native2AsciiUtils.ascii2Native(val);
}
}
依賴的unicode轉碼工具類
轉自 https://blog.csdn.net/nospeak/article/details/83677030
package tool.i18n;
import java.io.IOException;
/**
* native2ascii.exe Java code implementation.
* @author https://blog.csdn.net/nospeak/article/details/83677030
* @version 1.0
*/
public class Native2AsciiUtils {
public static void main(String[] args) throws IOException {
System.out.println(Native2AsciiUtils.ascii2Native("1\u4e2d 2\u56fd c"));
System.out.println(Native2AsciiUtils.native2Ascii("1中 2國 c"));
}
/**
* prefix of ascii string of native character
*/
private static String PREFIX = "\\u";
/**
* Native to ascii string. It's same as execut native2ascii.exe.<br>
* 和這個效果一致 native2ascii -encoding UTF-8 utf_8.txt unicode.properties
*
* @param str
* native string
* @return ascii string
*/
public static String native2Ascii(String str) {
char[] chars = str.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
sb.append(char2Ascii(chars[i]));
}
return sb.toString();
}
/**
* Native character to ascii string.<br>
* 和這個效果一致 native2ascii -reverse unicode.properties utf_8.txt
* @param c
* native character
* @return ascii string
*/
private static String char2Ascii(char c) {
if (c > 255) {
StringBuffer sb = new StringBuffer();
sb.append(PREFIX);
int code = (c >> 8);
String tmp = Integer.toHexString(code);
if (tmp.length() == 1) {
sb.append("0");
}
sb.append(tmp);
code = (c & 0xFF);
tmp = Integer.toHexString(code);
if (tmp.length() == 1) {
sb.append("0");
}
sb.append(tmp);
return sb.toString();
} else {
return Character.toString(c);
}
}
/**
* Ascii to native string. It's same as execut native2ascii.exe -reverse.
*
* @param str
* ascii string
* @return native string
*/
public static String ascii2Native(String str) {
StringBuffer sb = new StringBuffer();
int begin = 0;
int index = str.indexOf(PREFIX);
while (index != -1) {
sb.append(str.substring(begin, index));
sb.append(ascii2Char(str.substring(index, index + 6)));
begin = index + 6;
index = str.indexOf(PREFIX, begin);
}
sb.append(str.substring(begin));
return sb.toString();
}
/**
* Ascii to native character.
*
* @param str
* ascii string
* @return native character
*/
private static char ascii2Char(String str) {
if (str.length() != 6) {
throw new IllegalArgumentException("Ascii string of a native character must be 6 character.");
}
if (!PREFIX.equals(str.substring(0, 2))) {
throw new IllegalArgumentException("Ascii string of a native character must start with \"\\u\".");
}
String tmp = str.substring(2, 4);
int code = Integer.parseInt(tmp, 16) << 8;
tmp = str.substring(4, 6);
code += Integer.parseInt(tmp, 16);
return (char) code;
}
}
PS:此工具類和使用native2ascii轉碼的一致,轉碼批處理腳本:
toUnicode.bat
REM UTF-8編碼的文件utf_8.txt 轉爲 unicode編碼的文件unicode.properties
REM 需要使用“ -encoding UTF-8”指定編碼否則會多輸出\ufffd等
REM 在 native2ascii 命令中 -encoding 指定的編碼爲(生成的)目標文件的編碼格式。
native2ascii -encoding UTF-8 utf_8.txt unicode.properties
toUtf8.bat
REM unicode編碼的文件 unicode.properties 轉成 utf-8的明文
REM native2ascii -reverse 命令中 -encoding 指定的編碼爲源文件的編碼格式。
native2ascii -reverse unicode.properties utf_8.txt
二、json類型的國際化資源串的讀取、修改、格式化、保存
package tool.i18n;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import net.sf.json.JSONObject;
/**
* json文件的讀取、修改、格式化、保存
*
* @author 陳小穩 csdn ID:ccxw1983
*
*/
public class JsonFileModify {
private File file;
private String encoding = "UTF-8";
// 用於修改
private JSONObject jsonObject = null;
public static void main(String[] args) throws IOException {
// 當前 json文件
String currentFilePath = "D:\\workspace123\\demo.json\\test_files\\1.json";
// 待保存的 json文件
String saveFilePath = "D:\\workspace123\\demo.json\\test_files\\new.json";
// 待修改的key-val
HashMap<String, String> modifyKeyVals = new HashMap<String, String>();
{
modifyKeyVals.put("bank1.attrs.attr2", "newval");
}
// 修改json文件內容 並保存爲新文件
modifyAndNewFile(currentFilePath, saveFilePath, modifyKeyVals, "【有待翻譯】");
// modifyAndNewFile(currentFilePath, saveFilePath, modifyKeyVals, null);
}
/**
* 修改json文件內容 並保存爲新文件
*
* @param currentFilePath
* 當前 json文件
* @param saveFilePath
* 待保存的 json文件
* @param modifyKeyVals
* 待修改的key-val
* @param defaultVal
* 沒修改的key設置默認val
* @throws IOException
*/
public static void modifyAndNewFile(String currentFilePath, String saveFilePath,
HashMap<String, String> modifyKeyVals, String defaultVal) throws IOException {
// 讀取json文件信息
JsonFileModify jsonFile = toJsonFile(currentFilePath);
// 檢查是否所有都修改到了
// 獲取當前 json文件的key-val
HashMap<String, String> currentMap = jsonFile.getKeyValMap();
Boolean setDefaultVal = StringUtils.isNotBlank(defaultVal);
if (currentMap.size() > modifyKeyVals.size()) {
System.out.println("json文件key-val數目:" + currentMap.size() + "> 修改條目:" + modifyKeyVals.size());
// 設置默認值
if (setDefaultVal) {
for (Iterator iterator = currentMap.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
if (!modifyKeyVals.containsKey(key)) {
// System.out.println("沒有條目的翻譯:" + key);
modifyKeyVals.put(key, defaultVal);
}
}
}
}
// 修改屬性
for (Iterator iterator = modifyKeyVals.keySet().iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
String val = modifyKeyVals.get(key);
jsonFile.modifyJsonValByKey(key, val);
}
// 輸出json字符串
String formatJsonStr = jsonFile.toFormatJsonStr();
// System.out.println(formatJsonStr);
// 保存爲文件
File newfile = new File(saveFilePath);
if (newfile.exists()) {
newfile.delete();
}
FileUtils.writeStringToFile(newfile, formatJsonStr, "UTF-8");
}
private HashMap<String, String> keyValMap = new HashMap<String, String>();
/**
* 根據 json對象 獲取key-val
*
* @return
*/
private HashMap<String, String> getKeyValMap() {
this.keyValMap.clear();
analysisJSONObject2keyVal(this.jsonObject, null);
return this.keyValMap;
}
private void addToMap(String key, String val) {
keyValMap.put(key, val);
// System.out.println(key + "=" + val);
}
/**
* 解析 key-val,同時設置每對key-val的行號(從0開始,基於沒空白行且格式化的前提來推斷的行號)
*
* @param obj
* @param keypath
*/
public void analysisJSONObject2keyVal(Object obj, String keypath) {
if (obj instanceof String) {
String key = keypath;
String val = obj.toString();
addToMap(key, val);
// this.lineNumber++;
} else if (obj instanceof JSONObject) {
// 新的開始
// this.lineNumber++;
JSONObject jsonObject = (JSONObject) obj;
for (Object iterable_element : jsonObject.keySet()) {
String key = (String) iterable_element;
Object childobj = jsonObject.get(key);
String keychild = StringUtils.isBlank(keypath) ? key : keypath + "." + key;
analysisJSONObject2keyVal(childobj, keychild);
}
// 結尾
// this.lineNumber++;
}
}
/**
* 根據json文件路徑初始化json文件修改類對象:確保文件存在,讀取json文件內容,轉成json對象
*
* @param path
* json文件路徑
* @return
* @throws IOException
*/
public static JsonFileModify toJsonFile(String path) throws IOException {
File file = new File(path);
if (!file.exists()) {
throw new RuntimeException("file not exist: " + path);
}
JsonFileModify jsonFile = new JsonFileModify();
jsonFile.setFile(file);
jsonFile.init();
return jsonFile;
}
/**
* 讀取json文件內容,轉成json對象
*
* @throws IOException
*/
private void init() throws IOException {
String content = FileUtils2.readFileContext(file, encoding);
// 字符串 轉 json對象,參考:https://www.cnblogs.com/teach/p/5791029.html
this.jsonObject = JSONObject.fromObject(content);
}
/**
* 轉成json字符串並格式化
*/
public String toFormatJsonStr() {
// json對象 轉 json字符串
String newjsonstr = this.jsonObject.toString();
// 測試:格式化 json字符串
newjsonstr = formatJsonStr(newjsonstr);
// System.out.println(newjsonstr);
return newjsonstr;
}
/**
* 格式化json字符串
*
* @param newjsonstr
* @return
*/
public static String formatJsonStr(String newjsonstr) {
newjsonstr = StringUtils.replace(newjsonstr, "{", "{\r\n");
newjsonstr = StringUtils.replace(newjsonstr, "}", "\r\n}");
newjsonstr = StringUtils.replace(newjsonstr, ",", ",\r\n");
// newjsonstr = StringUtils.replaceAll(newjsonstr, "\\{", "\\{\r\n");
// newjsonstr = StringUtils.replaceAll(newjsonstr, "\\}", "\r\n\\}");
// newjsonstr = StringUtils.replaceAll(newjsonstr, ",", ",\r\n");
String[] lines = newjsonstr.split("\r\n");
int tcount = 0;
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (line.startsWith("}") || line.endsWith("}")) {
tcount--;
}
buffer.append(StringUtils.repeat("\t", tcount));
buffer.append(line);
buffer.append("\r\n");
if (line.startsWith("{") || line.endsWith("{")) {
tcount++;
}
}
return buffer.toString();
}
/**
* 根據key修改 json對象 的值
*
* @param keypath
* @param val
*/
public void modifyJsonValByKey(String keypath, Object val) {
modifyJsonValByKey(this.jsonObject, keypath, val);
}
/**
* 修改json對象的屬性<br>
* JSONObject newjsonobj = modifyJson(jsonobj, "bank1.attrs.attr2",
* "newval");
*
* @param jsonobj
* json對象
* @param keypath
* 路徑,路徑間用.隔開
* @param val
* 內容值
* @return
*/
public static JSONObject modifyJsonValByKey(JSONObject jsonobj, String keypath, Object val) {
String[] dirs = keypath.split("\\.");
JSONObject tmp = jsonobj;
String key = null;
if (dirs.length > 1) {
for (int i = 0; i < dirs.length - 1; i++) {
key = dirs[i];
tmp = (JSONObject) tmp.get(key);
}
key = dirs[dirs.length - 1];
} else {
key = keypath;
}
// 設置值
tmp.element(key, val);
return jsonobj;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
}
測試文件 D:\\workspace123\\demo.json\\test_files\\1.json
{
"name":"cxw",
"age":"37",
"bank1":{
"id":"bank1001",
"money":"1",
"attrs":{
"attr1":"attr11",
"attr2":"attr22"
}
},
"bank2":{
"id":"bank2002",
"money":"2"
}
}
測試文件 D:\\workspace123\\demo.json\\test_files\\unicode.properties
a.b.c=1\u4e2d 2\u56fd c
a.b.c1=1
a.b.c2=\u4e2d
a.b.c3=2
a.b.c4=\u56fd
a.b.c5=c
a.a.a=\u4e2d mm\u56fd nn
所需jar使用maven下載,pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo.json</groupId>
<artifactId>demo.json</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>json demo</name>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-io -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<!-- <dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId>
<version>2.4</version> </dependency> -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<!-- https://maven.aliyun.com/mvn/view的central的 /net/sf/json-lib/json-lib/2.4/json-lib-2.4-jdk15.jar -->
<classifier>jdk15</classifier>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>