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

Last change on this file since 8018 was 7901, checked in by Don-vip, 9 years ago

fix #10892 - update multipolygon preset + javadoc update

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