KanKan: kanji-component-aware online Japanese dictionary

So I found something to complain about have a feature request :slight_smile:

Can you highlight the part of the search result that contains the searched string?
So for example when I type ε‹•, instead of seeing this:


I would like to see this:

Second feature request, can there be an option for a light theme? Never thought that I would ask for that, but right now that I am reading a paper book near my computer, and living in Denmark and all where it’s dark at 16 in the winter, it is nice if the screen can emit some light :grimacing:

7 Likes

Good ideas, I pushed a (very untested) change. There’s a button at the bottom of the page to toggle between light and dark themes. Normally by default the chosen theme should be selected based on device preference, or dark if no preference is found. The setting is then stored in the browser’s local storage, so it should be preserved across visits.

I also β€œmuted” the extra part of matches to make the actual selection stand out:


EDIT: oh and I absolutely suck at graphic design so don’t hesitate to propose color changes. I put everything in CSS variables at the top of the file so it should be easy to experiment:

:root {
    --fg-color: white;
    --fg-color-secondary: lightgrey;
    --bg-color: #1f3f3f;
    --match-bg: #103030;
    --match-bg-visited: #203030;
    --match-bg-hover: #143444;
    --help-bg: #333333;
    --link-color: #aaaaff;
    --radical-bg: #173c0c;
    --radical-title: lightblue;
    --radical-stroke: black;
    --match-extra-color: #9999aa;
}

:root[data-theme='light'] {
    --fg-color: black;
    --fg-color-secondary: #111111;
    --bg-color: #fdf6e3;
    --match-bg: #99ee99;
    --match-bg-visited: #aaffaa;
    --match-bg-hover: #77aa77;
    --help-bg: #cccccc;
    --link-color: #0000aa;
    --radical-bg: #aaddaa;
    --radical-title: #111155;
    --radical-stroke: white;
    --match-extra-color: #557777;
}
6 Likes

I love it!! Thank you and thank you for doing so fast too :smiling_face:

3 Likes

I started implementing conjugation handling:

I haven’t handled volitional/potential/causative/etc… yet, only basic stuff like negatives and γŸγƒ»γ¦ forms.

It’s also a very simplistic approach using regex which can’t handle the virtually infinite combinations of Japanese agglutination grammar. So 見ている is handled but 見ていγͺγ‹γ£γŸ isn’t. I could just add more regex to handle more cases but the total combinatorial of all possible verb forms is extremely large.

const deconjugation_table = [
    // Verb ます forms
    [/(い(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|いる|う)$'],
    [/(き(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|きる|く|くる)$'],
    [/(ぎ(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|γŽγ‚‹|ぐ)$'],
    [/(し(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|しる|す|する)$'],
    [/(け(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|ける|぀)$'],
    [/(に(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|にる|ぬ)$'],
    [/(び(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|びる|ぢ)$'],
    [/(み(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|みる|γ‚€)$'],
    [/(γ‚Š(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ))$/, '($1|γ‚Š?γ‚‹)$'],
    [/(ます|ません(γ§γ—γŸ)?|γΎγ—γŸ)$/, '($1|γ‚‹)$'],

    // Godan verb negative
    [/(わγͺい)$/, '($1|う|わる)$'],
    [/(かγͺい)$/, '($1|く|かる)$'],
    [/(がγͺい)$/, '($1|ぐ|γŒγ‚‹)$'],
    [/(さγͺい)$/, '($1|す|さる)$'],
    [/(γͺγͺい)$/, '($1|ぬ|γͺγ‚‹)$'],
    [/(ばγͺい)$/, '($1|ぢ|ばる)$'],
    [/(まγͺい)$/, '($1|γ‚€|まる)$'],
    [/(らγͺい)$/, '($1|γ‚‹|らる)$'],
    // する special case
    [/(しγͺい)$/, '($1|する|しる)$'],

    // Adjectives γŸγƒ»γ¦ + negative
    [/(くγͺい|γ‹γ£γŸ|くγͺγ‹γ£γŸ)$/, '($1|い)$'],
    [/(くて|くγͺくて)$/, '($1|い)$'],

    // Verb γŸγƒ»γ¦ forms
    [/(って(い?γ‚‹)?)$/, '($1|γ‚‹|う|぀)$'],
    [/(った)$/, '($1|γ‚‹|う|぀)$'],
    [/(いて(い?γ‚‹)?)$/, '($1|く|いる)$'],
    [/(γ„γŸ)$/, '($1|く|いる)$'],
    [/(いで(い?γ‚‹)?)$/, '($1|ぐ)$'],
    [/(いだ)$/, '($1|ぐ)$'],
    [/(んで(い?γ‚‹)?)$/, '($1|γ‚€|ぢ|ぬ)$'],
    [/(んだ)$/, '($1|γ‚€|ぢ|ぬ)$'],
    [/(して(い?γ‚‹)?)$/, '($1|する?|しる)$'],
    [/(γ—γŸ)$/, '($1|する?|しる)$'],
    [/(て(い?γ‚‹)?)$/, '($1|γ‚‹)$'],
    [/(た)$/, '($1|γ‚‹)$'],

    // Ichidan verb negative (needs to come last not to match against godan and
    // adjectives)
    [/(γͺい)$/, '($1|γ‚‹)$'],
]
3 Likes

By the way the reason I wanted this is because naturally it can be tricky to guess the dictionary form of an unknown conjugated verb. So if you encounter, say, 翔って and you don’t know the word or kanji, it can be tricky to search for because what’s the correct form of this? Is it ηΏ”γ‚‹, 翔う or 翔぀?

Now you don’t have to worry about this, you can just search for γ€ŒηΎŠηΎ½γ€γ£γ¦ and it finds the right word for you.

3 Likes

Hm when that happens I just search for ηΏ” and see what the results are :grimacing:

2 Likes

That does work in this case but it assumes that you have a way to input the kanji. If you start searching by component there will potentially be a ton of matches for a single character.

2 Likes

Hmm I see your thinking, but not sure that I have seen a use case for it myself yet

1 Like

It’s part of my world dominion plan to get to a point where I can use this as my main dictionary and being able to just write random forms without worrying about grammar and still get results.

I also intend to eventually change the result list to have some kind of β€œfold” that would let you access extra data for the vocab similar to a jisho page (kanji composition, examples, etc…) but that will take more work because I need some sort of backend to do this instead of doing everything in the browser.

7 Likes

As long as you don’t change the order of the radicals, you can go ahead and take over the world, fine by me :+1:

6 Likes

Can’t you program the conjugation rules themselves?

Like 見る > 見て + いる > 見ている - γ‚‹ + γͺい/た > 見ていγͺい - い + γ‹γ£γŸ > 見ていγͺγ‹γ£γŸ

2 Likes

The issue is that I’m trying to do the opposite: I start with the conjugated form in the query string and I need to β€œdeconjugate” it back to the dictionary form. That’s trickier to do algorithmically especially if I’m given a fuzzy search like, say γ€Œθ²γ€γ€Œι•·γ€γ‚ŠγΎγ™ that’s supposed to find ι ‘εΌ΅γ‚‹. In this case my algorithm would need to guess that the ending is really γ‚‹ but how can I know that?

I could use your solution and pre-compute all reasonable conjugations for all existing Japanese verbs and adjectives and match against that, but that seems really brutal computing-wise.

3 Likes

I added the remaining β€œbasic” conjugations: imperative, causative, passive, causative-passive, potential and volitional: δΌ‘γΎγ›γ‚‰γ‚Œγ‚‹

3 Likes

This is great!! Thanks so much for sharing. I bookmarked it for later use. :gift_heart:

3 Likes

Thanks for the cool tool! Previously I’ve used https://kanji.club in a separate tab to hunt for these kanji, but it makes a lot of sense to just integrate that functionality into the dictionary prompt itself.

There’s something funny going on with the back button, almost as if navigating to an entry uses history.pushState to create a duplicate entry in the history after loading the result page (instead of history.replaceState).

4 Likes

Yeah that part is very shoddy, I’ve already fixed a few bugs but it definitely doesn’t work perfectly still. I’ll have a look at replaceState.

4 Likes

I got a domain name! kankan.pt

At this point it should behave identically to the current page at svkt.eu/kankan/ but it’s actually a big rewrite: there’s now python Flask running in the backend (for now doing basically nothing) and I ported the Javascript to TypeScript because why not.

Also, new favicon made with love to replace the AI-generated one I used until now:


Behold my mad c4ll1gr4phy skillz.

10 Likes

This thing you made is awesome. Thank you!

4 Likes

Nani?

5 Likes

γŠε‰γ―γ‚‚γ†ζ•™γˆγ‚‰γ‚Œγ¦γ‚‹

5 Likes