JavaRush /Курсы /ChatGPT Apps /Стратегия локализации для App

Стратегия локализации для App

ChatGPT Apps
9 уровень , 0 лекция
Открыта

1. Зачем думать о локализации именно в ChatGPT App

Если вы делали обычные веб‑приложения, локализация у вас, скорее всего, ассоциировалась с классическим i18n: строки интерфейса, пара форматов дат и чисел, словари — и вы аккуратно всё переводите. В ChatGPT App всё веселее: здесь участник номер три — сама LLM‑модель. Она читает ваши описания инструментов, промпты, результаты, делает выводы и принимает решения.

То есть язык — это не только «как красиво показать текст пользователю», но и «как модель поймёт, что делает ваш инструмент, когда его вызывать и какие аргументы туда подставлять». Кнопку «Купить» можно перевести кое‑как, пользователь разберётся. А если вы расплывчато описали tool, который делает платёж, на смеси русского и английского, модель может либо никогда его не вызвать, либо вызвать совсем не так, как вы ожидали.

Ещё один момент: ChatGPT уже передаёт в ваш MCP‑сервер подсказки по локали и локации пользователя — _meta["openai/locale"] и _meta["openai/userLocation"]. Это делается на уровне MCP‑запросов к инструментам, чтобы вы могли адаптировать текст и данные под язык и регион пользователя. То есть платформа уже «подсовывает» вам контекст, а задача разработчика — продуманно им воспользоваться.

Поэтому мы в этом модуле смотрим на локализацию как на архитектурный аспект ChatGPT App, а не как на «перевели UI и забыли».

2. Слои, которые нужно локализовать

Давайте посмотрим на App как на пирог из слоёв. Каждый слой может (и часто должен) быть локализован. Чтобы не утонуть, начнём с карты.

Обзор слоёв

Сначала — общая таблица, а потом разберём по кусочкам.

Слой Что это Примеры Влияние
Widget UI Весь видимый фронтенд в виджете Заголовки, кнопки, ошибки, подсказки UX пользователя
Тексты модели и промпты System‑prompt и заготовленные фразы Инструкции, шаблоны ответов Поведение ChatGPT
Данные и контент Тексты, которые App показывает и обрабатывает Каталоги товаров, описания, даты, цены И UX, и точность ответов
Описания tools/схем Метаданные инструментов и полей JSON Schema description, подсказки типов Как модель вызывает ваши tools
Commerce и юридическая часть Всё, что связано с покупками и политиками Названия SKU, Terms, Privacy, письма Юридическая корректность, доверие

Фактически это первый слой нашей карты локализации: дальше мы добавим глубину (косметика/семантика), языки и конкретные элементы.

Теперь пойдем по слоям по очереди.

Widget UI

Самый очевидный слой — интерфейс виджета. В GiftGenius это:

  • заголовки блоков;
  • подписи полей («Получатель», «Бюджет», «Интересы»);
  • кнопки («Подобрать подарок», «Сбросить фильтры»);
  • подсказки в инпутах («например, коллега, мама…»);
  • сообщения об ошибках и пустых состояниях («Подарков не найдено»).

В обычном React‑приложении это первые кандидаты для вынесения в словари. Здесь всё то же самое, только с поправкой на то, что UI — это не весь App, а лишь одно из его лиц.

Чуть позже в модуле мы будем делать нормальную архитектуру i18n для виджета, но уже сейчас важно зафиксировать: строк в JSX быть не должно. Даже если вы пока поддерживаете один язык, удобно сразу структурировать UI‑тексты.

Мини‑пример с нашим GiftGenius (пока без реальной i18n‑библиотеки):


type Locale = "en" | "ru";

const uiText = {
  en: {
    title: "GiftGenius: find a perfect present",
    recipientLabel: "Recipient",
  },
  ru: {
    title: "GiftGenius: подберите идеальный подарок",
    recipientLabel: "Получатель",
  },
};

function GiftForm({ locale }: { locale: Locale }) {
  const t = uiText[locale];

  return (
    <div>
      <h2>{t.title}</h2>
      <label>{t.recipientLabel}</label>
      {/* остальные поля */}
    </div>
  );
}

Здесь мы ещё не делаем «настоящую» локализацию, но уже явно выделяем слой UI‑текстов.

Тексты GPT и промпты

Следующий слой — системные и вспомогательные тексты, которые не видны пользователю напрямую, но сильно влияют на поведение модели:

  • system‑prompt вашего App («Ты — ассистент по подбору подарков…»);
  • шаблоны объяснений, которые вы даёте модели («Сформируй краткое резюме выбора»);
  • заготовленные follow‑ups и подсказки для модели («предложи пользователю уточнить бюджет, если…»).

Эти тексты тоже могут (и часто должны) быть локализованы. Простой пример: если пользователь пишет на русском, а system‑prompt у вас полностью на английском, модель, конечно, справится, но вы лишаете себя точного контроля над стилем и формулировками для этого языка.

Чуть позже, в лекциях про инструменты локализации промптов и описаний (prompts/descriptions), мы посмотрим, как аккуратно играть с многоязычными system‑prompts. Здесь нам важно обозначить: промпты — такой же локализуемый слой, как и UI.

Данные и контент

Дальше идут ваши данные. Для GiftGenius это каталог подарков: названия, описания, категории, иногда подсказки как использовать подарок. Для коммерческого App это ещё и цены, валюты, единицы измерения, форматы дат и т. д. В спецификациях product feed для ChatGPT (формат, по которому вы описываете свои товары и услуги для платформы) эти текстовые поля (title, description) и цены явно выделены, чтобы их можно было корректно показывать пользователям внутри ChatGPT.

Если вы хотите глобальный App, у каталога подарков возникают как минимум такие вопросы:

  • храним ли мы названия/описания на нескольких языках;
  • как выбираем, какой язык отдать пользователю;
  • что делаем, если перевода ещё нет (fallback);
  • как показываем валюты и форматы дат/цен для разных регионов.

Небольшой типизированный пример для каталога:

type Locale = "en" | "ru";

interface LocalizedString {
  en: string;
  ru: string;
}

interface Gift {
  id: string;
  title: LocalizedString;
  description: LocalizedString;
  priceCents: number;
  currency: "USD" | "EUR" | "BGN";
}
function getLocalizedTitle(gift: Gift, locale: Locale) {
  return gift.title[locale] ?? gift.title.en;
}

То есть локализация — это не только фронтенд, но и структура данных в базе и MCP‑ресурсах. К этому мы вернёмся, когда будем говорить о Gateway (шлюзе между ChatGPT и вашими сервисами) и MCP‑сервере.

Описания tools и JSON Schema

Четвёртый слой — описания инструментов и их аргументов. Именно через них модель понимает, когда надо вызвать ваш tool и какие аргументы туда передать. В MCP это title, description инструмента и description у полей схемы JSON.

Документация по Apps SDK подчёркивает, что модель использует имена, описания и документацию параметров, чтобы выбирать инструменты и строить аргументы.

Условный пример инструмента GiftGenius в TypeScript‑сервере MCP:

server.registerTool(
  "suggest_gifts",
  {
    title: "Suggest gifts",
    description: "Suggest 3–5 gift ideas based on recipient profile.",
    inputSchema: {
      type: "object",
      properties: {
        recipient: {
          type: "string",
          description: "Who is the gift for (e.g. mother, colleague)?",
        },
      },
      required: ["recipient"],
    },
  },
  async ({ input }) => { /* ... */ }
);

Сейчас всё на английском, модели отлично понятно. Но что если пользователь пишет на русском? Она всё равно сможет связать «мама» с recipient, но при сложных полях и доменных терминах шанс на промах растёт. В лекции про стратегии локализации описаний мы отдельно обсудим: единый английский язык описаний против локализованных описаний.

На этом этапе в карте локализации важно просто отметить: описания tools и JSON Schema тоже могут быть локализованы, и это влияет на поведение модели.

Commerce и юридическая часть

Наконец, слой, про который часто вспоминают в самом конце, — всё, что связано с деньгами и юридическими текстами:

  • названия SKU и планов подписки;
  • поля title/description в commerce‑фидах (товары, услуги, подписки);
  • Terms of Service, Privacy Policy, Refund Policy;
  • письма и уведомления (email, пуши), если App что‑то отправляет снаружи ChatGPT;
  • статусы заказов и ошибки оплаты, которые вы показываете пользователю («Платёж отклонён», «Недоступно в вашем регионе»).

Тут есть два аспекта: UX и закон. Пользователь должен понимать, на что он соглашается и за что платит, на своём языке. И одновременно переводы должны быть юридически корректными: иногда юристы требуют, чтобы юридически значимыми считались только тексты на одном языке (например, английском), а другие переводы носили «референсный» характер.

В нашей карте локализации мы обязательно отмечаем commerce и юридический контент как отдельный слой, потому что для него часто нужен другой процесс (юристы, комплаенс, согласование текстов с маркетингом).

3. Глубина локализации: «косметика» против «семантики»

Когда мы говорим «локализовать App», полезно различать два уровня глубины: косметический и семантический.

Косметическая локализация

Косметика — это всё, что меняет внешний вид и читабельность, но почти не меняет поведение системы. Примеры:

  • переведённые заголовки и подписи на кнопках;
  • переведённые placeholders в инпутах;
  • «человечные» сообщения об ошибках в UI;
  • локализованный текст маркетингового баннера в виджете.

Для классических веб‑приложений часто на этом и останавливаются. В ChatGPT App это важная, но только верхняя часть айсберга.

Семантическая локализация

Семантика — это вещи, от которых меняется поведение модели и логика App. Здесь язык влияет на:

  • то, какой инструмент модель выберет;
  • то, как она заполнит аргументы инструмента;
  • то, какие данные она будет считать «правильными» для данного пользователя.

Примеры семантической локализации:

  • system‑prompt на языке пользователя, задающий стиль и правила общения;
  • descriptions tools и их полей на языке, на котором общается пользователь;
  • разные тексты подсказок/инструкций в зависимости от культурного контекста;
  • настройки форматов дат/валют, влияющие на парсинг и генерацию (31.12.2025 vs 12/31/2025).

Если вы локализовали только косметику, но не семантику, ваш App может выглядеть локализованным, но вести себя как «англоязычный» под капотом. В карте локализации полезно прямо отметить, какие элементы критичны для поведения модели.

Для нашего GiftGenius это, например:

  • описание поля budget в JSON Schema («Budget in the user’s currency») — семантика;
  • подпись кнопки «Подобрать подарок» — косметика (важно для UX, но модель её не видит).

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

4. Одноязычный vs многоязычный ChatGPT App

Прежде чем рисовать карту, нужно понять амбиции: вы делаете строго одноязычный App или нацеливаетесь на многоязычную аудиторию.

Одноязычный App

Одноязычный App — это вариант, где вы сознательно поддерживаете только один язык. Например, только английский.

UI‑виджет, промпты, описания инструментов и данные — всё на одном языке. Это сильно упрощает жизнь:

  • одна кодовая база без ветвления по языкам;
  • одна схема каталога (без title_en, title_ru и прочего);
  • проще поддерживать и тестировать.

Но понятно, что аудитория ограничена. В случае ChatGPT App это ещё и значит: если пользователь придёт с другой локалью, ChatGPT всё равно может показать ваш App, но ему придётся постоянно «перекладывать» язык пользователя на внутренний язык App. В ряде ниш это окей, но для массового потребительского подарочного сервиса — вряд ли.

Многоязычный App

Многоязычный App — это уже архитектурное решение. Здесь:

  • UI и тексты корректно показываются на основе locale пользователя;
  • данные (каталоги, описания товаров) тоже привязаны к языку/региону;
  • descriptions tools и system‑prompts могут варьироваться по языку;
  • commerce‑сценарии учитывают локальные валюты, налоги, ограничения.

В этом случае одного условного if (locale === "ru") по всему коду уже явно недостаточно. Нужна архитектура: словари, локализуемые ресурсы, единое место, где хранится и обрабатывается locale и userLocation, договорённости между виджетом и MCP‑сервером.

Документация по Apps SDK прямо подчёркивает, что ChatGPT передаёт вам locale и userLocation в _meta, когда вызывает ваши инструменты, именно чтобы вы могли на стороне сервера выбирать правильный язык и формат данных. Это и есть «топливо» для многоязычных App.

Небольшое сравнение

Для наглядности — мини‑сравнение:

Характеристика Одноязычный App Многоязычный App
Объём кода Меньше Больше (словари, логика выбора)
Охват аудитории Ограниченный Глобальный
Сложность тестирования Ниже Выше
Работа с commerce/легалкой Проще Требует процессов и юристов
Работа с GPT‑поведением Одноязычный prompt Многоязычные prompts/descriptions

На уровне курса мы будем исходить из того, что GiftGenius становится многоязычным (как минимум EN/RU), чтобы показать «взрослую» схему. Но многие приёмчики будут полезны и для аккуратного одноязычного App, если вы хотите быть готовы к расширению.

5. Где язык реально влияет на модель

Теперь давайте выделим точки, в которых язык напрямую влияет на поведение ChatGPT.

Язык user input vs язык descriptions tools

Представим:

  • пользователь пишет: «Подбери подарок коллеге на 50 евро»;
  • ваш tool suggest_gifts описан только на английском;
  • поля схемы: recipient, budget, currency, interests.

Модель должна:

  1. решить, что вообще нужно вызвать suggest_gifts;
  2. извлечь recipient = "colleague", budget = 50, currency = "EUR";
  3. корректно сериализовать это в JSON аргументы.

Если descriptions краткие и на другом языке, модель с этим справляется, но вероятность ошибочно заполнить поля выше. Например, спутать budget и price_limit или передать текст в поле interests, потому что в описании поля было что‑то расплывчатое вроде «Any extra info about the gift».

Для русского текста пользователя и английских descriptions модель ещё и постоянно «перепрыгивает» между языками.

Вариант с локализованной схемой:

const locale = _meta?.["openai/locale"] ?? "en"; // приходит от ChatGPT 
const isRu = locale.startsWith("ru");

server.registerTool(
  "suggest_gifts",
  {
    title: isRu ? "Подбор подарков" : "Suggest gifts",
    description: isRu
      ? "Подбери 3–5 идей подарков на основе профиля получателя."
      : "Suggest 3–5 gift ideas based on recipient profile.",
    inputSchema: { /* ... */ },
  },
  async ({ input }) => { /* ... */ }
);

Здесь упрощённо: на самом деле descriptions лучше генерировать один раз при старте сервера, а не на каждый вызов, но идея понятна. Мы можем отдавать ChatGPT разные descriptions в зависимости от locale, чтобы модели было проще понимать пользователя.

Язык данных vs язык запроса

Если ваш каталог подарков только на английском, а пользователь общается на русском, модель будет подбирать англоязычные названия и описания. Иногда это окей, иногда — нет. Но важнее то, как вы форматируете вывод:

  • показываете ли вы пользователю оригинальные titles/description с сервера;
  • или модель пересказывает их на языке пользователя в своём тексте;
  • или ваш tool сам возвращает уже локализованный текст на основе locale.

В Apps SDK structured content (структурированные данные, которые вы возвращаете из tools) и текстовый ответ могут жить отдельно. Вы можете вернуть структурированные данные (например, JSON с полями товара) и отдельный текст для пользователя, а модель уже дальше решит, как это отрендерить или пересказать.

Локализация может происходить на уровне сервера (данные) или на уровне модели (переформулировать на нужном языке). При составлении карты полезно решить, где именно вы хотите держать «последнюю инстанцию».

System‑prompt и follow‑ups

Если system‑prompt у вас только на английском, а пользователь — русскоговорящий, модель будет постоянно балансировать между двумя языками. Это может быть нормально, но иногда вы хотите жёстко задать тон: например, в русской версии App вы хотите более неформальный стиль, а в английской — формальный.

Следовательно, в карте локализации нужно отметить:

  • system‑prompt EN;
  • system‑prompt RU;
  • шаблоны follow‑ups (EN/RU);
  • любые «жёсткие» подсказки в промпте для инструментов.

6. Карта локализации для GiftGenius

Теперь соберём всё, что мы уже обсудили про слои, глубину и языки, в явную карту локализации для GiftGenius. Давайте сделаем то, что вам потом предстоит сделать для своего App: составим карту локализации. Идея простая: таблица, в столбцах — слой и тип сущности, в строках — конкретные элементы.

Пример карты

Вот упрощённая карта для GiftGenius (EN/RU):

Категория Элемент Пример значения (EN) Пример (RU) Косметика или семантика
UI Заголовок виджета GiftGenius: find a perfect present GiftGenius: подберите идеальный подарок Косметика
UI Лейбл получателя Recipient Получатель Косметика
UI Ошибка пустого списка No gifts found Подарков не найдено Косметика
Prompts System‑prompt You are GiftGenius, a gift assistant… Ты — GiftGenius, ассистент по подбору подарков… Семантика
Prompts Шаблон резюме выбора Here’s why these gifts fit… Вот почему эти подарки подходят… Семантика
Data Название подарка Smart mug Умная кружка И UX, и семантика
Data Описание подарка Self‑heating mug with app control… Самонагревающаяся кружка с управлением через приложение… И UX, и семантика
Data Валюта 59.99 USD 116.61 BGN / 59,99 EUR Семантика (формат/валюта)
Tools/schema
suggest_gifts.description
Suggest gift ideas based on profile… Подбирает идеи подарков на основе профиля… Семантика
Tools/schema
budget.description
Budget in user’s currency Бюджет в валюте пользователя Семантика
Commerce Название SKU в фиде “Premium subscription – 1 year” «Премиум‑подписка — 1 год» И UX, и юр.
Commerce Страница Terms Terms of Service (EN only) Уведомление: юридически значим только EN‑текст Семантика/право
Errors (backend) Сообщение об ошибке оплаты Payment failed, please try again later Платёж не прошёл, попробуйте позже Косметика + UX

Слева мы группируем по слоям, далее — конкретные элементы. Последний столбец помогает понимать, что нельзя править без согласования с промпт‑дизайнером/моделистом: всё, что помечено как семантика, влияет на поведение GPT.

Небольшой кодовый набросок

Чтобы связать карту с кодом, можно завести простой тип для локализуемых сущностей:

type LocalizedTextKey =
  | "ui.title"
  | "ui.recipient_label"
  | "error.no_gifts"
  | "prompt.summary_intro";

type Locale = "en" | "ru";

type Messages = Record<Locale, Record<LocalizedTextKey, string>>;
const messages: Messages = {
  en: {
    "ui.title": "GiftGenius: find a perfect present",
    "ui.recipient_label": "Recipient",
    "error.no_gifts": "No gifts found",
    "prompt.summary_intro": "Here’s why these gifts fit:",
  },
  ru: {
    "ui.title": "GiftGenius: подберите идеальный подарок",
    "ui.recipient_label": "Получатель",
    "error.no_gifts": "Подарков не найдено",
    "prompt.summary_intro": "Вот почему эти подарки подходят:",
  },
};

Дальше эти же ключи можно использовать и в виджете, и при формировании промптов на сервере (при условии, что вы передаёте locale сквозь стек — об этом будет следующая лекция). Таким образом, ваша «карта локализации» постепенно превращается в типизированный словарь, а не в разрозненный набор строк.

7. Практика: сделайте карту локализации для своего App

Прежде чем углубляться в конкретные техники i18n и архитектуру Gateway/MCP, важно сделать одно скучное, но очень полезное упражнение: честно описать, что именно вы собираетесь локализовать.

Хороший подход — открыть любой редактор (хоть Google Sheets, хоть Notion) и завести таблицу с колонками:

  • категория/слой (UI, промпты, данные, tools, commerce и юридическая часть, ошибки);
  • элемент (конкретная кнопка, конкретное описание поля, конкретный endpoint с текстом);
  • пример EN‑значения;
  • пример значения на втором языке (если уже есть или хотя бы черновик);
  • пометка «косметика/семантика/юридически важно»;
  • владелец (кто отвечает за исправления: фронтенд, MCP‑сервер, продакт, юрист).

Дальше проходите по своему App и честно выписываете всё, где есть текст либо язык влияет на формат данных.

Для GiftGenius получилась бы примерно расширенная версия таблицы выше. По пути вы почти гарантированно обнаружите пару «скрытых» мест:

  • текстовые константы в коде MCP‑серверов (например, сообщения об ошибках);
  • дефолтные значения в structuredContent (например, категории, которые вы не выводили в UI);
  • старые подписи у tools, которые уже не соответствуют их фактическому поведению.

Это упражнение особенно полезно сделать до того, как вы соедините локализацию с реальным бизнес‑процессом (платежи, активации подписок, юридические документы). Переименовывать tool charge_user в многоязычной системе с ACP и юридическими текстами потом гораздо больнее.

В целом, если вы заранее рисуете карту локализации и честно отмечаете, что именно и на каких языках собираетесь поддерживать, вы сильно экономите себе нервы на следующих модулях — когда в игру войдут MCP, Gateway, commerce и Store.

8. Типичные ошибки при планировании локализации

Ошибка №1: считать, что локализация = «перевести кнопки».
Очень частый сценарий: команда аккуратно выносит все строки UI в словари, переводит их и радуется. При этом system‑prompt остаётся только на английском, descriptions tools — тоже, а каталог товаров содержит исключительно англоязычные названия. В результате App выглядит локализованным, но модель внутри продолжает жить в своём мирке, и поведение остаётся англоцентричным. На практике это проявляется в странных рекомендациях и ошибках в аргументах tools.

Ошибка №2: не различать косметику и семантику.
Иногда продакт просит «немного подправить формулировку» в описании инструмента или в system‑prompt, и разработчик меняет текст, как будто это простой UI‑лейбл. Но description поля JSON Schema или фраза в system‑prompt — это часть контракта с моделью. Такие изменения могут радикально изменить то, как GPT вызывает ваш tool. Если заранее не помечать семантические элементы в карте локализации, легко случайно сломать поведение App.

Ошибка №3: начинать с многоязычного хаоса без архитектуры.
Очень заманчиво в начале просто раскидать по коду if (locale === "ru") и подставлять русские строки, где понадобится. В результате через пару недель приложение превращается в «локализационный ад»: в одном компоненте строки из словаря, в другом — зашиты в JSX, на сервере — третья схема именования ключей. Позже подключить нормальную i18n‑систему и привести всё к единому виду становится намного сложнее.

Ошибка №4: забывать про данные и деньги.
Даже опытные команды часто начинают с перевода UI и промптов, но упускают, что каталоги товаров, цены, валюты и юридические тексты тоже должны учитывать locale и userLocation. В спецификациях product feed для ChatGPT как раз жёстко задано, какие текстовые поля и цены нужны для корректного отображения товаров пользователя. Если вы не заложите многоязычность на уровне данных, потом придётся либо дублировать фид, либо делать болезненные миграции.

Ошибка №5: игнорировать сигналы платформы о локали и локации.
ChatGPT уже передаёт в MCP‑вызовах _meta["openai/locale"] и _meta["openai/userLocation"], чтобы вы могли понимать, на каком языке и из какого региона с вами общаются. Некоторые разработчики всё равно просят у пользователя «Выберите язык интерфейса» при первом запуске и никак не используют эти сигналы для выбора ресурсов и цен. В результате UX страдает, а архитектура становится сложнее, чем нужно.

Ошибка №6: не фиксировать «владельцев» локализуемых элементов.
Когда всё пошло в бой, оказывается, что переводы расползлись по разным людям: фронтендеры правят UI‑тексты, бэкендеры — descriptions tools, ML‑специалист — system‑prompt, а юристы присылают отредактированные Terms. Если в карте локализации не указать, кто отвечает за какой слой, изменения начинают конфликтовать, а какие‑то тексты обновляются в одном месте и не обновляются в другом.

1
Задача
ChatGPT Apps, 9 уровень, 0 лекция
Недоступна
Страница “Localization Map” (слои + глубина)
Страница “Localization Map” (слои + глубина)
1
Задача
ChatGPT Apps, 9 уровень, 0 лекция
Недоступна
Двуязычные UI + follow-up шаблоны (локализуем “тексты модели”)
Двуязычные UI + follow-up шаблоны (локализуем “тексты модели”)
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ