JavaRush /Курси /ChatGPT Apps /Звідки взяти locale: openai/locale та _meta["openai/userL...

Звідки взяти locale: openai/locale та _meta["openai/userLocation"]

ChatGPT Apps
Рівень 9 , Лекція 1
Відкрита

1. Чому взагалі важливо знати locale з платформи, а не питати користувача щоразу

Якщо підходити до локалізації «по‑старому», логіка зазвичай така: показати модальне вікно «Виберіть мову» й зберегти результат у localStorage. У ChatGPT Apps підхід інший: платформа вже має контекст і щедро ділиться сигналами про мову та регіон. Ваше завдання — навчитися ними користуватися й не турбувати користувача зайвими запитаннями.

ChatGPT у кожному запиті до вашого застосунку додає в контекст:

  • бажану локаль користувача (мова + регіон) — у полі openai/locale / _meta["openai/locale"];
  • геолокацію / регіон користувача — у полі _meta["openai/userLocation"].

На боці віджета (клієнтська частина) ви отримуєте locale через window.openai або через хук SDK. А на боці MCP / серверної частини — через _meta у MCP‑запиті.

У результаті «правильний» сценарій виглядає так: користувач пише «Підбери подарунок мамі в межах 50 євро». ChatGPT уже знає його locale і userLocation, платформа передає ці сигнали вашому App, і ви:

  • показуєте інтерфейс зрозумілою мовою,
  • завантажуєте потрібну мову каталогу,
  • форматуєте ціни у відповідній валюті та форматі.

І все це — без окремої розмови на кшталт «До речі, а якою мовою ви користуєтеся?».

2. Сигнал № 1: openai/locale — мова й регіон користувача

Що це за поле і як воно виглядає

openai/locale — це рядок у форматі BCP‑47, який ви напевно вже бачили: "en", "en-US", "uk", "de-DE", "uk-UA" тощо.

Важливо, що платформа:

  • може надіслати лише мову ("en", "ru"),
  • а може надіслати мову + регіон ("en-US", "en-GB", "fr-CA").

BCP‑47 — стандарт, з яким добре працюють і Intl-API в браузері, і більшість i18n‑бібліотек. Тобто openai/locale можна майже безпосередньо передавати в Intl.NumberFormat, у рушій перекладів і всередину ваших tools.

Де locale доступний у віджеті

У власному UI, який рендериться всередині ChatGPT, Apps SDK надає глобальний обʼєкт window.openai, у якому є locale.

Зазвичай це виглядає так (TypeScript, Next.js 16, наш віджет GiftGenius):

// src/app/widgets/gift-widget.tsx
declare global {
  interface Window {
    openai?: { locale?: string };
  }
}

function getOpenAiLocale(): string {
  if (typeof window === "undefined") return "en";
  return window.openai?.locale || "en";
}

У реальному застосунку зручніше зробити хук, який працюватиме і в «пісочниці» ChatGPT, і в Storybook:

// src/app/hooks/useOpenAiLocale.ts
import { useEffect, useState } from "react";

export function useOpenAiLocale(defaultLocale: string = "en") {
  const [locale, setLocale] = useState(defaultLocale);

  useEffect(() => {
    if (typeof window === "undefined") return;
    const next = window.openai?.locale || defaultLocale;
    setLocale(next);
  }, [defaultLocale]);

  return locale;
}

Тепер у будь‑якому компоненті:

import { useOpenAiLocale } from "../hooks/useOpenAiLocale";

export function GiftHeader() {
  const locale = useOpenAiLocale();

  return (
    <h2>
      {/* пізніше тут буде t('titles.gift_search') */}
      {locale.startsWith("ru") ? "Підбір подарунка" : "Gift search"}
    </h2>
  );
}

У лекції 4 ми акуратно винесемо всі рядки у словники. Але вже зараз ви привʼязали UI до реального сигналу від платформи, а не до випадкового navigator.language. Цей хук доволі вузький. У реальному проєкті зручніше будувати його поверх загальнішого механізму доступу до глобалів ChatGPT — до цього ми повернемося в окремому розділі нижче.

Де locale доступний у MCP/серверній частині

Коли ChatGPT викликає MCP‑інструмент, SDK передає _meta["openai/locale"] у JSON‑RPC‑запиті. На TypeScript‑сервері (наш GiftGenius MCP) це зазвичай доступно в другому аргументі обробника інструмента.

Приклад:

// src/mcp/server.ts
import { McpServer } from "@openai/mcp-sdk";

const server = new McpServer();

server.registerTool(
  "suggest_gifts",
  {
    title: "Підбір подарунків",
    description: "Пропонує список подарунків за вподобаннями",
    inputSchema: {
      type: "object",
      properties: {
        recipient: { type: "string" },
        budget: { type: "number" }
      },
      required: ["recipient", "budget"]
    }
  },
  async ({ input }, extra) => {
    const locale = extra?._meta?.["openai/locale"] || "en";
    // далі можна завантажувати потрібний каталог
    const gifts = await loadGiftCatalog(locale);
    // ...
    return {
      content: [
        {
          type: "text",
          text: `Found ${gifts.length} gifts for locale ${locale}`
        }
      ],
      structuredContent: { gifts }
    };
  }
);

Отже, locale проходить крізь увесь стек: ChatGPT → Apps SDK → ваш MCP‑сервер.

Інсайт

У кожного MCP‑інструмента на сервері є параметр extra, куди MCP‑сервер збирає всі дані, які не помістилися в inputSchema. Ось приклад такого обʼєкта:

{
  sessionId: undefined,			// завжди undefined; використовуйте `openai/subject` нижче
  _meta: {
    'openai/userAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
    'openai/locale': 'en-US',		// локаль компʼютера користувача; може не збігатися з мовою в чаті
    'openai/userLocation': {		// доволі точне місцезнаходження користувача
      city: 'London',
      region: 'London City',
      country: 'GB',
      timezone: 'Europe/London',
      latitude: '5.45466',
      longitude: '-0.52380'
    },
    timezone_offset_minutes: -240,	// зміщення часового поясу
    'openai/subject': 'v1/sEtRuS92UEOPNdwzEUZORfeOKf7XSk2KZoIUGfAsb68BzZ8h5FAOgrH'	// це sessionId
  },
  authInfo: undefined,
  requestId: 1,
  requestInfo: {
    headers: {
      accept: 'application/json, text/event-stream',
      'accept-encoding': 'gzip, deflate, br, zstd',
      'access-control-allow-headers': '*',
      'access-control-allow-methods': 'GET,POST,PUT,DELETE,OPTIONS',
      'access-control-allow-origin': '*',
      'content-length': '542',
      'content-type': 'application/json',
      host: 'test.ngrok.app',					// рідний домен застосунку
      'mcp-protocol-version': '2025-11-25',	
      traceparent: '00-69399d3a000000004fb8cc13dc3a2203-8748a8698107eb34-00',
      tracestate: 'dd=s:-1;p:01514e334c1ccef5;t.dm:-3',
      'user-agent': 'openai-mcp/1.0.0',
      'x-datadog-parent-id': '6089244476286233754',
      'x-datadog-sampling-priority': '-1',
      'x-datadog-tags': '_dd.p.tid=69399c3a00000000,_dd.p.dm=-3',
      'x-datadog-trace-id': '5744565710382309891',
      'x-forwarded-for': '199.210.139.232',
      'x-forwarded-host': 'test.ngrok.app',
      'x-forwarded-port': '3001',
      'x-forwarded-proto': 'https'
    }
  },
}

Можливо, частину заголовків тут додав ngrok, але корисної інформації все одно чимало.

3. Сигнал № 2: _meta["openai/userLocation"] — географія користувача

Структура та зміст

_meta["openai/userLocation"] — це обʼєкт із геоінформацією: країна, регіон, місто, часовий пояс і навіть координати. Приблизно так:

{
  "city": "London",
  "region": "England",
  "country": "GB",
  "timezone": "Europe/London",
  "latitude": 51.5074,
  "longitude": -0.1278
}

Головні поля, якими ви реально користуватиметеся в GiftGenius:

  • country — дволітерний ISO‑код країни; критично важливий для асортименту й валюти;
  • timezone — знадобиться для форматів дати й часу та нагадувань.

Інсайт

Перевірено на практиці: визначення userLocation працює дуже якісно. Дані приходять у кожен виклик MCP‑інструмента через параметр extra._meta["openai/userLocation"]. На них можна впевнено спиратися під час розробки застосунків.

Як використовувати userLocation у MCP‑інструментах

На MCP‑сервері userLocation живе в _meta["openai/userLocation"] поруч із _meta["openai/locale"].

Розширимо приклад нашого інструмента:

server.registerTool(
  "suggest_gifts",
  { /* схема як вище */ },
  async ({ input }, extra) => {
    const meta = extra?._meta ?? {};
    const locale = (meta["openai/locale"] as string) || "en";
    const userLocation = meta["openai/userLocation"] as
      | { country?: string; city?: string }
      | undefined;

    const country = userLocation?.country || "US";

    const gifts = await loadGiftCatalog(locale, country);

    return {
      content: [
        {
          type: "text",
          text: `Found ${gifts.length} gifts for locale=${locale}, country=${country}`
        }
      ],
      structuredContent: { gifts }
    };
  }
);

Функція loadGiftCatalog(locale, country) уже може:

  • вибрати потрібний JSON‑файл: gift_catalog.en-US.json, gift_catalog.uk-UA.json,
  • відфільтрувати товари, які не можна доставити в цю країну,
  • обрати базову валюту.

Трохи пізніше в commerce‑модулях ви на основі country обиратимете податкові правила й мапитимете на правильні SKU. Але з архітектурної точки зору ви все одно спираєтеся на той самий сигнал — country.

Як userLocation доповнює locale

Класичний приклад:

locale = "en", userLocation.country = "DE".

Логіка може бути такою:

  • UI і підказки — англійською (поважаємо locale);
  • формат валюти та ціни — євро, бо користувач фізично в Німеччині;
  • список подарунків — лише ті, що доставляються в DE.

У GiftGenius це можна виразити невеликою допоміжною функцією:

export function deriveCurrency(locale: string, country?: string): string {
  if (country === "DE") return "EUR";
  if (country === "JP") return "JPY";   
  if (locale === "zh_CN") return "CNY"; 
  return "USD";
}

І використати на серверній частині або у віджеті для форматування цін:

const currency = deriveCurrency(locale, country);
const formatted = new Intl.NumberFormat(locale, {
  style: "currency",
  currency
}).format(price);

На серверній частині ми вже навчилися використовувати locale і country для вибору каталогу та валюти. Далі важливо акуратно донести ті самі сигнали до UI у віджеті, щоб користувач бачив тексти та ціни в очікуваному форматі.

4. Як отримувати locale і userLocation у віджеті GiftGenius

Ми вже подивилися, як locale і userLocation працюють на боці MCP і як вони впливають на каталоги та валюту. Тепер розберімося, як коректно передати locale у віджет GiftGenius і використовувати його прямо в React‑UI.

Важливо: у віджеті є прямий доступ лише до locale (через window.openai і хуки SDK). userLocation живе в _meta і використовується на боці MCP / серверної частини — з ним ми вже працювали вище.

В Apps SDK, окрім «сирого» window.openai, є утиліти у вигляді React‑хуків. У документації описують хуки на кшталт useOpenAiGlobal("locale"), які дістають значення глобального контексту ChatGPT у React‑компоненти.

Смоделюймо такий хук самі, щоб було зрозуміло, що відбувається «під капотом».

Базовий хук useOpenAiGlobal

Раніше ми зробили вузькоспеціалізований useOpenAiLocale. На практиці зручніше мати один універсальний хук для доступу до глобалів ChatGPT. На його основі легко зібрати і useOpenAiLocale, і інші обгортки. Уявімо такий хук:

// src/app/hooks/useOpenAiGlobal.ts
import { useEffect, useState } from "react";

type OpenAiGlobals = {
  locale?: string;
  // сюди пізніше можна додати theme, userAgent тощо
};

export function useOpenAiGlobal<K extends keyof OpenAiGlobals>(
  key: K,
  fallback?: NonNullable<OpenAiGlobals[K]>
): NonNullable<OpenAiGlobals[K]> {
  const [value, setValue] = useState<NonNullable<OpenAiGlobals[K]>>(
    (fallback ?? "") as NonNullable<OpenAiGlobals[K]>
  );

  useEffect(() => {
    if (typeof window === "undefined") return;
    const globals = (window.openai || {}) as OpenAiGlobals;
    const next = globals[key] ?? fallback;
    if (next !== undefined) {
      setValue(next as NonNullable<OpenAiGlobals[K]>);
    }
  }, [key, fallback]);

  return value;
}

Тепер useOpenAiGlobal("locale", "en") дає вам актуальне значення locale із типовим значенням "en".

Застосування у віджеті GiftGenius

Зробімо невеликий компонент, який показує локалізоване привітання і поточну локаль для налагодження:

// src/app/widgets/GiftWelcome.tsx
"use client";

import React from "react";
import { useOpenAiGlobal } from "../hooks/useOpenAiGlobal";

export function GiftWelcome() {
  const locale = useOpenAiGlobal("locale", "en");

  const greeting =
    locale.startsWith("ru") || locale.startsWith("uk")
      ? "Привіт! Я допоможу підібрати подарунок."
      : "Hi! I’ll help you find a great gift.";

  return (
    <div>
      <p>{greeting}</p>
      <small style={{ opacity: 0.6 }}>Debug locale: {locale}</small>
    </div>
  );
}

Поки що — жодних словників і i18n‑бібліотек: це буде пізніше. Зараз важливо інше: ви вже вмієте коректно брати мову з ChatGPT, а не покладатися на випадкові припущення.

5. Коли потрібно питати користувача про мову напряму

Якщо openai/locale і userLocation такі корисні, чи означає це, що користувача можна взагалі ніколи не питати, якою мовою він хоче працювати? На жаль, іноді доводиться.

Коли сигналів недостатньо

Є кілька типових ситуацій:

  • Обліковий запис ChatGPT англомовний (locale = "en"), але користувач пише іншою мовою. Модель відповідає цією мовою, а UI ви показуєте англійською.
  • Користувач у Німеччині (userLocation.country = "DE"), locale = "en", а ви готові запропонувати і німецький, і англійський інтерфейс.
  • Застосунок критично залежить від мови комунікації: психотерапія, юридичні консультації, навчання. Там точність розуміння важливіша за комфорт автоматичного визначення.

У таких випадках доречно поставити коротке й ввічливе запитання один раз на початку сценарію, а потім запамʼятати вибір.

Як поставити запитання про мову ненавʼязливо

Зазвичай формулювання роблять максимально простим і наочним, наприклад:

  • «Якою мовою вам зручніше: English чи болгарською?»
  • «Ми визначили вашу мову як English. Хочете перемкнутися на іншу?»

У ChatGPT App це можна зробити двома способами:

  • Через UI віджета: додати невеликий перемикач мов угорі.
  • Через follow‑up повідомлення в чат від імені App: надіслати follow‑up із запитанням, а потім обробити відповідь.

Код: простий вибір мови в GiftGenius

Зробімо компонент‑перемикач, який:

  • бере стартову мову з locale,
  • дає користувачу вибрати ru або en,
  • зберігає вибір у стані віджета (поки що — просто в React‑state).
// src/app/widgets/LanguageSwitcher.tsx
"use client";

import React, { useState, useEffect } from "react";
import { useOpenAiGlobal } from "../hooks/useOpenAiGlobal";

type SupportedLocale = "en" | "ru";

export function LanguageSwitcher(props: {
  onChange?: (locale: SupportedLocale) => void;
}) {
  const initialLocale = useOpenAiGlobal("locale", "en");
  const [locale, setLocale] = useState<SupportedLocale>("en");

  useEffect(() => {
    const normalized: SupportedLocale = initialLocale.startsWith("ru")
      ? "ru"
      : "en";
    setLocale(normalized);
    props.onChange?.(normalized);
  }, [initialLocale, props]);

  const handleChange = (next: SupportedLocale) => {
    setLocale(next);
    props.onChange?.(next);
  };

  return (
    <div style={{ marginBottom: 8 }}>
      <span style={{ marginRight: 8 }}>
        {locale === "ru" ? "Мова:" : "Language:"}
      </span>
      <button
        type="button"
        onClick={() => handleChange("en")}
        style={{ fontWeight: locale === "en" ? "bold" : "normal" }}
      >
        EN
      </button>
      <button
        type="button"
        onClick={() => handleChange("uk")}
        style={{ fontWeight: locale === "uk" ? "bold" : "normal", marginLeft: 4 }}
      >
        UK
      </button>
    </div>
  );
}

А в основному віджеті GiftGenius можна вже підбирати тексти/словник за selectedLocale, а не за «сирими» даними від ChatGPT.

У майбутніх лекціях ви заміните локальний state на надійніше зберігання (наприклад, прокинете обрану мову в MCP / Gateway через _meta["openai/subject"]), але сам патерн залишиться тим самим.

6. Як передавати locale і userLocation у backend і зберігати їх

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

Явне поле locale в аргументах tools

Найнадійніший прийом — додати locale (і, за бажання, country) як окремі поля в inputSchema інструмента. Тоді модель отримує чіткий сигнал: «потрібно заповнити ось це поле».

server.registerTool(
  "suggest_gifts",
  {
    title: "Gift suggestions",
    description: "Suggest gifts based on recipient and budget",
    inputSchema: {
      type: "object",
      properties: {
        recipient: { type: "string" },
        budget: { type: "number" },
        locale: {
          type: "string",
          description: "Current user UI locale, BCP-47 (e.g. en-US, fr-FR)"
        },
        country: {
          type: "string",
          description: "ISO country code (e.g. US, DE)"
        }
      },
      required: ["recipient", "budget"]
    }
  },
  async ({ input }, extra) => {
    // Якщо модель не заповнила locale/country, підстрахуємося з _meta:
    const meta = extra?._meta ?? {};
    const locale = input.locale || (meta["openai/locale"] as string) || "en";
    const country =
      input.country ||
      (meta["openai/userLocation"] as any)?.country ||
      "US";

    // ...
  }
);

Так на сервері буде менше «магії»: ви чітко бачите аргументи, які модель збирається використовувати.

Зберігання locale на рівні сесії / користувача

В архітектурі з MCP Gateway (майбутні модулі) зазвичай зберігають «стан клієнта»: locale, currency, вподобання. Зараз важливо лише зрозуміти ідею: один раз прочитали сигнали від ChatGPT — далі використовуємо їх як частину сесійного стану, а не обчислюємо / визначаємо щоразу.

Умовний псевдокод:

// gateway.ts
const sessionState = new Map<string, { locale: string; country?: string }>();

function onMcpRequest(request: any) {
  const subject = request._meta?.["openai/subject"]; // анонімний user id
  const locale = request._meta?.["openai/locale"] || "en";
  const country = request._meta?.["openai/userLocation"]?.country;

  if (subject) {
    sessionState.set(subject, { locale, country });
  }

  // далі передаємо locale/country у конкретний MCP-сервер
}

У межах цієї лекції вам не потрібно реалізовувати Gateway — достатньо розуміти, що locale і userLocation цілком можуть стати частиною такого «сесійного стану».

Інсайт

Експериментальні дані: request._meta?.["openai/locale"] показує поточну встановлену локаль користувача. А мову спілкування можна отримати як параметр tool через inputSchema.

Я встановив у себе на компʼютері локаль EN, а спілкувався з ChatGPT німецькою (DE). У результаті:

  • request._meta?.["openai/locale"] дорівнювало EN
  • locale, отриманий як параметр tool через inputSchema, був рівний DE

7. Locale vs автовизначення мови за текстом

Іноді розробників тягне до ідеї: «Давайте просто визначати мову за текстом користувача — LLM же все вміє». На практиці це майже завжди гірше, ніж спиратися на openai/locale.

Причини доволі прості:

  • користувач може писати сумішшю мов;
  • тонкі відмінності (uk-UA vs ru-RU) складно коректно визначити за одним повідомленням;
  • ChatGPT уже виконав цю роботу за вас і надіслав locale.

Автовизначення корисне як резервний варіант (fallback), якщо openai/locale приходить у дивному вигляді або взагалі відсутній (нині це трапляється рідко). Але будувати на ньому основну логіку не варто. Грубе правило таке:

  • спочатку дивимося на openai/locale як на «джерело правди»;
  • потім враховуємо userLocation (валюта, асортимент);
  • і лише в зовсім спірних випадках додатково заглядаємо в мову останнього повідомлення.

8. Різні комбінації locale та userLocation: таблиця сценаріїв

Для закріплення подивімося, як GiftGenius має поводитися в різних сценаріях.

Сценарій locale userLocation.country Мова UI Валюта Каталог
1
en-US
US
EN
USD
Товари для США
2
uk-UA
UA
UK/RU
UAH
Товари для України
3
en
DE
EN
EUR
Товари для Німеччини
4
uk-UA
DE
UK
EUR
Товари для Німеччини
5
en
(немає даних) EN
USD
Глобальний за замовчуванням

Ця «матриця» стане у пригоді пізніше, коли ми обговорюватимемо commerce. Але вже зараз видно, як легко змінювати поведінку, просто підставляючи різні locale і country.

9. Невелика діаграма потоку сигналів локалі

Щоб зібратися з думками, подивімося на спрощену схему:

flowchart TD
  U[Користувач<br/>пише повідомлення] --> C[ChatGPT]
  C -->|визначає| L[openai/locale<br/>+ userLocation]
  L -->|передає| W["Widget (Next.js)"]
  L -->|передає через _meta| S[MCP Server]

  W -->|locale| UI[GiftGenius UI<br/>тексти + формат чисел]
  S -->|locale + country| DATA[Каталоги, ціни, фільтри]

  style L fill:#e0f7ff,stroke:#00a
  style W fill:#f7fff0,stroke:#4b4
  style S fill:#fdf0ff,stroke:#b4

Зверніть увагу: у цій схемі ніде не зʼявляється модальне вікно «Виберіть мову». Воно потрібне лише як додатковий шар — коли сигнали не збігаються з очікуваннями користувача.

10. Практика: що можна зробити просто зараз у вашому App

Щоб лекція не залишилася лише теорією, ось короткий практичний чекліст для GiftGenius:

  • У віджеті: додати хук useOpenAiGlobal("locale") або його аналог і щонайменше в одному місці зробити розвилку UK/EN для тексту.
  • У MCP‑сервері: в одному з наявних інструментів (suggest_gifts) дістати _meta["openai/locale"] і _meta["openai/userLocation"], вивести їх у лог і використати для вибору каталогу.
  • Написати просту функцію deriveCurrency(locale, country) і використати її в одному місці під час форматування ціни.

Не потрібно одразу будувати повноцінний i18n‑рушій і 15 мов — зараз ваше завдання простіше: навчитися коректно користуватися сигналами платформи.

11. Типові помилки під час роботи з locale і userLocation

Помилка № 1: повністю ігнорувати openai/locale і покладатися лише на navigator.language.
Так часто роблять ті, хто звик до звичайних веб‑застосунків. У ChatGPT користувач узагалі може нічого не відкривати в браузері, а navigator.language на вашому боці — це мова середовища виконання (наприклад, сервера або хостингу), а не користувача. У підсумку інтерфейс завжди «загадково» англійською, хоча ChatGPT стабільно надсилає вам uk-UA.

Помилка № 2: щоразу питати користувача «якою мовою зручніше?»
Якщо у вас у кожному чаті перша репліка віджета — опитування про мову, користувачі швидко втомлюються. Платформа вже знає мову й регіон — достатньо поважати openai/locale і питати лише за очевидного конфлікту (наприклад, запит українською чи болгарською при locale = "en").

Помилка № 3: зберігати обрану мову лише в UI і не передавати її в MCP‑інструменти.
Віджет може бути українською, а сервер продовжуватиме віддавати англомовний каталог, бо він не знає про зміну мови. Завжди думайте про «наскрізний» шлях: якщо в UI є перемикач, його результат потрібно донести до серверної частини — або через аргументи інструмента, або через сесію Gateway.

Помилка № 4: намагатися «вгадати» мову лише за текстом повідомлень, ігноруючи openai/locale.
Автовизначення за текстом може працювати непогано… доки в користувача чиста англійська. Щойно зʼявляться змішані мови або схожі фрази, результат почне «плавати». openai/locale — уже готова, достатньо надійна оцінка, надана платформою. Її варто вважати основним джерелом правди, а визначення за текстом — лише додатковим сигналом.

Помилка № 5: змішувати бізнес‑логіку й локалізацію в стилі if (locale === 'ru') { ... } по всьому коду.
У цій лекції ми ще трохи робимо так заради простоти. Але важливо заздалегідь планувати, що рядки, формати й каталоги мають бути відокремлені від бізнес‑логіки. Інакше за кілька місяців ви опинитеся в коді, де кожна функція починається з if (locale.startsWith("ru")), а додати ще одну мову буде боляче. На лекції 44 ми лікуватимемо саме цю проблему, памʼятаючи, що джерело locale у нас уже є — і користуватися ним ми вміємо.

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