關於psv某文字游戲漢化的研究


首先想提醒大家的是,根據現行法律,未經著作權人等許可的游戲漢化是一種侵權行為,我曾經聽說過一種說法,即只要不以營利為目的進行漢化則沒問題,但我認為這是個有問題的說法。當然自我學習之用則可以。本心得以psv文字游戲《可塑性記憶》為例,向大家展示我漢化的流程。以下內容僅為個人觀點,若有欠妥之處我會及時修改。下面是干貨。

漢化總步驟:
    |---- 解包
    |      (然后分析解包出來的文件,你至少得搞清楚要漢化的東西都在哪些文件里吧)
    |                             |--- 提取文本
    |       |---文本漢化- |    翻譯         
    |       |                     |---替換文本
    |---- |
    |       |                    |---P圖
   |        |---圖片漢化-|
    |                            |---保存(是的,這一步非常重要而且讓人掉頭發)
    |
    |---- 制作字庫
    |
    |
    |---- 視頻漢化(如果你想的話)
    |
    |---- 打包



解包:
想必第一步就讓好多人望而卻步。就一個psv游戲而言:

  1. 首先准備一個mai版的游戲文件,一般是壓縮包,解壓后游戲文件盡收眼底。

接着初步分析目錄:

  • mai_moe文件夾:不用管,是安裝mai用的
  • movie文件夾:無需多說,該游戲內的一些視頻
  • sce_module文件夾:不知道干什么用的,里面文件后綴為.suprx,是psv的系統文件
  • sce_sys文件夾:里面有些圖片,隨便看看你就知道是什么了,psv標志的貼紙和獎杯等

下面的文件都是未知格式xxx_body.bin和xxx_info.psb.bin等,而且是成組的,可以看到有幾個占了很大內存,猜測游戲本體就是由這些文件組成。

注:解包這些未知格式文件就是最棘手的問題了,你可能需要大量時間在網上尋找是否有前輩提供解包工具,或者自己造輪子,但是我想大部分人是沒有能力自己造的,所以只能碰運氣去找,找到了就有漢化的可能,找不到就只能放棄。

這次運氣好,在github上找到了某大神的一個工具FreeMote,貌似該工具的初衷並非用於漢化,但客觀上確實能解包該游戲的重要文件,其詳細信息在此不做贅述。(請正確上網,不FQ,github無需FQ)

        2. 用FreeMote解包xxx_body.bin和xxx_info.psb.bin文件(解包方法略)

注:需要說明的是解包這類文件需要一個key,若想獲得該游戲的key需要在未解包時的bin文件源碼中找,總之挺麻煩。

以font_body.bin和font_info.psb.bin為例:解出來一個文件夾和兩個json文件

文件夾內也是json文件。先在psv上打開游戲看一下游戲第一句話,記下來。用notepad隨便打開一個json文件,search一下全文件(指定搜索路徑可以提高效率)是否存在第一句話,有的話則說明文本已經解出來了。接下來只要找到文本文件即可。



文本漢化

雖可以直接在源文件上翻譯文本,但效率過低,如能提取出來做成excel就可以批量翻譯了,我選擇python解決此問題。對於翻譯這種小項目,無需使用面向對象的方式編程,簡單的函數足以應付:

1. 提取文本小程序

 1 import json    #用於解析json文件
 2 import csv      #用於保存csv文件
 3 
 4 def savefile(filename,words,name,nikname):
 5     path2 = r"C:\Users\xxxxxx\scenariotest\get_word\{0}".format(filename)
 6     with open(path2,'a+',encoding='utf-8') as csvfile:
 7         writer = csv.writer(csvfile)
 8         writer.writerow([name,nikname,words])
 9     csvfile.close()         #該函數用於寫入csv文件並保存
10 
11 def get_word(path):
12     file = path.split("\\")[-1]
13     change = file.split(".")[0]
14     filename = change + ".csv"
15     fp = open(path,encoding='utf-8')      #注意解碼用utf-8
16     json_data = fp.read()                           #讀取json文件
17     data = json.loads(json_data)
18     data01 = data["scenes"]                       #定位到一級標簽
19     for m in data01:
20         if ('texts' in m.keys()):            #定位到text標簽
21             print("loading.......................")
22             for i in m['texts']:
23                 words = i[2]                     #獲取文本
24                 name = i[0]
25                 nikname = i[1]
26                 if name == 'NULL':
27                     name = ' '
28                 if nikname == 'NULL':
29                     nikname = ' '
30                 savefile(filename,words,name,nikname)
31         else:
32             print("NULL") 
33             continue
34 
35 if __name__ == '__main__':
36     file_path = r"C:\Users\xxxxxx\pm1-01.txt.scn.m.json"      # 改文件名
37     get_word(file_path)

 

思路:觀察得知每個文件中“text”標簽后即一堆數組,文本就是數組中的一個元素,用json包直接定位到文本即可,然后保存為csv格式。

使用方法:改一下程序中要提取的文件名后運行

運行結果:以示例文件名為例,生成一個文件:pm1-01.csv,用excel打開即可

2. 翻譯小程序

雖可逐句手動翻譯,但奈何我日語5級都難過,不如先讓度娘翻譯一遍,再修修補補即可:

 1 import requests
 2 import hashlib
 3 import json
 4 import csv
 5 import time
 6 # python3.0 已經取消了MD5,需要使用hashlib
 7 # 該程序最后輸出的文件為xxxfanyi.csv   文件只包含翻譯結果,每隔一句空一行
 8 
 9 # 獲取csv中文本
10 def getword(path):
11     csvfile = csv.reader(open(path,'r',encoding='utf-8'))
12     words = []
13     i = 1
14     for line in csvfile:
15         if i%2 == 1:
16             words.append(line[2])
17         else:
18             pass
19         i = i + 1
20     return words
21 
22 # 翻譯函數,具體使用方法在api申請頁面有教程
23 def fanyi(str):
24     q = str  # 句子
25     ifrom = 'jp'  # 翻譯源:日語
26     to = 'zh'  # 翻譯到:中文
27     appid = 'xxxxxxxx'  # id號
28     key = 'xxxxxxxx'  # 密鑰
29     salt = 'xxxxxxxx'  # salt隨便取一個
30     # appid+q+salt+密鑰 的MD5值
31     sign_1 = appid + q + salt + key
32     sign = hashlib.md5(sign_1.encode(encoding='utf-8')).hexdigest()
33     # 產生url
34     url = 'https://fanyi-api.baidu.com/api/trans/vip/translate?q={0}&from={1}&to={2}&appid={3}&salt={4}&sign={5}'.format(
35         q, ifrom, to, appid, salt, sign)
36     try:
37         res = requests.get(url=url)
38         words = json.loads(res.text)
39         words = words['trans_result']
40         words = words[0]
41         words = words['dst']
42         return words
43     except BaseException as e:
44         print(e)
45 
46 # 最后輸出
47 def pack(list01):
48      path = r'C:\Users\xxxxxxxx\pm1-01fanyi.csv'             # 改文件名,這是最終生成的文件名
49      f = open(path,'w+',encoding='utf-8')
50      writer = csv.writer(f)
51      for n in list01:
52          writer.writerow([n])
53 
54 if __name__ == '__main__':
55     # 獲取word
56     path = r'C:\Users\xxxxxx\pm1-01.csv'       # 也改一下文件名,這是之前生成的那個csv文件
57     list01 = []
58     m = getword(path)
59     num = 0                        # 計數用於調試
60     for j in m:
61         print('waiting.......')
62         a = fanyi(j)
63         list01.append(a)
64         time.sleep(1.5)
65         num = num+1
66     pack(list01)

 

思路:百度翻譯有個api接口,自己申請一個就可以用了,實名后貌似可以每秒翻譯10句,但網速實在不給力,而且我也懶得做錯誤處理了,就寫成個半成品。直接利用之前生成的csv翻譯再生成一個翻譯版csv,就這么簡單。

使用方法:在程序中改需要翻譯的文件名后運行

運行結果:以示例文件名為例,生成一個文件:pm1-01fanyi.csv,用excel打開即可

3. 導入小程序

 1 import csv
 2 import json
 3 # 本文件需要03.csv和03mid.csv兩個文件
 4 # 生成文件即03.csv,需要翻譯名字
 5 
 6 def csv_read_word(path):
 7     strword01 = []
 8     flag = 1
 9     file = csv.reader(open(path, 'r', encoding='gbk'))
10     for line in file:
11         if flag%2 == 1:
12 #             print(line)
13             strword01.append(line[0])
14         flag = flag + 1
15     return strword01
16 
17 def csv_read_name(path,h):
18     strword02 = []
19     flag = 1
20     flag2 = 0
21     file = csv.reader(open(path, 'r', encoding='utf-8'))
22     for line in file:
23         if flag%2 == 1:
24             strword02.append(line[h])
25         flag = flag + 1
26     return strword02
27 
28 def recsv(word,name,nikname,csv_path):
29     with open(csv_path,'w+',encoding='utf-8') as csvfile:
30         writer = csv.writer(csvfile)
31         for i in range(0,len(word)-1):
32 #             print([name[i],nikname[i],word[i]])
33             writer.writerow([name[i],nikname[i],word[i]])
34     csvfile.close()
35 
36 if __name__ == '__main__':
37     mid_path = r'C:\Users\xxxxxxx\pm1-01mid.csv'       # 改之前的pm1-01fanyi.csv文件名為這里的文件名
38     csv_path = r'C:\Users\xxxxxxx\pm1-01.csv'          # 改文件名,為源文件名
39     word = csv_read_word(mid_path)
40     name = csv_read_name(csv_path,0)
41     nikname = csv_read_name(csv_path,1)
42     recsv(word,name,nikname,csv_path)

 

思路:這個程序就有點無厘頭了,不知道我當時怎么想的。。。總之有很大的修改空間。具體來說就是將之前翻譯好的pm1-01fanyi.csv導入到源文件中,即第一個程序的逆向,沒有什么技術難度。

注:這個程序一個大問題是,因為galgame的文本有對應的人物名字,我在第二個翻譯程序中忘了翻譯人名,導致這里想再翻譯人名就很麻煩。

使用方法:修修補補完成pm1-01fanyi.csv文件翻譯后,將該文件的文件名改為pm1-01mid.csv,然后改一下程序中的文件名,運行

運行結果:導入完成。

至此,文本翻譯告一段落。



圖片漢化

 1. 該游戲中,游戲菜單等內容並非以文本形式存儲,而是圖片,因此還要翻譯圖片。和解包文本相同,解包圖片后是一堆png格式圖片,用photoshop進行修圖翻譯即可。(這里要感謝FreeMote工具的大佬幫忙更新了工具,能夠打包了,否則只能解包,圖片漢化就不可能了)

 2. 保存:保存之所以成為一個問題,是因為如果保存格式不正確,放回游戲后顯示會有問題,這就好比你用txt打開一個exe文件,改幾下后再保存,雖然它可能還是一個exe后綴的文件名,但電腦可能完全運行不了它了。同理,雖然你用ps保存為png格式,但與原來的那個png已經完全不同了。這個問題我暫時沒有找到好的解決辦法,只能嘗試改變保存時的各種參數來碰運氣。最難過的是,游戲中不同的圖片,保存格式也不同,而有一些圖片你試完了所有ps提供的可變項后,還是無法正確運行,好在只有少數不重要的圖片,不然你可能要氣炸了(忙了大半個月了就因為這玩意,毀了所有努力啊有木有!!!)有了解圖片格式的大佬可以自行研究解決。


 

視頻漢化

關於視頻漢化,就是加字幕了,該游戲的一些劇情是以視頻形式表現的,但沒有字幕,日語聽力還是饒了我吧。。。我還未進行實踐,自然不知道結果如何,用pr加字幕是沒有問題,但是不是和圖片一樣有保存的問題就不得而知了。



字庫

字庫也一度讓我止步不前,但只要理解了原理,造輪子不是問題。

1. 字庫是什么:游戲中的文本本質上是圖片,字庫就是一堆字的圖片拼在一起而組成一張大圖,有點像排好的活字印刷術的活字。當需要顯示時,將映射表中的文字映射到大圖中的某個坐標從而調取到字圖,得以顯示。

2. 怎么做字庫:我找了很多生成字庫的工具,但總有各種問題,如字圖大小不一,順序混亂等,最終只能自己解決了。

  • 到網上找常用字集合,我找了一個3500字集合,做成txt

注:應當為一個矩形,不要一行多一行少

  • 在解包的文件中找到字庫,該游戲字庫在font文件夾中,且有好幾個字號的字庫,不知道為什么要這么多字號,實際只需改其中一個即可,直觀感受一下最終需要達到的成果

其中一個字號的解包結果

  • 編程生成字庫

字庫小程序:

 1 import os
 2 from PIL import ImageFont,ImageDraw,Image
 3 
 4 def Read():
 5     fp = open(r'F:\pycharm\xxxxxx\3500字_new.txt','r',True,encoding='utf-8-sig')
 6     while True:
 7         word = fp.read(1)
 8         if not word:
 9             break
10         yield word
11     fp.close()
12 
13 if __name__ == '__main__':
14     m = 5                 # x軸
15     n = 5                 # y軸
16     wordlist = []
17     text = Read()
18     im = Image.new("RGB", (2048, 2048), (255, 255, 255))
19     dr = ImageDraw.Draw(im)
20     font = ImageFont.truetype(os.path.join("fonts", "goodfont01.ttf"), 22)
21     for word in text:
22         wordlist.append(word)
23     # 逐字寫入
24     for i in range(1, 46):            # i列
25         for j in range(1, 79):        # j行
26             flag = (i-1)*78+j         # 第flag個字
27             if flag <= 3500:
28                 dr.text((m, n), text=wordlist[flag-1], fill="#000000", font=font)
29                 m = m + 26
30             else:
31                 break
32         print("{0}層完成".format(i))
33         m = 5                         # 換行定位
34         n = n + 26
35     im.show()
36     im.save('font_new.png')

 

思路:制作字庫就三步,讀取文字、定位、寫入,讀取文字即讀取txt文件中的3500字中的一個,定位即定位到這個文字應該放在哪里,寫入不說了。我使用了PIL包,先生成一張底圖,再逐字寫入即可,這個包還可以設定底圖的顏色,字號,字體顏色等。但問題是我需要透明底圖,PIL貌似沒有透明這個選項。因此只能先白底黑字再ps反色摳圖解決了,實際效果強差人意,因為我不知如何將字調為單色透明度,如該游戲字庫圖實際上是白色字且有透明度的,摳圖的結果是一堆狗牙,但至少做到了排列整齊。

  • 修改映射表

你可以在和字庫圖一起解包的json文件中找到,有很明顯的規律,只要將里面文字的部分用3500字重新寫一遍,覆蓋原內容即可,程序很簡單就不做解釋了。

映射表小程序:

 1 if __name__ == '__main__':
 2     alljs = []
 3     jstext = []
 4     x = 1
 5     y = 213
 6 
 7     # get words
 8     fp = open(r'F:\pycharm\xxxxxxx\3500字_new.txt','r',True,encoding='utf-8-sig')
 9     while True:
10         word = fp.read(1)
11         if not word:
12             break
13         unit = '"first": {"a": 0,"b": 20,"d": 24.0,"h": 24,"height": 24,"id": 0,"w": 24.0,"width": 24.0,"x": second,"y": third}'
14         unit2 = unit.replace('first',word)
15         jstext.append(unit2)
16     fp.close()
17 
18     # change x,y
19     for i in range(1,46):
20         for j in range(1,79):
21             flag = (i-1)*78+j
22             if flag <= 3500:
23                 str01 = jstext[flag-1].replace('second',str(x))
24                 str02 = str01.replace('third',str(y))
25                 alljs.append(str02)
26             x = x + 26
27         print('完成{0}行'.format(i))
28         x = 1
29         y = y + 26
30     print('完成')
31 
32     # write file
33     fp02 = open(r'F:\pycharm\xxxxxxx\font24.txt','w+',encoding='utf-8')
34     for m in alljs:
35         m = m + ',' + '\n'
36         fp02.write(m)
37     fp02.close()

最終結果無需追求源碼的縮進,只要符合json格式即可,如可以做成這樣:

  • 如果翻譯中有些字在3500字中沒有怎么辦?先在映射表里找一個不常用的字,改掉它。再到字庫圖里把相應的字圖改掉。(或者重新生成)


打包

用FreeMote反向操作一下即可。這一步的問題是為了方便安裝,究竟是制作漢化補丁,還是整體打包替換,但該問題已經超出我想討論的話題了。



結語

若完成以上所有工作,該游戲即漢化完成。但可知這其中仍有很多問題有待解決,如對於人名的漢化我並未完成自動化,圖片的漢化尚存漏洞,字庫的顏色問題,當然還有丑的不行的代碼 T _ T。總之盡善盡美是很困難的。另外,上述方法也不具有通用性。最后希望這些看似已經脫離時代的東西能幫助到有需要的人吧。

最終效果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM