Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Multiple Language VX

Multiple Language VX
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...).


Features


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


Screenshots

mlvx01qy7.jpg



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]


Instructions


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.
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.
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.
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.



FAQ


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.


Compatibility


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)


Author's Notes


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.


Thanks


...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


Terms and Conditions


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.
 
1. it is nice
2. but i have a one this is better *ätsch*

Bug:
-you cant change the lang at running

Idea: make multilang Messange from NPCs


Freak Idea: whould you work together with me?
 
1st - thanks.
2nd - good for ya. :p It's not a contest for me though, so yeah...

For the 'bug', it's no bug, not even a flaw... it's totally intentional that you can't switch languages on the fly, for two reasons: a) If you choose a language, you most likely choose it because you're smart an understand that language, and b) if people use script conditionals using text strings stored within the Language file (unlikely, but hey), it'll cause bugs if you change the language during the process between setting that string and asking for it.

I don't get your 'idea', though... you can assign language strings to every message window there is by default, so I don't see what else you'd want to add. If you're talking about non-active messages (like in that system ccoa released aeons ago), I won't add that because I'm not going to do a custom message system here.

For the working together, you might show me what you have, since I don't think you released it.
 

apkx24

Member

can u make it support languages like greek/japaneese where they dont use the alphabet?? cos in my game ive always wanted like when you goto a far away town they speak a totally foreign language, instead of all the people in the entire game speaking one language
 
@apkx24 : you can use all languages that the font support. (-> UTF-8)


Info: this is for the lang in the WHOLE game.
to let NPCs speak outer stuff than you i will think about
 

apkx24

Member

?? dont understand your english very well....
u can simply call the script and change the font in game for a certain message, right?
 
Like hanmac said, since you can save and load txt-files with UTF-8 encoding (you can choose this while saving files with Windows' default notepad application), you can add every possible character into your language files, including special characters of any sort.

For your idea, though, I don't think you need a script like this... because if you want different languages for different regions, making a default one selectable wouldn't make that much sense... also, from a gamedesign point-of-view, I wouldn't suggest you going with that idea, because while it's sure innovative, you'd have to learn the respective languages to progress - unless you include translators or stuff like that - and that's a total no-go, for obvious reasons...

It's not in any way related, but if you want to change the Font mid-game, you'd have to call a script, containing this line:
Code:
Font.default_name = "Arial"
 

yion

Member

BlueScope":2htgru7m said:
Like hanmac said, since you can save and load txt-files with UTF-8 encoding (you can choose this while saving files with Windows' default notepad application), you can add every possible character into your language files, including special characters of any sort.

For your idea, though, I don't think you need a script like this... because if you want different languages for different regions, making a default one selectable wouldn't make that much sense... also, from a gamedesign point-of-view, I wouldn't suggest you going with that idea, because while it's sure innovative, you'd have to learn the respective languages to progress - unless you include translators or stuff like that - and that's a total no-go, for obvious reasons...

It's not in any way related, but if you want to change the Font mid-game, you'd have to call a script, containing this line:
Code:
Font.default_name = "Arial"

When my German Game is done, do you want to make an English translation with this? 8D
 
Well, of course I can't promise anything without knowing the time and date and what I'm up to then, ya know... and also, I'm not the best English speaker myself ^^ but if you think I'm doing alright and you need a translation somewhen, just drop me a line and I'll look into it.
 

yion

Member

My Demo is already done :P
if you want to translate it or test it feel free to do so.
(look into my signature :P)
 
I managed to get your last Language script to work with images, btw.


Code:
"Language/" + $game_system.language + "/Text Graphics/", filename"

but since this one works a little different the method I used wouldn't really work. I did however find one problem and I don't really understand why I'm getting the problem. I had a friend who translated my game into Arabic but the text shows up mirrored since Arabic is read from right to left.
 
@yion: I'll have a look into that when I get home from work...

@numbnuts: The problem I had with that (I thought about that method before as well, of course), and as well with the language files themselves, was that it doesn't encrypt the default graphics coming with the game, which is why that feature will be implemented when I include the possibility to use an encrypted language file as the default language. The updates to this script are kinda in cascading intervalls really, because I'm only here and then working on it... I have a couple of more important scripts on my hands that are necessary for my project to be completed before I can go on, so yeah...
 
If you mean choices, then yeah, I'm completely aware of that. If you check the ToDo list, you'll see that it's a planned feature for the upcoming version. Thanks for trying, though ^^
 
sorry, ive not noticed the  that actually you had a todo list.

Anywai, its called choices? aw this damn language hahahha Im only usued to the program language sintaxe XD
 
Oh this is awesome!

I was wondering if there's something that could make a translation process easier in VX. Then suddenly I found this script.

Salute for you dude!
 
@Lucas: It's cool ;) I just hope I'll get that list done somewhen soon...

@Frederick: It is a lot of effort if you merge it into an existing project. However, if you include and work with this script from the beginning, you won't have as much of a hazzle, and it also eases some things up, such as the message text wrapping you don't need to bother for anymore. Ultimately, I think that it's a very comfortable script to use, hopefully also for non-scripters.

@lahandi: I'm glad it's of use to ya... ^^
 
I'll youse your script in my game, since i want to do it in english and portuguese ^_^

ow, if only the list/choices where ok by now XD

Do you have any idea of why the mouse dosnt works properly? it does the "case selection" but it do not "change" the selection (just the graphic shows to be moved to another file, but the game does not understand it as a change of files... then if I try to select the second file (in my case, first is englis, second is português) it just "highlight" the second but the window does not update, still with the first file info (english, versio XX, translated by xXXX) and if i do select the second one it will enter the first... but if I do it by the keyboard (arrows) its ok and works just fine...
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top