diff --git a/dict/main.go b/dict/main.go
index 77755a9..8b4328b 100644
--- a/dict/main.go
+++ b/dict/main.go
@@ -6,6 +6,7 @@ import (
"log"
"net/http"
"os"
+ "strings"
"foosoft.net/projects/jmdict"
"git.elnu.com/ElnuDev/jichanorg/httputils"
@@ -30,7 +31,12 @@ func LoadDict() error {
type Entry struct {
Kanji string
Reading string
- Definitions []string
+ Definitions []Definition
+}
+
+type Definition struct {
+ Definition string
+ PartOfSpeech []string
}
func ParseEntry(entry jmdict.JmdictEntry) Entry {
@@ -42,11 +48,18 @@ func ParseEntry(entry jmdict.JmdictEntry) Entry {
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
+ var definitions []Definition
+ definitions = make([]Definition, len(entry.Sense))
+ for i, sense := range entry.Sense {
+ definition := sense.Glossary[0].Content
+ if len(sense.Glossary) > 1 {
+ for _, glossary := range sense.Glossary[1:] {
+ definition += "; " + glossary.Content
+ }
+ }
+ definitions[i] = Definition{
+ Definition: definition,
+ PartOfSpeech: sense.PartsOfSpeech,
}
}
return Entry{
@@ -56,25 +69,59 @@ func ParseEntry(entry jmdict.JmdictEntry) Entry {
}
}
-func Search(query string) []Entry {
- entries := make([]Entry, 0)
+func Search(query string) (exactResults []Entry, otherResults []Entry, truncated bool) {
+ query = strings.TrimSpace(query)
+ exactResults = make([]Entry, 0)
+ otherResults = make([]Entry, 0)
+ count := 0
for _, jmdictEntry := range dict.Entries {
+ exactMatch := false
for _, kanji := range jmdictEntry.Kanji {
if kanji.Expression == query {
+ exactMatch = true
+ goto match
+ }
+ if strings.Contains(kanji.Expression, query) {
goto match
}
}
+ // TODO: Skip if query contains kanji
for _, reading := range jmdictEntry.Readings {
- if reading.Reading == query {
+ if strings.Contains(reading.Reading, query) {
goto match
}
}
continue
match:
entry := ParseEntry(jmdictEntry)
- entries = append(entries, entry)
+ if exactMatch {
+ exactResults = append(exactResults, entry)
+ } else {
+ otherResults = append(otherResults, entry)
+ }
+ count++
+ if count >= 500 {
+ truncated = true
+ break
+ }
+ }
+ return
+}
+
+type searchTemplateData struct {
+ ExactResults []Entry
+ OtherResults []Entry
+ Truncated bool
+ Count int
+}
+
+func initSearchTemplateData(exactResults []Entry, otherResults []Entry, truncated bool) searchTemplateData {
+ return searchTemplateData{
+ ExactResults: exactResults,
+ OtherResults: otherResults,
+ Truncated: truncated,
+ Count: len(exactResults) + len(otherResults),
}
- return entries
}
func main() {
@@ -85,6 +132,34 @@ func main() {
}
fmt.Println("JMdict loaded!")
r := mux.NewRouter()
+ r.HandleFunc("/", httputils.GenerateHandler(
+ "index.html",
+ func(w http.ResponseWriter, r *http.Request) bool { return true },
+ func(w http.ResponseWriter, r *http.Request) any { return nil },
+ []string{http.MethodGet},
+ ))
+ redirectToHome := func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, "/", http.StatusPermanentRedirect)
+ }
+ r.HandleFunc("/search", redirectToHome)
+ r.HandleFunc("/search/", redirectToHome)
+ r.HandleFunc("/search/{query}", httputils.GenerateHandler(
+ "index.html",
+ func(w http.ResponseWriter, r *http.Request) bool {
+ return true
+ },
+ func(w http.ResponseWriter, r *http.Request) any {
+ query := mux.Vars(r)["query"]
+ return struct {
+ Query string
+ Results searchTemplateData
+ }{
+ Query: query,
+ Results: initSearchTemplateData(Search(query)),
+ }
+ },
+ []string{http.MethodGet},
+ ))
r.HandleFunc("/api/search", httputils.GenerateHandler(
"search.html",
func(w http.ResponseWriter, r *http.Request) bool {
@@ -94,18 +169,17 @@ func main() {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
r.ParseMultipartForm(0)
query := r.FormValue("q")
- entries := Search(query)
- jsonBytes, _ := json.Marshal(entries)
+ exactResults, otherResults, _ := Search(query)
+ jsonBytes, _ := json.Marshal(append(exactResults, otherResults...))
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
+ return initSearchTemplateData(Search(query))
},
- []string{http.MethodGet, http.MethodPost},
+ []string{http.MethodGet},
))
r.Handle("/", http.FileServer(http.Dir("static")))
log.Fatal(http.ListenAndServe(":3334", r))
diff --git a/dict/templates/definition.html b/dict/templates/definition.html
new file mode 100644
index 0000000..86595c7
--- /dev/null
+++ b/dict/templates/definition.html
@@ -0,0 +1,3 @@
+{{- define "definition" -}}
+{{ if .PartOfSpeech }}
{{ end }}{{ .Definition -}}
+{{ end }}
\ No newline at end of file
diff --git a/dict/static/index.html b/dict/templates/index.html
similarity index 55%
rename from dict/static/index.html
rename to dict/templates/index.html
index cfebb64..ca01362 100644
--- a/dict/static/index.html
+++ b/dict/templates/index.html
@@ -5,6 +5,11 @@
{{ $count := (len .) }}{{ if eq $count 0 }}No results{{ else }}{{ $count }} result{{ if ne $count 1}}s{{ end }}{{ end }}.
-{{- range . -}} -{{- index .Definitions 0 -}}
- {{- else -}} -{{ if .Truncated }}Truncated results, showing first {{ .Count }}{{ else }}{{ if eq .Count 0 }}No results{{ else }}{{ .Count }} result{{ if ne .Count 1}}s{{ end }}{{ end }}{{ end }}.
+{{- range .ExactResults -}} +{{- template "word" . -}} +{{- end }} +{{- template "definition" (index .Definitions 0) -}}
+ {{- else -}} +