package com.marginallyclever.makelangelo;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import java.util.stream.Stream;
import org.apache.commons.io.FilenameUtils;
import com.marginallyclever.makelangelo.preferences.LanguagePreferences;
import com.marginallyclever.util.MarginallyCleverTranslationXmlFileHelper;
import com.marginallyclever.util.PreferencesHelper;
/**
* MultilingualSupport is the translation engine. You ask for a string it finds the matching string in the currently selected language.
*
* @author dan royer
* @author Peter Colapietro
* @see <a href="http://www.java-samples.com/showtutorial.php?tutorialid=152">XML and Java - Parsing XML using Java Tutorial</a>
*/
public final class Translator {
/**
* Working directory. This represents the directory where the java executable launched the jar from.
*/
public static final String WORKING_DIRECTORY = /*File.separator + */"languages"/*+File.separator*/;
/**
* The name of the preferences node containing the user's choice.
*/
private static final String LANGUAGE_KEY = "language";
/**
*
*/
private static final Preferences languagePreferenceNode = PreferencesHelper.getPreferenceNode(PreferencesHelper.MakelangeloPreferenceKey.LANGUAGE);
/**
* The default choice when nothing has been selected.
*/
private static String defaultLanguage = "English";
/**
* The current choice
*/
private static String currentLanguage;
/**
* a list of all languages and their translations strings
*/
private static final Map<String, TranslatorLanguage> languages = new HashMap<>();
/**
*
*/
static public void start() {
// find the english name of the default language.
Locale locale = Locale.getDefault();
defaultLanguage = locale.getDisplayLanguage(Locale.ENGLISH);
//System.out.println("Default language = "+defaultLanguage);
loadLanguages();
loadConfig();
if (isThisTheFirstTimeLoadingLanguageFiles()) {
LanguagePreferences.chooseLanguage();
}
}
/**
* @return true if this is the first time loading language files (probably on install)
*/
static private boolean isThisTheFirstTimeLoadingLanguageFiles() {
// Did the language file disappear? Offer the language dialog.
try {
if (doesLanguagePreferenceExist()) {
return false;
}
} catch (BackingStoreException e) {
Log.error(e.getMessage());
}
return true;
}
/**
* @return true if a preferences node exists
* @throws BackingStoreException
*/
static private boolean doesLanguagePreferenceExist() throws BackingStoreException {
if (Arrays.asList(languagePreferenceNode.keys()).contains(LANGUAGE_KEY)) {
return true;
}
return false;
}
/**
* save the user's current langauge choice
*/
static public void saveConfig() {
languagePreferenceNode.put(LANGUAGE_KEY, currentLanguage);
}
/**
* load the user's language choice
*/
static public void loadConfig() {
currentLanguage = languagePreferenceNode.get(LANGUAGE_KEY, defaultLanguage);
}
/**
* Scan folder for language files.
* @see http://stackoverflow.com/questions/1429172/how-do-i-list-the-files-inside-a-jar-file
* @throws IllegalStateException No language files found
*/
static public void loadLanguages() {
try {
// iterate and find all language files
URI uri = null;
try {
uri = Translator.class.getClassLoader().getResource(WORKING_DIRECTORY).toURI();
} catch (URISyntaxException e) {
e.printStackTrace();
}
Path myPath;
if (uri.getScheme().equals("jar")) {
FileSystem fileSystem = null;
try {
fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
} catch (IOException e) {
e.printStackTrace();
}
myPath = fileSystem.getPath(WORKING_DIRECTORY);
} else {
myPath = Paths.get(uri);
}
Stream<Path> walk = null;
try {
walk = Files.walk(myPath, 1);
} catch (IOException e) {
e.printStackTrace();
}
int found=0;
Iterator<Path> it = walk.iterator();
while( it.hasNext() ) {
Path p = it.next();
String name = p.toString();
//System.out.println("testing "+name);
//if( f.isDirectory() || f.isHidden() ) continue;
String ext = FilenameUtils.getExtension(name).toLowerCase();
if( ext.equals("xml") == false ) {
continue;
}
// found an XML file in the /languages folder. Good sign!
++found;
name = WORKING_DIRECTORY+"/"+FilenameUtils.getName(name);
//System.out.println("found: "+name);
InputStream stream = Translator.class.getClassLoader().getResourceAsStream(name);
//if( stream != null )
{
TranslatorLanguage lang = new TranslatorLanguage();
lang.loadFromInputStream(stream);
languages.put(lang.getName(), lang);
}
}
//System.out.println("total found: "+found);
if(found==0) {
throw new IllegalStateException("No translations found.");
}
} catch (IllegalStateException e) {
Log.error( e.getMessage()+". Defaulting to "+defaultLanguage+". Language folder expected to be located at "+ WORKING_DIRECTORY);
final TranslatorLanguage languageContainer = new TranslatorLanguage();
String path = MarginallyCleverTranslationXmlFileHelper.getDefaultLanguageFilePath();
System.out.println("default path requested: "+path);
URL pathFound = Translator.class.getClassLoader().getResource(path);
System.out.println("path found: "+pathFound);
try (InputStream s = pathFound.openStream()) {
languageContainer.loadFromInputStream(s);
} catch (IOException ie) {
Log.error(ie.getMessage());
}
languages.put(languageContainer.getName(), languageContainer);
}
}
/**
* @param key
* @return the translated value for key
*/
static public String get(String key) {
String value = null;
try {
value = languages.get(currentLanguage).get(key);
} catch (Exception e) {
System.out.println("Translated string missing: "+key);
e.printStackTrace();
}
return value;
}
/**
* @return the list of language names
*/
static public String[] getLanguageList() {
final String[] choices = new String[languages.keySet().size()];
final Object[] lang_keys = languages.keySet().toArray();
for (int i = 0; i < lang_keys.length; ++i) {
choices[i] = (String) lang_keys[i];
}
return choices;
}
/**
* @param currentLanguage the name of the language to make active.
*/
static public void setCurrentLanguage(String currentLanguage) {
Translator.currentLanguage = currentLanguage;
}
static public int getCurrentLanguageIndex() {
String [] set = getLanguageList();
// find the current language
for( int i=0;i<set.length; ++i) {
if( set[i].equals(Translator.currentLanguage)) return i;
}
// now try the default
for( int i=0;i<set.length; ++i) {
if( set[i].equals(Translator.defaultLanguage)) return i;
}
// failed both, return 0 for the first option.
return 0;
}
}