Make the dictionary startup line report rows, not capabilities
It logged dictionary.Langs(), which is a compile-time constant of the languages DreamDict *supports*. The database deployed until today supported Spanish and contained none of it, so the line printed a confident "[en fr pt-PT es zh]" over a file where every Spanish lookup came back empty — the exact failure the line exists to catch, reported as success. Contents() counts rows per language instead. For a file somebody has to copy onto the box by hand, "what is in it" is the only question worth asking, and the answer is now en=136615 es=102971 fr=56096 pt-PT=136300 zh=120883. Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
+1
-1
@@ -96,7 +96,7 @@ func main() {
|
||||
defer dict.Close()
|
||||
lexSet := lexicon.NewSet(dict)
|
||||
if lexSet.HasDreamDict() {
|
||||
log.Printf("dictionary: DreamDict open at %s (%v)", cfg.DictPath, dict.Langs())
|
||||
log.Printf("dictionary: DreamDict open at %s (%s)", cfg.DictPath, lexSet.Contents())
|
||||
} else {
|
||||
log.Printf("dictionary: no dict.db at %s — English/Chinese only", cfg.DictPath)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@ package lexicon
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
@@ -56,9 +58,34 @@ func (dd *DreamDict) Close() error {
|
||||
return dd.d.Close()
|
||||
}
|
||||
|
||||
// Langs returns the language codes dict.db was built with, so startup can log
|
||||
// what it actually got rather than what it hoped for.
|
||||
func (dd *DreamDict) Langs() []string { return dictionary.Langs() }
|
||||
// Contents reports how many words the open dict.db holds per language, so
|
||||
// startup can log what it actually got.
|
||||
//
|
||||
// It counts rows rather than returning DreamDict's list of supported languages.
|
||||
// Those are not the same thing and the difference is the whole point: a
|
||||
// database built before Spanish existed still *supports* Spanish, and a log
|
||||
// line naming the supported set would have said so cheerfully while every
|
||||
// Spanish lookup came back empty. Counting rows is the question worth asking of
|
||||
// a file somebody had to copy onto the box by hand.
|
||||
func (dd *DreamDict) Contents() string {
|
||||
counts, err := dd.d.WordCount()
|
||||
if err != nil {
|
||||
return "unreadable: " + err.Error()
|
||||
}
|
||||
langs := make([]string, 0, len(counts))
|
||||
for lang := range counts {
|
||||
langs = append(langs, lang)
|
||||
}
|
||||
sort.Strings(langs)
|
||||
parts := make([]string, 0, len(langs))
|
||||
for _, lang := range langs {
|
||||
parts = append(parts, fmt.Sprintf("%s=%d", lang, counts[lang]))
|
||||
}
|
||||
if len(parts) == 0 {
|
||||
return "no words"
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
// dreamProvider serves one writer: English lookups from dict.db, glossed into
|
||||
// native. The struct is a value, created per request by [Set.For] — it holds no
|
||||
@@ -180,8 +207,8 @@ const maxGlossSenses = 3
|
||||
//
|
||||
// A language dict.db was built without simply has no rows, so this returns "" —
|
||||
// which is exactly what an unglossed word returns, and the popover already
|
||||
// renders that case. Spanish today is precisely this: supported by DreamDict,
|
||||
// absent from the deployed database until it is rebuilt.
|
||||
// renders that case. Spanish was precisely this until the database was rebuilt
|
||||
// with it on 2026-07-27; the code path did not change, the file did.
|
||||
func (p dreamProvider) translate(norm string) (string, error) {
|
||||
for _, c := range candidates(norm) {
|
||||
trs, err := p.dict.d.Equivalents(c, langEN, p.native)
|
||||
|
||||
@@ -519,3 +519,25 @@ func TestHandlerDecodesPunctuatedWords(t *testing.T) {
|
||||
t.Errorf("Word = %q, want the decoded word", res.Word)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContentsCountsRowsNotSupportedLanguages(t *testing.T) {
|
||||
// The fixture is seeded with English and pt-PT only. DreamDict *supports*
|
||||
// French, Spanish and Chinese too — and a startup line that reported the
|
||||
// supported set would have named all five while every French lookup came
|
||||
// back empty. That is the failure this log line exists to catch, so it must
|
||||
// count rows.
|
||||
got := NewSet(openFixture(t))
|
||||
summary := got.Contents()
|
||||
if !strings.Contains(summary, "en=") || !strings.Contains(summary, "pt-PT=") {
|
||||
t.Errorf("Contents = %q, want the languages the fixture actually holds", summary)
|
||||
}
|
||||
for _, absent := range []string{"fr=", "es=", "zh="} {
|
||||
if strings.Contains(summary, absent) {
|
||||
t.Errorf("Contents = %q, must not name %q — no rows exist for it", summary, absent)
|
||||
}
|
||||
}
|
||||
// No dictionary at all still has to answer something printable.
|
||||
if s := NewSet(nil).Contents(); s == "" {
|
||||
t.Error("Contents with no dictionary must still say something")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,16 @@ func NewSet(dream *DreamDict) *Set {
|
||||
// usable.
|
||||
func (s *Set) HasDreamDict() bool { return s.dream != nil }
|
||||
|
||||
// Contents describes what the open dict.db actually holds, for the startup log.
|
||||
// With no dictionary it says so rather than returning an empty string, because
|
||||
// a blank in a log line is indistinguishable from a bug in the log line.
|
||||
func (s *Set) Contents() string {
|
||||
if s.dream == nil {
|
||||
return "no dict.db — embedded datasets only"
|
||||
}
|
||||
return s.dream.Contents()
|
||||
}
|
||||
|
||||
// For returns the provider that should answer lookups for a writer whose pair
|
||||
// language is lang.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user