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

Стратегія локалізації для застосунку

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
Комерційна й юридична частина Усе, що повʼязано з покупками та політиками Назви 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" | "UAH";
}
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 також можна локалізувати, і це впливає на поведінку моделі.

Комерційна й юридична частина

Нарешті шар, про який часто згадують уже наприкінці, — усе, що повʼязано з грошима та юридичними текстами:

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

Тут є два аспекти: UX і закон. Користувач має розуміти, на що він погоджується і за що платить, своєю мовою. Водночас переклади мають бути юридично коректними: інколи юристи вимагають, щоб юридично значущими вважалися лише тексти однією мовою (наприклад, англійською), а інші переклади мали довідковий характер.

У нашій карті локалізації ми обовʼязково виділяємо комерційний і юридичний контент в окремий шар, тому що для нього часто потрібен інший процес (юристи, комплаєнс, погодження текстів із маркетингом).

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

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

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

Косметика — це все, що змінює зовнішній вигляд і читабельність, але майже не впливає на поведінку системи. Приклади:

  • перекладені заголовки та мітки на кнопках;
  • перекладені підказки в полях введення;
  • «людяні» повідомлення про помилки в UI;
  • локалізований текст маркетингового банера у віджеті.

Для класичних вебзастосунків часто на цьому й зупиняються. У ChatGPT App це важливо, але це лише верхівка айсберга.

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

Семантика — це речі, від яких змінюється поведінка моделі та логіка App. Тут мова впливає на:

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

Приклади семантичної локалізації:

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

Якщо ви локалізували лише косметику, але не семантику, ваш App може виглядати локалізованим, але «під капотом» поводитися англомовно. Під час складання карти локалізації корисно прямо позначати, які елементи критичні для поведінки моделі.

Для нашого GiftGenius це, наприклад:

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

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

4. Одномовний чи багатомовний ChatGPT App

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

Одномовний App

Одномовний App — це варіант, коли ви свідомо підтримуєте лише одну мову. Наприклад, тільки англійську.

UI‑віджет, промпти, описи інструментів і дані — усе однією мовою. Це суттєво спрощує роботу:

  • одна кодова база без розгалуження за мовами;
  • одна схема каталогу (без title_en, title_ru та подібного);
  • простіша підтримка й тестування.

Але очевидно, що аудиторія буде обмеженою. У випадку ChatGPT App це ще й означає: якщо користувач прийде з іншою локаллю, ChatGPT усе одно може показати ваш App, але йому доведеться постійно «перекладати» мову користувача на внутрішню мову App. Для деяких ніш це нормально, але для масового споживчого подарункового сервісу — навряд чи.

Багатомовний App

Багатомовний App — це вже архітектурне рішення. Тут:

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

У цьому випадку одного умовного if (locale === "ru") по всьому коду вже явно недостатньо. Потрібна архітектура: словники, ресурси, що підлягають локалізації, єдине місце, де зберігається й обробляється locale і userLocation, а також домовленості між віджетом і MCP‑сервером.

Документація до Apps SDK прямо підкреслює, що ChatGPT передає вам locale і userLocation у _meta, коли викликає ваші інструменти, — саме щоб ви могли на боці сервера обирати правильну мову й формат даних. Це і є «паливо» для багатомовних App.

Невелике порівняння

Для наочності — мініпорівняння:

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

На рівні курсу ми виходитимемо з того, що GiftGenius стає багатомовним (щонайменше EN/UK), щоб показати «дорослу» схему. Водночас багато прийомів стануть у пригоді й для акуратного одномовного App — якщо ви хочете бути готовими до розширення.

5. Де мова справді впливає на модель

Тепер виділимо точки, у яких мова безпосередньо впливає на поведінку ChatGPT.

Мова введення користувача та мова описів tools

Уявімо:

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

Модель повинна:

  1. вирішити, що взагалі потрібно викликати suggest_gifts;
  2. видобути recipient = "colleague", budget = 50, currency = "EUR";
  3. коректно серіалізувати це в JSON‑аргументи.

Якщо описи короткі та ще й іншою мовою, модель із цим упорається, але ймовірність хибно заповнити поля буде вищою. Наприклад, вона може переплутати budget і price_limit або передати текст у поле interests, бо в описі поля було щось розпливчасте на кшталт «Any extra info about the gift».

Для українського тексту користувача й англійських описів модель ще й постійно «перемикається» між мовами.

Варіант із локалізованою схемою:

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 }) => { /* ... */ }
);

Тут усе спрощено: насправді описи краще згенерувати один раз під час старту сервера, а не на кожен виклик. Але ідея зрозуміла: ми можемо віддавати ChatGPT різні описи залежно від locale, щоб моделі було простіше розуміти користувача.

Мова даних і мова запиту

Якщо ваш каталог подарунків лише англійською, а користувач спілкується українською, модель підбиратиме англомовні назви й описи. Іноді це нормально, іноді — ні. Але важливіше інше: як саме ви форматуєте виведення.

  • чи показуєте ви користувачеві оригінальні titles/description із сервера;
  • чи модель переказує їх мовою користувача у своєму тексті;
  • чи ваш tool повертає вже локалізований текст на основі locale.

В Apps SDK structured content (структуровані дані, які ви повертаєте з tools) і текстова відповідь можуть існувати окремо. Ви можете повернути структуровані дані (наприклад, JSON із полями товару) та окремий текст для користувача, а модель уже далі вирішить, як це відрендерити або переказати.

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

System‑prompt і follow‑ups

Якщо system‑prompt у вас лише англійською, а користувач — україномовний, модель постійно балансуватиме між двома мовами. Це може бути прийнятно. Але іноді ви хочете жорстко задати тон: наприклад, в українській версії App — менш формальний стиль, а в англійській — формальніший.

Відповідно, у карті локалізації варто позначити:

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

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

Тепер зберімо все, що ми вже обговорили про шари, глибину й мови, в явну карту локалізації для GiftGenius. Зробімо те, що вам потім потрібно буде зробити для свого App: скласти карту локалізації. Ідея проста: таблиця; у стовпцях — шар і тип сутності, у рядках — конкретні елементи.

Приклад карти

Ось спрощена карта для GiftGenius (EN/UK):

Категорія Елемент Приклад значення (EN) Приклад (UK) Косметика чи семантика
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 5 499 ₴ / 59,99 € Семантика (формат/валюта)
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, комерційна й юридична частина, помилки);
  • елемент (конкретна кнопка, конкретний опис поля, конкретний ендпойнт із текстом);
  • приклад EN‑значення;
  • приклад значення другою мовою (якщо вже є або хоча б чернетка);
  • позначка «косметика/семантика/юридично важливо»;
  • власник (хто відповідає за виправлення: фронтенд, MCP‑сервер, продакт, юрист).

Далі пройдіться своїм App і чесно випишіть усе, де є текст або де мова впливає на формат даних.

Для GiftGenius вийшла б приблизно розширена версія таблиці вище. У процесі ви майже гарантовано знайдете кілька «прихованих» місць:

  • текстові константи в коді MCP‑серверів (наприклад, повідомлення про помилки);
  • значення за замовчуванням у structuredContent (наприклад, категорії, які ви не виводили в UI);
  • старі підписи у tools, які вже не відповідають їхній фактичній поведінці.

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

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

8. Типові помилки під час планування локалізації

Помилка № 1: вважати, що локалізація = «перекласти кнопки».
Дуже поширений сценарій: команда акуратно виносить усі рядки UI у словники, перекладає їх і радіє. Водночас system‑prompt лишається тільки англійською, описи 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‑тексти, бекенд‑розробники — описи tools, ML‑фахівець — system‑prompt, а юристи надсилають відредаговані Terms. Якщо в карті локалізації не вказати, хто відповідає за який шар, зміни починають конфліктувати, а якісь тексти оновлюються в одному місці й не оновлюються в іншому.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ