Tradução Planescape Torment - Enhanced Edition
“python translate.py“
De vez em quando eu gosto de jogar alguns RPGs antigos estilo Fallout (1 e 2), essa semana encontrei um pessoal falando muito bem de um jogo chamado Planescape. É um jogo lançado em 1999 baseado nos conceitos de D&D e todo voltado para a história, afinal, se trata de um RPG de mesa adaptado para computador. Como o jogo é antigo, na Steam não tem a opção de jogar em pt-BR, pois sendo bem sincero, não estava afim de ficar lendo e traduzindo as palavras que eu não entendo, queria jogar aproveitando a história, apenas.
Como toda pessoa que jogou muitos jogos no começo dos anos 2000, comecei a procurar a tradução pela internet e não encontrei em lugar algum. Encontrei alguns posts de 2005~2009 em forums sobre cRPGs dizendo que o jogo era muito grande e tomaria muito tempo para traduzir. Então eu desisti... e fui atrás de entender como funciona a tradução de jogos.
TLK
Uma das empresas que desenvolveu Planescape é a Beamdog, se trata de uma empresa fundada pelo cofundador da Bioware. Essa informação é relevante pois os jogos da Bioware possuem arquivos com extensão .tlk. Nestes arquivos, são salvos os diálogos do jogo em diversas linguagens. Sabendo disso, comecei a pesquisar sobre como extrair estes textos dos arquivos. Em alguns forums bem antigos (2005), encontrei algumas ferramentas que começaram a me dar ideias de como eu iria traduzir o jogo. Uma delas se chama Inifinity Engine Talk Table Editor, através dela é possível carregar um arquivo .tlk, navegar entre os diálogos e substituir eles por outros.
Porém, o jogo possui mais de 100k de diálogos, com essa ferramente eu iria precisar traduzir os diálogos um a um, isso daria muito trabalho. Fazendo mais algumas pesquisas, encontrei uma ferramenta (da mesma empresa que desenvolveu o Table Editor), se chama Weidu, é um executável que consegue transformar um arquivo .tlk em um arquivo da extensão .tra, essa extensão diferente da .tlk, pode ser lida como um arquivo texto comum.
TRA
Cada @ representa um diálogo no jogo e o texto dos diálogos ficam entre TILS. Sabendo disso, usando NodeJS escrevi um código que faz um REGEX nesse arquivo e captura todos os textos que estão dentro dos TILS e salve em um json novo com a seguinte estrutura:
{
"index": 0,
"original": "text"
"translated": ""
}
Código:
const fs = require("fs")
const REGEX = /(?<=~)(.*?)(?=~)/gs
const allFileContents = fs.readFileSync("dialog.tra", "utf-8")
const array = allFileContents.match(REGEX)
const isEven = (number) => number % 2 == 0
const newFile = []
array.map((text, index) => {
if (!isEven(index)) return
newFile.push({ index, original: text, translated: "" })
})
fs.writeFileSync("new-file.json", JSON.stringify(newFile), "utf-8")
Tradução
Eu queria algo automático, não queria desprender algum tempo pra traduzir manualmente o jogo. Usando python eu escrevi um código que le esse json com os diálogos extraidos do jogo e traduz utilizando uma lib.
import io
import json
from deep_translator import GoogleTranslator
f = open("new-file.json", "rb")
data = json.load(f)
array = []
def save_file(content):
with io.open("output.txt",'w',encoding='utf8') as f:
f.write(json.dumps(content))
for dialog in data['dialogs']:
text = dialog['original']
try:
translated = GoogleTranslator(source='english', target='portuguese').translate(text)
dict_dialogue = { "original": text, "translated": translated }
array.append(dict_dialogue)
save_file(array)
print(f"finished dialogue")
except Exception as e:
print(f'ERRO={e} - DIALOGUE={text}')
print('finalizado')
Esse processo demorou cerca de 29hrs, eu não medi o tempo pelo código, mas levou cerca de 1 segundo por diálogo traduzido.
Depois de criar um json gigantesco com os diálogos originais e as traduções, escrevi um outro código em NodeJS para substituir no arquivo .tra os diálogos de en-US para pt-BR.
const fs = require("fs")
const dialogs = require("./output1.json")
let tra = fs.readFileSync("./dialog.tra", "utf-8")
const findInTraFile = (text) => tra.indexOf(`~${text}~`)
const replaceInTraFile = (originalText, translated) => tra.replace(`~${originalText}~`, `~${translated}~`)
console.time("translate")
for (let index = 0; index < dialogs.length; index++) {
const dialog = dialogs[index]
const text = dialog.original
console.log(text)
const exists = findInTraFile(text) > -1
if (exists) {
tra = replaceInTraFile(text, dialog.translated)
fs.writeFileSync("dialog-new.tra", tra, "utf-8")
console.log("ultimo trocado foi", index)
} else {
console.log("erro", index)
}
}
console.timeEnd("translate")
Esse passo demorou cerca de 1hr. E para finalizar, utilzei a ferramenta Weidu para transformar o arquivo .tra em .tlk.
Resultado
Faltam só alguns ajustes, como voltar o nome original dos personagens do jogo, mas para fazer isso basta editar o arquivo .tra e depois converter ele novamente.