Advertisement
Iavra

[Ace] Game Localization - Core Engine

May 28th, 2015
440
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 8.78 KB | None | 0 0
  1. #==============================================================================
  2. # Iavra Game Localization - Core Engine 1.00
  3. # -----------------------------------------------------------------------------
  4. # Description:
  5. # Loads language files for the database and messages modules and manages the
  6. # current language
  7. # -----------------------------------------------------------------------------
  8. # Prerequisites:
  9. # (optional) Iavra Game.ini Access
  10. # -----------------------------------------------------------------------------
  11. # How to Use:
  12. # To get an set the current language, call the follwoing methods:
  13. #
  14. # IAVRA::I18N.language
  15. # IAVRA::I18N.language=
  16. #
  17. # Languages are stored in symbol form, like :en or :de. By default, the script
  18. # stores the current language in its own file. If "Iavra Game.ini Access" is
  19. # present, it will be stored in the Game.ini file, instead.
  20. #
  21. # Language files are basically Ruby hashes and built like this:
  22. #
  23. # {
  24. #   :category =>
  25. #   {
  26. #     # module dependent
  27. #   }
  28. # }
  29. #
  30. # Localized text can be accessed by calling the following method:
  31. #
  32. # IAVRA::I18N[category]
  33. #
  34. # The language of a file is defined by its name and/or directory.
  35. # -----------------------------------------------------------------------------
  36. # Terms of Use:
  37. # Free to use for both commercial and non-commercial games. Please give credit.
  38. # -----------------------------------------------------------------------------
  39. # Credits:
  40. # Iavra
  41. # -----------------------------------------------------------------------------
  42. # Changelog:
  43. # - 1.00: Release version.
  44. #==============================================================================
  45.  
  46. ($imported ||= {})[:iavra_i18n_core] = true
  47.  
  48. #==============================================================================
  49. # ▼ IAVRA::I18N::CORE
  50. #==============================================================================
  51.  
  52. module IAVRA
  53.     module I18N
  54.         module CORE
  55.            
  56.             #========================================================================
  57.             # ■ ■ ■ ■ ■ CONFIGURATION ■ ■ ■ ■ ■
  58.             #========================================================================
  59.            
  60.             #========================================================================
  61.             # Lists all languages, that should be supported by the script.
  62.             #========================================================================
  63.            
  64.             LANGUAGES = [:en, :de]
  65.            
  66.             #========================================================================
  67.             # Defines the path, where language files will be loaded from. %s is
  68.             # replaced by one of the entries of LANGUAGES and the whole string is
  69.             # treated as a file glob.
  70.             #========================================================================
  71.            
  72.             FILE_PATH = "I18N/%s{_*,}.rb"
  73.            
  74.             #========================================================================
  75.             # This file is used to store the current language. If "Iavra Game.ini
  76.             # Access" is present, the Game.ini file will be used, instead.
  77.             #========================================================================
  78.            
  79.             PERSISTENCE = "I18N/current.txt"
  80.            
  81.             #========================================================================
  82.             # Setting this to true will enable deep merging for loaded files, which
  83.             # allows to split categories over multiple files.
  84.             #========================================================================
  85.            
  86.             DEEP_MERGE = false
  87.            
  88.             #========================================================================
  89.             # Setting this to true will cause language files to be loaded inside
  90.             # their own thread, which acts as a sandbox. Since the files are read in
  91.             # using eval, they could interact with the rest of your game if this is
  92.             # set to false.
  93.             #========================================================================
  94.            
  95.             SANDBOX = false
  96.            
  97.             #========================================================================
  98.             # ■ ■ ■ ■ ■ CONFIGURATION ■ ■ ■ ■ ■
  99.             #========================================================================
  100.            
  101.             class << self
  102.                 attr_accessor :language
  103.                 attr_reader :language_map
  104.             end
  105.            
  106.             #========================================================================
  107.             # Sandbox'ed eval, which runs inside its own thread with $SAFE = 4. This
  108.             # is as close to a sandbox as i can get.
  109.             #========================================================================
  110.            
  111.             def self.sandbox_eval(data)
  112.                 Thread.new{
  113.                     $SAFE = 4
  114.                     Thread.current[:result] = eval(data)
  115.                 }.join[:result]
  116.             end
  117.            
  118.             #========================================================================
  119.             # Methods for loading and saving the current language
  120.             #========================================================================
  121.            
  122.             if(($imported ||= {})[:iavra_ini_access])
  123.                
  124.                 def self.load_language
  125.                     value = IAVRA::INI.load("i18n", "Language", "-").to_sym
  126.                     value == :- ? nil : value
  127.                 end
  128.                
  129.                 def self.save_language
  130.                     IAVRA::INI.save("i18n", "Language", @language)
  131.                 end
  132.                
  133.             else
  134.                
  135.                 def self.load_language
  136.                     File.file?(PERSISTENCE) ? File.open(PERSISTENCE) {|file| file.read.to_sym} : nil
  137.                 end
  138.                
  139.                 def self.save_language
  140.                     File.open(PERSISTENCE, "w") {|file| file.write(@language.to_s)}
  141.                 end
  142.                
  143.             end
  144.            
  145.             #========================================================================
  146.             # Loads the current language on game starts. Defaults to the first entry
  147.             # in LANGUAGES, if no saved language can be found.
  148.             #========================================================================
  149.            
  150.             def self.initialize_current_language
  151.                 @language = load_language || (flag = LANGUAGES[0])
  152.                 @language = nil if !LANGUAGES.include?(@language)
  153.                 save_language if flag
  154.             end
  155.            
  156.             #========================================================================
  157.             # Loads all language files, either directly or inside a sandbox'ed eval.
  158.             # Afterwards, the files are merged to a hash.
  159.             #========================================================================
  160.            
  161.             def self.initialize_language_map
  162.                 @language_map = Hash[LANGUAGES.map{|lang|
  163.                     [lang, Dir[FILE_PATH.gsub("%s", lang.to_s)].map{|name|
  164.                         File.open(name) {|f| d = f.read; (SANDBOX ? sandbox_eval(d) : eval(d)) || {}}
  165.                     }.inject(DEEP_MERGE ? :iavra_i18n_deep_merge : :merge)]
  166.                 }]
  167.             end
  168.            
  169.         end
  170.        
  171.         #==========================================================================
  172.         # The initialize method is located outside the CORE module to make it
  173.         # easier for the modules to hook themselves into it.
  174.         #==========================================================================
  175.        
  176.         def self.initialize
  177.             CORE.initialize_current_language
  178.             CORE.initialize_language_map
  179.         end
  180.        
  181.         #==========================================================================
  182.         # This is called once at game start and whenever the current language is
  183.         # changed and can be used by modules to perform actions.
  184.         #==========================================================================
  185.        
  186.         def self.update
  187.         end
  188.        
  189.         #==========================================================================
  190.         # Getter and setter for the current language
  191.         #==========================================================================
  192.        
  193.         def self.language
  194.             CORE.language
  195.         end
  196.        
  197.         def self.language=(lang)
  198.             return if lang.nil?
  199.             return if (sym = lang.to_sym) == language
  200.             return unless CORE::LANGUAGES.include?(sym)
  201.             CORE.language = sym
  202.             CORE.save_language
  203.             update
  204.         end
  205.        
  206.         #==========================================================================
  207.         # Shortcut method to access localized text
  208.         #==========================================================================
  209.        
  210.         def self.[](sym)
  211.             (CORE.language_map[language] || {})[sym] || {}
  212.         end
  213.        
  214.     end
  215. end
  216.  
  217. #==============================================================================
  218. # ▼ Hash
  219. #==============================================================================
  220.  
  221. class Hash
  222.    
  223.     #============================================================================
  224.     # recursive deep merge
  225.     #============================================================================
  226.    
  227.     def iavra_i18n_deep_merge(second)
  228.         merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2}
  229.         self.merge(second, &merger)
  230.     end
  231.    
  232. end
  233.  
  234. #==============================================================================
  235. # ▼ DataManager
  236. #==============================================================================
  237.  
  238. module DataManager
  239.    
  240.     class << self
  241.         alias :iavra_i18n_core_load_database :load_database
  242.     end
  243.    
  244.     def self.load_database
  245.         iavra_i18n_core_load_database
  246.         IAVRA::I18N.initialize
  247.         IAVRA::I18N.update
  248.     end
  249.    
  250. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement