56.2. Para el programador #

56.2.1. Mecánica
56.2.2. Directrices para escribir mensajes

56.2.1. Mecánica #

Esta sección describe cómo implementar el soporte de idioma nativo en un programa o biblioteca que forma parte de la distribución de PostgreSQL. Actualmente, solo se aplica a programas en C.

Cómo añadir soporte NLS a un programa

  1. Inserta este código en la secuencia de inicio del programa:

    #ifdef ENABLE_NLS
    #include <locale.h>
    #endif
    
    ...
    
    #ifdef ENABLE_NLS
    setlocale(LC_ALL, "");
    bindtextdomain("nombre_programa", LOCALEDIR);
    textdomain("nombre_programa");
    #endif
    

    (El nombre_programa en realidad se puede elegir libremente).

  2. Dondequiera que se encuentre un mensaje que sea candidato para traducción, se debe insertar una llamada a gettext(). Por ejemplo:

    fprintf(stderr, "panic level %d\n", lvl);
    

    se cambiaría a:

    fprintf(stderr, gettext("panic level %d\n"), lvl);
    

    (gettext se define como una operación sin efecto si el soporte NLS no está configurado).

    Esto suele añadir mucho ruido visual. Un atajo común es usar:

    #define _(x) gettext(x)
    

    Otra solución es factible si el programa realiza gran parte de su comunicación a través de una o unas pocas funciones, como ereport() en el backend. En ese caso, haces que esta función llame a gettext internamente para todas las cadenas de entrada.

  3. Añade un archivo nls.mk en el directorio con las fuentes del programa. Este archivo se leerá como un makefile. Aquí se deben realizar las siguientes asignaciones de variables:

    CATALOG_NAME

    El nombre del programa, tal como se proporciona en la llamada a textdomain().

    GETTEXT_FILES

    Lista de archivos que contienen cadenas traducibles, es decir, aquellos marcados con gettext o una solución alternativa. Con el tiempo, esto incluirá casi todos los archivos fuente del programa. Si esta lista se vuelve demasiado larga, puedes hacer que el primer archivo sea un + y la segunda palabra sea un archivo que contenga un nombre de archivo por línea.

    GETTEXT_TRIGGERS

    Las herramientas que generan catálogos de mensajes para que trabajen los traductores necesitan saber qué llamadas a funciones contienen cadenas traducibles. Por defecto, solo se conocen las llamadas a gettext(). Si utilizas _ u otros identificadores, debes enumerarlos aquí. Si la cadena traducible no es el primer argumento, el elemento debe tener la forma func:2 (para el segundo argumento). Si tienes una función que admite mensajes en plural, el elemento debe verse como func:1,2 (identificando los argumentos de mensaje en singular y plural).

  4. Añade un archivo po/LINGUAS, que contendrá la lista de traducciones proporcionadas; inicialmente estará vacío.

El sistema de construcción se encargará automáticamente de compilar e instalar los catálogos de mensajes.

56.2.2. Directrices para escribir mensajes #

Aquí tienes algunas directrices para escribir mensajes que sean fáciles de traducir.

  • No construyas oraciones en tiempo de ejecución, como:

    printf("Files were %s.\n", flag ? "copied" : "removed");
    

    El orden de las palabras dentro de la oración puede ser diferente en otros idiomas. Además, incluso si recuerdas llamar a gettext() en cada fragmento, es posible que los fragmentos no se traduzcan bien por separado. Es mejor duplicar un poco de código para que cada mensaje a traducir sea un todo coherente. Solo los números, nombres de archivos y variables similares en tiempo de ejecución deben insertarse en tiempo de ejecución en el texto de un mensaje.

  • Por razones similares, esto no funcionará:

    printf("copied %d file%s", n, n!=1 ? "s" : "");
    

    porque asume cómo se forma el plural. Si pensabas que podías solucionarlo de esta manera:

    if (n==1)
        printf("copied 1 file");
    else
        printf("copied %d files", n):
    

    entonces te llevarás una decepción. Algunos idiomas tienen más de dos formas, con algunas reglas peculiares. A menudo es mejor diseñar el mensaje para evitar el problema por completo, por ejemplo de esta manera:

    printf("number of copied files: %d", n);
    

    Si realmente quieres construir un mensaje correctamente pluralizado, existe soporte para esto, pero es un poco complejo. Al generar un mensaje de error principal o de detalle en ereport(), puedes escribir algo como esto:

    errmsg_plural("copied %d file",
                  "copied %d files",
                  n,
                  n)
    

    El primer argumento es la cadena de formato adecuada para la forma singular en inglés, el segundo es la cadena de formato adecuada para la forma plural en inglés, y el tercero es el valor de control entero que determina qué forma de plural usar. Los argumentos siguientes se formatean según la cadena de formato como de costumbre. (Normalmente, el valor de control de pluralización también será uno de los valores a formatear, por lo que tiene que escribirse dos veces). En inglés solo importa si n es 1 o no es 1, pero en otros idiomas puede haber muchas formas de plural diferentes. El traductor ve las dos formas en inglés como un grupo y tiene la oportunidad de proporcionar múltiples cadenas sustitutas, seleccionándose la adecuada en función del valor en tiempo de ejecución de n.

    Si necesitas pluralizar un mensaje que no va directamente a un informe errmsg o errdetail, tienes que usar la función subyacente ngettext. Consulta la documentación de gettext.

  • Si quieres comunicar algo al traductor, como por ejemplo sobre cómo se pretende que se alinee un mensaje con otra salida, precede la aparición de la cadena con un comentario que comience con translator, por ejemplo:

    /* translator: This message is not what it seems to be. */
    

    Estos comentarios se copian a los archivos de catálogo de mensajes para que los traductores puedan verlos.