wohoo new VPExplorer moved into the grammar engine!
This commit is contained in:
parent
53bb07fcdc
commit
8d841a6c24
|
@ -28,3 +28,4 @@ yarn-debug.log*
|
|||
yarn-error.log*
|
||||
|
||||
/src/verbs.ts
|
||||
/src/noun-adjs.ts
|
||||
|
|
71
get-verbs.js
71
get-verbs.js
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const fetch = require("node-fetch");
|
||||
const path = require("path");
|
||||
const collectionPath = path.join(".", "verbs");
|
||||
const verbTsFiles = fs.readdirSync(collectionPath);
|
||||
const protoModels = require("./src/lib/dictionary-models.js");
|
||||
const Pbf = require("pbf");
|
||||
|
||||
const allTsS = [...new Set(verbTsFiles.reduce((arr, fileName) => {
|
||||
const TsS = require("./verbs/"+fileName);
|
||||
return [...arr, ...TsS];
|
||||
}, []))];
|
||||
|
||||
fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(buffer => {
|
||||
const pbf = new Pbf(buffer);
|
||||
const dictionary = protoModels.Dictionary.read(pbf);
|
||||
const entries = dictionary.entries;
|
||||
const allVerbs = getFromTsS(entries);
|
||||
const content = `
|
||||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import { DictionaryEntry } from "./types";
|
||||
|
||||
const verbs: {
|
||||
entry: DictionaryEntry,
|
||||
complement?: DictionaryEntry,
|
||||
}[] = ${JSON.stringify(allVerbs)};
|
||||
export default verbs;`;
|
||||
fs.writeFileSync("./src/verbs.ts", content);
|
||||
console.log("fetched verbs from dictionary");
|
||||
});
|
||||
|
||||
function getFromTsS(entries) {
|
||||
const missingEc = [];
|
||||
const toReturn = allTsS.map(ts => {
|
||||
const entry = entries.find(x => ts === x.ts);
|
||||
if (!entry.ec) {
|
||||
missingEc.push(entry.ts);
|
||||
}
|
||||
if (!entry) {
|
||||
console.log("couldn't find ts", ts);
|
||||
return undefined;
|
||||
}
|
||||
if (entry.c && entry.c.includes("comp.")) {
|
||||
const complement = entries.find(x => entry.l === x.ts);
|
||||
return {
|
||||
entry,
|
||||
complement,
|
||||
};
|
||||
}
|
||||
return { entry };
|
||||
}).filter(x => x);
|
||||
if (missingEc.length !== 0) {
|
||||
console.log("missingEc", missingEc);
|
||||
}
|
||||
return toReturn;
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
const fs = require("fs");
|
||||
const fetch = require("node-fetch");
|
||||
const path = require("path");
|
||||
const verbCollectionPath = path.join(".", "verbs");
|
||||
const nounAdjCollectionPath = path.join(".", "nouns-adjs");
|
||||
const verbTsFiles = fs.readdirSync(verbCollectionPath);
|
||||
const nounAdjTsFiles = fs.readdirSync(nounAdjCollectionPath);
|
||||
const protoModels = require("./src/lib/dictionary-models.js");
|
||||
const Pbf = require("pbf");
|
||||
|
||||
const allVerbTsS = [...new Set(verbTsFiles.reduce((arr, fileName) => {
|
||||
const TsS = require("./verbs/"+fileName);
|
||||
return [...arr, ...TsS];
|
||||
}, []))];
|
||||
|
||||
const allNounAdjTsS = [...new Set(nounAdjTsFiles.reduce((arr, fileName) => {
|
||||
const TsS = require("./nouns-adjs/"+fileName).map(x => x.ts);
|
||||
return [...arr, ...TsS];
|
||||
}, []))];
|
||||
|
||||
fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(buffer => {
|
||||
const pbf = new Pbf(buffer);
|
||||
const dictionary = protoModels.Dictionary.read(pbf);
|
||||
const entries = dictionary.entries;
|
||||
const allVerbs = getVerbsFromTsS(entries, allVerbTsS);
|
||||
const verbsContent = `
|
||||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import { DictionaryEntry, VerbEntry } from "./types";
|
||||
|
||||
const verbs: {
|
||||
entry: DictionaryEntry,
|
||||
complement?: DictionaryEntry,
|
||||
}[] = ${JSON.stringify(allVerbs)};
|
||||
export default verbs as VerbEntry[];`;
|
||||
fs.writeFileSync("./src/verbs.ts", verbsContent);
|
||||
const allNounsAdjs = getNounsAdjsFromTsS(entries, allNounAdjTsS);
|
||||
const nounsAdjsContent = `
|
||||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import { DictionaryEntry } from "./types";
|
||||
|
||||
const nounsAdjs: DictionaryEntry[] = ${JSON.stringify(allNounsAdjs)};
|
||||
export default nounsAdjs;`;
|
||||
fs.writeFileSync("./src/nouns-adjs.ts", nounsAdjsContent);
|
||||
console.log("fetched words from dictionary");
|
||||
});
|
||||
|
||||
function getNounsAdjsFromTsS(entries, tss) {
|
||||
const missingEc = [];
|
||||
const toReturn = tss.map(ts => {
|
||||
const entry = entries.find(x => ts === x.ts);
|
||||
if (!entry) {
|
||||
console.log("couldn't find ts", ts);
|
||||
return undefined;
|
||||
}
|
||||
if (ts.ec) {
|
||||
missingEc.push(ts);
|
||||
}
|
||||
return entry;
|
||||
}).filter(x => x);
|
||||
if (missingEc.length !== 0) {
|
||||
console.log("missingEc", missingEc);
|
||||
}
|
||||
return toReturn;
|
||||
|
||||
}
|
||||
|
||||
function getVerbsFromTsS(entries, tss) {
|
||||
const missingEc = [];
|
||||
const toReturn = tss.map(ts => {
|
||||
const entry = entries.find(x => ts === x.ts);
|
||||
if (!entry.ec) {
|
||||
missingEc.push(entry.ts);
|
||||
}
|
||||
if (!entry) {
|
||||
console.log("couldn't find ts", ts);
|
||||
return undefined;
|
||||
}
|
||||
if (entry.c && entry.c.includes("comp.")) {
|
||||
const complement = entries.find(x => entry.l === x.ts);
|
||||
return {
|
||||
entry,
|
||||
complement,
|
||||
};
|
||||
}
|
||||
return { entry };
|
||||
}).filter(x => x);
|
||||
if (missingEc.length !== 0) {
|
||||
console.log("missingEc", missingEc);
|
||||
}
|
||||
return toReturn;
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
module.exports = [
|
||||
{ ts: 1527812797, e: "woman" }, // xudza
|
||||
{ ts: 1527816466, e: `peace` }, // صلح - sUlha
|
||||
{ ts: 1527816589, e: `plan` }, // طرح - tarha
|
||||
{ ts: 1589023873660, e: `victory, conquest` }, // فتح - fathá
|
||||
{ ts: 1527813791, e: `permission` }, // اجازه - ijaaza
|
||||
{ ts: 1614083533098, e: `agenda` }, // اجنډه - ajanDa
|
||||
{ ts: 1527811425, e: "door" }, // darwaaza
|
||||
{ ts: 1527816215, e: `administration, management, directorate` }, // اداره - idaara
|
||||
{ ts: 1527812687, e: `continuation` }, // ادامه - idaama
|
||||
{ ts: 1527811661, e: `base, army post, (air) port` }, // اډه - aDa
|
||||
{ ts: 1527814310, e: `evaluation, appraisal, assessment` }, // ارزونه - arzawuna
|
||||
{ ts: 1527821380, e: `saw (the tool)` }, // اره - ara
|
||||
{ ts: 1527822277, e: `mare, female horse; fever` }, // اسپه - aspa
|
||||
{ ts: 1527814922, e: `addition, add-on, augmentation` }, // اضافه - izaafa
|
||||
{ ts: 1527822458, e: `expression` }, // افاده - ifaada
|
||||
{ ts: 1527813303, e: `myth, legend, fairy tale` }, // افسانه - afsaana
|
||||
{ ts: 1527822494, e: `cheek` }, // انانګه - anaangá
|
||||
{ ts: 1527817225, e: `measure, dimension, extent, scale` }, // اندازه - andaaza
|
||||
{ ts: 1527813759, e: `worry, concern, fear` }, // اندېښنه - andexna
|
||||
{ ts: 1527815787, e: `shoulder` }, // اوږه - ooGá
|
||||
{ ts: 1527813787, e: `tear (from eye)` }, // اوښکه - ooxka
|
||||
{ ts: 1527819927, e: `liver` }, // اینه - éena
|
||||
{ ts: 1527816261, e: `wallet` }, // بټوه - baTwa
|
||||
{ ts: 1527812001, e: `poriton, part, share` }, // برخه - barkha
|
||||
{ ts: 1578009902092, e: `veil, burka` }, // برقه - bUrqá
|
||||
{ ts: 1527816994, e: `program` }, // برنامه - barnaama
|
||||
{ ts: 1579294091093, e: `balcony, veranda, porch` }, // برنډه - baranDá
|
||||
{ ts: 1527823617, e: `crime, offense, sin, guilt, fault` }, // بزه - bazá
|
||||
{ ts: 1527823619, e: `moth` }, // بزه - bUzá
|
||||
{ ts: 1527823620, e: `patch (in a garment)` }, // بزه - bza
|
||||
{ ts: 1591026261598, e: `she-goat` }, // بزه - buza
|
||||
{ ts: 1574188090133, e: `contribution, donation, gift, charity` }, // بسپنه - baspuna
|
||||
{ ts: 1527816590, e: `sufficiency, to have enough or get by` }, // بسنه - basuna
|
||||
{ ts: 1593852212828, e: `fear, fright` }, // بېره - béra
|
||||
{ ts: 1527815862, e: `speed, rush, hurry, urgency` }, // بېړه - beRa
|
||||
{ ts: 1527815156, e: `leaf` }, // پاڼه - paaNa
|
||||
{ ts: 1527813481, e: `project` }, // پروژه - projza
|
||||
{ ts: 1527818409, e: `process` }, // پروسه - purosa
|
||||
{ ts: 1527815192, e: `decision` }, // پرېکړه - prékRa
|
||||
{ ts: 1527822412, e: `nose` }, // پزه - páza
|
||||
{ ts: 1527816124, e: `foot` }, // پښه - pxa
|
||||
{ ts: 1527815155, e: `pretext, excuse` }, // پلمه - palma
|
||||
{ ts: 1566469328688, e: `fan` }, // پنکه - panka
|
||||
{ ts: 1527815184, e: `question` }, // پوښتنه - poxtuna
|
||||
{ ts: 1527822437, e: `shelf, niche` }, // تاخچه - taakhchá
|
||||
{ ts: 1527814974, e: `fever` }, // تبه - tuba
|
||||
{ ts: 1527815332, e: `expectation` }, // تمه - tama
|
||||
{ ts: 1527815716, e: `stone, rock` }, // تیږه - teeGa
|
||||
{ ts: 1582390417084, e: `escape, flight, running away` }, // تېښته - téxta
|
||||
{ ts: 1527822268, e: `carriage, buggy` }, // ټانګه - Taangá
|
||||
{ ts: 1527812014, e: `society, association, gathering, assembly, congregation` }, // ټولنه - Toluna
|
||||
{ ts: 1527816696, e: `sentence; whole, total, sum` }, // جمله - jUmla
|
||||
{ ts: 1527820504, e: `land, earth, ground` }, // ځمکه - dzmuka
|
||||
{ ts: 1527815497, e: `face, picture` }, // څېره - tsera
|
||||
{ ts: 1527811993, e: `attack, assault` }, // حمله - hamla
|
||||
{ ts: 1527812720, e: `language` }, // ژبه - jzúba, jzíba
|
||||
{ ts: 1527812052, e: `brick, cinder-block` }, // خښته - khuxta
|
||||
{ ts: 1527813475, e: `minute` }, // دقیقه - daqeeqa
|
||||
{ ts: 1527812542, e: `break, rest` }, // دمه - dama
|
||||
{ ts: 1527812085, e: `obligation, duty, responsibility; job, work, position` }, // دنده - danda
|
||||
{ ts: 1527822847, e: `jaw` }, // ژامه - jzaamá
|
||||
{ ts: 1527815278, e: `night` }, // شپه - shpa
|
||||
{ ts: 1527813145, e: `tribe` }, // قبیله - qabeela
|
||||
{ ts: 1566653299904, e: `camara` }, // کمره - kamara
|
||||
{ ts: 1527812825, e: `street` }, // کوڅه - kootsa
|
||||
{ ts: 1527812756, e: `banana` }, // کېله - kela
|
||||
{ ts: 1527812859, e: `game, match` }, // لوبه - lóba
|
||||
{ ts: 1527819087, e: `defeat` }, // ماته - maata
|
||||
{ ts: 1588076706989, e: `distance, span` }, // مسافه - masaafá
|
||||
{ ts: 1527818358, e: `apple` }, // مڼه - maNá
|
||||
{ ts: 1527812901, e: `stomach` }, // مېده - meda
|
||||
{ ts: 1527813387, e: `gluing, joining, wrangle, quarrel, fighting, skirmish, battle` }, // نښته - nuxúta
|
||||
{ ts: 1527815110, e: `sign, mark, indication` }, // نښه - náxa, núxa
|
||||
{ ts: 1527813391, e: `date (as in time)` }, // نېټه - neTa
|
||||
{ ts: 1527811429, e: `graveyard, cemetery` }, // هدیره - hadeera
|
||||
{ ts: 1527814323, e: `gift, present, donation, contribution` }, // هدیه - hadiya
|
||||
{ ts: 1527812655, e: `week` }, // هفته - hafta
|
||||
{ ts: 1527812681, e: `agreement` }, // هوکړه - hókRa
|
||||
{ ts: 1578343468611, e: `tendon, sinew; hamstring` }, // واڼه - wáaNa
|
||||
{ ts: 1527822717, e: `snow` }, // واوره - wáawra
|
||||
{ ts: 1527811207, e: `eyebrow` }, // وروځه - wróodza
|
||||
{ ts: 1527816375, e: `niece; brother's daughter` }, // ورېره - wrera
|
||||
{ ts: 1527822259, e: `breeze, light wind` }, // وږمه - waGmá
|
||||
{ ts: 1527814719, e: `weapons, firearms, artillery` }, // وسله - wasla
|
||||
{ ts: 1527823717, e: `cloth, fabric, material, clothing, garment` }, // کپړه - kapRá
|
||||
{ ts: 1527816257, e: `notebook, little book` }, // کتابچه - kitaabcha
|
||||
{ ts: 1527820050, e: `bag, purse` }, // کڅوړه - katsóRa
|
||||
{ ts: 1527813252, e: `line, trace` }, // کرښه - kurxa
|
||||
{ ts: 1527823590, e: `sphere, globe` }, // کره - kará
|
||||
{ ts: 1527823591, e: `shovel, scraper, scoop` }, // کره - kára
|
||||
{ ts: 1527815884, e: `criticism` }, // کره کتنه - karakatuna
|
||||
{ ts: 1527823035, e: `whip` }, // کروړه - karoRá
|
||||
{ ts: 1527816870, e: `farmland` }, // کرونده - karwanda
|
||||
{ ts: 1527817371, e: `lament, mourning aloud, wail, cry (also out of hapiness)` }, // کریږه - kreeGa
|
||||
{ ts: 1598119732734, e: `bitter melon` }, // کرېله - karelá
|
||||
{ ts: 1527820606, e: `cave, cavern` }, // سمڅه - smútsa
|
||||
{ ts: 1527815249, e: `song, poem, verse` }, // سندره - sandura
|
||||
{ ts: 1591034128816, e: `mistake, error, blunder, fault` }, // سهوه - sáhwa
|
||||
{ ts: 1527814370, e: `nostril` }, // سوږمه - soGma
|
||||
{ ts: 1527817498, e: `famine, starvation, serious hunger/lack of food, drought, crop failure` }, // سوکړه - sookRá
|
||||
];
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527813115, e: "claim" }, // ادعا - idaa
|
||||
{ ts: 1527818119, e: "stick, walking staff, walking stick, crutch" }, // امسا - amsaa
|
||||
{ ts: 1527815043, e: "punishment, retribution" }, // جزا - jazaa
|
||||
{ ts: 1527819022, e: "well, water-hole" }, // څا - tsaa
|
||||
{ ts: 1527814225, e: "mistake, error, blunder" }, // خطا - khataa
|
||||
{ ts: 1610797589510, e: "cavity, emptiness, vacuum, empty space, space (as in planets etc.)" }, // خلا - khaláa
|
||||
{ ts: 1527812582, e: "prayer" }, // دعا - dUaa
|
||||
{ ts: 1527813415, e: "medicine, medication" }, // دوا - dawaa
|
||||
{ ts: 1527812272, e: "light, glory" }, // رڼا - raNaa
|
||||
{ ts: 1527823245, e: "dream, vision" }, // رویا - rooyáa
|
||||
{ ts: 1586596579414, e: "council (an institution)" }, // شورا - shooraa
|
||||
{ ts: 1527815984, e: "beauty" }, // ښکلا - xkulaa
|
||||
{ ts: 1527817670, e: "theft, robbery, stealing" }, // غلا - ghlaa
|
||||
{ ts: 1527814362, e: "cow" }, // غوا - ghwaa
|
||||
{ ts: 1585487002625, e: "castle, fort, fortress" }, // قلا - qaláa
|
||||
{ ts: 1527812048, e: "meaning, sense, spirit" }, // مانا - maanaa
|
||||
{ ts: 1527815483, e: "back (body part)" }, // ملا - mlaa
|
||||
{ ts: 1527812230, e: "friendship" }, // ملګرتیا - malgurtiyaa
|
||||
{ ts: 1527812910, e: "hospitality; invitation, event, party, banquet, reception" }, // مېلمستیا - melmastiyaa
|
||||
{ ts: 1617781446945, e: "sickness, illness" }, // ناجوړتیا - naajoRtiyaa, naajoRtyaa
|
||||
{ ts: 1527815120, e: "grandmother" }, // نیا - niyaa
|
||||
{ ts: 1527811740, e: "incompleteness, default, shortcoming" }, // نیمګړتیا - neemguRtiyaa
|
||||
{ ts: 1527821040, e: "plague, cholera" }, // وبا - wabáa
|
||||
{ ts: 1527823534, e: "ability, capacity, capability, power, volumeá" }, // وړتیا - waRtiyáa
|
||||
{ ts: 1610443988250, e: "division, distribution" }, // وېشلتیا - weshiltyaa, weshiltiyaa
|
||||
{ ts: 1527816806, e: "speech, statement" }, // وینا - waynaa
|
||||
];
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527815197, e: "Pashtun" }, // پښتون
|
||||
{ ts: 1527813148, e: "lying" }, // پروت
|
||||
{ ts: 1574867531681, e: "mature, ripe, cooked" }, // پوخ
|
||||
{ ts: 1576952412644, e: "soft" }, // پوست
|
||||
{ ts: 1527815366, e: "bitter" }, // تریخ
|
||||
{ ts: 1527818789, e: "sour" }, // تریو
|
||||
// { ts: 1527815333, e: "'tandoor'" }, // تنور
|
||||
{ ts: 1527817664, e: "hot" }, // تود
|
||||
// { ts: 1577408901204, e: "knee" }, // ځنګون
|
||||
{ ts: 1527816071, e: "spread" }, // خپور
|
||||
{ ts: 1574865652928, e: "sweet" }, // خوږ
|
||||
{ ts: 1527813499, e: "heavy" }, // دروند
|
||||
{ ts: 1527813943, e: "returned, come back" }, // راستون
|
||||
{ ts: 1576596860977, e: "clear, bright" }, // روڼ
|
||||
{ ts: 1527811971, e: "blind" }, // ړوند
|
||||
{ ts: 1527815451, e: "old" }, // زوړ
|
||||
// { ts: 1527815845, e: "life" }, // ژوندون
|
||||
{ ts: 1527815300, e: "rider, mounted" }, // سپور
|
||||
{ ts: 1527819505, e: "being (in a place after returning, coming back etc.)" }, // ستون
|
||||
{ ts: 1600080053835, e: "riding, mounted" }, // سور
|
||||
{ ts: 1527813068, e: "cold" }, // سوړ
|
||||
{ ts: 1575924767041, e: "shepherd" }, // شپون
|
||||
// { ts: 1610448014063, e: "large flat basket" }, // شکور
|
||||
{ ts: 1527813172, e: "bent" }, // کوږ
|
||||
{ ts: 1527811973, e: "deaf" }, // کوڼ
|
||||
// { ts: 1527823497, e: "intestines" }, // لړمون
|
||||
// { ts: 1527813809, e: "namaz" }, // لمونځ
|
||||
{ ts: 1527817123, e: "wet" }, // لومد
|
||||
{ ts: 1527817117, e: "wet" }, // لوند
|
||||
{ ts: 1576889120767, e: "wet" }, // لوند
|
||||
{ ts: 1527812927, e: "full, satisfied" }, // موړ
|
||||
{ ts: 1527812908, e: "guest" }, // مېلمه
|
||||
{ ts: 1579463171333, e: "cleansed" }, // نوږ
|
||||
{ ts: 1576113803291, e: "small" }, // ووړ
|
||||
{ ts: 1527819244, e: "host" }, // کوربه
|
||||
{ ts: 1527812908, e: "guest" }, // مېلمه
|
||||
];
|
|
@ -0,0 +1,18 @@
|
|||
module.exports = [
|
||||
{ ts: 1527814150, e: `road, way, path` }, // لار - laar
|
||||
{ ts: 1527815417, e: `day` }, // ورځ - wradz
|
||||
{ ts: 1527812922, e: `month` }, // میاشت - miyaasht
|
||||
{ ts: 1527823306, e: `elbow` }, // څنګل - tsangúl
|
||||
{ ts: 1527813824, e: `bosom, breast; wrestling` }, // غېږ - gheG
|
||||
{ ts: 1527820524, e: `pelt, skin, hide, leather` }, // څرمن - tsarmún
|
||||
{ ts: 1527814147, e: `blanket, coving, quilt` }, // بړستن - bRastun
|
||||
{ ts: 1527818707, e: `wedge; gusset (in a shirt)` }, // ترخځ - turkhúdz
|
||||
{ ts: 1527822792, e: `narrow mattress used as a bed or a couch, reversible rug` }, // توشک - toshák
|
||||
{ ts: 1527813294, e: `comb` }, // ږمنځ - Gmundz
|
||||
{ ts: 1527811580, e: `needle, injection; pillar, mast` }, // ستن - stun
|
||||
{ ts: 1527815779, e: `swearing, name-calling, verbal abuse, bad language` }, // کنځل - kundzul
|
||||
{ ts: 1527817456, e: `skirt, portion of clothing hanging down from the waist; foot, base (eg. of a mountain)` }, // لمن - lamun
|
||||
{ ts: 1527822725, e: `span` }, // لوېشت - lwesht
|
||||
{ ts: 1527811609, e: `claw, paw` }, // منګل - mangul
|
||||
{ ts: 1527821684, e: `cloud` }, // ورېځ - wurédz
|
||||
]
|
|
@ -0,0 +1,102 @@
|
|||
module.exports = [
|
||||
{ ts: 1527812432, e: `sky, heaven` }, // آسمان - aasmaan
|
||||
{ ts: 1527812431, e: `mango` }, // آم - aam
|
||||
{ ts: 1527812434, e: `sound, voice` }, // آواز - aawaaz
|
||||
{ ts: 1527816724, e: `room, chamber` }, // اتاق - Utaaq
|
||||
{ ts: 1527811859, e: `union, alliance` }, // اتحاد - itihaad
|
||||
{ ts: 1527822033, e: `joining, connection, contiguity, junction` }, // اتصال - ittisáal
|
||||
{ ts: 1527811858, e: `unity, alliance, agreement, understanding, consent; coincidence` }, // اتفاق - itifaaq
|
||||
{ ts: 1527813560, e: `accusation, charge, indictment` }, // اتهام - itihaam
|
||||
{ ts: 1527812105, e: `respect, honor, esteem, deference` }, // احترام - ihtiraam
|
||||
{ ts: 1527819653, e: `possibility, probability, likelihood` }, // احتمال - ihtimaal
|
||||
{ ts: 1527812689, e: `need, requirement` }, // احتیاج - ihtiyaaj
|
||||
{ ts: 1527812690, e: `caution` }, // احتیاط - ihtiyaat
|
||||
{ ts: 1527813782, e: `feeling, sensation, emotion` }, // احساس - ahsaas
|
||||
{ ts: 1527817303, e: `objection, protest` }, // اعتراض - itiraaz
|
||||
{ ts: 1527813418, e: `influence, effect, affect, action` }, // اغېز - aghez
|
||||
{ ts: 1527816625, e: `disaster` }, // افت - afat
|
||||
{ ts: 1527813558, e: `accusation, charge, blame` }, // الزام - ilzaam
|
||||
{ ts: 1527815388, e: `hope, expectation` }, // امید - Umeed
|
||||
{ ts: 1527812453, e: `picture, painting, image` }, // انځور - andzoor
|
||||
{ ts: 1527813827, e: `fire, flame` }, // اور - or
|
||||
{ ts: 1527814787, e: `rain` }, // باران - baaraan
|
||||
{ ts: 1527817293, e: `roof` }, // بام - baam
|
||||
{ ts: 1527814849, e: `eggplant` }, // بانجن - baanjan
|
||||
{ ts: 1527814106, e: `crisis` }, // بحران - bUhraan
|
||||
{ ts: 1527814885, e: `fortune, luck, fate` }, // بخت - bakht
|
||||
{ ts: 1527811281, e: `garden` }, // بڼ - baN
|
||||
{ ts: 1624039195280, e: `scholarship` }, // بورس - boors
|
||||
{ ts: 1527816877, e: `flag` }, // بیرغ - beyragh
|
||||
{ ts: 1527820423, e: `passport` }, // پاسپورټ - paasporT
|
||||
{ ts: 1527813224, e: `bridge` }, // پل - pUl
|
||||
{ ts: 1527813480, e: `plan` }, // پلان - plaan
|
||||
{ ts: 1527815199, e: `central-asian/middle-eastern rice dish, pilaf` }, // پلاو - pulaaw
|
||||
{ ts: 1527815185, e: `loan, debt` }, // پور - por
|
||||
{ ts: 1527815176, e: `onion` }, // پیاز - piyaaz
|
||||
{ ts: 1527815171, e: `start` }, // پیل - peyl
|
||||
{ ts: 1527816610, e: `crown, crest` }, // تاج - taaj
|
||||
{ ts: 1527822373, e: `vine; mouthful` }, // تاک - taak
|
||||
{ ts: 1527815326, e: `confirmation` }, // تایید - taayeed
|
||||
{ ts: 1527815357, e: `seed` }, // تخم - tUkhum
|
||||
{ ts: 1527821586, e: `pity, sympathy` }, // ترحم - tarahhÚm
|
||||
{ ts: 1527811389, e: `picture` }, // تصویر - tasweer
|
||||
{ ts: 1527814679, e: `guarantee, insurance, security` }, // تضمین - tazmeen
|
||||
{ ts: 1527814258, e: `speech, lecture` }, // تقریر - taqreer
|
||||
{ ts: 1527821670, e: `cheating, deception, fraud, forgery` }, // تقلب - taqalÚb
|
||||
{ ts: 1527811602, e: `attempt, aspiration, intention, effort` }, // تکل - takál
|
||||
{ ts: 1527813398, e: `movement, motion, going` }, // تګ - tug, tag
|
||||
{ ts: 1527822126, e: `anniversary` }, // تلین - tleen
|
||||
{ ts: 1527811308, e: `contact, touch` }, // تماس - tamaas
|
||||
{ ts: 1527817900, e: `body, flesh` }, // تن - tan
|
||||
{ ts: 1527821061, e: `contrast, opposition, contradiction` }, // تناقض - tanaaqÚz
|
||||
{ ts: 1527822387, e: `rope, cord; a measurement of ground or distances` }, // تناو - tanáaw
|
||||
{ ts: 1527818995, e: `lightning` }, // تندر - tandúr
|
||||
{ ts: 1527815362, e: `ball; (cannon) ball` }, // توپ - top
|
||||
{ ts: 1527816820, e: `spit` }, // توک - took
|
||||
{ ts: 1527816520, e: `family, clan, tribe, people` }, // ټبر - Tabar
|
||||
{ ts: 1527811348, e: `wound` }, // ټپ - Tap
|
||||
{ ts: 1527819566, e: `piece, part; cloth, fabric` }, // ټکر - TUkúr
|
||||
{ ts: 1527812213, e: `mosque` }, // جمات - jUmaat
|
||||
{ ts: 1527811705, e: `structure` }, // جوړښت - joRuxt
|
||||
{ ts: 1527814058, e: `answer, reply` }, // ځواب - dzawaab
|
||||
{ ts: 1527816887, e: `life, existence, energy, force` }, // ځواک - dzwaak
|
||||
{ ts: 1527814649, e: `market square, crossroads, paved area in front of entrance` }, // چوک - chok
|
||||
{ ts: 1527815065, e: `hammer` }, // څټک - tsaTak, tsTuk
|
||||
{ ts: 1527814589, e: `side` }, // څنګ - tsang
|
||||
{ ts: 1527816228, e: `boundary, limit, extent` }, // حد - had
|
||||
{ ts: 1527813749, e: `government, reign, rule` }, // حکومت - hUkoomat
|
||||
{ ts: 1527814125, e: `solution` }, // حل - hal
|
||||
{ ts: 1527818703, e: `shirt` }, // خت - khut
|
||||
{ ts: 1527813804, e: `sleep, dream` }, // خوب - khob
|
||||
{ ts: 1527812815, e: `safety, security` }, // خوندیتوب - khwundeetob
|
||||
{ ts: 1527813763, e: `religion, faith` }, // دین - deen
|
||||
{ ts: 1527811517, e: `journey, travel` }, // سفر - safar
|
||||
{ ts: 1527815389, e: `age, life` }, // عمر - Úmur
|
||||
{ ts: 1527816746, e: `tooth` }, // غاښ - ghaax
|
||||
{ ts: 1527812631, e: `ear` }, // غوږ - ghwuG, ghwaG
|
||||
{ ts: 1527812265, e: `decree, order` }, // فرمان - farmaan
|
||||
{ ts: 1527817205, e: `film, movie` }, // فلم - film
|
||||
{ ts: 1527812727, e: `year` }, // کال - kaal
|
||||
{ ts: 1527812817, e: `book` }, // کتاب - kitaab
|
||||
{ ts: 1527812611, e: `step, move` }, // ګام - gaam
|
||||
{ ts: 1527812641, e: `rose, flower` }, // ګل - gUl
|
||||
{ ts: 1527812650, e: `threat, danger, challeng` }, // ګواښ - gwaax
|
||||
{ ts: 1527813521, e: `mourning, grief, grieving, deep sorrow` }, // ماتم - maatam
|
||||
{ ts: 1527812176, e: `evening` }, // ماښام - maaxaam
|
||||
{ ts: 1527813601, e: `death` }, // مرګ - marg
|
||||
{ ts: 1527817691, e: `future` }, // مستقبل - mUstaqbil
|
||||
{ ts: 1527811866, e: `damage, defect, loss` }, // نقصان - nUqsaan
|
||||
{ ts: 1527815122, e: `name` }, // نوم - noom
|
||||
{ ts: 1527812661, e: `boy, young lad` }, // هلک - halík, halúk
|
||||
{ ts: 1566476070874, e: `street, road` }, // واټ - waaT
|
||||
{ ts: 1527816036, e: `authority, power` }, // واک - waak
|
||||
{ ts: 1527815400, e: `time` }, // وخت - wakht
|
||||
{ ts: 1527818582, e: `building, prosperity, habitable state` }, // ودانښت - wadaanuxt
|
||||
{ ts: 1527811441, e: `door, gate, entrance` }, // ور - war
|
||||
{ ts: 1527815406, e: `homeland, home country` }, // وطن - watán
|
||||
{ ts: 1573149648251, e: `fellow country-man` }, // وطن وال - watanwaal
|
||||
{ ts: 1586428847646, e: `national (person), a citizen or person of that land` }, // وطنوال - watanwáal
|
||||
{ ts: 1527822208, e: `bat, coward, pipsqueak, hesitant person` }, // وطواط - watwáat
|
||||
{ ts: 1527819571, e: `apprehension, anxiety, suspicion; imagination, whims, some problem made up in someone’s head` }, // وهم - wáhum, wahm
|
||||
{ ts: 1527816332, e: `pride, glory` }, // ویاړ - wyaaR
|
||||
];
|
|
@ -0,0 +1,128 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527815408, e: "asleep" }, // ویده - weedú
|
||||
{ ts: 1527812796, e: "good" }, // ښه - xu
|
||||
{ ts: 1527821744, e: "cook, chef" }, // آشپز - aashpáz
|
||||
{ ts: 1527812461, e: "hero, brave" }, // اتل - atul
|
||||
{ ts: 1527821649, e: "impressive, effective, influencing" }, // اثرناک - asarnáak
|
||||
{ ts: 1527818704, e: "wide, spacious, extensive" }, // ارت - arát
|
||||
{ ts: 1578340121962, e: "free, independant" }, // ازاد - azáad
|
||||
{ ts: 1527819418, e: "independant, autonomous" }, // خپلواک - khpulwaak
|
||||
{ ts: 1527817146, e: "resident; settled" }, // استوګن - astogan
|
||||
{ ts: 1527813713, e: "hopeful, pregnant" }, // امیدوار - Umeedwaar
|
||||
{ ts: 1527819451, e: "Englishman, English (adjective)" }, // انګرېز - angréz
|
||||
{ ts: 1527820346, e: "on-line" }, // انلاین - anlaayn
|
||||
{ ts: 1527813667, e: "important" }, // اهم - aham
|
||||
{ ts: 1598724912198, e: "dry" }, // اوچ - ooch
|
||||
{ ts: 1527815138, e: "insurgent" }, // اورپک - orpak
|
||||
{ ts: 1586452587974, e: "free, available" }, // اوزګار - oozgáar
|
||||
{ ts: 1527816489, e: "faithful, believer" }, // ایماندار - eemaandaar
|
||||
{ ts: 1527820433, e: "valiant" }, // باتور - baatóor
|
||||
{ ts: 1527813425, e: "stingy" }, // بخیل - bakheel
|
||||
{ ts: 1527812511, e: "bad" }, // بد - bud, bad
|
||||
{ ts: 1527812518, e: "equal, even, set up" }, // برابر - buraabur
|
||||
{ ts: 1527811861, e: "naked" }, // بربنډ - barbunD
|
||||
{ ts: 1527811511, e: "full, complete" }, // بشپړ - bushpuR
|
||||
{ ts: 1527812515, e: "other, next" }, // بل - bul
|
||||
{ ts: 1527815725, e: "knowledgeable, accustomed" }, // بلد - balad
|
||||
{ ts: 1577301753727, e: "closed" }, // بند - band
|
||||
{ ts: 1527812490, e: "useless" }, // بې کار - be kaar
|
||||
{ ts: 1527812031, e: "separate, different" }, // بېل - bel
|
||||
{ ts: 1527815144, e: "clean, pure" }, // پاک - paak
|
||||
{ ts: 1527815201, e: "hidden" }, // پټ - puT
|
||||
{ ts: 1527815179, e: "wide" }, // پلن - plun
|
||||
{ ts: 1527819059, e: "thick, fat" }, // پنډ - punD
|
||||
{ ts: 1611767359178, e: "compassionate" }, // ترسناک - tarsnáak
|
||||
{ ts: 1527813270, e: "sour" }, // تروش - troosh
|
||||
{ ts: 1527813817, e: "narrow, cramped" }, // تنګ - tang
|
||||
{ ts: 1527816354, e: "ready" }, // تیار - tayaar
|
||||
{ ts: 1527817056, e: "sharp, fast" }, // تېز - tez
|
||||
{ ts: 1527814076, e: "societal, social" }, // ټولنیز - Toluneez
|
||||
{ ts: 1527819864, e: "low" }, // ټیټ - TeeT
|
||||
{ ts: 1527811894, e: "firm, tough, rigid" }, // ټینګ - Teeng
|
||||
{ ts: 1527812943, e: "constant, stable, proven" }, // ثابت - saabit
|
||||
{ ts: 1527813085, e: "heavy, difficult" }, // ثقیل - saqeel
|
||||
{ ts: 1527820479, e: "ignorant" }, // جاهل - jaahíl
|
||||
{ ts: 1588160800930, e: "surgeon" }, // جراح - jarráah
|
||||
{ ts: 1527812707, e: "high, tall" }, // جګ - jig, jug
|
||||
{ ts: 1527816944, e: "clear, evident" }, // جوت - jawat
|
||||
{ ts: 1527822996, e: "alongside, adjoining" }, // جوخت - jokht
|
||||
{ ts: 1527812711, e: "well, healthy" }, // جوړ - joR
|
||||
{ ts: 1527816323, e: "shining, sparkling" }, // ځلاند - dzalaand
|
||||
{ ts: 1527812291, e: "young, youthful" }, // ځوان - dzwaan
|
||||
{ ts: 1527820112, e: "hanging" }, // ځوړند - dzwáRund
|
||||
{ ts: 1527819672, e: "crafty" }, // چالاک - chaaláak
|
||||
{ ts: 1527811230, e: "quick, fast" }, // چټک - chaTak
|
||||
{ ts: 1527812524, e: "started, in motion" }, // چلان - chalaan
|
||||
{ ts: 1527815370, e: "clear, apparent" }, // څرګند - tsărgund
|
||||
{ ts: 1576366107077, e: "straight, upright" }, // څک - tsak
|
||||
{ ts: 1527812113, e: "present, on hand, ready" }, // حاضر - haazir, haazur
|
||||
{ ts: 1527820699, e: "pregnant, carrying" }, // حامل - haamíl
|
||||
{ ts: 1527819824, e: "greedy" }, // حریص - harées
|
||||
{ ts: 1527812669, e: "sensitive" }, // حساس - hasaas
|
||||
{ ts: 1527812057, e: "raw, unripe" }, // خام - khaam
|
||||
{ ts: 1527811523, e: "traitor, treacherous" }, // خاین - khaayin
|
||||
{ ts: 1527814219, e: "relative, one's own" }, // خپل - khpul
|
||||
{ ts: 1527812795, e: "relative" }, // خپلوان - khpulwaan
|
||||
{ ts: 1527812808, e: "poor, miserable" }, // خوار - khwaar
|
||||
{ ts: 1527814880, e: "tall" }, // دنګ - dung
|
||||
{ ts: 1527812537, e: "assured" }, // ډاډمن - DaaDmun
|
||||
{ ts: 1527812583, e: "full" }, // ډک - Duk
|
||||
{ ts: 1527822674, e: "gaunt" }, // ډنګر - Dungár, Dangár
|
||||
{ ts: 1527817256, e: "sunk" }, // ډوب - Doob
|
||||
{ ts: 1527814277, e: "healthy" }, // روغ - rogh
|
||||
{ ts: 1609780006604, e: "fruitful" }, // زرخېز - zarkhéz
|
||||
{ ts: 1527817116, e: "green, flourishing" }, // زرغون - zarghoon
|
||||
{ ts: 1527814026, e: "golden" }, // زرین - zareen
|
||||
{ ts: 1567594312839, e: "brave" }, // زړه ور - zuRawár
|
||||
{ ts: 1527815848, e: "committed" }, // ژمن - jzman
|
||||
{ ts: 1527813498, e: "light" }, // سپک - spuk
|
||||
{ ts: 1578329248464, e: "white" }, // سپین - speen
|
||||
{ ts: 1527811860, e: "great" }, // ستر - stur
|
||||
{ ts: 1527820178, e: "problematic" }, // ستونزمن - stoonzmán
|
||||
{ ts: 1527815246, e: "difficult" }, // سخت - sakht
|
||||
{ ts: 1527817262, e: "barren" }, // شنډ - shanD
|
||||
{ ts: 1527813426, e: "stingy" }, // شوم - shoom
|
||||
{ ts: 1527812625, e: "big" }, // غټ - ghuT, ghaT
|
||||
{ ts: 1527811846, e: "successful" }, // کامیاب - kaamyaab
|
||||
{ ts: 1527823678, e: "lazy" }, // کاهل - kaahíl
|
||||
{ ts: 1527814896, e: "proud, arrogant" }, // کبرجن - kaburjun
|
||||
{ ts: 1527813117, e: "firm, solid" }, // کلک - klak, kluk
|
||||
{ ts: 1578769492475, e: "few, little" }, // کم - kam
|
||||
// { ts: 1527814253, e: "mixed up" }, // ګډ وډ // TODO: FIX INFLECTION MACHINE FOR DOUBLES!
|
||||
{ ts: 1578769409512, e: "weak" }, // کمزور - kamzór
|
||||
{ ts: 1527812639, e: "dear, difficult" }, // ګران - graan
|
||||
{ ts: 1527816786, e: "all" }, // ګرد - gurd
|
||||
{ ts: 1527814811, e: "warm, hot" }, // ګرم - garm, garum
|
||||
{ ts: 1527817662, e: "guilty" }, // ګرم - gram
|
||||
{ ts: 1527812308, e: "thick, lots" }, // ګڼ - gaN
|
||||
{ ts: 1527813848, e: "desiring, eager" }, // لېوال - lewaal
|
||||
{ ts: 1527816011, e: "broken" }, // مات - maat
|
||||
{ ts: 1527812881, e: "child" }, // ماشوم - maashoom
|
||||
{ ts: 1527817007, e: "known" }, // مالوم - maaloom
|
||||
{ ts: 1527814321, e: "positive" }, // مثبت - mUsbat
|
||||
{ ts: 1527811264, e: "condemned" }, // محکوم - mahkoom
|
||||
{ ts: 1527814802, e: "foul" }, // مردار - mUrdáar
|
||||
{ ts: 1527821812, e: "arrogant" }, // مغرور - maghróor
|
||||
{ ts: 1527820222, e: "lying down" }, // ملاست - mlaast
|
||||
{ ts: 1527814344, e: "important" }, // مهم - mUhím
|
||||
{ ts: 1527816033, e: "uncommon" }, // نادر - naadir
|
||||
{ ts: 1527815106, e: "sitting, seated" }, // ناست - naast
|
||||
{ ts: 1527815127, e: "nurse" }, // نرس - nurs
|
||||
{ ts: 1527821673, e: "moist, damp, wet" }, // نمجن - namjún
|
||||
{ ts: 1527815130, e: "dry, land, ground" }, // وچ - wuch, wUch
|
||||
{ ts: 1527817486, e: "ruined, destroyed; destructive, bad, naughty" }, // وران - wraan
|
||||
{ ts: 1527814373, e: "lost" }, // ورک - wruk
|
||||
{ ts: 1527822838, e: "decayed, spoiled, rotten" }, // وروست - wrost
|
||||
{ ts: 1609949334478, e: "roasted" }, // وریت - wreet
|
||||
{ ts: 1527811544, e: "standing" }, // ولاړ - waláaR, wuláaR
|
||||
{ ts: 1527815498, e: "aforementioned" }, // یاد - yaad
|
||||
{ ts: 1527815434, e: "cold" }, // یخ - yakh, yukh
|
||||
];
|
|
@ -0,0 +1,25 @@
|
|||
module.exports = [
|
||||
{ ts: 1568926976497, e: `x-ray` }, // اکسرې - iksre
|
||||
{ ts: 1602179757779, e: `alphabet` }, // الف بې - alif be
|
||||
{ ts: 1527813840, e: `ashes` }, // ایرې - eere
|
||||
{ ts: 1527816692, e: `glasses, spectacles` }, // اینکې - aynake
|
||||
{ ts: 1527819286, e: `stairs, steps, staircase` }, // پاشتقې - paashtáqe
|
||||
{ ts: 1527816299, e: `money (plural of پېسې)` }, // پیسې - peyse
|
||||
{ ts: 1527814529, e: `buttermilk` }, // تروې - turwe
|
||||
{ ts: 1527816369, e: `widow, woman` }, // تورسرې - torsăre
|
||||
{ ts: 1577408787088, e: `sprey (as in a medicinal spray)` }, // سپرې - spre
|
||||
{ ts: 1527822255, e: `break of dawn, first light of day, sunrise` }, // سپېدې - spedé
|
||||
{ ts: 1626765107329, e: `chickenpox, chicken pox` }, // شرې - sharé
|
||||
{ ts: 1527815008, e: `milk` }, // شودې - shoode
|
||||
{ ts: 1527822131, e: `raw rice, unprocessed rice` }, // شولې - shole
|
||||
{ ts: 1527815009, e: `milk (plural of شيده)` }, // شیدې - sheede
|
||||
{ ts: 1527823571, e: `spit, saliva` }, // ښیالمې - xyaalmé
|
||||
{ ts: 1527816530, e: `sister in law` }, // ښینې - xeene
|
||||
{ ts: 1527823567, e: `spit, saliva, slobber, slime` }, // لاړې - laaRe
|
||||
{ ts: 1527822275, e: `dishes, pots, pans` }, // لوښې - looxe
|
||||
{ ts: 1617443138210, e: `urine, pee, piss` }, // مچیازې - michyaaze, muchyaaze
|
||||
{ ts: 1527814420, e: `yogurt` }, // مستې - maste
|
||||
{ ts: 1577999538077, e: `a sound/cry used to drive sheep on` }, // هرې - hire
|
||||
{ ts: 1586551382412, e: `rice` }, // وریژې - wreejze
|
||||
{ ts: 1527820261, e: `plow, plowing, plough, ploughing` }, // یوې - yuwe
|
||||
];
|
|
@ -0,0 +1,34 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527820771, e: "population, number of settlers; prosperity, well-being; organization of public services and amenities; construction" }, // آباداني - aabaadaanee
|
||||
{ ts: 1527813939, e: "freedom, independence" }, // آزادي - aazaadee
|
||||
{ ts: 1527818402, e: "championship; courage" }, // اتلولي - atalwalée
|
||||
{ ts: 1527814060, e: "ease" }, // اساني - asaanee
|
||||
{ ts: 1527821293, e: "preparation, readiness, planning" }, // امادګي - amaadagee
|
||||
{ ts: 1527819502, e: "kingship, kingdom, rule, throne, authority" }, // باچهي - baachahee
|
||||
{ ts: 1527820035, e: "dominion, holding sway over someone" }, // باداري - baadaaree
|
||||
{ ts: 1527817732, e: "misfortune, difficulty" }, // بدبختي - badbakhtee
|
||||
{ ts: 1588786872582, e: "shame, disrepute, dishonour" }, // بدنامي - badnaamee
|
||||
{ ts: 1573682378816, e: "sickness, illness" }, // بیماري - beemaaree
|
||||
{ ts: 1527816817, e: "cleanliness, hygiene" }, // پاکوالي - paakwaalee
|
||||
{ ts: 1586204619186, e: "righteousness, abstinence, self-control" }, // پرهېزګاري - parhezgaaree
|
||||
{ ts: 1584444376984, e: "patriarchy" }, // پلارواکي - plaarwaakee
|
||||
{ ts: 1527818744, e: "carpentry" }, // ترکاڼي - tarkaaNee
|
||||
{ ts: 1527815337, e: "consolation, comfort, satisfaction" }, // تسلي - tasallee
|
||||
{ ts: 1527819521, e: "happiness (خوشحالي)" }, // خوشالي - khoshaalee
|
||||
{ ts: 1527818037, e: "good fortune, good luck, hapiness" }, // خوشبختي - khooshbakhtee
|
||||
{ ts: 1527815914, e: "optimism" }, // خوشبیني - khooshbeenee
|
||||
{ ts: 1527811877, e: "friendship" }, // دوستي - dostee
|
||||
{ ts: 1527818019, e: "shopkeeping, retail store selling" }, // دوکانداري - dookaandaaree
|
||||
{ ts: 1527822080, e: "democracy" }, // دېموکراسي - demokraasee
|
||||
{ ts: 1527813462, e: "key" }, // کیلي - keelee
|
||||
{ ts: 1527814492, e: "cattle farming" }, // ګاوداري - gaawdaaree
|
||||
{ ts: 1610013679820, e: "brotherhood" }, // ورورولي - wrorwalée
|
||||
];
|
|
@ -0,0 +1,13 @@
|
|||
module.exports = [
|
||||
{ ts: 1527821971, e: `second wife of own husband` }, // بن - bun
|
||||
{ ts: 1527816397, e: `aunt` }, // ترور - tror
|
||||
{ ts: 1578704593901, e: `aunt (paternal uncle's wife)` }, // تندار - tandaar
|
||||
{ ts: 1527812785, e: `sister` }, // خور - khor
|
||||
{ ts: 1527812861, e: `daughter` }, // لور - loor
|
||||
{ ts: 1527812928, e: `mother, mom` }, // مور - mor
|
||||
{ ts: 1527812912, e: `lady, woman, wife` }, // مېرمن - mermán
|
||||
{ ts: 1527816476, e: `stepsister, half sister` }, // مېرېنۍ خور - merenuy khor
|
||||
{ ts: 1527823521, e: `daughter-in-law` }, // نږور - nGor
|
||||
{ ts: 1527816350, e: `brothers wife, sister-in-law` }, // ورندار - wrundaar
|
||||
{ ts: 1527816485, e: `wife of husbands brother, wife of brother-in-law` }, // یور - yor
|
||||
];
|
|
@ -0,0 +1,37 @@
|
|||
module.exports = [
|
||||
{ ts: 1527821817, e: `uncle (paternal)` }, // اکا - akáa
|
||||
{ ts: 1527816411, e: `father, grandfather (vocative or in child's speech)` }, // بابا - baabaa
|
||||
{ ts: 1527819439, e: `king, ruler, president, padishah` }, // باچا - baacháa
|
||||
{ ts: 1527823298, e: `sparrow-hawk, eagle` }, // باښه - baaxá
|
||||
{ ts: 1527817718, e: `slave, servant, a human, person (as in a slave of God)` }, // بنده - bandá
|
||||
{ ts: 1527815031, e: `prisoner, captive` }, // بندي - bandee
|
||||
{ ts: 1527815142, e: `king` }, // پاچا - paachaa
|
||||
{ ts: 1527817280, e: `leper` }, // جذامي - jUzaamee
|
||||
{ ts: 1527814236, e: `pot smoker, pothead, someone addicted to marijuana, pot, hash` }, // چرسي - charsee
|
||||
{ ts: 1578618561154, e: `Haji, someone who has gone on the Hajj` }, // حاجي - haajee
|
||||
{ ts: 1527821193, e: `supporter, protector, defender, patron, saviour` }, // حامي - haamee
|
||||
{ ts: 1591711877815, e: `washerman, someone who does the laundry` }, // دوبي - dobée
|
||||
{ ts: 1527820139, e: `rabab player, rubab player` }, // ربابي - rabaabee
|
||||
{ ts: 1619278755267, e: `troubling, pestering` }, // ربړنه - rabaRúna
|
||||
{ ts: 1577066022588, e: `cupbearer, butler, bartender, alchohol maker` }, // ساقي - saaqée
|
||||
{ ts: 1527822817, e: `soldier, warrior, guard` }, // سپاهي - sipaahee
|
||||
{ ts: 1527812975, e: `barber, hairdresser` }, // سلماني - salmaanee
|
||||
{ ts: 1527819414, e: `prince` }, // شاهزاده - shaahzaadá
|
||||
{ ts: 1527818084, e: `drinker, drunkard, alcoholic, wine-bibber` }, // شرابي - sharaabee
|
||||
{ ts: 1527821950, e: `prince` }, // شهزاده - shahzaadá
|
||||
{ ts: 1588158828142, e: `hunter` }, // ښکاري - xkaaree
|
||||
{ ts: 1527815206, e: `judge, religious authority/judge` }, // قاضي - qaazee
|
||||
{ ts: 1527818500, e: `contractor, supplier` }, // قراردادي - qaraardaadee
|
||||
{ ts: 1527816446, e: `paternal uncle, term of address for elderly man` }, // کاکا - kaakaa
|
||||
{ ts: 1595232159907, e: `begger, panhandler` }, // ګدا - gadáa
|
||||
{ ts: 1527816512, e: `elder brother, general form of familiar and respectful address` }, // لالا - laalaa
|
||||
{ ts: 1527812878, e: `uncle (maternal), respectful form of address` }, // ماما - maamaa
|
||||
{ ts: 1610556640847, e: `census` }, // مردمشماري - mărdamshUmaaree
|
||||
{ ts: 1527815484, e: `mullah, priest` }, // ملا - mUllaa
|
||||
{ ts: 1527821714, e: `parallel, matching, appropriate, identical` }, // موازي - mUwaazée
|
||||
{ ts: 1527816514, e: `shoemaker, shoe repairman, cobbler` }, // موچي - mochee
|
||||
{ ts: 1527823093, e: `prophet` }, // نبي - nabee
|
||||
{ ts: 1579041957559, e: `call, appeal, shout, summoning` }, // ندا - nadáa
|
||||
{ ts: 1527816253, e: `grandson` }, // نواسه - nawaasa
|
||||
{ ts: 1527819971, e: `governor` }, // والي - waalée
|
||||
];
|
|
@ -0,0 +1,133 @@
|
|||
module.exports = [
|
||||
{ ts: 1527818948, e: `sneezing, sneeze` }, // اټسکی - aTúskey
|
||||
{ ts: 1573681135691, e: `tribal constable, tribal offical with police powers` }, // اربکی - arbakéy
|
||||
{ ts: 1573659054031, e: `width, spaciousness` }, // ارتوالی - artwaaley, aratwaaley
|
||||
{ ts: 1527811890, e: `thorn, prickle` }, // ازغی - azghey
|
||||
{ ts: 1527817036, e: `representative, envoy, ambassador, commissioner` }, // استازی - astaazey
|
||||
{ ts: 1527816982, e: `residence, dwelling; hostel, dormitory` }, // استوګنځی - astogundzey
|
||||
{ ts: 1527818489, e: `yawn, sigh, deep breath, shivering` }, // اسوېلی - asweley
|
||||
{ ts: 1527822497, e: `cheek` }, // اننګی - anangey
|
||||
{ ts: 1527821967, e: `beaver, seal` }, // اوبسپی - obspéy
|
||||
{ ts: 1527822190, e: `stove, oven, furnace, hearth, floor of a fireplace` }, // اور غالی - orgháaley
|
||||
{ ts: 1527821545, e: `volcano` }, // اورشیندی - orsheendéy
|
||||
{ ts: 1527819192, e: `train` }, // اورګاډی - orgáaDey
|
||||
{ ts: 1527815585, e: `summer` }, // اوړی - oRey
|
||||
{ ts: 1623044357441, e: `tuft, clump, shock of hair` }, // ببوتنکی - bubootúnkey
|
||||
{ ts: 1527821668, e: `spark, speck, flicker` }, // بڅری - batsúrey
|
||||
{ ts: 1527821239, e: `kidney` }, // بډوری - baDóorey
|
||||
{ ts: 1527821099, e: `earring` }, // برغوږی - barghwáGey
|
||||
{ ts: 1527822629, e: `lid, cover` }, // برغولی - barghóley
|
||||
{ ts: 1527811903, e: `success, victory` }, // بری - barey
|
||||
{ ts: 1594904072731, e: `bracelet` }, // بنګړی - bangRéy
|
||||
{ ts: 1527817159, e: `plant` }, // بوټی - booTey
|
||||
{ ts: 1527815055, e: `terrible` }, // بوږنوړی - boGnwaRey
|
||||
{ ts: 1610618917483, e: `orphanage, nursery` }, // پالنځی - paalundzéy
|
||||
{ ts: 1527814666, e: `final point, end point` }, // پای ټکی - paayTakey
|
||||
{ ts: 1527816195, e: `small turban` }, // پټکی - paTkey
|
||||
{ ts: 1527811611, e: `field, place where crops are sown` }, // پټی - paTey
|
||||
{ ts: 1588762458105, e: `kitchen` }, // پخلنځی - pukhlandzéy
|
||||
{ ts: 1527816059, e: `cooking, preparation of food; wisdom, maturity` }, // پخلی - pakhley
|
||||
{ ts: 1527821241, e: `acorn` }, // پرګی - purgéy
|
||||
{ ts: 1527813812, e: `veil, covering for women, cover` }, // پړونی - paRóoney
|
||||
{ ts: 1527822385, e: `rope, cable, cord` }, // پړی - púRey
|
||||
{ ts: 1527812980, e: `whispering, murmuring, rumor, gossip` }, // پس پسی - puspusey
|
||||
{ ts: 1527814005, e: `spring, springtime (season)` }, // پسرلی - psarléy, pusărléy
|
||||
{ ts: 1527821229, e: `kidney` }, // پښتورګی - paxtawurgey
|
||||
{ ts: 1527817035, e: `mission, delegation` }, // پلاوی - plaawey
|
||||
{ ts: 1527815187, e: `mat` }, // پوزی - pozey
|
||||
{ ts: 1527816627, e: `fleece, pelt, skin, shell, rind, bark; ear lobe` }, // پوستکی - postukey
|
||||
{ ts: 1527819332, e: `kidney` }, // پوښتورګی - pooxtawúrgey
|
||||
{ ts: 1527819496, e: `understanding, comprehension` }, // پوهاوی - pohaawéy
|
||||
{ ts: 1527815168, e: `load, weight, burden` }, // پېټی - peTéy
|
||||
{ ts: 1527815927, e: `customer` }, // پېرونکی - peroonkey
|
||||
{ ts: 1527815017, e: `cream` }, // پېروی - perúwey, peráwey
|
||||
{ ts: 1527815325, e: `violence` }, // تاوتریخوالی - taawtreekhwaaley
|
||||
{ ts: 1611397750325, e: `screwdriver, screw` }, // تاوی - taawéy
|
||||
{ ts: 1622374978659, e: `hatchet` }, // تبرګی - tubúrgey
|
||||
{ ts: 1527818705, e: `gusset (in a shirt)` }, // تخرګی - tkhurgéy
|
||||
{ ts: 1527814392, e: `band, bandage` }, // تړونی - taRooney
|
||||
{ ts: 1527822723, e: `side, groin, empty place, void` }, // تشی - túshey
|
||||
{ ts: 1577585114379, e: `sole (of a shoe); yard, compound; palm` }, // تلی - táley
|
||||
{ ts: 1527816630, e: `forehead, brow, slope` }, // تندی - tandey
|
||||
{ ts: 1527821980, e: `bellyband (of a harness)` }, // تڼی - taNéy
|
||||
{ ts: 1527819719, e: `spleen` }, // توری - tórey
|
||||
{ ts: 1527819721, e: `letter, letter of the alphabet` }, // توری - tórey
|
||||
{ ts: 1527819622, e: `rocket, missile` }, // توغندی - toghandéy
|
||||
{ ts: 1527814705, e: `element, item, material; thing, material, kind, type` }, // توکی - tokey
|
||||
{ ts: 1527819563, e: `piece, small piece; a length (of cloth); blanket` }, // ټکری - TUkréy
|
||||
{ ts: 1577408381145, e: `shawl, head-covering` }, // ټکری - Tikréy
|
||||
{ ts: 1527814667, e: `word; point; dot` }, // ټکی - Tákey
|
||||
{ ts: 1527813617, e: `shawl, head covering` }, // ټیکری - Teekréy
|
||||
{ ts: 1527819733, e: `young, youth, young lad` }, // ځلمی - dzalméy
|
||||
{ ts: 1527815465, e: `official authority, official, authority` }, // چارواکی - chaarwaakey
|
||||
{ ts: 1527822356, e: `worm, small insect` }, // چنجی - chinjéy
|
||||
{ ts: 1527822808, e: `basin, bowl` }, // چنی - chanéy
|
||||
{ ts: 1527822357, e: `worm, small insect` }, // چینجی - cheenjéy
|
||||
{ ts: 1527819046, e: `drop` }, // څاڅکی - tsáatskey
|
||||
{ ts: 1527817874, e: `quality, nature` }, // څرنګوالی - tsurangwaaley
|
||||
{ ts: 1527814041, e: `spring (season)` }, // څړمنی - tsaRmuney
|
||||
{ ts: 1573055311846, e: `warning, notice, alarm` }, // خبرداری - khabardaarey
|
||||
{ ts: 1527820324, e: `melon` }, // خټکی - khaTakéy
|
||||
{ ts: 1527819828, e: `weight; respect, honour` }, // درناوی - dranaawey
|
||||
{ ts: 1588161660483, e: `crutch, walking-stick, cane` }, // ډانګوری - Daangooréy
|
||||
{ ts: 1527819732, e: `young, youth, young lad` }, // زلمی - zalméy
|
||||
{ ts: 1527813708, e: `good news, gospel` }, // زېری - zerey
|
||||
{ ts: 1588758498458, e: `jaundice` }, // زېړی - zeRéy
|
||||
{ ts: 1571626392709, e: `birthplace` }, // زېږنځی - zeGundzey
|
||||
{ ts: 1527815698, e: `winter` }, // ژمی - jzúmey
|
||||
{ ts: 1573686563723, e: `wineskin, bagpipe, skin for carrying liquid` }, // ژی - jzey
|
||||
{ ts: 1527815239, e: `entertainment, fun, recreation` }, // ساتېری - saaterey
|
||||
{ ts: 1527813725, e: `equal, equivalent, match, precedent` }, // ساری - sáarey
|
||||
{ ts: 1527814021, e: `spring (season)` }, // سپرلی - sparléy
|
||||
{ ts: 1527813509, e: `insult, disgrace, defamation, disrespect` }, // سپکاوی - spukaawéy
|
||||
{ ts: 1527815298, e: `clarification, attestation` }, // سپیناوی - speenaawey
|
||||
{ ts: 1578002674551, e: `eye-socket, eyelid; orbit` }, // سترغلی - sturghúley
|
||||
{ ts: 1527811999, e: `star` }, // ستوری - storey
|
||||
{ ts: 1527817001, e: `throat, larynx` }, // ستونی - stóoney
|
||||
{ ts: 1527813511, e: `headache, trouble` }, // سرخوږی - sărkhwuGey
|
||||
{ ts: 1527815251, e: `man` }, // سړی - saRéy
|
||||
{ ts: 1527819850, e: `lung` }, // سږی - súGey
|
||||
{ ts: 1527812302, e: `hole, slit, opening` }, // سوری - soorey
|
||||
{ ts: 1527818221, e: `burning, zeal, fervour` }, // سوی - swey
|
||||
{ ts: 1527812304, e: `shade, shadow` }, // سیوری - syórey, syóorey
|
||||
{ ts: 1527815268, e: `thing` }, // شی - shey
|
||||
{ ts: 1527822527, e: `ankle, ankle-bone` }, // ښتګری - xatgaréy
|
||||
{ ts: 1527812793, e: `school` }, // ښوونځی - xowundzey
|
||||
{ ts: 1527821064, e: `a quick, clever, agile, bright man; a swindler, a fraud` }, // ښویکی - xwayakéy
|
||||
{ ts: 1527822650, e: `largeness, bigness` }, // غټوالی - ghaTwaaley
|
||||
{ ts: 1527814569, e: `member` }, // غړی - ghuRey
|
||||
{ ts: 1527817627, e: `arrow` }, // غشی - ghúshey
|
||||
{ ts: 1527822913, e: `precious stone, precious stone in a signet ring` }, // غمی - ghaméy
|
||||
{ ts: 1527816181, e: `vomit, nausea (Arabic)` }, // قی - qey
|
||||
{ ts: 1527814715, e: `user` }, // کاروونکی - kaarawoonkey
|
||||
{ ts: 1527823295, e: `stone, rock` }, // کاڼی - káaNey
|
||||
{ ts: 1527818563, e: `muscle` }, // کبوړی - kabóoRey
|
||||
{ ts: 1527822824, e: `booklet, notebook` }, // کتاب ګوټی - kitaabgóTey
|
||||
{ ts: 1582388629980, e: `pupil (of an eye)` }, // کسی - kúsey
|
||||
{ ts: 1594906790729, e: `boy` }, // ککی - kakéy
|
||||
{ ts: 1527812836, e: `village` }, // کلی - kuley, kiley
|
||||
{ ts: 1610616852625, e: `echo` }, // کنګرېزی - kangrezéy
|
||||
{ ts: 1527819196, e: `car, train` }, // ګاډی - gaaDey
|
||||
{ ts: 1579016593220, e: `beehive; wasps' nest` }, // ګنی - ganéy
|
||||
{ ts: 1527819076, e: `doll, puppet` }, // ګوډاګی - gooDaagéy
|
||||
{ ts: 1527822505, e: `cheek` }, // ګومبوری - goomboorey
|
||||
{ ts: 1527819079, e: `puppet` }, // لاسپوڅی - laaspotséy
|
||||
{ ts: 1573149568665, e: `access, availability` }, // لاسرسی - laasraséy
|
||||
{ ts: 1527817464, e: `wood, timber` }, // لرګی - largey
|
||||
{ ts: 1527822801, e: `sleeve` }, // لستوڼی - lastóNey
|
||||
{ ts: 1527814401, e: `toy` }, // لوبونی - lobawuney
|
||||
{ ts: 1527814519, e: `side, direction` }, // لوری - lorey
|
||||
{ ts: 1527823103, e: `perspective, viewpoint` }, // لیدلوری - leedlorey
|
||||
{ ts: 1527819920, e: `mosquito, midge` }, // ماشی - maashey
|
||||
{ ts: 1527820224, e: `fly swatter` }, // مچوژی - muchwajzéy
|
||||
{ ts: 1527817770, e: `dead body, corpse` }, // مړی - múRey
|
||||
{ ts: 1527813189, e: `fall, autumn` }, // منی - máney
|
||||
{ ts: 1527812421, e: `ant` }, // مېږی - meGey
|
||||
{ ts: 1527819227, e: `lack` }, // نشتوالی - nashtwaaley
|
||||
{ ts: 1527823577, e: `sapling, seedling, sprout, young tree` }, // نیالګی - niyaalgey
|
||||
{ ts: 1527812073, e: `bone` }, // هډوکی - haDookey
|
||||
{ ts: 1527812668, e: `welcome` }, // هرکلی - hărkáley
|
||||
{ ts: 1588153218244, e: `height, elevation, tallness` }, // هسکوالی - haskwáaley
|
||||
{ ts: 1585309922022, e: `flu, respiratory illness, influenza, cold` }, // والګی - waalgéy
|
||||
{ ts: 1527821465, e: `shoulder` }, // ولی - wuléy
|
||||
]
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527822004, e: "last, final" }, // آخرینی - aakhireenéy
|
||||
{ ts: 1591872915426, e: "Afghan (person)" }, // افغانی - afghaanéy
|
||||
{ ts: 1612616237182, e: "Pakistani (person)"}, // پاکستانی - paakistaanéy
|
||||
{ ts: 1527813400, e: "current" }, // اوسنی - oosanéy
|
||||
{ ts: 1527815661, e: "first" }, // اولنی - awwalunéy
|
||||
{ ts: 1527812476, e: "child" }, // بچی - bachéy
|
||||
{ ts: 1527816646, e: "foreigner, outer" }, // بهرنی - baharanéy, bahranéy
|
||||
{ ts: 1527818769, e: "emergency" }, // بېړنی - beRanéy
|
||||
{ ts: 1592382613021, e: "old, ancient, former" }, // پخوانی - pakhwaanéy
|
||||
{ ts: 1527819532, e: "foreign, unrelated" }, // پردی - pradéy, prudéy
|
||||
{ ts: 1577381894391, e: "Englishman, Westerner" }, // پرنګی - parangéy
|
||||
{ ts: 1527820194, e: "so-and-so" }, // پلانکی - pulaankéy
|
||||
{ ts: 1527820130, e: "adherent" }, // پلوی - palawéy
|
||||
{ ts: 1582390092514, e: "upper, above" }, // پورتنی - portinéy
|
||||
{ ts: 1610617741649, e: "old, ancient" }, // ځنډنی - dzanDanéy, dzanDunéy
|
||||
{ ts: 1610793723568, e: "goat" }, // چېلی - cheléy
|
||||
{ ts: 1527819362, e: "calf (animal)" }, // خوسی - khooséy
|
||||
{ ts: 1590052667427, e: "witness" }, // درستی - drustéy, drastéy
|
||||
{ ts: 1527822854, e: "first, before" }, // ړومبی - Roombéy
|
||||
{ ts: 1527820213, e: "lion" }, // زمری - zmaréy
|
||||
{ ts: 1527813923, e: "living" }, // ژوندی - jzwundéy
|
||||
{ ts: 1527815299, e: "dog" }, // سپی - spéy
|
||||
{ ts: 1527820788, e: "city, urban" }, // ښارنی - xaaranéy
|
||||
{ ts: 1527812822, e: "little, small" }, // کوچنی - koochnéy
|
||||
{ ts: 1527823742, e: "nomadic" }, // کوچی - kochéy
|
||||
{ ts: 1527818765, e: "speedy, quick" }, // ګړندی - guRandéy
|
||||
{ ts: 1527819130, e: "cute" }, // ګلالی - gUlaaléy
|
||||
{ ts: 1576101261017, e: "mute (person)" }, // ګنګی - gangéy
|
||||
{ ts: 1582316583262, e: "lower, bottom" }, // لاندینی - laandeenéy
|
||||
{ ts: 1527816249, e: "grandchild" }, // لمسی - lmaséy
|
||||
{ ts: 1527813472, e: "first" }, // لومړنی - loomRanéy
|
||||
{ ts: 1527813132, e: "first" }, // لومړی - loomRéy
|
||||
{ ts: 1527819910, e: "slippery, smooth" }, // متلی - mutléy
|
||||
{ ts: 1527820414, e: "middle, central" }, // منځنی - mandzunéy
|
||||
{ ts: 1527811202, e: "monthly" }, // میاشتنی - miyaashtanéy
|
||||
{ ts: 1527819320, e: "thin" }, // نری - naréy
|
||||
{ ts: 1527816251, e: "grandchild" }, // نمسی - nmaséy
|
||||
{ ts: 1527821373, e: "deer" }, // هوسی - hoséy
|
||||
{ ts: 1527813636, e: "last" }, // وروستی - wroostéy
|
||||
{ ts: 1527815430, e: "only" }, // یوازنی - yawaazunéy
|
||||
];
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1582853867682, e: "resident" }, // اوسېدونکی
|
||||
{ ts: 1527813469, e: "forgiving" }, // بخښونکی
|
||||
{ ts: 1527817829, e: "debtor" }, // پوروړی
|
||||
{ ts: 1527815205, e: "powerful" }, // پیاوړی
|
||||
{ ts: 1527815924, e: "customer" }, // پېرودونکی
|
||||
{ ts: 1527819604, e: "tense, stern" }, // ترینګلی
|
||||
{ ts: 1527813406, e: "bound, tied" }, // تړلی
|
||||
{ ts: 1527815381, e: "thirsty" }, // تږی
|
||||
{ ts: 1527817607, e: "disgraceful, shameful, dishonered" }, // تور مخی
|
||||
{ ts: 1527822859, e: "dishevelled, messy, curly (with hair etc.)" }, // څپولی
|
||||
{ ts: 1527811466, e: "researcher" }, // څېړونکی
|
||||
{ ts: 1527812377, e: "obedient, submissive" }, // حکم منونکی
|
||||
{ ts: 1527817299, e: "amazing, surprising" }, // حیرانوونکی
|
||||
{ ts: 1527813282, e: "seller" }, // خرڅوونکی
|
||||
{ ts: 1527812809, e: "malnourished" }, // خوار ځواکی
|
||||
{ ts: 1591871233587, e: "well-spoken" }, // خوږژبی
|
||||
{ ts: 1527814118, e: "painful, agonizing" }, // دردوونکی
|
||||
{ ts: 1527820657, e: "mediator, arbitrator" }, // درېیمګړی
|
||||
{ ts: 1527815713, e: "coming, future" }, // راتلونکی
|
||||
{ ts: 1527812142, e: "true, truthful" }, // رښتنی
|
||||
{ ts: 1527812161, e: "true, truthful" }, // رښتونی
|
||||
{ ts: 1527811507, e: "true, truthful" }, // رښتینی
|
||||
{ ts: 1527813758, e: "student" }, // زدکوونکی
|
||||
{ ts: 1577058349091, e: "interesting, pleasant" }, // زړه پوری
|
||||
{ ts: 1527817400, e: "merciful, compassionate" }, // زړه سواندی
|
||||
{ ts: 1527819587, e: "translator" }, // ژباړونکی
|
||||
{ ts: 1527814888, e: "savior, saviour, rescuer" }, // ژغورونکی
|
||||
{ ts: 1527818109, e: "pure, holy, magnificent" }, // سپېڅلی
|
||||
{ ts: 1527811338, e: "sincere hearted, trusting" }, // سپین زړی
|
||||
{ ts: 1527815306, e: "tired" }, // ستړی
|
||||
{ ts: 1527822745, e: "burned" }, // سټکوری
|
||||
{ ts: 1527817442, e: "heard-hearted" }, // سخت زړی
|
||||
{ ts: 1527816932, e: "soldier" }, // سرتېری
|
||||
{ ts: 1527820170, e: "singer" }, // سندرغاړی
|
||||
{ ts: 1527819964, e: "burning" }, // سوځېدونکی
|
||||
{ ts: 1527821951, e: "burned" }, // سوی
|
||||
{ ts: 1527812779, e: "beautiful" }, // ښکلی
|
||||
{ ts: 1527812806, e: "teacher" }, // ښوونکی
|
||||
{ ts: 1527811350, e: "quiet, silent" }, // غلی
|
||||
{ ts: 1527819637, e: "worker" }, // کارکوونکی
|
||||
{ ts: 1527818613, e: "weak" }, // کمزوری
|
||||
{ ts: 1595516629483, e: "deafening" }, // کڼوونکی
|
||||
{ ts: 1527820661, e: "mediator" }, // مېنځګړی
|
||||
{ ts: 1527814047, e: "aforesaid, above-mentioned" }, // نوموړی
|
||||
{ ts: 1527813822, e: "new" }, // نوی
|
||||
{ ts: 1586453720908, e: "encouraging" }, // هڅوونکی
|
||||
{ ts: 1588163180700, e: "stunning, amazing" }, // هېښوونکی
|
||||
{ ts: 1527823715, e: "small, little" }, // وړکوټی
|
||||
{ ts: 1527823714, e: "small, little" }, // وړکی
|
||||
{ ts: 1527815403, e: "little, small" }, // وړوکی
|
||||
{ ts: 1527813916, e: "lethal, deadly" }, // وژونکی
|
||||
{ ts: 1527815424, e: "hungry" }, // وږی
|
||||
{ ts: 1527823713, e: "small, little" }, // ووړکی
|
||||
{ ts: 1527816455, e: "separated, divided" }, // وېشلی
|
||||
];
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = [
|
||||
{"ts":1527812798,"i":5593,"p":"خفه","f":"khúfa","g":"khufa","e":"sad, upset, angry; choked, suffocated","c":"adj."},
|
||||
{"ts":1527812792,"i":5773,"p":"خوشاله","f":"khoshaala","g":"khoshaala","e":"happy, glad","c":"adj."},
|
||||
{"ts":1527812761,"i":8534,"p":"ښایسته","f":"xáaysta","g":"xaayusta","e":"beautiful","c":"adj."},
|
||||
];
|
|
@ -0,0 +1,79 @@
|
|||
module.exports = [
|
||||
{ ts: 1527821744, e: `cook, chef` }, // آشپز - aashpáz
|
||||
{ ts: 1527812156, e: `officer` }, // افسر - afsar
|
||||
{ ts: 1591872915426, e: `Afghan (person)` }, // افغانی - afghaanéy
|
||||
{ ts: 1527815137, e: `instigator, insurgent, terrorist` }, // اورپکی - orpakey
|
||||
{ ts: 1582853867682, e: `resident` }, // اوسېدونکی - osedóonkey
|
||||
{ ts: 1527812476, e: `child, offspring` }, // بچی - bachéy
|
||||
{ ts: 1623044005072, e: `insurrectionist, rebel` }, // بلواګر - balwaagar
|
||||
{ ts: 1612616237182, e: `Pakistani (person)` }, // پاکستانی - paakistaanéy
|
||||
{ ts: 1527817965, e: `keeper, one who brings up, raises (cattle etc.)` }, // پالونکی - paaloonkey
|
||||
{ ts: 1527815197, e: `Pashtun` }, // پښتون - puxtoon
|
||||
{ ts: 1527819228, e: `inspector, detective, person checking people at the doors etc.` }, // پلټونکی - pulaToonkey
|
||||
{ ts: 1527820130, e: `adherent, supporter; the outside or further ox in a team of oxes grinding or threshing` }, // پلوی - palawéy
|
||||
{ ts: 1527815924, e: `customer` }, // پېرودونکی - perodoonkey
|
||||
{ ts: 1527816431, e: `cousin (of paternal aunt)` }, // ترورزی - trorzéy
|
||||
{ ts: 1527820820, e: `follower` }, // تعقیبوونکی - ta'qeebawóonkey
|
||||
{ ts: 1586270915475, e: `mammal` }, // تي لرونکی - tee laroonkey
|
||||
{ ts: 1613563994424, e: `joker, jester, mocker` }, // ټوقمار - Toqmaar
|
||||
{ ts: 1610793723568, e: `ram, goat` }, // چېلی - cheléy
|
||||
{ ts: 1527811466, e: `researcher` }, // څېړونکی - tseRoonkey
|
||||
{ ts: 1527812795, e: `relative` }, // خپلوان - khpulwaan
|
||||
{ ts: 1527812802, e: `donkey` }, // خر - khur
|
||||
{ ts: 1527813282, e: `seller` }, // خرڅوونکی - khartsawóonkey
|
||||
{ ts: 1527819362, e: `calf (animal)` }, // خوسی - khooséy
|
||||
{ ts: 1527822535, e: `tailor` }, // خیاط - khayáat
|
||||
{ ts: 1590052667427, e: `witness` }, // درستی - drustéy, drastéy
|
||||
{ ts: 1622873938137, e: `crook, swindler, criminal` }, // درغلګر - darghalgar
|
||||
{ ts: 1527820656, e: `mediator, arbitrator` }, // دریمګړی - driyamgúRey
|
||||
{ ts: 1614081825855, e: `priest, monk/nun` }, // راهب - raahib
|
||||
{ ts: 1527813758, e: `student, learner, pupil` }, // زدکوونکی - zdakawóonkey
|
||||
{ ts: 1527819587, e: `translator` }, // ژباړونکی - jzbaaRoonkey
|
||||
{ ts: 1527815299, e: `dog` }, // سپی - spéy
|
||||
{ ts: 1610447830096, e: `calf; bull-calf` }, // سخی - skhey
|
||||
{ ts: 1527816932, e: `soldier` }, // سرتېری - sărtérey
|
||||
{ ts: 1527811519, e: `embassador, ambassador` }, // سفیر - safeer
|
||||
{ ts: 1622366208373, e: `secretary` }, // سکرتر - sakratár
|
||||
{ ts: 1527820170, e: `singer` }, // سندرغاړی - sandurgháaRey
|
||||
{ ts: 1566468540788, e: `rabbit` }, // سوی - sooy
|
||||
{ ts: 1527819801, e: `tourist, sightseer, visitor` }, // سیلانی - seylaanéy
|
||||
{ ts: 1575924767041, e: `shepherd` }, // شپون - shpoon
|
||||
{ ts: 1527815279, e: `shepherd` }, // شپونکی - shpoonkey
|
||||
{ ts: 1527819173, e: `analyst, examiner` }, // شنونکی - shanóonkey
|
||||
{ ts: 1527812806, e: `teacher` }, // ښووونکی - xowóonkey
|
||||
{ ts: 1527815436, e: `tyrant, oppressor, cruel person` }, // ظالم - zaalim
|
||||
{ ts: 1527818632, e: `twin` }, // غبرګونی - ghbargoney
|
||||
{ ts: 1527812624, e: `thief` }, // غل - ghul
|
||||
{ ts: 1613561408232, e: `guilty, at fault` }, // قصوروار - qUsoorwáar
|
||||
{ ts: 1527814715, e: `user` }, // کاروونکی - kaarawoonkey
|
||||
{ ts: 1527816256, e: `great-grandson` }, // کړوسی - kaRwaséy
|
||||
{ ts: 1594906790729, e: `child` }, // ککی - kakéy
|
||||
{ ts: 1527819244, e: `host, hostess; master of house` }, // کوربه - korba
|
||||
{ ts: 1527812174, e: `neighbour` }, // ګاونډی - gaawanDéy
|
||||
{ ts: 1579030083953, e: `sinner, sinful` }, // ګناه ګار - gUnaahgáar
|
||||
{ ts: 1527816249, e: `grandchild` }, // لمسی - lmaséy
|
||||
{ ts: 1527822661, e: `athlete, player; actor; mischevious, playful (of a child)` }, // لوبغاړی - lobgháaRey
|
||||
{ ts: 1589885143650, e: `fox` }, // لومبړ - loombáR
|
||||
{ ts: 1527812043, e: `writer, author` }, // لیکوال - leekwaal
|
||||
{ ts: 1527820680, e: `crazy, insane, mad person` }, // لېونی - lewanéy
|
||||
{ ts: 1527812881, e: `child, kid` }, // ماشوم - maashoom
|
||||
{ ts: 1527814445, e: `assigned, appointed, given orders or istructions (Arabic), authorized, sent on business; officer (as in government worker)` }, // مامور - maamóor
|
||||
{ ts: 1527818760, e: `civil activist` }, // مدني فاعل - madanee faa'al
|
||||
{ ts: 1527821523, e: `slave, servant` }, // مریی - mrayéy
|
||||
{ ts: 1527814159, e: `friend, companion` }, // ملګری - malgúrey
|
||||
{ ts: 1527820661, e: `mediator, go-between, arbitrator` }, // مېنځګړی - mendzgúRey
|
||||
{ ts: 1527823403, e: `fan, someone who loves or appreciates someone or something` }, // مینه وال - meenawáal
|
||||
{ ts: 1527815127, e: `nurse` }, // نرس - nurs
|
||||
{ ts: 1527816254, e: `grandson` }, // نوسی - nwaséy
|
||||
{ ts: 1527814806, e: `peer, someone of the same age` }, // همځولی - hamdzoléy ??
|
||||
{ ts: 1527812684, e: `co-worker, fellow worker, collaborator, aid` }, // همکار - hamkaar
|
||||
{ ts: 1527811732, e: `artist, performer` }, // هنر مند - hUnarmand
|
||||
{ ts: 1527821373, e: `deer` }, // هوسی - hoséy
|
||||
{ ts: 1591027046896, e: `goat` }, // وز - wuz
|
||||
{ ts: 1611395180139, e: `fellow countryman, person from the same country` }, // وطندار - watandáar
|
||||
{ ts: 1527811296, e: `lawyer, proxy holder` }, // وکیل - wakeel
|
||||
{ ts: 1527813585, e: `person, human being, creature` }, // وګړی - wagúRey
|
||||
{ ts: 1527814672, e: `spokesperson, spokesman, newcaster` }, // ویاند - wayaand
|
||||
{ ts: 1586454081484, e: `orphan` }, // یتیم - yateem
|
||||
{ ts: 1527812461, e: "hero" }, // اتل - atal
|
||||
];
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = [
|
||||
{ ts: 1527816016, e: "Pashto" }, // پښټو
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527816778, e: "long" }, // اوږد - ooGd, ooGud
|
||||
{ ts: 1527822706, e: "raw, unripe, immature" }, // اوم - oom
|
||||
{ ts: 1527812802, e: "donkey" }, // خر - khur
|
||||
{ ts: 1527813293, e: "red, hot" }, // سور - soor
|
||||
{ ts: 1527815265, e: "green, blue" }, // شین - sheen
|
||||
{ ts: 1527812624, e: "thief" }, // غل - ghul
|
||||
{ ts: 1527815087, e: "dead" }, // مړ - muR
|
||||
{ ts: 1527814151, e: "companion, friend" }, // مل - mal
|
||||
{ ts: 1527813580, e: "one" }, // یو - yo
|
||||
];
|
|
@ -0,0 +1,23 @@
|
|||
module.exports = [
|
||||
{ ts: 1527819345, e: `sheep, ram` }, // پسه - psu
|
||||
{ ts: 1527822173, e: `bush, shrub` }, // جاړه - jaaRú
|
||||
{ ts: 1527813508, e: `heart` }, // زړه - zRu
|
||||
{ ts: 1588857967561, e: `bull` }, // غوایه - ghwaayú
|
||||
{ ts: 1527817108, e: `look, gaze, examination, inspection, spying` }, // کاته - kaatu
|
||||
{ ts: 1527817768, e: `raven, crow` }, // کارګه - kaargu
|
||||
{ ts: 1527819245, e: `master of house, head of family, married man` }, // کوربانه - korbaanú
|
||||
{ ts: 1527818516, e: `swimming, bathing` }, // لمبېده - lambedú
|
||||
{ ts: 1527813986, e: `sunset, west` }, // لمر پرېواته - lmarprewaatu
|
||||
{ ts: 1527813992, e: `sunset` }, // لمر لوېده - lmarlwedu
|
||||
{ ts: 1527813987, e: `sunrise, east` }, // لمرخاته - lmarkhaatu
|
||||
{ ts: 1527818255, e: `wolf, wild dog` }, // لېوه - lewú
|
||||
{ ts: 1527821522, e: `slave, servant` }, // مریه - mrayú
|
||||
{ ts: 1527812911, e: `husband, brave` }, // مېړه - meRu
|
||||
{ ts: 1527811626, e: `impracticability, impossibility, improbability` }, // نکېده - nukedu
|
||||
{ ts: 1527816410, e: `grandfather, grandpa` }, // نیکه - neekú
|
||||
{ ts: 1527822420, e: `rein, bridle (for horses); string for trousers, string used inside to hold up the partoog/shalwar` }, // واګه - waagu
|
||||
{ ts: 1527816357, e: `nephew, brother's son` }, // وراره - wraaru
|
||||
{ ts: 1527823225, e: `flock, herd, drove` }, // وله - wUlú
|
||||
{ ts: 1527814789, e: `hair` }, // وېښته - wextu
|
||||
{ ts: 1527815394, e: 'wedding' }, // واده - waadú
|
||||
];
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Copyright (c) 2021 lingdocs.com
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
{ ts: 1527818017, e: "store, shop" }, // اټۍ - aTuy
|
||||
{ ts: 1527812694, e: "girl" }, // انجنۍ - injUnuy
|
||||
{ ts: 1527815140, e: "week" }, // اونۍ - onuy, ownuy, owunuy
|
||||
{ ts: 1566476931206, e: "lamp, light" }, // بتۍ - batúy
|
||||
{ ts: 1527822192, e: "stove, oven, furnace" }, // بټۍ - baTúy
|
||||
{ ts: 1527820828, e: "daughter, girl" }, // بچۍ - bachúy
|
||||
{ ts: 1527822974, e: "cart, buggy, stroller" }, // بګۍ - bagúy
|
||||
{ ts: 1591805634565, e: "rib" }, // پوښتۍ - pooxtúy
|
||||
{ ts: 1586276322639, e: "hat, cap" }, // ټوپۍ - Topuy
|
||||
{ ts: 1527820058, e: "kneecap, patella" }, // ټوټکۍ - ToTakúy
|
||||
{ ts: 1527812564, e: "bread, food, meal" }, // ډوډۍ - DoDuy
|
||||
{ ts: 1527821555, e: "edge, verge, side" }, // ژۍ - jzuy
|
||||
{ ts: 1527814788, e: "moon" }, // سپوږمۍ - spoGmuy
|
||||
{ ts: 1527820120, e: "hill, hillrock, mound" }, // غونډۍ - ghwunDúy
|
||||
{ ts: 1527814203, e: "chair, seat, stool" }, // کرسۍ - kUrsuy
|
||||
{ ts: 1527812045, e: "window" }, // کړکۍ - kuRkúy
|
||||
{ ts: 1527816026, e: "ring, curl; handcuffs, link, chain; loom; department, section" }, // کړۍ - kaRuy
|
||||
{ ts: 1527813870, e: "boat, ship" }, // کشتۍ - kishtúy
|
||||
{ ts: 1527821895, e: "doll" }, // ګوډۍ - gooDúy
|
||||
{ ts: 1527814564, e: "pill tablet; bullet" }, // ګولۍ - golúy
|
||||
{ ts: 1527811763, e: "tail" }, // لکۍ - lakuy
|
||||
{ ts: 1527812659, e: "egg" }, // هګۍ - haguy
|
||||
{ ts: 1527821372, e: "gazelle, antelope" }, // هوسۍ - hosúy
|
||||
];
|
|
@ -0,0 +1,14 @@
|
|||
module.exports = [
|
||||
{ ts: 1527815154, e: `end, finish, close, conclusion` }, // پای - paay
|
||||
{ ts: 1527812594, e: `place, space` }, // ځای - dzaay
|
||||
{ ts: 1527812525, e: `tea` }, // چای - chaay
|
||||
{ ts: 1527812783, e: `God, Lord` }, // خدای - khUdaay
|
||||
{ ts: 1527819514, e: `tier, row, foundation (masonry etc.)` }, // دای - daay
|
||||
{ ts: 1610797797756, e: `hollow, depression` }, // سای - saay
|
||||
{ ts: 1527822345, e: `caravansary, inn, large house` }, // سرای - saráay
|
||||
|
||||
|
||||
{ ts: 1586598425514, e: `smell` }, // بوی - booy
|
||||
{ ts: 1527814511, e: `character, nature, disposition, habit` }, // خوی - khooy
|
||||
{ ts: 1566468540788, e: `rabbit` }, // سوی - sooy
|
||||
]
|
11
package.json
11
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@lingdocs/pashto-inflector",
|
||||
"version": "1.7.0",
|
||||
"version": "1.8.0",
|
||||
"author": "lingdocs.com",
|
||||
"description": "A Pashto inflection and verb conjugation engine, inculding React components for displaying Pashto text, inflections, and conjugations",
|
||||
"homepage": "https://verbs.lingdocs.com",
|
||||
|
@ -25,7 +25,8 @@
|
|||
"dependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"pbf": "^3.2.1",
|
||||
"rambda": "^6.7.0"
|
||||
"rambda": "^6.7.0",
|
||||
"react-select": "^5.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||
|
@ -64,10 +65,10 @@
|
|||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"build-website": "node get-verbs.js && npm run build",
|
||||
"build-library": "node get-verbs.js && rimraf dist && rimraf dist-cjs && tsc --project library-tsconfig.json && node library-post-build.js && rollup -c",
|
||||
"build-website": "node get-words.js && npm run build",
|
||||
"build-library": "node get-words.js && rimraf dist && rimraf dist-cjs && tsc --project library-tsconfig.json && node library-post-build.js && rollup -c",
|
||||
"test-ci": "npm run test -- --watchAll=false",
|
||||
"get-verbs": "node get-verbs.js"
|
||||
"get-words": "node get-words.js"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
* {
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
|
||||
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
}
|
||||
|
||||
:root {
|
||||
--secondary: #00c1fc;
|
||||
--primary: #ffda54;
|
||||
|
|
20
src/App.tsx
20
src/App.tsx
|
@ -7,8 +7,8 @@
|
|||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import ConjugationViewer from "./components/ConjugationViewer";
|
||||
import verbs from "./verbs";
|
||||
import nounsAdjs from "./nouns-adjs";
|
||||
import Pashto from "./components/Pashto";
|
||||
import Phonetics from "./components/Phonetics";
|
||||
import { getVerbInfo } from "./lib/verb-info";
|
||||
|
@ -23,7 +23,9 @@ import {
|
|||
Modal
|
||||
} from "react-bootstrap";
|
||||
import * as T from "./types";
|
||||
import { isNounEntry } from "./lib/type-predicates";
|
||||
import defualtTextOptions from "./lib/default-text-options";
|
||||
import PhraseBuilder from "./components/vp-explorer/VPExplorer";
|
||||
const textOptionsLocalStorageName = "textOptions2";
|
||||
type VerbType = "simple" | "stative compound" | "dynamic compound";
|
||||
const verbTypes: VerbType[] = [
|
||||
|
@ -31,6 +33,7 @@ const verbTypes: VerbType[] = [
|
|||
"stative compound",
|
||||
"dynamic compound",
|
||||
];
|
||||
const nouns = nounsAdjs.filter(isNounEntry);
|
||||
|
||||
const transitivities: T.Transitivity[] = [
|
||||
"transitive",
|
||||
|
@ -192,7 +195,7 @@ function App() {
|
|||
<p className="lead my-4">
|
||||
Each form is made from one simple <samp>formula</samp> which <a href="https://www.lingdocs.com/blog/pashto-verbs-master-chart">works for all verbs</a>. 👨🔬
|
||||
</p>
|
||||
<p>Choose a verb 👇, look at its roots and stems 🌳, see how all the forms are made and what they mean. 🤓</p>
|
||||
<p>Choose a verb 👇, look at its roots and stems 🌳, see how all the forms are made. 🤓</p>
|
||||
</div>
|
||||
<div className="d-block mx-auto card" style={{ maxWidth: "700px", background: "var(--closer)"}}>
|
||||
<div className="card-body">
|
||||
|
@ -288,11 +291,14 @@ function App() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{v?.verb.entry && <ConjugationViewer
|
||||
entry={v?.verb.entry}
|
||||
complement={v?.verb.complement}
|
||||
textOptions={textOptions}
|
||||
/>}
|
||||
{v?.verb.entry && <div style={{ paddingBottom: "100px" }}>
|
||||
<PhraseBuilder
|
||||
verb={v.verb as T.VerbEntry}
|
||||
nouns={nouns}
|
||||
verbs={verbs}
|
||||
opts={textOptions}
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
</main>
|
||||
<Modal show={showingTextOptions} onHide={() => setShowingTextOptions(false)}>
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import * as T from "../types";
|
||||
import Select from "react-select";
|
||||
import AsyncSelect from "react-select/async";
|
||||
import {
|
||||
makeSelectOption,
|
||||
makeVerbSelectOption,
|
||||
zIndexProps,
|
||||
} from "./np-picker/picker-tools";
|
||||
|
||||
function EntrySelect<E extends T.DictionaryEntry | T.VerbEntry>(props: ({
|
||||
entries: E[]
|
||||
} | {
|
||||
searchF: (search: string) => E[],
|
||||
getByTs: (ts: number) => E | undefined,
|
||||
}) & {
|
||||
value: E | undefined,
|
||||
onChange: (value: E | undefined) => void,
|
||||
name: string | undefined,
|
||||
isVerbSelect?: boolean,
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
function makeOption(e: E | T.DictionaryEntry) {
|
||||
if ("entry" in e) {
|
||||
return (props.isVerbSelect ? makeVerbSelectOption : makeSelectOption)(e, props.opts);
|
||||
}
|
||||
return makeSelectOption(e, props.opts);
|
||||
}
|
||||
const value = props.value ? makeOption(props.value) : undefined;
|
||||
if ("searchF" in props) {
|
||||
const options = (searchString: string) =>
|
||||
new Promise<{ value: string, label: string | JSX.Element }[]>(resolve => {
|
||||
resolve(props.searchF(searchString).map(makeOption));
|
||||
});
|
||||
const onChange = (v: { label: string | JSX.Element, value: string } | null) => {
|
||||
if (!v) {
|
||||
props.onChange(undefined);
|
||||
return;
|
||||
}
|
||||
const s = props.getByTs(parseInt(v.value));
|
||||
if (!s) return;
|
||||
props.onChange(s);
|
||||
}
|
||||
return <div>
|
||||
<AsyncSelect
|
||||
isSearchable={true}
|
||||
className="mb-2"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
defaultOptions={[]}
|
||||
loadOptions={options}
|
||||
placeholder={props.name ? `Select ${props.name}...` : undefined}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
const options = props.entries
|
||||
.sort((a, b) => {
|
||||
if ("entry" in a) {
|
||||
return a.entry.p.localeCompare("p" in b ? b.p : b.entry.p, "af-PS")
|
||||
}
|
||||
return a.p.localeCompare("p" in b ? b.p : b.entry.p, "af-PS");
|
||||
})
|
||||
.map(makeOption);
|
||||
const onChange = (v: { label: string | JSX.Element, value: string } | null) => {
|
||||
if (!v) {
|
||||
props.onChange(undefined);
|
||||
return;
|
||||
}
|
||||
const s = props.entries.find(e => (
|
||||
("entry" in e)
|
||||
? e.entry.ts.toString() === v.value
|
||||
: e.ts.toString() === v.value
|
||||
));
|
||||
if (!s) return;
|
||||
props.onChange(s);
|
||||
}
|
||||
return <div>
|
||||
<Select
|
||||
isSearchable={true}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
className="mb-2"
|
||||
options={options}
|
||||
placeholder={props.name ? `Select ${props.name}...` : undefined}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default EntrySelect;
|
|
@ -0,0 +1,163 @@
|
|||
import {
|
||||
makeNounSelection,
|
||||
} from "./picker-tools";
|
||||
import * as T from "../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import InlinePs from "../InlinePs";
|
||||
// import { useState } from "react";
|
||||
// import { isFemNounEntry, isPattern1Entry, isPattern2Entry, isPattern3Entry, isPattern4Entry, isPattern5Entry, isPattern6FemEntry } from "../../lib/type-predicates";
|
||||
import EntrySelect from "../EntrySelect";
|
||||
|
||||
// const filterOptions = [
|
||||
// {
|
||||
// label: "1",
|
||||
// value: "1",
|
||||
// },
|
||||
// {
|
||||
// label: "2",
|
||||
// value: "2",
|
||||
// },
|
||||
// {
|
||||
// label: "3",
|
||||
// value: "3",
|
||||
// },
|
||||
// {
|
||||
// label: "4",
|
||||
// value: "4",
|
||||
// },
|
||||
// {
|
||||
// label: "5",
|
||||
// value: "5",
|
||||
// },
|
||||
// {
|
||||
// label: "6",
|
||||
// value: "6",
|
||||
// },
|
||||
// ];
|
||||
|
||||
// type FilterPattern = "1" | "2" | "3" | "4" | "5" | "6";
|
||||
|
||||
// function nounFilter(p: FilterPattern | undefined) {
|
||||
// return p === undefined
|
||||
// ? () => true
|
||||
// : (p === "1")
|
||||
// ? isPattern1Entry
|
||||
// : (p === "2")
|
||||
// ? isPattern2Entry
|
||||
// : (p === "3")
|
||||
// ? isPattern3Entry
|
||||
// : (p === "4")
|
||||
// ? isPattern4Entry
|
||||
// : (p === "5")
|
||||
// ? isPattern5Entry
|
||||
// : (p === "6")
|
||||
// ? (n: NounEntry) => (isFemNounEntry(n) && isPattern6FemEntry(n))
|
||||
// : () => true;
|
||||
// }
|
||||
|
||||
function NPNounPicker(props: ({
|
||||
nouns: T.NounEntry[],
|
||||
} | {
|
||||
nouns: (s: string) => T.NounEntry[],
|
||||
getNounByTs: (ts: number) => T.NounEntry | undefined;
|
||||
}) & {
|
||||
noun: T.NounSelection | undefined,
|
||||
onChange: (p: T.NounSelection | undefined) => void,
|
||||
clearButton?: JSX.Element,
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
// const [patternFilter, setPatternFilter] = useState<FilterPattern | undefined>(undefined);
|
||||
// const [showFilter, setShowFilter] = useState<boolean>(false)
|
||||
// const nounsFiltered = props.nouns
|
||||
// .filter(nounFilter(patternFilter))
|
||||
// .sort((a, b) => (a.p.localeCompare(b.p, "af-PS")));
|
||||
function onEntrySelect(entry: T.NounEntry | undefined) {
|
||||
if (!entry) {
|
||||
return props.onChange(undefined);
|
||||
}
|
||||
props.onChange(makeNounSelection(entry));
|
||||
}
|
||||
// function handleFilterClose() {
|
||||
// setPatternFilter(undefined);
|
||||
// setShowFilter(false);
|
||||
// }
|
||||
return <div style={{ maxWidth: "225px", minWidth: "125px" }}>
|
||||
<div className="d-flex flex-row justify-content-left">
|
||||
{props.clearButton}
|
||||
{/* {(!showFilter && !(noun?.dynamicComplement)) && <div className="text-right">
|
||||
<button className="btn btn-sm btn-light mb-2 text-small" onClick={() => setShowFilter(true)}>
|
||||
<i className="fas fa-filter fa-xs" />
|
||||
</button>
|
||||
</div>} */}
|
||||
</div>
|
||||
{/* {showFilter && <div className="mb-2 text-center">
|
||||
<div className="d-flex flex-row justify-content-between">
|
||||
<div className="text-small mb-1">Filter by inflection pattern</div>
|
||||
<div className="clickable" onClick={handleFilterClose}>X</div>
|
||||
</div>
|
||||
<ButtonSelect
|
||||
options={filterOptions}
|
||||
// @ts-ignore
|
||||
value={patternFilter}
|
||||
// @ts-ignore
|
||||
handleChange={setPatternFilter}
|
||||
/>
|
||||
</div>} */}
|
||||
{!(props.noun && props.noun.dynamicComplement) ? <div>
|
||||
<EntrySelect
|
||||
value={props.noun?.entry}
|
||||
{..."getNounByTs" in props ? {
|
||||
getByTs: props.getNounByTs,
|
||||
searchF: props.nouns
|
||||
} : {
|
||||
entries: props.nouns,
|
||||
}}
|
||||
onChange={onEntrySelect}
|
||||
name="Noun"
|
||||
opts={props.opts}
|
||||
/>
|
||||
</div> : <div>
|
||||
{props.noun && <div>
|
||||
<div className="mb-2">Included in Dyn. Compound:</div>
|
||||
<div className="mb-3 text-center">
|
||||
<InlinePs opts={props.opts}>
|
||||
{{ p: props.noun.entry.p, f: props.noun.entry.f }}
|
||||
</InlinePs>
|
||||
<div className="text-muted">{props.noun.entry.e}</div>
|
||||
</div>
|
||||
</div>}
|
||||
</div>}
|
||||
{props.noun && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>
|
||||
{props.noun.changeGender ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Masc", value: "masc" },
|
||||
{ label: "Fem", value: "fem" },
|
||||
]}
|
||||
value={props.noun.gender}
|
||||
handleChange={(g) => {
|
||||
if (!props.noun || !props.noun.changeGender) return;
|
||||
props.onChange(props.noun.changeGender(g));
|
||||
}}
|
||||
/> : props.noun.gender === "masc" ? "Masc." : "Fem."}
|
||||
</div>
|
||||
<div>
|
||||
{props.noun.changeNumber ? <ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Sing.", value: "singular" },
|
||||
{ label: "Plur.", value: "plural" },
|
||||
]}
|
||||
value={props.noun.number}
|
||||
handleChange={(n) => {
|
||||
if (!props.noun || !props.noun.changeNumber) return;
|
||||
props.onChange(props.noun.changeNumber(n));
|
||||
}}
|
||||
/> : props.noun.number === "singular" ? "Sing." : "Plur."}
|
||||
</div>
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default NPNounPicker;
|
|
@ -0,0 +1,50 @@
|
|||
import EntrySelect from "../EntrySelect";
|
||||
import * as T from "../../types";
|
||||
|
||||
function makeParticipleSelection(verb: T.VerbEntry): T.ParticipleSelection {
|
||||
return {
|
||||
type: "participle",
|
||||
verb,
|
||||
};
|
||||
}
|
||||
|
||||
function NPParticiplePicker(props: ({
|
||||
verbs: T.VerbEntry[],
|
||||
} | {
|
||||
verbs: (s: string) => T.VerbEntry[],
|
||||
getVerbByTs: (ts: number) => T.VerbEntry | undefined;
|
||||
}) & {
|
||||
participle: T.ParticipleSelection | undefined,
|
||||
onChange: (p: T.ParticipleSelection | undefined) => void,
|
||||
clearButton: JSX.Element,
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
function onEntrySelect(entry: T.VerbEntry | undefined) {
|
||||
if (!entry) {
|
||||
props.onChange(undefined);
|
||||
return;
|
||||
}
|
||||
props.onChange(makeParticipleSelection(entry));
|
||||
}
|
||||
return <div style={{ maxWidth: "225px" }}>
|
||||
{props.clearButton}
|
||||
<EntrySelect
|
||||
value={props.participle?.verb}
|
||||
{..."getVerbByTs" in props ? {
|
||||
getByTs: props.getVerbByTs,
|
||||
searchF: props.verbs,
|
||||
} : {
|
||||
entries: props.verbs,
|
||||
}}
|
||||
onChange={onEntrySelect}
|
||||
name="Pariticple"
|
||||
opts={props.opts}
|
||||
/>
|
||||
{props.participle && <div className="my-2 d-flex flex-row justify-content-around align-items-center">
|
||||
<div>Masc.</div>
|
||||
<div>Plur.</div>
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default NPParticiplePicker;
|
|
@ -0,0 +1,113 @@
|
|||
import PronounPicker from "./NPPronounPicker";
|
||||
import NounPicker from "./NPNounPicker";
|
||||
import ParticiplePicker from "./NPParticiplePicker";
|
||||
// import { getEnglishPronoun } from "../../lib/english-pronoun-tools";
|
||||
// import { ButtonSelect } from "@lingdocs/pashto-inflector";
|
||||
import {
|
||||
randomPerson,
|
||||
} from "../../lib/np-tools";
|
||||
import { useState, useEffect } from "react";
|
||||
import * as T from "../../types";
|
||||
// import { capitalizeFirstLetter } from "../../lib/text-tools";
|
||||
|
||||
const npTypes: T.NPType[] = ["pronoun", "noun", "participle"];
|
||||
|
||||
function NPPicker(props: {
|
||||
onChange: (nps: T.NPSelection | undefined) => void,
|
||||
np: T.NPSelection | undefined,
|
||||
counterPart: T.NPSelection | T.VerbObject | undefined,
|
||||
asObject?: boolean,
|
||||
opts: T.TextOptions,
|
||||
} & ({
|
||||
nouns: (s: string) => T.NounEntry[],
|
||||
verbs: (s: string) => T.VerbEntry[],
|
||||
getNounByTs: (ts: number) => T.NounEntry | undefined,
|
||||
getVerbByTs: (ts: number) => T.VerbEntry | undefined,
|
||||
} | {
|
||||
nouns: T.NounEntry[],
|
||||
verbs: T.VerbEntry[],
|
||||
})) {
|
||||
const [npType, setNpType] = useState<T.NPType | undefined>(props.np ? props.np.type : undefined);
|
||||
useEffect(() => {
|
||||
setNpType(props.np ? props.np.type : undefined);
|
||||
}, [props.np]);
|
||||
function handleClear() {
|
||||
if (props.np && props.np.type === "noun" && props.np.dynamicComplement) return;
|
||||
setNpType(undefined);
|
||||
props.onChange(undefined);
|
||||
}
|
||||
function handleNPTypeChange(ntp: T.NPType) {
|
||||
if (ntp === "pronoun") {
|
||||
const person = randomPerson({ counterPart: props.counterPart });
|
||||
const pronoun: T.PronounSelection = {
|
||||
type: "pronoun",
|
||||
person,
|
||||
distance: "far",
|
||||
};
|
||||
setNpType(ntp);
|
||||
props.onChange(pronoun);
|
||||
} else {
|
||||
props.onChange(undefined);
|
||||
setNpType(ntp);
|
||||
}
|
||||
}
|
||||
const isDynamicComplement = props.np && props.np.type === "noun" && props.np.dynamicComplement;
|
||||
const clearButton = <button className="btn btn-sm btn-light mb-2" onClick={handleClear}>X</button>;
|
||||
return <div>
|
||||
{!npType && <div className="text-center mt-3">
|
||||
{/* <div className="h6 mr-3">
|
||||
Choose NP
|
||||
</div> */}
|
||||
{npTypes.map((npt) => <div className="mb-2">
|
||||
<button
|
||||
key={npt}
|
||||
type="button"
|
||||
className="mr-2 btn btn-sm btn-outline-secondary"
|
||||
onClick={() => handleNPTypeChange(npt)}
|
||||
>
|
||||
{npt}
|
||||
</button>
|
||||
</div>)}
|
||||
</div>}
|
||||
{(npType === "pronoun" && props.np?.type === "pronoun")
|
||||
? <PronounPicker
|
||||
asObject={props.asObject}
|
||||
pronoun={props.np}
|
||||
onChange={props.onChange}
|
||||
clearButton={clearButton}
|
||||
opts={props.opts}
|
||||
/>
|
||||
: npType === "noun"
|
||||
? <NounPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
nouns: props.nouns,
|
||||
getNounByTs: props.getNounByTs,
|
||||
} : {
|
||||
nouns: props.nouns,
|
||||
}}
|
||||
noun={(props.np && props.np.type === "noun") ? props.np : undefined}
|
||||
onChange={props.onChange}
|
||||
clearButton={!isDynamicComplement ? clearButton : undefined}
|
||||
opts={props.opts}
|
||||
/>
|
||||
: npType === "participle"
|
||||
? <ParticiplePicker
|
||||
{..."getVerbByTs" in props ? {
|
||||
verbs: props.verbs,
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
} : {
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
participle={(props.np && props.np.type === "participle") ? props.np : undefined}
|
||||
onChange={props.onChange}
|
||||
clearButton={clearButton}
|
||||
opts={props.opts}
|
||||
/>
|
||||
: null
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
|
||||
// {(npType && !isDynamicComplement) && }
|
||||
|
||||
export default NPPicker;
|
|
@ -0,0 +1,147 @@
|
|||
import * as T from "../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import useStickyState from "../../lib/useStickyState";
|
||||
import classNames from "classnames";
|
||||
|
||||
const gColors = {
|
||||
masc: "LightSkyBlue",
|
||||
fem: "pink",
|
||||
};
|
||||
|
||||
const labels = (asObject: boolean) => ({
|
||||
persons: [
|
||||
["1st", "1st pl."],
|
||||
["2nd", "2nd pl."],
|
||||
["3rd", "3rd pl."],
|
||||
],
|
||||
e: asObject ? [
|
||||
["me", "us"],
|
||||
["you", "you pl."],
|
||||
[{ masc: "him/it", fem: "her/it"}, "them"],
|
||||
] : [
|
||||
["I", "We"],
|
||||
["You", "You pl."],
|
||||
[{ masc: "He/It", fem: "She/It"}, "They"],
|
||||
],
|
||||
p: {
|
||||
far: [
|
||||
["زه", "مونږ"],
|
||||
["ته", "تاسو"],
|
||||
["هغه", "هغوي"],
|
||||
],
|
||||
near: [
|
||||
["زه", "مونږ"],
|
||||
["ته", "تاسو"],
|
||||
[{ masc: "دی", fem: "دا" }, "دوي"],
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
type PickerState = { row: number, col: number, gender: T.Gender };
|
||||
|
||||
function personToPickerState(person: T.Person): PickerState {
|
||||
const col = person > 5 ? 1 : 0;
|
||||
const row = Math.floor((person > 5 ? (person - 6) : person) / 2);
|
||||
const gender: T.Gender = (person % 2) ? "fem" : "masc";
|
||||
return { col, row, gender };
|
||||
}
|
||||
|
||||
function pickerStateToPerson(s: PickerState): T.Person {
|
||||
return (s.row * 2)
|
||||
+ (s.gender === "masc" ? 0 : 1)
|
||||
+ (6 * s.col);
|
||||
}
|
||||
|
||||
function NPPronounPicker({ onChange, pronoun, asObject, clearButton, opts }: {
|
||||
pronoun: T.PronounSelection,
|
||||
onChange: (p: T.PronounSelection) => void,
|
||||
asObject?: boolean,
|
||||
clearButton?: JSX.Element,
|
||||
opts: T.TextOptions,
|
||||
}) {
|
||||
const [display, setDisplay] = useStickyState<"persons" | "p" | "e">("persons", "prounoun-picker-display");
|
||||
|
||||
const p = personToPickerState(pronoun.person);
|
||||
function handleClick(row: number, col: number) {
|
||||
const person = pickerStateToPerson({ ...p, row, col });
|
||||
onChange({
|
||||
...pronoun,
|
||||
person,
|
||||
});
|
||||
}
|
||||
function handleGenderChange(gender: T.Gender) {
|
||||
const person = pickerStateToPerson({ ...p, gender });
|
||||
onChange({
|
||||
...pronoun,
|
||||
person,
|
||||
});
|
||||
}
|
||||
function handlePronounTypeChange(distance: "far" | "near") {
|
||||
onChange({
|
||||
...pronoun,
|
||||
distance,
|
||||
});
|
||||
}
|
||||
function handleDisplayChange() {
|
||||
const newPerson = display === "persons"
|
||||
? "p"
|
||||
: display === "p"
|
||||
? "e"
|
||||
: "persons";
|
||||
setDisplay(newPerson);
|
||||
}
|
||||
const prs = labels(!!asObject)[display];
|
||||
const pSpec = "near" in prs ? prs[pronoun.distance] : prs;
|
||||
return <div style={{ maxWidth: "145px", padding: 0 }}>
|
||||
{clearButton}
|
||||
<div className="d-flex flex-row justify-content-around mb-3">
|
||||
<ButtonSelect
|
||||
xSmall
|
||||
options={[
|
||||
{ label: "Far", value: "far" },
|
||||
{ label: "Near", value: "near" },
|
||||
]}
|
||||
value={pronoun.distance}
|
||||
handleChange={(g) => handlePronounTypeChange(g as "far" | "near")}
|
||||
/>
|
||||
<button className="btn btn-sm btn-outline" onClick={handleDisplayChange}>{display === "persons" ? "#" : display === "p" ? "PS" : "EN"}</button>
|
||||
</div>
|
||||
<table className="table table-bordered table-sm" style={{ textAlign: "center", minWidth: "100px", tableLayout: "fixed" }}>
|
||||
<tbody>
|
||||
{pSpec.map((rw, i) => (
|
||||
<tr>
|
||||
{rw.map((r, j) => {
|
||||
const active = (p.row === i && p.col === j)
|
||||
return <td
|
||||
onClick={() => handleClick(i, j)}
|
||||
className={classNames({ "table-active": active })}
|
||||
style={{
|
||||
backgroundColor: active ? gColors[p.gender] : "inherit",
|
||||
padding: "0.25rem 0",
|
||||
}}
|
||||
>
|
||||
<div className="my-1">
|
||||
{typeof r === "string" ? r : r[p.gender]}
|
||||
</div>
|
||||
</td>;
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<div className="text-center">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: <div style={{ margin: "0.15rem"}}>Masc.</div>, value: "masc", color: gColors.masc },
|
||||
{ label: <div style={{ margin: "0.15rem"}}>Fem.</div>, value: "fem", color: gColors.fem },
|
||||
]}
|
||||
value={p.gender}
|
||||
handleChange={(g) => handleGenderChange(g as T.Gender)}
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default NPPronounPicker;
|
|
@ -0,0 +1,115 @@
|
|||
import {
|
||||
isPluralNounEntry,
|
||||
isMascNounEntry,
|
||||
isUnisexNounEntry,
|
||||
isVerbEntry,
|
||||
} from "../../lib/type-predicates";
|
||||
import {
|
||||
getEnglishParticiple,
|
||||
getEnglishVerb,
|
||||
} from "../../lib/np-tools";
|
||||
import * as T from "../../types";
|
||||
import {
|
||||
removeFVarients,
|
||||
} from "../../lib/accent-and-ps-utils";
|
||||
import {
|
||||
getEnglishWord,
|
||||
} from "../../lib/get-english-word";
|
||||
import { phoneticsToDiacritics } from "../../lib/phonetics-to-diacritics";
|
||||
import {
|
||||
convertSpelling,
|
||||
} from "../../lib/convert-spelling";
|
||||
import {
|
||||
translatePhonetics,
|
||||
} from "../../lib/translate-phonetics";
|
||||
|
||||
export const zIndexProps = {
|
||||
menuPortalTarget: document.body,
|
||||
styles: { menuPortal: (base: any) => ({ ...base, zIndex: 9999 }) },
|
||||
};
|
||||
|
||||
export function makeVerbSelectOption(e: T.VerbEntry, opts: T.TextOptions): { value: string, label: string | JSX.Element } {
|
||||
const eng = getEnglishVerb(e.entry);
|
||||
const ps = plainTextPsAdjustment(
|
||||
{ p: e.entry.p, f: removeFVarients(e.entry.f) },
|
||||
opts,
|
||||
);
|
||||
return {
|
||||
label: `${ps.p} - ${ps.f} (${eng})`,
|
||||
value: e.entry.ts.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
function plainTextPsAdjustment(ps: T.PsString, opts: T.TextOptions): T.PsString {
|
||||
function getP(ps: T.PsString): string {
|
||||
const p = opts.diacritics
|
||||
? (phoneticsToDiacritics(ps.p, ps.f) || ps.p)
|
||||
: ps.p;
|
||||
return convertSpelling(p, opts.spelling);
|
||||
}
|
||||
function getF(f: string): string {
|
||||
if (opts.phonetics === "none") {
|
||||
return "";
|
||||
}
|
||||
return opts.phonetics === "lingdocs"
|
||||
? f
|
||||
: translatePhonetics(f, {
|
||||
dialect: opts.dialect,
|
||||
// @ts-ignore - weird TS not picking up the elimination of "none herre"
|
||||
system: opts.phonetics,
|
||||
});
|
||||
}
|
||||
return { p: getP(ps), f: getF(ps.f) };
|
||||
}
|
||||
|
||||
export function makeSelectOption(
|
||||
e: T.DictionaryEntry | T.VerbEntry | T.NounEntry | T.AdjectiveEntry | T.LocativeAdverbEntry,
|
||||
opts: T.TextOptions,
|
||||
): { value: string, label: string } {
|
||||
const entry = "entry" in e ? e.entry : e;
|
||||
const eng = (isVerbEntry(e))
|
||||
? (getEnglishParticiple(e.entry))
|
||||
: getEnglishWord(e);
|
||||
const english = typeof eng === "string"
|
||||
? eng
|
||||
: !eng
|
||||
? ""
|
||||
: ("singular" in eng && eng.singular !== undefined)
|
||||
? eng.singular
|
||||
: eng.plural;
|
||||
const ps = plainTextPsAdjustment(
|
||||
{ p: entry.p, f: removeFVarients(entry.f) },
|
||||
opts,
|
||||
);
|
||||
return {
|
||||
label: `${ps.p} - ${ps.f} (${english})`,
|
||||
value: entry.ts.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function makeNounSelection(entry: T.NounEntry, dynamicComplement?: true): T.NounSelection {
|
||||
const number = isPluralNounEntry(entry) ? "plural" : "singular";
|
||||
return {
|
||||
type: "noun",
|
||||
entry,
|
||||
gender: isMascNounEntry(entry) ? "masc" : "fem",
|
||||
number,
|
||||
dynamicComplement,
|
||||
...isUnisexNounEntry(entry) ? {
|
||||
changeGender: function(gender: T.Gender): T.NounSelection {
|
||||
return {
|
||||
...this,
|
||||
gender,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
...number === "singular" ? {
|
||||
changeNumber: function(number: T.NounNumber): T.NounSelection {
|
||||
return {
|
||||
...this,
|
||||
number,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
};
|
||||
}
|
|
@ -11,8 +11,8 @@ import InlinePs from "../InlinePs";
|
|||
import Pashto from "../Pashto";
|
||||
import Phonetics from "../Phonetics";
|
||||
import {
|
||||
makePsString
|
||||
} from "../../lib/p-text-helpers";
|
||||
makePsString,
|
||||
} from "../../lib/accent-and-ps-utils";
|
||||
import { Modal } from "react-bootstrap";
|
||||
import stativeCompTrans from "./stative-compound-transitive.svg";
|
||||
import stativeCompIntrans from "./stative-compound-intransitive.svg";
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import ButtonSelect from "../ButtonSelect";
|
||||
import * as T from "../../types";
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: "Full",
|
||||
value: "full",
|
||||
},
|
||||
{
|
||||
label: "🚫 King",
|
||||
value: "noKing",
|
||||
},
|
||||
{
|
||||
label: "👶 Servant",
|
||||
value: "shrinkServant",
|
||||
},
|
||||
{
|
||||
label: "👶 🚫 Both",
|
||||
value: "shortest",
|
||||
},
|
||||
];
|
||||
|
||||
function formToValue(f: T.FormVersion) {
|
||||
if (f.removeKing === false && f.shrinkServant === false) {
|
||||
return "full";
|
||||
}
|
||||
if (f.removeKing === true && f.shrinkServant === false) {
|
||||
return "noKing";
|
||||
}
|
||||
if (f.removeKing === false && f.shrinkServant === true) {
|
||||
return "shrinkServant";
|
||||
}
|
||||
if (f.removeKing === true && f.shrinkServant === true) {
|
||||
return "shortest";
|
||||
}
|
||||
throw new Error("unrecognized abbreviation form");
|
||||
}
|
||||
|
||||
function limitOptions(adjustable: "both" | "king" | "servant") {
|
||||
if (adjustable === "both") {
|
||||
return options;
|
||||
}
|
||||
if (adjustable === "king") {
|
||||
return options.filter(o => !["shrinkServant", "shortest"].includes(o.value));
|
||||
}
|
||||
if (adjustable === "servant") {
|
||||
return options.filter(o => !["noKing", "shortest"].includes(o.value));
|
||||
}
|
||||
}
|
||||
|
||||
function limitValue(value: string, adjustable: "both" | "king" | "servant") {
|
||||
if (adjustable === "both") return value;
|
||||
if (adjustable === "king") {
|
||||
return (value === "shortest")
|
||||
? "noKing"
|
||||
: (value === "shrinkServant")
|
||||
? "full"
|
||||
: value;
|
||||
}
|
||||
if (adjustable === "servant") {
|
||||
return (value === "shortest")
|
||||
? "shrinkServant"
|
||||
: (value === "noKing")
|
||||
? "full"
|
||||
: value;
|
||||
}
|
||||
throw new Error("unrecognized adjustable value");
|
||||
}
|
||||
|
||||
function AbbreviationFormSelector({ form, onChange, adjustable }: {
|
||||
form: T.FormVersion,
|
||||
onChange: (f: T.FormVersion) => void,
|
||||
adjustable: "both" | "king" | "servant",
|
||||
}) {
|
||||
function handleChange(f: "full" | "noKing" | "shrinkServant" | "shortest") {
|
||||
if (f === "full") {
|
||||
onChange({ removeKing: false, shrinkServant: false });
|
||||
} else if (f === "noKing") {
|
||||
onChange({ removeKing: true, shrinkServant: false });
|
||||
} else if (f === "shrinkServant") {
|
||||
onChange({ removeKing: false, shrinkServant: true });
|
||||
} else if (f === "shortest") {
|
||||
onChange({ removeKing: true, shrinkServant: true });
|
||||
}
|
||||
}
|
||||
// TODO: limit display of shrinking options based on the verb type
|
||||
return <div className="mb-3">
|
||||
{/* <div className="text-center text-small mb-2">Abbreviation Options</div> */}
|
||||
<ButtonSelect
|
||||
small
|
||||
// @ts-ignore
|
||||
value={limitValue(formToValue(form), adjustable)}
|
||||
// @ts-ignore
|
||||
options={limitOptions(adjustable)}
|
||||
// @ts-ignore
|
||||
handleChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default AbbreviationFormSelector;
|
|
@ -0,0 +1,27 @@
|
|||
import { getTenseVerbForm } from "../../lib/phrase-building/vp-tools";
|
||||
import VerbFormDisplay from "../VerbFormDisplay";
|
||||
import { conjugateVerb } from "../../lib/verb-conjugation";
|
||||
import * as T from "../../types";
|
||||
|
||||
function ChartDisplay({ VS, opts }: { VS: T.VerbSelection, opts: T.TextOptions }) {
|
||||
const rawConjugations = conjugateVerb(VS.verb.entry, VS.verb.complement);
|
||||
if (!rawConjugations) {
|
||||
return <div>Error conjugating verb</div>;
|
||||
}
|
||||
const conjugations = ("stative" in rawConjugations)
|
||||
? rawConjugations[VS.isCompound === "stative" ? "stative" : "dynamic"]
|
||||
: ("transitive" in rawConjugations)
|
||||
? rawConjugations[VS.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
||||
: rawConjugations;
|
||||
const form = getTenseVerbForm(conjugations, VS.tense, VS.tenseCategory, VS.voice);
|
||||
return <div className="mb-4">
|
||||
<VerbFormDisplay
|
||||
displayForm={form}
|
||||
showingFormInfo={false}
|
||||
textOptions={opts}
|
||||
info={conjugations.info}
|
||||
/>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default ChartDisplay;
|
|
@ -0,0 +1,178 @@
|
|||
import Select from "react-select";
|
||||
import {
|
||||
zIndexProps,
|
||||
} from "../np-picker/picker-tools";
|
||||
import * as T from "../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
|
||||
|
||||
const tenseOptions: { label: string | JSX.Element, value: T.VerbTense }[] = [{
|
||||
label: <div><i className="fas fa-video mr-2" />present</div>,
|
||||
value: "presentVerb",
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />subjunctive</div>,
|
||||
value: "subjunctiveVerb",
|
||||
}, {
|
||||
label: <div><i className="fas fa-video mr-2" />imperfective future</div>,
|
||||
value: "imperfectiveFuture",
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />perfective future</div>,
|
||||
value: "perfectiveFuture",
|
||||
}, {
|
||||
label: <div><i className="fas fa-video mr-2" />continuous past</div>,
|
||||
value: "imperfectivePast",
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />simple past</div>,
|
||||
value: "perfectivePast",
|
||||
}, {
|
||||
label: <div><i className="fas fa-video mr-2" />habitual continual past</div>,
|
||||
value: "habitualImperfectivePast",
|
||||
}, {
|
||||
label: <div><i className="fas fa-camera mr-2" />habitual simple past</div>,
|
||||
value: "habitualPerfectivePast",
|
||||
}];
|
||||
|
||||
const perfectTenseOptions: { label: string | JSX.Element, value: T.PerfectTense }[] = [{
|
||||
label: "Present Perfect",
|
||||
value: "present perfect",
|
||||
}, {
|
||||
label: "Habitual Perfect",
|
||||
value: "habitual perfect",
|
||||
}, {
|
||||
label: "Subjunctive Perfect",
|
||||
value: "subjunctive perfect",
|
||||
}, {
|
||||
label: "Future Perfect",
|
||||
value: "future perfect",
|
||||
}, {
|
||||
label: "Past Perfect",
|
||||
value: "past perfect",
|
||||
}, {
|
||||
label: `"Would Be" Perfect`,
|
||||
value: "wouldBe perfect",
|
||||
}, {
|
||||
label: "Past Subjunctive Perfect",
|
||||
value: "pastSubjunctive perfect",
|
||||
}];
|
||||
|
||||
function TensePicker({ onChange, verb, mode }: {
|
||||
verb: T.VerbSelection | undefined,
|
||||
onChange: (p: T.VerbSelection | undefined) => void,
|
||||
mode: "charts" | "phrases",
|
||||
}) {
|
||||
function onTenseSelect(o: { value: T.VerbTense | T.PerfectTense } | null) {
|
||||
const value = o?.value ? o.value : undefined;
|
||||
if (verb && value) {
|
||||
if (isPerfectTense(value)) {
|
||||
onChange({
|
||||
...verb,
|
||||
tense: value,
|
||||
tenseCategory: "perfect",
|
||||
});
|
||||
} else {
|
||||
onChange({
|
||||
...verb,
|
||||
tense: value,
|
||||
tenseCategory: verb.tenseCategory === "perfect" ? "basic" : verb.tenseCategory,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
function moveTense(dir: "forward" | "back") {
|
||||
if (!verb) return;
|
||||
return () => {
|
||||
const tenses = verb.tenseCategory === "perfect" ? perfectTenseOptions : tenseOptions;
|
||||
const currIndex = tenses.findIndex(tn => tn.value === verb.tense)
|
||||
if (currIndex === -1) {
|
||||
console.error("error moving tense", dir);
|
||||
return;
|
||||
}
|
||||
const newIndex = dir === "forward"
|
||||
? ((currIndex + 1) % tenses.length)
|
||||
: (currIndex === 0 ? (tenses.length - 1) : (currIndex - 1))
|
||||
const newTense = tenses[newIndex];
|
||||
onTenseSelect(newTense);
|
||||
};
|
||||
}
|
||||
function onPosNegSelect(value: string) {
|
||||
if (verb) {
|
||||
onChange({
|
||||
...verb,
|
||||
negative: value === "true",
|
||||
});
|
||||
}
|
||||
}
|
||||
function onTenseCategorySelect(value: "basic" | "modal" | "perfect") {
|
||||
if (verb) {
|
||||
if (value === "perfect") {
|
||||
onChange({
|
||||
...verb,
|
||||
tenseCategory: value,
|
||||
tense: isPerfectTense(verb.tense) ? verb.tense : "present perfect",
|
||||
});
|
||||
} else {
|
||||
onChange({
|
||||
...verb,
|
||||
tenseCategory: value,
|
||||
tense: isPerfectTense(verb.tense) ? "presentVerb" : verb.tense,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const tOptions = (verb?.tenseCategory === "perfect") ? perfectTenseOptions : tenseOptions;
|
||||
return <div>
|
||||
<div style={{ maxWidth: "300px", minWidth: "250px", margin: "0 auto" }}>
|
||||
<div className="d-flex flex-row justify-content-between align-items-center">
|
||||
<div className="h5">Tense:</div>
|
||||
{verb && <div className="mb-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
value={verb.tenseCategory}
|
||||
options={[{
|
||||
label: "Basic",
|
||||
value: "basic",
|
||||
}, {
|
||||
label: "Perfect",
|
||||
value: "perfect",
|
||||
}, {
|
||||
label: "Modal",
|
||||
value: "modal",
|
||||
}]}
|
||||
handleChange={onTenseCategorySelect}
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
<Select
|
||||
isSearchable={false}
|
||||
// for some reason can't use tOptions with find here;
|
||||
value={verb && ([...tenseOptions, ...perfectTenseOptions].find(o => o.value === verb.tense))}
|
||||
onChange={onTenseSelect}
|
||||
className="mb-2"
|
||||
options={tOptions}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
{verb && <div className="d-flex flex-row justify-content-between align-items-center mt-3 mb-1" style={{ width: "100%" }}>
|
||||
<div className="btn btn-light clickable" onClick={moveTense("back")}>
|
||||
<i className="fas fa-chevron-left" />
|
||||
</div>
|
||||
{mode !== "charts" && <ButtonSelect
|
||||
small
|
||||
value={verb.negative.toString()}
|
||||
options={[{
|
||||
label: "Pos.",
|
||||
value: "false",
|
||||
}, {
|
||||
label: "Neg.",
|
||||
value: "true",
|
||||
}]}
|
||||
handleChange={onPosNegSelect}
|
||||
/>}
|
||||
<div onClick={moveTense("forward")} className="btn btn-light clickable">
|
||||
<i className="fas fa-chevron-right" />
|
||||
</div>
|
||||
</div>}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default TensePicker;
|
|
@ -0,0 +1,71 @@
|
|||
import { useState } from "react";
|
||||
import { renderVP, compileVP } from "../../lib/phrase-building/index";
|
||||
import * as T from "../../types";
|
||||
import InlinePs from "../InlinePs";
|
||||
import AbbreviationFormSelector from "./AbbreviationFormSelector";
|
||||
import { isPastTense } from "../../lib/phrase-building/vp-tools";
|
||||
|
||||
function VPDisplay({ VP, opts }: { VP: T.VPSelection, opts: T.TextOptions }) {
|
||||
const [form, setForm] = useState<T.FormVersion>({ removeKing: false, shrinkServant: false });
|
||||
const [OSV, setOSV] = useState<boolean>(false);
|
||||
const result = compileVP(renderVP(VP), { ...form, OSV });
|
||||
return <div className="text-center mt-2">
|
||||
{VP.verb.transitivity === "transitive" && <div className="form-check mb-2">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
checked={OSV}
|
||||
id="OSVCheckbox"
|
||||
onChange={e => setOSV(e.target.checked)}
|
||||
/>
|
||||
<label className="form-check-label text-muted" htmlFor="OSVCheckbox">
|
||||
Include O S V
|
||||
</label>
|
||||
</div>}
|
||||
<AbbreviationFormSelector
|
||||
adjustable={whatsAdjustable(VP)}
|
||||
form={form}
|
||||
onChange={setForm}
|
||||
/>
|
||||
{"long" in result.ps ?
|
||||
<div>
|
||||
{/* <div className="h6">Long Verb:</div> */}
|
||||
<VariationLayer vs={result.ps.long} opts={opts} />
|
||||
{/* <div className="h6">Short Verb:</div> */}
|
||||
<VariationLayer vs={result.ps.short} opts={opts} />
|
||||
{result.ps.mini && <>
|
||||
{/* <div className="h6">Mini Verb:</div> */}
|
||||
<VariationLayer vs={result.ps.mini} opts={opts} />
|
||||
</>}
|
||||
</div>
|
||||
: <VariationLayer vs={result.ps} opts={opts} />
|
||||
}
|
||||
{result.e && <div className="text-muted">
|
||||
{result.e.map((e, i) => <div key={i}>{e}</div>)}
|
||||
</div>}
|
||||
</div>
|
||||
}
|
||||
|
||||
function whatsAdjustable(VP: T.VPSelection): "both" | "king" | "servant" {
|
||||
// TODO: intransitive dynamic compounds?
|
||||
return (VP.verb.isCompound === "dynamic" && VP.verb.transitivity === "transitive")
|
||||
? (isPastTense(VP.verb.tense) ? "servant" : "king")
|
||||
: VP.verb.transitivity === "transitive"
|
||||
? "both"
|
||||
: VP.verb.transitivity === "intransitive"
|
||||
? "king"
|
||||
// grammTrans
|
||||
: isPastTense(VP.verb.tense)
|
||||
? "servant"
|
||||
: "king";
|
||||
}
|
||||
|
||||
function VariationLayer({ vs, opts }: { vs: T.PsString[], opts: T.TextOptions }) {
|
||||
return <div className="mb-2">
|
||||
{vs.map((r, i) => <div key={i}>
|
||||
<InlinePs opts={opts}>{r}</InlinePs>
|
||||
</div>)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default VPDisplay;
|
|
@ -0,0 +1,214 @@
|
|||
import NPPicker from "../np-picker/NPPicker";
|
||||
import VerbPicker from "./VerbPicker";
|
||||
import TensePicker from "./TensePicker";
|
||||
import VPDisplay from "./VPDisplay";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { renderVP } from "../../lib/phrase-building/index";
|
||||
import {
|
||||
isInvalidSubjObjCombo,
|
||||
} from "../../lib/phrase-building/vp-tools";
|
||||
import * as T from "../../types";
|
||||
import ChartDisplay from "./ChartDisplay";
|
||||
import useStickyState from "../../lib/useStickyState";
|
||||
import { makeVerbSelection } from "./verb-selection";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const kingEmoji = "👑";
|
||||
const servantEmoji = "🙇♂️";
|
||||
|
||||
// TODO: Drill Down text display options
|
||||
|
||||
// TODO: SHOW KING AND SERVANT ONCE TENSE PICKED, EVEN IF NPs not selected
|
||||
// TODO: Issue with dynamic compounds english making with plurals
|
||||
// TODO: Issue with "the money were taken"
|
||||
// TODO: Use the same component for PronounPicker and NPPronounPicker (sizing issue)
|
||||
// get the practice pronoun picker page into a typesafe file
|
||||
// A little button you can press on the tense select to show the formula and info about the tense
|
||||
// in a popup
|
||||
// TODO: option to show 3 modes Phrases - Charts - Quiz
|
||||
|
||||
// TODO: error handling on error with rendering etc
|
||||
export function VPExplorer(props: {
|
||||
verb?: T.VerbEntry,
|
||||
opts: T.TextOptions,
|
||||
} & ({
|
||||
nouns: T.NounEntry[],
|
||||
verbs: T.VerbEntry[],
|
||||
} | {
|
||||
nouns: (s: string) => T.NounEntry[],
|
||||
verbs: (s: string) => T.VerbEntry[],
|
||||
getNounByTs: (ts: number) => T.NounEntry | undefined,
|
||||
getVerbByTs: (ts: number) => T.VerbEntry | undefined,
|
||||
})) {
|
||||
const [subject, setSubject] = useStickyState<T.NPSelection | undefined>(undefined, "subjectNPSelection");
|
||||
const [mode, setMode] = useStickyState<"charts" | "phrases">("phrases", "verbExplorerMode");
|
||||
const passedVerb = props.verb;
|
||||
const [verb, setVerb] = useStickyState<T.VerbSelection | undefined>(
|
||||
passedVerb
|
||||
? (old) => makeVerbSelection(passedVerb, setSubject, old)
|
||||
: undefined,
|
||||
"verbExplorerVerb",
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!passedVerb) {
|
||||
setVerb(undefined);
|
||||
} else {
|
||||
setVerb(o => makeVerbSelection(passedVerb, setSubject, o));
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
}, [passedVerb]);
|
||||
function handleSubjectChange(subject: T.NPSelection | undefined, skipPronounConflictCheck?: boolean) {
|
||||
if (!skipPronounConflictCheck && hasPronounConflict(subject, verb?.object)) {
|
||||
alert("That combination of pronouns is not allowed");
|
||||
return;
|
||||
}
|
||||
setSubject(subject);
|
||||
}
|
||||
function handleObjectChange(object: T.NPSelection | undefined) {
|
||||
if (!verb) return;
|
||||
if ((verb.object === "none") || (typeof verb.object === "number")) return;
|
||||
// check for pronoun conflict
|
||||
if (hasPronounConflict(subject, object)) {
|
||||
alert("That combination of pronouns is not allowed");
|
||||
return;
|
||||
}
|
||||
setVerb({ ...verb, object });
|
||||
}
|
||||
function handleSubjObjSwap() {
|
||||
if (verb?.isCompound === "dynamic") return;
|
||||
const output = switchSubjObj({ subject, verb });
|
||||
setSubject(output.subject);
|
||||
setVerb(output.verb);
|
||||
}
|
||||
const verbPhrase: T.VPSelection | undefined = verbPhraseComplete({ subject, verb });
|
||||
const VPRendered = verbPhrase && renderVP(verbPhrase);
|
||||
return <div className="mt-3" style={{ maxWidth: "950px"}}>
|
||||
<VerbPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
verbs: props.verbs,
|
||||
} : {
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
verbLocked={!!props.verb}
|
||||
verb={verb}
|
||||
subject={subject}
|
||||
changeSubject={(s) => handleSubjectChange(s, true)}
|
||||
onChange={setVerb}
|
||||
opts={props.opts}
|
||||
/>
|
||||
<div className="mt-2 mb-3">
|
||||
<ButtonSelect
|
||||
value={mode}
|
||||
options={[
|
||||
{ label: "Charts", value: "charts" },
|
||||
{ label: "Phrases", value: "phrases" },
|
||||
]}
|
||||
handleChange={setMode}
|
||||
/>
|
||||
</div>
|
||||
{(verb && (typeof verb.object === "object") && (verb.isCompound !== "dynamic") && (mode !== "charts")) &&
|
||||
<div className="text-center mt-4">
|
||||
<button onClick={handleSubjObjSwap} className="btn btn-sm btn-light">
|
||||
<i className="fas fa-exchange-alt mr-2" /> subj/obj
|
||||
</button>
|
||||
</div>}
|
||||
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
|
||||
{mode !== "charts" && <>
|
||||
<div className="my-2">
|
||||
<div className="h5 text-center">Subject {showRole(VPRendered, "subject")}</div>
|
||||
<NPPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
getNounByTs: props.getNounByTs,
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
} : {
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
np={subject}
|
||||
counterPart={verb ? verb.object : undefined}
|
||||
onChange={handleSubjectChange}
|
||||
opts={props.opts}
|
||||
/>
|
||||
</div>
|
||||
{verb && (verb.object !== "none") && <div className="my-2">
|
||||
<div className="h5 text-center">Object {showRole(VPRendered, "object")}</div>
|
||||
{(typeof verb.object === "number")
|
||||
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
|
||||
: <NPPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
getNounByTs: props.getNounByTs,
|
||||
getVerbByTs: props.getVerbByTs,
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
} : {
|
||||
nouns: props.nouns,
|
||||
verbs: props.verbs,
|
||||
}}
|
||||
asObject
|
||||
np={verb.object}
|
||||
counterPart={subject}
|
||||
onChange={handleObjectChange}
|
||||
opts={props.opts}
|
||||
/>}
|
||||
</div>}
|
||||
</>}
|
||||
<div className="my-2">
|
||||
<TensePicker
|
||||
verb={verb}
|
||||
onChange={setVerb}
|
||||
mode={mode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{(verbPhrase && (mode === "phrases")) &&
|
||||
<VPDisplay VP={verbPhrase} opts={props.opts} />
|
||||
}
|
||||
{(verb && (mode === "charts")) && <ChartDisplay VS={verb} opts={props.opts} />}
|
||||
</div>
|
||||
}
|
||||
|
||||
export default VPExplorer;
|
||||
|
||||
function hasPronounConflict(subject: T.NPSelection | undefined, object: undefined | T.VerbObject): boolean {
|
||||
const subjPronoun = (subject && subject.type === "pronoun") ? subject : undefined;
|
||||
const objPronoun = (object && typeof object === "object" && object.type === "pronoun") ? object : undefined;
|
||||
if (!subjPronoun || !objPronoun) return false;
|
||||
return isInvalidSubjObjCombo(subjPronoun.person, objPronoun.person);
|
||||
}
|
||||
|
||||
function verbPhraseComplete({ subject, verb }: { subject: T.NPSelection | undefined, verb: T.VerbSelection | undefined }): T.VPSelection | undefined {
|
||||
if (!subject) return undefined;
|
||||
if (!verb) return undefined;
|
||||
if (verb.object === undefined) return undefined;
|
||||
return {
|
||||
type: "VPSelection",
|
||||
subject,
|
||||
object: verb.object,
|
||||
verb,
|
||||
};
|
||||
}
|
||||
|
||||
function showRole(VP: T.VPRendered | undefined, member: "subject" | "object") {
|
||||
return VP
|
||||
? <span className="ml-2">
|
||||
{(VP.king === member ? kingEmoji : VP.servant === member ? servantEmoji : "")}
|
||||
</span>
|
||||
: "";
|
||||
}
|
||||
|
||||
type SOClump = { subject: T.NPSelection | undefined, verb: T.VerbSelection | undefined };
|
||||
function switchSubjObj({ subject, verb }: SOClump): SOClump {
|
||||
if (!subject|| !verb || !verb.object || !(typeof verb.object === "object")) {
|
||||
return { subject, verb };
|
||||
}
|
||||
return {
|
||||
subject: verb.object,
|
||||
verb: {
|
||||
...verb,
|
||||
object: subject,
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
import * as T from "../../types";
|
||||
import ButtonSelect from "../ButtonSelect";
|
||||
import { RootsAndStems } from "../verb-info/VerbInfo";
|
||||
import { getVerbInfo } from "../../lib/verb-info";
|
||||
import Hider from "../Hider";
|
||||
import { makeVerbSelection } from "./verb-selection";
|
||||
import EntrySelect from "../EntrySelect";
|
||||
import useStickyState from "../../lib/useStickyState";
|
||||
|
||||
|
||||
// TODO: dark on past tense selecitons
|
||||
|
||||
function VerbPicker(props: ({
|
||||
verbs: T.VerbEntry[],
|
||||
} | {
|
||||
verbs: (s: string) => T.VerbEntry[],
|
||||
getVerbByTs: (ts: number) => T.VerbEntry | undefined;
|
||||
}) & {
|
||||
verb: T.VerbSelection | undefined,
|
||||
subject: T.NPSelection | undefined,
|
||||
onChange: (p: T.VerbSelection | undefined) => void,
|
||||
changeSubject: (p: T.NPSelection | undefined) => void,
|
||||
opts: T.TextOptions,
|
||||
verbLocked: boolean,
|
||||
}) {
|
||||
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
|
||||
const infoRaw = props.verb ? getVerbInfo(props.verb.verb.entry, props.verb.verb.complement) : undefined;
|
||||
const info = (!infoRaw || !props.verb)
|
||||
? undefined
|
||||
: ("stative" in infoRaw)
|
||||
? infoRaw[props.verb.isCompound === "stative" ? "stative" : "dynamic"]
|
||||
: ("transitive" in infoRaw)
|
||||
? infoRaw[props.verb.transitivity === "grammatically transitive" ? "grammaticallyTransitive" : "transitive"]
|
||||
: infoRaw;
|
||||
if (info && ("stative" in info || "transitive" in info)) {
|
||||
return <div>ERROR: Verb version should be select first</div>;
|
||||
}
|
||||
// const [filters, useFilters] = useState<Filters>({
|
||||
// stative: true,
|
||||
// dynamic: true,
|
||||
// transitive: true,
|
||||
// intransitive: true,
|
||||
// grammaticallyTransitive: true,
|
||||
// });
|
||||
function onVerbSelect(v: T.VerbEntry | undefined) {
|
||||
// TODO: what to do when clearing
|
||||
if (!v) {
|
||||
return props.onChange(v);
|
||||
}
|
||||
props.onChange(makeVerbSelection(v, props.changeSubject, props.verb));
|
||||
}
|
||||
function onVoiceSelect(value: "active" | "passive") {
|
||||
if (props.verb && props.verb.changeVoice) {
|
||||
if (value === "passive" && (typeof props.verb.object === "object")) {
|
||||
props.changeSubject(props.verb.object);
|
||||
}
|
||||
if (value === "active") {
|
||||
props.changeSubject(undefined);
|
||||
}
|
||||
props.onChange(props.verb.changeVoice(value, value === "active" ? props.subject : undefined));
|
||||
}
|
||||
}
|
||||
function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" {
|
||||
return t === "intransitive" ? "transitive" : t;
|
||||
}
|
||||
function handleChangeTransitivity(t: "transitive" | "grammatically transitive") {
|
||||
if (props.verb && props.verb.changeTransitivity) {
|
||||
props.onChange(props.verb.changeTransitivity(t));
|
||||
}
|
||||
}
|
||||
function handleChangeStatDyn(c: "stative" | "dynamic") {
|
||||
if (props.verb && props.verb.changeStatDyn) {
|
||||
props.onChange(props.verb.changeStatDyn(c));
|
||||
}
|
||||
}
|
||||
return <div className="mb-3">
|
||||
{!props.verbLocked && <div style={{ maxWidth: "300px", margin: "0 auto" }}>
|
||||
<div className="h5">Verb:</div>
|
||||
<EntrySelect
|
||||
{..."getVerbByTs" in props ? {
|
||||
searchF: props.verbs,
|
||||
getByTs: props.getVerbByTs,
|
||||
} : {
|
||||
entries: props.verbs,
|
||||
}}
|
||||
value={props.verb?.verb}
|
||||
onChange={onVerbSelect}
|
||||
name="Verb"
|
||||
isVerbSelect
|
||||
opts={props.opts}
|
||||
/>
|
||||
</div>}
|
||||
{info && <div className="mt-3 mb-1 text-center">
|
||||
<Hider
|
||||
showing={showRootsAndStems}
|
||||
label="🌳 Roots and Stems"
|
||||
handleChange={() => setShowRootsAndStems(p => !p)}
|
||||
hLevel={5}
|
||||
>
|
||||
<RootsAndStems
|
||||
textOptions={props.opts}
|
||||
info={info}
|
||||
/>
|
||||
</Hider>
|
||||
</div>}
|
||||
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ maxWidth: "400px", margin: "0 auto" }}>
|
||||
{props.verb && props.verb.changeTransitivity && <div className="text-center my-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[{
|
||||
label: "gramm. trans.",
|
||||
value: "grammatically transitive",
|
||||
}, {
|
||||
label: "trans.",
|
||||
value: "transitive",
|
||||
}]}
|
||||
value={notInstransitive(props.verb.transitivity)}
|
||||
handleChange={handleChangeTransitivity}
|
||||
/>
|
||||
</div>}
|
||||
{props.verb && props.verb.changeVoice && <div className="text-center my-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
value={props.verb.voice}
|
||||
options={[{
|
||||
label: "Active",
|
||||
value: "active",
|
||||
}, {
|
||||
label: "Passive",
|
||||
value: "passive",
|
||||
}]}
|
||||
handleChange={onVoiceSelect}
|
||||
/>
|
||||
</div>}
|
||||
{props.verb && props.verb.changeStatDyn && <div className="text-center my-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[{
|
||||
label: "stative",
|
||||
value: "stative",
|
||||
}, {
|
||||
label: "dynamic",
|
||||
value: "dynamic",
|
||||
}]}
|
||||
value={props.verb.isCompound ? props.verb.isCompound : "stative"}
|
||||
handleChange={handleChangeStatDyn}
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
|
||||
export default VerbPicker;
|
|
@ -0,0 +1,106 @@
|
|||
import {
|
||||
makeNounSelection,
|
||||
} from "../np-picker/picker-tools";
|
||||
import * as T from "../../types";
|
||||
import { getVerbInfo } from "../../lib/verb-info";
|
||||
import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
|
||||
|
||||
export function makeVerbSelection(verb: T.VerbEntry, changeSubject: (s: T.NPSelection | undefined) => void, oldVerbSelection?: T.VerbSelection): T.VerbSelection {
|
||||
const info = getVerbInfo(verb.entry, verb.complement);
|
||||
function getTransObjFromOldVerbSelection() {
|
||||
if (
|
||||
!oldVerbSelection ||
|
||||
oldVerbSelection.object === "none" ||
|
||||
typeof oldVerbSelection.object === "number" ||
|
||||
oldVerbSelection.isCompound === "dynamic" ||
|
||||
(oldVerbSelection.object?.type === "noun" && oldVerbSelection.object.dynamicComplement)
|
||||
) return undefined;
|
||||
return oldVerbSelection.object;
|
||||
}
|
||||
const transitivity: T.Transitivity = "grammaticallyTransitive" in info
|
||||
? "transitive"
|
||||
: info.transitivity;
|
||||
const object = (transitivity === "grammatically transitive")
|
||||
? T.Person.ThirdPlurMale
|
||||
: (info.type === "dynamic compound" && oldVerbSelection?.voice !== "passive")
|
||||
? makeNounSelection(info.objComplement.entry as T.NounEntry, true)
|
||||
: (transitivity === "transitive" && oldVerbSelection?.voice !== "passive")
|
||||
? getTransObjFromOldVerbSelection()
|
||||
: "none";
|
||||
if (oldVerbSelection?.voice === "passive" && info.type === "dynamic compound") {
|
||||
changeSubject(makeNounSelection(info.objComplement.entry as T.NounEntry, true));
|
||||
}
|
||||
const isCompound = ("stative" in info || info.type === "stative compound")
|
||||
? "stative"
|
||||
: info.type === "dynamic compound"
|
||||
? "dynamic"
|
||||
: false;
|
||||
// TODO: here and below in the changeStatDyn function ... allow for entries with complement
|
||||
const dynAuxVerb: T.VerbEntry | undefined = isCompound !== "dynamic"
|
||||
? undefined
|
||||
: info.type === "dynamic compound"
|
||||
? { entry: info.auxVerb } as T.VerbEntry
|
||||
: "dynamic" in info
|
||||
? { entry: info.dynamic.auxVerb } as T.VerbEntry
|
||||
: undefined;
|
||||
const tenseSelection = ((): { tenseCategory: "perfect", tense: T.PerfectTense } | {
|
||||
tenseCategory: "basic" | "modal",
|
||||
tense: T.VerbTense,
|
||||
} => {
|
||||
if (!oldVerbSelection) {
|
||||
return { tense: "presentVerb", tenseCategory: "basic" };
|
||||
}
|
||||
if (oldVerbSelection.tenseCategory === "modal") {
|
||||
return { tenseCategory: "modal", tense: isPerfectTense(oldVerbSelection.tense) ? "presentVerb" : oldVerbSelection.tense };
|
||||
}
|
||||
if (oldVerbSelection.tenseCategory === "basic") {
|
||||
return { tenseCategory: "basic", tense: isPerfectTense(oldVerbSelection.tense) ? "presentVerb" : oldVerbSelection.tense };
|
||||
}
|
||||
return { tenseCategory: "perfect", tense: isPerfectTense(oldVerbSelection.tense) ? oldVerbSelection.tense : "present perfect" };
|
||||
})();
|
||||
return {
|
||||
type: "verb",
|
||||
verb: verb,
|
||||
dynAuxVerb,
|
||||
...tenseSelection,
|
||||
object,
|
||||
transitivity,
|
||||
isCompound,
|
||||
voice: transitivity === "transitive"
|
||||
? (oldVerbSelection?.voice || "active")
|
||||
: "active",
|
||||
negative: oldVerbSelection ? oldVerbSelection.negative : false,
|
||||
...("grammaticallyTransitive" in info) ? {
|
||||
changeTransitivity: function(t) {
|
||||
return {
|
||||
...this,
|
||||
transitivity: t,
|
||||
object: t === "grammatically transitive" ? T.Person.ThirdPlurMale : undefined,
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
...("stative" in info) ? {
|
||||
changeStatDyn: function(c) {
|
||||
return {
|
||||
...this,
|
||||
isCompound: c,
|
||||
object: c === "dynamic"
|
||||
? makeNounSelection(info.dynamic.objComplement.entry as T.NounEntry, true)
|
||||
: undefined,
|
||||
dynAuxVerb: c === "dynamic"
|
||||
? { entry: info.dynamic.auxVerb } as T.VerbEntry
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
} : {},
|
||||
...(transitivity === "transitive") ? {
|
||||
changeVoice: function(v, s) {
|
||||
return {
|
||||
...this,
|
||||
voice: v,
|
||||
object: v === "active" ? s : "none",
|
||||
};
|
||||
},
|
||||
} : {},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import { removeFVarients, makePsString } from "./accent-and-ps-utils";
|
||||
|
||||
test(`removeFVarients`, () => {
|
||||
expect(removeFVarients("ist'imaal, istimaal")).toBe("ist'imaal");
|
||||
expect(removeFVarients({ p: "معالوم", f: "ma'aalóom, maalóom" }))
|
||||
.toEqual({ p: "معالوم", f: "ma'aalóom" });
|
||||
expect(removeFVarients("kor")).toBe("kor");
|
||||
});
|
||||
|
||||
test(`makePsString should work`, () => {
|
||||
expect(makePsString("کور", "kor")).toEqual({ p: "کور", f: "kor" });
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
import * as T from "../types";
|
||||
|
||||
/**
|
||||
* Creates a Pashto string structure
|
||||
*
|
||||
* @param p - the Pashto text
|
||||
* @param f - the phonetics text
|
||||
*/
|
||||
export function makePsString(p: string, f: string): T.PsString {
|
||||
return { p, f };
|
||||
}
|
||||
|
||||
export function removeFVarients(x: T.DictionaryEntry): T.DictionaryEntryNoFVars;
|
||||
export function removeFVarients(x: T.PsString): T.PsStringNoFVars;
|
||||
export function removeFVarients(x: string): T.FStringNoFVars;
|
||||
export function removeFVarients(x: string | T.PsString | T.DictionaryEntry): T.FStringNoFVars | T.PsStringNoFVars | T.DictionaryEntryNoFVars {
|
||||
if (typeof x === "string") {
|
||||
return x.split(",")[0] as T.FStringNoFVars;
|
||||
}
|
||||
if ("ts" in x) {
|
||||
return {
|
||||
...x,
|
||||
f: removeFVarients(x.f),
|
||||
} as unknown as T.DictionaryEntryNoFVars;
|
||||
}
|
||||
return {
|
||||
...x,
|
||||
f: removeFVarients(x.f),
|
||||
} as unknown as T.PsStringNoFVars;
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { makePsString } from "./p-text-helpers";
|
||||
import { makePsString } from "./accent-and-ps-utils";
|
||||
import {
|
||||
accentOnFront,
|
||||
accentPastParticiple,
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import { makePsString, removeFVarients } from "./p-text-helpers";
|
||||
import * as T from "../types";
|
||||
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
|
||||
|
||||
/**
|
||||
* Returns a Pashto string (or string with Length options) ensuring that
|
||||
|
|
|
@ -29,7 +29,7 @@ import {
|
|||
PhonemeStatus,
|
||||
} from "./diacritics-helpers";
|
||||
|
||||
import { removeFVarients } from "./p-text-helpers";
|
||||
import { removeFVarients } from "./accent-and-ps-utils";
|
||||
import { pipe } from "rambda";
|
||||
|
||||
/**
|
||||
|
|
|
@ -152,6 +152,7 @@ export function randomNumber(minInclusive: number, maxExclusive: number): number
|
|||
return Math.floor(Math.random() * (maxExclusive - minInclusive) + minInclusive);
|
||||
}
|
||||
|
||||
// TODO: deprecate this because we have it in np-tools?
|
||||
/**
|
||||
* Sees if a possiblePerson (for subject/object) is possible, given the other person
|
||||
*
|
||||
|
@ -173,6 +174,7 @@ export function personIsAllowed(possiblePerson: T.Person, existingPerson?: T.Per
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO: deprecate this because we have it in np-tools?
|
||||
/**
|
||||
* Picks a random person while assuring that the other person is not in conflict
|
||||
*
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
import * as T from "../types";
|
||||
import { parseEc } from "../lib/misc-helpers";
|
||||
|
||||
function getRandPers(): T.Person {
|
||||
return Math.floor(Math.random() * 12);
|
||||
}
|
||||
|
||||
export function randomPerson(a?: { prev?: T.Person, counterPart?: T.VerbObject | T.NPSelection }) {
|
||||
// no restrictions, just get any person
|
||||
if (!a) {
|
||||
return getRandPers();
|
||||
}
|
||||
if (a.counterPart !== undefined && typeof a.counterPart === "object" && a.counterPart.type === "pronoun") {
|
||||
// with counterpart pronoun
|
||||
let newP = 0;
|
||||
do {
|
||||
newP = getRandPers();
|
||||
} while (
|
||||
isInvalidSubjObjCombo(a.counterPart.person, newP)
|
||||
||
|
||||
(newP === a.prev)
|
||||
);
|
||||
return newP;
|
||||
}
|
||||
// without counterpart pronoun, just previous
|
||||
let newP = 0;
|
||||
do {
|
||||
newP = getRandPers();
|
||||
} while (newP === a.prev);
|
||||
return newP;
|
||||
}
|
||||
|
||||
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||
const firstPeople = [
|
||||
T.Person.FirstSingMale,
|
||||
T.Person.FirstSingFemale,
|
||||
T.Person.FirstPlurMale,
|
||||
T.Person.FirstPlurFemale,
|
||||
];
|
||||
const secondPeople = [
|
||||
T.Person.SecondSingMale,
|
||||
T.Person.SecondSingFemale,
|
||||
T.Person.SecondPlurMale,
|
||||
T.Person.SecondPlurFemale,
|
||||
];
|
||||
return (
|
||||
(firstPeople.includes(subj) && firstPeople.includes(obj))
|
||||
||
|
||||
(secondPeople.includes(subj) && secondPeople.includes(obj))
|
||||
);
|
||||
}
|
||||
|
||||
export function randomSubjObj(old?: { subj: T.Person, obj: T.Person }): { subj: T.Person, obj: T.Person } {
|
||||
let subj = 0;
|
||||
let obj = 0;
|
||||
do {
|
||||
subj = getRandPers();
|
||||
obj = getRandPers();
|
||||
} while (
|
||||
(old && ((old.subj === subj) || (old.obj === obj)))
|
||||
||
|
||||
isInvalidSubjObjCombo(subj, obj)
|
||||
);
|
||||
return { subj, obj };
|
||||
}
|
||||
export function getEnglishVerb(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored verb");
|
||||
console.log(entry);
|
||||
throw new Error("no english information for verb");
|
||||
}
|
||||
if (entry.ep) {
|
||||
const ec = entry.ec.includes(",") ? parseEc(entry.ec)[0] : entry.ec;
|
||||
return `to ${ec} ${entry.ep}`;
|
||||
}
|
||||
const ec = parseEc(entry.ec);
|
||||
return `to ${ec[0]}`;
|
||||
}
|
||||
|
||||
export function getEnglishParticiple(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored participle");
|
||||
console.log(entry);
|
||||
throw new Error("no english information for participle");
|
||||
}
|
||||
const ec = parseEc(entry.ec);
|
||||
const participle = ec[2];
|
||||
return (entry.ep)
|
||||
? `${participle} ${entry.ep}`
|
||||
: participle;
|
||||
}
|
|
@ -5,10 +5,9 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
*/
|
||||
|
||||
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
|
||||
import {
|
||||
concatPsString,
|
||||
makePsString,
|
||||
removeEndingL,
|
||||
yulEndingInfinitive,
|
||||
mapVerbBlock,
|
||||
|
@ -22,7 +21,6 @@ import {
|
|||
splitDoubleWord,
|
||||
endsInConsonant,
|
||||
addOEnding,
|
||||
removeFVarients,
|
||||
endsInShwa,
|
||||
splitPsByVarients,
|
||||
endsWith,
|
||||
|
@ -701,8 +699,8 @@ test(`splitDoubleWord should work`, () => {
|
|||
c: "adj.",
|
||||
i: 1,
|
||||
},
|
||||
]
|
||||
expect(splitDoubleWord(orig)).toEqual(out);
|
||||
];
|
||||
expect(splitDoubleWord(removeFVarients(orig))).toEqual(out);
|
||||
});
|
||||
|
||||
// test(`allThirdPersMascPlur should work`, () => {
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import {
|
||||
inflectRegularYeyUnisex,
|
||||
} from "./pashto-inflector";
|
||||
import { baParticle } from "./grammar-units";
|
||||
import {
|
||||
getVerbBlockPosFromPerson,
|
||||
|
@ -21,6 +18,7 @@ import {
|
|||
} from "./accent-helpers";
|
||||
import { phoneticsConsonants } from "./pashto-consonants";
|
||||
import { simplifyPhonetics } from "./simplify-phonetics";
|
||||
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
|
||||
|
||||
// export function concatPsStringWithVars(...items: Array<T.PsString | " " | "">): T.PsString[] {
|
||||
|
||||
|
@ -182,25 +180,6 @@ export function ensureBaAt(ps: T.FullForm<T.PsString>, pos: number): T.FullForm<
|
|||
return baInserted;
|
||||
}
|
||||
|
||||
export function removeFVarients(x: T.DictionaryEntry): T.DictionaryEntryNoFVars;
|
||||
export function removeFVarients(x: T.PsString): T.PsStringNoFVars;
|
||||
export function removeFVarients(x: string): T.FStringNoFVars;
|
||||
export function removeFVarients(x: string | T.PsString | T.DictionaryEntry): T.FStringNoFVars | T.PsStringNoFVars | T.DictionaryEntryNoFVars {
|
||||
if (typeof x === "string") {
|
||||
return x.split(",")[0] as T.FStringNoFVars;
|
||||
}
|
||||
if ("ts" in x) {
|
||||
return {
|
||||
...x,
|
||||
f: removeFVarients(x.f),
|
||||
} as unknown as T.DictionaryEntryNoFVars;
|
||||
}
|
||||
return {
|
||||
...x,
|
||||
f: removeFVarients(x.f),
|
||||
} as unknown as T.PsStringNoFVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lets us know if all the forms of a verb block are the same
|
||||
*
|
||||
|
@ -214,16 +193,6 @@ export function isAllOne (block: T.VerbBlock | T.ImperativeBlock): boolean {
|
|||
), true) as unknown as boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Pashto string structure
|
||||
*
|
||||
* @param p - the Pashto text
|
||||
* @param f - the phonetics text
|
||||
*/
|
||||
export function makePsString(p: string, f: string): T.PsString {
|
||||
return { p, f };
|
||||
}
|
||||
|
||||
/**
|
||||
* Retuns a Pashto string with the ل - ul on the end removed
|
||||
*
|
||||
|
@ -635,15 +604,7 @@ export function removeRetroflexR(ps: T.PsString): T.PsString {
|
|||
};
|
||||
}
|
||||
|
||||
export function inflectYey(ps: T.SingleOrLengthOpts<T.PsString>): T.SingleOrLengthOpts<T.UnisexInflections> {
|
||||
if ("long" in ps) {
|
||||
return {
|
||||
long: inflectYey(ps.long) as T.UnisexInflections,
|
||||
short: inflectYey(ps.short) as T.UnisexInflections,
|
||||
}
|
||||
}
|
||||
return inflectRegularYeyUnisex(ps.p, ps.f);
|
||||
}
|
||||
|
||||
|
||||
export function clamp(s: string, chars: number): string {
|
||||
return `${s.slice(0, 20)}${s.length > 20 ? "..." : ""}`;
|
||||
|
@ -1011,3 +972,25 @@ export function endsWith(
|
|||
: true)
|
||||
);
|
||||
}
|
||||
|
||||
export function firstVariation(s: string): string {
|
||||
return s.split(/[,|;]/)[0].trim();
|
||||
}
|
||||
|
||||
export function psStringFromEntry(entry: T.PsString): T.PsString {
|
||||
return {
|
||||
p: entry.p,
|
||||
f: removeFVarients(entry.f),
|
||||
};
|
||||
}
|
||||
|
||||
export function getLong<U>(x: T.SingleOrLengthOpts<U>): U {
|
||||
if ("long" in x) {
|
||||
return x.long;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
export function capitalizeFirstLetter(string: string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
|
@ -11,8 +11,6 @@ import {
|
|||
concatInflections,
|
||||
splitDoubleWord,
|
||||
ensureUnisexInflections,
|
||||
makePsString,
|
||||
removeFVarients,
|
||||
concatPsString,
|
||||
endsInConsonant,
|
||||
endsInAaOrOo,
|
||||
|
@ -22,6 +20,7 @@ import {
|
|||
removeEndTick,
|
||||
endsWith,
|
||||
} from "./p-text-helpers";
|
||||
import { makePsString, removeFVarients } from "./accent-and-ps-utils";
|
||||
import {
|
||||
accentFSylsOnNFromEnd,
|
||||
hasAccents,
|
||||
|
@ -625,3 +624,13 @@ function makePlural(w: T.DictionaryEntryNoFVars): { plural: T.PluralInflections
|
|||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function inflectYey(ps: T.SingleOrLengthOpts<T.PsString>): T.SingleOrLengthOpts<T.UnisexInflections> {
|
||||
if ("long" in ps) {
|
||||
return {
|
||||
long: inflectYey(ps.long) as T.UnisexInflections,
|
||||
short: inflectYey(ps.short) as T.UnisexInflections,
|
||||
}
|
||||
}
|
||||
return inflectRegularYeyUnisex(ps.p, ps.f);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,386 @@
|
|||
import * as T from "../../types";
|
||||
import {
|
||||
concatPsString,
|
||||
} from "../p-text-helpers";
|
||||
import { makePsString } from "../accent-and-ps-utils";
|
||||
import {
|
||||
removeAccents,
|
||||
} from "../accent-helpers";
|
||||
import { getVerbBlockPosFromPerson } from "../misc-helpers";
|
||||
import * as grammarUnits from "../grammar-units";
|
||||
import {
|
||||
removeBa,
|
||||
removeDuplicates,
|
||||
} from "./vp-tools";
|
||||
|
||||
type Form = T.FormVersion & { OSV?: boolean };
|
||||
export function compileVP(VP: T.VPRendered, form: Form): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] };
|
||||
export function compileVP(VP: T.VPRendered, form: Form, combineLengths: true): { ps: T.PsString[], e?: string [] };
|
||||
export function compileVP(VP: T.VPRendered, form: Form, combineLengths?: true): { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string [] } {
|
||||
const verb = VP.verb.ps;
|
||||
const { kids, NPs } = getSegmentsAndKids(VP, form);
|
||||
const psResult = compilePs({
|
||||
NPs,
|
||||
kids,
|
||||
verb,
|
||||
VP,
|
||||
});
|
||||
return {
|
||||
ps: combineLengths ? flattenLengths(psResult) : psResult,
|
||||
// TODO: English doesn't quite work for dynamic compounds in passive voice
|
||||
e: (VP.verb.voice === "passive" && VP.isCompound === "dynamic") ? undefined : compileEnglish(VP),
|
||||
};
|
||||
}
|
||||
|
||||
type CompilePsInput = {
|
||||
NPs: Segment[][],
|
||||
kids: Segment[],
|
||||
verb: {
|
||||
head: T.PsString | undefined,
|
||||
rest: T.SingleOrLengthOpts<T.PsString[]>,
|
||||
},
|
||||
VP: T.VPRendered,
|
||||
}
|
||||
function compilePs({ NPs, kids, verb: { head, rest }, VP }: CompilePsInput): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
if ("long" in rest) {
|
||||
return {
|
||||
long: compilePs({ NPs, verb: { head, rest: rest.long }, VP, kids }) as T.PsString[],
|
||||
short: compilePs({ NPs, verb: { head, rest: rest.short }, VP, kids }) as T.PsString[],
|
||||
...rest.mini ? {
|
||||
mini: compilePs({ NPs, verb: { head, rest: rest.mini }, VP, kids }) as T.PsString[],
|
||||
} : {},
|
||||
};
|
||||
}
|
||||
const verbWNegativeVersions = arrangeVerbWNegative(head, rest, VP.verb);
|
||||
|
||||
// put together all the different possible permutations based on:
|
||||
// a. potential different versions of where the nu goes
|
||||
return removeDuplicates(verbWNegativeVersions.flatMap((verbSegments) => (
|
||||
// b. potential reordering of NPs
|
||||
NPs.flatMap(NP => {
|
||||
// for each permutation of the possible ordering of NPs and Verb + nu
|
||||
// 1. put in kids in the kids section
|
||||
const segments = putKidsInKidsSection([...NP, ...verbSegments], kids);
|
||||
// 2. space out the words properly
|
||||
const withProperSpaces = addSpacesBetweenSegments(segments);
|
||||
// 3. throw it all together into a PsString for each permutation
|
||||
return combineSegments(withProperSpaces);
|
||||
})
|
||||
)));
|
||||
}
|
||||
|
||||
function getSegmentsAndKids(VP: T.VPRendered, form: Form): { kids: Segment[], NPs: Segment[][] } {
|
||||
const SO = {
|
||||
subject: VP.subject.ps,
|
||||
object: typeof VP.object === "object" ? VP.object.ps : undefined,
|
||||
}
|
||||
const removeKing = form.removeKing && !(VP.isCompound === "dynamic" && VP.isPast);
|
||||
const shrinkServant = form.shrinkServant && !(VP.isCompound === "dynamic" && !VP.isPast);
|
||||
|
||||
const toShrink = (() => {
|
||||
if (!shrinkServant) return undefined;
|
||||
if (!VP.servant) return undefined;
|
||||
const servant = VP[VP.servant];
|
||||
if (typeof servant !== "object") return undefined;
|
||||
return servant;
|
||||
})();
|
||||
function getSegment(t: "subject" | "object"): Segment | undefined {
|
||||
const word = (VP.servant === t)
|
||||
? (!shrinkServant ? SO[t] : undefined)
|
||||
: (VP.king === t)
|
||||
? (!removeKing ? SO[t] : undefined)
|
||||
: undefined;
|
||||
if (!word) return undefined;
|
||||
return makeSegment(word);
|
||||
}
|
||||
const subject = getSegment("subject");
|
||||
const object = getSegment("object");
|
||||
|
||||
return {
|
||||
kids: [
|
||||
...VP.verb.hasBa
|
||||
? [makeSegment(grammarUnits.baParticle, ["isBa", "isKid"])] : [],
|
||||
...toShrink
|
||||
? [shrinkNP(toShrink)] : [],
|
||||
],
|
||||
NPs: [
|
||||
[
|
||||
...subject ? [subject] : [],
|
||||
...object ? [object] : [],
|
||||
],
|
||||
// TODO: make this an option to also include O S V order ??
|
||||
// also show O S V if both are showing
|
||||
...(subject && object && form.OSV) ? [[object, subject]] : [],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function putKidsInKidsSection(segments: Segment[], kids: Segment[]): Segment[] {
|
||||
const first = segments[0];
|
||||
const rest = segments.slice(1);
|
||||
return [
|
||||
first,
|
||||
// TODO: simplify to just isKidAfterHead ??
|
||||
...(first.isVerbHead && rest[0] && rest[0].isVerbRest)
|
||||
? kids.map(k => k.adjust({ desc: ["isKidBetweenHeadAndRest"] }))
|
||||
: kids,
|
||||
...rest,
|
||||
];
|
||||
}
|
||||
|
||||
function arrangeVerbWNegative(head: T.PsString | undefined, restRaw: T.PsString[], V: T.VerbRendered): Segment[][] {
|
||||
const hasLeapfrog = V.tenseCategory === "modal" || V.tenseCategory === "perfect";
|
||||
const rest = (() => {
|
||||
if (hasLeapfrog) {
|
||||
const [restF, restLast] = splitOffLeapfrogWord(restRaw);
|
||||
return {
|
||||
front: makeSegment(restF.map(removeBa), ["isVerbRest"]),
|
||||
last: makeSegment(restLast.map(removeBa), ["isVerbRest"]),
|
||||
};
|
||||
}
|
||||
return makeSegment(restRaw.map(removeBa), ["isVerbRest"]);
|
||||
})();
|
||||
const headSegment: Segment | undefined = !head
|
||||
? head
|
||||
: makeSegment(
|
||||
head,
|
||||
(head.p === "و" || head.p === "وا")
|
||||
? ["isVerbHead", "isOoOrWaaHead"]
|
||||
: ["isVerbHead"]
|
||||
);
|
||||
if (!V.negative) {
|
||||
if ("front" in rest) {
|
||||
return [
|
||||
headSegment ? [headSegment, rest.front, rest.last] : [rest.front, rest.last],
|
||||
]
|
||||
}
|
||||
return [
|
||||
headSegment ? [headSegment, rest] : [rest],
|
||||
];
|
||||
}
|
||||
const nu: T.PsString = { p: "نه", f: "nú" };
|
||||
if (!headSegment) {
|
||||
if ("front" in rest) {
|
||||
return [
|
||||
// pefect nu dey me leeduley and nu me dey leeduley
|
||||
[
|
||||
mergeSegments(
|
||||
makeSegment(nu, ["isNu"]),
|
||||
rest.last.adjust({ ps: removeAccents }),
|
||||
),
|
||||
rest.front.adjust({ ps: removeAccents }),
|
||||
],
|
||||
[
|
||||
makeSegment(nu, ["isNu"]),
|
||||
rest.last.adjust({ ps: removeAccents }),
|
||||
rest.front.adjust({ ps: removeAccents }),
|
||||
],
|
||||
[
|
||||
rest.front.adjust({ ps: removeAccents }),
|
||||
makeSegment(nu, ["isNu"]),
|
||||
rest.last.adjust({ ps: removeAccents }),
|
||||
],
|
||||
];
|
||||
}
|
||||
return [[
|
||||
makeSegment(nu, ["isNu"]),
|
||||
rest.adjust({ ps: removeAccents }),
|
||||
]];
|
||||
}
|
||||
if ("front" in rest) {
|
||||
return [
|
||||
[
|
||||
headSegment.adjust({ ps: removeAccents }),
|
||||
rest.last.adjust({
|
||||
ps: r => concatPsString(nu, " ", removeAccents(r)),
|
||||
desc: ["isNu"],
|
||||
}),
|
||||
rest.front.adjust({
|
||||
ps: r => removeAccents(r),
|
||||
}),
|
||||
],
|
||||
[
|
||||
headSegment.adjust({ ps: removeAccents }),
|
||||
rest.front.adjust({
|
||||
ps: r => concatPsString(nu, " ", removeAccents(r)),
|
||||
desc: ["isNu"],
|
||||
}),
|
||||
rest.last.adjust({
|
||||
ps: r => removeAccents(r),
|
||||
}),
|
||||
],
|
||||
...(!headSegment.isOoOrWaaHead && !V.isCompound) ? [[
|
||||
mergeSegments(headSegment, rest.front, "no space").adjust({
|
||||
ps: r => concatPsString(nu, " ", removeAccents(r)),
|
||||
desc: ["isNu"],
|
||||
}),
|
||||
rest.last.adjust({
|
||||
ps: r => removeAccents(r),
|
||||
}),
|
||||
]] : [],
|
||||
];
|
||||
}
|
||||
return [
|
||||
...(V.voice !== "passive") ? [[
|
||||
...headSegment ? [headSegment.adjust({ ps: removeAccents })] : [],
|
||||
rest.adjust({
|
||||
ps: r => concatPsString(nu, " ", removeAccents(r)),
|
||||
desc: ["isNu"],
|
||||
}),
|
||||
]] : [],
|
||||
// verbs that have a perfective prefix that is not و or وا can put the
|
||||
// nu *before* the prefix as well // TODO: also وي prefixes?
|
||||
...((!headSegment.isOoOrWaaHead && !V.isCompound) || (V.voice === "passive")) ? [[
|
||||
makeSegment(nu, ["isNu"]),
|
||||
headSegment.adjust({ ps: removeAccents }),
|
||||
rest.adjust({ ps: removeAccents }),
|
||||
]] : [],
|
||||
];
|
||||
}
|
||||
|
||||
function shrinkNP(np: T.Rendered<T.NPSelection>): Segment {
|
||||
const [row, col] = getVerbBlockPosFromPerson(np.person);
|
||||
return makeSegment(grammarUnits.pronouns.mini[row][col], ["isKid", "isMiniPronoun"]);
|
||||
}
|
||||
|
||||
function mergeSegments(s1: Segment, s2: Segment, noSpace?: "no space"): Segment {
|
||||
if (noSpace) {
|
||||
return s2.adjust({ ps: (p) => concatPsString(s1.ps[0], p) });
|
||||
}
|
||||
return s2.adjust({ ps: (p) => concatPsString(s1.ps[0], " ", p) });
|
||||
}
|
||||
|
||||
function addSpacesBetweenSegments(segments: Segment[]): (Segment | " " | "" | T.PsString)[] {
|
||||
const o: (Segment | " " | "" | T.PsString)[] = [];
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const current = segments[i];
|
||||
const next = segments[i+1];
|
||||
o.push(current);
|
||||
if (!next) break;
|
||||
if (
|
||||
// stative compound part
|
||||
!current.ps[0].p.endsWith(" ")
|
||||
&&
|
||||
(
|
||||
(next.isKidBetweenHeadAndRest || next.isNu)
|
||||
||
|
||||
(next.isVerbRest && current.isKidBetweenHeadAndRest)
|
||||
)
|
||||
) {
|
||||
o.push({
|
||||
f: " ", // TODO: make this "-" in the right places
|
||||
p: ((current.isVerbHead && (next.isMiniPronoun || next.isNu))
|
||||
|| (current.isOoOrWaaHead && (next.isBa || next.isNu))) ? "" : " ", // or if its waa head
|
||||
});
|
||||
} else if (current.isVerbHead && next.isVerbRest) {
|
||||
o.push("");
|
||||
} else {
|
||||
o.push(" ");
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
function compileEnglish(VP: T.VPRendered): string[] | undefined {
|
||||
function insertEWords(e: string, { subject, object }: { subject: string, object?: string }): string {
|
||||
return e.replace("$SUBJ", subject).replace("$OBJ", object || "");
|
||||
}
|
||||
const engSubj = VP.subject.e || undefined;
|
||||
const engObj = (typeof VP.object === "object" && VP.object.e) ? VP.object.e : undefined;
|
||||
// require all English parts for making the English phrase
|
||||
return (VP.englishBase && engSubj && (engObj || typeof VP.object !== "object"))
|
||||
? VP.englishBase.map(e => insertEWords(e, {
|
||||
subject: engSubj,
|
||||
object: engObj,
|
||||
}))
|
||||
: undefined;
|
||||
}
|
||||
|
||||
// SEGMENT TOOLS
|
||||
// TODO: PULL OUT FOR SHARING ACROSS COMPILE EP ETC?
|
||||
|
||||
type SegmentDescriptions = {
|
||||
isVerbHead?: boolean,
|
||||
isOoOrWaaHead?: boolean,
|
||||
isVerbRest?: boolean,
|
||||
isMiniPronoun?: boolean,
|
||||
isKid?: boolean,
|
||||
// TODO: Simplify to just isKidAfterHead?
|
||||
isKidBetweenHeadAndRest?: boolean,
|
||||
isNu?: boolean,
|
||||
isBa?: boolean,
|
||||
}
|
||||
|
||||
type SDT = keyof SegmentDescriptions;
|
||||
type Segment = { ps: T.PsString[] } & SegmentDescriptions & {
|
||||
adjust: (o: { ps?: T.PsString | T.PsString[] | ((ps: T.PsString) => T.PsString), desc?: SDT[] }) => Segment,
|
||||
};
|
||||
|
||||
function makeSegment(
|
||||
ps: T.PsString | T.PsString[],
|
||||
options?: (keyof SegmentDescriptions)[],
|
||||
): Segment {
|
||||
return {
|
||||
ps: Array.isArray(ps) ? ps : [ps],
|
||||
...options && options.reduce((all, curr) => ({
|
||||
...all,
|
||||
[curr]: true,
|
||||
}), {}),
|
||||
adjust: function(o): Segment {
|
||||
return {
|
||||
...this,
|
||||
...o.ps ? {
|
||||
ps: Array.isArray(o.ps)
|
||||
? o.ps
|
||||
: "p" in o.ps
|
||||
? [o.ps]
|
||||
: this.ps.map(o.ps)
|
||||
} : {},
|
||||
...o.desc && o.desc.reduce((all, curr) => ({
|
||||
...all,
|
||||
[curr]: true,
|
||||
}), {}),
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function combineSegments(loe: (Segment | " " | "" | T.PsString)[]): T.PsString[] {
|
||||
const first = loe[0];
|
||||
const rest = loe.slice(1);
|
||||
if (!rest.length) {
|
||||
if (typeof first === "string" || !("ps" in first)) {
|
||||
throw new Error("can't end with a spacer");
|
||||
}
|
||||
return first.ps;
|
||||
}
|
||||
return combineSegments(rest).flatMap(r => (
|
||||
(typeof first === "object" && "ps" in first)
|
||||
? first.ps.map(f => concatPsString(f, r))
|
||||
: [concatPsString(first, r)]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function flattenLengths(r: T.SingleOrLengthOpts<T.PsString[]>): T.PsString[] {
|
||||
if ("long" in r) {
|
||||
return Object.values(r).flat();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function splitOffLeapfrogWord(psVs: T.PsString[]): [T.PsString[], T.PsString[]] {
|
||||
return psVs.reduce((tp, ps) => {
|
||||
const pWords = ps.p.split(" ");
|
||||
const fWords = ps.f.split(" ");
|
||||
const beginning = makePsString(
|
||||
pWords.slice(0, -1).join(" "),
|
||||
fWords.slice(0, -1).join(" "),
|
||||
);
|
||||
const end = makePsString(
|
||||
pWords.slice(-1).join(" "),
|
||||
fWords.slice(-1).join(" "),
|
||||
);
|
||||
return [[...tp[0], beginning], [...tp[1], end]];
|
||||
}, [[], []] as [T.PsString[], T.PsString[]]);
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
import * as T from "../../types";
|
||||
import { getVerbBlockPosFromPerson, parseEc } from "../misc-helpers";
|
||||
import * as grammarUnits from "../grammar-units";
|
||||
|
||||
function engHave(s: T.Person): string {
|
||||
function isThirdPersonSing(p: T.Person): boolean {
|
||||
return (
|
||||
p === T.Person.ThirdSingMale ||
|
||||
p === T.Person.ThirdSingFemale
|
||||
);
|
||||
}
|
||||
return isThirdPersonSing(s) ? "has" : "have";
|
||||
}
|
||||
|
||||
export function renderEnglishVPBase({ subjectPerson, object, vs }: {
|
||||
subjectPerson: T.Person,
|
||||
object: T.NPSelection | T.ObjectNP,
|
||||
vs: T.VerbSelection,
|
||||
}): string[] {
|
||||
const ec = parseEc(vs.verb.entry.ec || "");
|
||||
const ep = vs.verb.entry.ep;
|
||||
function engEquative(tense: "past" | "present", s: T.Person): string {
|
||||
const [row, col] = getVerbBlockPosFromPerson(s);
|
||||
return grammarUnits.englishEquative[tense][row][col];
|
||||
}
|
||||
function engPresC(s: T.Person, ec: T.EnglishVerbConjugationEc | [string, string]): string {
|
||||
function isThirdPersonSing(p: T.Person): boolean {
|
||||
return (
|
||||
p === T.Person.ThirdSingMale ||
|
||||
p === T.Person.ThirdSingFemale
|
||||
);
|
||||
}
|
||||
return isThirdPersonSing(s) ? ec[1] : ec[0];
|
||||
}
|
||||
function isToBe(v: T.EnglishVerbConjugationEc): boolean {
|
||||
return (v[2] === "being");
|
||||
}
|
||||
const futureEngBuilder: T.EnglishBuilder = (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
]);
|
||||
// TODO: Pull these out to a seperate entity and import it
|
||||
const basicBuilders: Record<
|
||||
T.VerbTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
presentVerb: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${isToBe(ec)
|
||||
? `${engEquative("present", s)}${n ? " not" : ""}`
|
||||
: `${n ? engPresC(s, ["don't", "doesn't"]) : ""} ${n ? ec[0] : engPresC(s, ec)}`}`,
|
||||
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} ${ec[2]}`,
|
||||
]),
|
||||
subjunctiveVerb: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`that $SUBJ ${n ? " won't" : " will"} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
`should $SUBJ ${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
]),
|
||||
imperfectiveFuture: futureEngBuilder,
|
||||
perfectiveFuture: futureEngBuilder,
|
||||
imperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
// - subj pastEquative (N && "not") ec.2 obj
|
||||
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${ec[2]}`,
|
||||
// - subj "would" (N && "not") ec.0 obj
|
||||
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
// - subj pastEquative (N && "not") going to" ec.0 obj
|
||||
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} going to ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
]),
|
||||
perfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ${isToBe(ec)
|
||||
? ` ${engEquative("past", s)}${n ? " not" : ""}`
|
||||
: (n ? ` did not ${ec[0]}` : ` ${ec[3]}`)
|
||||
}`
|
||||
]),
|
||||
habitualPerfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
`$SUBJ used to${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
]),
|
||||
habitualImperfectivePast: (s: T.Person, ec: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
`$SUBJ used to${n ? " not" : ""} ${isToBe(ec) ? "be" : ec[0]}`,
|
||||
]),
|
||||
};
|
||||
const modalBuilders: Record<
|
||||
T.VerbTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`that $SUBJ can${n ? "'t" : ""} ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
`$SUBJ could${n ? " not" : ""} ${v[0]}`,
|
||||
]),
|
||||
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engEquative("past", s)} ${n ? " not" : ""} able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
`$SUBJ could${n ? " not" : ""} ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
`$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ used to ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
`$SUBJ would ${n ? " not" : ""} be able to ${isToBe(v) ? "be" : v[0]}`,
|
||||
]),
|
||||
};
|
||||
const perfectBuilders: Record<
|
||||
T.PerfectTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
"present perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`,
|
||||
]),
|
||||
"past perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ had${n ? " not" : ""} ${v[4]}`,
|
||||
]),
|
||||
"habitual perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engHave(s)}${n ? " not" : ""} ${v[4]}`,
|
||||
]),
|
||||
"subjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`that $SUBJ will have${n ? " not" : ""} ${v[4]}`,
|
||||
]),
|
||||
"future perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} have ${v[4]}`,
|
||||
]),
|
||||
"wouldBe perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} have ${v[4]}`,
|
||||
]),
|
||||
"pastSubjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} have ${v[4]}`,
|
||||
`$SUBJ should${n ? " not" : ""} have ${v[4]}`,
|
||||
]),
|
||||
}
|
||||
const passiveBasicBuilders: Record<
|
||||
T.VerbTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} being ${v[4]}`,
|
||||
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} ${v[4]}`,
|
||||
]),
|
||||
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`that $SUBJ will${n ? " not" : ""} be ${v[4]}`,
|
||||
]),
|
||||
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} be ${v[4]}`,
|
||||
]),
|
||||
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} be ${v[4]}`,
|
||||
]),
|
||||
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} being ${v[4]}`,
|
||||
`$SUBJ would${n ? " not" : ""} be ${v[4]}`,
|
||||
]),
|
||||
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} ${v[4]}`,
|
||||
]),
|
||||
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} be ${v[4]}`,
|
||||
]),
|
||||
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} be ${v[4]}`,
|
||||
]),
|
||||
};
|
||||
const passivePerfectBuilders: Record<
|
||||
T.PerfectTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
"present perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`,
|
||||
]),
|
||||
"past perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ had${n ? " not" : ""} been ${v[4]}`,
|
||||
]),
|
||||
"habitual perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engHave(s)}${n ? " not" : ""} been ${v[4]}`,
|
||||
]),
|
||||
"subjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`that $SUBJ will${n ? " not" : ""} have been ${v[4]}`,
|
||||
]),
|
||||
"future perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} have been ${v[4]}`,
|
||||
]),
|
||||
"wouldBe perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} have been ${v[4]}`,
|
||||
]),
|
||||
"pastSubjunctive perfect": (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} have been ${v[4]}`,
|
||||
]),
|
||||
}
|
||||
const passiveModalBuilders: Record<
|
||||
T.VerbTense,
|
||||
(s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => string[]
|
||||
> = {
|
||||
presentVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ can${n ? " not" : ""} be ${v[4]}`,
|
||||
`$SUBJ ${engEquative("present", s)}${n ? " not" : ""} able to be ${v[4]}`,
|
||||
]),
|
||||
subjunctiveVerb: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`that $SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
`that $SUBJ ${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
]),
|
||||
imperfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
]),
|
||||
perfectiveFuture: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ will${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
]),
|
||||
imperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} being able to be ${v[4]}`,
|
||||
]),
|
||||
perfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ ${engEquative("past", s)}${n ? " not" : ""} able to be ${v[4]}`,
|
||||
]),
|
||||
habitualPerfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
]),
|
||||
habitualImperfectivePast: (s: T.Person, v: T.EnglishVerbConjugationEc, n: boolean) => ([
|
||||
`$SUBJ would${n ? " not" : ""} be able to be ${v[4]}`,
|
||||
]),
|
||||
};
|
||||
const base = (
|
||||
(vs.tenseCategory === "perfect")
|
||||
? (vs.voice === "active" ? perfectBuilders : passivePerfectBuilders)[vs.tense]
|
||||
: vs.tenseCategory === "basic"
|
||||
? (vs.voice === "active" ? basicBuilders : passiveBasicBuilders)[vs.tense]
|
||||
: (vs.voice === "active" ? modalBuilders : passiveModalBuilders)[vs.tense])(subjectPerson, ec, vs.negative);
|
||||
return base.map(b => `${b}${typeof object === "object" ? " $OBJ" : ""}${ep ? ` ${ep}` : ""}`);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { renderVP } from "./render-vp";
|
||||
import { compileVP } from "./compile-vp";
|
||||
|
||||
export {
|
||||
renderVP,
|
||||
compileVP,
|
||||
};
|
|
@ -0,0 +1,344 @@
|
|||
import * as T from "../../types";
|
||||
import { parseEc } from "../../lib/misc-helpers";
|
||||
import { inflectWord } from "../pashto-inflector";
|
||||
import { getEnglishWord } from "../get-english-word";
|
||||
import * as grammarUnits from "../grammar-units";
|
||||
import {
|
||||
getVerbBlockPosFromPerson,
|
||||
getPersonNumber,
|
||||
} from "../misc-helpers";
|
||||
import { conjugateVerb } from "../verb-conjugation";
|
||||
import {
|
||||
concatPsString,
|
||||
hasBaParticle,
|
||||
psStringFromEntry,
|
||||
getLong,
|
||||
} from "../p-text-helpers";
|
||||
import { removeAccents } from "../accent-helpers";
|
||||
import {
|
||||
getPersonFromNP,
|
||||
removeBa,
|
||||
isPastTense,
|
||||
isPerfectTense,
|
||||
getTenseVerbForm,
|
||||
} from "./vp-tools";
|
||||
import { isPattern4Entry } from "../type-predicates";
|
||||
import { renderEnglishVPBase } from "./english-vp-rendering";
|
||||
|
||||
// TODO: ISSUE GETTING SPLIT HEAD NOT MATCHING WITH FUTURE VERBS
|
||||
|
||||
export function renderVP(VP: T.VPSelection): T.VPRendered {
|
||||
// Sentence Rules Logic
|
||||
const isPast = isPastTense(VP.verb.tense);
|
||||
const isTransitive = VP.object !== "none";
|
||||
const { king, servant } = getKingAndServant(isPast, isTransitive);
|
||||
const kingPerson = getPersonFromNP(VP[king]);
|
||||
// TODO: more elegant way of handling this type safety
|
||||
if (kingPerson === undefined) {
|
||||
throw new Error("king of sentance does not exist");
|
||||
}
|
||||
const subjectPerson = getPersonFromNP(VP.subject);
|
||||
const objectPerson = getPersonFromNP(VP.object);
|
||||
// TODO: also don't inflect if it's a pattern one animate noun
|
||||
const inflectSubject = isPast && isTransitive && !isMascSingAnimatePattern4(VP.subject);
|
||||
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object);
|
||||
// Render Elements
|
||||
return {
|
||||
type: "VPRendered",
|
||||
king,
|
||||
servant,
|
||||
isPast,
|
||||
isTransitive,
|
||||
isCompound: VP.verb.isCompound,
|
||||
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"),
|
||||
object: renderNPSelection(VP.object, inflectObject, true, "object"),
|
||||
verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
|
||||
englishBase: renderEnglishVPBase({
|
||||
subjectPerson,
|
||||
object: VP.verb.isCompound === "dynamic" ? "none" : VP.object,
|
||||
vs: VP.verb,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
export function renderNPSelection(NP: T.NPSelection, inflected: boolean, inflectEnglish: boolean, role: "subject"): T.Rendered<T.NPSelection>
|
||||
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "object"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none";
|
||||
export function renderNPSelection(NP: T.NPSelection | T.ObjectNP, inflected: boolean, inflectEnglish: boolean, role: "subject" | "object"): T.Rendered<T.NPSelection> | T.Person.ThirdPlurMale | "none" {
|
||||
if (typeof NP !== "object") {
|
||||
if (role !== "object") {
|
||||
throw new Error("ObjectNP only allowed for objects");
|
||||
}
|
||||
return NP;
|
||||
}
|
||||
if (NP.type === "noun") {
|
||||
return renderNounSelection(NP, inflected);
|
||||
}
|
||||
if (NP.type === "pronoun") {
|
||||
return renderPronounSelection(NP, inflected, inflectEnglish);
|
||||
}
|
||||
if (NP.type === "participle") {
|
||||
return renderParticipleSelection(NP, inflected)
|
||||
}
|
||||
throw new Error("unknown NP type");
|
||||
};
|
||||
|
||||
function renderNounSelection(n: T.NounSelection, inflected: boolean): T.Rendered<T.NounSelection> {
|
||||
const english = getEnglishFromNoun(n.entry, n.number);
|
||||
const pashto = ((): T.PsString[] => {
|
||||
const infs = inflectWord(n.entry);
|
||||
const ps = n.number === "singular"
|
||||
? getInf(infs, "inflections", n.gender, false, inflected)
|
||||
: [
|
||||
...getInf(infs, "plural", n.gender, true, inflected),
|
||||
...getInf(infs, "arabicPlural", n.gender, true, inflected),
|
||||
...getInf(infs, "inflections", n.gender, true, inflected),
|
||||
];
|
||||
return ps.length > 0
|
||||
? ps
|
||||
: [psStringFromEntry(n.entry)];
|
||||
})();
|
||||
return {
|
||||
...n,
|
||||
person: getPersonNumber(n.gender, n.number),
|
||||
inflected,
|
||||
ps: pashto,
|
||||
e: english,
|
||||
};
|
||||
}
|
||||
|
||||
function renderPronounSelection(p: T.PronounSelection, inflected: boolean, englishInflected: boolean): T.Rendered<T.PronounSelection> {
|
||||
const [row, col] = getVerbBlockPosFromPerson(p.person);
|
||||
return {
|
||||
...p,
|
||||
inflected,
|
||||
ps: grammarUnits.pronouns[p.distance][inflected ? "inflected" : "plain"][row][col],
|
||||
e: grammarUnits.persons[p.person].label[englishInflected ? "object" : "subject"],
|
||||
};
|
||||
}
|
||||
|
||||
function renderParticipleSelection(p: T.ParticipleSelection, inflected: boolean): T.Rendered<T.ParticipleSelection> {
|
||||
return {
|
||||
...p,
|
||||
inflected,
|
||||
person: T.Person.ThirdPlurMale,
|
||||
// TODO: More robust inflection of inflecting pariticiples - get from the conjugation engine
|
||||
ps: [psStringFromEntry(p.verb.entry)].map(ps => inflected ? concatPsString(ps, { p: "و", f: "o" }) : ps),
|
||||
e: getEnglishParticiple(p.verb.entry),
|
||||
};
|
||||
}
|
||||
|
||||
function renderVerbSelection(vs: T.VerbSelection, person: T.Person, objectPerson: T.Person | undefined): T.VerbRendered {
|
||||
const v = vs.dynAuxVerb || vs.verb;
|
||||
const conjugations = conjugateVerb(v.entry, v.complement);
|
||||
// TODO: error handle this?
|
||||
const conj = "grammaticallyTransitive" in conjugations
|
||||
// if there's an option for grammatically transitive or transitive
|
||||
// will default to transitive
|
||||
? conjugations.transitive
|
||||
: "stative" in conjugations
|
||||
// TODO: option to manually select stative/dynamic
|
||||
? conjugations.stative
|
||||
: conjugations;
|
||||
return {
|
||||
...vs,
|
||||
person,
|
||||
...getPsVerbConjugation(conj, vs, person, objectPerson),
|
||||
}
|
||||
}
|
||||
|
||||
function getPsVerbConjugation(conj: T.VerbConjugation, vs: T.VerbSelection, person: T.Person, objectPerson: T.Person | undefined): {
|
||||
ps: {
|
||||
head: T.PsString | undefined,
|
||||
rest: T.SingleOrLengthOpts<T.PsString[]>,
|
||||
},
|
||||
hasBa: boolean,
|
||||
} {
|
||||
const f = getTenseVerbForm(conj, vs.tense, vs.tenseCategory, vs.voice);
|
||||
const block = getMatrixBlock(f, objectPerson, person);
|
||||
const perfective = isPerfective(vs.tense);
|
||||
const verbForm = getVerbFromBlock(block, person);
|
||||
const hasBa = hasBaParticle(getLong(verbForm)[0]);
|
||||
if (perfective) {
|
||||
const past = isPastTense(vs.tense);
|
||||
const splitInfo = conj.info[past ? "root" : "stem"].perfectiveSplit;
|
||||
if (!splitInfo) return { ps: { head: undefined, rest: verbForm }, hasBa };
|
||||
// TODO: Either solve this in the inflector or here, it seems silly (or redundant)
|
||||
// to have a length option in the perfective split stem??
|
||||
const [splitHead] = getLong(getMatrixBlock(splitInfo, objectPerson, person));
|
||||
const ps = getHeadAndRest(splitHead, verbForm);
|
||||
return {
|
||||
hasBa,
|
||||
ps,
|
||||
};
|
||||
}
|
||||
return { hasBa, ps: { head: undefined, rest: verbForm }};
|
||||
}
|
||||
|
||||
function getVerbFromBlock(block: T.SingleOrLengthOpts<T.VerbBlock>, person: T.Person): T.SingleOrLengthOpts<T.PsString[]> {
|
||||
function grabFromBlock(b: T.VerbBlock, [row, col]: [ row: number, col: number ]): T.PsString[] {
|
||||
return b[row][col];
|
||||
}
|
||||
const pos = getVerbBlockPosFromPerson(person);
|
||||
if ("long" in block) {
|
||||
return {
|
||||
long: grabFromBlock(block.long, pos),
|
||||
short: grabFromBlock(block.short, pos),
|
||||
...block.mini ? {
|
||||
mini: grabFromBlock(block.mini, pos),
|
||||
} : {},
|
||||
};
|
||||
}
|
||||
return grabFromBlock(block, pos);
|
||||
}
|
||||
|
||||
function getHeadAndRest(head: T.PsString, rest: T.PsString[]): { head: T.PsString | undefined, rest: T.PsString[] };
|
||||
function getHeadAndRest(head: T.PsString, rest: T.SingleOrLengthOpts<T.PsString[]>): { head: T.PsString | undefined, rest: T.SingleOrLengthOpts<T.PsString[]> };
|
||||
function getHeadAndRest(head: T.PsString, rest: T.SingleOrLengthOpts<T.PsString[]>): { head: T.PsString | undefined, rest: T.SingleOrLengthOpts<T.PsString[]> } {
|
||||
if ("long" in rest) {
|
||||
return {
|
||||
// whether or not to include the head (for irreg tlul) -- eww // TODO: make nicer?
|
||||
head: removeBa(rest.long[0]).p.slice(0, head.p.length) === head.p
|
||||
? head : undefined,
|
||||
rest: {
|
||||
long: getHeadAndRest(head, rest.long).rest,
|
||||
short: getHeadAndRest(head, rest.short).rest,
|
||||
...rest.mini ? {
|
||||
mini: getHeadAndRest(head, rest.mini).rest,
|
||||
} : {},
|
||||
},
|
||||
};
|
||||
}
|
||||
let headMismatch = false;
|
||||
const restM = rest.map((psRaw) => {
|
||||
const ps = removeBa(psRaw);
|
||||
const pMatches = removeAccents(ps.p.slice(0, head.p.length)) === head.p
|
||||
const fMatches = removeAccents(ps.f.slice(0, head.f.length)) === removeAccents(head.f);
|
||||
if (!(pMatches && fMatches)) {
|
||||
headMismatch = true;
|
||||
return psRaw;
|
||||
// throw new Error(`split head does not match - ${JSON.stringify(ps)} ${JSON.stringify(head)}`);
|
||||
}
|
||||
return {
|
||||
p: ps.p.slice(head.p.length),
|
||||
f: ps.f.slice(head.f.length),
|
||||
}
|
||||
});
|
||||
return {
|
||||
head: headMismatch ? undefined : head,
|
||||
rest: restM,
|
||||
}
|
||||
}
|
||||
|
||||
function getMatrixBlock<U>(f: {
|
||||
mascSing: T.SingleOrLengthOpts<U>;
|
||||
mascPlur: T.SingleOrLengthOpts<U>;
|
||||
femSing: T.SingleOrLengthOpts<U>;
|
||||
femPlur: T.SingleOrLengthOpts<U>;
|
||||
} | T.SingleOrLengthOpts<U>, objectPerson: T.Person | undefined, kingPerson: T.Person): T.SingleOrLengthOpts<U> {
|
||||
if (!("mascSing" in f)) {
|
||||
return f;
|
||||
}
|
||||
function personToLabel(p: T.Person): "mascSing" | "mascPlur" | "femSing" | "femPlur" {
|
||||
if (p === T.Person.FirstSingMale || p === T.Person.SecondSingMale || p === T.Person.ThirdSingMale) {
|
||||
return "mascSing";
|
||||
}
|
||||
if (p === T.Person.FirstSingFemale || p === T.Person.SecondSingFemale || p === T.Person.ThirdSingFemale) {
|
||||
return "femSing";
|
||||
}
|
||||
if (p === T.Person.FirstPlurMale || p === T.Person.SecondPlurMale || p === T.Person.ThirdPlurMale) {
|
||||
return "mascPlur";
|
||||
}
|
||||
return "femPlur";
|
||||
}
|
||||
// if there's an object the matrix will agree with that, otherwise with the kingPerson (subject for intransitive)
|
||||
const person = (objectPerson === undefined) ? kingPerson : objectPerson;
|
||||
return f[personToLabel(person)];
|
||||
}
|
||||
|
||||
function getEnglishParticiple(entry: T.DictionaryEntry): string {
|
||||
if (!entry.ec) {
|
||||
console.log("errored participle");
|
||||
console.log(entry);
|
||||
throw new Error("no english information for participle");
|
||||
}
|
||||
const ec = parseEc(entry.ec);
|
||||
const participle = ec[2];
|
||||
return (entry.ep)
|
||||
? `${participle} ${entry.ep}`
|
||||
: participle;
|
||||
}
|
||||
|
||||
function getEnglishFromNoun(entry: T.DictionaryEntry, number: T.NounNumber): string {
|
||||
const articles = {
|
||||
singular: "(a/the)",
|
||||
plural: "(the)",
|
||||
};
|
||||
const article = articles[number];
|
||||
function addArticle(s: string) {
|
||||
return `${article} ${s}`;
|
||||
}
|
||||
const e = getEnglishWord(entry);
|
||||
if (!e) throw new Error(`unable to get english from subject ${entry.f} - ${entry.ts}`);
|
||||
|
||||
if (typeof e === "string") return ` ${e}`;
|
||||
if (number === "plural") return addArticle(e.plural);
|
||||
if (!e.singular || e.singular === undefined) {
|
||||
throw new Error(`unable to get english from subject ${entry.f} - ${entry.ts}`);
|
||||
}
|
||||
return addArticle(e.singular);
|
||||
}
|
||||
|
||||
function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflections", gender: T.Gender, plural: boolean, inflected: boolean): T.PsString[] {
|
||||
// TODO: make this safe!!
|
||||
// @ts-ignore
|
||||
if (infs && t in infs && infs[t] !== undefined && gender in infs[t] && infs[t][gender] !== undefined) {
|
||||
// @ts-ignore
|
||||
const iset = infs[t][gender] as T.InflectionSet;
|
||||
const inflectionNumber = (inflected ? 1 : 0) + ((t === "inflections" && plural) ? 1 : 0);
|
||||
return iset[inflectionNumber];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getKingAndServant(isPast: boolean, isTransitive: boolean):
|
||||
{ king: "subject", servant: "object" } |
|
||||
{ king: "object", servant: "subject" } |
|
||||
{ king: "subject", servant: undefined } {
|
||||
if (!isTransitive) {
|
||||
return { king: "subject", servant: undefined };
|
||||
}
|
||||
return isPast ? {
|
||||
king: "object",
|
||||
servant: "subject",
|
||||
} : {
|
||||
king: "subject",
|
||||
servant: "object",
|
||||
};
|
||||
}
|
||||
|
||||
function isFirstOrSecondPersPronoun(o: "none" | T.NPSelection | T.Person.ThirdPlurMale): boolean {
|
||||
if (typeof o !== "object") return false;
|
||||
if (o.type !== "pronoun") return false;
|
||||
return [0,1,2,3,6,7,8,9].includes(o.person);
|
||||
}
|
||||
|
||||
function isPerfective(t: T.VerbTense | T.PerfectTense): boolean {
|
||||
if (isPerfectTense(t)) return false;
|
||||
if (t === "presentVerb" || t === "imperfectiveFuture" || t === "imperfectivePast" || t === "habitualImperfectivePast") {
|
||||
return false;
|
||||
}
|
||||
if (t === "perfectiveFuture" || t === "subjunctiveVerb" || t === "perfectivePast" || t === "habitualPerfectivePast") {
|
||||
return true;
|
||||
}
|
||||
throw new Error("tense not implemented yet");
|
||||
}
|
||||
|
||||
function isMascSingAnimatePattern4(np: T.NPSelection): boolean {
|
||||
if (np.type !== "noun") {
|
||||
return false;
|
||||
}
|
||||
return isPattern4Entry(np.entry)
|
||||
&& np.entry.c.includes("anim.")
|
||||
&& (np.number === "singular")
|
||||
&& (np.gender === "masc");
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
import * as T from "../../types";
|
||||
import {
|
||||
concatPsString,
|
||||
psRemove,
|
||||
psStringEquals,
|
||||
} from "../../lib/p-text-helpers";
|
||||
import * as grammarUnits from "../../lib/grammar-units";
|
||||
|
||||
export function isInvalidSubjObjCombo(subj: T.Person, obj: T.Person): boolean {
|
||||
const firstPeople = [
|
||||
T.Person.FirstSingMale,
|
||||
T.Person.FirstSingFemale,
|
||||
T.Person.FirstPlurMale,
|
||||
T.Person.FirstPlurFemale,
|
||||
];
|
||||
const secondPeople = [
|
||||
T.Person.SecondSingMale,
|
||||
T.Person.SecondSingFemale,
|
||||
T.Person.SecondPlurMale,
|
||||
T.Person.SecondPlurFemale,
|
||||
];
|
||||
return (
|
||||
(firstPeople.includes(subj) && firstPeople.includes(obj))
|
||||
||
|
||||
(secondPeople.includes(subj) && secondPeople.includes(obj))
|
||||
);
|
||||
}
|
||||
|
||||
export function getTenseVerbForm(conjR: T.VerbConjugation, tense: T.VerbTense | T.PerfectTense, tenseCategory: "basic" | "modal" | "perfect", voice: "active" | "passive"): T.VerbForm {
|
||||
const conj = (voice === "passive" && conjR.passive) ? conjR.passive : conjR;
|
||||
if (tenseCategory === "basic") {
|
||||
if (tense === "presentVerb") {
|
||||
return conj.imperfective.nonImperative;
|
||||
}
|
||||
if (tense === "subjunctiveVerb") {
|
||||
return conj.perfective.nonImperative;
|
||||
}
|
||||
if (tense === "imperfectiveFuture") {
|
||||
return conj.imperfective.future;
|
||||
}
|
||||
if (tense === "perfectiveFuture") {
|
||||
return conj.perfective.future;
|
||||
}
|
||||
if (tense === "imperfectivePast") {
|
||||
return conj.imperfective.past;
|
||||
}
|
||||
if (tense === "perfectivePast") {
|
||||
return conj.perfective.past;
|
||||
}
|
||||
if (tense === "habitualImperfectivePast") {
|
||||
return conj.imperfective.habitualPast;
|
||||
}
|
||||
if (tense === "habitualPerfectivePast") {
|
||||
return conj.perfective.habitualPast;
|
||||
}
|
||||
}
|
||||
if (tenseCategory === "modal") {
|
||||
if (tense === "presentVerb") {
|
||||
return conj.imperfective.modal.nonImperative;
|
||||
}
|
||||
if (tense === "subjunctiveVerb") {
|
||||
return conj.perfective.modal.nonImperative;
|
||||
}
|
||||
if (tense === "imperfectiveFuture") {
|
||||
return conj.imperfective.modal.future;
|
||||
}
|
||||
if (tense === "perfectiveFuture") {
|
||||
return conj.perfective.modal.future;
|
||||
}
|
||||
if (tense === "imperfectivePast") {
|
||||
return conj.imperfective.modal.past;
|
||||
}
|
||||
if (tense === "perfectivePast") {
|
||||
return conj.perfective.modal.past;
|
||||
}
|
||||
if (tense === "habitualImperfectivePast") {
|
||||
return conj.imperfective.modal.habitualPast;
|
||||
}
|
||||
if (tense === "habitualPerfectivePast") {
|
||||
return conj.perfective.modal.habitualPast;
|
||||
}
|
||||
}
|
||||
if (tense === "present perfect") {
|
||||
return conj.perfect.present;
|
||||
}
|
||||
if (tense === "past perfect") {
|
||||
return conj.perfect.past;
|
||||
}
|
||||
if (tense === "future perfect") {
|
||||
return conj.perfect.future;
|
||||
}
|
||||
if (tense === "habitual perfect") {
|
||||
return conj.perfect.habitual;
|
||||
}
|
||||
if (tense === "subjunctive perfect") {
|
||||
return conj.perfect.subjunctive;
|
||||
}
|
||||
if (tense === "wouldBe perfect") {
|
||||
return conj.perfect.affirmational;
|
||||
}
|
||||
if (tense === "pastSubjunctive perfect") {
|
||||
return conj.perfect.pastSubjunctiveHypothetical;
|
||||
}
|
||||
throw new Error("unknown tense");
|
||||
}
|
||||
|
||||
export function getPersonFromNP(np: T.NPSelection): T.Person;
|
||||
export function getPersonFromNP(np: T.NPSelection | T.ObjectNP): T.Person | undefined;
|
||||
export function getPersonFromNP(np: T.NPSelection | T.ObjectNP): T.Person | undefined {
|
||||
if (np === "none") {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof np === "number") return np;
|
||||
if (np.type === "participle") {
|
||||
return T.Person.ThirdPlurMale;
|
||||
}
|
||||
if (np.type === "pronoun") {
|
||||
return np.person;
|
||||
}
|
||||
return np.number === "plural"
|
||||
? (np.gender === "masc" ? T.Person.ThirdPlurMale : T.Person.ThirdPlurFemale)
|
||||
: (np.gender === "masc" ? T.Person.ThirdSingMale : T.Person.ThirdSingFemale);
|
||||
}
|
||||
|
||||
export function removeBa(ps: T.PsString): T.PsString {
|
||||
return psRemove(ps, concatPsString(grammarUnits.baParticle, " "));
|
||||
}
|
||||
|
||||
export function isEquativeTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.EquativeTense {
|
||||
return (t === "present" || t === "future" || t === "habitual" || t === "past" || t === "wouldBe" || t === "subjunctive" || t === "pastSubjunctive");
|
||||
}
|
||||
|
||||
export function isPerfectTense(t: T.VerbTense | T.EquativeTense | T.PerfectTense): t is T.PerfectTense {
|
||||
return (
|
||||
t === "present perfect" ||
|
||||
t === "habitual perfect" ||
|
||||
t === "future perfect" ||
|
||||
t === "past perfect" ||
|
||||
t === "wouldBe perfect" ||
|
||||
t === "subjunctive perfect" ||
|
||||
t === "pastSubjunctive perfect"
|
||||
);
|
||||
}
|
||||
|
||||
export function isPastTense(tense: T.VerbTense | T.PerfectTense): boolean {
|
||||
if (isPerfectTense(tense)) return true;
|
||||
return tense.toLowerCase().includes("past");
|
||||
}
|
||||
|
||||
export function removeDuplicates(psv: T.PsString[]): T.PsString[] {
|
||||
return psv.filter((ps, i, arr) => (
|
||||
i === arr.findIndex(t => (
|
||||
psStringEquals(t, ps)
|
||||
))
|
||||
));
|
||||
}
|
|
@ -23,6 +23,6 @@ const sampleDictionary: T.Dictionary = {
|
|||
}
|
||||
|
||||
test("should encode and decode", () => {
|
||||
expect(readDictionaryInfo(writeDictionaryInfo(sampleDictionaryInfo))).toEqual(sampleDictionaryInfo);
|
||||
expect(readDictionary(writeDictionary(sampleDictionary))).toEqual(sampleDictionary);
|
||||
expect(readDictionaryInfo(writeDictionaryInfo(sampleDictionaryInfo) as Uint8Array)).toEqual(sampleDictionaryInfo);
|
||||
expect(readDictionary(writeDictionary(sampleDictionary) as Uint8Array)).toEqual(sampleDictionary);
|
||||
});
|
|
@ -73,6 +73,7 @@ translations.forEach((t) => {
|
|||
// check each dialect with given system
|
||||
dialects.forEach((dialect) => {
|
||||
test(
|
||||
// @ts-ignore
|
||||
`${t.original} should be translated to ${t.ipa[dialect]} using ${system} with ${dialect} dialect`,
|
||||
() => {
|
||||
const translated = translatePhonetics(t.original, {
|
||||
|
@ -81,6 +82,7 @@ translations.forEach((t) => {
|
|||
// @ts-ignore
|
||||
dialect,
|
||||
});
|
||||
// @ts-ignore
|
||||
expect(translated).toBe(t[system][dialect]);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
import * as T from "../types";
|
||||
import { pashtoConsonants } from "./pashto-consonants";
|
||||
import { endsWith } from "../lib/p-text-helpers";
|
||||
import { countSyllables } from "../lib/accent-helpers";
|
||||
|
||||
|
||||
export function isNounEntry(e: T.Entry | T.DictionaryEntry): e is T.NounEntry {
|
||||
if ("entry" in e) return false;
|
||||
return !!(e.c && (e.c.includes("n. m.") || e.c.includes("n. f.")));
|
||||
}
|
||||
|
||||
export function isAdjectiveEntry(e: T.Entry): e is T.AdjectiveEntry {
|
||||
if ("entry" in e) return false;
|
||||
return !!e.c?.includes("adj.") && !isNounEntry(e);
|
||||
}
|
||||
|
||||
export function isAdverbEntry(e: T.Entry): e is T.AdverbEntry {
|
||||
if ("entry" in e) return false;
|
||||
return !!e.c?.includes("adv.");
|
||||
}
|
||||
|
||||
export function isLocativeAdverbEntry(e: T.Entry): e is T.LocativeAdverbEntry {
|
||||
return isAdverbEntry(e) && e.c.includes("loc. adv.");
|
||||
}
|
||||
|
||||
export function isNounOrAdjEntry(e: T.Entry): e is (T.NounEntry | T.AdjectiveEntry) {
|
||||
return isNounEntry(e) || isAdjectiveEntry(e);
|
||||
}
|
||||
|
||||
export function isVerbEntry(e: T.Entry | T.DictionaryEntry): e is T.VerbEntry {
|
||||
return "entry" in e && !!e.entry.c?.startsWith("v.");
|
||||
}
|
||||
|
||||
export function isMascNounEntry(e: T.NounEntry | T.AdjectiveEntry): e is T.MascNounEntry {
|
||||
return !!e.c && e.c.includes("n. m.");
|
||||
}
|
||||
|
||||
export function isFemNounEntry(e: T.NounEntry | T.AdjectiveEntry): e is T.FemNounEntry {
|
||||
return !!e.c && e.c.includes("n. f.");
|
||||
}
|
||||
|
||||
export function isUnisexNounEntry(e: T.NounEntry | T.AdjectiveEntry): e is T.UnisexNounEntry {
|
||||
return isNounEntry(e) && e.c.includes("unisex");
|
||||
}
|
||||
|
||||
export function isAdjOrUnisexNounEntry(e: T.Entry): e is (T.AdjectiveEntry | T.UnisexNounEntry) {
|
||||
return isAdjectiveEntry(e) || (
|
||||
isNounEntry(e) && isUnisexNounEntry(e)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* shows if a noun/adjective has the basic (consonant / ه) inflection pattern
|
||||
*
|
||||
* @param e
|
||||
* @returns
|
||||
*/
|
||||
export function isPattern1Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern1Entry<T> {
|
||||
if (e.noInf) return false;
|
||||
if (e.infap) return false;
|
||||
if (isFemNounEntry(e)) {
|
||||
return (
|
||||
endsWith([{ p: "ه", f: "a" }, { p: "ح", f: "a" }], e) ||
|
||||
(endsWith({ p: pashtoConsonants }, e) && !e.c.includes("anim."))
|
||||
);
|
||||
}
|
||||
return (
|
||||
endsWith([{ p: pashtoConsonants }], e) ||
|
||||
endsWith([{ p: "ه", f: "u" }, { p: "ه", f: "h" }], e) ||
|
||||
endsWith([{ p: "ای", f: "aay" }, { p: "وی", f: "ooy" }], e)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* shows if a noun/adjective has the unstressed ی inflection pattern
|
||||
*
|
||||
* @param e
|
||||
* @returns T.T.T.T.
|
||||
*/
|
||||
export function isPattern2Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern2Entry<T> {
|
||||
if (e.noInf) return false;
|
||||
if (e.infap) return false;
|
||||
if (isFemNounEntry(e)) {
|
||||
return !e.c.includes("pl.") && endsWith({ p: "ې", f: "e" }, e, true);
|
||||
}
|
||||
// TODO: check if it's a single syllable word, in which case it would be pattern 1
|
||||
return endsWith({ p: "ی", f: "ey" }, e, true) && (countSyllables(e.f) > 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* shows if a noun/adjective has the stressed ی inflection pattern
|
||||
*
|
||||
* @param e
|
||||
* @returns
|
||||
*/
|
||||
export function isPattern3Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern3Entry<T> {
|
||||
if (e.noInf) return false;
|
||||
if (e.infap) return false;
|
||||
if (isFemNounEntry(e)) {
|
||||
return endsWith({ p: "ۍ" }, e);
|
||||
}
|
||||
return (countSyllables(e.f) > 1)
|
||||
? endsWith({ p: "ی", f: "éy" }, e, true)
|
||||
: endsWith({ p: "ی", f: "ey" }, e)
|
||||
}
|
||||
|
||||
/**
|
||||
* shows if a noun/adjective has the "Pashtoon" inflection pattern
|
||||
*
|
||||
* @param e
|
||||
* @returns
|
||||
*/
|
||||
export function isPattern4Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern4Entry<T> {
|
||||
if (e.noInf) return false;
|
||||
return (
|
||||
!!(e.infap && e.infaf && e.infbp && e.infbf)
|
||||
&&
|
||||
(e.infap.slice(1).includes("ا") && e.infap.slice(-1) === "ه")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* shows if a noun/adjective has the shorter squish inflection pattern
|
||||
*
|
||||
* @param e
|
||||
* @returns
|
||||
*/
|
||||
export function isPattern5Entry<T extends (T.NounEntry | T.AdjectiveEntry)>(e: T): e is T.Pattern5Entry<T> {
|
||||
if (e.noInf) return false;
|
||||
return (
|
||||
!!(e.infap && e.infaf && e.infbp && e.infbf)
|
||||
&&
|
||||
(e.infaf.slice(-1) === "u")
|
||||
&&
|
||||
!e.infap.slice(1).includes("ا")
|
||||
);
|
||||
}
|
||||
|
||||
export function isPattern6FemEntry(e: T.FemNounEntry): e is T.Pattern6FemEntry<T.FemNounEntry> {
|
||||
if (!isFemNounEntry(e)) return false;
|
||||
if (e.c.includes("anim.")) return false;
|
||||
return e.p.slice(-1) === "ي";
|
||||
}
|
||||
|
||||
export function isPluralNounEntry<U extends T.NounEntry>(e: U): e is T.PluralNounEntry<U> {
|
||||
return e.c.includes("pl.");
|
||||
}
|
||||
|
||||
export function isSingularEntry<U extends T.NounEntry>(e: U): e is T.SingularEntry<U> {
|
||||
return !isPluralNounEntry(e);
|
||||
}
|
||||
|
||||
export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> {
|
||||
return a.length > 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
import { useEffect, useState } from "react";
|
||||
|
||||
/**
|
||||
* replacement from the React useState hook that will persist the state in local storage
|
||||
*
|
||||
* @param defaultValue The default value to use if there was nothing saved previously OR
|
||||
* a function that will take the saved value and return a modified new value to start with
|
||||
* @param key a key for saving the state in locolStorage
|
||||
* @returns
|
||||
*/
|
||||
export default function useStickyState<T extends string | object | boolean | undefined | null>(
|
||||
defaultValue: T | ((old: T | undefined) => T),
|
||||
key: string
|
||||
): [
|
||||
value: T,
|
||||
setValue: React.Dispatch<React.SetStateAction<T>>,
|
||||
] {
|
||||
const [value, setValue] = useState<T>(() => {
|
||||
const v = window.localStorage.getItem(key);
|
||||
// nothing saved
|
||||
if (v === null) {
|
||||
if (typeof defaultValue === "function") {
|
||||
return defaultValue(undefined);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
// something saved before
|
||||
try {
|
||||
const old = JSON.parse(v) as T;
|
||||
if (typeof defaultValue === "function") {
|
||||
return defaultValue(old);
|
||||
}
|
||||
return defaultValue;
|
||||
} catch (e) {
|
||||
console.error("error parsting saved state from stickState");
|
||||
return (typeof defaultValue === "function")
|
||||
? defaultValue(undefined)
|
||||
: defaultValue;
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
window.localStorage.setItem(key, JSON.stringify(value));
|
||||
}, [key, value]);
|
||||
|
||||
return [value, setValue];
|
||||
}
|
|
@ -24,11 +24,13 @@ import {
|
|||
complementInflects,
|
||||
concatInflections,
|
||||
unisexInfToObjectMatrix,
|
||||
inflectYey,
|
||||
allOnePersonInflection,
|
||||
psStringEquals,
|
||||
makePsString,
|
||||
} from "./p-text-helpers";
|
||||
import { makePsString } from "./accent-and-ps-utils";
|
||||
import {
|
||||
inflectYey,
|
||||
} from "./pashto-inflector";
|
||||
import {
|
||||
accentOnNFromEnd,
|
||||
} from "./accent-helpers";
|
||||
|
|
|
@ -8,12 +8,10 @@
|
|||
|
||||
import {
|
||||
concatPsString,
|
||||
makePsString,
|
||||
psStringEquals,
|
||||
removeEndingL,
|
||||
yulEndingInfinitive,
|
||||
removeRetroflexR,
|
||||
inflectYey,
|
||||
unisexInfToObjectMatrix,
|
||||
complementInflects,
|
||||
beginsWithDirectionalPronoun,
|
||||
|
@ -21,9 +19,15 @@ import {
|
|||
removeStartingTick,
|
||||
ensureShortWurShwaShift,
|
||||
choosePersInf,
|
||||
removeFVarients,
|
||||
isUnisexSet,
|
||||
} from "./p-text-helpers";
|
||||
import {
|
||||
makePsString,
|
||||
removeFVarients,
|
||||
} from "./accent-and-ps-utils";
|
||||
import {
|
||||
inflectYey,
|
||||
} from "./pashto-inflector";
|
||||
import {
|
||||
accentOnFront,
|
||||
accentOnNFromEnd,
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
import {
|
||||
getVerbInfo,
|
||||
} from "./lib/verb-info";
|
||||
import { makeVerbSelection } from "./components/vp-explorer/verb-selection";
|
||||
import ConjugationViewer from "./components/ConjugationViewer";
|
||||
import InflectionsTable from "./components/InflectionsTable";
|
||||
import Pashto from "./components/Pashto";
|
||||
|
@ -24,12 +25,18 @@ import ButtonSelect from "./components/ButtonSelect";
|
|||
import VerbFormDisplay from "./components/VerbFormDisplay";
|
||||
import VerbTable from "./components/VerbTable";
|
||||
import Examples from "./components/Examples";
|
||||
import Hider from "./components/Hider";
|
||||
import EntrySelect from "./components/EntrySelect";
|
||||
import VerbInfo, { RootsAndStems } from "./components/verb-info/VerbInfo";
|
||||
import VPExplorer from "./components/vp-explorer/VPExplorer";
|
||||
import useStickyState from "./lib/useStickyState";
|
||||
import {
|
||||
makePsString,
|
||||
removeFVarients,
|
||||
} from "./lib/accent-and-ps-utils";
|
||||
import {
|
||||
addToForm,
|
||||
concatPsString,
|
||||
makePsString,
|
||||
removeFVarients,
|
||||
isVerbBlock,
|
||||
isImperativeBlock,
|
||||
isPluralInflectionSet,
|
||||
|
@ -39,6 +46,10 @@ import {
|
|||
endsWith,
|
||||
hasBaParticle,
|
||||
psRemove,
|
||||
firstVariation,
|
||||
psStringFromEntry,
|
||||
getLong,
|
||||
capitalizeFirstLetter,
|
||||
} from "./lib/p-text-helpers";
|
||||
import {
|
||||
getEnglishWord,
|
||||
|
@ -48,6 +59,11 @@ import {
|
|||
standardizePhonetics,
|
||||
} from "./lib/standardize-pashto";
|
||||
import { phoneticsToDiacritics } from "./lib/phonetics-to-diacritics";
|
||||
import {
|
||||
randomPerson,
|
||||
isInvalidSubjObjCombo,
|
||||
randomSubjObj,
|
||||
} from "./lib/np-tools";
|
||||
import {
|
||||
convertSpelling,
|
||||
revertSpelling,
|
||||
|
@ -100,6 +116,7 @@ import defaultTextOptions from "./lib/default-text-options";
|
|||
import * as grammarUnits from "./lib/grammar-units";
|
||||
import genderColors from "./lib/gender-colors";
|
||||
import * as Types from "./types";
|
||||
import * as typePredicates from "./lib/type-predicates";
|
||||
|
||||
export {
|
||||
// FUNCTIONS
|
||||
|
@ -143,13 +160,23 @@ export {
|
|||
countSyllables,
|
||||
hasBaParticle,
|
||||
psRemove,
|
||||
firstVariation,
|
||||
capitalizeFirstLetter,
|
||||
psStringFromEntry,
|
||||
getLong,
|
||||
makeVerbSelection,
|
||||
useStickyState,
|
||||
randomPerson,
|
||||
isInvalidSubjObjCombo,
|
||||
randomSubjObj,
|
||||
// protobuf helpers
|
||||
readDictionary,
|
||||
writeDictionary,
|
||||
readDictionaryInfo,
|
||||
writeDictionaryInfo,
|
||||
// COMPONENTS
|
||||
ConjugationViewer,
|
||||
VPExplorer,
|
||||
ConjugationViewer, // TODO: Deprecated - remove
|
||||
Examples,
|
||||
VerbFormDisplay,
|
||||
VerbTable,
|
||||
|
@ -160,7 +187,10 @@ export {
|
|||
Phonetics,
|
||||
InlinePs,
|
||||
ButtonSelect,
|
||||
Hider,
|
||||
EntrySelect,
|
||||
// OTHER
|
||||
typePredicates,
|
||||
grammarUnits,
|
||||
pashtoConsonants,
|
||||
defaultTextOptions,
|
||||
|
|
File diff suppressed because one or more lines are too long
164
src/types.ts
164
src/types.ts
|
@ -473,3 +473,167 @@ export type DisplayFormSubgroup = {
|
|||
}
|
||||
|
||||
export type AayTail = "ey" | "aay";
|
||||
|
||||
export type NounEntry = DictionaryEntry & { c: string } & { __brand: "a noun entry" };
|
||||
export type MascNounEntry = NounEntry & { __brand2: "a masc noun entry" };
|
||||
export type FemNounEntry = NounEntry & { __brand2: "a fem noun entry" };
|
||||
export type UnisexNounEntry = MascNounEntry & { __brand3: "a unisex noun entry" };
|
||||
export type AdverbEntry = DictionaryEntry & { c: string } & { __brand: "an adverb entry" };
|
||||
export type LocativeAdverbEntry = AdverbEntry & { __brand2: "a locative adverb entry" };
|
||||
export type AdjectiveEntry = DictionaryEntry & { c: string } & { __brand: "an adjective entry" };
|
||||
export type VerbEntry = {
|
||||
entry: DictionaryEntry & { __brand: "a verb entry" },
|
||||
// TODO: the compliment could also be typed? Maybe?
|
||||
complement?: DictionaryEntry,
|
||||
};
|
||||
|
||||
export type SingularEntry<T extends NounEntry> = T & { __brand7: "a singular noun - as opposed to an always plural noun" };
|
||||
export type PluralNounEntry<T extends NounEntry> = T & { __brand7: "a noun that is always plural" };
|
||||
|
||||
export type Pattern1Entry<T> = T & { __brand3: "basic inflection pattern" };
|
||||
export type Pattern2Entry<T> = T & { __brand3: "ending in unstressed ی pattern" };
|
||||
export type Pattern3Entry<T> = T & { __brand3: "ending in stressed ی pattern" };
|
||||
export type Pattern4Entry<T> = T & { __brand3: "Pashtoon pattern" };
|
||||
export type Pattern5Entry<T> = T & { __brand3: "short squish pattern" };
|
||||
export type Pattern6FemEntry<T extends FemNounEntry> = T & { __brand3: "non anim. ending in ي" };
|
||||
export type NonInflecting<T> = T & { __brand3: "non-inflecting" };
|
||||
|
||||
export type Entry = NounEntry | AdjectiveEntry | AdverbEntry | VerbEntry;
|
||||
|
||||
export type Words = {
|
||||
nouns: NounEntry[],
|
||||
adjectives: AdjectiveEntry[],
|
||||
verbs: VerbEntry[],
|
||||
adverbs: AdverbEntry[],
|
||||
}
|
||||
|
||||
export type VPSelection = {
|
||||
type: "VPSelection",
|
||||
subject: NPSelection,
|
||||
object: Exclude<VerbObject, undefined>,
|
||||
verb: Exclude<VerbSelection, "object">,
|
||||
};
|
||||
|
||||
// TODO: make this Rendered<VPSelection> with recursive Rendered<>
|
||||
export type VPRendered = {
|
||||
type: "VPRendered",
|
||||
king: "subject" | "object",
|
||||
servant: "subject" | "object" | undefined,
|
||||
isPast: boolean,
|
||||
isTransitive: boolean,
|
||||
isCompound: "stative" | "dynamic" | false,
|
||||
subject: Rendered<NPSelection>,
|
||||
object: Rendered<NPSelection> | ObjectNP,
|
||||
verb: VerbRendered,
|
||||
englishBase?: string[],
|
||||
}
|
||||
|
||||
export type VerbTense = "presentVerb"
|
||||
| "subjunctiveVerb"
|
||||
| "perfectiveFuture"
|
||||
| "imperfectiveFuture"
|
||||
| "perfectivePast"
|
||||
| "imperfectivePast"
|
||||
| "habitualPerfectivePast"
|
||||
| "habitualImperfectivePast";
|
||||
|
||||
export type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
|
||||
export type NounNumber = "singular" | "plural";
|
||||
|
||||
export type PerfectTense = `${EquativeTense} perfect`;
|
||||
|
||||
export type VerbSelection = {
|
||||
type: "verb",
|
||||
verb: VerbEntry,
|
||||
dynAuxVerb?: VerbEntry,
|
||||
object: VerbObject, // TODO: should have a locked in (but number changeable noun) here for dynamic compounds
|
||||
transitivity: Transitivity,
|
||||
isCompound: "stative" | "dynamic" | false,
|
||||
voice: "active" | "passive",
|
||||
changeTransitivity?: (t: "transitive" | "grammatically transitive") => VerbSelection,
|
||||
changeStatDyn?: (t: "stative" | "dynamic") => VerbSelection,
|
||||
changeVoice?: (v: "active" | "passive", subj?: NPSelection) => VerbSelection,
|
||||
// TODO: changeStativeDynamic
|
||||
// TODO: add in aspect element here??
|
||||
negative: boolean,
|
||||
} & ({
|
||||
tense: VerbTense,
|
||||
tenseCategory: "basic" | "modal",
|
||||
} | {
|
||||
tense: PerfectTense,
|
||||
tenseCategory: "perfect"
|
||||
});
|
||||
|
||||
export type VerbRendered = Omit<VerbSelection, "object"> & {
|
||||
ps: {
|
||||
head: PsString | undefined,
|
||||
rest: SingleOrLengthOpts<
|
||||
PsString[]
|
||||
>,
|
||||
},
|
||||
hasBa: boolean,
|
||||
person: Person,
|
||||
};
|
||||
|
||||
export type VerbObject =
|
||||
// transitive verb - object not selected yet
|
||||
undefined |
|
||||
// transitive verb - obect selected
|
||||
NPSelection |
|
||||
// grammatically transitive verb with unspoken 3rd pers masc plur entity
|
||||
// or intransitive "none"
|
||||
ObjectNP;
|
||||
|
||||
export type NPSelection = NounSelection | PronounSelection | ParticipleSelection;
|
||||
|
||||
export type NPType = "noun" | "pronoun" | "participle";
|
||||
|
||||
export type ObjectNP = "none" | Person.ThirdPlurMale;
|
||||
|
||||
// TODO require/import Person and PsString
|
||||
export type NounSelection = {
|
||||
type: "noun",
|
||||
entry: NounEntry,
|
||||
gender: Gender,
|
||||
number: NounNumber,
|
||||
dynamicComplement?: boolean,
|
||||
// TODO: Implement
|
||||
// adjectives: [],
|
||||
// TODO: Implement
|
||||
// possesor: NPSelection | undefined,
|
||||
/* method only present if it's possible to change gender */
|
||||
changeGender?: (gender: Gender) => NounSelection,
|
||||
/* method only present if it's possible to change number */
|
||||
changeNumber?: (number: NounNumber) => NounSelection,
|
||||
};
|
||||
|
||||
// take an argument for subject/object in rendering English
|
||||
export type PronounSelection = {
|
||||
type: "pronoun",
|
||||
person: Person,
|
||||
distance: "near" | "far",
|
||||
};
|
||||
|
||||
export type ParticipleSelection = {
|
||||
type: "participle",
|
||||
verb: VerbEntry,
|
||||
};
|
||||
|
||||
// not object
|
||||
// type Primitive = string | Function | number | boolean | Symbol | undefined | null;
|
||||
// If T has key K ("user"), replace it
|
||||
export type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ? (Omit<T, K> & Record<K, R>) : T;
|
||||
|
||||
export type FormVersion = { removeKing: boolean, shrinkServant: boolean };
|
||||
|
||||
export type Rendered<T extends NPSelection> = ReplaceKey<
|
||||
Omit<T, "changeGender" | "changeNumber" | "changeDistance">,
|
||||
"e",
|
||||
string
|
||||
> & {
|
||||
ps: PsString[],
|
||||
e?: string,
|
||||
inflected: boolean,
|
||||
person: Person,
|
||||
};
|
||||
// TODO: recursive changing this down into the possesor etc.
|
||||
|
|
163
yarn.lock
163
yarn.lock
|
@ -209,6 +209,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
|
||||
integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
|
||||
|
||||
"@babel/helper-plugin-utils@^7.16.7":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
|
||||
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
|
||||
|
||||
"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.15.4":
|
||||
version "7.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f"
|
||||
|
@ -541,6 +546,13 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.8.0"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.12.13":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
|
||||
integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.16.7"
|
||||
|
||||
"@babel/plugin-syntax-jsx@^7.14.5":
|
||||
version "7.14.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201"
|
||||
|
@ -1164,6 +1176,13 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.12.0", "@babel/runtime@^7.13.10":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72"
|
||||
integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.10.4", "@babel/template@^7.15.4", "@babel/template@^7.3.3":
|
||||
version "7.15.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194"
|
||||
|
@ -1219,6 +1238,89 @@
|
|||
resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-10.1.0.tgz#f0950bba18819512d42f7197e56c518aa491cf18"
|
||||
integrity sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg==
|
||||
|
||||
"@emotion/babel-plugin@^11.7.1":
|
||||
version "11.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0"
|
||||
integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.12.13"
|
||||
"@babel/plugin-syntax-jsx" "^7.12.13"
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@emotion/hash" "^0.8.0"
|
||||
"@emotion/memoize" "^0.7.5"
|
||||
"@emotion/serialize" "^1.0.2"
|
||||
babel-plugin-macros "^2.6.1"
|
||||
convert-source-map "^1.5.0"
|
||||
escape-string-regexp "^4.0.0"
|
||||
find-root "^1.1.0"
|
||||
source-map "^0.5.7"
|
||||
stylis "4.0.13"
|
||||
|
||||
"@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1":
|
||||
version "11.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539"
|
||||
integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==
|
||||
dependencies:
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
"@emotion/sheet" "^1.1.0"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
stylis "4.0.13"
|
||||
|
||||
"@emotion/hash@^0.8.0":
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
|
||||
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
|
||||
|
||||
"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
|
||||
integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
|
||||
|
||||
"@emotion/react@^11.1.1":
|
||||
version "11.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.9.0.tgz#b6d42b1db3bd7511e7a7c4151dc8bc82e14593b8"
|
||||
integrity sha512-lBVSF5d0ceKtfKCDQJveNAtkC7ayxpVlgOohLgXqRwqWr9bOf4TZAFFyIcNngnV6xK6X4x2ZeXq7vliHkoVkxQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@emotion/babel-plugin" "^11.7.1"
|
||||
"@emotion/cache" "^11.7.1"
|
||||
"@emotion/serialize" "^1.0.3"
|
||||
"@emotion/utils" "^1.1.0"
|
||||
"@emotion/weak-memoize" "^0.2.5"
|
||||
hoist-non-react-statics "^3.3.1"
|
||||
|
||||
"@emotion/serialize@^1.0.2", "@emotion/serialize@^1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.3.tgz#99e2060c26c6292469fb30db41f4690e1c8fea63"
|
||||
integrity sha512-2mSSvgLfyV3q+iVh3YWgNlUc2a9ZlDU7DjuP5MjK3AXRR0dYigCrP99aeFtaB2L/hjfEZdSThn5dsZ0ufqbvsA==
|
||||
dependencies:
|
||||
"@emotion/hash" "^0.8.0"
|
||||
"@emotion/memoize" "^0.7.4"
|
||||
"@emotion/unitless" "^0.7.5"
|
||||
"@emotion/utils" "^1.0.0"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@emotion/sheet@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2"
|
||||
integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==
|
||||
|
||||
"@emotion/unitless@^0.7.5":
|
||||
version "0.7.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf"
|
||||
integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==
|
||||
|
||||
"@emotion/weak-memoize@^0.2.5":
|
||||
version "0.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
|
||||
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
|
||||
|
||||
"@eslint/eslintrc@^0.4.3":
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
|
||||
|
@ -1975,6 +2077,13 @@
|
|||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^4.4.0":
|
||||
version "4.4.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e"
|
||||
integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^4.4.1":
|
||||
version "4.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.3.tgz#b0994da0a7023d67dbb4a8910a62112bc00d5688"
|
||||
|
@ -2798,7 +2907,7 @@ babel-plugin-jest-hoist@^26.6.2:
|
|||
"@types/babel__core" "^7.0.0"
|
||||
"@types/babel__traverse" "^7.0.6"
|
||||
|
||||
babel-plugin-macros@2.8.0:
|
||||
babel-plugin-macros@2.8.0, babel-plugin-macros@^2.6.1:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
|
||||
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
|
||||
|
@ -3670,7 +3779,7 @@ convert-source-map@^0.3.3:
|
|||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
|
||||
integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
|
||||
|
||||
convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
|
||||
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
|
||||
|
@ -5211,6 +5320,11 @@ find-cache-dir@^3.3.1:
|
|||
make-dir "^3.0.2"
|
||||
pkg-dir "^4.1.0"
|
||||
|
||||
find-root@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
|
||||
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
|
||||
|
||||
find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
|
||||
|
@ -5664,6 +5778,13 @@ hmac-drbg@^1.0.1:
|
|||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
hoopy@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
|
||||
|
@ -7326,6 +7447,11 @@ media-typer@0.3.0:
|
|||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||
|
||||
memoize-one@^5.0.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
|
||||
integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
|
||||
|
||||
memory-fs@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
|
||||
|
@ -9106,6 +9232,15 @@ prop-types-extra@^1.1.0:
|
|||
react-is "^16.3.2"
|
||||
warning "^4.0.0"
|
||||
|
||||
prop-types@^15.6.0:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
prop-types@^15.6.2, prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
|
@ -9354,7 +9489,7 @@ react-error-overlay@^6.0.9:
|
|||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
||||
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
||||
|
||||
react-is@^16.3.2, react-is@^16.8.1:
|
||||
react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0, react-is@^16.8.1:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
@ -9454,7 +9589,20 @@ react-scripts@4.0.3:
|
|||
optionalDependencies:
|
||||
fsevents "^2.1.3"
|
||||
|
||||
react-transition-group@^4.4.1:
|
||||
react-select@^5.2.2:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.2.tgz#3d5edf0a60f1276fd5f29f9f90a305f0a25a5189"
|
||||
integrity sha512-miGS2rT1XbFNjduMZT+V73xbJEeMzVkJOz727F6MeAr2hKE0uUSA8Ff7vD44H32x2PD3SRB6OXTY/L+fTV3z9w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.0"
|
||||
"@emotion/cache" "^11.4.0"
|
||||
"@emotion/react" "^11.1.1"
|
||||
"@types/react-transition-group" "^4.4.0"
|
||||
memoize-one "^5.0.0"
|
||||
prop-types "^15.6.0"
|
||||
react-transition-group "^4.3.0"
|
||||
|
||||
react-transition-group@^4.3.0, react-transition-group@^4.4.1:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470"
|
||||
integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==
|
||||
|
@ -10305,7 +10453,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc
|
|||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@^0.5.0, source-map@^0.5.6:
|
||||
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
|
||||
|
@ -10631,6 +10779,11 @@ stylehacks@^4.0.0:
|
|||
postcss "^7.0.0"
|
||||
postcss-selector-parser "^3.0.0"
|
||||
|
||||
stylis@4.0.13:
|
||||
version "4.0.13"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91"
|
||||
integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==
|
||||
|
||||
supports-color@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
|
||||
|
|
Loading…
Reference in New Issue