feat(dictionary): the radicals, each listing the kanji written with it
Beside Words and Kanji & kana, a Radicals tab lists the 214 Kangxi
radicals by their strokes, with the forms Japanese writes them as inside
kanji (亻, 氵, 艹, …). One chosen lists the kanji KANJIDIC2 files under
it, in the dictionary's order, to add or to see how one is written; the
tab shares the characters' bloc, so a kanji added there shows as held in
a search too.
The curator labels each kanji with its classical radical (`radical:N`),
so the server's existing label queries serve the tab unchanged. Its
files now say which conversion made them (`.conversion`): an instance
running a curator that converts differently converts again at once,
rather than at its weekly update, so the radicals appear right after a
deploy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-10 02:13:06 +02:00
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
|
import 'package:halkyon_learn_flutter/src/feature/kanji/model/radical.dart';
|
|
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
|
test('the 214 Kangxi radicals in their order, by their strokes from 1 '
|
|
|
|
|
'to 17', () {
|
|
|
|
|
expect(
|
|
|
|
|
[for (final radical in radicals) radical.number],
|
|
|
|
|
[
|
|
|
|
|
for (var number = 1; number <= 214; number++) number,
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
final strokes = [for (final radical in radicals) radical.strokes];
|
|
|
|
|
expect(strokes, orderedEquals([...strokes]..sort()));
|
|
|
|
|
expect((strokes.first, strokes.last), (1, 17));
|
|
|
|
|
// Const, as the table is: a record compares its lists by identity.
|
|
|
|
|
expect(radicals[84], const (
|
|
|
|
|
number: 85,
|
|
|
|
|
character: '水',
|
|
|
|
|
variants: ['氵'],
|
|
|
|
|
strokes: 4,
|
|
|
|
|
name: 'water',
|
|
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('each is one character, as is every form it takes in kanji', () {
|
|
|
|
|
for (final radical in radicals) {
|
|
|
|
|
for (final form in [radical.character, ...radical.variants]) {
|
|
|
|
|
expect(form.runes, hasLength(1), reason: '${radical.number}');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("a radical's label is the dictionary's", () {
|
|
|
|
|
expect(radicalLabel(85), 'radical:85');
|
|
|
|
|
});
|
feat(dictionary): characters of Chinese, Korean and Greek, written by hand; pinyin typed
Parity with Japanese's kanji and kana:
- The characters' tab is named by its language (Hanzi, Hangul & Hanja,
Alphabet), its groups too: HSK levels and the characters in common use
(Hong Kong's grades for traditional ones); Hangul and the Hanja taught
in schools; Greek's letters. Radicals for Chinese and Korean in their
own forms (讠 for 言 in simplified Chinese), none for Greek.
- A character's readings are named as its language names them: On and
Kun, Pinyin, Eum and Hun (음, 훈); a letter means its sound and name.
- How characters are written comes by language: Chinese from Make Me a
Hanzi (its medians in KanjiVG's square, Arphic Public License, a data
file beside the app, never in cards), the Hangul letters drawn by the
curator; a Korean word is written letter by letter (닭: ㄷ ㅏ ㄺ). Words
of alphabets (German, Greek) aren't written by hand.
- A Chinese word's pinyin is typed in a session, tone numbers turning
into marks (ni3 → nǐ); KRDict's levels (초급, 중급, 고급) tag Korean
words; a Korean word's pronunciation shows in brackets ([가치]).
- Smaller: Look up in the composer keeps a noun's article; the Watch
filter names its level list; hints and placeholders by language.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 12:35:17 +02:00
|
|
|
|
|
|
|
|
test('the forms a radical takes in each language: simplified Chinese its '
|
|
|
|
|
"own, traditional Chinese and Korean without Japanese's own", () {
|
|
|
|
|
final speech = radicals[148];
|
|
|
|
|
final dragon = radicals[211];
|
|
|
|
|
final food = radicals[183];
|
|
|
|
|
expect(radicalFormsIn(speech, 'zh-Hans'), ['讠']);
|
|
|
|
|
expect(radicalFormsIn(speech, 'zh-Hant'), isEmpty);
|
|
|
|
|
expect(radicalFormsIn(dragon, 'ja'), ['竜']);
|
|
|
|
|
expect(radicalFormsIn(dragon, 'zh'), ['龙']);
|
|
|
|
|
expect(radicalFormsIn(dragon, 'ko'), isEmpty);
|
|
|
|
|
// Simplified Chinese writes 食 as 饣 at a character's side, not 飠.
|
|
|
|
|
expect(radicalFormsIn(food, 'zh-CN'), ['饣']);
|
|
|
|
|
expect(radicalFormsIn(food, 'zh-TW'), ['飠']);
|
|
|
|
|
expect(radicalsIn('zh-Hans')[148].variants, ['讠']);
|
|
|
|
|
expect((hasRadicals('ko'), hasRadicals('el')), (true, false));
|
|
|
|
|
});
|
feat(dictionary): the radicals, each listing the kanji written with it
Beside Words and Kanji & kana, a Radicals tab lists the 214 Kangxi
radicals by their strokes, with the forms Japanese writes them as inside
kanji (亻, 氵, 艹, …). One chosen lists the kanji KANJIDIC2 files under
it, in the dictionary's order, to add or to see how one is written; the
tab shares the characters' bloc, so a kanji added there shows as held in
a search too.
The curator labels each kanji with its classical radical (`radical:N`),
so the server's existing label queries serve the tab unchanged. Its
files now say which conversion made them (`.conversion`): an instance
running a curator that converts differently converts again at once,
rather than at its weekly update, so the radicals appear right after a
deploy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMm7usAo6q9ZZRoPkWjoxi
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-10 02:13:06 +02:00
|
|
|
}
|