Ми зробили перекладач документів, який не ламає форматування (і чому це зайняло довше, ніж здавалося)
Ми зробили перекладач документів, який не ламає форматування (і чому це зайняло довше, ніж здавалося)
Є один конкретний різновид роздратування, який добре знайомий усім, хто працює з документами. Ти витрачаєш дві години на те, щоб відшліфувати презентацію чи пропозицію. Заголовки вирівняні. Таблиці виглядають чисто. Відстань між секціями збалансована. Потім ти прогоняєш це через сервіс перекладу, завантажуєш результат, і раптом кожне твоє ретельне рішення про структуру просто зникає. Заголовки з'їжджають. Клітинки таблиць схлопуються. Картинки пропадають або опиняються в дивних місцях. Переноси рядків множаться без жодної причини. Перекладений документ технічно містить твої слова іншою мовою, але він уже більше не відчувається як твій документ.
Це роздратування не нове, і воно не дрібне. Це та річ, яку люди вчаться приймати, тому що більшість альтернатив гірші. Ти можеш найняти професійного перекладача і чекати кілька днів. Ти можеш копіювати все в Google Translate і потім вручну перебудовувати макет. Ти можеш платити за дорогі корпоративні інструменти, які обіцяють зберегти форматування, але все одно половину часу видають дивні артефакти. Жоден із цих варіантів не відчувається добре, тому люди просто обирають найменш поганий і йдуть далі.
Ми вирішили, що це недостатньо добре. Не тому, що ми одержимі перфекціонізмом, а тому, що ми самі постійно натикалися на цю проблему. CSS-Zone - це інструмент для людей, які звертають увагу на деталі. Наші користувачі - це дизайнери, розробники та технічні письменники, які помічають, коли радіус тіні відрізняється на два пікселі. Вони точно помічають, коли перекладений документ повертається з виглядом, ніби його пропустили через текстовий блендер. Якщо ми збиралися додати інструмент перекладу в CSS-Zone, він мав справді поважати роботу, яку люди вже вклали у свої документи.
Технічний виклик тут тонший, ніж здається. Переклад - це не просто заміна слів між мовами. Це підтримка невидимої структури, яка робить документ читабельним. Ця структура живе в дивній суміші XML, стилів, зв'язків, вбудованих зображень, визначень хедерів, правил футерів і десятків інших шматочків, які Microsoft Word вирішив з'єднати способами, які лише наполовину задокументовані. Коли ти парсиш DOCX-файл, ти не просто читаєш текст. Ти читаєш маленьку файлову систему, стиснуту в ZIP-архів, де реальний контент розкиданий по кількох XML-файлах, які посилаються один на одного через непрозорі ідентифікатори.
Наївний підхід до перекладу документів полягає в тому, щоб витягти весь текст, відправити його кудись і викинути результат назад. Це працює, якщо тебе цікавлять тільки перекладені слова на екрані. Це провалюється в той момент, коли тебе турбує будь-що інше. Жирний текст стає звичайним. Курсив зникає. Таблиці втрачають рамки. Списки перетворюються на плоскі параграфи. Хедери та футери зникають повністю. Результат технічно є документом, але це не той самий документ. Це його привид.
Founder & CEO of CSS-Zone
"Більшість інструментів перекладу ставляться до форматування як до необов'язкової прикраси. Ми ставимося до нього як до структури, яка робить документи зручними з самого початку."
Ця думка - не для драматичного ефекту. Це основний принцип дизайну, до якого ми постійно поверталися під час розробки. Форматування - це не декорація. Це інформація. Коли ти робиш слово жирним у контракті, ти не робиш його красивим. Ти сигналізуєш важливість. Коли ти використовуєш нумерований список у технічному гайді, ти не естетичуєш. Ти створюєш послідовність, на яку читачі покладаються, щоб правильно виконувати кроки. Коли ти вирівнюєш таблицю у фінансовому звіті, ти робиш цифри порівнянними з першого погляду. Усе це значення живе у форматуванні, і якщо ти його втрачаєш під час перекладу, ти втрачаєш не просто стиль. Ти втрачаєш ясність.
Перша версія нашого перекладача документів була принизливо простою. Ми використали jszip, щоб розпакувати DOCX-архів, знайшли основний документ XML, витягли текстові вузли, відправили їх у AI-модель для перекладу і записали назад. Це працювало в тому сенсі, що продукувало результат. Воно провалювалося в усіх інших сенсах. Параграфи зливалися один в одного. Стилі зникали. Зображення перетворювалися на зламаний текст-заповнювач. Ми знали, що це станеться. Але нам все одно треба було це зібрати і побачити, як воно ламається, щоб зрозуміти, де саме живе складність.
Реальна проблема була не у витяганні тексту. Реальна проблема була у збереженні невидимих зв'язків між контентом і структурою. DOCX-файл не зберігає форматування inline з текстом, як це робить HTML. Він зберігає стилі в окремому файлі визначень і посилається на них через ID. Якщо ти хочеш зберегти параграф жирним після перекладу, ти не можеш просто запам'ятати, що він був жирним. Ти маєш запам'ятати, який ID стилю зробив його жирним, зберегти цей ID через процес перекладу, переконатися, що визначення стилю все ще існує у вихідному файлі, і правильно все перепідключити. Та сама логіка застосовується до таблиць, зображень, хедерів, футерів, гіперпосилань, закладок і кожного іншого шматка структурованого контенту, який підтримує Word.
Зображення були особливо дратівливими. Коли ти кидаєш зображення у Word-документ, Word не просто вбудовує його inline. Він створює окремий файл зображення всередині DOCX-архіву, генерує унікальний ID зв'язку, посилається на цей ID в основному XML документа, зберігає метадані розміру та позиції, і іноді розділяє зображення на кілька файлів, якщо воно з'являється в хедерах або футерах. Перекласти навколишній текст легко. Переконатися, що зображення залишається в правильному місці, з правильним розміром, в правильній секції, не ламаючи жодне з цих внутрішніх посилань? Це зайняло три окремі переписування, перш ніж ми зробили це стабільним.
Таблиці були ще гіршими. Word-таблиці - це не прості сітки. Вони мають об'єднані клітинки, вкладені таблиці, умовні рамки, специфічний padding для клітинок, правила вирівнювання, які залежать від стилів параграфа, і розрахунки ширини, які посилаються на поля сторінки. Коли ти перекладаєш текст всередині клітинки таблиці, довжина тексту змінюється. Різні мови мають різну середню довжину слів. Тризначний англійський заголовок може стати семислівним німецьким заголовком. Якщо ти не коригуєш ширину колонок розумно, таблиця або виходить за межі сторінки, або виглядає абсурдно розтягнутою. Ми в підсумку зібрали маленький движок перерахунку макета, який оцінює довжину перекладеного тексту і коригує відстані відповідно. Він не ідеальний, але достатньо хороший, щоб більшість таблиць все ще виглядали розумно після перекладу.
Хедери та футери концептуально прості, але технічно прискіпливі. Вони живуть в окремих XML-файлах, які посилаються на основний документ через mapping зв'язків. Якщо ти перекладеш текст у хедері, але забудеш оновити файл зв'язків, Word або нічого не покаже, або викине криптичну помилку, коли ти спробуєш відкрити документ. Ми витратили принизливу кількість часу на дебаг випадків, коли перекладений документ виглядав нормально в нашому preview, але не відкривався у Word, тому що ми пропустили одне obscure посилання зв'язку, заховане у файлі під назвою _rels/document.xml.rels. Специфікація DOCX - це сотні сторінок, і більшість з них - не про happy path. Це про edge cases, legacy-сумісність і obscure можливості, які ніхто не використовує, але які все одно мають працювати.
AI-частина перекладу була майже легкою порівняно з усім цим. Ми використовуємо Gemini для фактичної роботи перекладу. Промпт простий: зберігай усі HTML-теги, підтримуй форматування, перекладай лише текстовий контент, зберігай той самий тон. Gemini добре з цим справляється. Він розуміє, що <strong>important</strong> має стати <strong>важливо</strong> українською, а не важливо без тегів. Він поважає переноси рядків, обережно обробляє технічні терміни і не намагається переписувати речення у щось більш "природне", що змінює значення. Якість порівнянна з професійним перекладом для більшості бізнес-документів, і це миттєво замість очікування днями.
Ми додали визначення мови, щоб людям не доводилося вручну вказувати вихідну мову. Це було менше про зручність і більше про зменшення помилок. Якщо хтось завантажує російський документ, але випадково вибирає українську як вихідну, переклад буде сміттям. Автовизначення не ідеальне, але воно ловить більшість очевидних помилок. Для крайніх випадків, де мова неоднозначна або змішана, користувачі все ще можуть вручну перевизначити detection.
Система квот навмисно щедра для безкоштовних користувачів, тому що ми вважаємо, що цей інструмент справді корисний для людей, які не мають бюджетів на переклад. П'ять документів на день достатньо для випадкового використання. Якщо тобі потрібно більше, Pro-план дає безлімітні переклади, що має сенс для професійних workflow, де ти можеш перекладати десятки контрактів, гайдів або звітів на тиждень. Ми не намагаємося гейткіпити функціональність. Нам просто потрібен якийсь розумний ліміт, щоб запобігти зловживанням і тримати витрати на сервер керованими.
Одне дизайнерське рішення, про яке ми довго дебатували, було чи підтримувати інші формати документів крім DOCX. PDF - очевидний кандидат. У всіх є PDF. Але PDF - це фундаментально ворожий формат для редагування. Він розроблений для відображення, а не для структури. Витягувати текст з PDF можливо, але зберігати макет майже неможливо, якщо ти не готовий інвестувати місяці в повноцінний PDF-рендер движок. Навіть тоді результати непослідовні, тому що PDF можуть генеруватися тисячею різних способів, і немає єдиного стандарту для того, як контент має бути закодований. Ми вирішили, що DOCX - правильна стартова точка, тому що він редагований, широко використовується в професійних контекстах і має (переважно) задокументовану структуру. Якщо достатньо людей попросить підтримку PDF, ми повернемося до цього, але наразі DOCX покриває більшість реальних use cases.
Ще одна річ, яку ми навмисно не робили: машинне навчання для оптимізації макета. Багато інструментів перекладу використовують ML-моделі для передбачення оптимальної ширини колонок, відстаней параграфів і розміщення зображень на основі перекладеного контенту. Це звучить розумно, але на практиці часто продукує макети, які виглядають алгоритмічно дивно. Люди мають сильні інтуїції про те, що виглядає збалансовано, і ML-прогнози не завжди відповідають цим інтуїціям. Ми вирішили використовувати простіші евристики, які передбачувані і легко зрозуміти. Якщо колонці треба бути ширшою, тому що перекладений текст довший, ми робимо її ширшою пропорційно. Якщо параграфу треба більше вертикального простору, ми додаємо простір на основі кількості рядків. Це не fancy, але це надійно, і користувачі можуть виправити edge cases вручну, якщо потрібно.
Найскладнішою частиною збирання цієї можливості була не технічна складність. Це була боротьба зі спокусою додати п'ятдесят більше опцій і налаштувань. Ми могли б додати контролі для стилю перекладу, рівня формальності, регіональних варіантів мови, кастомних глосаріїв, batch-обробки, історії версій, колаборативних review-workflow і десятка інших можливостей, які деяка підмножина користувачів полюбила б. Але кожна можливість додає когнітивне навантаження. Кожна опція - це рішення, яке користувачі мають прийняти перед тим, як отримати цінність. Ми зрізали інтерфейс до абсолютного мінімуму: завантажити документ, вибрати цільову мову, перекласти. Просунуті користувачі можуть коригувати визначення вихідної мови або перемикати збереження форматування, якщо хочуть, але дефолтний flow - це просто три кліки. Це стримування було болючим, але необхідним.
Результат - це інструмент, який робить одну річ добре замість двадцяти речей адекватно. Ти завантажуєш DOCX-документ. Він перекладається зі збереженням форматування. Ти завантажуєш його і продовжуєш працювати. Якість достатньо хороша, щоб більшість людей могли використовувати перекладений документ відразу без ручного cleanup. Це стандарт, до якого ми цілилися, і після кількох місяців ітерацій ми насправді його досягли. Не ідеально, але достатньо послідовно, щоб нам було комфортно shipити його публічно.
Є ще edge cases. Складні вкладені таблиці іноді мають незначні проблеми вирівнювання. Кастомні шрифти іноді fallback до дефолтних. Документи з важким використанням макросів можуть втратити деяку динамічну поведінку. Ми документуємо ці обмеження ясно, тому що ми б радше були чесними про те, що інструмент може і не може робити, ніж overрromise і розчаровувати людей. Для переважної більшості бізнес-документів, технічних гайдів, звітів і пропозицій перекладач працює як очікується. Цього достатньо.
Один несподіваний бенефіт збирання цього інструменту був у тому, наскільки це змусило нас покращити нашу інфраструктуру. Переклад вимагає server-side обробки, що означало, що нам треба було зібрати належну job queue, імплементувати rate limiting, додати кращий error handling і масштабувати наш API-шар для обробки довготривалих запитів. Ці покращення розходяться на кожну іншу частину CSS-Zone. Генератор градієнтів швидший. Shadow previewer стабільніший. Вся платформа відчувається міцнішою, тому що ми інвестували в негламурну backend-роботу, яку вимагав переклад.
Ми також багато чого навчилися про те, що реальним користувачам насправді потрібно versus що ми припускали, що їм потрібно. На ранніх етапах ми думали, що люди захочуть детальні логи перекладу, які показують точно, які фрази були перекладені і як. Ми зібрали цю можливість. Майже ніхто її не використовував. Що люди насправді хотіли, це простий progress bar і ясна індикація того, коли завантаження готове. Урок тут не в тому, що користувачі несофістиковані. Це в тому, що більшість людей просто хочуть, щоб їхня робота була зроблена ефективно без необхідності думати про механізм під капотом. Найкращі інструменти невидимі, поки тобі не потрібно, щоб вони були видимими.
Перекладач документів тепер live на css-zone.com/document-translator. Він доступний дванадцятьма мовами: англійською, українською, російською, німецькою, французькою, іспанською, італійською, польською, португальською, японською, китайською і корейською. Інтерфейс повністю локалізований, тому українські користувачі бачать український текст, а англійські користувачі бачать англійський текст. Ця маленька деталь має більше значення, ніж може здатися. Переклад і так когнітивно вимогливий. Змушувати користувачів навігувати незнайомим інтерфейсом чужою мовою під час спроби перекласти важливі документи - це просто жорстоко. Ми локалізували все, тому що саме це робить шанобливе програмне забезпечення.
Це не найгламурніша можливість, яку ми коли-небудь збирали. Вона не буде трендити в соцмережах або виграти дизайнерські премії. Але вона вирішує реальну проблему для реальних людей, і вона робить це без змушення їх жертвувати якістю, яку вони вже інвестували у свої документи. Це той вид роботи, який відчувається вартим робити, навіть коли це займає довше, ніж очікувалося, і включає набагато більше XML-парсингу, ніж будь-хто хотів мати справу. Ми зібрали це, тому що нам самим це було потрібно, і тому що ми думаємо, що інші люди, які дбають про деталі, оцінять наявність одного меншого фруструвального інструменту в їхньому workflow.
Якщо ти регулярно перекладаєш документи і втомився від того, що руйнування макета є ціною багатомовної роботи, спробуй це. Це безкоштовно для випадкового використання і безлімітно для Pro-підписників. Ми думаємо, що це добре. Якщо ти знайдеш edge cases або способи його зламати, дай нам знати. Ми це виправимо. Саме так інструменти стають кращими.

Коментарі
0Щоб залишати коментарі, увійдіть у свій акаунт.