mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
created separate branch for refactoring
This commit is contained in:
@@ -22,47 +22,56 @@
|
|||||||
package processing.app;
|
package processing.app;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import processing.core.PApplet;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internationalization (i18n)
|
* Internationalization (i18n)
|
||||||
* @author Darius Morawiec
|
* @author Darius Morawiec
|
||||||
*/
|
*/
|
||||||
public class Language {
|
public class Language {
|
||||||
static private final String FILE = "processing.app.languages.PDE";
|
|
||||||
//static private final String LISTING = "processing/app/languages/languages.txt";
|
|
||||||
|
|
||||||
// Store the language information in a file separate from the preferences,
|
/**
|
||||||
// because preferences need the language on load time.
|
* Store the language information in a file separate from the preferences,
|
||||||
static protected final String PREF_FILE = "language.txt";
|
* because preferences need the language on load time.
|
||||||
static protected final File prefFile = Base.getSettingsFile(PREF_FILE);
|
*/
|
||||||
|
static private final String LANG_FILE = "language.properties";
|
||||||
|
|
||||||
|
/** Directory of available languages */
|
||||||
|
static private final String LANG_FILES = "languages";
|
||||||
|
|
||||||
|
/** Definition of package for fallback */
|
||||||
|
static private final String LANG_PACKAGE = "processing.app.languages";
|
||||||
|
static private final String LANG_BASE_NAME = "PDE";
|
||||||
|
|
||||||
|
static private Properties props;
|
||||||
|
static private File propsFile;
|
||||||
|
|
||||||
|
/** Language */
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
/** Available languages */
|
||||||
|
private HashMap<String, String> languages;
|
||||||
|
|
||||||
|
/** Define the location of language files */
|
||||||
|
static private File langFiles = Base.getSettingsFile(LANG_FILES);
|
||||||
|
|
||||||
|
/** Set version of current PDE */
|
||||||
|
static private final String version = Base.getVersionName();
|
||||||
|
static private ResourceBundle bundle;
|
||||||
|
|
||||||
/** Single instance of this Language class */
|
/** Single instance of this Language class */
|
||||||
static private volatile Language instance;
|
static private volatile Language instance;
|
||||||
|
|
||||||
/** The system language */
|
|
||||||
private String language;
|
|
||||||
|
|
||||||
/** Available languages */
|
|
||||||
private HashMap<String, String> languages;
|
|
||||||
|
|
||||||
private ResourceBundle bundle;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Language() {
|
private Language() {
|
||||||
String systemLanguage = Locale.getDefault().getLanguage();
|
|
||||||
language = loadLanguage();
|
|
||||||
boolean writePrefs = false;
|
|
||||||
|
|
||||||
if (language == null) {
|
// Set default language
|
||||||
language = systemLanguage;
|
language = "en";
|
||||||
writePrefs = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set available languages
|
// Set available languages
|
||||||
languages = new HashMap<String, String>();
|
languages = new HashMap<String, String>();
|
||||||
@@ -70,20 +79,85 @@ public class Language {
|
|||||||
languages.put(code, Locale.forLanguageTag(code).getDisplayLanguage(Locale.forLanguageTag(code)));
|
languages.put(code, Locale.forLanguageTag(code).getDisplayLanguage(Locale.forLanguageTag(code)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default language
|
if(loadProps()){
|
||||||
if (!languages.containsKey(language)) {
|
|
||||||
language = "en";
|
|
||||||
writePrefs = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writePrefs) {
|
boolean updateProps = false;
|
||||||
saveLanguage(language);
|
boolean updateLangFiles = false;
|
||||||
|
|
||||||
|
// Define and check version
|
||||||
|
if(props.containsKey("version") && langFiles.exists()){
|
||||||
|
if(!props.getProperty("version").equals(version)){
|
||||||
|
updateLangFiles = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
updateLangFiles = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy new language properties
|
||||||
|
if(updateLangFiles){
|
||||||
|
if(updateLangFiles()){
|
||||||
|
props.setProperty("version", version);
|
||||||
|
updateProps = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define language
|
||||||
|
if(props.containsKey("language")){
|
||||||
|
language = props.getProperty("language");
|
||||||
|
} else {
|
||||||
|
if (!languages.containsKey(Locale.getDefault().getLanguage())) {
|
||||||
|
language = Locale.getDefault().getLanguage();
|
||||||
|
}
|
||||||
|
props.setProperty("language", language);
|
||||||
|
updateProps = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save changes
|
||||||
|
if(updateProps){
|
||||||
|
updateProps();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL[] paths = { langFiles.toURI().toURL() };
|
||||||
|
bundle = ResourceBundle.getBundle(
|
||||||
|
Language.LANG_BASE_NAME,
|
||||||
|
new Locale(language),
|
||||||
|
new URLClassLoader(paths),
|
||||||
|
new UTF8Control()
|
||||||
|
);
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
// Fallback: Does we need a fallback?
|
||||||
|
// bundle = ResourceBundle.getBundle(
|
||||||
|
// Language.LANG_PACKAGE+"."+Language.LANG_BASE_NAME,
|
||||||
|
// new Locale(this.language),
|
||||||
|
// new UTF8Control()
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get bundle with translations (processing.app.language.PDE)
|
|
||||||
bundle = ResourceBundle.getBundle(Language.FILE, new Locale(this.language), new UTF8Control());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean updateLangFiles() {
|
||||||
|
// Delete old languages
|
||||||
|
if(langFiles.exists()){
|
||||||
|
File[] lang = langFiles.listFiles();
|
||||||
|
for (int i = 0; i < lang.length; i++) {
|
||||||
|
lang[i].delete();
|
||||||
|
}
|
||||||
|
langFiles.delete();
|
||||||
|
}
|
||||||
|
// Copy new languages
|
||||||
|
String javaPath = new File(Base.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getParentFile().getAbsolutePath();
|
||||||
|
try {
|
||||||
|
copyDirectory(
|
||||||
|
new File(javaPath+"/lib/languages"), // from shared library
|
||||||
|
Base.getSettingsFile("languages") // to editable library location
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static private String[] listSupported() {
|
static private String[] listSupported() {
|
||||||
// List of languages in alphabetical order. (Add yours here.)
|
// List of languages in alphabetical order. (Add yours here.)
|
||||||
@@ -101,6 +175,8 @@ public class Language {
|
|||||||
"tr", // Turkish
|
"tr", // Turkish
|
||||||
"zh" // chinese
|
"zh" // chinese
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Arrays.sort(SUPPORTED);
|
||||||
return SUPPORTED;
|
return SUPPORTED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -120,38 +196,71 @@ public class Language {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Load properties of language.properties */
|
||||||
/** Read the saved language */
|
static private boolean loadProps(){
|
||||||
static private String loadLanguage() {
|
if (props == null) {
|
||||||
try {
|
props = new Properties();
|
||||||
if (prefFile.exists()) {
|
|
||||||
String language = PApplet.loadStrings(prefFile)[0];
|
|
||||||
language = language.trim().toLowerCase();
|
|
||||||
if (!language.equals("")) {
|
|
||||||
return language;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
return null;
|
propsFile = Base.getSettingsFile(LANG_FILE);
|
||||||
|
if(!propsFile.exists()){
|
||||||
|
try {
|
||||||
|
Base.saveFile("", propsFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InputStream is = null;
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(propsFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
props.load(is);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Save changes in language.properties */
|
||||||
|
static private boolean updateProps(){
|
||||||
|
if (props != null) {
|
||||||
|
try {
|
||||||
|
OutputStream out = new FileOutputStream(propsFile);
|
||||||
|
props.store(out, "language preferences");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save the language directly to a settings file. This is 'save' and not
|
* Save the language directly to a settings file. This is 'save' and not
|
||||||
* 'set' because a language change requires a restart of Processing.
|
* 'set' because a language change requires a restart of Processing.
|
||||||
*/
|
*/
|
||||||
static public void saveLanguage(String language) {
|
static public void saveLanguage(String language) {
|
||||||
try {
|
if (loadProps()) {
|
||||||
Base.saveFile(language, prefFile);
|
props.setProperty("language", language);
|
||||||
} catch (Exception e) {
|
if (updateProps()) {
|
||||||
e.printStackTrace();
|
Base.getPlatform().saveLanguage(language);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Base.getPlatform().saveLanguage(language);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Singleton constructor */
|
/** Singleton constructor */
|
||||||
static public Language init() {
|
static public Language init() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
@@ -164,24 +273,27 @@ public class Language {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Get translation from bundles. */
|
/** Get translation from bundles. */
|
||||||
static public String text(String text) {
|
static public String text(String text) {
|
||||||
ResourceBundle bundle = init().bundle;
|
ResourceBundle bundle = init().bundle;
|
||||||
|
// System.out.println(prefDir.toString());
|
||||||
|
// try {
|
||||||
|
// System.out.println(prefDir.toURI().toURL().toString());
|
||||||
|
// } catch (MalformedURLException e1) {
|
||||||
|
// // TODO Auto-generated catch block
|
||||||
|
// e1.printStackTrace();
|
||||||
|
// }
|
||||||
try {
|
try {
|
||||||
return bundle.getString(text);
|
return bundle.getString(text);
|
||||||
} catch (MissingResourceException e) {
|
} catch (MissingResourceException e) {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static public String interpolate(String text, Object... arguments) {
|
static public String interpolate(String text, Object... arguments) {
|
||||||
return String.format(init().bundle.getString(text), arguments);
|
return String.format(init().bundle.getString(text), arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static public String pluralize(String text, int count) {
|
static public String pluralize(String text, int count) {
|
||||||
ResourceBundle bundle = init().bundle;
|
ResourceBundle bundle = init().bundle;
|
||||||
|
|
||||||
@@ -192,38 +304,53 @@ public class Language {
|
|||||||
}
|
}
|
||||||
return interpolate(String.format(fmt, "n"), count);
|
return interpolate(String.format(fmt, "n"), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Get all available languages */
|
/** Get all available languages */
|
||||||
static public Map<String, String> getLanguages() {
|
static public Map<String, String> getLanguages() {
|
||||||
return init().languages;
|
return init().languages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Get current language */
|
/** Get current language */
|
||||||
static public String getLanguage() {
|
static public String getLanguage() {
|
||||||
return init().language;
|
return init().language;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy files without dependencies (Java >= 7)
|
||||||
// /** Set new language (called by Preferences) */
|
// http://stackoverflow.com/a/5368745/1293700
|
||||||
// static public void setLanguage(String language) {
|
static private void copy(File sourceLocation, File targetLocation)
|
||||||
// this.language = language;
|
throws IOException {
|
||||||
//
|
if (sourceLocation.isDirectory()) {
|
||||||
// try {
|
copyDirectory(sourceLocation, targetLocation);
|
||||||
// File file = Base.getContentFile("lib/language.txt");
|
} else {
|
||||||
// Base.saveFile(language, file);
|
copyFile(sourceLocation, targetLocation);
|
||||||
// } catch (Exception e) {
|
}
|
||||||
// e.printStackTrace();
|
}
|
||||||
// }
|
static private void copyDirectory(File source, File target)
|
||||||
// }
|
throws IOException {
|
||||||
|
if (!target.exists()) {
|
||||||
|
target.mkdir();
|
||||||
|
}
|
||||||
|
for (String f : source.list()) {
|
||||||
|
copy(new File(source, f), new File(target, f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static private void copyFile(File source, File target) throws IOException {
|
||||||
|
try (InputStream in = new FileInputStream(source);
|
||||||
|
OutputStream out = new FileOutputStream(target)) {
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int length;
|
||||||
|
while ((length = in.read(buf)) > 0) {
|
||||||
|
out.write(buf, 0, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom 'Control' class for consistent encoding.
|
* Custom 'Control' class for consistent encoding.
|
||||||
* http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle
|
* http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle
|
||||||
*/
|
*/
|
||||||
static class UTF8Control extends ResourceBundle.Control {
|
|
||||||
|
static private class UTF8Control extends ResourceBundle.Control {
|
||||||
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException,IOException {
|
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException,IOException {
|
||||||
// The below is a copy of the default implementation.
|
// The below is a copy of the default implementation.
|
||||||
String bundleName = toBundleName(baseName, locale);
|
String bundleName = toBundleName(baseName, locale);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
Reference in New Issue
Block a user