BookTranslator
BookTranslator

چگونه یک فایل زبان JSON را بدون شکستن کلیدها یا جای‌نگهدارها ترجمه کنیم

ببینید کدام مقادیر در یک فایل en.json ترجمه می‌شوند، یک مترجم فایل چه چیزهایی را بازنویسی می‌کند (کامنت‌ها، ترتیب کلیدها، شناسه‌های بزرگ)، و چگونه جای‌نگهدارها، جمع‌های ICU و کلیدها را با یک اسکریپت رایگان و یک فایل تست بررسی کنید.

BookTranslator

BookTranslator Team

14 دقیقه مطالعه

برای ترجمه یک فایل زبان 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>."ترجمه می‌شود؛ تعداد تگ‌ها پس از ترجمه بررسی می‌شودنام و تعداد تگ‌ها (بررسی‌کننده این کار را انجام می‌دهد)
نشانی‌های اینترنتی که به صورت متن ذخیره شده‌اند"https://example.com/help"برای ترجمه ارسال می‌شودکه بدون تغییر بازگشته است
مقادیری که هیچ حرفی ندارند"2.4.1", "—", ""بدون تغییر باقی می‌مانندهیچ‌کدام
اعداد، true/false، null20, trueبدون تغییر باقی می‌مانندشناسه‌های بسیار بزرگ (به پایین مراجعه کنید)
آرایه‌های رشته‌ای["Open", "Save", "Export as EPUB"]در فایل ترجمه‌شده ترجمه می‌شود؛ در فایل دوزبانه ترجمه‌نشده باقی می‌ماندفایل دوزبانه، اگر از آن استفاده کنید
توضیحات (JSONC)// Shown on the home screenحذف می‌شود. اگر یک مقدار نیز شامل // باشد، ممکن است فایل بارگذاری نشودپیش از بارگذاری، توضیحات را حذف کنید

باقی این راهنما نشان می‌دهد هر ردیف از کجا می‌آید و چه باید کرد.

مرحله ۱: فایل منبع را پیش از بارگذاری بررسی کنید

بررسی‌کننده را روی فایلی که قصد ترجمه‌اش را دارید اجرا کنید. فقط به پایتون ۳ نیاز دارد و نه چیز دیگری:

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

دو هشدار و یادداشت مربوط به کلیدهای شبه‌عدد صحیح، هر کدام با تغییری مطابقت دارند که هنگام عبور فایل آزمایشی ما از مترجم مشاهده کردیم. اگر فایل شما هیچ‌کدام را دریافت نکرد، می‌توانید به مرحله ۳ بروید.

بررسی‌کننده همچنین فایلی را که JSON سخت‌گیرانه نیست، مانند فایلی با توضیحات یا ویرگول‌های انتهایی، رد می‌کند، زیرا مشکل بعدی همان است.

آنچه از فایل آزمایشی ما بازگشت

آزمایش در ۲ نوامبر ۲۰۲۶، در برابر پردازش فعلی JSON در بک‌اند BookTranslator اجرا شد. آزمایش به جای فراخوانی یک مدل، هر مقداری را که برای ترجمه ارسال می‌شد با [ZH] به‌علاوه متن اصلی جایگزین کرد. این کار نتیجه را قابل پیش‌بینی نگه می‌دارد: هر چیزی که [ZH] در ابتدای آن باشد ارسال شده و هر چیزی که نداشته باشد ارسال نشده است. هر دو خروجی منتشر شده‌اند: فایل ترجمه‌شده و فایل دوزبانه.

فایل ترجمه‌شده

همه کلیدها بدون تغییر بازگشتند و فایل همچنان قابل تجزیه بود. مقادیر دارای حروف ارسال شدند، از جمله {name}، %s، پیام ICU، تگ <b> و نشانی راهنما. رشته نسخه "2.4.1"، خط تیره و رشته خالی ارسال نشدند، چون هیچ حرفی ندارند. اعداد و مقادیر بولی دست‌نخورده ماندند.

چهار چیز دیگر تغییر کرد:

  1. یک رشته به کلید اشتباه رفت. در آزمایش ما، فایل یک کلید تخت "error.network" با متن "اتصال خود را بررسی کنید." داشت و همچنین یک کلید تودرتوی "error": { "network": "Network error" }. مترجم هر رشته را با مسیرش که با نقطه بین بخش‌ها جدا شده شناسایی می‌کند، بنابراین هر دو رشته یک آدرس یکسان داشتند: error.network. در خروجی، هر دو کلید ترجمه «خطای شبکه» را نگه داشتند. «اتصال خود را بررسی کنید.» از بین رفت. این مشکل به وجود هر دو سبک در یک فایل نیاز دارد که نادر است، اما بی‌صدا شکست می‌خورد. بررسی‌کننده پیش از بارگذاری درباره آن هشدار می‌دهد.
  2. کلیدهای شبیه عدد بازآرایی شدند. "steps": { "10": ..., "2": ..., "1": ... } به صورت "1"، "2"، "10" بازگشت. جاوااسکریپت هنگام بازسازی یک شیء همیشه کلیدهای شبیه عدد را ابتدا و به ترتیب عددی فهرست می‌کند. کلیدها و مقادیر همچنان مطابقت دارند، بنابراین برنامه شما سالم است، اما تفاوت با فایل مبدأ پرنویز خواهد بود.
  3. یک شناسه بزرگ دقت خود را از دست داد. 9007199254740993 به صورت 9007199254740992 بازگشت. جاوااسکریپت اعداد را به صورت ممیز شناور ۶۴ بیتی ذخیره می‌کند و اعداد صحیح بالاتر از 2^53 را نمی‌توان همگی دقیق نمایش داد (MDN درباره Number.MAX_SAFE_INTEGER). شناسه‌های طولانی را به صورت رشته ذخیره کنید یا آن‌ها را از فایل زبان بیرون نگه دارید.
  4. قالب‌بندی بازنویسی شد. خروجی از تورفتگی دو فاصله‌ای استفاده می‌کند و با یک خط جدید پایان می‌یابد. اگر مبدأ شما از تب یا چهار فاصله استفاده می‌کرد، انتظار تغییرات فضای خالی را در تفاوت داشته باشید.

فایل آزمایشی ما کلید تکراری نداشت، اما دانستن درباره آن‌ها ارزشمند است: تجزیه‌کننده JSON جاوااسکریپت فقط آخرین مقدار را برای یک کلید تکراری نگه می‌دارد، بنابراین متن قبلی هرگز ترجمه نمی‌شود. برنامه شما همان آخرین مقدار را بارگذاری می‌کند، پس چیز قابل مشاهده‌ای خراب نمی‌شود، اما بررسی‌کننده کلیدهای تکراری را فهرست می‌کند تا بتوانید آن‌ها را پاک‌سازی کنید.

فایل دوزبانه

فایل دوزبانه هر مقدار اصلی را نگه می‌دارد و یک کلید خواهر با _translated در انتها اضافه می‌کند:

"greeting": "Welcome back, {name}!",
"greeting_translated": "[ZH] Welcome back, {name}!",

این برای بازبینی خوب است، چون مبدأ و ترجمه کنار هم قرار می‌گیرند. اما فایلی نیست که برنامه شما بتواند بارگذاری کند، چون هر کلید اکنون یک دوقلو دارد. از فایل ترجمه‌شده در برنامه خود استفاده کنید.

یک شکاف: رشته‌های داخل آرایه‌ها کلید خواهر _translated نمی‌گیرند، چون آیتم‌های آرایه کلیدی برای افزودن ندارند. در آزمایش ما، "menu": ["Open", "Save", "Export as EPUB"] در فایل دوزبانه به انگلیسی بازگشت، اما در فایل ترجمه‌شده ترجمه شده بود. اگر از فایل دوزبانه بازبینی می‌کنید، آرایه‌ها را در فایل ترجمه‌شده بررسی کنید.

فایل‌های دارای توضیح

بسیاری از پروژه‌ها توضیح‌ها را در فایل‌های زبان خود نگه می‌دارند (JSONC)، که JSON سخت‌گیرانه آن را مجاز نمی‌داند. مترجم ابتدا JSON سخت‌گیرانه را امتحان می‌کند. اگر شکست خورد، توضیح‌ها و ویرگول‌های انتهایی را حذف می‌کند و دوباره تلاش می‌کند. حذف توضیح‌ها یعنی پاک کردن همه چیز پس از // در یک خط، و این شامل // در https:// می‌شود.

فایل ما با یک توضیح و یک نشانی اصلاً بارگذاری نشد؛ تجزیه در اولین توضیح شکست خورد. فایلی با توضیح اما بدون // در هیچ مقدار، به خوبی بارگذاری شد و توضیح‌ها از خروجی حذف شدند.

پس: اگر فایل شما توضیح دارد، پیش از بارگذاری آن‌ها را حذف کنید، یا نسخه‌ای با توضیح‌ها نگه دارید و بپذیرید که ترجمه آن‌ها را نخواهد داشت.

گام ۲: آماده‌سازی فایل

می‌توانید بیشتر این مشکلات را پیش از ترجمه برطرف کنید:

  • آن را JSON سخت‌گیرانه کنید. توضیح‌ها و ویرگول‌های انتهایی را حذف کنید. اگر ابزار ساخت شما JSONC را می‌خواند، فایل دارای توضیح را به عنوان مبدأ نگه دارید و یک نسخه تمیز برای ترجمه صادر کنید.
  • از یک سبک کلید استفاده کنید. یا کلیدها را تودرتو کنید یا آن‌ها را با نقطه تخت کنید، نه هر دو در یک فایل. اگر از i18next استفاده می‌کنید، گزینه keySeparator آن کنترل می‌کند که نقطه‌ها در کلیدها چگونه خوانده شوند، پس پیش از تخت کردن هر چیزی آن تنظیم را بررسی کنید.
  • داده‌های غیرمتنی را بیرون ببرید. شناسه‌ها، نشانی‌ها، پرچم‌های ویژگی و محدودیت‌ها به پیکربندی تعلق دارند، نه فایل زبان. اگر نشانی‌ای باید بماند، آن را نگه دارید، اما انتظار داشته باشید پس از ترجمه آن را بررسی کنید. راهنمای عدم ترجمه ما پوشش می‌دهد که چگونه تصمیم بگیرید چه چیز دیگری باید به زبان اصلی بماند.
  • جانگهدارها را همه‌جا یکسان بنویسید. یک سبک، مانند {name}، آسان‌تر از ترکیبی از {name}، {{name}} و %s قابل بررسی است.

گام ۳: ترجمه کل فایل

فایل تمیزشده را در مترجم اسناد BookTranslator بارگذاری کنید، که .json را همراه با سایر قالب‌های بومی‌سازی و متن ساختاریافته‌ای که می‌پذیرد فهرست می‌کند. قیمت پیش از پرداخت نمایش داده می‌شود. وقتی کار تمام شد، صفحه تاریخچه شما فایل ترجمه‌شده و فایل دوزبانه را به صورت دانلودهای جداگانه ارائه می‌دهد.

دو نکته درباره نحوه ترجمه متن بر نتیجه تأثیر می‌گذارد:

  • مدل کلیدهای شما را نمی‌بیند. هر مقدار به صورت یک بخش شماره‌گذاری‌شده و بدون نام کلید ارسال می‌شود. اگر "button.open" و "status.open" هر دو «Open» باشند، مدل هیچ راهی ندارد که بداند یکی فعل است و دیگری صفت. رشته‌های کوتاه و مبهم همان‌هایی هستند که باید دستی بررسی شوند.
  • هر مقدار به تنهایی ترجمه می‌شود. هیچ چیزی دو کلید را به هم پیوند نمی‌دهد، بنابراین یک واژه در دو جای مختلف می‌تواند به دو شکل متفاوت برگردد و واژه‌ای که به دو ترجمه متفاوت نیاز دارد ممکن است یکسان برگردد. واژه‌نامه خودکار اختیاری BookTranslator نام‌ها، مکان‌ها و اصطلاحات تخصصی را جمع‌آوری و یکدست نگه می‌دارد، اما نمی‌توانید ترجمه‌های ثابت خود را به آن بدهید. برای اصطلاحاتی که باید دقیقاً به یک شکل ترجمه شوند، فهرستی از اصطلاحات نگه دارید و آن رشته‌ها را پس از ترجمه بررسی کنید؛ راهنمای واژه‌نامه ما توضیح می‌دهد چگونه یکی را برنامه‌ریزی کنید.

تگ‌های HTML درون‌خطی پس از ترجمه شمرده می‌شوند و بخشی که تگ‌هایش مطابقت نداشته باشد دوباره تلاش می‌شود. جای‌نگهدارهای آکولاد، جای‌نگهدارهای به سبک %s و نحو ICU به عنوان بخشی از متن ارسال می‌شوند اما به همان شکل بررسی نمی‌شوند. مرحله ۴ را روی هر ترجمه اجرا کنید.

اگر ترجیح می‌دهید با یک مدل چت یا یک مدل محلی ترجمه کنید، فقط مقادیر را بفرستید، هرگز فایل خام را نه، و آن‌ها را با یک اسکریپت بر اساس کلید برگردانید. بررسی‌های زیر در هر دو حالت اعمال می‌شوند.

مرحله ۴: بررسی فایل ترجمه‌شده

ترجمه را با منبع مقایسه کنید:

python3 check_i18n_json.py en.json fr.json

برای نشان دادن آنچه می‌گیرد، یک فایل فرانسوی با خطاهای عمدی ساختیم. این فایل دست‌ساز است، نه خروجی مدل. پس از همان هشدارهای منبع مانند مرحله ۱، بررسی‌کننده چاپ کرد:

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. بنابراین عدم تطابق در اینجا همیشه خطا نیست.

دسته‌ها از قواعد جمع 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.

آیا می‌توانم فقط کلیدهای جدید را ترجمه کنم؟ نه در یک بارگذاری؛ کل فایل ترجمه می‌شود. کلیدهای جدید را در یک فایل جداگانه قرار دهید، آن را ترجمه کنید و نتیجه را بر اساس کلید ادغام کنید. بررسی‌کننده تأیید می‌کند که فایل ادغام‌شده همه کلیدها را دارد.

آیا باید کلیدها را ترجمه کنم؟ نه. کلیدها شناسه‌هایی هستند که کد شما جستجو می‌کند. فقط مقادیر متن برای خواندن افراد هستند.

مطالب مرتبط