Refactor of Dictionary Management
The entire pathway from BIN data to card generation has been refactored for better maintainability and better logical separation.
This commit is contained in:
parent
e996940789
commit
b9bc96a451
|
@ -2,3 +2,5 @@
|
|||
/.idea
|
||||
/build.sh
|
||||
.DS_Store
|
||||
/wordlist.txt
|
||||
/*.apkg
|
||||
|
|
|
@ -87,22 +87,6 @@ version = "0.4.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "474a626a67200bd107d44179bb3d4fc61891172d11696609264589be6a0e6a43"
|
||||
|
||||
[[package]]
|
||||
name = "binscrape"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"csv",
|
||||
"genanki-rs",
|
||||
"rand 0.8.4",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"select",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.5.2"
|
||||
|
@ -277,6 +261,27 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "directories-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.28"
|
||||
|
@ -621,6 +626,26 @@ version = "2.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
||||
|
||||
[[package]]
|
||||
name = "is-anki-gen"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"csv",
|
||||
"directories-next",
|
||||
"genanki-rs",
|
||||
"rand 0.8.4",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"select",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
|
@ -1127,6 +1152,16 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom 0.2.3",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "binscrape"
|
||||
name = "is-anki-gen"
|
||||
version = "0.1.0"
|
||||
authors = ["Seth Morabito <web@loomcom.com>"]
|
||||
edition = "2018"
|
||||
|
@ -7,6 +7,7 @@ edition = "2018"
|
|||
[dependencies]
|
||||
clap = "2"
|
||||
csv = "1.1"
|
||||
directories-next = "2.0"
|
||||
genanki-rs = "0.1"
|
||||
rand = "0.8"
|
||||
regex = "1.5"
|
||||
|
@ -14,4 +15,7 @@ reqwest = "0.11"
|
|||
select = "0.6.0-alpha.1"
|
||||
serde_json = "1.0"
|
||||
serde = "1.0"
|
||||
tokio = { version = "1.6", features = ["full"] }
|
||||
tempfile = "3.2"
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1.6", features = ["full"] }
|
||||
zip = "0.5"
|
61
README.md
61
README.md
|
@ -1,4 +1,4 @@
|
|||
# BÍN Scraper
|
||||
# Icelandic Anki Deck Generator
|
||||
|
||||
BÍN (Beygingarlýsing íslensks nútímamáls) is an online database of
|
||||
Icelandic grammatical forms. It contains full declensions and
|
||||
|
@ -7,51 +7,42 @@ utility can compile Anki flash cards based on this data. It is very
|
|||
much a work in progress, and probably only useful for myself at the
|
||||
moment.
|
||||
|
||||
This program requires the raw *Sigrúnarsnið* format data from BÍN to
|
||||
work. The data is available as a CSV file from the following page:
|
||||
|
||||
https://bin.arnastofnun.is/gogn/mimisbrunnur/
|
||||
|
||||
The program can automatically download and uncompress the correct file
|
||||
on initial run.
|
||||
|
||||
## Usage
|
||||
|
||||
USAGE:
|
||||
binscrape [OPTIONS] <wordlist> --bindata <FILE> --category <CATEGORY> --deck <FILE>
|
||||
|
||||
is-anki-gen [OPTIONS] <wordlist>
|
||||
|
||||
FLAGS:
|
||||
-h, --help Prints help information
|
||||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-b, --bindata <FILE> BÍN CSV File
|
||||
--category <CATEGORY> Wordlist file category ('nouns' or 'adjectives')
|
||||
-d, --deck <FILE> Anki Deck output file
|
||||
--deck-id <ID> Optional numeric ID for the generated Anki deck
|
||||
--model-id <ID> Optional numeric ID for the generated Anki model
|
||||
|
||||
--binurl <URL> URL to fetch BÍN CSV [default:
|
||||
https://bin.arnastofnun.is/django/api/nidurhal/?file=SHsnid.csv.zip]
|
||||
-d, --deck <FILE> Anki Deck output file [default: deck.apkg]
|
||||
--deck-id <ID> Optional numeric ID for the generated Anki deck
|
||||
|
||||
ARGS:
|
||||
<wordlist> List of words and definitions, tab separated, one per line
|
||||
<wordlist> List of words and categories, tab separated, one per line
|
||||
|
||||
This program requires the raw *Sigrúnarsnið* format data from BÍN to work.
|
||||
The data is available as a CSV file from the following page:
|
||||
The optional argument `--deck-id` can be used to set the Anki ID on
|
||||
the generated deck. If not supplied, a random ID based on the current
|
||||
timestamp will be used.
|
||||
|
||||
https://bin.arnastofnun.is/gogn/mimisbrunnur/
|
||||
|
||||
Download the file named `SHsnid.csv.zip`, and unzip it. When running
|
||||
binscraper, use the `-c` or `--csvfile` argument to point at the unzipped
|
||||
`SHsnid.csv` file.
|
||||
|
||||
Example wordlist files can be found in the `sample-data` directory. To test:
|
||||
|
||||
binscrape --bindata SHsnid.csv --deck noun.apkg \
|
||||
--category nouns sample-data/nouns.csv
|
||||
|
||||
binscrape --bindata SHsnid.csv --deck adj.apkg \
|
||||
--category adjectives sample-data/adjectives.csv
|
||||
|
||||
The optional arguments `--deck-id` and `--model-id` can be used to set IDs on the
|
||||
generated deck and model. If not supplied, random IDs based on the current
|
||||
timestamp will be used.
|
||||
|
||||
Anki uses these IDs in its internal database to keep track of what decks contain what
|
||||
cards, so they really do have to be unique. Setting IDs for your own decks rather than
|
||||
using random IDs is the preferred way, because you can regenerate decks at any time
|
||||
after adding more words to the word list, and only the new words will be imported
|
||||
into Anki on the next import.
|
||||
Anki uses these IDs in its internal database to keep track of what
|
||||
decks contain what cards, so they really do have to be unique. Setting
|
||||
IDs for your own decks rather than using random IDs is the preferred
|
||||
way, because you can regenerate decks at any time after adding more
|
||||
words to the word list, and only the new words will be imported into
|
||||
Anki on the next import.
|
||||
|
||||
# Links
|
||||
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
alþjóðlegur "{""translations"":[{""meaning"":""international"",""usage"":null}]}"
|
||||
appelsínugulur "{""translations"":[{""meaning"":""orange, orange-colored/(UK) coloured"",""usage"":null}]}"
|
||||
auðveldur "{""translations"":[{""meaning"":""easy, simple"",""usage"":null}]}"
|
||||
bjartur "{""translations"":[{""meaning"":""bright, clear, shining"",""usage"":null}]}"
|
||||
bleikur "{""translations"":[{""meaning"":""pink, pale"",""usage"":null}]}"
|
||||
blár "{""translations"":[{""meaning"":""blue"",""usage"":null},{""meaning"":""unadulterated, pure"",""usage"":""eintómur""},{""meaning"":""be unaffected, natural"",""usage"":null}]}"
|
||||
brúnn "{""translations"":[{""meaning"":""brown"",""usage"":null}]}"
|
||||
dapur "{""translations"":[{""meaning"":""sad, depressed"",""usage"":""hryggur""},{""meaning"":""poor, inadequate"",""usage"":""lélegur""}]}"
|
||||
dimmur "{""translations"":[{""meaning"":""dark"",""usage"":""myrkur""},{""meaning"":""deep"",""usage"":""um rödd""},{""meaning"":""grave"",""usage"":""í málfr""}]}"
|
||||
duglegur "{""translations"":[{""meaning"":""energetic, hard-working, efficient"",""usage"":null}]}"
|
||||
erfiður "{""translations"":[{""meaning"":""difficult, hard"",""usage"":""torveldur""},{""meaning"":""wearying, fatiguing"",""usage"":""þreytandi""},{""meaning"":""troublesome"",""usage"":""ódæll""},{""meaning"":""stiff-necked, unwielding"",""usage"":""ósveigjanlegur""}]}"
|
||||
fallegur "{""translations"":[{""meaning"":""beautiful"",""usage"":null}]}"
|
||||
fjólublár "{""translations"":[{""meaning"":""violet"",""usage"":null}]}"
|
||||
fjölbreyttur "{""translations"":[{""meaning"":""varied, many-sided"",""usage"":null}]}"
|
||||
flestur "{""translations"":[{""meaning"":""many, a lot"",""usage"":""um mergð""},{""meaning"":""much, many things"",""usage"":""um mörg atriði""}]}"
|
||||
frekur "{""translations"":[{""meaning"":""pushy, forward"",""usage"":null}]}"
|
||||
frábær "{""translations"":[{""meaning"":""distinguished, excellent"",""usage"":null}]}"
|
||||
frægur "{""translations"":[{""meaning"":""famous"",""usage"":null}]}"
|
||||
fróður "{""translations"":[{""meaning"":""knowledgeable, learned, erudite, well-read"",""usage"":null}]}"
|
||||
fyndinn "{""translations"":[{""meaning"":""witty, funny"",""usage"":null}]}"
|
||||
félagslyndur "{""translations"":[{""meaning"":""sociable, gregarious"",""usage"":null}]}"
|
||||
gamall "{""translations"":[{""meaning"":""old, ancient"",""usage"":null}]}"
|
||||
glaður "{""translations"":[{""meaning"":""glad, happy, cheerful"",""usage"":""kátur""},{""meaning"":""bright"",""usage"":""bjartur""}]}"
|
||||
glæsilegur "{""translations"":[{""meaning"":""splendid, magnificent, elegant"",""usage"":null}]}"
|
||||
grár "{""translations"":[{""meaning"":""grey"",""usage"":null},{""meaning"":""white horse"",""usage"":null},{""meaning"":""deal harshly with sby"",""usage"":null}]}"
|
||||
grænn "{""translations"":[{""meaning"":""green"",""usage"":null}]}"
|
||||
gulur "{""translations"":[{""meaning"":""yellow"",""usage"":null}]}"
|
||||
gáfaður "{""translations"":[{""meaning"":""intelligent"",""usage"":null}]}"
|
||||
hamingjusamur "{""translations"":[{""meaning"":""happy"",""usage"":null}]}"
|
||||
heimsfrægur "{""translations"":[{""meaning"":""world-famous"",""usage"":null}]}"
|
||||
heimskur "{""translations"":[{""meaning"":""stupid"",""usage"":null}]}"
|
||||
heitur "{""translations"":[{""meaning"":""hot, warm"",""usage"":null}]}"
|
||||
hlýr "{""translations"":[{""meaning"":""warm"",""usage"":null}]}"
|
||||
hreinn "{""translations"":[{""meaning"":""clean"",""usage"":null},{""meaning"":""pure"",""usage"":""óblandaður""},{""meaning"":""it is not completely clear"",""usage"":null}]}"
|
||||
hress "{""translations"":[{""meaning"":""fit, well"",""usage"":""heilsugóður""},{""meaning"":""in high spirits, in good form"",""usage"":""kátur""}]}"
|
||||
hvítur "{""translations"":[{""meaning"":""white"",""usage"":null}]}"
|
||||
hæfileikaríkur "{""translations"":[{""meaning"":""talented"",""usage"":null}]}"
|
||||
hægur "{""translations"":[{""meaning"":""easy, convenient"",""usage"":""auðveldur""},{""meaning"":""possible"",""usage"":""mögulegur""},{""meaning"":""calm, quiet, slow"",""usage"":""stilltur""}]}"
|
||||
kaldur "{""translations"":[{""meaning"":""cold"",""usage"":null}]}"
|
||||
kveðinn "{""translations"":[{""meaning"":""say"",""usage"":""segja""},{""meaning"":""compose"",""usage"":""yrkja""},{""meaning"":""chant, intone"",""usage"":""syngja""},{""meaning"":""say of oneself"",""usage"":null},{""meaning"":""lay down, pronounce"",""usage"":""phrases""}]}"
|
||||
kvíðinn "{""translations"":[{""meaning"":""fearful, anxious, apprehensive"",""usage"":null}]}"
|
||||
kátur "{""translations"":[{""meaning"":""cheerful, merry, jolly"",""usage"":null}]}"
|
||||
latur "{""translations"":[{""meaning"":""lazy"",""usage"":null}]}"
|
||||
leiðinlegur "{""translations"":[{""meaning"":""dull, boring, tedious"",""usage"":""þreytandi""},{""meaning"":""sad"",""usage"":""sorglegur""}]}"
|
||||
ljótur "{""translations"":[{""meaning"":""ugly"",""usage"":""ófagur""},{""meaning"":""bad"",""usage"":""slæmur""}]}"
|
||||
léttur "{""translations"":[{""meaning"":""light"",""usage"":""ekki þungur""},{""meaning"":""easy, light"",""usage"":""ekki erfiður""},{""meaning"":""light, nimble"",""usage"":""léttfær""},{""meaning"":""cheerful, merry"",""usage"":""glaður""}]}"
|
||||
lítill "{""translations"":[{""meaning"":""small, short"",""usage"":""smár""},{""meaning"":""little, insignificant"",""usage"":""óverulegur""},{""meaning"":""short"",""usage"":""um tíma""},{""meaning"":""less than average"",""usage"":null},{""meaning"":""at least"",""usage"":null}]}"
|
||||
margur "{""translations"":[{""meaning"":""many, a lot"",""usage"":""um mergð""},{""meaning"":""much, many things"",""usage"":""um mörg atriði""}]}"
|
||||
nógur "{""translations"":[{""meaning"":""enough, sufficient, satisfactory"",""usage"":null}]}"
|
||||
nýlegur "{""translations"":[{""meaning"":""almost new, recent"",""usage"":null}]}"
|
||||
nýr "{""translations"":[{""meaning"":""new, fresh"",""usage"":null}]}"
|
||||
rauður "{""translations"":[{""meaning"":""red"",""usage"":null}]}"
|
||||
rólegur "{""translations"":[{""meaning"":""calm, quiet, tranquil"",""usage"":""stilltur""},{""meaning"":""slow"",""usage"":""hægur""}]}"
|
||||
saddur "{""translations"":[{""meaning"":""full, replete"",""usage"":null}]}"
|
||||
skemmtilegur "{""translations"":[{""meaning"":""amusing, funny"",""usage"":""fyndinn""},{""meaning"":""entertaining, diverting"",""usage"":""sem veitir skemmtun""},{""meaning"":""interesting"",""usage"":""forvitnilegur""}]}"
|
||||
skýr "{""translations"":[{""meaning"":""clear, distinct"",""usage"":""greinilegur""},{""meaning"":""lucid, readily-intelligible"",""usage"":""auðskilinn""},{""meaning"":""sharp, quick, intelligent"",""usage"":""greindur""}]}"
|
||||
sorglegur "{""translations"":[{""meaning"":""tragic, sad"",""usage"":""harmrænn""},{""meaning"":""sad, distressed"",""usage"":""ókátur""}]}"
|
||||
spennandi "{""translations"":[{""meaning"":""thrilling, exciting"",""usage"":null}]}"
|
||||
spenntur "{""translations"":[{""meaning"":""expectant, eager, anxious"",""usage"":""eftirvæntingarfullur""},{""meaning"":""tense, nervous, keyed up"",""usage"":""taugastrekktur""},{""meaning"":""be keen on sth, be excited about sth"",""usage"":null}]}"
|
||||
stórkostlegur "{""translations"":[{""meaning"":""great, magnificent, splendid"",""usage"":null}]}"
|
||||
svangur "{""translations"":[{""meaning"":""hungry"",""usage"":null}]}"
|
||||
svartur "{""translations"":[{""meaning"":""black"",""usage"":null}]}"
|
||||
svolítill "{""translations"":[{""meaning"":""small, little"",""usage"":""lítill""},{""meaning"":""a little"",""usage"":""dálítið""}]}"
|
||||
sérstakur "{""translations"":[{""meaning"":""separate"",""usage"":""einn sér""},{""meaning"":""particular"",""usage"":""frábrugðinn""},{""meaning"":""special, unusual"",""usage"":""óvenjulegur""}]}"
|
||||
tilbúinn "{""translations"":[{""meaning"":""ready"",""usage"":""reiðubúinn""},{""meaning"":""prepared"",""usage"":""viðbúinn""},{""meaning"":""fictional, fictitious"",""usage"":""upploginn""},{""meaning"":""ready-made"",""usage"":""fyrirframgerður""},{""meaning"":""artificial"",""usage"":""unninn af mönnum""}]}"
|
||||
ungur "{""translations"":[{""meaning"":""young"",""usage"":null}]}"
|
||||
vinsæll "{""translations"":[{""meaning"":""popular"",""usage"":null}]}"
|
||||
vondur "{""translations"":[{""meaning"":""bad, evil"",""usage"":""illur""},{""meaning"":""angry, mad"",""usage"":""reiður""},{""meaning"":""poor, bad, in bad shape"",""usage"":""lélegur""},{""meaning"":""he is a very bad man"",""usage"":null}]}"
|
||||
yndislegur "{""translations"":[{""meaning"":""wonderful, marvellous"",""usage"":null}]}"
|
||||
áhugasamur "{""translations"":[{""meaning"":""interested, keen"",""usage"":null}]}"
|
||||
ánægjulegur "{""translations"":[{""meaning"":""enjoyable, pleasant, delightful"",""usage"":null}]}"
|
||||
ótrúlegur "{""translations"":[{""meaning"":""unbelievable"",""usage"":null}]}"
|
||||
óvinsæll "{""translations"":[{""meaning"":""unpopular, disliked"",""usage"":null}]}"
|
||||
óþekktur "{""translations"":[{""meaning"":""unknown"",""usage"":null}]}"
|
||||
örugglega "{""translations"":[{""meaning"":""certainly, definitely"",""usage"":""áreiðanlega""},{""meaning"":""with assurance, securely"",""usage"":""af öryggi""}]}"
|
||||
þreyttur "{""translations"":[{""meaning"":""tired, exhausted, fatigued"",""usage"":null}]}"
|
||||
þröngur "{""translations"":[{""meaning"":""crowded, confined"",""usage"":""rúmlítill""},{""meaning"":""narrow"",""usage"":""krappur""},{""meaning"":""difficult"",""usage"":""erfiður""},{""meaning"":""close-fitting"",""usage"":""aðskorinn""}]}"
|
||||
þunglyndur "{""translations"":[{""meaning"":""sad, melancholy, depressed"",""usage"":null}]}"
|
||||
þyrstur "{""translations"":[{""meaning"":""thirsty"",""usage"":null}]}"
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,155 +0,0 @@
|
|||
afmælisveisla "{""translations"":[{""meaning"":""birthday party"",""usage"":null}]}"
|
||||
anddyri "{""translations"":[{""meaning"":""entrance, vestibule"",""usage"":null}]}"
|
||||
aðalhlutverk "{""translations"":[{""meaning"":""main role"",""usage"":null}]}"
|
||||
belti "{""translations"":[{""meaning"":""belt"",""usage"":""mittisól""},{""meaning"":""zone"",""usage"":""svæði""},{""meaning"":""caterpillar tread"",""usage"":""keðja""}]}"
|
||||
birta "{""translations"":[{""meaning"":""light, brightness"",""usage"":null}]}"
|
||||
blaðagrein "{""translations"":[{""meaning"":""newspaper article"",""usage"":null}]}"
|
||||
borg "{""translations"":[{""meaning"":""city, town"",""usage"":""bær""},{""meaning"":""castle"",""usage"":""kastali""},{""meaning"":""rocky hill"",""usage"":""klettahæð""},{""meaning"":""shelter"",""usage"":""byrgi""}]}"
|
||||
borð "{""translations"":[{""meaning"":""table, desk"",""usage"":""plata á fótum""},{""meaning"":""plank, board"",""usage"":""planki""},{""meaning"":""go aboard, go on board"",""usage"":""skipshlið""},{""meaning"":""of the same caliber/(UK) calibre as sby"",""usage"":""phrases""}]}"
|
||||
bróðir "{""translations"":[{""meaning"":""brother"",""usage"":null}]}"
|
||||
bíll "{""translations"":[{""meaning"":""car, automobile"",""usage"":null}]}"
|
||||
bíó "{""translations"":[{""meaning"":""movie theater, (UK) cinema"",""usage"":null}]}"
|
||||
bíómynd "{""translations"":[{""meaning"":""film"",""usage"":null}]}"
|
||||
bók "{""translations"":[{""meaning"":""book"",""usage"":null}]}"
|
||||
bókmenntafræði "{""translations"":[{""meaning"":""literary studies, literature"",""usage"":null}]}"
|
||||
dagblað "{""translations"":[{""meaning"":""daily (news)paper, daily"",""usage"":null}]}"
|
||||
dagur "{""translations"":[{""meaning"":""day"",""usage"":null}]}"
|
||||
dalur "{""translations"":[{""meaning"":""valley, dale"",""usage"":""lægð""},{""meaning"":""dollar"",""usage"":""mynt""}]}"
|
||||
diskur "{""translations"":[{""meaning"":""plate"",""usage"":null},{""meaning"":""disk/disc"",""usage"":""í tölvu""}]}"
|
||||
dót "{""translations"":[{""meaning"":""luggage, things"",""usage"":""farangur""},{""meaning"":""toys"",""usage"":""leikföng""},{""meaning"":""rabble"",""usage"":""hyski""}]}"
|
||||
eignarfall "{""translations"":[{""meaning"":""genitive, possessive case"",""usage"":null}]}"
|
||||
fangelsi "{""translations"":[{""meaning"":""prison"",""usage"":null}]}"
|
||||
farangur "{""translations"":[{""meaning"":""luggage, baggage"",""usage"":null}]}"
|
||||
ferð "{""translations"":[{""meaning"":""trip, journey"",""usage"":""för""},{""meaning"":""speed"",""usage"":""hraði""}]}"
|
||||
fjall "{""translations"":[{""meaning"":""mountain"",""usage"":null}]}"
|
||||
forrit "{""translations"":[{""meaning"":""program, (UK) programme"",""usage"":""tölvu~""},{""meaning"":""exemplar"",""usage"":""heimild, sem skrifað er eftir""}]}"
|
||||
forritari "{""translations"":[]}"
|
||||
framtíð "{""translations"":[{""meaning"":""future"",""usage"":null},{""meaning"":""future tense"",""usage"":""í málfr""}]}"
|
||||
frelsishetja "{""translations"":[{""meaning"":""frredom champion"",""usage"":null}]}"
|
||||
gaman "{""translations"":[{""meaning"":""fun, enjoyment"",""usage"":null}]}"
|
||||
gangstétt "{""translations"":[{""meaning"":""sidewalk, (UK) pavement"",""usage"":null}]}"
|
||||
gata "{""translations"":[{""meaning"":""street, way, path"",""usage"":null}]}"
|
||||
geisladiskur "{""translations"":[{""meaning"":""compact disc, CD"",""usage"":null}]}"
|
||||
grein "{""translations"":[{""meaning"":""branch, bough"",""usage"":""á tré""},{""meaning"":""subject, field, speciality, specialty"",""usage"":""fag""},{""meaning"":""article"",""usage"":""blaða~""},{""meaning"":""paragraph"",""usage"":""laga~""},{""meaning"":""point"",""usage"":""atriði""},{""meaning"":""consideration"",""usage"":""athugun""}]}"
|
||||
greiða "{""translations"":[{""meaning"":""pay"",""usage"":""borga""},{""meaning"":""comb"",""usage"":null}]}"
|
||||
gönguferð "{""translations"":[{""meaning"":""walk, hike"",""usage"":null}]}"
|
||||
handklæði "{""translations"":[{""meaning"":""towel"",""usage"":null}]}"
|
||||
handrit "{""translations"":[{""meaning"":""manuscript"",""usage"":null}]}"
|
||||
hangikjöt "{""translations"":[{""meaning"":""smoked meat (esp lamb)"",""usage"":null}]}"
|
||||
haust "{""translations"":[{""meaning"":""fall, (UK) autumn"",""usage"":null}]}"
|
||||
herbergi "{""translations"":[{""meaning"":""room"",""usage"":null}]}"
|
||||
hestur "{""translations"":[{""meaning"":""horse"",""usage"":null}]}"
|
||||
hlutur "{""translations"":[{""meaning"":""thing, object"",""usage"":""gripur""},{""meaning"":""part, share"",""usage"":""hluti""}]}"
|
||||
hlutverk "{""translations"":[{""meaning"":""task"",""usage"":""verkefni""},{""meaning"":""mission, role"",""usage"":""ætlunarverk""}]}"
|
||||
hreinleiki "{""translations"":[{""meaning"":""purity"",""usage"":null}]}"
|
||||
hálstafla "{""translations"":[]}"
|
||||
hár "{""translations"":[{""meaning"":""hair"",""usage"":null}]}"
|
||||
hárþurrka "{""translations"":[{""meaning"":""dryer"",""usage"":null}]}"
|
||||
hörkuvinna "{""translations"":[{""meaning"":""(extremely) hard work"",""usage"":null}]}"
|
||||
hús "{""translations"":[{""meaning"":""house, home"",""usage"":null}]}"
|
||||
innsetning "{""translations"":[{""meaning"":""installation (as a work of art)"",""usage"":null}]}"
|
||||
kennari "{""translations"":[{""meaning"":""teacher"",""usage"":null}]}"
|
||||
kongur "{""translations"":[{""meaning"":""king"",""usage"":null}]}"
|
||||
kort "{""translations"":[{""meaning"":""map"",""usage"":""landa~""},{""meaning"":""postcard, card"",""usage"":""bréfspjald""}]}"
|
||||
króna "{""translations"":[{""meaning"":""króna, krone, crown (Icelandic unit of currency = 100 aurar)"",""usage"":""peningur""},{""meaning"":""tree-top, crown of a tree"",""usage"":""trjátoppur""}]}"
|
||||
kvikmynd "{""translations"":[{""meaning"":""film, movie"",""usage"":null}]}"
|
||||
kvöldmatur "{""translations"":[{""meaning"":""supper, dinner"",""usage"":null}]}"
|
||||
kyrrð "{""translations"":[{""meaning"":""silence, stillness"",""usage"":""þögn""},{""meaning"":""peace and quiet"",""usage"":""ró""}]}"
|
||||
kóramót "{""translations"":[]}"
|
||||
leikstjóri "{""translations"":[{""meaning"":""director (of a film, play)"",""usage"":null}]}"
|
||||
leiðsögumaður "{""translations"":[{""meaning"":""guide, travel guide"",""usage"":null}]}"
|
||||
listamaður "{""translations"":[{""meaning"":""artist"",""usage"":null}]}"
|
||||
listasafn "{""translations"":[{""meaning"":""art museum"",""usage"":null}]}"
|
||||
listaverk "{""translations"":[{""meaning"":""work of art"",""usage"":null}]}"
|
||||
listfræðingur "{""translations"":[{""meaning"":""art historian"",""usage"":null}]}"
|
||||
litur "{""translations"":[{""meaning"":""color, (UK) colour, hue"",""usage"":""farfi""},{""meaning"":""dye, coloring, (UK) colouring"",""usage"":""litarefni""},{""meaning"":""crayon"",""usage"":""vaxlitur o.s.frv.""},{""meaning"":""suit (in cards)"",""usage"":""í spilum""},{""meaning"":""show interest in sth"",""usage"":null}]}"
|
||||
líf "{""translations"":[{""meaning"":""life"",""usage"":null}]}"
|
||||
lýsingarorð "{""translations"":[{""meaning"":""adjective"",""usage"":null}]}"
|
||||
mappa "{""translations"":[{""meaning"":""folder, file"",""usage"":null}]}"
|
||||
matur "{""translations"":[{""meaning"":""food"",""usage"":null},{""meaning"":""he knows how to cash in on everything"",""usage"":null}]}"
|
||||
maður "{""translations"":[{""meaning"":""person, human being, individual"",""usage"":""manneskja""},{""meaning"":""man"",""usage"":""karlmaður""},{""meaning"":""man!"",""usage"":""óformlegt ávarp""},{""meaning"":""husband"",""usage"":""eiginmaður""},{""meaning"":""piece (in chess)"",""usage"":""í skák""},{""meaning"":""one, you"",""usage"":""fornafn""}]}"
|
||||
meistari "{""translations"":[{""meaning"":""master, maestro (in music)"",""usage"":null}]}"
|
||||
mikill "{""translations"":[{""meaning"":""large, big"",""usage"":""stór""},{""meaning"":""much"",""usage"":""um magn""},{""meaning"":""great"",""usage"":""stórkostlegur""}]}"
|
||||
miðbær "{""translations"":[{""meaning"":""city center, downtown area, (UK) city centre"",""usage"":null}]}"
|
||||
miði "{""translations"":[{""meaning"":""slip of paper, note"",""usage"":""seðill""},{""meaning"":""ticket"",""usage"":""aðgöngumiði""}]}"
|
||||
mynd "{""translations"":[{""meaning"":""shape, form"",""usage"":""lögun""},{""meaning"":""photo(graph), picture, snapshot"",""usage"":""ljósmynd""},{""meaning"":""movie, (UK) film"",""usage"":""bíómynd""},{""meaning"":""painting, picture"",""usage"":""málverk""},{""meaning"":""illustration"",""usage"":""myndskreyting""},{""meaning"":""figure, diagram"",""usage"":""skýringarmynd""},{""meaning"":""voice (in grammar)"",""usage"":""í málfr""},{""meaning"":""image (metaphor, etc)"",""usage"":""í skáldskap""},{""meaning"":""this is poorly done"",""usage"":""phrases""}]}"
|
||||
málverk "{""translations"":[{""meaning"":""painting"",""usage"":null}]}"
|
||||
mót "{""translations"":[{""meaning"":""meeting, gathering"",""usage"":""samkoma""},{""meaning"":""tournament, meet"",""usage"":""keppni""},{""meaning"":""mould, form"",""usage"":""form""},{""meaning"":""joint"",""usage"":""samskeyti""},{""meaning"":""in many different ways"",""usage"":""phrases""}]}"
|
||||
nafnorð "{""translations"":[{""meaning"":""noun, substantive"",""usage"":null}]}"
|
||||
nammi "{""translations"":[{""meaning"":""candy, (UK) sweets (baby talk for sth good to eat as in‘yummy, yummy')"",""usage"":null}]}"
|
||||
nefnifall "{""translations"":[{""meaning"":""nominative, nominative case"",""usage"":null}]}"
|
||||
nemandi "{""translations"":[{""meaning"":""student, pupil"",""usage"":null}]}"
|
||||
nóta "{""translations"":[{""meaning"":""note"",""usage"":""í músík""},{""meaning"":""bill"",""usage"":""reikningur""},{""meaning"":""receipt"",""usage"":""kvittun""},{""meaning"":""comment, note"",""usage"":""athugasemd""},{""meaning"":""be with it, know what is going on"",""usage"":null}]}"
|
||||
ostur "{""translations"":[{""meaning"":""cheese"",""usage"":null}]}"
|
||||
persóna "{""translations"":[{""meaning"":""person"",""usage"":""einstaklingur""},{""meaning"":""personality"",""usage"":""persónuleiki""},{""meaning"":""character"",""usage"":""~~ í skáldverki""}]}"
|
||||
peysa "{""translations"":[{""meaning"":""sweater, (UK) jersey"",""usage"":""ullarpeysa""},{""meaning"":""blouse (of the woman's Icelandic national costume)"",""usage"":""peysufatapeysa""}]}"
|
||||
piltur "{""translations"":[{""meaning"":""boy, young man"",""usage"":null}]}"
|
||||
popp "{""translations"":[{""meaning"":""pop music"",""usage"":""tónlist""},{""meaning"":""popcorn"",""usage"":""poppkorn""}]}"
|
||||
pottur "{""translations"":[{""meaning"":""pot"",""usage"":""ílát""},{""meaning"":""liter, (UK) litre"",""usage"":""mál""},{""meaning"":""chamber pot"",""usage"":""koppur""},{""meaning"":""pot, pool (of money)"",""usage"":""sjóður""},{""meaning"":""hot pool (small extra pool like a hot spring alongside a swimming pool)"",""usage"":""heitur pottur""},{""meaning"":""sth is well/badly prepared"",""usage"":""phrases""}]}"
|
||||
rós "{""translations"":[{""meaning"":""rose"",""usage"":null}]}"
|
||||
rúm "{""translations"":[{""meaning"":""bed"",""usage"":""rekkja""},{""meaning"":""area, space"",""usage"":""svæði""}]}"
|
||||
rúta "{""translations"":[{""meaning"":""coach, bus"",""usage"":""bíll""},{""meaning"":""route"",""usage"":""leið""}]}"
|
||||
safn "{""translations"":[{""meaning"":""collection"",""usage"":null},{""meaning"":""museum"",""usage"":""stofnun""},{""meaning"":""flock of sheep"",""usage"":""fjárhópur""}]}"
|
||||
sagnorð "{""translations"":[{""meaning"":""verb"",""usage"":null}]}"
|
||||
samband "{""translations"":[{""meaning"":""connection, contact"",""usage"":""tengsl""},{""meaning"":""relationship"",""usage"":""~~ fólks""},{""meaning"":""union, federation"",""usage"":""bandalag""}]}"
|
||||
samloka "{""translations"":[{""meaning"":""sandwich"",""usage"":""brauðsneiðar""},{""meaning"":""shellfish"",""usage"":""skelfiskur""},{""meaning"":""they are inseparable"",""usage"":null}]}"
|
||||
samúð "{""translations"":[{""meaning"":""sympathy, compassion"",""usage"":null}]}"
|
||||
sjampó "{""translations"":[{""meaning"":""shampoo"",""usage"":null}]}"
|
||||
skinka "{""translations"":[{""meaning"":""ham, smoked pork"",""usage"":null}]}"
|
||||
skógur "{""translations"":[{""meaning"":""forest, wood"",""usage"":null}]}"
|
||||
skór "{""translations"":[{""meaning"":""shoe"",""usage"":null}]}"
|
||||
sonur "{""translations"":[{""meaning"":""son"",""usage"":null}]}"
|
||||
spjall "{""translations"":[{""meaning"":""conversation, chat"",""usage"":null}]}"
|
||||
steinn "{""translations"":[{""meaning"":""stone"",""usage"":null}]}"
|
||||
stelpa "{""translations"":[{""meaning"":""girl"",""usage"":null}]}"
|
||||
stjórnandi "{""translations"":[{""meaning"":""leader"",""usage"":""foringi""},{""meaning"":""conductor"",""usage"":""hljómsveitarstjóri""},{""meaning"":""directors, the management"",""usage"":null}]}"
|
||||
stjórnmálamaður "{""translations"":[{""meaning"":""politician"",""usage"":null}]}"
|
||||
strákur "{""translations"":[{""meaning"":""boy"",""usage"":null}]}"
|
||||
stytta "{""translations"":[{""meaning"":""statue"",""usage"":null}]}"
|
||||
stærðfræði "{""translations"":[{""meaning"":""math, mathematics"",""usage"":null}]}"
|
||||
stóll "{""translations"":[{""meaning"":""chair"",""usage"":null}]}"
|
||||
sumar "{""translations"":[{""meaning"":""summer"",""usage"":null}]}"
|
||||
sundbolur "{""translations"":[{""meaning"":""swimsuit"",""usage"":null}]}"
|
||||
sundföt "{""translations"":[{""meaning"":""bathing suit"",""usage"":null}]}"
|
||||
sundgleraugu "{""translations"":[]}"
|
||||
sundskýla "{""translations"":[{""meaning"":""swimming trunks"",""usage"":null}]}"
|
||||
svefnpoki "{""translations"":[{""meaning"":""sleeping bag"",""usage"":null}]}"
|
||||
svæði "{""translations"":[{""meaning"":""area, zone"",""usage"":null}]}"
|
||||
systkini "{""translations"":[{""meaning"":""brothers and sisters, siblings"",""usage"":null}]}"
|
||||
sápa "{""translations"":[{""meaning"":""soap"",""usage"":null}]}"
|
||||
sími "{""translations"":[{""meaning"":""telephone"",""usage"":null}]}"
|
||||
sólarolía "{""translations"":[{""meaning"":""suntan oil/lotion"",""usage"":null}]}"
|
||||
sólbekkur "{""translations"":[{""meaning"":""window sill"",""usage"":null}]}"
|
||||
söguþráður "{""translations"":[{""meaning"":""plot"",""usage"":null}]}"
|
||||
söngkona "{""translations"":[{""meaning"":""singer (female)"",""usage"":null}]}"
|
||||
söngvari "{""translations"":[{""meaning"":""singer"",""usage"":null}]}"
|
||||
súpa "{""translations"":[{""meaning"":""soup"",""usage"":null}]}"
|
||||
taska "{""translations"":[{""meaning"":""suitcase"",""usage"":""ferða~""},{""meaning"":""bag, handbag"",""usage"":""hand~""},{""meaning"":""briefcase, case, attaché case"",""usage"":""skjala~""},{""meaning"":""satchel"",""usage"":""skóla~""}]}"
|
||||
torg "{""translations"":[{""meaning"":""(city) square"",""usage"":null}]}"
|
||||
tækifæri "{""translations"":[{""meaning"":""opportunity"",""usage"":null}]}"
|
||||
tónlist "{""translations"":[{""meaning"":""music"",""usage"":null}]}"
|
||||
tónlistarmaður "{""translations"":[{""meaning"":""musician"",""usage"":""hljóðfæraleikari""},{""meaning"":""composer"",""usage"":""tónskáld""}]}"
|
||||
tölva "{""translations"":[{""meaning"":""computer"",""usage"":null}]}"
|
||||
tölvupóstur "{""translations"":[{""meaning"":""e-mail"",""usage"":null}]}"
|
||||
undantekning "{""translations"":[{""meaning"":""exception"",""usage"":null}]}"
|
||||
upplýsing "{""translations"":[{""meaning"":""information"",""usage"":null},{""meaning"":""Enlightenment"",""usage"":""fræðslustefna""},{""meaning"":""illumination, lighting"",""usage"":""það að lýsa upp""}]}"
|
||||
uppáhald "{""translations"":[{""meaning"":""pet, favorite, (UK) favourite"",""usage"":null}]}"
|
||||
vatn "{""translations"":[{""meaning"":""water"",""usage"":""lögur""},{""meaning"":""lake"",""usage"":""stöðu~""},{""meaning"":""they could not keep back their tears, they could not contain themselves"",""usage"":""phrases""}]}"
|
||||
vefsíða "{""translations"":[{""meaning"":""web page"",""usage"":null}]}"
|
||||
veitingahús "{""translations"":[{""meaning"":""restaurant"",""usage"":null}]}"
|
||||
veitingastaður "{""translations"":[]}"
|
||||
verkefni "{""translations"":[{""meaning"":""task, assignment, project"",""usage"":null}]}"
|
||||
verðlaun "{""translations"":[{""meaning"":""prize, award"",""usage"":""sigurlaun""},{""meaning"":""reward"",""usage"":""laun""}]}"
|
||||
vetur "{""translations"":[{""meaning"":""winter"",""usage"":null}]}"
|
||||
vina "{""translations"":[{""meaning"":""girl friend"",""usage"":null}]}"
|
||||
vinur "{""translations"":[{""meaning"":""friend"",""usage"":null}]}"
|
||||
vor "{""translations"":[{""meaning"":""spring"",""usage"":null}]}"
|
||||
vél "{""translations"":[{""meaning"":""motor, engine"",""usage"":""hreyfill""},{""meaning"":""machine"",""usage"":""tæki""}]}"
|
||||
á "{""translations"":[{""meaning"":""river, stream"",""usage"":null}]}"
|
||||
áhorfandi "{""translations"":[{""meaning"":""spectator, onlooker"",""usage"":null}]}"
|
||||
æfing "{""translations"":[{""meaning"":""training, practice"",""usage"":""þjálfun""},{""meaning"":""exercise, drill"",""usage"":""þjálfunarverkefni""},{""meaning"":""rehearsal"",""usage"":""~ leikrits""},{""meaning"":""go to a training session"",""usage"":null}]}"
|
||||
öld "{""translations"":[{""meaning"":""age"",""usage"":""tímabil""},{""meaning"":""century"",""usage"":""hundrað ár""},{""meaning"":""from time immemorial"",""usage"":""phrases""}]}"
|
||||
þjóðlistasafn "{""translations"":[]}"
|
||||
þjóðminjasafn "{""translations"":[{""meaning"":""national museum"",""usage"":null}]}"
|
||||
þolfall "{""translations"":[{""meaning"":""accusative (case)"",""usage"":null}]}"
|
||||
þágufall "{""translations"":[{""meaning"":""dative"",""usage"":null}]}"
|
|
|
@ -0,0 +1,234 @@
|
|||
afmælisveisla noun
|
||||
anddyri noun
|
||||
aðalhlutverk noun
|
||||
belti noun
|
||||
birta noun
|
||||
blaðagrein noun
|
||||
borg noun
|
||||
borð noun
|
||||
bróðir noun
|
||||
bíll noun
|
||||
bíó noun
|
||||
bíómynd noun
|
||||
bók noun
|
||||
bókmenntafræði noun
|
||||
dagblað noun
|
||||
dagur noun
|
||||
dalur noun
|
||||
diskur noun
|
||||
dót noun
|
||||
eignarfall noun
|
||||
fangelsi noun
|
||||
farangur noun
|
||||
ferð noun
|
||||
fjall noun
|
||||
forrit noun
|
||||
forritari noun
|
||||
framtíð noun
|
||||
frelsishetja noun
|
||||
gaman noun
|
||||
gangstétt noun
|
||||
gata noun
|
||||
geisladiskur noun
|
||||
grein noun
|
||||
greiða noun
|
||||
gönguferð noun
|
||||
handklæði noun
|
||||
handrit noun
|
||||
hangikjöt noun
|
||||
haust noun
|
||||
herbergi noun
|
||||
hestur noun
|
||||
hlutur noun
|
||||
hlutverk noun
|
||||
hreinleiki noun
|
||||
hálstafla noun
|
||||
hár noun
|
||||
hárþurrka noun
|
||||
hörkuvinna noun
|
||||
hús noun
|
||||
innsetning noun
|
||||
kennari noun
|
||||
kongur noun
|
||||
kort noun
|
||||
króna noun
|
||||
kvikmynd noun
|
||||
kvöldmatur noun
|
||||
kyrrð noun
|
||||
kóramót noun
|
||||
leikstjóri noun
|
||||
leiðsögumaður noun
|
||||
listamaður noun
|
||||
listasafn noun
|
||||
listaverk noun
|
||||
listfræðingur noun
|
||||
litur noun
|
||||
líf noun
|
||||
lýsingarorð noun
|
||||
mappa noun
|
||||
matur noun
|
||||
maður noun
|
||||
meistari noun
|
||||
mikill noun
|
||||
miðbær noun
|
||||
miði noun
|
||||
mynd noun
|
||||
málverk noun
|
||||
mót noun
|
||||
nafnorð noun
|
||||
nammi noun
|
||||
nefnifall noun
|
||||
nemandi noun
|
||||
nóta noun
|
||||
ostur noun
|
||||
persóna noun
|
||||
peysa noun
|
||||
piltur noun
|
||||
popp noun
|
||||
pottur noun
|
||||
rós noun
|
||||
rúm noun
|
||||
rúta noun
|
||||
safn noun
|
||||
sagnorð noun
|
||||
samband noun
|
||||
samloka noun
|
||||
samúð noun
|
||||
sjampó noun
|
||||
skinka noun
|
||||
skógur noun
|
||||
skór noun
|
||||
sonur noun
|
||||
spjall noun
|
||||
steinn noun
|
||||
stelpa noun
|
||||
stjórnandi noun
|
||||
stjórnmálamaður noun
|
||||
strákur noun
|
||||
stytta noun
|
||||
stærðfræði noun
|
||||
stóll noun
|
||||
sumar noun
|
||||
sundbolur noun
|
||||
sundföt noun
|
||||
sundgleraugu noun
|
||||
sundskýla noun
|
||||
svefnpoki noun
|
||||
svæði noun
|
||||
systkini noun
|
||||
sápa noun
|
||||
sími noun
|
||||
sólarolía noun
|
||||
sólbekkur noun
|
||||
söguþráður noun
|
||||
söngkona noun
|
||||
söngvari noun
|
||||
súpa noun
|
||||
taska noun
|
||||
torg noun
|
||||
tækifæri noun
|
||||
tónlist noun
|
||||
tónlistarmaður noun
|
||||
tölva noun
|
||||
tölvupóstur noun
|
||||
undantekning noun
|
||||
upplýsing noun
|
||||
uppáhald noun
|
||||
vatn noun
|
||||
vefsíða noun
|
||||
veitingahús noun
|
||||
veitingastaður noun
|
||||
verkefni noun
|
||||
verðlaun noun
|
||||
vetur noun
|
||||
vina noun
|
||||
vinur noun
|
||||
vor noun
|
||||
vél noun
|
||||
á noun
|
||||
áhorfandi noun
|
||||
æfing noun
|
||||
öld noun
|
||||
þjóðlistasafn noun
|
||||
þjóðminjasafn noun
|
||||
þolfall noun
|
||||
þágufall noun
|
||||
alþjóðlegur adjective
|
||||
appelsínugulur adjective
|
||||
auðveldur adjective
|
||||
bjartur adjective
|
||||
bleikur adjective
|
||||
blár adjective
|
||||
brúnn adjective
|
||||
dapur adjective
|
||||
dimmur adjective
|
||||
duglegur adjective
|
||||
erfiður adjective
|
||||
fallegur adjective
|
||||
fjólublár adjective
|
||||
fjölbreyttur adjective
|
||||
flestur adjective
|
||||
frekur adjective
|
||||
frábær adjective
|
||||
frægur adjective
|
||||
fróður adjective
|
||||
fyndinn adjective
|
||||
félagslyndur adjective
|
||||
gamall adjective
|
||||
glaður adjective
|
||||
glæsilegur adjective
|
||||
grár adjective
|
||||
grænn adjective
|
||||
gulur adjective
|
||||
gáfaður adjective
|
||||
hamingjusamur adjective
|
||||
heimsfrægur adjective
|
||||
heimskur adjective
|
||||
heitur adjective
|
||||
hlýr adjective
|
||||
hreinn adjective
|
||||
hress adjective
|
||||
hvítur adjective
|
||||
hæfileikaríkur adjective
|
||||
hægur adjective
|
||||
kaldur adjective
|
||||
kveðinn adjective
|
||||
kvíðinn adjective
|
||||
kátur adjective
|
||||
latur adjective
|
||||
leiðinlegur adjective
|
||||
ljótur adjective
|
||||
léttur adjective
|
||||
lítill adjective
|
||||
margur adjective
|
||||
nógur adjective
|
||||
nýlegur adjective
|
||||
nýr adjective
|
||||
rauður adjective
|
||||
rólegur adjective
|
||||
saddur adjective
|
||||
skemmtilegur adjective
|
||||
skýr adjective
|
||||
sorglegur adjective
|
||||
spennandi adjective
|
||||
spenntur adjective
|
||||
stórkostlegur adjective
|
||||
svangur adjective
|
||||
svartur adjective
|
||||
svolítill adjective
|
||||
sérstakur adjective
|
||||
tilbúinn adjective
|
||||
ungur adjective
|
||||
vinsæll adjective
|
||||
vondur adjective
|
||||
yndislegur adjective
|
||||
áhugasamur adjective
|
||||
ánægjulegur adjective
|
||||
ótrúlegur adjective
|
||||
óvinsæll adjective
|
||||
óþekktur adjective
|
||||
örugglega adjective
|
||||
þreyttur adjective
|
||||
þröngur adjective
|
||||
þunglyndur adjective
|
||||
þyrstur adjective
|
|
@ -0,0 +1,698 @@
|
|||
use crate::ProgramError;
|
||||
use csv::ReaderBuilder;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io::Read;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct BinEntry {
|
||||
pub id: u64,
|
||||
pub word_class: String,
|
||||
pub classification: String,
|
||||
pub form: String,
|
||||
pub tag: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum Gender {
|
||||
Masculine,
|
||||
Feminine,
|
||||
Neuter,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct NounEntry {
|
||||
pub gender: Gender,
|
||||
pub nom_sg: Option<String>,
|
||||
pub acc_sg: Option<String>,
|
||||
pub dat_sg: Option<String>,
|
||||
pub gen_sg: Option<String>,
|
||||
pub nom_pl: Option<String>,
|
||||
pub acc_pl: Option<String>,
|
||||
pub dat_pl: Option<String>,
|
||||
pub gen_pl: Option<String>,
|
||||
pub nom_sg_def: Option<String>,
|
||||
pub acc_sg_def: Option<String>,
|
||||
pub dat_sg_def: Option<String>,
|
||||
pub gen_sg_def: Option<String>,
|
||||
pub nom_pl_def: Option<String>,
|
||||
pub acc_pl_def: Option<String>,
|
||||
pub dat_pl_def: Option<String>,
|
||||
pub gen_pl_def: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct AdjectiveEntry {
|
||||
pub masc_nom_sg_strong: Option<String>,
|
||||
pub masc_acc_sg_strong: Option<String>,
|
||||
pub masc_dat_sg_strong: Option<String>,
|
||||
pub masc_gen_sg_strong: Option<String>,
|
||||
pub fem_nom_sg_strong: Option<String>,
|
||||
pub fem_acc_sg_strong: Option<String>,
|
||||
pub fem_dat_sg_strong: Option<String>,
|
||||
pub fem_gen_sg_strong: Option<String>,
|
||||
pub neut_nom_sg_strong: Option<String>,
|
||||
pub neut_acc_sg_strong: Option<String>,
|
||||
pub neut_dat_sg_strong: Option<String>,
|
||||
pub neut_gen_sg_strong: Option<String>,
|
||||
pub masc_nom_pl_strong: Option<String>,
|
||||
pub masc_acc_pl_strong: Option<String>,
|
||||
pub masc_dat_pl_strong: Option<String>,
|
||||
pub masc_gen_pl_strong: Option<String>,
|
||||
pub fem_nom_pl_strong: Option<String>,
|
||||
pub fem_acc_pl_strong: Option<String>,
|
||||
pub fem_dat_pl_strong: Option<String>,
|
||||
pub fem_gen_pl_strong: Option<String>,
|
||||
pub neut_nom_pl_strong: Option<String>,
|
||||
pub neut_acc_pl_strong: Option<String>,
|
||||
pub neut_dat_pl_strong: Option<String>,
|
||||
pub neut_gen_pl_strong: Option<String>,
|
||||
pub masc_nom_sg_weak: Option<String>,
|
||||
pub masc_acc_sg_weak: Option<String>,
|
||||
pub masc_dat_sg_weak: Option<String>,
|
||||
pub masc_gen_sg_weak: Option<String>,
|
||||
pub fem_nom_sg_weak: Option<String>,
|
||||
pub fem_acc_sg_weak: Option<String>,
|
||||
pub fem_dat_sg_weak: Option<String>,
|
||||
pub fem_gen_sg_weak: Option<String>,
|
||||
pub neut_nom_sg_weak: Option<String>,
|
||||
pub neut_acc_sg_weak: Option<String>,
|
||||
pub neut_dat_sg_weak: Option<String>,
|
||||
pub neut_gen_sg_weak: Option<String>,
|
||||
pub masc_nom_pl_weak: Option<String>,
|
||||
pub masc_acc_pl_weak: Option<String>,
|
||||
pub masc_dat_pl_weak: Option<String>,
|
||||
pub masc_gen_pl_weak: Option<String>,
|
||||
pub fem_nom_pl_weak: Option<String>,
|
||||
pub fem_acc_pl_weak: Option<String>,
|
||||
pub fem_dat_pl_weak: Option<String>,
|
||||
pub fem_gen_pl_weak: Option<String>,
|
||||
pub neut_nom_pl_weak: Option<String>,
|
||||
pub neut_acc_pl_weak: Option<String>,
|
||||
pub neut_dat_pl_weak: Option<String>,
|
||||
pub neut_gen_pl_weak: Option<String>,
|
||||
}
|
||||
|
||||
pub struct BinData {
|
||||
pub data: BTreeMap<String, Vec<BinEntry>>,
|
||||
}
|
||||
|
||||
impl BinData {
|
||||
pub fn load<T>(reader: T) -> Result<Box<Self>, ProgramError>
|
||||
where
|
||||
T: Read,
|
||||
{
|
||||
let mut bin_data = Box::new(BinData { data: BTreeMap::new() });
|
||||
|
||||
let mut db_reader =
|
||||
ReaderBuilder::new().has_headers(false).delimiter(b';').from_reader(reader);
|
||||
|
||||
for result in db_reader.records() {
|
||||
let record = result?;
|
||||
|
||||
let lemma = record.get(0).unwrap().to_string();
|
||||
let id = record.get(1).unwrap().parse::<u64>().unwrap();
|
||||
let word_class = record.get(2).unwrap().to_string();
|
||||
let classification = record.get(3).unwrap().to_string();
|
||||
let form = record.get(4).unwrap().to_string();
|
||||
let tag = record.get(5).unwrap().to_string();
|
||||
|
||||
let entry = bin_data.data.entry(lemma).or_insert_with(Vec::new);
|
||||
entry.push(BinEntry { id, word_class, classification, form, tag });
|
||||
}
|
||||
|
||||
Ok(bin_data)
|
||||
}
|
||||
|
||||
pub fn adjective(&self, root: &str) -> Option<AdjectiveEntry> {
|
||||
let entries = self.data.get(root);
|
||||
|
||||
match entries {
|
||||
Some(entries) => {
|
||||
let entries =
|
||||
entries.iter().filter(|&e| is_adjective(e)).collect::<Vec<&BinEntry>>();
|
||||
|
||||
if entries.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(AdjectiveEntry {
|
||||
masc_nom_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_acc_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_dat_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_gen_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_nom_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_acc_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_dat_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_gen_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_nom_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_acc_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_dat_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_gen_sg_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_nom_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_acc_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_dat_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_gen_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KK-EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_nom_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_acc_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_dat_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_gen_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-KVK-EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_nom_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_acc_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_dat_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_gen_pl_strong: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FSB-HK-EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_nom_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_acc_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_dat_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_gen_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_nom_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_acc_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_dat_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_gen_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_nom_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_acc_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_dat_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_gen_sg_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_nom_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_acc_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_dat_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
masc_gen_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KK-EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_nom_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_acc_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_dat_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
fem_gen_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-KVK-EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_nom_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_acc_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_dat_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
neut_gen_pl_weak: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "FVB-HK-EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn noun(&self, root: &str) -> Option<NounEntry> {
|
||||
let entries = self.data.get(root);
|
||||
|
||||
match entries {
|
||||
Some(entries) => {
|
||||
let entries = entries.iter().filter(|&f| is_noun(f)).collect::<Vec<&BinEntry>>();
|
||||
|
||||
if entries.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let gender = entries.first().unwrap().word_class.as_str();
|
||||
Some(NounEntry {
|
||||
gender: match gender {
|
||||
"kvk" => Gender::Feminine,
|
||||
"hk" => Gender::Neuter,
|
||||
_ => Gender::Masculine,
|
||||
},
|
||||
nom_sg: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "NFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
acc_sg: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
dat_sg: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞGFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
gen_sg: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "EFET")
|
||||
.map(|&e| e.form.to_string()),
|
||||
nom_pl: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "NFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
acc_pl: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
dat_pl: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞGFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
gen_pl: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "EFFT")
|
||||
.map(|&e| e.form.to_string()),
|
||||
nom_sg_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "NFETgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
acc_sg_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞFETgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
dat_sg_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞGFETgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
gen_sg_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "EFETgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
nom_pl_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "NFFTgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
acc_pl_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞFFTgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
dat_pl_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "ÞGFFTgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
gen_pl_def: entries
|
||||
.iter()
|
||||
.find(|&&e| e.tag == "EFFTgr")
|
||||
.map(|&e| e.form.to_string()),
|
||||
})
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_adjective(entry: &BinEntry) -> bool {
|
||||
entry.word_class == "lo"
|
||||
}
|
||||
|
||||
fn is_noun(entry: &BinEntry) -> bool {
|
||||
entry.word_class == "kk" || entry.word_class == "kvk" || entry.word_class == "hk"
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const TEST_DATA: &str = "aðalhellir;74631;kk;alm;aðalhellir;NFET
|
||||
aðalhellir;74631;kk;alm;aðalhellirinn;NFETgr
|
||||
aðalhellir;74631;kk;alm;aðalhelli;ÞFET
|
||||
aðalhellir;74631;kk;alm;aðalhellinn;ÞFETgr
|
||||
aðalhellir;74631;kk;alm;aðalhelli;ÞGFET
|
||||
aðalhellir;74631;kk;alm;aðalhellinum;ÞGFETgr
|
||||
aðalhellir;74631;kk;alm;aðalhellis;EFET
|
||||
aðalhellir;74631;kk;alm;aðalhellisins;EFETgr
|
||||
aðalhellir;74631;kk;alm;aðalhellar;NFFT
|
||||
aðalhellir;74631;kk;alm;aðalhellarnir;NFFTgr
|
||||
aðalhellir;74631;kk;alm;aðalhella;ÞFFT
|
||||
aðalhellir;74631;kk;alm;aðalhellana;ÞFFTgr
|
||||
aðalhellir;74631;kk;alm;aðalhellum;ÞGFFT
|
||||
aðalhellir;74631;kk;alm;aðalhellunum;ÞGFFTgr
|
||||
aðalhellir;74631;kk;alm;aðalhella;EFFT
|
||||
aðalhellir;74631;kk;alm;aðalhellanna;EFFTgr
|
||||
aðalhenda;153961;kvk;alm;aðalhenda;NFET
|
||||
aðalhenda;153961;kvk;alm;aðalhendan;NFETgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendu;ÞFET
|
||||
aðalhenda;153961;kvk;alm;aðalhenduna;ÞFETgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendu;ÞGFET
|
||||
aðalhenda;153961;kvk;alm;aðalhendunni;ÞGFETgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendu;EFET
|
||||
aðalhenda;153961;kvk;alm;aðalhendunnar;EFETgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendur;NFFT
|
||||
aðalhenda;153961;kvk;alm;aðalhendurnar;NFFTgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendur;ÞFFT
|
||||
aðalhenda;153961;kvk;alm;aðalhendurnar;ÞFFTgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendum;ÞGFFT
|
||||
aðalhenda;153961;kvk;alm;aðalhendunum;ÞGFFTgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendna;EFFT
|
||||
aðalhenda;153961;kvk;alm;aðalhenda;EFFT2
|
||||
aðalhenda;153961;kvk;alm;aðalhendnanna;EFFTgr
|
||||
aðalhenda;153961;kvk;alm;aðalhendanna;EFFTgr2
|
||||
fallegur;168136;lo;alm;fallegur;FSB-KK-NFET
|
||||
fallegur;168136;lo;alm;fallegan;FSB-KK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegum;FSB-KK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegs;FSB-KK-EFET
|
||||
fallegur;168136;lo;alm;fallegir;FSB-KK-NFFT
|
||||
fallegur;168136;lo;alm;fallega;FSB-KK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegum;FSB-KK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegra;FSB-KK-EFFT
|
||||
fallegur;168136;lo;alm;falleg;FSB-KVK-NFET
|
||||
fallegur;168136;lo;alm;fallega;FSB-KVK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegri;FSB-KVK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegrar;FSB-KVK-EFET
|
||||
fallegur;168136;lo;alm;fallegar;FSB-KVK-NFFT
|
||||
fallegur;168136;lo;alm;fallegar;FSB-KVK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegum;FSB-KVK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegra;FSB-KVK-EFFT
|
||||
fallegur;168136;lo;alm;fallegt;FSB-HK-NFET
|
||||
fallegur;168136;lo;alm;fallegt;FSB-HK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegu;FSB-HK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegs;FSB-HK-EFET
|
||||
fallegur;168136;lo;alm;falleg;FSB-HK-NFFT
|
||||
fallegur;168136;lo;alm;falleg;FSB-HK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegum;FSB-HK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegra;FSB-HK-EFFT
|
||||
fallegur;168136;lo;alm;fallegi;FVB-KK-NFET
|
||||
fallegur;168136;lo;alm;fallega;FVB-KK-ÞFET
|
||||
fallegur;168136;lo;alm;fallega;FVB-KK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallega;FVB-KK-EFET
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KK-NFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KK-EFFT
|
||||
fallegur;168136;lo;alm;fallega;FVB-KVK-NFET
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-EFET
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-NFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-KVK-EFFT
|
||||
fallegur;168136;lo;alm;fallega;FVB-HK-NFET
|
||||
fallegur;168136;lo;alm;fallega;FVB-HK-ÞFET
|
||||
fallegur;168136;lo;alm;fallega;FVB-HK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallega;FVB-HK-EFET
|
||||
fallegur;168136;lo;alm;fallegu;FVB-HK-NFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-HK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-HK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegu;FVB-HK-EFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-NFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-EFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-NFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KK-EFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-NFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-EFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-NFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-KVK-EFFT
|
||||
fallegur;168136;lo;alm;fallegra;MST-HK-NFET
|
||||
fallegur;168136;lo;alm;fallegra;MST-HK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegra;MST-HK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegra;MST-HK-EFET
|
||||
fallegur;168136;lo;alm;fallegri;MST-HK-NFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-HK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-HK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegri;MST-HK-EFFT
|
||||
fallegur;168136;lo;alm;fallegastur;ESB-KK-NFET
|
||||
fallegur;168136;lo;alm;fallegastan;ESB-KK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegustum;ESB-KK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegasts;ESB-KK-EFET
|
||||
fallegur;168136;lo;alm;fallegastir;ESB-KK-NFFT
|
||||
fallegur;168136;lo;alm;fallegasta;ESB-KK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegustum;ESB-KK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegastra;ESB-KK-EFFT
|
||||
fallegur;168136;lo;alm;fallegust;ESB-KVK-NFET
|
||||
fallegur;168136;lo;alm;fallegasta;ESB-KVK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegastri;ESB-KVK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegastrar;ESB-KVK-EFET
|
||||
fallegur;168136;lo;alm;fallegastar;ESB-KVK-NFFT
|
||||
fallegur;168136;lo;alm;fallegastar;ESB-KVK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegustum;ESB-KVK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegastra;ESB-KVK-EFFT
|
||||
fallegur;168136;lo;alm;fallegast;ESB-HK-NFET
|
||||
fallegur;168136;lo;alm;fallegast;ESB-HK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegustu;ESB-HK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegasts;ESB-HK-EFET
|
||||
fallegur;168136;lo;alm;fallegust;ESB-HK-NFFT
|
||||
fallegur;168136;lo;alm;fallegust;ESB-HK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegustum;ESB-HK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegastra;ESB-HK-EFFT
|
||||
fallegur;168136;lo;alm;fallegasti;EVB-KK-NFET
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-KK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-KK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-KK-EFET
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KK-NFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KK-EFFT
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-KVK-NFET
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-EFET
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-NFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-KVK-EFFT
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-HK-NFET
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-HK-ÞFET
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-HK-ÞGFET
|
||||
fallegur;168136;lo;alm;fallegasta;EVB-HK-EFET
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-HK-NFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-HK-ÞFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-HK-ÞGFFT
|
||||
fallegur;168136;lo;alm;fallegustu;EVB-HK-EFFT";
|
||||
|
||||
#[test]
|
||||
pub fn loads_bin_data() {
|
||||
let bin_data = BinData::load(TEST_DATA.as_bytes()).unwrap();
|
||||
|
||||
assert_eq!(3, bin_data.data.len());
|
||||
|
||||
assert!(bin_data.data.contains_key("aðalhellir"));
|
||||
assert!(bin_data.data.contains_key("aðalhenda"));
|
||||
|
||||
assert_eq!(16, bin_data.data.get("aðalhellir").unwrap().len());
|
||||
assert_eq!(18, bin_data.data.get("aðalhenda").unwrap().len());
|
||||
assert_eq!(120, bin_data.data.get("fallegur").unwrap().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn gets_noun_entry() {
|
||||
let bin_data = BinData::load(TEST_DATA.as_bytes()).unwrap();
|
||||
let noun_entry = bin_data.noun("aðalhenda").unwrap();
|
||||
|
||||
assert_eq!(Gender::Feminine, noun_entry.gender);
|
||||
// Singular
|
||||
assert_eq!("aðalhenda", noun_entry.nom_sg.unwrap());
|
||||
assert_eq!("aðalhendan", noun_entry.nom_sg_def.unwrap());
|
||||
assert_eq!("aðalhendu", noun_entry.acc_sg.unwrap());
|
||||
assert_eq!("aðalhenduna", noun_entry.acc_sg_def.unwrap());
|
||||
assert_eq!("aðalhendu", noun_entry.dat_sg.unwrap());
|
||||
assert_eq!("aðalhendunni", noun_entry.dat_sg_def.unwrap());
|
||||
assert_eq!("aðalhendu", noun_entry.gen_sg.unwrap());
|
||||
assert_eq!("aðalhendunnar", noun_entry.gen_sg_def.unwrap());
|
||||
// Plural
|
||||
assert_eq!("aðalhendur", noun_entry.nom_pl.unwrap());
|
||||
assert_eq!("aðalhendurnar", noun_entry.nom_pl_def.unwrap());
|
||||
assert_eq!("aðalhendur", noun_entry.acc_pl.unwrap());
|
||||
assert_eq!("aðalhendurnar", noun_entry.acc_pl_def.unwrap());
|
||||
assert_eq!("aðalhendum", noun_entry.dat_pl.unwrap());
|
||||
assert_eq!("aðalhendunum", noun_entry.dat_pl_def.unwrap());
|
||||
assert_eq!("aðalhendna", noun_entry.gen_pl.unwrap());
|
||||
assert_eq!("aðalhendnanna", noun_entry.gen_pl_def.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn gets_adjective_entry() {
|
||||
let bin_data = BinData::load(TEST_DATA.as_bytes()).unwrap();
|
||||
let adjective_entry = bin_data.adjective("fallegur").unwrap();
|
||||
|
||||
assert_eq!("fallegur", adjective_entry.masc_nom_sg_strong.unwrap());
|
||||
assert_eq!("fallegan", adjective_entry.masc_acc_sg_strong.unwrap());
|
||||
assert_eq!("fallegum", adjective_entry.masc_dat_sg_strong.unwrap());
|
||||
assert_eq!("fallegs", adjective_entry.masc_gen_sg_strong.unwrap());
|
||||
|
||||
assert_eq!("falleg", adjective_entry.fem_nom_sg_strong.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.fem_acc_sg_strong.unwrap());
|
||||
assert_eq!("fallegri", adjective_entry.fem_dat_sg_strong.unwrap());
|
||||
assert_eq!("fallegrar", adjective_entry.fem_gen_sg_strong.unwrap());
|
||||
|
||||
assert_eq!("fallegt", adjective_entry.neut_nom_sg_strong.unwrap());
|
||||
assert_eq!("fallegt", adjective_entry.neut_acc_sg_strong.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.neut_dat_sg_strong.unwrap());
|
||||
assert_eq!("fallegs", adjective_entry.neut_gen_sg_strong.unwrap());
|
||||
|
||||
assert_eq!("fallegir", adjective_entry.masc_nom_pl_strong.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.masc_acc_pl_strong.unwrap());
|
||||
assert_eq!("fallegum", adjective_entry.masc_dat_pl_strong.unwrap());
|
||||
assert_eq!("fallegra", adjective_entry.masc_gen_pl_strong.unwrap());
|
||||
|
||||
assert_eq!("fallegar", adjective_entry.fem_nom_pl_strong.unwrap());
|
||||
assert_eq!("fallegar", adjective_entry.fem_acc_pl_strong.unwrap());
|
||||
assert_eq!("fallegum", adjective_entry.fem_dat_pl_strong.unwrap());
|
||||
assert_eq!("fallegra", adjective_entry.fem_gen_pl_strong.unwrap());
|
||||
|
||||
assert_eq!("falleg", adjective_entry.neut_nom_pl_strong.unwrap());
|
||||
assert_eq!("falleg", adjective_entry.neut_acc_pl_strong.unwrap());
|
||||
assert_eq!("fallegum", adjective_entry.neut_dat_pl_strong.unwrap());
|
||||
assert_eq!("fallegra", adjective_entry.neut_gen_pl_strong.unwrap());
|
||||
|
||||
assert_eq!("fallegi", adjective_entry.masc_nom_sg_weak.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.masc_acc_sg_weak.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.masc_dat_sg_weak.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.masc_gen_sg_weak.unwrap());
|
||||
|
||||
assert_eq!("fallega", adjective_entry.fem_nom_sg_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.fem_acc_sg_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.fem_dat_sg_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.fem_gen_sg_weak.unwrap());
|
||||
|
||||
assert_eq!("fallega", adjective_entry.neut_nom_sg_weak.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.neut_acc_sg_weak.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.neut_dat_sg_weak.unwrap());
|
||||
assert_eq!("fallega", adjective_entry.neut_gen_sg_weak.unwrap());
|
||||
|
||||
assert_eq!("fallegu", adjective_entry.masc_nom_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.masc_acc_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.masc_dat_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.masc_gen_pl_weak.unwrap());
|
||||
|
||||
assert_eq!("fallegu", adjective_entry.fem_nom_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.fem_acc_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.fem_dat_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.fem_gen_pl_weak.unwrap());
|
||||
|
||||
assert_eq!("fallegu", adjective_entry.neut_nom_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.neut_acc_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.neut_dat_pl_weak.unwrap());
|
||||
assert_eq!("fallegu", adjective_entry.neut_gen_pl_weak.unwrap());
|
||||
}
|
||||
}
|
|
@ -1,25 +1,52 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::time::Duration;
|
||||
|
||||
use genanki_rs::Error;
|
||||
use regex::Regex;
|
||||
use select::document::Document;
|
||||
use select::predicate::{Class, Name, Predicate};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::ProgramError;
|
||||
use csv::ReaderBuilder;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub enum Category {
|
||||
Noun,
|
||||
Adjective,
|
||||
}
|
||||
|
||||
impl FromStr for Category {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"noun" | "nouns" => Ok(Category::Noun),
|
||||
"adjective" | "adjectives" => Ok(Category::Adjective),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct Translation {
|
||||
pub meaning: String,
|
||||
pub usage: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Definition {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct DictionaryEntry {
|
||||
pub category: Category,
|
||||
pub translations: Vec<Translation>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||
pub struct Dictionary {
|
||||
pub entries: BTreeMap<String, DictionaryEntry>,
|
||||
}
|
||||
|
||||
impl Display for Translation {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match &self.usage {
|
||||
|
@ -33,38 +60,102 @@ impl Display for Translation {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for Definition {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match &self.translations.len() {
|
||||
1 => {
|
||||
write!(f, "{}", &self.translations.get(0).unwrap())
|
||||
}
|
||||
_ => {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
&self
|
||||
.translations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, t)| format!("{}. {}", i + 1, t))
|
||||
.collect::<Vec<String>>()
|
||||
.join("; ")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Translation {
|
||||
pub fn new(translation: String, usage: Option<String>) -> Self {
|
||||
Translation { meaning: translation, usage }
|
||||
}
|
||||
}
|
||||
|
||||
impl DictionaryEntry {
|
||||
pub fn definition(&self) -> String {
|
||||
if self.translations.len() == 1 {
|
||||
format!("{}", self.translations.get(0).unwrap())
|
||||
} else {
|
||||
self.translations
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, t)| format!("{}. {}", i + 1, t))
|
||||
.collect::<Vec<String>>()
|
||||
.join("; ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dictionary {
|
||||
pub fn new() -> Self {
|
||||
Dictionary { entries: BTreeMap::new() }
|
||||
}
|
||||
|
||||
/// Retrieve a dictionary from the specified reader.
|
||||
pub fn load<T>(input: T) -> Result<Self, ProgramError>
|
||||
where
|
||||
T: std::io::Read,
|
||||
{
|
||||
Ok(serde_json::from_reader(input)?)
|
||||
}
|
||||
|
||||
/// Store a dictionary to the specified writer.
|
||||
pub fn store<T>(&self, output: &mut T) -> Result<(), ProgramError>
|
||||
where
|
||||
T: std::io::Write,
|
||||
{
|
||||
Ok(serde_json::to_writer_pretty(output, self)?)
|
||||
}
|
||||
|
||||
/// Import a set of words into a dictionary, returning the number of entries added.
|
||||
pub fn import_wordlist<T>(&mut self, wordlist: T) -> Result<usize, ProgramError>
|
||||
where
|
||||
T: std::io::Read,
|
||||
{
|
||||
let mut synced: usize = 0;
|
||||
|
||||
let mut reader = ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.delimiter(b'\t')
|
||||
.flexible(true)
|
||||
.from_reader(wordlist);
|
||||
|
||||
for record in reader.records().flatten() {
|
||||
if let (Some(root), Some(category)) = (record.get(0), record.get(1)) {
|
||||
if !self.entries.contains_key(root) {
|
||||
self.entries.insert(
|
||||
root.to_string(),
|
||||
DictionaryEntry {
|
||||
// TODO: Convert to ProgramError
|
||||
category: Category::from_str(category).unwrap(),
|
||||
translations: vec![],
|
||||
},
|
||||
);
|
||||
synced += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(synced)
|
||||
}
|
||||
|
||||
/// TODO: Testing! How do we test this? It'll be nasty, but we have to.
|
||||
pub async fn update_definitions(&mut self) -> Result<usize, ProgramError> {
|
||||
let client = reqwest::Client::new();
|
||||
let mut updated: usize = 0;
|
||||
|
||||
for (root, entry) in &mut self.entries {
|
||||
if entry.translations.is_empty() {
|
||||
entry.translations.append(&mut search(&client, &root).await?);
|
||||
updated += 1;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(updated)
|
||||
}
|
||||
}
|
||||
|
||||
/// Look up a root word in the Online Icelandic Dictionary and return
|
||||
/// a vector of definitions for the root.
|
||||
pub async fn search(client: &reqwest::Client, word: &str) -> Result<Definition, Error> {
|
||||
pub async fn search(
|
||||
client: &reqwest::Client,
|
||||
word: &str,
|
||||
) -> Result<Vec<Translation>, ProgramError> {
|
||||
println!("Searching Icelandic online dictionary for definitions: {}", word);
|
||||
|
||||
let url = format!("https://digicoll.library.wisc.edu/cgi-bin/IcelOnline/IcelOnline.TEId-idx?type=simple&size=First+100&rgn=lemma&q1={}&submit=Search", word);
|
||||
|
@ -90,10 +181,10 @@ pub async fn search(client: &reqwest::Client, word: &str) -> Result<Definition,
|
|||
.text()
|
||||
.await?;
|
||||
let document = Document::from(res.borrow());
|
||||
Ok(Definition { translations: get_translations(&document) })
|
||||
Ok(get_translations(&document))
|
||||
}
|
||||
|
||||
None => Ok(Definition { translations: get_translations(&document) }),
|
||||
None => Ok(get_translations(&document)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,3 +206,93 @@ fn get_translations(document: &Document) -> Vec<Translation> {
|
|||
.flatten()
|
||||
.collect::<Vec<Translation>>()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn stores_and_loads_dictionary() {
|
||||
let mut serialized = Vec::new();
|
||||
|
||||
let mut stored_dictionary = Dictionary::new();
|
||||
|
||||
stored_dictionary.entries.insert(
|
||||
"foo".to_owned(),
|
||||
DictionaryEntry {
|
||||
category: Category::Adjective,
|
||||
translations: vec![Translation {
|
||||
meaning: "A Word".to_owned(),
|
||||
usage: Some("A Usage".to_owned()),
|
||||
}],
|
||||
},
|
||||
);
|
||||
stored_dictionary.entries.insert(
|
||||
"bar".to_string(),
|
||||
DictionaryEntry {
|
||||
category: Category::Adjective,
|
||||
translations: vec![Translation {
|
||||
meaning: "Another Word".to_string(),
|
||||
usage: None,
|
||||
}],
|
||||
},
|
||||
);
|
||||
|
||||
let _ = stored_dictionary.store(&mut serialized).unwrap();
|
||||
|
||||
let json = std::str::from_utf8(serialized.as_slice()).unwrap().to_string();
|
||||
|
||||
let loaded_dictionary = Dictionary::load(json.as_bytes()).unwrap();
|
||||
|
||||
assert_eq!(loaded_dictionary, stored_dictionary);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn loads_new_words_into_dictionary() {
|
||||
let wordlist = "foo\tnouns\nbar\tadjectives\nbaz\tnouns\nquux\tadjectives".as_bytes();
|
||||
|
||||
let mut dictionary = Dictionary::new();
|
||||
|
||||
assert!(dictionary.entries.is_empty());
|
||||
|
||||
let synced = dictionary.import_wordlist(wordlist).unwrap();
|
||||
assert_eq!(4, synced);
|
||||
assert!(dictionary.entries.contains_key("foo"));
|
||||
assert!(dictionary.entries.contains_key("bar"));
|
||||
assert!(dictionary.entries.contains_key("baz"));
|
||||
assert!(dictionary.entries.contains_key("quux"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn does_not_overwrite_words_in_dictionary() {
|
||||
let wordlist = "foo\tnouns\nbar\tadjectives\nbaz\tnouns\nquux\tadjectives".as_bytes();
|
||||
|
||||
let mut dictionary = Dictionary::new();
|
||||
|
||||
dictionary.entries.insert(
|
||||
"baz".to_owned(),
|
||||
DictionaryEntry {
|
||||
category: Category::Noun,
|
||||
translations: vec![Translation {
|
||||
meaning: "The definition of baz".to_string(),
|
||||
usage: Some("Some Usage".to_string()),
|
||||
}],
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(1, dictionary.entries.len());
|
||||
|
||||
let synced = dictionary.import_wordlist(wordlist).unwrap();
|
||||
// Only three synced out of four
|
||||
assert_eq!(3, synced);
|
||||
assert!(dictionary.entries.contains_key("foo"));
|
||||
assert!(dictionary.entries.contains_key("bar"));
|
||||
assert!(dictionary.entries.contains_key("baz"));
|
||||
assert!(dictionary.entries.contains_key("quux"));
|
||||
|
||||
assert_eq!(
|
||||
"The definition of baz",
|
||||
dictionary.entries.get("baz").unwrap().translations.get(0).unwrap().meaning
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
519
src/main.rs
519
src/main.rs
|
@ -1,15 +1,28 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::time::SystemTime;
|
||||
use std::time::{SystemTime, SystemTimeError};
|
||||
|
||||
use crate::dictionary::Definition;
|
||||
use clap::{arg_enum, value_t, App, Arg};
|
||||
use csv::{ReaderBuilder, WriterBuilder};
|
||||
use genanki_rs::{Deck, Error, Field, Model, Note, Template};
|
||||
use crate::bindata::{BinData, Gender};
|
||||
use crate::dictionary::{Category, Dictionary, DictionaryEntry};
|
||||
use clap::{App, Arg};
|
||||
use directories_next::ProjectDirs;
|
||||
use genanki_rs::{Deck, Field, Model, Note, Template};
|
||||
use rand::prelude::*;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use tempfile::tempfile;
|
||||
use thiserror::Error;
|
||||
use zip::result::ZipError;
|
||||
|
||||
mod bindata;
|
||||
mod dictionary;
|
||||
|
||||
const DEFAULT_BIN_CSV: &str = "SHsnid.csv";
|
||||
const DEFAULT_DECK: &str = "deck.apkg";
|
||||
const BIN_CSV_URL: &str = "https://bin.arnastofnun.is/django/api/nidurhal/?file=SHsnid.csv.zip";
|
||||
const NOUN_MODEL_ID: usize = 1625673414000;
|
||||
const ADJECTIVE_MODEL_ID: usize = 1625673415000;
|
||||
|
||||
const CSS: &str = "\
|
||||
.card {\
|
||||
font-family: arial;\
|
||||
|
@ -45,91 +58,47 @@ const ADJ_TMPL: &str = r#"{{FrontSide}}
|
|||
<hr id="definition">
|
||||
<p>{{Definition}}</p>"#;
|
||||
|
||||
arg_enum! {
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum Category {
|
||||
Nouns,
|
||||
Adjectives,
|
||||
}
|
||||
}
|
||||
|
||||
struct Adjective {
|
||||
definition: Definition,
|
||||
masc_singular: Option<String>,
|
||||
fem_singular: Option<String>,
|
||||
neut_singular: Option<String>,
|
||||
masc_plural: Option<String>,
|
||||
fem_plural: Option<String>,
|
||||
neut_plural: Option<String>,
|
||||
}
|
||||
|
||||
impl Adjective {
|
||||
fn new(definition: Definition) -> Self {
|
||||
Adjective {
|
||||
definition,
|
||||
masc_singular: None,
|
||||
fem_singular: None,
|
||||
neut_singular: None,
|
||||
masc_plural: None,
|
||||
fem_plural: None,
|
||||
neut_plural: None,
|
||||
}
|
||||
}
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ProgramError {
|
||||
#[error("cannot access configuration")]
|
||||
Configuration,
|
||||
#[error("invalid dictionary file")]
|
||||
Dictionary,
|
||||
#[error("io error")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("network error")]
|
||||
Network(#[from] reqwest::Error),
|
||||
#[error("zip error")]
|
||||
Zip(#[from] ZipError),
|
||||
#[error("bin data file does not exist")]
|
||||
BinData,
|
||||
#[error("system time")]
|
||||
SystemTime(#[from] SystemTimeError),
|
||||
#[error("CSV parse failed")]
|
||||
Csv(#[from] csv::Error),
|
||||
#[error("Serialization")]
|
||||
Serialization(#[from] serde_json::Error),
|
||||
#[error("Anki Generation")]
|
||||
Anki(#[from] genanki_rs::Error),
|
||||
}
|
||||
|
||||
/// Return a somewhat, kind-of, more-or-less random ID for an Anki record.
|
||||
fn random_id() -> Result<usize, Error> {
|
||||
fn random_id() -> Result<usize, ProgramError> {
|
||||
let mut rng = thread_rng();
|
||||
let delta: usize = rng.gen_range(0..100);
|
||||
Ok(SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?.as_millis() as usize + delta)
|
||||
}
|
||||
|
||||
async fn read_word_map(file_name: &str) -> BTreeMap<String, Definition> {
|
||||
let client = reqwest::Client::new();
|
||||
let mut result: BTreeMap<String, Definition> = BTreeMap::new();
|
||||
|
||||
if let Ok(mut reader) =
|
||||
ReaderBuilder::new().has_headers(false).delimiter(b'\t').flexible(true).from_path(file_name)
|
||||
{
|
||||
for record in reader.records().flatten() {
|
||||
if let Some(root) = record.get(0) {
|
||||
// TODO: Error Handling
|
||||
let definition = match record.get(1) {
|
||||
Some(json) => serde_json::from_str::<Definition>(json).unwrap(),
|
||||
None => dictionary::search(&client, &root).await.unwrap(),
|
||||
};
|
||||
|
||||
result.insert(root.to_owned(), definition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn update_word_map(file_name: &str, word_map: &BTreeMap<String, Definition>) {
|
||||
if let Ok(mut writer) =
|
||||
WriterBuilder::new().has_headers(false).delimiter(b'\t').from_path(file_name)
|
||||
{
|
||||
word_map.iter().for_each(|(k, v)| {
|
||||
let definition = serde_json::to_string(v).unwrap();
|
||||
let _ = writer.write_record(&[k, &definition]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Build an Anki deck based on adjectives
|
||||
fn adjectives(
|
||||
word_map: &BTreeMap<String, Definition>,
|
||||
csv_file: &str,
|
||||
deck_id: usize,
|
||||
model_id: usize,
|
||||
) -> Result<Deck, Error> {
|
||||
fn generate_deck(
|
||||
dictionary: &Dictionary,
|
||||
bin_data: &BinData,
|
||||
config: &AppConfig,
|
||||
) -> Result<Deck, ProgramError> {
|
||||
let mut deck =
|
||||
Deck::new(deck_id, "Icelandic Adjectives", "Deck for studying Icelandic adjectives");
|
||||
Deck::new(config.deck_id, "Icelandic Vocabulary", "Deck for studying Icelandic Vocabulary");
|
||||
|
||||
let model = Model::new_with_options(
|
||||
model_id,
|
||||
let adjective_model = Model::new_with_options(
|
||||
ADJECTIVE_MODEL_ID,
|
||||
"Icelandic Adjectives",
|
||||
vec![
|
||||
Field::new("MascSg"),
|
||||
|
@ -148,83 +117,19 @@ fn adjectives(
|
|||
None,
|
||||
);
|
||||
|
||||
let mut db_reader =
|
||||
ReaderBuilder::new().has_headers(false).delimiter(b';').from_path(csv_file)?;
|
||||
|
||||
let mut adjective_cards: BTreeMap<String, Adjective> = BTreeMap::new();
|
||||
|
||||
for result in db_reader.records() {
|
||||
let record = result?;
|
||||
let root = record.get(0).unwrap();
|
||||
let key = record.get(2).unwrap();
|
||||
|
||||
if word_map.contains_key(root) && key == "lo" {
|
||||
if !adjective_cards.contains_key(root) {
|
||||
if let Some(definition) = word_map.get(root) {
|
||||
adjective_cards.insert(String::from(root), Adjective::new(definition.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(card) = adjective_cards.get_mut(root) {
|
||||
let form = record.get(5).unwrap();
|
||||
let decl = record.get(4).unwrap().to_owned();
|
||||
|
||||
match form {
|
||||
"FSB-KK-NFET" => card.masc_singular = Some(decl),
|
||||
"FSB-KVK-NFET" => card.fem_singular = Some(decl),
|
||||
"FSB-HK-NFET" => card.neut_singular = Some(decl),
|
||||
"FSB-KK-NFFT" => card.masc_plural = Some(decl),
|
||||
"FSB-KVK-NFFT" => card.fem_plural = Some(decl),
|
||||
"FSB-HK-NFFT" => card.neut_plural = Some(decl),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now map over the adjectives and build cards.
|
||||
for (_, val) in adjective_cards {
|
||||
let note = Note::new(
|
||||
model.clone(),
|
||||
vec![
|
||||
val.masc_singular.unwrap_or_else(String::new).borrow(),
|
||||
val.fem_singular.unwrap_or_else(String::new).borrow(),
|
||||
val.neut_singular.unwrap_or_else(String::new).borrow(),
|
||||
val.masc_plural.unwrap_or_else(String::new).borrow(),
|
||||
val.fem_plural.unwrap_or_else(String::new).borrow(),
|
||||
val.neut_plural.unwrap_or_else(String::new).borrow(),
|
||||
&val.definition.to_string(),
|
||||
],
|
||||
);
|
||||
|
||||
deck.add_note(note.unwrap());
|
||||
}
|
||||
|
||||
Ok(deck)
|
||||
}
|
||||
|
||||
/// Build an Anki deck based on nouns
|
||||
fn nouns(
|
||||
word_map: &BTreeMap<String, Definition>,
|
||||
csv_file: &str,
|
||||
deck_id: usize,
|
||||
model_id: usize,
|
||||
) -> Result<Deck, Error> {
|
||||
let mut deck =
|
||||
Deck::new(deck_id, "Icelandic Noun Plurals", "Deck for studying Icelandic noun plurals");
|
||||
|
||||
let model = Model::new_with_options(
|
||||
model_id,
|
||||
let noun_model = Model::new_with_options(
|
||||
NOUN_MODEL_ID,
|
||||
"Noun Plurals",
|
||||
vec![
|
||||
Field::new("Singular"),
|
||||
Field::new("Plural"),
|
||||
Field::new("NomSg"),
|
||||
Field::new("GenSg"),
|
||||
Field::new("NomPl"),
|
||||
Field::new("Gender"),
|
||||
Field::new("Definition"),
|
||||
],
|
||||
vec![Template::new("Card 1")
|
||||
.qfmt("<h1>{{Singular}}</h1>")
|
||||
.afmt(r#"{{FrontSide}}<hr id="plural"><h2>{{Plural}} ({{Gender}})</h2> <p>{{Definition}}</p>"#)],
|
||||
.qfmt("<h1>{{NomSg}}</h1>")
|
||||
.afmt(r#"{{FrontSide}}<hr id="gender"/><h2>{{Gender}}</h2><hr id="forms"/><h2><em>g. sg.</em> {{GenSg}}, <em>n. pl.</em> {{NomPl}}</h2> <p>{{Definition}}</p>"#)],
|
||||
Some(CSS),
|
||||
None,
|
||||
None,
|
||||
|
@ -232,31 +137,17 @@ fn nouns(
|
|||
None,
|
||||
);
|
||||
|
||||
let mut db_reader =
|
||||
ReaderBuilder::new().has_headers(false).delimiter(b';').from_path(csv_file)?;
|
||||
|
||||
for result in db_reader.records() {
|
||||
let record = result?;
|
||||
let form = record.get(5).unwrap();
|
||||
let class = record.get(3).unwrap();
|
||||
|
||||
if "alm" == class && "NFFT" == form {
|
||||
if let Some(root) = record.get(0) {
|
||||
if word_map.contains_key(root) {
|
||||
let gender = match record.get(2).unwrap() {
|
||||
"kk" => "masc.",
|
||||
"hk" => "neut.",
|
||||
"kvk" => "fem.",
|
||||
_ => "...",
|
||||
};
|
||||
let plural = record.get(4).unwrap();
|
||||
if let Some(definition) = word_map.get(root) {
|
||||
let note = Note::new(
|
||||
model.clone(),
|
||||
vec![root, plural, gender, &definition.to_string()],
|
||||
);
|
||||
deck.add_note(note.unwrap());
|
||||
}
|
||||
for (root, dictionary_entry) in &dictionary.entries {
|
||||
match dictionary_entry.category {
|
||||
Category::Noun => {
|
||||
if let Some(note) = noun(&root, bin_data, &dictionary_entry, &noun_model) {
|
||||
deck.add_note(note)
|
||||
}
|
||||
}
|
||||
Category::Adjective => {
|
||||
if let Some(note) = adjective(&root, bin_data, &dictionary_entry, &adjective_model)
|
||||
{
|
||||
deck.add_note(note)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,19 +156,73 @@ fn nouns(
|
|||
Ok(deck)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let matches = App::new("BÍN Scraper")
|
||||
fn adjective(
|
||||
root: &str,
|
||||
bin_data: &BinData,
|
||||
dictionary_entry: &DictionaryEntry,
|
||||
model: &Model,
|
||||
) -> Option<Note> {
|
||||
match bin_data.adjective(root) {
|
||||
Some(adjective_entry) => Some(
|
||||
Note::new(
|
||||
model.clone(),
|
||||
vec![
|
||||
adjective_entry.masc_nom_sg_strong.unwrap_or("—".to_string()).borrow(),
|
||||
adjective_entry.fem_nom_sg_strong.unwrap_or("—".to_string()).borrow(),
|
||||
adjective_entry.neut_nom_sg_strong.unwrap_or("—".to_string()).borrow(),
|
||||
adjective_entry.masc_nom_pl_strong.unwrap_or("—".to_string()).borrow(),
|
||||
adjective_entry.fem_nom_pl_strong.unwrap_or("—".to_string()).borrow(),
|
||||
adjective_entry.neut_nom_pl_strong.unwrap_or("—".to_string()).borrow(),
|
||||
&dictionary_entry.definition(),
|
||||
],
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn noun(
|
||||
root: &str,
|
||||
bin_data: &BinData,
|
||||
dictionary_entry: &DictionaryEntry,
|
||||
model: &Model,
|
||||
) -> Option<Note> {
|
||||
match bin_data.noun(root) {
|
||||
Some(noun_entry) => Some(
|
||||
Note::new(
|
||||
model.clone(),
|
||||
vec![
|
||||
root,
|
||||
noun_entry.gen_sg.unwrap_or("—".to_string()).borrow(),
|
||||
noun_entry.nom_pl.unwrap_or("—".to_string()).borrow(),
|
||||
match noun_entry.gender {
|
||||
Gender::Masculine => "Masculine",
|
||||
Gender::Feminine => "Feminine",
|
||||
Gender::Neuter => "Neuter",
|
||||
},
|
||||
&dictionary_entry.definition(),
|
||||
],
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Read application config from command line arguments.
|
||||
fn app_config(project_dirs: &ProjectDirs) -> AppConfig {
|
||||
let arg_matches = App::new("Icelandic Anki Flashcard Generator")
|
||||
.version("1.0")
|
||||
.author("Seth Morabito")
|
||||
.arg(
|
||||
Arg::with_name("bindata")
|
||||
.help("BÍN CSV File")
|
||||
.short("b")
|
||||
.long("bindata")
|
||||
.value_name("FILE")
|
||||
Arg::with_name("binurl")
|
||||
.help("URL to fetch BÍN CSV")
|
||||
.long("binurl")
|
||||
.value_name("URL")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
.default_value(BIN_CSV_URL)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("deck")
|
||||
|
@ -285,16 +230,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.short("d")
|
||||
.long("deck")
|
||||
.value_name("FILE")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("category")
|
||||
.help("Wordlist file category ('nouns' or 'adjectives')")
|
||||
.long("category")
|
||||
.value_name("CATEGORY")
|
||||
.takes_value(true)
|
||||
.required(true),
|
||||
.default_value("deck.apkg")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("deck-id")
|
||||
|
@ -304,53 +241,175 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.takes_value(true)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("model-id")
|
||||
.help("Optional numeric ID for the generated Anki model")
|
||||
.long("model-id")
|
||||
.value_name("ID")
|
||||
.takes_value(true)
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("wordlist")
|
||||
.help("List of words and definitions, tab separated, one per line")
|
||||
.help("List of words and categories, tab separated, one per line")
|
||||
.required(true),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let csv_file = matches.value_of("bindata").unwrap();
|
||||
let deck_file = matches.value_of("deck").unwrap();
|
||||
let category: Category = value_t!(matches, "category", Category).unwrap();
|
||||
let input_file = matches.value_of("wordlist").unwrap();
|
||||
let deck_id = match matches.value_of("deck-id") {
|
||||
Some(id) => id.parse::<usize>().unwrap(),
|
||||
None => random_id().unwrap(),
|
||||
let dictionary = project_dirs.data_dir().join("dictionary.json");
|
||||
let bin_data: PathBuf = project_dirs.data_dir().join(DEFAULT_BIN_CSV);
|
||||
|
||||
let bin_csv_url = match arg_matches.value_of("binurl") {
|
||||
Some(binurl) => binurl.to_string(),
|
||||
None => BIN_CSV_URL.to_string(),
|
||||
};
|
||||
let model_id = match matches.value_of("model-id") {
|
||||
|
||||
let deck: String = match arg_matches.value_of("deck") {
|
||||
Some(deck) => deck.to_string(),
|
||||
None => DEFAULT_DECK.to_string(),
|
||||
};
|
||||
|
||||
let wordlist: PathBuf = match arg_matches.value_of("wordlist") {
|
||||
Some(wordlist) => Path::new(wordlist).to_path_buf(),
|
||||
None => Path::new("wordlist.txt").to_path_buf(),
|
||||
};
|
||||
|
||||
let deck_id = match arg_matches.value_of("deck-id") {
|
||||
Some(id) => id.parse::<usize>().unwrap(),
|
||||
None => random_id().unwrap(),
|
||||
};
|
||||
|
||||
println!("Generating Anki deck with id `{}`, model id `{}`.", deck_id, model_id);
|
||||
AppConfig { bin_csv_url, bin_data, dictionary, deck, wordlist, deck_id }
|
||||
}
|
||||
|
||||
println!("Loading {}...", input_file);
|
||||
let word_map = read_word_map(input_file).await;
|
||||
#[derive(Debug)]
|
||||
struct AppConfig {
|
||||
bin_csv_url: String,
|
||||
bin_data: PathBuf,
|
||||
dictionary: PathBuf,
|
||||
deck: String,
|
||||
wordlist: PathBuf,
|
||||
deck_id: usize,
|
||||
}
|
||||
|
||||
// TODO: A builder pattern would probably be nice here.
|
||||
println!("Starting Anki deck generation...");
|
||||
let deck = match category {
|
||||
Category::Nouns => nouns(&word_map, csv_file, deck_id, model_id)?,
|
||||
Category::Adjectives => adjectives(&word_map, csv_file, deck_id, model_id)?,
|
||||
};
|
||||
fn setup_project_dirs(project_dirs: &ProjectDirs) -> Result<(), ProgramError> {
|
||||
let data_dir = project_dirs.data_dir();
|
||||
let config_dir = project_dirs.config_dir();
|
||||
std::fs::create_dir_all(data_dir)?;
|
||||
std::fs::create_dir_all(config_dir)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_bin_csv(app_config: &AppConfig) -> Result<(), ProgramError> {
|
||||
let mut tmp_file = tempfile()?;
|
||||
|
||||
println!("Downloading BIN data from URL {:?}...", &app_config.bin_csv_url);
|
||||
|
||||
let response = reqwest::get(&app_config.bin_csv_url).await?;
|
||||
let content = response.bytes().await?;
|
||||
|
||||
tmp_file.write_all(content.as_ref())?;
|
||||
|
||||
println!("Extracting ZIP file to {:?}...", &app_config.bin_data);
|
||||
|
||||
let mut archive = zip::ZipArchive::new(tmp_file)?;
|
||||
let mut file = archive.by_name(DEFAULT_BIN_CSV)?;
|
||||
let mut outfile = File::create(&app_config.bin_data)?;
|
||||
io::copy(&mut file, &mut outfile)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure that the BIN CSV data file exists locally. If it does not exist,
|
||||
/// it will be downloaded and unzipped automatically.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `config` - The application config.
|
||||
///
|
||||
async fn ensure_bin_data_exists(config: &AppConfig) -> Result<(), ProgramError> {
|
||||
if config.bin_data.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("===============================================================================");
|
||||
println!("The required BIN data file {} does not exist. It can be downloaded", DEFAULT_BIN_CSV);
|
||||
println!("automatically for you, or you may download it and unzip it yourself.");
|
||||
println!();
|
||||
println!("The compressed download is about 35 MB, and the uncompressed file uses about");
|
||||
println!("325 MB of disk space.");
|
||||
println!();
|
||||
println!("This download only needs to occur once. The file will be saved as:");
|
||||
println!(" {:?}", config.bin_data);
|
||||
println!("===============================================================================");
|
||||
println!();
|
||||
print!("Continue with download? [y/N]: ");
|
||||
std::io::stdout().flush()?;
|
||||
let mut input = String::new();
|
||||
let _ = std::io::stdin().read_line(&mut input)?;
|
||||
|
||||
if input.trim().to_ascii_lowercase().starts_with('y') {
|
||||
get_bin_csv(&config).await?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ProgramError::BinData)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), ProgramError> {
|
||||
// Establish directories for holding state
|
||||
match ProjectDirs::from("com", "loomcom", "is-anki-gen") {
|
||||
Some(project_dirs) => {
|
||||
let config = app_config(&project_dirs);
|
||||
|
||||
// If the word list doesn't exist, bail immediately.
|
||||
if !config.wordlist.exists() {
|
||||
println!("Word list file {:?} does not exist.", config.wordlist);
|
||||
return Err(ProgramError::Configuration);
|
||||
}
|
||||
|
||||
setup_project_dirs(&project_dirs)?;
|
||||
|
||||
if let Err(e) = ensure_bin_data_exists(&config).await {
|
||||
match e {
|
||||
ProgramError::BinData => {
|
||||
println!("BIN file not downloaded or found locally.");
|
||||
}
|
||||
_ => {
|
||||
println!("Couldn't download BIN file: {:?}", e);
|
||||
}
|
||||
}
|
||||
println!("Good bye!");
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
let mut dictionary = if config.dictionary.exists() {
|
||||
Dictionary::load(File::open(&config.dictionary)?)?
|
||||
} else {
|
||||
Dictionary::new()
|
||||
};
|
||||
|
||||
println!("Loading word list {:#?}...", config.wordlist);
|
||||
|
||||
let synced = dictionary.import_wordlist(File::open(&config.wordlist)?)?;
|
||||
|
||||
println!("Loaded {} words.", synced);
|
||||
|
||||
let updated = dictionary.update_definitions().await?;
|
||||
|
||||
if updated > 0 {
|
||||
println!("Storing dictionary back to file... {:?}", &config.dictionary);
|
||||
dictionary.store(&mut File::create(&config.dictionary)?)?;
|
||||
}
|
||||
|
||||
println!("Loading BIN Data...");
|
||||
let bin_data_file = File::open(&config.bin_data)?;
|
||||
let bin_data = BinData::load(bin_data_file)?;
|
||||
|
||||
println!("Starting Anki deck generation...");
|
||||
let deck = generate_deck(&dictionary, &bin_data, &config)?;
|
||||
|
||||
println!("Saving Anki deck...");
|
||||
deck.write_to_file(&config.deck)?;
|
||||
|
||||
println!("Done!");
|
||||
}
|
||||
None => println!("Cannot access default application storage directory. Giving up."),
|
||||
}
|
||||
|
||||
println!("Saving Anki deck...");
|
||||
deck.write_to_file(deck_file)?;
|
||||
|
||||
// TODO: Back up original file
|
||||
println!("Updating {}...", input_file);
|
||||
update_word_map(input_file, &word_map);
|
||||
|
||||
println!("Done!");
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue