This commit is contained in:
parent
5c283f2cea
commit
b4a84645ea
|
@ -5,7 +5,7 @@
|
|||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"@lingdocs/lingdocs-main": "^0.2.0",
|
||||
"@lingdocs/pashto-inflector": "^2.0.5",
|
||||
"@lingdocs/pashto-inflector": "^2.3.2",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const fs = require("fs");
|
||||
const fetch = require("node-fetch");
|
||||
const path = require("path");
|
||||
const { readDictionary } = require("@lingdocs/pashto-inflector");
|
||||
const verbsPath = path.join(".", "src", "words");
|
||||
const pChars = [
|
||||
"آ",
|
||||
|
@ -51,10 +50,11 @@ const pChars = [
|
|||
'ږ',
|
||||
];
|
||||
|
||||
fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(data => {
|
||||
const { entries } = readDictionary(data);
|
||||
|
||||
fetch(process.env.LINGDOCS_DICTIONARY_URL + ".json").then(res => res.json()).then(data => {
|
||||
const { entries } = data;
|
||||
const filtered = shuffle(entries.filter(e => (
|
||||
e.c?.includes("n. f.") && e.p.endsWith("ي")
|
||||
e.c?.includes("loc. adv.")
|
||||
)));
|
||||
const content = `module.exports = [
|
||||
${filtered.reduce((text, entry) => (
|
||||
|
|
|
@ -4,11 +4,8 @@ import {
|
|||
EntrySelect,
|
||||
Types as T,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import {
|
||||
nouns,
|
||||
verbs,
|
||||
} from "../words/words";
|
||||
import { useStickyState } from "@lingdocs/pashto-inflector";
|
||||
import entryFeeder from "../lib/entry-feeder";
|
||||
|
||||
function VPBuilder() {
|
||||
const [entry, setEntry] = useStickyState<T.VerbEntry | undefined>(undefined, "vEntrySelect");
|
||||
|
@ -18,7 +15,7 @@ function VPBuilder() {
|
|||
<EntrySelect
|
||||
value={entry}
|
||||
onChange={setEntry}
|
||||
entries={verbs}
|
||||
entryFeeder={entryFeeder.verbs}
|
||||
opts={defaultTextOptions}
|
||||
isVerbSelect
|
||||
name="Verb"
|
||||
|
@ -29,8 +26,8 @@ function VPBuilder() {
|
|||
? <VPExplorer
|
||||
verb={entry}
|
||||
opts={defaultTextOptions}
|
||||
nouns={nouns}
|
||||
verbs={verbs}
|
||||
entryFeeder={entryFeeder}
|
||||
handleLinkClick="none"
|
||||
/>
|
||||
: <div className="lead">
|
||||
Choose a verb to start building
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
import {
|
||||
VerbTable,
|
||||
defaultTextOptions as opts,
|
||||
ButtonSelect,
|
||||
Types as T,
|
||||
personGender,
|
||||
personIsPlural,
|
||||
typePredicates,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import {
|
||||
ExplorerState,
|
||||
ExplorerReducerAction,
|
||||
} from "./explorer-types";
|
||||
import {
|
||||
equativeMachine,
|
||||
assembleEquativeOutput,
|
||||
} from "../../lib/equative-machine";
|
||||
const {
|
||||
isUnisexNounEntry,
|
||||
isAdjectiveEntry,
|
||||
isVerbEntry,
|
||||
isLocativeAdverbEntry,
|
||||
isNounEntry,
|
||||
} = typePredicates;
|
||||
|
||||
function chooseLength<O>(o: T.SingleOrLengthOpts<O>, length: "short" | "long"): O {
|
||||
return ("long" in o) ? o[length] : o;
|
||||
}
|
||||
|
||||
function SingleItemDisplay({ state }: { state: ExplorerState }) {
|
||||
if (state.subject.type === "pronouns") {
|
||||
return <div>ERROR: Wrong display being used</div>;
|
||||
}
|
||||
try {
|
||||
const se = state.subject[state.subject.type];
|
||||
const pe = state.predicate[state.predicate.type];
|
||||
const subject = makeNounPhrase(se, state, "subject");
|
||||
const predicate = (isAdjectiveEntry(pe) || isLocativeAdverbEntry(pe))
|
||||
? makeComplement(pe)
|
||||
: makeNounPhrase(pe, state, "predicate");
|
||||
const block = assembleEquativeOutput(
|
||||
equativeMachine({
|
||||
subject,
|
||||
predicate,
|
||||
tense: state.tense,
|
||||
negative: state.negative,
|
||||
})
|
||||
);
|
||||
return <div>
|
||||
<VerbTable textOptions={opts} block={chooseLength(block, state.length)} />
|
||||
</div>;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return <div>Error making equative sentence</div>
|
||||
}
|
||||
}
|
||||
|
||||
function makeComplement(entry: T.AdjectiveEntry | T.LocativeAdverbEntry): Compliment {
|
||||
return {
|
||||
type: "compliment",
|
||||
entry,
|
||||
};
|
||||
}
|
||||
|
||||
function makeNounPhrase(entry: T.NounEntry | T.UnisexNounEntry | T.VerbEntry, state: ExplorerState, entity: "subject" | "predicate"): NounPhrase {
|
||||
if (isVerbEntry(entry)) {
|
||||
return {
|
||||
type: "participle",
|
||||
entry,
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "noun",
|
||||
number: state[entity].info.number,
|
||||
gender: state[entity].info.gender,
|
||||
entry,
|
||||
};
|
||||
}
|
||||
|
||||
export function makeBlockWPronouns(e: T.AdjectiveEntry | T.UnisexNounEntry | T.LocativeAdverbEntry, tense: EquativeTense, negative: boolean, length?: "short" | "long"): T.SingleOrLengthOpts<T.VerbBlock> {
|
||||
// if the output's gonna have long / short forms (if it's past or wouldBe) then recursive call to make the long and short versions
|
||||
if (!length && "long" in assembleEquativeOutput(equativeMachine({
|
||||
subject: { type: "pronoun", pronounType: "near", person: 0 },
|
||||
predicate: (isAdjectiveEntry(e) || isLocativeAdverbEntry(e))
|
||||
? { type: "compliment", entry: e }
|
||||
: { type: "noun", gender: "masc", number: "singular", entry: e },
|
||||
tense,
|
||||
negative,
|
||||
}))) {
|
||||
return {
|
||||
short: makeBlockWPronouns(e, tense, negative, "short") as T.VerbBlock,
|
||||
long: makeBlockWPronouns(e, tense, negative, "long") as T.VerbBlock,
|
||||
};
|
||||
}
|
||||
const makeP = (p: T.Person): T.ArrayOneOrMore<T.PsString> => {
|
||||
const b = assembleEquativeOutput(equativeMachine({
|
||||
subject: { type: "pronoun", pronounType: "far", person: p },
|
||||
predicate: (isAdjectiveEntry(e) || isLocativeAdverbEntry(e))
|
||||
? { type: "compliment", entry: e }
|
||||
: { type: "noun", gender: personGender(p), number: personIsPlural(p) ? "plural" : "singular", entry: e },
|
||||
tense,
|
||||
negative,
|
||||
}));
|
||||
if ("long" in b) {
|
||||
if (!length) throw new Error("bad length processing");
|
||||
return b[length];
|
||||
}
|
||||
return b;
|
||||
};
|
||||
return [
|
||||
[makeP(0), makeP(6)],
|
||||
[makeP(1), makeP(7)],
|
||||
[makeP(2), makeP(8)],
|
||||
[makeP(3), makeP(9)],
|
||||
[makeP(4), makeP(10)],
|
||||
[makeP(5), makeP(11)],
|
||||
];
|
||||
}
|
||||
|
||||
function PronounBlockDisplay({ state }: { state: ExplorerState }) {
|
||||
const pred = state.predicate[state.predicate.type];
|
||||
if (!isVerbEntry(pred) && (isAdjectiveEntry(pred) || isLocativeAdverbEntry(pred) || (isNounEntry(pred) && isUnisexNounEntry(pred)))) {
|
||||
const block = makeBlockWPronouns(pred, state.tense, state.negative);
|
||||
return <VerbTable
|
||||
textOptions={opts}
|
||||
block={chooseLength(block, state.length)}
|
||||
/>;
|
||||
}
|
||||
return <div>Invalid combination</div>
|
||||
}
|
||||
|
||||
function EquativeDisplay({ state, dispatch }: { state: ExplorerState, dispatch: (action: ExplorerReducerAction) => void }) {
|
||||
return <>
|
||||
{(state.tense === "past" || state.tense === "wouldBe") && <div className="text-center">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Long", value: "long" },
|
||||
{ label: "Short", value: "short" },
|
||||
]}
|
||||
value={state.length}
|
||||
handleChange={(p) => dispatch({ type: "setLength", payload: p as "long" | "short" })}
|
||||
/>
|
||||
</div>}
|
||||
{state.subject.type === "pronouns"
|
||||
? <PronounBlockDisplay state={state} />
|
||||
: <SingleItemDisplay state={state} />
|
||||
}
|
||||
{state.predicate.type === "participle" && <div className="mt-2 small text-muted text-center">
|
||||
Note: This means that the subject <em>is</em> the act of the participle/verb, not that the subject is currently doing the verb!
|
||||
</div>}
|
||||
</>;
|
||||
}
|
||||
|
||||
export default EquativeDisplay;
|
|
@ -1,70 +0,0 @@
|
|||
import { useState } from "react";
|
||||
import {
|
||||
reducer,
|
||||
} from "./explorer-reducer";
|
||||
import {
|
||||
InputSelector,
|
||||
TenseSelector,
|
||||
} from "./explorer-selectors";
|
||||
import {
|
||||
ExplorerState,
|
||||
ExplorerReducerAction,
|
||||
} from "./explorer-types";
|
||||
import {
|
||||
defaultUnisexNoun,
|
||||
defaultAdjective,
|
||||
defaultNoun,
|
||||
defaultParticiple,
|
||||
defaultAdverb,
|
||||
} from "./explorer-inputs";
|
||||
import EquativeDisplay from "./EquativeDisplay";
|
||||
|
||||
const defaultState: ExplorerState = {
|
||||
tense: "present",
|
||||
length: "short",
|
||||
negative: false,
|
||||
predicate: {
|
||||
type: "adjective",
|
||||
adjective: defaultAdjective,
|
||||
adverb: defaultAdverb,
|
||||
unisexNoun: defaultUnisexNoun,
|
||||
participle: defaultParticiple,
|
||||
noun: defaultNoun,
|
||||
info: {
|
||||
number: "singular",
|
||||
gender: "masc",
|
||||
},
|
||||
},
|
||||
subject: {
|
||||
type: "pronouns",
|
||||
noun: defaultNoun,
|
||||
participle: defaultParticiple,
|
||||
unisexNoun: defaultUnisexNoun,
|
||||
info: {
|
||||
number: "singular",
|
||||
gender: "masc",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function EquativeExplorer() {
|
||||
const [state, unsafeSetState] = useState<ExplorerState>(defaultState);
|
||||
function dispatch(action: ExplorerReducerAction) {
|
||||
const newState = reducer(state, action);
|
||||
unsafeSetState(newState);
|
||||
}
|
||||
return <>
|
||||
<TenseSelector state={state} dispatch={dispatch} />
|
||||
<div className="row">
|
||||
<div className="col">
|
||||
<InputSelector entity="subject" state={state} dispatch={dispatch} />
|
||||
</div>
|
||||
<div className="col">
|
||||
<InputSelector entity="predicate" state={state} dispatch={dispatch} />
|
||||
</div>
|
||||
</div>
|
||||
<EquativeDisplay state={state} dispatch={dispatch} />
|
||||
</>;
|
||||
}
|
||||
|
||||
export default EquativeExplorer;
|
|
@ -1,37 +0,0 @@
|
|||
import { nouns, adjectives, verbs, adverbs } from "../../words/words";
|
||||
import {
|
||||
Types as T,
|
||||
typePredicates as tp,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
||||
function sort<T extends (T.AdjectiveEntry | T.NounEntry | T.VerbEntry | T.AdverbEntry)>(arr: Readonly<T[]>): T[] {
|
||||
if ("entry" in arr[0]) {
|
||||
return [...arr].sort((a, b) => (
|
||||
// @ts-ignore
|
||||
a.entry.p.localeCompare(b.entry.p)
|
||||
));
|
||||
}
|
||||
return [...arr].sort((a, b) => (
|
||||
// @ts-ignore
|
||||
a.p.localeCompare(b.p)
|
||||
));
|
||||
}
|
||||
|
||||
const unisexNouns = sort(nouns.filter(x => tp.isUnisexNounEntry(x)) as T.UnisexNounEntry[]);
|
||||
const nonUnisexNouns = sort(nouns.filter(x => !tp.isUnisexNounEntry(x)) as (T.MascNounEntry | T.FemNounEntry)[]);
|
||||
|
||||
const inputs = {
|
||||
adjective: sort(adjectives),
|
||||
unisexNoun: unisexNouns,
|
||||
noun: nonUnisexNouns,
|
||||
participle: sort(verbs),
|
||||
adverb: sort(adverbs.filter(tp.isLocativeAdverbEntry)),
|
||||
};
|
||||
|
||||
export const defaultAdjective = inputs.adjective.find(ps => ps.p === "زوړ") || inputs.adjective[0];
|
||||
export const defaultAdverb = inputs.adverb.find(ps => ps.p === "دلته") || inputs.adverb[0];
|
||||
export const defaultUnisexNoun = inputs.unisexNoun.find(ps => ps.p === "پښتون") || inputs.unisexNoun[0];
|
||||
export const defaultNoun = inputs.noun.find(ps => ps.p === "کتاب") || inputs.noun[0];
|
||||
export const defaultParticiple = inputs.participle.find(ps => ps.entry.p === "لیکل") || inputs.participle[0];
|
||||
|
||||
export default inputs;
|
|
@ -1,110 +0,0 @@
|
|||
import inputs from "./explorer-inputs";
|
||||
import { ExplorerState, ExplorerReducerAction } from "./explorer-types";
|
||||
import {
|
||||
Types as T,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
|
||||
export function reducer(state: ExplorerState, action: ExplorerReducerAction): ExplorerState {
|
||||
if (action.type === "setPredicate") {
|
||||
const pile = inputs[state.predicate.type] as (T.UnisexNounEntry | T.AdjectiveEntry)[];
|
||||
const predicate = (pile.find(p => p.ts === action.payload) || pile[0]);
|
||||
return {
|
||||
...state,
|
||||
predicate: {
|
||||
...state.predicate,
|
||||
[state.predicate.type]: predicate,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (action.type === "setPredicateType") {
|
||||
const predicateType = action.payload;
|
||||
return {
|
||||
...state,
|
||||
predicate: {
|
||||
...state.predicate,
|
||||
type: predicateType,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (action.type === "setSubjectType") {
|
||||
const subjectType = action.payload;
|
||||
return {
|
||||
...state,
|
||||
subject: {
|
||||
...state.subject,
|
||||
type: subjectType,
|
||||
},
|
||||
predicate: {
|
||||
...state.predicate,
|
||||
type: (
|
||||
subjectType === "pronouns" &&
|
||||
!["adjective", "adverb", "unisexNoun"].includes(state.predicate.type)
|
||||
) ? "adjective" : state.predicate.type,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (action.type === "setSubject") {
|
||||
if (state.subject.type === "pronouns") return state;
|
||||
const pile = inputs[state.subject.type];
|
||||
// @ts-ignore
|
||||
const subject = (pile.find(p => p.ts === action.payload) || pile[0]);
|
||||
return {
|
||||
...state,
|
||||
subject: {
|
||||
...state.subject,
|
||||
[state.subject.type]: subject,
|
||||
},
|
||||
};
|
||||
}
|
||||
if (action.type === "setNumber") {
|
||||
const entity = action.payload.entity;
|
||||
return {
|
||||
...state,
|
||||
[entity]: {
|
||||
...state[entity],
|
||||
info: {
|
||||
...state[entity].info,
|
||||
number: action.payload.number,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (action.type === "setGender") {
|
||||
const entity = action.payload.entity;
|
||||
return {
|
||||
...state,
|
||||
[entity]: {
|
||||
...state[entity],
|
||||
info: {
|
||||
...state[entity].info,
|
||||
gender: action.payload.gender,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (action.type === "setTense") {
|
||||
return {
|
||||
...state,
|
||||
tense: action.payload,
|
||||
};
|
||||
}
|
||||
// if (action.type === "setPredicateEntity") {
|
||||
// return {
|
||||
// ...state,
|
||||
// predicate: {
|
||||
// ...state.predicate,
|
||||
// entity: action.payload,
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
if (action.type === "setNegative") {
|
||||
return {
|
||||
...state,
|
||||
negative: action.payload,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
length: action.payload,
|
||||
};
|
||||
}
|
|
@ -1,233 +0,0 @@
|
|||
// import { makeOptionLabel } from "./explorer-helpers";
|
||||
import inputs from "./explorer-inputs";
|
||||
import {
|
||||
ExplorerReducerAction,
|
||||
ExplorerState,
|
||||
SubjectType,
|
||||
PredicateType,
|
||||
} from "./explorer-types";
|
||||
import {
|
||||
getEnglishParticiple,
|
||||
} from "../../lib/np-tools";
|
||||
import {
|
||||
ButtonSelect,
|
||||
getEnglishWord,
|
||||
Types as T,
|
||||
removeFVarients,
|
||||
typePredicates,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import Select from "react-select";
|
||||
const {
|
||||
isAdjectiveEntry,
|
||||
isAdverbEntry,
|
||||
isFemNounEntry,
|
||||
isMascNounEntry,
|
||||
isNounEntry,
|
||||
isPluralNounEntry,
|
||||
} = typePredicates;
|
||||
|
||||
const zIndexProps = {
|
||||
menuPortalTarget: document.body,
|
||||
styles: { menuPortal: (base: any) => ({ ...base, zIndex: 9999 }) },
|
||||
};
|
||||
|
||||
const npTypeOptions: { type: SubjectType, label: string }[] = [
|
||||
{ type: "unisexNoun", label: "Unisex Noun"},
|
||||
{ type: "noun", label: "Noun" },
|
||||
{ type: "participle", label: "Participle" },
|
||||
];
|
||||
const subjectTypeOptions: { type: SubjectType, label: string }[] = [
|
||||
{ type: "pronouns" as SubjectType, label: "Pronouns" }
|
||||
];
|
||||
const compTypeOptions: { type: PredicateType, label: string }[] = [
|
||||
{ type: "adjective", label: "Adjective" },
|
||||
{ type: "adverb", label: "Loc. Adverb" },
|
||||
];
|
||||
|
||||
export function InputSelector({ state, dispatch, entity }: {
|
||||
state: ExplorerState,
|
||||
dispatch: (action: ExplorerReducerAction) => void,
|
||||
entity: "subject" | "predicate",
|
||||
}) {
|
||||
const typeOptions = [
|
||||
...entity === "subject"
|
||||
? subjectTypeOptions
|
||||
: compTypeOptions,
|
||||
...npTypeOptions.filter(o => !(entity === "predicate" && (
|
||||
(state.subject.type === "pronouns" && ["noun", "participle"].includes(o.type))
|
||||
// || (state.subject.type === "unisexNoun" && o.type === "unisexNoun")
|
||||
))),
|
||||
];
|
||||
|
||||
function onTypeSelect(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
if (entity === "subject") {
|
||||
const t = e.target.value as SubjectType;
|
||||
dispatch({ type: "setSubjectType", payload: t });
|
||||
} else {
|
||||
const t = e.target.value as PredicateType;
|
||||
dispatch({ type: "setPredicateType", payload: t });
|
||||
}
|
||||
}
|
||||
|
||||
function onEntrySelect({ value }: any) {
|
||||
dispatch({ type: entity === "subject" ? "setSubject" : "setPredicate", payload: parseInt(value) });
|
||||
}
|
||||
|
||||
function CheckboxItem({ type, label }: { type: string, label: string }) {
|
||||
const id = `${entity}-${type}-radio`;
|
||||
return <div className="form-check">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="radio"
|
||||
id={id}
|
||||
value={type}
|
||||
checked={state[entity].type === type}
|
||||
onChange={onTypeSelect}
|
||||
/>
|
||||
<label className="form-check-label" htmlFor={id}>
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
|
||||
const type = state[entity].type;
|
||||
const entry: T.NounEntry | T.VerbEntry | T.AdjectiveEntry | T.LocativeAdverbEntry | undefined = type === "pronouns"
|
||||
? undefined
|
||||
// @ts-ignore
|
||||
: state[entity][type];
|
||||
const options = type === "pronouns"
|
||||
? []
|
||||
: inputs[type].map(makeOption);
|
||||
|
||||
return <div className="form-group">
|
||||
<h5 className="mb-2">{entity === "subject" ? "Subject:" : "Predicate:"}</h5>
|
||||
<div className="mb-2">
|
||||
{typeOptions.map(({ type, label }) => (
|
||||
<CheckboxItem type={type} label={label} key={`${entity}-${type}-radio`} />
|
||||
))}
|
||||
</div>
|
||||
{type !== "pronouns" && <>
|
||||
<Select
|
||||
value={entry && ("entry" in entry ? entry.entry : entry).ts.toString()}
|
||||
onChange={onEntrySelect}
|
||||
className="mb-2"
|
||||
// @ts-ignore
|
||||
options={options}
|
||||
isSearchable
|
||||
// @ts-ignore
|
||||
placeholder={options.find(o => o.value === ("entry" in entry ? entry.entry : entry).ts.toString())?.label}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
{!["adjective", "adverb"].includes(type) && !(state.subject.type === "pronouns" && state.predicate.type === "unisexNoun") &&
|
||||
<GenderAndNumberSelect state={state} dispatch={dispatch} entity={entity} />
|
||||
}
|
||||
</>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
function GenderAndNumberSelect({ state, dispatch, entity }: {
|
||||
state: ExplorerState,
|
||||
dispatch: (action: ExplorerReducerAction) => void,
|
||||
entity: "subject" | "predicate",
|
||||
}) {
|
||||
const type = state[entity].type;
|
||||
if (type === "pronouns") {
|
||||
return <div>ERROR: Should not display with pronouns</div>;
|
||||
}
|
||||
// @ts-ignore
|
||||
const entry: NounEntry | VerbEntry | AdverbEntry | AdjectiveEntry = state[entity][type];
|
||||
const gender = type === "noun"
|
||||
? (isNounEntry(entry) && isMascNounEntry(entry) ? "masc" : "fem")
|
||||
: type === "participle"
|
||||
? "masc"
|
||||
: state[entity].info.gender;
|
||||
const pluralNounSelected = (
|
||||
type === "noun" && isPluralNounEntry(state[entity][type])
|
||||
);
|
||||
return <div className="d-flex flex-row justify-content-center mt-3">
|
||||
<div className="mr-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
...(type === "unisexNoun" || (type === "participle") || (isNounEntry(entry) && isMascNounEntry(entry)))
|
||||
? [{ label: "Masc.", value: "masc" }] : [],
|
||||
...(type === "unisexNoun" || ((type !== "participle") && (isNounEntry(entry) && isFemNounEntry(entry))))
|
||||
? [{ label: "Fem.", value: "fem" }] : [],
|
||||
]}
|
||||
value={gender}
|
||||
handleChange={type === "noun" ? p => null : (p) => dispatch({ type: "setGender", payload: { gender: p as T.Gender, entity }})}
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
...(!pluralNounSelected && type !== "participle") ? [{ label: "Singular", value: "singular" }] : [],
|
||||
{ label: "Plural", value: "plural" },
|
||||
]}
|
||||
value={(state[entity].info.number === "plural" || pluralNounSelected || type === "participle") ? "plural" : "singular"}
|
||||
handleChange={(p) => dispatch({ type: "setNumber", payload: { number: p as NounNumber, entity }})}
|
||||
/>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function makeOption(e: T.VerbEntry | T.NounEntry | T.AdjectiveEntry | T.LocativeAdverbEntry): { value: string, label: string } {
|
||||
const entry = "entry" in e ? e.entry : e;
|
||||
// TODO: THIS IS SUUUPER SKETCH
|
||||
const eng = (isNounEntry(e) || isAdjectiveEntry(e) || isAdverbEntry(e))
|
||||
? getEnglishWord(e)
|
||||
: getEnglishParticiple(entry);
|
||||
const english = typeof eng === "string"
|
||||
? eng
|
||||
: !eng
|
||||
? ""
|
||||
: ("singular" in eng && eng.singular !== undefined)
|
||||
? eng.singular
|
||||
: eng.plural;
|
||||
return {
|
||||
label: `${entry.p} - ${removeFVarients(entry.f)} (${english})`,
|
||||
value: entry.ts.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
export function TenseSelector({ state, dispatch }: {
|
||||
state: ExplorerState,
|
||||
dispatch: (action: ExplorerReducerAction) => void,
|
||||
}) {
|
||||
const options: { value: EquativeTense, label: string }[] = [
|
||||
{ value: "present", label: "Present" },
|
||||
{ value: "habitual", label: "Habitual" },
|
||||
{ value: "subjunctive", label: "Subjunctive" },
|
||||
{ value: "past", label: "Past" },
|
||||
{ value: "future", label: "Future" },
|
||||
{ value: "wouldBe", label: '"Would Be"' },
|
||||
{ value: "pastSubjunctive", label: "Past Subjunctive" },
|
||||
];
|
||||
function onTenseSelect({ value }: any) {
|
||||
dispatch({ type: "setTense", payload: value });
|
||||
}
|
||||
return <div>
|
||||
<h5>Equative:</h5>
|
||||
<Select
|
||||
value={state.tense}
|
||||
onChange={onTenseSelect}
|
||||
className="mb-2"
|
||||
// @ts-ignore
|
||||
options={options}
|
||||
placeholder={options.find(o => o.value === state.tense)?.label}
|
||||
{...zIndexProps}
|
||||
/>
|
||||
<div className="text-center mb-2">
|
||||
<ButtonSelect
|
||||
small
|
||||
options={[
|
||||
{ label: "Pos.", value: "pos" },
|
||||
{ label: "Neg.", value: "neg" },
|
||||
]}
|
||||
value={state.negative ? "neg" : "pos"}
|
||||
handleChange={(p) => dispatch({ type: "setNegative", payload: p === "neg" })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
import { Types as T } from "@lingdocs/pashto-inflector";
|
||||
|
||||
export type PredicateNPType = "noun" | "unisexNoun" | "participle";
|
||||
export type PredicateCompType = "adjective" | "adverb";
|
||||
export type PredicateType = PredicateNPType | PredicateCompType;
|
||||
export type SubjectType = "pronouns" | "noun" | "unisexNoun" | "participle";
|
||||
|
||||
export type ExplorerState = {
|
||||
tense: EquativeTense,
|
||||
length: "short" | "long",
|
||||
subject: SubjectEntityInfo,
|
||||
predicate: PredicateEntityInfo,
|
||||
negative: boolean,
|
||||
};
|
||||
|
||||
export type SubjectEntityInfo = EntitiyInfo & { type: SubjectType };
|
||||
|
||||
export type PredicateEntityInfo = EntitiyInfo & {
|
||||
type: PredicateType,
|
||||
adjective: import("@lingdocs/pashto-inflector").Types.AdjectiveEntry,
|
||||
adverb: import("@lingdocs/pashto-inflector").Types.LocativeAdverbEntry,
|
||||
}
|
||||
|
||||
type EntitiyInfo = {
|
||||
noun: import("@lingdocs/pashto-inflector").Types.NounEntry,
|
||||
participle: import("@lingdocs/pashto-inflector").Types.VerbEntry,
|
||||
unisexNoun: import("@lingdocs/pashto-inflector").Types.UnisexNounEntry,
|
||||
info: {
|
||||
number: NounNumber,
|
||||
gender: T.Gender,
|
||||
},
|
||||
};
|
||||
|
||||
export type ExplorerReducerAction = {
|
||||
type: "setPredicateType", payload: PredicateType,
|
||||
} | {
|
||||
type: "setPredicate", payload: number,
|
||||
} | {
|
||||
type: "setSubjectType", payload: SubjectType,
|
||||
} | {
|
||||
type: "setSubject", payload: number,
|
||||
} | {
|
||||
type: "setNumber", payload: { entity: "subject" | "predicate", number: NounNumber },
|
||||
} | {
|
||||
type: "setGender", payload: { entity: "subject" | "predicate", gender: T.Gender },
|
||||
} | {
|
||||
type: "setTense", payload: EquativeTense,
|
||||
} | {
|
||||
type: "setLength", payload: "short" | "long",
|
||||
} | {
|
||||
type: "setNegative", payload: boolean,
|
||||
};
|
|
@ -2,17 +2,15 @@
|
|||
title: Equative Explorer 🌎
|
||||
---
|
||||
|
||||
import EquativeExplorer from "../../components/equative-explorer/EquativeExplorer";
|
||||
import { useState } from "react";
|
||||
|
||||
You can use this tool to explore how to make different equative sentences. Everything that comes out of this will be **gramatically correct**, but the sentences might not always make sense! 🤪
|
||||
import {
|
||||
EPExplorer,
|
||||
defaultTextOptions,
|
||||
} from "@lingdocs/pashto-inflector";
|
||||
import entryFeeder from "../../lib/entry-feeder";
|
||||
|
||||
<div className="mb-4">
|
||||
<EquativeExplorer />
|
||||
<EPExplorer
|
||||
entryFeeder={entryFeeder}
|
||||
opts={defaultTextOptions}
|
||||
/>
|
||||
</div>
|
||||
|
||||
### Equative Rules: 👨🏫
|
||||
|
||||
- The **subject** has to be a **noun phrase**
|
||||
- The **predicate** can be a **noun phrase** or **compliment**
|
||||
- In Pashto, if the predicate is a noun phrase, the equative agrees with the predicate. Otherwise, if the predicate is a compliment, the equative agrees with the subject. In English, the equative always agrees with the subject.
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { Types as T } from "@lingdocs/pashto-inflector";
|
||||
import {
|
||||
nouns,
|
||||
verbs,
|
||||
adjectives,
|
||||
locativeAdverbs,
|
||||
} from "../words/words";
|
||||
|
||||
const entryFeeder: T.EntryFeeder = {
|
||||
nouns,
|
||||
verbs,
|
||||
adjectives,
|
||||
locativeAdverbs,
|
||||
}
|
||||
|
||||
export default entryFeeder;
|
|
@ -1,6 +1,15 @@
|
|||
// TODO: I think this is just used for the old equative explorer
|
||||
// build a new better equative explorer using NP Pickers etc and deprecate all this
|
||||
|
||||
type EPSelection = {
|
||||
subject: NPSelection,
|
||||
predicate: NPSelection | EComplementSelection,
|
||||
equative: {
|
||||
tense: EquativeTense,
|
||||
negative: boolean,
|
||||
},
|
||||
};
|
||||
|
||||
type EquativeTense = "present" | "subjunctive" | "habitual" | "past" | "future" | "wouldBe" | "pastSubjunctive";
|
||||
type NounNumber = "singular" | "plural";
|
||||
|
||||
|
|
|
@ -5,16 +5,23 @@ import {
|
|||
} from "@lingdocs/pashto-inflector";
|
||||
import { categorize } from "../lib/categorize";
|
||||
|
||||
const words = categorize<T.Entry, T.Words>(rawWords, {
|
||||
"nouns": tp.isNounEntry,
|
||||
"adjectives": tp.isAdjectiveEntry,
|
||||
"verbs": tp.isVerbEntry,
|
||||
"adverbs": tp.isAdverbEntry,
|
||||
const words = categorize<T.Entry, {
|
||||
nouns: T.NounEntry[],
|
||||
adjectives: T.AdjectiveEntry[],
|
||||
verbs: T.VerbEntry[],
|
||||
adverbs: T.AdverbEntry[],
|
||||
locativeAdverbs: T.LocativeAdverbEntry[],
|
||||
}>(rawWords, {
|
||||
nouns: tp.isNounEntry,
|
||||
adjectives: tp.isAdjectiveEntry,
|
||||
verbs: tp.isVerbEntry,
|
||||
adverbs: tp.isAdverbEntry,
|
||||
locativeAdverbs: tp.isLocativeAdverbEntry,
|
||||
});
|
||||
|
||||
export default words;
|
||||
|
||||
export const { nouns, adjectives, verbs, adverbs } = words;
|
||||
export const { nouns, adjectives, verbs, adverbs, locativeAdverbs } = words;
|
||||
|
||||
// console.log(
|
||||
// Object.entries(
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
"jsx": "react-jsx",
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
|
|
|
@ -1684,10 +1684,10 @@
|
|||
pbf "^3.2.1"
|
||||
rambda "^6.7.0"
|
||||
|
||||
"@lingdocs/pashto-inflector@^2.0.5":
|
||||
version "2.0.5"
|
||||
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-2.0.5.tgz#b917428e81395206d78f8f72122dddc4432364b3"
|
||||
integrity sha512-WdkunOYqj3045Too4PioDIh9ljYXrbGiV+CVZtbF8s8Bnw/L+6Y7ShgYFb2DQalkwtis+5BJzzcKMMUE4ZtTYQ==
|
||||
"@lingdocs/pashto-inflector@^2.3.2":
|
||||
version "2.3.2"
|
||||
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-2.3.2.tgz#59c42d5bbe4e2befc467cd506b12a11632545eaf"
|
||||
integrity sha512-EGWHwe8RdRD7NcZtE4CVUQGSvfXCcVyTrNmmqv1kJeRLZIn2MN2UMCbGRMZcz3681mCQvvfkRpsAD8xJSSjyNw==
|
||||
dependencies:
|
||||
classnames "^2.2.6"
|
||||
pbf "^3.2.1"
|
||||
|
|
Loading…
Reference in New Issue