Skip to content

Support deinflection entries in the Yomitan format#718

Merged
ilius merged 8 commits into
ilius:masterfrom
daxida:yomitan-deinf
May 5, 2026
Merged

Support deinflection entries in the Yomitan format#718
ilius merged 8 commits into
ilius:masterfrom
daxida:yomitan-deinf

Conversation

@daxida

@daxida daxida commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Closes #714

Notes:

  1. Tested with output format = Json and wty-el-el (a big dict, 35MB zipped, 1GB unzipped), took 42secs. It crashed before so there is no reference measurement.
  2. There needs to be two passes over the data because Yomitan doesn't require redirection forms to be in a particular place across banks. See the schema
  3. We also keep the orphaned alts (alts of terms that are not in the dictionary), by making a new entry using the causal chain. Some examples below*:
  4. Eventually the "of" part that I added should be changed to something language-agnostic like a < symbol as it makes no sense to have it in a monolingual Greek dictionary...
  5. There are some types I didn't add because of laziness/was unsure.
  6. Running pytest crashed on a bunch of unrelated modules and I didn't try harder. Maybe I broke some Yomitan tests but there was no way to quickly check it.

Examples of 3.

	"φιλοαμερικανοί (2)": "nominative/vocative of φιλοαμερικανός",
	"φιλοαμερικανοί (3)": "plural of φιλοαμερικανός",
	"κλαδιστική": "feminine of κλαδιστικός",
	"κλαδιστική (2)": "nominative/accusative/vocative of κλαδιστικός",
	"κλαδιστική (3)": "singular of κλαδιστικός",
	"Λιμολάρη": "genitive/accusative/vocative of Λιμολάρης",
	"Λιμολάρη (2)": "masculine of Λιμολάρης",
	"Λιμολάρη (3)": "singular of Λιμολάρης",

Cons:
Because of 2. the code is going to be slower even if there are no alts, since we can't know that unless we read once the data.

Pros:
Supports every modern yomitan dictionary that includes redirection forms as described in the issue.

@daxida daxida changed the title Support deinflection entries Support deinflection entries in the Yomitan format Apr 28, 2026
Comment thread pyglossary/plugins/yomichan/reader.py Outdated
Comment thread pyglossary/plugins/yomichan/reader.py Outdated
def _readTermBank(self, termBankName: str) -> Generator[EntryType, None, None]:
def _readTermBanks(self) -> Generator[EntryType, None, None]:
termToAlts = self._readTermBanksAlts()
orphanedTerms: set[str] = {*termToAlts.keys()}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set(termToAlts) is much easier to read.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, in my mind that would have made a list of items, but apparently the python convention is to retain the keys. TIL

Comment thread pyglossary/plugins/yomichan/reader.py Outdated
if altInfo := termToAlts.get(item[0]):
orphanedTerms.discard(item[0])
alts = [elt[0] for elt in altInfo]
term = [term, *alts] if isinstance(term, str) else [*term, *alts]

@ilius ilius Apr 30, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this syntax. Let's use term + alts
Oh and if term can be a list, would term = [term, reading] above still work as expected?
Maybe this:

l_term: list[str] = term if isinstance(term, list) else [term]

l_term.extend(alts)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what you mean with this one. I still need to pass term to newEntry below.

So you just want?:

l_term: list[str] = term if isinstance(term, list) else [term]
l_term.extend(alts)
term = l_term

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please annotate the type of term in this block. And use two different vars for two types (list and str). Seems kinda fragile.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure I did what you wanted. Let me know if that suits you.

@ilius

ilius commented Apr 30, 2026

Copy link
Copy Markdown
Owner

BTW, you can the tests with ./scripts/test.sh
We use unittest, not pytest.
Yomichan tests in tests/g_yomichan_test.py.
But we don't have tests for Yomichan reader.

Can you upload a sample Yomichan glossary that contains about 10 to 20 entries that cover these cases?

So I can compare the changes and add a test.

@daxida

daxida commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

Can you upload a sample Yomichan glossary that contains about 10 to 20 entries that cover these cases?

Sure, it will need to be hand-made because all the dictionaries I have are quite large. I will try to come up with something simple.

@daxida

daxida commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

02-deinflection.zip

These are the contents:

[
    ["term", "", "", "", 5, ["Prelude"], 26, ""],
    ["term0", "", "", "", 5, ["Prelude0"], 26, ""],
    ["term1", "", "", "", 5, ["term1 definition"], 26, ""],
    ["term2", "reading2", "", "", 5, ["term2 definition1", "term2 definition2"], 27, ""],
    ["infl1", "", "", "", 1, [["term1", ["plural"]]], 28, ""],
    ["infl2", "", "", "", 1, [["term2", ["first cause", "second cause"]]], 29, ""],
    ["infl3", "", "", "", 1, [["term3", ["first cause"]]], 29, ""],
    ["infl4", "", "", "", 1, [["term3", ["first cause", "second cause"]]], 29, ""]
]

image image

@daxida

daxida commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

020-deinflection.zip

I added more cases. In particular:

  • term2 now has many entries with different readings, in case you want to test if the inflection goes to everyone of them
  • infl2 now also refers to term1, so we have two inflections for the same term (which is the cura|curas, curar|curas case in the docstring) - infl4 and 5 also referred to term3, but term3 was not present.
[
    ["term", "", "", "", 5, ["Prelude"], 26, ""],
    ["term0", "", "", "", 5, ["Prelude0"], 26, ""],
    ["term1", "", "", "", 5, ["term1 definition"], 26, ""],
    ["term2", "", "", "", 5, ["term2 no reading definition"], 27, ""],
    ["term2", "reading1", "", "", 5, ["term2 reading1 definition"], 27, ""],
    ["term2", "reading2", "", "", 5, ["term2 definition1", "term2 definition2"], 27, ""],
    ["infl1", "", "", "", 1, [["term1", ["plural"]]], 28, ""],
    ["infl2", "", "", "", 1, [["term1", ["genitive"]]], 28, ""],
    ["infl3", "", "", "", 1, [["term2", ["first cause", "second cause"]]], 29, ""],
    ["infl4", "", "", "", 1, [["term3", ["first cause"]]], 29, ""],
    ["infl5", "", "", "", 1, [["term3", ["first cause", "second cause"]]], 29, ""]
]

@ilius ilius merged commit af7ae47 into ilius:master May 5, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Yomichan format crashes on deinflection term-bank entry

2 participants