Cum să traduci un fișier de limbă JSON fără a strica cheile sau substituenții
Află ce valori dintr-un fișier en.json sunt traduse, ce rescrie un traducător de fișiere (comentarii, ordinea cheilor, ID-uri mari) și cum să verifici substituenții, formele de plural ICU și cheile cu un script gratuit și un fișier de test.

Pentru a traduce un fișier de limbă JSON precum en.json, oferă întregul fișier unui traducător care înțelege JSON. Să lipești textul brut într-o fereastră de chat sau într-un traducător web este metoda riscantă. Un traducător care înțelege JSON citește fișierul, traduce doar valorile text și scrie înapoi aceleași chei, astfel încât aplicația ta poate încărca în continuare fișierul. Copierea și lipirea pot traduce o cheie, pot schimba un ghilim sau pot elimina o acoladă. Oricare dintre acestea strică fișierul.
Păstrarea cheilor este partea ușoară. Cele mai multe probleme apar după: un substituent {name} care revine ca {nom}, o formă de plural ICU care își pierde cazul other, un URL trimis spre traducere ca orice alt text și câteva modificări pe care traducătorul le face fișierului în sine. Acestea sunt aspectele pe care le acoperă acest ghid.
Am creat un fișier de test care conține fiecare dintre aceste cazuri și am scris un verificator gratuit care compară un fișier sursă cu traducerea sa. De asemenea, am rulat fișierul de test printr-o copie locală a codului de parsare și scriere JSON folosit de BookTranslator, cu un marcaj în locul unui model, astfel încât să poți vedea exact ce valori sunt trimise și cum revine fișierul.
Răspuns rapid: Ce se întâmplă cu fiecare parte a fișierului
| Partea din fișier | Exemplu din testul nostru | Ce face BookTranslator | Ce trebuie verificat |
|---|---|---|---|
| Chei | "greeting", "error" | Păstrate așa cum sunt | Nimic |
| Valori text simple | "Reading list" | Traduse | Sensul, lungimea pe ecran |
| Valori cu substituenți | "Welcome back, {name}!", "Saved %s of %d chapters" | Traduse, substituenții incluși în textul trimis | Numele și numărul substituenților (verificatorul face asta) |
| Mesaje de plural ICU | "{count, plural, one {# book} other {# books}}" | Trimise ca un singur șir | Cazul other și categoriile de plural pentru limba țintă |
| HTML inline | "accept the <b>Terms</b>." | Tradus; numărul de etichete este verificat după traducere | Numele și numărul de etichete (verificatorul face asta) |
| URL-uri stocate ca text | "https://example.com/help" | Trimise pentru traducere | Că au revenit neschimbate |
| Valori fără litere | "2.4.1", "—", "" | Lăsate așa cum erau | Nimic |
Numere, true/false, null | 20, true | Lăsate așa cum erau | ID-uri foarte mari (vezi mai jos) |
| Matrice de șiruri | ["Open", "Save", "Export as EPUB"] | Traduse în fișierul tradus; lăsate netraduse în fișierul bilingv | Fișierul bilingv, dacă îl folosești |
| Comentarii (JSONC) | // Shown on the home screen | Eliminate. Dacă o valoare conține și //, fișierul poate să nu se încarce | Elimină comentariile înainte de încărcare |
Restul acestui ghid arată de unde provine fiecare rând și ce trebuie făcut în privința lui.
Pasul 1: Verifică fișierul sursă înainte de a-l încărca
Rulează verificatorul pe fișierul pe care intenționezi să-l traduci. Are nevoie doar de Python 3, nimic altceva:
python3 check_i18n_json.py en.json
Pe fișierul nostru de test, a afișat:
WARN limits.projectId: 9007199254740993 is above 2^53 and can change in a JavaScript round trip; store IDs as strings
WARN error.network: a flat key with dots and a nested key resolve to the same dot path; tools that address strings by dot path can mix them up
INFO (root): 3 keys look like integers; JavaScript sorts those first and in numeric order when it rewrites the object
INFO source: 17 strings, 2 numbers
Cele două avertismente și nota despre cheile asemănătoare numerelor întregi corespund fiecare unei modificări pe care am observat-o când fișierul nostru de test a trecut prin traducător. Dacă fișierul tău nu primește niciunul dintre ele, poți sări la Pasul 3.
De asemenea, verificatorul respinge un fișier care nu este JSON strict, cum ar fi unul cu comentarii sau virgule finale, deoarece aceasta este următoarea problemă.
Ce a revenit din fișierul nostru de test
Testul a rulat pe 2 noiembrie 2026, împotriva gestionării actuale a JSON în backend-ul BookTranslator. În loc să apeleze un model, testul a înlocuit fiecare valoare care ar fi fost trimisă pentru traducere cu [ZH] plus textul original. Astfel, rezultatul rămâne previzibil: orice avea [ZH] în față a fost trimis, orice nu avea nu a fost. Ambele rezultate sunt publicate: fișierul tradus și fișierul bilingv.
Fișierul tradus
Fiecare cheie a revenit neschimbată, iar fișierul s-a parsat în continuare. Au fost trimise valorile cu litere, inclusiv {name}, %s, mesajul ICU, eticheta <b> și URL-ul de ajutor. Șirul de versiune "2.4.1", cratima și șirul gol nu au fost trimise, deoarece nu conțin litere. Numerele și valorile booleene au rămas neatinse.
Alte patru lucruri s-au schimbat:
- Un șir a ajuns la cheia greșită. În testul nostru, fișierul avea o cheie plată
"error.network"cu textul „Check your connection.” și, de asemenea, o cheie imbricată"error": { "network": "Network error" }. Traducătorul identifică fiecare șir prin calea sa cu puncte între părți, așa că ambele șiruri aveau aceeași adresă,error.network. În rezultat, ambele chei conțineau traducerea pentru „Network error”. „Check your connection.” dispăruse. Acest lucru necesită ambele stiluri în același fișier, ceea ce este rar, dar eșuează silențios. Verificatorul avertizează despre asta înainte de încărcare. - Cheile asemănătoare numerelor întregi au fost reordonate.
"steps": { "10": ..., "2": ..., "1": ... }a revenit ca"1","2","10". JavaScript listează întotdeauna cheile asemănătoare numerelor întregi primele, în ordine numerică, atunci când reconstruiește un obiect. Cheile și valorile încă se potrivesc, așa că aplicația ta este în regulă, dar un diff față de fișierul sursă va fi zgomotos. - Un ID mare a pierdut precizie.
9007199254740993a revenit ca9007199254740992. JavaScript stochează numerele ca virgulă mobilă pe 64 de biți, iar numerele întregi peste 2^53 nu pot fi toate reprezentate exact (MDN despreNumber.MAX_SAFE_INTEGER). Stochează ID-urile lungi ca șiruri de caractere sau ține-le în afara fișierului de limbă. - Formatarea a fost rescrisă. Rezultatul folosește indentare cu două spații și se termină cu o linie nouă. Dacă sursa ta folosea tabulatoare sau patru spații, așteaptă-te la modificări de spații albe în diff.
Fișierul nostru de test nu avea chei duplicate, dar merită să știi despre ele: parserul JSON al JavaScript păstrează doar ultima valoare pentru o cheie repetată, așa că textul anterior nu este niciodată tradus. Aplicația ta ar încărca aceeași ultimă valoare, deci nimic vizibil nu se strică, dar verificatorul listează cheile duplicate pentru a le putea curăța.
Fișierul bilingv
Fișierul bilingv păstrează fiecare valoare originală și adaugă o cheie soră cu _translated la final:
"greeting": "Welcome back, {name}!",
"greeting_translated": "[ZH] Welcome back, {name}!",
Acest lucru funcționează bine pentru revizuire, deoarece sursa și traducerea stau una lângă alta. Nu este un fișier pe care aplicația ta îl poate încărca, deoarece fiecare cheie are acum un geamăn. Folosește fișierul tradus în aplicația ta.
O lacună: șirurile din interiorul array-urilor nu primesc o cheie soră _translated, deoarece elementele de array nu au o cheie căreia să i se adauge una. În testul nostru, "menu": ["Open", "Save", "Export as EPUB"] a revenit în engleză în fișierul bilingv, dar tradus în fișierul tradus. Dacă revizuiești din fișierul bilingv, verifică array-urile în fișierul tradus.
Fișiere cu comentarii
Multe proiecte păstrează comentarii în fișierele lor de limbă (JSONC), ceea ce JSON strict nu permite. Traducătorul încearcă mai întâi JSON strict. Dacă eșuează, elimină comentariile și virgulele finale și încearcă din nou. Eliminarea comentariilor înseamnă ștergerea a tot ce urmează după // pe o linie, iar asta include // din https://.
Fișierul nostru cu un comentariu și un URL nu s-a încărcat deloc; parsarea a eșuat la primul comentariu. Un fișier cu comentarii, dar fără // în interiorul vreunei valori, s-a încărcat bine, iar comentariile au fost eliminate din rezultat.
Deci: dacă fișierul tău are comentarii, elimină-le înainte de a încărca, sau păstrează o copie cu comentariile și acceptă că traducerea nu le va avea.
Pasul 2: Pregătește fișierul
Poți rezolva majoritatea acestor probleme înainte de a traduce:
- Fă-l JSON strict. Elimină comentariile și virgulele finale. Dacă instrumentul tău de build citește JSONC, păstrează fișierul cu comentarii ca sursă și exportă o copie curată pentru traducere.
- Folosește un singur stil de chei. Fie imbrică cheile, fie aplatizează-le cu puncte, nu ambele în același fișier. Dacă folosești i18next, opțiunea
keySeparatorcontrolează modul în care sunt citite punctele din chei, așa că verifică această setare înainte de a aplati ceva. - Mută datele non-text în altă parte. ID-urile, URL-urile, steagurile de funcționalitate și limitele aparțin în config, nu în fișierul de limbă. Dacă un URL trebuie să rămână, păstrează-l, dar așteaptă-te să-l verifici după traducere. Ghidul nostru despre ce nu trebuie tradus acoperă cum să decizi ce altceva ar trebui să rămână în limba originală.
- Scrie placeholder-ele la fel peste tot. Un singur stil, cum ar fi
{name}, este mai ușor de verificat decât un amestec de{name},{{name}}și%s.
Pasul 3: Tradu întregul fișier
Încarcă fișierul curățat în traducătorul de documente al BookTranslator, care listează .json alături de celelalte formate de localizare și text structurat acceptate. Prețul este afișat înainte de finalizarea comenzii. Când sarcina se termină, pagina ta de istoric oferă fișierul tradus și fișierul bilingv ca descărcări separate.
Două aspecte legate de modul în care este tradus textul afectează rezultatul:
- Modelul nu vede cheile tale. Fiecare valoare este trimisă ca un segment numerotat, fără numele cheii. Dacă
"button.open"și"status.open"conțin ambele „Open”, modelul nu are cum să știe că unul este verb și celălalt adjectiv. Șirurile scurte și ambigue sunt cele pe care trebuie să le verifici manual. - Fiecare valoare este tradusă separat. Nimic nu leagă două chei între ele, așa că același cuvânt din două locuri poate reveni în două moduri diferite, iar un cuvânt care necesită două traduceri diferite poate reveni la fel. Glosarul automat opțional al BookTranslator colectează nume, locuri și termeni specializați și îi menține consecvenți, dar nu îi poți furniza traduceri fixe proprii. Pentru termenii care trebuie traduși într-un singur mod exact, păstrează o listă de termeni și verifică acele șiruri după traducere; ghidul nostru despre glosare explică cum să planifici una.
Etichetele HTML inline sunt numărate după traducere, iar un segment ale cărui etichete nu corespund este reîncercat. Substituenții cu acolade, substituenții de tip %s și sintaxa ICU sunt trimiși ca parte a textului, dar nu sunt verificați în același mod. Rulează Pasul 4 pentru fiecare traducere.
Dacă preferi să traduci cu un model de chat sau cu un model local, trimite doar valorile, niciodată fișierul brut, și pune-le înapoi pe chei cu un script. Verificările de mai jos se aplică în ambele cazuri.
Pasul 4: Verifică fișierul tradus
Compară traducerea cu sursa:
python3 check_i18n_json.py en.json fr.json
Pentru a arăta ce detectează, am creat un fișier francez cu erori introduse intenționat. Este realizat manual, nu este rezultatul unui model. După aceleași avertismente despre sursă ca la Pasul 1, verificatorul a afișat:
ERROR app.greeting: placeholders differ; lost ['name'] extra ['nom']
ERROR app.help_url: urls differ; lost ['https://example.com/help'] extra ['https://example.com/aide']
ERROR app.items: ICU message has no 'other' case
ERROR app.legacy: placeholders differ; lost ['%d'] extra []
ERROR limits.maxFiles: type changed from int to str
ERROR limits.projectId: non-text value changed: 9007199254740993 -> 9007199254740992
INFO menu[1]: identical to source: 'Save'
INFO compared 20 source values, 1 unchanged strings
Fiecare dintre acestea ar apărea ca un bug în aplicație: un nume gol, un link rupt, un crash sau un mesaj brut când este redat pluralul, un număr de capitole lipsă, o limită comparată ca text. Linia INFO listează șirurile care au revenit neschimbate. Unele sunt în regulă, cum ar fi numele de brand; „Save” într-un meniu francez nu este.
Verificatorul compară cheile, tipurile de valori, valorile non-text, substituenții ({name}, {{name}}, %s, %1$s, %@), numele argumentelor ICU, etichetele HTML și URL-urile. Nu judecă traducerea în sine.
Cazurile de plural ar trebui să se schimbe
Un plural ICU listează un mesaj pentru fiecare categorie de plural. Engleza are două categorii, one și other, dar multe limbi au un set diferit. O traducere bună în rusă a mesajului nostru items ar folosi în mod normal one, few, many și other, iar una în japoneză doar other. Așadar, o nepotrivire aici nu este întotdeauna o eroare.
Categoriile provin din regulile de plural CLDR Unicode, iar other este cea pe care o are fiecare limbă. Acestea sunt categoriile cardinale raportate de Intl.PluralRules în Node.js cu CLDR 48:
| Limbă | Categorii de plural |
|---|---|
| Engleză, germană | one, other |
| Franceză, spaniolă, portugheză | one, many, other |
| Rusă, poloneză | one, few, many, other |
| Arabă | zero, one, two, few, many, other |
| Japoneză, chineză, coreeană | altele |
Franceza, spaniola și portugheza folosesc many doar pentru numere rotunde foarte mari, cum ar fi un milion, așa că un mesaj pentru numere mici poate de obicei să nu îl includă. Verificatorul raportează un other lipsă ca eroare, iar orice altă modificare a categoriilor ca avertisment pentru a fi comparată cu acest tabel. Poți afișa lista pentru orice limbă:
node -e 'console.log(new Intl.PluralRules("ru").resolvedOptions().pluralCategories)'
Traducătorului i se dau cazurile din engleză, așa că verifică ce a returnat. Dacă un mesaj în rusă sau arabă are încă doar one și other, adaugă manual cazurile lipsă sau roagă un traducător să o facă.
Apoi încarcă-l în aplicație
Verificatorul demonstrează că fișierul este sigur de încărcat, nu că se citește bine. Schimbă aplicația pe limba nouă și uită-te la ecrane: cuvinte lungi în germană sau finlandeză care depășesc un buton, text de la dreapta la stânga în arabă sau ebraică și date sau numere pe care codul tău le formatează separat de fișierul de limbă. Ghidul nostru despre traducere versus localizare acoperă ce altceva se schimbă între piețe în afară de cuvinte.
Probleme frecvente
Fișierul tradus nu se încarcă în aplicația mea. Rulează verificatorul pe el. Dacă verificatorul nu îl poate analiza, fișierul a fost editat după traducere sau nu a fost valid de la început. Dacă îl analizează, caută linii ERROR despre chei sau tipuri.
Un șir apare ca mesaj ICU brut, cum ar fi {count, plural, ...}. Sintaxa ICU s-a stricat la traducere, de obicei o acoladă lipsă sau un caz other lipsă. Copiază structura din sursă și traduce doar cuvintele din interiorul fiecărui caz.
Fișierul meu este YAML, un fișier .po sau Markdown. BookTranslator le acceptă și pe acestea, dar fiecare format are propriile reguli. Pentru documentație, vezi ghidul nostru de traducere Markdown; pentru pagini web, ghidul fișierelor HTML.
Pot traduce doar cheile noi? Nu într-o singură încărcare; întregul fișier este tradus. Pune cheile noi într-un fișier separat, traduce-l și îmbină rezultatul după cheie. Verificatorul va confirma că fișierul îmbinat are fiecare cheie.
Ar trebui să traduc cheile? Nu. Cheile sunt identificatori pe care codul tău îi caută. Doar valorile sunt text pentru oameni.
Articole asociate





