New launcher class to start all 3 modes:
[jvcard.git] / src / be / nikiroo / jvcard / resources / Trans.java
CommitLineData
7da41ecd 1package be.nikiroo.jvcard.resources;
a3b510ab 2
e7418457
NR
3import java.io.BufferedWriter;
4import java.io.File;
5import java.io.FileOutputStream;
6import java.io.IOException;
7import java.io.OutputStreamWriter;
8import java.lang.reflect.Field;
668268fc
NR
9import java.util.Locale;
10import java.util.ResourceBundle;
296a0b75 11
a3b510ab 12/**
e7418457 13 * This class manages the translation of {@link Trans.StringId}s into
a3b510ab
NR
14 * user-understandable text.
15 *
16 * @author niki
17 *
18 */
19public class Trans {
7f82bf68 20 private ResourceBundle map;
7da41ecd 21 private boolean utf = true;
a3b510ab 22
a3b510ab 23 /**
668268fc 24 * Create a translation service with the default language.
a3b510ab 25 */
668268fc 26 public Trans() {
e7418457 27 setLanguage(null);
668268fc 28 }
a3b510ab 29
668268fc
NR
30 /**
31 * Create a translation service for the given language. (Will fall back to
32 * the default one i not found.)
33 *
34 * @param language
35 * the language to use
36 */
37 public Trans(String language) {
e7418457 38 setLanguage(language);
a3b510ab
NR
39 }
40
296a0b75
NR
41 /**
42 * Translate the given {@link StringId} into user text.
43 *
44 * @param stringId
45 * the ID to translate
46 *
47 * @return the translated text
48 */
a3b510ab 49 public String trans(StringId stringId) {
296a0b75 50 StringId id = stringId;
7da41ecd 51 if (!isUnicode()) {
296a0b75 52 try {
2a96e7b2 53 id = StringId.valueOf(stringId.name() + "_NOUTF");
296a0b75
NR
54 } catch (IllegalArgumentException iae) {
55 // no special _NOUTF version found
56 }
57 }
58
668268fc
NR
59 if (id == StringId.NULL) {
60 return "";
61 }
62
63 if (id == StringId.DUMMY) {
64 return "[dummy]";
65 }
66
2a96e7b2
NR
67 if (map.containsKey(id.name())) {
68 return map.getString(id.name());
296a0b75
NR
69 }
70
71 return id.toString();
72 }
73
74 /**
7da41ecd 75 * Check if unicode characters should be used.
296a0b75 76 *
7da41ecd 77 * @return TRUE to allow unicode
296a0b75 78 */
7da41ecd
NR
79 public boolean isUnicode() {
80 return utf;
81 }
a3b510ab 82
7da41ecd
NR
83 /**
84 * Allow or disallow unicode characters in the program.
85 *
86 * @param utf
87 * TRUE to allow unuciode, FALSE to only allow ASCII characters
88 */
89 public void setUnicode(boolean utf) {
90 this.utf = utf;
a3b510ab
NR
91 }
92
668268fc
NR
93 /**
94 * Initialise the translation mappings for the given language.
95 *
d3e940b6
NR
96 * @param language
97 * the language to initialise, in the form "en-GB" or "fr" for
98 * instance
668268fc 99 */
d3e940b6
NR
100 private void setLanguage(String language) {
101 map = Bundles.getBundle("resources", getLocaleFor(language));
a3b510ab 102 }
e7418457
NR
103
104 /**
105 * Create/update the translation .properties files. Will use the most likely
106 * candidate as base if the file does not already exists (for instance,
107 * "en_US" will use "en" as a base).
108 *
7da41ecd
NR
109 * @param path
110 * the path where the .properties files are
111 *
112 * @param language
113 * the language code to create/update (e.g.: <tt>fr-BE</tt>)
e7418457
NR
114 *
115 * @throws IOException
116 * in case of IO errors
117 */
7da41ecd
NR
118 static public void generateTranslationFile(String path, String language)
119 throws IOException {
120
121 Locale locale = getLocaleFor(language);
122 String code = locale.toString();
123 Trans trans = new Trans(code);
e7418457 124
7da41ecd
NR
125 File file = null;
126 if (code.length() > 0) {
127 file = new File(path + "resources_" + code + ".properties");
128 } else {
129 // Default properties file:
130 file = new File(path + "resources.properties");
131 }
e7418457 132
7da41ecd
NR
133 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
134 new FileOutputStream(file), "UTF-8"));
e7418457 135
7da41ecd
NR
136 String name = locale.getDisplayCountry(locale);
137 if (name.length() == 0)
138 name = locale.getDisplayLanguage(locale);
139 if (name.length() == 0)
140 name = "default";
e7418457 141
7da41ecd
NR
142 if (code.length() > 0) {
143 name = name + " (" + code + ")";
144 }
145
146 writer.append("# " + name + " translation file (UTF-8)\n");
147 writer.append("# \n");
148 writer.append("# Note that any key can be doubled with a _NOUTF suffix\n");
149 writer.append("# to use when the flag --noutf is passed\n");
150 writer.append("# \n");
151 writer.append("# Also, the comments always refer to the key below them.\n");
152 writer.append("# \n");
153 writer.append("\n");
154
155 for (Field field : StringId.class.getDeclaredFields()) {
156 Meta meta = field.getAnnotation(Meta.class);
157 if (meta != null) {
158 StringId id = StringId.valueOf(field.getName());
159 String info = getMetaInfo(meta);
160 if (info != null) {
161 writer.append(info);
e7418457
NR
162 writer.append("\n");
163 }
e7418457 164
7da41ecd
NR
165 writer.append(id.name());
166 writer.append(" = ");
167 if (!trans.trans(id).equals(id.name()))
168 writer.append(trans.trans(id));
169 writer.append("\n");
170 }
e7418457 171 }
7da41ecd
NR
172
173 writer.close();
e7418457
NR
174 }
175
d3e940b6
NR
176 /**
177 * Return the {@link Locale} representing the given language.
178 *
179 * @param language
180 * the language to initialise, in the form "en-GB" or "fr" for
181 * instance
182 *
183 * @return the corresponding {@link Locale} or the default {@link Locale} if
184 * it is not known
185 */
186 static private Locale getLocaleFor(String language) {
187 Locale locale;
188
189 if (language == null) {
190 locale = Locale.getDefault();
191 } else {
192 language = language.replaceAll("_", "-");
193 String lang = language;
194 String country = null;
195 if (language.contains("-")) {
196 lang = language.split("-")[0];
197 country = language.split("-")[1];
198 }
199
200 if (country != null)
201 locale = new Locale(lang, country);
202 else
203 locale = new Locale(lang);
204 }
205
206 return locale;
207 }
208
e7418457
NR
209 /**
210 * Return formated, display-able information from the {@link Meta} field
211 * given. Each line will always starts with a "#" character.
212 *
213 * @param meta
214 * the {@link Meta} field
215 *
216 * @return the information to display or NULL if none
217 */
d3e940b6 218 static private String getMetaInfo(Meta meta) {
e7418457
NR
219 String what = meta.what();
220 String where = meta.where();
221 String format = meta.format();
222 String info = meta.info();
223
224 int opt = what.length() + where.length() + format.length();
225 if (opt + info.length() == 0)
226 return null;
227
228 StringBuilder builder = new StringBuilder();
229 builder.append("# ");
230
231 if (opt > 0) {
232 builder.append("(");
233 if (what.length() > 0) {
234 builder.append("WHAT: " + what);
235 if (where.length() + format.length() > 0)
236 builder.append(", ");
237 }
238
239 if (where.length() > 0) {
240 builder.append("WHERE: " + where);
241 if (format.length() > 0)
242 builder.append(", ");
243 }
244
245 if (format.length() > 0) {
246 builder.append("FORMAT: " + format);
247 }
248
249 builder.append(")\n# ");
250 }
251
252 builder.append(info);
253
254 return builder.toString();
255 }
256
257 /**
258 * The enum representing textual information to be translated to the user as
259 * a key.
260 *
261 * Note that each key that should be translated MUST be annotated with a
262 * {@link Meta} annotation.
263 *
264 * @author niki
265 *
266 */
267 public enum StringId {
268 DUMMY, // <-- TODO : remove
269 NULL, // Special usage, no annotations so it is not visible in
270 // .properties files
271 @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Tab key")
272 KEY_TAB, // keys
273 @Meta(what = "a key to press", where = "action keys", format = "MUST BE 3 chars long", info = "Enter key")
274 KEY_ENTER, //
275 @Meta(what = "", where = "", format = "", info = "")
276 KEY_ACTION_BACK, // MainWindow
277 @Meta(what = "", where = "", format = "", info = "")
278 KEY_ACTION_HELP, //
279 @Meta(what = "", where = "", format = "", info = "")
280 KEY_ACTION_VIEW_CARD, // FileList
281 @Meta(what = "", where = "", format = "", info = "")
282 KEY_ACTION_VIEW_CONTACT, // ContactList
283 @Meta(what = "", where = "", format = "", info = "")
284 KEY_ACTION_EDIT_CONTACT, //
285 @Meta(what = "", where = "", format = "", info = "")
286 KEY_ACTION_SAVE_CARD, //
287 @Meta(what = "", where = "", format = "", info = "")
288 KEY_ACTION_DELETE_CONTACT, //
289 @Meta(what = "", where = "", format = "", info = "")
290 KEY_ACTION_SEARCH, //
291 @Meta(what = "", where = "", format = "", info = "we could use: ' ', ┃, │...")
292 DEAULT_FIELD_SEPARATOR, // MainContentList
293 @Meta(what = "", where = "", format = "", info = "")
294 DEAULT_FIELD_SEPARATOR_NOUTF, //
295 @Meta(what = "", where = "", format = "", info = "")
296 KEY_ACTION_INVERT, // ContactDetails
297 @Meta(what = "", where = "", format = "", info = "")
298 KEY_ACTION_FULLSCREEN, //
299 @Meta(what = "", where = "", format = "", info = "")
300 KEY_ACTION_SWITCH_FORMAT, // multi-usage
301 };
a3b510ab 302}