gt-next@6.8.0
Обзор
Мы часто замечаем: чем зрелее становится кодовая база, тем более фрагментированным оказывается контент. Предложения оказываются разбросаны по функциям, утилитам, логике и сервисам.
function getSubject(gender) {
return gender === "male" ? "мальчик" : "девочка"
}
function getObject(toy, gender) {
return toy === "мяч" ? "мяч" : getSubject(gender)
}
function Component({ gender, toy }) {
return (
<>
<p>
Красив{getSubject(gender) === "мальчик" ? "ый" : "ая"} {getSubject(gender)} играет с {getObject(toy, gender) === "мяч" ? "мячом" : getObject(toy, gender) === "мальчик" ? "мальчиком" : "девочкой"}.
</p>
</>
)
}Когда неизбежно приходит время заниматься интернационализацией, разработчики обнаруживают, что загнали себя в угол. Обеспечить такие вещи, как согласование, спряжение и изменения порядка слов по нескольким файлам, невозможно без серьёзного рефакторинга. Традиционно это означало ручное извлечение всех возможных вариантов каждого предложения и добавление их в словарь переводов.
В gt-next 6.8.0 мы ещё сильнее укрепляем убеждение, что мощная библиотека i18n должна адаптироваться под кодовую базу, а не наоборот.
Хотя gt-next уже умеет переводить контент inline, ему не хватает двух фундаментальных возможностей такой библиотеки:
(1) поддержки фрагментации предложений и (2) возможности повторного использования контента при сохранении согласования слов, спряжения и изменений порядка слов.
Мы представляем компонент <Static>, который позволяет вызывать статические функции непосредственно внутри переводов.
function getSubject(gender) {
return gender === "male" ? "мальчик" : "девочка"
}
function getObject(type, gender) {
return type === "мяч" ? "мяч" : getSubject(gender)
}
function Component({ gender, toy }) {
return (
<T>
<p>
Красив{genderAgreement} <Static>{getSubject(gender)}</Static> играет с <Static>{getObject(toy, gender)}</Static>.
</p>
</T>
)
}Важные замечания
При этом мы настоятельно рекомендуем использовать компонент <Static> аккуратно и взвешенно.
Компонент <Static>, несмотря на свою мощь, может привести к значительному увеличению числа переводческих записей.
При неправильном использовании это может негативно сказаться на времени загрузки приложения.
Как использовать <Static>
Как и компоненты <T> и <Var>, компонент <Static> — это флаг, который указывает CLI‑инструменту, где нужно, а где не нужно искать переводимый контент.
Он говорит CLI‑инструменту разыменовать вызов функции внутри тегов <Static> и занести в каталог все возможные варианты контента, возвращаемого этой функцией.
Относитесь к каждому оператору return так, как будто он обёрнут в компонент <T>.
После того как CLI‑инструмент найдёт все возможные результаты вызова функции, он создаёт отдельную запись перевода для каждого возможного результата. Например, следующий код создаёт две отдельные записи перевода: "The boy is beautiful" и "The girl is beautiful". Поскольку для каждого возможного результата существует своя запись перевода, мы можем корректно обрабатывать согласование, спряжение и порядок слов во фрагментированном предложении: "El niño es hermoso" и "La niña es hermosa".
function getSubject(gender) {
return gender === "male" ? "boy" : "girl"
}
function Component({ gender }) {
return (
<T>
<Static>{getSubject(gender)}</Static> красив(а/о).
</T>
)
}Ограничения и планы по улучшению
Умножение
Как уже упоминалось, если слишком активно использовать компонент <Static>, он может сгенерировать большое количество записей переводов, что негативно скажется на времени загрузки.
Например, рассмотрим компонент с двумя компонентами <Static>, каждый из которых оборачивает вызов функции с двумя возможными вариантами результата.
В этом случае создаются четыре записи перевода.
Каждый дополнительный компонент <Static> умножает количество переводов на число возможных вариантов результата каждого вызова функции.
function getSubject(gender) {
return gender === "male" ? "мальчик" : "девочка"
}
function getObject(toy) {
return toy === "ball" ? "мяч" : "карандаш"
}
function Component({ gender, toy }) {
return (
<T>
<Static>{getSubject(gender)}</Static> играет с <Static>{getObject(toy)}</Static>.
</T>
)
}Синтаксис
Важно рассматривать каждый оператор return так, как будто он обёрнут в компонент <T>.
Любые переменные или вызовы функций, которые являются динамическими, по‑прежнему должны быть обёрнуты в компоненты <Var>.
В данный момент <Static> поддерживает только вызовы функций в качестве дочерних элементов, но в будущем он сможет работать с более сложными выражениями.
Начиная с gt-next 6.8.0, для статических функций поддерживается следующий синтаксис:
function getExamples(key) {
switch (key) {
case "string, number, and boolean literals":
if (condition1) {
return "Мальчик"
} else if (condition2) {
return 22
} else {
return true
}
case "jsx expressions":
return (
<>
Привет, <Static>{getTitle(title)}</Static>. Как у тебя дела, <Var>{name}</Var>?
</>
);
case "ternary operators":
return condition ? "Мальчик" : "Девочка"
case "function calls":
return otherStaticFunction();
}
}Заключение
gt-next 6.8.0 представляет компонент <Static> как решение проблемы фрагментации предложений без потери полноты перевода и корректного грамматического согласования.