aboutsummaryrefslogtreecommitdiffstats
path: root/i18n/src/closureI18nExtractor.js
diff options
context:
space:
mode:
Diffstat (limited to 'i18n/src/closureI18nExtractor.js')
-rw-r--r--i18n/src/closureI18nExtractor.js175
1 files changed, 175 insertions, 0 deletions
diff --git a/i18n/src/closureI18nExtractor.js b/i18n/src/closureI18nExtractor.js
new file mode 100644
index 00000000..a26f89b7
--- /dev/null
+++ b/i18n/src/closureI18nExtractor.js
@@ -0,0 +1,175 @@
+'use strict';
+
+var converter = require('./converter.js');
+
+exports.extractNumberSymbols = extractNumberSymbols;
+exports.extractCurrencySymbols = extractCurrencySymbols;
+exports.extractDateTimeSymbols = extractDateTimeSymbols;
+exports.pluralExtractor = pluralExtractor;
+exports.outputLocale = outputLocale;
+exports.correctedLocaleId = correctedLocaleId;
+exports.findLocaleId = findLocaleId;
+
+var goog = { provide: function() {},
+ require: function() {},
+ i18n: {currency: {}, pluralRules: {}} };
+
+function findLocaleId(str, type) {
+ if (type === 'num') {
+ return (str.match(/^NumberFormatSymbols_(.+)$/) || [])[1];
+ }
+
+ if (type != 'datetime') { throw new Error('unknown type in findLocaleId: ' + type); }
+
+ return (str.match(/^DateTimeSymbols_(.+)$/) || [])[1];
+}
+
+
+function getInfoForLocale(localeInfo, localeID) {
+ if (!localeInfo[localeID]) {
+ localeInfo[localeID] = {};
+ //localeIds.push(localeID);
+ }
+ return localeInfo[localeID];
+}
+
+function extractNumberSymbols(content, localeInfo, currencySymbols) {
+ //eval script in the current context so that we get access to all the symbols
+ eval(content.toString());
+ for (var propName in goog.i18n) {
+ var localeID = findLocaleId(propName, 'num');
+ if (localeID) {
+ var info = getInfoForLocale(localeInfo, localeID);
+ info.NUMBER_FORMATS =
+ converter.convertNumberData(goog.i18n[propName], currencySymbols);
+ }
+ }
+}
+
+function extractCurrencySymbols(content) {
+ //eval script in the current context so that we get access to all the symbols
+ eval(content.toString());
+ var currencySymbols = goog.i18n.currency.CurrencyInfo;
+ currencySymbols.__proto__ = goog.i18n.currency.CurrencyInfoTier2;
+
+ return currencySymbols;
+}
+
+function extractDateTimeSymbols(content, localeInfo) {
+ //eval script in the current context so that we get access to all the symbols
+ eval(content.toString());
+ for (var propName in goog.i18n) {
+ var localeID = findLocaleId(propName, 'datetime');
+ if (localeID) {
+ var info = getInfoForLocale(localeInfo, localeID);
+ localeInfo[localeID].DATETIME_FORMATS =
+ converter.convertDatetimeData(goog.i18n[propName]);
+ }
+ }
+}
+
+function pluralExtractor(content, localeInfo) {
+ var contentText = content.toString();
+ var localeIds = Object.keys(localeInfo);
+ for (var i = 0; i < localeIds.length; i++) {
+ //We don't need to care about country ID because the plural rules in more specific id are
+ //always the same as those in its language ID.
+ // e.g. plural rules for en_SG is the same as those for en.
+ goog.LOCALE = localeIds[i].match(/[^_]+/)[0];
+ try {
+ eval(contentText);
+ } catch(e) {
+ console.log("Error in eval(contentText): " + e.stack);
+ }
+ if (!goog.i18n.pluralRules.select) {
+ console.log('No select for lang [' + goog.LOCALE + ']');
+ continue;
+ }
+ var temp = goog.i18n.pluralRules.select.toString().
+ replace(/goog.i18n.pluralRules.Keyword/g, 'PLURAL_CATEGORY').replace(/\n/g, '');
+
+ ///@@ is a crazy place holder to be replaced before writing to file
+ localeInfo[localeIds[i]].pluralCat = "@@" + temp + "@@";
+ }
+}
+
+function correctedLocaleId(localeID) {
+// e.g. from zh_CN to zh-CN, from en_US to en-US
+ return localeID.replace(/_/g, '-').toLowerCase();
+}
+
+function canonicalizeForJsonStringify(unused_key, object) {
+ // This function is intended to be called as the 2nd argument to
+ // JSON.stringify. The goal here is to ensure that the generated JSON has
+ // objects with their keys in ascending order. Without this, it's much
+ // harder to diff the generated files in src/ngLocale as the order isn't
+ // exactly consistent. We've gotten lucky in the past.
+ //
+ // Iteration order, for string keys, ends up being the same as insertion
+ // order. Refer :-
+ // 1. http://ejohn.org/blog/javascript-in-chrome/
+ // (search for "for loop order").
+ // Currently all major browsers loop over the properties of an object
+ // in the order in which they were defined.
+ // - John Resig
+ // 2. https://code.google.com/p/v8/issues/detail?id=164
+ // ECMA-262 does not specify enumeration order. The de facto standard
+ // is to match insertion order, which V8 also does ...
+ if (typeof object != "object") {
+ return object;
+ }
+ var result = {};
+ Object.keys(object).sort().forEach(function(key) {
+ result[key] = object[key];
+ });
+ return result;
+}
+
+function outputLocale(localeInfo, 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;
+ }
+
+ // datetimesymbolsext.js provides more top level locales than the other
+ // files. We process datetimesymbolsext.js because we want the country
+ // specific formats that are missing from datetimesymbols.js. However, we
+ // don't want to write locale files that only have dateformat (i.e. missing
+ // number formats.) So we skip them.
+ if (!localeObj.NUMBER_FORMATS) {
+ console.log("Skipping locale %j: Don't have any number formats", localeID);
+ return null;
+ }
+
+ if (!localeObj.DATETIME_FORMATS) {
+ localeObj.DATETIME_FORMATS = fallBackObj.DATETIME_FORMATS;
+ }
+ localeObj.id = correctedLocaleId(localeID);
+
+ var prefix =
+ 'angular.module("ngLocale", [], ["$provide", function($provide) {\n' +
+ 'var PLURAL_CATEGORY = {' +
+ 'ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"' +
+ '};\n' +
+ '$provide.value("$locale", ';
+
+ var suffix = ');\n}]);';
+
+ localeObj = {
+ DATETIME_FORMATS: localeObj.DATETIME_FORMATS,
+ NUMBER_FORMATS: localeObj.NUMBER_FORMATS,
+ pluralCat: localeObj.pluralCat,
+ id: localeObj.id
+ };
+
+ var content = JSON.stringify(localeInfo[localeID], canonicalizeForJsonStringify, ' ')
+ .replace(/\ยค/g, '\\u00A4')
+ .replace(/"@@|@@"/g, '');
+
+ return prefix + content + suffix;
+}