290c8e7a3f
The gettext N_ macro is used to mark strings for translation without actually translating them. At runtime the string is expected to be passed to the gettext API for translation. If two N_ macro invocations appear next to each other with only whitespace (or nothing at all) between them, the two separate strings will be marked for translation, but the preprocessor will then silently combine the strings into one and at runtime the string passed to gettext will not match the strings that were translated so no translation will actually occur. Avoid this by adding parentheses around the expansion of the N_ macro so that instead of ending up with two adjacent strings that are then combined by the preprocessor, two adjacent strings surrounded by parentheses result instead which causes a compile error so the mistake can be quickly found and corrected. However, since these string literals are typically assigned to static variables and not all compilers support parenthesized string literal assignments, allow this to be controlled by the Makefile with the default only enabled when the compiler is known to support the syntax. For now only __GNUC__ enables this by default which covers both gcc and clang which should result in early detection of any adjacent N_ macros. Although the necessary tests make the affected files a bit less elegant, the benefit of avoiding propagation of a translation- marking error to all the translation teams thus creating extra work for them when the error is eventually detected and fixed would seem to outweigh the minor inelegance the additional configuration tests introduce. Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Kyle J. McKay <mackyle@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
93 lines
2.1 KiB
C
93 lines
2.1 KiB
C
/*
|
|
* Copyright (c) 2010-2011 Ævar Arnfjörð Bjarmason
|
|
*
|
|
* This is a skeleton no-op implementation of gettext for Git.
|
|
* You can replace it with something that uses libintl.h and wraps
|
|
* gettext() to try out the translations.
|
|
*/
|
|
|
|
#ifndef GETTEXT_H
|
|
#define GETTEXT_H
|
|
|
|
#if defined(_) || defined(Q_)
|
|
#error "namespace conflict: '_' or 'Q_' is pre-defined?"
|
|
#endif
|
|
|
|
#ifndef NO_GETTEXT
|
|
# include <libintl.h>
|
|
#else
|
|
# ifdef gettext
|
|
# undef gettext
|
|
# endif
|
|
# define gettext(s) (s)
|
|
# ifdef ngettext
|
|
# undef ngettext
|
|
# endif
|
|
# define ngettext(s, p, n) ((n == 1) ? (s) : (p))
|
|
#endif
|
|
|
|
#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
|
|
|
|
#ifndef NO_GETTEXT
|
|
extern void git_setup_gettext(void);
|
|
extern int gettext_width(const char *s);
|
|
#else
|
|
static inline void git_setup_gettext(void)
|
|
{
|
|
}
|
|
static inline int gettext_width(const char *s)
|
|
{
|
|
return strlen(s);
|
|
}
|
|
#endif
|
|
|
|
#ifdef GETTEXT_POISON
|
|
extern int use_gettext_poison(void);
|
|
#else
|
|
#define use_gettext_poison() 0
|
|
#endif
|
|
|
|
static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
|
|
{
|
|
if (!*msgid)
|
|
return "";
|
|
return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid);
|
|
}
|
|
|
|
static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
|
|
const char *Q_(const char *msgid, const char *plu, unsigned long n)
|
|
{
|
|
if (use_gettext_poison())
|
|
return "# GETTEXT POISON #";
|
|
return ngettext(msgid, plu, n);
|
|
}
|
|
|
|
/* Mark msgid for translation but do not translate it. */
|
|
#if !USE_PARENS_AROUND_GETTEXT_N
|
|
#define N_(msgid) msgid
|
|
#else
|
|
/*
|
|
* Strictly speaking, this will lead to invalid C when
|
|
* used this way:
|
|
* static const char s[] = N_("FOO");
|
|
* which will expand to
|
|
* static const char s[] = ("FOO");
|
|
* and in valid C, the initializer on the right hand side must
|
|
* be without the parentheses. But many compilers do accept it
|
|
* as a language extension and it will allow us to catch mistakes
|
|
* like:
|
|
* static const char *msgs[] = {
|
|
* N_("one")
|
|
* N_("two"),
|
|
* N_("three"),
|
|
* NULL
|
|
* };
|
|
* (notice the missing comma on one of the lines) by forcing
|
|
* a compilation error, because parenthesised ("one") ("two")
|
|
* will not get silently turned into ("onetwo").
|
|
*/
|
|
#define N_(msgid) (msgid)
|
|
#endif
|
|
|
|
#endif
|