generated from ElnuDev/go-project
parent
f8ccf62570
commit
01204ffc81
@ -0,0 +1 @@
|
||||
JMdict.xml
|
@ -0,0 +1,14 @@
|
||||
# jichanorg/dict
|
||||
|
||||
**jichanorg/dict** is a [hypermedia](https://hypermedia.systems/) and JSON API for parsing the JMDict Japanese dictionary project.
|
||||
|
||||
Its primary goals are:
|
||||
|
||||
- be a self-hostable dictionary solution to replace existing proprietary ([Jisho.org](https://jisho.org/)) and partially proprietary ([Jotoba](https://jotoba.de/)) dictionaries.
|
||||
- Provide a hypermedia API for integration into other applications, such as [jichanorg/shiritori](../shiritori).
|
||||
|
||||
### Configuration
|
||||
|
||||
1. [Download the latest version of JMdict](https://www.edrdg.org/wiki/index.php/JMdict-EDICT_Dictionary_Project#CURRENT_VERSION_&_DOWNLOAD). For development, download the file with only English glosses, which will substantially decrease parsing time.
|
||||
2. Extract the archive
|
||||
3. Rename the file to JMDict.xml
|
@ -0,0 +1,8 @@
|
||||
module git.elnu.com/ElnuDev/jichanorg/dict
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
foosoft.net/projects/jmdict v0.0.0-20220714211640-cc9bc30b68a3 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
)
|
@ -0,0 +1,4 @@
|
||||
foosoft.net/projects/jmdict v0.0.0-20220714211640-cc9bc30b68a3 h1:zjHGpgUR2WP3pf6NVZM38OKYNse0GjovCW2v23V72PQ=
|
||||
foosoft.net/projects/jmdict v0.0.0-20220714211640-cc9bc30b68a3/go.mod h1:ZrjLCcE7ZrND28ZOSGYMd78tL+Dffiv2g+NjOMKgnew=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
@ -0,0 +1,112 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"foosoft.net/projects/jmdict"
|
||||
"git.elnu.com/ElnuDev/jichanorg/httputils"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var dict jmdict.Jmdict
|
||||
|
||||
func LoadDict() error {
|
||||
const jmdictFile = "JMdict.xml"
|
||||
reader, err := os.Open(jmdictFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dict, _, err = jmdict.LoadJmdict(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Entry struct {
|
||||
Kanji string
|
||||
Reading string
|
||||
Definitions []string
|
||||
}
|
||||
|
||||
func ParseEntry(entry jmdict.JmdictEntry) Entry {
|
||||
kanji := ""
|
||||
if len(entry.Kanji) > 0 {
|
||||
kanji = entry.Kanji[0].Expression
|
||||
}
|
||||
reading := ""
|
||||
if len(entry.Readings) > 0 {
|
||||
reading = entry.Readings[0].Reading
|
||||
}
|
||||
var definitions []string
|
||||
if len(entry.Sense) > 0 && len(entry.Sense[0].Glossary) > 0 {
|
||||
definitions = make([]string, len(entry.Sense[0].Glossary))
|
||||
for i, glossary := range entry.Sense[0].Glossary {
|
||||
definitions[i] = glossary.Content
|
||||
}
|
||||
}
|
||||
return Entry{
|
||||
Kanji: kanji,
|
||||
Reading: reading,
|
||||
Definitions: definitions,
|
||||
}
|
||||
}
|
||||
|
||||
func Search(query string) []Entry {
|
||||
entries := make([]Entry, 0)
|
||||
for _, jmdictEntry := range dict.Entries {
|
||||
for _, kanji := range jmdictEntry.Kanji {
|
||||
if kanji.Expression == query {
|
||||
goto match
|
||||
}
|
||||
}
|
||||
for _, reading := range jmdictEntry.Readings {
|
||||
if reading.Reading == query {
|
||||
goto match
|
||||
}
|
||||
}
|
||||
continue
|
||||
match:
|
||||
entry := ParseEntry(jmdictEntry)
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := LoadDict()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("JMdict loaded!")
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/api/search", httputils.GenerateHandler(
|
||||
"search.html",
|
||||
func(w http.ResponseWriter, r *http.Request) bool {
|
||||
if r.Header.Get("Accept") != "application/json" {
|
||||
return true
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
r.ParseMultipartForm(0)
|
||||
query := r.FormValue("q")
|
||||
entries := Search(query)
|
||||
jsonBytes, _ := json.Marshal(entries)
|
||||
fmt.Fprint(w, string(jsonBytes))
|
||||
return false
|
||||
},
|
||||
func(w http.ResponseWriter, r *http.Request) any {
|
||||
r.ParseMultipartForm(0)
|
||||
query := r.FormValue("q")
|
||||
entry := Search(query)
|
||||
return entry
|
||||
},
|
||||
[]string{http.MethodGet, http.MethodPost},
|
||||
))
|
||||
r.Handle("/", http.FileServer(http.Dir("static")))
|
||||
log.Fatal(http.ListenAndServe(":3334", r))
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>jidict</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/missing.css@1.0.9/dist/missing.min.css">
|
||||
<script src="https://unpkg.com/htmx.org@1.9.3"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<a href="/">
|
||||
<img src="https://jichan.org/logo.svg" style="height: 4em; display: block; margin: 1em auto 1em auto">
|
||||
</a>
|
||||
<form
|
||||
hx-post="/api/search"
|
||||
hx-target="#results"
|
||||
hx-swap="innerHTML">
|
||||
<input type="text" name="q" placeholder="辞書をサーチする" class="width:100%" autocomplete="false">
|
||||
</form>
|
||||
<div id="results"></div>
|
||||
<br>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,21 @@
|
||||
<p><i>{{ $count := (len .) }}{{ if eq $count 0 }}No results{{ else }}{{ $count }} result{{ if ne $count 1}}s{{ end }}{{ end }}.</i></p>
|
||||
{{- range . -}}
|
||||
<div class="box">
|
||||
<h3>
|
||||
{{- if .Kanji -}}
|
||||
<ruby>{{- .Kanji -}}<rp>(</rp><rt>{{- .Reading -}}</rt><rp>)</rp></ruby>
|
||||
{{- else -}}
|
||||
{{- .Reading -}}
|
||||
{{- end -}}
|
||||
</h3>
|
||||
{{ if le (len .Definitions) 2 -}}
|
||||
<p>{{- index .Definitions 0 -}}</p>
|
||||
{{- else -}}
|
||||
<ol>
|
||||
{{- range .Definitions }}
|
||||
<li>{{- . -}}</li>
|
||||
{{- end }}
|
||||
</ol>
|
||||
{{- end }}
|
||||
</div>
|
||||
{{ end -}}
|
Reference in new issue