/* GNU gettext for Java * Copyright (C) 2001 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. */ package gnu.gettext; import java.lang.reflect.*; import java.util.*; /** * This class implements the main GNU libintl functions in Java. *
* Using the GNU gettext approach, compiled message catalogs are normal * Java ResourceBundle classes and are thus interoperable with standard * ResourceBundle based code. *
* The main differences between the Sun ResourceBundle approach and the * GNU gettext approach are: *
\
unnnn
syntax. Very few editors
* can natively display international characters in this format. In the
* GNU gettext approach, the translation files are called
* "Resource.locale.po"
* and are in the encoding the translator has chosen. Many editors
* can be used. There are at least three GUI translating tools
* (Emacs PO mode, KDE KBabel, GNOME gtranslator).
* ResourceBundle.getString
throws a
* MissingResourceException
when no translation is found.
* In the GNU gettext approach, the gettext
function
* returns the (English) message key in that case.
* ngettext
function.
*
* To compile GNU gettext message catalogs into Java ResourceBundle classes,
* the msgfmt
program can be used.
*
* @author Bruno Haible
*/
public abstract class GettextResource extends ResourceBundle {
public static boolean verbose = false;
/**
* Returns the translation of msgid.
* @param catalog a ResourceBundle
* @param msgid the key string to be translated, an ASCII string
* @return the translation of msgid, or msgid if
* none is found
*/
public static String gettext (ResourceBundle catalog, String msgid) {
try {
String result = (String)catalog.getObject(msgid);
if (result != null)
return result;
} catch (MissingResourceException e) {
}
return msgid;
}
/**
* Returns the plural form for n of the translation of
* msgid.
* @param catalog a ResourceBundle
* @param msgid the key string to be translated, an ASCII string
* @param msgid_plural its English plural form
* @return the translation of msgid depending on n,
* or msgid or msgid_plural if none is found
*/
public static String ngettext (ResourceBundle catalog, String msgid, String msgid_plural, long n) {
// The reason why we use so many reflective API calls instead of letting
// the GNU gettext generated ResourceBundles implement some interface,
// is that we want the generated ResourceBundles to be completely
// standalone, so that migration from the Sun approach to the GNU gettext
// approach (without use of plurals) is as straightforward as possible.
ResourceBundle origCatalog = catalog;
do {
// Try catalog itself.
if (verbose)
System.out.println("ngettext on "+catalog);
Method handleGetObjectMethod = null;
Method getParentMethod = null;
try {
handleGetObjectMethod = catalog.getClass().getMethod("handleGetObject", new Class[] { java.lang.String.class });
getParentMethod = catalog.getClass().getMethod("getParent", new Class[0]);
} catch (NoSuchMethodException e) {
} catch (SecurityException e) {
}
if (verbose)
System.out.println("handleGetObject = "+(handleGetObjectMethod!=null)+", getParent = "+(getParentMethod!=null));
if (handleGetObjectMethod != null
&& Modifier.isPublic(handleGetObjectMethod.getModifiers())
&& getParentMethod != null) {
// A GNU gettext created class.
Method lookupMethod = null;
Method pluralEvalMethod = null;
try {
lookupMethod = catalog.getClass().getMethod("lookup", new Class[] { java.lang.String.class });
pluralEvalMethod = catalog.getClass().getMethod("pluralEval", new Class[] { Long.TYPE });
} catch (NoSuchMethodException e) {
} catch (SecurityException e) {
}
if (verbose)
System.out.println("lookup = "+(lookupMethod!=null)+", pluralEval = "+(pluralEvalMethod!=null));
if (lookupMethod != null && pluralEvalMethod != null) {
// A GNU gettext created class with plural handling.
Object localValue = null;
try {
localValue = lookupMethod.invoke(catalog, new Object[] { msgid });
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
}
if (localValue != null) {
if (verbose)
System.out.println("localValue = "+localValue);
if (localValue instanceof String)
// Found the value. It doesn't depend on n in this case.
return (String)localValue;
else {
String[] pluralforms = (String[])localValue;
long i = 0;
try {
i = ((Long) pluralEvalMethod.invoke(catalog, new Object[] { new Long(n) })).longValue();
if (!(i >= 0 && i < pluralforms.length))
i = 0;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
}
return pluralforms[(int)i];
}
}
} else {
// A GNU gettext created class without plural handling.
Object localValue = null;
try {
localValue = handleGetObjectMethod.invoke(catalog, new Object[] { msgid });
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
}
if (localValue != null) {
// Found the value. It doesn't depend on n in this case.
if (verbose)
System.out.println("localValue = "+localValue);
return (String)localValue;
}
}
Object parentCatalog = catalog;
try {
parentCatalog = getParentMethod.invoke(catalog, new Object[0]);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
}
if (parentCatalog != catalog)
catalog = (ResourceBundle)parentCatalog;
else
break;
} else
// Not a GNU gettext created class.
break;
} while (catalog != null);
// The end of chain of GNU gettext ResourceBundles is reached.
if (catalog != null) {
// For a non-GNU ResourceBundle we cannot access 'parent' and
// 'handleGetObject', so make a single call to catalog and all
// its parent catalogs at once.
Object value;
try {
value = catalog.getObject(msgid);
} catch (MissingResourceException e) {
value = null;
}
if (value != null)
// Found the value. It doesn't depend on n in this case.
return (String)value;
}
// Default: English strings and Germanic plural rule.
return (n != 1 ? msgid_plural : msgid);
}
}