Search code examples
cgettext

How to use gettext with __VA_ARGS__ in c


I'm trying to translate my console log with gettext, but I get the follow error:

program.c: In function ‘program_take_screenshot’:
program.c:55:14: error: expected ‘)’ before ‘dcgettext’
 #define _(x) gettext(x)
              ^
program_logger.h:117:49: note: in definition of macro ‘PROGRAM_ERR’
       fprintf(LOG_FILE, "Program [ERROR] :: " __VA_ARGS__); \
                                                 ^
program.c:173:17: note: in expansion of macro ‘_’
       PROGRAM_ERR(_("Cannot take screenshot. GPU rendering is used and read_viewport is not supported.\n"));
                 ^

what I do wrong?

definition in program_logger.h:

#define PROGRAM_LOG(...) do { \
      if (PROGRAM_LOG_VERBOSE) \
      { \
         fprintf(LOG_FILE, "Program: " __VA_ARGS__); \
         fflush(LOG_FILE); \
      } \
   } while (0)

definition of PROGRAM_ERR:

#define PROGRAM_ERR(...) do { \
      fprintf(LOG_FILE, "PROGRAM [ERROR] :: " __VA_ARGS__); \
      fflush(LOG_FILE); \
   } while (0)

Solution

  • Although one of the other answers explains what's going on, it doesn't give you an appropriate means of solving the problem.

    What you had:

    #define PROGRAM_ERR(...) do { \
          fprintf(LOG_FILE, "PROGRAM [ERROR] :: " __VA_ARGS__); \
          fflush(LOG_FILE); \
       } while (0)
    

    would allow, for example, using it like PROGRAM_ERR("some error: %s", "error message"). Yet as you've found, PROGRAM_ERR(_("some error: %s"), "error message") fails.

    The cause is, as explained already, indeed that this expands to

    do { fprintf(LOG_FILE, "PROGRAM [ERROR] :: " _("some error: %s"), "error message"); fflush(LOG_FILE); } while(0)
    

    and string concatenation only works for string literals.

    In my opinion, the simplest way to make this work, is

    #define PROGRAM_ERR(...) do { \
          fputs("PROGRAM [ERROR] :: ", LOG_FILE); \
          fprintf(LOG_FILE, __VA_ARGS__); \
          fflush(LOG_FILE); \
       } while (0)
    

    By separating the two strings, you don't need any compile-time string concatenation, which is simply not possible if the strings are not known at compile-time.