finish phonetics conversion
This commit is contained in:
parent
5df7a85003
commit
d076fff05c
|
@ -17,7 +17,7 @@
|
|||
"@formkit/auto-animate": "^1.0.0-beta.6",
|
||||
"@fortawesome/fontawesome-free": "5.15.4",
|
||||
"@lingdocs/lingdocs-main": "^0.3.3",
|
||||
"@lingdocs/ps-react": "^5.7.13",
|
||||
"@lingdocs/ps-react": "^6.0.2",
|
||||
"@mdx-js/rollup": "^2.2.1",
|
||||
"@stefanprobst/rehype-extract-toc": "^2.2.0",
|
||||
"@types/mdx": "^2.0.3",
|
||||
|
|
|
@ -11,25 +11,26 @@ const allTs = [...nounAdjTs, ...verbs, ...adverbs];
|
|||
console.log("getting words from dictionary...");
|
||||
|
||||
fetch("https://account.lingdocs.com/dictionary/entries", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ ids: allTs }),
|
||||
}).then(res => res.json()).then(data => {
|
||||
const content = `
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ ids: allTs }),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
const content = `
|
||||
// @ts-ignore
|
||||
const words: Word[] = ${JSON.stringify(data.results)};
|
||||
export default words;`;
|
||||
fs.writeFileSync(wordsFile, content);
|
||||
const missingEc = data.results.filter(x => "entry" in x && !x.entry.ec);
|
||||
if (missingEc.length) {
|
||||
console.log("verbs missing ec");
|
||||
console.log(missingEc);
|
||||
}
|
||||
if (data.notFound.length) {
|
||||
console.log("entries not found:");
|
||||
console.log(data.notFound);
|
||||
}
|
||||
});
|
||||
|
||||
fs.writeFileSync(wordsFile, content);
|
||||
const missingEc = data.results.filter((x) => "entry" in x && !x.entry.ec);
|
||||
if (missingEc.length) {
|
||||
console.log("verbs missing ec");
|
||||
console.log(missingEc);
|
||||
}
|
||||
if (data.notFound.length) {
|
||||
console.log("entries not found:");
|
||||
console.log(data.notFound);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,295 +1,409 @@
|
|||
import {
|
||||
Types as T,
|
||||
RootsAndStems,
|
||||
conjugateVerb,
|
||||
VerbTable,
|
||||
renderVP,
|
||||
compileVP,
|
||||
ButtonSelect,
|
||||
getEnglishVerb,
|
||||
InlinePs,
|
||||
removeFVarients,
|
||||
isPastTense,
|
||||
getPassiveRootsAndStems,
|
||||
getAbilityRootsAndStems,
|
||||
Types as T,
|
||||
RootsAndStems,
|
||||
conjugateVerb,
|
||||
VerbTable,
|
||||
renderVP,
|
||||
compileVP,
|
||||
ButtonSelect,
|
||||
getEnglishVerb,
|
||||
InlinePs,
|
||||
removeFVarients,
|
||||
isPastTense,
|
||||
getPassiveRootsAndStems,
|
||||
getAbilityRootsAndStems,
|
||||
} from "@lingdocs/ps-react";
|
||||
import { isImperativeTense, isPerfectTense } from "@lingdocs/ps-react/dist/lib/src/type-predicates";
|
||||
import {
|
||||
isImperativeTense,
|
||||
isPerfectTense,
|
||||
} from "@lingdocs/ps-react/dist/lib/src/type-predicates";
|
||||
import { useState } from "react";
|
||||
import Carousel from "./Carousel";
|
||||
import { basicVerbs, intransitivePastVerbs } from "../content/verbs/basic-present-verbs";
|
||||
import {
|
||||
basicVerbs,
|
||||
intransitivePastVerbs,
|
||||
} from "../content/verbs/basic-present-verbs";
|
||||
import { getLength } from "@lingdocs/ps-react/dist/lib/src/p-text-helpers";
|
||||
import { isThirdPerson } from "@lingdocs/ps-react";
|
||||
|
||||
function BasicVerbShowCase({ opts, tense, passive, ability }: {
|
||||
opts: T.TextOptions,
|
||||
tense: T.VerbTense | T.ImperativeTense,
|
||||
passive?: boolean,
|
||||
ability?: boolean,
|
||||
function BasicVerbShowCase({
|
||||
opts,
|
||||
tense,
|
||||
passive,
|
||||
ability,
|
||||
}: {
|
||||
opts: T.TextOptions;
|
||||
tense: T.VerbTense | T.ImperativeTense;
|
||||
passive?: boolean;
|
||||
ability?: boolean;
|
||||
}) {
|
||||
const items = isPastTense(tense)
|
||||
? intransitivePastVerbs
|
||||
: (passive ? basicVerbs.filter(v => v.entry.p !== "کول") : basicVerbs);
|
||||
return <Carousel stickyTitle items={items} render={(item) => {
|
||||
const items = isPastTense(tense)
|
||||
? intransitivePastVerbs
|
||||
: passive
|
||||
? basicVerbs.filter((v) => v.entry.p !== "کول")
|
||||
: basicVerbs;
|
||||
return (
|
||||
<Carousel
|
||||
stickyTitle
|
||||
items={items}
|
||||
render={(item) => {
|
||||
return {
|
||||
title: <InlinePs opts={opts}>{{
|
||||
title: (
|
||||
<InlinePs opts={opts}>
|
||||
{{
|
||||
...removeFVarients(item.entry),
|
||||
e: undefined,
|
||||
}}</InlinePs>,
|
||||
body: <BasicVerbChart
|
||||
passive={passive}
|
||||
ability={ability}
|
||||
verb={item}
|
||||
opts={opts}
|
||||
tense={tense}
|
||||
/>,
|
||||
}}
|
||||
</InlinePs>
|
||||
),
|
||||
body: (
|
||||
<BasicVerbChart
|
||||
passive={passive}
|
||||
ability={ability}
|
||||
verb={item}
|
||||
opts={opts}
|
||||
tense={tense}
|
||||
/>
|
||||
),
|
||||
};
|
||||
}}/>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default BasicVerbShowCase;
|
||||
|
||||
function BasicVerbChart({ verb, opts, tense, passive, ability }: {
|
||||
verb: T.VerbEntry,
|
||||
opts: T.TextOptions,
|
||||
tense: T.VerbTense | T.ImperativeTense | T.PerfectTense,
|
||||
passive?: boolean,
|
||||
ability?: boolean,
|
||||
function BasicVerbChart({
|
||||
verb,
|
||||
opts,
|
||||
tense,
|
||||
passive,
|
||||
ability,
|
||||
}: {
|
||||
verb: T.VerbEntry;
|
||||
opts: T.TextOptions;
|
||||
tense: T.VerbTense | T.ImperativeTense | T.PerfectTense;
|
||||
passive?: boolean;
|
||||
ability?: boolean;
|
||||
}) {
|
||||
const [voice, setVoice] = useState<"active" | "passive">("active");
|
||||
const [category, setCategory] = useState<"basic" | "ability">("basic");
|
||||
const [negative, setNegative] = useState<boolean>(false);
|
||||
const [length, setLength] = useState<"short" | "long">("short");
|
||||
const c = conjugateVerb(verb.entry, verb.complement);
|
||||
const conjugations = "stative" in c
|
||||
? c.stative
|
||||
: "grammaticallyTransitive" in c
|
||||
? c.grammaticallyTransitive
|
||||
: c;
|
||||
const phrasesForTable = makeExamplePhrases(verb, tense, negative, length, voice, category);
|
||||
return <div>
|
||||
<div>
|
||||
{getEnglishVerb(verb.entry)}
|
||||
const [voice, setVoice] = useState<"active" | "passive">("active");
|
||||
const [category, setCategory] = useState<"basic" | "ability">("basic");
|
||||
const [negative, setNegative] = useState<boolean>(false);
|
||||
const [length, setLength] = useState<"short" | "long">("short");
|
||||
const c = conjugateVerb(verb.entry, verb.complement);
|
||||
const conjugations =
|
||||
"stative" in c
|
||||
? c.stative
|
||||
: "grammaticallyTransitive" in c
|
||||
? c.grammaticallyTransitive
|
||||
: c;
|
||||
const phrasesForTable = makeExamplePhrases(
|
||||
verb,
|
||||
tense,
|
||||
negative,
|
||||
length,
|
||||
voice,
|
||||
category
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<div>{getEnglishVerb(verb.entry)}</div>
|
||||
{passive && (
|
||||
<div className="my-2">
|
||||
<ButtonSelect
|
||||
options={[
|
||||
{
|
||||
label: "Active",
|
||||
value: "active",
|
||||
},
|
||||
{
|
||||
label: "Passive",
|
||||
value: "passive",
|
||||
},
|
||||
]}
|
||||
value={voice}
|
||||
handleChange={setVoice}
|
||||
/>
|
||||
</div>
|
||||
{passive && <div className="my-2">
|
||||
)}
|
||||
{ability && (
|
||||
<div className="my-2">
|
||||
<ButtonSelect
|
||||
options={[
|
||||
{
|
||||
label: "Basic",
|
||||
value: "basic",
|
||||
},
|
||||
{
|
||||
label: "Ability",
|
||||
value: "ability",
|
||||
},
|
||||
]}
|
||||
value={category}
|
||||
handleChange={setCategory}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<RootsAndStems
|
||||
textOptions={opts}
|
||||
info={
|
||||
category === "ability"
|
||||
? getAbilityRootsAndStems(conjugations.info)
|
||||
: voice === "passive"
|
||||
? getPassiveRootsAndStems(conjugations.info) ||
|
||||
/* type safety */ conjugations.info
|
||||
: conjugations.info
|
||||
}
|
||||
hidePastParticiple={isPerfectTense(tense) ? false : true}
|
||||
highlighted={[tenseToStem(tense)]}
|
||||
/>
|
||||
<div className="my-3 d-flex flex-row justify-content-center">
|
||||
{((isPastTense(tense) && !isPerfectTense(tense)) ||
|
||||
category === "ability") && (
|
||||
<div className="mx-2">
|
||||
<ButtonSelect
|
||||
options={[{
|
||||
label: "Active",
|
||||
value: "active",
|
||||
}, {
|
||||
label: "Passive",
|
||||
value: "passive",
|
||||
}]}
|
||||
value={voice}
|
||||
handleChange={setVoice}
|
||||
handleChange={setLength}
|
||||
value={length}
|
||||
small
|
||||
options={[
|
||||
{ value: "long", label: "long" },
|
||||
{ value: "short", label: "short" },
|
||||
]}
|
||||
/>
|
||||
</div>}
|
||||
{ability && <div className="my-2">
|
||||
<ButtonSelect
|
||||
options={[{
|
||||
label: "Basic",
|
||||
value: "basic",
|
||||
}, {
|
||||
label: "Ability",
|
||||
value: "ability",
|
||||
}]}
|
||||
value={category}
|
||||
handleChange={setCategory}
|
||||
/>
|
||||
</div>}
|
||||
<RootsAndStems
|
||||
textOptions={opts}
|
||||
info={category === "ability"
|
||||
? (getAbilityRootsAndStems(conjugations.info))
|
||||
: voice === "passive"
|
||||
? (getPassiveRootsAndStems(conjugations.info) || /* type safety */ conjugations.info)
|
||||
: conjugations.info
|
||||
}
|
||||
hidePastParticiple={isPerfectTense(tense) ? false : true}
|
||||
highlighted={[tenseToStem(tense)]}
|
||||
</div>
|
||||
)}
|
||||
<div className="mx-2">
|
||||
<ButtonSelect
|
||||
handleChange={(value) => setNegative(value === "true")}
|
||||
value={String(negative)}
|
||||
small
|
||||
options={[
|
||||
{ value: "true", label: "Neg." },
|
||||
{ value: "false", label: "Pos." },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<VerbTable
|
||||
textOptions={opts}
|
||||
block={phrasesForTable.ps}
|
||||
english={phrasesForTable.e}
|
||||
/>
|
||||
<div className="my-3 d-flex flex-row justify-content-center">
|
||||
{((isPastTense(tense) && !isPerfectTense(tense)) || category === "ability") && <div className="mx-2">
|
||||
<ButtonSelect
|
||||
handleChange={setLength}
|
||||
value={length}
|
||||
small
|
||||
options={[
|
||||
{ value: "long", label: "long" },
|
||||
{ value: "short", label: "short" },
|
||||
]}
|
||||
/>
|
||||
</div>}
|
||||
<div className="mx-2">
|
||||
<ButtonSelect
|
||||
handleChange={(value) => setNegative(value === "true")}
|
||||
value={String(negative)}
|
||||
small
|
||||
options={[
|
||||
{ value: "true", label: "Neg." },
|
||||
{ value: "false", label: "Pos." },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<VerbTable
|
||||
textOptions={opts}
|
||||
block={phrasesForTable.ps}
|
||||
english={phrasesForTable.e}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function makeExamplePhrases(
|
||||
verb: T.VerbEntry,
|
||||
tense: T.VerbTense | T.ImperativeTense | T.PerfectTense,
|
||||
negative: boolean,
|
||||
length: "short" | "long",
|
||||
voice: "active" | "passive",
|
||||
category: "basic" | "ability",
|
||||
): { ps: T.VerbBlock | T.ImperativeBlock, e: T.EnglishBlock } {
|
||||
function tenseToModal(t: T.VerbTense | T.ImperativeTense | T.PerfectTense): T.ModalTense {
|
||||
if (isImperativeTense(t)) {
|
||||
throw new Error("can't have imperative tense with modal");
|
||||
}
|
||||
if (isPerfectTense(t)) {
|
||||
throw new Error("cant' have perfect tense with modal");
|
||||
}
|
||||
return `${t}Modal`;
|
||||
verb: T.VerbEntry,
|
||||
tense: T.VerbTense | T.ImperativeTense | T.PerfectTense,
|
||||
negative: boolean,
|
||||
length: "short" | "long",
|
||||
voice: "active" | "passive",
|
||||
category: "basic" | "ability"
|
||||
): { ps: T.VerbBlock | T.ImperativeBlock; e: T.EnglishBlock } {
|
||||
function tenseToModal(
|
||||
t: T.VerbTense | T.ImperativeTense | T.PerfectTense
|
||||
): T.AbilityTense {
|
||||
if (isImperativeTense(t)) {
|
||||
throw new Error("can't have imperative tense with modal");
|
||||
}
|
||||
function makeSelection(person: T.Person): T.VPSelectionComplete{
|
||||
return {
|
||||
"blocks": [
|
||||
{"key":Math.random(),"block":{"type":"subjectSelection","selection":{"type":"NP","selection":{"type":"pronoun","person": person,"distance":"far"}}}},
|
||||
{
|
||||
key: Math.random(),
|
||||
// @ts-ignore
|
||||
block: (verb.entry.c?.includes("intrans.") || voice === "passive")
|
||||
? {"type":"objectSelection","selection":"none"}
|
||||
: {"type":"objectSelection", "selection":{"type":"NP","selection":{"type":"noun","entry":{"ts":1527812817,"i":10011,"p":"کتاب","f":"kitáab","g":"kitaab","e":"book","c":"n. m."},"gender":"masc","genderCanChange":false,"number":"singular","numberCanChange":true,"adjectives":[]}}},
|
||||
},
|
||||
],
|
||||
"verb":{
|
||||
"type":"verb",
|
||||
verb,
|
||||
tense: category === "basic" ? tense : tenseToModal(tense),
|
||||
"transitivity":"intransitive",
|
||||
"isCompound":false,
|
||||
voice,
|
||||
negative,
|
||||
"canChangeTransitivity":false,
|
||||
"canChangeVoice":false,
|
||||
"canChangeStatDyn":false,
|
||||
if (isPerfectTense(t)) {
|
||||
throw new Error("cant' have perfect tense with modal");
|
||||
}
|
||||
return `${t}Modal`;
|
||||
}
|
||||
function makeSelection(person: T.Person): T.VPSelectionComplete {
|
||||
return {
|
||||
blocks: [
|
||||
{
|
||||
key: Math.random(),
|
||||
block: {
|
||||
type: "subjectSelection",
|
||||
selection: {
|
||||
type: "NP",
|
||||
selection: { type: "pronoun", person: person, distance: "far" },
|
||||
},
|
||||
"form":{"removeKing":false,"shrinkServant":false},
|
||||
};
|
||||
}
|
||||
function makePhrase(person: T.Person): { ps: T.ArrayOneOrMore<T.PsString>, e: string } {
|
||||
const selection = makeSelection(person);
|
||||
const rendered = renderVP(selection);
|
||||
const compiled = compileVP(rendered, rendered.form);
|
||||
return {
|
||||
ps: [modifyP(getLength(compiled.ps, length)[0])],
|
||||
e: compiled.e ? modifyEnglish(compiled.e.join(" • "), tense, isThirdPerson(person)) : "",
|
||||
};
|
||||
}
|
||||
return createVerbTable(makePhrase, isImperativeTense(tense) ? "imperative" : isPastTense(tense) ? "past" : "nonImperative");
|
||||
},
|
||||
},
|
||||
{
|
||||
key: Math.random(),
|
||||
// @ts-ignore
|
||||
block:
|
||||
verb.entry.c?.includes("intrans.") || voice === "passive"
|
||||
? { type: "objectSelection", selection: "none" }
|
||||
: {
|
||||
type: "objectSelection",
|
||||
selection: {
|
||||
type: "NP",
|
||||
selection: {
|
||||
type: "noun",
|
||||
entry: {
|
||||
ts: 1527812817,
|
||||
i: 10011,
|
||||
p: "کتاب",
|
||||
f: "kitáab",
|
||||
g: "kitaab",
|
||||
e: "book",
|
||||
c: "n. m.",
|
||||
},
|
||||
gender: "masc",
|
||||
genderCanChange: false,
|
||||
number: "singular",
|
||||
numberCanChange: true,
|
||||
adjectives: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
verb: {
|
||||
type: "verb",
|
||||
verb,
|
||||
tense: category === "basic" ? tense : tenseToModal(tense),
|
||||
transitivity: "intransitive",
|
||||
isCompound: false,
|
||||
voice,
|
||||
negative,
|
||||
canChangeTransitivity: false,
|
||||
canChangeVoice: false,
|
||||
canChangeStatDyn: false,
|
||||
},
|
||||
form: { removeKing: false, shrinkServant: false },
|
||||
};
|
||||
}
|
||||
function makePhrase(person: T.Person): {
|
||||
ps: T.ArrayOneOrMore<T.PsString>;
|
||||
e: string;
|
||||
} {
|
||||
const selection = makeSelection(person);
|
||||
const rendered = renderVP(selection);
|
||||
const compiled = compileVP(rendered, rendered.form);
|
||||
return {
|
||||
ps: [modifyP(getLength(compiled.ps, length)[0])],
|
||||
e: compiled.e
|
||||
? modifyEnglish(compiled.e.join(" • "), tense, isThirdPerson(person))
|
||||
: "",
|
||||
};
|
||||
}
|
||||
return createVerbTable(
|
||||
makePhrase,
|
||||
isImperativeTense(tense)
|
||||
? "imperative"
|
||||
: isPastTense(tense)
|
||||
? "past"
|
||||
: "nonImperative"
|
||||
);
|
||||
}
|
||||
|
||||
function modifyP(ps: T.PsString): T.PsString {
|
||||
return {
|
||||
p: ps.p.replace(" کتاب ", ""),
|
||||
f: ps.f.replace(" kitáab ", ""),
|
||||
};
|
||||
return {
|
||||
p: ps.p.replace(" کتاب ", ""),
|
||||
f: ps.f.replace(" kitáab ", ""),
|
||||
};
|
||||
}
|
||||
|
||||
function modifyEnglish(e: string, tense: T.VerbTense | T.ImperativeTense | T.PerfectTense, isThirdPerson: boolean): string {
|
||||
// "kitaab" used as a dummy object
|
||||
const dummyObjectRemoved =
|
||||
e.replace(/\(a\/the\) +book/ig, "")
|
||||
return (isPerfectTense(tense) || (isPastTense(tense) && isThirdPerson))
|
||||
? dummyObjectRemoved
|
||||
: dummyObjectRemoved
|
||||
.replace(/he\/it/ig, "he/she/it")
|
||||
.replace(/We \(m\. pl\.\)/ig, "We ")
|
||||
.replace(/They \(m\. pl\.\)/ig, "They ")
|
||||
.replace(/\(m\. pl\.\)/ig, "(pl.)")
|
||||
.replace(/\(m\.\)/ig, "");
|
||||
function modifyEnglish(
|
||||
e: string,
|
||||
tense: T.VerbTense | T.ImperativeTense | T.PerfectTense,
|
||||
isThirdPerson: boolean
|
||||
): string {
|
||||
// "kitaab" used as a dummy object
|
||||
const dummyObjectRemoved = e.replace(/\(a\/the\) +book/gi, "");
|
||||
return isPerfectTense(tense) || (isPastTense(tense) && isThirdPerson)
|
||||
? dummyObjectRemoved
|
||||
: dummyObjectRemoved
|
||||
.replace(/he\/it/gi, "he/she/it")
|
||||
.replace(/We \(m\. pl\.\)/gi, "We ")
|
||||
.replace(/They \(m\. pl\.\)/gi, "They ")
|
||||
.replace(/\(m\. pl\.\)/gi, "(pl.)")
|
||||
.replace(/\(m\.\)/gi, "");
|
||||
}
|
||||
|
||||
function tenseToStem(t: T.VerbTense | T.ImperativeTense | T.PerfectTense): "imperfective stem" | "perfective stem" | "imperfective root" | "perfective root" | "past participle" {
|
||||
const stem = t === "presentVerb"
|
||||
? "imperfective stem"
|
||||
: t === "subjunctiveVerb"
|
||||
? "perfective stem"
|
||||
: t === "imperfectiveFuture"
|
||||
? "imperfective stem"
|
||||
: t === "perfectiveFuture"
|
||||
? "perfective stem"
|
||||
: t === "imperfectivePast"
|
||||
? "imperfective root"
|
||||
: t === "perfectivePast"
|
||||
? "perfective root"
|
||||
: t === "habitualImperfectivePast"
|
||||
? "imperfective root"
|
||||
: t === "habitualPerfectivePast"
|
||||
? "perfective root"
|
||||
: t === "imperfectiveImperative"
|
||||
? "imperfective stem"
|
||||
: t === "perfectiveImperative"
|
||||
? "perfective stem"
|
||||
: t.endsWith("Perfect")
|
||||
? "past participle"
|
||||
: "perfective root";
|
||||
return stem;
|
||||
function tenseToStem(
|
||||
t: T.VerbTense | T.ImperativeTense | T.PerfectTense
|
||||
):
|
||||
| "imperfective stem"
|
||||
| "perfective stem"
|
||||
| "imperfective root"
|
||||
| "perfective root"
|
||||
| "past participle" {
|
||||
const stem =
|
||||
t === "presentVerb"
|
||||
? "imperfective stem"
|
||||
: t === "subjunctiveVerb"
|
||||
? "perfective stem"
|
||||
: t === "imperfectiveFuture"
|
||||
? "imperfective stem"
|
||||
: t === "perfectiveFuture"
|
||||
? "perfective stem"
|
||||
: t === "imperfectivePast"
|
||||
? "imperfective root"
|
||||
: t === "perfectivePast"
|
||||
? "perfective root"
|
||||
: t === "habitualImperfectivePast"
|
||||
? "imperfective root"
|
||||
: t === "habitualPerfectivePast"
|
||||
? "perfective root"
|
||||
: t === "imperfectiveImperative"
|
||||
? "imperfective stem"
|
||||
: t === "perfectiveImperative"
|
||||
? "perfective stem"
|
||||
: t.endsWith("Perfect")
|
||||
? "past participle"
|
||||
: "perfective root";
|
||||
return stem;
|
||||
}
|
||||
|
||||
function createVerbTable(f: (person: T.Person) => { ps: T.ArrayOneOrMore<T.PsString>, e: string }, type: "imperative" | "nonImperative" | "past"): { ps: T.VerbBlock | T.ImperativeBlock, e: T.EnglishBlock } {
|
||||
if (type === "imperative") {
|
||||
const b = [
|
||||
[f(2), f(8)],
|
||||
[f(3), f(9)],
|
||||
];
|
||||
return {
|
||||
ps: [
|
||||
[b[0][0].ps, b[0][1].ps],
|
||||
[b[1][0].ps, b[1][1].ps],
|
||||
],
|
||||
e: [
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
],
|
||||
};
|
||||
}
|
||||
function createVerbTable(
|
||||
f: (person: T.Person) => { ps: T.ArrayOneOrMore<T.PsString>; e: string },
|
||||
type: "imperative" | "nonImperative" | "past"
|
||||
): { ps: T.VerbBlock | T.ImperativeBlock; e: T.EnglishBlock } {
|
||||
if (type === "imperative") {
|
||||
const b = [
|
||||
[f(0), f(6)],
|
||||
[f(1), f(7)],
|
||||
[f(2), f(8)],
|
||||
[f(3), f(9)],
|
||||
[f(4), f(10)],
|
||||
[f(5), f(11)],
|
||||
[f(2), f(8)],
|
||||
[f(3), f(9)],
|
||||
];
|
||||
return {
|
||||
ps: [
|
||||
[b[0][0].ps, b[0][1].ps],
|
||||
[b[1][0].ps, b[1][1].ps],
|
||||
[b[2][0].ps, b[2][1].ps],
|
||||
[b[3][0].ps, b[3][1].ps],
|
||||
[b[4][0].ps, b[4][1].ps],
|
||||
[b[5][0].ps, b[5][1].ps],
|
||||
],
|
||||
e: [
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
[b[2][0].e, b[2][1].e],
|
||||
[b[3][0].e, b[3][1].e],
|
||||
[b[4][0].e, b[4][1].e],
|
||||
[b[5][0].e, b[5][1].e],
|
||||
],
|
||||
ps: [
|
||||
[b[0][0].ps, b[0][1].ps],
|
||||
[b[1][0].ps, b[1][1].ps],
|
||||
],
|
||||
e: [
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
const b = [
|
||||
[f(0), f(6)],
|
||||
[f(1), f(7)],
|
||||
[f(2), f(8)],
|
||||
[f(3), f(9)],
|
||||
[f(4), f(10)],
|
||||
[f(5), f(11)],
|
||||
];
|
||||
return {
|
||||
ps: [
|
||||
[b[0][0].ps, b[0][1].ps],
|
||||
[b[1][0].ps, b[1][1].ps],
|
||||
[b[2][0].ps, b[2][1].ps],
|
||||
[b[3][0].ps, b[3][1].ps],
|
||||
[b[4][0].ps, b[4][1].ps],
|
||||
[b[5][0].ps, b[5][1].ps],
|
||||
],
|
||||
e: [
|
||||
[b[0][0].e, b[0][1].e],
|
||||
[b[1][0].e, b[1][1].e],
|
||||
[b[2][0].e, b[2][1].e],
|
||||
[b[3][0].e, b[3][1].e],
|
||||
[b[4][0].e, b[4][1].e],
|
||||
[b[5][0].e, b[5][1].e],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import { Component } from "react";
|
||||
import classNames from "classnames";
|
||||
import highlightExample from "./highlight-example";
|
||||
import {
|
||||
phonemes,
|
||||
Phoneme,
|
||||
PhonemeExample,
|
||||
} from "./phonemes";
|
||||
import { phonemes, Phoneme, PhonemeExample } from "./phonemes";
|
||||
import playAudio from "../../lib/play-audio";
|
||||
import views from "./views";
|
||||
import Media from "react-media";
|
||||
|
||||
export type ViewOptions = "all" | "shortVowel" | "longVowel" | "fiveYs" | "specialConsonant";
|
||||
export type ViewOptions =
|
||||
| "all"
|
||||
| "shortVowel"
|
||||
| "longVowel"
|
||||
| "fiveYs"
|
||||
| "specialConsonant";
|
||||
|
||||
interface IAppState {
|
||||
view: ViewOptions;
|
||||
|
@ -28,100 +29,119 @@ class PhoneticsViewer extends Component<any, IAppState> {
|
|||
const phonemesShowing =
|
||||
this.state.view === "all"
|
||||
? phonemes
|
||||
// @ts-ignore
|
||||
: phonemes.filter((p) => p[this.state.view]);
|
||||
: // @ts-ignore
|
||||
phonemes.filter((p) => p[this.state.view]);
|
||||
const selectedOption = views.find((v) => v.value === this.state.view);
|
||||
const generatePlayerFunction = (item: Phoneme | PhonemeExample) => {
|
||||
if ("phoneme" in item && item.a) {
|
||||
return () => { playAudio(item.a || ""); };
|
||||
return () => {
|
||||
playAudio(item.a || "");
|
||||
};
|
||||
}
|
||||
if ("f" in item && item.a) {
|
||||
// dumb typescript
|
||||
return () => { playAudio(item.a || ""); };
|
||||
// dumb typescript
|
||||
return () => {
|
||||
playAudio(item.a || "");
|
||||
};
|
||||
}
|
||||
return () => null;
|
||||
}
|
||||
return <>
|
||||
<div className="text-center mt-4">
|
||||
<Media queries={{ small: "(max-width: 599px)" }}>
|
||||
{matches => (
|
||||
<div className={`btn-group${matches.small ? "-vertical" : ""} mb-3`}>
|
||||
{views.map(({ label, value }) => (
|
||||
<button
|
||||
key={value}
|
||||
type="button"
|
||||
className={classNames("btn", "btn-outline-secondary", {
|
||||
active: this.state.view === value,
|
||||
})}
|
||||
onClick={() => this.setState({ view: value })}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Media>
|
||||
<div className="small mb-2"><i className="fas fa-volume-down"></i> click the phonetic letter or examples to hear - not all sounds are available</div>
|
||||
</div>
|
||||
<div style={{ overflowX: "auto", marginBottom: "1em" }}>
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Phonetic Letter</th>
|
||||
{/* <th>IPA Letter</th> */}
|
||||
<th>Short Explanation</th>
|
||||
<th>Example</th>
|
||||
<th>Pashto Letter(s)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{phonemesShowing.map((phoneme) => (
|
||||
<tr key={phoneme.phoneme}>
|
||||
<td onClick={generatePlayerFunction(phoneme)}>
|
||||
{phoneme.phoneme}
|
||||
</td>
|
||||
{/* <td>{phoneme.ipa.letter} </td> */}
|
||||
<td>
|
||||
{phoneme.quickExplanation}{" "}
|
||||
{phoneme.ipa.video && (
|
||||
<a href={phoneme.ipa.video} target="_blank" rel="noopener noreferrer">
|
||||
<i className="fa fa-video" />
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
<td onClick={generatePlayerFunction(phoneme.examples[0])}>
|
||||
{highlightExample(
|
||||
phoneme.examples[0].f,
|
||||
phoneme.examples[0].fHighlight
|
||||
)}
|
||||
{` - `}
|
||||
{highlightExample(
|
||||
phoneme.examples[0].p,
|
||||
phoneme.examples[0].pHighlight
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
{phoneme.possibleLetters
|
||||
? phoneme.possibleLetters.reduce(
|
||||
(s, l) =>
|
||||
`${s}${l.letter} ${
|
||||
l.alternate ? ` (${l.alternate}) ` : ""
|
||||
}`,
|
||||
""
|
||||
)
|
||||
: ""}
|
||||
{/* phoneme.diacritic && `(diacritic ◌${phoneme.diacritic})` */}
|
||||
</td>
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="text-center mt-4">
|
||||
<Media queries={{ small: "(max-width: 599px)" }}>
|
||||
{(matches) => (
|
||||
<div
|
||||
className={`btn-group${matches.small ? "-vertical" : ""} mb-3`}
|
||||
>
|
||||
{views.map(({ label, value }) => (
|
||||
<button
|
||||
key={value}
|
||||
type="button"
|
||||
className={classNames("btn", "btn-outline-secondary", {
|
||||
active: this.state.view === value,
|
||||
})}
|
||||
onClick={() => this.setState({ view: value })}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Media>
|
||||
<div className="small mb-2">
|
||||
<i className="fas fa-volume-down"></i> click the phonetic letter or
|
||||
examples to hear - not all sounds are available
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ overflowX: "auto", marginBottom: "1em" }}>
|
||||
<table className="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Phonetic Letter</th>
|
||||
{/* <th>IPA Letter</th> */}
|
||||
<th>Short Explanation</th>
|
||||
<th>Example</th>
|
||||
<th>Pashto Letter(s)</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{selectedOption?.notes && <div>
|
||||
<p><strong>Notes about {selectedOption.label.toLowerCase()}:</strong></p>
|
||||
{selectedOption.notes}
|
||||
</div>}
|
||||
</>;
|
||||
</thead>
|
||||
<tbody>
|
||||
{phonemesShowing.map((phoneme) => (
|
||||
<tr key={phoneme.phoneme}>
|
||||
<td onClick={generatePlayerFunction(phoneme)}>
|
||||
{phoneme.phoneme}
|
||||
</td>
|
||||
{/* <td>{phoneme.ipa.letter} </td> */}
|
||||
<td>
|
||||
{phoneme.quickExplanation}{" "}
|
||||
{phoneme.ipa.video && (
|
||||
<a
|
||||
href={phoneme.ipa.video}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<i className="fa fa-video" />
|
||||
</a>
|
||||
)}
|
||||
</td>
|
||||
<td onClick={generatePlayerFunction(phoneme.examples[0])}>
|
||||
{highlightExample(
|
||||
phoneme.examples[0].f,
|
||||
phoneme.examples[0].fHighlight
|
||||
)}
|
||||
{` - `}
|
||||
{highlightExample(
|
||||
phoneme.examples[0].p,
|
||||
phoneme.examples[0].pHighlight
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
{phoneme.possibleLetters
|
||||
? phoneme.possibleLetters.reduce(
|
||||
(s, l) =>
|
||||
`${s}${l.letter} ${
|
||||
l.alternate ? ` (${l.alternate}) ` : ""
|
||||
}`,
|
||||
""
|
||||
)
|
||||
: ""}
|
||||
{/* phoneme.diacritic && `(diacritic ◌${phoneme.diacritic})` */}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{selectedOption?.notes && (
|
||||
<div>
|
||||
<p>
|
||||
<strong>Notes about {selectedOption.label.toLowerCase()}:</strong>
|
||||
</p>
|
||||
{selectedOption.notes}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
import React, { ReactNode } from "react";
|
||||
|
||||
export default function highlightExample(text: string, highlight: number[][]): ReactNode {
|
||||
if (!highlight.length) {
|
||||
return text;
|
||||
}
|
||||
let index = 0;
|
||||
// @ts-ignore
|
||||
const pText = highlight.reduce((acc, curr, i): ReactNode => {
|
||||
const isLastElement = i === (highlight.length - 1);
|
||||
const section = [
|
||||
...acc,
|
||||
curr[0] > 0 ? text.slice(index, curr[0]) : "",
|
||||
<strong>{text.slice(curr[0], curr[1] + 1)}</strong>,
|
||||
isLastElement ? text.slice(curr[1] + 1) : "",
|
||||
];
|
||||
index = curr[1] + 1;
|
||||
return section;
|
||||
}, []);
|
||||
return pText;
|
||||
export default function highlightExample(
|
||||
text: string,
|
||||
highlight: number[][]
|
||||
): ReactNode {
|
||||
if (!highlight.length) {
|
||||
return text;
|
||||
}
|
||||
let index = 0;
|
||||
// @ts-ignore
|
||||
const pText = highlight.reduce((acc, curr, i): ReactNode => {
|
||||
const isLastElement = i === highlight.length - 1;
|
||||
const section = [
|
||||
...acc,
|
||||
curr[0] > 0 ? text.slice(index, curr[0]) : "",
|
||||
<strong>{text.slice(curr[0], curr[1] + 1)}</strong>,
|
||||
isLastElement ? text.slice(curr[1] + 1) : "",
|
||||
];
|
||||
index = curr[1] + 1;
|
||||
return section;
|
||||
}, []);
|
||||
return pText;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ export const letters: IAlphabet = {
|
|||
|
||||
export const diacritics = {
|
||||
zwar: "َ",
|
||||
zwarakey: "ٙ",
|
||||
zwarakay: "ٙ",
|
||||
zer: "ِ",
|
||||
pesh: "ُ",
|
||||
sukun: "ْ",
|
||||
|
@ -116,30 +116,28 @@ export const diacritics = {
|
|||
fathahan: "ً",
|
||||
};
|
||||
|
||||
export type PhonemeExample = (
|
||||
T.PsString &
|
||||
{
|
||||
pHighlight: number[][],
|
||||
fHighlight: number[][],
|
||||
a?: string,
|
||||
audio?: { externalLink: string },
|
||||
});
|
||||
export type PhonemeExample = T.PsString & {
|
||||
pHighlight: number[][];
|
||||
fHighlight: number[][];
|
||||
a?: string;
|
||||
audio?: { externalLink: string };
|
||||
};
|
||||
|
||||
export type Phoneme = {
|
||||
phoneme: string,
|
||||
a?: string,
|
||||
quickExplanation: string | JSX.Element,
|
||||
specialConsonant?: boolean,
|
||||
shortVowel?: boolean,
|
||||
longVowel?: boolean,
|
||||
addAlefToStart?: boolean,
|
||||
fiveYs?: boolean,
|
||||
canBeIgnored?: boolean,
|
||||
ipa: any,
|
||||
onlyOnEnd?: boolean,
|
||||
endingLetter?: ILetter,
|
||||
examples: PhonemeExample[],
|
||||
} & ({ possibleLetters: ILetter[] } | { diacritic: string })
|
||||
phoneme: string;
|
||||
a?: string;
|
||||
quickExplanation: string | JSX.Element;
|
||||
specialConsonant?: boolean;
|
||||
shortVowel?: boolean;
|
||||
longVowel?: boolean;
|
||||
addAlefToStart?: boolean;
|
||||
fiveYs?: boolean;
|
||||
canBeIgnored?: boolean;
|
||||
ipa: any;
|
||||
onlyOnEnd?: boolean;
|
||||
endingLetter?: ILetter;
|
||||
examples: PhonemeExample[];
|
||||
} & ({ possibleLetters: ILetter[] } | { diacritic: string });
|
||||
|
||||
export const phonemes = [
|
||||
// consonants
|
||||
|
@ -567,9 +565,9 @@ export const phonemes = [
|
|||
examples: [
|
||||
{
|
||||
p: "وږی",
|
||||
f: "wuGey",
|
||||
f: "wuGay",
|
||||
e: "hungry",
|
||||
a: "wuggey",
|
||||
a: "wuggay",
|
||||
pHighlight: [[1, 1]],
|
||||
fHighlight: [[2, 2]],
|
||||
},
|
||||
|
@ -824,8 +822,7 @@ export const phonemes = [
|
|||
quickExplanation: "l with back of tongue higher up",
|
||||
ipa: {
|
||||
letter: "l",
|
||||
link:
|
||||
"https://en.wikipedia.org/wiki/Voiced_dental,_alveolar_and_postalveolar_lateral_approximants#Voiced_alveolar_lateral_approximant",
|
||||
link: "https://en.wikipedia.org/wiki/Voiced_dental,_alveolar_and_postalveolar_lateral_approximants#Voiced_alveolar_lateral_approximant",
|
||||
},
|
||||
examples: [
|
||||
{
|
||||
|
@ -833,8 +830,14 @@ export const phonemes = [
|
|||
f: "leekul",
|
||||
e: "to write",
|
||||
a: "leekul",
|
||||
pHighlight: [[0, 0], [3, 3]],
|
||||
fHighlight: [[0, 0], [5, 5]],
|
||||
pHighlight: [
|
||||
[0, 0],
|
||||
[3, 3],
|
||||
],
|
||||
fHighlight: [
|
||||
[0, 0],
|
||||
[5, 5],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -940,8 +943,8 @@ export const phonemes = [
|
|||
examples: [
|
||||
{
|
||||
p: "وږی",
|
||||
f: "wuGey",
|
||||
a: "wuggey",
|
||||
f: "wuGay",
|
||||
a: "wuggay",
|
||||
e: "hungry",
|
||||
pHighlight: [[0, 0]],
|
||||
fHighlight: [[0, 0]],
|
||||
|
@ -994,9 +997,9 @@ export const phonemes = [
|
|||
examples: [
|
||||
{
|
||||
p: "سَړی",
|
||||
f: "saRey",
|
||||
f: "saRay",
|
||||
e: "man",
|
||||
a: "sarrey",
|
||||
a: "sarray",
|
||||
pHighlight: [[1, 1]],
|
||||
fHighlight: [[1, 1]],
|
||||
},
|
||||
|
@ -1059,7 +1062,7 @@ export const phonemes = [
|
|||
{
|
||||
phoneme: "u",
|
||||
shortVowel: true,
|
||||
diacritic: diacritics.zwarakey,
|
||||
diacritic: diacritics.zwarakay,
|
||||
quickExplanation: (
|
||||
<>
|
||||
shwa sound similar to u in b<strong>u</strong>d
|
||||
|
@ -1200,11 +1203,7 @@ export const phonemes = [
|
|||
longVowel: true,
|
||||
fiveYs: true,
|
||||
addAlefToStart: true,
|
||||
quickExplanation: (
|
||||
<>
|
||||
close to ee in b<strong>ee</strong> but more open
|
||||
</>
|
||||
),
|
||||
quickExplanation: <>'ee' sound but with mouth slightly more open</>,
|
||||
ipa: {
|
||||
letter: "e",
|
||||
},
|
||||
|
@ -1220,15 +1219,15 @@ export const phonemes = [
|
|||
],
|
||||
},
|
||||
{
|
||||
phoneme: "ey",
|
||||
a: "ey",
|
||||
phoneme: "ay",
|
||||
a: "ay",
|
||||
possibleLetters: [letters.naareenaYe],
|
||||
longVowel: true,
|
||||
fiveYs: true,
|
||||
addAlefToStart: true,
|
||||
quickExplanation: (
|
||||
<>
|
||||
similar to ay in d<strong>ay</strong>
|
||||
short 'a' sound + y. similar to ay in d<strong>ay</strong>
|
||||
</>
|
||||
),
|
||||
ipa: {
|
||||
|
@ -1237,32 +1236,31 @@ export const phonemes = [
|
|||
examples: [
|
||||
{
|
||||
p: "سړی",
|
||||
f: "saRey",
|
||||
f: "saRay",
|
||||
e: "man",
|
||||
a: "saRey",
|
||||
a: "saRay",
|
||||
pHighlight: [[2, 2]],
|
||||
fHighlight: [[3, 4]],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
phoneme: "eyy",
|
||||
a: "eyy",
|
||||
phoneme: "ey",
|
||||
a: "ey",
|
||||
possibleLetters: [letters.faailiyaYe],
|
||||
longVowel: true,
|
||||
fiveYs: true,
|
||||
onlyOnEnd: true,
|
||||
quickExplanation:
|
||||
"Close or the same as 'uy'. Starts with a ‘ey’ sound and glides into an ‘ee’ at the end",
|
||||
quickExplanation: "‘e’ sound + y",
|
||||
ipa: {
|
||||
letter: "əi",
|
||||
},
|
||||
examples: [
|
||||
{
|
||||
p: "کښېنئ",
|
||||
f: "kxeneyy",
|
||||
f: "kxeney",
|
||||
e: "please sit",
|
||||
a: "kxeneyy",
|
||||
a: "kxeney",
|
||||
pHighlight: [[4, 4]],
|
||||
fHighlight: [[4, 6]],
|
||||
},
|
||||
|
@ -1274,8 +1272,7 @@ export const phonemes = [
|
|||
possibleLetters: [letters.xudzeenaYe],
|
||||
longVowel: true,
|
||||
fiveYs: true,
|
||||
quickExplanation:
|
||||
"Starts with a ‘u’ (schwa) sound and glides into an ‘ee’ at the end",
|
||||
quickExplanation: "‘u’ (schwa) sound + y",
|
||||
ipa: {
|
||||
letter: "əi",
|
||||
},
|
||||
|
|
|
@ -23,9 +23,9 @@ import e from "./audio/e.m4a";
|
|||
// @ts-ignore
|
||||
import ee from "./audio/ee.m4a";
|
||||
// @ts-ignore
|
||||
import ey from "./audio/ey.m4a";
|
||||
import ay from "./audio/ey.m4a";
|
||||
// @ts-ignore
|
||||
import eyy from "./audio/eyy.m4a";
|
||||
import ey from "./audio/eyy.m4a";
|
||||
// @ts-ignore
|
||||
import gh from "./audio/gh.m4a";
|
||||
// @ts-ignore
|
||||
|
@ -144,10 +144,76 @@ import naayee from "./audio/naayee.mp3";
|
|||
import fojee from "./audio/fojee.mp3";
|
||||
|
||||
export default {
|
||||
a, aa, aasmaan, d, D, DoDuy, dwa, dz, dzaay, dzungul, e, ee, ey,
|
||||
eyy, gh, gharma, h, halaat, i, injuluy, islaam, joR, jz, jzwund, kadoo,
|
||||
kh, khwux, kxeneyy, l, leekul, lUtfan, maalTa, maNa, meena, N, o, oo,
|
||||
oox, ooy, paaNa, poza, puxto, q, qaazee, r, R, rang, saRey, t, tor, ts,
|
||||
tsomra, T, u, uu, uy, w, wuGey, waadu, x, xudza, xudze, zooy, sheen, chaa,
|
||||
baad, kor, gUl, maat, maruy, naayee, fojee,
|
||||
a,
|
||||
aa,
|
||||
aasmaan,
|
||||
d,
|
||||
D,
|
||||
DoDuy,
|
||||
dwa,
|
||||
dz,
|
||||
dzaay,
|
||||
dzungul,
|
||||
e,
|
||||
ee,
|
||||
ay,
|
||||
ey,
|
||||
gh,
|
||||
gharma,
|
||||
h,
|
||||
halaat,
|
||||
i,
|
||||
injuluy,
|
||||
islaam,
|
||||
joR,
|
||||
jz,
|
||||
jzwund,
|
||||
kadoo,
|
||||
kh,
|
||||
khwux,
|
||||
kxeneyy,
|
||||
l,
|
||||
leekul,
|
||||
lUtfan,
|
||||
maalTa,
|
||||
maNa,
|
||||
meena,
|
||||
N,
|
||||
o,
|
||||
oo,
|
||||
oox,
|
||||
ooy,
|
||||
paaNa,
|
||||
poza,
|
||||
puxto,
|
||||
q,
|
||||
qaazee,
|
||||
r,
|
||||
R,
|
||||
rang,
|
||||
saRey,
|
||||
t,
|
||||
tor,
|
||||
ts,
|
||||
tsomra,
|
||||
T,
|
||||
u,
|
||||
uu,
|
||||
uy,
|
||||
w,
|
||||
wuGey,
|
||||
waadu,
|
||||
x,
|
||||
xudza,
|
||||
xudze,
|
||||
zooy,
|
||||
sheen,
|
||||
chaa,
|
||||
baad,
|
||||
kor,
|
||||
gUl,
|
||||
maat,
|
||||
maruy,
|
||||
naayee,
|
||||
fojee,
|
||||
};
|
||||
|
|
|
@ -34,7 +34,8 @@ const views: {
|
|||
<div>
|
||||
<p>
|
||||
Long vowels are <strong>always written</strong> in Pashto script. When
|
||||
long vowels come at the beginning of a word, they are prefixed with a letter alef (ا).
|
||||
long vowels come at the beginning of a word, they are prefixed with a
|
||||
letter alef (ا).
|
||||
</p>
|
||||
<p>for example:</p>
|
||||
<ul>
|
||||
|
@ -46,8 +47,9 @@ const views: {
|
|||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
Note: When ey - ی or ee - ي are written in the middle of a word, both appear as ـیـ.
|
||||
To differentiate ee - ي from ey - ی you can (optionally) add a ◌ِ diacritic. (eg. شِین - sheen)
|
||||
Note: When ay - ی or ee - ي are written in the middle of a word, both
|
||||
appear as ـیـ. To differentiate ee - ي from ay - ی you can
|
||||
(optionally) add a ◌ِ diacritic. (eg. شِین - sheen)
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -2,15 +2,7 @@
|
|||
title: Intro to Compound Verbs
|
||||
---
|
||||
|
||||
import {
|
||||
defaultTextOptions as opts,
|
||||
Examples,
|
||||
InlinePs,
|
||||
} from "@lingdocs/ps-react";
|
||||
import { KidsSection, VP, KingIcon, ServantIcon } from "../../components/terms-links";
|
||||
import psmd from "../../lib/psmd";
|
||||
import Link from "../../components/Link";
|
||||
import Formula from "../../components/formula/Formula";
|
||||
import { defaultTextOptions as opts, InlinePs } from "@lingdocs/ps-react";
|
||||
import cookingPotatoes from "./cooking-potatoes.svg";
|
||||
import doingWork from "./doing-work.svg";
|
||||
import stativeCompoundTransitive from "./stative-compound-transitive.svg";
|
||||
|
@ -19,73 +11,86 @@ import dynamicCopmoundTransitive from "./dynamic-compound-transitive.svg";
|
|||
Compound verbs are verbs made up from a helper verb and some other word. These are extremely common in Pashto. In fact, 70% of the verbs in the [LingDocs Pashto Dictionary](https://dictionary.lingdocs.com) are compound verbs. Here are some examples:
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<InlinePs
|
||||
opts={opts}
|
||||
ps={{ p: "کار کول", f: "kaar kawul", e: "to work" }}
|
||||
/>
|
||||
</li>
|
||||
<ul>
|
||||
<li>
|
||||
<InlinePs opts={opts} ps={{ p: "کار کول", f: "kaar kawul", e: "to work" }} />
|
||||
<InlinePs opts={opts} ps={{ p: "کار", f: "kaar", e: "work" }} /> +{" "}
|
||||
<InlinePs opts={opts} ps={{ p: "کول", f: "kawul", e: "to do" }} />
|
||||
</li>
|
||||
<ul>
|
||||
<li>
|
||||
<InlinePs opts={opts} ps={{ p: "کار", f: "kaar", e: "work" }} /> + <InlinePs opts={opts} ps={{ p: "کول", f: "kawul", e: "to do" }} />
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<li>
|
||||
<InlinePs
|
||||
opts={opts}
|
||||
ps={{ p: "منډې وهل", f: "munDe wahul", e: "to run" }}
|
||||
/>
|
||||
</li>
|
||||
<ul>
|
||||
<li>
|
||||
<InlinePs opts={opts} ps={{ p: "منډې وهل", f: "munDe wahul", e: "to run" }} />
|
||||
<InlinePs opts={opts} ps={{ p: "منډې", f: "munDe", e: "runs" }} /> +{" "}
|
||||
<InlinePs opts={opts} ps={{ p: "وهل", f: "wahul", e: "to hit" }} />
|
||||
</li>
|
||||
<ul>
|
||||
<li>
|
||||
<InlinePs opts={opts} ps={{ p: "منډې", f: "munDe", e: "runs" }} /> + <InlinePs opts={opts} ps={{ p: "وهل", f: "wahul", e: "to hit" }} />
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<li>
|
||||
<InlinePs opts={opts} ps={{ p: "بندول", f: "bandawul", e: "to close" }} />
|
||||
</li>
|
||||