Назад

gt-react@10.18.0

Ernest McCarter avatarErnest McCarter
gt-reactдеривацияконтекстi18n

Обзор

В этом релизе добавлена поддержка значений контекста с деривацией в gt-react. При переводе контента между исходным текстом и его переводами не всегда есть соответствие один к одному — одной английской фразе в другом языке может требоваться несколько переводов. Деривация контекста решает эту проблему, позволяя создавать несколько записей перевода из одной исходной строки.

Общие сведения: как работают переводы в GT

В системе переводов GT вы оборачиваете строки, которые нужно переводить, в gt():

import { useGT } from 'gt-react';

function Greeting() {
  const gt = useGT();
  return <p>{gt("Hello, world!")}</p>;
}

Каждый вызов gt() создает исходную запись — фрагмент текста, который нужно перевести. Обычно одной исходной записи соответствует один перевод на каждый язык.

Что такое derive?

Функция derive() указывает CLI GT зарегистрировать несколько записей перевода из одного вызова gt() на основе разных значений во время выполнения. Вместо того чтобы писать отдельные вызовы gt() для каждого варианта, вы используете derive(), чтобы описать все варианты в одном месте, а CLI на этапе сборки генерирует соответствующие исходные записи.

Например, в английском языке род не различается во фразе "The boy/girl is playing,", а в испанском — различается ("El niño está jugando" и "La niña está jugando"). С derive() это можно обработать в одном вызове gt():

const subject = isBoy ? "boy" : "girl";
gt(`The ${derive(subject)} is playing.`);

CLI обнаруживает вызов derive() и регистрирует две исходные записи — одну для "The boy is playing." и одну для "The girl is playing." — при этом каждая получает собственный перевод с правильным согласованием в испанском языке.

Проблема: сопоставления «один-ко-многим»

Рассмотрим три случая того, как исходные записи сопоставляются с записями перевода:

Случай 1: взаимно-однозначное сопоставление

Каждая исходная запись сопоставляется ровно с одной записью перевода. Это простой случай.

Исходные записиЗаписи перевода
Мальчик красивый.El niño es hermoso.
Девочка красивая.La niña es hermosa.

Случай 2: Маппинг many-to-one

Несколько исходных записей объединяются в одну запись перевода. Например, в английском есть формы множественного числа, а в китайском (мандаринском) — нет:

Исходные записиЗаписи перевода
I have {n} cat.我有{n}只猫。
I have {n} cats.

Случай 3: сопоставление one-to-many

Для одной исходной записи требуется несколько переводов. Например, в испанском языке есть согласование прилагательных по роду, а в английском его нет:

Исходные записиЗаписи перевода
I am tiredEstoy cansado
Estoy cansada

Это как раз тот случай, который не поддерживался до этого релиза. Ранее GT предполагал сопоставление one-to-one между исходными записями и их переводами.

Решение: derive с $context

Опция $context в GT позволяет различать записи перевода для одного и того же исходного текста. В сочетании с derive() это можно задать прямо в месте вызова:

import { useGT, derive } from 'gt-react';

function StatusMessage({ isMasculine }) {
  const gt = useGT();

  return (
    <p>
      {gt("I am tired", {
        $context: derive(
          isMasculine ? "inflect as masculine" : "inflect as feminine"
        )
      })}
    </p>
  );
}

На этапе сборки CLI обнаруживает вызов derive() и регистрирует две отдельные исходные записи, каждая из которых получает собственный перевод:

"I am tired" ($context: "inflect as masculine") → "Estoy cansado"
"I am tired" ($context: "inflect as feminine")  → "Estoy cansada"

Во время выполнения правильный перевод выбирается в зависимости от значения isMasculine.

Без derive() вам пришлось бы сделать два отдельных вызова:

// Без derive — более громоздко, исходный текст дублируется
const message = isMasculine
  ? gt("I am tired", { $context: "inflect as masculine" })
  : gt("I am tired", { $context: "inflect as feminine" });

derive() позволяет добиться того же результата с меньшим количеством дублирования и яснее показывает замысел.

Почему нельзя просто использовать условие?

Как и строки контента, значения $context должны быть статическими — CLI должен определять их на этапе сборки. Нельзя напрямую передать в $context выражение, вычисляемое во время выполнения, потому что CLI не будет знать, какие значения оно может принимать. derive() решает эту проблему, проходя по стеку вызовов, чтобы определить все возможные статические строки, которые могут быть переданы, и позволяя CLI зарегистрировать исходную запись для каждой из них.

Вкратце

Деривация контекста устраняет фундаментальный пробел в модели перевода: невозможность представлять сопоставления «один ко многим» между исходными записями и записями перевода. Комбинируя derive() с $context, один вызов gt() может возвращать несколько переводов, неоднозначность между которыми снимается по контексту во время выполнения.

Ссылки по теме