UI tekstas išlieka nuoseklus, kai kiekviena naudotojui matoma eilutė saugoma viename kataloge saugykloje, naudojama per raktą ir keičiama tik peržiūrėtu diff'u. Tai ta pati disciplina, kurią jau taikote logikai, tik pritaikyta formuluotėms. Visa kita šiame puslapyje yra praktika, padedanti tai išlaikyti.

Tai praktinis vadovas. Architektūra, kuria jis remiasi, ir argumentai, kodėl produkto teksto šaltiniu turėtų būti kodo bazė, aprašyti straipsnyje kode integruotas produkto tekstas. Skaitykite jį, jei norite sužinoti kodėl. Skaitykite toliau, jei norite sužinoti kaip.

Kur turėtų būti saugomas UI tekstas?

Viename katalogo faile kiekvienai šaltinio kalbai, saugykloje, šalia jį atvaizduojančio kodo. Ne skaičiuoklėje, ne dizaino faile, ne wiki puslapyje, kuris buvo tikslus kovą. Katalogas yra vieta, kur programuotojas, peržiūros dalyvis, vertėjas ir kodavimo agentas žiūri, kai nori sužinoti, ką sako ekranas.

Praktinės taisyklės, kylančios iš to:

  • Vienas katalogas, viena šaltinio lokalė. Vienas en.json (arba .po, .ftl, .strings, ką beskaitytų jūsų i18n biblioteka) yra pagrindinė teksto kopija. Jei monorepo turite kelias programas, kiekviena gauna po vieną, o bendros eilutės gauna bendrą katalogą, kurį importuoja abi. Venkite dviejų failų, kuriuose gali būti tas pats pranešimas.
  • Grupuokite pagal ekraną ar funkciją, o ne pagal komponentą. Raktai, tokie kaip checkout.summary.total, laikui bėgant išlieka tinkamesni nei SummaryCard.totalLabel, nes komponentai pervadinami ir skaidomi, o ekranas ir pranešimas lieka tie patys.
  • Raktą pavadinkite pagal pranešimą, o ne pagal formuluotę. checkout.submit išlieka tinkamas, kai „Place order“ pakeičiama į „Buy now“. checkout.placeOrderButton – ne, o rakto ir teksto neatitikimas vėliau priverčia peržiūros dalyvį manyti, kad tai dvi skirtingos eilutės.
  • Katalogą laikykite tame pačiame pull request'e kaip ir jį naudojantį kodą. Eilutė, pridėta viename PR, o jos komponentas kitame, bus praleista, užmiršta ar dubliuota.

Jei jūsų eilutės vis dar yra literalai komponentų viduje, katalogą reikia sukurti pirmiausia. Daryti tai rankiniu būdu yra atskiras projektas, todėl verta prijungti saugyklą ir leisti konversijai padaryti tai už jus, apie tai žemiau.

Kodėl nuoroda per raktą pranašesnė už literalo paiešką?

Nes raktas gali nurodyti tik vieną eilutę, o literalą galima užrašyti tiek būdų, kiek yra programuotojų. „Sign in“, „Sign In“, „Log in“ ir „Login“ paieškos įrankiui yra keturios eilutės, o naudotojui – vienas ketinimas. Kai kiekvienas komponentas kviečia t("auth.signIn"), klausimas, kuri formuluotė teisinga, išsprendžiamas vieną kartą, vienoje vietoje, ir atsakymas galioja visur, kur raktas naudojamas.

Du įpročiai padeda tai išlaikyti:

  • Naudokite pakartotinai, prieš pridėdami naują. Prieš kurdami raktą, katalogo paieškoje ieškokite pranešimo. Jei common.cancel jau yra, naujas dialog.cancelButton su tuo pačiu tekstu yra nukrypimo pradžia, o ne nekenksmingas dublikatas. Vos kam nors pakeitus vieną iš jų, abu bus redaguojami nepriklausomai.
  • Nejunkite eilučių. t("cart.items") + " " + count sukuria tekstą, kurio neaprašo jokia katalogo eilutė. Naudokite savo bibliotekos interpoliaciją ir daugiskaitos formas, kad visas sakinys būtų vienas peržiūrimas vienetas.

Dažnas pasiteisinimas: „ši eilutė pasirodo tik kartą, tad literalas tinka“. Šiandien ji pasirodo kartą. Komponentas bus nukopijuotas, greta atsiras panašus ekranas, o literalas keliaus kartu ir paskui pradės skirtis.

Kaip peržiūrėti teksto pakeitimus pull request'e?

Pakeistą katalogo eilutę vertinkite taip, kaip pakeistą funkcijos signatūrą: kaip kažką, ką recenzentas perskaito, apsvarsto ir patvirtina. Tai praktika, kuri nuoseklumą iš atminties problemos paverčia peržiūros problema, o peržiūra yra vienintelė akimirka, kai kas nors patikimai skiria dėmesį.

Kas leidžia katalogo peržiūrai veikti:

  • Formuluotės pakeitimas yra atskira eilutė diff'e. Tai galioja tik jei eilutė yra kataloge. Formuluotės pakeitimas komponento viduje taip pat yra diff eilutė, bet ji pasimeta tarp logikos pakeitimų ir praleidžiama kaip „tik tekstas“.
  • Nukreipkite katalogo pakeitimus už tekstus atsakingam asmeniui. CODEOWNERS įrašas katalogo kelyje reiškia, kad kiekvienam jo pakeitimui peržiūrėti pakviečiamas tas, kas atsako už formuluotes: produkto vadovas, turinio dizaineris ar programuotojas, kuriam tai svarbiausia. Visa kita PR eina įprasta peržiūra.
  • Užduokite tris klausimus kiekvienai pakeistai eilutei. Ar tai patvirtintas šio dalyko terminas? Ar jis tonu ir raidžių dydžiu atitinka aplinkines eilutes? Ar rakto pavadinimas vis dar apibūdina pranešimą? Recenzentas, užduodantis šiuos tris klausimus, pagauna didžiąją dalį to, ko padeda išvengti stiliaus gairės.
  • Atmeskite tylius pervadinimus. PR, kuris pakeičia auth.signIn iš „Sign in“ į „Log in“ be paaiškinimo, yra teksto sprendimas, kurį priėmė tas, kas atsitiktinai redagavo. Reikia vieno sakinio PR aprašyme, paaiškinančio kodėl, arba pakeitimas turi būti atšauktas.

Gedimo, kurio tai padeda išvengti, būdas turi pavadinimą. Teksto nukrypimas (copy drift) – tai naudotojui matomo teksto nukrypimas nuo patvirtinto šaltinio skirtingose vietose ir laikui bėgant, kai nėra vieno tiesos šaltinio, nuo kurio galėtų nukrypti. Kas yra teksto nukrypimas aptaria priežastis; katalogo peržiūra diff'e yra praktika, sustabdanti daugumą jų.

Kaip neleisti patekti naujoms kode tiesiogiai įrašytoms eilutėms?

Padarykite, kad naujas literalas lemtų nesėkmingą build'ą. Taisyklės ir peržiūros pagauna tai, ko žmonės prisimena ieškoti. Lint taisyklė pagauna likusius atvejus kiekviename pull request'e, ir niekam nereikia nieko prisiminti.

Nustatymas nedidelis:

  • Įjunkite no-literal-string taisyklę. eslint-plugin-i18next pateikia tokią taisyklę JavaScript ir TypeScript projektams. Apribokite ją JSX tekstu ir naudotojui matomais atributais, pavyzdžiui, įvesties užuominomis, title, aria-label ir alt, o testų failus ir Storybook istorijas pažymėkite kaip išimtis, kad taisyklė išliktų patikima.
  • Vykdykite ją ten, kur vyksta merge. Pre-commit hook'as patogus; CI žingsnis yra tas, kuris svarbiausias, nes jis vykdomas pull request'e nepriklausomai nuo to, ar autoriaus redaktorius buvo sukonfigūruotas.
  • Pridėkite nenaudojamų ir trūkstamų raktų patikrą. Daugumos i18n bibliotekų yra papildomas įrankis, išvardijantis raktus, kurie naudojami kode, bet nėra kataloge, ir raktus kataloge, kurie niekur nenaudojami. Vykdykite jį ir CI. Nenaudojami raktai yra ten, kur slepiasi pasenusi formuluotė.
  • Pradėkite griežtai, o išimtis leiskite per komentarą. Taisyklė, išjungta visam components/ aplankui, nėra taisyklė. Taisyklė, išjungta vienoje eilutėje su priežastimi, yra dokumentacija.

Komandos, kurios kuria su DI kodavimo įrankiais, su tuo susiduria dažniau, nes įrankiai iš vietinio konteksto iš naujo sugeneruoja komponentus ir kartu grąžina literalus. Kodėl Cursor AI nuolat prideda užkoduotas eilutes išsamiai aptaria lint taisyklę, įskaitant trijų lygių sąranką: taisyklių failą, linterį ir CI.

Kas priklauso teksto stiliaus gairėms programuotojams?

Trumpas failas saugykloje, tilpstantis viename ekrane, apibrėžiantis toną, fiksuojantis terminus ir nurodantis, kur dedamos eilutės. Ilgos stiliaus gairės dažniausiai laikomos wiki ir perskaitomos vieną kartą. Trumpos laikomos šalia kodo ir skaitomos žmonių bei įrankių kaskart, kai pridedama eilutė.

Veikiantis COPY.md (arba skyrius esamame kontribucijų vadove) apima:

  1. Toną trimis sakiniais. Kaip skamba produktas, kiek jis formalus, ar sako „jūs“, ar „naudotojas“. Pakanka, kad būtų išspręsta dauguma ginčų.
  2. Terminai, kurie niekada nesikeičia. Produkto pavadinimai kiekvienai funkcijai, pagrindinių veiksmų veiksmažodžiai (ar „Save“, ar „Update“? „Delete“ ar „Remove“?) ir žodžiai, kurių nusprendėte nenaudoti.
  3. Didžiųjų raidžių ir skyrybos taisyklės. Ar mygtukuose ir antraštėse rašoma tik pirma žodžio raidė didžiąja, ar visi žodžiai didžiosiomis, ar paaiškinimuose rašomi taškai, kaip rašomi skaičiai ir datos.
  4. Kur dedamos eilutės ir kaip pavadinami raktai. Katalogo kelias, grupavimo taisyklė, rakto pavadinimo taisyklė ir „ieškok, prieš pridėdamas“.
  5. Ką daryti, kai abejojate. Kreiptis į ką nors ar kurį raktą panaudoti kol kas.

Laikykite jį saugykloje, kad taisyklių failas galėtų į jį rodyti, peržiūros dalyvis galėtų pateikti nuorodą komentare, o kodavimo agentas galėtų jį perskaityti prieš rašydamas užrašą.

Kaip neleisti DI kodavimo agentams sugadinti nuoseklumo?

Duokite agentui skaitytiną tiesos šaltinį ir patikrą, kuri jį sustabdo, kai jis šaltinio nepaiso. Formą generuojantis agentas noriai parašys „Submit“ viename ekrane ir „Send“ kitame, nes kiekvienu atveju tai buvo vietoje labiausiai tikėtinas žodis. Jis nėra nerūpestingas; jis tiesiog neturi su kuo būti nuoseklus.

Du žingsniai išsprendžia didžiąją dalį. Pirma, taisyklių failas (AGENTS.md, .cursor/rules, CLAUDE.md – kurį tik skaito jūsų įrankiai), kuriame sakoma: naudotojui matomas tekstas dedamas į katalogą, naudokite esamus raktus ir perskaitykite COPY.md prieš rašydami užrašą. Antra, lint taisyklė iš ankstesnio skyriaus, nes taisyklių failas sumažina spėliojimą, o lint taisyklė pagauna spėjimus, kurie praslydo.

Tai viskas, ką šis puslapis sako apie agentus. Konkreti problema, kai agentas pakeičia jau egzistavusių eilučių formuluotes, ir kaip tą pakeitimą padaryti matomą, o ne tylų, yra atskira tema: kaip sustabdyti DI kodavimo agentus, perrašančius jūsų UI tekstą.

Kur čia įsiterpia lokalizavimas?

Nuoseklumas ir lokalizacija remiasi tuo pačiu – sutartu šaltiniu, todėl katalogas, suteikiantis vieną, suteikia ir kitą. Komanda, negalinti pasakyti, kuri iš trijų formuluočių yra patvirtinta, negali teisingai išversti nė vienos iš jų. Sutvarkykite šaltinį ir vertimas tampa išvestiniu katalogo produktu, o ne atskiru projektu su sava tiesos versija.

Praktiškai tai reiškia, kad katalogas, kurį sukūrėte nuoseklumui, jau yra failas, su kuriuo dirba vertėjas ar vertimo įrankis. Kiekvienas raktas gauna atitikmenis visomis tikslinėmis kalbomis, galioja tie patys raktų pavadinimai, o formuluotės pakeitimas šaltinio kataloge matomas kaip pakeitimas, kurio turi laikytis vertimai. Kai vertimams leidžiama atsilikti nuo šaltinio, gaunate problemų klasę, aprašytą straipsnyje kodėl vertimų failai praranda sinchronizaciją, o sprendimas yra ta pati disciplina: vienas katalogas, raktai, pakeitimai diff'e.

Kur tinka globalize.now

globalize.now yra kode integruota teksto valdymo sistema su įtaisyta lokalizacija, o kiekviena šio puslapio praktika yra prielaida, kurią ji daro apie jūsų saugyklą. Programoje prijungiate GitHub ar GitLab saugyklą. Skenavimas nustato, kas joje yra. Jei eilutės yra literalai komponentų viduje, vienkartinė konversija perkelia jas į katalogą ir susieja per raktus, o jei i18n sąrankos nėra, ją prideda. Jei jau naudojate next-intl, react-i18next, i18next ar Lingui, ji veikia su tuo, ką turite. Rezultatas pateikiamas kaip pull request atskiroje šakoje, todėl pirmasis katalogas patenka į tokią pačią peržiūrą, kaip aprašyta aukščiau. Po to naujas jūsų pridėtas šaltinio eilutes verčia push užduotys, kurios atidaro pull request'ą su rezultatu. Saugykla lieka vieninteliu tiesos šaltiniu.

Dirbame, kad ta pati disciplina galiotų visoje rinkodaros svetainėje, nukreipimo puslapyje ir produkte iš vieno šaltinio, kad funkcija būtų aprašoma vienodai visur, kur naudotojas su ja susiduria. Tai kryptis, kuria einame, o ne tai, ką galima nusipirkti šiandien. Kainos pateiktos kainų puslapyje.

Kontrolinis sąrašas, kurį galite pritaikyti šią savaitę

  1. Sukurkite po vieną katalogą kiekvienai šaltinio kalbai saugykloje ir nuspręskite dėl raktų pavadinimų taisyklės.
  2. Perkelkite į jį eilutes iš dažniausiai naudojamų ekranų; kreipkitės į jas per raktus.
  3. Įjunkite no-literal-string lint taisyklę, apribotą naudotojui matomam tekstui, ir vykdykite ją CI.
  4. Pridėkite CODEOWNERS eilutę katalogo keliui.
  5. Parašykite COPY.md: tonas, fiksuoti terminai, didžiųjų raidžių taisyklės, kur saugomos eilutės. Vienas ekranas.
  6. Nukreipkite savo agento taisyklių failą į katalogą ir į COPY.md.
  7. Peržiūros metu atmeskite bet kokį formuluotės pakeitimą, kurio priežastis nenurodyta PR aprašyme.

Jei antrasis žingsnis atrodo kaip mėnesio darbas, prijunkite saugyklą, perskaitykite pasiūlytą planą ir peržiūrėkite sukurtą sujungimo užklausą (pull request).

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