54.2. Для программиста#

54.2. Для программиста

54.2. Для программиста #

54.2.1. Механика #

Этот раздел описывает, как реализовать поддержку родного языка в программе или библиотеке, которая является частью дистрибутива Tantor BE. В настоящее время это применимо только к программам на языке C.

Добавление поддержки NLS в программу

  1. Вставьте этот код в последовательность запуска программы:

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

    (Имя progname может быть выбрано произвольно).

  2. Где бы ни было найдено сообщение, которое является кандидатом для перевода, необходимо вставить вызов функции gettext(). Например:

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

    будет изменено на:

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

    (gettext определен как пустая операция, если поддержка NLS не настроена).

    Это обычно добавляет много мусора. Один распространенный способ сокращения - использовать:

    #define _(x) gettext(x)
    

    Другое решение возможно, если программа осуществляет большую часть своего взаимодействия через одну или несколько функций, таких как ereport() в бэкенде. Затем вы вызываете эту функцию gettext внутренне для всех входных строк.

  3. Добавьте файл nls.mk в каталог с исходными файлами программы. Этот файл будет считываться как makefile. Здесь необходимо выполнить следующие присваивания переменных:

    CATALOG_NAME

    Имя программы, указанное в вызове textdomain().

    GETTEXT_FILES

    Список файлов, содержащих переводимые строки, то есть те, которые помечены с помощью gettext или альтернативного решения. В конечном итоге, это будет включать практически все исходные файлы программы. Если этот список становится слишком длинным, вы можете сделать первый файл символом +, а вторым словом файл, содержащий по одному имени файла на каждой строке.

    GETTEXT_TRIGGERS

    Средства, генерирующие каталоги сообщений для работы переводчиков, должны знать, какие вызовы функций содержат переводимые строки. По умолчанию известны только вызовы функции gettext(). Если вы использовали _ или другие идентификаторы, вам нужно перечислить их здесь. Если переводимая строка не является первым аргументом, элемент должен иметь форму func:2 (для второго аргумента). Если у вас есть функция, поддерживающая множественные сообщения, элемент должен выглядеть как func:1,2 (идентификация аргументов единственного и множественного сообщений).

  4. Добавьте файл po/LINGUAS, который будет содержать список предоставленных переводов — изначально пустой.

Система сборки автоматически позаботится о сборке и установке каталогов сообщений.

54.2.2. Руководство по написанию сообщений #

Вот несколько рекомендаций по написанию сообщений, которые легко переводятся.

  • Не создавайте предложения во время выполнения, например:

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

    Порядок слов в предложении может отличаться в других языках. Кроме того, даже если вы помните вызвать gettext() для каждого фрагмента, фрагменты могут плохо переводиться отдельно. Лучше дублировать немного кода, чтобы каждое сообщение для перевода было цельным. В текст сообщения должны вставляться только числа, имена файлов и подобные переменные времени выполнения.

  • По аналогичным причинам это не сработает:

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

    потому что он предполагает, как образуется множественное число. Если вы думали, что можете решить это таким образом:

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

    тогда будут разочарованы. Некоторые языки имеют более двух форм, с некоторыми особыми правилами. Часто лучше всего спроектировать сообщение таким образом, чтобы избежать этой проблемы, например, так:

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

    Если вам действительно нужно создать правильно склоняемое сообщение, для этого есть поддержка, но она немного неудобна. При генерации основного или детального сообщения об ошибке в функции ereport(), вы можете написать что-то вроде этого:

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

    Первый аргумент - это строка формата, соответствующая единственному числу в английском языке, второй - строка формата, соответствующая множественному числу в английском языке, а третий - целочисленное значение, которое определяет, какую форму множественного числа использовать. Последующие аргументы форматируются согласно строке формата, как обычно. (Обычно значение управления множественным числом также будет одним из значений, которые должны быть отформатированы, поэтому его нужно написать дважды). На английском языке важно только, является ли n равным 1 или не равным 1, но в других языках может быть много различных форм множественного числа. Переводчик видит две английские формы как группу и имеет возможность предоставить несколько заменяемых строк, из которых выбирается подходящая в зависимости от значения n во время выполнения.

    Если вам нужно сделать множественное число сообщения, которое не направляется непосредственно в отчет errmsg или errdetail, вам нужно использовать базовую функцию ngettext. См. документацию по gettext.

  • Если нужно передать что-то переводчику, например, указать, как сообщение должно соответствовать другому выводу, перед строкой введите комментарий, начинающийся с translator, например:

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

    Эти комментарии копируются в файлы каталога сообщений, чтобы переводчики могли их видеть.