유니티 게임의 한글화와 패치 제작 – 언어 파일

유니티 게임을 제작할 때 텍스트를 넣을 때 텍스트를 하드코딩해서 넣을 수 있지만, 외국계 게임의 경우 보통 영어, 프랑스어, 독일어, 스페인어, 러시아어를 한번에 넣어서 배포하기때문에 보통 localization 도구를 사용하여 각 텍스트 Object마다 부여되는 key와 각각의 키와 해당하는 언어에 따라 번역된 문장들을 모아둔 언어 파일을 별도로 만들어 사용하게된다.

여러 유니티 게임에서 사용하는 언어파일이 무엇이 있는지, 어떠한 형태로 저장되어있는지 알아보고, 언어 파일이 어디에 있는지 실제 예를 사용하여 찾아본다음 실제로 그 파일이 맞는지 언어 파일을 수정하여 게임상에서 확인하고, 마지막으로 해당 언어가 한글 폰트 출력을 지원하는지 확인해본다.

본 문서는 많은 사진을 포함하고 있다. 모바일 데이터 환경에서 접속할 때 주의.

유니티 게임 우리말화 도구 베타 버전을 공개하였습니다. 이에 관한 설명은 GitHub의 wiki에서 서술합니다. https://github.com/dmc31a42/UnityL10nTool/wiki

유니티 게임의 한글화와 패치 제작 – 서론 으로 돌아가기

본 강좌는 70~80% 완성되면 바로 공개되며, 잘못된 부분이 있으면 그때 그때 수정하는 것으로 하겠습니다. 아래의 강좌 내용은 언제든지 수정될 수 있습니다. 질문은 댓글로 달아주시거나 GitHub(https://github.com/dmc31a42/UnityGameL10nTutorial/)의 issue를 활용하여주시면 감사하겠습니다.

언어 파일 형식

Text

제일 분석하기 힘든 저장 형식이다. 일반적인 텍스트 파일에 개발자가 정한 방식으로 key와 번역어를 구분한다. parse 형식은 스크립트에서 일정한 절차에 따라 문장을 split으로 자르거나 replace로 줄바꿈 구분자나 탭, key와 번역어를 구분하는 문자등을 원래의 형식으로 바꾸기도 한다.

대응되는 각 언어에 대하여 각각 언어 파일이 존재하는 경우가 많으며, 각 언어별로 파일 이름이 다르거나 Container상 파일/폴더 경로가 다르게 되어있다.

보통 key는 알파벳과 _(underbar), ‘.'(dot) 들만 포함되는 경우가 많다.

구분자는 보통 ‘='(대입) 또는 ‘,'(comma)로 구분하고 구분자 기준으로 전(왼쪽)이 key이고 후(오른쪽)가 번역어인 경우가 많다.

번역어는 텍스트 파일에 대응되는 문장을 c-style(c 언어와 c 언어의 계보를 잇는 후속 언어들에서 문장을 소스 파일에 표현하는 방법; 한줄로 쓰고 줄넘김은 ‘\r\n’ (또는 ‘\n)으로 표현하는 방식과, 탭과 같은 특수문자를 ‘\t’와 같이 작성함)이나 html-style(화면에 보이는 모습을 <color></color>와 같이 표현한 것) 방식외에 여러가지 방법으로 작성하거나 이를 섞어 쓰는 식으로 작성한다.

텍스트 파일로 언어 파일을 작성하는 것은 개발자 나름이기 때문에 많은 형식을 보고 많이 경험해보는 수 밖에 없다.

 

JSON

인터넷에 좋은 자료들이 많으니 참조하면 된다.

SQLite3

인터넷에 좋은 자료들이 많으니 참조하면 된다. 필자는 주로 ‘DB Browser for SQLite’로 확인하고 수정한다.

XML

한번도 xml로 되어있는 언어 파일을 보지 못했지만, 인터넷에는 xml으로 작성된 게임이 있다고하니 일단은 적어둔다.

CSV

csv 파일을 열어보면 내용물은 단순한 텍스트 파일로 구성되어있다. 열 구분은 ‘,'(comma)로 하고 행 구분은 줄바꿈으로 한다. 만약 셀의 내용물에 줄바꿈이 있으면 셀을 쌍따옴표로 묶고 줄바꿈은 그대로한다. 따라서 한 행이 여러줄에 걸쳐서 있을 수도 있다. 그 외에는 인터넷에 해당 파일의 포맷을 찾아보면 더 자세한 정보가 있을것이다.

 

언어 파일 위치

위 형태의 파일이 언어파일로 존재할 수 있음을 알아두고 다음의 위치에서 해당 파일이 있는지 확인해보면된다. 어셈블리를 분석해서 어디서 언어파일을 불러오는지 직접적으로 확인하거나, 게임 내 존재하는 문장을 찾아서 검색하는 방식으로 언어 파일을 찾게 된다.

언어 파일이 어떤 방식으로 존재하는지 찾는 과정은 많은 경험을 필요하는 과정이다. 아래의 예시를 통해 언어 파일이 이러한 장소에, 이러한 형태로 존재할 수 있음을 알아두고, 이를 바탕으로 본인이 한글화하고자 하는 게임으로 시도해보자.

언어 파일을 찾을때는 게임은 무조건 한번은 실행시켜 보아야한다. 게임 내의 텍스트를 찾는 문제도 있고, 그 외에 후술할 문제도 있기 때문이다.

Assets 파일

Assets 파일에는 수많은 TextAsset이 있다. UABE를 이용해서 일일이 TextAsset을 추출하여 내용물을 확인해보기에는 많은 시간이 걸린다. 대신, assets 파일을 바로 파일 에디터로 열어서 게임 내 문장을 검색해본다음, 있다고 확신이 들면 해당 assets 파일을 UABE로 열어서 언어 파일에 해당하는 TextAsset을 찾으면된다.

주로 ‘resources.assets을 위주로 찾게된다.

고급

Resources.Load() 함수는 컴파일할 때 ‘Resources’ 폴더 안의 상대 경로를 기준으로 리소스를 불러올 수 있는 기능을 제공한다. 언어 파일이 언어 당 폴더별로 이루어져있다면 각 언어 파일일의 이름은 같을 것이다. 이를 구분하기 위해서는 (어셈블리에서 해당 언어 파일을 불러오는 방식을 파악해서) resources.assets 파일을 바로 여는 것이 아니라 globalgamemanager 열면 의존성 때문에 resources.assets 파일도 열린다. 이렇게 열면 Resources.Load()로 열 때 사용되는 경로가 Container 열에 표시될 것이다.

{{Build Name}}_Data\StreamingAssets 폴더 내

이전 강좌의 유니티 게임의 한글화와 패치 제작 – 유니티 게임의 폴더 구조 – 기본 폴더에 나와있는 것처럼 특별한 설정을 하지 않으면 외부 파일은 StreamingAssets 폴더에 저장된다. 여기에는 유니티 에셋 타입에 포함되지 않는 파일들이 존재한다.

유니티 기본 폴더 구조에 포함되지 않은 폴더

StreamingAssets 폴더와 같이 유니티 에셋 타입에 포함되지 않는 파일들을 특정한 폴더에서 파일을 가져오기로 프로그래밍 되어있으면 해당 경로에서 언어 파일을 가져와서 해당 언어 파일을 해석할 수 있는 라이브러리로 해석해서 사용하게된다.

Webplayer cache

유니티 AssetBundle을 인터넷에서 동적으로 받을 때 받아진 파일이 저장되는 장소이다. 이 폴더에서 언어 파일을 찾을 때는 AssetBundle의 압축을 풀면 나오는 Assets을 위의 Assets 분석방법에 따라 분석하면 된다. 경로는  ‘C:\Users\{{User Name}}\AppData\LocalLow\Unity\WebPlayer\Cache\{{Company Name}}_{{Game Name}}\’ 이다.

Application.persistentDataPath

Webplayer cache와 마찬가지로 인터넷에서 언어 파일을 동적으로 받아오나 언어파일이 유니티 에셋 타입으로 지원되지 않는 파일을 받아서 저장하는 장소이다. 폴더 위치는 ‘C:\Users\{{User Name}}\AppData\LocalLow\{{Company Name}}\{{Game Name}}\’ 이고, StreamingAssets 폴더때와 기본 폴더가 아닌 폴더를 분석할 때와 같이 하면 된다.

실제 게임을 사용한 예제

Slime Rancher

  • 경로 : Resources.Load() 함수를 사용하여 resources.assets 안의 에셋을 동적으로 불러옴. 상대경로는 ‘i18n/en/’ 폴더 내에 ‘achieve’, ‘actor’, ‘exchange’, ‘global’, ‘keys’, ‘mail’, ‘pedia’, ‘range’, ‘tutorial’, ‘ui’ TextAssets 에셋.
  • 언어 파일 : Text 방식, key와 value의 구분은 프로그래밍 언어처럼 =(대입)을 기준으로 왼쪽이 key, 오른쪽 나머지가 value.

슬라임 랜처의 메인 화면에는 ‘Continue’, ‘Load’, ‘New Game’, ‘Options’, ‘About’, ‘Quit’, ‘English’, ‘http://forums.monomipark.com&#8217;, ‘support@monomipark.com’ 텍스트가 있다.

In Slime Rancher menu screen, there are 'Continue', 'Load', 'New Game', Options', 'About', 'Quit', 'English', 'Http://forums.monomipark.com', 'support@monomipark.com' text.

이 중 ‘New Game’ 텍스트를 resources.assets 파일 안에서 찾아보기로 한다. 적당한 텍스트 에디터로(여기서는 notepad++을 사용함) resources.assets 파일을 연다. 이상한 문자들도 같이 있는 것이 보인다. ASCII에서 문자용으로 사용되는 영역외에 다른 영역의 데이터는 제어용으로 사용되고, 텍스트 에디터는 이를 제어코드로 인식해서 이상한 코드들이 보이는 것이다. notepad++로 수정을 하는 것이 아니라 검색만 할 것이기 때문에 무시해도 된다.

When open resources.asset file of slime rancher. there are many characters and control code.

찾기 창을 띄워 ‘New Game’을 검색한다.

Search text in Slime Rancher game menu screen from resources.assets file. I will search 'New Game' so input that.

‘t.new_game = Create New Game’ 문장의 ‘New Game’이 찾아졌다. 전후로 살펴보면 게임에 사용되는 문장이 나타나있다. 이로서 언어 파일이 ‘resources.assets 파일에 있다는 것은 확인되었다.

Search result of 'New Game'. 'New Game' is highlighted in 't.new_game = Create New Game' sentence.

해당 검색어를 찾은 부분에서 위로 스크롤을 하다보면 제어코드가 나타나는 부분이 있다. 순수하게 텍스트만 나오는부분하고 제어 코드가 나오는부분하고의 경계에 에셋의 이름이 나와있다. TextAsset에셋은 에셋의 이름, 본문의 길이(글자수), 본문순으로 기록되어있다. 아래의 예시에는 에셋의 이름이 ‘ui’로 글자수는 25221자(공백 포함)인데 25221은 Big-Endian 으로 ’85 62 00 00′(Hex)이고 ’85 62′(Hex; 34146, Dec)가 유니코드상으론 ‘蕢’이나 한글 윈도우에서는 ‘꿣’으로 표시된다. 에셋이름이 ‘ui’인 것을 알았으니 UABE를 통해서 찾으면 된다. 에셋 이름을 찾지 못했더라도 해당 내용을 가지고 있는 TextAsset을 일일이 찾아보면된다.

Between Only text area where we search 'New Game' and mixed text and control code(upper)

resources.assets에 있는 TextAsset을 조사해보니 ui란 에셋이 있고 ‘View Data’로 확인해보면 notepad++에서 에셋 이름을 찾을 때 보였던 문장이 보인다.

Contents of one of ui TextAsset in Slime Rancher 'resources.asset'

동일한 이름의 에셋이 많은데 Container을 보면 i18n/en/ 경로 안에 있는 에셋들이 영어의 언어 파일로 추정된다.

Assets info when open globalgamemanager assets. 'Container' column has value(relative path)

찾은 언어 파일이 TextAsset이므로 Plugins을 사용하여 txt 파일을 추출한다.

Exported ui TextAsset. Show by notepad++ editor

메뉴 화면에 나타난 ‘Continue’, ‘Load’, ‘New Game’, ‘Options’, ‘About’, ‘Quit’ 문구들에 ‘asdf’ 같은 문구를 추가한다.

Modifiy some sentences which are assumed as ui menu text by adding 'asdf' at end of these.

수정한 txt 파일을 UABE에서 Plugin을 통하여 Import 하고 assets을 원본과 다른 이름으로 저장한 뒤, 원본과 수정된 assets의 이름을 바꿔치기한다. 그리고 게임을 실행하여 변경사항이 반영되었는지 확인한다. 각 메뉴의 끝에 ‘asdf’가 추가된 것으로 보아 찾은 파일이 언어 파일이 맞는 것으로 추정된다.

After modifying resources.assets, there is 'asdf' at the ends of some menu text ..png

마지막으로 위와 같은 방법을 사용하여 ‘asdf’ 대신 ‘ㅁㄴㅇㄹ’처럼 한글을 추가해보고 제대로 표시되는지 확인해본다.

Modifiy some sentences which are assumed as ui menu text by adding 'ㅁㄴㅇㄹ' at end of these.

게임에서 한글 문자는 표시되지 않고 □로 처리되었다. (□는 글자 데이터가 폰트에 대응되는 형상이 없을 때 대체되는 표시이다.)

After modifying resources.assets, there is '□□□□' at the ends of some menu text ..png

Bomber Crew

  • 경로 : resources.assets 내부에 있는 LanguageData.json TextAsset 에셋
  • 언어 파일 : JSON, property 중 ‘key’가 있는 object에서 key값이 ‘key’ 프로퍼티의 값이고, 번역어가 ‘value’ 프로퍼티의 값.

Bomber Crew의 메뉴 화면에는 ‘NEW GAME’, ‘NEW GAME – skip training’, ‘LOAD GAME’, ‘MEMORIAL’, ‘CHANGE LANGUAGE’, ‘QUIT GAME’, CHANGELIST: 4465′, ‘COPYRIGHT ⓒ 2017 RUNNER DUCK GAMES LIMITED. ALL RIGHTS RESERVED.’, ‘DLS AVAILABLE NOW’ 등이 있다.

Bomber Crew Menu screen.png

그 중에서 ‘NEW GAME – skip training’을 찾아본다. 마찬가지로 ‘resources.assets’을 nodepad++로 열어서 검색한 결과 다음과 같다.

'NEW GAME - skip training' is highlighted in "value": "NEW GAME - skip training", line

Slime Rancher에서 언어 파일을 찾을 때와 마찬가지로 제어 코드가 있는 문장을 위로 스크롤하면서 찾아보면 에셋 이름이 ‘LanguageData.json’이고 글자수가 [FS] ?로 표시된다. 실제로는 1C B9 04 00(Hex; Big-Endian으로 해석하면 309532자)인데 해당하는 문자가 없어서 위와 같이 표시되는 것으로 보인다.

Between Only text area where we search 'NEW GAME - skip training' and mixed text and control code(upper)

LanguageData.json 파일을 txt로 추출해서 메인 화면에 나오는 ‘NEW GAME’, ‘NEW GAME – skip training’, ‘LOAD GAME’, ‘MEMORIAL’, ‘CHANGE LANGUAGE’, ‘QUIT GAME’ 텍스트 뒤에 ‘asdf’를 추가하고 import 한다음 게임을 다시 열어본다.

After modifying resources.assets, there is 'asdf' at the ends of some menu text .

정상적으로 ‘asdf’가 추가된 것으로 보여 해당 파일이 언어 파일이 맞음을 확인하였다. 그럼 한글도 알아서 나오는지 확인해보자. ‘asdf’ 대신 ‘ㅁㄴㅇㄹ’를 추가하고 다시 import 한 다음 게임을 실행한다.  분명히 한글을 추가했는데 수정이 안되어있는 것 처럼 보인다. 추가하는 문자열을 조금 다르게 적용해본다. ‘ㅁaㄴsㅇ.dㄹf’ 같이 추가해두면 수정이 되었는지, 한글이 지원되는지 한번에 알 수 있다. 보면 한글이 아예 출력자체가 안됨을 확인할 수 있다.

After modifying resources.assets, there is 'as.df' at the ends of some menu text ..png

Detention

  • 경로 : {{Build Name}}_Data\8_Translations\{{ISO 639 Alpha-2 Code}}.xls
  • 언어 파일 : xls, 각 시트의 A 열(ID 열)이 key, B 열(Data 열)부터 번역어. 특이하게도 B열만 쓰는 것이 아니라 C, D, E 열등도 사용함.

Detention의 Data폴더에는 기본 데이터 폴더 이외에도 눈에 띄는 폴더가 2개가 있다. ‘8_Translations’, 폴더와 ‘GI’ 폴더가 보이는데, 대강 훓어봐도 ‘8_Translations’ 폴더에 언어 파일이 있을 것이라 짐작된다. 두 폴더를 열어서 안의 내용물이 무엇인지 확인해본다.

Detention_Data folder contents. '8_Translations', 'GI' folders are selected.

‘8_Translations’ 폴더에는 파일 이름이 중국어, 영어, 일본어의 준말로 되어있는 파일이 존재한다. 아마도 이 파일일 것이라 생각되지만 나머지 ‘GI’ 폴더의 내용물도 확인해본다.

Detention_Data8_Translations folder contents

GI\level{{Number}}\{{Hex}}\ 폴더 안에는 지금까지 단 한번도 본적이 없는 확장자를 단 파일들이 있는데 이 것보다는 위의 ‘8_Translations’ 폴더가 확률이 더 높으니 위의 폴더를 살펴보도록 한다.

Detention_DataGIlevel{{number}}{{Hex}} folder contents

‘8_Translations’ 폴더 안에 ‘en.xls’ 파일을 열어보면 다양한 문장이 존재하는 것을 볼 수 있다.

Detention - Contents of {{Build Name}}_Data8-Translationsen.xls

게임을 실행해서 메뉴 화면을 확인한다. 게임 화면에는 ‘New Game’, ‘Exit’, ‘About’, ‘Setting’ 이 표시된다.

Menu screen. There are 'New Game', 'Exit', 'About', 'Setting' texts

언어 파일에서 해당하는 텍스트를 찾으려고 했지만 발견하지 못했다. 찾은 언어 파일이 더미 파일이라 보기에는 안에 들어있는 내용이 많기 때문에, 메뉴에 있는 해당 텍스트가 Level에 하드코딩 됬을 가능성을 생각하고 Setting 안에 있는 텍스트로 다시 확인해보도록 한다.

Setting menu. There are 'Video', 'Resolution', 'Windowed', 'Brightness', 'Default', 'Audio', 'Volume', 'Confirm', 'Cancel' texts.

언어 파일에서 ‘Resolution’ 으로 검색을 하니 검색결과가 ‘System’ 시트와 ‘Notebook’ 시트에 각각 나왔다.

Search result of 'Resolution'. There are two exactly same result in 'System' and 'Notebook' sheet in 'Detention' game

System 시트에 있는 단어들 중 위의 Setting 창에 있던 텍스트들의 가운데에 ‘ㅁaㄴs.ㅇdㄹf’을 추가하고 ‘Resolution’에만 ‘Notebook’ 시트에 있는 ‘Resolution’과 구분하기 위하여 숫자를 붙였다.

Modifiy sentence which are assumed as ui text by adding 'ㅁaㄴs.ㅇdㄹf' at mittle of these.

System 시트에 있는 내용만 봐도 이 시트가 Setting 메뉴에 해당함을 짐작할 수 있지만, 혹시나해서 ‘Notebook’ 시트에도 동일하게 작업을 하였다.

Modifiy 'Resolution' to 'Resoㅁaㄴs.ㅇdㄹf2lution' from Notebook sheet.

한글이 정상적으로 나오기는 한데, 공간에 제약이 일부 있는 것 같다.

Detention - After modifying UI texts in en.xls, there is 'ㅁaㄴs.ㅇdㄹf' at the middle of some menu text. and some charactor is cut

 

My Time at Portia

  • 경로 : {{Build Name}}_Data\StreamingAssets\LocalDb.bytes
  • 언어 파일 : SQLite3, Translation_hint 테이블의 ID 열이 key,  ‘English’, ‘Chinese’ 열이 각 언어에 대응되는 번역어.

메뉴 화면이 아래와 같은데 ‘New’, ‘Load’, ‘Options’, ‘Exit’ 같은건 언어 파일외에도 존재할 것 같아서 다른 문자열을 찾아보고자 한다.

My Time at Portia menu screen.png

‘Options’을 클릭해서 나온 문장 중 ‘Camera Sensitivity’가 눈에 띄여서 이 문장으로 검색하기로 하였다.

My Time at Portia option screen.png

게임 폴더의 StreamingAssets 폴더 안에 LocalDb.bytes란 파일이 있다.

{{Build Name}}_DataStreamingAssetsCccData, 'LocalDb.bytes' file is

notepad++로 열어 ‘Camera Sensitivity’ 을 검색해본 결과이다.

Search result of 'Camera Sensitivity' and highlighted in ~sentence in 'My Time at Portia' game

‘DB Browser for SQLite’로 열어서 ‘Translation_hint’ 테이블에서 ‘English’ 열에 ‘Camera Sensitivity’로 검색해본 결과이다. 그 외에 안에 들어있는 내용물을 보니 언어 파일이 맞는 것 같다. 그럼 안에 있는 내용물을 수정해서 확인해보도록 한다.

In 'DB Browser for SQLite' program, open 'LocalDb.bytes' file, view 'Data View' tab, 'Translation_hint' table is selected, value column is filtered as 'Camera Sensitivity'

아래와 같이 ‘□a□s□.d□f’로 표시되는 것으로 보아 언어 파일은 맞으나 한글은 지원하지 않는 것으로 보인다.

My Time at Portia - After modifying UI texts in LocalDb.bytes, there is '□a□s□.d□f' at the middle of some menu text .

My Time at Portia - After modifying UI texts in LocalDb.bytes, there is '□a□s□.d□f' at the middle of some menu text. 2

 

The Elder Scrolls: Legends

  • 경로 : Application.persistentDataPath\Localization.db
  • 언어 파일 : SQLite3, ‘Lookup’ 테이블에서 ‘key’ column이 key이고 ‘value’ column이 번역어.

게임을 실행하고 멈춰져있는 화면이 나오는 장면이 아래와 같다. 무조건 해당 종족 고정되는건 아니고 무작위로 나오는 것 같다. 여튼 해당 종족의 문구를 기반으로 실제 해당 대사가 있는지 찾아본다. 설명에는

The clanfolk of the Valenwood are the finest archers in Tamriel, excelling at hunting and dispatching the unwary.
As a Wood Elf, you will more quickly collect cards that prey on weakened foes.

로 표시되어있다. 해당 문장 중 일부 또는 전체를 찾아본다.

The Elder Scrolls_ Legends first screen.png

엘더스크롤 레전드 게임은 app.info에 나와있는 제작사가 ‘Dire Wolf Digital’ 이고 게임명은 ‘The Elder Scrolls: Legends’ 이다. ‘:’는 폴더명으로 쓸 수 없기 때문에 ‘:’ 가 ‘_’로 바뀌어서 ‘Application.persistentDataPath’ 이 ‘C:\Users\nakwonelec\AppData\LocalLow\Dire Wolf Digital\The Elder Scrolls_ Legends’이 된다.

‘Application.persistentDataPath’ 폴더에 확장자가 ‘db’인 파일이 있다.

Application.persistentDataPath folder LocalizationDB.db file is

해당 파일을 ‘DB Browser for SQLite’로 열어보고 안에 있는 테이블을 확인해볼때 ‘Lookup’ 테이블에서 해당 대사가 발견되었다.

In 'DB Browser for SQLite' program, open 'LocalizationDB.db' file, view 'Data View' tab, 'Lookup' table is selected, value column is filtered as 'The clanfo'

같은 문장을 가지고 있는 key가 여러개 발견되었다. 중간에 ‘ㅁaㄴs.ㅇdㄹf’을 넣고 그 뒤에 구분하기 위하여 1부터 5까지 숫자를 하나씩 추가해준다.

Modifiy some sentences which are assumed as ui menu text by adding 'ㅁaㄴs.ㅇdㄹf1'(2,3,4,5) at end of these.

저장한 후 게임에서 다시 확인해본다. 게임에서는 ‘ㅁaㄴs.ㅇdㄹf5’가 표시되는 것으로 봐서 한글도 되고 ui는 key값이 Hex 형태로 되어있는 것이 아니라 xxxx.xxxxx.xxxx 형태로 되어있는 것으로 추정된다.

After modifying Localization.db, there is 'ㅁaㄴ.ㅇdㄹf5' at the ends of some menu text ..png

그러나, 계속 확인해본 결과 카드의 설명란에서는 한글이 적용되지 않음을 확인하였다.

Modifiy sentence which are assumed as card description text by adding 'ㅁaㄴs.ㅇdㄹf' at end of that.

The Elder Scrolls_ Legends - After modifying card description in Localization.db, there is 'as.df' at the ends of some menu text .

 

Mansions of Madness

  • 경로 : Webplayer cache\
  • 언어 파일 : SQLite3, Translation_hint 테이블의 ID 열이 key,  ‘English’, ‘Chinese’ 열이 각 언어에 대응되는 번역어.

게임을 실행해보기에 앞서 Data 폴더를 살펴보면 StreamingAssets 폴더가 있는것을 알 수 있다. 폴더 안의 내용물은 아래와 같고, 대충 살펴보면 localization을 위한 폴더가 눈에 띄게 있음을 알 수 있다.

.\-AssetBundles
.  \-1.4.5
.    \-Windows
.      | Windows
.      | Windowsunpacked
.      | Windows.manifest
.      |
.      +-audio
.      | +-aa
.      | |   en
.      | |   en.manifest
.      | |
.      | +-an
.      | |   en
.      | |   en.manifest
.      | |
.      | +-coe
.      | |   en
.      | |   en.manifest
.      | |
.      | |    ︙
.      | +-sb
.      | |   en
.      | |   en.manifest
.      | |
.      | +-vi
.      | |   en
.      | |   en.manifest
.      | |
.      | \-wlw
.      |     en
.      |     en.manifest
.      |
.      +-localization
.      |   dlc
.      |   dlc.manifest
.      |   languages
.      |   languages.manifest
.      |   mad20
.      |   mad20.manifest
.      |   mad21
.      |   mad21.manifest
.      |   mad22
.      |   mad22unpacked
.      |   mad22.manifest
.      |   mad23
.      |   mad23.manifest
.      |   mad25
.      |   mad25.manifest
.      |   main
.      |   main.manifest
.      |
.      \-textures
.        \-logomad20
.            en
.            en.manifest

StreamingAssets\AssetBundle\1.4.5\Windows\localization 폴더에 있는 AssetBundle 파일을 압축해제한 다음 ‘Info’로 Assets을 바로 열어서 안에 언어 파일이 있는지 확인하고 ‘Plugins’로 TextAsset을 추출하여 게임 내 대사를 찾아보아도 되고, Assets 파일을 확인할 때 처럼, Assets 파일을 ‘Export’ 한다음 이를 텍스트 에디터로 열어서 게임 내 대사를 찾아보아도 된다. 여기서는 전자로 확인하겠다.

StreamingAssets\AssetBundle\1.4.5\Windows\localization\main AssetBundle 파일 안에 있는 Asset에서 이름이 Localization_{{ISO 639 Alpha-2 code}}인 TextAsset이 발견되었다.

Content of assets in 'main' AsseBundle.

이를 추출 한 후 언어 파일이 맞는지 확인하기 위하여 일부를 수정한 후 Assets에 Import하고 AssetBundle로 저장한다.

Mansions of Madness - Modifiy some sentences which are assumed as ui menu text by adding 'ㅁaㄴs.ㅇdㄹf' at middle of these.

그런데, 게임 실행해보면 적용이 안된다. 메뉴만 그런가 싶어서 다른곳도 수정해봤는데 안된다. 어셈블리 뜯어봐서 정확하게 알게된 사실이지만 에셋을 인터넷에서 받아오게 되어있다. 유니티 Data 폴더안에 없으면 다른 곳에 눈을 돌려보자.

Application.persistentDataPath 폴더 내용물
(C:\Users\{{User Name}}\AppData\LocalLow\Fantasy Flight Games\Mansions of Madness Second Edition)

.+-SavedGame
.\-Unity
.  \-01494d90-2de4-457d-a0ea-96876806eb41
.    \-Analytics
.      | config
.      | values
.      |
.      \-ArchivedEvents

Webplayer cache 폴더 내용물
(C:\Users\{{User Name}}\AppData\LocalLow\Unity\WebPlayer\Cache\Fantasy Flight Games_Mansions of Madness Second Edition)

.| __info
.|
.+-29f94b687fca72e4a5e712749cad0d9e94613692
.|   __data
.|   __info
.|
.+-362d1b721c3178f3191987c24aa498640238ffc1
.|   __data
.|   __info
.|
.|  ︙
.+-e34f17d2e77d4de980b072e6881b9267280bba81
.|   __data
.|   __info
.|
.\-e7d51fef12b8703231622d3b14c416d22523d917
.    __data
.    __info

Application.persistentDataPath 폴더에는 Save 파일 외에는 특별할 것이 없다. Webplayer cache 폴더에는 게임을 실행한 시점이후로 여러개의 파일을 다운받은 흔적이 있다. 안에 있는 AssetBundle을 하나하나 열어보면서 안의 내용물을 확인해본다.

Webplayer cache 폴더\e7d51fef12b8703231622d3b14c416d22523d917\__data AssetBundle 파일의 Assets 내용물이 StreamingAssets\AssetBundle\1.4.5\Windows\localization\main AssetBundle 파일의 Assets 내용물과 구조가 비슷했다.

Content of assets in 'Webplayer cachee7d51fef12b8703231622d3b14c416d22523d917__data' AsseBundle.

위에서 언어 파일을 수정한 것과 같은 방식으로 수정하고 게임상에서 확인해본다. 이번에는 추가한 글자가 정상적으로 나타나고, 한글도 출력되는 것을 확인할 수 있다.

After modifying UI texts in Webplayer cache AssetBundle, there is 'ㅁaㄴs.ㅇdㄹf' at the middle of some menu text.

 

Cat Quest

  • 경로 : sharedassets0.assets 내 strings.{{ISO 639 Alpha-2 code}} TextAsset
  • 언어 파일 : Text, key와 번역어는 ‘,'(콤마)로 구분되어 있고, 콤마 기준으로 왼쪽이 key 오른쪽이 번역어.

게임을 실행하고, 초반의 컷신이 지나간 뒤 나타나는 메뉴 화면에는 ‘NEW GAME’, ‘CONTINUE’, ‘SETTINGS’, ‘CAT QUEST IS A COPYRIGHT OF THE GENTLEBROS PTE. LTD. 2017.

Cat Quest - Menu screen. There are 'NEW GAME', 'CONTINUE', 'SETTINGS' texts..png

게임 폴더에는 기본 폴더외에 ‘GI’, ‘StreamingAssets’ 폴더가 보이고, 게임을 실행할 때 에셋을 외부에서 받아오는 것 같아보이지는 않는다. ‘GI’ 폴더는 무시하고, ‘SteamingAssets’ 폴더에는 확장자가 ‘chroma’인 파일 밖에 없다. 안을 notepad++로 열어보니 의미 없는 값들만 있어서 일단 배제하도록 한다. 메뉴 화면에 나온 텍스트를 assets 파일에서 찾아본다. ‘resources.assets’에는 일치하는 문장이 없었고, 특이하게도 ‘sharedassets0.assets’ 파일에서 일치하는 문장이 발견되었다.

Cat Quest - Search resoult of 'NEW GAME' in sharedassets0.assets file. It is highlighted in 'TITLESCENE_01,New Game' sentence.

위로 스크롤을 하다보면 에셋의 정보가 담긴 부분이 나온다. 여기서는 에셋의 이름이 ‘strings.en’으로 나타나있다.

Cat Quest - Between Only text area where we search 'New Game' and mixed text and control code(upper). Asset name is found as 'strings.en'

이를 ‘sharedassets0.assets’ 파일을 UABE로 열어서 해당 에셋을 찾아본다.

Cat Quest - Content of assets in 'sharedassets0.assets' after load globalgamemanager asset. 'strings.en' TextAsset' is.

언어 파일로 추정되는 ‘strings.en’ 을 추출하여 notepad++로 열어보면 다음과 같다.

Cat Quest - Contents of 'strings.en' TextAsset.

메뉴 화면에 있었던 문장을 찾아 문장 사이에 ‘ㅁaㄴs.dㅇfㄹ’을 추가하고 원래 있었던 곳인 ‘sharedassets0.assets’에 Import한 뒤 저장한다.

Cat Quest - Modifiy some sentences which are assumed as ui menu text by adding 'ㅁaㄴs.ㅇdㄹf' at middle of these.

sharedassets0.assets을 수정한 후 게임을 실행해보면, 문장이 수정된 것으로 보아 assets 파일에서 찾은 언어 파일이 실제 언어 파일인 것으로 확인되었다. 하지만 한글이 ‘□’로 표시되는 것으로 보아 폰트를 수정해야 할것으로 보인다.

After modifying UI texts in sharedassets0.assets, there is '□a□s.□d□f' at the middle of some menu text.

 

번외: 하드코딩

 

유니티 게임의 한글화와 패치 제작 – 언어 파일”의 20개의 생각

    1. 본 강좌는 게임을 번역할 수 있는지 없는지 확인해보는 과정을 적어둔 것이고, 실제 패처를 만들어서 배포에 이르기까지는 UnityL10nTool 을 참고하시면 됩니다.

      좋아요

    1. 수동으로 직접 하실꺼면 UABE로 level0 를 열어서 텍스트에 관여하는 Type(class) 만 정렬하고, export dump, import dump를 통해 수정하실 수 있을껍니다

      좋아요

  1. 댓글에 사진이 첨부되지 않아 명확히 말씀드리긴 어렵지만, ㅁ로 나오는 대부분의 경우는 한글 폰트가 없기 때문이며 https://github.com/dmc31a42/UnityL10nTool/wiki/Home-ko-KR 로 폰트 패치를 시도해보시기 바랍니다. 폰트 패치의 이론적 배경은 https://blog.nakwonelec.com/2018/04/20/%ed%8f%b0%ed%8a%b8-%ec%97%94%ec%a7%84%ed%94%8c%eb%9f%ac%ea%b7%b8%ec%9d%b8-%ec%86%8c%ea%b0%9c/ 이 글을 참고해보시기 바랍니다.

    좋아요

  2. 안녕하세요. 블로그의 글들로 많은 도움을 받고 있습니다. 최근에 번역을 시도하려고 하는 게임이 있는데 asset 파일까지느 찾았습니다. 헥사 에디터나 노트패드를 열면 대사들이 나옵니다. 하지만 UABE 로 asset을 들어가서 플러그인으로 txt 파일로 추출하려하였으나 각각의 asset info에 들어가서 확인해보면 txt 파일로 추출되는 asset이 보이지 않습니다. 방법이 없을까요?

    좋아요

  3. 태오회권이라는 중국 게임을 이 프로그램을 통해 한글화 하게 되었습니다.
    지난 11월경에 패치로 한글이 미지원되는 폰트로 바뀌고 나서 한글화가 막혀 많이 혼란스러웠는데, 이 프로그램을 사용해 한글화가 대략적으로 완료되었습니다. 지금에서야 감사하다는 인사를 남기게 되었네요. 덕분에 즐겁게 게임을 즐기게 되었습니다. 감사합니다.

    좋아요

  4. 안녕하세요, 올려주신 글 읽으면서 텍스트 찾고 유용하게 잘 활용하고 있습니다. 최근 ボーダーレイン이라는 모바일 게임의 텍스트를 찾고 있는데, 아무리 찾아봐도 텍스트에셋의 위치를 모르겠어서 질문드립니다ㅠ
    apk와 android/data 폴더에서 마땅한 에셋이나 스트리밍에셋 폴더가 보이지 않는데 manifest 파일들을 열어서 경로를 확인해보다가 참조해오는 경로같은 걸 확인했습니다. StreamingAssets 폴더를 발견했는데 Assets폴더 내에 LuaFramework 폴더나, J: 같은 폴더는 보이지 않는데 실제로 어떻게 찾으면 좋을까요? \
    Assets:
    – Assets/LuaFramework/Examples/Builds/Message/MessagePanel.prefab
    Dependencies:
    – J:/SVN_KS_JP_Release/Assets/StreamingAssets/shared_asset.unity3d

    좋아요

  5. 안녕하세요.
    위 글을 읽으며 Everhood라는 게임을 한글화해보려 하고있습니다
    우선 텍스트의 변화가 되는지 확인해보려고 그 메뉴 화면에 있는 글자들을 resources.assets에서 찾아 한글과 영어를 붙여보았지만
    한국어로, 심지어 영어까지 인게임에 변화가 없습니다

    이런 경우에 가능성은
    resources.assets의 텍스트는 인게임에 영향을 주지 못한다
    -> 다른 파일을 찾아보아야한다
    밖에 없을까요?

    좋아요

    1. ‘The Elder Scrolls: Legends’ 게임의 경우 게임내에도 텍스트가 있었고 인터넷에서 업데이트 받아서 오는 텍스트도 있었습니다. 게임 내 파일은 수정해도 반영이 안되고 인터넷에서 우선적으로 받아오는 것을 사용하는데 한번 확인해보세요

      좋아요

  6. 정말 좋은 글 감사합니다. 작성해주신 글에 따라서 번역을 해보려고 하는데, 게임 내 대사들의 위치를 찾고 대사가 수정되는 것 까지 확인했습니다. 그런데 게임 메뉴창의 단어들의 TextAsset을 찾을 수 가 없네요. 위 게임의 cat quest처럼 sharedassets0.assets를 노트패드로 확인해 메뉴의 단어들이 있는것은 확인했으나, 모든 TextAsset를 뒤져보아도 메뉴의 단어들을 찾을 수 가 없네요. 혹시 메뉴의 버튼들만 따로 이미지파일 같이 적용되어있을 가능성이 있나요?

    좋아요

  7. 이 글로 배워서 번역에 도전하려고 하는데 도중에 막혔습니다.
    게임은 Valheim 입니다.
    UABE를 사용해서 txt 파일을 raw dump export 하긴 했는데 2019.4.16f 버전을 지원 안해서 일단 2019.2.0f1으로 불러오긴 했습니다. txt 파일은 잘 열리고 내용물도 잘 보여서 구글 docs나 libreoffice 를 이용해서 엑셀형식으로 보려 했으나 깔끔하게 나오지 않네요.
    형식이 콤마로 셀을 나누고 \r\n으로 새로운 라인을 만드는 것 같은데 어떻게 불러와야 깔끔하게 불러올 수 있을까요? UABE가 2019.4.16f를 지원 안해서 생기는 문제일까요?

    0 TextAsset Base
    1 string m_Name = “localization”
    1 string m_Script = ” ,English,Swedish,French,Italian,German,Spanish,Russian,Romanian,Bulgarian,Macedonian,Finnish,Danish,Icelandic,Turkish,Lithuanian,Czech,Hungarian,Polish,Dutch,Portuguese_European,Portuguese_Brazilian,Chinese,Japanese,Korean\r\n”// COLOR KEY:\n// GREEN is READY FOR TRANSLATION\n// YELLOW is IN PROGRESS, DON’T TRANSLATE\n// RED is UNUSED, DON’T TRANSLATE”,,,,,,,,,,,,,,,,,,,,,,,,

    위는 처음 시작부분입니다.

    좋아요

      1. 감사합니다 plugin을 이용하면 잘 추출되네요
        혹시라도 다른분들에게 도움이 될지 몰라서 언어를 추가한 파일을 적용하는 방법을 적어드리자면
        1. 플러그인으로 txt 추출
        2. libreoffice 로 파일을 열고 수정후
        3. 저장할때는 “복사본 저장” 을 사용하고 csv 확장자가 아닌 txt 확장자로 저장
        4. 저장하려고 하면 하나 창이 뜨는데 valheim의 경우는 “유니코드 8”, 필드 구분은 “,”, 문자열 구분자는 ” ” “, “표시되는 대로 셀 내용 저장”, “계산된 값 대신 셀 수식을 저장”
        5. 그 후에 플러그인을 이용해서 불러오고 리소스 에셋을 저장후에 적용시키시면 됩니다.

        좋아요

댓글 남기기