174 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @license
 | |
|  * Copyright Google Inc. All Rights Reserved.
 | |
|  *
 | |
|  * Use of this source code is governed by an MIT-style license that can be
 | |
|  * found in the LICENSE file at https://angular.io/license
 | |
|  */
 | |
| 
 | |
| const cldr = require('cldr');
 | |
| // locale list
 | |
| const locales = cldr.localeIds;
 | |
| const langToRule = {};
 | |
| const ruleToLang = {};
 | |
| const variants = [];
 | |
| const localeToVariant = {};
 | |
| const DEFAULT_RULE = `function anonymous(n\n/**/) {\nreturn"other"\n}`;
 | |
| 
 | |
| locales.forEach(locale => {
 | |
|   const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
 | |
|   const lang = getVariantLang(locale, rule);
 | |
| 
 | |
|   if (!lang || !rule) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!ruleToLang[rule]) {
 | |
|     ruleToLang[rule] = [];
 | |
|   } else if (ruleToLang[rule].indexOf(lang) > -1) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ruleToLang[rule].push(lang);
 | |
| });
 | |
| 
 | |
| var nextVariantCode = 'a'.charCodeAt(0);
 | |
| 
 | |
| variants.forEach(locale => {
 | |
|   const rule = normalizeRule(cldr.extractPluralRuleFunction(locale).toString());
 | |
| 
 | |
|   if (!rule) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   var mapTo = null;
 | |
| 
 | |
|   if (ruleToLang[rule]) {
 | |
|     mapTo = ruleToLang[rule][0];
 | |
|     localeToVariant[locale] = mapTo;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!mapTo) {
 | |
|     mapTo = '_' + String.fromCharCode(nextVariantCode++);
 | |
| 
 | |
|     langToRule[mapTo] = rule;
 | |
|     ruleToLang[rule] = [mapTo];
 | |
|     localeToVariant[locale] = mapTo;
 | |
|   }
 | |
| });
 | |
| 
 | |
| console.log(generateCode());
 | |
| 
 | |
| function generateCode() {
 | |
|   checkMapping();
 | |
| 
 | |
|   return `
 | |
| // This is generated code DO NOT MODIFY
 | |
| // see angular2/script/cldr/gen_plural_rules.js
 | |
| 
 | |
| enum Plural {
 | |
|   Zero,
 | |
|   One,
 | |
|   Two,
 | |
|   Few,
 | |
|   Many,
 | |
|   Other
 | |
| }
 | |
| 
 | |
| function getPluralCase(locale: string, n: number|string): Plural {
 | |
| ` + generateVars() +
 | |
|     generateRules() + `
 | |
| }`;
 | |
| }
 | |
| 
 | |
| 
 | |
| function generateRules() {
 | |
|   const codeParts = [`
 | |
| const lang = locale.split('_')[0].toLowerCase();
 | |
| 
 | |
| switch (lang) {`];
 | |
| 
 | |
|   Object.keys(ruleToLang).forEach(rule => {
 | |
|     const langs = ruleToLang[rule];
 | |
|     codeParts.push(...langs.map(l => `  case '${l}': `));
 | |
|     codeParts.push(`    ${rule}`);
 | |
|   });
 | |
| 
 | |
|   codeParts.push(`  default:
 | |
|    return Plural.Other;
 | |
| }`);
 | |
| 
 | |
|   return codeParts.join('\n');
 | |
| }
 | |
| 
 | |
| function generateVars(){
 | |
|   return `
 | |
| function getPluralCase(locale: string, nLike: number | string): Plural {
 | |
| // TODO(vicb): lazy compute
 | |
| if (typeof nLike === 'string') {
 | |
|   nLike = parseInt(<string>nLike, 10);
 | |
| }
 | |
| const n: number = nLike as number;
 | |
| const nDecimal = n.toString().replace(/^[^.]*\\.?/, ""); 
 | |
| const i = Math.floor(Math.abs(n));
 | |
| const v = nDecimal.length;
 | |
| const f = parseInt(nDecimal, 10); 
 | |
| const t = parseInt(n.toString().replace(/^[^.]*\\.?|0+$/g,""), 10) || 0;
 | |
| `;
 | |
| }
 | |
| 
 | |
| function checkMapping() {
 | |
|   if (localeToVariant.length) {
 | |
|     console.log(`Mapping required:`);
 | |
|     console.log(localeToVariant);
 | |
|     throw new Error('not implemented');
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * If the language rule do not match an existing language rule, flag it as variant and handle it at the end
 | |
|  */
 | |
| function getVariantLang(locale, rule) {
 | |
|   var lang = locale.split('_')[0];
 | |
| 
 | |
|   if (!langToRule[lang]) {
 | |
|     langToRule[lang] = rule;
 | |
|     return lang;
 | |
|   }
 | |
| 
 | |
|   if (langToRule[lang] === rule) {
 | |
|     return lang;
 | |
|   }
 | |
| 
 | |
|   variants.push(locale);
 | |
|   return null;
 | |
| }
 | |
| 
 | |
| function normalizeRule(fn) {
 | |
|   if (fn === DEFAULT_RULE) return;
 | |
| 
 | |
|   return fn
 | |
|     .replace(toRegExp('function anonymous(n\n/**/) {\n'), '')
 | |
|     .replace(toRegExp('var'), 'let')
 | |
|     .replace(toRegExp('"zero"'), ' Plural.Zero')
 | |
|     .replace(toRegExp('"one"'), ' Plural.One')
 | |
|     .replace(toRegExp('"two"'), ' Plural.Two')
 | |
|     .replace(toRegExp('"few"'), ' Plural.Few')
 | |
|     .replace(toRegExp('"many"'), ' Plural.Many')
 | |
|     .replace(toRegExp('"other"'), ' Plural.Other')
 | |
|     .replace(toRegExp('\n}'), '')
 | |
|     .replace(toRegExp('let'), '')
 | |
|     .replace(toRegExp('if(typeof n==="string")n=parseInt(n,10);'), '')
 | |
|     .replace(toRegExp('i=Math.floor(Math.abs(n))'), '')
 | |
|     .replace(/v=n.toString.*?.length/g, '')
 | |
|     .replace(/f=parseInt.*?\|\|0/g, '')
 | |
|     .replace(/t=parseInt.*?\|\|0/g, '')
 | |
|     .replace(/^[ ,;]*/, '')
 | |
|   + ';';
 | |
| }
 | |
| 
 | |
| function toRegExp(s) {
 | |
|   return new RegExp(s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'), 'g');
 | |
| } |