1. Dlaczego w ogóle warto brać locale z platformy, a nie pytać użytkownika za każdym razem
Jeśli podejść do lokalizacji „po staremu”, logika bywa taka: pokazać modal „Wybierz język” i zapisać wynik w localStorage. W ChatGPT Apps podejście jest inne: platforma już dostarcza sprytne sygnały o języku i regionie. Trzeba nauczyć się z nich korzystać i nie męczyć użytkownika zbędnymi pytaniami.
ChatGPT w każdym żądaniu do twojej aplikacji dodaje do kontekstu:
- preferowaną lokalizację użytkownika (język + region) — w polu openai/locale / _meta["openai/locale"];
- geolokalizację/region użytkownika — w polu _meta["openai/userLocation"].
Po stronie widżetu (frontend) otrzymujesz locale przez window.openai lub hook SDK; po stronie MCP/backendu — przez _meta w żądaniu MCP.
W efekcie normalny scenariusz wygląda tak: użytkownik pisze „Dobierz prezent dla mamy do 50 euro”. ChatGPT już zna jego locale i userLocation, platforma przekazuje te sygnały twojej aplikacji, a ty:
- pokazujesz UI w zrozumiałym języku,
- ładujesz właściwy język katalogu,
- formatujesz ceny we właściwej walucie i formacie.
Bez dodatkowego dialogu „A tak w ogóle, jaki masz język?”.
2. Sygnał nr 1: openai/locale — język i region użytkownika
Czym jest to pole i jak wygląda
openai/locale — to łańcuch w formacie BCP‑47, który zapewne znasz: "en", "en-US", "ru", "ru-RU", "uk-UA" itd.
Ważne, że platforma:
- może przysłać sam język ("en", "ru"),
- może przysłać język + region ("en-US", "en-GB", "fr-CA").
BCP‑47 — standard, z którym świetnie współpracują zarówno Intl-API w przeglądarce, jak i większość bibliotek i18n. To znaczy, że openai/locale można niemal bezpośrednio przekazywać do Intl.NumberFormat, silnika tłumaczeń oraz twoich tools.
Gdzie locale jest dostępny w widżecie
W customowym UI renderowanym wewnątrz ChatGPT, Apps SDK udostępnia globalny obiekt window.openai, gdzie jest locale.
Typowo wygląda to tak (TypeScript, Next.js 16, nasz widżet 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";
}
W realnej aplikacji prościej zbudować hook, który zadziała zarówno w sandboxie ChatGPT, jak i w Storybooku:
// 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;
}
Teraz w dowolnym komponencie:
import { useOpenAiLocale } from "../hooks/useOpenAiLocale";
export function GiftHeader() {
const locale = useOpenAiLocale();
return (
<h2>
{/* później będzie tu t('titles.gift_search') */}
{locale.startsWith("ru") ? "Wybór prezentu" : "Gift search"}
</h2>
);
}
Na wykładzie 4 przeniesiemy wszystkie ciągi do słowników, ale już teraz powiązaliśmy UI z realnym sygnałem z platformy, a nie z losowym navigator.language. Ten hook jest wyspecjalizowany; w realnym projekcie wygodnie zbudować go na bazie bardziej ogólnego mechanizmu dostępu do globali ChatGPT — wrócimy do tego w osobnym rozdziale poniżej.
Gdzie locale jest dostępny w MCP/back-endzie
Gdy ChatGPT wywołuje MCP‑narzędzie, SDK przekazuje _meta["openai/locale"] w żądaniu JSON‑RPC. Na serwerze TypeScript (nasz GiftGenius MCP) jest to zwykle dostępne w drugim argumencie handlera narzędzia.
Przykład:
// src/mcp/server.ts
import { McpServer } from "@openai/mcp-sdk";
const server = new McpServer();
server.registerTool(
"suggest_gifts",
{
title: "Dobór prezentów",
description: "Proponuje listę prezentów na podstawie preferencji",
inputSchema: {
type: "object",
properties: {
recipient: { type: "string" },
budget: { type: "number" }
},
required: ["recipient", "budget"]
}
},
async ({ input }, extra) => {
const locale = extra?._meta?.["openai/locale"] || "en";
// dalej można ładować właściwy katalog
const gifts = await loadGiftCatalog(locale);
// ...
return {
content: [
{
type: "text",
text: `Found ${gifts.length} gifts for locale ${locale}`
}
],
structuredContent: { gifts }
};
}
);
W ten sposób locale „żyje” przez cały stos: ChatGPT → Apps SDK → twój serwer MCP.
Insight
Każdy mcp-tool na serwerze ma parametr extra, do którego mcp‑serwer odkłada wszystkie dane, które nie mieszczą się w inputSchema. Oto przykład takiego obiektu:
{
sessionId: undefined, // zawsze undefined, użyj `openai/subject` poniżej
_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', // locale komputera użytkownika, może nie pokrywać się z językiem na czacie
'openai/userLocation': { // dość dokładna lokalizacja użytkownika
city: 'London',
region: 'London City',
country: 'GB',
timezone: 'Europe/London',
latitude: '5.45466',
longitude: '-0.52380'
},
timezone_offset_minutes: -240, // przesunięcie strefy czasowej
'openai/subject': 'v1/sEtRuS92UEOPNdwzEUZORfeOKf7XSk2KZoIUGfAsb68BzZ8h5FAOgrH' // to jest 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', // bazowa domena aplikacji
'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'
}
},
}
Być może część nagłówków wypełnił tu ngrok, ale ciekawych danych i tak jest sporo.
3. Sygnał nr 2: _meta["openai/userLocation"] — geografia użytkownika
Struktura i sens
_meta["openai/userLocation"] — to obiekt z informacjami geograficznymi: kraj, region, miasto, strefa czasowa, a nawet współrzędne. Mniej więcej tak:
{
"city": "London",
"region": "England",
"country": "GB",
"timezone": "Europe/London",
"latitude": 51.5074,
"longitude": -0.1278
}
Najważniejsze pola, z których realnie skorzystasz w GiftGenius:
- country — dwuliterowy kod kraju ISO, kluczowy dla asortymentu i waluty;
- timezone — przyda się do formatów dat/godzin i przypomnień.
Insight
Empirycznie sprawdzone – określanie userLocation działa bardzo dobrze. Dane przychodzą przy każdym wywołaniu narzędzia MCP przez parametr extra._meta["openai/userLocation"]. Możesz na nich polegać podczas tworzenia swoich aplikacji.
Jak używać userLocation w narzędziach MCP
Na serwerze MCP userLocation żyje w _meta["openai/userLocation"] obok _meta["openai/locale"].
Rozszerzmy przykład naszego narzędzia:
server.registerTool(
"suggest_gifts",
{ /* schema jak wyżej */ },
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 }
};
}
);
Funkcja loadGiftCatalog(locale, country) może już:
- wybrać właściwy plik JSON: gift_catalog.en-US.json, gift_catalog.ru-RU.json,
- odfiltrować produkty, których nie da się dostarczyć do danego kraju,
- wybrać walutę bazową.
Nieco później, w modułach commerce, będziesz na podstawie country wybierać zasady podatkowe i mapować właściwe SKU, ale z architektonicznego punktu widzenia dalej opierasz się na tym samym sygnale — country.
Jak userLocation uzupełnia locale
Klasyczny przykład:
locale = "en", userLocation.country = "DE".
Logika może być taka:
- UI i podpowiedzi — po angielsku (szanuj locale);
- format waluty i cen — euro, bo użytkownik jest fizycznie w Niemczech;
- lista prezentów — tylko te, które można dostarczyć do DE.
W GiftGenius można to wyrazić krótką funkcją pomocniczą:
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";
}
I używać jej na back-endzie/front-endzie do formatowania cen:
const currency = deriveCurrency(locale, country);
const formatted = new Intl.NumberFormat(locale, {
style: "currency",
currency
}).format(price);
Na back-endzie nauczyliśmy się już używać locale i country do wyboru katalogu i waluty. Dalej ważne jest, by te same sygnały trafiły do UI w widżecie, aby użytkownik widział teksty i ceny w oczekiwanym formacie.
4. Jak pobierać locale i userLocation w widżecie GiftGenius
Już zobaczyliśmy, jak locale i userLocation działają po stronie MCP i wpływają na katalogi oraz walutę. Teraz omówmy, jak poprawnie pobrać locale w widżecie GiftGenius i użyć go bezpośrednio w React‑UI.
Ważne: w widżecie mamy bezpośredni dostęp tylko do locale (przez window.openai i hooki SDK). userLocation żyje w _meta i jest używany po stronie MCP/back‑endu — z nim pracowaliśmy wyżej.
W Apps SDK, poza „surowym” window.openai, są też narzędzia w postaci hooków React. Dokumentacja opisuje hooki w rodzaju useOpenAiGlobal("locale"), które wyciągają wartości globalnego kontekstu ChatGPT do komponentów React.
Zasymulujmy taki hook sami, żeby zrozumieć, co dzieje się pod spodem.
Podstawowy hook useOpenAiGlobal
Wcześniej zrobiliśmy wyspecjalizowany useOpenAiLocale. W praktyce wygodniej mieć jeden uniwersalny hook do dostępu do globali ChatGPT — na jego bazie łatwo zbudować i useOpenAiLocale, i inne wrappery. Załóżmy taki hook:
// src/app/hooks/useOpenAiGlobal.ts
import { useEffect, useState } from "react";
type OpenAiGlobals = {
locale?: string;
// tu później można dodać theme, userAgent itp.
};
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;
}
Teraz useOpenAiGlobal("locale", "en") daje nam aktualną wartość locale z domyślną wartością "en".
Zastosowanie w widżecie GiftGenius
Zróbmy mały komponent, który wyświetla zlokalizowane powitanie i bieżące locale do debugowania:
// 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")
? "Cześć! Pomogę dobrać prezent."
: "Hi! I’ll help you find a great gift.";
return (
<div>
<p>{greeting}</p>
<small style={{ opacity: 0.6 }}>Debug locale: {locale}</small>
</div>
);
}
Na razie bez słowników i bibliotek i18n — to będzie później. Teraz istotne jest, że umiemy już uczciwie pobrać język z ChatGPT, a nie z przypadkowych założeń.
5. Kiedy trzeba zapytać użytkownika o język wprost
Skoro openai/locale i userLocation są tak dobre, czy można już nigdy nie pytać użytkownika, w jakim języku chce pracować? Niestety, czasem trzeba.
Kiedy sygnałów brakuje
Jest kilka typowych sytuacji:
- Konto ChatGPT jest anglojęzyczne (locale = "en"), ale użytkownik pisze po rosyjsku. Model odpowiada po rosyjsku, ale UI pokazujesz po angielsku.
- Użytkownik jest w Niemczech (userLocation.country = "DE"), locale = "en", a ty masz gotowy interfejs po niemiecku i angielsku.
- Aplikacja jest krytyczna dla języka komunikacji: psychoterapia, porady prawne, edukacja. Tam precyzja zrozumienia jest ważniejsza niż wygoda autodetekcji.
W takich przypadkach warto zadać krótkie i uprzejme pytanie raz na początku scenariusza, a potem zapamiętać wybór.
Jak zadać pytanie o język nienachalnie
Zwykle formułuje się to maksymalnie prosto i wizualnie, na przykład:
- „W jakim języku jest ci wygodniej: English czy Rosyjski?”
- „Wykryliśmy twój język jako English. Chcesz przełączyć na inny?”
W ChatGPT App można to zrobić na dwa sposoby:
- Przez UI widżetu: narysować mały przełącznik języków u góry.
- Przez wiadomość typu follow‑up w czacie w imieniu aplikacji: wysłać tekstowy follow‑up z pytaniem, a następnie obsłużyć odpowiedź.
Kod: prosty wybór języka w GiftGenius
Zróbmy komponent‑przełącznik, który:
- bierze język startowy z locale,
- pozwala użytkownikowi wybrać ru lub en,
- przechowuje wybór w stanie widżetu (na razie w 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" ? "Język:" : "Language:"}
</span>
<button
type="button"
onClick={() => handleChange("en")}
style={{ fontWeight: locale === "en" ? "bold" : "normal" }}
>
EN
</button>
<button
type="button"
onClick={() => handleChange("ru")}
style={{ fontWeight: locale === "ru" ? "bold" : "normal", marginLeft: 4 }}
>
RU
</button>
</div>
);
}
A w głównym widżecie GiftGenius możesz już wybierać teksty/słownik na podstawie selectedLocale, a nie „surowych” danych z ChatGPT.
W przyszłych wykładach zamienisz lokalny stan na trwalsze przechowywanie (np. przekażesz wybrany język do MCP / Gateway przez _meta["openai/subject"]), ale wzorzec pozostanie ten sam.
6. Jak przekazywać locale i userLocation do back-endu i je przechowywać
Sygnały od ChatGPT przychodzą „z góry”, ale na tym życie się nie kończy. Trzeba te dane donieść do twoich narzędzi i serwisów, nie zgubić po drodze i nie zmuszać modelu do odgadywania języka od nowa.
Jawne pole locale w argumentach tools
Najpewniejsza metoda – dodać locale (i opcjonalnie country) jako osobne pola w inputSchema narzędzia. Wtedy model dostaje jasny sygnał: „trzeba wypełnić to pole”.
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) => {
// Jeśli model nie wypełnił locale/country, zabezpieczymy się przez _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";
// ...
}
);
To zmniejsza „magię” wewnątrz serwera: widzi on wyraźnie argumenty, których model zamierza użyć.
Przechowywanie locale na poziomie sesji/użytkownika
W architekturze z MCP Gateway (przyszłe moduły) przyjęło się przechowywać „stan klienta”: locale, currency, preferencje. Teraz ważne jest zrozumieć ideę: raz odczytaliśmy sygnały od ChatGPT — dalej używamy ich jako części stanu sesji, a nie liczymy na nowo za każdym razem.
Umowny pseudokod:
// gateway.ts
const sessionState = new Map<string, { locale: string; country?: string }>();
function onMcpRequest(request: any) {
const subject = request._meta?.["openai/subject"]; // anonimowy identyfikator użytkownika
const locale = request._meta?.["openai/locale"] || "en";
const country = request._meta?.["openai/userLocation"]?.country;
if (subject) {
sessionState.set(subject, { locale, country });
}
// dalej przekazujemy locale/country do konkretnego serwera MCP
}
W ramach tego wykładu nie musisz implementować Gateway, wystarczy rozumieć, że locale i userLocation są kandydatami do takiego „stanu sesji”.
Insight
Dane eksperymentalne: request._meta?.["openai/locale"] pokazuje aktualnie ustawione locale użytkownika. Język komunikacji możesz przekazać jako parametr tool przez inputSchema.
Ustawiłem u siebie w komputerze locale EN, a rozmawiałem z ChatGPT po niemiecku (DE). W rezultacie:
- request._meta?.["openai/locale"] było równe EN
- locale otrzymane jako parametr tool przez inputSchema było równe DE
7. Locale vs automatyczne wykrywanie języka po tekście
Czasem kusi pomysł: „Po prostu będziemy wykrywać język z tekstu użytkownika, przecież LLM wszystko potrafi”. W praktyce to prawie zawsze gorsze niż poleganie na openai/locale.
Powody są dość przyziemne:
- użytkownik może pisać mieszanką języków;
- drobne różnice (uk-UA vs ru-RU) słabo wykrywają się po jednej wiadomości;
- ChatGPT już wykonał tę pracę za ciebie i przysłał locale.
Automatyczne wykrywanie ma sens jako fallback, jeśli openai/locale przychodzi w jakiś nietypowy sposób albo brakuje go (co teraz zdarza się rzadko), ale nie powinno być podstawą logiki. Prosta zasada:
- najpierw patrzymy na openai/locale jako na „prawdę”;
- potem uwzględniamy userLocation (waluta, asortyment);
- i tylko w zupełnie spornych przypadkach dodatkowo zerkamy na język ostatniej wiadomości.
8. Różne kombinacje locale i userLocation: tabela scenariuszy
Dla utrwalenia zobaczmy, jak GiftGenius powinien zachowywać się w różnych scenariuszach.
| Scenariusz | locale | userLocation.country | Język UI | Waluta | Katalog |
|---|---|---|---|---|---|
| 1 | |
|
EN | |
US‑produkty |
| 2 | |
|
UKR/RU | |
UA‑produkty |
| 3 | |
|
EN | |
DE‑produkty |
| 4 | |
|
RU | |
DE‑produkty |
| 5 | |
(brak danych) | EN | |
Global default |
To spojrzenie przyda ci się później, gdy będziemy omawiać commerce, ale już teraz widać, jak łatwo zmieniać zachowanie, po prostu podsuwając różne locale i country.
9. Mały diagram przepływu sygnałów lokali
Aby ułożyć sobie temat, spójrzmy na uproszczony schemat:
flowchart TD U[Użytkownik<br/>pisze wiadomość] --> C[ChatGPT] C -->|określa| L[openai/locale<br/>+ userLocation] L -->|przekazuje| W["Widżet (Next.js)"] L -->|przekazuje przez _meta| S[MCP Server] W -->|locale| UI[GiftGenius UI<br/>teksty + format liczb] S -->|locale + country| DATA[Katalogi, ceny, filtry] style L fill:#e0f7ff,stroke:#00a style W fill:#f7fff0,stroke:#4b4 style S fill:#fdf0ff,stroke:#b4
Ważne: na tym schemacie nigdzie nie ma modala „Wybierz język”. Jest potrzebny tylko jako dodatkowa warstwa, gdy sygnały są sprzeczne z oczekiwaniami użytkownika.
10. Praktyka: co możesz zrobić od razu w swojej aplikacji
Aby wykład nie został teorią, krótki praktyczny checklist dla GiftGenius:
- W widżecie: dodać hook useOpenAiGlobal("locale") lub jego odpowiednik i przynajmniej w jednym miejscu zrobić rozwidlenie RU/EN dla tekstu.
- W serwerze MCP: w jednym z istniejących narzędzi (suggest_gifts) odczytać _meta["openai/locale"] i _meta["openai/userLocation"], wypisać je do logu i użyć do wyboru katalogu.
- Napisać prostą funkcję deriveCurrency(locale, country) i użyć jej w jednym miejscu przy formatowaniu ceny.
Nie trzeba od razu budować pełnego silnika i18n i 15 języków — naszym celem teraz jest nauczyć się rzetelnie korzystać z sygnałów platformy.
11. Typowe błędy przy pracy z locale i userLocation
Błąd nr 1: całkowicie ignorować openai/locale i polegać wyłącznie na navigator.language.
Tak robią ci, którzy przywykli do zwykłych aplikacji webowych. W ChatGPT użytkownik może w ogóle niczego nie otwierać w przeglądarce, a navigator.language po twojej stronie to język serwera tunelującego lub Vercela, a nie użytkownika. W efekcie UI jest „tajemniczo” po angielsku, choć ChatGPT konsekwentnie przysyła ci ru-RU.
Błąd nr 2: za każdym razem pytać użytkownika „w jakim języku wygodniej?”.
Jeśli w każdym czacie pierwsza kwestia widżetu to ankieta językowa, użytkownicy czują się jak na lotnisku, gdzie pięć razy z rzędu pytają ich, czy nie zapomnieli bagażu. Platforma już zna język i region — wystarczy respektować openai/locale i pytać tylko przy jawnym konflikcie (np. zapytanie po rosyjsku przy locale = "en").
Błąd nr 3: przechowywać wybrany język tylko w UI i nie przekazywać go do narzędzi MCP.
Widżet może być po polsku, a serwer nadal zwracać anglojęzyczny katalog, bo nie wie o zmianie języka. Zawsze myśl o ścieżce end‑to‑end: jeśli masz w UI przełącznik, wynik trzeba dostarczyć do back-endu — albo w argumentach narzędzia, albo przez sesję Gateway.
Błąd nr 4: próbować „zgadywać” język wyłącznie z tekstu wiadomości, ignorując openai/locale.
Autodetekcja po tekście może działać nieźle… dopóki użytkownik pisze czystym angielskim. Gdy tylko pojawią się mieszanki albo podobne frazy, rezultat zacznie pływać. openai/locale — to już gotowa, dość wiarygodna ocena, dostarczona przez platformę. Warto traktować ją jako główne źródło prawdy, a detekcję z tekstu — tylko jako sygnał dodatkowy.
Błąd nr 5: mieszać logikę biznesową i lokalizację w stylu if (locale === 'ru') { ... } w całym kodzie.
Na tym wykładzie jeszcze trochę tak robimy dla prostoty, ale warto z góry planować, że łańcuchy, formaty i katalogi powinny być oddzielone od logiki biznesowej. W przeciwnym razie za kilka miesięcy znajdziesz się w kodzie, gdzie każda funkcja zaczyna się od if (locale.startsWith("ru")), a dodanie kolejnego języka będzie bolesne. W wykładzie 44 będziemy leczyć właśnie ten problem, pamiętając, że źródło locale już mamy i umiemy z niego korzystać.
GO TO FULL VERSION