Previous: , Up: Preparing Program Sources   [Contents][Index]


4.10 Preparing Library Sources

When you are preparing a library, not a program, for the use of gettext, only a few details are different. Here we assume that the library has a translation domain and a POT file of its own. (If it uses the translation domain and POT file of the main program, then the previous sections apply without changes.)

  1. The library code doesn’t call setlocale (LC_ALL, ""). It’s the responsibility of the main program to set the locale. The library’s documentation should mention this fact, so that developers of programs using the library are aware of it.
  2. The library code doesn’t call textdomain (PACKAGE), because it would interfere with the text domain set by the main program.
  3. The initialization code for a program was
      setlocale (LC_ALL, "");
      bindtextdomain (PACKAGE, LOCALEDIR);
      textdomain (PACKAGE);
    

    For a library it is reduced to

      bindtextdomain (PACKAGE, LOCALEDIR);
    

    If your library’s API doesn’t already have an initialization function, you need to create one, containing at least the bindtextdomain invocation. However, you usually don’t need to export and document this initialization function: It is sufficient that all entry points of the library call the initialization function if it hasn’t been called before. The typical idiom used to achieve this is a static boolean variable that indicates whether the initialization function has been called. If the library is meant to be used in multithreaded applications, this variable needs to be marked volatile, so that its value get propagated between threads. Like this:

    static volatile bool libfoo_initialized;
    
    static void
    libfoo_initialize (void)
    {
      bindtextdomain (PACKAGE, LOCALEDIR);
      libfoo_initialized = true;
    }
    
    /* This function is part of the exported API.  */
    struct foo *
    create_foo (...)
    {
      /* Must ensure the initialization is performed.  */
      if (!libfoo_initialized)
        libfoo_initialize ();
      ...
    }
    
    /* This function is part of the exported API.  The argument must be
       non-NULL and have been created through create_foo().  */
    int
    foo_refcount (struct foo *argument)
    {
      /* No need to invoke the initialization function here, because
         create_foo() must already have been called before.  */
      ...
    }
    

    The more general solution for initialization functions, POSIX pthread_once, is not needed in this case.

  4. The usual declaration of the ‘_’ macro in each source file was
    #include <libintl.h>
    #define _(String) gettext (String)
    

    for a program. For a library, which has its own translation domain, it reads like this:

    #include <libintl.h>
    #define _(String) dgettext (PACKAGE, String)
    

    In other words, dgettext is used instead of gettext. Similarly, the dngettext function should be used in place of the ngettext function.


Previous: Marking Proper Names for Translation, Up: Preparing Program Sources   [Contents][Index]