/src/tinysparql/subprojects/glib-2.80.3/glib/ggettext.c
Line | Count | Source (jump to first uncovered line) |
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 | 890 | { |
100 | 890 | static gsize initialised; |
101 | | |
102 | 890 | if (g_once_init_enter (&initialised)) |
103 | 4 | { |
104 | | #ifdef G_OS_WIN32 |
105 | | gchar *tmp = _glib_get_locale_dir (); |
106 | | bindtextdomain (GETTEXT_PACKAGE, tmp); |
107 | | g_free (tmp); |
108 | | #else |
109 | 4 | bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR); |
110 | 4 | #endif |
111 | 4 | # ifdef HAVE_BIND_TEXTDOMAIN_CODESET |
112 | 4 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); |
113 | 4 | # endif |
114 | 4 | g_once_init_leave (&initialised, TRUE); |
115 | 4 | } |
116 | 890 | } |
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 | 890 | { |
131 | 890 | ensure_gettext_initialized (); |
132 | | |
133 | 890 | return g_dgettext (GETTEXT_PACKAGE, str); |
134 | 890 | } |
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 | 0 | { |
155 | 0 | ensure_gettext_initialized (); |
156 | |
|
157 | 0 | return g_dpgettext (GETTEXT_PACKAGE, msgctxtid, msgidoffset); |
158 | 0 | } |
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 | 0 | { |
177 | 0 | if (msgval == msgid) |
178 | 0 | { |
179 | 0 | const char *c = strchr (msgid, '|'); |
180 | 0 | if (c != NULL) |
181 | 0 | return c + 1; |
182 | 0 | } |
183 | | |
184 | 0 | return msgval; |
185 | 0 | } |
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 | 0 | { |
218 | 0 | const gchar *translation; |
219 | 0 | gchar *sep; |
220 | |
|
221 | 0 | translation = g_dgettext (domain, msgctxtid); |
222 | |
|
223 | 0 | if (translation == msgctxtid) |
224 | 0 | { |
225 | 0 | if (msgidoffset > 0) |
226 | 0 | return msgctxtid + msgidoffset; |
227 | 0 | sep = strchr (msgctxtid, '|'); |
228 | |
|
229 | 0 | if (sep) |
230 | 0 | { |
231 | | /* try with '\004' instead of '|', in case |
232 | | * xgettext -kQ_:1g was used |
233 | | */ |
234 | 0 | gchar *tmp = g_alloca (strlen (msgctxtid) + 1); |
235 | 0 | strcpy (tmp, msgctxtid); |
236 | 0 | tmp[sep - msgctxtid] = '\004'; |
237 | |
|
238 | 0 | translation = g_dgettext (domain, tmp); |
239 | |
|
240 | 0 | if (translation == tmp) |
241 | 0 | return sep + 1; |
242 | 0 | } |
243 | 0 | } |
244 | | |
245 | 0 | return translation; |
246 | 0 | } |
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 | 0 | { |
278 | 0 | size_t msgctxt_len = strlen (msgctxt) + 1; |
279 | 0 | size_t msgid_len = strlen (msgid) + 1; |
280 | 0 | const char *translation; |
281 | 0 | char* msg_ctxt_id; |
282 | |
|
283 | 0 | msg_ctxt_id = g_alloca (msgctxt_len + msgid_len); |
284 | |
|
285 | 0 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); |
286 | 0 | msg_ctxt_id[msgctxt_len - 1] = '\004'; |
287 | 0 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); |
288 | |
|
289 | 0 | translation = g_dgettext (domain, msg_ctxt_id); |
290 | |
|
291 | 0 | if (translation == msg_ctxt_id) |
292 | 0 | { |
293 | | /* try the old way of doing message contexts, too */ |
294 | 0 | msg_ctxt_id[msgctxt_len - 1] = '|'; |
295 | 0 | translation = g_dgettext (domain, msg_ctxt_id); |
296 | |
|
297 | 0 | if (translation == msg_ctxt_id) |
298 | 0 | return msgid; |
299 | 0 | } |
300 | | |
301 | 0 | return translation; |
302 | 0 | } |
303 | | |
304 | | static gboolean |
305 | | _g_dgettext_should_translate (void) |
306 | 6.05M | { |
307 | 6.05M | static gsize translate = 0; |
308 | 6.05M | enum { |
309 | 6.05M | SHOULD_TRANSLATE = 1, |
310 | 6.05M | SHOULD_NOT_TRANSLATE = 2 |
311 | 6.05M | }; |
312 | | |
313 | 6.05M | if (G_UNLIKELY (g_once_init_enter (&translate))) |
314 | 4 | { |
315 | 4 | gboolean should_translate = TRUE; |
316 | | |
317 | 4 | const char *default_domain = textdomain (NULL); |
318 | 4 | const char *translator_comment = gettext (""); |
319 | 4 | #ifndef G_OS_WIN32 |
320 | 4 | 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 | 4 | if (!default_domain || !translator_comment || !translate_locale || |
339 | 4 | (0 != strcmp (default_domain, "messages") && |
340 | 4 | '\0' == *translator_comment && |
341 | 4 | 0 != strncmp (translate_locale, "en_", 3) && |
342 | 4 | 0 != strcmp (translate_locale, "C"))) |
343 | 0 | should_translate = FALSE; |
344 | | |
345 | 4 | g_once_init_leave (&translate, |
346 | 4 | should_translate ? |
347 | 4 | SHOULD_TRANSLATE : |
348 | 4 | SHOULD_NOT_TRANSLATE); |
349 | 4 | } |
350 | | |
351 | 6.05M | return translate == SHOULD_TRANSLATE; |
352 | 6.05M | } |
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 | 6.05M | { |
401 | 6.05M | if (domain && G_UNLIKELY (!_g_dgettext_should_translate ())) |
402 | 0 | return msgid; |
403 | | |
404 | 6.05M | return dgettext (domain, msgid); |
405 | 6.05M | } |
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 | 0 | { |
428 | 0 | if (domain && G_UNLIKELY (!_g_dgettext_should_translate ())) |
429 | 0 | return msgid; |
430 | | |
431 | 0 | return dcgettext (domain, msgid, category); |
432 | 0 | } |
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 | 0 | { |
459 | 0 | if (domain && G_UNLIKELY (!_g_dgettext_should_translate ())) |
460 | 0 | return n == 1 ? msgid : msgid_plural; |
461 | | |
462 | 0 | return dngettext (domain, msgid, msgid_plural, n); |
463 | 0 | } |
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 > 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 | | */ |