Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

scala_gettext

By: edartuz on Mar 16th, 2013  |  syntax: Scala  |  size: 9.31 KB  |  views: 76  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. package ul
  2.  
  3. import java.{io, util}
  4. import collection.mutable.{HashMap};
  5.  
  6. /**
  7.  * Gettext support class
  8.  * @param root translations root directory
  9.  * @param domain translation domain (typically 'messages' or program name)
  10.  * @param category translation category (typically "MESSAGES")
  11.  * @param lang current translation language (default "en")
  12.  * @param langDef original language (default "en")
  13.  */
  14. class GetText(
  15.         var root: String     = "./locale",
  16.         var domain: String   = "messages",
  17.         var category: String = "MESSAGES",
  18.         var lang: String     = "en",
  19.         var langDef: String  = "en"
  20.     ) {
  21.    
  22.     /**
  23.      * Translations catalog map in format [lang => [str => [tran1,...tranN]]]
  24.      */
  25.     val cat = new HashMap[String, HashMap[String, Array[Array[String]]]];
  26.     load; // load/parse catalog
  27.    
  28.     /** Load all translations from root directory */
  29.     def load:GetText = {
  30.         try {
  31.             for (langDir <- new io.File(root).list if (new io.File(root + io.File.separator + langDir).isDirectory)) { //iterate over all dirs in root
  32.                 try {
  33.                     println("Loading: " + (root + io.File.separator + langDir + io.File.separator +
  34.                         "LC_" + category + io.File.separator + domain + ".mo"))
  35.                     //try to load and parse .MO file
  36.                     val moBytes = scala.io.Source.fromFile(
  37.                         root + io.File.separator + langDir + io.File.separator +
  38.                         "LC_" + category + io.File.separator + domain + ".mo",
  39.                         "ISO-8859-1"
  40.                         ).map(_.toByte ).toArray;
  41.                     val moCat = parseMO( moBytes )
  42.                     cat(langDir) = moCat
  43.                 } catch { case _:Throwable => }
  44.             }
  45.         } catch { case _:Throwable => }
  46.         this
  47.     }
  48.    
  49.     /**
  50.      * Parse .MO file contents
  51.      * @param mo file contents in byte array
  52.      * @return translations map
  53.      */
  54.     def parseMO( mo:Array[Byte] ):HashMap[String, Array[Array[String]]] = {
  55.         val lcat = new HashMap[String, Array[Array[String]]];
  56.         if (mo.length > 24) {
  57.             // check magick for msb/lsb
  58.             val magick = (((mo(0) & 0xff) * 256 + (mo(1) & 0xff)) * 256 + (mo(2) & 0xff)) * 256 + (mo(3) & 0xff);
  59.             val msb = magick == 0x950412deL;
  60.            
  61.             if ((magick == 0x950412de) || (magick == 0xde120495)) {
  62.                
  63.                 def u32( i:Int ):Int = if (msb)
  64.                     ((((mo(i) & 0xff) * 256 + (mo(i+1) & 0xff)) * 256 + (mo(i+2) & 0xff)) * 256 + (mo(i+3) & 0xff));
  65.                 else
  66.                     ((((mo(i+3) & 0xff) * 256 + (mo(i+2) & 0xff)) * 256 + (mo(i+1) & 0xff)) * 256 + (mo(i) & 0xff));
  67.                
  68.                 val rev = u32(4); // revision
  69.                 val (revMaj, revMin) = (rev >> 16, rev % 65536); // major/minor revision
  70.                 // number of strings, offsets of original and translation strings tables
  71.                 val (sn, oto, ott) = (u32(8), u32(12), u32(16));
  72.  
  73.                
  74.                 if (sn > 1 && revMaj <= 1 && revMin <= 1) {
  75.                     for (sc <- 1 to sn-1) { // process all strings
  76.                         // original string(s) length, offset
  77.                         val (osl, oso) = ( u32( oto + 8 * sc ), u32( oto + 8 * sc + 4 ) );
  78.                         // translation string(s) length, offset
  79.                         val (tsl, tso) = ( u32( ott + 8 * sc ), u32( ott + 8 * sc + 4 ) );
  80.                        
  81.                         if (osl > 0 && tsl > 0) {
  82.                             // original string(s)
  83.                             val os = mo.slice( oso, oso + osl + 1);
  84.                             // extract all original forms
  85.                             var (oss, ossp) = (List[String](), 0);
  86.                             for (i <- 0 to os.length-1) {
  87.                                 if ( os(i) == 0 ) {
  88.                                     oss = oss ::: new String(os.slice(ossp, i), "utf8") :: Nil;
  89.                                     ossp = i + 1;
  90.                                 }
  91.                             }
  92.                             // translation string(s)
  93.                             val ts = mo.slice( tso, tso + tsl + 1);
  94.                             // extract all translation forms
  95.                             var (tss, tssp) = (List[String](), 0);
  96.                             for (i <- 0 to ts.length-1) {
  97.                                 if ( ts(i) == 0 ) {
  98.                                     tss = tss ::: new String(ts.slice(tssp, i), "utf8") :: Nil;
  99.                                     tssp = i + 1;
  100.                                 }
  101.                             }
  102.                             lcat( oss(0) ) = Array( oss.toArray, tss.toArray );
  103.                         }
  104.                     }
  105.                 }
  106.                
  107.             }
  108.         }
  109.         return lcat
  110.     }
  111.    
  112.     /**
  113.      * Parse .PO file
  114.      * @param po sequence of strings from file
  115.      * @return translations map
  116.      */
  117.     def parsePo( po:Seq[String] ): HashMap[String, Array[String]] = {
  118.         val lcat = new HashMap[String, Array[String]];
  119. /*        tranMap.clear // clear map
  120.         localeDir = aLocaleDir
  121.         domainName = aDomainName
  122.         // search for translations
  123.         try {
  124.             for (langDir <- new File(localeDir).list()) {
  125.                 try {
  126.                     val poFile = new File(localeDir + File.separator + langDir + File.separator +
  127.                         messagesDir + File.separator + domainName + ".po")
  128.                     val moFile = new File(localeDir + File.separator + langDir + File.separator +
  129.                         messagesDir + File.separator + domainName + ".mo")
  130.                     if (poFile.exists()) { // parse .po file
  131.                         tranMap(langDir) = new HashMap[String, String]()
  132.                         val fi = new FileInputStream( poFile )
  133.                         val din = new Array[Byte](poFile.length().toInt)
  134.                         fi.read( din ); fi.close()
  135.                         val poStr = new String(din, poEncoding)
  136.                         val poRe = "(?msu:msgid +\"(.*?)\".*?msgstr +\"(.*?)\")".r
  137.                         for (m <- poRe.findAllIn( poStr ).matchData if ((m.groupCount == 2)&&(m.group(1).length > 0)))
  138.                             tranMap(langDir)(m.group(1)) = m.group(2);
  139.                     } else if (moFile.exists()) { // parse .mo file
  140.                        
  141.                     }
  142.                 } catch { case _=> if (logger != null) logger.log("Error loading localization directory " + langDir + ".") }
  143.             }
  144.         } catch { case _=> if (logger != null) logger.log("Error loading localization.") }
  145. */        
  146.         return lcat;
  147.     }
  148.    
  149.     /**
  150.      * Translation function
  151.      * @param s original string
  152.      * @param pl plural form
  153.      * @param aLang translation language
  154.      * @return translated string
  155.      */
  156.     def tr( s: String, pl: Int, aLang: String ): String = {
  157.         try {
  158.             return cat(aLang)(s)(1)(pl-1);
  159.         } catch {
  160.             case _:Throwable => return s;
  161.         }
  162.     }
  163.  
  164.     /**
  165.      * Translation function
  166.      * @param s original string
  167.      * @param pl plural form
  168.      * @return translated string
  169.      */
  170.     def tr( s: String, pl: Int ): String = { /// translation function
  171.         try {
  172.             return cat(lang)(s)(1)(pl-1);
  173.         } catch {
  174.             case _:Throwable => return s;
  175.         }
  176.     }
  177.  
  178.     /**
  179.      * Translation function
  180.      * @param s original string
  181.      * @return translated string
  182.      */
  183.     def tr( s: String ): String = { /// translation function
  184.         try {
  185.             return cat(lang)(s)(1)(0);
  186.         } catch {
  187.             case _:Throwable => return s;
  188.         }
  189.     }
  190.  
  191.     def langs: Seq[String] = langDef :: (for ((l,t) <- cat) yield l).toList;
  192.     def lang(l:String):String = {
  193.         if (langs.contains(l)) l
  194.         else if (displayLangs.contains(l)) langs(displayLangs.indexOf(l))
  195.         else ""
  196.     }
  197.     def lang(l:Int):String = langs(l);
  198.     def displayLangs:Seq[String] =
  199.         (for (l <- langs) yield {
  200.             val ls = l.split("_");
  201.             val loc = if (ls.length == 1) new util.Locale(l) else new util.Locale(ls(0), ls(1));
  202.             loc.getDisplayName(loc).capitalize;
  203.         });
  204.     def displayLang(l:String):String = {
  205.         if (langs.contains(l)) displayLangs(langs.indexOf(l))
  206.         else if (displayLangs.contains(l)) l
  207.         else ""
  208.     }
  209.     def displayLang(l:Int):String = displayLangs(l);
  210.     def langIndex(l:String):Int = {
  211.         if (langs.contains(l)) langs.indexOf(l)
  212.         else if (displayLangs.contains(l)) displayLangs.indexOf(l)
  213.         else -1
  214.     }
  215.    
  216. }
  217.  
  218. object GetText {
  219.     var tran:GetText = null;
  220.    
  221.     def tr(s:String):String = {
  222.         if (tran == null) s else tran.tr(s)
  223.     }
  224.    
  225.     def lang = tran.lang
  226.     def lang_=(l:String) = {tran.lang = l}
  227.    
  228.     def langs = tran.langs
  229.    
  230.     def load(path:String, domain:String, category:String, lang:String, langDef:String) = {
  231.         tran =  new GetText(path, domain, category, lang, langDef);
  232.     }
  233.     def load(path:String):Unit = {
  234.         load(path, "messages", "MESSAGES", "en", "en")
  235.     }
  236.     def load:Unit = load("./locale");
  237. }