55.2. Программисту #
55.2.1. Механизмы #
В данном разделе описывается, как добавить языковую поддержку в программе или библиотеке, которая является частью дистрибутива PostgreSQL. В настоящий момент это относится только к программам на языке С.
Добавление языковой поддержки для программы
Вставьте этот код в начало программы:
#ifdef ENABLE_NLS #include <locale.h> #endif ... #ifdef ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain("
progname
", LOCALEDIR); textdomain("progname
"); #endif(
progname
фактически может быть выбрана произвольно.)Везде, где сообщение нуждается в переводе, необходимо вставить вызов
gettext()
. Например:fprintf(stderr, "panic level %d\n", lvl);
нужно заменить на:
fprintf(stderr, gettext("panic level %d\n"), lvl);
(
gettext
определяется как холостая команда, если NLS поддержка не настроена.)Это часто приводит к немалой путанице. Один из распространённых подходов в этом случае:
#define _(x) gettext(x)
Ещё одно решение допустимо, если программа часто выполняет обмен данными через одну или несколько функций, таких как
ereport()
в серверном процессе. Тогда вы выполняете внутренний вызов функцииgettext
для каждой входящей строки.Добавьте файл
nls.mk
в каталог с исходными кодами программы. Данный файл будет считаться сборочным файлом (makefile). В нём необходимо выполнить присваивание значений для следующих переменных:CATALOG_NAME
Имя программы, которое указано в вызове
textdomain()
.GETTEXT_FILES
Список файлов, которые содержат подлежащие переводу строки, т. е. помеченные
gettext
или альтернативным решением. В итоге, в него будут включены почти все исходные файлы программы. Если список станет слишком длинным, можно первый «file» сделать+
а второе слово — файлом, который содержит по одному имени файла на строку.GETTEXT_TRIGGERS
Утилитам, которые генерируют каталоги сообщений для работы переводчиков, должно быть известно, какие вызовы функции содержат строки, подлежащие переводу. По умолчанию распознаются только вызовы
gettext()
. Если вы использовали_
или другие идентификаторы, необходимо перечислить их здесь. Если подлежащая переводу строка не является первым аргументом, необходимо, чтобы элемент имел формуfunc:2
(для второго аргумента). Если функция поддерживает сообщения в форме множественного числа, элемент должен выглядеть следующим образомfunc:1,2
(идентификация аргументов в виде сообщений в форме единственного и множественного числа).
Добавьте файл
po/LINGUAS
, содержащий список языков, для которых есть переведённые файлы (изначально пустой).
Система сборки автоматически соберёт и установит каталоги сообщений.
55.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
единицей или нет, но в других языках может быть много различных форм множественного числа. Переводчик рассматривает две английские формы как группу и имеет возможность задать несколько вариантов замены строк, при этом подходящий вариант выбирается исходя из текущего значенияn
.Если вам нужно составить сообщение в форме множественного числа, которое не используется непосредственно при выводе сообщений в
errmsg
илиerrdetail
, вы должны воспользоваться базовой функциейngettext
. См. документацию по gettext.Если вы хотите передать какую-либо информацию переводчику, например о том, насколько сообщение соотносится с другими выходными данными, перед строкой должен появиться комментарий, который начинается с
translator
, например:/* translator: This message is not what it seems to be. */
Эти комментарии копируются в файлы каталога сообщений, чтобы переводчик мог их видеть.