diff options
| author | Di Peng | 2011-07-29 14:22:37 -0700 | 
|---|---|---|
| committer | Igor Minar | 2011-08-14 23:44:20 -0700 | 
| commit | 966cbd4cf8d795b1706ff400f604c6002d7e81f9 (patch) | |
| tree | 3ca9c42d7bad4f151c72d39f3ef9b053de6cc861 /i18n/src | |
| parent | 8534b7c7c0aa352eb0f17dbe8b22ba34f995654d (diff) | |
| download | angular.js-966cbd4cf8d795b1706ff400f604c6002d7e81f9.tar.bz2 | |
feat(i18n): collect and convert locale info from closure
- add i18n/closure directory with closure i18n files and
  update-closure.sh script to update them
- generate.sh script runs node.js scripts that extract localization
  rules from the closure library, transform them to a more suitable
format and dumps them into i18n/locale directory as angular's $locale
services
- update Rakefile to copy i18n files to build/ and pkg/ dirs
- copy i18n stuff during rake build
- e2e tests for several locales
Diffstat (limited to 'i18n/src')
| -rw-r--r-- | i18n/src/closureSlurper.js | 106 | ||||
| -rw-r--r-- | i18n/src/converter.js | 60 | ||||
| -rw-r--r-- | i18n/src/parser.js | 64 | ||||
| -rw-r--r-- | i18n/src/util.js | 7 | 
4 files changed, 237 insertions, 0 deletions
diff --git a/i18n/src/closureSlurper.js b/i18n/src/closureSlurper.js new file mode 100644 index 00000000..32ef022c --- /dev/null +++ b/i18n/src/closureSlurper.js @@ -0,0 +1,106 @@ +#!/usr/bin/env node +'use strict'; + +require.paths.push(__dirname); +var Q  = require('qq'), +    qfs  = require('q-fs'), +    converter = require('converter.js'), +    util = require('util.js'), +    localeInfo = {}, +    localeIds = [], +    currencySymbols, +    goog = { provide: function() {}, +             require: function() {}, +             i18n: {currency: {}} }; + +createFolder('../locale/').then(function() { +  var promiseA = Q.defer(), +      promiseB = Q.defer(); + +  qfs.read(__dirname + '/../closure/currencySymbols.js', 'b').then(function(content) { +    eval(content.toString()); +    currencySymbols = goog.i18n.currency.CurrencyInfo; +    currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2; + +    qfs.read(__dirname + '/../closure/numberSymbols.js', 'b').then(function(content) { +      //eval script in the current context so that we get access to all the symbols +      eval(content.toString()); +      for (propName in goog.i18n) { +        var localeID = util.findLocaleId(propName, 'num'); +        if (localeID) { +          if (!localeInfo[localeID]) { +            localeInfo[localeID] = {}; +            localeIds.push(localeID); +          } +          var convertedData = converter.convertNumberData(goog.i18n[propName], currencySymbols); +          localeInfo[localeID].NUMBER_FORMATS = convertedData; +        } +      } + +      promiseA.resolve(); +    }); +  }); + + +  qfs.read(__dirname + '/../closure/datetimeSymbols.js', 'b').then(function(content) { +    eval(content.toString()); +    for (propName in goog.i18n) { +      var localeID = util.findLocaleId(propName, 'datetime'); +      if (localeID) { +        if (!localeInfo[localeID]) { +          localeInfo[localeID] = {}; +          localeIds.push(localeID); +        } +        var convertedData = converter.convertDatetimeData(goog.i18n[propName]); +        localeInfo[localeID].DATETIME_FORMATS = convertedData; +      } +    } + +    promiseB.resolve(); +  }); +   +  return Q.join(promiseA.promise, promiseB.promise, noop); +}).then(function() { +  localeIds.forEach(function(localeID) { +    var fallBackID = localeID.match(/[A-Za-z]+/)[0], +        localeObj = localeInfo[localeID], +        fallBackObj = localeInfo[fallBackID]; + +    // fallBack to language formats when country format is missing +    // e.g. if NUMBER_FORMATS of en_xyz is not present, use the NUMBER_FORMATS of en instead +    if (!localeObj.NUMBER_FORMATS) { +      localeObj.NUMBER_FORMATS = fallBackObj.NUMBER_FORMATS; +    } + +    if (!localeObj.DATETIME_FORMATS) { +       localeObj.DATETIME_FORMATS = fallBackObj.DATETIME_FORMATS; +    } + +    // e.g. from zh_CN to zh-CN, from en_US to en-US +    var correctedLocaleId = localeID.replace(/_/g, '-').toLowerCase(); +    localeObj.id = correctedLocaleId; + +    var prefix = 'angular.service("$locale", function() {\nreturn ', +        content = JSON.stringify(localeInfo[localeID]).replace(/\¤/g,'\\u00A4'), +        suffix; + +    suffix = ';\n});'; + +    var toWrite = prefix + content + suffix; + +    qfs.write(__dirname + '/../locale/' + 'angular-locale_' + correctedLocaleId + '.js', toWrite); +  }); +  console.log('Generated ' + localeIds.length + ' locale files!'); +}).end(); + +function noop() {}; + +/** +* Make a folder under current directory. +* @param folder {string} name of the folder to be made +*/ +function createFolder(folder) { +  return qfs.isDirectory(__dirname + '/' + folder).then(function(isDir) { +    if (!isDir) return qfs.makeDirectory(__dirname + '/' + folder); +  }); +} diff --git a/i18n/src/converter.js b/i18n/src/converter.js new file mode 100644 index 00000000..586bdb95 --- /dev/null +++ b/i18n/src/converter.js @@ -0,0 +1,60 @@ +/** + * after obtaining data from closure files, use converter to massage the data into the formats + * we want + */ +exports.convertDatetimeData = convertDatetimeData; +exports.convertNumberData = convertNumberData; + + +require.paths.push(__dirname); + + +var parsePattern = require('parser').parsePattern; + + +function convertNumberData(dataObj, currencySymbols) { +  var numberFormats = {}, + +  numberFormats = { +    DECIMAL_SEP: dataObj.DECIMAL_SEP, +    GROUP_SEP: dataObj.GROUP_SEP, +    PATTERNS: [parsePattern(dataObj.DECIMAL_PATTERN), +               parsePattern(dataObj.CURRENCY_PATTERN)] +  } + +  if (currencySymbols[dataObj.DEF_CURRENCY_CODE]) { +    numberFormats.CURRENCY_SYM = currencySymbols[dataObj.DEF_CURRENCY_CODE][1]; +  } else { +    if (dataObj.DEF_CURRENCY_CODE == 'MTL') { +      numberFormats.CURRENCY_SYM = '₤'; //for some reason this is missing in closure +    } else { +      // if there is no corresponding currency symbol, just use currency code. +      var code = numberFormats.CURRENCY_SYM = dataObj.DEF_CURRENCY_CODE; +      console.log(code +' has no currency symbol in closure, used ' + code + ' instead!'); +    } +  } +  return numberFormats; +} + + +function convertDatetimeData(dataObj) { +  var datetimeFormats = {}; + +  datetimeFormats.MONTH = dataObj.MONTHS; +  datetimeFormats.SHORTMONTH = dataObj.SHORTMONTHS; +  datetimeFormats.DAY = dataObj.WEEKDAYS; +  datetimeFormats.SHORTDAY = dataObj.SHORTWEEKDAYS; +  datetimeFormats.AMPMS = dataObj.AMPMS; + + +  datetimeFormats.medium      = dataObj.DATEFORMATS[2] + ' ' + dataObj.TIMEFORMATS[2]; +  datetimeFormats.short       = dataObj.DATEFORMATS[3] + ' ' + dataObj.TIMEFORMATS[3]; +  datetimeFormats.fullDate    = dataObj.DATEFORMATS[0]; +  datetimeFormats.longDate    = dataObj.DATEFORMATS[1]; +  datetimeFormats.mediumDate  = dataObj.DATEFORMATS[2]; +  datetimeFormats.shortDate   = dataObj.DATEFORMATS[3]; +  datetimeFormats.mediumTime  = dataObj.TIMEFORMATS[2]; +  datetimeFormats.shortTime   = dataObj.TIMEFORMATS[3]; + +  return datetimeFormats; +} diff --git a/i18n/src/parser.js b/i18n/src/parser.js new file mode 100644 index 00000000..db31aeef --- /dev/null +++ b/i18n/src/parser.js @@ -0,0 +1,64 @@ +/** +* A simple parser to parse a number format into a pattern object +*/ + +exports.parsePattern = parsePattern; + +var PATTERN_SEP = ';', +    DECIMAL_SEP = '.', +    GROUP_SEP   = ',', +    ZERO        = '0', +    DIGIT       = '#'; + +/** + * main funciton for parser + * @param str {string} pattern to be parsed (e.g. #,##0.###). + */ +function parsePattern(pattern) { +  var p = { +            minInt: 1, +            minFrac: 0, +            macFrac: 0, +            posPre: '', +            posSuf: '', +            negPre: '', +            negSuf: '', +            gSize: 0, +            lgSize: 0 +          }; + +  var parts = pattern.split(PATTERN_SEP), +      positive = parts[0], +      negative = parts[1]; + +  var parts = positive.split(DECIMAL_SEP), +      integer = parts[0], +      fraction = parts[1]; + +  p.posPre = integer.substr(0, integer.indexOf(DIGIT)); + +  for (var i = 0; i < fraction.length; i++) { +    var ch = fraction.charAt(i); +    if (ch == ZERO) p.minFrac = p.maxFrac = i + 1; +    else if (ch == DIGIT) p.maxFrac = i + 1; +    else p.posSuf += ch; +  } + +  var groups = integer.split(GROUP_SEP); +  p.gSize = groups[1].length; +  p.lgSize = (groups[2] || groups[1]).length; + +  if (negative) { +    var trunkLen = positive.length - p.posPre.length - p.posSuf.length, +        pos = negative.indexOf(DIGIT); + +    p.negPre = negative.substr(0, pos).replace(/\'/g, ''); +    p.negSuf = negative.substr(pos + trunkLen).replace(/\'/g, ''); +  } else { +    // hardcoded '-' sign is fine as all locale use '-' as MINUS_SIGN. (\u2212 is the same as '-') +    p.negPre = p.posPre + '-'; +    p.negSuf = p.posSuf; +  } + +  return p; +} diff --git a/i18n/src/util.js b/i18n/src/util.js new file mode 100644 index 00000000..82e2a7e4 --- /dev/null +++ b/i18n/src/util.js @@ -0,0 +1,7 @@ +exports.findLocaleId = function findLocaleId(str, type) { +  if (type === 'num') { +    return (str.match(/^NumberFormatSymbols_(.+)$/) || [])[1]; +  } else if (type == 'datetime') { +    return (str.match(/^DateTimeSymbols_(.+)$/) || [])[1]; +  } +}  | 
