package org.jblooming.waf.settings;
import com.Ostermiller.util.BadDelimiterException;
import com.Ostermiller.util.CSVParser;
import com.Ostermiller.util.CSVPrinter;
import org.jblooming.PlatformRuntimeException;
import org.jblooming.tracer.Tracer;
import org.jblooming.utilities.CodeValueList;
import org.jblooming.utilities.JSP;
import org.jblooming.utilities.StringUtilities;
import org.jblooming.utilities.file.FileUtilities;
import org.jblooming.waf.html.input.Combo;
import org.jblooming.waf.view.PageState;
import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
/**
* @author Pietro Polsinelli ppolsinelli@open-lab.com
*/
public class I18n {
// edit status
public final static String EDIT_STATUS_EDIT = "EDIT";
public final static String EDIT_STATUS_READ = "READ";
public final static String EDIT_STATUS_APPEND = "APPEND";
// lenient level
public static final int LENIENT_APP_LANG = 4;
public static final int LENIENT_APP = 3;
public static final int LENIENT_LANG = 2;
public static final int LENIENT_NONE = 1;
public static SortedSet<String> supportedLanguages = new TreeSet<String>();
public static TreeMap<String, I18nEntry> codeEntries = new TreeMap();
protected static int lenient = LENIENT_APP_LANG;
private static String editStatus = EDIT_STATUS_READ;
private static Serializable i18nEditingOperatorId;
public static boolean catchUsedLabels = false;
// commands
public static final String CMD_CHANGEMODALITY = "CMD_CHMDLT";
public static final String CMD_RELOAD = "CMD_REL";
public static final String CMD_DUMP = "CMD_DU";
public static final String CMD_NEW_LANGUAGE = "CMD_NL";
public static final String CMD_STORE_LABEL = "CMD_STLBL";
public static final String CMD_NEW_ENTRY = "CMD_NEW_ENTRY";
public static final String CMD_REMOVE_LABEL = "CMDRMLBL";
public static boolean dumpNeeded = false;
public static String g(String code) {
return get(code);
}
/**
* @param code
* @return the label related to the "code". Can be exact or the most similar in relation to the lenient level
*/
public static String get(String code) {
if (JSP.ex(code)) {
PageState pageState = PageState.getCurrentPageState();
Locale loc;
String opid = "";
if (pageState != null) {
loc = pageState.sessionState.getLocale();
opid = pageState.sessionState.getOpid() + "";
} else {
loc = ApplicationState.SYSTEM_LOCALE;
}
String language = loc.getLanguage().toUpperCase();
String application = ApplicationState.platformConfiguration.defaultApplication.getName();
I18nEntry i18nEntry = I18n.codeEntries.get(code);
String label = null;
if (i18nEntry != null && !i18nEntry.isSuspect()) // the suspected one are omitted
label = i18nEntry.getLabel(application, language);
// handling for "append" mode
if (label == null && EDIT_STATUS_APPEND.equals(I18n.getEditStatus())) {
I18nEntry i18ne = I18n.addEntry(code, application, language, "missing_" + code);
i18ne.setSuspect(true);
}
if (label == null)
label = code;
// EDIT MODE HANDLING && EDITING OPERATOR ONLY
if (EDIT_STATUS_EDIT.equals(I18n.editStatus) && (opid).equals(I18n.getI18nEditingOperatorId())) {
label = "<span i18n=" + code + ">" + label + "</span>";
}
return label;
} else
return "";
}
/**
* all the occurrences of '%%' in the i18nzation of rootToLocalize will be replaced by param
*/
public static String get(String rootToLocalize, String... params) {
String translation = get(rootToLocalize);
return StringUtilities.replaceParameters(translation, params);
}
public static String getLabel(String code, String language) {
return I18n.getLabel(code, ApplicationState.platformConfiguration.defaultApplication.getName(), language);
}
public static String getLabel(String code, String application, String language) {
// transform two part language as en_GB to EN only
if (language.indexOf("_") > 1)
language = language.substring(0, language.indexOf("_"));
String label = null;
I18nEntry i18nEntry = I18n.codeEntries.get(code);
if (i18nEntry != null)
label = i18nEntry.getLabel(application, language.toUpperCase());
if (label == null)
label = code;
return label;
}
/**
* @param code
* @param code
* @param language
* @return the exact matching label. null if not found
*/
public static String getRawLabel(String code, String application, String language) {
I18nEntry i18nEntry = I18n.codeEntries.get(code);
String label = null;
if (i18nEntry != null) {
ApplicationEntry applicationEntry = i18nEntry.applicationEntries.get(application);
if (applicationEntry != null) {
label = applicationEntry.entries.get(language);
}
}
return label;
}
public static SortedMap<String, I18nEntry> getEntriesForApplication(String applicationName) {
TreeMap<String, I18nEntry> efa = new TreeMap();
for (String code : codeEntries.keySet()) {
final I18nEntry i18nEntry = codeEntries.get(code);
final ApplicationEntry applicationEntry = (ApplicationEntry) i18nEntry.applicationEntries.get(applicationName);
if (applicationEntry != null)
efa.put(code, i18nEntry);
}
return efa;
}
public static I18nEntry addEntry(String code, String application, String language, String value) {
I18n.supportedLanguages.add(language.toUpperCase());
I18nEntry ie = I18n.codeEntries.get(code);
if (ie == null) {
ie = new I18nEntry(code, application, language, value);
} else {
ApplicationEntry ae = ie.applicationEntries.get(application);
if (ae == null)
ae = new ApplicationEntry(application);
ie.applicationEntries.put(application, ae);
ae.addEntry(language, value);
}
I18n.codeEntries.put(code, ie);
return ie;
}
public static void removeEntry(String code, String application, String language) {
if (I18n.getRawLabel(code, application, language) != null) {
I18nEntry i18nEntry = I18n.codeEntries.get(code);
ApplicationEntry ae = i18nEntry.applicationEntries.get(application);
ae.entries.remove(language);
if (ae.entries.size() <= 0)
i18nEntry.applicationEntries.remove(application);
if (i18nEntry.applicationEntries.size() <= 0)
I18n.codeEntries.remove(code);
}
}
public static void persistI18nByApplicationAndLanguage(Application application, File file) throws IOException {
final String applicationName = application != null ? application.getName() : "";
SortedMap i18nEntriesForApplication = I18n.getEntriesForApplication(applicationName);
for (String language : I18n.supportedLanguages) {
File fileForLang = new File(FileUtilities.getNameWithoutExt(file.getPath()) + "." + language + ".i18n");
fileForLang.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(fileForLang);
Charset charset = Charset.forName("UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(fos, charset);
CSVPrinter cvsp = new CSVPrinter(osw);
try {
cvsp.changeDelimiter('\t');
} catch (BadDelimiterException e) {
throw new PlatformRuntimeException(e);
}
if (i18nEntriesForApplication != null && i18nEntriesForApplication.size() > 0) {
for (Iterator iterator = i18nEntriesForApplication.keySet().iterator(); iterator.hasNext();) {
String code = (String) iterator.next();
I18nEntry ie = (I18nEntry) i18nEntriesForApplication.get(code);
ApplicationEntry ae = (ApplicationEntry) ie.applicationEntries.get(applicationName);
if (ae != null) {
String value = (String) ae.entries.get(language);
if (value != null) {
cvsp.print(applicationName);
cvsp.print(ie.getCode());
cvsp.print(language);
cvsp.println(value);
}
}
}
}
osw.close();
fos.close();
}
}
public static void loadI18n(File file) throws IOException {
FileInputStream fos = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fos, Charset.forName("UTF-8"));
CSVParser cvsr = new CSVParser(isr);
try {
cvsr.changeDelimiter('\t');
cvsr.setEscapes("nrf", "\n\r\f");
} catch (BadDelimiterException e) {
throw new PlatformRuntimeException(e);
}
String enabledLang=ApplicationState.applicationSettings.get("ENABLED_LANGUAGES");
if (JSP.ex(enabledLang))
enabledLang=enabledLang.toUpperCase();
String values[][] = cvsr.getAllValues();
if (values != null) {
for (int i = 0; i < values.length; i++) {
String[] value = values[i];
if (value == null)
Tracer.platformLogger.warn("open lab platform - empty row " + i + " for file " + file.getName());
else if (value.length != 4)
Tracer.platformLogger.warn("open lab platform - incomplete row " + i + ": " + JSP.arrayToString(value, " , ") + " for file " + file.getName());
else {
// check if language is enabled
if (JSP.ex(enabledLang)){
if (enabledLang.contains(value[2].toUpperCase()))
I18n.addEntry(value[1], value[0], value[2].toUpperCase(), value[3]);
} else {
I18n.addEntry(value[1], value[0], value[2].toUpperCase(), value[3]);
}
}
}
}
isr.close();
fos.close();
}
public static String getEditStatus() {
return I18n.editStatus;
}
public static void setEditStatus(String editStatus) {
I18n.editStatus = editStatus;
}
public static int getLenient() {
return I18n.lenient;
}
public void setLenient(int lenient) {
I18n.lenient = lenient;
}
public static void loadI18n(Application application) throws IOException {
String i18nPath = application.getRootFolder() + File.separator + "settings" + File.separator + "i18n";
String root = ApplicationState.webAppFileSystemRootPath;
final String path = root + File.separator + i18nPath;
File i18nFolder = new File(path);
if (i18nFolder.exists()) {
if (!i18nFolder.isDirectory())
throw new PlatformRuntimeException(path + " must be directory");
File[] files = i18nFolder.listFiles();
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.getName().toLowerCase().endsWith(".i18n"))
I18n.loadI18n(file);
}
Tracer.platformLogger.info("open lab platform - " + application.getName().toLowerCase() + " i18n settings loaded ok");
}
}
public static Serializable getI18nEditingOperatorId() {
return I18n.i18nEditingOperatorId;
}
public void setI18nEditingOperatorId(Serializable i18nEditingOperatorId) {
I18n.i18nEditingOperatorId = i18nEditingOperatorId;
}
/**
* @param selectLang is
*/
public static Locale getLocale(String selectLang) {
Locale ret = Locale.UK;
if (JSP.ex(selectLang)) { //
try {
if (selectLang.indexOf("_") != -1) {
String[] l = selectLang.split("_");
ret = new Locale(l[0], l[1]);
} else {
if ("en".equalsIgnoreCase(selectLang))
ret = Locale.US;
else if ("zh".equalsIgnoreCase(selectLang))
ret = Locale.CHINA;
else if ("br".equalsIgnoreCase(selectLang))
ret = new Locale("pt", "BR");
else
ret = new Locale(selectLang.toLowerCase(), selectLang.toUpperCase());
}
} catch (Throwable e) {
Tracer.platformLogger.error("Invalid lang properties:" + selectLang);
}
} else {
Tracer.platformLogger.error("Invalid lang properties:" + selectLang);
}
return ret;
}
/**
*
*/
public static class I18nEntry {
public String code;
private boolean suspect = false;
private boolean seen = false;
public Map<String, ApplicationEntry> applicationEntries = new TreeMap<String, ApplicationEntry>();
protected I18nEntry(String code, String application, String language, String value) {
ApplicationEntry ae = applicationEntries.get(application);
this.code = code;
if (ae == null)
ae = new ApplicationEntry(application);
ae.addEntry(language, value);
applicationEntries.put(application, ae);
}
protected ApplicationEntry getApplicationEntry(String application) {
ApplicationEntry ret = null;
String defaultApplication = Application.PLATFORM_APP_NAME;
if (application == null) {
application = defaultApplication;
}
ret = applicationEntries.get(application);
if (ret == null) {
if (lenient == LENIENT_APP || lenient == LENIENT_APP_LANG) {
ret = ret = applicationEntries.get(defaultApplication);
if (ret == null) {
if (applicationEntries.size() > 0)
ret = applicationEntries.get(applicationEntries.keySet().iterator().next());
}
} else {
ret = new ApplicationEntry(application);
}
}
return ret;
}
public String getLabel(String application, String language) {
if (I18n.catchUsedLabels)
setSeen(true);
return getApplicationEntry(application).getLabel(language);
}
public boolean matches(String textToFind) {
return matches(textToFind, null);
}
public boolean matches(String textToFind, Set<String> languages) {
boolean match = false;
if (!JSP.ex(languages))
languages = supportedLanguages;
if (code.toLowerCase().indexOf(textToFind.toLowerCase()) >= 0) {
match = true;
} else {
for (Iterator<ApplicationEntry> iterator = applicationEntries.values().iterator(); iterator.hasNext() && !match;) {
ApplicationEntry ae = iterator.next();
match = ae.matches(textToFind, languages);
}
}
return match;
}
public boolean isSuspect() {
return suspect;
}
public void setSuspect(boolean suspect) {
this.suspect = suspect;
}
public boolean isSeen() {
return seen;
}
public void setSeen(boolean seen) {
this.seen = seen;
}
public String getCode() {
return code;
}
}
/**
*
*/
public static class ApplicationEntry {
public String applicationName;
public ApplicationEntry(String applicationName) {
this.applicationName = applicationName;
}
public Map<String, String> entries = new TreeMap();
protected void addEntry(String lang, String value) {
entries.put(lang, value);
}
protected String getLabel(String language) {
String ret = null;
String defaultLanguage = ApplicationState.SYSTEM_LOCALE.getLanguage();
if (defaultLanguage != null) {
defaultLanguage = defaultLanguage.toUpperCase();
if (defaultLanguage.indexOf("_") > 1)
defaultLanguage = defaultLanguage.substring(0, defaultLanguage.indexOf("_"));
}
if (language == null) {
language = defaultLanguage;
}
language = language.toUpperCase();
ret = entries.get(language);
if (ret == null && (lenient == LENIENT_LANG || lenient == LENIENT_APP_LANG)) {
if (defaultLanguage != null)
ret = entries.get(defaultLanguage);
if (ret == null)
ret = entries.get("EN");
if (ret == null) {
if (entries.size() > 0)
ret = entries.get(entries.keySet().iterator().next());
}
}
return ret;
}
public boolean matches(String textToFind) {
return matches(textToFind, null);
}
public boolean matches(String textToFind, Set<String> languages) {
boolean match = false;
if (!JSP.ex(languages))
languages = supportedLanguages;
textToFind = textToFind.toLowerCase();
/*for (Iterator<String> iterator = entries.values().iterator(); iterator.hasNext() && !match;) {
String label = iterator.next();
match = label.toLowerCase().indexOf(textToFind) >= 0 ;
}*/
for (String lang : languages) {
String label = getLabel(lang);
match = label.toLowerCase().indexOf(textToFind) >= 0;
if (match)
break;
}
return match;
}
}
public static Combo getLocaleCombo(String fieldName, PageState pageState) {
Set<String> supportedLanguages = I18n.supportedLanguages;
String enabledLang=ApplicationState.applicationSettings.get("ENABLED_LANGUAGES");
CodeValueList cvl = new CodeValueList();
for (String lang : supportedLanguages) {
// check if language is enabled
if (JSP.ex(enabledLang)){
if (enabledLang.contains(lang.toUpperCase()))
cvl.add(lang, I18n.get(lang));
} else
cvl.add(lang, I18n.get(lang));
}
if (supportedLanguages.contains("EN"))
cvl.add(Locale.UK + "", I18n.get(Locale.UK + ""));
Combo cb = new Combo(I18n.get("SELECT_LANGUAGE_AND_LOCALE"), fieldName, "</td><td>", null, 30, null, cvl, "");
return cb;
}
}