Compare commits

...

13 Commits
1.2 ... master

Author SHA1 Message Date
Taskeren bf55d38a7b 修改方法位置
1. 将操作方法移动到T18n中
2. 添加 README
2019-10-01 19:17:50 +08:00
Taskeren 1625253fca 给予Gradlew执行权限 2019-08-30 12:19:25 +08:00
Taskeren b9d5915cda 调整部分方法
将设置和开发相关方法移动到T18n类中
2019-08-30 12:17:48 +08:00
倪钍 7e91fa3d4c
添加CI支持 2019-08-30 11:35:35 +08:00
Taskeren d87eb146d4 [+] 很多注解 2019-07-12 13:55:18 +08:00
Taskeren 240bc0cd0b [+] 修复LanguageMapBuilder#fromJarResource编码问题 2019-07-11 14:26:17 +08:00
Taskeren 355f64b475 [-] Clean up 2019-07-11 02:48:00 +08:00
Taskeren add75a4059 [+] 修复转码错误问题 2019-07-11 02:40:25 +08:00
Taskeren f02dbeabc1 [D] 添加一些神奇的注解 2019-07-10 15:12:27 +08:00
Taskeren 009699b11e [-/+] 再修改一点点 2019-07-07 14:22:20 +08:00
Taskeren 4eef26a4c8 [-] 稍微修改了一点点方法 2019-07-07 14:20:45 +08:00
Taskeren b4fa3f0fd0 [+] 添加了从在线网站读取的方法
1. 添加了从在线网站读取的方法
2. 移动了部分方法到 T18nUtils 里
2019-07-01 17:22:54 +08:00
Taskeren 4b01a2e58d [+/-] 对方法进行了调整
1. 添加了 translateList 和 flattenList 方法
2. 修改了 formatList 方法
2019-06-30 15:26:41 +08:00
14 changed files with 422 additions and 176 deletions

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

17
.github/workflows/gradle.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Java CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Build with Gradle
run: ./gradlew build

6
.gitignore vendored
View File

@ -3,3 +3,9 @@
# Ignore Gradle build output directory
build
# eclipse
bin/
.settings/
.classpath
.project

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>T18n</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@ -1,2 +0,0 @@
connection.project.dir=
eclipse.preferences.version=1

View File

@ -1,13 +0,0 @@
#
#Tue Jun 25 20:09:41 CST 2019
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

82
README.md Normal file
View File

@ -0,0 +1,82 @@
<h1 align="center">
Taskeren's Internationalization
</h1>
<h4 align="center">
A lightweight, powerful I18n tool for Java.
</h4>
## Get T18n
You can get this project in Jitpack with Maven, Gradle and so on.
### Maven
1. Import the Jitpack source.
```
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
```
2. Add the denpendency.
```
<dependency>
<groupId>com.github.nitu2003</groupId>
<artifactId>T18n</artifactId>
<version>1.5</version>
</dependency>
```
### Gradle
1. Import the Jitpack source.
```
repositories {
...
maven { url 'https://jitpack.io' }
}
```
2. Add the dependency.
```
dependencies {
implementation 'com.github.nitu2003:T18n:1.5'
}
```
### For else
[![](https://jitpack.io/v/nitu2003/T18n.svg)](https://jitpack.io/#nitu2003/T18n)
## Dev with T18n
1. Get the Language Map.
```java
// from file
LanguageMapBuilder.fromFile(new File("res/i18n/en_us.lang"));
// from jar resource
LanguageMapBuilder.fromJarResource("res/i18n/en_us.lang");
// from online content (Deprecated)
LanguageMapBuilder.fromURL("https://example.com/i18n/en.lang");
```
2. Push it to the I18n.
```java
// reset the I18n and push it
T18n.set(theMap);
// add the new to the old
T18n.add(theMap);
```
3. Use it in the project
_en.lang_
```
HelloToUser=Hello %s.
```
_app.java_
```java
System.out.println(I18n.format("HelloToUser", "Taskeren")); // It should be "Hello Taskeren"
```

2
bin/.gitignore vendored
View File

@ -1,2 +0,0 @@
/main/
/test/

0
gradlew vendored Normal file → Executable file
View File

View File

@ -4,21 +4,28 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
public class I18n {
private static LanguageMap map;
private static Charset charset;
protected static LanguageMap map;
protected static Charset charset;
protected static final int LOOP_MAX_COUNT = 32767;
static {
map = new LanguageMap();
charset = Charset.forName(System.getProperty("file.encoding"));
}
public static void setLanguageMap(LanguageMap map) {
I18n.map = map;
}
/* *******************************************************
*
* Localization functions
*
* *******************************************************/
public static void setEncoding(String charset) {
I18n.charset = Charset.forName(charset);
/** 自动从语言文件中提取翻译,空翻译时返回原键值 */
protected static String translate(String key) {
return reEncode(map.get(key), charset);
}
/** 自动翻译translate后再执行格式化format */
@ -28,24 +35,19 @@ public class I18n {
format);
}
/** 自动从语言文件中提取翻译,空翻译时返回原键值 */
public static String translate(String key) {
return reEncode(getLanguageMapSafe().get(key), charset);
}
/** translateformat<br>
* @param key format key<code>app.message.welcome.%s</code><code>%s</code><code>0</code>1000
/**
* translate
* @param keyRegular %s0welcome.%swelcome.0welcome.1...
*/
public static String format2(String key, Object...format) {
protected static List<String> translateList(String keyRegular) {
List<String> vlist = new ArrayList<String>();
int i = 0;
int max = 1000;
while(true) {
if(i >= max) break;
String k = tryFormat(key, i);
if(i >= LOOP_MAX_COUNT) break;
String k = tryFormat(keyRegular, i);
if(hasKey(k)) {
vlist.add(translate(k));
} else {
@ -54,28 +56,32 @@ public class I18n {
i++;
}
String v = "";
for(String o : vlist) {
v += o + "\n";
}
v = v.trim();
return vlist;
v = tryFormat(v, format);
return v;
}
/**
* format
* @see #translateList(String)
*/
public static String formatList(String keyRegular, Object...format) {
return tryFormat(T18nUtils.flattenList(translateList(keyRegular)), format);
}
public static boolean hasKey(String key) {
return getLanguageMapSafe().containsKey(key);
return map.containsKey(key);
}
public static boolean canTranslate(String key) {
return hasKey(key);
}
/* *******************************************************
*
* Utilities
*
* *******************************************************/
private static String reEncode(String bef, Charset charset) {
byte[] bytes = bef.getBytes();
byte[] bytes = bef.getBytes(charset);
return new String(bytes, charset);
}
@ -87,8 +93,4 @@ public class I18n {
}
}
private static LanguageMap getLanguageMapSafe() {
return map == null ? new LanguageMap() : map;
}
}

View File

@ -6,112 +6,149 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
public class LanguageMapBuilder {
/**
*
* @param langFile
* @return
*/
public static LanguageMap fromFile(File langFile) {
return fromFile(langFile, LanguageMapConfiguration.DEFAULT);
}
/**
*
* @param langFile
* @param config
* @return
*/
public static LanguageMap fromFile(File langFile, LanguageMapConfiguration config) {
List<String> lines = getLinesFromFile(langFile);
return getLanguageMapFromLines(config, lines);
}
private static List<String> getLinesFromFile(File file) {
if(file.isFile()) {
try {
return Files.readAllLines(file.toPath(), Charset.forName("UTF-8"));
} catch (Exception e) {
}
}
return new ArrayList<>();
}
private static LanguageMap getLanguageMapFromLines(LanguageMapConfiguration config, List<String> lines) {
final LanguageMap map = new LanguageMap();
for(String s : lines) {
String[] pair = getLanguageMapFromLine(config, s);
if(!isUnreadable(pair)) {
map.put(pair[0], pair[1]);
}
}
return map;
}
private static final String[] UNREADABLE = new String[] {null, null};
private static String[] getLanguageMapFromLine(LanguageMapConfiguration config, String s) {
/* Empty Line */
if(s == null || s.length() == 0) {
return UNREADABLE;
}
/* Annotation */
if(config.isAnnotation(s)) {
return UNREADABLE;
}
String[] parts = s.split(config.getSplitter(s), 2);
/* The Key is Null */
if(parts[0] == null || parts[0].length() == 0) {
return UNREADABLE;
}
/* The Value is Null */
if(parts[1] == null) {
parts[1] = "null";
}
return parts;
}
private static boolean isUnreadable(String[] s) {
return s[0] == null;
}
public static LanguageMap fromJarResource(String path) {
return fromJarResource(path, LanguageMapConfiguration.DEFAULT);
List<String> lines = T18nUtils.getLocalContent(langFile);
return processFinal(config, lines);
}
public static LanguageMap fromJarResource(String path, LanguageMapConfiguration config) {
/**
* UTF8 Jar
* @param path
* @return
*/
public static LanguageMap fromJarResource(String path) {
return fromJarResource(path, "UTF8", LanguageMapConfiguration.DEFAULT);
}
/**
* Jar
* @param path
* @param encode <code>UTF-8</code><code>GBK</code><code>Unicode</code>
* @param config
* @return
*/
public static LanguageMap fromJarResource(String path, String encode, LanguageMapConfiguration config) {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
if(is == null) {
if (is == null) {
return new LanguageMap();
}
BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName(encode)));
String cache;
List<String> strs = new ArrayList<>();
try {
while(true) {
if((cache = br.readLine()) != null) {
while (true) {
if ((cache = br.readLine()) != null) {
strs.add(cache);
} else {
break;
}
}
} catch(IOException e) {
} catch (IOException e) {
}
return getLanguageMapFromLines(config, strs);
return processFinal(config, strs);
}
/**
* 线
* @param url
* @return
*/
public static LanguageMap fromURL(String url) {
return fromURL(url, LanguageMapConfiguration.DEFAULT);
}
/**
* 线
* @param url
* @param config
* @return
*/
public static LanguageMap fromURL(String url, LanguageMapConfiguration config) {
return processFinal(config, T18nUtils.getOnlineContent(url));
}
private static final String[] UNREADABLE = new String[] { null, null };
/** 处理单行翻译 */
private static String[] process(LanguageMapConfiguration config, String s) {
/* Empty Line */
if (s == null || s.length() == 0) {
return UNREADABLE;
}
/* Annotation */
if (config.isAnnotation(s)) {
return UNREADABLE;
}
String[] parts = s.split(config.getSplitter(s), 2);
/* Part fewer than 2 */
if(parts.length < 2) {
return UNREADABLE;
}
/* The Key is Null */
if (parts[0] == null || parts[0].length() == 0) {
return UNREADABLE;
}
/* The Value is Null */
if (parts[1] == null) {
parts[1] = "null";
}
return parts;
}
private static boolean isUnreadable(String[] s) {
return s[0] == null;
}
/** 将处理的结果整合到翻译表中 */
private static LanguageMap processFinal(LanguageMapConfiguration config, List<String> lines) {
final LanguageMap map = new LanguageMap();
for (String s : lines) {
String[] pair = process(config, s);
if (!isUnreadable(pair)) {
map.put(pair[0], pair[1]);
}
}
return map;
}
}

View File

@ -2,7 +2,20 @@ package cn.glycol.t18n;
public interface LanguageMapConfiguration {
/**
* <br>
*
* @param s
* @return
*/
public String getSplitter(String s);
/**
* <br>
*
* @param s
* @return <code>true</code>
*/
public boolean isAnnotation(String s);
public static final LanguageMapConfiguration DEFAULT = new LanguageMapConfiguration() {

View File

@ -0,0 +1,42 @@
package cn.glycol.t18n;
import java.nio.charset.Charset;
import java.util.Objects;
public class T18n extends I18n {
/**
*
* @param map
*/
public static void set(LanguageMap map) {
Objects.requireNonNull(map, "map cannot be null");
I18n.map = map;
}
/**
*
* @param map
*/
public static void add(LanguageMap map) {
Objects.requireNonNull(map, "map cannot be null");
I18n.map.putAll(map);
}
/**
*
* @param charset
*/
public static void charset(Charset charset) {
Objects.requireNonNull(charset, "charset cannot be null");
I18n.charset = charset;
}
/**
*
*/
public static LanguageMap map() {
return I18n.map;
}
}

View File

@ -0,0 +1,105 @@
package cn.glycol.t18n;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
public class T18nUtils {
/** 从在线网站上读取内容 */
public static List<String> getOnlineContent(String _url) {
URL url;
try {
url = new URL(_url);
} catch(MalformedURLException e) {
e.printStackTrace();
return Collections.emptyList();
}
try {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
InputStream is = conn.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
List<String> lines = new ArrayList<String>();
String s;
while((s = br.readLine()) != null) {
lines.add(s);
}
is.close();
br.close();
return lines;
} catch (IOException e) {
e.printStackTrace();
return Collections.emptyList();
}
}
/** 从本地文件读取内容 */
public static List<String> getLocalContent(File file) {
if (file.isFile()) {
try {
return Files.readAllLines(file.toPath(), Charset.forName("UTF-8"));
} catch (Exception e) {
}
}
return new ArrayList<>();
}
/** 保存翻译表到文件 */
public static void saveLanguageMap(LanguageMap map, File file) {
Objects.requireNonNull(map);
Objects.requireNonNull(file);
try {
String content = "";
for(Entry<String, String> entries : map.entrySet()) {
content += entries.getKey() + "=" + entries.getValue() + "\n";
}
if(!file.exists()) {
file.getParentFile().mkdirs();
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
fw.write(content);
fw.close();
} catch (Exception e) {
System.err.println("Unable to write "+file);
}
}
/** 使字符串列表扁平化。 */
public static String flattenList(List<String> vlist) {
String v = "";
for(String o : vlist) {
v += o + "\n";
}
v = v.trim();
return v;
}
}