# General Translation Knowledge Base: Писать собственную i18n или использовать General Translation?
URL: https://generaltranslation.com/ru/kb/general-translation-vs-in-house-i18n.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: Самописной i18n (по словарю на каждый язык и небольшой вспомогательной функции t()) вполне достаточно для одного-двух языков и небольшого объёма текста. По мере роста приложения вам приходится заново реализовывать правила множественного числа, резервные варианты и синхронизацию файлов, а переводы всё равно нужно где-то брать. Библиотеки General Translation с открытым исходным кодом берут на себя рендеринг, а General Translation генерирует и обновляет переводы на основе вашего кода.
Category: Интернационализация
Last updated: 2026-10-16
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-16

Интернационализацию (i18n) можно реализовать самостоятельно: объект сообщений для каждого языка, вспомогательная функция `t()`, которая находит ключ и подставляет переменные, переключатель локали и встроенные API `Intl` для чисел и дат. Для одного-двух языков и нескольких десятков строк этого зачастую достаточно — и именно такой код обычно пишет агент для написания кода, если попросить его добавить язык. С ростом приложения разрастается всё, что окружает эту функцию: правила множественного числа, отсутствующие ключи, синхронизация всех языковых файлов с кодом и, в первую очередь, сами переводы, которые кто-то должен сделать. Библиотеки General Translation с открытым исходным кодом берут на себя ту часть работы, что приходится на время выполнения, а General Translation генерирует и обновляет переводы на основе вашего кода.

## Когда достаточно самописной i18n

* **Никаких сторонних зависимостей.** Словарь и вспомогательная функция — ваши, и вы контролируете каждую строку кода.
* **Форматирование берёт на себя платформа.** `Intl.NumberFormat`, `Intl.DateTimeFormat`, `Intl.PluralRules` и `Intl.Locale` [встроены в современные браузеры и Node.js](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) и форматируют валюты, даты и категории множественного числа с учётом локали.
* **Немного текста, и он редко меняется.** Прототипу, внутреннему инструменту или сайту с одним дополнительным языком, тексты на котором пишет коллега, большего не нужно.
* **Языки с английской моделью множественного числа.** И в английском, и в немецком есть только [`one` и `other`](https://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).

## Что ломается по мере роста

Вот типичная первая версия, в которую добавлен польский словарь:

```js title="i18n.mjs"
const messages = {
  en: {
    greeting: 'Hello, {name}!',
    files: { one: '{count} file', other: '{count} files' },
    checkout: 'Checkout',
  },
  pl: {
    greeting: 'Cześć, {name}!',
    files: { one: '{count} plik', other: '{count} pliki' },
    // «checkout» ещё не переведён
  },
};

export function t(locale, key, vars = {}) {
  let message = messages[locale][key];
  if (typeof message === 'object') {
    message = vars.count === 1 ? message.one : message.other;
  }
  return message.replace(/\{(\w+)\}/g, (_, name) => vars[name]);
}

console.log(t('pl', 'greeting', { name: 'Ania' }));
console.log([1, 2, 5].map((count) => t('pl', 'files', { count })).join(', '));
console.log(t('pl', 'checkout'));
```

Запустим его в Node.js 24:

```text title="Output"
Cześć, Ania!
1 plik, 2 pliki, 5 pliki
TypeError: Cannot read properties of undefined (reading 'replace')
```

Сразу всплывают две ошибки. «5 pliki» — неправильно (по-польски говорят «5 plików»), а непереведённый ключ `checkout` ломает рендеринг. В платформе есть всё необходимое, чтобы исправить обе:

```js title="intl.mjs"
// Категории множественного числа для каждого языка
for (const locale of ['en', 'ja', 'pl', 'ar']) {
  console.log(locale, new Intl.PluralRules(locale).resolvedOptions().pluralCategories.join(' '));
}
const pl = new Intl.PluralRules('pl');
console.log([1, 2, 5, 22].map((n) => `${n} → ${pl.select(n)}`).join(', '));

// Валюты и даты
const date = new Date(Date.UTC(2026, 9, 16));
for (const locale of ['en-US', 'de-DE', 'ja-JP']) {
  const price = new Intl.NumberFormat(locale, { style: 'currency', currency: 'EUR' }).format(1234.5);
  const day = new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeZone: 'UTC' }).format(date);
  console.log(locale, price, day);
}

// Направление текста
console.log(new Intl.Locale('ar').getTextInfo().direction);
```

```text title="Output"
en one other
ja other
pl one few many other
ar zero one two few many other
1 → one, 2 → few, 5 → many, 22 → few
en-US €1,234.50 October 16, 2026
de-DE 1.234,50 € 16. Oktober 2026
ja-JP €1,234.50 2026年10月16日
rtl
```

Каждое исправление по отдельности незначительно, но в сумме они дают заметный эффект:

* **Множественное число.** Проверка `n === 1` не работает для польского (четыре категории) и арабского (шесть), поэтому вспомогательной функции нужен [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules), а в каждом словаре — отдельная строка для каждой категории. (См. [Как работать с формами множественного числа в React?](/kb/how-to-handle-plurals-in-react))
* **Порядок слов.** Заполнители вроде `{name}` позволяют каждому языку ставить значение в нужное место. Конкатенация так не умеет: `t('by') + ' ' + author` ставит имя в конец, а по-японски пишут «Ana 著».
* **Форматирование.** `{count}` вставляет число как есть, поэтому вспомогательной функции нужен ещё и [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat), чтобы на польском 12,500 выводилось как «12 500».
* **Отсутствующие ключи.** Вспомогательной функции нужна цепочка резервных вариантов (язык перевода, затем исходный язык, затем сам ключ), иначе пользователи увидят `undefined` или приложение упадёт.
* **Синхронизация файлов.** Никто не подскажет вам, что в `pl` нет `checkout` или там осталась формулировка месячной давности, — пока это не заметит пользователь.
* **Языки с написанием справа налево.** Для арабского и иврита на странице нужны `lang` и `dir="rtl"`, а также зеркальная вёрстка.
* **Поисковые системы.** Если переключатель хранит выбор в состоянии или cookie-файле, все языки остаются на одном URL, тогда как Google рекомендует отдельный URL для каждого языка ([Managing multilingual sites](https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites)). (См. [Как настроить SEO для многоязычного приложения Next.js?](/kb/multilingual-nextjs-seo))
* **Сами переводы.** От этих затрат не избавит никакая вспомогательная функция: кто-то должен написать «plików» и все остальные строки на всех языках — и переписывать их при каждом изменении английского текста.

Когда вспомогательная функция научится работать с категориями множественного числа, резервными вариантами и форматированием чисел, окажется, что вы написали ядро библиотеки интернационализации, — а переводы всё равно нужны.

## Что предлагает General Translation

General Translation сохраняет сильные стороны самописного подхода (читаемый текст и встроенное форматирование платформы) и берёт на себя то, что со временем разрастается. С `gt-react` (или `gt-next` для Next.js) текст остаётся прямо в компоненте внутри [`<T>`](/docs/react/reference/components/t), поэтому не нужно поддерживать ни словарь, ни вспомогательную функцию:

```tsx title="Inbox.tsx"
import { T, Plural, Num, Var } from 'gt-react';

export function Inbox({ name, count }: { name: string; count: number }) {
  return (
    <T>
      <h1>Welcome back, <Var>{name}</Var></h1>
      <Plural
        n={count}
        singular={<p>You have <Num>{count}</Num> unread message.</p>}
        plural={<p>You have <Num>{count}</Num> unread messages.</p>}
      />
    </T>
  );
}
```

[`<Plural>`](/docs/react/reference/components/plural) выбирает ветку по правилам множественного числа CLDR для каждой локали — тем же, на которых построен `Intl.PluralRules`, поэтому писать условие `n === 1` и ошибаться в нём не придётся. [`<Num>`](/docs/react/reference/components/num) форматирует число для локали читателя, а значение внутри [`<Var>`](/docs/react/reference/components/var) никогда не отправляется в API General Translation. Ниже — результат серверного рендеринга компонента с `gt-react` 11.4.12. Для наглядности испанский перевод вписан вручную в шаблон, созданный командой [`gt generate`](/docs/cli/reference/commands/generate) (текстовые разделители React удалены):

```html title="Output"
<!-- en, count = 12500 -->
<h1>Welcome back, Ana</h1><p>You have 12,500 unread messages.</p>
<!-- es, count = 12500 -->
<h1>Hola de nuevo, Ana</h1><p>Tienes 12.500 mensajes sin leer.</p>
```

Если для блока в какой-либо локали нет перевода, [`<T>`](/docs/react/reference/components/t) выводит исходное содержимое, а не `undefined` и не ошибку.

Главное отличие в том, что переводы создаёт General Translation:

* **Создаются с учётом контекста.** [`npx gt translate`](/docs/cli/reference/commands/translate) отправляет каждый блок [`<T>`](/docs/react/reference/components/t) вместе с его элементами, переменными, ветвями множественного числа и заметкой [`context`](/docs/react/reference/components/t#context), если она есть, и записывает по файлу на каждую локаль. Glossary закрепляет термины, а пользовательские промпты задают тон во всех проектах, использующих общую контекстную группу. (См. [Определение контекста для переводов](/docs/platform/dashboard/guides/defining-context-for-translations).)
* **Остаются актуальными.** При каждом запуске переводится новое и изменённое содержимое, а для остального повторно используются готовые переводы. Запускайте перевод в CI или поручите [Locadex](/docs/platform/locadex/quickstart), AI-агенту General Translation, открывать пул-реквесты по выбранным вами триггерам. В приложениях на Next.js и React Locadex также может обернуть существующие тексты в [`<T>`](/docs/react/reference/components/t).
* **Проверяются людьми.** Ваша команда редактирует переводы в панели управления. (См. [Проверка и редактирование переводов](/docs/platform/dashboard/guides/reviewing-translations).)
* **Направление письма и маршрутизация.** [`useLocaleDirection`](/docs/react/reference/hooks/use-locale-direction) возвращает `'rtl'` для арабского языка, а `gt-next` с помощью своего [промежуточного ПО](/docs/react/nextjs/app-router-middleware) может отдавать каждую локаль по отдельному URL.

JavaScript-библиотеки распространяются под лицензией MIT и работают без аккаунта General Translation, если вы предоставляете переводы сами. Приложение, настроенное на загрузку всех переводов из своего бандла, не обращается к General Translation во время выполнения. Для создания переводов используйте облачный сервис с [оплатой по факту использования](https://generaltranslation.com/pricing).

Пример с другого конца шкалы — Profound: компания выпускает свою платформу и документацию более чем в 47 локалях с помощью General Translation. (См. [развёртывания в рабочей среде](https://generaltranslation.com/enterprise).)

## Собственное решение, библиотека или General Translation: краткое сравнение

|                            | Собственный словарь и вспомогательная функция               | Библиотека с открытым исходным кодом, например i18next                                                       | General Translation                                                                                                                                                                |
| -------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Зависимости                | Нет                                                         | Сама библиотека и привязки к фреймворку, например `react-i18next`                                            | `gt-react` или `gt-next`, а также CLI `gt`                                                                                                                                         |
| Формы множественного числа | Ваш собственный код выбора формы и все формы в каждом файле | Выбор по правилам CLDR; формы предоставляют люди или подключённый сервис перевода                            | [`<Plural>`](/docs/react/reference/components/plural) выбирает форму по правилам CLDR; при переводе формы для каждого языка перевода генерируются на основе написанных вами ветвей |
| Числа, даты, валюты        | API `Intl`, которые вы вызываете сами                       | Встроенные средства форматирования поверх `Intl`                                                             | [`<Num>`](/docs/react/reference/components/num), [`<Currency>`](/docs/react/reference/components/currency) и [`<DateTime>`](/docs/react/reference/components/datetime)             |
| Отсутствующие переводы     | Зависит от реализации вспомогательной функции               | [Используется заданный резервный язык, затем отображается ключ](https://www.i18next.com/principles/fallback) | Отображается исходное содержимое                                                                                                                                                   |
| Синхронизация языков       | Вручную или собственным скриптом                            | Инструменты извлечения строк и подключённый вами сервис перевода                                             | Каждый запуск [`npx gt translate`](/docs/cli/reference/commands/translate) переводит новое и изменённое содержимое                                                                 |
| Кто переводит              | Люди или интегрированный вами сервис                        | Люди или подключённый сервис перевода                                                                        | ИИ с учётом размеченного контекста JSX, Glossary и пользовательских промптов; ваша команда проверяет переводы в панели управления                                                  |
| Стоимость                  | Ваше время и стоимость интегрированных сервисов             | Библиотека бесплатна, перевод оплачивается отдельно                                                          | Бесплатные библиотеки для JavaScript; [оплата перевода по факту использования](https://generaltranslation.com/pricing)                                                             |

## Когда стоит сделать всё самостоятельно

Делайте всё самостоятельно, если вы поддерживаете один-два языка, текстов немного и они редко меняются, множественное число в ваших языках образуется так же, как в английском, а переводы пишет кто-то из команды, — или если речь идёт о прототипе. Подключите библиотеку с открытым исходным кодом, например i18next, если вам нужны правила множественного числа и резервные варианты, а переводчики или система управления переводами у вас уже есть. Выбирайте General Translation, если вы добавляете сразу несколько языков, тексты меняются с каждым релизом или никому в команде не стоит возиться с польскими формами множественного числа: General Translation генерирует переводы с учётом контекста вашего кода и при каждой сборке поддерживает все языки в актуальном состоянии. (См. [General Translation в сравнении с i18next, react-intl и next-intl](/kb/general-translation-vs-i18n-libraries).)

## Сохраните свой словарь и доверьте его перевод CLI

Чтобы отказаться от ручного перевода, не нужно переписывать вспомогательную функцию. Перенесите сообщения для каждого языка в отдельный JSON-файл (`locales/en.json`, `locales/es.json`), оставьте свою функцию `t()` и укажите путь к этим файлам в `gt.config.json` с помощью заполнителя `[locale]`:

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": [
    "es"
  ],
  "files": {
    "json": {
      "include": [
        "locales/[locale].json"
      ]
    }
  }
}
```

[`npx gt translate --dry-run`](/docs/cli/reference/commands/translate) показывает `locales/en.json` как источник, а полный запуск создаёт `locales/es.json`. В этом примере используются английские и испанские сообщения с одинаковой структурой ключей и простыми заполнителями, например `{name}`. В сопутствующем файле `locales/en.metadata.json` можно указать контекст или ограничения на количество символов для каждого ключа. См. [JSON](/docs/cli/reference/formats/json-files) и [Метаданные, привязанные к ключам](/docs/cli/reference/keyed-metadata). Поиск по ключу и выбор формы множественного числа по-прежнему остаются за вашей вспомогательной функцией — проверьте и то и другое на отрендеренном испанском тексте.

Чтобы отказаться от вспомогательной функции, постепенно оборачивайте компоненты в [`<T>`](/docs/react/reference/components/t) — по одному за раз — или сохраните ключи, используя [`useTranslations`](/docs/react/guides/translating-with-dictionaries). Если работу выполняет агент для написания кода, вместо того чтобы просить его написать вспомогательную функцию `t()`, передайте ему [инструкции для агентов](/docs/overview/for-coding-agents) от General Translation. Начните с [Быстрого старта для Next.js](/docs/react/nextjs-quickstart) или [Быстрого старта SPA для React](/docs/react/react-spa-quickstart).

## Основные выводы

* Словаря, вспомогательной функции `t()` и встроенных API `Intl` достаточно, если у вас один-два языка, немного текста и формы множественного числа устроены так же, как в английском.
* По мере роста приложения вам приходится самостоятельно поддерживать выбор форм множественного числа, резервные варианты, форматирование, синхронизацию файлов, поддержку right-to-left, отдельные URL для каждой локали и сам процесс подготовки переводов.
* Библиотеки General Translation берут на себя работу во время выполнения, General Translation генерирует переводы, используя ваш код как контекст, а если вы хотите сохранить самописный JSON-словарь, CLI может перевести и его.

## Related questions

- [General Translation против i18next, react-intl и next-intl: какую библиотеку интернационализации выбрать?](https://generaltranslation.com/ru/kb/general-translation-vs-i18n-libraries.mdx): Библиотеки с открытым исходным кодом, такие как i18next, react-intl и next-intl, ничего не переводят. Они лишь отображают переводы, которые вы сами помещаете в файл каталога для каждого языка, — их пишете вы, ваши переводчики или сторонний сервис. Библиотеки General Translation тоже имеют открытый исходный код и делают то же самое, но General Translation ещё и выполняет перевод, используя ваш код как контекст.
- [Как работать с формами множественного числа в React?](https://generaltranslation.com/ru/kb/how-to-handle-plurals-in-react.mdx): Не зашивайте логику выбора формы множественного числа в код с помощью проверок вроде n === 1. Для приложений только на английском хватит небольшой вспомогательной функции, но многоязычным приложениям нужны locale-aware правила множественного числа. С ними для любого языка справляется i18n-компонент, например `<Plural>` из gt-react или gt-next.
- [Как настроить SEO для многоязычного приложения Next.js?](https://generaltranslation.com/ru/kb/multilingual-nextjs-seo.mdx): Выделите каждому языку собственный URL, задайте атрибут lang у тега html, укажите для каждой страницы канонический URL, ведущий на неё саму, добавьте альтернативные версии hreflang для всех языков, переведите заголовки и описания и перечислите все языковые версии в карте сайта.
- [Можно ли реализовать i18n без файлов перевода?](https://generaltranslation.com/ru/kb/i18n-without-translation-files.mdx): Да. С gt-react или gt-next контент остаётся встроенным прямо в ваши компоненты внутри компонента `<T>`, а переводы генерируются во время сборки, поэтому не нужно писать ключи и JSON-файлы для каждой локали и следить за их синхронизацией.
- [Альтернативы Google Translate: General Translation и Google Translate](https://generaltranslation.com/ru/kb/general-translation-vs-google-translate.mdx): Google Translate — быстрый способ перевести разовый текст, но чтобы выпустить продукт на другом языке, нужно переводить каждую строку с учётом контекста, соблюдать единую терминологию, правильно обрабатывать переменные и формы множественного числа, проводить ревью и выстроить процесс релизов. General Translation понимает контекст каждой строки в вашем коде и автоматизирует весь рабочий процесс локализации — от кода до ревью и каждого релиза.

## Previous and next questions

- Previous question: [Какая библиотека интернационализации лучше всего подходит для приложения React?](https://generaltranslation.com/ru/kb/best-react-i18n-library.mdx)
- Next question: [Почему стоит выбрать General Translation вместо TMS (Smartling, Lokalise, Phrase, Crowdin или Transifex)?](https://generaltranslation.com/ru/kb/general-translation-vs-tms.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/ru/kb/sitemap.md) for every article.
