diff --git a/dict/.gitignore b/dict/.gitignore index 1a06b16..18e00d2 100644 --- a/dict/.gitignore +++ b/dict/.gitignore @@ -1,3 +1,2 @@ JMdict.xml -JmdictFurigana.txt dict.bin \ No newline at end of file diff --git a/dict/README.md b/dict/README.md index 7518875..bb0c063 100644 --- a/dict/README.md +++ b/dict/README.md @@ -9,13 +9,6 @@ Its primary goals are: ### Configuration -#### JMdict - 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 - -#### JmdictFurigana - -1. [Download the latest version of JmdictFurigana.txt](https://github.com/Doublevil/JmdictFurigana/releases) -2. Ensure it's named JmdictFurigana.txt. \ No newline at end of file +3. Rename the file to JMDict.xml \ No newline at end of file diff --git a/dict/main.go b/dict/main.go index 2261a1c..073ab2e 100644 --- a/dict/main.go +++ b/dict/main.go @@ -1,15 +1,12 @@ package main import ( - "bufio" "encoding/gob" "encoding/json" "fmt" - "html/template" "log" "net/http" "os" - "strconv" "strings" "foosoft.net/projects/jmdict" @@ -17,15 +14,9 @@ import ( "github.com/gorilla/mux" ) -var words []string // since iterating over map isn't the same every time var dict map[string]Entry func LoadDict() error { - type binaryData struct { - Words []string - Dict map[string]Entry - } - // Loading from binary const binaryFile = "dict.bin" file, err := os.Open(binaryFile) @@ -36,10 +27,7 @@ func LoadDict() error { } else { defer file.Close() decoder := gob.NewDecoder(file) - var data binaryData - err = decoder.Decode(&data) - words = data.Words - dict = data.Dict + err = decoder.Decode(&dict) return err } @@ -53,52 +41,10 @@ func LoadDict() error { if err != nil { return err } - - const jmdictFuriganaFile = "JmdictFurigana.txt" - reader, err = os.Open(jmdictFuriganaFile) - if err != nil { - return err - } - scanner := bufio.NewScanner(reader) - furiganaData := make(map[string]string) - for scanner.Scan() { - params := strings.Split(scanner.Text(), "|") - // We need to include the reading as well since some words have the same kanji - furiganaData[fmt.Sprintf("%s|%s", params[0], params[1])] = params[2] - } - - words = make([]string, len(jmdict.Entries)) dict = make(map[string]Entry) - for i, jmdictEntry := range jmdict.Entries { - // お願い致します|おねがいいたします|1:ねが;3:いた - var furiganaInfo *string - if len(jmdictEntry.Kanji) > 0 { - data := furiganaData[fmt.Sprintf("%s|%s", jmdictEntry.Kanji[0].Expression, jmdictEntry.Readings[0].Reading)] - furiganaInfo = &data - } else { - furiganaInfo = nil - } - entry := ParseEntry(&jmdictEntry, furiganaInfo) - offset := 0 - getKey := func() string { - if offset == 0 { - // unique - return entry.Kanji - } else { - return fmt.Sprintf("%s-%d", entry.Kanji, offset) - } - } - for { - if _, ok := dict[getKey()]; ok { - offset++ - } else { - break - } - } - key := getKey() - entry.Key = key - words[i] = key - dict[key] = entry + for _, jmdictEntry := range jmdict.Entries { + entry := ParseEntry(&jmdictEntry) + dict[entry.Kanji] = entry } // Encoding to binary @@ -108,11 +54,7 @@ func LoadDict() error { } defer file.Close() encoder := gob.NewEncoder(file) - data := binaryData{ - Words: words, - Dict: dict, - } - err = encoder.Encode(&data) + err = encoder.Encode(&dict) if err != nil { return err } @@ -120,16 +62,8 @@ func LoadDict() error { return nil } -type Furigana struct { - Kanji string - Furigana string -} - type Entry struct { - Key string - Kanji string - // Mapping of character index to furigana - Furigana []Furigana + Kanji string Reading string Definitions []Definition } @@ -139,15 +73,13 @@ type Definition struct { PartOfSpeech []string } -func ParseEntry(entry *jmdict.JmdictEntry, furiganaInfo *string) Entry { +func ParseEntry(entry *jmdict.JmdictEntry) Entry { kanji := "" if len(entry.Kanji) > 0 { kanji = entry.Kanji[0].Expression - } else { - kanji = entry.Readings[0].Reading } reading := "" - if kanji != "" { + if len(entry.Readings) > 0 { reading = entry.Readings[0].Reading } var definitions []Definition @@ -164,104 +96,29 @@ func ParseEntry(entry *jmdict.JmdictEntry, furiganaInfo *string) Entry { PartOfSpeech: sense.PartsOfSpeech, } } - // 1:ねが;3:いた - var furiganaList []Furigana - if reading == "" || furiganaInfo == nil || *furiganaInfo == "" { - furiganaList = []Furigana{{Kanji: reading, Furigana: ""}} - } else { - furiganaEntries := strings.Split(*furiganaInfo, ";") - // ["1:ねが", "3:いた"] - type rawFurigana struct { - from int - to int - furigana string - } - ruby := make([]rawFurigana, 0) - for _, entry := range furiganaEntries { - // 1:ねが - // multiple: 0-1:きょう - params := strings.Split(entry, ":") - // ["1", "ねが"] - // multiple: ["0-1", "きょう"] - indexRange := strings.Split(params[0], "-") - // [1] - // multiple: [0, 1] - var from, to int - if len(indexRange) == 1 { - index, _ := strconv.Atoi(indexRange[0]) - from, to = index, index - } else { - from, _ = strconv.Atoi(indexRange[0]) - to, _ = strconv.Atoi(indexRange[1]) - } - ruby = append(ruby, rawFurigana{ - from: from, - to: to, - furigana: params[1], - }) - } - furiganaList = make([]Furigana, 0) - slice := func(from, to int) string { - return string([]rune(kanji)[from : to+1]) - } - nextIndex := 0 - for _, raw := range ruby { - if raw.from > nextIndex { - furiganaList = append(furiganaList, Furigana{ - Kanji: slice(nextIndex, raw.from-1), - Furigana: "", - }) - } - furiganaList = append(furiganaList, Furigana{ - Kanji: slice(raw.from, raw.to), - Furigana: raw.furigana, - }) - nextIndex = raw.to + 1 - } - length := len([]rune(kanji)) - if nextIndex < length { - furiganaList = append(furiganaList, Furigana{ - Kanji: slice(nextIndex, length-1), - Furigana: "", - }) - } - } return Entry{ Kanji: kanji, - Furigana: furiganaList, Reading: reading, Definitions: definitions, } } -func highlight(input, substring string) template.HTML { - // Replace all occurrences of substring with the highlighted version - replacement := fmt.Sprintf("%s", substring) - result := strings.ReplaceAll(input, substring, replacement) - return template.HTML(result) -} - func Search(query string) queryResult { query = strings.TrimSpace(query) exactResults := make([]Entry, 0) otherResults := make([]Entry, 0) truncated := false count := 0 - for _, key := range words { + for kanji := range dict { exactMatch := false - entry := dict[key] - if entry.Kanji == query { + entry := dict[kanji] + if kanji == query { exactMatch = true goto match } - if strings.Contains(entry.Kanji, query) { + if strings.Contains(kanji, query) { goto match } - for _, definition := range entry.Definitions { - if strings.Contains(strings.ToLower(definition.Definition), strings.ToLower(strings.TrimSpace(query))) { - goto match - } - } // TODO: Skip if query contains kanji if strings.Contains(entry.Reading, query) { goto match @@ -314,12 +171,6 @@ func main() { return } fmt.Println("JMdict loaded!") - httputils.DefaultTemplateFuncs = template.FuncMap{ - "highlight": func(input string) string { - return input - }, - } - httputils.TemplateFuncs = httputils.DefaultTemplateFuncs r := mux.NewRouter() r.HandleFunc("/", httputils.GenerateHandler( func(w http.ResponseWriter, r *http.Request) bool { return true }, @@ -360,20 +211,15 @@ func main() { }, httputils.NewTemplateSet("index.html", "search.html"), // template data - func(w http.ResponseWriter, r *http.Request) (templateName string, data any) { + func(w http.ResponseWriter, r *http.Request) (template string, data any) { if r.Header.Get("HX-Request") == "" { - templateName = "search.html" + template = "search.html" } else { - templateName = "search" + template = "search" } // Only runs if handler returns true query := mux.Vars(r)["query"] data = Search(query) - httputils.TemplateFuncs = template.FuncMap{ - "highlight": func(input string) template.HTML { - return highlight(input, strings.TrimSpace(query)) - }, - } return }, []string{http.MethodGet}, @@ -404,6 +250,6 @@ func main() { }, []string{http.MethodGet}, )) - r.PathPrefix("/").Handler(http.FileServer(http.Dir("static"))) + r.Handle("/", http.FileServer(http.Dir("static"))) log.Fatal(http.ListenAndServe(":3334", r)) } diff --git a/dict/static/logo.svg b/dict/static/logo.svg deleted file mode 100644 index 9e412b3..0000000 --- a/dict/static/logo.svg +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/dict/templates/index.html b/dict/templates/index.html index e16e3da..ea33ea8 100644 --- a/dict/templates/index.html +++ b/dict/templates/index.html @@ -22,11 +22,8 @@
- + -
- jichan.org is in open alpha. The site may be buggy. More features are coming soon. If you have ideas or want to contribute, DM me on Discord @elnudev or open an issue on Codeberg. -
- {{ block "results" . }} - {{ if .Query }} - {{ template "search" . }} - {{ else }} -

Thank you to

- - {{ end }} - {{ end }} + {{ block "results" . }}{{ if .Query }}{{ template "search" . }}{{ end }}{{ end }}

diff --git a/dict/templates/partials/definition.html b/dict/templates/partials/definition.html index cc826d4..86595c7 100644 --- a/dict/templates/partials/definition.html +++ b/dict/templates/partials/definition.html @@ -1,3 +1,3 @@ {{- define "definition" -}} -{{ if .PartOfSpeech }}{{ .PartOfSpeech }}
{{ end }}{{ highlight .Definition -}} +{{ if .PartOfSpeech }}{{ .PartOfSpeech }}
{{ end }}{{ .Definition -}} {{ end }} \ No newline at end of file diff --git a/dict/templates/partials/entry.html b/dict/templates/partials/entry.html index 0d42249..9d74569 100644 --- a/dict/templates/partials/entry.html +++ b/dict/templates/partials/entry.html @@ -1,15 +1,11 @@ {{ define "entry" }}
-

- - {{- range .Furigana -}} - {{- if .Furigana -}} - {{- .Kanji -}}({{- .Furigana -}}) - {{- else -}} - {{- .Kanji -}} - {{- end -}} +

+ {{- if .Kanji -}} + {{- .Kanji -}}({{- .Reading -}}) + {{- else -}} + {{- .Reading -}} {{- end -}} -

{{- $count := len .Definitions -}} {{ if eq $count 1 -}} diff --git a/dict/templates/partials/entryfull.html b/dict/templates/partials/entryfull.html index dce3966..8488cbc 100644 --- a/dict/templates/partials/entryfull.html +++ b/dict/templates/partials/entryfull.html @@ -1,12 +1,10 @@ {{ define "entryfull" }}
-

- {{- range .Furigana -}} - {{- if .Furigana -}} - {{- .Kanji -}}({{- .Furigana -}}) - {{- else -}} - {{- .Kanji -}} - {{- end -}} +

+ {{- if .Kanji -}} + {{- .Kanji -}}({{- .Reading -}}) + {{- else -}} + {{- .Reading -}} {{- end -}}

{{- $count := len .Definitions -}} diff --git a/dict/templates/partials/sitetitle.html b/dict/templates/partials/sitetitle.html index 72b7d48..67e6c0a 100644 --- a/dict/templates/partials/sitetitle.html +++ b/dict/templates/partials/sitetitle.html @@ -1 +1 @@ -{{ define "sitetitle" }}jichan.org{{ end }} \ No newline at end of file +{{ define "sitetitle" }}jidict{{ end }} \ No newline at end of file diff --git a/dict/templates/search.html b/dict/templates/search.html index b143d74..ffa8680 100644 --- a/dict/templates/search.html +++ b/dict/templates/search.html @@ -3,7 +3,7 @@ {{- define "value" }}{{ .Query }}{{- end -}} {{- define "results" -}} -{{- template "search" . -}} +{{- template "entryfull" .Entry -}} {{- end -}} {{- template "index" . -}} \ No newline at end of file diff --git a/httputils/templates.go b/httputils/templates.go index 2e61d06..7c48e1e 100644 --- a/httputils/templates.go +++ b/httputils/templates.go @@ -29,11 +29,9 @@ func newTemplateSet(partials *TemplateSet, paths ...string) TemplateSet { fileInfo, _ := os.Stat(path) modTimes[path] = fileInfo.ModTime() } - templates := template.Template{} - templates.Funcs(DefaultTemplateFuncs) - templates.ParseFiles(allPaths...) + templates := template.Must(template.ParseFiles(allPaths...)) return TemplateSet{ - templates: &templates, + templates: templates, paths: allPaths, loadTimes: modTimes, } @@ -48,10 +46,7 @@ func NewTemplateSet(paths ...string) TemplateSet { func (templateSet *TemplateSet) ExecuteTemplate(wr io.Writer, name string, data any) error { templateSet.reloadTemplatesIfModified() - templateSet.templates.Funcs(TemplateFuncs) - err := templateSet.templates.ExecuteTemplate(wr, name, data) - TemplateFuncs = DefaultTemplateFuncs - return err + return templateSet.templates.ExecuteTemplate(wr, name, data) } func (templateSet *TemplateSet) reloadTemplatesIfModified() { @@ -91,5 +86,3 @@ const partialsFolder = templateFolder + "/partials" var paths, _ = getTemplatePathsInDirectory(partialsFolder) var partials = newTemplateSet(nil, paths...) -var DefaultTemplateFuncs template.FuncMap -var TemplateFuncs template.FuncMap