Вышел перевод Heaven’s Vault
Товарищ Sneaksie выпустил русификатор для приключенческой игры Heaven’s Vault.
Ее особенностью является использование необычной технологии повествования, опирающейся на нормы английского языка. Именно поэтому у игры нет ни одного официального перевода на другие языки.
В связи с этим, ряд фраз на русском языке будет смотреться чужеродно, исправить это невозможно.
ЦитатаЭто настоящая интерактивная книга (и большая). В итоговом переводе заменено около 44 тысяч фраз (!) состоящих почти из 220 тысяч слов (это чуть меньше двух томов «Войны и мира» Толстого), каждая из которых отредактирована вручную и по мере возможности подогнана под разные ситуации, где она может быть использована.
Наконец, в игре используется еще один искусственный язык, символы из которого записываются в файл сохранения. Поэтому русификатор заработает только после начала новой игры.
Новости и статьи по тегам:
- 2 Вышел перевод Brassheart
- 4 Вышел перевод Prison Princess
- 1 Вышел перевод Everdell
- 1 Вышел перевод Munchkin Digital
- 10 В архив добавлены переводы Snowbreak: Containment Zone
- 17 Вышел перевод Final Fantasy VII Rebirth от Tigra_Spartan
Отдельная особенность заключается в том, что текстовая часть игры сделана на нарративном движке Inkle - это один из сложнейших нарративных движков для перевода.
Насколько мне известно, ни у одной из использующих этот нарративный движок игр, не существует официальных переводов, потому что даже официально это невероятный геморрой.
В связи с этим считалось, что перевод данной игры практически невозможен.
@0wn3df1x геморрой, потому что нет нормальных ответвлений диалога для удобного перевода или там геморройно извлечь текст и запихнуть его обратно?
Проблема в самой архитектуре движка Inkle, которая требует не просто перевода, а лингвистического реинжиниринга нарратива на уровне низкоуровневого кода, то есть перестройки логической системы, созданной для английской языковой модели, под другую парадигму.
Первое и главное, что нужно понимать: Inkle - это не классическое диалоговое дерево “выберите вариант А, получите ветку А”. Inkle ткёт повествование из мелких фрагментов текста, переменных, функций и логических условий. Переводчик видит не цельные, готовые к переводу предложения, а их составные части - по сути, сырье, из которого движок будет склеивать финальный текст на лету. Это больше похоже на работу с ассемблером для текста, чем с привычными строковыми ресурсами. Как программист на ассемблере должен знать архитектуру процессора, так и локализатор Inkle обязан понимать внутреннюю логику его нарративной виртуальной машины.
К примеру, возьмём игру The Pale Beyond и её текстовый ФАЙЛИК на 33 мб.
Там есть функция ShortSentenceDeadClickTest:
"ShortSentenceDeadClickTest": [ [ "ev", "str", "^x", "/str", "/ev", { "temp=": "Xstring" }, "ev", "str", "^y ", "/str", "/ev", { "temp=": "Ystring" }, [ "^Loop ", "ev", { "CNT?": ".^" }, "out", "/ev", "^. String X ", "ev", { "VAR?": "Xstring" }, "out", "/ev", "^. String Y ", "ev", { "VAR?": "Ystring" }, "out", "/ev", "\n", // ... логика выбора ... "ev", { "VAR?": "Xstring" }, "str", "^x", "/str", "+", { "temp=": "Xstring", "re": true }, "/ev", // ... "ev", { "VAR?": "Ystring" }, "str", "^y ", "/str", "+", { "temp=": "Ystring", "re": true }, "/ev", ], ],]Это квинтэссенция подхода Inkle. Там нет диалогов в привычном понимании. Это низкоуровневый программный код. Команды ev (evaluate), str (string), VAR? (get variable), out (output), temp= (assign to temporary variable), re= (reassign) - это инструкции для виртуальной машины движка. Этот код инициализирует две переменные и в цикле (CNT? - вероятно, счетчик цикла) конкатенирует (оператор +) к ним новые символы.
Для английского языка, где слова редко меняются, это нормально. Для русского - это катастрофа. Можно представить ситуацию, где вместо "x" нужно подставлять слово, которое должно меняться в зависимости от контекста (например, числа итераций цикла), а этот контекст определяется где-то в совершенно другой части кода. Это черный ящик, который невозможно перевести, не декомпилировав в уме логику его работы. Повествование управляется состоянием сотен переменных, и переводчик видит лишь разрозненные атомы текста, не зная, в какую молекулу-предложение они соберутся.
Так вот, раз уже я начал о конкатенации и связанном с ней грамматическом аде.
Конкатенация (простое склеивание строк) является в Inkle основным инструментом повествования. И именно в ней кроется дьявол для флективных языков, порождающий каскадные грамматические зависимости.
Гипотетический пример на английском:
itemCount = 1, itemAdjective = "red", itemName = "apple" -> "You have 1 red apple."itemCount = 5, itemAdjective = "red", itemName = "apples" -> "You have 5 red apples."Всё просто. Сценарист готовит две формы существительного и одно прилагательное.
"У вас есть " + itemCount + " " + itemAdjective + " " + itemName + "."itemCount = 1, itemAdjective = "красное", itemName = "яблоко". Получаем: «У вас есть 1 красное яблоко».itemCount = 2, itemAdjective = "красных", itemName = "яблока". Получаем: «У вас есть 2 красных яблока».itemCount = 5, itemAdjective = "красных", itemName = "яблок". Получаем: «У вас есть 5 красных яблок**_**».Тот же пример, но на русском:
Прилагательное “красный” и существительное “яблоко” меняют свои окончания в зависимости от числа itemCount. Причем правила для 1, 2-4 и 5+ разные. Движок этого не знает. Он просто подставит переменные. Локализатору нужно переписать всю эту строку в отдельную функцию с громоздкой логикой. А теперь представим, что таких переменных в игре тысячи, и они могут быть не только предметами, но и статусами, именами, локациями.
Вот реальный пример из функции GetWeeklyTitleCardTextSubtitle:
"GetWeeklyTitleCardTextSubtitle": [ // ... "ev", "str", "ev", { "VAR?": "TERRITORY_0_WEEKSHERE" }, "out", "/ev", "^ Week", "ev", { "VAR?": "TERRITORY_0_WEEKSHERE" }, 1, ">", "/ev", [ { "->": ".^.b", "c": true }, { "b": [ "^s", ... ] } ], "nop", "^ on the Temperance.", "/str", "/ev", "~ret", // ...],Этот код генерирует фразу типа “1 Week on the Temperance”. Логика примитивна: если переменная TERRITORY_0_WEEKSHERE больше единицы, то с помощью условного перехода { "->": ".^.b", "c": true } (по сути, goto) добавляется строка ^s. Команда ~ret означает, что эта собранная строка возвращается как результат функции. Куда? Возможно, она будет подставлена в другую строку, создавая новый виток грамматического ада.
Переводчик видит три изолированных куска: [число], Week, on the Temperance.
На русском это превращается в неразрешимую задачу: 1 неделя, 2 недели, 5 недель. Просто добавить окончание невозможно. Нужно полностью переписывать эту функцию на уровне кода.
И так - везде. Каждая такая строка - это мина замедленного действия.
Также Inkle обожает переиспользовать фразы. Одна и та же часть предложения может быть использована в десятках разных мест с разными подставляемыми существительными, прилагательными и глаголами.
Пример с родом:
"The " + objectName + " is broken."Прилагательное “broken” в русском языке должно согласовываться с родом существительного. Переводчик видит строку " is broken" в отрыве от objectName. Он не знает, к чему она будет применяться. Единственный выход - создавать для каждого объекта метаданные (например, его род), а затем вместо простой строки " is broken" писать целую функцию, которая будет запрашивать род объекта и возвращать правильную форму прилагательного: “сломан”, “сломана” или “сломано”. Это уже не перевод, а программирование.
Вот, например, функция listSurnamesWithCommas.
"listSurnamesWithCommas": [ { "temp=": "if_empty" }, { "temp=": "list" }, "ev", { "VAR?": "list" }, "LIST_COUNT", "/ev", [ "du", "ev", 2, "==", "/ev", { "->": ".^.b", "c": true }, { "b": [ "pop", "\n", "ev", { "VAR?": "list" }, "LIST_MIN", { "f()": "CrewNameToSurname" }, "out", "/ev", "^ and ", "ev", { "VAR?": "list" }, { "VAR?": "list" }, "LIST_MIN", "-", { "f()": ".^.^.^" }, "out", "/ev", // ... ]} ], // ...],Этот код берет список фамилий и красиво форматирует его в строку: "Smith, Jones and Williams". Он просто вставляет запятые и слово "and". А теперь представим, что нам нужно сказать не “Вот Смит и Джонс” (Именительный падеж), а “Я вижу Смита и Джонса” (Винительный падеж) или “Я говорю со Смитом и Джонсом” (Творительный падеж). Переводчик не может просто перевести "and" как "и". Ему нужно знать падеж, в котором будут стоять все эти фамилии, и создать отдельную функцию для каждого падежа.
Помимо этого, английский язык имеет строгий порядок слов (Subject-Verb-Object). Inkle-скрипты часто полагаются на это. В русском языке порядок слов гибкий и используется для расстановки смысловых акцентов. Попытка собрать русскую фразу из кусков в английском порядке приводит к уродливым, машинным конструкциям. Переводчик оказывается в ловушке: он не может изменить порядок сборки фразы, потому что он зашит в логику движка. Ему приходится либо жертвовать качеством языка, либо полностью переписывать логические блоки.
Короче говоря, ад Inkle для локализации заключается в том, что:
Вот такие пироги. Вот такая красота:

Да уж, вероятно это надо ОЧЕНЬ сильно любить эту далеко не самую известную и мягко говоря не самую популярную (даже в узких кругах) игру.
Но сугубо объективно — мое почтение. Локализатор реально сверхчеловек.