source: josm/trunk/src/org/openstreetmap/josm/tools/I18n.java@ 8241

Last change on this file since 8241 was 8241, checked in by stoecker, 9 years ago

see #11148 - removed language display name workaround, but keep the function nevertheless

  • Property svn:eol-style set to native
File size: 29.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.io.BufferedInputStream;
5import java.io.File;
6import java.io.FileInputStream;
7import java.io.IOException;
8import java.io.InputStream;
9import java.net.URL;
10import java.nio.charset.StandardCharsets;
11import java.text.MessageFormat;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.Comparator;
16import java.util.HashMap;
17import java.util.Locale;
18import java.util.Map;
19import java.util.jar.JarInputStream;
20import java.util.zip.ZipEntry;
21
22import javax.swing.JColorChooser;
23import javax.swing.JFileChooser;
24import javax.swing.UIManager;
25
26import org.openstreetmap.gui.jmapviewer.FeatureAdapter.TranslationAdapter;
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
29
30/**
31 * Internationalisation support.
32 *
33 * @author Immanuel.Scholz
34 */
35public final class I18n {
36
37 private I18n() {
38 // Hide default constructor for utils classes
39 }
40
41 /**
42 * Enumeration of possible plural modes. It allows us to identify and implement logical conditions of
43 * plural forms defined on <a href="https://help.launchpad.net/Translations/PluralForms">Launchpad</a>.
44 * See <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html">CLDR</a>
45 * for another complete list.
46 * @see #pluralEval
47 */
48 private enum PluralMode {
49 /** Plural = Not 1. This is the default for many languages, including English: 1 day, but 0 days or 2 days. */
50 MODE_NOTONE,
51 /** No plural. Mainly for Asian languages (Indonesian, Chinese, Japanese, ...) */
52 MODE_NONE,
53 /** Plural = Greater than 1. For some latin languages (French, Brazilian Portuguese) */
54 MODE_GREATERONE,
55 /* Special mode for
56 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar">Arabic</a>.*
57 MODE_AR,*/
58 /** Special mode for
59 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#cs">Czech</a>. */
60 MODE_CS,
61 /** Special mode for
62 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#pl">Polish</a>. */
63 MODE_PL,
64 /* Special mode for
65 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ro">Romanian</a>.*
66 MODE_RO,*/
67 /** Special mode for
68 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#lt">Lithuanian</a>. */
69 MODE_LT,
70 /** Special mode for
71 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ru">Russian</a>. */
72 MODE_RU,
73 /** Special mode for
74 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#sk">Slovak</a>. */
75 MODE_SK,
76 /* Special mode for
77 * <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#sl">Slovenian</a>.*
78 MODE_SL,*/
79 }
80
81 private static volatile PluralMode pluralMode = PluralMode.MODE_NOTONE; /* english default */
82 private static volatile String loadedCode = "en";
83
84 /* Localization keys for file chooser (and color chooser). */
85 private static final String[] javaInternalMessageKeys = new String[] {
86 /* JFileChooser windows laf */
87 "FileChooser.detailsViewActionLabelText",
88 "FileChooser.detailsViewButtonAccessibleName",
89 "FileChooser.detailsViewButtonToolTipText",
90 "FileChooser.fileAttrHeaderText",
91 "FileChooser.fileDateHeaderText",
92 "FileChooser.fileNameHeaderText",
93 "FileChooser.fileNameLabelText",
94 "FileChooser.fileSizeHeaderText",
95 "FileChooser.fileTypeHeaderText",
96 "FileChooser.filesOfTypeLabelText",
97 "FileChooser.homeFolderAccessibleName",
98 "FileChooser.homeFolderToolTipText",
99 "FileChooser.listViewActionLabelText",
100 "FileChooser.listViewButtonAccessibleName",
101 "FileChooser.listViewButtonToolTipText",
102 "FileChooser.lookInLabelText",
103 "FileChooser.newFolderAccessibleName",
104 "FileChooser.newFolderActionLabelText",
105 "FileChooser.newFolderToolTipText",
106 "FileChooser.refreshActionLabelText",
107 "FileChooser.saveInLabelText",
108 "FileChooser.upFolderAccessibleName",
109 "FileChooser.upFolderToolTipText",
110 "FileChooser.viewMenuLabelText",
111
112 /* JFileChooser gtk laf */
113 "FileChooser.acceptAllFileFilterText",
114 "FileChooser.cancelButtonText",
115 "FileChooser.cancelButtonToolTipText",
116 "FileChooser.deleteFileButtonText",
117 "FileChooser.filesLabelText",
118 "FileChooser.filterLabelText",
119 "FileChooser.foldersLabelText",
120 "FileChooser.newFolderButtonText",
121 "FileChooser.newFolderDialogText",
122 "FileChooser.openButtonText",
123 "FileChooser.openButtonToolTipText",
124 "FileChooser.openDialogTitleText",
125 "FileChooser.pathLabelText",
126 "FileChooser.renameFileButtonText",
127 "FileChooser.renameFileDialogText",
128 "FileChooser.renameFileErrorText",
129 "FileChooser.renameFileErrorTitle",
130 "FileChooser.saveButtonText",
131 "FileChooser.saveButtonToolTipText",
132 "FileChooser.saveDialogTitleText",
133
134 /* JFileChooser motif laf */
135 //"FileChooser.cancelButtonText",
136 //"FileChooser.cancelButtonToolTipText",
137 "FileChooser.enterFileNameLabelText",
138 //"FileChooser.filesLabelText",
139 //"FileChooser.filterLabelText",
140 //"FileChooser.foldersLabelText",
141 "FileChooser.helpButtonText",
142 "FileChooser.helpButtonToolTipText",
143 //"FileChooser.openButtonText",
144 //"FileChooser.openButtonToolTipText",
145 //"FileChooser.openDialogTitleText",
146 //"FileChooser.pathLabelText",
147 //"FileChooser.saveButtonText",
148 //"FileChooser.saveButtonToolTipText",
149 //"FileChooser.saveDialogTitleText",
150 "FileChooser.updateButtonText",
151 "FileChooser.updateButtonToolTipText",
152
153 /* gtk color chooser */
154 "GTKColorChooserPanel.blueText",
155 "GTKColorChooserPanel.colorNameText",
156 "GTKColorChooserPanel.greenText",
157 "GTKColorChooserPanel.hueText",
158 "GTKColorChooserPanel.nameText",
159 "GTKColorChooserPanel.redText",
160 "GTKColorChooserPanel.saturationText",
161 "GTKColorChooserPanel.valueText",
162
163 /* JOptionPane */
164 "OptionPane.okButtonText",
165 "OptionPane.yesButtonText",
166 "OptionPane.noButtonText",
167 "OptionPane.cancelButtonText"
168 };
169 private static volatile Map<String, String> strings = null;
170 private static volatile Map<String, String[]> pstrings = null;
171 private static Map<String, PluralMode> languages = new HashMap<>();
172
173 /**
174 * Translates some text for the current locale.
175 * These strings are collected by a script that runs on the source code files.
176 * After translation, the localizations are distributed with the main program.
177 * <br>
178 * For example, <code>tr("JOSM''s default value is ''{0}''.", val)</code>.
179 * <br>
180 * Use {@link #trn} for distinguishing singular from plural text, i.e.,
181 * do not use {@code tr(size == 1 ? "singular" : "plural")} nor
182 * {@code size == 1 ? tr("singular") : tr("plural")}
183 *
184 * @param text the text to translate.
185 * Must be a string literal. (No constants or local vars.)
186 * Can be broken over multiple lines.
187 * An apostrophe ' must be quoted by another apostrophe.
188 * @param objects the parameters for the string.
189 * Mark occurrences in {@code text} with <code>{0}</code>, <code>{1}</code>, ...
190 * @return the translated string.
191 * @see #trn
192 * @see #trc
193 * @see #trnc
194 */
195 public static final String tr(String text, Object... objects) {
196 if (text == null) return null;
197 return MessageFormat.format(gettext(text, null), objects);
198 }
199
200 /**
201 * Translates some text in a context for the current locale.
202 * There can be different translations for the same text within different contexts.
203 *
204 * @param context string that helps translators to find an appropriate
205 * translation for {@code text}.
206 * @param text the text to translate.
207 * @return the translated string.
208 * @see #tr
209 * @see #trn
210 * @see #trnc
211 */
212 public static final String trc(String context, String text) {
213 if (context == null)
214 return tr(text);
215 if (text == null)
216 return null;
217 return MessageFormat.format(gettext(text, context), (Object)null);
218 }
219
220 public static final String trc_lazy(String context, String text) {
221 if (context == null)
222 return tr(text);
223 if (text == null)
224 return null;
225 return MessageFormat.format(gettext_lazy(text, context), (Object)null);
226 }
227
228 /**
229 * Marks a string for translation (such that a script can harvest
230 * the translatable strings from the source files).
231 *
232 * For example, <code>
233 * String[] options = new String[] {marktr("up"), marktr("down")};
234 * lbl.setText(tr(options[0]));</code>
235 * @param text the string to be marked for translation.
236 * @return {@code text} unmodified.
237 */
238 public static final String marktr(String text) {
239 return text;
240 }
241
242 public static final String marktrc(String context, String text) {
243 return text;
244 }
245
246 /**
247 * Translates some text for the current locale and distinguishes between
248 * {@code singularText} and {@code pluralText} depending on {@code n}.
249 * <br>
250 * For instance, {@code trn("There was an error!", "There were errors!", i)} or
251 * <code>trn("Found {0} error in {1}!", "Found {0} errors in {1}!", i, Integer.toString(i), url)</code>.
252 *
253 * @param singularText the singular text to translate.
254 * Must be a string literal. (No constants or local vars.)
255 * Can be broken over multiple lines.
256 * An apostrophe ' must be quoted by another apostrophe.
257 * @param pluralText the plural text to translate.
258 * Must be a string literal. (No constants or local vars.)
259 * Can be broken over multiple lines.
260 * An apostrophe ' must be quoted by another apostrophe.
261 * @param n a number to determine whether {@code singularText} or {@code pluralText} is used.
262 * @param objects the parameters for the string.
263 * Mark occurrences in {@code singularText} and {@code pluralText} with <code>{0}</code>, <code>{1}</code>, ...
264 * @return the translated string.
265 * @see #tr
266 * @see #trc
267 * @see #trnc
268 */
269 public static final String trn(String singularText, String pluralText, long n, Object... objects) {
270 return MessageFormat.format(gettextn(singularText, pluralText, null, n), objects);
271 }
272
273 /**
274 * Translates some text in a context for the current locale and distinguishes between
275 * {@code singularText} and {@code pluralText} depending on {@code n}.
276 * There can be different translations for the same text within different contexts.
277 *
278 * @param context string that helps translators to find an appropriate
279 * translation for {@code text}.
280 * @param singularText the singular text to translate.
281 * Must be a string literal. (No constants or local vars.)
282 * Can be broken over multiple lines.
283 * An apostrophe ' must be quoted by another apostrophe.
284 * @param pluralText the plural text to translate.
285 * Must be a string literal. (No constants or local vars.)
286 * Can be broken over multiple lines.
287 * An apostrophe ' must be quoted by another apostrophe.
288 * @param n a number to determine whether {@code singularText} or {@code pluralText} is used.
289 * @param objects the parameters for the string.
290 * Mark occurrences in {@code singularText} and {@code pluralText} with <code>{0}</code>, <code>{1}</code>, ...
291 * @return the translated string.
292 * @see #tr
293 * @see #trc
294 * @see #trn
295 */
296 public static final String trnc(String context, String singularText, String pluralText, long n, Object... objects) {
297 return MessageFormat.format(gettextn(singularText, pluralText, context, n), objects);
298 }
299
300 private static final String gettext(String text, String ctx, boolean lazy) {
301 int i;
302 if(ctx == null && text.startsWith("_:") && (i = text.indexOf('\n')) >= 0) {
303 ctx = text.substring(2,i-1);
304 text = text.substring(i+1);
305 }
306 if(strings != null) {
307 String trans = strings.get(ctx == null ? text : "_:"+ctx+"\n"+text);
308 if(trans != null)
309 return trans;
310 }
311 if(pstrings != null) {
312 i = pluralEval(1);
313 String[] trans = pstrings.get(ctx == null ? text : "_:"+ctx+"\n"+text);
314 if(trans != null && trans.length > i)
315 return trans[i];
316 }
317 return lazy ? gettext(text, null) : text;
318 }
319
320 private static final String gettext(String text, String ctx) {
321 return gettext(text, ctx, false);
322 }
323
324 /* try without context, when context try fails */
325 private static final String gettext_lazy(String text, String ctx) {
326 return gettext(text, ctx, true);
327 }
328
329 private static final String gettextn(String text, String plural, String ctx, long num) {
330 int i;
331 if(ctx == null && text.startsWith("_:") && (i = text.indexOf('\n')) >= 0) {
332 ctx = text.substring(2,i-1);
333 text = text.substring(i+1);
334 }
335 if(pstrings != null) {
336 i = pluralEval(num);
337 String[] trans = pstrings.get(ctx == null ? text : "_:"+ctx+"\n"+text);
338 if(trans != null && trans.length > i)
339 return trans[i];
340 }
341
342 return num == 1 ? text : plural;
343 }
344
345 public static String escape(String msg) {
346 if (msg == null) return null;
347 return msg.replace("\'", "\'\'").replace("{", "\'{\'").replace("}", "\'}\'");
348 }
349
350 private static URL getTranslationFile(String lang) {
351 return Main.class.getResource("/data/"+lang.replace("@","-")+".lang");
352 }
353
354 /**
355 * Get a list of all available JOSM Translations.
356 * @return an array of locale objects.
357 */
358 public static final Locale[] getAvailableTranslations() {
359 Collection<Locale> v = new ArrayList<>(languages.size());
360 if(getTranslationFile("en") != null) {
361 for (String loc : languages.keySet()) {
362 if(getTranslationFile(loc) != null) {
363 v.add(LanguageInfo.getLocale(loc));
364 }
365 }
366 }
367 v.add(Locale.ENGLISH);
368 Locale[] l = new Locale[v.size()];
369 l = v.toArray(l);
370 Arrays.sort(l, new Comparator<Locale>() {
371 @Override
372 public int compare(Locale o1, Locale o2) {
373 return o1.toString().compareTo(o2.toString());
374 }
375 });
376 return l;
377 }
378
379 /**
380 * Determines if a language exists for the given code.
381 * @param code The language code
382 * @return {@code true} if a language exists, {@code false} otherwise
383 */
384 public static boolean hasCode(String code) {
385 return languages.containsKey(code);
386 }
387
388 /**
389 * I18n initialization.
390 */
391 public static void init() {
392 // Enable CLDR locale provider on Java 8 to get additional languages, such as Khmer.
393 // http://docs.oracle.com/javase/8/docs/technotes/guides/intl/enhancements.8.html#cldr
394 // FIXME: This can be removed after we switch to a minimal version of Java that enables CLDR by default
395 // or includes all languages we need in the JRE. See http://openjdk.java.net/jeps/8043554 for Java 9
396 Utils.updateSystemProperty("java.locale.providers", "JRE,CLDR");
397
398 //languages.put("ar", PluralMode.MODE_AR);
399 languages.put("ast", PluralMode.MODE_NOTONE);
400 languages.put("bg", PluralMode.MODE_NOTONE);
401 languages.put("ca", PluralMode.MODE_NOTONE);
402 languages.put("ca@valencia", PluralMode.MODE_NOTONE);
403 languages.put("cs", PluralMode.MODE_CS);
404 languages.put("da", PluralMode.MODE_NOTONE);
405 languages.put("de", PluralMode.MODE_NOTONE);
406 languages.put("el", PluralMode.MODE_NOTONE);
407 languages.put("en_AU", PluralMode.MODE_NOTONE);
408 languages.put("en_GB", PluralMode.MODE_NOTONE);
409 languages.put("es", PluralMode.MODE_NOTONE);
410 languages.put("et", PluralMode.MODE_NOTONE);
411 //languages.put("eu", PluralMode.MODE_NOTONE);
412 languages.put("fi", PluralMode.MODE_NOTONE);
413 languages.put("fr", PluralMode.MODE_GREATERONE);
414 languages.put("gl", PluralMode.MODE_NOTONE);
415 //languages.put("he", PluralMode.MODE_NOTONE);
416 languages.put("hu", PluralMode.MODE_NOTONE);
417 languages.put("id", PluralMode.MODE_NONE);
418 //languages.put("is", PluralMode.MODE_NOTONE);
419 languages.put("it", PluralMode.MODE_NOTONE);
420 languages.put("ja", PluralMode.MODE_NONE);
421 // fully supported only with Java 8 and later (needs CLDR)
422 languages.put("km", PluralMode.MODE_NONE);
423 languages.put("lt", PluralMode.MODE_LT);
424 //languages.put("nb", PluralMode.MODE_NOTONE);
425 languages.put("nl", PluralMode.MODE_NOTONE);
426 languages.put("pl", PluralMode.MODE_PL);
427 languages.put("pt", PluralMode.MODE_NOTONE);
428 languages.put("pt_BR", PluralMode.MODE_GREATERONE);
429 //languages.put("ro", PluralMode.MODE_RO);
430 languages.put("ru", PluralMode.MODE_RU);
431 languages.put("sk", PluralMode.MODE_SK);
432 //languages.put("sl", PluralMode.MODE_SL);
433 languages.put("sv", PluralMode.MODE_NOTONE);
434 //languages.put("tr", PluralMode.MODE_NONE);
435 languages.put("uk", PluralMode.MODE_RU);
436 languages.put("zh_CN", PluralMode.MODE_NONE);
437 languages.put("zh_TW", PluralMode.MODE_NONE);
438
439 /* try initial language settings, may be changed later again */
440 if(!load(Locale.getDefault().toString())) {
441 Locale.setDefault(Locale.ENGLISH);
442 }
443 }
444
445 public static void addTexts(File source) {
446 if ("en".equals(loadedCode))
447 return;
448 String enfile = "data/en.lang";
449 String langfile = "data/"+loadedCode+".lang";
450 try (
451 FileInputStream fis = new FileInputStream(source);
452 JarInputStream jar = new JarInputStream(fis)
453 ) {
454 ZipEntry e;
455 boolean found = false;
456 while (!found && (e = jar.getNextEntry()) != null) {
457 String name = e.getName();
458 if(name.equals(enfile))
459 found = true;
460 }
461 if (found) {
462 try (
463 FileInputStream fisTrans = new FileInputStream(source);
464 JarInputStream jarTrans = new JarInputStream(fisTrans)
465 ) {
466 found = false;
467 while(!found && (e = jarTrans.getNextEntry()) != null) {
468 String name = e.getName();
469 if (name.equals(langfile))
470 found = true;
471 }
472 if (found)
473 load(jar, jarTrans, true);
474 }
475 }
476 } catch (IOException e) {
477 // Ignore
478 }
479 }
480
481 private static boolean load(String l) {
482 if ("en".equals(l) || "en_US".equals(l)) {
483 strings = null;
484 pstrings = null;
485 loadedCode = "en";
486 pluralMode = PluralMode.MODE_NOTONE;
487 return true;
488 }
489 URL en = getTranslationFile("en");
490 if (en == null)
491 return false;
492 URL tr = getTranslationFile(l);
493 if (tr == null || !languages.containsKey(l)) {
494 int i = l.indexOf('_');
495 if (i > 0) {
496 l = l.substring(0, i);
497 }
498 tr = getTranslationFile(l);
499 if (tr == null || !languages.containsKey(l))
500 return false;
501 }
502 try (
503 InputStream enStream = en.openStream();
504 InputStream trStream = tr.openStream()
505 ) {
506 if (load(enStream, trStream, false)) {
507 pluralMode = languages.get(l);
508 loadedCode = l;
509 return true;
510 }
511 } catch (IOException e) {
512 // Ignore exception
513 }
514 return false;
515 }
516
517 private static boolean load(InputStream en, InputStream tr, boolean add) {
518 Map<String, String> s;
519 Map<String, String[]> p;
520 if (add) {
521 s = strings;
522 p = pstrings;
523 } else {
524 s = new HashMap<>();
525 p = new HashMap<>();
526 }
527 /* file format:
528 Files are always a group. English file and translated file must provide identical datasets.
529
530 for all single strings:
531 {
532 unsigned short (2 byte) stringlength
533 - length 0 indicates missing translation
534 - length 0xFFFE indicates translation equal to original, but otherwise is equal to length 0
535 string
536 }
537 unsigned short (2 byte) 0xFFFF (marks end of single strings)
538 for all multi strings:
539 {
540 unsigned char (1 byte) stringcount
541 - count 0 indicates missing translations
542 - count 0xFE indicates translations equal to original, but otherwise is equal to length 0
543 for stringcount
544 unsigned short (2 byte) stringlength
545 string
546 }
547 */
548 try {
549 InputStream ens = new BufferedInputStream(en);
550 InputStream trs = new BufferedInputStream(tr);
551 byte[] enlen = new byte[2];
552 byte[] trlen = new byte[2];
553 boolean multimode = false;
554 byte[] str = new byte[4096];
555 for(;;) {
556 if(multimode) {
557 int ennum = ens.read();
558 int trnum = trs.read();
559 if(trnum == 0xFE) /* marks identical string, handle equally to non-translated */
560 trnum = 0;
561 if((ennum == -1 && trnum != -1) || (ennum != -1 && trnum == -1)) /* files do not match */
562 return false;
563 if(ennum == -1) {
564 break;
565 }
566 String[] enstrings = new String[ennum];
567 String[] trstrings = new String[trnum];
568 for(int i = 0; i < ennum; ++i) {
569 int val = ens.read(enlen);
570 if(val != 2) /* file corrupt */
571 return false;
572 val = (enlen[0] < 0 ? 256+enlen[0]:enlen[0])*256+(enlen[1] < 0 ? 256+enlen[1]:enlen[1]);
573 if(val > str.length) {
574 str = new byte[val];
575 }
576 int rval = ens.read(str, 0, val);
577 if(rval != val) /* file corrupt */
578 return false;
579 enstrings[i] = new String(str, 0, val, StandardCharsets.UTF_8);
580 }
581 for(int i = 0; i < trnum; ++i) {
582 int val = trs.read(trlen);
583 if(val != 2) /* file corrupt */
584 return false;
585 val = (trlen[0] < 0 ? 256+trlen[0]:trlen[0])*256+(trlen[1] < 0 ? 256+trlen[1]:trlen[1]);
586 if(val > str.length) {
587 str = new byte[val];
588 }
589 int rval = trs.read(str, 0, val);
590 if(rval != val) /* file corrupt */
591 return false;
592 trstrings[i] = new String(str, 0, val, StandardCharsets.UTF_8);
593 }
594 if(trnum > 0 && !p.containsKey(enstrings[0])) {
595 p.put(enstrings[0], trstrings);
596 }
597 } else {
598 int enval = ens.read(enlen);
599 int trval = trs.read(trlen);
600 if(enval != trval) /* files do not match */
601 return false;
602 if(enval == -1) {
603 break;
604 }
605 if(enval != 2) /* files corrupt */
606 return false;
607 enval = (enlen[0] < 0 ? 256+enlen[0]:enlen[0])*256+(enlen[1] < 0 ? 256+enlen[1]:enlen[1]);
608 trval = (trlen[0] < 0 ? 256+trlen[0]:trlen[0])*256+(trlen[1] < 0 ? 256+trlen[1]:trlen[1]);
609 if(trval == 0xFFFE) /* marks identical string, handle equally to non-translated */
610 trval = 0;
611 if(enval == 0xFFFF) {
612 multimode = true;
613 if(trval != 0xFFFF) /* files do not match */
614 return false;
615 } else {
616 if (enval > str.length) {
617 str = new byte[enval];
618 }
619 if (trval > str.length) {
620 str = new byte[trval];
621 }
622 int val = ens.read(str, 0, enval);
623 if(val != enval) /* file corrupt */
624 return false;
625 String enstr = new String(str, 0, enval, StandardCharsets.UTF_8);
626 if (trval != 0) {
627 val = trs.read(str, 0, trval);
628 if(val != trval) /* file corrupt */
629 return false;
630 String trstr = new String(str, 0, trval, StandardCharsets.UTF_8);
631 if(!s.containsKey(enstr))
632 s.put(enstr, trstr);
633 }
634 }
635 }
636 }
637 } catch (IOException e) {
638 return false;
639 }
640 if (!s.isEmpty()) {
641 strings = s;
642 pstrings = p;
643 return true;
644 }
645 return false;
646 }
647
648 /**
649 * Sets the default locale (see {@link Locale#setDefault(Locale)} to the local
650 * given by <code>localName</code>.
651 *
652 * Ignored if localeName is null. If the locale with name <code>localName</code>
653 * isn't found the default local is set to <tt>en</tt> (english).
654 *
655 * @param localeName the locale name. Ignored if null.
656 */
657 public static void set(String localeName){
658 if (localeName != null) {
659 Locale l = LanguageInfo.getLocale(localeName);
660 if (load(LanguageInfo.getJOSMLocaleCode(l))) {
661 Locale.setDefault(l);
662 } else {
663 if (!"en".equals(l.getLanguage())) {
664 Main.info(tr("Unable to find translation for the locale {0}. Reverting to {1}.",
665 LanguageInfo.getDisplayName(l), LanguageInfo.getDisplayName(Locale.getDefault())));
666 } else {
667 strings = null;
668 pstrings = null;
669 }
670 }
671 }
672 }
673
674 /**
675 * Localizations for file chooser dialog.
676 * For some locales (e.g. de, fr) translations are provided
677 * by Java, but not for others (e.g. ru, uk).
678 */
679 public static void translateJavaInternalMessages() {
680 Locale l = Locale.getDefault();
681
682 AbstractFileChooser.setDefaultLocale(l);
683 JFileChooser.setDefaultLocale(l);
684 JColorChooser.setDefaultLocale(l);
685 for (String key : javaInternalMessageKeys) {
686 String us = UIManager.getString(key, Locale.US);
687 String loc = UIManager.getString(key, l);
688 // only provide custom translation if it is not already localized by Java
689 if (us != null && us.equals(loc)) {
690 UIManager.put(key, tr(us));
691 }
692 }
693 }
694
695 private static int pluralEval(long n) {
696 switch(pluralMode) {
697 case MODE_NOTONE: /* bg, da, de, el, en, en_GB, es, et, eu, fi, gl, is, it, iw_IL, nb, nl, sv */
698 return ((n != 1) ? 1 : 0);
699 case MODE_NONE: /* id, ja, km, tr, zh_CN, zh_TW */
700 return 0;
701 case MODE_GREATERONE: /* fr, pt_BR */
702 return ((n > 1) ? 1 : 0);
703 case MODE_CS:
704 return ((n == 1) ? 0 : (((n >= 2) && (n <= 4)) ? 1 : 2));
705 //case MODE_AR:
706 // return ((n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((((n % 100) >= 3)
707 // && ((n % 100) <= 10)) ? 3 : ((((n % 100) >= 11) && ((n % 100) <= 99)) ? 4 : 5)))));
708 case MODE_PL:
709 return ((n == 1) ? 0 : (((((n % 10) >= 2) && ((n % 10) <= 4))
710 && (((n % 100) < 10) || ((n % 100) >= 20))) ? 1 : 2));
711 //case MODE_RO:
712 // return ((n == 1) ? 0 : ((((n % 100) > 19) || (((n % 100) == 0) && (n != 0))) ? 2 : 1));
713 case MODE_LT:
714 return (((n % 10) == 1) && ((n % 100) != 11) ? 0 : (((n % 10) >= 2)
715 && (((n % 100) < 10) || ((n % 100) >= 20)) ? 1 : 2));
716 case MODE_RU:
717 return ((((n % 10) == 1) && ((n % 100) != 11)) ? 0 : (((((n % 10) >= 2)
718 && ((n % 10) <= 4)) && (((n % 100) < 10) || ((n % 100) >= 20))) ? 1 : 2));
719 case MODE_SK:
720 return ((n == 1) ? 1 : (((n >= 2) && (n <= 4)) ? 2 : 0));
721 //case MODE_SL:
722 // return (((n % 100) == 1) ? 1 : (((n % 100) == 2) ? 2 : ((((n % 100) == 3)
723 // || ((n % 100) == 4)) ? 3 : 0)));
724 }
725 return 0;
726 }
727
728 public static TranslationAdapter getTranslationAdapter() {
729 return new TranslationAdapter() {
730 @Override
731 public String tr(String text, Object... objects) {
732 return I18n.tr(text, objects);
733 }
734 };
735 }
736}
Note: See TracBrowser for help on using the repository browser.