v1.0
Introduction
Let's see, another Multiple Language script... this time, for RMVX, featuring everything the RMXP version had, eased up quite a bit, plus a bunch of new stuff - including things people and myself wanted to be in the previous version that never made it to v1.0 (and therefore probably didn't make it in any other game than my BlueSokoban...).
Reincluded Features
- textfile-based string display within your game
- included crediting system for language files
- supports multiple languages accompanying a single game executeable
- supports passing language files to voluntary translators without needing to pass your unencrypted game, plus adding them post-released via copy&paste easily
New and improved Features
- shorter and more hinting-on-the-content tags for messages
- database tags are automatically created by their type and ID, instead of you needing to manually set each
- back to single text file operating, for simplicity and distribution purposes
- automatic language file choice if you only have a single language file in the respective folder
- display of the tag to be specify for undefined strings (means it shows 'M-4', for example, if you call message #4, but don't have it specified in your language file - makes debugging very easy)
- much more lightweight than the previous version, both in performance (uses rewritten and way easier methods now) and compatibility (completely independent from Game_System and some other defaults) means.
- undefined actor, class, skill, item or equipment names get replaced with the name the database contains (regular name output, if you want).
- less thrown-into-the-blue language selection scene due to a customizeable header
Features planned
- Faces and choices in messages
- Support for language-specific images by reading them from a folder in the Language directory
- Replacement strings to display values from game_variables, actor names, gold, and a few more; not only in messages but everywhere

Demo
Multiple Language VX 1.0.zip hosted on box.net (212 KB)
Requires RMVX RTP to run
Script
[rgss]#==============================================================================
# Multiple Language VX v1.0
#------------------------------------------------------------------------------
# Script by BlueScope
#==============================================================================
module Language
#--------------------------------------------------------------------------
def self.list
entries = Dir.entries('Language/.')
entries.delete_at(0); entries.delete_at(0)
entries.sort!
return entries
end
#--------------------------------------------------------------------------
attr :value
@value = list[0]
#--------------------------------------------------------------------------
def self.set_value(id)
@value = self.list[id]
end
#--------------------------------------------------------------------------
def self.test(id)
id = id.split(' ')
file = File.open('Language/' + @value)
content = file.readlines
for line in 0..content.size-1
if content[line].include?(id[0] + ' ')
return true
end
end
return false
end
#--------------------------------------------------------------------------
def self.output(id)
id = id.split(' ')
temp_content = nil
file = File.open('Language/' + @value)
content = file.readlines
for line in 0..content.size-1
if content[line].include?(id[0] + ' ')
temp_content = content[line]
temp_content.gsub!((id[0] + ' '), "")
temp_content.chomp!
end
if temp_content == nil
temp_content = '[' + id.to_s + ']'
end
end
return temp_content
end
#--------------------------------------------------------------------------
end
class Bitmap
#-------------------------------------------------------------------------
def draw_wrap_text(x, y, width, height, text, lineheight)
strings = text.split
strings.each do |string|
word = string + ' '
word_width = text_size(word).width
x, y = 0, y + lineheight if x + word_width > width
self.draw_text(x, y, word_width, height, word)
x += word_width
end
end
#-------------------------------------------------------------------------
end
class Game_Actor < Game_Battler
#--------------------------------------------------------------------------
alias multiple_language_actor_setup setup
def setup(actor_id)
multiple_language_actor_setup(actor_id)
if Language.test('A-' + actor.id.to_s)
@name = Language.output('A-' + actor.id.to_s)
else
@name = actor.name
end
end
#--------------------------------------------------------------------------
end
class Game_Enemy < Game_Battler
#--------------------------------------------------------------------------
alias multiple_language_battler_initialize initialize
def initialize(index, enemy_id)
multiple_language_battler_initialize(index, enemy_id)
if Language.test('E-' + enemy.id.to_s)
@original_name = Language.output('E-' + enemy.id.to_s)
else
@original_name = enemy.name
end
end
#--------------------------------------------------------------------------
end
class Window_Base < Window
#--------------------------------------------------------------------------
def draw_actor_class(actor, x, y)
self.contents.font.color = normal_color
text = 'C-' + actor.class.id.to_s
if Language.test(text) or actor.class.name == ""
self.contents.draw_text(x, y, 108, WLH, Language.output(text))
else
self.contents.draw_text(x, y, 108, WLH, actor.class.name)
end
end
#--------------------------------------------------------------------------
def draw_item_name(item, x, y, enabled = true)
if item.is_a?(RPG::Skill); type = 0
elsif item.is_a?(RPG::Item); type = 2
elsif item.is_a?(RPG::Weapon); type = 4
elsif item.is_a?(RPG::Armor); type = 6; end
if item != nil
draw_icon(item.icon_index, x, y, enabled)
self.contents.font.color = normal_color
self.contents.font.color.alpha = enabled ? 255 : 128
text = 'D-' + type.to_s + '-' + item.id.to_s
if Language.test(text) or item.name == ""
self.contents.draw_text(x + 24, y, 172, WLH, Language.output(text))
else
self.contents.draw_text(x + 24, y, 172, WLH, item.name)
end
end
end
#--------------------------------------------------------------------------
end
class Window_Item < Window_Selectable
#--------------------------------------------------------------------------
def update_help
if item.is_a?(RPG::Item); type = 3
elsif item.is_a?(RPG::Weapon); type = 5
elsif item.is_a?(RPG::Armor); type = 7; end
text = Language.output('D-' + type.to_s + '-' + item.id.to_s)
@help_window.set_text(item == nil ? "" : text)
end
#--------------------------------------------------------------------------
end
class Window_Skill < Window_Selectable
#--------------------------------------------------------------------------
def update_help
text = Language.output('D-1-' + skill.id.to_s)
@help_window.set_text(skill == nil ? "" : text)
end
#--------------------------------------------------------------------------
end
class Window_Message < Window_Selectable
#--------------------------------------------------------------------------
def start_message
@text = $game_message.texts
end
#--------------------------------------------------------------------------
def update_message
contents.clear
if Language.test(@text[0]) == false
text = @text[0]
else
text = Language.output(@text[0])
end
contents.draw_wrap_text(0, -37, self.width-32, self.height-32, text, WLH)
finish_message
end
#--------------------------------------------------------------------------
end
class Window_Version < Window_Base
#--------------------------------------------------------------------------
def initialize
super(224, 192, 288, 96)
refresh
end
#--------------------------------------------------------------------------
def refresh
self.contents.clear
self.contents.font.color = system_color
self.contents.draw_text(4, 0, self.width-40, 32, Language.output('S-2'), 0)
self.contents.draw_text(4, 32, self.width-40, 32, Language.output('S-4'), 0)
self.contents.font.color = normal_color
self.contents.draw_text(4, 0, self.width-40, 32, Language.output('S-3'), 2)
self.contents.draw_text(4, 32, self.width-40, 32, Language.output('S-5'), 2)
end
#--------------------------------------------------------------------------
end
class Window_Header < Window_Base
#--------------------------------------------------------------------------
def initialize
super(32, 128, 480, 64)
refresh
end
#--------------------------------------------------------------------------
def refresh
self.contents.clear
self.contents.draw_text(4, 0, self.width-40, 32, Language.output('S-1'))
end
#--------------------------------------------------------------------------
end
class Scene_Battle < Scene_Base
#--------------------------------------------------------------------------
def display_exp_and_gold
exp = $game_troop.exp_total
gold = $game_troop.gold_total
$game_party.gain_gold(gold)
text = sprintf(Vocab::Victory, $game_party.name)
if exp > 0
text = sprintf(Vocab::ObtainExp, exp)
end
if gold > 0
text = sprintf(Vocab::ObtainGold, gold, Vocab::gold)
end
wait_for_message
end
#--------------------------------------------------------------------------
end
class Scene_Language < Scene_Base
#--------------------------------------------------------------------------
def start
super
@header_window = Window_Header.new
@background_window = Window_Base.new(32, 192, 192, 96)
@command_window = Window_Command.new(192, Language.list)
@command_window.x = 32
@command_window.height = 80 if @command_window.height > 80
@command_window.y = 240 - @command_window.height / 2
@command_window.opacity = 0
@version_window = Window_Version.new
end
#--------------------------------------------------------------------------
def terminate
@header_window.dispose
@background_window.dispose
@command_window.dispose
@version_window.dispose
end
#--------------------------------------------------------------------------
def update
@command_window.update
if Input.press?(Input::UP) or Input.press?(Input::DOWN)
Language.set_value(@command_window.index)
@header_window.refresh; @version_window.refresh
end
if Input.trigger?(Input::C)
$scene = nil
end
end
#--------------------------------------------------------------------------
end
begin
Graphics.freeze
entries = Dir.entries('Language/.')
if entries.size < 3
p "You don't have any language files in the respective directory."
exit
elsif entries.size > 3
$data_system = load_data("Data/System.rvdata")
$game_system = Game_System.new
$scene = Scene_Language.new
else
Language.set_value(0)
$scene = Scene_Title.new
end
$scene.main while $scene != nil
end
[/rgss]
[rgss]module Vocab
#--------------------------------------------------------------------------
ShopBuy = Language.output('V-1')
ShopSell = Language.output('V-2')
ShopCancel = Language.output('V-3')
Possession = Language.output('V-4')
ExpTotal = Language.output('V-5')
ExpNext = Language.output('V-6')
SaveMessage = Language.output('V-7')
LoadMessage = Language.output('V-8')
File = Language.output('V-9')
PartyName = Language.output('V-10')
Emerge = Language.output('V-11')
Preemptive = Language.output('V-12')
Surprise = Language.output('V-13')
EscapeStart = Language.output('V-14')
EscapeFailure = Language.output('V-15')
Victory = Language.output('V-16')
Defeat = Language.output('V-17')
ObtainExp = Language.output('V-18')
ObtainGold = Language.output('V-19')
ObtainItem = Language.output('V-20')
LevelUp = Language.output('V-21')
ObtainSkill = Language.output('V-22')
DoAttack = Language.output('V-23')
DoGuard = Language.output('V-24')
DoEscape = Language.output('V-25')
DoWait = Language.output('V-26')
UseItem = Language.output('V-27')
CriticalToEnemy = Language.output('V-28')
CriticalToActor = Language.output('V-29')
ActorDamage = Language.output('V-30')
ActorLoss = Language.output('V-31')
ActorDrain = Language.output('V-32')
ActorNoDamage = Language.output('V-33')
ActorNoHit = Language.output('V-34')
ActorEvasion = Language.output('V-35')
ActorRecovery = Language.output('V-36')
EnemyDamage = Language.output('V-37')
EnemyLoss = Language.output('V-38')
EnemyDrain = Language.output('V-39')
EnemyNoDamage = Language.output('V-40')
EnemyNoHit = Language.output('V-41')
EnemyEvasion = Language.output('V-42')
EnemyRecovery = Language.output('V-43')
ActionFailure = Language.output('V-44')
#--------------------------------------------------------------------------
def self.level; return Language.output('V-45'); end
def self.level_a; return Language.output('V-46'); end
def self.hp; return Language.output('V-47'); end
def self.hp_a; return Language.output('V-48'); end
def self.mp; return Language.output('V-49'); end
def self.mp_a; return Language.output('V-50'); end
def self.atk; return Language.output('V-51'); end
def self.def; return Language.output('V-52'); end
def self.spi; return Language.output('V-53'); end
def self.agi; return Language.output('V-54'); end
def self.weapon; return Language.output('V-55'); end
def self.armor1; return Language.output('V-56'); end
def self.armor2; return Language.output('V-57'); end
def self.armor3; return Language.output('V-58'); end
def self.armor4; return Language.output('V-59'); end
def self.weapon1; return Language.output('V-60'); end
def self.weapon2; return Language.output('V-61'); end
def self.attack; return Language.output('V-62'); end
def self.skill; return Language.output('V-63'); end
def self.guard; return Language.output('V-64'); end
def self.item; return Language.output('V-65'); end
def self.equip; return Language.output('V-66'); end
def self.status; return Language.output('V-67'); end
def self.save; return Language.output('V-68'); end
def self.game_end; return Language.output('V-69'); end
def self.fight; return Language.output('V-70'); end
def self.escape; return Language.output('V-71'); end
def self.new_game; return Language.output('V-72'); end
def self.continue; return Language.output('V-73'); end
def self.shutdown; return Language.output('V-74'); end
def self.to_title; return Language.output('V-75'); end
def self.cancel; return Language.output('V-76'); end
def self.gold; return Language.output('V-77'); end
#--------------------------------------------------------------------------
end
[/rgss]
The script works by replacing the regular text strings set by default in the script editor and database with methods passing that string to the Language module. This module looks for a line inside a textfile containing that string (I'll call those strings tags from now on, because you 'tag' the lines you want to draw), and if it's there, draws it ingame. If it isn't, it will display the tag itself enclosed by brackets as an indicator that you still need to define that tag's content.
What it does until now is nothing more than the default. The trick is that the player can choose what language file to go with at the start of the program start, allowing your game to have multiple text sets.
What it does until now is nothing more than the default. The trick is that the player can choose what language file to go with at the start of the program start, allowing your game to have multiple text sets.
Copy the Multiple Language VX script into your project, directly above Main, but not below '? Main Process'. You might want to create a '? Multiple Language' subentry similar to the one in the demo.
If you want to use the Vocab module, copy that one somewhere in your script editor, below the default Vocab module.
If you experience problems, just take a look at how the demo stores the scripts.
If you want to use the Vocab module, copy that one somewhere in your script editor, below the default Vocab module.
If you experience problems, just take a look at how the demo stores the scripts.
I chose different tags this time to give the viewer more of an idea what he's translating right now. To make it easier for both co-developers and external translators, you should stick with this setting, while of course you can enhance it any way you need.
A-x > Actor names, x being their database ID.
B > not used yet, but might serve as an optional battle message container in the future for overviewing purposes.
C-x > Class names, x being their database ID.
D-y-x > Skill and Item names (even numbers) and descriptions (odd numbers). 0/1 are used for skills, 2/3 for items, 4/5 for weapons, and 6/7 for armor parts, each replacing y; x is the database ID.
E-x > Enemy names, x being their database ID.
F > Reserved for a planned, unlistet feature.
M-x > Messages, tag is to be inserted completely into the message entry (you'd insert 'M-45', not just '45').
S-x > System tags called in custom scripts within the script editor. Just like the messages, tags are to be used with the leading 'S-'.
V-x > Vocab module tags, pointing to strings defined in that module. You don't have to set these unless you create custom ones; if so, please copy the notation from my predefined Vocab module.
You can always add custom tags, but please stick with the letter-hyphen-number notation to prevent confusion. Also, don't use any of the letters listed above, as you might experience compatibility errors if you apply a later version of this script and I added those.
A-x > Actor names, x being their database ID.
B > not used yet, but might serve as an optional battle message container in the future for overviewing purposes.
C-x > Class names, x being their database ID.
D-y-x > Skill and Item names (even numbers) and descriptions (odd numbers). 0/1 are used for skills, 2/3 for items, 4/5 for weapons, and 6/7 for armor parts, each replacing y; x is the database ID.
E-x > Enemy names, x being their database ID.
F > Reserved for a planned, unlistet feature.
M-x > Messages, tag is to be inserted completely into the message entry (you'd insert 'M-45', not just '45').
S-x > System tags called in custom scripts within the script editor. Just like the messages, tags are to be used with the leading 'S-'.
V-x > Vocab module tags, pointing to strings defined in that module. You don't have to set these unless you create custom ones; if so, please copy the notation from my predefined Vocab module.
You can always add custom tags, but please stick with the letter-hyphen-number notation to prevent confusion. Also, don't use any of the letters listed above, as you might experience compatibility errors if you apply a later version of this script and I added those.
Just a small overview about what tricks you can do with the language contents to ease up your game development process, as well as things you may not do in order to make the script work as it should.
- You can name items and skills within the database any way you want, for example to see what you give the actor with an event command. While you wouldn't have to name them at all since their names are read from the txt-file, you'd need to look their ID up in the database or text file every time you'd give your party some items.
- You can comment in the language textfiles whereever you want, as long as you don't write in the tagged lines. The # as comment indicator isn't necessary, but I'd suggest using it to not confuse anyone.
- You shouldn't include a tag in another tag's content (or a comment), for example having the line 'M-24 This is the message before M-25.', because if you don't have M-25 specified, the message window will display this line for it, because it contains 'M-25'.
- For obvious reasons, you shouldn't have two equal tags... if you still have them, the first one will be chosen by the script.
Q: As you, BlueScope, are German... will you translate my project for me into that language?
A: That depends on your game, your attitude when asking and the time I can spare, but in general, I'd like to, of course.
Q: As you, BlueScope, are German... do you want me to translate your upcoming project into [insert language here]?
A: Well, basically, hell yeah, because you can never have enough languages, huh... I still have a lot to do on my current project until I could call it somewhere close to being finished, so don't make promises yet.
Q: My custom system uses images with text. How can I assign a language-specific image?
A: I'll add a hopefully easy-to-use feature to read image tags in a future version.
Q: If you have important stuff like message features ToDo-list... why is this v1.0?
A: Because what you have here is what you'd need for a completed game. The message window works flawless, just misses a couple of features... also, from here on, you won't need to re-assemble your game to adjust it to newer versions - you can just replace the script and enjoy the new features.
Q: Who are Markus Reinhardt and Kenny Hatcher?
A: Impressively underdeveloped characters I created just for the prupose of not having placeholders in the opening screen.
Theory
Should be compatible with any scripts that don't modify Window_Message (huge incompatibility probability), Window_Base or Scene_Battle's treasure display.
Modified methods
Game_Actor > initialize (aliased method, shouldn't interfere with whatever you have in any way)
Game_Enemy > initialize (aliased method, shouldn't interfere with whatever you have in any way)
Window_Base > draw_class_name, draw_item_name
Window_Item > update_help
Window_Skill > update_help
Window_Message > start_message, update_message
Scene_Battle > display_exp_and_gold (dependency on this will be removed along with special characters in messages being added)
What can I say... you should use this. I myself find it easier to work with textfile strings than with the regular RM interface that especially creeps the fuck out of me as far as messages go. I think being a game designer means fulfilling the requests of the gamers, so setting the base for your game being translated is something very productive, I think... you not having to translate the game yourself and still be able to keep the uncompiled project to yourself, keeping your project small and neat without the need of multiple versions, is another plus...
I'm positive that games in general, but especially games from non-English game developers would gain from this script... I wonder if it'll come any far.
...to vgvgf, for helping me out with a code issue for Multiple Language XP, whose solution is also vital to Multiple Language VX
...to Trickster, for the draw_wrap_text method I once again stripped from the MACL and which probably is the most useful non-default method ever written
You may use and/or modify this script in any way you want, and/or release your modifications, as long as you accept the following terms and conditions entirely.
You may not use this for commercial projects, profit-oriented projects, or projects that aren't meant to be sold, but otherwise aquire money (i.e. through donations). That is not limited to RPG Maker projects, but valid for all appliances. You may not remove or delete contents of the original header included in the script, but you may add your name if you made any changes.
The actual mentioning of my nickname in your release (i.e. in-media credits, printed pages or even a readme file) is not necessary, but much apprechiated.