package de.steffomio.sockserver.I18N;
import de.steffomio.sockserver.util.PropertiesUtil;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
import org.apache.log4j.Logger;
/**
*
* @author Stefan Brinkmann <steffomio@arcor.de>
*/
public enum T {
// available locales
de_DE("de", "DE"), // <-- index[0] is default Translation
en_EN("en", "EN");
private static final Logger logger = Logger.getLogger(T.class);
// current Locale
private Locale locale = null;
// Filename prefix of I18N Files
private static String PREFIX_TRANSLATIONS_FILE = "translation";
private static String KEY_NOT_FOUND = "::Key not found!";
//current Translation
private static ResourceBundle TRANSLATION = null;
/**
*
* Use T.activateTranslation(T.anyEntry)<br />
* to load Resource of translation Data into Instance<br />
* and set field as active Translation<br /><br />
*
* To switch Translation use:<br />
* T.activateTranslation(T.anyOtherEntry);<br />
* T.translateAll();<br />
*
* @param lang
* @param country
*/
T(String lang, String country){
locale = new Locale(lang, country);
String Classpath = T.class.getPackage().getName().toString();
int i = 0;
}
/**
*
* @param translation
*/
public static void activateTranslation(T language){
language.activateTranslation();
}
/**
* loads translation Resource
*/
public void activateTranslation(){
TRANSLATION = ResourceBundle.getBundle(T.class.getPackage().getName().toString() + "." + PREFIX_TRANSLATIONS_FILE, locale);
}
/**
*
* @param
* @return T activated Language
*/
public static T setLanguage(String language){
//get all locales from T
T[] tList = T.values();
// search for available Translations
for(int i = 0; i < tList.length; i++){
if(language.equals(tList[i].toString())){
tList[i].activateTranslation();
return tList[i];
}
}
// no valid translation found
tList[0].activateTranslation();
return tList[0];
}
/**
*
* @param key
* @param args
* @return
*/
public static String t (String key, Object... args){
// catch emty things
if(key.equals("") || key == null){
return "";
}
// return translation
if(TRANSLATION.containsKey(key)){
return MessageFormat.format(TRANSLATION.getString(key), args);
}
// write missed keys to developers best friend File ;)
missedI18NKeys.put(key, "");
return key + KEY_NOT_FOUND;
}
/**
* for dev only
* contains not found I18N Keys and write them to missedI18N.properties
*/
public static void writeMissedKeys(){
missedI18NKeys.writeOnExit();
}
private static MissedI18NKeys missedI18NKeys = new MissedI18NKeys();
private static class MissedI18NKeys extends PropertiesUtil{
private String _fileName = "./missed_I18N_keys.properties";
public MissedI18NKeys(){
//loadExternalFile(_fileName, true, true);
}
/**
* try to sort and write possibly empty file with missed keys
*/
public void writeOnExit(){
try {
storePropertiesSorted(_fileName, 5, "", true);
} catch (IOException ex) {
logger.error("Can't write out missed I18N Keys.", ex);
}
}
}
}
Aber mir ist das jedoch alles zu Primitiv. So gibts z.B. keine Fallbacks und so'n bisschen extra Schnickschnack wäre auch nicht schlecht.
public class T {
private static final Logger logger = Logger.getLogger(T.class);
// current locale
private static Locs currentBundle = Locs.values()[0];
// FallBack if key was not found
public final static Locs FALL_BACK = Locs.en_EN;
// write not existing keys to file
private static KeyLogger keyLogger = new KeyLogger();
/**
* If FallBack don't has the key, the key itself will be displayed, Followed by the KEY_NOT_FOUND.<br/> You can call
* writeMissedKeys() to write out missed keys to file in workdir
*/
private static String KEY_NOT_FOUND = "::Key not found!";
/**
* handy way for direct access
* @param key
* @param args
* @return
*/
public static String t(String key, Object... args) {
return tr(key, args);
}
/**
* Use this for wrappers in your Base classes
* @param key
* @param args
* @return
*/
public static String tr(String key, Object[] args) {
// catch emty things
if (key.equals("") || key == null) {
return "";
}
// return translation
if (currentBundle.rBundle.containsKey(key)) {
return MessageFormat.format(currentBundle.rBundle.getString(key), args);
// or FallBack
} else if (FALL_BACK.rBundle.containsKey(key)) {
return MessageFormat.format(FALL_BACK.rBundle.getString(key), args);
}
// or write missed keys to developers best friend File ;)
keyLogger.put(key, "");
return key + KEY_NOT_FOUND;
}
/**
* set current used translationSet
*
* @param t
*/
public static void setLanguage(Locs t) {
currentBundle = t;
}
/**
* for dev only contains not found I18N Keys and write them to missedI18N.properties
*/
public static void writeMissedKeys() {
keyLogger.write();
}
//<editor-fold defaultstate="collapsed" desc="Subclass Locs contains provided Locales">
/**
*
*/
public enum Locs{
// available locales
en_EN("en", "EN"),
de_DE("de", "DE");
public final String lang;
public final String country;
/**
* The Package where the Recource Bundles are stored
*/
private String resourcePackagePath = "de.steffomio.sockserver.resource.translation";
/**
* contains the ResourceBundle
*/
public ResourceBundle rBundle;
// current Locale
private Locale locale;
private Locs(String l, String c){
lang = l;
country = c;
locale = new Locale(lang, country);
try {
rBundle = ResourceBundle.getBundle(resourcePackagePath, locale);
} catch (MissingResourceException ex) {
logger.fatal(ex.getMessage(), ex);
}
}
}
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="SubClass KeyLogger">
/**
*
*/
private static class KeyLogger extends PropertiesUtil {
/**
* try to sort and write possibly empty file with missed keys
*/
public void write() {
try {
storePropertiesSorted("./missed_I18N_keys.properties", 5, "", true);
} catch (IOException ex) {
logger.error("Can't write out missed I18N Keys.", ex);
}
}
}
//</editor-fold>
}
public class PropertiesUtil extends Properties {
/*
*
*/
public PropertiesUtil() {
}
/**
*
* @param prop
* @param value search string
* @return PropertiesUtil.Iteration
*/
public String[] getByValue(Properties prop, String value) {
// String array with max. possible entries
String[] preList = new String[size()];
// temp search Container
Map.Entry next;
// iterate through Property
Iterator iter = entrySet().iterator();
int found = 0;
while (iter.hasNext()) {
// map next to Entry
next = (Map.Entry) iter.next();
// check and return
if (next.getValue().equals(value)) {
preList[found] = (String) next.getKey();
found++;
}
}
// cut length of array to found Items
String[] list = new String[found];
int i = 0;
while (i < found) {
list[i] = preList[i];
i++;
}
return list;
}
/**
*
* @param path loads from <b>external</b> resources - not from inside the
* executed .jar file.<br /><br />
*
* local Path is relative to executed .jar File or assigned working Dir <br
* />like <b>dir/file.properties</b> absolute ath begins with Harddisk ID
* like C:/dir1/dir2/file.properties <br /> don't use Backslash \ for File
* seperator don't use trailing Slash for relative Paths
*
* @param overwrite overwrite existing Keys or not
*
* @param autoCreateFile creates file if not exists. Don't creates
* Directories
*
* @return instance of Properties
* @throws IOException
*/
public void loadExternalFile(String path, boolean overwriteKeys, boolean autoCreateFile) throws IOException {
Properties prop = new Properties();
File file = new File(path);
if (autoCreateFile == true && !file.isFile()) {
file.createNewFile();
}
//load File to prop
FileInputStream fis = new FileInputStream(file);
prop.load(fis);
mergeProperties(prop, overwriteKeys);
}
/**
*
* @param fullPath
* @return
* @throws IOException
*/
/**
*
* @param fullPath full qualified slashed (not dotted!) Package Path <br
* />like /com/me/application/resource/props.properties
* @param overwriteKeys overwrite existing Keys or not
*/
public void loadInternalFile(String fullPath, boolean overwriteKeys) throws IOException{
Properties prop = new Properties();
InputStream stream = PropertiesUtil.class.getResourceAsStream(fullPath);
prop.load(stream);
mergeProperties(prop, overwriteKeys);
}
/**
*
* Stores File outside of executed .jar File.<br /> For working Dir of jar
* File simply use bare Filename like <br /> myFile.properties<br /> else
* use full Paths like: <br /> String path =
* System.getProperty("user.home"); String path =
* System.getProperty("user.home") + "\\Local Settings\\ApplicationData";
* String path = System.getProperty("user.dir"); // for working dir full
* path
*
* @param prop
* @param path
* @param comment an in File Description (use \r\n for Linebreak)
* @throws IOException
*/
public void storeProperties(String path, String comment) throws IOException {
store(new FileOutputStream(path), comment);
}
/**
* same as storeProperties() but Properties are well sorted by keyName
*
* @param path
* any suitable filepath
* @param sortExtraLineBreak
* if property-key changes after String-index(n) an extra linebreak will be inserted for better owerview
* @param comment
* comment on top of File. Maybe Licens Info, usage...
* @param autoCreate
* automatically create the File if not exists
*/
public void storePropertiesSorted(String path, int sortExtraLineBreak, String comment, boolean autoCreate) throws IOException {
// read keys into array
String[] list = new String[size()];
Enumeration keys = keys();
int i = 0;
while (keys.hasMoreElements()) {
list[i++] = keys.nextElement().toString();
}
// sort keys
Arrays.sort(list);
// build file content
String out = comment;
String last = "";
String now = "";
int checkLength = sortExtraLineBreak;
for (String s : list) {
now = s.substring(0, s.length() < checkLength ? s.length() : checkLength);
if (!now.equals(last)) {
out += "\r\n";
last = now;
}
out += "\r\n" + s + "=" + this.get(s);
}
// write out file
FileUtil.writeString(path, out, autoCreate);
}
/**
* read from other Properties and write into this Instance
*
* @param source the Properties from where will be readed
* @param target the Properties to where will be written
* @param overwrite if true, existing keys of target will be overwritten
* @return
*/
public void mergeProperties(Properties source, boolean overwrite) {
Enumeration<Object> keys = source.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
if (overwrite == true) {
put(key, source.getProperty(key));
} else if (getProperty(key) == null) {
put(key, source.getProperty(key));
}
}
}
}