Как да преведете JSON езиков файл, без да счупите ключове или заместители
Вижте кои стойности в един en.json файл се превеждат, какво пренаписва преводачът на файлове (коментари, ред на ключовете, големи ID-та) и как да проверите заместители, ICU множествени форми и ключове с безплатен скрипт и тестов файл.

За да преведете JSON езиков файл като en.json, дайте целия файл на преводач, който разбира JSON. Поставянето на суровия текст в чат прозорец или уеб преводач е рискованият начин. Преводач, който разбира JSON, прочита файла, превежда само текстовите стойности и записва същите ключове обратно, така че приложението ви все още може да зареди файла. Копирането и поставянето може да преведе ключ, да промени кавичка или да изпусне скоба. Всяко от тези неща чупи файла.
Запазването на ключовете е лесната част. Повечето проблеми идват след това: заместител {name}, който се връща като {nom}, ICU множествена форма, която губи своя случай other, URL, изпратен за превод като всеки друг текст, и няколко промени, които преводачът прави по самия файл. Точно това обхваща това ръководство.
Създадохме тестов файл с всеки един от тези случаи в него и написахме безплатна проверка, която сравнява изходен файл с неговия превод. Също така прекарахме тестовия файл през локално копие на кода за JSON анализ и запис, който BookTranslator използва, с маркер на мястото на модел, за да видите точно кои стойности се изпращат и как се връща файлът.
Бърз отговор: Какво се случва с всяка част от файла
| Част от файла | Пример от нашия тест | Какво прави BookTranslator | Какво да проверите |
|---|---|---|---|
| Ключове | "greeting", "error" | Запазват се както са | Нищо |
| Обикновени текстови стойности | "Reading list" | Превеждат се | Смисъл, дължина на екрана |
| Стойности със заместители | "Welcome back, {name}!", "Saved %s of %d chapters" | Превеждат се, заместителите се включват в изпращания текст | Имена и брой на заместителите (проверката прави това) |
| ICU множествени съобщения | "{count, plural, one {# book} other {# books}}" | Изпращат се като един низ | Случаят other и множествените категории за целевия език |
| Вграден HTML | "accept the <b>Terms</b>." | Превежда се; броят на таговете се проверява след превода | Имена и брой на таговете (проверяващият скрипт прави това) |
| URL адреси, съхранени като текст | "https://example.com/help" | Изпращат се за превод | Че се е върнало непроменено |
| Стойности без букви | "2.4.1", "—", "" | Оставени както са били | Нищо |
Числа, true/false, null | 20, true | Оставени както са били | Много големи ID (вижте по-долу) |
| Масиви от низове | ["Open", "Save", "Export as EPUB"] | Преведени в преведения файл; непреведени в двуезичния файл | Двуезичният файл, ако го използвате |
| Коментари (JSONC) | // Shown on the home screen | Премахнати. Ако дадена стойност също съдържа //, файлът може да не се зареди | Премахнете коментарите преди качване |
Останалата част от това ръководство показва откъде идва всеки ред и какво да правите с него.
Стъпка 1: Проверете изходния файл преди качване
Стартирайте проверяващия скрипт върху файла, който планирате да преведете. Той се нуждае само от Python 3 и нищо друго:
python3 check_i18n_json.py en.json
Върху нашия тестов файл той отпечата:
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
Двете предупреждения и бележката за ключовете, подобни на цели числа, всяко съответства на промяна, която видяхме, когато тестовият ни файл премина през преводача. Ако вашият файл не получи нито едно от тях, можете да преминете към Стъпка 3.
Проверяващият скрипт също отказва файл, който не е строг JSON, например такъв с коментари или завършващи запетаи, защото това е следващият проблем.
Какво се върна от нашия тестов файл
Тестът беше проведен на 2 ноември 2026 г. срещу текущата обработка на JSON в бекенда на BookTranslator. Вместо да извика модел, тестът замени всяка стойност, която би била изпратена за превод, с [ZH] плюс оригиналния текст. Това прави резултата предвидим: всичко с [ZH] отпред е било изпратено, всичко без него не е. И двата изхода са публикувани: преведения файл и двуезичния файл.
Преведеният файл
Всеки ключ се върна непроменен и файлът все още се парсваше. Изпратени бяха стойности с букви, включително {name}, %s, ICU съобщението, тагът <b> и URL адресът за помощ. Низът за версия "2.4.1", тирето и празният низ не бяха изпратени, защото не съдържат букви. Числата и булевите стойности останаха непокътнати.
Промениха се четири други неща:
- Един низ попадна в грешен ключ. В нашия тест файлът ни имаше плосък ключ
"error.network"с текст "Check your connection.", както и вложен"error": { "network": "Network error" }. Преводът идентифицира всеки низ по пътя му с точки между частите, така че и двата низа имаха един и същ адрес,error.network. В изхода и двата ключа съдържаха превода на "Network error". "Check your connection." беше изчезнал. Това изисква и двата стила в един файл, което е рядкост, но се проваля безшумно. Проверяващият инструмент предупреждава за това преди качване. - Ключовете, подобни на цели числа, бяха пренаредени.
"steps": { "10": ..., "2": ..., "1": ... }се върна като"1","2","10". JavaScript винаги изброява ключовете, подобни на цели числа, първи, в числов ред, когато възстановява обект. Ключовете и стойностите все още съвпадат, така че приложението ви е наред, но разликата спрямо изходния файл ще бъде шумна. - Голям ID загуби точност.
9007199254740993се върна като9007199254740992. JavaScript съхранява числата като 64-битови числа с плаваща запетая и целите числа над 2^53 не могат всички да бъдат представени точно (MDN заNumber.MAX_SAFE_INTEGER). Съхранявайте дългите ID като низове или ги дръжте извън езиковия файл. - Форматирането беше пренаписано. Изходът използва отстъп от два интервала и завършва с нов ред. Ако източникът ви е използвал табулатори или четири интервала, очаквайте промени в белите пространства в разликата.
Тестовият ни файл нямаше дублирани ключове, но си струва да ги познавате: JSON парсерът на JavaScript запазва само последната стойност за повторен ключ, така че по-ранният текст никога не се превежда. Приложението ви ще зареди същата последна стойност, така че нищо видимо не се чупи, но проверяващият инструмент изброява дублираните ключове, за да можете да ги изчистите.
Двуезичният файл
Двуезичният файл запазва всяка оригинална стойност и добавя съседен ключ с _translated в края:
"greeting": "Welcome back, {name}!",
"greeting_translated": "[ZH] Welcome back, {name}!",
Това работи добре за преглед, защото източникът и преводът стоят един до друг. Това не е файл, който приложението ви може да зареди, защото всеки ключ сега има близнак. Използвайте преведения файл в приложението си.
Една празнина: низовете в масиви не получават съседен ключ _translated, защото елементите на масива нямат ключ, към който да се добави. В нашия тест "menu": ["Open", "Save", "Export as EPUB"] се върна на английски в двуезичния файл, но преведен в преведения файл. Ако преглеждате от двуезичния файл, проверете масивите в преведения файл.
Файлове с коментари
Много проекти пазят коментари в езиковите си файлове (JSONC), което строгият JSON не позволява. Преводачът първо опитва строг JSON. Ако това се провали, той премахва коментарите и завършващите запетаи и опитва отново. Премахването на коментари означава изтриване на всичко след // на реда, а това включва // в https://.
Нашият файл с коментар и URL изобщо не се зареди; парсването се провали на първия коментар. Файл с коментари, но без // във всяка стойност, се зареди успешно и коментарите бяха премахнати от изхода.
Така че: ако файлът ви има коментари, премахнете ги преди качване или запазете копие с коментарите и приемете, че преводът няма да ги има.
Стъпка 2: Подгответе файла
Можете да поправите повечето от тези проблеми преди да преведете:
- Направете го строг JSON. Премахнете коментарите и завършващите запетаи. Ако инструментът ви за изграждане чете JSONC, запазете файла с коментари като източник и експортирайте чисто копие за превод.
- Използвайте един стил на ключове. Или вложете ключовете, или ги изравнете с точки, но не и двете в един файл. Ако използвате i18next, неговата опция
keySeparatorконтролира как се четат точките в ключовете, така че проверете тази настройка, преди да изравните нещо. - Преместете данните, които не са текст, навън. ID, URL адреси, флагове за функции и ограничения принадлежат в конфигурацията, не в езиковия файл. Ако URL адрес трябва да остане, запазете го, но очаквайте да го проверите след превод. Нашето ръководство за това какво да не се превежда обхваща как да решите какво друго трябва да остане на оригиналния език.
- Пишете заместителите по един и същ начин навсякъде. Един стил, като
{name}, е по-лесен за проверка от смесица от{name},{{name}}и%s.
Стъпка 3: Преведете целия файл
Качете почистения файл в преводача на документи на BookTranslator, който изброява .json заедно с другите формати за локализация и структуриран текст, които приема. Цената се показва преди плащане. Когато задачата приключи, страницата ви с история предлага преведения файл и двуезичния файл като отделни изтегляния.
Две неща в начина, по който се превежда текстът, влияят на резултата:
- Моделът не вижда вашите ключове. Всяка стойност се изпраща като номериран сегмент, без името на ключа. Ако
"button.open"и"status.open"и двете казват „Open“, моделът няма как да знае, че едното е глагол, а другото – прилагателно. Кратките, двусмислени низове са тези, които трябва да проверите на ръка. - Всяка стойност се превежда самостоятелно. Нищо не свързва два ключа, така че една и съща дума на две места може да се върне по два различни начина, а дума, която изисква два различни превода, може да се върне еднакво. Опционалният автоматичен глосар на BookTranslator събира имена, места и специализирани термини и ги поддържа последователни, но не можете да му зададете собствени фиксирани преводи. За термини, които трябва да се превеждат по един точен начин, водете списък с термини и проверявайте тези низове след превода; нашето ръководство за глосар обяснява как да го планирате.
Вградените HTML тагове се броят след превода и сегмент, чиито тагове не съвпадат, се опитва отново. Заместителите в къдрави скоби, заместителите от типа %s и ICU синтаксисът се изпращат като част от текста, но не се проверяват по същия начин. Изпълнете Стъпка 4 за всеки превод.
Ако предпочитате да превеждате с чат модел или локален модел, изпращайте само стойностите, никога суровия файл, и ги връщайте по ключ със скрипт. Проверките по-долу важат и в двата случая.
Стъпка 4: Проверете преведения файл
Сравнете превода с източника:
python3 check_i18n_json.py en.json fr.json
За да покажем какво улавя, създадохме френски файл с умишлени грешки. Той е направен на ръка, не е изход от модел. След същите предупреждения за източника, както в Стъпка 1, проверяващият отпечата:
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
Всяко от тях би се проявило като бъг в приложението: празно име, счупена връзка, срив или сурово съобщение при изобразяване на множественото число, липсващ брой глави, ограничение, сравнявано като текст. Редът INFO изброява низове, които са се върнали непроменени. Някои са наред, като маркови имена; „Save“ във френско меню не е.
Проверяващият сравнява ключове, типове стойности, нетекстови стойности, заместители ({name}, {{name}}, %s, %1$s, %@), имена на ICU аргументи, HTML тагове и URL адреси. Той не съди самия превод.
Падежите за множествено число е нормално да се променят
ICU множественото число изброява по едно съобщение за всяка категория за множествено число. Английският има две категории, one и other, но много езици имат различен набор. Добър руски превод на нашето съобщение items обикновено би използвал one, few, many и other, а японски – само other. Затова несъответствието тук не винаги е грешка.
Категориите идват от правилата за множествено число на Unicode CLDR и other е тази, която всеки език има. Това са кардиналните категории, отчетени от Intl.PluralRules в Node.js с CLDR 48:
| Език | Категории за множествено число |
|---|---|
| Английски, немски | one, other |
| Френски, испански, португалски | one, many, other |
| Руски, полски | one, few, many, other |
| Арабски | zero, one, two, few, many, other |
| Японски, китайски, корейски | друго |
Френският, испанският и португалският използват many само за много големи кръгли числа, като например един милион, така че съобщение за малки бройки обикновено може да мине без него. Проверяващият отчита липсващо other като грешка, а всяка друга промяна в категориите – като предупреждение, което да сравните с тази таблица. Можете сами да отпечатате списъка за всеки език:
node -e 'console.log(new Intl.PluralRules("ru").resolvedOptions().pluralCategories)'
На преводача се подават английските случаи, така че проверете какво е върнал. Ако руско или арабско съобщение все още има само one и other, добавете липсващите случаи на ръка или възложете това на преводач.
След това го заредете в приложението
Проверяващият доказва, че файлът е безопасен за зареждане, а не че се чете добре. Превключете приложението на новия език и разгледайте екраните: дълги думи на немски или фински, които излизат извън бутон, текст отдясно наляво на арабски или иврит, и дати или числа, които кодът ви форматира отделно от езиковия файл. Нашето ръководство за превод срещу локализация обхваща какво друго се променя между пазарите освен думите.
Чести проблеми
Преведеният файл не се зарежда в приложението ми. Пуснете проверяващия върху него. Ако проверяващият не може да го анализира, файлът е бил редактиран след превода или не е бил валиден от самото начало. Ако се анализира, потърсете редове с ERROR за ключове или типове.
Низ се показва като сурово ICU съобщение, например {count, plural, ...}. ICU синтаксисът се е счупил при превода, обикновено липсваща скоба или липсващ случай other. Копирайте структурата от източника и преведете само думите във всеки случай.
Файлът ми е YAML, .po файл или Markdown. BookTranslator приема и тях, но всеки формат има свои собствени правила. За документация вижте нашето ръководство за превод на Markdown; за уеб страници – ръководството за HTML файлове.
Мога ли да преведа само новите ключове? Не в рамките на едно качване; целият файл се превежда. Поставете новите ключове в отделен файл, преведете го и обединете резултата по ключ. Проверяващият ще потвърди, че обединеният файл съдържа всеки ключ.
Трябва ли да превеждам ключовете? Не. Ключовете са идентификатори, които кодът ви търси. Само стойностите са текст за четене от хора.
Свързани публикации





