(root)/
glib-2.79.0/
glib/
ggettext.c
       1  /* GLIB - Library of useful routines for C programming
       2   * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  /*
      21   * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
      22   * file for a list of people on the GLib Team.  See the ChangeLog
      23   * files for a list of changes.  These files are distributed with
      24   * GLib at ftp://ftp.gtk.org/pub/gtk/. 
      25   */
      26  
      27  #include "config.h"
      28  
      29  #include "ggettext.h"
      30  #include "glibintl.h"
      31  #include "glib-private.h"
      32  
      33  #include "galloca.h"
      34  #include "gthread.h"
      35  #include "gmem.h"
      36  #ifdef G_OS_WIN32
      37  #include "gwin32.h"
      38  #include "gfileutils.h"
      39  #include "gstrfuncs.h"
      40  #include "glib-init.h"
      41  #endif
      42  
      43  #include <string.h>
      44  #include <locale.h>
      45  #include <libintl.h>
      46  
      47  #ifdef G_OS_WIN32
      48  
      49  /**
      50   * _glib_get_locale_dir:
      51   *
      52   * Return the path to the share\locale or lib\locale subfolder of the
      53   * GLib installation folder. The path is in the system codepage. We
      54   * have to use system codepage as bindtextdomain() doesn't have a
      55   * UTF-8 interface.
      56   */
      57  gchar *
      58  _glib_get_locale_dir (void)
      59  {
      60    gchar *install_dir = NULL, *locale_dir;
      61    gchar *retval = NULL;
      62  
      63    if (glib_dll != NULL)
      64      install_dir = g_win32_get_package_installation_directory_of_module (glib_dll);
      65  
      66    if (install_dir)
      67      {
      68        /*
      69         * Append "/share/locale" or "/lib/locale" depending on whether
      70         * autoconfigury detected GNU gettext or not.
      71         */
      72        const char *p = GLIB_LOCALE_DIR + strlen (GLIB_LOCALE_DIR);
      73        while (*--p != '/')
      74  	;
      75        while (*--p != '/')
      76  	;
      77  
      78        locale_dir = g_build_filename (install_dir, p, NULL);
      79  
      80        retval = g_win32_locale_filename_from_utf8 (locale_dir);
      81  
      82        g_free (install_dir);
      83        g_free (locale_dir);
      84      }
      85  
      86    if (retval)
      87      return retval;
      88    else
      89      return g_strdup ("");
      90  }
      91  
      92  #undef GLIB_LOCALE_DIR
      93  
      94  #endif /* G_OS_WIN32 */
      95  
      96  
      97  static void
      98  ensure_gettext_initialized (void)
      99  {
     100    static gsize initialised;
     101  
     102    if (g_once_init_enter (&initialised))
     103      {
     104  #ifdef G_OS_WIN32
     105        gchar *tmp = _glib_get_locale_dir ();
     106        bindtextdomain (GETTEXT_PACKAGE, tmp);
     107        g_free (tmp);
     108  #else
     109        bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
     110  #endif
     111  #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
     112        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
     113  #    endif
     114        g_once_init_leave (&initialised, TRUE);
     115      }
     116  }
     117  
     118  /**
     119   * glib_gettext:
     120   * @str: The string to be translated
     121   *
     122   * Returns the translated string from the glib translations.
     123   * This is an internal function and should only be used by
     124   * the internals of glib (such as libgio).
     125   *
     126   * Returns: the translation of @str to the current locale
     127   */
     128  const gchar *
     129  glib_gettext (const gchar *str)
     130  {
     131    ensure_gettext_initialized ();
     132  
     133    return g_dgettext (GETTEXT_PACKAGE, str);
     134  }
     135  
     136  /**
     137   * glib_pgettext:
     138   * @msgctxtid: a combined message context and message id, separated
     139   *   by a \004 character
     140   * @msgidoffset: the offset of the message id in @msgctxid
     141   *
     142   * This function is a variant of glib_gettext() which supports
     143   * a disambiguating message context. See g_dpgettext() for full
     144   * details.
     145   *
     146   * This is an internal function and should only be used by
     147   * the internals of glib (such as libgio).
     148   *
     149   * Returns: the translation of @str to the current locale
     150   */
     151  const gchar *
     152  glib_pgettext (const gchar *msgctxtid,
     153                 gsize        msgidoffset)
     154  {
     155    ensure_gettext_initialized ();
     156  
     157    return g_dpgettext (GETTEXT_PACKAGE, msgctxtid, msgidoffset);
     158  }
     159  
     160  /**
     161   * g_strip_context:
     162   * @msgid: a string
     163   * @msgval: another string
     164   *
     165   * An auxiliary function for gettext() support (see Q_()).
     166   *
     167   * Returns: @msgval, unless @msgval is identical to @msgid
     168   *     and contains a '|' character, in which case a pointer to
     169   *     the substring of msgid after the first '|' character is returned.
     170   *
     171   * Since: 2.4
     172   */
     173  const gchar *
     174  g_strip_context (const gchar *msgid,
     175                   const gchar *msgval)
     176  {
     177    if (msgval == msgid)
     178      {
     179        const char *c = strchr (msgid, '|');
     180        if (c != NULL)
     181          return c + 1;
     182      }
     183  
     184    return msgval;
     185  }
     186  
     187  /**
     188   * g_dpgettext:
     189   * @domain: (nullable): the translation domain to use, or %NULL to use
     190   *   the domain set with textdomain()
     191   * @msgctxtid: a combined message context and message id, separated
     192   *   by a \004 character
     193   * @msgidoffset: the offset of the message id in @msgctxid
     194   *
     195   * This function is a variant of g_dgettext() which supports
     196   * a disambiguating message context. GNU gettext uses the
     197   * '\004' character to separate the message context and
     198   * message id in @msgctxtid.
     199   * If 0 is passed as @msgidoffset, this function will fall back to
     200   * trying to use the deprecated convention of using "|" as a separation
     201   * character.
     202   *
     203   * This uses g_dgettext() internally. See that functions for differences
     204   * with dgettext() proper.
     205   *
     206   * Applications should normally not use this function directly,
     207   * but use the C_() macro for translations with context.
     208   *
     209   * Returns: The translated string
     210   *
     211   * Since: 2.16
     212   */
     213  const gchar *
     214  g_dpgettext (const gchar *domain,
     215               const gchar *msgctxtid,
     216               gsize        msgidoffset)
     217  {
     218    const gchar *translation;
     219    gchar *sep;
     220  
     221    translation = g_dgettext (domain, msgctxtid);
     222  
     223    if (translation == msgctxtid)
     224      {
     225        if (msgidoffset > 0)
     226          return msgctxtid + msgidoffset;
     227        sep = strchr (msgctxtid, '|');
     228  
     229        if (sep)
     230          {
     231            /* try with '\004' instead of '|', in case
     232             * xgettext -kQ_:1g was used
     233             */
     234            gchar *tmp = g_alloca (strlen (msgctxtid) + 1);
     235            strcpy (tmp, msgctxtid);
     236            tmp[sep - msgctxtid] = '\004';
     237  
     238            translation = g_dgettext (domain, tmp);
     239  
     240            if (translation == tmp)
     241              return sep + 1;
     242          }
     243      }
     244  
     245    return translation;
     246  }
     247  
     248  /* This function is taken from gettext.h
     249   * GNU gettext uses '\004' to separate context and msgid in .mo files.
     250   */
     251  /**
     252   * g_dpgettext2:
     253   * @domain: (nullable): the translation domain to use, or %NULL to use
     254   *   the domain set with textdomain()
     255   * @context: the message context
     256   * @msgid: the message
     257   *
     258   * This function is a variant of g_dgettext() which supports
     259   * a disambiguating message context. GNU gettext uses the
     260   * '\004' character to separate the message context and
     261   * message id in @msgctxtid.
     262   *
     263   * This uses g_dgettext() internally. See that functions for differences
     264   * with dgettext() proper.
     265   *
     266   * This function differs from C_() in that it is not a macro and
     267   * thus you may use non-string-literals as context and msgid arguments.
     268   *
     269   * Returns: The translated string
     270   *
     271   * Since: 2.18
     272   */
     273  const gchar *
     274  g_dpgettext2 (const gchar *domain,
     275                const gchar *msgctxt,
     276                const gchar *msgid)
     277  {
     278    size_t msgctxt_len = strlen (msgctxt) + 1;
     279    size_t msgid_len = strlen (msgid) + 1;
     280    const char *translation;
     281    char* msg_ctxt_id;
     282  
     283    msg_ctxt_id = g_alloca (msgctxt_len + msgid_len);
     284  
     285    memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
     286    msg_ctxt_id[msgctxt_len - 1] = '\004';
     287    memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
     288  
     289    translation = g_dgettext (domain, msg_ctxt_id);
     290  
     291    if (translation == msg_ctxt_id)
     292      {
     293        /* try the old way of doing message contexts, too */
     294        msg_ctxt_id[msgctxt_len - 1] = '|';
     295        translation = g_dgettext (domain, msg_ctxt_id);
     296  
     297        if (translation == msg_ctxt_id)
     298          return msgid;
     299      }
     300  
     301    return translation;
     302  }
     303  
     304  static gboolean
     305  _g_dgettext_should_translate (void)
     306  {
     307    static gsize translate = 0;
     308    enum {
     309      SHOULD_TRANSLATE = 1,
     310      SHOULD_NOT_TRANSLATE = 2
     311    };
     312  
     313    if (G_UNLIKELY (g_once_init_enter (&translate)))
     314      {
     315        gboolean should_translate = TRUE;
     316  
     317        const char *default_domain     = textdomain (NULL);
     318        const char *translator_comment = gettext ("");
     319  #ifndef G_OS_WIN32
     320        const char *translate_locale   = setlocale (LC_MESSAGES, NULL);
     321  #else
     322        const char *translate_locale   = g_win32_getlocale ();
     323  #endif
     324        /* We should NOT translate only if all the following hold:
     325         *   - user has called textdomain() and set textdomain to non-default
     326         *   - default domain has no translations
     327         *   - locale does not start with "en_" and is not "C"
     328         *
     329         * Rationale:
     330         *   - If text domain is still the default domain, maybe user calls
     331         *     it later. Continue with old behavior of translating.
     332         *   - If locale starts with "en_", we can continue using the
     333         *     translations even if the app doesn't have translations for
     334         *     this locale.  That is, en_UK and en_CA for example.
     335         *   - If locale is "C", maybe user calls setlocale(LC_ALL,"") later.
     336         *     Continue with old behavior of translating.
     337         */
     338        if (!default_domain || !translator_comment || !translate_locale ||
     339            (0 != strcmp (default_domain, "messages") &&
     340            '\0' == *translator_comment &&
     341            0 != strncmp (translate_locale, "en_", 3) &&
     342            0 != strcmp (translate_locale, "C")))
     343          should_translate = FALSE;
     344  
     345        g_once_init_leave (&translate,
     346                           should_translate ?
     347                           SHOULD_TRANSLATE :
     348                           SHOULD_NOT_TRANSLATE);
     349      }
     350  
     351    return translate == SHOULD_TRANSLATE;
     352  }
     353  
     354  /**
     355   * g_dgettext:
     356   * @domain: (nullable): the translation domain to use, or %NULL to use
     357   *   the domain set with textdomain()
     358   * @msgid: message to translate
     359   *
     360   * This function is a wrapper of dgettext() which does not translate
     361   * the message if the default domain as set with textdomain() has no
     362   * translations for the current locale.
     363   *
     364   * The advantage of using this function over dgettext() proper is that
     365   * libraries using this function (like GTK) will not use translations
     366   * if the application using the library does not have translations for
     367   * the current locale.  This results in a consistent English-only
     368   * interface instead of one having partial translations.  For this
     369   * feature to work, the call to textdomain() and setlocale() should
     370   * precede any g_dgettext() invocations.  For GTK, it means calling
     371   * textdomain() before gtk_init or its variants.
     372   *
     373   * This function disables translations if and only if upon its first
     374   * call all the following conditions hold:
     375   * 
     376   * - @domain is not %NULL
     377   *
     378   * - textdomain() has been called to set a default text domain
     379   *
     380   * - there is no translations available for the default text domain
     381   *   and the current locale
     382   *
     383   * - current locale is not "C" or any English locales (those
     384   *   starting with "en_")
     385   *
     386   * Note that this behavior may not be desired for example if an application
     387   * has its untranslated messages in a language other than English. In those
     388   * cases the application should call textdomain() after initializing GTK.
     389   *
     390   * Applications should normally not use this function directly,
     391   * but use the _() macro for translations.
     392   *
     393   * Returns: The translated string
     394   *
     395   * Since: 2.18
     396   */
     397  const gchar *
     398  g_dgettext (const gchar *domain,
     399              const gchar *msgid)
     400  {
     401    if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
     402      return msgid;
     403  
     404    return dgettext (domain, msgid);
     405  }
     406  
     407  /**
     408   * g_dcgettext:
     409   * @domain: (nullable): the translation domain to use, or %NULL to use
     410   *   the domain set with textdomain()
     411   * @msgid: message to translate
     412   * @category: a locale category
     413   *
     414   * This is a variant of g_dgettext() that allows specifying a locale
     415   * category instead of always using `LC_MESSAGES`. See g_dgettext() for
     416   * more information about how this functions differs from calling
     417   * dcgettext() directly.
     418   *
     419   * Returns: the translated string for the given locale category
     420   *
     421   * Since: 2.26
     422   */
     423  const gchar *
     424  g_dcgettext (const gchar *domain,
     425               const gchar *msgid,
     426               gint         category)
     427  {
     428    if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
     429      return msgid;
     430  
     431    return dcgettext (domain, msgid, category);
     432  }
     433  
     434  /**
     435   * g_dngettext:
     436   * @domain: (nullable): the translation domain to use, or %NULL to use
     437   *   the domain set with textdomain()
     438   * @msgid: message to translate
     439   * @msgid_plural: plural form of the message
     440   * @n: the quantity for which translation is needed
     441   *
     442   * This function is a wrapper of dngettext() which does not translate
     443   * the message if the default domain as set with textdomain() has no
     444   * translations for the current locale.
     445   *
     446   * See g_dgettext() for details of how this differs from dngettext()
     447   * proper.
     448   *
     449   * Returns: The translated string
     450   *
     451   * Since: 2.18
     452   */
     453  const gchar *
     454  g_dngettext (const gchar *domain,
     455               const gchar *msgid,
     456               const gchar *msgid_plural,
     457               gulong       n)
     458  {
     459    if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
     460      return n == 1 ? msgid : msgid_plural;
     461  
     462    return dngettext (domain, msgid, msgid_plural, n);
     463  }
     464  
     465  /**
     466   * _:
     467   * @String: the string to be translated
     468   *
     469   * Marks a string for translation, gets replaced with the translated string
     470   * at runtime.
     471   *
     472   * Since: 2.4
     473   */
     474  
     475  /**
     476   * Q_:
     477   * @String: the string to be translated, with a '|'-separated prefix
     478   *     which must not be translated
     479   *
     480   * Like _(), but handles context in message ids. This has the advantage
     481   * that the string can be adorned with a prefix to guarantee uniqueness
     482   * and provide context to the translator.
     483   *
     484   * One use case given in the gettext manual is GUI translation, where one
     485   * could e.g. disambiguate two "Open" menu entries as "File|Open" and
     486   * "Printer|Open". Another use case is the string "Russian" which may
     487   * have to be translated differently depending on whether it's the name
     488   * of a character set or a language. This could be solved by using
     489   * "charset|Russian" and "language|Russian".
     490   *
     491   * See the C_() macro for a different way to mark up translatable strings
     492   * with context.
     493   *
     494   * If you are using the Q_() macro, you need to make sure that you pass
     495   * `--keyword=Q_` to xgettext when extracting messages.
     496   * If you are using GNU gettext >= 0.15, you can also use
     497   * `--keyword=Q_:1g` to let xgettext split the context
     498   * string off into a msgctxt line in the po file.
     499   *
     500   * Returns: the translated message
     501   *
     502   * Since: 2.4
     503   */
     504  
     505  /**
     506   * C_:
     507   * @Context: a message context, must be a string literal
     508   * @String: a message id, must be a string literal
     509   *
     510   * Uses gettext to get the translation for @String. @Context is
     511   * used as a context. This is mainly useful for short strings which
     512   * may need different translations, depending on the context in which
     513   * they are used.
     514   * |[<!-- language="C" -->
     515   * label1 = C_("Navigation", "Back");
     516   * label2 = C_("Body part", "Back");
     517   * ]|
     518   *
     519   * If you are using the C_() macro, you need to make sure that you pass
     520   * `--keyword=C_:1c,2` to xgettext when extracting messages.
     521   * Note that this only works with GNU gettext >= 0.15.
     522   *
     523   * Returns: the translated message
     524   *
     525   * Since: 2.16
     526   */
     527  
     528  /**
     529   * N_:
     530   * @String: the string to be translated
     531   *
     532   * Only marks a string for translation. This is useful in situations
     533   * where the translated strings can't be directly used, e.g. in string
     534   * array initializers. To get the translated string, call gettext()
     535   * at runtime.
     536   * |[<!-- language="C" -->
     537   * {
     538   *   static const char *messages[] = {
     539   *     N_("some very meaningful message"),
     540   *     N_("and another one")
     541   *   };
     542   *   const char *string;
     543   *   ...
     544   *   string
     545   *     = index &gt; 1 ? _("a default message") : gettext (messages[index]);
     546   *
     547   *   fputs (string);
     548   *   ...
     549   * }
     550   * ]|
     551   *
     552   * Since: 2.4
     553   */
     554  
     555  /**
     556   * NC_:
     557   * @Context: a message context, must be a string literal
     558   * @String: a message id, must be a string literal
     559   *
     560   * Only marks a string for translation, with context.
     561   * This is useful in situations where the translated strings can't
     562   * be directly used, e.g. in string array initializers. To get the
     563   * translated string, you should call g_dpgettext2() at runtime.
     564   *
     565   * |[<!-- language="C" -->
     566   * {
     567   *   static const char *messages[] = {
     568   *     NC_("some context", "some very meaningful message"),
     569   *     NC_("some context", "and another one")
     570   *   };
     571   *   const char *string;
     572   *   ...
     573   *   string
     574   *     = index > 1 ? g_dpgettext2 (NULL, "some context", "a default message")
     575   *                 : g_dpgettext2 (NULL, "some context", messages[index]);
     576   *
     577   *   fputs (string);
     578   *   ...
     579   * }
     580   * ]|
     581   *
     582   * If you are using the NC_() macro, you need to make sure that you pass
     583   * `--keyword=NC_:1c,2` to xgettext when extracting messages.
     584   * Note that this only works with GNU gettext >= 0.15. Intltool has support
     585   * for the NC_() macro since version 0.40.1.
     586   *
     587   * Since: 2.18
     588   */