Skip to content

Commit

Permalink
z18n: actually translate messages (hidden setting for now)
Browse files Browse the repository at this point in the history
Also mark more messages and fix a few minor things in z18n.
  • Loading branch information
arp242 committed Jun 7, 2021
1 parent 8f7be90 commit ef68024
Show file tree
Hide file tree
Showing 37 changed files with 289 additions and 201 deletions.
1 change: 1 addition & 0 deletions .ignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/public/jquery.js
/public/*.min.*
/pack
/msg
47 changes: 13 additions & 34 deletions docs/translating.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ prefixes:
error/ Error messages
link/ Links
p/ Paragraphs of text
top-nav/ Navigation at top
bot-nav/ Navigation at bottom
dash-nav/ Dashboard navigation

----

Expand All @@ -63,52 +66,28 @@ Files to be translated:
handlers/settings_user.go
handlers/user.go

tpl/_backend_bottom.gohtml
tpl/_backend_signin.gohtml
tpl/_backend_top.gohtml
tpl/_bottom_links.gohtml
tpl/_dashboard_hchart.gohtml
tpl/_dashboard_pages.gohtml
tpl/_dashboard_pages_refs.gohtml
tpl/_dashboard_pages_rows.gohtml
tpl/_dashboard_pages_text.gohtml
tpl/_dashboard_pages_text_rows.gohtml
tpl/_dashboard_toprefs.gohtml
tpl/_dashboard_totals.gohtml
tpl/_dashboard_totals_row.gohtml
tpl/_dashboard_warn_collect.gohtml
tpl/_dashboard_widgets.gohtml
tpl/_email_bottom.gotxt
tpl/_top.gohtml
tpl/_user_dashboard_widgets.gohtml
tpl/_user_nav.gohtml
tpl/backend_updates.gohtml
tpl/dashboard.gohtml
tpl/email_adduser.gotxt
tpl/email_export_done.gotxt
tpl/email_forgot_site.gotxt
tpl/email_import_done.gotxt
tpl/email_import_error.gotxt
tpl/email_password_reset.gotxt
tpl/email_verify.gotxt
tpl/email_welcome.gotxt
tpl/settings_changecode.gohtml
tpl/settings_delete.gohtml
tpl/settings_export.gohtml
tpl/settings_main.gohtml
tpl/settings_purge.gohtml
tpl/settings_purge_confirm.gohtml
tpl/settings_sites.gohtml
tpl/settings_sites_rm_confirm.gohtml
tpl/settings_users.gohtml
tpl/settings_users_form.gohtml
tpl/totp.gohtml
tpl/user.gohtml
tpl/user_api.gohtml
tpl/user_auth.gohtml
tpl/user_dashboard.gohtml
tpl/user_forgot_code.gohtml
tpl/user_forgot_pw.gohtml
tpl/user_pref.gohtml

tpl/_email_bottom.gotxt
tpl/email_adduser.gotxt
tpl/email_export_done.gotxt
tpl/email_forgot_site.gotxt
tpl/email_import_done.gotxt
tpl/email_import_error.gotxt
tpl/email_password_reset.gotxt
tpl/email_verify.gotxt
tpl/email_welcome.gotxt

public/backend.js
8 changes: 4 additions & 4 deletions handlers/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,19 +136,19 @@ func (h backend) Mount(r chi.Router, db zdb.DB, dev bool, domainStatic string, d
})

{
af := r.With(keyAuth, loggedIn)
af := r.With(keyAuth, loggedIn, addz18n())
bosmang{}.mount(af, db)
}

a := r.With(mware.Headers(headers), keyAuth)
a := r.With(mware.Headers(headers), keyAuth, addz18n())
user{}.mount(a)
{
ap := a.With(loggedInOrPublic)
ap := a.With(loggedInOrPublic, addz18n())
ap.Get("/", zhttp.Wrap(h.dashboard))
ap.Get("/load-widget", zhttp.Wrap(h.loadWidget))
}
{
af := a.With(loggedIn)
af := a.With(loggedIn, addz18n())
if zstripe.SecretKey != "" && zstripe.SignSecret != "" && zstripe.PublicKey != "" {
billing{}.mount(a, af)
}
Expand Down
28 changes: 24 additions & 4 deletions handlers/mw.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ var (
}, "/bosmang/profile/setrate")
)

var bundle = z18n.NewBundle(language.MustParse("en-UK"))
var bundle = func() *z18n.Bundle {
b := z18n.NewBundle(language.MustParse("en-GB"))
//b.AddMessages(language.MustParse("nl-NL"), msg.NL_NL())
return b
}()

type statusWriter interface{ Status() int }

Expand Down Expand Up @@ -180,10 +184,26 @@ func addctx(db zdb.DB, loadSite bool, dashTimeout int) func(http.Handler) http.H
*r = *r.WithContext(goatcounter.WithSite(r.Context(), &s))
}

// Add z18n.
var siteLang, userLang string // TODO: load from site/user preferences.
*r = *r.WithContext(z18n.With(r.Context(), bundle.Locale(userLang, siteLang, r.Header.Get("Accept-Language"))))
// Make sure there's always a z18n object.
*r = *r.WithContext(z18n.With(r.Context(), bundle.Locale(r.Header.Get("Accept-Language"))))

next.ServeHTTP(w, r)
})
}
}

func addz18n() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var siteLang, userLang string
if s := goatcounter.GetSite(r.Context()); s != nil {
siteLang = s.UserDefaults.Language
}
if u := goatcounter.GetUser(r.Context()); u != nil {
userLang = u.Settings.Language
}

*r = *r.WithContext(z18n.With(r.Context(), bundle.Locale(userLang, siteLang, r.Header.Get("Accept-Language"))))
next.ServeHTTP(w, r)
})
}
Expand Down
2 changes: 1 addition & 1 deletion handlers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (h user) mount(r chi.Router) {
rate.Get("/user/verify/{key}", zhttp.Wrap(h.verify))
rate.Post("/user/reset/{key}", zhttp.Wrap(h.doReset))

auth := r.With(loggedIn)
auth := r.With(loggedIn, addz18n())
auth.Post("/user/logout", zhttp.Wrap(h.logout))
auth.Post("/user/change-password", zhttp.Wrap(h.changePassword))
auth.Post("/user/disable-totp", zhttp.Wrap(h.disableTOTP))
Expand Down
7 changes: 4 additions & 3 deletions public/all.min.css
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,17 @@ table td.right {
font-variant-numeric: tabular-nums;
font-family: sans-serif;
}
sup, sub {
sup, sub, .sup, .sub {
height: 0;
line-height: 1;
vertical-align: baseline;
position: relative;
font-size: smaller;
}
sup {
sup, .sup {
bottom: 1ex;
}
sub {
sub, .sub {
top: .5ex;
}
hr {
Expand Down
4 changes: 4 additions & 0 deletions settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type (
UserSettings struct {
TwentyFourHours bool `json:"twenty_four_hours"`
SundayStartsWeek bool `json:"sunday_starts_week"`
Language string `json:"language"`
DateFormat string `json:"date_format"`
NumberFormat rune `json:"number_format"`
Timezone *tz.Zone `json:"timezone"`
Expand Down Expand Up @@ -463,6 +464,9 @@ func (v Views) Get(name string) (View, int) {
}

func (ss *UserSettings) Defaults() {
if ss.Language == "" {
ss.Language = "en-GB"
}
if ss.DateFormat == "" {
ss.DateFormat = "2 Jan ’06"
}
Expand Down
8 changes: 6 additions & 2 deletions tpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ import (
)

func init() {
tplfunc.Add("t", func(ctx context.Context, msg string, data ...interface{}) template.HTML {
return template.HTML(z18n.T(ctx, msg, data...))
tplfunc.Add("t", z18n.Thtml)
tplfunc.Add("tag", z18n.Tag)

// TODO: move to ztpl
tplfunc.Add("concat", func(sep string, strs ...string) string {
return strings.Join(strs, sep)
})

tplfunc.Add("percentage", func(n, total int) float64 {
Expand Down
7 changes: 4 additions & 3 deletions tpl/_backend_bottom.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
{{template "_bottom_links.gohtml" .}}
{{if and .User.ID .Billing (eq .Path "/") (.Site.ShowPayBanner .Context)}}
<div id="trial-expired">
<p>Hey hey; you’ve been using GoatCounter for more than 14 days.<br>
Please choose if you want to subscribe to a plan or continue with the
free plan on the <a href="/billing">billing page</a>.</p>
<p>{{.T `nav-bot/trial-expired|Hey hey; you’ve been using GoatCounter for more than 14 days.<br>
Please choose if you want to subscribe to a plan or continue with the free plan on the %[link billing page].`
(tag "a" `href="/billing"`)}}
</p>
</div>
{{end}}
<span id="js-settings"
Expand Down
36 changes: 21 additions & 15 deletions tpl/_backend_top.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<body id="page-{{.Path | path_id}}">
<noscript>
<p>GoatCounter requires JavaScript enabled to function well; please allow JavaScript to run from {{.StaticDomain}}.</p>
<p>{{.T "top-nav/need-js|GoatCounter requires JavaScript enabled to function well; please allow JavaScript to run from %(domain)." .StaticDomain}}</p>
<!--
<p><small>For a rationale, see: <a href="https://arp242.net/noscript.html">https://arp242.net/noscript.html</a></small></p>
-->
Expand All @@ -22,7 +22,8 @@
<div>
{{if eq .Path "/"}}
{{- if gt (len .SubSites) 1 -}}
Sites:
{{/* z18n: "Site switcher", a list of sites will follow; e.g. "Sites: [site1] [site2]" */}}
{{.T "top-nav/sites|Sites:"}}
{{- range $i, $s := .SubSites -}}
{{- if gt $i 0 -}}|{{- end -}}
{{if $.GoatcounterCom}} <a{{if eq $s $.Site.Code}} class="active"{{end}} href="//{{$s}}.{{$.Domain}}{{$.Port}}">{{$s}}</a>
Expand All @@ -31,34 +32,39 @@
{{- end -}}
{{- end -}}
{{else if has_prefix .Path "/settings/sites/remove/"}}
<strong id="back"><a href="/settings/sites">←&#xfe0e; Back</a></strong>
<strong id="back"><a href="/settings/sites">←&#xfe0e; {{.T "top-nav/back|Back"}}</a></strong>
{{else if has_prefix .Path "/settings/purge/confirm"}}
<strong id="back"><a href="/settings/purge">←&#xfe0e; Back</a></strong>
<strong id="back"><a href="/settings/purge">←&#xfe0e; {{.T "top-nav/back|Back"}}</a></strong>
{{else if has_prefix .Path "/billing/"}}
<strong id="back"><a href="/billing">←&#xfe0e; Back</a></strong>
<strong id="back"><a href="/billing">←&#xfe0e; {{.T "top-nav/back|Back"}}</a></strong>
{{else}}
<strong id="back"><a href="/">←&#xfe0e; Dashboard</a></strong>
<strong id="back"><a href="/">←&#xfe0e; {{.T "top-nav/dashboard|Dashboard"}}</a></strong>
{{end}}
</div>
<div>
{{if .GoatcounterCom}}<a href="/updates" class="{{if .HasUpdates}}updates{{end}} {{if eq .Path "/updates"}}active{{end}}">Updates</a> |{{end}}
<a {{if eq .Path "/code"}}class="active" {{end}}href="/code">Site code</a> |
{{if .User.AccessSettings}}<a {{if has_prefix .Path "/settings"}}class="active" {{end}}href="/settings">Settings</a> |{{end}}
<a {{if has_prefix .Path "/user"}}class="active" {{end}}href="/user">User</a> |
{{if .GoatcounterCom}}<a href="/updates" class="{{if .HasUpdates}}updates{{end}} {{if eq .Path "/updates"}}active{{end}}">{{.T "top-nav/updates|Updates"}}</a> |{{end}}
<a {{if eq .Path "/code"}}class="active" {{end}}href="/code">{{.T "top-nav/site-code|Site code"}}</a> |
{{if .User.AccessSettings}}<a {{if has_prefix .Path "/settings"}}class="active" {{end}}href="/settings">{{.T "top-nav/settings|Settings"}}</a> |{{end}}
<a {{if has_prefix .Path "/user"}}class="active" {{end}}href="/user">{{.T "top-nav/user|User"}}</a> |
<form method="post" action="/user/logout">
<input type="hidden" name="csrf" value="{{.User.CSRFToken}}">
<button class="link">Sign out</button>
<button class="link">{{.T "top-nav/sign-out|Sign out"}}</button>
</form>
</div>
{{else if .Site.Settings.Public}}
<div style="margin-left: .3em;">
{{if .Site.LinkDomain -}}
Analytics for <a href="http://{{.Site.LinkDomain}}" target="_blank" rel="noopener">{{.Site.LinkDomain}}</a>.
{{.T "top-nav/public-link|Analytics for %[link %(domain)]." (map
"link" (tag "a" (printf `target="_blank" rel="noopener" href="%s"` .Site.LinkDomain))
"domain" .Site.LinkDomain
)}}
{{end}}
The public view is updated once an hour{{if .User.Settings.Timezone}}; all times are in
{{join .User.Settings.Timezone.Abbr ", "}} ({{.User.Settings.Timezone.OffsetDisplay}}){{end}}
{{.T "top-nav/public-time|The public view is updated once an hour; all times are in %(timezone-name) (%(timezone-offset))." (map
"timezone-name" (join .User.Settings.Timezone.Abbr ", ")
"timezone-offset" .User.Settings.Timezone.OffsetDisplay
)}}
</div>
<div id="signin"><a href="/user/new">Sign in</a></div>
<div id="signin"><a href="/user/new">{{.T "top-nav/sign-in|Sign in"}}</a></div>
{{- end -}}
</nav>

Expand Down
10 changes: 5 additions & 5 deletions tpl/_bottom_links.gohtml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<footer class="center cbox">
<div>
<a {{if .Site}}target="_blank" rel="noopener"{{end}} href="https://www.goatcounter.com">Home</a><span> |</span>
<a href="/contact" >Contact</a><span> |</span>
<a href="/help" >Documentation</a><span> |</span>
<a href="/contribute">Contribute</a>
<a {{if .Site}}target="_blank" rel="noopener"{{end}} href="https://www.goatcounter.com">{{.T "nav-bot/home|Home"}}</a><span> |</span>
<a href="/contact" >{{.T "nav-bot/contact|Contact"}}</a><span> |</span>
<a href="/help" >{{.T "nav-bot/docs|Documentation"}}</a><span> |</span>
<a href="/contribute">{{.T "nav-bot/contribute|Contribute"}}</a>
</div>
<div>
<a href="https://github.com/zgoat/goatcounter" target="_blank" rel="noopener">Source code</a><span> |</span>
<a href="https://github.com/zgoat/goatcounter" target="_blank" rel="noopener">{{.T "nav-bot/src|Source code"}}</a><span> |</span>
<a href="https://nlnet.nl/project/GoatCounter/" target="_blank" rel="noopener">NLnet NGI0</a><span> |</span>
<a href="https://github.com/sponsors/arp242" target="_blank" rel="noopener">GitHub sponsors</a><span> |</span>
<a href="https://patreon.com/arp242" target="_blank" rel="noopener">Patreon</a><span> |</span>
Expand Down
2 changes: 1 addition & 1 deletion tpl/_contact.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
{{if has_errors .v}}
<div class="flash flash-e"
style="position: fixed; bottom: 0; right: .5em; min-width: 20em; z-index: 5; text-align: left;">
Additional errors:{{.v.HTML}}</div>
{{.T "p/additional-errors|Additional errors"}}:{{.v.HTML}}</div>
{{end}}
{{end}}

Expand Down
4 changes: 2 additions & 2 deletions tpl/_dashboard_hchart.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
{{- else -}}
<div class="hchart" data-widget="{{.ID}}">
<h2>{{.Header}}</h2>
{{template "_dashboard_warn_collect.gohtml" .IsCollected}}
{{template "_dashboard_warn_collect.gohtml" (map "IsCollected" .IsCollected "Context" .Context)}}
{{if .Err}}
<em>Error: {{.Err}}</em>
<em>{{.T "p/error|Error: %(error-message)" .Err}}</em>
{{else}}
{{$x}}
{{end}}
Expand Down
17 changes: 12 additions & 5 deletions tpl/_dashboard_pages.gohtml
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
<div class="pages-list {{if .Daily}}pages-list-daily{{end}}" data-widget="{{.ID}}">
{{/* TODO: make option to split counts between events and regular pageviews */}}
<h2 class="full-width">Pages <small>
{{/* TODO: make option to split counts between events and regular pageviews */}}
<span class="total-unique-display">{{nformat .TotalUniqueDisplay $.User}}</span> out of
{{nformat .TotalUnique $.User}} visits shown
</small></h2>
{{/*
TODO: bit tricky due to nested HTML
{{t .Context "header/pages|Pages %[small %(n) out of %(total) visits shown]" (dict
"small" (tag "small")
"n" (nformat .TotalUniqueDisplay $.User)
"total" (nformat .TotalUnique $.User)
)}}
*/}}

{{if .Err}}
<em>Error: {{.Err}}</em>
<em>{{t .Context "p/error|Error: %(error-message)" .Err}}</em>
{{else}}
<table class="count-list count-list-pages" data-max="{{.Max}}" data-scale="{{.Max}}">
<tbody class="pages">{{template "_dashboard_pages_rows.gohtml" .}}</tbody>
</table>
<a href="#" class="load-more" {{if not .MorePages}}style="display: none"{{end}}>Show more</a>
<a href="#" class="load-more" {{if not .MorePages}}style="display: none"{{end}}>{{t .Context "link/show-more|Show more"}}</a>
{{end}}
</div>


16 changes: 8 additions & 8 deletions tpl/_dashboard_pages_rows.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@
</td>
<td class="col-path hide-mobile">
<a class="load-refs rlink" title="{{$h.Path}}" href="#">{{$h.Path}}</a><br>
<small class="page-title {{if not $h.Title}}no-title{{end}}">{{if $h.Title}}{{$h.Title}}{{else}}<em>(no title)</em>{{end}}</small>
{{if $h.Event}}<sup class="label-event">event</sup>{{end}}
<small class="page-title {{if not $h.Title}}no-title{{end}}">{{if $h.Title}}{{$h.Title}}{{else}}<em>({{t $.Context "no-title|no title"}})</em>{{end}}</small>
{{if $h.Event}}<sup class="label-event">{{t $.Context "event|event"}}</sup>{{end}}

{{if and $.Site.LinkDomain (not $h.Event)}}
<br><small class="go"><a target="_blank" rel="noopener" href="https://{{$.Site.LinkDomain}}{{$h.Path}}">Go to {{$.Site.LinkDomain}}{{$h.Path}}</a></small>
<br><small class="go"><a target="_blank" rel="noopener" href="https://{{$.Site.LinkDomain}}{{$h.Path}}">{{t $.Context "link/goto-path|Go to %(path)" (concat "" $.Site.LinkDomain $h.Path)}}</a></small>
{{end}}
</td>
<td>
<div class="show-mobile">
<a class="load-refs rlink" title="{{$h.Path}}" href="#">{{$h.Path}}</a>
<small class="page-title {{if not $h.Title}}no-title{{end}}">| {{if $h.Title}}{{$h.Title}}{{else}}<em>(no title)</em>{{end}}</small>
{{if $h.Event}}<sup class="label-event">event</sup>{{end}}
{{if $h.Event}}<sup class="label-event">{{t $.Context "event|event"}}</sup>{{end}}
{{if and $.Site.LinkDomain (not $h.Event)}}
<br><small class="go"><a target="_blank" rel="noopener" href="https://{{$.Site.LinkDomain}}{{$h.Path}}">Go to {{$.Site.LinkDomain}}{{$h.Path}}</a></small>
<br><small class="go"><a target="_blank" rel="noopener" href="https://{{$.Site.LinkDomain}}{{$h.Path}}">{{t $.Context "link/goto-path|Go to %(path)" (concat "" $.Site.LinkDomain $h.Path)}}</a></small>
{{end}}
</div>
<div class="chart chart-bar" data-max="{{$h.Max}}">
<span class="chart-left"><a href="#" class="rescale" title="Scale Y axis to max">↕&#xfe0e;</a></span>
<span class="chart-left"><a href="#" class="rescale" title="{{t $.Context "scale-y|Scale Y axis to max"}}">↕&#xfe0e;</a></span>
<span class="chart-right">{{$n := sum $.Offset $i}}
{{- if (eq $i 0)}}<small class="scale" title="Y-axis scale">{{nformat $.Max $.User}}</small>
{{- else if ge $n 11}}<span class="page-n" title="Page ranking">#{{$n}}</span>{{end -}}
{{- if (eq $i 0)}}<small class="scale" title="{{t $.Context "y-scale|Y-axis scale"}}">{{nformat $.Max $.User}}</small>
{{- else if ge $n 11}}<span class="page-n" title="{{t $.Context "page-ranking|Page ranking"}}">#{{$n}}</span>{{end -}}
</span>
<span class="half"></span>
{{bar_chart $.Context .Stats $.Max $.Daily}}
Expand Down
Loading

0 comments on commit ef68024

Please sign in to comment.