Last active
October 22, 2025 02:03
-
-
Save sebilasse/77ab52bb4ad82a9665f910a174c6ad90 to your computer and use it in GitHub Desktop.
IntlToActivitypub - for reference - converts JS Intl to Regexes which are used in the ActivityPub Parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // see below | |
| import { intlLocales, cardinalSuffix, isS, isNr, ok, calcTime, toTimeInt } from './shared.ts'; | |
| import { custom, dateCasual, dateCasualKeys } from './local.ts'; | |
| const IS_SERVER = (typeof document === 'undefined'); | |
| let m49regionMissing; let m49regionMap; | |
| if (IS_SERVER) { | |
| m49regionMissing = (await import('./m49.ts')).m49regionMissing; | |
| m49regionMap = (await import('./m49.ts')).m49regionMap; | |
| } | |
| export const alias = { | |
| GB: ['UK', 'United Kingdom'], | |
| Edmonton: ['Alberta'], | |
| Dawson: ['Yukon'], | |
| Winnipeg: ['Manitoba'], | |
| Toronto: ['Montreal','Ottawa'], | |
| Edmonton: ['Calgary','Banff'], | |
| Moncton: ['New Brunswick','Nova Scotia', 'Prince Edward Island'], | |
| 'St Johns': ['Newfoundland'], | |
| McMurdo: ['Amundsen–Scott', 'South Pole'], | |
| 'Rio Branco': ['Acre'], | |
| 'Punta Arenas': ['Magallanes','Chilean Antarctica'], | |
| Easter: ['Easter Island'], | |
| Jakarta: ['Sumatra', 'Java', 'Madura'], | |
| Jayapura: ['Western New Guinea ', 'Maluku'], | |
| Makassar: ['Sulawesi', 'Bali'], | |
| Pontianak: ['Borneo'], | |
| Guayaquil: ['mainland'], | |
| Galapagos: ['Galápagos'], | |
| Detroit: ['DC', 'Washington D.C.', 'Washington DC'], | |
| Moscow: ['St. Petersburg'] | |
| }; | |
| export const capitalAlias = { | |
| AU: 'Canberra', BR: 'Brasilia', CA: 'Ottawa', EC: 'Quito', FM: 'Palikir', NZ: 'Wellington', US: 'Washington, D.C.', | |
| AE: "Abu Dhabi", AG: "Saint John's", AI: "The Valley", AW: "Oranjestad", BB: "Bridgetown", BH: "Manama", BI: "Gitega", | |
| BJ: "Porto-Novo", BL: "Gustavia", BM: "Hamilton", BN: "Bandar Seri Begawan", BO: "Sucre", BZ: "Belmopan", CC: "West Island", | |
| CH: "Bern", CI: "Yamoussoukro", CK: "Avarua", CM: "Yaoundé", CN: "Beijing", CR: "San José", CV: "Praia", CW: "Willemstad", | |
| CX: "Flying Fish Cove", DM: "Roseau", FJ: "Suva", FO: "Tórshavn", GD: "St. George's", GG: "St. Peter Port", GL: "Nuuk", | |
| GP: "Basse-Terre", GS: "King Edward Point", GU: "Hagåtña", GY: "Georgetown", IM: "Douglas", IN: "New Delhi", | |
| IO: "Diego Garcia", JE: "Saint Helier", JM: "Kingston", KM: "Moroni", KN: "Basseterre", KY: "George Town", KZ: "Astana", | |
| LC: "Castries", MA: "Rabat", MD: "Chișinău", MM: "Naypyidaw", MN: "Ulan Bator", MO: '-', MQ: "Fort-de-France", MS: "Plymouth", | |
| MT: "Valletta", MU: "Port Louis", MV: "Malé", MW: "Lilongwe", NC: "Nouméa", NF: "Kingston", NG: "Abuja", NP: "Kathmandu", | |
| NR: "Yaren", NU: "Alofi", PF: "Papeetē", PK: "Islamabad", PM: "Saint-Pierre", PN: "Adamstown", PR: "San Juan", PS: "Ramallah", | |
| PW: "Ngerulmud", PY: "Asunción", QA: "Doha", RE: "Saint-Denis", SB: "Honiara", SC: "Victoria", SH: "Jamestown", SM: "City of San Marino", | |
| SV: "San Salvador", SX: "Philipsburg", SZ: "Lobamba", TC: "Cockburn Town", TD: "N'Djamena", TF: "Port-aux-Français", TG: "Lomé", | |
| TO: "Nuku'alofa", TR: "Ankara", TT: "Port of Spain", TZ: "Dodoma", UA: "Kyiv", UM: '-', VA: "Vatican City", VC: "Kingstown", | |
| VG: "Road Town", VI: "Charlotte Amalie", VN: "Hanoi", VU: "Port Vila", WF: "Mata-Utu", YE: "Sana'a", YT: "Mamoudzou", ZA: "Pretoria" | |
| }; | |
| export const countryOlson = [ | |
| /* always multiple tz, can have an [] with region aliases */ | |
| ['AQ',['Casey','Dav','Dum','Maw','Mc','Palmr','Rot','Syo','Tro','Vos','Riy','Sin','Au','Porty'],1], | |
| ['AU',['Syd','Adele','Bri','Bro','Darwn','Eu','Hob','Lin','Lor','Mel','Per','Macqe','Tok',['HM','CC','CX','NF']],1], | |
| ['BR',['Sao o','Rio o','Ara','Bahia','Belem','Boa','Campe','Cui','Ei','Forta','Maceo','Manas','Noroa','Porto','Rec','Santm'],1], | |
| ['CA',[ | |
| 'Toroo','Van','Ed','Hal','Camby','Corar','Cr','Dawsn','Dawsk','Fortn','Gl','Goo','Inu','Iq','Moncn', | |
| 'Pan','Pho','Pue','Rankt','Reg','Res','St Js','Sw','Wh','Winng' | |
| ],1], | |
| ['CD',['Kin','Lag','Lub','Map'],1], | |
| ['CL',['Santiago','Pun','Ea'],1], | |
| ['DK',['Cop','Berln',['GL','FO']],1], | |
| ['EC',['Guayl','Gal'],1], | |
| ['ES',['Madrd','Ceu','Canay'],1], | |
| ['FM',['Ponae','Guadl','Ko','Porty','Tru'],1], | |
| ['FR',['Paris',['BL','GP','MF','MQ','GF','PM','YT','RE','TF','NC','WF']],1], | |
| ['GB',['Londn',['GG','IM','JE','GI','IO','PN','KY','TC','AI','BM','MS','VG','FK','GS']],1], | |
| ['ID',['Jak','Jay','Mak','Pontk'],1], | |
| ['KI',['Tar','En','Kirii'],1], | |
| ['MN',['Ula','Cho','Hov'],1], | |
| ['MX',['Mex','Bahis','Cancn','Chiha','Ci','Her','Mat','Maz','Mer','Monty','Oj','Tij'],1], | |
| ['NL',['Ams','Bruss',['BQ','AW','CW','SX']],1], | |
| ['NZ',['Au','Chatm',['NU','CK','TK']],1], | |
| ['PG',['Porty','Bou'],1], | |
| ['PT',['Lis','Az','Madea'],1], | |
| ['RU',[ | |
| 'Mos','Samaa','Yek','Om','Krask','Ir','Yakuk','Vl','Mag','Kamca','Ana','Barnl','Chita','Khana', | |
| 'Novokuznetsk','Novosibirsk','Sak','Sr','Tom','Ast','Kal','Kirov','Sarav','Sim','Uly','Vol' | |
| ],1], | |
| ['US',[ | |
| 'Det','Ada','Anc','Boi','Chico','Den','Ind','Jun','Los','Lou','Menoe','Met','New k','Nom','Pho','Sit','Yakut','Honou', | |
| ['GU', 'MP', 'AS', 'PR', 'VI'] | |
| ],1], | |
| /* usually single tz */ | |
| ['AD',['And']], ['AE',['Dubai']], ['AF',['Kab']], ['AG',['Antia','Pue']], ['AI',['Ang','Pue']], ['AL',['Tir']], ['AM',['Yer']], | |
| ['AO',['Lua','Lag']], ['AR',['Bue','Cat','Corda','Juj','Menda']], ['AS',['Pag']], ['AT',['Viena']], ['AW',['Aru','Pue']], | |
| ['AX',['Marin','Hel']], ['AZ',['Bak']], ['BA',['Sarao','Belge']], ['BB',['Barbs']], ['BD',['Dh']], ['BE',['Bruss']], | |
| ['BF',['Ou','Ab']], ['BG',['Sof']], ['BH',['Bahrn','Qa']], ['BI',['Buj','Map']], ['BJ',['Lag']], ['BL',['Pue','St By']], | |
| ['BM',['Berma']], ['CV',['Cap']], ['BN',['Bruni','Kuc']], ['BO',['La Pz']], ['PE',['Lim']], ['BQ',['Kralk','Pue']], | |
| ['BS',['Nas','Toroo']], ['BT',['Thi']], ['BW',['Gab','Map']], ['BY',['Min']], ['BZ',['Belie']], ['CI',['Ab']], ['CC',['Coc']], | |
| ['CF',['Bangi','Lag']], ['CG',['Braze','Lag']], ['CH',['Zu']], ['CK',['Rar']], ['CM',['Dou','Lag']], ['CN',['Sh','Ur']], | |
| ['CO',['Bog']], ['CR',['Cos']], ['CU',['Hav']], ['CW',['Cur','Pue']], ['CX',['Bangk','Chr']], ['CY',['Nic','Fam']], ['CZ',['Pr']], | |
| ['DE',['Berln','Bus','Zu']], ['DJ',['Dj','Nai']], ['DM',['Dom','Pue']], ['DO',['Santo Domingo']], ['DZ',['Alg']], ['EE',['Tal']], | |
| ['EG',['Cai']], ['EH',['El An']], ['ER',['Asm','Nai']], ['ET',['Add','Nai']], ['FI',['Hel']], ['FJ',['Fi']], ['FO',['Fae']], | |
| ['FK',['Sta']], ['GA',['Lib','Lag']], ['GD',['Gre','Pue']], ['GE',['Tb']], ['GF',['Cayee']], ['GG',['Gue','Londn']], | |
| ['GH',['Ac','Ab']], ['GI',['Gi']], ['GL',['Dan','God','Sc','Thu']], ['GM',['Banjl','Ab']], ['GN',['Con','Ab']], ['GP',['Guade','Pue']], | |
| ['GQ',['Malao','Lag']], ['GR',['Ath']], ['GS',['Sou']], ['GT',['Guata']], ['GW',['Bissu']], ['GU',['Guamm']], ['GY',['Guy']], | |
| ['HK',['Hongg']], ['HN',['Teg']], ['HR',['Za','Belge']], ['HU',['Bud']], ['IE',['Dubln']], ['IL',['Jerum']], ['IM',['Isl','Londn']], | |
| ['IN',['Cal']], ['IO',['Chags']], ['IQ',['Bag']], ['IR',['Teh']], ['IS',['Rey','Ab']], ['IT',['Rom']], ['JE',['Jersy','Londn']], | |
| ['JM',['Jam']], ['JO',['Amm']], ['JP',['Tok']], ['KE',['Nai']], ['KG',['Bishk']], ['KH',['Phn','Bangk']], ['KM',['Nai','Com']], | |
| ['KN',['Pue','St Ks']], ['KY',['Caymn','Pan']], ['KP',['Py']], ['KR',['Se']], ['KW',['Kuw','Riy']], | |
| ['KZ',['Alm','Aqtau','Aqtoe','Aty','Or','Qo','Qy']], ['LA',['Viene','Bangk']], ['LB',['Bei']], ['LC',['Pue','St La']], ['LI',['Vad','Zu']], | |
| ['LK',['Col']], ['LR',['Monra']], ['LS',['Mas','Jo']], ['LT',['Vil']], ['LU',['Lux','Bruss']], ['LV',['Rig']], ['LY',['Tri']], | |
| ['MA',['Casaa']], ['MC',['Monao','Paris']],['MD',['Chisu']], ['ME',['Pod','Belge']], ['MF',['Marit','Pue']], ['MG',['Antao','Nai']], | |
| ['MH',['Maj','Kw','Tar']], ['MK',['Sk','Belge']], ['ML',['Bam','Ab']], ['MM',['Rangn']], ['MO',['Macau']], ['MP',['Saipn','Guamm']], | |
| ['MR',['Nouat','Ab']], ['MQ',['Marte']], ['MS',['Montt','Pue']], ['MT',['Malta']], ['MU',['Mau']], ['MV',['Malds']], ['MW',['Blane','Map']], | |
| ['MY',['Kua','Kuc','Sin']], ['MZ',['Map']], ['NA',['Windk']], ['NC',['Nouma']], ['NE',['Nia','Lag']], ['NF',['Norfk']], ['NG',['Lag']], | |
| ['NI',['Manaa']], ['NO',['Os','Berln']], ['NP',['Kat']], ['NR',['Nau']], ['NU',['Niu']], ['OM',['Mu','Dubai']], ['PA',['Pan']], | |
| ['PF',['Gam','Marqs','Tah']], ['PH',['Mania']], ['PK',['Kar']], ['PL',['War']], ['PM',['Miq']], ['PN',['Pi']], ['PR',['Pue']], | |
| ['PS',['Gaz','Heb']], ['PW',['Palau']], ['PY',['Asu']], ['QA',['Qa']], ['RO',['Buc']], ['RE',['Dubai','Reu']], ['RS',['Belge']], | |
| ['RW',['Kig','Map']], ['SA',['Riy']], ['SB',['Guadl']], ['SC',['Dubai','Mah']], ['SD',['Kharm']], ['SE',['Sto','Berln']], | |
| ['SG',['Sin']], ['SH',['Ab','St Ha']], ['SI',['Lj','Belge']], ['SJ',['Longn','Berln']], ['SK',['Brata','Pr']], ['SL',['Fr','Ab']], | |
| ['SM',['Rom','San o']], ['SN',['Dak','Ab']], ['SO',['Mog','Nai']], ['SR',['Parao']], ['SS',['Jub']], ['ST',['Sao e']], ['SV',['El Sr']], | |
| ['SX',['Low','Pue']], ['SY',['Dam']], ['SZ',['Jo','Mb']], ['TC',['Gra']], ['TD',['Nd']], ['TF',['Dubai','Ke','Malds']], ['TH',['Bangk']], | |
| ['TG',['Ab','Lom']], ['TJ',['Dus']], ['TK',['Fak']], ['TL',['Di']], ['TM',['Ash']], ['TN',['Tun']], ['TO',['Ton']], ['TR',['Ist']], | |
| ['TT',['Portn','Pue']], ['TV',['Fu','Tar']], ['TW',['Tai']], ['TZ',['Dar m','Nai']], ['UA',['Kie','Sim']], ['UG',['Kampa','Nai']], | |
| ['UM',['Mid','Pag','Tar','Wak']], ['UY',['Monto']], ['UZ',['Tas','Samad']], ['VA',['Rom','Vat']], ['VC',['Pue','St Vt']], | |
| ['VE',['Car']], ['VG',['Pue','Torta']], ['VI',['Pue','St Ts']], ['VN',['Bangk','Saign']], ['VU',['Ef']], ['WF',['Tar','Wal']], | |
| ['WS',['Ap']], ['YE',['Adenn','Riy']], ['YT',['Nai','May']], ['ZM',['Lus','Map']], ['ZW',['Har','Map']], ['ZA',['Jo']] | |
| ]; | |
| const base = [ | |
| { l: [ 'ar-AE','ar-BH','ar-DZ','ar-EG','ar-IQ','ar-JO','ar-KW','ar-LB','ar-LY','ar-MA','ar-OM','ar-QA','ar-SA','ar-SY','ar-TN','ar-YE'], | |
| o: { am: 'ص', pm: 'م' } }, | |
| { l: [ 'cy-GB','en-NZ','es-AR','es-BO','es-CO','es-CR','es-DO','es-GT','es-HN','es-MX','es-NI', | |
| 'es-PA','es-PE','es-PR','es-PY','es-SV','es-UY','es-VE','gl-ES','mi-NZ','quz-BO','quz-PE' ], | |
| o: { am: 'a.m.', pm: 'p.m.' } }, | |
| { l: [ 'en-029','en-AU','en-BZ','en-CA','en-GB','en-JM','en-PH','en-TT','en-US','en-ZA', | |
| 'en-ZW','he-IL','mt-MT','ns-ZA','sw-KE','th-TH','tn-ZA','ur-PK','xh-ZA', 'zh-SG','zu-ZA' ], | |
| o: { am: 'AM', pm: 'PM' } }, | |
| { l: [ 'zh-CN','zh-TW' ], o: { am: '上午', pm: '下午' } }, | |
| { l: [ 'hi-IN','sa-IN' ], o: { am: 'पूर्वाह्न', pm: 'अपराह्न' } }, | |
| { l: [ 'kok-IN','mr-IN' ], o: { am: 'म.पू.', pm: 'म.नं.' } } | |
| ].reduce((r, o) => { for (const k of o.l) { r[k] = o.o; } return r; }, { | |
| _: {am:"", pm:""}, | |
| 'af-ZA': { am: '', pm: 'nm' }, | |
| 'cs-CZ': { am: 'dop.', pm: 'odp.' }, | |
| 'dv-MV': { am: 'މކ', pm: 'މފ' }, | |
| 'el-GR': { am: 'πμ', pm: 'μμ' }, | |
| 'et-EE': { am: 'EL', pm: 'PL' }, | |
| 'fa-IR': { am: 'ق.ظ', pm: 'ب.ظ' }, | |
| 'gu-IN': { am: 'પૂર્વ મધ્યાહ્ન', pm: 'ઉત્તર મધ્યાહ્ન' }, | |
| 'hu-HU': { am: 'de.', pm: 'du.' }, | |
| 'ja-JP': { am: '午前', pm: '午後' }, | |
| 'kn-IN': { am: 'ಪೂರ್ವಾಹ್ನ', pm: 'ಅಪರಾಹ್ನ' }, | |
| 'ko-KR': { am: '오전', pm: '오후' }, | |
| 'pa-IN': { am: 'ਸਵੇਰੇ', pm: 'ਸ਼ਾਮ' }, | |
| 'sq-AL': { am: 'PD', pm: 'MD' }, | |
| 'syr-SY': { am: 'ܩ.ܛ', pm: 'ܒ.ܛ' }, | |
| 'ta-IN': { am: 'காலை', pm: 'மாலை' }, | |
| 'te-IN': { am: 'పూర్వాహ్న', pm: 'అపరాహ్న' }, | |
| 'vi-VN': { am: 'SA', pm: 'CH' } | |
| }); | |
| [ | |
| 'az-Cyrl-AZ', 'az-Latn-AZ', 'be-BY', 'bg-BG', 'bs-Latn-BA', 'ca-ES', 'da-DK', 'de-AT', 'de-CH', 'de-DE', | |
| 'de-LI', 'de-LU', 'en-IE', 'es-CL', 'es-EC', 'es-ES', 'eu-ES', 'fi-FI', 'fo-FO', 'fr-BE', 'fr-CA', 'fr-CH', | |
| 'fr-FR', 'fr-LU', 'fr-MC', 'hr-BA', 'hr-HR', 'hy-AM', 'id-ID', 'is-IS', 'it-CH', 'it-IT', 'ka-GE', 'kk-KZ', | |
| 'ky-KG', 'lt-LT', 'lv-LV', 'mk-MK', 'mn-MN', 'ms-BN', 'ms-MY', 'nb-NO', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', | |
| 'pt-BR', 'pt-PT', 'quz-EC', 'ro-RO', 'ru-RU', 'se-FI', 'se-NO', 'se-SE', 'sk-SK', 'sl-SI', 'sma-NO', 'sma-SE', | |
| 'smj-NO', 'smj-SE', 'smn-FI', 'sms-FI', 'sr-Cyrl-BA', 'sr-Cyrl-CS', 'sr-Latn-BA', 'sr-Latn-CS', 'sv-FI', | |
| 'sv-SE', 'tr-TR', 'tt-RU', 'uk-UA', 'uz-Cyrl-UZ', 'uz-Latn-UZ', 'zh-HK', 'zh-MO' | |
| ].forEach((k) => { base[k] = base._; }); | |
| const ar1 = {'ar-LB':1,'ar-MA':1,'ar-TN':1}; | |
| const f0set = new Set(['af-ZA', 'dv-MV', 'en-BZ', 'en-CA','en-JM', 'en-PH', 'en-TT', 'en-US','en-ZA', 'en-ZA2', 'en-ZW', 'es-AR', | |
| 'es-BO', 'es-CL', 'es-CO', 'es-CR','es-DO', 'es-EC', 'es-GT', 'es-HN','es-MX', 'es-NI', 'es-PA', 'es-PE', | |
| 'es-PR', 'es-SV', 'es-VE', 'fa-IR', 'fr-CA', 'he-IL', 'ja-JP', 'ko-KR', 'ns-ZA', 'pt-BR', 'quz-BO', 'quz-EC', | |
| 'quz-PE', 'sa-IN', 'sw-KE', 'tn-ZA', 'xh-ZA', 'zh-CN', 'zh-HK', 'zh-MO', 'zh-SG', 'zh-TW', 'zu-ZA']); | |
| for (const k in base) { | |
| if (k.startsWith('ar-') || k.startsWith('syr-')) { base[k].firstDayOfWeek = ar1[k] ? 1 : 6; continue; } | |
| if (f0set.has(k)) { base[k].firstDayOfWeek = 0; continue; } | |
| base[k].firstDayOfWeek = 1; | |
| } | |
| const ymdset = new Set(['af-ZA', 'en-ZA', 'en-ZA2', 'eu-ES', 'fr-CA', 'hu-HU', 'ja-JP', 'ko-KR', 'lt-LT', 'lv-LV', 'mn-MN', 'ns-ZA', | |
| 'pl-PL', 'se-SE', 'sma-SE', 'smj-SE', 'sq-AL', 'sv-SE', 'tn-ZA', 'xh-ZA', 'zh-CN', 'zh-TW', 'zu-ZA']); | |
| const mdyset = new Set(['en-029', 'en-PH', 'en-US', 'en-ZW', 'es-PA', 'fa-IR', 'sw-KE']); | |
| const timeZone = 'Europe/Berlin'; | |
| export const [ SUNDAY_OPTION, SUNDAY_OPTION_SHORT ] = [ {weekday:'long', timeZone}, {weekday:'short', timeZone} ]; | |
| export const [ JANUARY_OPTION, JANUARY_OPTION_SHORT ] = [ {month:'long', timeZone}, {month:'short', timeZone} ]; | |
| const y20 = parseInt(new Intl.DateTimeFormat('en', {year: 'numeric', timeZone}).formatToParts(new Date())[0].value, 10)+20; | |
| const y20ar = new Intl.DateTimeFormat('ar-SA', {year: 'numeric'}).formatToParts(new Date())[0].value; | |
| const twoDigitYearMax = parseInt(`${y20}`.slice(0,-1)+'9', 10); | |
| const arNr = Array.from(`٠١٢٣٤٥٦٧٨٩`).reduce((r, k, i) => { r[k] = `${i}`; return r; }, {}); | |
| const twoDigitYearMaxAr = parseInt(`${parseInt(Array.from(`${y20ar}`).map((k) => arNr[k]).join(''), 10)+20}`.slice(0,-1)+'9', 10); | |
| for (const k in base) { | |
| base[k].twoDigitYearMax = (k === 'ar-SA' || k === 'dv-MV') ? twoDigitYearMaxAr : twoDigitYearMax; | |
| if (ymdset.has(k)) { base[k].dateElementOrder = 'ymd'; continue; } | |
| if (mdyset.has(k)) { base[k].dateElementOrder = 'mdy'; continue; } | |
| base[k].dateElementOrder = 'dmy'; | |
| } | |
| export const supportedLocales = Object.keys(base).filter((k) => (k !== '_')); | |
| const countryLocalesCustom = { | |
| AD: ['ca','fr-AD'], AE: ['ar-AE'], AF: ['fa-AF', 'ps', 'ug', 'uz-AF'], AG: ['en-AG'], AI: ['en-AI'], | |
| AO: ['pt-AO', 'kg', 'kj'], AR: ['es-AR', 'cy-AR', 'gn'], AW: ['nl-AW', 'en'], BD: ['bn-BD'], | |
| BE: ['nl-BE', 'fr-BE', 'de-BE', 'en', 'wa', 'yi'], BH: ['ar-BH'], BI: ['fr-BI','rn'], BJ: ['fr-BJ'], | |
| BN: ['ms-BN', 'en-BN'], BO: ['es-BO', 'ay'], BS: ['en-BS'], BT: ['dz', 'ne'], BW: ['tn-BW', 'sn', 'en-BW'], | |
| BZ: ['en-BZ'], CA: ['fr-CA', 'en-CA', 'cr', 'iu', 'oj', 'yi' ], CC: ['ms-CC'], CF: ['fr-CF', 'sg'], CI: ['fr-CI', 'ak', 'bm'], | |
| CM: ['fr-CM', 'en-CM'], CR: ['es-CR'], CU: ['es-CU'], CV: ['pt-CV', 'en'], DJ: ['fr-DJ', 'so-DJ', 'aa-DJ'], | |
| DM: ['en-DM'], DZ: ['ar-DZ'], EC: ['es-EC', 'es'], EG: ['ar-EG'], ER: ['aa-ER', 'tig', 'ti-ER', 'byn', 'en-ER', 'gez-ER'], | |
| ET: ['am', 'ti-ET', 'om-ET', 'so-ET', 'en-ET', 'gez-ET', 'sid', 'wal', 'aa-ET' ], FJ: ['fj', 'en-FJ'], GA: ['fr-GA'], GD: ['en-GD'], | |
| GE: ['ka', 'ab', 'os'], GF: ['fr-GF'], GH: ['ak', 'ee', 'tw', 'en-GH'], GI: ['en-GI'], GL: ['kl', 'da-GL'], GM: ['wo', 'bm', 'en-GM'], | |
| GN: ['fr-GN', 'fr', 'en'], GP: ['fr-GP', 'fr', 'en'], GQ: ['es-GQ', 'es', 'en'], GU: ['ch-GU', 'en-GU'], GW: ['pt-GW', 'en'], | |
| GY: ['en-GY'], IE: ['en-IE', 'ga-IE', 'ga'], IQ: ['ar-IQ', 'ku'], JM: ['en-JM'], JO: ['ar-JO'], KG: ['ky', 'ug'], KM: ['fr-KM'], | |
| KN: ['en-KN'], KP: ['ko-KP'], KW: ['ar-KW'], KZ: ['kk', 'av', 'os', 'ug'], KY: [ 'en-KY' ], LA: ['lo', 'en'], LB: ['ar-LB', 'fr-LB'], | |
| LC: ['en-LC'], LI: ['de-LI'], LR: ['en-LR'], LS: ['st', 'xh', 'en-LS'], LU: ['lb', 'fr-LU', 'de-LU'], LY: ['ar-LY'], MA: ['ar-MA'], | |
| MC: ['fr-MC'], MD: ['mo', 'ro', 'tr', 'uk', 'yi'], MG: ['mg', 'fr-MG'], MH: ['mh', 'en-MH'], MK: ['mk', 'cu'], ML: ['fr-ML', 'bm'], | |
| MM: ['my'], MO: ['zh-MO', 'zh-Hant'], MP: ['ch-MP','en-MP' ], MQ: ['fr-MQ'], MR: ['ar-MR', 'wo'], MS: ['en-MS'], MT: ['mt', 'en-MT'], | |
| MU: ['en-MU'], MV: ['dv'], MW: ['ny', 'en-MW'], MZ: ['pt-MZ', 'sn'], NA: ['hz', 'ng', 'en-NA'], NC: ['fr-NC'], | |
| NE: ['fr-NE', 'ha', 'ff-NE', 'kr'], NG: ['en-NG', 'ha', 'yo', 'ig', 'ff-NG', 'kr'], NI: ['es-NI'], NP: ['ne'], NR: ['na', 'en-NR'], | |
| NU: ['en-NU'], OM: ['ar-OM'], PA: ['es-PA'], PF: ['fr-PF', 'ty'], PM: ['fr-PM'], PR: ['es-PR', 'en-PR'], PS: ['ar-PS'], PW: ['en-PW'], | |
| PY: ['es-PY', 'gn'], QA: ['ar-QA'], RE: ['fr-RE'], RW: ['rw', 'fr-RW', 'en-RW'], SA: ['ar-SA'], SD: ['ar-SD', 'din', 'ha'], | |
| SI: ['hu-SI', 'it-SI'], SL: ['en-SL'], SM: ['it-SM'], SN: ['wo', 'ff-SN'], SO: ['so-SO', 'ar-SO', 'en-SO'], SR: ['nl-SR', 'jv'], | |
| ST: ['pt-ST'], SV: ['es-SV'], SY: ['ar-SY', 'syr'], SZ: ['ss-SZ','en-SZ'], TC: ['en-TC'], TD: ['fr-TD', 'ar-TD'], | |
| TG: ['fr-TG', 'ee', 'ha'], TJ: ['tg', 'os', 'ug'], TK: ['en-TK'], TL: ['pt-TL'], TM: ['tk', 'os'], TN: ['ar-TN'], TO: ['to', 'en-TO'], | |
| TT: ['en-TT'], TV: ['tvl', 'gil'], TZ: ['sw-TZ', 'en'], UG: ['en-UG', 'lg'], UM: ['en-UM'], UY: ['es-UY'], | |
| UZ: ['uz-UZ', 'uz-Cyrl', 'uz-Latn', 'os', 'ug'], VA: ['it', 'la', 'fr'], VC: ['en-VC'], VE: ['es-VE'], VI: ['en-VI'], | |
| VU: ['bi', 'en-VU', 'fr-VU'], WF: ['fr-WF'], WS: ['sm','en-WS'], YE: ['ar-YE'], YT: ['fr-YT'], ZM: ['en-ZM'], | |
| ZW: ['sn', 'en-ZW', 'nd', 've', 'zu'] | |
| }; | |
| const countryLocalesAdd = { | |
| AU: ['yi'], CL: ['ay'], ES: ['ca', 'eu', 'an', 'gl'], FM: ['en-FM'], | |
| FR: ['fr-FR', 'br', 'co', 'de-FR', 'oc'], GB: ['gd', 'fr-GB', 'ga-GB', 'gv', 'kw'], | |
| ID: ['jv', 'su'], 'KI': ['en-KI'], AT: ['hu'], AZ: ['az-Arab', 'az-Cyrl', 'az-Latn', 'av', 'os'], | |
| BA: ['bs', 'sr-BA'], BF: ['fr-BF', 'bm', 'ha'], BG: ['tr-BG', 'cu'], BQ: ['nl'], | |
| BY: ['be', 'cu', 'yi'], CG: ['fr-CG', 'ln-CG', 'kg'], CH: ['rm'], | |
| CN: ['zh-Hans','zh-guoyu','zh-yue','zh-yue','zh-wuu','zh-xiang','zh-gan','zh-hakka','i-hak','ii','za','bo'], | |
| CY: ['el-CY', 'tr-CY'], DE: ['nds', 'da-DE', 'da-DE', 'dsb', 'fy-DE', 'hsb', 'lb', 'wen', 'yi'], | |
| EE: ['yi'], FI: ['sv-FI', 'smn'], FO: ['da-FO'], HR: ['it-HR', 'it'], HU: ['de-HU', 'sk-HU', 'sr-HU'], | |
| IL: ['he', 'ar-IL', 'en-IL', 'yi'], | |
| IN: ['hi', 'gu', 'ks', 'ml', 'mr', 'or', 'te', 'kn', 'as', 'sa', 'bh', 'kok', 'ne', 'pa', 'pi'], | |
| IT: ['de-IT', 'fr-IT', 'co', 'sc'], KE: ['en-KE', 'ki', 'om-KE', 'so-KE'], KH: ['km'], LK: ['si'], | |
| LT: ['yi'], LV: ['yi'], PH: ['tl'], PL: ['de-PL', 'yi'], RO: ['hu', 'cu', 'yi'], SC: ['fr-SC'], | |
| SE: ['sv-SE', 'sma', 'sme', 'fi-SE'], SK: ['hu'], TH: ['si'], TR: ['ku', 'ab', 'av', 'ug'], | |
| UA: ['ru-UA', 'ro', 'pl', 'hu', 'ab', 'cu', 'os', 'yi'] | |
| } | |
| const bcp = supportedLocales.reduce((r, s) => { | |
| r.push(s); r.push(s.split('-')[0]); return r; | |
| }, []); | |
| const countryLocales = countryOlson.map(([iso]) => { | |
| if (countryLocalesCustom[iso]) { | |
| return [iso, countryLocalesCustom[iso]]; | |
| } else if (bcp.filter((k) => k === iso.toLowerCase()).length) { | |
| return [iso, [iso.toLowerCase()]] | |
| } else { | |
| const locs = bcp.filter((k) => k.split('-')[1] === iso); | |
| if (locs.length) { return [iso, [...locs, ...(countryLocalesAdd[iso] ?? [])]] } | |
| return [iso, ['en', ...(countryLocalesAdd[iso] ?? [])]] | |
| } | |
| }).reduce((r, [iso, locales]) => { r[iso] = locales; return r; }, {}); | |
| const tzset = new Set(Intl.supportedValuesOf('timeZone')); | |
| const a = Array.from(tzset); | |
| const tzId = {}; | |
| const tzBase = a.reduce((r, s) => { | |
| if (s.indexOf('/') < 0) { return r; } | |
| const parts = s.split('/'); | |
| const locId = parts[parts.length-1]; | |
| const location = locId.replace(/[_-]/g, ' '); | |
| const [k2,k3,k_] = [location.slice(0,2), location.slice(0,3), `${location.slice(0,4)}${s.slice(-1)}`]; | |
| let rK = null; | |
| for (const k of [k2,k3]) { | |
| if (a.filter((s2) => { | |
| const parts2 = s2.split('/'); | |
| return parts2[parts2.length-1].startsWith(k); | |
| }).length === 1) { | |
| rK = k; | |
| break; | |
| } | |
| } | |
| tzId[rK ?? k_] = s; | |
| tzId[location] = s; | |
| return {...r, s, [locId]: s, [location]: s, ...(!alias[location] ? {} : alias[location].reduce((r2, s2) => ({...r2, [s2]: s}) ), {})}; | |
| }, {}); | |
| const nameMap_spokenLangFromIntl = (type, iso, locales = (IS_SERVER ? intlLocales : ['en', 'de', 'fr', 'pt', 'es'])) => { | |
| const nameFormat = locales.map((l) => [[l, 'long'], [l, 'short'], [l, 'narrow']]).flat(); | |
| const nameMapBlank = [...locales].reduce((r,k) => ({...r, [k]: []}), {}); | |
| let nameMap = [...nameFormat].reduce((r, [locale, style]) => { | |
| try { | |
| const name = new Intl.DisplayNames([locale], { type, style }); | |
| if (!r[locale]) { r[locale] = []; } | |
| r[locale].push(name.of(iso)); | |
| } catch(e) { } | |
| return r; | |
| }, nameMapBlank); | |
| nameMap.und = [...nameMap.en]; | |
| const spokenLanguage = Object.hasOwnProperty.call(countryLocales, iso) ? countryLocales[iso] : []; | |
| Array.from(new Set(spokenLanguage.map((l) => { | |
| let locName = ''; | |
| try { locName = new Intl.DisplayNames([l], { type: 'region'}).of(iso); } catch(e) { } | |
| return [l, locName]; | |
| }))).filter((s) => s).forEach(([l, locName]) => { | |
| nameMap[l] = [locName]; | |
| nameMap.und.push(locName) | |
| }); | |
| for (const k in nameMap) { nameMap[k] = Array.from(new Set(nameMap[k])); } | |
| return {spokenLanguage, nameMap}; | |
| } | |
| const dtu = {second:1, minute:1, hour:1, day:1, week:1, month:1, year:1}; | |
| const getStdNameIntl = (intlType, locales, _type = []) => { | |
| const checkType = intlType === 'unit' ? 'dateTimeField' : intlType; | |
| const [def, defName] = [{}, {}]; | |
| Intl.supportedValuesOf(intlType).forEach((id) => { | |
| const { nameMap } = nameMap_spokenLangFromIntl(checkType, id, locales); | |
| const contentMap = {}; | |
| if (intlType === 'unit') { | |
| for (const l in nameMap) { | |
| for (const unitDisplay of ['long','short','narrow']) { | |
| const options = { style: 'unit', unit: id, unitDisplay }; | |
| const numberFormat = new Intl.NumberFormat(l, options); | |
| const parts = [numberFormat.formatToParts(1), numberFormat.formatToParts(2)].flat().filter(({type}) => type==='unit').map(({value}) => value); | |
| nameMap[l] = [...nameMap[l], ...(parts && parts.length ? parts : [])]; | |
| contentMap[l] = [...(contentMap[l] ?? []), (1).toLocaleString(l, options), (2).toLocaleString(l, options)]; | |
| } | |
| nameMap[l] = Array.from(new Set(nameMap[l])); | |
| contentMap[l] = Array.from(new Set(contentMap[l])); | |
| } | |
| } else if (intlType === 'timeZone') { | |
| for (const l in nameMap) { | |
| const d = new Date(Date.UTC(2020, 11, 20, 3, 0, 0, 0)); | |
| const tzNames = Array.from(new Set(['full', 'long'].map((timeStyle) => | |
| new Intl.DateTimeFormat(l, {timeStyle, timeZone: id}).formatToParts(d) | |
| .filter(({type}) => type==='timeZoneName').map(({value}) => value)).flat())); | |
| if (/^[A-Z][a-z]+[/][A-Z]/.test(id)) { | |
| const parts = id.split('/'); | |
| const location = parts[parts.length-1]; | |
| nameMap[l].push(location); | |
| nameMap[l].push(location.replace(/_/g, ' ')); | |
| } | |
| nameMap[l] = Array.from(new Set([...nameMap[l], id, ...(tzNames.length ? tzNames : [])])); | |
| } | |
| } | |
| const type = (dtu[id] ? [..._type, 'redaktor:DateTimeUnit'] : _type); | |
| def[id] = { id, type, nameMap, ...(intlType === 'timeZone' ? {} : {contentMap}) }; | |
| defName[id] = id; | |
| Array.from(new Set(Object.values(nameMap).flat())).forEach((k) => { defName[k] = id; }); | |
| }); | |
| return [def, defName]; | |
| } | |
| // 001-096, // 100 (+4) [no 128] //142-145 // | |
| const [weekday, monthname] = [ | |
| ['sun', 'mon','tue','wed','thu','fri','sat'], | |
| ['jan','feb','mar','apr', 'may', 'jun','jul','aug','sep','oct','nov','dec'] | |
| ]; | |
| const rtl = new Set(['Mero', 'Merc', 'Psin', 'Sarb', 'Narb', 'Chrs', 'Phnx', 'Lydi', 'Tfng', | |
| 'Samr', 'Armi', 'Hebr', 'Palm', 'Hatr', 'Elym', 'Prti', 'Phli', 'Phlp', | |
| 'Phlv', 'Avst', 'Syrc', 'Syrn', 'Syrj', 'Syre', 'Mani', 'Mand', 'Sogd', | |
| 'Sogo', 'Ougr', 'Mong', 'Nbat', 'Arab', 'Aran', 'Gara', 'Nkoo', 'Adlm', | |
| 'Rohg', 'Thaa', 'Orkh', 'Hung', 'Sidt', 'Yezi']); | |
| export const intlToActivityPub = (_locales = (IS_SERVER ? intlLocales : ['en', 'de', 'fr', 'pt', 'es'])) => { | |
| const locales = Array.from(new Set(['en', ..._locales])); | |
| const [o, parser] = [{}, {}]; | |
| const localDateParser = { keys: ['localDate', 'monthDate', 'weekdayMonth', 'relative', 'casualTime', 'localTime'], r: {}, fn: {} } | |
| const addDateConstant = (i: number, l: string, type: 'day'|'month' = 'day') => { | |
| const d = new Date(type === 'day' ? Date.UTC(0, 0, i, 0, 0, 0) : Date.UTC(0, i, 0, 0, 0, 0)); | |
| let [r, rShort] = ['', '']; | |
| try { r = new Intl.DateTimeFormat(l, (type === 'day' ? SUNDAY_OPTION : JANUARY_OPTION)).formatToParts(d)[0].value } catch(e) {} | |
| try { | |
| rShort = new Intl.DateTimeFormat(l, (type === 'day' ? SUNDAY_OPTION_SHORT : JANUARY_OPTION_SHORT)) | |
| .formatToParts(d)[0].value | |
| } catch(e) {} | |
| // console.log( l, day ); | |
| o[l][type].push(r); | |
| o[l][`${type}Short`].push(rShort); | |
| if (type === 'day') o[l].dayChar.push(r.charAt(0)); | |
| } | |
| const reduceMonthDigit = (r, m, i) => { r[m] = (i+1); return r; } | |
| for (const l of locales) { | |
| parser[l] = {}; | |
| o[l] = { day: [], dayShort: [], dayChar: [], month: [], monthShort: [] }; | |
| for (let i = 0; i <= 6; i++) { addDateConstant(i, l); } | |
| for (let i = 1; i <= 12; i++) { addDateConstant(i, l, 'month'); } | |
| } | |
| const dayPeriod = {}; | |
| for (const [i, start, end, id] of [ | |
| [8,'07','11','morning'],[11,'11','15','noon'],[15,'15','18','afternoon'], | |
| [18,'18','22','evening'],[2,'22','07','night'] | |
| ]) { | |
| const res = {} | |
| const date = new Date(Date.UTC(0, 0, 0, i, 0, 0) ); | |
| dayPeriod[id] = {id, type: ['Event', 'redaktor:dayPeriod'], nameMap: {}, startTime: `${start}:00:00`, endTime: `${end}:00:00`}; | |
| for (const l of locales) { | |
| const LOC_PERIOD1 = new Intl.DateTimeFormat(l, { dayPeriod: "short" }); | |
| const LOC_PERIOD2 = new Intl.DateTimeFormat(l, { dayPeriod: "long" }); | |
| dayPeriod[id].nameMap[l] = Array.from(new Set([ | |
| LOC_PERIOD1.formatToParts(date)[0]?.value, | |
| LOC_PERIOD2.formatToParts(date)[0]?.value | |
| ].filter((s) => s))); | |
| } | |
| } | |
| const [daysOfWeek, monthsOfYear] = [ | |
| weekday.map(((id) => ({id, type: ['redaktor:Weekday'], nameMap: {}}))), | |
| monthname.map(((id) => ({id, type: ['redaktor:GregorianMonth'], nameMap: {}}))) | |
| ]; | |
| const fallback = o['en-US']; | |
| const toRK = (s) => (s.endsWith('.') || s.endsWith(',')) | |
| ? s.slice(0, -1).replace(/(\W)/g, '[$1]') | |
| : s.replace(/(\W)/g, '[$1]'); | |
| const toRegexString = (l, name, long, short?, char?, key = 'monthDigit') => { | |
| const res = []; | |
| long.forEach((r, i) => { | |
| const rArr = !short || short[i] === r | |
| ? [toRK(r), `${toRK(name[i])}`] | |
| : [toRK(r), `${toRK(short[i])}`, `${toRK(name[i])}`]; | |
| if (char) { rArr.push(`${toRK(char[i])}`); } | |
| if (key && dateCasual?.r[l] && dateCasual.r[l][key]) { | |
| for (const k in dateCasual.r[l][key]) { if (dateCasual.r[l][key][k] === i) { rArr.push(`${toRK(k)}`) } } | |
| } | |
| res.push(Array.from(new Set(rArr))); | |
| }); | |
| return `(${res.map((a) => `(${a.join('|')})`).join('|')})`; | |
| } | |
| for (const l in o) { | |
| const { day, dayShort, dayChar, month, monthShort } = o[l]; | |
| day.forEach((d, i) => { | |
| if (!daysOfWeek[i].nameMap[l]) { daysOfWeek[i].nameMap[l] = []; } | |
| daysOfWeek[i].nameMap[l].push(d); | |
| }); | |
| dayShort.forEach((d, i) => { daysOfWeek[i].nameMap[l].push(d); }); | |
| dayChar.forEach((d, i) => { | |
| daysOfWeek[i].nameMap[l].push(d); | |
| daysOfWeek[i].nameMap[l].push(daysOfWeek[i].id); | |
| }); | |
| month.forEach((m, i) => { | |
| if (!monthsOfYear[i].nameMap[l]) { monthsOfYear[i].nameMap[l] = []; } | |
| monthsOfYear[i].nameMap[l].push(m); | |
| }); | |
| monthShort.forEach((m, i) => { | |
| monthsOfYear[i].nameMap[l].push(m); | |
| monthsOfYear[i].nameMap[l].push(monthsOfYear[i].id); | |
| }); | |
| let r = toRegexString(l, weekday, day, dayShort, dayChar, 'dayDigit') | |
| parser[l].dayOfWeek = { r, g: weekday, regex: new RegExp(`\\b(?:${r})\\b[.,]*`, 'i') }; | |
| if (l === 'fr') console.log(parser[l].dayOfWeek ) | |
| //[.]? | |
| r = toRegexString(l, monthname, month, monthShort); | |
| parser[l].monthOfYear = { r, g: monthname, regex: new RegExp(`\\b(?:${r})\\b[.,]*`, 'i') }; | |
| } | |
| const dayOfWeek = daysOfWeek.reduce((r, o) => { r[o.id] = o; return r; }, {}); | |
| const monthOfYear = monthsOfYear.reduce((r, o) => { r[o.id] = o; return r; }, {}); | |
| const regionNameEn = new Intl.DisplayNames(['en'], { type: 'region', style: 'long' }); | |
| let type = ['redaktor:Country', 'redaktor:TimezoneLocation']; | |
| const countryCache = {}; | |
| const [country, countryName] = [{}, {}]; | |
| countryOlson.forEach(([iso, ids, multiTz = false]) => { | |
| countryCache[regionNameEn.of(iso)] = iso; | |
| const timezone = ids.map((id) => Array.isArray(id) ? id : tzId[id]); | |
| const {spokenLanguage, nameMap} = nameMap_spokenLangFromIntl('region', iso, locales); | |
| const firstParts = timezone[0].split('/'); | |
| const firstLocation = firstParts[firstParts.length-1].replace(/[_]/g, ' '); | |
| const capital = iso === 'AQ' ? '-' : (capitalAlias[iso] || firstLocation); | |
| country[iso] = { type, id: iso, nameMap, capital, timezone, differentTimezones: !!multiTz, spokenLanguage }; | |
| countryName[iso] = iso; | |
| if (capitalAlias[iso] && !tzBase[capitalAlias[iso]]) { tzBase[capitalAlias[iso]] = timezone[0]; } | |
| Array.from(new Set(Object.values(nameMap).flat())).forEach((k) => { countryName[k] = iso; }); | |
| if (alias[iso]) { alias[iso].forEach((isoDup) => { if (!countryName[isoDup]) { countryName[isoDup] = iso; } }) } | |
| }); | |
| const toParser = (asO, key) => { | |
| const [g, c] = [Object.values(asO).map(({id}) => id), {}]; | |
| for (const l in o) { | |
| try { | |
| c[l] = Object.values(asO).map(({id, nameMap}) => {return [id, ...(nameMap[l]||nameMap[l.split('-')[0]||nameMap.en||{}])]}); | |
| } catch(e) { } | |
| } | |
| for (const l in c) { | |
| const res = c[l].map((a) => { | |
| const [iso, ..._names] = a; | |
| const prefix = key === 'unit' ? '\\d' : ''; | |
| const isoR = key === 'timezone' ? `${prefix}(?:${toRK(iso)})` : `${prefix}(?:\\[?\\(?${iso}\\]?\\)?)`; | |
| return `(${_names.map(toRK).map((k) => `${prefix}(?:${k})`).join('|')}|${isoR})`; | |
| }).join('|') | |
| parser[l][key] = {r: `(${res})`, g} | |
| } | |
| } | |
| toParser(dayPeriod, 'dayPeriod'); | |
| toParser(country, 'country'); | |
| // console.log(country, countryName); | |
| type = ['redaktor:Locale']; // TODO redaktor:Language (deu, eng) relations | |
| const [language, languageName] = [{}, {}]; | |
| countryOlson.forEach(([iso]) => { | |
| if (!country[iso]?.spokenLanguage) { return; } | |
| for (const id of country[iso].spokenLanguage) { | |
| try { | |
| if (!language[id]) { | |
| const locale = new Intl.Locale(id).maximize(); | |
| const summary = `Locale ${locale.toString()}`; | |
| const { script } = locale; | |
| const { nameMap } = nameMap_spokenLangFromIntl('language', id, locales); | |
| language[id] = { id, type, nameMap, summary, country: [], script, direction: rtl.has(script) ? 'rtl' : 'ltr' } | |
| } | |
| language[id].country.push(iso); | |
| } catch(e) {} | |
| } | |
| }); | |
| for (const id in language) { | |
| languageName[id] = id; | |
| Array.from(new Set(Object.values(language[id].nameMap).flat())).forEach((k) => { languageName[k] = id; }); | |
| } | |
| toParser(language, 'language'); | |
| // console.log(language, languageName); | |
| const [currency, currencyName] = getStdNameIntl('currency', locales, ['redaktor:Currency']); | |
| const [unit, unitName] = getStdNameIntl('unit', locales, ['redaktor:Unit']); | |
| const [timezone, timezoneName] = getStdNameIntl('timeZone', locales, ['redaktor:Timezone']); | |
| // console.log(currency, currencyName); | |
| // console.log(unit, unitName); | |
| for (const id in timezone) { | |
| timezone[id].country = Object.keys(country).filter((k) => { | |
| const ctz = country[k]?.timezone ?? []; | |
| if (ctz.indexOf(id) > -1) { return true; } | |
| const [alias] = ctz.filter((a) => Array.isArray(a)); | |
| if (alias && alias.filter((cId) => (country[cId]?.timezone ?? []).indexOf(id) > -1)) { return true; } | |
| return false; | |
| }); | |
| } | |
| for (const id in country) { | |
| if (country[id]?.capital && country[id]?.timezone?.length) { | |
| for (const l in timezone[country[id].timezone[0]].nameMap) { | |
| timezone[country[id].timezone[0]].nameMap[l].push(country[id].capital); | |
| } | |
| } | |
| } | |
| // console.log(timezone, timezoneName); | |
| toParser(currency, 'currency'); | |
| toParser(unit, 'unit'); | |
| toParser(timezone, 'timezone'); | |
| //console.log(unit); | |
| // TODO ! deno is missing Intl UN M49 regions | |
| // see ./m49.ts and https://github.com/denoland/deno/issues/13257 | |
| // TODO add from ./m49.ts if no '003' .name and deno | |
| type = ['redaktor:Region']; | |
| let [region, regionName] = [{}, {}] | |
| const m49 = {}; | |
| for (let i = 1; i < 100; i++) { | |
| const k = (i < 10 ? `00${i}` : `0${i}`); | |
| const name = regionNameEn.of(k); | |
| if (k !== name) { m49[k] = name; } | |
| } | |
| for (let i = 100; i < 900; i++) { | |
| const name = regionNameEn.of(`${i}`); | |
| if (`${i}` !== name) { m49[`${i}`] = name; } | |
| } | |
| for (const id in m49) { | |
| const cK = countryCache[m49[id]]; | |
| if (cK) { | |
| if (!country[cK].m49) { country[cK].m49 = []; } | |
| country[cK].m49.push(id); | |
| } else { | |
| const { nameMap } = nameMap_spokenLangFromIntl('region', id, locales); | |
| region[id] = { id, type, nameMap }; | |
| regionName[id] = id; | |
| Array.from(new Set(Object.values(region[id].nameMap).flat())).forEach((k) => { regionName[k] = id; }); | |
| } | |
| } | |
| if (m49regionMissing) { | |
| // currently deno-only (server), see https://github.com/denoland/deno/issues/13257 - TODO chromium? | |
| region = {...region, ...m49regionMissing}; | |
| for (const id in region) { | |
| regionName[id] = id; | |
| Array.from(new Set(Object.values(region[id].nameMap).flat())).forEach((k) => { regionName[k] = id; }); | |
| } | |
| for (const cK in country) { | |
| if (!m49regionMap[cK]) { continue; } | |
| if (!country[cK].m49) { country[cK].m49 = []; } | |
| country[cK].m49.push(m49regionMap[cK]); | |
| } | |
| } | |
| toParser(region, 'region'); | |
| /* | |
| const testR = new RegExp(parser.de.monthOfYear.r, 'gi') | |
| console.log(testR.exec('Am Samstag im Juli ist nachmittags ein 2 Minuten event bezahlt in USD aus Berlin')) | |
| console.log('Am Samstag im Juli ist nachmittags ein 2 Minuten event bezahlt in USD aus Berlin'.split(testR)) | |
| */ | |
| const dKeys = { year:1, month:1, day:1, weekday:1 }; | |
| const tKeys = { hour:1, minute:1, second:1, timeZoneName:1, dayPeriod:1 }; | |
| const dtMode = ['full', 'long', 'medium', 'short']; | |
| const cardinalSuffix = '(?:\\s?(?:th|nd|rd|er?|ieme|te|-?й|ro|do|[.˚ ]))?'; | |
| const AM = '(?:a[.]?\\s?m[.]?)|(?:π[.]?\\s?μ[.]?)|PG|ಪೂರ್ವಾಹ್ನ|오전|[ص]'; | |
| const PM = '(?:p[.]?\\s?m[.]?)|(?:μ[.]?\\s?μ[.]?)|PTG|ಅಪರಾಹ್ನ|오후|[م]'; | |
| const AM_PM = `(?<am>${AM})|(?<pm>${PM})`; | |
| const date = new Date(Date.UTC(1999, 7, 2, 15, 3, 4) ); | |
| const toLocalO = (r, f) => ({...r, [f[0].format(date)]: {parts: f[0].formatToParts(date), format: f[1]}}); | |
| const relative = {}; | |
| const unitRelative = ["second", "minute", "hour", "day", "week", "month", "quarter", "year"]; | |
| for (const l of locales) { | |
| const [dLocal, tLocal] = [ | |
| dtMode.map((dateStyle) => [new Intl.DateTimeFormat(l, { dateStyle }), dateStyle]).reduce(toLocalO, {}), | |
| dtMode.map((timeStyle) => [new Intl.DateTimeFormat(l, { timeStyle }), timeStyle]).reduce(toLocalO, {}) | |
| ]; | |
| localDateParser.r[l] = {}; | |
| let minutes = []; | |
| for (const unitDisplay of ['long','short','narrow']) { | |
| const options = { style: 'unit', unit: 'minute', unitDisplay }; | |
| const numberFormat = new Intl.NumberFormat(l, options); | |
| minutes = [...minutes, ...[numberFormat.formatToParts(2)].flat().filter(({type}) => type==='unit').map(({value}) => | |
| value.endsWith('.') ? value.slice(0, -1) : value)]; | |
| } | |
| const minUnit = `(?:${Array.from(new Set(minutes)).join('|')})[.,]*`; | |
| const hDigit = `(?:0?\\d)|(?:1\\d)|20|21|22|23|24`; | |
| const adBc = `\\s?(?:(?<yBc>${(dateCasual?.r[l] ?? dateCasual.r.en).yearBC})|(?<yAd>${(dateCasual?.r[l] ?? dateCasual.r.en).yearAD}))?`; | |
| const minSec = '(?:[0-5]\\d)|\\d'; | |
| const hasCasualParser = dateCasual?.r[l] ?? dateCasual?.r[l.split('-')[0]]; | |
| const W = (hasCasualParser ?? dateCasual.r.en); | |
| const Cardinal = W.cardinal.map((c) => `${c}\\b`).join('|'); | |
| const {concatPrefix, concatTime = '[:]'} = W; | |
| const [qPrefix, qSuffix] = [((hasCasualParser && W.timeQuarterPrefix) ?? ''), (hasCasualParser && W.timeQuarterSuffix) ?? '']; | |
| localDateParser.r[l] = { | |
| weekdayMonth: `\\b(?:${W.concatPrefix})?(?<past>${W.past})?(?<next>${W.next})?(?<each>${W.each})?\\s?(?<ordinal>${W.ordinal})?\\s?(?:(?<dayOfWeek>${ | |
| parser[l].dayOfWeek.r | |
| })|(?<monthOfYear>${parser[l].monthOfYear.r}))(?<eachSuffix>${W.weekdayEachSuffix})?\\W?\\s?\\b`, | |
| monthDate: `(?:(?:${W.concatPrefix})?\\s?(?:(?:(?<d>(?:[0-3]\\d)|[1-9]|(?<ordinal>${W.ordinal}))[., ]*(?<m>${ | |
| parser[l].monthOfYear.r | |
| })\\s?)|(?:(?<m>${ | |
| parser[l].monthOfYear.r | |
| })(?:${W.concatPrefix})?\\s?(?<d>(?:[0-3]\\d)|[1-9]|(?<ordinal>${ | |
| W.ordinal | |
| })|(?<cardinal>${Cardinal}))[., ]*(?<y>\\d\\d?\\d?\\d?)?${adBc})))` | |
| }; | |
| /* | |
| if (l === 'es') { | |
| console.log('ES ---- :'); | |
| console.log(new RegExp(localDateParser.r[l].monthDate, 'gi'), parser[l].dayOfWeek.r); | |
| console.log(''); | |
| } | |
| */ | |
| localDateParser.r[l].localDate = `\\b(?:${W.concatPrefix})?${ | |
| Object.keys(dLocal).map((k) => `(?<${dLocal[k].format}>${dLocal[k].parts.map(({type, value}, i) => { | |
| const isInt = !isNaN(parseInt(value, 10)); | |
| // | |
| return type === 'year' | |
| ? (isInt ? `(?<y>\\d\\d?\\d?\\d?)?${adBc}` : `(?<y>${value})?${adBc}`) | |
| : (type === 'month' | |
| ? `(?<m>${parser[l].monthOfYear.r}|10|11|12|(?:0?[1-9]))${cardinalSuffix}` | |
| : ( | |
| type === 'day' | |
| ? `(?:${W.concatPrefix})?`+(isInt | |
| ? `(?<d>(?:[0-3]\\d)|[1-9])(?:\\w?\\w?\\w?\\s?)` | |
| : `(?<d>.+\\b)`)+cardinalSuffix | |
| : (type === 'literal' ? value.replace(/([\W])\s?/g, '(?:\\b|[$1])\\s?') : (type === 'weekday' | |
| ? parser[l].dayOfWeek.r+'?' | |
| : (value ?? '')) | |
| ) | |
| ) | |
| ) | |
| }).join('')})` | |
| ).join('|')}`; | |
| localDateParser.r[l].localTime = `(?:${ | |
| Object.keys(tLocal).map((k) => `(?<${tLocal[k].format}>${tLocal[k].parts.map(({type, value}, i) => { | |
| const isInt = !isNaN(parseInt(value, 10)); | |
| // if (l === 'de') console.log(W.cardinal) | |
| return type === 'hour' | |
| ? `(?:(?<prefix>${concatPrefix})?\\s?${ | |
| qPrefix ? `(?<quarter>${qPrefix})?\\s?`: '' | |
| }${isInt ? `(?:(?<h>(?:0?\\d)|(?:1\\d)|20|21|22|23|24)` : `(?<h>.*)`}${ | |
| hasCasualParser ? `|\\b(?<hCardinal>${W.cardinal.join('|')})\\b` : '' | |
| }))\\b${ | |
| qSuffix ? `(?<quarter>${qSuffix})?`: '' | |
| }` | |
| : (type === 'minute' | |
| ? (isInt ? `(?<min>${minSec}\\b)?(?:${concatTime})?` : `(?<min>.*\\b)?(?:${concatTime})?`) | |
| : ( | |
| type === 'second' | |
| ? (isInt ? `(?<sec>${minSec}\\b)?` : `(?<sec>.*\\b)?`) | |
| : (type === 'literal' | |
| ? value.replace(/([\W])\s?/g, `(?:\\b|[$1]|${concatTime})\\s?`) | |
| : (type === 'timeZoneName' ? '' : (type === 'dayPeriod' ? AM_PM : (value ?? '')) | |
| ) | |
| ) | |
| ) | |
| ) | |
| }).join('')})` | |
| ).join('|') | |
| })(?:${concatPrefix})?(?<timezone>\\s|${parser[l].timezone.r.slice(1)}`; | |
| // TODO merge with above | |
| localDateParser.r[l].casualTime = `\\b(?<prefix>${ | |
| W.concatPrefix | |
| })?\\s?(?:(?:(?<minute_sub>${ | |
| minSec | |
| }|(?:${Cardinal}))?(?: ${minUnit})* (?:${W.substract})\\s)|(?:(?<minute_add>${ | |
| minSec | |
| }|(?:${Cardinal}))?(?: ${minUnit})* (?:${W.add})\\s))?\\s*(?<h>(?:(?:0?\\d)|(?:1\\d)|20|21|22|23|24|(?:${ | |
| Cardinal | |
| }))(?:\\s|$))\\s*(?<suffix>${W.concatTime})?\\s*(?<_and>${W.and} )?(?<min>${ | |
| minSec | |
| }|(?:${Cardinal}))?(?: ${minUnit})*\\b`; | |
| if (l === 'de') console.log(localDateParser.r[l].casualTime); | |
| // if (l === 'de') console.log(localDateParser.r[l].localTime) | |
| relative[l] = []; | |
| const names = new Intl.DisplayNames([l], { type: 'dateTimeField' }); | |
| const rtf1 = new Intl.RelativeTimeFormat(l, { style: "long" }); | |
| const rtf2 = new Intl.RelativeTimeFormat(l, { style: "short" }); | |
| const rtf3 = new Intl.RelativeTimeFormat(l, { style: "narrow" }); | |
| const mapRelative = (s) => `(?:${s.replace(/[.]/g, '[. ]').replace(/(\W)/g, '[$1]') | |
| .replace(/\d/, `(?:(?<amount>\\d[\\d,.]*)|(?<few>${W.few})|(?<couple>${W.couple})|(?<several>${W.several | |
| })|(?<cardinal>[a-z]+(?: [a-z]+)?))`)})\\b`; | |
| for (const u of unitRelative) { | |
| const [prev, prev2, next, next2] = [rtf1.format(-2,u),rtf1.format(-1,u),rtf1.format(1,u),rtf1.format(2,u)]; | |
| const [_prev, _prev2, _next, _next2] = [rtf2.format(-2,u),rtf2.format(-1,u),rtf2.format(1,u),rtf2.format(2,u)]; | |
| const [__prev, __prev2, __next, __next2] = [rtf3.format(-2,u),rtf3.format(-1,u),rtf3.format(1,u),rtf3.format(2,u)]; | |
| relative[l].push(`(?<${u}_sub>${ | |
| Array.from(new Set([prev, prev2, _prev, _prev2, __prev, __prev2])).map(mapRelative).join('|') | |
| })`); | |
| relative[l].push(`(?<${u}_add>${ | |
| Array.from(new Set([next, next2, _next, _next2, __next, __next2])).map(mapRelative).join('|') | |
| })`); | |
| /* + past/next like (next Monday) .map(pastNextMapper(...args)).flat().filter(ok)*/ | |
| } | |
| localDateParser.r[l].relative = `(?:${relative[l].join('|')})`; | |
| //if (l === 'de') {console.log(new RegExp('\\b'+localDateParser.r[l].relative+'\\b'))} | |
| } | |
| const RELATIVE = { | |
| second: ((n)=>calcTime(n,'sec')), minute: ((n)=>calcTime(60,'sec')), hour: ((n)=>calcTime(60*n,'m')), | |
| day: ((n)=>calcTime(24*n,'h')), week: ((n)=>calcTime(168*n,'h')), month: ((n)=>calcDate(30*n,'d')), | |
| quarter: ((n)=>calcDate(90*n,'d')), year: ((n)=>calcDate(12*n,'m')) | |
| }; | |
| const QUARTERS = [15, -15, 30, -30]; | |
| const R = {cardinal: {}, ordinal: {}}; | |
| const numericAmount = (s, l, type = 'cardinal') => { | |
| if (!R[type][l]) { | |
| const r = (dateCasual.r[l.split('-')[0]]||dateCasual.r.en)[type]; | |
| R[type][l] = new RegExp(`\\b(${type === 'ordinal' ? r : r.join('|')})\\b`, 'i'); | |
| } | |
| const res = R[type][l].exec(s); | |
| if (!res) return false; | |
| //console.log(res) | |
| const [m, _m, ...numbers] = res; | |
| //console.log('--', l, s, s.match(R), m); | |
| return (numbers.map((s, i) => !s ? s : i).filter(ok)[0]); | |
| } | |
| const getMonthFromResult = (res, m, l) => { | |
| const match = parser[l].monthOfYear.regex.exec(m); | |
| return !match ? NaN : match.slice(2).reduce((r, el, i) => ((r < 0 && el) ? i : r), -1); | |
| } | |
| const localDateFn = ({ type, start, end, result, source, groups, l }, baseDate) => { | |
| // console.log('>', groups); | |
| // console.log('>', localDateParser.r.de.localDate, new RegExp('\\b'+localDateParser.r.de.localDate).exec('19. August')); | |
| if (typeof groups?.min === 'undefined' && typeof groups?.sec !== 'undefined') { | |
| groups.min = groups.sec; | |
| groups.sec = 0; | |
| } | |
| let {d, cardinal, ordinal, m, y, yBc, yAd, full, long, medium, quarter, hCardinal, h = 0, min = 0, sec = 0 } = groups; | |
| if (m && cardinal) { | |
| d = numericAmount(cardinal, l); | |
| } else if (m && ordinal) { | |
| d = numericAmount(ordinal, l, 'ordinal'); | |
| } | |
| if (!d || !m) { | |
| if (hCardinal || h) { | |
| const { timezone = 'UTC' } = groups; | |
| const tz = timezone === 'UTC' ? 'UTC' : timezoneName[timezone]; | |
| //console.log(source, l, !!hCardinal && !h, numericAmount(hCardinal, l)) | |
| if (!!hCardinal && !h) { h = numericAmount(hCardinal, l); } | |
| if ((!isS(h) && !isNr(h)) || (isNr(h) && h > 24)) { return source; } | |
| let [ hour, minute, second ] = [(h === '24' ? 0 : toTimeInt(h)), toTimeInt(min), toTimeInt(sec)]; | |
| if (quarter && !min) { | |
| const { add15, sub15, sub30 } = groups; | |
| if (sub15 || sub30) { hour = !hour ? 23 : (hour-1); } | |
| minute = add15 ? 15 : (sub15 ? 45 : 30); | |
| } | |
| // TODO hCardinal | |
| return {type: 'time', h: hour, min: minute, sec: second, tz, ...(hCardinal ? {hCardinal} : {}), start, end, source, l } | |
| } | |
| return source; | |
| } | |
| let [day, month, year] = [toTimeInt(d), toTimeInt(m)-1, baseDate.getFullYear()]; | |
| if (isS(y)) { | |
| const Y = parseInt(y, 10); | |
| if (!isNaN(Y)) { year = (yBc && Y > 0) ? 0-Y : Y; } | |
| } | |
| if (!isNr(month)) { month = getMonthFromResult(result, m, l); } | |
| const mode = [(full ? 'localFull' : (long ? 'localLong' : (medium ? 'localMedium' : 'localShort')))]; | |
| const date = new Date(Date.UTC(year, month, day, h, min, sec)); | |
| if (isNaN(date)) { return source; } | |
| return { type: 'date', mode, startTime: date.toISOString(), start, end, source, l }; | |
| } | |
| // TODO dayPeriod instead time | |
| /* | |
| const tzStd = '((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\\s*(\\+|\\-)\\s*\\d\\d\\d\\d?)|gmt|utc)'; | |
| const TZ = { | |
| EST: '-0500', | |
| EDT: '-0400', | |
| CST: '-0600', | |
| CDT: '-0500', | |
| MST: '-0700', | |
| MDT: '-0600', | |
| PST: '-0800', | |
| PDT: '-0700' | |
| }; | |
| */ | |
| localDateParser.fn = { | |
| localDate: localDateFn, localTime: localDateFn, monthDate: localDateFn, | |
| casualTime: ({ type, start, end, result, source, groups, l }, d) => { | |
| // TODO timezone | |
| let { minute_sub, minute_add, prefix, suffix, _and, h, min = 0, sec = 0, timezone = 'UTC' } = groups; | |
| if (!h || (!minute_sub && !minute_add && !prefix && !suffix && !_and)) { return source; } | |
| const tz = timezone === 'UTC' ? 'UTC' : timezoneName[timezone]; | |
| let isWord = {h: false, min: false}; | |
| if (isNaN(parseInt(h, 10))) { isWord.h = h; h = numericAmount(h, l); } | |
| if (isS(minute_sub) && isNaN(parseInt(minute_sub, 10))) { isWord.min = minute_sub; minute_sub = numericAmount(minute_sub, l); } | |
| if (isS(minute_add) && isNaN(parseInt(minute_add, 10))) { isWord.min = minute_add; minute_add = numericAmount(minute_add, l); } | |
| if (!isNr(h) || h > 24) { return source; } | |
| if (minute_sub) { | |
| h = !h ? 23 : (h-1); | |
| min = 60-minute_sub; | |
| } else if (minute_add) { | |
| min = minute_add; | |
| } | |
| const cardinals = { ...(isWord.h ? {hCardinal: isWord.h} : {}), ...(isWord.min ? {minCardinal: isWord.min} : {}) }; | |
| return {type: 'time', h, min, sec, tz, ...cardinals, start, end, source, l } | |
| }, | |
| weekdayMonth: ({ type, start, end, result, source, groups, l }, d) => { | |
| // console.log('weekdayMonth',groups); | |
| const baseD = new Date(d.getTime()); | |
| const { dayOfWeek, monthOfYear, eachSuffix, ordinal, each, past, next } = groups; | |
| if (!isS(dayOfWeek) && !isS(monthOfYear)) { return source; } | |
| let index; | |
| let ordinalIndex = !isS(ordinal) ? false : result.slice(6).reduce((r, el, i) => ((r < 0 && el) ? i : r), -1); | |
| if (dayOfWeek) { | |
| // console.log(l, parser[l].dayOfWeek.regex, dayOfWeek); | |
| const [dayIndex] = (parser[l].dayOfWeek.regex.exec(dayOfWeek)).slice(2).map((s, i) => !s ? s : i).filter(isNr); | |
| if (!isNr(ordinalIndex)) { | |
| d.setDate((d.getDate() + (dayIndex+(7-d.getDay())) % 7) - (past ? (d.getDay() === dayIndex ? 14 : 7) : 0)); | |
| //console.log('dayIndex', l, dayIndex, past, d.toISOString()); | |
| index = dayIndex; | |
| } else if (!past && !next && ordinalIndex > 0 && ordinalIndex < 5) { | |
| console.log('ordinalIndex',ordinalIndex); | |
| d.setDate(1); | |
| d.setDate((d.getDate() + (dayIndex+(7-d.getDay())) % 7)); | |
| if (ordinalIndex > 1) { d.setDate((d.getDate() + (ordinalIndex-1 * 7))) } | |
| if (d.getTime() < baseD.getTime()) { | |
| d.setDate(1); | |
| d.setMonth(baseD.getMonth()+1); | |
| d.setDate((d.getDate() + (dayIndex+(7-d.getDay())) % 7)); | |
| if (ordinalIndex > 1) { d.setDate((d.getDate() + (ordinalIndex-1 * 7))) } | |
| } | |
| index = dayIndex; | |
| } | |
| } else { | |
| index = getMonthFromResult(result, monthOfYear, l); | |
| console.log('!:', ordinalIndex, index); | |
| if (!isNr(ordinalIndex)) { | |
| console.log('ordinal a index', index); | |
| if (past || next) { | |
| d.setDate((d.getDate() + (index+(12-d.getMonth())) % 12) - (past ? (d.getMonth() === index ? 24 : 12) : 0)); | |
| } else { | |
| d.setMonth(index); d.setDate(1); | |
| } | |
| } else if (ordinalIndex > 0 && ordinalIndex < 32) { | |
| console.log('ordinalIndex',ordinalIndex); | |
| d.setMonth(index); | |
| d.setDate(ordinalIndex); | |
| if (d.getTime() < baseD.getTime()) { d.setFullYear( baseD.getFullYear() + 1) } | |
| } | |
| } | |
| if (!isNr(index) || isNaN(d)) { return source; } | |
| //d.setHours(0); d.setMinutes(0); d.setSeconds(0); | |
| const baseMode = `${dayOfWeek ? 'dayOfWeek' : 'monthOfYear'}${isNr(ordinalIndex) ? 'Ordinal' : ''}`; | |
| const res = { type: 'date', value: dayOfWeek ?? monthOfYear, index, startTime: d.toISOString(), start, end, source, l }; | |
| if (isNr(ordinalIndex)) { res.ordinal = ordinalIndex; } | |
| if ((eachSuffix || each)) { | |
| return { ...res, mode: [baseMode, 'each'], cadence: (dayOfWeek ? {days: 7} : {months: 12}) }; | |
| } | |
| return { ...res, mode: [baseMode, (past ? 'past' : (next ? 'next' : 'word'))] }; | |
| }, | |
| relative: ({ type, start, end, result, source, groups, l }) => { | |
| //console.log(groups, result); | |
| if (groups?.relative) { | |
| let {amount, cardinal, few, couple, several} = groups; | |
| if (cardinal) { | |
| amount = numericAmount(cardinal, l); | |
| } else if (few || couple || several) { | |
| amount = few ? 3 : (couple ? 5 : 7); | |
| } else { | |
| amount = /\D/.test(amount) ? parseFloat(amount.replace(/\D/, '.')) : parseInt(amount, 10) | |
| } | |
| if (!isNr(amount)) { return source; } | |
| let [[unit, type]] = ['second', 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'year'].map((u) => { | |
| if (!groups[`${u}_add`] && !groups[`${u}_sub`]) { return false } | |
| return [u, (groups[`${u}_add`] ? 'add' : 'sub')]; | |
| }).filter((a) => Array.isArray(a)); | |
| if (isNr(amount) && unit && RELATIVE[unit] && type) { | |
| if (type === 'sub') { amount = amount * -1; } | |
| const startTime = RELATIVE[unit](amount); | |
| return !isS(startTime) ? source : { type: 'date', mode: ['relative'], startTime, start, end, source, l }; | |
| } | |
| } | |
| return source; | |
| } | |
| }; | |
| return { | |
| localDateParser, | |
| parser, | |
| as: { | |
| dayOfWeek, weekday, monthOfYear, monthname, dayPeriod,country, countryName, language, languageName, | |
| currency, currencyName, unit, unitName, timezone, timezoneName, region, regionName, | |
| }, | |
| keys: ['dayOfWeek', 'monthOfYear', 'dayPeriod', 'unit', 'timezone', 'country', 'language', 'currency', 'region'] | |
| } | |
| } | |
| const { as } = intlToActivityPub(['en']); | |
| export const asEN = as; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // languages which Intl does not support have an own module not covered here, set customExtended = {}: | |
| import { customExtended } from './optionalExtended.ts'; | |
| const op = (w) => w.replace(/^[(]/, '(?:'); | |
| const rd = (fn) => (r, w, i, a) => (i > 19 ? [...r, w, ...a.slice(1, 10).map((w1) => fn(w, w1))] : [...r, w]); | |
| const r = (a, mapFn) => new RegExp(`\\b(?:${(mapFn ? a.map(mapFn) : a).join('\\b|')})`, 'gi'); | |
| const esPt = [ | |
| '(nullo?|zero)', '(uno|uma?)', '(doi?s|duas)', '(tr[eê]s)', '([qc]uatro)', '(cinco)', '(seis)', '(si?ete)', | |
| '(ocho|oito)', '(nueve|nove)', '(di?ez)', '(once)', '(doce)', '(tre[cz]e)', '(cator[cz]e)', | |
| '(quin[cz]e)', '(dieciséis|dezesseis|dezasseis)', '(diecisiete|dezessete|dezassete)', | |
| '(dieciocho|dezoito)', '(diecinueve|dezenove|dezanove)', '(ve?inte)', '(tre?inta)' | |
| ] | |
| const esPtO = [ | |
| '(nullo?|zero)', '(primeir[oa])', '(second[oa]|segund[oa])', '(terz[oa]|terceir[oa])', '(quart[oa])', '(quint[oa])', | |
| '(se[sx]t[oa])', '(s[eé]tt?im[oa])', '(o[it]tav[oa])', '(non[oa])', '(d[eé]cim[oa])', | |
| '(und[eé]cim[oa]|décimo primeir[oa])', '(duo?d[eé]cim[oa]|décimo segund[oa])', | |
| '(tred[eé]cim[oa]|décimo terceir[oa])', '(quattordicesim[oa]|décimo quart[oa])', | |
| '(quindicesim[oa]|décimo quint[oa])', '(sedicesim[oa]|décimo sext[oa])', | |
| '(diciassettesim[oa]|décimo sétim[oa])', '(diciottesim[oa]|décimo oitav[oa])', | |
| '(diciannovesim[oa]|décimo non[oa])' | |
| ]; | |
| const cardinal = { | |
| en: [ | |
| '(null|zero)', '(a|one)', '(two)', '(three)', '(four)', '(fi(?:ve|f))', '(six)', '(seven)', | |
| '(eight)', '(nine?)', '(ten)', '(eleven)', '(twelve)', '(thirteen)', '(fourteen)', '(fifteen)', | |
| '(sixteen)', '(seventeen)', '(eighteen)', '(nineteen)', '(twent(?:y|ie))', '(thirt(?:y|ie))' | |
| ], | |
| de: [ | |
| '(null)', '((?:ais|ein)(?:em|en|er|s|e)?)', '(zwei|zwai|zwo)', '(drei|drüü|dry)', '(vier|viär)', | |
| '(fünf|fuenf|foif)', '(sechs|sech)', '(sieben|sibe)', '(acht|achter)', '(neun|nüün)', '(zehn|zä)', | |
| '(elf|elve?)', '(zwölf|zwoelf)', '(dreizehn|drüüzä)', '(vierzehn|viärzä)', '(fünfzehn|foifzä)', | |
| '(sechs?zehn|sechszä)', '(siebzehn|sibezä)', '(achtzehn|achtzä)', '(neunzehn|nüünzä)', | |
| '(zwanzigs?|zwänzgs?)', '(drei(?:ss|ß)igs?|dryssgs?)' | |
| ], | |
| fr: [ | |
| '(null?|z[eéè]ro|zénith)', '(une?)', '(deux)', '(trois)', '(quatre)', '(cinq)', '(six)', '(sept)', | |
| '(huit)', '(neuf)', '(dix)', '(onze)', '(douze)', '(treize)', '(quatorze)', '(quinze)', | |
| '(seize)', '(dix-sept)', '(dix-huit)', '(dix-neuf)', '(vingt(?: |$))', '(trente(?: |$))' | |
| ], | |
| it: [ | |
| '(null?|z[eéè]ro)', '(uno?)', '(due)', '(tre)', '(quattro)', '(cinque)', '(sei)', '(sette)', | |
| '(otto)', '(nove)', '(dieci)', '(undici)', '(dodici)', '(tredici)', '(quattordici)', '(quindici)', | |
| '(sedici)', '(diciassette)', '(diciotto)', '(diciannove)', '(venti)', '(trente)' | |
| ], | |
| es: esPt, | |
| pt: esPt, | |
| ru: [ | |
| '(ноль|нуль|зеро)', '(один|o-din)', '(два|двое|dva)', '(три|tri)', '(четыре|che-TY-rye)', | |
| "(пять|pyat')", "(шесть|shest')", "(семь|sem')", "(восемь|vo-sem')", | |
| "(девять|dye-vyat')", "(десять|dye-syat')", "(одиннадцать|o-di-NA-tsy-t')", | |
| "(двенадцать|dve-NA-tsy-t')", "(тринадцать|tri-NA-tsy-t')", "(четырнадцать|che-TYR-na-tsy-t')", | |
| "(пятнадцать|pyat-NA-tsy-t')", "(шестнадцать|shes-NA-tsy-t')", "(семнадцать|sem-NA-tsy-t')", | |
| "(восемнадцать|vo-sim-NA-tsy-t')", "(девятнадцать|dye-vyat-NA-tsy-t)", "(двадцать|dvád-tsat')", | |
| "(тридцать|trí-d-tsat')" | |
| ], | |
| ja: [ | |
| '(零|rei|zero)', '(一|ichi)', '(二|ni)', '(三|san)', '(四|yon|shi)', '(五|go)', '(六|roku)', | |
| '(七|nana|shichi)', '(八|hachi)', '(九|kyuu|ku)', '(十|juu)', '(十一)', '(十二)', '(十三)', '(十四)', | |
| '(十五)', '(十六)', '(十七)', '(十八)', '(十九)', '(二十)', '(二一)', '(二二)', '(二三)', '(二四)', | |
| '(二五)', '(二六)', '(二七)', '(二八)', '(二九)', '(三十)', '(三一)' | |
| ], | |
| ko: [ | |
| '(0)', '(하나|hana)', '(둘|dul)', '(셋|set)', '(넷|net)', '(다섯|daseot)', '(여섯|yeoseot)', '(일곱|ilgop)', | |
| '(여덟|yeodeol)', '(아홉|ahop)', '(열|yeol)', '(열하나|yeol-hana)', '(열둘|yeol-dul)', '(열셋|yeol-set)', | |
| '(열넷|yeol-net)', '(열다섯|yeol-daseot)', '(열여섯|yeol-yeoseot)', '(열일곱|yeol-ilgop)', | |
| '(열여덟|yeol-yeodeol)', '(열아홉|yeol-ahop)', '(스물|seumul)', '(스물한)', '(스물두)', '(스물셋)', | |
| '(스물넷)', '(스물다섯)', '(스물여섯)', '(스물일곱)', '(스물열넷)', '(스물다섯)', '(스물여섯)', | |
| '(서른|seoreun)', '(서른하나|삼십일)' | |
| ], | |
| zh: [ | |
| '(〇|零|líng)', '(一|壹)', '(二|貳)', '(三|叁)', '(四|肆)', '(五|伍)', '(六|陸)', '(七|柒)', '(八|捌)', '(九|玖)', | |
| '(十|拾)', '(十一|拾壹)', '(十二|拾貳)', '(十三|拾叁)', '(十四|拾肆)', '(十五|拾伍)', '(十六|拾陸)', | |
| '(十七|拾柒)', '(十八|拾捌)', '(十九|拾玖)', '(二十|貳拾|廿)', '(二十一|貳拾壹)', '(二十二|貳拾貳)', | |
| '(二十三|貳拾叁)', '(二十四|貳拾肆)', '(二十五|貳拾伍)', '(二十六|貳拾陸)', '(二十七|貳拾柒)', | |
| '(二十八|貳拾捌)', '(二十九|貳拾玖)', '(三十|叁拾|卅)', '(三十一|叁拾壹)' | |
| ] | |
| }; | |
| const ordinal = { | |
| it: [ | |
| '(null|zero)', '(primo)', '(secondo)', '(terzo)', '(quarto)', '(quinto)', '(sesto)', '(settimo)', '(ottavo)', | |
| '(nono)', '(decimo)', '(undicesimo)', '(dodicesimo)', '(tredicesimo)', '(quattordicesimo)', | |
| '(quindicesimo)', '(sedicesimo)', '(diciassettesimo)', '(diciottesimo)', '(diciannovesimo)', | |
| '(ventesimo)', '(ventunesimo)', '(ventiduesimo)', '(ventitreesimo)', '(ventiquattresimo)', | |
| '(venticinquesimo)', '(ventiseiesimo)', '(ventisettesimo)', '(ventottesimo)','(ventinovesimo)', | |
| '(trentesimo)', '(trentunesimo)' | |
| ], | |
| es: [...esPtO, ...[ | |
| 'esimo', 'unesimo', 'iduesimo', 'itreesimo', 'iquattresimo', | |
| 'icinquesimo', 'iseiesimo', 'isettesimo', 'ottesimo', 'inovesimo' | |
| ].map((s) => `(vent${s})`), 'trentesimo', 'trentunesimo' | |
| ], | |
| pt: [...esPtO, 'vigésimo', | |
| ...esPtO.slice(1,10).map((s) => `(vigésimo ${s.slice(1)}`), 'trigésimo', 'trigésimo primeiro' | |
| ], | |
| ru: [ | |
| '(ноль|нуль|зеро)', '(пе́рвый|pervyj)', '(второ́й|vtoroj)', '(тре́тий|tretij)', '(четвёртый|četvërtyj)', | |
| "(пя́тый|pjat'yj)", '(шесто́й|šestoj)', "(седьмо́й|sed'moj)", "(восьмо́й|vos'moj)", | |
| '(девя́тый|devjatyj)', '(деся́тый|desjatyj)', '(оди́ннадцатый|odinnadcatyj)', '(двена́дцатый|dvenadcatyj)', | |
| '(трина́дцатый|trinadcatyj)', '(четы́рнадцатый|četyrnadcatyj)', '(пятна́дцатый|pjatnadcatyj)', | |
| '(шестна́дцатый|šestnadcatyj)', '(семна́дцатый|semnadcatyj)', '(восемна́дцатый|vosemnadcatyj)', | |
| '(девятна́дцатый|devjatnadcatyj)', '(двадца́тый|dvadcatyj)', "(два́дцать пе́рвый|dvadcat' pervyj)", | |
| "(два́дцать второ́й|dvadcat' vtoroj)", "(два́дцать тре́тий|dvadcat' tretij)", | |
| "(два́дцать четвёртый|dvadcat' četvërtyj)", "(два́дцать пя́тый|dvadcat' pjatyj)", | |
| "(два́дцать шесто́й|dvadcat' šestoj)", "(два́дцать седьмо́й|dvadcat' sed'moj)", | |
| "(два́дцать восьмо́й|dvadcat' vos'emoj)", "(два́дцать девя́тый|dvadcat' devjatyj)", '(тридцатый|тридцатилетний)', '(тридцать первый)' | |
| ], | |
| ja: [ | |
| '(ゼロ|第0)', '(一つ目|hitotsume|一番目|ichibanme|第1)', '(二つ目|futatsume|二番目|nibanme|第2)', | |
| '(三番目|sanbanme|三つ目|mittsume|第3)', '(四番目|yonbanme|四つ目|yottsume|第4)', | |
| '(五番目|gobanme|五つ目|itsutsume|第5)', '(六番目|rokubanme|六つ目|muttsume|第6)', | |
| '(七番目|nanabanme|七つ目|nanatsume|第7)', '(八番目|hachibanme|八つ目|yattsume|第8)', | |
| '(九番目|kyūbanme|九つ目|kokonotsume|第9)', '(十番目|jūbanme|第10)', '(十一番目|jū ichi banme|第11)', | |
| '(十二番目|jū ni banme|第12)', '(十三番目|jū san banme|第13)', '(十四番目|jū yon banme|第14)', | |
| '(十五番目|jū go banme|第15)', '(十六番目|jū roku banme|第16)', '(十七番目|jū nana banme|第17)', | |
| '(十八番目|jū hachi banme|第18)', '(十九番目|jū kyū banme|第19)', '(二十番目|ni-jū banme|第20)', | |
| '(二十一|二十一番目|21番目の?)', '(二十二番目の?|22番目)', '(二十三番目の?|23番目)', | |
| '(二十四番目の?||24番目の?)', '(二十五番目の?|25番目の?)', '(二十六番目の?|26番目の?)', | |
| '(二十七番目の?|27番目の?)', '(二十八番目の?|28番目の?)', '(二十九番目の?|29番目の?)', '(三十番目|san-jū banme|第30)', | |
| '(三十一番目の?|31番目の?)' | |
| ], | |
| zh: [ | |
| '(〇|零|líng)', '(第一)', '(第二)', '(第三)', '(第四)', '(第五)', '(第六)', '(第七)', '(第八)', | |
| '(第九)', '(第十)', '(第十一)', '(第十二)', '(第十三)', '(第十四)', '(第十五)', '(第十六)', '(第十七)', | |
| '(第十八)', '(第十九)', '(第二十)', '(第二十一)', '(第二十二)', '(第二十三)', '(第二十四)', '(第二十五)', | |
| '(第二十六)', '(第二十七)', '(第二十八)', '(第二十九)', '(第三十)', '(第三十一)' | |
| ] | |
| } | |
| const wdEachStd = { weekdayEachSuffix: 's' } | |
| const en = { | |
| timeShift: '(recently|not long ago|(?:just )?(?:a )moments? ago)|(currently|n(?:ow)?)|'+ | |
| '(soon|right|in a second|in a minute|shortly)|(afterwards|later)', | |
| dayShift: '((?:the day )?before yes[.]?(?:terday)?)|(yes[.]?terday)|(t[.]?od[.]?ay)|(tom[.]?orrow)|'+ | |
| '((?:the day )?after tom[.]?(?:orrow)?)', | |
| // morning, forenoon, noon, afternoon, evening, night, midnight | |
| // _8, _10, _12, _15, _19, _22, _0 */ | |
| dayPeriodCasual: '(?:(?:at\\b)|(?:in (?:the)?\\b))?\\s?(?:mornings?|early(?: day)?)|'+ | |
| '((?:(?:at\\b)|(?:in (?:the)?\\b))?\\s?late morning|mid-morning|forenoon)|'+ | |
| '((?:at )?noon|meridie|lunch(?: break)?|[sS]iesta)|((?:(?:at\\b)|(?:in (?:the)?\\b))?\\s?afternoons?)|'+ | |
| '((?:(?:at\\b)|(?:in (?:the)?\\b))?\\s?evenings?)|(nights?)|((?:at )?midnight)', | |
| // daily, nightly, weekly, biweekly, monthly, bimonthly, yearly, annual, biannual | |
| cadence: '(daily)|(nightly)|(weekly)|(biweekly)|(monthly)|(bimonthly)|(quarterly|by quarter)'+ | |
| '(yearly|annual)|(bi(?:yearly|annual))', | |
| within: '\\bin|of\\b', each: '\\b(?:at )?(?:each|every|any)|(?:always(?: at)?)\\b', to: '\\bto|until|till?\\b', | |
| or: '\\b(?:else|or|along with)( also)?\\b', and: '\\b(?:plus|in addition to|as well as|together with|and)( also)?\\b', | |
| past: '\\b(?:[pl]ast|prev(?:ious)?)s?\\b', next: '\\bnext?s?\\b', | |
| few: '\\ba few(?: of)?|few', couple: '\\ba couple(?: of)?|couple|some', several: '\\bseveral|more', | |
| add: '\\b\\+|from|hence|aft(?:er)?\\b', substract: '\\b\\-|ago|bef(?:ore)?\\b', | |
| half: '\\bhalf(?: to)?\\b', addHalf: '\\bhalf past|and(?: a)? half\\b', | |
| yearBC: '\\s?(?:(?:b[.]?\\s?efore?(?:[cd]| [cd]))|bce|ce)[.]?', | |
| yearAD: '\\s?(?:(?:a[.]?\\s?nno?(?:d| d))|anno(?: domini)?)[.]?', | |
| timeMSubAdd: "(?:at\\s)?((?:\\d\\d?)|[a-züßö]{3,16})\\s?(?:mn[.]?|min(?:[.]?ute)?s?\\s)?(?:(to)|(past))\\s?"+ | |
| "((?:\\d\\d?)|[a-z]{3,6})(?: o['‘]clock| of the clock| oh| h[.]?)?", | |
| timeQuarterPrefix: '(?<add15>(?:a\\s)?quarter past)|(?<sub15>(?:a\\s)?quarter to)|'+ | |
| '(?<add30>(?:a\\s)?half past)|(?<sub30>(?:a\\s)?half to)', | |
| concatTime: "(?:\\s?(?:o['‘]clock|of the clock|oh|and|h[.]?))", | |
| concatPrefix: '\\b\\W?\\s?(?:at|o[fhn]|the|in)\\s?\\b', | |
| cardinal: cardinal.en.reduce(rd((w, w1) => `(${op(w)}[-]?${op(w1)})`), []), ...wdEachStd | |
| }; | |
| const ptEs = { | |
| timeShift: '(reci?entemente|(?:há|hace)? pou?co(?: tiempo)?|(?:há|hace)? un (?:rato|momento))|'+ | |
| '(a[gh]ora|(?:en este |no |neste )?(?:momento|instante)|ac?tualmente)|'+ | |
| '(enseguida|pronto|inmediatamente|em breve)|(después|depois|más tarde)', | |
| dayShift: '(ante(?:ayer|ontem))|(ayer|ontem)|(ho[jy]e)|(mañana|amanhã)|((?:pasado|depois de) mañana|amanhã)', | |
| dayPeriodCasual: '(mañanas|manhãs)|((?:(?:pela |de )manhã)|por la mañana)|(med?io[-]?(?:d[ií]as?))|'+ | |
| '((?:à |por la )?tardes?)|(por la tarde|ao fim da tarde|por la noche|à tardinha)|'+ | |
| '((?:[aà] )última hora|muy de noche|(?:[aà] )?noites?|noches?)|(med?ia[-]?(?:noite|noche))', | |
| cadence: '(diari(?:o|amente))|(noc?turn(?:o|amente))|(semanal(?:o|amente))|(quin[cz]enal(?:o|amente))|'+ | |
| '(mensu?al(?:o|amente))|(bimensu?al(?:o|amente))|(trimestral(?:mente)?)|(anual(?:o|amente))|(bianual(?:o|amente)|semestralmente)', | |
| within: '\\be[nm]\\b', each: '\\btodos l?[ao]s|cadas?|si?empre(?: l?[ao]s)?\\b', to: '\\baté|hasta(?: el)?\\b', | |
| or: '\\bou?\\b', and: '\\bplus|[ye]\\b', | |
| past: '\\bpasad[ao]|anterior|últim[ao]\\b', next: '\\bpróxim[ao]\\b', | |
| few: '\\bpou?c[ao]s?|men[ao]s?', couple: '\\bun[ao]s|alg[uú][mn]a?s', several: '\\bv[aá]ri[ao]s|divers[ao]s?', | |
| add: '\\b\\+|después|após|a partir\\b', substract: '\\b\\-|(?:desde )?hace|há|desde\\b', | |
| half: '\\bmed?io\\b', addHalf: '\\b1[/]2|[ye] med?io\\b', | |
| yearBC: '\\s?(?:antes de Cristo|a[.]C[.]|ante christum)', | |
| yearAD: '\\s?(?:después de Cristo|d[.]C[.]|anno(?: domini)?)', | |
| /*timeMSubAdd: "(?:at\\s)?((?:\\d\\d?)|[a-züßö]{3,16})\\s?(?:mn[.]?|min(?:[.]?ute)?s?\\s)?(?:(to)|(past))\\s?"+ | |
| "((?:\\d\\d?)|[a-z]{3,6})(?: o['‘]clock| of the clock| oh| h[.]?)?", | |
| um 20 vor drei = a las tres menos veinte | |
| The Spanish language also has an established convention for days of the week using one letter. | |
| These are: L – lunes (Monday); M – martes (Tuesday); X – miércoles (Wednesday); | |
| J – jueves (Thursday); V – viernes (Friday), S – sábado (Saturday); and D – domingo (Sunday). | |
| */ | |
| timeQuarterSuffix: '(?<add15>(?:[ey]) (?:um )?[cq]uarto)|(?<sub15>menos (?:um )?[cq]uarto)|'+ | |
| '(?<add30>[ey] med?ia)|(?<sub30>menos med?ia)', | |
| concatTime: "(?:\\s?(?:[ey]|horas|(?:en )?punto|h[.]?))", | |
| concatPrefix: '\\b\\W?\\s?(?:des?|e[lmn]|[aà]s?||l[ao]s?)\\s?\\b', | |
| } | |
| const CASUAL = { | |
| keys: [ | |
| 'timeShift','dayShift','dayPeriodCasual','cadence','within','to','or','and', | |
| /*'each','few','couple','several','half','addHalf','yearBC','yearAD'*/ | |
| ], | |
| en: { | |
| monthDigit: { sept: 8 }, | |
| regex: {} | |
| }, | |
| de: { | |
| monthDigit: { 'jänner': 0, janner: 0, feber: 1, maerz: 2, mrz: 2, sept: 8 }, | |
| unit: { y: 'J', d: 'T'}, | |
| regex: {} | |
| }, | |
| r: { | |
| // TODO not | |
| // this diese?[mnrs] esta... | |
| // cardinalSuffix = 'th|nd|rd|er?|te|-?й|ro|do|[.˚]'; | |
| en, | |
| de: { | |
| timeShift: '(kürzlich|neulich|unlängst|vorhin|(?:gerade |so)?eben)|(jetzt|momentan|i[nm] (?:diesem )?Moment)|'+ | |
| '(gleich|bald|sofort|in Kürze|umgehend)|(nachher|später)', | |
| dayShift: '(vorgestern)|(ges[.]?tern)|(heute?|heuer|heit|hüt)|(morgen?|moin|moorn)|((?:ü|ue)ber(?:morgen?|moin|moorn))', | |
| // morning, forenoon, noon, afternoon, evening, night, midnight | |
| dayPeriodCasual: '((?:(?:am )?(Morgen|morgendlich))|(vormittags?)|'+ | |
| '(Mittag|mittäglich|meridie|(?:zur )?Mittagszeit|(?:in der )?Mittagspause|[sS]iesta)|([nN]achmittags?)|((?:am )?Abends?)|'+ | |
| '((?:in der )?Nachts?|nächtlich)|((?:um |zur? )?Mitternacht|Geisterstunde))', | |
| // daily, nightly, weekly, biweekly, monthly, bimonthly, quaterly, yearly, annual, biannual | |
| cadence: '(täglich)|(nächtlich)|(wöchentlich)|((?:(?:2|zwei)[-]?wöchentlich)|alle (?:2|zwei) Wochen)|'+ | |
| '(monatlich|jeden Monat)|((?:(?:2|zwei)[-]?monatlich)|alle (?:2|zwei) Monate)|(quartalsweise|jedes Quartal)|'+ | |
| '(jährlich|jedes Jahr)|((?:(?:2|zwei)[-]?jährlich)|alle (?:2|zwei) Jahre)', | |
| within: '\\bi[nm]\\b', each: '\\b(?:an )?(?:jede[mnrs]?)|(?:immer(?: a[mn])?)\\b', to: '\\bbis( zum?)?\\b', | |
| or: '\\boder\\b', and: '\\b(?:plus|und|als auch)\\b', | |
| past: '\\b(?:letzte[mnrs]?)|(?:vorige[mnrs]?)\\b', next: '\\bnächste[mnrs]?\\b', | |
| few: '\\bwenig(?:e(?:[mnrs])?)', couple: '\\beinig(?:e(?:[mnrs])?)', several: '\\b(?:ein paar)|mehrer(?:e(?:[mnrs])?)', | |
| add: '\\b\\+|nach|in|ab jetzt\\b', substract: '\\b\\-|(?:(zu)?vor)|seit\\b', | |
| half: '\\b(?:hoib|halb)(?:e(?:[mnrs])?)\\b', addHalf: '\\b1[/]2|einhalb|(?:th?alb)\\b', | |
| yearBC: '\\s?(?:(?:vor|(?:v|a)[.]?)\\s(?:Ch?r?[.]?(?:istus)?)|ante christum)', | |
| yearAD: '\\s?(?:(?:nach|n[.]?)\\s(?:Ch?r?[.]?(?:istus)?)|anno(?: domini)?)', | |
| timeMSubAdd: '(?:um\\s)?((?:,\\d,\\d?)|[a-züßö]{4,16}),\\s?(?:mn[.]?|(?:min[.]?(?:ute)?n?),\\s)?'+ | |
| '(?:(vor)|(nach))\\s?((?:,\\d,\\d?)|[a-zöü]{4,6})(?: ?uhr)?', | |
| timeQuarterPrefix: '(?<add15>viertel(?: nach))|(?<sub15>viertel vor|dreiviertel)|'+ | |
| '(?<add30>(?:hoib|halb) nach)|(?<sub30>hoib|halb)', | |
| concatTime: '(\\s?(?:uhr|h[.]?)?(?: und)?\\s?)', | |
| concatPrefix: '\\b\\W?\\s?(?:am|an|ab|um|den|der|des|i[nm])\\s?\\b', | |
| cardinal: cardinal.de.reduce(rd((w, w1) => `(${op(w1)}und${op(w)})`), []), ...wdEachStd | |
| }, | |
| fr: { // TODO past next can be suffix | |
| timeShift: '(récemment|il y a peu|tout à l\'heure)|(maintenant|en (?:ce )?moment|cette moment|actuellement|immédiament)|'+ | |
| '(tout à l\'heure|bientôt|tout (?:de )?suite)|(après|plus tard)', | |
| dayShift: '(avant-hier)|(hier)|(aujourd\'hui)|(demain)|(après-demain)', | |
| dayPeriodCasual: '(matins)|(matinées)|(midis)|(après-midis)|(soirs)|(nuits)|(minuit)', | |
| cadence: '(quotidien)|(nocturne)|(hebdomadaire)|(bihebdomadaire)|(mensuel)|(bimensuel)|(trimestriel)|(annuel)|(biannuel)', | |
| within: '\\bà|en\\b', each: '\\bchaque|toujours(?: l[ae])?\\b', to: '\\bjusqu\'à|jusqu\'en|jusque\\b', | |
| or: '\\bou\\b', and: '\\bet\\b', | |
| past: '\\bdernier|dernière\\b', next: '\\bprochaine?|précédente?\\b', | |
| few: '\\bpeu|quelques?|moins?(?: de)?', couple: '\\bun couple', several: '\\bplusieurs?|plus de', | |
| add: '\\b\\+|après|à partir de maintenant\\b', substract: '\\b\\-|il y a|depuis\\b', | |
| half: '\\bdemi[-]\\b', addHalf: '\\b1[/]2|(?:et )?demie\\b', | |
| yearBC: '\\s?(?:avant Jésus[- ]?(?:Christ)?|ante christum)', | |
| yearAD: '\\s?(?:après Jésus[- ]?(?:Christ)?|anno(?: domini)?)', | |
| /* timeMSubAdd: "", um 20 vor drei = à trois heures moins vingt */ | |
| timeQuarterSuffix: '(?<add15>et quart)|(?<sub15>moins (?:le )?quart)|(?<add30>et demie)|(?<sub30>moins (?:le )?demie)', | |
| concatTime: "(?:\\s?(?:heures?|et|h[.]?))", | |
| concatPrefix: '\\b\\W?\\s?(?:dans|des|l[ae]s?|[ei][nm])\\s?\\b', | |
| //(?: |$) | |
| cardinal: cardinal.fr.reduce(rd((w, w1) => { return `(${op(w.replace('(?: |$)', ''))}[- ](?:et[- ])?${op(w1)})`}), []), | |
| ...wdEachStd | |
| }, | |
| es: { | |
| ...ptEs, cardinal: cardinal.es.reduce(rd((w, w1) => `(${op(w1)}(?: [ye] )?\\s?${op(w)})`), []), ...wdEachStd | |
| }, | |
| pt: { | |
| ...ptEs, cardinal: cardinal.pt.reduce(rd((w, w1) => `(${op(w1)}(?: [ye] )?\\s?${op(w)})`), []), ...wdEachStd | |
| }, | |
| it: { | |
| // (?:un )?quarto)|? (?:un )?quarto)|?<sub15> | |
| timeShift: '(recentemente|di recente|poco(?: tempo)? fa|proprio ora)|(ora|al momento|in questo momento)|'+ | |
| '(tra poco|presto|subito)|(dopo|più tardi)', | |
| dayShift: '((?:l\')?altro ieri)|(ieri)|(oggi)|(domani|dmn[.]?)|(dopodomani)', | |
| dayPeriodCasual: '(mattine)|(mattinate)|(mezzogiorni)|(pomeriggi)|(sere)|(notti)|(mezzanotte)', | |
| cadence: '(giornaliero)|(notturno)|(settimanale)|(bisettimanale)|(mensile)|(bimestrale)|(trimestrale)|'+ | |
| '(annuale)|(biennale|semestrale)', | |
| within: '\\ba|in\\b', each: '\\bogni|sempre(?: la)\\b', to: '\\bfino(?: a)?\\b', | |
| or: '\\bo\\b', and: '\\bplus|e\\b', | |
| past: '\\bscors[ao]|(?:l\')?ultimo|precedente\\b', next: '\\bprossim[ao]\\b', | |
| few: '\\bpoch[ei]|poc[ao]', couple: '\\bqualche|alcune', several: '\\bdivers[eio]|alcuni', | |
| add: '\\b\\+|dopo|da adesso\\b', substract: '\\b\\-|[fd]a\\b', | |
| half: '\\bmezzo\\b', addHalf: '\\b1[/]2|e mezzo\\b', | |
| yearBC: '\\s?(?:prima(?: di) Cristo|a[.]C[.]|ante christum)', | |
| yearAD: '\\s?(?:dopo(?: di) Cristo|d[.]C[.]|anno(?: domini)?)', | |
| /* timeMSubAdd: "", um 20 vor drei = alle due meno venti */ | |
| timeQuarterSuffix: '(?<add15>(?:e )?(?:un )?quarto)|(?<sub15>meno (?:un )?quarto)|'+ | |
| '(?<add30>(?:e )? mezza)|(?<sub30>meno mezza)', | |
| concatTime: "(?:\\s?(?:in punto|e|h[.]?))", | |
| concatPrefix: '\\b\\W?\\s?(?:e[lmn]|tra||d[ao]s?|al?)\\s?\\b', | |
| cardinal: cardinal.it.reduce(rd((w, w1) => `(${op(w1)}\\s?${op(w)})`), []), ...wdEachStd | |
| }, | |
| ru: { | |
| timeShift: '(недавно|только что)|(сейчас|(?:в данный |в этот )?момент)|(сразу|скоро|немедленно)|(после|позже)', | |
| dayShift: '(позавчера)|(вчера)|(сегодня)|(завтра)|(послезавтра)', | |
| dayPeriodCasual: '(утром)|(до полудня)|(в полдень)|(днем)|(вечером)|(ночью)|(полночь)', | |
| cadence: '(ежедневно)|(ежедневно)|(еженедельно)|(два раза в неделю)|'+ | |
| '(ежемесячно)|(два раза в месяц)|(ежеквартально)|(ежегодно)|(два раза в год)', | |
| within: '\\bв\\b', each: '\\bкаждый|каждое|каждую|всегда по\\b', to: '\\bдо\\b', | |
| or: '\\bили\\b', and: '\\bplus|и\\b', | |
| past: '\\bпрошлую|прошлый|последнее\\b', next: '\\bследующий|следующую\\b', | |
| few: '\\bнесколько|меньшее|немного', couple: '\\bнекоторое', several: '\\bнескольких', | |
| add: '\\b\\+|через|с этого момента\\b', substract: '\\b\\-|назад\\b', | |
| half: '\\bполовине|полдня|полгода\\b', addHalf: '\\b1[/]2|с половиной\\b', | |
| /* timeMSubAdd: "", um 20 vor drei = за 20 минут до трех */ | |
| timeQuarterPrefix: '(?<add15>четверть)|(?<sub15>четверть до)|(?<add30>до пол)|(?<sub30>пол)', | |
| concatTime: "(?:\\s?(?:в|за|до|часа|h[.]?))", | |
| concatPrefix: '\\b\\W?\\s?(?:в|i[nm])\\s?\\b', | |
| cardinal: cardinal.ru.reduce(rd((w, w1) => `(${op(w)}[-]?${op(w1)})`), []), ...wdEachStd | |
| }, | |
| // TODO : | |
| ja: { | |
| ...en, | |
| timeShift: '(最近|つい先日|ついさっき|さっき|ちょうど今)|(今|現在|この瞬間)|(すぐに|まもなく|すぐに)|(後で|後ほど)', | |
| dayShift: '(一昨日|一昨日の前日)|(昨日|きのう)|(本日|今日|ほんじつ|きょう)|(明日|あした)|(あさって|明後日)', | |
| dayPeriodCasual: '(朝)|(午前中)|(昼)|(午後)|(夕方)|(夜)|(真夜中)', | |
| cadence: '(毎日)|(毎晩)|(毎週)|(隔週)|(毎月)|(隔月)|(四半期ごと)|(毎年)|(半年ごと)', | |
| cardinal: cardinal.ja, ...wdEachStd | |
| }, | |
| ko: { | |
| ...en, | |
| timeShift: '(최근에|얼마 전에|얼마 전|방금 전에|방금)|(지금|현재|이 순간)|(곧|곧바로|즉시)|(나중에|나중)', | |
| dayShift: '(그저께|엊그제)|(어제)|(오늘)|(내일)|(모레)', | |
| dayPeriodCasual: '(아침)|(오전)|(점심)|(오후)|(저녁)|(밤)|(한밤중)', | |
| cadence: '(매일)|(매일 밤)|(매주)|(격주)|(매월)|(2개월마다)|(분기별)|(매년)|(반년마다)', | |
| cardinal: cardinal.ko, ...wdEachStd | |
| }, | |
| zh: { | |
| ...en, | |
| cardinal: cardinal.zh, ...wdEachStd | |
| } | |
| }, | |
| fn: { | |
| } | |
| }; | |
| /* | |
| ja | |
| こんや|今夜 Heute Abend | |
| けさ|今朝 Heute Morgen | |
| zh | |
| if (text == "今夜" || text == "今夕" || text == "今晩") { | |
| components.imply("hour", 22); | |
| components.assign("meridiem", Meridiem.PM); | |
| } else if (text.match("今朝")) { | |
| components.imply("hour", 6); | |
| components.assign("meridiem", Meridiem.AM); | |
| } | |
| const PATTERN = | |
| /(?:(?:([同今本])|((昭和|平成|令和)?([0-90-9]{1,4}|元)))年\s*)?([0-90-9]{1,2})月\s*([0-90-9]{1,2})日/i; | |
| const SPECIAL_YEAR_GROUP = 1; | |
| const TYPICAL_YEAR_GROUP = 2; | |
| const ERA_GROUP = 3; | |
| const YEAR_NUMBER_GROUP = 4; | |
| const MONTH_GROUP = 5; | |
| const DAY_GROUP = 6; | |
| */ | |
| // TODO ordinal | |
| const [enO, deS, frO, koO] = [ | |
| {1: '(first|1st)', 2: '(second|2nd)', 3: '(third|3rd)'}, | |
| `(?:[mnrs])?)`, | |
| {1: '(premier|première?)', 2: '(deuxième|seconde)', 4: '(quartième)' }, | |
| {1: '(첫 번째|cheot beonjjae)', 2: '(두 번째|du beonjjae)', 3: '(세 번째|se beonjjae)'} | |
| ]; | |
| /** */ | |
| const baseKeys = ['monthDigit', 'unit', 'regex']; | |
| for (const l in CASUAL.r) { | |
| if (!CASUAL[l]) { CASUAL[l] = {regex: {}}; } | |
| //CASUAL[l].regex.cardinal = r(CASUAL.r[l].cardinal); | |
| } | |
| /* | |
| for (const l in cardinal) { | |
| if (!CASUAL[l]) { CASUAL[l] = {regex: {}}; } | |
| baseKeys.forEach((k) => { if (!CASUAL[l][k]) { CASUAL[l][k] = {}; } }); | |
| CASUAL[l].regex.cardinal = r(cardinal[l]); | |
| } | |
| */ | |
| // ordinals … | |
| CASUAL.en.regex.ordinal = r(cardinal.en, (s,i) => (enO[i] || `(${(i>20&&i<24) | |
| ? `${op(cardinal.en[20])}[-]?${op(enO[i-20])}` | |
| : (i>30&&i<34 ? `${op(cardinal.en[30])}[-]?${op(enO[i-30])}` : op(s+'th'))}|${i}th)`)); | |
| CASUAL.de.regex.ordinal = r(cardinal.de, (s,i) => (i===1 | |
| ? `(erste${deS}` | |
| : `((?:${(i>9 ? s : s.replace('drei|','drit|').replace('sieben|','siebe?n?|')).slice(1)}te${deS}`)); | |
| CASUAL.fr.regex.ordinal = r(cardinal.fr, (s,i) => (frO[i] || | |
| `${s.replace(/f$/, 'v').replace(/e$/, '').replace(/^vingt/, 'ving?t')+'ième'}`)); | |
| CASUAL.ko.regex.ordinal = r(cardinal.ko, (s,i) => | |
| (koO[i] || `(${s.replace(/[()]/g, '').split('|').map((s2) => `${s2}번째`).join('|')})`)); | |
| /* Sino-Korean : | |
| Alternatively, for more formal or written contexts, the prefix 제 (je) is used with Sino-Korean numbers (e.g., 제 일 장 for "Chapter 1"). | |
| */ | |
| CASUAL.it.regex.ordinal = r(ordinal.it); | |
| CASUAL.pt.regex.ordinal = r(ordinal.pt); | |
| CASUAL.es.regex.ordinal = r(ordinal.es); | |
| CASUAL.ru.regex.ordinal = r(ordinal.ru); | |
| CASUAL.ja.regex.ordinal = r(ordinal.ja); | |
| CASUAL.zh.regex.ordinal = r(ordinal.zh); | |
| for (const l in CASUAL) { | |
| if (CASUAL[l]?.regex?.ordinal) { CASUAL.r[l].ordinal = CASUAL[l].regex.ordinal.source; } | |
| } | |
| export const dateCasual = CASUAL; | |
| //console.log(CASUAL.r.fr.cardinal, CASUAL.r.fr.ordinal); | |
| /*console.log(CASUAL.de.regex.ordinal);*/ | |
| /* | |
| export const extend = { | |
| en: { | |
| regexPattern: { | |
| time: /((?:(?:at|from)\s)?(2[0-3]|[01][0-9]|[0-9]\b)(?:\s?(?:o['‘]clock|of the clock|oh|h[.]?))(?: and)?\s?([0-5][0-9]|[0-9]\b)(?: (?:mn[.]?|min(?:[.]?ute)?s?)(?: and)?\s?)?([0-5][0-9]|[0-9]\b)?(?:\s(?:sec[.]?(?:ond)?s?))?\s?(?:o['‘]clock|of the clock|oh|h[.]?)?|(?:(?:(?:at|from)\s)(2[0-3]|[01][0-9]|[0-9]\b)[.,:]?\s?([0-5][0-9]|[0-9]\b)?(?:\s?(?:o['‘]clock|of the clock|oh|h[.]?)?)))/i, | |
| timeMSubAdd: /(?:at\s)?((?:\d\d?)|[a-züßö]{3,16})\s?(?:mn[.]?|min(?:[.]?ute)?s?\s)?(?:(to)|(past))\s?((?:\d\d?)|[a-z]{3,6})(?: o['‘]clock| of the clock| oh| h[.]?)?/i, | |
| timeHalfSubAdd: /(?:at\s)?half(?:( to )|( past ))((?:\d\d?)|[a-z]{3,6})(?: o['‘]clock| of the clock| oh| h[.]?)?/i, | |
| timeQSub: /(?:at\s)?(a\s)?quarter to ((?:\d\d?)|[a-z]{3,6})/i, timeQAdd: /(?:at\s)?(a\s)?quarter past ((?:\d\d?)|[a-z]{3,6})/i, | |
| // _8, _10, _12, _15, _19, _22, _0 | |
| dayPeriodExt: /\b((?:(?:at\b)|(?:in (?:the)?\b))?\s?(mornings?|early day)|(late morning|forenoon)|(noon|meridie|lunch(?: break)?|[sS]iesta)|(afternoons?)|(evenings?)|(night|nightly)|(midnight))/ | |
| // cadence the daily / nightly / weekly / biweekly / monthly / bimonthly / yearly / annual / biannual... event / festival / fair / party... | |
| // alternate | |
| // The abbreviation QOD or QAD (from Latin mean Quaque Alternis Die") means 'every other day' or 'every two days'. | |
| } | |
| }, | |
| // | |
| de: { // Todo: vor 2 Wochen = 2 Wochen vorher/zuvor | |
| regexPattern: { | |
| time: /((?:(?:um|ab)\s)?(2[0-3]|[01][0-9]|[0-9]\b)(?:\s?(?:uhr|h[.]?)(?: und)?\s?)?([0-5][0-9]|[0-9]\b)(?: (?:mn[.]?|(?:min[.]?(?:ute)?n?))?)?(?: und )?([0-5][0-9]|[0-9]\b)?(?:\s(?:sek[.]?(?:unde)?n?))?|(?:(?:(?:um|ab)\s)(2[0-3]|[01][0-9]|[0-9]\b)[.,:]?\s?([0-5][0-9]|[0-9]\b)?(?:\s?(?:uhr|h[.]?)?)))/i, | |
| timeMSubAdd: /(?:um\s)?((?:\d\d?)|[a-züßö]{4,16})\s?(?:mn[.]?|(?:min[.]?(?:ute)?n?)\s)?(?:(vor)|(nach))\s?((?:\d\d?)|[a-zöü]{4,6})(?: ?uhr)?/i, | |
| timeHalfSubAdd: /(?:um\s)?(?:hoib|halb)(?:( )|( nach ))((?:\d\d?)|[a-zöü]{4,6})/i, | |
| timeQSub: /(?:um\s)?viertel vor ((?:\d\d?)|[a-zöü]{4,6})/i, | |
| timeQAdd: /(?:um\s)?(?:(?:viertel nach )|(?:drei)?viertel )((?:\d\d?)|[a-zöü]{4,6})/i, | |
| dayPeriodExt: /((?:am )?(Morgen|morgendlich)|(Vormittag|vormittags)|(Mittag|mittäglich|meridie|(?:zur )?Mittagszeit|(?:in der )?Mittagspause|[sS]iesta)|([nN]achmittags?)|(Abend)|((?:in der )?Nacht|nächtlich)|((?:um |zur? )?Mitternacht|Geisterstunde))/ | |
| } | |
| } | |
| } | |
| */ | |
| // TODO optional: | |
| //for (const k in customExtended) { customExtended[k] = {...base[k], ...customExtended[k]}; } | |
| export const custom = { ...customExtended }; | |
| // <-- optional |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment