Сайт Anivisual.net закрыт

Он продолжит функционировать в виде архива. Новые материалы добавлять нельзя.

Многоязычность в Ren'Py: можно ли сделать лучше?

Многоязычность в Ren'Py: можно ли сделать лучше?

Что у нас есть

Любой, кто задумывался о переводе новеллы на иностранный язык или с него, знает, что в Ren'Py встроена мощная система интернационализации. Возможности её не ограничиваются простым переводом текста — она позволяет переводить надписи на иллюстрациях, заменять шрифты и даже встраивать в сценарий произвольный код. «Pretty much everything your game needs!» — утверждает Эйлин, и, пожалуй, она недалека от истины. В этом хорошем гайде человек объясняет, как ею пользоваться.

К сожалению, есть в бочке и ложка дёгтя: к началу работы над переводами ваша игра должна быть уже полностью завершена. Если же вы потом захотите что-то поменять в сценарии, вас ждёт много головной боли — тем больше, чем крупнее правки.

Мы, в частности, столкнулись с этой проблемой при создании новеллы «Всё в порядке!». Одновременное написание русской и английской версий грозило стать, мягко говоря, не самым приятным занятием.

Позвольте мне рассказать, в чём дело и к чему всё это в итоге привело.

Что оно нам даёт

Возьмём для примера небольшой отрывок. Скажем, вот этот:
Код
label smoothstart:
    "На всякий случай проверил часы. Опасения не подтвердились — свою станцию не проехал. Да и прочих не так много успел."
    "Я зевнул, да так сладко и от души, что прослезился даже. Шли вторые сутки без сна."
    "Всю ночь я вчера доводил до ума статьи, упиваясь крепчайшим чаем, но всё-таки сделал работу на два дня вперед. Чтобы выкроить их для поездки."

Он переведён на английский язык в файле game/tl/english/script.rpy. Но время от времени вносятся правки (это неизбежно) — хотя далеко не всегда они требуют обновления перевода и не всегда они затрагивают даже сам текст. Чуть позже наш отрывок мог бы выглядеть как-нибудь так:
Код
label smoothstart:
    "На всякий случай проверил часы. Опасения не подтвердились — свою станцию не проехал. Да и прочих не так много успел." # ⑴
    "Я зевнул, да так широко, что прослезился даже. Шли вторые сутки без сна." # ⑵
    "А то и третьи." # ⑶
    jump hard_job

label hard_job:
    "Всю ночь я вчера доводил до ума статьи, упиваясь крепчайшим чаем, но всё-таки сделал работу на два дня вперед. Чтобы выкроить их для поездки." # ⑷

Рассмотрим подробнее:

  • ⑴ — без изменений;
  • ⑵ — заменена пара слов, смысл остался тем же;
  • ⑶ — новая строчка;
  • ⑷ — без изменений, но под другой меткой.

Что же станет с нашим файлом перевода, если мы нажмём кнопку Generate Translations в Ren'Py? Мы обнаружим там следующее:
Код
# game/script.rpy:633
translate english smoothstart_0c5ceafe:

    # "На всякий случай проверил часы. Опасения не подтвердились — свою станцию не проехал. Да и прочих не так много успел."
    "I checked my watch: no, I hadn’t missed my station yet. Unfortunately, not many others either."

# game/script.rpy:634
translate english smoothstart_00986b0e:

    # "Я зевнул, да так сладко и от души, что прослезился даже. Шли вторые сутки без сна."
    "I yawned so heartily that a tear came out. It was a second day without sleep."

# game/script.rpy:635
translate english smoothstart_09feead2:

    # "Всю ночь я вчера доводил до ума статьи, упиваясь крепчайшим чаем, но всё-таки сделал работу на два дня вперед. Чтобы выкроить их для поездки."
    "The night before I had been finishing my articles, while helping myself with the strongest tea I could brew, and finally managed to do the work for the coming two days. To free them up for this trip."

# TODO: Translation updated at 2019-07-13 12:34

# game/script.rpy:634
translate english smoothstart_ceb6699e:

    # "Я зевнул, да так широко, что прослезился даже. Шли вторые сутки без сна."
    ""

# game/script.rpy:635
translate english smoothstart_451bdca2:

    # "А то и третьи."
    ""

# game/script.rpy:639
translate english hard_job_09feead2:

    # "Всю ночь я вчера доводил до ума статьи, упиваясь крепчайшим чаем, но всё-таки сделал работу на два дня вперед. Чтобы выкроить их для поездки."
    ""

  • • Со строчкой ⑴ ничего не случилось — что ж, спасибо и на том.
  • • Ren'Py дописал шаблоны для строк ⑵, ⑶ и — зачем-то — ⑷.
  • • Переводы строк ⑵ и ⑷ сбросились: если запустить игру, их видно не будет.
  • • Шаблоны изменённых строчек дописываются исключительно в конец файла. После нескольких запусков хронологический порядок угадывается с большим трудом.
  • • Невозможно понять, какие переводы актуальны, а какие — нет.

Очевидно, инструмент попросту не предназначен для работы в таких условиях.

А значит, нужно создать новый.

Что мы хотим

Уже через две недели после постановки задачи был готов рабочий прототип. Ещё две ушли на совершенствование интерфейса и отлов хитрых багов. Сейчас мы считаем программу достаточно стабильной и выкладываем на всеобщее обозрение. Скачать 7z-архив можно с Гитхаба; запускать следует bin/renpy-update-tl-gui.exe. А выглядит это так:

Интерфейс программы

Давайте взглянем, как он справится с нашим примером:
Код
# game/script.rpy:633
translate english smoothstart_0c5ceafe:

    # "На всякий случай проверил часы. Опасения не подтвердились — свою станцию не проехал. Да и прочих не так много успел."
    "I checked my watch: no, I hadn’t missed my station yet. Unfortunately, not many others either."

# game/script.rpy:634
translate english smoothstart_ceb6699e:

    # "Я зевнул, да так широко, что прослезился даже. Шли вторые сутки без сна."
    # "Я зевнул, да так сладко и от души, что прослезился даже. Шли вторые сутки без сна." # TODO: OUTDATED; delete this line when no longer needed.
    "I yawned so heartily that a tear came out. It was a second day without sleep."

# game/script.rpy:635
# TODO: NEW.
translate english smoothstart_451bdca2:

    # "А то и третьи."
    ""

# game/script.rpy:639
translate english hard_job_09feead2:

    # "Всю ночь я вчера доводил до ума статьи, упиваясь крепчайшим чаем, но всё-таки сделал работу на два дня вперед. Чтобы выкроить их для поездки."
    "The night before I had been finishing my articles, while helping myself with the strongest tea I could brew, and finally managed to do the work for the coming two days. To free them up for this trip."

  • • Строка ⑵ помечена как устаревшая, и друг под другом написаны новый и старый её варианты. Глядя на них, легко исправить перевод, если надо.
  • • Строка ⑶ вписана на своё законное место, а не в конец файла.
  • • У строчки ⑷ просто поменялась метка (hard_job).
  • • Переводы строк ⑵ и ⑷ продолжают работать.
  • • Всё, что требует внимания переводчика, помечается словом TODO. Достаточно лишь выполнить поиск по файлу.

На мой взгляд, это явно лучше того, что предлагает нам Ren'Py по умолчанию. Посему означенную цель считаю достигнутой.

Спасибо за внимание.


P. S. Уже после релиза мы обнаружили Ren'Py Translator Toolkit. Он добивается той же цели иными средствами: конвертирует .rpy в .po и обратно. Так что если вы собираетесь переводить свою новеллу, советую обратить внимание и на этот проект тоже. У каждого подхода есть свои сильные и слабые стороны; попробуйте оба и решите, какой вам удобнее.
18
Декабрь
3
4.2
4341
Добавлять комментарии могут только зарегистрированные пользователи.

Комментарии к записи: 3

avatar
#1 Хемуль
87473
в 12:48 (13/Июл/2019)
0
Очень полезная статья. Думаю, поможет многим разработчикам. Спасибо!
avatar
#2 orikanekoi
5668
в 12:05 (16/Июл/2019)
1
Спасибо, как раз столкнулись с похожими проблемами! Попробуем и вашу прогу и тулкит!

UPD: Ваша программа нам помогла на 100%, спасибо!
avatar
#3 EvgenFree
582016
в 18:53 (06/Янв/2022)
0
Доброе время суток... Прошу прощения, может не туда пишу, но вот пробую себя в переводах новелл... Прога, описанная выше очень часто помогает, но вот иногда попадаются хитрые таки новеллы где она иногда проскакивает.

У меня просто такой вопрос, может подскажите как формируется вот этот код что в конце... На примере из Вашей статьи.

# game/script.rpy:635
# TODO: NEW.
translate english smoothstart_451bdca2:

    # "А то и третьи."
    ""

Заранее благодарен... )) А то в исходниках этой программы смотрел, аж глаза сломал но так и не понял...