• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-runtime/intl-java/gnu/gettext/
1/* GNU gettext for Java
2 * Copyright (C) 2001, 2007 Free Software Foundation, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Library General Public License as published
6 * by the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 * USA.
18 */
19
20package gnu.gettext;
21
22import java.lang.reflect.*;
23import java.util.*;
24
25/**
26 * This class implements the main GNU libintl functions in Java.
27 * <P>
28 * Using the GNU gettext approach, compiled message catalogs are normal
29 * Java ResourceBundle classes and are thus interoperable with standard
30 * ResourceBundle based code.
31 * <P>
32 * The main differences between the Sun ResourceBundle approach and the
33 * GNU gettext approach are:
34 * <UL>
35 *   <LI>In the Sun approach, the keys are abstract textual shortcuts.
36 *       In the GNU gettext approach, the keys are the English/ASCII version
37 *       of the messages.
38 *   <LI>In the Sun approach, the translation files are called
39 *       "<VAR>Resource</VAR>_<VAR>locale</VAR>.properties" and have non-ASCII
40 *       characters encoded in the Java
41 *       <CODE>\</CODE><CODE>u<VAR>nnnn</VAR></CODE> syntax. Very few editors
42 *       can natively display international characters in this format. In the
43 *       GNU gettext approach, the translation files are called
44 *       "<VAR>Resource</VAR>.<VAR>locale</VAR>.po"
45 *       and are in the encoding the translator has chosen. Many editors
46 *       can be used. There are at least three GUI translating tools
47 *       (Emacs PO mode, KDE KBabel, GNOME gtranslator).
48 *   <LI>In the Sun approach, the function
49 *       <CODE>ResourceBundle.getString</CODE> throws a
50 *       <CODE>MissingResourceException</CODE> when no translation is found.
51 *       In the GNU gettext approach, the <CODE>gettext</CODE> function
52 *       returns the (English) message key in that case.
53 *   <LI>In the Sun approach, there is no support for plural handling.
54 *       Even the most elaborate MessageFormat strings cannot provide decent
55 *       plural handling. In the GNU gettext approach, we have the
56 *       <CODE>ngettext</CODE> function.
57 * </UL>
58 * <P>
59 * To compile GNU gettext message catalogs into Java ResourceBundle classes,
60 * the <CODE>msgfmt</CODE> program can be used.
61 *
62 * @author Bruno Haible
63 */
64public abstract class GettextResource extends ResourceBundle {
65
66  public static boolean verbose = false;
67
68  /**
69   * Like gettext(catalog,msgid), except that it returns <CODE>null</CODE>
70   * when no translation was found.
71   */
72  private static String gettextnull (ResourceBundle catalog, String msgid) {
73    try {
74      return (String)catalog.getObject(msgid);
75    } catch (MissingResourceException e) {
76      return null;
77    }
78  }
79
80  /**
81   * Returns the translation of <VAR>msgid</VAR>.
82   * @param catalog a ResourceBundle
83   * @param msgid the key string to be translated, an ASCII string
84   * @return the translation of <VAR>msgid</VAR>, or <VAR>msgid</VAR> if
85   *         none is found
86   */
87  public static String gettext (ResourceBundle catalog, String msgid) {
88    String result = gettextnull(catalog,msgid);
89    if (result != null)
90      return result;
91    return msgid;
92  }
93
94  /**
95   * Like ngettext(catalog,msgid,msgid_plural,n), except that it returns
96   * <CODE>null</CODE> when no translation was found.
97   */
98  private static String ngettextnull (ResourceBundle catalog, String msgid, long n) {
99    // The reason why we use so many reflective API calls instead of letting
100    // the GNU gettext generated ResourceBundles implement some interface,
101    // is that we want the generated ResourceBundles to be completely
102    // standalone, so that migration from the Sun approach to the GNU gettext
103    // approach (without use of plurals) is as straightforward as possible.
104    ResourceBundle origCatalog = catalog;
105    do {
106      // Try catalog itself.
107      if (verbose)
108        System.out.println("ngettext on "+catalog);
109      Method handleGetObjectMethod = null;
110      Method getParentMethod = null;
111      try {
112        handleGetObjectMethod = catalog.getClass().getMethod("handleGetObject", new Class[] { java.lang.String.class });
113        getParentMethod = catalog.getClass().getMethod("getParent", new Class[0]);
114      } catch (NoSuchMethodException e) {
115      } catch (SecurityException e) {
116      }
117      if (verbose)
118        System.out.println("handleGetObject = "+(handleGetObjectMethod!=null)+", getParent = "+(getParentMethod!=null));
119      if (handleGetObjectMethod != null
120          && Modifier.isPublic(handleGetObjectMethod.getModifiers())
121          && getParentMethod != null) {
122        // A GNU gettext created class.
123        Method lookupMethod = null;
124        Method pluralEvalMethod = null;
125        try {
126          lookupMethod = catalog.getClass().getMethod("lookup", new Class[] { java.lang.String.class });
127          pluralEvalMethod = catalog.getClass().getMethod("pluralEval", new Class[] { Long.TYPE });
128        } catch (NoSuchMethodException e) {
129        } catch (SecurityException e) {
130        }
131        if (verbose)
132          System.out.println("lookup = "+(lookupMethod!=null)+", pluralEval = "+(pluralEvalMethod!=null));
133        if (lookupMethod != null && pluralEvalMethod != null) {
134          // A GNU gettext created class with plural handling.
135          Object localValue = null;
136          try {
137            localValue = lookupMethod.invoke(catalog, new Object[] { msgid });
138          } catch (IllegalAccessException e) {
139            e.printStackTrace();
140          } catch (InvocationTargetException e) {
141            e.getTargetException().printStackTrace();
142          }
143          if (localValue != null) {
144            if (verbose)
145              System.out.println("localValue = "+localValue);
146            if (localValue instanceof String)
147              // Found the value. It doesn't depend on n in this case.
148              return (String)localValue;
149            else {
150              String[] pluralforms = (String[])localValue;
151              long i = 0;
152              try {
153                i = ((Long) pluralEvalMethod.invoke(catalog, new Object[] { new Long(n) })).longValue();
154                if (!(i >= 0 && i < pluralforms.length))
155                  i = 0;
156              } catch (IllegalAccessException e) {
157                e.printStackTrace();
158              } catch (InvocationTargetException e) {
159                e.getTargetException().printStackTrace();
160              }
161              return pluralforms[(int)i];
162            }
163          }
164        } else {
165          // A GNU gettext created class without plural handling.
166          Object localValue = null;
167          try {
168            localValue = handleGetObjectMethod.invoke(catalog, new Object[] { msgid });
169          } catch (IllegalAccessException e) {
170            e.printStackTrace();
171          } catch (InvocationTargetException e) {
172            e.getTargetException().printStackTrace();
173          }
174          if (localValue != null) {
175            // Found the value. It doesn't depend on n in this case.
176            if (verbose)
177              System.out.println("localValue = "+localValue);
178            return (String)localValue;
179          }
180        }
181        Object parentCatalog = catalog;
182        try {
183          parentCatalog = getParentMethod.invoke(catalog, new Object[0]);
184        } catch (IllegalAccessException e) {
185          e.printStackTrace();
186        } catch (InvocationTargetException e) {
187          e.getTargetException().printStackTrace();
188        }
189        if (parentCatalog != catalog)
190          catalog = (ResourceBundle)parentCatalog;
191        else
192          break;
193      } else
194        // Not a GNU gettext created class.
195        break;
196    } while (catalog != null);
197    // The end of chain of GNU gettext ResourceBundles is reached.
198    if (catalog != null) {
199      // For a non-GNU ResourceBundle we cannot access 'parent' and
200      // 'handleGetObject', so make a single call to catalog and all
201      // its parent catalogs at once.
202      Object value;
203      try {
204        value = catalog.getObject(msgid);
205      } catch (MissingResourceException e) {
206        value = null;
207      }
208      if (value != null)
209        // Found the value. It doesn't depend on n in this case.
210        return (String)value;
211    }
212    // Default: null.
213    return null;
214  }
215
216  /**
217   * Returns the plural form for <VAR>n</VAR> of the translation of
218   * <VAR>msgid</VAR>.
219   * @param catalog a ResourceBundle
220   * @param msgid the key string to be translated, an ASCII string
221   * @param msgid_plural its English plural form
222   * @return the translation of <VAR>msgid</VAR> depending on <VAR>n</VAR>,
223   *         or <VAR>msgid</VAR> or <VAR>msgid_plural</VAR> if none is found
224   */
225  public static String ngettext (ResourceBundle catalog, String msgid, String msgid_plural, long n) {
226    String result = ngettextnull(catalog,msgid,n);
227    if (result != null)
228      return result;
229    // Default: English strings and Germanic plural rule.
230    return (n != 1 ? msgid_plural : msgid);
231  }
232
233  /* The separator between msgctxt and msgid.  */
234  private static final String CONTEXT_GLUE = "\u0004";
235
236  /**
237   * Returns the translation of <VAR>msgid</VAR> in the context of
238   * <VAR>msgctxt</VAR>.
239   * @param catalog a ResourceBundle
240   * @param msgctxt the context for the key string, an ASCII string
241   * @param msgid the key string to be translated, an ASCII string
242   * @return the translation of <VAR>msgid</VAR>, or <VAR>msgid</VAR> if
243   *         none is found
244   */
245  public static String pgettext (ResourceBundle catalog, String msgctxt, String msgid) {
246    String result = gettextnull(catalog,msgctxt+CONTEXT_GLUE+msgid);
247    if (result != null)
248      return result;
249    return msgid;
250  }
251
252  /**
253   * Returns the plural form for <VAR>n</VAR> of the translation of
254   * <VAR>msgid</VAR> in the context of <VAR>msgctxt</VAR>.
255   * @param catalog a ResourceBundle
256   * @param msgctxt the context for the key string, an ASCII string
257   * @param msgid the key string to be translated, an ASCII string
258   * @param msgid_plural its English plural form
259   * @return the translation of <VAR>msgid</VAR> depending on <VAR>n</VAR>,
260   *         or <VAR>msgid</VAR> or <VAR>msgid_plural</VAR> if none is found
261   */
262  public static String npgettext (ResourceBundle catalog, String msgctxt, String msgid, String msgid_plural, long n) {
263    String result = ngettextnull(catalog,msgctxt+CONTEXT_GLUE+msgid,n);
264    if (result != null)
265      return result;
266    // Default: English strings and Germanic plural rule.
267    return (n != 1 ? msgid_plural : msgid);
268  }
269}
270