/* GNU gettext for Java * Copyright (C) 2001, 2007, 2015 Free Software Foundation, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ 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: *

*

* 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; /** * Like gettext(catalog,msgid), except that it returns null * when no translation was found. */ private static String gettextnull (ResourceBundle catalog, String msgid) { try { return (String)catalog.getObject(msgid); } catch (MissingResourceException e) { return null; } } /** * 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) { String result = gettextnull(catalog,msgid); if (result != null) return result; return msgid; } /** * Like ngettext(catalog,msgid,msgid_plural,n), except that it returns * null when no translation was found. */ private static String ngettextnull (ResourceBundle catalog, String msgid, 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: null. return null; } /** * 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) { String result = ngettextnull(catalog,msgid,n); if (result != null) return result; // Default: English strings and Germanic plural rule. return (n != 1 ? msgid_plural : msgid); } /* The separator between msgctxt and msgid. */ private static final String CONTEXT_GLUE = "\u0004"; /** * Returns the translation of msgid in the context of * msgctxt. * @param catalog a ResourceBundle * @param msgctxt the context for the key string, an ASCII string * @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 pgettext (ResourceBundle catalog, String msgctxt, String msgid) { String result = gettextnull(catalog,msgctxt+CONTEXT_GLUE+msgid); if (result != null) return result; return msgid; } /** * Returns the plural form for n of the translation of * msgid in the context of msgctxt. * @param catalog a ResourceBundle * @param msgctxt the context for the key string, an ASCII string * @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 npgettext (ResourceBundle catalog, String msgctxt, String msgid, String msgid_plural, long n) { String result = ngettextnull(catalog,msgctxt+CONTEXT_GLUE+msgid,n); if (result != null) return result; // Default: English strings and Germanic plural rule. return (n != 1 ? msgid_plural : msgid); } }