Switching language in module Vocab

Discussion in 'Learning Ruby and RGSSx' started by TheoAllen, Nov 19, 2013.

  1. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,397
    Likes Received:
    4,972
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    I just got a something funny in module Vocab.

    My goal was to be able to switching Vocab to other language.

    But, since the variables in Vocab are constant (which is unable to change), I though that was impossible.

    Later ......

    Since I knew the word 'require' in ruby, I planned to make a switching vocab by a script call.

    def translated require 'indo_vocab'enddef english require 'english_vocab'endThe indo_vocab.rb contains translated module vocab in my language.I tried to make two events that call these two methods.

    But I realized that you could only call the 'require' keyword with same parameter in one time.

    Okay, my experiment was failed ...

    Then, I've been wondering what if I could re-define Vocab by using script call. So, I tried to make these code

    def indonesian_vocab eval(" module Vocab ShopBuy = \"Beli\" # Buy in my language end ")enddef english_vocab eval(" module Vocab ShopBuy = \"Buy\" end ")endAnd did you know? it works perfectly :D Well, I just want to share this trick. And I'm sorry if I can't explain a thing in english properly
     
    #1
    Archeia likes this.
  2. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,062
    Location:
    Toronto
    First Language:
    English
    Though, that's a strange way to do it, re-defining your methods just to retrieve a different string.
     
    #2
  3. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,397
    Likes Received:
    4,972
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    #3
  4. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,062
    Location:
    Toronto
    First Language:
    English
    Just store both texts and then choose which one to display. I think that's how most people do it.
     
    #4
  5. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,397
    Likes Received:
    4,972
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    No, you can't do this to Constant.
    I've tried this sample

    Code:
    SomeConstant = (condition ? "text1" : "text2")
    The condition is checked one time. So it won't be checked once again in the middle of the game.
     
    #5
  6. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,062
    Location:
    Toronto
    First Language:
    English
    Oh, you wanted to continue to use the Vocab module rather than using something else. Missed that part.
     
    #6
  7. estriole

    estriole Veteran Veteran

    Messages:
    1,030
    Likes Received:
    334
    First Language:
    indonesian
    i try implementing your method but cannot make it work. where did you put the def translated

    game interpreter? or module Vocab.

    btw i try it like this:

    class Game_Interpreterdef indonesian_vocabeval("module VocabShopBuy = \"Beli\" # Buy in my languageend")endendbut cannot change the vocab...

    Found a way to change constant !!!

    class Game_Interpreter  def buy_vocab(str)    Vocab::ShopBuy.replace str  endendand it change the buy vocab to any string we type

    found from this articles:

    http://stackoverflow.com/questions/6712298/dynamic-constant-assignment

    and to revert back to 'original' value i use this:

    Code:
    module Vocab  Default_ShopBuy = ShopBuy  Default_ShopSell = ShopSell  Default_ShopCancel = ShopCancelendclass Game_Interpreter  def reset_shop_vocab    Vocab::ShopBuy.replace Vocab::Default_ShopBuy    Vocab::ShopSell.replace Vocab::Default_ShopSell    Vocab::ShopCancel.replace Vocab::Default_ShopCancel  endend
     
    Last edited by a moderator: Nov 19, 2013
    #7
    TheoAllen likes this.
  8. richter_h

    richter_h Eh? Sweetroll? Veteran

    Messages:
    581
    Likes Received:
    958
    Location:
    Leila's Tavern
    First Language:
    Indonesian
    Primarily Uses:
    N/A
    Well, nice pick to make another module.

    And obviously it needs many changes to have both modules to be checked in-game. How about adding certain method in Game_Interpreter which calls the module instead of checking each of the dialogue lines?

    Also, it's only affects the basic vocabs (or the one tagged in Vocab module). If we want to make the module affects other scripts, we should alter the scripts to read the module as well.

    Of course, it might need a bit more effort to include the module into scripts :guffaw:

    BTW it's kinda eye-opening for me, since I need it to expand the bilingual possibility in my game. Nice one, fella.

    OOT: TheoAllen, I saw your siggy and you missed a character. We have 20 playable characters, not 19 :p

    You missed Schneide, I see...
     
    Last edited by a moderator: Nov 19, 2013
    #8
  9. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,397
    Likes Received:
    4,972
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    Sorry for late reply. For some reason, I could not connect to internet back then


    @estriole :


    Dont define the methods in Game_Interpreter or anything. Just write "def blabablbal..." and it should works


    Btw, what a nice way to change value of the constant you have found. :D


    To return to original value, I use $RGSS_SCRIPTS.


    I found this trick when I was observing to TDS Script Disabler


    Basically. $RGSS_SCRIPTS is an array that contains the scripts in Script.rvdata2.


    The default location of Vocab is in 3rd index. So, I just only need to access the 3rd index of that array ($RGSS_SCRIPTS[2])


    And I also found that the $RGSS_SCRIPTS is a nested array. To access the original Vocab string, I need to access its 4th index. So, that all I need is to write down $RGSS_SCRIPTS[2][3].


    Here is my concept (ready to be released)


    http://pastebin.com/PRk2TzPC


    It was tested and it works


    @richter_h:


    Great effort indeed. A great game must have a great effort too :p


    And thanks for mentioning my signature :p
     
    #9
    estriole likes this.
  10. Dr.Yami

    Dr.Yami 。◕‿◕。 Developer

    Messages:
    994
    Likes Received:
    736
    Location:
    Finland
    First Language:
    Vietnamese
    Primarily Uses:
    Other
    I would prefer making an external file that store all the vocabs and parser them when open game  :rock-left:   :distrust:   :rock-right:
     
    #10
    richter_h and TheoAllen like this.
  11. IceDragon

    IceDragon Elder Cookie Dragon Veteran

    Messages:
    73
    Likes Received:
    60
    Location:
    Jamaica
    First Language:
    English
    Primarily Uses:
    N/A
    5 cents: (copy and pasted)

    Code:
    ## kode-xchange/lib/core/locale.rb#   by IceDragonclass Locale  ##  # @return [String] name of this Locale  attr_reader :name  ##  # @param [String] name  def initialize(name)    @name = name    @data = Hash.new  end  ##  # @param [String] locname  # @return [String]  def [](locname)    @data.fetch(locname)  end  ##  # @param [String] locname  # @param [String] translated  # @return [Void]  def []=(locname, translated)    @data[locname.dup.freeze] = translated.dup.freeze  endend
    Vocab:
    Code:
    module Vocab  class << self    attr_accessor :locale  end  def self.param(id)    locale["param/#{id}"]  end    # loaded from a binary file  #self.locale = load_data("locale/us_english.lbin")  # set from known locale  self.locale = Locale::Englishend
    English Locale example:
    Code:
    class Locale  English = Locale.new('us_english')  English['param/0'] = 'Max. Hp'  English['param/1'] = 'Max. Mp'  English['param/2'] = 'Attack'  English['param/3'] = 'Defense'  English['param/4'] = 'Mag. Ak'  English['param/5'] = 'Mag. Df'  English['param/6'] = 'Agility'  English['param/7'] = 'Luck'end
     
    Last edited by a moderator: Nov 20, 2013
    #11
    Dr.Yami likes this.
  12. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,062
    Location:
    Toronto
    First Language:
    English
    How does that deal with the constants?


    The problem is that most of the default scripts reference Vocab::ConstName directly. If it's the method calls that's easy to address.
     
    Last edited by a moderator: Nov 20, 2013
    #12
  13. estriole

    estriole Veteran Veteran

    Messages:
    1,030
    Likes Received:
    334
    First Language:
    indonesian
    ah i see. that's why i get undefined method Vocab blablabla when i put it in Game_Interpreter :D . i never know we can define def outside a class :D . and we can call it using script call box (the reason i put the method in game interpreter is so i can call it using script call). this info is really useful. since we can use the method inside another class too (not like game_interpreter).

    btw i change my above concept too... too bad that i cannot use your implementation (switch auto translate) so i have to script my own... since i want to change the vocab to anything i want... (not just two language). it's used in my script to define shop vocab at run time. example in this city the shop buy vocab is "Tuku" (wong jowo bang hehehehe), in other city the shop buy vocab is "Nukar"(urang banjar). in other city the shop buy vocab is "Meuli" (sunda). LOL.

    i also realize that using another constant inside vocab module i used before will not be saved to save files. so i store the default value in a nested hash inside $game_system variable whenever i change any constant value. and also store the 'used' value in a nested hash whenever i change any constant value... and change all the vocab to 'used' value when loading the save (if i don't do this when closing the game.exe and loading it will revert back to old vocab. in your case it won't happen like that since it seek the switch and translate it automatically).... in the end. it works too in my case. :D

    i also made it able to change any constant in any module / class. :D . as long it's string, array, or fixnum (this one still experimental)

    here's the code for reference :D (will release it later too inside another script maybe or independent script. if i do i will credit you too theo :D ).

    it's use two extra variables. but i guess in my case it still necessary... (open to any suggestion to reduce the variables :D )

    http://pastebin.com/H0UjHukK

    btw i see a new idea for your technique here. i try redefining method and it works too!!! how about redefining the entire battle system runtime :D .

    so we can switch battle system easily. or maybe start with simple scenes first for experiment :D .

    before i have tried it using eval inside game_interpreter. and it throw error. who know i only have to put it outside :D .

    the concept maybe like this:

    1) store each battle system in a txt files.

       - default battle system (might involve scene_battle, battle_manager, etc) (to reset before switching to another battle system since most people use this as base)

       - battle system 1

       - battle system 2

       - battle system 3

    [will this step necessary?] then before switching destroy the class / module

    2) then reset to the default battle system and then redefine the class to default battle system

    3) then redefine to another battle system

    it will be huge work though. :D .

    edit:

    nice idea... we could create language txt files with vocab module. and redefine Vocab module when loading the game (based on the saved variable in $game_system).

    but this won't solve my case though (only change one or some vocab, and change it to many different combination).
     
    Last edited by a moderator: Nov 20, 2013
    #13
    TheoAllen likes this.
  14. IceDragon

    IceDragon Elder Cookie Dragon Veteran

    Messages:
    73
    Likes Received:
    60
    Location:
    Jamaica
    First Language:
    English
    Primarily Uses:
    N/A
    You can cheat.

    Code:
    module Vocab  constants.each(&:remove_const)  def self.ConstName    "Stuff"  endend
    ruby allows ::method_name calls as well.
     
    Last edited by a moderator: Nov 20, 2013
    #14
    Tsukihime likes this.
  15. Tsukihime

    Tsukihime Veteran Veteran

    Messages:
    8,230
    Likes Received:
    3,062
    Location:
    Toronto
    First Language:
    English
    Never knew you could call constants that way lol


    That looks a lot more elegant than evaluating entire modules.
     
    Last edited by a moderator: Nov 20, 2013
    #15
  16. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,397
    Likes Received:
    4,972
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    Well, nice idea you have there. If you want to use trilingual or more, just make a filename that contains a number in its name. For example, lang_1.rb and such. Then we use Game_Variables to determine which language is currently used

    I knew that we can define a method outside other class in first time I learned Ruby. And my very first script call done in that way (I didn't know if we should define script call in Game_Interpreter).

    Well done, what a tricky trick you have there. It's nice though.

    If you release the script, I'm sure that I will make a tutorial based on your script (Indonesian tutorial of course, negara kita kurang SDM yang peduli RGSS :hammer: ) or maybe some addons implement to other scripts to allow dynamically change constant :D

    And yes, we can redefine method or anything in any classes (All hail eval function!)

    However, if we re-define a class which has a global instance variable (such as $game_system), you should reinitialize the instance object. Maybe, by using this script http://forums.rpgmakerweb.com/index.php?/topic/18457-rgss3-object-reinitializer/

    I tried to implement your idea

    module Theo  def self.TestConst    $game_switches[1] ? "Text 1" : "Text 2"  endendThen I did a script call using "Theo::TestConst". But it gave me an "uninitialized constant" error.
     
    #16
  17. IceDragon

    IceDragon Elder Cookie Dragon Veteran

    Messages:
    73
    Likes Received:
    60
    Location:
    Jamaica
    First Language:
    English
    Primarily Uses:
    N/A
    Ah *facepalms*, I forgot it only works with downcased method names


    :p just use Theo.TestConst or Theo.test_method


    Module::method_name, is uncommon in ruby (as in, not practiced)
     
    Last edited by a moderator: Nov 20, 2013
    #17
  18. TheoAllen

    TheoAllen Self-proclaimed jack of all trades Veteran

    Messages:
    4,397
    Likes Received:
    4,972
    Location:
    Riftverse
    First Language:
    Indonesian
    Primarily Uses:
    RMVXA
    I tried that script call and it works :D

    However, the RTP Scripts uses Vocab::Constant to access the string.

    It still can't be done by your trick
     
    #18
  19. estriole

    estriole Veteran Veteran

    Messages:
    1,030
    Likes Received:
    334
    First Language:
    indonesian
    HAIL eval function !!!!  (although there' some risk with it according some post in stackoverflow. but who cares :D ).

    nice tips about needing to reinitialize the instance object. :D .

    i define in Game_Interpreter because i didn't directly learn ruby at first (only lately i really learn ruby :D ). but learn from reading other scripter script :D . so in their script mostly put that in Game_Interpreter or in module class method. it's not requirement. just personal style perhaps.

    iya nih kurang sdm >.<. gak jadi duit soalnya gan wkwkwkwk. tp mudah2an makin bermunculan sdm baru. :D .
     
    #19
  20. richter_h

    richter_h Eh? Sweetroll? Veteran

    Messages:
    581
    Likes Received:
    958
    Location:
    Leila's Tavern
    First Language:
    Indonesian
    Primarily Uses:
    N/A
    Well, this one is the best (and simplest) way to make the game to has more than 1 language. Maybe it could support external scripts to have the same effect as the default Vocab module could get.

    An external file with extension of .rvdata, .rvdata2 or something else than .txt might works here ;)

    Instead of using the variable provided in the RPG Maker, why we don't use local variable that accessible from outside the module? It might sounds unwise and hardcoded in its way, but it could prevent unwilling changes upon the variable (and well, I'm the kind of pweson who misses little things often and often changes something without checking other related things :p ).

    Agreed with estriole, Game_Interpreter is one of the good places to put the "language change" method call. If using another class, it also works like a charm.

    One more thing, eval function might sounds good but has some risks, but often worth it. ;)
     
    #20

Share This Page