Using vgperson's Custom Translation Engine Plugin for RPG Maker MV

What is the Custom Translation Engine?

Some of my RPG Maker MV game translations now use a special plugin of my own creation to implement English support. This plugin, dubbed the Custom Translation Engine (CTE), loads and inserts translation data from dedicated language files, aiming to minimize the need to do anything direct to the base game data, put everything needed for translation in an easy-to-find place, and allow for conveniences like in-game language switching.

You can download it here. (People can use and modify it as they wish, so feel free to use it for your own translation projects!) The plugin help text explains many of the plugin's functions, so you should definitely at least skim through it. However, this guide aims to walk you through some specific common use cases.

Note that I've made various updates to the plugin over time, so if some things described here don't match up with what you have, it may not be the latest version. If you're looking to add to a game that uses CTE, you should redownload the game to be safe.

Case 1: I want to make a translation for a game that uses CTE, based on the original language!

Open the game in RPG Maker MV, go to Tools > Plugin Mamager, and edit settings for CustomTranslationEngine (at the very bottom of the plugin list, usually).

Add a new language code to the Language Codes list to represent the language of your translation. Turn on "Export Base Text," press OK to save the settings, and hit Playtest. Upon launching, the game should generate a text file or subfolder in the "languages" folder containing the relevant text for the Base Language. Rename it to your language code, and you're more or less set to start translating.

There are various options for how to split up text across files, ranging from "everything in one text file" to "subfolder with individual files for every map, common event, troop event, and database." If you don't like the way it's currently split up, you can customize this in the plugin settings, then run Export Base Text again.

IMPORTANT NOTE: The Extra section (found at the end of the all-in-one language file, at the end of AllDatabases.txt, or in Extra.txt) is a special case. While it does also include a few "Core Language Settings," it's mainly a section for additional string definitions that are not (and cannot be) automatically exported from the game because they're only referred to by JavaScript code, whether in events or plugins.

Thus, you'll want to refer to other language files' Extra sections (or the bottom of ReferenceTable.csv, which lists each language side by side) and copy over the missing value definitions. (And if you need to know what the values/strings are defined as for the base language, you'll have to track down where they're used and look for the "default" argument.)

Case 2: I want to make a translation for a game that uses CTE, based on existing CTE language files!

Open the game in RPG Maker MV, go to Tools > Plugin Mamager, and edit settings for CustomTranslationEngine (at the very bottom of the plugin list, usually). Add a new language code to the Language Codes list to represent the language of your translation.

The next step depends on what format the language you want to work from is in. If there's a TXT file with that language code, or a subfolder named after the language code full of TXT files, all you have to do is make a copy of it, rename it to your language code, and you're more or less set to start translating.

If there's only a ".cte" file - which holds only the necessary data in a compressed and encrypted form - you'll need to get the uncompressed TXT scripts. My translations are usually released in .cte format, but it is possible to export the data from a CTE back to TXT scripts. (That said, if it's one of my English translations, you can contact me to provide the unextracted files, which will typically include helpful comments for Variables and Extra sections that are otherwise lost.)

To generate TXT scripts from a CTE, start a Playtest. If you're not already using the language you want to base yours on, go into the Options menu and select it. Go to a part of the game that isn't the title screen or mid-cutscene, and hold down the Script Reload key (default F10). Select "Export reformatted language text." This will export "XX (Reformated)", where XX is the language code. Rename it to your language code (without Reformatted), and it should be ready for translation.

Case 3: I want to implement CTE into a game that doesn't have it to make a translation!

Download the standard CustomTranslationEngine.js and put it in the "js/plugins" folder. Open the game in RPG Maker MV, go to Tools > Plugin Mamager, and add it to the plugin list. (Where it's placed in the list can be important, but it generally only matters when other plugins get involved in the translation, and you can move it if necessary.) Open up its plugin settings, and read the "Setup Procedure" section of the plugin help text for a basic outline of how to get started.

When you encounter something beyond the extent of what's in the exported scripts that needs to be change between languages (text that's part of plugins, script commands in events, pictures that need repositioning, etc.), there are a few ways you can go about addressing it. While you can add conditions directly checking for a certain language, like ConfigManager.isLanguage("JP") or ConfigManager.isBaseLanguage(), this isn't a very flexible approach if you or others add more languages in the future.

Instead, the best practice (when possible) is to add a number or string definition to the Extra section, and edit the code to use that value/alter behavior based on that value. This makes it easy for each language to define everything just through the scripts. You can obtain Extra values for the current language using CTE.getNumber("VariableName", 0) or CTE.getString("VariableName", "defaultString"), where "0" and "defaultString" are what to use for the base language or if that value is not defined in the current language.

For dealing with plugin text, the easiest way is to edit the plugins directly to replace direct string references with a call to CTE.getString. (It's generally recommended to replace the part of the code that actually displays the text. If you instead replace something like plugin parameter being assigned to a variable, it may not properly update when you switch languages.)

Note that if you want to minimize changes to the base game (mostly so it's easier to handle game updates), you can instead add code to the bottom of CustomTranslationEngine.js (or in some plugin of your own) that replaces/extends the relevant plugin functions to make these edits, though this tends to require more knowledge of JavaScript than direct edits do.

Finally, with a little JavaScript coding, it's possible to add custom comments to scripts to help give more context when translating. The "Customizable Handlers" section of CustomTranslationEngine.js has placeholder functions you can, well, customize - read the comments above them for details.

In particular, "commandExportHandlerPrefix" lets you check for certain command types and parameters to include a helpful comment before the command is written in the script. This can be used for all sorts of things - noting what character is speaking, pictures or sound effects, whatever you deem necessary. (It may help to refer to specific games' versions of this function for reference on what can be done and how to do it.)

The details provided by commandExportHandlerPrefix/Postfix will be included when exporting base language scripts, but if you have existing language scripts you want to update with them, that's a good case for Export Reformatted Language Text. Switch to the language in question, go to a part of the game that isn't the title screen or mid-cutscene, and hold down the Script Reload key (default F10). Select "Export reformatted language text." This will export "XX (Reformated)", a sort of "refreshed" version of the language scripts based on the latest game data, but retaining all the translated text.

Note, though, that reformatting can result in loss of clarity/comments in the Variables and Extra database sections in particular, so you may want to copy those from the pre-reformat scripts.

Addendum 1: How do I translate images?

Whenever the game loads any image, the CTE plugin checks to see if there's a different version of that image corresponding to the current language, and if there is, it automatically loads that instead.

Adding edited images to use for a specific language is very simple: go to the image folder containing the original image (i.e. img/pictures), make a subfolder with the language code if one doesn't already exist (i.e. img/pictures/EN), and put the edited image in there using the same filename. Also, it doesn't matter if an image needs to be changed for some languages but not others - again, it's all automatic.

Also, keep in mind that the game's encrypted image settings also apply to these images - if the rest of the images are encrypted, your language's images should be too. If you need to convert from .rpgmvp to .png or vice versa, there are decrypters for that online.

(Note that if you're releasing the game in a browser, you'll need a TranslationImages.txt file to serve as a lookup for edited images. Enable Make Image List in the plugin settings to auto-generate it.)

Addendum 2: What are .cte files, and how do I make them?

CTE files are compressed and lightly-encrypted files that hold all text data for a language. They're recommended for release versions over raw TXT scripts, given they're small and singular files whose encryption will keep the average user from being able to just look through the text data.

As long as you have the plugin setting Generate CTE Files enabled, CTE files for each language will be regularly auto-generated from the latest TXT scripts during playtests (on launch, on script reload, etc). And if Load From CTE Files is enabled, the game will prefer to load its language data from CTE files, so you only need to include "XX.cte" (where XX is the language code) for release.

As described elsewhere in this guide, TXT scripts can be rebuilt from CTE files - though because CTE files only hold relevant data, any manually-added comments from the original TXT scripts will be lost. So if you have added comments, be careful to avoid losing your TXT scripts so you don't lose those.

Addendum 3: How do I accomodate updates to the game?

Rather than mapping to specific text strings, language scripts depend on map IDs, event IDs, page numbers, and order of text commands remaining the same. Thus, your main concern when a game updates is how these things have changed. The best way to update your scripts, then, is to compare base language scripts exported from the previous version of the game with base language scripts exported from the latest version of the game. (I recommend the program WinMerge.)

Once you've brought your scripts up to date to the best of your ability, a useful tool for identifying any remaining missing text/mismatches/etc. is the Reference Table. Enable "Export Reference Table" in the CTE plugin settings, and when starting in playtest mode, it will export a CSV file that puts each language's text side by side.

A search for "<<<NOT FOUND>>>" will show places where the translation is missing text found in the base data, while "<<<NOT FOUND IN BASE>>>" shows the opposite case of translation text that doesn't match to anything in the base data. If you open the debug console (F12 in playtest), issues found while exporting the table will also be mentioned there.

Addendum 4: How do I update my existing pre-CTE translation of Your Turn To Die/Your Time To Shine to the latest CTE-using version?

It's easier than you might think! Probably.

The first thing you should do is get the text from your translated version in language script format. Put CustomTranslationEngine.js (best to copy the one from YTTD/YTTS) in the "js/plugins" folder of your version, add it to the plugins list, and enable Export Base Text in the plugin settings. Launch the game to export the scripts to the "languages" folder - the folder will likely be named "JP," since that's the default setting for Base Language. Rename that folder to your desired language code, copy it over to the languages folder in the latest version of YTTD/YTTS, and you're already most of the way there text-wise.

Image-wise, you should identify what images you've edited for your translation. Compare your version's "img" folder with the "img" folder in the latest version of YTTD/YTTS, and copy out any images that differ from the Japanese images, ignoring any language subfolders like EN. (I recommend the program WinMerge to do this.) Over in the new YTTD/YTTS, create subfolders for your language code (ala img/pictures/EN, img/titles2/EN, etc.) and place the images in their appropriate locations. That's basically it for images!

Next, a small but important thing: supporting saves from the previous version of your translation. Open up js/plugins/CustomTranslationEngine.js and search for the DataManager.loadGlobalInfo function definition toward the bottom. This function automatically converts any game titles in the localizedNames array to the Japanese title used in the base data (i.e. "Your Turn To Die" becomes "多数決デスゲーム"). Add your localized title to the list if it isn't already there; this makes it so saves with that title can still be loaded, rather than being treated as saves from another game and grayed out.

Also for the sake of supporting saves, the same process is applied for localized strings in variables in the DataManager.loadGameWithoutRescue function below. This is less important, though, as it's only an issue that can prevent progress if you load a save from specific parts of Chapter 3-1b. (Specifically, if there's a "target item" you need to present in discussion, and the string for it is localized in the save data, since the "current item" strings assigned when you select items are now internally Japanese, it becomes impossible to present the "right" item.)

Other than identifying minor language script issues with the help of the Reference Table (see Addendum 2), the remainder of the work from here revolves around the Variables and Extra database sections. While you can follow the steps given in Case 2 to extract the data from EN.cte, you may want to contact me to ask for a version with full comments, as it can be unclear what everything is without them.

The Variables section as exported from your original version will have a bunch of translated (for the most part) strings being repeated twice, but what you ultimately want is for the first line to be the Japanese string and the second line to be the translated string for your language. The exported Extra section will be mostly empty, save for some Core Translation Settings, so copy the missing Extra definitions from an existing language or from the scripts I provide you.

Below are specific rundowns on what's in YTTD and YTTS's Variables and Extra sections. (Click to reveal, as these contain spoilers for those games!)

Your Turn To Die: Variables Section

Amusingly, there are no string variables that get displayed until Chapter 3-1b, which then has quite a few of them.

V3 holds the names of the currently-equipped item in discussions. (This approach only started being used in 3-1b's discussion segment.)
V854 holds the names of the items in the locker room puzzle segment.
V921 holds the names of the characters who can be randomly targeted in the second Maple battle.
V921 also holds strings referencing other characters (changing depending on who's alive and thus who's talking) for certain lines about the hot cocoa in Common 1652.
V922 holds the actions characters can perform on the AIs in the second Maple battle.
V983 and V988 hold the names of victims in Russian Roulette, which can differ based on your choices.
V999 holds the string for the Shin AI stating that the shutter is "closed" or "open."

Your Turn To Die: Extra Values/Strings

The Core Language Settings are fairly self-explanatory (and are included in base text export with explanatory comments): the text for the language option in Options, the default font face (i.e. GameFont), and the default speed of messages. Contrary to the default CTE comment saying only specific speed factors are allowed, YTTD/YTTS's use of a message speed plugin means any speed factor can be used. If you want the message speed used in English, set it to "1.33x".

AnimationConvert_[ID] serves to convert animations from one ID to another; "AnimationConvert_4=45" makes animation 4 (the Japanese "This is it!!") turn into animation 45 (the English equivalent). Note that if you want to avoid the need to actually add new animations to the Animations database (and thus be independent of game data changes), you can make your animation in the editor, then copy the JSON string for the animation entry from Animations.json and use that as the value, i.e. AnimationConvert_4={"id": ... } (Just make sure it's all on one line, and check the debug console for parsing errors when the animation plays.)

MakeBalanceBattlesHorizontal=1 forces all Balance Battles to show the statement images (b-1 to b-16) in a horizontal manner, since in the Japanese version, the Balance Battle between Kai and Nao uses vertical text.

TotalTokensDisplayX/Y can be used to reposition the total token count (medaru-menyu10~100) in the 2-1 Prize Exchange token menu, since unless the "Total" text is on the same bottom baseline as the Japanese, it can look oddly aligned.

BlackboardName_koku#-#_X/Y give the X and Y coordinates of the highlighted name pictures on the blackboard (koku1-1 to koku4-3), for the part in the second Main Game where the names on the roster are compared to the blackboard.

ShutterStatusX gives the X position of the "Open/Closed" images for the "Shutter ... Open/Closed" text on the control room coffin monitor, since it's just a single character in Japanese, whereas other languages may need to reposition it to fit.

NameBoxWidth_[Name] gives the width of various characters' names when displaying "fake" message boxes for them (i.e. for reacted-to messages in Main Game 2 or the Hinako flashback in 3-1b), so as to decide what size of name box image to use. 1 English letter is 1 "width unit," so in English this is just the letter length of their name, but other symbols, such as Japanese characters, take up 2 units. Note that there are currently only name boxes of size 3, 4, 5, and 6.

NameEntryTables defines what character set to show for the Midori naming screen. It currently supports three settings for using preset tables: JP (Japanese), EN (Latin), and RU (Russian). If you instead specify a custom array of 90 elements (ending with strings corresponding to Backspace and OK, or Backspace/Page/OK for multiple pages), or an array of 90-element arrays (for multiple pages), it will use that instead. (Check the debug console for info if there's an error parsing it.)

NameEntryWidth is the width of the name entry box (default 480), if you need to make it wider to fit the name display. (520, used for English, should be sufficient to hold a 16-letter name.)

NameEntryMax is the character limit (not a width limit like NameBoxWidth) for Midori's name. Currently only the values 8 (the Japanese limit) or 16 (the maximum allowed) will work.

OptionTouchpadMode is the name for the Minigame Auto-Click option.

BacklogPageNumber is the header of the backlog opened by pressing Page Up.

FirstTrialCode is the useless code in the First Trial, modified to 3141 in English since it was a number pun.

DText_[String] are replacements for strings drawn with DTEXT, namely the Clout/Mind text on the "health bar" in discussions.

Name_[Name] defines translations for all speaker names. To get these from a pre-CTE translation, I'd recommend using Notepad++ or something to search through the files in the data folder for all "NameBoxSet" commands.

ItemExtraDesc## are additional item descriptions for the corresponding item ID (defined in their Note section) in the few cases where you can tap the box to get more info. Use \n for linebreaks.

GlossaryCommand/Help are the strings for the Items glossary. ItemDesc## are the glossary descriptions for the corresponding item IDs (defined in their Note section). Use \n for linebreaks.

MidoriDefaultName is the name that initially appears for Midori's naming screen. Midori_[NameString] are the various names he checks for and has responses to, ignoring letter case, spaces, and hyphens. In a few cases, like the spelling of Joe/Jou and the "full name" of Sue Miley, there was reason to include additional checks relative to the Japanese (though they just go to an existing response), so those are marked with "_Other".

TalkSpriteName_[Name] isn't for something that shows up in-game, but rather for the comments noting character talk sprites in exported scripts. Most refer to Name_ definitions to name the characters, but a few don't have any speaker names to refer to, so they end up here. TalkSpriteFormatWith/WithoutExpression also describes the format for how talk sprites are presented in scripts.

Your Time To Shine: Variables Section

V555 holds the name of the person who's randomly fed by the Small Trap, or healed by Kanna's special ability.

V669 is a general-purpose string variable that holds a lot of different things:
It holds the name of the protagonist as referred to by Sara in the version of the Day 17 scene where the hut is abandoned.
It holds the name of the protagonist as referred to by Jin at the end of the Day 24 scene.
It holds the name of the protagonist as referred to by Jin in the Day 29 scene - a partial overlap with the Day 24 ones, though he does say "Kazumi" on Day 24 vs. "Mishima" on Day 29.
It holds the name of the current special item in Safalin's shop, and V670 holds the string for how Safalin describes it.
It holds the "first/second/third" text used in each judge's introduction line for Kai's cooking competitions.
It holds the different quality descriptions of ingredients for Kai's cooking competitions, and V670 holds the name of the ingredient type.
It holds the name of the partner that shows up to help Kai for cooking competitions, as referred to by Kai.

V679 holds the name of the protagonist for generic ending titles, i.e. "___'s Story: "Normality Regained" End"

V681 holds Kai's description of his current stamina in cooking competitions.

Your Time To Shine: Extra Values/Strings

The Core Language Settings are fairly self-explanatory (and are included in base text export with explanatory comments): the text for the language option in Options, the default font face (i.e. GameFont), and the default speed of messages. Contrary to the default CTE comment saying only specific speed factors are allowed, YTTD/YTTS's use of a message speed plugin means any speed factor can be used. If you want the message speed used in English, set it to "1.33x".

AnimationConvert_[ID] serves to convert animations from one ID to another; "AnimationConvert_24=40" makes animation 24 (the Japanese "Time Passes") turn into animation 40 (the English equivalent). Note that if you want to avoid the need to actually add new animations to the Animations database (and thus be independent of game data changes), you can make your animation in the editor, then copy the JSON string for the animation entry from Animations.json and use that as the value, i.e. AnimationConvert_24={"id": ... } (Just make sure it's all on one line, and check the debug console for parsing errors when the animation plays.)

BacklogPageNumber is the header of the backlog opened by pressing Page Up.

DText_[String] are replacements for strings drawn with DTEXT, namely the Day counter, your current material/food count (uses the same counter word in Japanese, so they're not separatable), and your current money count. $1 represents where the number will go. Notably, you may want to make the latter two just be "$1" since there's no real reason for a counter in other languages.

Name_[Name] defines translations for all speaker names. To get these from a pre-CTE translation, I'd recommend using Notepad++ or something to search through the files in the data folder for all "NameBoxSet" commands. Note that some of these names (grouped at the end) come from leftover YTTD events in the data and I don't think are actually used in YTTS, but I included them in my English scripts on the off chance they are.

TalkSpriteName_[Name] isn't for something that shows up in-game, but rather for the comments noting character talk sprites in exported scripts. Most refer to Name_ definitions to name the characters, but a few don't have any speaker names to refer to, so they end up here. TalkSpriteFormatWith/WithoutExpression also describes the format for how talk sprites are presented in scripts.

Posted September 8th, 2022

Post List