8b4b899959
Require `-language=english_extra` to produce the complete version of the new JMdict dictionary file. If and when we determine that the all the new features are ready to be included the dictionary by default, we can remove this logic.
301 lines
9.2 KiB
Go
301 lines
9.2 KiB
Go
package yomichan
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"foosoft.net/projects/jmdict"
|
|
)
|
|
|
|
func glossaryContainsLanguage(glossary []jmdict.JmdictGlossary, language string) bool {
|
|
hasGlosses := false
|
|
for _, gloss := range glossary {
|
|
if glossContainsLanguage(gloss, language) {
|
|
hasGlosses = true
|
|
break
|
|
}
|
|
}
|
|
return hasGlosses
|
|
}
|
|
|
|
func glossContainsLanguage(gloss jmdict.JmdictGlossary, language string) bool {
|
|
if gloss.Language == nil && language != "eng" {
|
|
return false
|
|
} else if gloss.Language != nil && language != *gloss.Language {
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
}
|
|
|
|
func makeGlossListItem(gloss jmdict.JmdictGlossary, language string) any {
|
|
contents := []any{gloss.Content}
|
|
listItem := contentListItem(contentAttr{}, contents...)
|
|
return listItem
|
|
}
|
|
|
|
func makeInfoGlossListItem(gloss jmdict.JmdictGlossary, language string) any {
|
|
// Prepend gloss with "type" (literal, figurative, trademark, etc.)
|
|
glossTypeCode := *gloss.Type
|
|
contents := []any{}
|
|
if name, ok := glossTypeCodeToName[LangCode{language, glossTypeCode}]; ok {
|
|
if name != "" {
|
|
italicStyle := contentAttr{fontStyle: "italic"}
|
|
contents = append(contents, contentSpan(italicStyle, "("+name+")"), " ")
|
|
}
|
|
} else {
|
|
fmt.Println("Unknown glossary type code " + *gloss.Type + " for build language " + language)
|
|
contents = append(contents, "["+glossTypeCode+"] ")
|
|
}
|
|
contents = append(contents, gloss.Content)
|
|
listItem := contentListItem(contentAttr{}, contents...)
|
|
return listItem
|
|
}
|
|
|
|
func makeSourceLangListItem(sourceLanguage jmdict.JmdictSource, language string) any {
|
|
contents := []any{}
|
|
|
|
var srcLangCode string
|
|
if sourceLanguage.Language == nil {
|
|
srcLangCode = "eng"
|
|
} else {
|
|
srcLangCode = *sourceLanguage.Language
|
|
}
|
|
|
|
// Format: [Language] ([Partial?], [Wasei?]): [Original word?]
|
|
// [Language]
|
|
if langName, ok := langCodeToName[LangCode{language, srcLangCode}]; ok {
|
|
contents = append(contents, langName)
|
|
} else {
|
|
contents = append(contents, srcLangCode)
|
|
fmt.Println("Unable to convert ISO 639 code " + srcLangCode + " to its full name in language " + language)
|
|
}
|
|
|
|
// ([Partial?], [Wasei?])
|
|
var sourceLangTypeCode string
|
|
if sourceLanguage.Type == nil {
|
|
sourceLangTypeCode = ""
|
|
} else {
|
|
sourceLangTypeCode = *sourceLanguage.Type
|
|
}
|
|
var sourceLangType string
|
|
if val, ok := sourceLangTypeCodeToType[LangCode{language, sourceLangTypeCode}]; ok {
|
|
sourceLangType = val
|
|
} else {
|
|
sourceLangType = sourceLangTypeCode
|
|
fmt.Println("Unknown source language type code " + sourceLangTypeCode + " for build language " + language)
|
|
}
|
|
if sourceLangType != "" && sourceLanguage.Wasei == "y" {
|
|
contents = append(contents, " ("+sourceLangType+", wasei)")
|
|
} else if sourceLangType != "" {
|
|
contents = append(contents, " ("+sourceLangType+")")
|
|
} else if sourceLanguage.Wasei == "y" {
|
|
contents = append(contents, " (wasei)")
|
|
}
|
|
|
|
// : [Original word?]
|
|
if sourceLanguage.Content != "" {
|
|
contents = append(contents, ": ")
|
|
attr := contentAttr{lang: ISOtoHTML[srcLangCode]}
|
|
contents = append(contents, contentSpan(attr, sourceLanguage.Content))
|
|
}
|
|
|
|
listItem := contentListItem(contentAttr{}, contents...)
|
|
return listItem
|
|
}
|
|
|
|
func makeReferenceListItem(reference string, refType string, meta jmdictMetadata) any {
|
|
contents := []any{}
|
|
attr := contentAttr{}
|
|
|
|
hint := refNoteHint[LangCode{meta.language, refType}]
|
|
contents = append(contents, hint+": ")
|
|
|
|
refHeadword, senseNumber, ok := parseReference(reference)
|
|
if !ok {
|
|
contents = append(contents, "【"+reference+"】")
|
|
return contentListItem(attr, contents...)
|
|
}
|
|
|
|
sequence, ok := meta.referenceToSeq[reference]
|
|
if !ok {
|
|
contents = append(contents, "【"+reference+"】")
|
|
return contentListItem(attr, contents...)
|
|
}
|
|
|
|
targetSense := senseID{
|
|
sequence: sequence,
|
|
number: senseNumber,
|
|
}
|
|
|
|
expHash := refHeadword.ExpHash()
|
|
doDisplayReading := (len(meta.expHashToReadings[expHash]) > 1)
|
|
doDisplaySenseNumber := (meta.seqToSenseCount[targetSense.sequence] > 1)
|
|
refGlossAttr := contentAttr{
|
|
fontSize: "65%",
|
|
verticalAlign: "middle",
|
|
data: map[string]string{"content": "refGlosses"},
|
|
}
|
|
|
|
contents = append(contents, refHeadword.ToInternalLink(doDisplayReading))
|
|
if doDisplaySenseNumber {
|
|
contents = append(contents, contentSpan(refGlossAttr, " "+strconv.Itoa(targetSense.number)+". "+meta.condensedGlosses[targetSense]))
|
|
} else {
|
|
contents = append(contents, contentSpan(refGlossAttr, " "+meta.condensedGlosses[targetSense]))
|
|
}
|
|
|
|
listItem := contentListItem(attr, contents...)
|
|
return listItem
|
|
}
|
|
|
|
func makeExampleListItem(sentence jmdict.JmdictExampleSentence) any {
|
|
if sentence.Lang == "jpn" {
|
|
return contentListItem(contentAttr{}, sentence.Text)
|
|
} else {
|
|
attr := contentAttr{
|
|
lang: ISOtoHTML[sentence.Lang],
|
|
listStyleType: ISOtoFlag[sentence.Lang],
|
|
}
|
|
return contentListItem(attr, sentence.Text)
|
|
}
|
|
}
|
|
|
|
func listAttr(lang string, listStyleType string, dataContent string) contentAttr {
|
|
return contentAttr{
|
|
lang: lang,
|
|
listStyleType: listStyleType,
|
|
data: map[string]string{"content": dataContent},
|
|
}
|
|
}
|
|
|
|
func needsStructuredContent(sense jmdict.JmdictSense, language string) bool {
|
|
for _, gloss := range sense.Glossary {
|
|
if glossContainsLanguage(gloss, language) && gloss.Type != nil {
|
|
return true
|
|
}
|
|
}
|
|
if len(sense.SourceLanguages) > 0 {
|
|
return true
|
|
} else if len(sense.Information) > 0 {
|
|
return true
|
|
} else if len(sense.Antonyms) > 0 {
|
|
return true
|
|
} else if len(sense.References) > 0 {
|
|
return true
|
|
} else if len(sense.Examples) > 0 {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func createGlossaryContent(sense jmdict.JmdictSense, meta jmdictMetadata) any {
|
|
glossaryContents := []any{}
|
|
|
|
// Add normal glosses
|
|
glossListItems := []any{}
|
|
for _, gloss := range sense.Glossary {
|
|
if glossContainsLanguage(gloss, meta.language) && gloss.Type == nil {
|
|
listItem := makeGlossListItem(gloss, meta.language)
|
|
glossListItems = append(glossListItems, listItem)
|
|
}
|
|
}
|
|
if len(glossListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML[meta.language], "circle", "glossary")
|
|
list := contentUnorderedList(attr, glossListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
// Add information glosses
|
|
infoGlossListItems := []any{}
|
|
for _, gloss := range sense.Glossary {
|
|
if glossContainsLanguage(gloss, meta.language) && gloss.Type != nil {
|
|
listItem := makeInfoGlossListItem(gloss, meta.language)
|
|
infoGlossListItems = append(infoGlossListItems, listItem)
|
|
}
|
|
}
|
|
if len(infoGlossListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML[meta.language], infoMarker, "infoGlossary")
|
|
list := contentUnorderedList(attr, infoGlossListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
// Add language-of-origin / loanword information
|
|
sourceLangListItems := []any{}
|
|
for _, sourceLanguage := range sense.SourceLanguages {
|
|
listItem := makeSourceLangListItem(sourceLanguage, meta.language)
|
|
sourceLangListItems = append(sourceLangListItems, listItem)
|
|
}
|
|
if len(sourceLangListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML[meta.language], langMarker, "sourceLanguages")
|
|
list := contentUnorderedList(attr, sourceLangListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
// Add sense notes
|
|
noteListItems := []any{}
|
|
for _, information := range sense.Information {
|
|
listItem := contentListItem(contentAttr{}, information)
|
|
noteListItems = append(noteListItems, listItem)
|
|
}
|
|
if len(noteListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML["jpn"], noteMarker, "notes") // notes often contain japanese text
|
|
list := contentUnorderedList(attr, noteListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
// Add antonyms
|
|
antonymListItems := []any{}
|
|
for _, antonym := range sense.Antonyms {
|
|
listItem := makeReferenceListItem(antonym, "ant", meta)
|
|
antonymListItems = append(antonymListItems, listItem)
|
|
}
|
|
if len(antonymListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML[meta.language], antonymMarker, "antonyms")
|
|
list := contentUnorderedList(attr, antonymListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
// Add cross-references
|
|
referenceListItems := []any{}
|
|
for _, reference := range sense.References {
|
|
listItem := makeReferenceListItem(reference, "xref", meta)
|
|
referenceListItems = append(referenceListItems, listItem)
|
|
}
|
|
if len(referenceListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML[meta.language], refMarker, "references")
|
|
list := contentUnorderedList(attr, referenceListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
// Add example sentences
|
|
exampleListItems := []any{}
|
|
for _, example := range sense.Examples {
|
|
for _, sentence := range example.Sentences {
|
|
listItem := makeExampleListItem(sentence)
|
|
exampleListItems = append(exampleListItems, listItem)
|
|
}
|
|
}
|
|
if len(exampleListItems) > 0 {
|
|
attr := listAttr(ISOtoHTML["jpn"], ISOtoFlag["jpn"], "examples")
|
|
list := contentUnorderedList(attr, exampleListItems...)
|
|
glossaryContents = append(glossaryContents, list)
|
|
}
|
|
|
|
return contentStructure(glossaryContents...)
|
|
}
|
|
|
|
func createGlossary(sense jmdict.JmdictSense, meta jmdictMetadata) []any {
|
|
glossary := []any{}
|
|
if meta.extraMode && needsStructuredContent(sense, meta.language) {
|
|
glossary = append(glossary, createGlossaryContent(sense, meta))
|
|
} else {
|
|
for _, gloss := range sense.Glossary {
|
|
if glossContainsLanguage(gloss, meta.language) {
|
|
glossary = append(glossary, gloss.Content)
|
|
}
|
|
}
|
|
}
|
|
return glossary
|
|
}
|