Žemiau pateikta i18n sekcija skirta įklijuoti į AGENTS.md: dešimt trumpų taisyklių, kurios nurodo kodavimo agentui kiekvieną vartotojui matomą eilutę perduoti per vertimo funkciją, raktus pavadinti pagal funkciją, niekada nejungti fragmentų, niekada neimituoti daugiskaitos ternary operatoriumi ir niekada nelieskite sugeneruoto lokalės failo. globalize.now yra dirbtiniu intelektu grįsta lokalizacijos infrastruktūra, todėl matome daug agentų parašyto i18n kodo, ir beveik visas problemas sukelia tos pačios kelios klaidos. Kiekviena taisyklė atitinka vieną iš jų.

Antroje šio įrašo pusėje kalbama apie tai, kur failas nustoja veikti. Dvi dažniausiai naudojamos kodo rašymo aplinkos jo neskaito, ir jokia formuluotė to nepataisys.

Ką turėtų nurodyti AGENTS.md i18n sekcija?

Štai šis blokas. Pakeiskite tris failų kelius ir lint komandą pagal savo projektą, o likusį palikite.

## Internationalization

- Every user-visible string goes through the translation function. That
  includes JSX text, input hint text, `title`, `aria-label`, `alt`, toast and
  error messages, empty states and the document `<title>`.
- The source locale is `en`. The catalog is `locales/en.json`. Add the key in
  the same change that uses it.
- Keys are namespaced by feature: `checkout.summary.total`, not `total3`.
  Search the catalog for an existing key before creating one.
- Never concatenate translated fragments. Use interpolation:
  `t('cart.items', { count })`, not `t('cart.you_have') + count`.
- Plurals use the library's plural forms (`_one` / `_other` keys, or ICU
  `{count, plural, ...}`). Never `count === 1 ? 'item' : 'items'`.
- Dates, numbers and currency go through `Intl.DateTimeFormat` and
  `Intl.NumberFormat` with the active locale. Never a bare
  `toLocaleString()`, never a currency symbol glued to a number.
- Do not hardcode the locale list, language names or text direction in
  components. Read them from `i18n/config.ts`.
- Do not translate brand names, code identifiers, URLs or environment values.
- Do not edit locale files other than `en`. They are generated. If a
  translation looks wrong, fix the source key or the glossary, not the file.
- Before finishing, run `npm run lint`. The `i18next/no-literal-string`
  rule must pass.

Dešimt taisyklių — sąmoningas pasirinkimas. Paties Cursor taisyklių dokumentacija nurodo, kad taisyklės turi būti sutelktos į dažnai naudojamus šablonus ir kad vietoj stiliaus vadovo reikia naudoti linterį; Claude Code gairės tokios pat: rašykite pakankamai konkrečias instrukcijas, kad jas būtų galima patikrinti, ir laikykite failą trumpą, nes jam ilgėjant agentas jo laikosi vis prasčiau. i18n sekciją iš keturiasdešimties punktų tik permetama akimis.

Kodėl būtent šios dešimt taisyklių, o ne tiesiog „naudok i18n“?

Nes „naudok i18n“ yra būtent tai, ką agentas jau mano darąs, kai rašo <Button>Save changes</Button>. Miglotas instrukcijas agentas įvykdo pagal savo paties suvokimą apie atitiktį. Kiekviena žemiau pateikta taisyklė įvardija konkretų rezultatą ir jį draudžia.

Tekstai atributuose. Agentai išmoksta, kad JSX turinį (children) reikia versti, bet aria-label="Close" ir alt="Company logo" vis tiek įrašo kaip paprastas eilutes, nes atributai atrodo kaip konfigūracija, o ne tekstas. Išvardijus atributus pavadinimais, ši spraga užsidaro; bendras „išversk viską“ jos neuždaro.

Jungimas (konkatenacija). t('greeting') + ' ' + name + '!' angliškai atrodo gerai, bet jo neįmanoma išversti į jokią kalbą, kurioje vardas einąs pirmas arba yra linksniuojamas. Interpoliacija vertėjui duoda vieną eilutę su vienu kintamuoju, kurį galima perkelti.

Daugiskaita per ternary. count === 1 ? 'item' : 'items' — tai dažniausia, ką matome agento parašytą jau sukonfigūravus i18n, ir tai klaidinga kiekvienai kalbai, turinčiai daugiau nei dvi daugiskaitos formas. Taisyklė įvardija šį šabloną, kad agentas galėtų jį atpažinti. Jei jūsų kataloge naudojamas ICU, sintaksę aprašo kas yra ICU MessageFormat ir kur jis nepasiteisina dirbtinio intelekto sukurtose programose.

Sugeneruoti lokalės failai. Ši taisyklė egzistuoja todėl, kad agentai nori padėti. Paprašytas ištaisyti vokišką rašybos klaidą, agentas atidarys locales/de.json ir jį redaguos — tai veikia tol, kol kitas vertimo darbas iš naujo sugeneruos failą iš šaltinio. Pasakius, kad ne šaltinio failai yra sugeneruoti, ir nurodžius, kur daryti tikrąjį pataisymą, išvengiama visos klasės tylių regresijų.

en redagavimas tame pačiame pakeitime. Be šios taisyklės agentas prideda t('checkout.summary.total') ir eina toliau, o raktas rodomas kaip savo paties pavadinimas, kol kas nors tai pastebi. Katalogo įrašas ir pirmasis jo panaudojimas turi patekti į tą patį pakeitimų rinkinį (diff).

Kur kiekvienas įrankis iš tikrųjų skaito failą?

Tas pats turinys dedamas į skirtingas vietas, priklausomai nuo agento, o vieta lemia, ar taisyklė visada yra kontekste, ar įkeliama tik tada, kai reikia.

AGENTS.md saugyklos šaknyje yra bendra vieta. Formatas — paprastas Markdown be privalomų laukų, jį prižiūri Linux Foundation priklausanti Agentic AI Foundation, o skaito Cursor, Codex, Copilot coding agent ir daugybė kitų. Specifikacija palaiko įdėtinius failus, o pirmenybė teikiama redaguojamam failui artimiausiam.

Cursor tiesiogiai skaito AGENTS.md, įskaitant įdėtinius, ir turi savo taikymo sritį ribojantį formatą. UI failams skirta taisyklė nepatenka į kontekstą, kol neatidarytas atitinkamas failas:

---
description: i18n rules for user-visible strings
globs: src/**/*.tsx, src/**/*.jsx
alwaysApply: false
---
(paste the Internationalization section here)

Failo galūnė turi būti .mdc, o pats failas turi būti aplanke .cursor/rules/; paprastas .md tame aplanke ignoruojamas, nes neturi frontmatter.

GitHub Copilot VS Code aplinkoje turi tris variantus. .github/copilot-instructions.md taikomas kiekvienai pokalbio užklausai. .github/instructions/i18n.instructions.md failas su applyTo: "**/*.tsx,**/*.jsx" frontmatter taikomas tik tada, kai tie failai kuriami ar keičiami. O AGENTS.md saugyklos šaknyje skaito Local agent, kai įjungtas chat.useAgentsMdFile nustatymas; įdėtiniai AGENTS.md failai poaplankiuose priklauso nuo atskiro eksperimentinio nustatymo chat.useNestedAgentsMdFiles, kuris pagal numatytuosius nustatymus išjungtas. Su Copilot susijusi elgsena aprašyta straipsnyje kaip pridėti i18n prie programos, sukurtos su GitHub Copilot.

Claude Code skaito CLAUDE.md, o nuo v2.1.277 pats skaito šakninį AGENTS.md, kai virš darbo katalogo projekte nėra CLAUDE.md. Jei laikote abu, dokumentuotas šablonas — @AGENTS.md importas CLAUDE.md pradžioje, kad failas būtų įkeltas vieną kartą. Apimčiai riboti .claude/rules/i18n.md su paths: sąrašu frontmatter įkeliamas tik tada, kai Claude skaito atitinkamą failą. Visas Claude Code darbo procesas aprašytas kaip lokalizuoti programą, kurią sugeneravo Claude Code.

Praktinis sprendimas saugyklai, kurią liečia keli agentai: dešimt taisyklių — apimtimi ribojamame faile tam agentui, kurį jūsų komanda naudoja dažniausiai, o AGENTS.md — dviejų eilučių nuoroda („UI eilutės: žr. i18n taisykles .cursor/rules/i18n.mdc ir jų laikykitės“), kad bet kuris agentas be apimties palaikymo vis tiek gautų instrukciją.

Kurios kodo rašymo vietos niekada neskaito AGENTS.md?

Eilutės užbaigimo pasiūlymai rašant. Tai dokumentuota abiejų tiekėjų ir būtent dėl to taisyklių failas negali būti visas atsakymas.

Cursor taisyklių DUK į klausimą „Ar taisyklės veikia Cursor Tab ar kitas dirbtinio intelekto funkcijas?“ atsako paprastai — ne. Taisyklės maitina Agent; Tab, automatinis užbaigimas, užpildantis eilutę, kurią rašote, jų nemato. VS Code pasirinktinių instrukcijų puslapyje Copilot pateikta ta pati pastaba: instrukcijos neįskaitomos į įterptinius pasiūlymus, kai rašote redaktoriuje.

Taigi vieta, kur kūrėjas rašo <p>No results found</p> ir priima pilką siūlomą tekstą, yra būtent ta, kurios taisyklės niekada nepasiekia. Pokalbis ir agento režimas eilutei priskirs raktą; pasiūlymas, kuris užbaigė eilutę, kol jūs galvojote apie kažką kita, — ne. Per įprastą darbo savaitę kodo bazėje kaupiasi eilutės iš vienintelio kelio, kurio instrukcijų failas nepadengia, o kūrėjas, parašęs kruopštų taisyklių failą, mano, kad agentas jo nepaiso.

Claude Code neturi įterptinio užbaigimo, bet jo dokumentacija tą patį sako iš kitos pusės: CLAUDE.md turinys yra kontekstas, o ne privaloma konfigūracija, ir norint užblokuoti veiksmą nepriklausomai nuo modelio sprendimo, reikia naudoti hook. Tai teisingas mąstymo modelis visiems čia minimiems įrankiams. Instrukcijų failai keičia tikimybes. Jie nieko neįpareigoja.

Kas iš tikrųjų užtikrina taisyklės laikymąsi?

Lint taisyklė CI aplinkoje, o pridėti ją — vienos eilutės darbas, kai taisyklių failas jau liepia agentui ją paleisti. eslint-plugin-i18next pateikia no-literal-string; įjunkite ją savo komponentų aplankams, ir eilutė JSX nepraeis build, o ne gaus mandagų priminimą. Sąranka, taisyklės parinktys ir tai, kodėl instrukcija bei vykdymas yra du skirtingi sluoksniai, aprašyti straipsnyje kodėl Cursor vis prideda tiesiogiai kode įrašytų eilučių po i18n sąrankos, tad čia to nekartosime.

Du dalykai, kuriuos suteikia lint sluoksnis, bet ne taisyklių failas. Jis pagauna įterptinio užbaigimo rezultatą, nes tikrina failą, o ne pokalbį. Ir jis paverčia paties agento ciklą pataisymu: paskutinė aukščiau esančio bloko taisyklė liepia agentui prieš baigiant paleisti lint, o agentas, pamatęs, kad no-literal-string nepavyko, pats priskirs eilutei raktą toje pačioje sesijoje.

Konkrečiai Claude Code atveju PreToolUse arba po redagavimo vykdomas hook, kuris paleidžia linterį ką tik parašytam failui, yra vykdymo užtikrinimo mechanizmas, kurį nurodo jo dokumentacija. Hook veikia kaip shell komandos fiksuotuose taškuose ir taikomi nepriklausomai nuo to, ar modelis nusprendė laikytis taisyklės.

Kas nutinka eilutėms, kurios vis tiek prasprūsta?

Jas reikia išgauti, priskirti raktus pagal esamas vardų erdves ir išversti — būtent tai verta automatizuoti, o ne kartoti užklausas agentui. Nepavykęs build parodo, kad kode yra tiesiogiai įrašyta eilutė. Vis tiek kažkas turi paversti ją raktu, pridėti į en ir pasirūpinti, kad ji atsirastų kiekvienoje kitoje lokalėje.

Būtent šiame sluoksnyje veikia globalize.now. Konvertavimas vyksta vieną kartą ir pačioje programoje: prijungiate saugyklą, kodo bazė konvertuojama vieną kartą, o katalogas pateikiamas kaip pull request peržiūrai. Po to push užduotys išverčia naujus katalogo vienetus vos jiems atsiradus, taigi raktas, pridėtas antradienio PR, vertimus gauna trečiadienio PR. Runtime biblioteka, katalogo formatas ir aukščiau pateiktas taisyklių failas — visa tai jūsų; kūrėjo dokumentacijoje aprašyta, kaip Cursor, Claude Code, Codex ir Copilot agentai perima vaidmenį po sąrankos, o Cursor integracija yra trumpiausias žingsnis po žingsnio vadovas.

Dvi susijusios problemos turi savo įrašus. Jei problema ta, kad agentas performuluoja jau raktais pažymėtą tekstą, žr. kaip sustabdyti dirbtinio intelekto agentus nuo jūsų UI tekstų perrašinėjimo — sprendimas yra ta pati šaltinio lokalės disciplina, kaip ir devintoji aukščiau esanti taisyklė. Jei lokalės egzistuoja, bet nuolat išsiskiria, kodėl vertimo failai praranda sinchronizaciją paaiškina už to slypintį maršrutizavimo gedimą.

Nuo ko pradėti?

Įklijuokite bloką, apribokite jį savo UI aplankais ir tą pačią popietę įjunkite no-literal-string CI aplinkoje. Tada savaitę stebėkite, ką pagauna lint taisyklė; tai ir bus jūsų matas, kiek taisyklių failas pats iš savęs buvo pajėgus padaryti. Jei kuriate dirbtinio intelekto sukurtą programą ir norite, kad visa, kas vis tiek prasprūsta, būtų išgaunama ir verčiama už jus, o ne prižiūrima jūsų pačių, vibe coders puslapis pateikia apžvalgą, o kainos nurodytos atskirame puslapyje.

globalize.now paverčia užkoduotą programos tekstą į vertimui paruoštus lokalės failus ir juos atnaujina, kai jūs diegiate naujus pakeitimus.

Išbandyti globalize.now nemokamai