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>
This commit is contained in:
parent
7070cd6bd2
commit
5479b973fc
10 changed files with 2559 additions and 230 deletions
|
|
@ -0,0 +1,52 @@
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/chinese/pinyin_input.dart';
|
||||
|
||||
void main() {
|
||||
test('tone numbers become tone marks: on a or e, on the o of ou, else on '
|
||||
'the last vowel; ü typed as v or u:; the neutral tone unmarked', () {
|
||||
expect(withToneMarks('ni3hao3'), 'nǐhǎo');
|
||||
expect(withToneMarks('xue2xi2'), 'xuéxí');
|
||||
expect(withToneMarks('dou1'), 'dōu');
|
||||
expect(withToneMarks('gui4'), 'guì');
|
||||
expect(withToneMarks('liu2'), 'liú');
|
||||
expect(withToneMarks('lv4'), 'lǜ');
|
||||
expect(withToneMarks('nu:3'), 'nǚ');
|
||||
expect(withToneMarks('ma5'), 'ma');
|
||||
expect(withToneMarks('Bei3jing1'), 'Běijīng');
|
||||
expect(withToneMarks('xuéxí'), 'xuéxí');
|
||||
});
|
||||
|
||||
test('pinyin compares with its tones, whatever its case, spaces and '
|
||||
'numbers', () {
|
||||
expect(pinyinKey('Xué xí'), 'xuéxí');
|
||||
expect(pinyinKey('xue2 xi2'), 'xuéxí');
|
||||
expect(pinyinKey("Xi1'an1"), 'xīān');
|
||||
expect(givenPinyin('xíng, háng'), {'xíng', 'háng'});
|
||||
expect(givenPinyin('xíng').contains(pinyinKey('xing2')), isTrue);
|
||||
expect(givenPinyin('xíng').contains(pinyinKey('xing1')), isFalse);
|
||||
});
|
||||
|
||||
test("pinyin is told from kana and from words' own letters", () {
|
||||
expect(isPinyin('xué xí'), isTrue);
|
||||
expect(isPinyin('shuō'), isTrue);
|
||||
expect(isPinyin('たべる'), isFalse);
|
||||
expect(isPinyin('가치'), isFalse);
|
||||
expect(isPinyin(''), isFalse);
|
||||
});
|
||||
|
||||
test('typing turns a syllable and its tone into the marked syllable, the '
|
||||
'caret where it was typed', () {
|
||||
const formatter = PinyinInputFormatter();
|
||||
final value = formatter.formatEditUpdate(
|
||||
const TextEditingValue(text: 'ni'),
|
||||
const TextEditingValue(
|
||||
text: 'ni3',
|
||||
selection: TextSelection.collapsed(offset: 3),
|
||||
),
|
||||
);
|
||||
|
||||
expect(value.text, 'nǐ');
|
||||
expect(value.selection, const TextSelection.collapsed(offset: 2));
|
||||
});
|
||||
}
|
||||
|
|
@ -91,6 +91,91 @@ void main() {
|
|||
});
|
||||
});
|
||||
|
||||
group('a character of another language', () {
|
||||
test("Chinese: its pinyin as its readings, its HSK level and Hong Kong's "
|
||||
'grade from its labels', () {
|
||||
final say = DictionaryCharacter.fromEntry(
|
||||
ref: (source: 'unihan-hant', id: '說'),
|
||||
headword: '說',
|
||||
labels: const ['hsk:1', 'common', 'grade:1', 'radical:149'],
|
||||
entry:
|
||||
'{"meanings": ["speak", "say"], "pinyin": ["shuō", "shuì"], '
|
||||
'"strokes": 14, "simplified": ["说"]}',
|
||||
language: 'zh-Hant',
|
||||
);
|
||||
|
||||
expect(say.onReadings, ['shuō', 'shuì']);
|
||||
expect(say.kunReadings, isEmpty);
|
||||
expect((say.hsk, say.grade, say.strokes), (1, 1, 14));
|
||||
expect(say.tagNames, ['HSK-1', 'Grade 1']);
|
||||
expect(say.card.onReadings, ['shuō', 'shuì']);
|
||||
});
|
||||
|
||||
test('Korean: a Hanja its sounds and native meanings, the 1,800 of '
|
||||
'education tagged; a letter its sound and name', () {
|
||||
final water = DictionaryCharacter.fromEntry(
|
||||
ref: (source: 'unihan-ko', id: '水'),
|
||||
headword: '水',
|
||||
labels: const ['education', 'radical:85'],
|
||||
entry:
|
||||
'{"meanings": ["water"], "eum": ["수"], "hun": ["물"], '
|
||||
'"eumhun": ["물 수"], "strokes": 4}',
|
||||
language: 'ko',
|
||||
);
|
||||
expect(water.onReadings, ['수']);
|
||||
expect(water.kunReadings, ['물']);
|
||||
expect(water.isEducationHanja, isTrue);
|
||||
expect(water.tagNames, ['Education Hanja']);
|
||||
|
||||
final giyeok = DictionaryCharacter.fromEntry(
|
||||
ref: (source: 'unihan-ko', id: 'ㄱ'),
|
||||
headword: 'ㄱ',
|
||||
labels: const ['hangul'],
|
||||
entry: '{"romaji": "g, k", "script": "hangul", "name": "기역"}',
|
||||
language: 'ko',
|
||||
);
|
||||
expect(giyeok.isKana, isTrue);
|
||||
expect(giyeok.meaningsShown, ['g, k', '기역']);
|
||||
expect(giyeok.tagNames, ['Hangul']);
|
||||
});
|
||||
|
||||
test('Greek: a letter with its capital, its transliteration and its '
|
||||
'names', () {
|
||||
final beta = DictionaryCharacter.fromEntry(
|
||||
ref: (source: 'greek-alphabet', id: 'β'),
|
||||
headword: 'Β β',
|
||||
labels: const ['greek'],
|
||||
entry:
|
||||
'{"romaji": "v", "script": "greek", "name": "βήτα", '
|
||||
'"englishName": "beta", "sound": "v"}',
|
||||
language: 'el',
|
||||
);
|
||||
|
||||
expect(beta.card.front.plainText.trim(), 'Β β');
|
||||
expect(beta.card.meanings, ['v', 'βήτα (beta)']);
|
||||
expect(beta.tagNames, ['Greek alphabet']);
|
||||
expect(isDictionaryTagName('Greek alphabet'), isTrue);
|
||||
});
|
||||
|
||||
test("a Korean word's KRDict level names its tag as KRDict does", () {
|
||||
final school = DictionaryWord.fromEntry(
|
||||
ref: (source: 'krdict', id: '73276'),
|
||||
headword: '학교',
|
||||
reading: '학꾜',
|
||||
labels: const ['level:beginner'],
|
||||
entry:
|
||||
'{"pos": "noun", "hanja": ["學校"], '
|
||||
'"senses": [{"glosses": ["school"]}]}',
|
||||
language: 'ko',
|
||||
);
|
||||
|
||||
expect(school.koreanLevel, 1);
|
||||
expect(school.tagNames, ['초급', 'Noun']);
|
||||
expect(isDictionaryTagName('초급'), isTrue);
|
||||
expect(school.card.reading, '학꾜');
|
||||
});
|
||||
});
|
||||
|
||||
group('Cards behind the dictionary', () {
|
||||
late FakeCardGateway cardGateway;
|
||||
late CardRepository cards;
|
||||
|
|
|
|||
|
|
@ -72,8 +72,9 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
/// Opens the studyset [id]: `japanese` (Japanese with English meanings)
|
||||
/// or `german`, on an instance with JMdict ([dictionaries]), at
|
||||
/// Opens the studyset [id]: `japanese` (Japanese with English meanings),
|
||||
/// `german`, `greek` or `chinese`, on an instance with JMdict
|
||||
/// ([dictionaries]), at
|
||||
/// [location] (the studyset's screen unless given).
|
||||
Future<void> show(
|
||||
WidgetTester tester, {
|
||||
|
|
@ -107,6 +108,28 @@ void main() {
|
|||
backLanguage: 'en',
|
||||
),
|
||||
),
|
||||
)
|
||||
..receiveRemoteChange(
|
||||
'greek',
|
||||
encodeStudysetPayload(
|
||||
StudysetContent(
|
||||
title: 'Greek',
|
||||
description: RichContent.empty(),
|
||||
frontLanguage: 'el',
|
||||
backLanguage: 'en',
|
||||
),
|
||||
),
|
||||
)
|
||||
..receiveRemoteChange(
|
||||
'chinese',
|
||||
encodeStudysetPayload(
|
||||
StudysetContent(
|
||||
title: 'Chinese',
|
||||
description: RichContent.empty(),
|
||||
frontLanguage: 'zh-Hans',
|
||||
backLanguage: 'en',
|
||||
),
|
||||
),
|
||||
);
|
||||
await pumpApp(
|
||||
tester,
|
||||
|
|
@ -259,6 +282,76 @@ void main() {
|
|||
expect(made.content.entry, (source: 'kanjidic', id: '食'));
|
||||
});
|
||||
|
||||
testWidgets("Greek's letters in a tab of their own, without radicals, "
|
||||
'added whole as character cards', (tester) async {
|
||||
await show(
|
||||
tester,
|
||||
id: 'greek',
|
||||
dictionaries: FakeDictionaryGateway(
|
||||
available: [wiktionaryEl, greekAlphabet],
|
||||
words: [
|
||||
character(
|
||||
'Β β',
|
||||
labels: ['greek'],
|
||||
romaji: 'v',
|
||||
name: 'βήτα (beta)',
|
||||
of: greekAlphabet,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
await addMaterial(tester, 'From the dictionary');
|
||||
|
||||
expect(find.text('Radicals'), findsNothing);
|
||||
await tester.tap(find.text('Alphabet'));
|
||||
await settle(tester);
|
||||
expect(find.text('Letters'), findsOneWidget);
|
||||
await tester.tap(find.text('Greek alphabet').hitTestable());
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Add 1 character'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final made = (await cards.cardsOf('greek')).single;
|
||||
expect(made.content.front.plainText.trim(), 'Β β');
|
||||
expect(made.content.meanings, ['v', 'βήτα (beta)']);
|
||||
});
|
||||
|
||||
testWidgets('Chinese characters by HSK level and in common use, beside '
|
||||
'the radicals in their simplified forms', (tester) async {
|
||||
await show(
|
||||
tester,
|
||||
id: 'chinese',
|
||||
dictionaries: FakeDictionaryGateway(
|
||||
available: [ccCedictHans, unihanHans],
|
||||
words: [
|
||||
character(
|
||||
'说',
|
||||
meanings: ['speak'],
|
||||
on: ['shuō'],
|
||||
labels: ['hsk:1', 'common', 'radical:149'],
|
||||
of: unihanHans,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
await addMaterial(tester, 'From the dictionary');
|
||||
|
||||
await tester.tap(find.text('Hanzi'));
|
||||
await settle(tester);
|
||||
expect(find.text('HSK levels'), findsOneWidget);
|
||||
expect(find.text('In common use'), findsOneWidget);
|
||||
expect(find.text('HSK 1'), findsOneWidget);
|
||||
await tester.tap(find.text('Radicals'));
|
||||
await settle(tester);
|
||||
// 言 as simplified Chinese writes it at a character's side.
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('讠'),
|
||||
400,
|
||||
scrollable: find.byType(Scrollable).last,
|
||||
);
|
||||
expect(find.text('讠'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('a character found shows its readings and strokes, and is '
|
||||
'added as a card', (tester) async {
|
||||
await show(tester, dictionaries: withKanji());
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/kanji/model/hangul.dart';
|
||||
|
||||
void main() {
|
||||
test('a Hangul syllable is written with its letters: the opening '
|
||||
'consonant, the vowel and the closing one or cluster', () {
|
||||
expect(hangulLetters('가'), ['ㄱ', 'ㅏ']);
|
||||
expect(hangulLetters('닭'), ['ㄷ', 'ㅏ', 'ㄺ']);
|
||||
expect(hangulLetters('쓰'), ['ㅆ', 'ㅡ']);
|
||||
expect(hangulLetters('왜'), ['ㅇ', 'ㅙ']);
|
||||
expect(hangulLetters('힣'), ['ㅎ', 'ㅣ', 'ㅎ']);
|
||||
// What is no syllable stays as it is.
|
||||
expect(hangulLetters('ㄱ'), ['ㄱ']);
|
||||
expect(hangulLetters('食'), ['食']);
|
||||
});
|
||||
|
||||
test('scripts whose strokes are drawn: Han characters, kana, Hangul; '
|
||||
'not the alphabets', () {
|
||||
expect(hasDrawnScript('食べる'), isTrue);
|
||||
expect(hasDrawnScript('学习'), isTrue);
|
||||
expect(hasDrawnScript('학교'), isTrue);
|
||||
expect(hasDrawnScript('ㄱ'), isTrue);
|
||||
expect(hasDrawnScript('das Haus'), isFalse);
|
||||
expect(hasDrawnScript('Β β'), isFalse);
|
||||
});
|
||||
}
|
||||
|
|
@ -34,4 +34,21 @@ void main() {
|
|||
test("a radical's label is the dictionary's", () {
|
||||
expect(radicalLabel(85), 'radical:85');
|
||||
});
|
||||
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,43 @@ void main() {
|
|||
expect(await strokes.strokesOf(''), isNull);
|
||||
});
|
||||
|
||||
test("Chinese draws its characters as Make Me a Hanzi does, KanjiVG's "
|
||||
'for what it lacks; Korean its letters with its own strokes', () async {
|
||||
final strokes = StrokeRepository();
|
||||
|
||||
// 说 is simplified Chinese's alone, which KanjiVG doesn't draw.
|
||||
expect(await strokes.strokesOf('说'), isNull);
|
||||
final say = await strokes.strokesOf('说', language: 'zh-Hans');
|
||||
expect(say!.paths, hasLength(9));
|
||||
expect(strokes.read('说', language: 'zh'), say);
|
||||
// 水 is drawn by both, each in its own shapes.
|
||||
expect(
|
||||
(await strokes.strokesOf('水', language: 'zh'))!.paths,
|
||||
isNot((await strokes.strokesOf('水'))!.paths),
|
||||
);
|
||||
// A kana Make Me a Hanzi doesn't draw comes from KanjiVG.
|
||||
expect(await strokes.strokesOf('あ', language: 'zh'), isNotNull);
|
||||
expect(
|
||||
(await strokes.strokesOf('ㄹ', language: 'ko'))!.paths,
|
||||
hasLength(3),
|
||||
);
|
||||
expect(
|
||||
(await strokes.strokesOf('ㄺ', language: 'ko'))!.components,
|
||||
['ㄹ', 'ㄱ'],
|
||||
);
|
||||
expect(await strokes.strokesOf('ㄹ', language: 'ja'), isNull);
|
||||
});
|
||||
|
||||
test('each set by language: Japanese KanjiVG, Chinese Make Me a Hanzi '
|
||||
'first, Korean its letters first', () {
|
||||
expect(StrokeSet.of(null), [StrokeSet.kanjivg]);
|
||||
expect(StrokeSet.of('zh-Hant'), [
|
||||
StrokeSet.makemeahanzi,
|
||||
StrokeSet.kanjivg,
|
||||
]);
|
||||
expect(StrokeSet.of('ko').first, StrokeSet.hangul);
|
||||
});
|
||||
|
||||
test('the file a character is in: each 256 code points', () {
|
||||
expect(strokeFileOf('食'), '098');
|
||||
expect(strokeFileOf('あ'), '030');
|
||||
|
|
|
|||
|
|
@ -773,7 +773,7 @@ void main() {
|
|||
'japanese',
|
||||
CardContent(
|
||||
type: CardType.character,
|
||||
front: text('食'),
|
||||
front: RichContent.plain('食'),
|
||||
back: RichContent.empty(),
|
||||
meanings: const ['eat'],
|
||||
),
|
||||
|
|
@ -800,7 +800,12 @@ void main() {
|
|||
await withClock(Clock(() => now), () async {
|
||||
final bloc = session();
|
||||
addTearDown(bloc.close);
|
||||
final kanji = await showing(bloc, '食');
|
||||
final kanji = await until(
|
||||
bloc,
|
||||
(s) =>
|
||||
s is StudySessionStateShowing &&
|
||||
s.card.content.front == RichContent.plain('食'),
|
||||
) as StudySessionStateShowing;
|
||||
expect(kanji.writes, isTrue);
|
||||
rate(bloc, Rating.good);
|
||||
final word = await until(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/card/model/card_content.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/study/model/card_study_mode.dart';
|
||||
import 'package:halkyon_learn_flutter/src/feature/study/model/study_options.dart';
|
||||
|
||||
void main() {
|
||||
const writing = StudyOptions(writeByHand: true);
|
||||
|
||||
CardContent word(String front) => CardContent(
|
||||
type: CardType.vocabulary,
|
||||
front: RichContent.plain(front),
|
||||
back: RichContent.empty(),
|
||||
meanings: const ['a meaning'],
|
||||
);
|
||||
|
||||
test('written by hand: words and characters of scripts whose strokes are '
|
||||
'drawn, not words of alphabets', () {
|
||||
expect(writtenByHand(word('食べる'), writing), isTrue);
|
||||
expect(writtenByHand(word('学习'), writing), isTrue);
|
||||
expect(writtenByHand(word('학교'), writing), isTrue);
|
||||
expect(writtenByHand(word('das Haus'), writing), isFalse);
|
||||
expect(writtenByHand(word('σπίτι'), writing), isFalse);
|
||||
expect(
|
||||
writtenByHand(
|
||||
CardContent(
|
||||
type: CardType.character,
|
||||
front: RichContent.plain('Β β'),
|
||||
back: RichContent.empty(),
|
||||
meanings: const ['v'],
|
||||
),
|
||||
writing,
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
expect(writtenByHand(word('食べる'), const StudyOptions()), isFalse);
|
||||
});
|
||||
}
|
||||
|
|
@ -768,12 +768,13 @@ void main() {
|
|||
'japanese',
|
||||
CardContent(
|
||||
type: CardType.character,
|
||||
front: paragraph('😀'),
|
||||
// A Han character of Unicode's Extension B, which KanjiVG lacks.
|
||||
front: paragraph('𠀀'),
|
||||
back: RichContent.empty(),
|
||||
meanings: const ['grin'],
|
||||
meanings: const ['breath'],
|
||||
),
|
||||
);
|
||||
await study(tester, strokes: await loadedStrokes(tester, ['😀']));
|
||||
await study(tester, strokes: await loadedStrokes(tester, ['𠀀']));
|
||||
await tester.tap(find.text('Show answer'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Stroke order'));
|
||||
|
|
@ -875,6 +876,35 @@ void main() {
|
|||
expect(find.byType(RatingRow), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets("a Chinese word's pinyin is typed: tone numbers turn into "
|
||||
'marks, and the tones count', (tester) async {
|
||||
await cards.create(
|
||||
'japanese',
|
||||
CardContent(
|
||||
type: CardType.vocabulary,
|
||||
front: paragraph('学习'),
|
||||
back: RichContent.empty(),
|
||||
reading: 'xué xí',
|
||||
meanings: const ['to learn'],
|
||||
),
|
||||
);
|
||||
final settings = SettingsRepository(settingsGateway);
|
||||
addTearDown(settings.dispose);
|
||||
await settings.update(
|
||||
(each) => each.withStudy(const StudyOptions(typeReadings: true)),
|
||||
);
|
||||
await study(tester);
|
||||
|
||||
expect(find.text('The pinyin, with tone numbers or marks'), findsOneWidget);
|
||||
await tester.enterText(find.byType(TextField), 'xue2xi2');
|
||||
await tester.pump();
|
||||
expect(find.text('xuéxí'), findsOneWidget);
|
||||
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Right'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('a reading typed right says so', (tester) async {
|
||||
await cards.create(
|
||||
'japanese',
|
||||
|
|
|
|||
|
|
@ -61,6 +61,82 @@ const wiktionaryDe = Dictionary(
|
|||
entryCount: 4,
|
||||
);
|
||||
|
||||
/// Chinese words of CC-CEDICT in simplified characters.
|
||||
const ccCedictHans = Dictionary(
|
||||
source: 'cc-cedict-hans',
|
||||
sourceVersion: '2026-10-14',
|
||||
kind: DictionaryKind.words,
|
||||
language: 'zh-Hans',
|
||||
glossLanguage: 'en',
|
||||
license: 'CC-BY-SA-4.0',
|
||||
credits: [
|
||||
(
|
||||
name: 'CC-CEDICT',
|
||||
by: 'MDBG',
|
||||
license: 'CC-BY-SA-4.0',
|
||||
url: 'https://www.mdbg.net/chinese/dictionary?page=cc-cedict',
|
||||
),
|
||||
],
|
||||
entryCount: 0,
|
||||
);
|
||||
|
||||
/// Chinese characters of Unihan in simplified writing.
|
||||
const unihanHans = Dictionary(
|
||||
source: 'unihan-hans',
|
||||
sourceVersion: '18.0.0',
|
||||
kind: DictionaryKind.characters,
|
||||
language: 'zh-Hans',
|
||||
glossLanguage: 'en',
|
||||
license: 'Unicode-3.0',
|
||||
credits: [
|
||||
(
|
||||
name: 'Unihan Database',
|
||||
by: 'Unicode, Inc.',
|
||||
license: 'Unicode-3.0',
|
||||
url: 'https://www.unicode.org/reports/tr38/',
|
||||
),
|
||||
],
|
||||
entryCount: 1,
|
||||
);
|
||||
|
||||
/// Greek words with English meanings from Wiktionary.
|
||||
const wiktionaryEl = Dictionary(
|
||||
source: 'wiktionary-el',
|
||||
sourceVersion: '2026-10-03',
|
||||
kind: DictionaryKind.words,
|
||||
language: 'el',
|
||||
glossLanguage: 'en',
|
||||
license: 'CC-BY-SA-4.0',
|
||||
credits: [
|
||||
(
|
||||
name: 'Wiktionary',
|
||||
by: 'Wiktionary contributors',
|
||||
license: 'CC-BY-SA-4.0',
|
||||
url: 'https://en.wiktionary.org/wiki/Wiktionary:Copyrights',
|
||||
),
|
||||
],
|
||||
entryCount: 0,
|
||||
);
|
||||
|
||||
/// The Greek alphabet the curator writes.
|
||||
const greekAlphabet = Dictionary(
|
||||
source: 'greek-alphabet',
|
||||
sourceVersion: '1',
|
||||
kind: DictionaryKind.characters,
|
||||
language: 'el',
|
||||
glossLanguage: 'en',
|
||||
license: 'CC0-1.0',
|
||||
credits: [
|
||||
(
|
||||
name: 'Alphabets (Hangul, Greek)',
|
||||
by: 'Halkyon Learn contributors',
|
||||
license: 'CC0-1.0',
|
||||
url: 'https://code.halkyon.app/project-halkyon/halkyon_learn',
|
||||
),
|
||||
],
|
||||
entryCount: 1,
|
||||
);
|
||||
|
||||
/// A German word of Wiktionary: [headword], its part of speech [pos] in
|
||||
/// full, meaning [glosses], its [genders] and the [forms] that find it.
|
||||
DictionaryWord germanWord(
|
||||
|
|
@ -104,7 +180,8 @@ DictionaryWord word(
|
|||
);
|
||||
|
||||
/// A KANJIDIC2 character: [headword] meaning [meanings], read [on] and
|
||||
/// [kun], with [labels]; a kana with its [romaji].
|
||||
/// [kun], with [labels]; a kana with its [romaji]; or a character [of]
|
||||
/// another dictionary of characters.
|
||||
DictionaryCharacter character(
|
||||
String headword, {
|
||||
List<String> meanings = const [],
|
||||
|
|
@ -112,11 +189,15 @@ DictionaryCharacter character(
|
|||
List<String> kun = const [],
|
||||
List<String> labels = const [],
|
||||
String? romaji,
|
||||
String? name,
|
||||
int? grade,
|
||||
int? strokes,
|
||||
String? version,
|
||||
Dictionary of = kanjidic,
|
||||
}) => DictionaryCharacter(
|
||||
ref: (source: 'kanjidic', id: headword),
|
||||
ref: (source: of.source, id: headword),
|
||||
name: name,
|
||||
language: of.language,
|
||||
headword: headword,
|
||||
labels: labels,
|
||||
meanings: meanings,
|
||||
|
|
|
|||
Loading…
Reference in a new issue