fix(dictionary): a German separated verb is a verb, never a joined noun or particle

A clause ending in a separable particle joined each word before it to the
particle and offered whatever the dictionary found, so "Er holt mich ab."
offered aber, "Er schläft ein." einer and "Er hört dem Lehrer zu." zudem.
Now only an entry that is a verb is offered, and a capitalised word after
the clause's first is taken for a noun and never joined.

The particles of fernsehen, hochheben, durchlesen, unterbringen,
übersetzen and bereitstellen were missing, as were the spoken rein, raus
and runter, so "Ich sehe heute Abend fern." now finds fernsehen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-14 17:44:46 +02:00
commit d3063e82e1
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -14,6 +14,20 @@ void main() {
final rufen = germanWord('rufen', pos: 'verb', glosses: ['to shout']);
final an = germanWord('an', pos: 'preposition', glosses: ['at']);
/// The entries of each longer word the part [text] of German [sentence]
/// offers beside itself, cut as [found] has its keys.
List<List<DictionaryItem>> widerAt(
String sentence,
String text,
Map<String, List<DictionaryItem>> found,
) => [
for (final wider in germanSentenceParts(
sentence,
found,
).singleWhere((part) => part.text == text).wider)
wider.entries,
];
test('a clause ending in a separable particle asks for each word before '
'it with the particle joined on, as subordinate clauses write it', () {
final keys = germanSentenceKeys('Ich rufe dich morgen an.');
@ -45,4 +59,142 @@ void main() {
// The particle's place in the line is where it stands.
expect(particle.start, 'Ich rufe dich morgen '.length);
});
test('only a verb is offered: a word before the particle joined to it '
'into a word of another kind is no separated verb', () {
final abholen = germanWord(
'abholen',
pos: 'verb',
glosses: ['to pick up'],
forms: ['abholt'],
);
final found = <String, List<DictionaryItem>>{
'er': [
germanWord('er', pos: 'pronoun', glosses: ['he']),
],
'holt': [
germanWord('holen', pos: 'verb', glosses: ['to fetch']),
],
'ab': [
germanWord('ab', pos: 'adverb', glosses: ['off']),
],
'aber': [
germanWord('aber', pos: 'conjunction', glosses: ['but']),
],
'abholt': [abholen],
'ein': [
germanWord('ein', pos: 'article', glosses: ['a']),
],
'einer': [
germanWord('einer', pos: 'pronoun', glosses: ['one']),
],
'dem': [
germanWord('der', pos: 'article', glosses: ['the']),
],
'zu': [
germanWord('zu', pos: 'preposition', glosses: ['to']),
],
'zudem': [
germanWord('zudem', pos: 'adverb', glosses: ['moreover']),
],
};
// ab and er are no aber, ein and er no einer, zu and dem no zudem.
expect(widerAt('Er holt mich ab.', 'ab', found), [
[abholen],
]);
expect(widerAt('Er holt mich ab.', 'Er', found), isEmpty);
expect(widerAt('Er schläft ein.', 'ein', found), isEmpty);
expect(widerAt('Er hört dem Lehrer zu.', 'zu', found), isEmpty);
});
test('a capitalised word is a noun unless it opens the clause, and is '
'never taken for the verb', () {
final abstellen = germanWord(
'abstellen',
pos: 'verb',
glosses: ['to put down'],
forms: ['abstellt'],
);
final anrufenAsked = germanWord(
'anrufen',
pos: 'verb',
glosses: ['to call'],
forms: ['anrufst'],
);
expect(
germanSentenceKeys('Er stellt das Essen ab.'),
allOf(contains('abstellt'), isNot(contains('abessen'))),
);
expect(
widerAt('Er stellt das Essen ab.', 'ab', {
'stellt': [
germanWord('stellen', pos: 'verb', glosses: ['to put']),
],
'essen': [
germanWord('Essen', pos: 'noun', glosses: ['food']),
],
'ab': [
germanWord('ab', pos: 'adverb', glosses: ['off']),
],
'abstellt': [abstellen],
'abessen': [
germanWord('abessen', pos: 'verb', glosses: ['to eat up']),
],
}),
[
[abstellen],
],
);
// A question opens with its verb.
expect(
widerAt('Rufst du mich an?', 'Rufst', {
'rufst': [rufen],
'an': [an],
'anrufst': [anrufenAsked],
}),
[
[anrufenAsked],
],
);
});
test('fern, hoch, durch, unter, über, bereit and the spoken rein, raus '
'and runter separate too', () {
for (final (sentence, key) in [
('Ich sehe heute Abend fern.', 'fernsehe'),
('Er hebt die Kiste hoch.', 'hochhebt'),
('Sie liest den Text durch.', 'durchliest'),
('Wir bringen die Gäste unter.', 'unterbringen'),
('Die Fähre setzt uns über.', 'übersetzt'),
('Sie stellt das Essen bereit.', 'bereitstellt'),
('Komm doch rein!', 'reinkomm'),
('Er geht raus.', 'rausgeht'),
('Sie kommt runter.', 'runterkommt'),
]) {
expect(germanSentenceKeys(sentence), contains(key), reason: sentence);
}
final fernsehen = germanWord(
'fernsehen',
pos: 'verb',
glosses: ['to watch television'],
forms: ['fernsehe'],
);
expect(
widerAt('Ich sehe heute Abend fern.', 'sehe', {
'sehe': [
germanWord('sehen', pos: 'verb', glosses: ['to see']),
],
'fern': [
germanWord('fern', pos: 'adjective', glosses: ['far']),
],
'fernsehe': [fernsehen],
}),
[
[fernsehen],
],
);
});
}