diff --git a/src/components/popups/datePicker.ts b/src/components/popups/datePicker.ts index dcf6a08e..71033d18 100644 --- a/src/components/popups/datePicker.ts +++ b/src/components/popups/datePicker.ts @@ -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'); diff --git a/src/lib/langPack.ts b/src/lib/langPack.ts index 45e565bc..ecf09018 100644 --- a/src/lib/langPack.ts +++ b/src/lib/langPack.ts @@ -68,10 +68,14 @@ export type LangPackKey = Strings.LangPackKey; namespace I18n { export const strings: Map = new Map(); + let pluralRules: Intl.PluralRules; let lastRequestedLangCode: string; export function getCacheLangPack(): Promise { - 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; } diff --git a/src/lib/pluralPolyfill.ts b/src/lib/pluralPolyfill.ts new file mode 100644 index 00000000..d265eafe --- /dev/null +++ b/src/lib/pluralPolyfill.ts @@ -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; diff --git a/tsconfig.json b/tsconfig.json index fe164d31..9740bdbe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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. */ diff --git a/webpack.common.js b/webpack.common.js index 2704e1e9..23401baf 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -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"