Plural polyfill

This commit is contained in:
Eduard Kuzmenko 2021-03-21 21:09:20 +04:00
parent eab07f7ebc
commit 1c3e59988e
5 changed files with 413 additions and 12 deletions

View File

@ -42,7 +42,7 @@ export default class PopupDatePicker extends PopupElement {
}, {
text: 'CANCEL',
isCancel: true
}], {body: true, ...options});
}], {body: true, overlayClosable: true, ...options});
this.minDate = options.minDate || new Date('2013-08-01T00:00:00');

View File

@ -68,10 +68,14 @@ export type LangPackKey = Strings.LangPackKey;
namespace I18n {
export const strings: Map<LangPackKey, LangPackString> = new Map();
let pluralRules: Intl.PluralRules;
let lastRequestedLangCode: string;
export function getCacheLangPack(): Promise<LangPackDifference> {
return sessionStorage.get('langPack').then((langPack: LangPackDifference) => {
return Promise.all([
sessionStorage.get('langPack'),
polyfillPromise
]).then(([langPack]) => {
if(!langPack) {
return getLangPack('en');
}
@ -87,22 +91,37 @@ namespace I18n {
export function getLangPack(langCode: string) {
lastRequestedLangCode = langCode;
return apiManager.invokeApi('langpack.getLangPack', {
lang_code: langCode,
lang_pack: 'macos'
}).then(langPack => {
return Promise.all([
apiManager.invokeApi('langpack.getLangPack', {
lang_code: langCode,
lang_pack: 'macos'
}),
polyfillPromise
]).then(([langPack, _]) => {
return sessionStorage.set({langPack}).then(() => {
applyLangPack(langPack);
return langPack;
});
});
}
export const polyfillPromise = (function checkIfPolyfillNeeded() {
if(typeof(Intl) !== 'undefined' && typeof(Intl.PluralRules) !== 'undefined'/* && false */) {
return Promise.resolve();
} else {
return import('./pluralPolyfill').then(_Intl => {
(window as any).Intl = _Intl.default;
});
}
})();
export function applyLangPack(langPack: LangPackDifference) {
if(langPack.lang_code !== lastRequestedLangCode) {
return;
}
pluralRules = new Intl.PluralRules(langPack.lang_code);
strings.clear();
for(const string of langPack.strings) {
@ -125,7 +144,10 @@ namespace I18n {
if(str) {
if(str._ === 'langPackStringPluralized') {
out = str.one_value;
const v = args[0] as number;
const s = pluralRules.select(v);
// @ts-ignore
out = str[s + '_value'];
} else if(str._ === 'langPackString') {
out = str.value;
} else {
@ -135,6 +157,12 @@ namespace I18n {
out = '[' + key + ']';
}
if(args?.length) {
out = out.replace(/%./g, (match, offset, string) => {
return '' + args.shift();
});
}
return out;
}

370
src/lib/pluralPolyfill.ts Normal file
View File

@ -0,0 +1,370 @@
const NumberPluralizationFormZero: Intl.LDMLPluralRule = 'zero';
const NumberPluralizationFormOne: Intl.LDMLPluralRule = 'one';
const NumberPluralizationFormTwo: Intl.LDMLPluralRule = 'two';
const NumberPluralizationFormFew: Intl.LDMLPluralRule = 'few';
const NumberPluralizationFormMany: Intl.LDMLPluralRule = 'many';
const NumberPluralizationFormOther: Intl.LDMLPluralRule = 'other';
function numberPluralizationForm(lc: number, n: number): Intl.LDMLPluralRule {
switch (lc) {
// set1
case 0x6c74: // lt
if (((n % 10) == 1) && (((n % 100) < 11 || (n % 100) > 19))) // n mod 10 is 1 and n mod 100 not in 11..19
return NumberPluralizationFormOne;
if ((((n % 10) >= 2 && (n % 10) <= 9)) && (((n % 100) < 11 || (n % 100) > 19))) // n mod 10 in 2..9 and n mod 100 not in 11..19
return NumberPluralizationFormFew;
break;
// set2
case 0x6c76: // lv
if (n == 0) // n is 0
return NumberPluralizationFormZero;
if (((n % 10) == 1) && ((n % 100) != 11)) // n mod 10 is 1 and n mod 100 is not 11
return NumberPluralizationFormOne;
break;
// set3
case 0x6379: // cy
if (n == 2) // n is 2
return NumberPluralizationFormTwo;
if (n == 3) // n is 3
return NumberPluralizationFormFew;
if (n == 0) // n is 0
return NumberPluralizationFormZero;
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if (n == 6) // n is 6
return NumberPluralizationFormMany;
break;
// set4
case 0x6265: // be
case 0x6273: // bs
case 0x6872: // hr
case 0x7275: // ru
case 0x7368: // sh
case 0x7372: // sr
case 0x756b: // uk
if (((n % 10) == 1) && ((n % 100) != 11)) // n mod 10 is 1 and n mod 100 is not 11
return NumberPluralizationFormOne;
if ((((n % 10) >= 2 && (n % 10) <= 4)) && (((n % 100) < 12 || (n % 100) > 14))) // n mod 10 in 2..4 and n mod 100 not in 12..14
return NumberPluralizationFormFew;
if (((n % 10) == 0) || (((n % 10) >= 5 && (n % 10) <= 9)) || (((n % 100) >= 11 && (n % 100) <= 14))) // n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14
return NumberPluralizationFormMany;
break;
// set5
case 0x6b7368: // ksh
if (n == 0) // n is 0
return NumberPluralizationFormZero;
if (n == 1) // n is 1
return NumberPluralizationFormOne;
break;
// set6
case 0x736869: // shi
if ((n >= 2 && n <= 10)) // n in 2..10
return NumberPluralizationFormFew;
if ((n >= 0 && n <= 1)) // n within 0..1
return NumberPluralizationFormOne;
break;
// set7
case 0x6865: // he
if (n == 2) // n is 2
return NumberPluralizationFormTwo;
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if ((n != 0) && ((n % 10) == 0)) // n is not 0 AND n mod 10 is 0
return NumberPluralizationFormMany;
break;
// set8
case 0x6373: // cs
case 0x736b: // sk
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if ((n >= 2 && n <= 4)) // n in 2..4
return NumberPluralizationFormFew;
break;
// set9
case 0x6272: // br
if ((n != 0) && ((n % 1000000) == 0)) // n is not 0 and n mod 1000000 is 0
return NumberPluralizationFormMany;
if (((n % 10) == 1) && (((n % 100) != 11) && ((n % 100) != 71) && ((n % 100) != 91))) // n mod 10 is 1 and n mod 100 not in 11,71,91
return NumberPluralizationFormOne;
if (((n % 10) == 2) && (((n % 100) != 12) && ((n % 100) != 72) && ((n % 100) != 92))) // n mod 10 is 2 and n mod 100 not in 12,72,92
return NumberPluralizationFormTwo;
if ((((n % 10) >= 3 && (n % 10) <= 4) || ((n % 10) == 9)) && (((n % 100) < 10 || (n % 100) > 19) && ((n % 100) < 70 || (n % 100) > 79) && ((n % 100) < 90 || (n % 100) > 99))) // n mod 10 in 3..4,9 and n mod 100 not in 10..19,70..79,90..99
return NumberPluralizationFormFew;
break;
// set10
case 0x736c: // sl
if ((n % 100) == 2) // n mod 100 is 2
return NumberPluralizationFormTwo;
if ((n % 100) == 1) // n mod 100 is 1
return NumberPluralizationFormOne;
if (((n % 100) >= 3 && (n % 100) <= 4)) // n mod 100 in 3..4
return NumberPluralizationFormFew;
break;
// set11
case 0x6c6167: // lag
if (n == 0) // n is 0
return NumberPluralizationFormZero;
if (((n >= 0 && n <= 2)) && (n != 0) && (n != 2)) // n within 0..2 and n is not 0 and n is not 2
return NumberPluralizationFormOne;
break;
// set12
case 0x706c: // pl
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if ((((n % 10) >= 2 && (n % 10) <= 4)) && (((n % 100) < 12 || (n % 100) > 14))) // n mod 10 in 2..4 and n mod 100 not in 12..14
return NumberPluralizationFormFew;
if (((n != 1) && (((n % 10) >= 0 && (n % 10) <= 1))) || (((n % 10) >= 5 && (n % 10) <= 9)) || (((n % 100) >= 12 && (n % 100) <= 14))) // n is not 1 and n mod 10 in 0..1 or n mod 10 in 5..9 or n mod 100 in 12..14
return NumberPluralizationFormMany;
break;
// set13
case 0x6764: // gd
if ((n == 2) || (n == 12)) // n in 2,12
return NumberPluralizationFormTwo;
if ((n == 1) || (n == 11)) // n in 1,11
return NumberPluralizationFormOne;
if ((n >= 3 && n <= 10) || (n >= 13 && n <= 19)) // n in 3..10,13..19
return NumberPluralizationFormFew;
break;
// set14
case 0x6776: // gv
if ((((n % 10) >= 1 && (n % 10) <= 2)) || ((n % 20) == 0)) // n mod 10 in 1..2 or n mod 20 is 0
return NumberPluralizationFormOne;
break;
// set15
case 0x6d6b: // mk
if (((n % 10) == 1) && (n != 11)) // n mod 10 is 1 and n is not 11
return NumberPluralizationFormOne;
break;
// set16
case 0x6d74: // mt
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if (((n % 100) >= 11 && (n % 100) <= 19)) // n mod 100 in 11..19
return NumberPluralizationFormMany;
if ((n == 0) || (((n % 100) >= 2 && (n % 100) <= 10))) // n is 0 or n mod 100 in 2..10
return NumberPluralizationFormFew;
break;
// set17
case 0x6d6f: // mo
case 0x726f: // ro
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if ((n == 0) || ((n != 1) && (((n % 100) >= 1 && (n % 100) <= 19)))) // n is 0 OR n is not 1 AND n mod 100 in 1..19
return NumberPluralizationFormFew;
break;
// set18
case 0x6761: // ga
if (n == 2) // n is 2
return NumberPluralizationFormTwo;
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if ((n >= 3 && n <= 6)) // n in 3..6
return NumberPluralizationFormFew;
if ((n >= 7 && n <= 10)) // n in 7..10
return NumberPluralizationFormMany;
break;
// set19
case 0x6666: // ff
case 0x6672: // fr
case 0x6b6162: // kab
if (((n >= 0 && n <= 2)) && (n != 2)) // n within 0..2 and n is not 2
return NumberPluralizationFormOne;
break;
// set20
case 0x6975: // iuw
case 0x6b77: // kw
case 0x7365: // se
case 0x6e6171: // naq
case 0x736d61: // sma
case 0x736d69: // smi
case 0x736d6a: // smj
case 0x736d6e: // smn
case 0x736d73: // sms
if (n == 2) // n is 2
return NumberPluralizationFormTwo;
if (n == 1) // n is 1
return NumberPluralizationFormOne;
break;
// set21
case 0x616b: // ak
case 0x616d: // am
case 0x6268: // bh
case 0x6869: // hi
case 0x6c6e: // ln
case 0x6d67: // mg
case 0x7469: // ti
case 0x746c: // tl
case 0x7761: // wa
case 0x66696c: // fil
case 0x677577: // guw
case 0x6e736f: // nso
if ((n >= 0 && n <= 1)) // n in 0..1
return NumberPluralizationFormOne;
break;
// set22
case 0x747a6d: // tzm
if (((n >= 0 && n <= 1)) || ((n >= 11 && n <= 99))) // n in 0..1 or n in 11..99
return NumberPluralizationFormOne;
break;
// set23
case 0x6166: // af
case 0x6267: // bg
case 0x626e: // bn
case 0x6361: // ca
case 0x6461: // da
case 0x6465: // de
case 0x6476: // dv
case 0x6565: // ee
case 0x656c: // el
case 0x656e: // en
case 0x656f: // eo
case 0x6573: // es
case 0x6574: // et
case 0x6575: // eu
case 0x6669: // fi
case 0x666f: // fo
case 0x6679: // fy
case 0x676c: // gl
case 0x6775: // gu
case 0x6861: // ha
case 0x6973: // is
case 0x6974: // it
case 0x6b6b: // kk
case 0x6b6c: // kl
case 0x6b73: // ks
case 0x6b75: // ku
case 0x6b79: // ky
case 0x6c62: // lb
case 0x6c67: // lg
case 0x6d6c: // ml
case 0x6d6e: // mn
case 0x6d72: // mr
case 0x6e62: // nb
case 0x6e64: // nd
case 0x6e65: // ne
case 0x6e6c: // nl
case 0x6e6e: // nn
case 0x6e6f: // no
case 0x6e72: // nr
case 0x6e79: // ny
case 0x6f6d: // om
case 0x6f72: // or
case 0x6f73: // os
case 0x7061: // pa
case 0x7073: // ps
case 0x7074: // pt
case 0x726d: // rm
case 0x736e: // sn
case 0x736f: // so
case 0x7371: // sq
case 0x7373: // ss
case 0x7374: // st
case 0x7376: // sv
case 0x7377: // sw
case 0x7461: // ta
case 0x7465: // te
case 0x746b: // tk
case 0x746e: // tn
case 0x7473: // ts
case 0x7572: // ur
case 0x7665: // ve
case 0x766f: // vo
case 0x7868: // xh
case 0x7a75: // zu
case 0x617361: // asa
case 0x617374: // ast
case 0x62656d: // bem
case 0x62657a: // bez
case 0x627278: // brx
case 0x636767: // cgg
case 0x636872: // chr
case 0x636b62: // ckb
case 0x667572: // fur
case 0x677377: // gsw
case 0x686177: // haw
case 0x6a676f: // jgo
case 0x6a6d63: // jmc
case 0x6b616a: // kaj
case 0x6b6367: // kcg
case 0x6b6b6a: // kkj
case 0x6b7362: // ksb
case 0x6d6173: // mas
case 0x6d676f: // mgo
case 0x6e6168: // nah
case 0x6e6e68: // nnh
case 0x6e796e: // nyn
case 0x706170: // pap
case 0x726f66: // rof
case 0x72776b: // rwk
case 0x736171: // saq
case 0x736568: // seh
case 0x737379: // ssy
case 0x737972: // syr
case 0x74656f: // teo
case 0x746967: // tig
case 0x76756e: // vun
case 0x776165: // wae
case 0x786f67: // xog
if (n == 1) // n is 1
return NumberPluralizationFormOne;
break;
// set24
case 0x6172: // ar
if (n == 2) // n is 2
return NumberPluralizationFormTwo;
if (n == 1) // n is 1
return NumberPluralizationFormOne;
if (n == 0) // n is 0
return NumberPluralizationFormZero;
if (((n % 100) >= 3 && (n % 100) <= 10)) // n mod 100 in 3..10
return NumberPluralizationFormFew;
if (((n % 100) >= 11 && (n % 100) <= 99)) // n mod 100 in 11..99
return NumberPluralizationFormMany;
break;
}
return NumberPluralizationFormOther;
}
function languageCodehash(code: string) {
let lc = 0;
for(let i = 0; i < code.length; ++i) { lc = (lc << 8) + code.charCodeAt(i); }
return lc;
}
const Intl = {
PluralRules: class {
public select: (n: number) => Intl.LDMLPluralRule;
constructor(code: string) {
this.select = numberPluralizationForm.bind(null, languageCodehash(code));
}
}
};
export default Intl;

View File

@ -4,7 +4,7 @@
// "incremental": true, /* Enable incremental compilation */
//"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"module": "esnext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": ["es2015", "dom", "webworker"], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
@ -17,7 +17,7 @@
//"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
"removeComments": false, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
//"importHelpers": true, /* Import emit helpers from 'tslib'. */
"downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
@ -30,7 +30,7 @@
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
"strictPropertyInitialization": false, /* Enable strict checking of property initialization in classes. */
// "skipLibCheck": true,
"skipLibCheck": true,
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */

View File

@ -9,7 +9,7 @@ const fs = require('fs');
const allowedIPs = ['194.58.97.147', '195.66.140.39', '127.0.0.1', '176.100.8.254'];
const devMode = process.env.NODE_ENV !== 'production';
const useLocal = true;
const useLocalNotLocal = false;
const useLocalNotLocal = true;
if(devMode) {
console.log('DEVMODE IS ON!');
@ -17,6 +17,7 @@ if(devMode) {
const opts = {
MTPROTO_WORKER: true,
MTPROTO_SW: false,
MTPROTO_HTTP: false,
MTPROTO_HTTP_UPLOAD: false,
DEBUG: devMode,
@ -81,11 +82,13 @@ module.exports = {
entry: './src/index.ts',
/* entry: {
index: './src/index.ts'
index: './src/index.ts',
pluralPolyfill: './src/lib/pluralPolyfill.ts'
}, */
//devtool: 'inline-source-map',
output: {
globalObject: "this",
path: path.resolve(__dirname, 'public'),
filename: "[name].[chunkhash].bundle.js",
chunkFilename: "[name].[chunkhash].chunk.js"