1 /* i18n.c - gettext initialization
2 * Copyright (C) 2007, 2010 Free Software Foundation, Inc.
3 * Copyright (C) 2015 g10 Code GmbH
5 * This file is free software; you can redistribute it and/or modify
6 * it under the terms of either
8 * - the GNU Lesser General Public License as published by the Free
9 * Software Foundation; either version 3 of the License, or (at
10 * your option) any later version.
14 * - the GNU General Public License as published by the Free
15 * Software Foundation; either version 2 of the License, or (at
16 * your option) any later version.
18 * or both in parallel, as here.
20 * This file is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see <https://www.gnu.org/licenses/>.
33 #ifdef HAVE_LANGINFO_CODESET
42 #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES) \
43 && !defined(USE_SIMPLE_GETTEXT) && defined(ENABLE_NLS)
44 # define USE_MSGCACHE 1
49 /* An object to store pointers to static strings and their static
50 translations. A linked list is not optimal but given that we only
51 have a few dozen messages it should be acceptable. */
54 struct msg_cache_s *next;
59 /* A object to store an lc_messages string and a link to the cache
61 struct msg_cache_heads_s
63 struct msg_cache_heads_s *next;
64 struct msg_cache_s *cache;
68 /* Out static cache of translated messages. We need this because
69 there is no gettext API to return a translation depending on the
70 locale. Switching the locale for each access to a translatable
71 string seems to be too expensive. Note that this is used only for
72 strings in gpg-agent which are passed to Pinentry. All other
73 strings are using the regular gettext interface. Note that we can
74 never release this memory because consumers take the result as
76 static struct msg_cache_heads_s *msgcache;
78 #endif /*USE_MSGCACHE*/
84 #ifdef USE_SIMPLE_GETTEXT
85 bindtextdomain (PACKAGE_GT, gnupg_localedir ());
86 textdomain (PACKAGE_GT);
89 setlocale (LC_ALL, "" );
90 bindtextdomain (PACKAGE_GT, LOCALEDIR);
91 textdomain (PACKAGE_GT);
97 /* The Assuan agent protocol requires us to transmit utf-8 strings
98 thus we need a way to temporary switch gettext from native to
101 i18n_switchto_utf8 (void)
103 #ifdef USE_SIMPLE_GETTEXT
104 /* Return an arbitrary pointer as true value. */
105 return gettext_use_utf8 (1) ? (char*)(-1) : NULL;
106 #elif defined(ENABLE_NLS)
107 char *orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
108 # ifdef HAVE_LANGINFO_CODESET
110 orig_codeset = nl_langinfo (CODESET);
113 { /* We only switch when we are able to restore the codeset later.
114 Note that bind_textdomain_codeset does only return on memory
115 errors but not if a codeset is not available. Thus we don't
116 bother printing a diagnostic here. */
117 orig_codeset = xstrdup (orig_codeset);
118 if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
120 xfree (orig_codeset);
130 /* Switch back to the saved codeset. */
132 i18n_switchback (char *saved_codeset)
134 #ifdef USE_SIMPLE_GETTEXT
135 gettext_use_utf8 (!!saved_codeset);
136 #elif defined(ENABLE_NLS)
139 bind_textdomain_codeset (PACKAGE_GT, saved_codeset);
140 xfree (saved_codeset);
148 /* Gettext variant which temporary switches to utf-8 for string. */
150 i18n_utf8 (const char *string)
152 char *saved = i18n_switchto_utf8 ();
153 const char *result = _(string);
154 i18n_switchback (saved);
159 /* A variant of gettext which allows the programmer to specify the
160 locale to use for translating the message. The function assumes
161 that utf-8 is used for the encoding. */
163 i18n_localegettext (const char *lc_messages, const char *string)
166 const char *result = NULL;
168 struct msg_cache_heads_s *mh;
169 struct msg_cache_s *mc;
174 /* Lookup in the cache. */
175 for (mh = msgcache; mh; mh = mh->next)
176 if (!strcmp (mh->lc_messages, lc_messages))
180 /* A cache entry for this local exists - find the string.
181 Because the system is designed for static strings it is
182 sufficient to compare the pointers. */
183 for (mc = mh->cache; mc; mc = mc->next)
184 if (mc->key == string)
192 /* Cached miss. Change the locale, translate, reset locale. */
193 saved = setlocale (LC_MESSAGES, NULL);
196 saved = xtrystrdup (saved);
199 if (!setlocale (LC_MESSAGES, lc_messages))
202 bindtextdomain (PACKAGE_GT, LOCALEDIR);
203 result = gettext (string);
204 setlocale (LC_MESSAGES, saved);
205 bindtextdomain (PACKAGE_GT, LOCALEDIR);
207 /* Cache the result. */
210 /* First use of this locale - create an entry. */
211 mh = xtrymalloc (sizeof *mh + strlen (lc_messages));
214 strcpy (mh->lc_messages, lc_messages);
219 mc = xtrymalloc (sizeof *mc);
224 mc->next = mh->cache;
229 return result? result : _(string);
231 #else /*!USE_MSGCACHE*/
236 #endif /*!USE_MSGCACHE*/