Move gettext variations into their own files
[platform/upstream/glib.git] / 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  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
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
31 #include "galloca.h"
32 #include "gthread.h"
33
34 #include <string.h>
35 #include <locale.h>
36 #include <libintl.h>
37
38
39 static void
40 ensure_gettext_initialized (void)
41 {
42   static gsize initialised;
43
44   if (g_once_init_enter (&initialised))
45     {
46 #ifdef G_OS_WIN32
47       gchar *tmp = _glib_get_locale_dir ();
48       bindtextdomain (GETTEXT_PACKAGE, tmp);
49       g_free (tmp);
50 #else
51       bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
52 #endif
53 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
54       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
55 #    endif
56       g_once_init_leave (&initialised, TRUE);
57     }
58 }
59
60 /**
61  * glib_gettext:
62  * @str: The string to be translated
63  *
64  * Returns the translated string from the glib translations.
65  * This is an internal function and should only be used by
66  * the internals of glib (such as libgio).
67  *
68  * Returns: the transation of @str to the current locale
69  */
70 const gchar *
71 glib_gettext (const gchar *str)
72 {
73   ensure_gettext_initialized ();
74
75   return g_dgettext (GETTEXT_PACKAGE, str);
76 }
77
78 /**
79  * glib_pgettext:
80  * @msgctxtid: a combined message context and message id, separated
81  *   by a \004 character
82  * @msgidoffset: the offset of the message id in @msgctxid
83  *
84  * This function is a variant of glib_gettext() which supports
85  * a disambiguating message context. See g_dpgettext() for full
86  * details.
87  *
88  * This is an internal function and should only be used by
89  * the internals of glib (such as libgio).
90  *
91  * Returns: the transation of @str to the current locale
92  */
93 const gchar *
94 glib_pgettext (const gchar *msgctxtid,
95                gsize        msgidoffset)
96 {
97   ensure_gettext_initialized ();
98
99   return g_dpgettext (GETTEXT_PACKAGE, msgctxtid, msgidoffset);
100 }
101
102 /**
103  * g_strip_context:
104  * @msgid: a string
105  * @msgval: another string
106  *
107  * An auxiliary function for gettext() support (see Q_()).
108  *
109  * Return value: @msgval, unless @msgval is identical to @msgid
110  *     and contains a '|' character, in which case a pointer to
111  *     the substring of msgid after the first '|' character is returned.
112  *
113  * Since: 2.4
114  */
115 const gchar *
116 g_strip_context (const gchar *msgid,
117                  const gchar *msgval)
118 {
119   if (msgval == msgid)
120     {
121       const char *c = strchr (msgid, '|');
122       if (c != NULL)
123         return c + 1;
124     }
125
126   return msgval;
127 }
128
129 /**
130  * g_dpgettext:
131  * @domain: the translation domain to use, or %NULL to use
132  *   the domain set with textdomain()
133  * @msgctxtid: a combined message context and message id, separated
134  *   by a \004 character
135  * @msgidoffset: the offset of the message id in @msgctxid
136  *
137  * This function is a variant of g_dgettext() which supports
138  * a disambiguating message context. GNU gettext uses the
139  * '\004' character to separate the message context and
140  * message id in @msgctxtid.
141  * If 0 is passed as @msgidoffset, this function will fall back to
142  * trying to use the deprecated convention of using "|" as a separation
143  * character.
144  *
145  * This uses g_dgettext() internally. See that functions for differences
146  * with dgettext() proper.
147  *
148  * Applications should normally not use this function directly,
149  * but use the C_() macro for translations with context.
150  *
151  * Returns: The translated string
152  *
153  * Since: 2.16
154  */
155 const gchar *
156 g_dpgettext (const gchar *domain,
157              const gchar *msgctxtid,
158              gsize        msgidoffset)
159 {
160   const gchar *translation;
161   gchar *sep;
162
163   translation = g_dgettext (domain, msgctxtid);
164
165   if (translation == msgctxtid)
166     {
167       if (msgidoffset > 0)
168         return msgctxtid + msgidoffset;
169       sep = strchr (msgctxtid, '|');
170
171       if (sep)
172         {
173           /* try with '\004' instead of '|', in case
174            * xgettext -kQ_:1g was used
175            */
176           gchar *tmp = g_alloca (strlen (msgctxtid) + 1);
177           strcpy (tmp, msgctxtid);
178           tmp[sep - msgctxtid] = '\004';
179
180           translation = g_dgettext (domain, tmp);
181
182           if (translation == tmp)
183             return sep + 1;
184         }
185     }
186
187   return translation;
188 }
189
190 /* This function is taken from gettext.h
191  * GNU gettext uses '\004' to separate context and msgid in .mo files.
192  */
193 /**
194  * g_dpgettext2:
195  * @domain: the translation domain to use, or %NULL to use
196  *   the domain set with textdomain()
197  * @context: the message context
198  * @msgid: the message
199  *
200  * This function is a variant of g_dgettext() which supports
201  * a disambiguating message context. GNU gettext uses the
202  * '\004' character to separate the message context and
203  * message id in @msgctxtid.
204  *
205  * This uses g_dgettext() internally. See that functions for differences
206  * with dgettext() proper.
207  *
208  * This function differs from C_() in that it is not a macro and
209  * thus you may use non-string-literals as context and msgid arguments.
210  *
211  * Returns: The translated string
212  *
213  * Since: 2.18
214  */
215 const gchar *
216 g_dpgettext2 (const gchar *domain,
217               const gchar *msgctxt,
218               const gchar *msgid)
219 {
220   size_t msgctxt_len = strlen (msgctxt) + 1;
221   size_t msgid_len = strlen (msgid) + 1;
222   const char *translation;
223   char* msg_ctxt_id;
224
225   msg_ctxt_id = g_alloca (msgctxt_len + msgid_len);
226
227   memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
228   msg_ctxt_id[msgctxt_len - 1] = '\004';
229   memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
230
231   translation = g_dgettext (domain, msg_ctxt_id);
232
233   if (translation == msg_ctxt_id)
234     {
235       /* try the old way of doing message contexts, too */
236       msg_ctxt_id[msgctxt_len - 1] = '|';
237       translation = g_dgettext (domain, msg_ctxt_id);
238
239       if (translation == msg_ctxt_id)
240         return msgid;
241     }
242
243   return translation;
244 }
245
246 static gboolean
247 _g_dgettext_should_translate (void)
248 {
249   static gsize translate = 0;
250   enum {
251     SHOULD_TRANSLATE = 1,
252     SHOULD_NOT_TRANSLATE = 2
253   };
254
255   if (G_UNLIKELY (g_once_init_enter (&translate)))
256     {
257       gboolean should_translate = TRUE;
258
259       const char *default_domain     = textdomain (NULL);
260       const char *translator_comment = gettext ("");
261 #ifndef G_OS_WIN32
262       const char *translate_locale   = setlocale (LC_MESSAGES, NULL);
263 #else
264       const char *translate_locale   = g_win32_getlocale ();
265 #endif
266       /* We should NOT translate only if all the following hold:
267        *   - user has called textdomain() and set textdomain to non-default
268        *   - default domain has no translations
269        *   - locale does not start with "en_" and is not "C"
270        *
271        * Rationale:
272        *   - If text domain is still the default domain, maybe user calls
273        *     it later. Continue with old behavior of translating.
274        *   - If locale starts with "en_", we can continue using the
275        *     translations even if the app doesn't have translations for
276        *     this locale.  That is, en_UK and en_CA for example.
277        *   - If locale is "C", maybe user calls setlocale(LC_ALL,"") later.
278        *     Continue with old behavior of translating.
279        */
280       if (0 != strcmp (default_domain, "messages") &&
281           '\0' == *translator_comment &&
282           0 != strncmp (translate_locale, "en_", 3) &&
283           0 != strcmp (translate_locale, "C"))
284         should_translate = FALSE;
285
286       g_once_init_leave (&translate,
287                          should_translate ?
288                          SHOULD_TRANSLATE :
289                          SHOULD_NOT_TRANSLATE);
290     }
291
292   return translate == SHOULD_TRANSLATE;
293 }
294
295 /**
296  * g_dgettext:
297  * @domain: the translation domain to use, or %NULL to use
298  *   the domain set with textdomain()
299  * @msgid: message to translate
300  *
301  * This function is a wrapper of dgettext() which does not translate
302  * the message if the default domain as set with textdomain() has no
303  * translations for the current locale.
304  *
305  * The advantage of using this function over dgettext() proper is that
306  * libraries using this function (like GTK+) will not use translations
307  * if the application using the library does not have translations for
308  * the current locale.  This results in a consistent English-only
309  * interface instead of one having partial translations.  For this
310  * feature to work, the call to textdomain() and setlocale() should
311  * precede any g_dgettext() invocations.  For GTK+, it means calling
312  * textdomain() before gtk_init or its variants.
313  *
314  * This function disables translations if and only if upon its first
315  * call all the following conditions hold:
316  * <itemizedlist>
317  * <listitem>@domain is not %NULL</listitem>
318  * <listitem>textdomain() has been called to set a default text domain</listitem>
319  * <listitem>there is no translations available for the default text domain
320  *           and the current locale</listitem>
321  * <listitem>current locale is not "C" or any English locales (those
322  *           starting with "en_")</listitem>
323  * </itemizedlist>
324  *
325  * Note that this behavior may not be desired for example if an application
326  * has its untranslated messages in a language other than English.  In those
327  * cases the application should call textdomain() after initializing GTK+.
328  *
329  * Applications should normally not use this function directly,
330  * but use the _() macro for translations.
331  *
332  * Returns: The translated string
333  *
334  * Since: 2.18
335  */
336 const gchar *
337 g_dgettext (const gchar *domain,
338             const gchar *msgid)
339 {
340   if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
341     return msgid;
342
343   return dgettext (domain, msgid);
344 }
345
346 /**
347  * g_dcgettext:
348  * @domain: (allow-none): the translation domain to use, or %NULL to use
349  *   the domain set with textdomain()
350  * @msgid: message to translate
351  * @category: a locale category
352  *
353  * This is a variant of g_dgettext() that allows specifying a locale
354  * category instead of always using %LC_MESSAGES. See g_dgettext() for
355  * more information about how this functions differs from calling
356  * dcgettext() directly.
357  *
358  * Returns: the translated string for the given locale category
359  *
360  * Since: 2.26
361  */
362 const gchar *
363 g_dcgettext (const gchar *domain,
364              const gchar *msgid,
365              gint         category)
366 {
367   if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
368     return msgid;
369
370   return dcgettext (domain, msgid, category);
371 }
372
373 /**
374  * g_dngettext:
375  * @domain: the translation domain to use, or %NULL to use
376  *   the domain set with textdomain()
377  * @msgid: message to translate
378  * @msgid_plural: plural form of the message
379  * @n: the quantity for which translation is needed
380  *
381  * This function is a wrapper of dngettext() which does not translate
382  * the message if the default domain as set with textdomain() has no
383  * translations for the current locale.
384  *
385  * See g_dgettext() for details of how this differs from dngettext()
386  * proper.
387  *
388  * Returns: The translated string
389  *
390  * Since: 2.18
391  */
392 const gchar *
393 g_dngettext (const gchar *domain,
394              const gchar *msgid,
395              const gchar *msgid_plural,
396              gulong       n)
397 {
398   if (domain && G_UNLIKELY (!_g_dgettext_should_translate ()))
399     return n == 1 ? msgid : msgid_plural;
400
401   return dngettext (domain, msgid, msgid_plural, n);
402 }