internal/{frontend,middleware}: group import count in search
- Add a middleware that extracts the preferred i18n information from the
client.
- Use that information to format the imported-by count displayed in
search.
Change-Id: Id6676c135cb6b094c53a039206ef4702256120d6
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/347553
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go
index e1e6e62..f8100b4 100644
--- a/cmd/frontend/main.go
+++ b/cmd/frontend/main.go
@@ -174,6 +174,7 @@
middleware.Panic(panicHandler),
ermw,
middleware.Timeout(54*time.Second),
+ middleware.Language,
)
addr := cfg.HostAddr(*hostAddr)
log.Infof(ctx, "Listening on addr %s", addr)
diff --git a/go.mod b/go.mod
index a3e9e88..de77081 100644
--- a/go.mod
+++ b/go.mod
@@ -43,6 +43,7 @@
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
+ golang.org/x/text v0.3.6
golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c
google.golang.org/api v0.32.0
google.golang.org/genproto v0.0.0-20200923140941-5646d36feee1
diff --git a/internal/frontend/search.go b/internal/frontend/search.go
index 1b58297..dc09c6a 100644
--- a/internal/frontend/search.go
+++ b/internal/frontend/search.go
@@ -23,9 +23,11 @@
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/experiment"
"golang.org/x/pkgsite/internal/log"
+ "golang.org/x/pkgsite/internal/middleware"
"golang.org/x/pkgsite/internal/postgres"
"golang.org/x/pkgsite/internal/stdlib"
"golang.org/x/pkgsite/internal/version"
+ "golang.org/x/text/message"
)
const defaultSearchLimit = 10
@@ -48,7 +50,7 @@
DisplayVersion string
Licenses []string
CommitTime string
- NumImportedBy int
+ NumImportedBy string
Approximate bool
Symbols *subResult
SameModule *subResult // package paths in the same module
@@ -88,7 +90,8 @@
var results []*SearchResult
for _, r := range dbresults {
- results = append(results, newSearchResult(r, searchSymbols))
+ sr := newSearchResult(r, searchSymbols, message.NewPrinter(middleware.LanguageTag(ctx)))
+ results = append(results, sr)
}
var (
@@ -124,7 +127,7 @@
return sp, nil
}
-func newSearchResult(r *postgres.SearchResult, searchSymbols bool) *SearchResult {
+func newSearchResult(r *postgres.SearchResult, searchSymbols bool, pr *message.Printer) *SearchResult {
// For commands, change the name from "main" to the last component of the import path.
chipText := ""
name := r.Name
@@ -146,7 +149,7 @@
DisplayVersion: displayVersion(r.ModulePath, r.Version, r.Version),
Licenses: r.Licenses,
CommitTime: elapsedTime(r.CommitTime),
- NumImportedBy: int(r.NumImportedBy),
+ NumImportedBy: pr.Sprint(r.NumImportedBy),
SameModule: packagePaths(moduleDesc+":", r.SameModule),
// Say "other" instead of "lower" because at some point we may
// prefer to show a tagged, lower major version over an untagged
diff --git a/internal/frontend/search_test.go b/internal/frontend/search_test.go
index 5a3a45b..35f1cfc 100644
--- a/internal/frontend/search_test.go
+++ b/internal/frontend/search_test.go
@@ -18,6 +18,8 @@
"golang.org/x/pkgsite/internal/licenses"
"golang.org/x/pkgsite/internal/postgres"
"golang.org/x/pkgsite/internal/testing/sample"
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
)
func TestSearchQuery(t *testing.T) {
@@ -246,31 +248,37 @@
func TestNewSearchResult(t *testing.T) {
for _, test := range []struct {
name string
+ tag language.Tag
in postgres.SearchResult
want SearchResult
}{
{
name: "basic",
+ tag: language.English,
in: postgres.SearchResult{
- Name: "pkg",
- PackagePath: "m.com/pkg",
- ModulePath: "m.com",
- Version: "v1.0.0",
+ Name: "pkg",
+ PackagePath: "m.com/pkg",
+ ModulePath: "m.com",
+ Version: "v1.0.0",
+ NumImportedBy: 3,
},
want: SearchResult{
Name: "pkg",
PackagePath: "m.com/pkg",
ModulePath: "m.com",
DisplayVersion: "v1.0.0",
+ NumImportedBy: "3",
},
},
{
name: "command",
+ tag: language.English,
in: postgres.SearchResult{
- Name: "main",
- PackagePath: "m.com/cmd",
- ModulePath: "m.com",
- Version: "v1.0.0",
+ Name: "main",
+ PackagePath: "m.com/cmd",
+ ModulePath: "m.com",
+ Version: "v1.0.0",
+ NumImportedBy: 1234,
},
want: SearchResult{
Name: "cmd",
@@ -278,10 +286,12 @@
ModulePath: "m.com",
DisplayVersion: "v1.0.0",
ChipText: "command",
+ NumImportedBy: "1,234",
},
},
{
name: "stdlib",
+ tag: language.English,
in: postgres.SearchResult{
Name: "math",
PackagePath: "math",
@@ -294,11 +304,31 @@
ModulePath: "std",
DisplayVersion: "go1.14",
ChipText: "standard library",
+ NumImportedBy: "0",
+ },
+ },
+ {
+ name: "German",
+ tag: language.German,
+ in: postgres.SearchResult{
+ Name: "pkg",
+ PackagePath: "m.com/pkg",
+ ModulePath: "m.com",
+ Version: "v1.0.0",
+ NumImportedBy: 3456,
+ },
+ want: SearchResult{
+ Name: "pkg",
+ PackagePath: "m.com/pkg",
+ ModulePath: "m.com",
+ DisplayVersion: "v1.0.0",
+ NumImportedBy: "3.456",
},
},
} {
t.Run(test.name, func(t *testing.T) {
- got := newSearchResult(&test.in, false)
+ pr := message.NewPrinter(test.tag)
+ got := newSearchResult(&test.in, false, pr)
test.want.CommitTime = "Jan 1, 0001"
if diff := cmp.Diff(&test.want, got); diff != "" {
t.Errorf("mimatch (-want, +got):\n%s", diff)
diff --git a/internal/middleware/language.go b/internal/middleware/language.go
new file mode 100644
index 0000000..e038e0a
--- /dev/null
+++ b/internal/middleware/language.go
@@ -0,0 +1,34 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package middleware
+
+import (
+ "context"
+ "net/http"
+
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
+)
+
+type tagKey struct{}
+
+var matcher = language.NewMatcher(message.DefaultCatalog.Languages())
+
+// Language is a middleware that provides browser i18n information to handlers,
+// in the form of a golang.org/x/text/language.Tag.
+func Language(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ tag, _ := language.MatchStrings(matcher, r.Header.Get("Accept-Language"))
+ h.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), tagKey{}, tag)))
+ })
+}
+
+// LanguageTag returns the language.Tag from the context, or language.English if none is set.
+func LanguageTag(ctx context.Context) language.Tag {
+ if tag, ok := ctx.Value(tagKey{}).(language.Tag); ok {
+ return tag
+ }
+ return language.English
+}