Перевод более длинных текстов (шаблоны просмотра и электронной почты) с помощью gettext
Я разрабатываю многоязычное веб-приложение PHP, и у меня есть длинные (-ish) тексты, которые мне нужно перевести с помощью gettext. Это шаблоны электронной почты (обычно короткие, но несколько строк) и части шаблонов представлений (более длинные описательные блоки текста). Эти тексты будут включать в себя некоторые простые HTML (например, жирный/курсивный для акцента, возможно, ссылка здесь или там). Шаблоны представляют собой PHP-скрипты, выходные данные которых записаны.
Проблема в том, что gettext кажется очень неуклюжим для обработки более длинных текстов. Более длинные тексты, как правило, будут иметь больше изменений с течением времени, чем короткие тексты - я могу либо сменить msgid, и обязательно обновить его во всех переводах (может быть много работы и очень подвержено ошибкам, когда долгое время существует), или я могу сохранить msgstr "Не изменяйте и изменяйте только переводы (которые оставляют в шаблонах устаревшие тексты). Кроме того, я видел совет против включения HTML в строки gettext, но, избегая этого, он разбил бы один естественный фрагмент текста на множество кусков, что станет еще большим кошмаром для перевода и сборки, и я также видел совет против ненужное разбиение строк gettext на отдельные msgid.
Другой подход, который я вижу, заключается в том, чтобы игнорировать gettext в целом для этих более длинных текстов и отделить эти блоки во внешних подтемах для каждого языкового стандарта и просто включить один из них для текущей локали. Недостатком является то, что я отделяю усилия перевода между файлами gettext.po и отдельными шаблонами, расположенными в совершенно другом месте.
Так как это приложение будет использоваться в качестве отправной точки для других приложений в будущем, я пытаюсь найти лучший подход в долгосрочной перспективе. Мне нужны рекомендации для лучших практик в таких сценариях. Как вы реализовали подобные случаи? Что оказалось работать и что получилось плохой идеей?
Ответы
Ответ 1
Здесь рабочий процесс, который я использовал, на очень сильно зараженном сайтом, который имел около нескольких десятков длинных блоков стилизованного текстового контента, переведен на шесть языков:
- Выберите текстовый язык разметки (мы использовали Markdown)
- Для длинных строк используйте фиксированные идентификаторы сообщений, например "About_page_intro_markdown", которые:
- описывает намерение текста
- дает понять, что он будет интерпретироваться в формате уценки
- Приложите наше приложение к строкам "* _markdown" соответствующим образом, убедившись, что разрешите только несколько безопасных HTML-тегов
- Создайте инструмент для переводчиков, который:
- показывает, что их Markdown отображается в реальном времени (вроде Markdown dingus)
- упрощает для них возможность увидеть теперь авторитарный перевод текста на базовом языке (поскольку это уже не в
msgid
)
- Научите переводчиков, как использовать новый рабочий процесс
Плюсы этого рабочего процесса:
- Идентификаторы сообщений не изменяются все время
- Поскольку переводчики редактируются в безопасном синтаксисе более высокого уровня, сложно испортить HTML
- Нетехнические переводчики посчитали его очень легким для записи в Markdown, vs. HTML
Недостатки этого рабочего процесса:
- Наличие статических неизменных идентификаторов сообщений означает, что изменения в тексте должны передаваться вне диапазона (что мы все равно будем делать, так как в длинном тексте могут возникать вопросы о тональности или акценте)
Я очень доволен тем, как этот рабочий процесс работал на нашем веб-сайте, и он абсолютно рекомендовал бы его и снова использовал. Потребовалось пару дней, чтобы начать, но было легко построить, обучить и запустить.
Надеюсь, что это поможет, и удачи в вашем проекте.
Ответ 2
У меня только была эта конкретная проблема, и я считаю, что я решил это элегантным способом.
Проблема: мы хотели использовать Gettext в PHP и использовать первичные языковые строки в качестве переводов ключей. Однако для больших блоков HTML (с h1, h2, p, a и т.д.) Я либо должен:
- Создайте перевод для каждого тега с контентом.
или
- Поместите весь блок с тегами в один перевод.
Ни один из этих вариантов не понравился мне, поэтому я это сделал:
- Сохраняйте простые строки ( "ОК", "Добавить", "Подтвердить", "Мое удивительное приложение" ) в качестве обычных записей Gettext.po с исходным текстом в качестве ключа
-
Записывайте контент (большие текстовые блоки) в уценку и храните их в файлах.
Файлы примеров будут /homepage/content.md
(первичный/исходный текст), /homepage/content.da-DK.md
, /homepage/content.de-DE.md
-
Напишите класс, который извлекает файлы содержимого (для текущей локали) и анализирует его. Затем я использовал его как:
<?=Template::getContent("homepage/content")?>
Однако, как насчет динамического большого текста? Просто. Используйте шаблонный двигатель. Я решил Smarty и использовал его в моем классе Template
.
Теперь я могу использовать логику шаблонов. в пределах уценки! Насколько это удивительно?!
Затем появилась сложная часть.
Чтобы контент выглядел хорошо, иногда вам нужно структурировать свой HTML по-разному. Рассмотрите область кампании с 3 "ящиками функций" под ней. Простое решение: укажите файл для области кампании и по одному для каждого из трех полей.
Но я мог бы сделать лучше.
Я написал быстрый синтаксический анализатор блоков, поэтому я бы написал весь контент в одном файле, а затем каждый отдельный рендеринг каждого блока.
Файл примера:
[block campaign]
Buy this now!
=============
Blaaaah... And a smarty tag: {$cool}
[/block]
[block feature 1]
Feature 1
---------
asdasd you get it..
[/block]
[block feature 2] ...
И так я бы сделал их в разметке:
<?php
// At the top of the document...
// Class handles locale. :)
$template = Template::getContent("homepage/content", [
"cool" => "Smarty variable! AWESOME!"
]);
?>
...
<title><?=_("My Awesome App")?></title>
...
<div class="hero">
<!-- Template data already processed! :) -->
<?=$template->renderBlock("campaign")?>
</div>
<div class="featurebox">
<?=$template->renderBlock("feature 1")?>
</div>
<div class="featurebox">
<?=$template->renderBlock("feature 2")?>
</div>
Я боюсь, что не могу предоставить какой-либо исходный код, поскольку это было для проекта компании, но я надеюсь, что вы поняли эту идею.
Ответ 3
gettext не был предназначен для перевода больших фрагментов текста.
fwiw Я включил базовый HTML (сильный, а и т.д.) в строки gettext, так как я был уверен, что наши переводчики знают, что они делают (в основном правильно) и что переводы будут хорошо протестированы.
Я пробовал подход разбивать текст на одну строку за абзац. Грубо, поскольку это выглядит странно, если там есть один абзац английского языка в середине текста. Там, где одна из этих строк изменилась, это означало, что нам пришлось ждать перевода, прежде чем выпускать новую версию, что привело нас к замедлению. С положительной стороны переводчикам легко понять, какая часть текста изменилась. Этот подход хорошо зарекомендовал себя для одного приложения, с которым я его пробовал.
Разделение текста на внешние местоположения также работало, но это вызвало накладные расходы на управление, а не только файл .po или два, была целая куча другого текста, который должен был быть вручную сравнен с английской версией и обновлен соответствующим образом, Это можно сделать, если вы не забыли предоставить заметки своим переводчикам, объясняющие, где и в чем разница в английской версии.
Я по-прежнему не продаюсь ни по одному из подходов.