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

Last change on this file since 7731 was 7578, checked in by Don-vip, 10 years ago

fix #10024 - Add an option in Preferences/Look-and-Feel to use native file-choosing dialogs.
They look nicer but they do not support file filters, so we cannot use them (yet) as default.
Based on patch by Lesath and code review by simon04.
The native dialogs are not used if selection mode is not supported ("files and directories" on all platforms, "directories" on systems other than OS X)

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