gettext.h (10854B)
1 /* Convenience header for conditional use of GNU <libintl.h>. 2 Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2020 Free Software 3 Foundation, Inc. 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as published by 7 the Free Software Foundation; either version 2.1 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17 #ifndef _LIBGETTEXT_H 18 #define _LIBGETTEXT_H 1 19 20 /* NLS can be disabled through the configure --disable-nls option 21 or through "#define ENABLE NLS 0" before including this file. */ 22 #if defined ENABLE_NLS && ENABLE_NLS 23 24 /* Get declarations of GNU message catalog functions. */ 25 # include <libintl.h> 26 27 /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by 28 the gettext() and ngettext() macros. This is an alternative to calling 29 textdomain(), and is useful for libraries. */ 30 # ifdef DEFAULT_TEXT_DOMAIN 31 # undef gettext 32 # define gettext(Msgid) \ 33 dgettext (DEFAULT_TEXT_DOMAIN, Msgid) 34 # undef ngettext 35 # define ngettext(Msgid1, Msgid2, N) \ 36 dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) 37 # endif 38 39 #else 40 41 /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which 42 chokes if dcgettext is defined as a macro. So include it now, to make 43 later inclusions of <locale.h> a NOP. We don't include <libintl.h> 44 as well because people using "gettext.h" will not include <libintl.h>, 45 and also including <libintl.h> would fail on SunOS 4, whereas <locale.h> 46 is OK. */ 47 #if defined(__sun) 48 # include <locale.h> 49 #endif 50 51 /* Many header files from the libstdc++ coming with g++ 3.3 or newer include 52 <libintl.h>, which chokes if dcgettext is defined as a macro. So include 53 it now, to make later inclusions of <libintl.h> a NOP. */ 54 #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) 55 # include <cstdlib> 56 # if (__GLIBC__ >= 2 && ! defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H 57 # include <libintl.h> 58 # endif 59 #endif 60 61 /* Disabled NLS. 62 The casts to 'const char *' serve the purpose of producing warnings 63 for invalid uses of the value returned from these functions. 64 On pre-ANSI systems without 'const', the config.h file is supposed to 65 contain "#define const". */ 66 # undef gettext 67 # define gettext(Msgid) ((const char *) (Msgid)) 68 # undef dgettext 69 # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) 70 # undef dcgettext 71 # define dcgettext(Domainname, Msgid, Category) \ 72 ((void) (Category), dgettext (Domainname, Msgid)) 73 # undef ngettext 74 # define ngettext(Msgid1, Msgid2, N) \ 75 ((N) == 1 \ 76 ? ((void) (Msgid2), (const char *) (Msgid1)) \ 77 : ((void) (Msgid1), (const char *) (Msgid2))) 78 # undef dngettext 79 # define dngettext(Domainname, Msgid1, Msgid2, N) \ 80 ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) 81 # undef dcngettext 82 # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ 83 ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) 84 # undef textdomain 85 # define textdomain(Domainname) ((const char *) (Domainname)) 86 # undef bindtextdomain 87 # define bindtextdomain(Domainname, Dirname) \ 88 ((void) (Domainname), (const char *) (Dirname)) 89 # undef bind_textdomain_codeset 90 # define bind_textdomain_codeset(Domainname, Codeset) \ 91 ((void) (Domainname), (const char *) (Codeset)) 92 93 #endif 94 95 /* Prefer gnulib's setlocale override over libintl's setlocale override. */ 96 #ifdef GNULIB_defined_setlocale 97 # undef setlocale 98 # define setlocale rpl_setlocale 99 #endif 100 101 /* A pseudo function call that serves as a marker for the automated 102 extraction of messages, but does not call gettext(). The run-time 103 translation is done at a different place in the code. 104 The argument, String, should be a literal string. Concatenated strings 105 and other string expressions won't work. 106 The macro's expansion is not parenthesized, so that it is suitable as 107 initializer for static 'char[]' or 'const char[]' variables. */ 108 #define gettext_noop(String) String 109 110 /* The separator between msgctxt and msgid in a .mo file. */ 111 #define GETTEXT_CONTEXT_GLUE "\004" 112 113 /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a 114 MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be 115 short and rarely need to change. 116 The letter 'p' stands for 'particular' or 'special'. */ 117 #ifdef DEFAULT_TEXT_DOMAIN 118 # define pgettext(Msgctxt, Msgid) \ 119 pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ 120 LC_MESSAGES) 121 #else 122 # define pgettext(Msgctxt, Msgid) \ 123 pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 124 #endif 125 #define dpgettext(Domainname, Msgctxt, Msgid) \ 126 pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ 127 LC_MESSAGES) 128 #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ 129 pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) 130 #ifdef DEFAULT_TEXT_DOMAIN 131 # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ 132 npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ 133 MsgidPlural, N, LC_MESSAGES) 134 #else 135 # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ 136 npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, \ 137 N, LC_MESSAGES) 138 #endif 139 #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ 140 npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ 141 MsgidPlural, N, LC_MESSAGES) 142 #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ 143 npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, \ 144 MsgidPlural, N, Category) 145 146 #ifdef __GNUC__ 147 __inline 148 #else 149 #ifdef __cplusplus 150 inline 151 #endif 152 #endif 153 static const char * 154 pgettext_aux (const char *domain, 155 const char *msg_ctxt_id, const char *msgid, 156 int category) 157 { 158 const char *translation = dcgettext (domain, msg_ctxt_id, category); 159 if (translation == msg_ctxt_id) 160 return msgid; 161 else 162 return translation; 163 } 164 165 166 #ifdef __GNUC__ 167 __inline 168 #else 169 #ifdef __cplusplus 170 inline 171 #endif 172 #endif 173 static const char * 174 npgettext_aux (const char *domain, 175 const char *msg_ctxt_id, const char *msgid, 176 const char *msgid_plural, unsigned long int n, 177 int category) 178 { 179 const char *translation = 180 dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); 181 if ((translation == msg_ctxt_id) || (translation == msgid_plural)) 182 return (n == 1 ? msgid : msgid_plural); 183 else 184 return translation; 185 } 186 187 188 /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID 189 can be arbitrary expressions. But for string literals these macros are 190 less efficient than those above. */ 191 192 #include <string.h> 193 194 /* GNULIB_NO_VLA can be defined to disable use of VLAs even if supported. 195 This relates to the -Wvla and -Wvla-larger-than warnings, enabled in 196 the default GCC many warnings set. This allows programs to disable use 197 of VLAs, which may be unintended, or may be awkward to support portably, 198 or may have security implications due to non-deterministic stack usage. */ 199 200 #if (! defined GNULIB_NO_VLA \ 201 && (((__GNUC__ >= 3 || __GNUG__ >= 2) && ! defined __STRICT_ANSI__) \ 202 /* || (__STDC_VERSION__ == 199901L && !defined __HP_cc) 203 || (__STDC_VERSION__ >= 201112L && !defined __STDC_NO_VLA__) */)) 204 # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1 205 #else 206 # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0 207 #endif 208 209 #if ! _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 210 #include <stdlib.h> 211 #endif 212 213 #define pgettext_expr(Msgctxt, Msgid) \ 214 dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) 215 #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ 216 dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) 217 218 #ifdef __GNUC__ 219 __inline 220 #else 221 #ifdef __cplusplus 222 inline 223 #endif 224 #endif 225 static const char * 226 dcpgettext_expr (const char *domain, 227 const char *msgctxt, const char *msgid, 228 int category) 229 { 230 size_t msgctxt_len = strlen (msgctxt) + 1; 231 size_t msgid_len = strlen (msgid) + 1; 232 const char *translation; 233 #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 234 char msg_ctxt_id[msgctxt_len + msgid_len]; 235 #else 236 char buf[1024]; 237 char *msg_ctxt_id = 238 (msgctxt_len + msgid_len <= sizeof (buf) 239 ? buf 240 : (char *) malloc (msgctxt_len + msgid_len)); 241 if (msg_ctxt_id != NULL) 242 #endif 243 { 244 int found_translation; 245 memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); 246 msg_ctxt_id[msgctxt_len - 1] = '\004'; 247 memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); 248 translation = dcgettext (domain, msg_ctxt_id, category); 249 found_translation = (translation != msg_ctxt_id); 250 #if ! _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 251 if (msg_ctxt_id != buf) 252 free (msg_ctxt_id); 253 #endif 254 if (found_translation) 255 return translation; 256 } 257 return msgid; 258 } 259 260 261 #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ 262 dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) 263 #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ 264 dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) 265 266 #ifdef __GNUC__ 267 __inline 268 #else 269 #ifdef __cplusplus 270 inline 271 #endif 272 #endif 273 static const char * 274 dcnpgettext_expr (const char *domain, 275 const char *msgctxt, const char *msgid, 276 const char *msgid_plural, unsigned long int n, 277 int category) 278 { 279 size_t msgctxt_len = strlen (msgctxt) + 1; 280 size_t msgid_len = strlen (msgid) + 1; 281 const char *translation; 282 #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 283 char msg_ctxt_id[msgctxt_len + msgid_len]; 284 #else 285 char buf[1024]; 286 char *msg_ctxt_id = 287 (msgctxt_len + msgid_len <= sizeof (buf) 288 ? buf 289 : (char *) malloc (msgctxt_len + msgid_len)); 290 if (msg_ctxt_id != NULL) 291 #endif 292 { 293 int found_translation; 294 memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); 295 msg_ctxt_id[msgctxt_len - 1] = '\004'; 296 memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); 297 translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); 298 found_translation = ! (translation == msg_ctxt_id || translation == 299 msgid_plural); 300 #if ! _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 301 if (msg_ctxt_id != buf) 302 free (msg_ctxt_id); 303 #endif 304 if (found_translation) 305 return translation; 306 } 307 return (n == 1 ? msgid : msgid_plural); 308 } 309 310 311 #endif /* _LIBGETTEXT_H */