- it can delete a contact
- it can be used to edit your data (currently in RAW format, field by field)
- it can save back to file
+- English and French versions available (will look for the host language, can be forced with "--lang en")
## TODO
- ".properties" files to easily change the colours
- correct EDIT support
- customisation of VIEW_CONTACT
-- French translation to check if everything is translatable
- lot of other things
--- /dev/null
+package be.nikiroo.jvcard.i18n;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Locale;
+import java.util.PropertyResourceBundle;
+import java.util.ResourceBundle;
+import java.util.ResourceBundle.Control;
+
+public class FixedResourceBundleControl extends Control {
+ 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.
+ String bundleName = toBundleName(baseName, locale);
+ String resourceName = toResourceName(bundleName, "properties");
+ ResourceBundle bundle = null;
+ InputStream stream = null;
+ if (reload) {
+ URL url = loader.getResource(resourceName);
+ if (url != null) {
+ URLConnection connection = url.openConnection();
+ if (connection != null) {
+ connection.setUseCaches(false);
+ stream = connection.getInputStream();
+ }
+ }
+ } else {
+ stream = loader.getResourceAsStream(resourceName);
+ }
+ if (stream != null) {
+ try {
+ // Only this line is changed to make it to read properties files
+ // as UTF-8.
+ // How can someone use an archaic encoding such as ISO 8859-1 by
+ // *DEFAULT* is beyond me...
+ bundle = new PropertyResourceBundle(new InputStreamReader(
+ stream, "UTF-8"));
+ } finally {
+ stream.close();
+ }
+ }
+ return bundle;
+ }
+}
\ No newline at end of file
package be.nikiroo.jvcard.i18n;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.googlecode.lanterna.input.KeyStroke;
+import java.util.Locale;
+import java.util.ResourceBundle;
import be.nikiroo.jvcard.tui.UiColors;
+import com.googlecode.lanterna.input.KeyStroke;
+
/**
* This class manages the translation of {@link Trans#StringId}s into
* user-understandable text.
*
*/
public class Trans {
- static private Object lock = new Object();
- static private Trans instance = null;
-
- private Map<StringId, String> map = null;
+ ResourceBundle map;
/**
* An enum representing information to be translated to the user.
*/
public enum StringId {
DUMMY, // <-- TODO : remove
+ KEY_TAB, KEY_ENTER, // keys
KEY_ACTION_BACK, KEY_ACTION_HELP, // MainWindow
KEY_ACTION_VIEW_CARD, // FileList
KEY_ACTION_VIEW_CONTACT, KEY_ACTION_EDIT_CONTACT, KEY_ACTION_SAVE_CARD, KEY_ACTION_DELETE_CONTACT, KEY_ACTION_SEARCH, // ContactList
KEY_ACTION_INVERT, KEY_ACTION_FULLSCREEN, // ContactDetails
KEY_ACTION_SWITCH_FORMAT, // multi-usage
NULL; // Special usage
-
- public String trans() {
- return Trans.getInstance().trans(this);
- }
};
/**
- * Get the (unique) instance of this class.
- *
- * @return the (unique) instance
+ * Create a translation service with the default language.
*/
- static public Trans getInstance() {
- synchronized (lock) {
- if (instance == null)
- instance = new Trans();
- }
+ public Trans() {
+ init(null);
+ }
- return instance;
+ /**
+ * Create a translation service for the given language. (Will fall back to
+ * the default one i not found.)
+ *
+ * @param language
+ * the language to use
+ */
+ public Trans(String language) {
+ init(language);
}
/**
}
}
- if (map.containsKey(id)) {
- return map.get(id);
+ if (id == StringId.NULL) {
+ return "";
+ }
+
+ if (id == StringId.DUMMY) {
+ return "[dummy]";
+ }
+
+ if (map.containsKey(id.toString())) {
+ return map.getString(id.toString());
}
return id.toString();
if (UiColors.getInstance().isUnicode())
keyTrans = " ⤶ ";
else
- keyTrans = "ENT";
+ keyTrans = trans(StringId.KEY_ENTER);
break;
case Tab:
if (UiColors.getInstance().isUnicode())
keyTrans = " ↹ ";
else
- keyTrans = "TAB";
+ keyTrans = trans(StringId.KEY_TAB);
break;
case Character:
return keyTrans;
}
- private Trans() {
- map = new HashMap<StringId, String>();
-
- // TODO: get from a file instead?
- map.put(StringId.NULL, "");
- map.put(StringId.DUMMY, "[dummy]");
- // we could use: " ", "┃", "│"...
- map.put(StringId.DEAULT_FIELD_SEPARATOR, "┃");
- map.put(StringId.DEAULT_FIELD_SEPARATOR_NOUTF, "|");
- map.put(StringId.KEY_ACTION_BACK, "Back");
- map.put(StringId.KEY_ACTION_HELP, "Help");
- map.put(StringId.KEY_ACTION_VIEW_CONTACT, "Open");
- map.put(StringId.KEY_ACTION_VIEW_CARD, "Open");
- map.put(StringId.KEY_ACTION_EDIT_CONTACT, "Edit");
- map.put(StringId.KEY_ACTION_DELETE_CONTACT, "Delete");
- map.put(StringId.KEY_ACTION_SWITCH_FORMAT, "Change view");
- map.put(StringId.KEY_ACTION_INVERT, "Invert colours");
- map.put(StringId.KEY_ACTION_FULLSCREEN, "Fullscreen");
- map.put(StringId.KEY_ACTION_SEARCH, "Search");
+ /**
+ * Initialise the translation mappings for the given language.
+ *
+ * @param lang
+ * the language to initialise
+ */
+ private void init(String lang) {
+ Locale locale = null;
+
+ if (lang == null) {
+ locale = Locale.getDefault();
+ } else {
+ locale = Locale.forLanguageTag(lang);
+ }
+
+ map = ResourceBundle.getBundle(Trans.class.getPackage().getName()
+ + ".resources", locale, new FixedResourceBundleControl());
}
}
--- /dev/null
+# English translation file (UTF-8)
+
+# those 2 keys MUST be 3-characters long
+KEY_TAB = TAB
+KEY_ENTER = ENT
+# we could use: " ", ┃, │...
+DEAULT_FIELD_SEPARATOR = ┃
+DEAULT_FIELD_SEPARATOR_NOUTF = |
+KEY_ACTION_BACK = Back
+KEY_ACTION_HELP = Help
+KEY_ACTION_VIEW_CONTACT = Open
+KEY_ACTION_VIEW_CARD = Open
+KEY_ACTION_EDIT_CONTACT = Edit
+KEY_ACTION_DELETE_CONTACT = Delete
+KEY_ACTION_SWITCH_FORMAT = Change view
+KEY_ACTION_INVERT = Invert colours
+KEY_ACTION_FULLSCREEN = Fullscreen
+KEY_ACTION_SEARCH = Search
--- /dev/null
+# default translation file (UTF-8)
+
+# those 2 keys MUST be 3-characters long
+KEY_TAB = TAB
+KEY_ENTER = ENT
+# we could use: " ", ┃, │...
+DEAULT_FIELD_SEPARATOR = ┃
+DEAULT_FIELD_SEPARATOR_NOUTF = |
+KEY_ACTION_BACK = Back
+KEY_ACTION_HELP = Help
+KEY_ACTION_VIEW_CONTACT = Open
+KEY_ACTION_VIEW_CARD = Open
+KEY_ACTION_EDIT_CONTACT = Edit
+KEY_ACTION_DELETE_CONTACT = Delete
+KEY_ACTION_SWITCH_FORMAT = Change view
+KEY_ACTION_INVERT = Invert colours
+KEY_ACTION_FULLSCREEN = Fullscreen
+KEY_ACTION_SEARCH = Search
--- /dev/null
+# French translation file (UTF-8)
+
+# les deux touches qui suivent DOIVENT faire 3 caractères de long
+KEY_TAB = TAB
+KEY_ENTER = ENT
+# autres options: " ", ┃, │...
+DEAULT_FIELD_SEPARATOR = ┃
+DEAULT_FIELD_SEPARATOR_NOUTF = |
+KEY_ACTION_BACK = Retour
+KEY_ACTION_HELP = Aide
+KEY_ACTION_VIEW_CONTACT = Afficher
+KEY_ACTION_VIEW_CARD = Ouvrir
+KEY_ACTION_EDIT_CONTACT = Éditer
+KEY_ACTION_DELETE_CONTACT = Supprimer
+KEY_ACTION_SWITCH_FORMAT = Autre affichage
+KEY_ACTION_INVERT = Couleurs inversées
+KEY_ACTION_FULLSCREEN = Plein écran
+KEY_ACTION_SEARCH = Rechercher
import java.util.LinkedList;
import java.util.List;
+import be.nikiroo.jvcard.i18n.Trans;
+import be.nikiroo.jvcard.i18n.Trans.StringId;
import be.nikiroo.jvcard.tui.panes.FileList;
import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
import com.googlecode.lanterna.gui2.Window;
import com.googlecode.lanterna.gui2.table.Table;
+import com.googlecode.lanterna.input.KeyStroke;
import com.googlecode.lanterna.screen.Screen;
import com.googlecode.lanterna.screen.TerminalScreen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
public static final String APPLICATION_TITLE = "jVcard";
public static final String APPLICATION_VERSION = "1.0-beta1-dev";
+ static private Trans transService;
+
+ /**
+ * Translate the given {@link StringId}.
+ *
+ * @param id
+ * the ID to translate
+ *
+ * @return the translation
+ */
+ static public String trans(StringId id) {
+
+ if (transService == null)
+ return "";
+
+ return transService.trans(id);
+ }
+
+ /**
+ * Translate the given {@link KeyStroke}.
+ *
+ * @param key
+ * the key to translate
+ *
+ * @return the translation
+ */
+ static public String trans(KeyStroke key) {
+ if (transService == null)
+ return "";
+
+ return transService.trans(key);
+ }
+
+ /**
+ * Start the application.
+ *
+ * @param args
+ * the parameters (see --help to know hich are supported)
+ */
public static void main(String[] args) {
Boolean textMode = null;
boolean noMoreParams = false;
boolean filesTried = false;
+ // get the "system default" language to help translate the --help
+ // message if needed
+ String language = null;
+ transService = new Trans(null);
+
List<File> files = new LinkedList<File>();
- for (String arg : args) {
+ for (int index = 0; index < args.length; index++) {
+ String arg = args[index];
if (!noMoreParams && arg.equals("--")) {
noMoreParams = true;
} else if (!noMoreParams && arg.equals("--help")) {
+ "Usable switches:\n"
+ "\t--: stop looking for switches\n"
+ "\t--help: this here thingy\n"
+ + "\t--lang LANGUAGE: choose the language, for instance en_GB\n"
+ "\t--tui: force pure text mode even if swing treminal is available\n"
+ "\t--gui: force swing terminal mode\n"
+ "\t--noutf: force non-utf8 mode if you need it\n"
textMode = false;
} else if (!noMoreParams && arg.equals("--noutf")) {
UiColors.getInstance().setUnicode(false);
+ } else if (!noMoreParams && arg.equals("--lang")) {
+ index++;
+ if (index < args.length)
+ language = args[index];
+ transService = new Trans(language);
} else {
filesTried = true;
files.addAll(open(arg));
ioe.printStackTrace();
System.exit(2);
}
-
- /*
- * String file = args.length > 0 ? args[0] : null; String file2 =
- * args.length > 1 ? args[1] : null;
- *
- * if (file == null) file =
- * "/home/niki/workspace/rcard/utils/CVcard/test.vcf"; if (file2 ==
- * null) file2 = "/home/niki/workspace/rcard/utils/CVcard/test.abook";
- *
- * Card card = new Card(new File(file), Format.VCard21);
- * System.out.println(card.toString());
- *
- * System.out.println("\n -- PINE -- \n");
- *
- * card = new Card(new File(file2), Format.Abook);
- * System.out.println(card.toString(Format.Abook));
- */
}
/**
import java.util.LinkedList;
import java.util.List;
-import be.nikiroo.jvcard.i18n.Trans;
import be.nikiroo.jvcard.i18n.Trans.StringId;
import be.nikiroo.jvcard.tui.KeyAction.Mode;
import be.nikiroo.jvcard.tui.UiColors.Element;
actionPanel.removeAllComponents();
for (KeyAction action : this.actions) {
- String trans = " " + action.getStringId().trans() + " ";
+ String trans = " " + Main.trans(action.getStringId()) + " ";
if (" ".equals(trans))
continue;
- String keyTrans = Trans.getInstance().trans(action.getKey());
+ String keyTrans = Main.trans(action.getKey());
Panel kPane = new Panel();
LinearLayout layout = new LinearLayout(Direction.HORIZONTAL);
import com.googlecode.lanterna.terminal.ResizeListener;
import com.googlecode.lanterna.terminal.Terminal;
-/*
- *
- * Change in Lanterna 3.0.0-beta2 (issue and fix reported to GitHub):
- *
- * java.lang.StringIndexOutOfBoundsException: String index out of range: 83
- * at java.lang.String.charAt(String.java:686)
- * at com.googlecode.lanterna.TerminalTextUtils.getWordWrappedText(TerminalTextUtils.java:237)
- *
+/**
+ * Starting the TUI.
*
+ * @author niki
+ *
*/
-
public class TuiLauncher {
- public static void start(Boolean textMode, Window win) throws IOException {
+
+ static public void start(Boolean textMode, Window win) throws IOException {
Terminal terminal = null;
DefaultTerminalFactory factory = new DefaultTerminalFactory();
import java.util.List;
import be.nikiroo.jvcard.i18n.Trans.StringId;
+import be.nikiroo.jvcard.tui.Main;
import be.nikiroo.jvcard.tui.StringUtils;
import be.nikiroo.jvcard.tui.UiColors;
import be.nikiroo.jvcard.tui.UiColors.Element;
* @return the separator
*/
public String getSeparator() {
- return StringId.DEAULT_FIELD_SEPARATOR.trans();
+ return Main.trans(StringId.DEAULT_FIELD_SEPARATOR);
}
@Override