gettext: Contexts

1 
1 11.2.5 Using contexts for solving ambiguities
1 ---------------------------------------------
1 
1    One place where the ‘gettext’ functions, if used normally, have big
1 problems is within programs with graphical user interfaces (GUIs).  The
1 problem is that many of the strings which have to be translated are very
1 short.  They have to appear in pull-down menus which restricts the
1 length.  But strings which are not containing entire sentences or at
1 least large fragments of a sentence may appear in more than one
1 situation in the program but might have different translations.  This is
1 especially true for the one-word strings which are frequently used in
1 GUI programs.
1 
1    As a consequence many people say that the ‘gettext’ approach is wrong
1 and instead ‘catgets’ should be used which indeed does not have this
1 problem.  But there is a very simple and powerful method to handle this
1 kind of problems with the ‘gettext’ functions.
1 
1    Contexts can be added to strings to be translated.  A context
1 dependent translation lookup is when a translation for a given string is
1 searched, that is limited to a given context.  The translation for the
1 same string in a different context can be different.  The different
1 translations of the same string in different contexts can be stored in
1 the in the same MO file, and can be edited by the translator in the same
1 PO file.
1 
1    The ‘gettext.h’ include file contains the lookup macros for strings
1 with contexts.  They are implemented as thin macros and inline functions
1 over the functions from ‘<libintl.h>’.
1 
1      const char *pgettext (const char *msgctxt, const char *msgid);
1 
1    In a call of this macro, MSGCTXT and MSGID must be string literals.
1 The macro returns the translation of MSGID, restricted to the context
1 given by MSGCTXT.
1 
1    The MSGCTXT string is visible in the PO file to the translator.  You
1 should try to make it somehow canonical and never changing.  Because
1 every time you change an MSGCTXT, the translator will have to review the
1 translation of MSGID.
1 
1    Finding a canonical MSGCTXT string that doesn’t change over time can
1 be hard.  But you shouldn’t use the file name or class name containing
1 the ‘pgettext’ call – because it is a common development task to rename
1 a file or a class, and it shouldn’t cause translator work.  Also you
1 shouldn’t use a comment in the form of a complete English sentence as
1 MSGCTXT – because orthography or grammar changes are often applied to
1 such sentences, and again, it shouldn’t force the translator to do a
1 review.
1 
1    The ‘p’ in ‘pgettext’ stands for “particular”: ‘pgettext’ fetches a
1 particular translation of the MSGID.
1 
1      const char *dpgettext (const char *domain_name,
1                             const char *msgctxt, const char *msgid);
1      const char *dcpgettext (const char *domain_name,
1                              const char *msgctxt, const char *msgid,
1                              int category);
1 
1    These are generalizations of ‘pgettext’.  They behave similarly to
1 ‘dgettext’ and ‘dcgettext’, respectively.  The DOMAIN_NAME argument
1 defines the translation domain.  The CATEGORY argument allows to use
1 another locale category than ‘LC_MESSAGES’.
1 
1    As as example consider the following fictional situation.  A GUI
1 program has a menu bar with the following entries:
1 
1      +------------+------------+--------------------------------------+
1      | File       | Printer    |                                      |
1      +------------+------------+--------------------------------------+
1      | Open     | | Select   |
1      | New      | | Open     |
1      +----------+ | Connect  |
1                   +----------+
1 
1    To have the strings ‘File’, ‘Printer’, ‘Open’, ‘New’, ‘Select’, and
1 ‘Connect’ translated there has to be at some point in the code a call to
1 a function of the ‘gettext’ family.  But in two places the string passed
1 into the function would be ‘Open’.  The translations might not be the
1 same and therefore we are in the dilemma described above.
1 
1    What distinguishes the two places is the menu path from the menu root
1 to the particular menu entries:
1 
1      Menu|File
1      Menu|Printer
1      Menu|File|Open
1      Menu|File|New
1      Menu|Printer|Select
1      Menu|Printer|Open
1      Menu|Printer|Connect
1 
1    The context is thus the menu path without its last part.  So, the
1 calls look like this:
1 
1      pgettext ("Menu|", "File")
1      pgettext ("Menu|", "Printer")
1      pgettext ("Menu|File|", "Open")
1      pgettext ("Menu|File|", "New")
1      pgettext ("Menu|Printer|", "Select")
1      pgettext ("Menu|Printer|", "Open")
1      pgettext ("Menu|Printer|", "Connect")
1 
1    Whether or not to use the ‘|’ character at the end of the context is
1 a matter of style.
1 
1    For more complex cases, where the MSGCTXT or MSGID are not string
1 literals, more general macros are available:
1 
1      const char *pgettext_expr (const char *msgctxt, const char *msgid);
1      const char *dpgettext_expr (const char *domain_name,
1                                  const char *msgctxt, const char *msgid);
1      const char *dcpgettext_expr (const char *domain_name,
1                                   const char *msgctxt, const char *msgid,
1                                   int category);
1 
1    Here MSGCTXT and MSGID can be arbitrary string-valued expressions.
1 These macros are more general.  But in the case that both argument
1 expressions are string literals, the macros without the ‘_expr’ suffix
1 are more efficient.
1