Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
759696e
ukrainian localization
vykliuk Jun 6, 2025
7f47068
Merge branch 'master' of github.com:apertium/apertium-html-tools
vykliuk Jun 9, 2025
7993620
minor edit
vykliuk Jun 9, 2025
8ea944b
updated localization numbers
vykliuk Jun 9, 2025
56171e3
basic dictionary mode
vykliuk Jun 18, 2025
f7b95d5
fetch billooup pairs
vykliuk Jun 20, 2025
3d00114
disable detect lang in dict mode
vykliuk Jun 20, 2025
10b6e7d
tgt->src lookup
vykliuk Jun 23, 2025
f9babf8
modify how tags are displayed
vykliuk Jun 25, 2025
d9f3ada
pos localization
vykliuk Jun 27, 2025
6d04dd2
styling and some thoughts
vykliuk Jun 27, 2025
b911050
results not found
vykliuk Jun 27, 2025
9eb28bc
support search of definition words
vykliuk Jun 29, 2025
089314c
UI expand paradigms
vykliuk Jun 29, 2025
8f16df2
ignore pos subdirectory
vykliuk Jun 29, 2025
8b78f79
dynamic link change
vykliuk Jun 29, 2025
eb54e41
paradigms start, urum
vykliuk Jul 4, 2025
8f18355
generate lang registry automatically
vykliuk Jul 8, 2025
69718be
styling
vykliuk Jul 8, 2025
995bc27
collapse paradigms
vykliuk Jul 8, 2025
10f8d23
fix no results found
vykliuk Jul 8, 2025
c5ed378
paradigm styling
vykliuk Jul 8, 2025
556d0e7
no POS found msg
vykliuk Jul 9, 2025
2eb7a96
russian expand paradigms button
vykliuk Jul 9, 2025
9433b2f
slovozmina
vykliuk Jul 9, 2025
10c9675
auto generated index ts
vykliuk Jul 9, 2025
ac417a0
slovozmina again
vykliuk Jul 9, 2025
b67cc9f
localization of prdgm tables (linguist only)
vykliuk Jul 9, 2025
9272b91
German prdgm localiz for debugging purposes
vykliuk Jul 9, 2025
daf68a0
modes
vykliuk Jul 11, 2025
f3f644c
rm prev results when change lang
vykliuk Jul 11, 2025
c8f61ad
fix lang selector crash
vykliuk Jul 11, 2025
8e00263
subcats
vykliuk Jul 11, 2025
b3e0a05
modes corrected
vykliuk Jul 12, 2025
dfea9e2
no expand prdgm if lang not supported
vykliuk Jul 12, 2025
38f8d4b
german dict localization
vykliuk Jul 12, 2025
fc78219
logic when POS not supported and some additions
vykliuk Jul 15, 2025
a95a3ab
german pos
vykliuk Jul 15, 2025
a436e28
rm 'no pos found'
vykliuk Jul 15, 2025
767e9a4
old spanish file
vykliuk Jul 15, 2025
38a4285
more spanish
vykliuk Jul 15, 2025
a7e1879
upd tables
vykliuk Jul 15, 2025
6f72ae1
fallback to 1st option
vykliuk Jul 15, 2025
5e54a6d
some fixes for spanish
vykliuk Jul 16, 2025
7f27e31
modes fix
vykliuk Jul 22, 2025
bd60d7a
fix pretxt and spanish compound
vykliuk Jul 23, 2025
ed9f07f
debug
vykliuk Jul 24, 2025
258d655
additional billookup for tgt-src
vykliuk Jul 24, 2025
27167f5
fix tgt-src lookup
vykliuk Jul 24, 2025
f50438d
rm uum dependency
vykliuk Jul 28, 2025
452eb61
combine word results; exact match on top
vykliuk Jul 31, 2025
48411fd
embeddings
vykliuk Jul 31, 2025
f6df099
similar to
vykliuk Jul 31, 2025
778aea8
better embeds logic
vykliuk Aug 1, 2025
c9fa727
italics
vykliuk Aug 1, 2025
4334a8c
similar to term display fix
vykliuk Aug 1, 2025
6502f9a
embeds mode logic
vykliuk Aug 4, 2025
e47e30e
extra tags
vykliuk Aug 9, 2025
b12cd24
xtra tags localize and position
vykliuk Aug 14, 2025
7fc13ac
embeddings deduplication
vykliuk Aug 14, 2025
2d518f2
rus for urum
vykliuk Aug 14, 2025
a06f5f3
german POS locale
vykliuk Aug 14, 2025
dff46a7
network requests concat
vykliuk Aug 17, 2025
4f43589
embeds logic
vykliuk Aug 17, 2025
4858506
imperfect converb
vykliuk Aug 17, 2025
deda844
fix input bug
vykliuk Aug 18, 2025
522c7ed
dynamic link
vykliuk Aug 22, 2025
749d376
show max num of src langs
vykliuk Aug 29, 2025
e63e8e3
show lang with most tgt available
vykliuk Aug 29, 2025
ef4d433
strip pound sign
vykliuk Aug 29, 2025
fb67b84
separate orig lang selector from new
vykliuk Oct 15, 2025
1330624
dictionary specific lang selector
vykliuk Oct 15, 2025
cea8220
reverting accidental changes to config (f7b95d5)
jonorthwash Oct 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
logic when POS not supported and some additions
  • Loading branch information
vykliuk committed Jul 15, 2025
commit fc78219b52af23165a7ba34e8bf2d8399fa21a8f
41 changes: 8 additions & 33 deletions src/components/dictionary/Paradigm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,57 +35,42 @@ const Paradigm: React.FC<ParadigmProps> = ({ head, lang, mode, onLoaded }) => {

useEffect(() => {
if (!plugin) return;

let isMounted = true;
const cancelers: CancelTokenSource[] = [];

const raw = plugin.addParadigms({ head, mode, locale, t, apyFetch });

if (!Array.isArray(raw)) {
setBlocks([]);
setLoading(false);
return;
}

const rawBlocks = raw;
setBlocks(rawBlocks);

setBlocks(raw);
const lemma = head.replace(/<[^>]+>/g, '');
const origTags = Array.from(head.matchAll(/<([^>]+)>/g), (m) => m[1]);

const fetchCells = rawBlocks
const fetchCells = raw
.flatMap((b) => b.subcats ?? [b])
.flatMap((b) => b.tabdata ?? [])
.flat();

if (fetchCells.length === 0) {
if (!fetchCells.length) {
if (isMounted) {
setLoading(false);
onLoaded?.();
}
return;
}

const out: Record<string, string> = {};

Promise.all(
fetchCells.map(async (cell) => {
if (!cell.tags) return;
const seq = plugin.parseTags(origTags, cell.tags);
const pattern = '^' + lemma + seq.map((x) => `<${x}>`).join('') + '$';
const [ctr, req] = apyFetch('generate', {
lang: plugin.backendLangCode,
q: pattern,
});
const [ctr, req] = apyFetch('generate', { lang: plugin.backendLangCode, q: pattern });
cancelers.push(ctr);
try {
const data = (await req).data as Array<[string, string]>;
if (data.length && !data[0][0].startsWith('#')) {
out[cell.tags] = data[0][0];
}
} catch (err) {
if (!axios.isCancel(err)) console.error(err);
}
} catch {}
}),
).then(() => {
if (isMounted) {
Expand All @@ -94,26 +79,20 @@ const Paradigm: React.FC<ParadigmProps> = ({ head, lang, mode, onLoaded }) => {
onLoaded?.();
}
});

return () => {
isMounted = false;
cancelers.forEach((c) => c.cancel());
};
}, [head, lang, locale, mode, t, apyFetch, plugin, onLoaded]);

if (!plugin) {
return <div className="text-center text-muted my-4">{t('No_paradigms_for_language', { lang })}</div>;
}
if (loading) {
return <Spinner animation="border" role="status" />;
}
if (blocks.length === 0) {
if (!plugin) return <div className="text-center text-muted my-4">{t('No_paradigms_for_language', { lang })}</div>;
if (loading) return <Spinner animation="border" role="status" />;
if (!blocks.length)
return (
<div className="text-center text-muted my-2" data-testid="no-paradigm-found">
{t('No_pos_found')}
</div>
);
}

return (
<div className="paradigm-container">
Expand All @@ -125,7 +104,6 @@ const Paradigm: React.FC<ParadigmProps> = ({ head, lang, mode, onLoaded }) => {
{block.subcats.map((sub, j) => (
<div key={j} id={sub.id}>
<h5>{t(sub.label())}</h5>

{sub.tablist ? (
<ul>
{sub.tablist.map((item, k) => (
Expand Down Expand Up @@ -157,15 +135,13 @@ const Paradigm: React.FC<ParadigmProps> = ({ head, lang, mode, onLoaded }) => {
</tbody>
</table>
)}

{sub.info && <div className="text-info">{t(sub.info)}</div>}
</div>
))}
</>
) : (
<div id={block.id}>
<h5>{t(block.label())}</h5>

{block.tablist ? (
<ul>
{block.tablist.map((item, k) => (
Expand Down Expand Up @@ -197,7 +173,6 @@ const Paradigm: React.FC<ParadigmProps> = ({ head, lang, mode, onLoaded }) => {
</tbody>
</table>
)}

{block.info && <div className="text-info">{t(block.info)}</div>}
</div>
)}
Expand Down
36 changes: 18 additions & 18 deletions src/components/dictionary/Word.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useContext } from 'react';
import './Word.css';
import { useLocalizationPOS } from '../../util/localization';
import { getPosTag } from '../../util/posLocalization';
Expand All @@ -8,6 +8,7 @@ import Dropdown from 'react-bootstrap/Dropdown';
import Paradigm from './Paradigm';
import { uumLabels } from './langs/uum';
import { languageRegistry } from './index';
import { APyContext } from '../../context';

export interface WordProps {
head: string;
Expand All @@ -19,29 +20,29 @@ export interface WordProps {
const Word: React.FC<WordProps> = ({ head, definitions, lang, onDefinitionClick }) => {
const { locale } = useLocalizationPOS();
const { t } = useLocalization();
const apyFetch = useContext(APyContext);
const [expanded, setExpanded] = useState(false);
const [loadingParadigm, setLoadingParadigm] = useState(false);

const plugin = languageRegistry[lang];
const code = locale.split('-')[0].toLowerCase();
const availableModes = Object.keys(uumLabels[code] || {}) as string[];
const [mode, setMode] = useState<string>(availableModes.length > 0 ? availableModes[0] : 'Linguist');
const [mode, setMode] = useState<string>(availableModes[0] || '');

useEffect(() => {
if (!availableModes.includes(mode)) {
setMode(availableModes[0] || 'Linguist');
if (availableModes.length && !availableModes.includes(mode)) {
setMode(availableModes[0]);
}
}, [locale, availableModes]);

const tagRe = /<([^>]+)>/g;
const tags: string[] = [];
let m: RegExpExecArray | null;
while ((m = tagRe.exec(head))) {
tags.push(m[1]);
}
while ((m = tagRe.exec(head))) tags.push(m[1]);

const word = head.replace(/<[^>]+>/g, '');
const cleanDefs = definitions.map((def) => def.replace(/<[^>]+>/g, '')).filter((def) => !/^\(.*\)$/.test(def));
const displayTag = tags.length > 0 ? getPosTag(locale, tags.join('.')) : null;
const displayTag = tags.length ? getPosTag(locale, tags.join('.')) : null;

const handleToggle = () => {
if (!expanded) {
Expand All @@ -52,23 +53,24 @@ const Word: React.FC<WordProps> = ({ head, definitions, lang, onDefinitionClick
}
};

const showExpand = Boolean(plugin && availableModes.length > 0);
const rawBlocks = plugin ? plugin.addParadigms({ head, mode, locale, t, apyFetch }) : [];
const hasParadigms = Array.isArray(rawBlocks) && rawBlocks.length > 0;
const showExpand = hasParadigms;
const showDropdown = hasParadigms && availableModes.length > 1;

return (
<div className="word-card">
<div className="word-header">
<span className="word-text">{word}</span>
{displayTag && <span className="word-pos">{displayTag}</span>}
</div>

<ol className="word-definitions">
{cleanDefs.map((def, i) => (
<li key={i} className="definition-item" onClick={() => onDefinitionClick?.(def, i)}>
{def}
</li>
))}
</ol>

{showExpand && (
<div className="expand-controls">
<button type="button" className="expand-button" onClick={handleToggle} disabled={loadingParadigm}>
Expand All @@ -83,24 +85,22 @@ const Word: React.FC<WordProps> = ({ head, definitions, lang, onDefinitionClick
t('Expand_Paradigms')
)}
</button>

{expanded && (
<Dropdown onSelect={(eventKey) => typeof eventKey === 'string' && setMode(eventKey)}>
{showDropdown && expanded && (
<Dropdown onSelect={(key) => typeof key === 'string' && setMode(key)}>
<Dropdown.Toggle id="mode-dropdown" className="expand-button">
{mode}
</Dropdown.Toggle>
<Dropdown.Menu>
{availableModes.map((mKey) => (
<Dropdown.Item key={mKey} eventKey={mKey}>
{mKey}
{availableModes.map((mk) => (
<Dropdown.Item key={mk} eventKey={mk}>
{mk}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
)}
</div>
)}

{showExpand && expanded && (
<div className="word-paradigm">
<Paradigm head={head} lang={lang} mode={mode} onLoaded={() => setLoadingParadigm(false)} />
Expand Down
46 changes: 12 additions & 34 deletions src/components/dictionary/langs/uum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ export interface UumLabels {
'poss-pl': Record<string, string>;
}

export type UumBlock = {
id?: string;
label: () => string;
tabcols?: string[];
tabrows?: string[];
tabdata?: Array<Array<{ tags: string }>>;
subcats?: UumBlock[];
};

export const uumLabels: Record<string, Record<string, UumLabels>> = {
eng: {
Linguist: {
Expand Down Expand Up @@ -137,7 +128,6 @@ export const uumLabels: Record<string, Record<string, UumLabels>> = {
},
},
},

ukr: {
'Лінгвіст': {
sg: 'Однина',
Expand Down Expand Up @@ -249,7 +239,6 @@ export const uumLabels: Record<string, Record<string, UumLabels>> = {
},
},
},

deu: {
'Sprachwissenschaftler': {
sg: 'Singular',
Expand Down Expand Up @@ -394,7 +383,7 @@ function add_uum(
[{ tags: `${tgs}.p3.sg` }],
[{ tags: `${tgs}.p3.pl` }],
].map((row, i) => [row[0], { tags: `neg.${row[0].tags}` }]),
};
}
}

const mkImpRows = () =>
Expand All @@ -415,9 +404,7 @@ function add_uum(
id: 'non-personal',
label: () => t(m.labels['non-personal']),
tabcols: [m.labels.affirmative, m.labels.negative].map(k => t(k)),
tabrows: [m.labels.infinitive, m.labels.participle, m.labels.converb].map(k =>
t(k)
),
tabrows: [m.labels.infinitive, m.labels.participle, m.labels.converb].map(k => t(k)),
tabdata: [
[{ tags: 'inf' }],
[{ tags: 'pp' }],
Expand Down Expand Up @@ -449,9 +436,7 @@ function add_uum(
id: 'non-personal',
label: () => t(m.labels['non-personal']),
tabcols: [m.labels.affirmative, m.labels.negative].map(k => t(k)),
tabrows: [m.labels.infinitive, m.labels.participle, m.labels.converb].map(k =>
t(k)
),
tabrows: [m.labels.infinitive, m.labels.participle, m.labels.converb].map(k => t(k)),
tabdata: [
[{ tags: 'inf' }],
[{ tags: 'pp' }],
Expand Down Expand Up @@ -499,9 +484,7 @@ function add_uum(
tabcols: Object.values(m['poss-sg']).map(k => t(k)),
tabrows: Object.values(m.cases).map(k => t(k)),
tabdata: Object.keys(m.cases).map(c =>
Object.keys(m['poss-sg']).map(p => ({
tags: `px${p.slice(1)}.${c}`,
}))
Object.keys(m['poss-sg']).map(p => ({ tags: `px${p.slice(1)}.${c}` }))
),
},
{
Expand All @@ -510,9 +493,7 @@ function add_uum(
tabcols: Object.values(m['poss-pl']).map(k => t(k)),
tabrows: Object.values(m.cases).map(k => t(k)),
tabdata: Object.keys(m.cases).map(c =>
Object.keys(m['poss-pl']).map(p => ({
tags: `pl.px${p.slice(1)}.${c}`,
}))
Object.keys(m['poss-pl']).map(p => ({ tags: `pl.px${p.slice(1)}.${c}` }))
),
},
],
Expand Down Expand Up @@ -540,9 +521,7 @@ function add_uum(
tabcols: Object.values(m['poss-sg']).map(k => t(k)),
tabrows: Object.values(m.cases).map(k => t(k)),
tabdata: Object.keys(m.cases).map(c =>
Object.keys(m['poss-sg']).map(p => ({
tags: `px${p.slice(1)}.${c}`,
}))
Object.keys(m['poss-sg']).map(p => ({ tags: `px${p.slice(1)}.${c}` }))
),
},
{
Expand All @@ -551,15 +530,13 @@ function add_uum(
tabcols: Object.values(m['poss-pl']).map(k => t(k)),
tabrows: Object.values(m.cases).map(k => t(k)),
tabdata: Object.keys(m.cases).map(c =>
Object.keys(m['poss-pl']).map(p => ({
tags: `pl.px${p.slice(1)}.${c}`,
}))
Object.keys(m['poss-pl']).map(p => ({ tags: `pl.px${p.slice(1)}.${c}` }))
),
},
],
},
],
};
}
}

export function parseTags(origTags: string[], cellTags: string): string[] {
Expand All @@ -580,13 +557,14 @@ export const uumPlugin: LanguagePlugin = {
const labelsForMode = uumLabels[code]?.[mode] ?? uumLabels.eng.Linguist;
const blocksMap = add_uum({ labels: labelsForMode, t });
const origTags = Array.from(head.matchAll(/<([^>]+)>/g), (m) => m[1]);
let key: string;
let key: string | undefined;
if (origTags.includes('iv')) key = 'verb_iv';
else if (origTags.includes('tv')) key = 'verb_tv';
else if (origTags.some((tag) => tag.startsWith('v'))) key = 'vaux';
else if (origTags.some((tag) => tag.startsWith('np.'))) key = 'pnoun';
else key = 'noun';
else if (origTags[0] === 'n') key = 'noun';
if (!key) return [];
return blocksMap[key] || [];
},
parseTags,
};
};
Loading