gettext индексирует или/и переводит некоторые индексированные сообщения на английском языке

## Синтаксис

                gettext("The literal reference message")
                gettext(["item #1" ; "item#2"])
                translated = gettext("The literal reference message")
                translated = gettext(["item #1" ; "item#2"])
                translated = gettext(msgid)
                .. gettext(domain, ..)

## Аргументы

"The literal reference message"

  Единый с учетом регистра символьный текст сообщения на английском языке, которое требуется индексировать или/и перевести. Может быть также указан столбец символьных текстов явно разделённых точкой с запятой. Messages can include some C-like placeholders starting with "%".

  Могут использоваться только стандартные символы ASCII. Любые иные расширенные символы ASCII или UTF-8 приведут к ошибке в работе `gettext()`.

msgid

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

  Могут использоваться только стандартные символы ASCII.

translated

  Сообщения на входе переводятся на текущий язык сессии Scilab. Если для входного сообщения не доступна версия перевода, то возвращается входная версия на английском. Входные и выходные массивы имеют одинаковые размеры.

  Эти сообщения определены в файлах ./locales/*.po. Они могут включать в себя расширенные символы ASCII или UTF-8.

domain

  слово или текст: имя домена. При локализации внешнего модуля `domain` обычно может быть установлен на техническое имя модуля.

  `domain` может быть как литералом, так и переменной. Он нечувствителен к регистру.

  `domain` требуется в `tbx_generate_pofile()` для того, чтобы сделать индексированную литеральную строку `msgid` (этап сбора. См. ниже.).

  Когда `gettext(domain, msgid)` используется для получения переведённой версии, то `domain` используется для получения пути к директории, где хранятся переводы, как это заранее записано с помощью `addlocalizationdomain(domain, path)`.

## Описание

### Сбор сообщений и общая обработка

gettext является свободным и открытым внешним приложением, поставляемым вместе с Scilab для поддержки мультилингвизма для сообщений. Эта поддержка состоит из 4 главных этапов:

1. Сбор сообщений внутри кода и индексирование их для перевода. Для внешнего модуля это явным образом выполняется с помощью внешней бинарной программы `xgettext`, которая является частью внешнего приложения `gettext`, и которая вызывается Scilab-функцией tbx_generate_pofile. В Scilab также можно использовать `tbx_build_localization(..)` или `tbx_make . localization`, которые обе вызывают `tbx_generate_pofile(..)`.

   Каждое собранное сообщение рассматривается в качестве идентификатора (msgid) для всех его последующих переводов. В Scilab опорным языком для идентификаторов является английский. Следовательно идентификаторы сообщений для индексации должны быть записаны на английском.

   В качестве входного аргумента `gettext` собираются только одиночные литеральные сообщения и сообщения одним куском. Таким образом, некоторые из следующих синтаксисов и случаев не будут индексировать рассматриваемое сообщение, и для них не будут доступны дополнительные переведенные версии:

   # | Синтаксис | Статус | Результаты сбора
   --- | --- | --- | ---
   1 | `gettext("To be translated")` | OK | стандартный синтаксис
   2 |
       msg = "To be translated";
       gettext(msg)
   | NOK | Текст внутри переменной. Он не символьный. Он не будет индексирован. Тем не менее, этот синтаксис будет работать для получения версии перевода, в случае, если сообщение было собрано где-нибудь правильным образом.
   3 | `gettext("To be" + " translated")` | NOK | "To be" и " translated" индексируются как 2 отдельных `msgid`. Тогда, следовательно, конкатенированного `msgid` "To be translated" не существует, получение его перевода не удастся.
   4 |
       gettext("To be" + ..
               " translated")
   | NOK | Также как и #3
   5 | `gettext(["item#1", "item#2"])` | NOK | Только "item#1" собирается. "item#2" игнорируется.
   6 | `gettext(["item#1" "item#2"])` | NOK | "item#1item#2" индексируется. Тогда, поскольку "item#1" и "item#2" неизвестные отдельные `msgid`, то получение их соответствующего перевода не удастся.
   7 |
       gettext(["item#1"
                "item#2"])
   | NOK | Также как и #6
   8 | `gettext(["item#1" ; "item#2"])` | OK | "item#1" и "item#2" индексируются в качестве отдельных `msgid`.
   9 |
       gettext(["item#1" ;
                "item#2"])
   | OK | Также как и #8. Обратите внимание на точку с запятой. Без неё это будет случай ошибки #7.
   10 |
       // gettext("item")
       /* gettext("item #2") */
       /*
          gettext("item #3")
       */
   | OK | расположения gettext() в комментариях также индексируются.

   Для внешнего модуля tbx_generate_pofile() собирает только то, что встречает `gettext` с указанием домена `domain`. Он игнорирует любой вызов `gettext` только с одним входным аргументом.

   Сбору не нужно предварительно указывать домен `domain` в `addlocalizationdomain()`

2. Все индексированные тексты затем переводятся автором кода или помощниками. В любом случае кем-то из людей. Хорошие инструменты перевода также доступны онлайн.

3. Все переведённые версии собираются таким образом, что `gettext(..)` становится эффективным для получения версии на текущем языке сессии. Это сделано запуском `tbx_generate_pofile()` в другой раз.

4. Наконец, некоторые вызовы, такие как `gettext(message)` или `gettext("The message content")`, используются для получения и выдачи переведённой версии.

   Когда сообщение не является естественным для Scilab (например, оно специфично для внешнего модуля), домен `domain` где сообщения и его переводы могут быть найдены, должен быть определён, как в `gettext(domain, message)` или `gettext(domain, "The message content")`. В это случае `addlocalizationdomain(domain, path)` должен быть запущен первым для того, чтобы указать Scilab директорию, в которой хранятся переведённые сообщения указанного домена `domain`.

Чаще всего сообщения указываются для сбора и используются для получения их переведённых версий через одинаковый вызов `gettext("The literal message")`. Однако, это не обязательно. Следовательно, кусок кода, такой как `if %F, gettext("The literal message"), end` никогда не будет исполнен вызов `gettext`, но тем не менее имеет смысл: оно здесь только для того, чтобы сделать сообщение видимым для сканера/сборщика `xgettext`. Тогда где-то ещё в коде можно использовать `msg = "The literal message"; gettext(msg)` для возврата переведённой версии.

Также многократное использование одного и того же литерального вызова `gettext("The literal message")` не будет редким, например, для получения перевода в нескольких файлах. В этом случае сборщик `xgettext` будет собирать сообщение только один раз, и одинаковый перевод будет получен во всех вызовах.

Ограничения: Нет способа перевести сообщение

- на языке, отличном от языка текущей сессии. Если это действительно требуется, то язык сессии следует временно переключить на желаемый язык, затем вызвать `gettext()`, и, наконец, восстановить язык сессии.

- из переведённой версии, а не из идентификатора сообщения на английском.

### msgid сообщения

Для корректной обработки сообщения на английском должны соответствовать нескольким правилам:

- Идентификаторы сообщений не чувствительны к регистру.

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

  Когда `gettext()` или `_()` используется в XML или XSL файлах, таких, как файлы настроек внешнего модуля, литеральная строка домена и литеральный идентификатор сообщения более не должны быть разделены.

  Например, `_(my_domain, My message)` будет использоваться вместо `_("my_domain", "My message")`.

  К тому же, пробелы до и после идентификатора сообщений тогда никогда не будут приниматься во внимание и никогда не будет принадлежать сообщению. Например, фактический идентификатор сообщения, соответствующий `_(my_domain, My message: )` это `"My message:"`, а не `" My message: "`.

- Двойные кавычки следует избегать внутри тела сообщения. Пожалуйста, используйте одинарные кавычки.

- Внутренние эскейп-последовательности, такие как "\t", "\n" и т.д., не интерпретируются ни сканером `xgettext` ни функцией `gettext`. Они собираются и сохраняются как есть в сообщениях.

- Некоторые шаблонные сообщения могут часто включать в себя некоторые C-подобные директивы "%" с целью замены некоторыми входными данными через `msprintf()` во время запуска. Например, `msprintf("Hi %s, could you come at %s today?", "John", "12:30")` вернёт `"Hi John, could you come at 12:30 today?"`.

### переведённые сообщения msgstr

Этот раздел будет в основном полезен тем, кто занимается переводом сообщений.

Special characters and sequences:

1. When a trailing \n is used in the `msgid`, it must also end the `msgstr` translated message.

2. ' single quotes are regular characters in `msgstr` strings. They do NOT need any special care or protection.

3. " double quotes must be protected with \".

4. When some C-like placeholders like %s, %d, %f, or some C-like escaped sequences \n, \r, or \t are used in the `msgid` string, this means that later in the code the corresponding `translated` `msgstr` string is processed with `msprintf()` to replace placeholders with actual values, and/or to interpret \n as a new_line character, \r as a carriage-return, \t as a tabulation, etc. Hence, all the C-like printf rules apply on the considered `msgstr`, and translaters must take a major care to them.
   - All and Only the placeholders used in the `msgid` must also appear in the `msgstr`.

   - If placeholders are not numbered: they must appear in the same order in the `translated` `msgstr` message than in the `msgid` message. Example (english to french):

         msgid  "%s is %d year old.\n"
         msgstr "%s a %d ans.\n"
         // первый %s (строка), второй %d (десятичное число), в обоих строках.

         Затем из Scilab-сессии установим французский язык и тогда получим
         gettext("%s is %d year old.\n") // => "%s a %d ans.\n"
         // и                                     первый v      v второй
         t = msprintf(gettext("%s is %d year old.\n"), "Peter", 18)
         // => "Peter a 18 ans."

   - В противном случае, ВСЕ заменители должны быть пронумерованы в переведённом сообщении `translated`. Каждый пронумерованный заменитель может быть использован только один раз в формате (ограничение Scilab). Например (с английского на японский):

         msgid "%s: Wrong number of input argument: %d to %d expected.\n"
         msgstr "%1$s: 入力引数で不正な数: %3$d への %2$d を想定します。\n"

         Тогда,
         msprintf(gettext("%s: Wrong number of input argument: %d to %d expected.\n"), "myFun", 2, 5)

         вернёт в Scilab-сессию, установленную на английский
         "myFun: Wrong number of input argument: 2 to 5 expected."

         а в Scilab-сессии, установленной на японский
         "myFun: 入力引数で不正な数: 5 への 2 を想定します。"

5. \n, \r, \t sequences fortuitously appearing in a `msgid` ending with "\n" should be considered as prone to issues, due to a lack of care from the programmer. This can occur for instance when some literal paths are part of the `msgid`, like in

   `msgid "Please use the file C:\users\you\net\record\time.txt instead.\n"`

   The trailing `\n` suggests that the corresponding `msgstr` will be processed by `msprintf()` or so. Being done, `\n` in `\net`, `\r` in `\record` and `\t` in `\time.txt` will be also -- unexpectedly -- interpreted. These `\` will have to be protected in the `msgstr`, even in the reference version (often english):

   `msgstr "Please use the file C:\users\you\\net\\record\\time.txt instead.\n"`:

## Примеры

    setlanguage("fr");

    // Идентификаторы сообщений чувствительны к регистру:
    // "monday" не является индексируемым msgid, в отличие от "Monday":
    gettext(["monday" ; "Monday"])

    //_() является псевдонимом gettext():
    _("Sunday")

    // В Scilab идентификаторы сообщений английские:
    setlanguage("ru");
    _("Dimanche")       // Французская версия не может использоваться в качестве msgid
    _("Sunday")

    --> gettext(["monday" ; "Monday"])
     ans  =
    !monday  !
    !Lundi   !

    --> _("Sunday")
     ans  =
     Dimanche

    --> setlanguage("ru");
    --> _("Dimanche")
     ans  =
     Dimanche

    --> _("Sunday")
     ans  =
     Воскресенье

Использование домена: Здесь "tbx" это предопределённый домен, используемый для проверки возможности перевода:

    setlanguage("fr");
    msg = "%s: something not in Scilab.\n";  // неизвестный в главном домене для Scilab:
    gettext(msg)          // поэтому он выдаётся как есть.

    //  Если мы используем домен без предварительного его декларирования, то
    //  Scilab не знает ещё где найти перевод:
    gettext("tbx", msg)   // входное сообщение возвращается как есть.

    // Теперь задекларируем домен:
    addlocalizationdomain("tbx", "SCI/modules/localization/tests/unit_tests/locale");
    gettext("tbx", msg)   // теперь работает

    // Ответом является шутка: здесь она остаётся на английском (хотя ожидалась на французском).
    // Дело в том, что она была установлена как французский перевод входного msgid.

    // Тот же msgid может использоваться в качестве идентификатора, естественного для Scilab с его переводами,
    // и в одном или в нескольких доменах с другими переводами:
    msg = "%s: No more memory.\n";
    [_(msg) ; _("tbx", msg)]

    --> msg = "%s: something not in Scilab.\n"; // неизвестный в главном домене для Scilab:
    --> gettext(msg)
     ans  =
     %s: something not in Scilab.\n

    --> //  Scilab не знает ещё где найти перевод:
    --> gettext("tbx", msg)
     ans  =
     %s: something not in Scilab.\n

    --> // Теперь задекларируем домен:
    --> addlocalizationdomain("tbx", "SCI/modules/localization/tests/unit_tests/locale");
    --> gettext("tbx", msg)   // теперь работает
     ans  =
     %s : it is true, that is not in Scilab.\n

    --> msg = "%s: No more memory.\n";
    --> [_(msg) ; _("tbx", msg)]
     ans  =
    !%s : Plus de mémoire disponible.\n    !
    !%s : Overwrite Scilab translation.\n  !

Сообщения с нумерованными C-подобными заменителями:

    in = getlanguage();
    msg = "%s: Unknown value %s for %s option"; // has already some translations
    setlanguage("en");
    t = gettext(msg)
    msprintf(t, "setdiff", "''f''", "''direction''")

    setlanguage("ja");
    t = gettext(msg)
    msprintf(t, "setdiff", "''f''", "''direction''")

    setlanguage(in);

    --> setlanguage("en");
    --> t = gettext(msg)
     t  =
      "%s: Unknown value %s for %s option"

    --> msprintf(t, "setdiff", "''f''", "''direction''")
     ans  =
      "setdiff: Unknown value 'f' for 'direction' option"

    --> setlanguage("ja");
    --> t = gettext(msg)
     t  =
      "%1$s: %3$s オプション の未知の値 %2$s"

    --> msprintf(t, "setdiff", "''f''", "''direction''")
     ans  =
      "setdiff: 'direction' オプション の未知の値 'f'"

## Смотрите также

- msprintf
- setlanguage
- addlocalizationdomain
- tbx_generate_pofile
- tbx_make . localization
- tbx_build_localization
- GNU gettext website

## История

5.5.0 Добавлено управление доменом.
6.1.0 Теперь C-подобные заменители в сообщениях могут быть нумерованными.