mirror of
https://git.ptzo.gdn/feditools/relay.git
synced 2024-09-21 09:57:31 +00:00
Metrics (#53)
This commit is contained in:
parent
32fb83af2f
commit
30e1682104
17
Jenkinsfile
vendored
17
Jenkinsfile
vendored
@ -1,12 +1,11 @@
|
||||
pipeline {
|
||||
environment {
|
||||
BUILD_IMAGE = 'gobuild:1.18'
|
||||
BUILD_ARGS = '-e GOCACHE=/gocache -e HOME=${WORKSPACE} -v /var/lib/jenkins/gocache:/gocache -v /var/lib/jenkins/go/pkg:/go/pkg'
|
||||
PATH = '/go/bin:~/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin'
|
||||
composeFile = "deployments/docker-compose-integration.yaml"
|
||||
networkName = "network-${env.BUILD_TAG}"
|
||||
registry = 'tyrm/relay'
|
||||
registryCredential = 'docker-io-feditools'
|
||||
dockerImage = ''
|
||||
gitDescribe = ''
|
||||
}
|
||||
|
||||
agent any
|
||||
@ -16,8 +15,8 @@ pipeline {
|
||||
stage('Build Static Assets') {
|
||||
agent {
|
||||
docker {
|
||||
image 'gobuild:1.18'
|
||||
args '-e HOME=${WORKSPACE}'
|
||||
image "${BUILD_IMAGE}"
|
||||
args "${BUILD_ARGS}"
|
||||
reuseNode true
|
||||
}
|
||||
}
|
||||
@ -53,8 +52,8 @@ pipeline {
|
||||
stage('Test') {
|
||||
agent {
|
||||
docker {
|
||||
image 'gobuild:1.18'
|
||||
args '--network ${networkName} -e HOME=${WORKSPACE}'
|
||||
image "${BUILD_IMAGE}"
|
||||
args "--network ${networkName} ${BUILD_ARGS}"
|
||||
reuseNode true
|
||||
}
|
||||
}
|
||||
@ -79,8 +78,8 @@ pipeline {
|
||||
stage('Build Snapshot') {
|
||||
agent {
|
||||
docker {
|
||||
image 'gobuild:1.18'
|
||||
args '--network ${networkName} -e HOME=${WORKSPACE}'
|
||||
image "${BUILD_IMAGE}"
|
||||
args "--network ${networkName} ${BUILD_ARGS}"
|
||||
reuseNode true
|
||||
}
|
||||
}
|
||||
|
8
Makefile
8
Makefile
@ -31,13 +31,13 @@ fmt:
|
||||
@go fmt $(shell go list ./... | grep -v /vendor/)
|
||||
|
||||
i18n-extract:
|
||||
goi18n extract -outdir locales
|
||||
goi18n extract -format yaml -outdir web/locales
|
||||
|
||||
i18n-merge:
|
||||
goi18n merge -outdir locales locales/active.*.toml locales/translate.*.toml
|
||||
goi18n merge -format yaml -outdir locales web/locales/active.*.toml web/locales/translate.*.toml
|
||||
|
||||
i18n-translations:
|
||||
goi18n merge -outdir locales locales/active.*.toml
|
||||
goi18n merge -format yaml -outdir locales web/locales/active.*.toml
|
||||
|
||||
lint:
|
||||
@echo linting
|
||||
@ -66,4 +66,4 @@ tidy:
|
||||
vendor: tidy
|
||||
go mod vendor
|
||||
|
||||
.PHONY: build-snapshot bun-new-migration clean fmt lint stage-static npm-scss npm-upgrade docker-restart docker-start docker-stop release stage-static test test-ext test-race test-race-ext test-verbose tidy vendor
|
||||
.PHONY: build-snapshot bun-new-migration clean fmt i18n-extract i18n-merge i18n-translations lint stage-static npm-scss npm-upgrade docker-restart docker-start docker-stop release stage-static test test-ext test-race test-race-ext test-verbose tidy vendor
|
||||
|
@ -3,7 +3,6 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"github.com/feditools/go-lib"
|
||||
liblanguage "github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/go-lib/metrics"
|
||||
"github.com/feditools/relay/internal/config"
|
||||
"github.com/feditools/relay/internal/db"
|
||||
@ -12,6 +11,7 @@ import (
|
||||
"github.com/feditools/relay/internal/http/activitypub"
|
||||
"github.com/feditools/relay/internal/http/static"
|
||||
"github.com/feditools/relay/internal/http/webapp"
|
||||
liblanguage "github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/logic"
|
||||
"github.com/feditools/relay/internal/runner"
|
||||
"github.com/feditools/relay/internal/token"
|
||||
|
@ -3,7 +3,6 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/go-lib/metrics/statsd"
|
||||
"github.com/feditools/relay/cmd/relay/action"
|
||||
"github.com/feditools/relay/internal/clock"
|
||||
@ -12,6 +11,7 @@ import (
|
||||
"github.com/feditools/relay/internal/fedi"
|
||||
"github.com/feditools/relay/internal/http"
|
||||
"github.com/feditools/relay/internal/kv/redis"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/logic/logic1"
|
||||
"github.com/feditools/relay/internal/runner/faktory"
|
||||
"github.com/feditools/relay/internal/token"
|
||||
@ -111,7 +111,7 @@ var Start action.Action = func(topCtx context.Context) error {
|
||||
|
||||
// create logic module
|
||||
l.Debug("creating logic module")
|
||||
logicMod, err := logic1.New(ctx, clockMod, dbClient, httpClient, tokz)
|
||||
logicMod, err := logic1.New(ctx, clockMod, dbClient, httpClient, kvClient, tokz)
|
||||
if err != nil {
|
||||
l.Errorf("logic: %s", err.Error())
|
||||
cancel()
|
||||
|
@ -23,6 +23,8 @@ func Server(cmd *cobra.Command, values config.Values) {
|
||||
cmd.PersistentFlags().String(config.Keys.WebappBootstrapCSSIntegrity, values.WebappBootstrapCSSIntegrity, usage.WebappBootstrapCSSIntegrity)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappBootstrapJSURI, values.WebappBootstrapJSURI, usage.WebappBootstrapJSURI)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappBootstrapJSIntegrity, values.WebappBootstrapJSIntegrity, usage.WebappBootstrapJSIntegrity)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappChartJSURI, values.WebappChartJSURI, usage.WebappChartJSURI)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappChartJSIntegrity, values.WebappChartJSIntegrity, usage.WebappChartJSIntegrity)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappFontAwesomeCSSURI, values.WebappFontAwesomeCSSURI, usage.WebappFontAwesomeCSSURI)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappFontAwesomeCSSIntegrity, values.WebappFontAwesomeCSSIntegrity, usage.WebappFontAwesomeCSSIntegrity)
|
||||
cmd.PersistentFlags().String(config.Keys.WebappLogoSrcDark, values.WebappLogoSrcDark, usage.WebappLogoSrcDark)
|
||||
|
8
go.mod
8
go.mod
@ -5,7 +5,7 @@ go 1.18
|
||||
require (
|
||||
github.com/contribsys/faktory v1.6.1
|
||||
github.com/contribsys/faktory_worker_go v1.6.0
|
||||
github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e
|
||||
github.com/feditools/go-lib v0.16.0
|
||||
github.com/go-fed/activity v1.0.0
|
||||
github.com/go-fed/httpsig v1.1.0
|
||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||
@ -19,6 +19,7 @@ require (
|
||||
github.com/jackc/pgconn v1.13.0
|
||||
github.com/jackc/pgx/v4 v4.17.0
|
||||
github.com/nickname76/telegrambot v1.1.1
|
||||
github.com/nicksnyder/go-i18n/v2 v2.2.0
|
||||
github.com/rbcervilla/redisstore/v8 v8.1.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/speps/go-hashids/v2 v2.0.1
|
||||
@ -33,6 +34,8 @@ require (
|
||||
github.com/uptrace/bun/extra/bundebug v1.1.7
|
||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
modernc.org/sqlite v1.17.1
|
||||
)
|
||||
|
||||
@ -71,7 +74,6 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nickname76/repeater v1.0.1 // indirect
|
||||
github.com/nicksnyder/go-i18n/v2 v2.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
@ -88,11 +90,9 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.10 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.36.0 // indirect
|
||||
|
6
go.sum
6
go.sum
@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
|
||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
@ -90,8 +90,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e h1:cvxBlyoDUq1KOnWD0Xb8muGu+X70T8vFe2UYdvpS9Es=
|
||||
github.com/feditools/go-lib v0.15.2-0.20220810024219-2d57c75a871e/go.mod h1:LtdLBvApYAhdblS6rTGQ12ZzySI9/6PyTiZlxw5uX10=
|
||||
github.com/feditools/go-lib v0.16.0 h1:sxAxvRb97Xn/jaDOSljMsWiXTVulbCZZHhr4sMRDrZE=
|
||||
github.com/feditools/go-lib v0.16.0/go.mod h1:kMw3Dl5vJ2j0dHtD5OHPy9lsm8v+p/szKM01yqX+gMY=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
|
@ -45,6 +45,8 @@ type KeyNames struct {
|
||||
WebappBootstrapCSSIntegrity string
|
||||
WebappBootstrapJSURI string
|
||||
WebappBootstrapJSIntegrity string
|
||||
WebappChartJSURI string
|
||||
WebappChartJSIntegrity string
|
||||
WebappFontAwesomeCSSURI string
|
||||
WebappFontAwesomeCSSIntegrity string
|
||||
WebappLogoSrcDark string
|
||||
@ -104,6 +106,8 @@ var Keys = KeyNames{
|
||||
WebappBootstrapCSSIntegrity: "webapp-bootstrap-css-integrity",
|
||||
WebappBootstrapJSURI: "webapp-bootstrap-js-uri",
|
||||
WebappBootstrapJSIntegrity: "webapp-bootstrap-js-integrity",
|
||||
WebappChartJSURI: "webapp-chart-js-uri",
|
||||
WebappChartJSIntegrity: "webapp-chart-js-integrity",
|
||||
WebappFontAwesomeCSSURI: "webapp-fontawesome-css-uri",
|
||||
WebappFontAwesomeCSSIntegrity: "webapp-fontawesome-css-integrity",
|
||||
WebappLogoSrcDark: "webapp-logo-src-dark",
|
||||
|
@ -45,6 +45,8 @@ type Values struct {
|
||||
WebappBootstrapCSSIntegrity string
|
||||
WebappBootstrapJSURI string
|
||||
WebappBootstrapJSIntegrity string
|
||||
WebappChartJSURI string
|
||||
WebappChartJSIntegrity string
|
||||
WebappFontAwesomeCSSURI string
|
||||
WebappFontAwesomeCSSIntegrity string
|
||||
WebappLogoSrcDark string
|
||||
@ -104,6 +106,8 @@ var Defaults = Values{
|
||||
WebappBootstrapCSSIntegrity: "sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor",
|
||||
WebappBootstrapJSURI: "https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js",
|
||||
WebappBootstrapJSIntegrity: "sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2",
|
||||
WebappChartJSURI: "https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js",
|
||||
WebappChartJSIntegrity: "sha384-9MhbyIRcBVQiiC7FSd7T38oJNj2Zh+EfxS7/vjhBi4OOT78NlHSnzM31EZRWR1LZ",
|
||||
WebappFontAwesomeCSSURI: "https://cdn.fedi.tools/vendor/fontawesome-free-6.1.1/css/all.min.css",
|
||||
WebappFontAwesomeCSSIntegrity: "sha384-/frq1SRXYH/bSyou/HUp/hib7RVN1TawQYja658FEOodR/FQBKVqT9Ol+Oz3Olq5",
|
||||
WebappLogoSrcDark: "https://cdn.fedi.tools/img/feditools-logo-dark.svg",
|
||||
|
@ -1,6 +1,7 @@
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/feditools/go-lib/fedihelper"
|
||||
@ -120,5 +121,7 @@ func (m *Module) inboxPostHandler(w nethttp.ResponseWriter, r *nethttp.Request)
|
||||
return
|
||||
}
|
||||
|
||||
go m.logic.MetricsIncReceived(context.Background(), instance.ID)
|
||||
|
||||
w.WriteHeader(nethttp.StatusAccepted)
|
||||
}
|
||||
|
16
internal/http/template/admin_instance_view.go
Normal file
16
internal/http/template/admin_instance_view.go
Normal file
@ -0,0 +1,16 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"github.com/feditools/relay/internal/models"
|
||||
)
|
||||
|
||||
// AdminInstanceViewName is the name of the admin block list template.
|
||||
const AdminInstanceViewName = "admin_instance_view"
|
||||
|
||||
// AdminInstanceView contains the variables for the admin block list template.
|
||||
type AdminInstanceView struct {
|
||||
Common
|
||||
|
||||
Instance *models.Instance
|
||||
Breadcrumbs *[]Breadcrumb
|
||||
}
|
6
internal/http/template/breadcrumb.go
Normal file
6
internal/http/template/breadcrumb.go
Normal file
@ -0,0 +1,6 @@
|
||||
package template
|
||||
|
||||
type Breadcrumb struct {
|
||||
HRef string
|
||||
Text string
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
)
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/config"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"github.com/feditools/relay/internal/token"
|
||||
@ -41,6 +41,7 @@ func New(tokz *token.Tokenizer) (*template.Template, error) {
|
||||
"pathAppAdminBlockExportCSV": path.GenAppAdminBlockExportCSV,
|
||||
"pathAppAdminBlockExportJSON": path.GenAppAdminBlockExportJSON,
|
||||
"pathAppAdminHome": path.GenAppAdminHomePath,
|
||||
"pathAppAdminInstanceView": path.GenAppAdminInstanceViewPath,
|
||||
"pathAppHome": path.GenAppHomePath,
|
||||
"pathAppLog": path.GenAppLogPath,
|
||||
"pathAppLogin": path.GenAppLoginPath,
|
||||
|
@ -2,9 +2,9 @@ package webapp
|
||||
|
||||
import (
|
||||
libhttp "github.com/feditools/go-lib/http"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package webapp
|
||||
|
||||
import (
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/util"
|
||||
"net/http"
|
||||
@ -93,7 +93,7 @@ func (m *Module) doAddBlock(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
FormAddError: &libtemplate.Alert{
|
||||
Color: libtemplate.ColorDanger,
|
||||
Text: localizer.TextBlockExists(domain).String(),
|
||||
Text: localizer.TextBlockExistsDomain(domain).String(),
|
||||
},
|
||||
|
||||
FormAddDomainValue: domain,
|
||||
|
@ -2,9 +2,9 @@ package webapp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/db"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/token"
|
||||
"net/http"
|
||||
|
@ -3,9 +3,9 @@ package webapp
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/db"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/token"
|
||||
"github.com/feditools/relay/internal/util"
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
libhttp "github.com/feditools/go-lib/http"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/util"
|
||||
"io"
|
||||
|
@ -2,9 +2,9 @@ package webapp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -2,9 +2,9 @@ package webapp
|
||||
|
||||
import (
|
||||
libhttp "github.com/feditools/go-lib/http"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"net/http"
|
||||
)
|
||||
|
113
internal/http/webapp/admin_instance_view.go
Normal file
113
internal/http/webapp/admin_instance_view.go
Normal file
@ -0,0 +1,113 @@
|
||||
package webapp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/db"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"github.com/feditools/relay/internal/token"
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// AdminInstanceViewGetHandler serves the instance info page.
|
||||
func (m *Module) AdminInstanceViewGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
l := logger.WithField("func", "AdminInstanceViewGetHandler")
|
||||
|
||||
// lookup instance
|
||||
vars := mux.Vars(r)
|
||||
kind, id, err := m.tokz.DecodeToken(vars[path.VarInstanceID])
|
||||
if err != nil {
|
||||
l.Debugf("decode token: %s", err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusBadRequest, "bad token")
|
||||
|
||||
return
|
||||
}
|
||||
if kind != token.KindInstance {
|
||||
l.Debug("token is wrong kind")
|
||||
m.returnErrorPage(w, r, http.StatusBadRequest, "bad token")
|
||||
|
||||
return
|
||||
}
|
||||
instance, err := m.db.ReadInstance(r.Context(), id)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
l.Errorf("db read instance: %s", err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
if errors.Is(err, db.ErrNoEntries) {
|
||||
m.returnErrorPage(w, r, http.StatusNotFound, vars[path.VarInstanceID])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
m.displayAdminInstanceView(w, r, displayAdminInstanceViewConfig{
|
||||
Instance: instance,
|
||||
})
|
||||
}
|
||||
|
||||
type displayAdminInstanceViewConfig struct {
|
||||
Alerts *[]libtemplate.Alert
|
||||
|
||||
Instance *models.Instance
|
||||
}
|
||||
|
||||
func (m *Module) displayAdminInstanceView(w http.ResponseWriter, r *http.Request, config displayAdminInstanceViewConfig) {
|
||||
l := logger.WithField("func", "displayAdminInstanceView")
|
||||
|
||||
// get localizer
|
||||
localizer := r.Context().Value(ContextKeyLocalizer).(*language.Localizer) //nolint
|
||||
|
||||
// Init template variables
|
||||
tmplVars := &template.AdminInstanceView{
|
||||
Common: template.Common{
|
||||
PageTitle: localizer.TextInstance(1).String() + " " + config.Instance.UnicodeDomain(),
|
||||
},
|
||||
|
||||
Breadcrumbs: &[]template.Breadcrumb{
|
||||
{
|
||||
Text: localizer.TextInstance(2).String(),
|
||||
HRef: path.AppAdminInstance,
|
||||
},
|
||||
{
|
||||
Text: config.Instance.UnicodeDomain(),
|
||||
},
|
||||
},
|
||||
|
||||
Instance: config.Instance,
|
||||
}
|
||||
|
||||
// alerts
|
||||
tmplVars.Alerts = config.Alerts
|
||||
|
||||
// get metrics
|
||||
deliverErrors, err := m.logic.MetricsGetDeliverErrorWeek(r.Context(), config.Instance.ID)
|
||||
if err != nil {
|
||||
l.Errorf("get metrics deliver error: %s", err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
deliverSuccess, err := m.logic.MetricsGetDeliverSuccessWeek(r.Context(), config.Instance.ID)
|
||||
if err != nil {
|
||||
l.Errorf("get metrics deliver error: %s", err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
received, err := m.logic.MetricsGetReceivedWeek(r.Context(), config.Instance.ID)
|
||||
if err != nil {
|
||||
l.Errorf("get metrics deliver error: %s", err.Error())
|
||||
m.returnErrorPage(w, r, http.StatusInternalServerError, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
tmplVars.AddFooterExtraScript(JSAdminInstanceView(deliverErrors, deliverSuccess, received))
|
||||
tmplVars.AddFooterScript(m.footerScriptChartJS)
|
||||
|
||||
m.executeTemplate(w, r, template.AdminInstanceViewName, tmplVars)
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package webapp
|
||||
|
||||
import (
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package webapp
|
||||
|
||||
import (
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"net/http"
|
||||
|
@ -2,7 +2,7 @@ package webapp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
)
|
||||
|
||||
const jsAdminBlock = `
|
||||
|
82
internal/http/webapp/js_chart.go
Normal file
82
internal/http/webapp/js_chart.go
Normal file
@ -0,0 +1,82 @@
|
||||
package webapp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/feditools/relay/internal/logic"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const jsAdminInstanceView = `
|
||||
new Chart(document.getElementById("deliveryChartContainer"), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [%s],
|
||||
datasets: [{
|
||||
data: [%s],
|
||||
label: "Error",
|
||||
borderColor: "#c45850",
|
||||
fill: false,
|
||||
lineTension: 0.2
|
||||
}, {
|
||||
data: [%s],
|
||||
label: "Success",
|
||||
borderColor: "#3cba9f",
|
||||
fill: false,
|
||||
lineTension: 0.2
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {}
|
||||
});
|
||||
|
||||
new Chart(document.getElementById("receiveChartContainer"), {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [%s],
|
||||
datasets: [{
|
||||
data: [%s],
|
||||
label: "Received",
|
||||
borderColor: "#3e95cd",
|
||||
fill: false,
|
||||
lineTension: 0.2
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {}
|
||||
});
|
||||
`
|
||||
|
||||
func JSAdminInstanceView(deliverErrors, deliverSuccess, receive *logic.MetricsDataPointsTime) string {
|
||||
labels := make([]string, len(*deliverErrors))
|
||||
for i, dp := range *deliverErrors {
|
||||
labels[i] = dp.X.Format("\"Jan 02 2006\"")
|
||||
}
|
||||
|
||||
deliverErrorsLen := len(*deliverErrors)
|
||||
deliverErrorsData := make([]string, deliverErrorsLen)
|
||||
for i, dp := range *deliverErrors {
|
||||
deliverErrorsData[deliverErrorsLen-1-i] = strconv.FormatInt(int64(dp.Y), 10)
|
||||
}
|
||||
|
||||
deliverSuccessLen := len(*deliverSuccess)
|
||||
deliverSuccessData := make([]string, deliverSuccessLen)
|
||||
for i, dp := range *deliverSuccess {
|
||||
deliverSuccessData[deliverSuccessLen-1-i] = strconv.FormatInt(int64(dp.Y), 10)
|
||||
}
|
||||
|
||||
receiveLen := len(*receive)
|
||||
receiveData := make([]string, receiveLen)
|
||||
for i, dp := range *receive {
|
||||
receiveData[receiveLen-1-i] = strconv.FormatInt(int64(dp.Y), 10)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
jsAdminInstanceView,
|
||||
strings.Join(labels, ","),
|
||||
strings.Join(deliverErrorsData, ","),
|
||||
strings.Join(deliverSuccessData, ","),
|
||||
strings.Join(labels, ","),
|
||||
strings.Join(receiveData, ","),
|
||||
)
|
||||
}
|
@ -3,10 +3,10 @@ package webapp
|
||||
import (
|
||||
"errors"
|
||||
"github.com/feditools/go-lib"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/db"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
nethttp "net/http"
|
||||
|
@ -2,9 +2,9 @@ package webapp
|
||||
|
||||
import (
|
||||
libhttp "github.com/feditools/go-lib/http"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -3,7 +3,7 @@ package webapp
|
||||
import (
|
||||
"context"
|
||||
libhttp "github.com/feditools/go-lib/http"
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
package webapp
|
@ -39,6 +39,7 @@ func (m *Module) Route(s *http.Server) error {
|
||||
admin.HandleFunc(path.AppAdminSubHome, m.AdminHomeGetHandler).Methods(nethttp.MethodGet)
|
||||
admin.HandleFunc(path.AppAdminSubHome, m.AdminHomePostHandler).Methods(nethttp.MethodPost)
|
||||
admin.HandleFunc(path.AppAdminSubInstance, m.AdminInstanceGetHandler).Methods(nethttp.MethodGet)
|
||||
admin.HandleFunc(path.AppAdminSubInstanceView, m.AdminInstanceViewGetHandler).Methods(nethttp.MethodGet)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package webapp
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/feditools/go-lib/language"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"net/http"
|
||||
)
|
||||
|
@ -2,8 +2,8 @@ package webapp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/models"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -97,12 +97,6 @@ func (m *Module) makeNavbar(r *http.Request) (template.Navbar, error) {
|
||||
FAIcon: "house",
|
||||
URL: path.AppHome,
|
||||
},
|
||||
{
|
||||
Text: l.TextActivityLog(1).String(),
|
||||
MatchStr: path.ReAppLog,
|
||||
FAIcon: "newspaper",
|
||||
URL: path.AppLog,
|
||||
},
|
||||
}
|
||||
|
||||
// show blocks page if any exist
|
||||
|
@ -3,7 +3,6 @@ package webapp
|
||||
import (
|
||||
"context"
|
||||
"encoding/gob"
|
||||
"github.com/feditools/go-lib/language"
|
||||
"github.com/feditools/go-lib/metrics"
|
||||
libtemplate "github.com/feditools/go-lib/template"
|
||||
"github.com/feditools/relay/internal/config"
|
||||
@ -12,6 +11,7 @@ import (
|
||||
ihttp "github.com/feditools/relay/internal/http"
|
||||
itemplate "github.com/feditools/relay/internal/http/template"
|
||||
"github.com/feditools/relay/internal/kv"
|
||||
"github.com/feditools/relay/internal/language"
|
||||
"github.com/feditools/relay/internal/logic"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"github.com/feditools/relay/internal/runner"
|
||||
@ -44,11 +44,12 @@ type Module struct {
|
||||
templates *template.Template
|
||||
tokz *token.Tokenizer
|
||||
|
||||
domain string
|
||||
logoSrcDark string
|
||||
logoSrcLight string
|
||||
headLinks []libtemplate.HeadLink
|
||||
footerScripts []libtemplate.Script
|
||||
domain string
|
||||
logoSrcDark string
|
||||
logoSrcLight string
|
||||
headLinks []libtemplate.HeadLink
|
||||
footerScripts []libtemplate.Script
|
||||
footerScriptChartJS libtemplate.Script
|
||||
|
||||
sigCache map[string]string
|
||||
sigCacheLock sync.RWMutex
|
||||
@ -143,6 +144,12 @@ func New(
|
||||
},
|
||||
}
|
||||
|
||||
fsCanvasJS := libtemplate.Script{
|
||||
Src: viper.GetString(config.Keys.WebappChartJSURI),
|
||||
CrossOrigin: COAnonymous,
|
||||
Integrity: viper.GetString(config.Keys.WebappChartJSIntegrity),
|
||||
}
|
||||
|
||||
return &Module{
|
||||
db: d,
|
||||
fedi: f,
|
||||
@ -155,11 +162,12 @@ func New(
|
||||
templates: tmpl,
|
||||
tokz: tokz,
|
||||
|
||||
domain: viper.GetString(config.Keys.ServerExternalHostname),
|
||||
logoSrcDark: viper.GetString(config.Keys.WebappLogoSrcDark),
|
||||
logoSrcLight: viper.GetString(config.Keys.WebappLogoSrcLight),
|
||||
headLinks: hl,
|
||||
footerScripts: fs,
|
||||
domain: viper.GetString(config.Keys.ServerExternalHostname),
|
||||
logoSrcDark: viper.GetString(config.Keys.WebappLogoSrcDark),
|
||||
logoSrcLight: viper.GetString(config.Keys.WebappLogoSrcLight),
|
||||
headLinks: hl,
|
||||
footerScripts: fs,
|
||||
footerScriptChartJS: fsCanvasJS,
|
||||
|
||||
sigCache: map[string]string{},
|
||||
}, nil
|
||||
|
@ -1,6 +1,9 @@
|
||||
package kv
|
||||
|
||||
import "strconv"
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
keyBase = "relay:"
|
||||
@ -16,6 +19,15 @@ const (
|
||||
keyInstance = keyBase + "instance:"
|
||||
keyInstanceOAuth = keyInstance + "oauth:"
|
||||
|
||||
keyMetrics = keyBase + "metrics:"
|
||||
keyMetricsDeliver = keyMetrics + "deliver:"
|
||||
keyMetricsDeliverError = keyMetricsDeliver + "e:"
|
||||
keyMetricsDeliverErrorTotal = keyMetricsDeliver + "et:"
|
||||
keyMetricsDeliverSuccess = keyMetricsDeliver + "s:"
|
||||
keyMetricsDeliverSuccessTotal = keyMetricsDeliver + "st:"
|
||||
keyMetricsReceived = keyMetrics + "received:"
|
||||
keyMetricsReceivedTotal = keyMetrics + "receivedt:"
|
||||
|
||||
keySession = keyBase + "session:"
|
||||
)
|
||||
|
||||
@ -34,5 +46,35 @@ func KeyFediHostMeta(d string) string { return keyFediHostMeta + d }
|
||||
// KeyInstanceOAuth returns the kv key which holds an instance's oauth tokens.
|
||||
func KeyInstanceOAuth(i int64) string { return keyInstanceOAuth + strconv.FormatInt(i, 10) }
|
||||
|
||||
// KeyMetricsDeliverError returns the kv key which holds the number of delivery errors to an instance.
|
||||
func KeyMetricsDeliverError(t time.Time) string {
|
||||
return keyMetricsDeliverError + t.Format("2006:01:02")
|
||||
}
|
||||
|
||||
// KeyMetricsDeliverErrorTotal returns the kv key which holds the number of delivery errors
|
||||
func KeyMetricsDeliverErrorTotal(t time.Time) string {
|
||||
return keyMetricsDeliverErrorTotal + t.Format("2006:01:02")
|
||||
}
|
||||
|
||||
// KeyMetricsDeliverSuccess returns the kv key which holds the number of delivery successes to an instance.
|
||||
func KeyMetricsDeliverSuccess(t time.Time) string {
|
||||
return keyMetricsDeliverSuccess + t.Format("2006:01:02")
|
||||
}
|
||||
|
||||
// KeyMetricsDeliverSuccessTotal returns the kv key which holds the number of delivery successes to an instance.
|
||||
func KeyMetricsDeliverSuccessTotal(t time.Time) string {
|
||||
return keyMetricsDeliverSuccessTotal + t.Format("2006:01:02")
|
||||
}
|
||||
|
||||
// KeyMetricsReceived returns the kv key which holds the number of receives from an instance.
|
||||
func KeyMetricsReceived(t time.Time) string {
|
||||
return keyMetricsReceived + t.Format("2006:01:02")
|
||||
}
|
||||
|
||||
// KeyMetricsReceivedTotal returns the kv key which holds the number of receives.
|
||||
func KeyMetricsReceivedTotal(t time.Time) string {
|
||||
return keyMetricsReceivedTotal + t.Format("2006:01:02")
|
||||
}
|
||||
|
||||
// KeySession returns the base kv key prefix.
|
||||
func KeySession() string { return keySession }
|
||||
|
@ -1,10 +1,26 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/feditools/go-lib/fedihelper"
|
||||
"time"
|
||||
)
|
||||
|
||||
// KV represents a key value store.
|
||||
type KV interface {
|
||||
fedihelper.KV
|
||||
|
||||
GetMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) (int, Error)
|
||||
GetMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) (int, Error)
|
||||
GetMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) (int, Error)
|
||||
GetMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) (int, Error)
|
||||
GetMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) (int, Error)
|
||||
GetMetricsReceivedTotal(ctx context.Context, timestamp time.Time) (int, Error)
|
||||
|
||||
IncMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) Error
|
||||
IncMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) Error
|
||||
IncMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) Error
|
||||
IncMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) Error
|
||||
IncMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) Error
|
||||
IncMetricsReceivedTotal(ctx context.Context, timestamp time.Time) Error
|
||||
}
|
||||
|
116
internal/kv/redis/metrics.go
Normal file
116
internal/kv/redis/metrics.go
Normal file
@ -0,0 +1,116 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/feditools/relay/internal/kv"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (c *Client) GetMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) (int, kv.Error) {
|
||||
count, err := c.redis.HGet(ctx, kv.KeyMetricsDeliverError(timestamp), strconv.FormatInt(instanceID, 10)).Int()
|
||||
if err != nil {
|
||||
return 0, c.ProcessError(err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) (int, kv.Error) {
|
||||
count, err := c.redis.Get(ctx, kv.KeyMetricsDeliverErrorTotal(timestamp)).Int()
|
||||
if err != nil {
|
||||
return 0, c.ProcessError(err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) (int, kv.Error) {
|
||||
count, err := c.redis.HGet(ctx, kv.KeyMetricsDeliverSuccess(timestamp), strconv.FormatInt(instanceID, 10)).Int()
|
||||
if err != nil {
|
||||
return 0, c.ProcessError(err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) (int, kv.Error) {
|
||||
count, err := c.redis.Get(ctx, kv.KeyMetricsDeliverSuccessTotal(timestamp)).Int()
|
||||
if err != nil {
|
||||
return 0, c.ProcessError(err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) (int, kv.Error) {
|
||||
count, err := c.redis.HGet(ctx, kv.KeyMetricsReceived(timestamp), strconv.FormatInt(instanceID, 10)).Int()
|
||||
if err != nil {
|
||||
return 0, c.ProcessError(err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetMetricsReceivedTotal(ctx context.Context, timestamp time.Time) (int, kv.Error) {
|
||||
count, err := c.redis.Get(ctx, kv.KeyMetricsReceivedTotal(timestamp)).Int()
|
||||
if err != nil {
|
||||
return 0, c.ProcessError(err)
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *Client) IncMetricsDeliverError(ctx context.Context, instanceID int64, timestamp time.Time) kv.Error {
|
||||
_, err := c.redis.HIncrBy(ctx, kv.KeyMetricsDeliverError(timestamp), strconv.FormatInt(instanceID, 10), 1).Result()
|
||||
if err != nil {
|
||||
return c.ProcessError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) IncMetricsDeliverErrorTotal(ctx context.Context, timestamp time.Time) kv.Error {
|
||||
_, err := c.redis.IncrBy(ctx, kv.KeyMetricsDeliverErrorTotal(timestamp), 1).Result()
|
||||
if err != nil {
|
||||
return c.ProcessError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) IncMetricsDeliverSuccess(ctx context.Context, instanceID int64, timestamp time.Time) kv.Error {
|
||||
_, err := c.redis.HIncrBy(ctx, kv.KeyMetricsDeliverSuccess(timestamp), strconv.FormatInt(instanceID, 10), 1).Result()
|
||||
if err != nil {
|
||||
return c.ProcessError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) IncMetricsDeliverSuccessTotal(ctx context.Context, timestamp time.Time) kv.Error {
|
||||
_, err := c.redis.IncrBy(ctx, kv.KeyMetricsDeliverSuccessTotal(timestamp), 1).Result()
|
||||
if err != nil {
|
||||
return c.ProcessError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) IncMetricsReceived(ctx context.Context, instanceID int64, timestamp time.Time) kv.Error {
|
||||
_, err := c.redis.HIncrBy(ctx, kv.KeyMetricsReceived(timestamp), strconv.FormatInt(instanceID, 10), 1).Result()
|
||||
if err != nil {
|
||||
return c.ProcessError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) IncMetricsReceivedTotal(ctx context.Context, timestamp time.Time) kv.Error {
|
||||
_, err := c.redis.IncrBy(ctx, kv.KeyMetricsReceivedTotal(timestamp), 1).Result()
|
||||
if err != nil {
|
||||
return c.ProcessError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,19 +1,14 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/feditools/relay/web"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"golang.org/x/text/language"
|
||||
"gopkg.in/yaml.v2"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Locales contains static files required by the application
|
||||
//go:embed locales/active.*.yaml
|
||||
var Locales embed.FS
|
||||
|
||||
// DefaultLanguage is the default language of the application.
|
||||
var DefaultLanguage = language.English
|
||||
|
||||
@ -34,7 +29,7 @@ func New() (*Module, error) {
|
||||
|
||||
module.langBundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)
|
||||
|
||||
dir, err := Locales.ReadDir("locales")
|
||||
dir, err := web.Files.ReadDir("locales")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -45,7 +40,7 @@ func New() (*Module, error) {
|
||||
l.Debugf("loading language file: %s", d.Name())
|
||||
|
||||
// open it
|
||||
file, err := Locales.Open("locales/" + d.Name())
|
||||
file, err := web.Files.Open("locales/" + d.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -68,3 +63,16 @@ func New() (*Module, error) {
|
||||
|
||||
// Language returns the default language.
|
||||
func (m Module) Language() language.Tag { return m.lang }
|
||||
|
||||
func isEmptyYaml(b []byte) bool {
|
||||
switch string(b) {
|
||||
case "":
|
||||
return true
|
||||
case "---":
|
||||
return true
|
||||
case "---\n":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
114
internal/language/language_test.go
Normal file
114
internal/language/language_test.go
Normal file
@ -0,0 +1,114 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const (
|
||||
testCantGetLocalizer = "[%d] can't get localizer for %s: %s"
|
||||
testGotInvalidLanguage = "[%d] got invalid language for %s, got: %v, want: %v"
|
||||
testGotInvalidTranslation = "[%d] got invalid translation for %s, got: %v, want: %v"
|
||||
testTranslatedTo = "[%d] Translating to %s"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
langMod, err := New()
|
||||
if err != nil {
|
||||
t.Errorf("can't get new language module: %s", err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if langMod == nil {
|
||||
t.Errorf("language module is nil")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if langMod.langBundle == nil {
|
||||
t.Errorf("language module's bundle is nil")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if langMod.Language() != DefaultLanguage {
|
||||
t.Errorf("got invalid language, got: %v, want: %v,", langMod.Language().String(), DefaultLanguage.String())
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsEmptyYaml(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []struct {
|
||||
input string
|
||||
output bool
|
||||
}{
|
||||
{"", true},
|
||||
{"---", true},
|
||||
{"---\n", true},
|
||||
{"---\nvalid: yaml", false},
|
||||
}
|
||||
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf("[%d] running isEmptyYaml", i)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
result := isEmptyYaml([]byte(table.input))
|
||||
if result != table.output {
|
||||
t.Errorf("[%d] got invalid response, got: %v, want: %v,", i, result, table.output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// text testers
|
||||
|
||||
type testTextTable struct {
|
||||
inputLang language.Tag
|
||||
inputCount int
|
||||
inputStrings []string
|
||||
|
||||
outputString string
|
||||
outputLang language.Tag
|
||||
}
|
||||
|
||||
func testText(t *testing.T, tid int, translate func() *LocalizedString, table testTextTable) {
|
||||
t.Helper()
|
||||
|
||||
result := translate()
|
||||
testTextCheckResults(t, tid, result, table)
|
||||
}
|
||||
|
||||
func testTextWithCount(t *testing.T, tid int, translate func(int) *LocalizedString, table testTextTable) {
|
||||
t.Helper()
|
||||
|
||||
result := translate(table.inputCount)
|
||||
testTextCheckResults(t, tid, result, table)
|
||||
}
|
||||
|
||||
func testTextWith1String(t *testing.T, tid int, translate func(string) *LocalizedString, table testTextTable) {
|
||||
t.Helper()
|
||||
|
||||
result := translate(table.inputStrings[0])
|
||||
testTextCheckResults(t, tid, result, table)
|
||||
}
|
||||
|
||||
func testTextCheckResults(t *testing.T, tid int, result *LocalizedString, table testTextTable) {
|
||||
t.Helper()
|
||||
|
||||
if result.String() != table.outputString {
|
||||
t.Errorf(testGotInvalidTranslation, tid, table.inputLang, result.String(), table.outputString)
|
||||
}
|
||||
if result.Language() != table.outputLang {
|
||||
t.Errorf(testGotInvalidLanguage, tid, table.inputLang, result.Language(), table.outputLang)
|
||||
}
|
||||
}
|
26
internal/language/localizer_test.go
Normal file
26
internal/language/localizer_test.go
Normal file
@ -0,0 +1,26 @@
|
||||
package language
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNewLocalizer(t *testing.T) {
|
||||
langMod, _ := New()
|
||||
|
||||
localizer, err := langMod.NewLocalizer()
|
||||
if err != nil {
|
||||
t.Errorf("can't get new language module: %s", err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if localizer == nil {
|
||||
t.Errorf("localizer module is nil")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if localizer.localizer == nil {
|
||||
t.Errorf("localizer module's localizer is nil")
|
||||
|
||||
return
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"github.com/feditools/go-lib/log"
|
||||
)
|
||||
import "github.com/feditools/relay/internal/log"
|
||||
|
||||
type empty struct{}
|
||||
|
111
internal/language/text_a.go
Normal file
111
internal/language/text_a.go
Normal file
@ -0,0 +1,111 @@
|
||||
package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextAccount returns a translated phrase.
|
||||
func (l *Localizer) TextAccount(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextAccount")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Account",
|
||||
One: "Account",
|
||||
Other: "Accounts",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextActivityLog returns a translated phrase.
|
||||
func (l *Localizer) TextActivityLog(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextActivityLog")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "ActivityLog",
|
||||
One: "Activity Log",
|
||||
Other: "Activity Logs",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextActorURI returns a translated phrase.
|
||||
func (l *Localizer) TextActorURI(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextActorURI")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "ActorURI",
|
||||
One: "Actor URI",
|
||||
Other: "Actor URIs",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextAddBlock returns a translated phrase.
|
||||
func (l *Localizer) TextAddBlock(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextAddBlock")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "AddBlock",
|
||||
One: "Add Block",
|
||||
Other: "Add Blocks",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextAdmin returns a translated phrase.
|
||||
func (l *Localizer) TextAdmin() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextAdmin")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Admin",
|
||||
Other: "Admin",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
196
internal/language/text_a_test.go
Normal file
196
internal/language/text_a_test.go
Normal file
@ -0,0 +1,196 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextAccount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Account",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Accounts",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextAccount, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextActivityLog(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Activity Log",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Activity Logs",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextActivityLog, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextActorURI(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Actor URI",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Actor URIs",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextActorURI, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextAddBlock(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Add Block",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Add Blocks",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextAddBlock, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextAdmin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Admin",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextAdmin, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -24,13 +24,13 @@ func (l *Localizer) TextBlock(count int) *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextBlockExists returns a translated phrase.
|
||||
func (l *Localizer) TextBlockExists(domain string) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextBlockExists")
|
||||
// TextBlockExistsDomain returns a translated phrase.
|
||||
func (l *Localizer) TextBlockExistsDomain(domain string) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextBlockExistsDomain")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "BlockExists",
|
||||
ID: "BlockExistsDomain",
|
||||
Other: "Block for domain {{.Domain}} already exists.",
|
||||
},
|
||||
TemplateData: map[string]interface{}{
|
195
internal/language/text_b_test.go
Normal file
195
internal/language/text_b_test.go
Normal file
@ -0,0 +1,195 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/text/language"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextBlock(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Block",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Blocks",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextBlock, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextBlockExistsDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example.com"},
|
||||
outputString: "Block for domain example.com already exists.",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example2.com"},
|
||||
outputString: "Block for domain example2.com already exists.",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWith1String(t, i, localizer.TextBlockExistsDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextBlockSubdomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Block Subdomain",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Block Subdomains",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextBlockSubdomain, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextBlocked(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Blocked",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextBlocked, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextBlockedDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Blocked Domain",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Blocked Domains",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextBlockedDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -2,35 +2,15 @@ package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextOauth returns a translated phrase.
|
||||
func (l *Localizer) TextOauth() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextOauth")
|
||||
// TextChatID returns a translated phrase.
|
||||
func (l *Localizer) TextChatID(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextChatID")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Oauth",
|
||||
Other: "OAuth",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextOauth20Client returns a translated phrase.
|
||||
func (l *Localizer) TextOauth20Client(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextOauth20Client")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Oauth20Client",
|
||||
One: "OAuth 2.0 Client",
|
||||
Other: "OAuth 2.0 Clients",
|
||||
ID: "ChatID",
|
||||
One: "Chat ID",
|
||||
Other: "Chat IDs",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
@ -44,14 +24,14 @@ func (l *Localizer) TextOauth20Client(count int) *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextOauth20Settings returns a translated phrase.
|
||||
func (l *Localizer) TextOauth20Settings() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextOauth20Settings")
|
||||
// TextClose returns a translated phrase.
|
||||
func (l *Localizer) TextClose() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextClose")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Oauth20Settings",
|
||||
Other: "OAuth 2.0 Settings",
|
||||
ID: "Close",
|
||||
Other: "Close",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@ -64,15 +44,15 @@ func (l *Localizer) TextOauth20Settings() *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextObfuscatedDomain returns a translated phrase.
|
||||
func (l *Localizer) TextObfuscatedDomain(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextObfuscatedDomain")
|
||||
// TextConfig returns a translated phrase.
|
||||
func (l *Localizer) TextConfig(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextConfig")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "ObfuscatedDomain",
|
||||
One: "Obfuscated Domain",
|
||||
Other: "Obfuscated Domains",
|
||||
ID: "Config",
|
||||
One: "Config",
|
||||
Other: "Configs",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
@ -85,3 +65,23 @@ func (l *Localizer) TextObfuscatedDomain(count int) *LocalizedString {
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextCreate returns a translated phrase.
|
||||
func (l *Localizer) TextCreate() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextCreate")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Create",
|
||||
Other: "Create",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
150
internal/language/text_c_test.go
Normal file
150
internal/language/text_c_test.go
Normal file
@ -0,0 +1,150 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextChatID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Chat ID",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Chat IDs",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextChatID, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextClose(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Close",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextClose, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Config",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Configs",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextConfig, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextCreate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Create",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextCreate, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -2,28 +2,6 @@ package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextDashboard returns a translated phrase.
|
||||
func (l *Localizer) TextDashboard(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextDashboard")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Dashboard",
|
||||
One: "Dashboard",
|
||||
Other: "Dashboards",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextDelete returns a translated phrase.
|
||||
func (l *Localizer) TextDelete() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextDelete")
|
||||
@ -90,18 +68,18 @@ func (l *Localizer) TextDeleteBlockConfirmDomain(domain string) *LocalizedString
|
||||
}
|
||||
}
|
||||
|
||||
// TextDemocrablock returns a translated phrase.
|
||||
func (l *Localizer) TextDemocrablock() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextDemocrablock")
|
||||
|
||||
// TextDeliveryStat returns a translated phrase.
|
||||
func (l *Localizer) TextDeliveryStat(count int) *LocalizedString {
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Democrablock",
|
||||
Other: "Democrablock",
|
||||
ID: "DeliveryStat",
|
||||
One: "Delivery Stat",
|
||||
Other: "Delivery Stats",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
logger.WithField("func", "TextDeliveryStat").Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
235
internal/language/text_d_test.go
Normal file
235
internal/language/text_d_test.go
Normal file
@ -0,0 +1,235 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextDelete(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Delete",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextDelete, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextDeleteBlockDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example.com"},
|
||||
outputString: "Delete Block example.com",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example2.com"},
|
||||
outputString: "Delete Block example2.com",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWith1String(t, i, localizer.TextDeleteBlockDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextDeleteBlockConfirmDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example.com"},
|
||||
outputString: "Are you sure you want to delete the block for example.com?",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example2.com"},
|
||||
outputString: "Are you sure you want to delete the block for example2.com?",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWith1String(t, i, localizer.TextDeleteBlockConfirmDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextDeliveryStat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Delivery Stat",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Delivery Stats",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextDeliveryStat, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextDescription(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Description",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Descriptions",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextDescription, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Domain",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Domains",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
110
internal/language/text_e_test.go
Normal file
110
internal/language/text_e_test.go
Normal file
@ -0,0 +1,110 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/text/language"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextEditBlock(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example.com"},
|
||||
outputString: "Edit Block example.com",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputStrings: []string{"example2.com"},
|
||||
outputString: "Edit Block example2.com",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWith1String(t, i, localizer.TextEditBlockDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextEnabled(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Enabled",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextEnabled, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextErrorDatabase(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "database error",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextErrorDatabase, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -2,14 +2,14 @@ package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextFediverse returns a translated phrase.
|
||||
func (l *Localizer) TextFediverse() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextFediverse")
|
||||
// TextFederation returns a translated phrase.
|
||||
func (l *Localizer) TextFederation() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextFederation")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Fediverse",
|
||||
Other: "Fediverse",
|
||||
ID: "Federation",
|
||||
Other: "Federation",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
72
internal/language/text_f_test.go
Normal file
72
internal/language/text_f_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextFederation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Federation",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextFederation, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextFollowing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Following",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextFollowing, table)
|
||||
})
|
||||
}
|
||||
}
|
39
internal/language/text_g_test.go
Normal file
39
internal/language/text_g_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/text/language"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextGeneral(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "General",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextGeneral, table)
|
||||
})
|
||||
}
|
||||
}
|
104
internal/language/text_h_test.go
Normal file
104
internal/language/text_h_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextHomeWeb(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Home",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextHomeWeb, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextHomePageBody(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Home Page Body",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextHomePageBody, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextHowToJoin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "How to Join",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextHowToJoin, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -44,6 +44,28 @@ func (l *Localizer) TextImportBlockList(count int) *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextInboxURI returns a translated phrase.
|
||||
func (l *Localizer) TextInboxURI(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextInboxURI")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "InboxURI",
|
||||
One: "Inbox URI",
|
||||
Other: "Inbox URIs",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextInstance returns a translated phrase.
|
||||
func (l *Localizer) TextInstance(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextInstance")
|
||||
@ -65,25 +87,3 @@ func (l *Localizer) TextInstance(count int) *LocalizedString {
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextInvalidURI returns a translated phrase.
|
||||
func (l *Localizer) TextInvalidURI(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextInvalidURI")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "InvalidURI",
|
||||
One: "Invalid URI",
|
||||
Other: "Invalid URIs",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
157
internal/language/text_i_test.go
Normal file
157
internal/language/text_i_test.go
Normal file
@ -0,0 +1,157 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextImport(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Import",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextImport, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextImportBlockList(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Import Block List",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Import Block Lists",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextImportBlockList, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextInboxURI(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Inbox URI",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Inbox URIs",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextInboxURI, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextInstance(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Instance",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Instances",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextInstance, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -2,28 +2,6 @@ package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextList returns a translated phrase.
|
||||
func (l *Localizer) TextList(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextList")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "List",
|
||||
One: "List",
|
||||
Other: "Lists",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextLogin returns a translated phrase.
|
||||
func (l *Localizer) TextLogin() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextLogin")
|
104
internal/language/text_l_test.go
Normal file
104
internal/language/text_l_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextLogin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Login",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextLogin, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextLogout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Logout",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextLogout, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextLookGood(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Looks Good!",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextLooksGood, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -2,15 +2,17 @@ package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextModeration returns a translated phrase.
|
||||
func (l *Localizer) TextModeration() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextLogin")
|
||||
// TextMetric returns a translated phrase.
|
||||
func (l *Localizer) TextMetric(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextMetric")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Moderation",
|
||||
Other: "Moderation",
|
||||
ID: "Metric",
|
||||
One: "Metric",
|
||||
Other: "Metrics",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
85
internal/language/text_m_test.go
Normal file
85
internal/language/text_m_test.go
Normal file
@ -0,0 +1,85 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/text/language"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextMetric(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Metric",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Metrics",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextMetric, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextModerator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Moderator",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Moderators",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextModerator, table)
|
||||
})
|
||||
}
|
||||
}
|
46
internal/language/text_n_test.go
Normal file
46
internal/language/text_n_test.go
Normal file
@ -0,0 +1,46 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/text/language"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextNotification(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Notification",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Notifications",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextNotification, table)
|
||||
})
|
||||
}
|
||||
}
|
41
internal/language/text_o.go
Normal file
41
internal/language/text_o.go
Normal file
@ -0,0 +1,41 @@
|
||||
package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextOAuthConfigured returns a translated phrase.
|
||||
func (l *Localizer) TextOAuthConfigured() *LocalizedString {
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "OAuthConfigured",
|
||||
Other: "OAuth Configured",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
logger.WithField("func", "TextOAuthConfigured").Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextObfuscatedDomain returns a translated phrase.
|
||||
func (l *Localizer) TextObfuscatedDomain(count int) *LocalizedString {
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "ObfuscatedDomain",
|
||||
One: "Obfuscated Domain",
|
||||
Other: "Obfuscated Domains",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
logger.WithField("func", "TextObfuscatedDomain").Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
79
internal/language/text_o_test.go
Normal file
79
internal/language/text_o_test.go
Normal file
@ -0,0 +1,79 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextOAuthConfigured(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "OAuth Configured",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextOAuthConfigured, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextObfuscatedDomain(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Obfuscated Domain",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Obfuscated Domains",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextObfuscatedDomain, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -2,6 +2,26 @@ package language
|
||||
|
||||
import "github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
|
||||
// TextReceivedStat returns a translated phrase.
|
||||
func (l *Localizer) TextReceivedStat(count int) *LocalizedString {
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "ReceivedStat",
|
||||
One: "Received Stat",
|
||||
Other: "Received Stats",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
logger.WithField("func", "TextReceivedStat").Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextRelay returns a translated phrase.
|
||||
func (l *Localizer) TextRelay(count int) *LocalizedString {
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
@ -22,40 +42,18 @@ func (l *Localizer) TextRelay(count int) *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextRequired returns a translated phrase.
|
||||
func (l *Localizer) TextRequired() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextRequired")
|
||||
|
||||
// TextRepo returns a translated phrase.
|
||||
func (l *Localizer) TextRepo(count int) *LocalizedString {
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Required",
|
||||
Other: "Required",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextRedirectURI returns a translated phrase.
|
||||
func (l *Localizer) TextRedirectURI(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextRedirectURI")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "RedirectURI",
|
||||
One: "Redirect URI",
|
||||
Other: "Redirect URIs",
|
||||
ID: "Repo",
|
||||
One: "Repo",
|
||||
Other: "Repos",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
logger.WithField("func", "TextRepo").Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
125
internal/language/text_r_test.go
Normal file
125
internal/language/text_r_test.go
Normal file
@ -0,0 +1,125 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextReceivedStat(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Received Stat",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Received Stats",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextReceivedStat, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextRelay(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Relay",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Relays",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextRelay, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextRepo(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Repo",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Repos",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextRepo, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -22,6 +22,28 @@ func (l *Localizer) TextSave() *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextServerHostname returns a translated phrase.
|
||||
func (l *Localizer) TextServerHostname(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextServerHostname")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "ServerHostname",
|
||||
One: "Server Hostname",
|
||||
Other: "Server Hostnames",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextSetting returns a translated phrase.
|
||||
func (l *Localizer) TextSetting(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextSetting")
|
||||
@ -44,17 +66,15 @@ func (l *Localizer) TextSetting(count int) *LocalizedString {
|
||||
}
|
||||
}
|
||||
|
||||
// TextSystem returns a translated phrase.
|
||||
func (l *Localizer) TextSystem(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextSystem")
|
||||
// TextSoftware returns a translated phrase.
|
||||
func (l *Localizer) TextSoftware() *LocalizedString {
|
||||
lg := logger.WithField("func", "TextSoftware")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "System",
|
||||
One: "System",
|
||||
Other: "Systems",
|
||||
ID: "Software",
|
||||
Other: "Software",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
150
internal/language/text_s_test.go
Normal file
150
internal/language/text_s_test.go
Normal file
@ -0,0 +1,150 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextSave(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Save",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextSave, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextServerHostname(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Server Hostname",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Server Hostnames",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextServerHostname, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextSetting(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Setting",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Settings",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextSetting, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextSoftware(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Software",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextSoftware, table)
|
||||
})
|
||||
}
|
||||
}
|
86
internal/language/text_t_test.go
Normal file
86
internal/language/text_t_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextTimestamp(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Timestamp",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Timestamps",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextTimestamp, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Token",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Tokens",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextToken, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -43,25 +43,3 @@ func (l *Localizer) TextUpdate(count int) *LocalizedString {
|
||||
string: text,
|
||||
}
|
||||
}
|
||||
|
||||
// TextUsername returns a translated phrase.
|
||||
func (l *Localizer) TextUsername(count int) *LocalizedString {
|
||||
lg := logger.WithField("func", "TextUsername")
|
||||
|
||||
text, tag, err := l.localizer.LocalizeWithTag(&i18n.LocalizeConfig{
|
||||
DefaultMessage: &i18n.Message{
|
||||
ID: "Username",
|
||||
One: "Username",
|
||||
Other: "Usernames",
|
||||
},
|
||||
PluralCount: count,
|
||||
})
|
||||
if err != nil {
|
||||
lg.Warningf(missingTranslationWarning, err.Error())
|
||||
}
|
||||
|
||||
return &LocalizedString{
|
||||
language: tag,
|
||||
string: text,
|
||||
}
|
||||
}
|
79
internal/language/text_u_test.go
Normal file
79
internal/language/text_u_test.go
Normal file
@ -0,0 +1,79 @@
|
||||
package language
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestLocalizer_TextUnauthorized(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
outputString: "Unauthorized",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testText(t, i, localizer.TextUnauthorized, table)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalizer_TextUpdate(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tables := []testTextTable{
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 1,
|
||||
outputString: "Update",
|
||||
outputLang: language.English,
|
||||
},
|
||||
{
|
||||
inputLang: language.English,
|
||||
inputCount: 2,
|
||||
outputString: "Updates",
|
||||
outputLang: language.English,
|
||||
},
|
||||
}
|
||||
|
||||
langMod, _ := New()
|
||||
for i, table := range tables {
|
||||
i := i
|
||||
table := table
|
||||
|
||||
name := fmt.Sprintf(testTranslatedTo, i, table.inputLang)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localizer, err := langMod.NewLocalizer(table.inputLang.String())
|
||||
if err != nil {
|
||||
t.Errorf(testCantGetLocalizer, i, table.inputLang, err.Error())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
testTextWithCount(t, i, localizer.TextUpdate, table)
|
||||
})
|
||||
}
|
||||
}
|
@ -25,6 +25,12 @@ type Logic interface {
|
||||
GetLoginURL(ctx context.Context, instance *models.Instance) (*url.URL, error)
|
||||
GetPeers(ctx context.Context) (*[]string, error)
|
||||
IsDomainBlocked(ctx context.Context, d string) (bool, error)
|
||||
MetricsGetDeliverErrorWeek(ctx context.Context, instanceID int64) (*MetricsDataPointsTime, error)
|
||||
MetricsGetDeliverSuccessWeek(ctx context.Context, instanceID int64) (*MetricsDataPointsTime, error)
|
||||
MetricsGetReceivedWeek(ctx context.Context, instanceID int64) (*MetricsDataPointsTime, error)
|
||||
MetricsIncDeliverError(ctx context.Context, instanceID int64)
|
||||
MetricsIncDeliverSuccess(ctx context.Context, instanceID int64)
|
||||
MetricsIncReceived(ctx context.Context, instanceID int64)
|
||||
ProcessActivity(ctx context.Context, jid string, instanceID int64, actorIRI *url.URL, activity fedihelper.Activity) error
|
||||
ProcessBlockAdd(ctx context.Context, blockID int64) error
|
||||
ProcessBlockDelete(ctx context.Context, blockID int64) error
|
||||
|
@ -47,11 +47,16 @@ func (l *Logic) DeliverActivity(ctx context.Context, jid string, instanceID int6
|
||||
log.Debugf("sending activity: %s to %s", string(body), inboxIRI.String())
|
||||
resp, err := l.transport.InstancePost(ctx, inboxIRI, body, libhttp.MimeAppActivityJSON, libhttp.MimeAppActivityJSON)
|
||||
if err != nil {
|
||||
log.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
msg := fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
log.Error(msg.Error())
|
||||
|
||||
return fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
l.MetricsIncDeliverError(ctx, instance.ID)
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
l.MetricsIncDeliverSuccess(ctx, instance.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -166,26 +171,9 @@ func (l *Logic) doFollow(ctx context.Context, jid string, instanceID int64, acti
|
||||
|
||||
// send accept
|
||||
outgoingActivity := genActivityAccept(l.domain, instance.ActorIRI, id)
|
||||
body, err := json.Marshal(outgoingActivity)
|
||||
err = l.runner.EnqueueDeliverActivity(ctx, instance.ID, outgoingActivity)
|
||||
if err != nil {
|
||||
log.Errorf("can't marshal response: %s", err.Error())
|
||||
|
||||
return fmt.Errorf("can't marshal response: %s", err.Error())
|
||||
}
|
||||
|
||||
inboxIRI, err := url.Parse(instance.InboxIRI)
|
||||
if err != nil {
|
||||
log.Errorf("can't parse actor iri: %s", err.Error())
|
||||
|
||||
return fmt.Errorf("can't parse actor iri: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Debugf("sending activity: %s", string(body))
|
||||
resp, err := l.transport.InstancePost(ctx, inboxIRI, body, libhttp.MimeAppActivityJSON, libhttp.MimeAppActivityJSON)
|
||||
if err != nil {
|
||||
log.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
|
||||
return fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
log.Errorf("enqueueing delivery: %s", err.Error())
|
||||
}
|
||||
|
||||
go l.runner.EnqueueSendNotification(
|
||||
@ -391,26 +379,9 @@ func (l *Logic) doUndo(ctx context.Context, jid string, instanceID int64, activi
|
||||
|
||||
// send undo
|
||||
outgoingActivity := genActivityUndo(l.domain, instance.ActorIRI)
|
||||
body, err := json.Marshal(outgoingActivity)
|
||||
err = l.runner.EnqueueDeliverActivity(ctx, instance.ID, outgoingActivity)
|
||||
if err != nil {
|
||||
log.Errorf("can't marshal response: %s", err.Error())
|
||||
|
||||
return fmt.Errorf("can't marshal response: %s", err.Error())
|
||||
}
|
||||
|
||||
inboxIRI, err := url.Parse(instance.InboxIRI)
|
||||
if err != nil {
|
||||
log.Errorf("can't parse actor iri: %s", err.Error())
|
||||
|
||||
return fmt.Errorf("can't parse actor iri: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Debugf("sending activity: %s", string(body))
|
||||
resp, err := l.transport.InstancePost(ctx, inboxIRI, body, libhttp.MimeAppActivityJSON, libhttp.MimeAppActivityJSON)
|
||||
if err != nil {
|
||||
log.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
|
||||
return fmt.Errorf("can't post to instance: %s\n%s", err.Error(), resp)
|
||||
log.Errorf("enqueueing delivery: %s", err.Error())
|
||||
}
|
||||
|
||||
go l.runner.EnqueueSendNotification(
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/feditools/relay/internal/db"
|
||||
"github.com/feditools/relay/internal/fedi"
|
||||
ihttp "github.com/feditools/relay/internal/http"
|
||||
"github.com/feditools/relay/internal/kv"
|
||||
"github.com/feditools/relay/internal/notification"
|
||||
"github.com/feditools/relay/internal/path"
|
||||
"github.com/feditools/relay/internal/runner"
|
||||
@ -25,6 +26,7 @@ import (
|
||||
type Logic struct {
|
||||
db db.DB
|
||||
fedi *fedi.Module
|
||||
kv kv.KV
|
||||
notifier notification.Notifier
|
||||
runner runner.Runner
|
||||
tokz *token.Tokenizer
|
||||
@ -48,7 +50,7 @@ type Logic struct {
|
||||
}
|
||||
|
||||
// New created a new logic module
|
||||
func New(ctx context.Context, c pub.Clock, d db.DB, h *ihttp.Client, tokz *token.Tokenizer) (*Logic, error) {
|
||||
func New(ctx context.Context, c pub.Clock, d db.DB, h *ihttp.Client, k kv.KV, tokz *token.Tokenizer) (*Logic, error) {
|
||||
log := logger.WithFields(logrus.Fields{
|
||||
"func": "New",
|
||||
})
|
||||
@ -56,6 +58,7 @@ func New(ctx context.Context, c pub.Clock, d db.DB, h *ihttp.Client, tokz *token
|
||||
// create module
|
||||
l := Logic{
|
||||
db: d,
|
||||
kv: k,
|
||||
tokz: tokz,
|
||||
|
||||
domain: viper.GetString(config.Keys.ServerExternalHostname),
|
||||
|
81
internal/logic/logic1/metrics_get.go
Normal file
81
internal/logic/logic1/metrics_get.go
Normal file
@ -0,0 +1,81 @@
|
||||
package logic1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/feditools/relay/internal/kv"
|
||||
"github.com/feditools/relay/internal/logic"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (l *Logic) MetricsGetDeliverErrorWeek(ctx context.Context, instanceID int64) (*logic.MetricsDataPointsTime, error) {
|
||||
now := time.Now().UTC()
|
||||
now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
||||
|
||||
var days logic.MetricsDataPointsTime = make([]logic.MetricsDataPointTime, 7)
|
||||
for i := 0; i < 7; i++ {
|
||||
day := now.Add(-24 * time.Duration(i) * time.Hour)
|
||||
|
||||
count := 0
|
||||
var err error
|
||||
count, err = l.kv.GetMetricsDeliverError(ctx, instanceID, day)
|
||||
if err != nil && !errors.Is(err, kv.ErrNil) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
days[i] = logic.MetricsDataPointTime{
|
||||
X: day,
|
||||
Y: count,
|
||||
}
|
||||
}
|
||||
|
||||
return &days, nil
|
||||
}
|
||||
|
||||
func (l *Logic) MetricsGetDeliverSuccessWeek(ctx context.Context, instanceID int64) (*logic.MetricsDataPointsTime, error) {
|
||||
now := time.Now().UTC()
|
||||
now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
||||
|
||||
var days logic.MetricsDataPointsTime = make([]logic.MetricsDataPointTime, 7)
|
||||
for i := 0; i < 7; i++ {
|
||||
day := now.Add(-24 * time.Duration(i) * time.Hour)
|
||||
|
||||
count := 0
|
||||
var err error
|
||||
count, err = l.kv.GetMetricsDeliverSuccess(ctx, instanceID, day)
|
||||
if err != nil && !errors.Is(err, kv.ErrNil) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
days[i] = logic.MetricsDataPointTime{
|
||||
X: day,
|
||||
Y: count,
|
||||
}
|
||||
}
|
||||
|
||||
return &days, nil
|
||||
}
|
||||
|
||||
func (l *Logic) MetricsGetReceivedWeek(ctx context.Context, instanceID int64) (*logic.MetricsDataPointsTime, error) {
|
||||
now := time.Now().UTC()
|
||||
now = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
||||
|
||||
var days logic.MetricsDataPointsTime = make([]logic.MetricsDataPointTime, 7)
|
||||
for i := 0; i < 7; i++ {
|
||||
day := now.Add(-24 * time.Duration(i) * time.Hour)
|
||||
|
||||
count := 0
|
||||
var err error
|
||||
count, err = l.kv.GetMetricsReceived(ctx, instanceID, day)
|
||||
if err != nil && !errors.Is(err, kv.ErrNil) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
days[i] = logic.MetricsDataPointTime{
|
||||
X: day,
|
||||
Y: count,
|
||||
}
|
||||
}
|
||||
|
||||
return &days, nil
|
||||
}
|
54
internal/logic/logic1/metrics_inc.go
Normal file
54
internal/logic/logic1/metrics_inc.go
Normal file
@ -0,0 +1,54 @@
|
||||
package logic1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (l *Logic) MetricsIncDeliverError(ctx context.Context, instanceID int64) {
|
||||
log := logger.WithField("func", "MetricsIncDeliverError")
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
err := l.kv.IncMetricsDeliverError(ctx, instanceID, now)
|
||||
if err != nil {
|
||||
log.Warnf("instance: %s", err.Error())
|
||||
}
|
||||
|
||||
err = l.kv.IncMetricsDeliverErrorTotal(ctx, now)
|
||||
if err != nil {
|
||||
log.Warnf("total: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logic) MetricsIncDeliverSuccess(ctx context.Context, instanceID int64) {
|
||||
log := logger.WithField("func", "MetricsIncDeliverSuccess")
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
err := l.kv.IncMetricsDeliverSuccess(ctx, instanceID, now)
|
||||
if err != nil {
|
||||
log.Warnf("instance: %s", err.Error())
|
||||
}
|
||||
|
||||
err = l.kv.IncMetricsDeliverSuccessTotal(ctx, now)
|
||||
if err != nil {
|
||||
log.Warnf("total: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logic) MetricsIncReceived(ctx context.Context, instanceID int64) {
|
||||
log := logger.WithField("func", "MetricsIncReceived")
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
err := l.kv.IncMetricsReceived(ctx, instanceID, now)
|
||||
if err != nil {
|
||||
log.Warnf("instance: %s", err.Error())
|
||||
}
|
||||
|
||||
err = l.kv.IncMetricsReceivedTotal(ctx, now)
|
||||
if err != nil {
|
||||
log.Warnf("total: %s", err.Error())
|
||||
}
|
||||
}
|
10
internal/logic/metrics.go
Normal file
10
internal/logic/metrics.go
Normal file
@ -0,0 +1,10 @@
|
||||
package logic
|
||||
|
||||
import "time"
|
||||
|
||||
type MetricsDataPointsTime []MetricsDataPointTime
|
||||
|
||||
type MetricsDataPointTime struct {
|
||||
X time.Time
|
||||
Y int
|
||||
}
|
@ -27,6 +27,11 @@ func GenAppAdminHomePath() string {
|
||||
return AppAdminHome
|
||||
}
|
||||
|
||||
// GenAppAdminInstanceViewPath returns a path for the admin instance view page.
|
||||
func GenAppAdminInstanceViewPath(t string) string {
|
||||
return AppAdminPreInstanceView + t
|
||||
}
|
||||
|
||||
// GenAppHomePath returns a path for the home page.
|
||||
func GenAppHomePath() string {
|
||||
return AppHome
|
||||
|
@ -69,4 +69,8 @@ const (
|
||||
AppAdminInstance = AppAdmin + AppAdminSubInstance
|
||||
// AppAdminSubInstance is the sub path for the admin instances page.
|
||||
AppAdminSubInstance = "/" + PartInstance
|
||||
// AppAdminPreInstanceView is the prefix path for the admin instance view page.
|
||||
AppAdminPreInstanceView = AppAdmin + AppAdminSubInstance + "/"
|
||||
// AppAdminSubInstanceView is the sub path for the admin instance view page.
|
||||
AppAdminSubInstanceView = AppAdminSubInstance + "/" + VarInstance
|
||||
)
|
||||
|
38
test/fake_metrics.sh
Executable file
38
test/fake_metrics.sh
Executable file
@ -0,0 +1,38 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
METRIC_MAX=500
|
||||
|
||||
KEY_DELIVERY_S="relay:metrics:deliver:s:"
|
||||
KEY_DELIVERY_S_TOTAL="relay:metrics:deliver:st:"
|
||||
KEY_DELIVERY_E="relay:metrics:deliver:e:"
|
||||
KEY_DELIVERY_E_TOTAL="relay:metrics:deliver:et:"
|
||||
KEY_RECEIVED="relay:metrics:received:"
|
||||
KEY_RECEIVED_TOTAL="relay:metrics:receivedt:"
|
||||
|
||||
for day in {0..30}; do
|
||||
#echo $day
|
||||
|
||||
DATE1=$(date -v -${day}d +"%Y:%m:%d")
|
||||
|
||||
DELIVERY_S_TOTAL=0
|
||||
DELIVERY_E_TOTAL=0
|
||||
RECEIVED_TOTAL=0
|
||||
|
||||
for instance in {2..3}; do
|
||||
DELIVERY_S=$((1 + $RANDOM % ${METRIC_MAX}))
|
||||
DELIVERY_E=$((1 + $RANDOM % ${METRIC_MAX}))
|
||||
RECEIVED=$((1 + $RANDOM % ${METRIC_MAX}))
|
||||
|
||||
DELIVERY_S_TOTAL=$(expr ${DELIVERY_S_TOTAL} + ${DELIVERY_S})
|
||||
DELIVERY_E_TOTAL=$(expr ${DELIVERY_E_TOTAL} + ${DELIVERY_E})
|
||||
RECEIVED_TOTAL=$(expr ${RECEIVED_TOTAL} + ${RECEIVED})
|
||||
|
||||
docker exec -it relay_redis_1 redis-cli --pass test HSET ${KEY_DELIVERY_S}${DATE1} ${instance} ${DELIVERY_S}
|
||||
docker exec -it relay_redis_1 redis-cli --pass test HSET ${KEY_DELIVERY_E}${DATE1} ${instance} ${DELIVERY_E}
|
||||
docker exec -it relay_redis_1 redis-cli --pass test HSET ${KEY_RECEIVED}${DATE1} ${instance} ${RECEIVED}
|
||||
done
|
||||
|
||||
docker exec -it relay_redis_1 redis-cli --pass test SET ${KEY_DELIVERY_S_TOTAL}${DATE1} ${DELIVERY_S_TOTAL}
|
||||
docker exec -it relay_redis_1 redis-cli --pass test SET ${KEY_DELIVERY_E_TOTAL}${DATE1} ${DELIVERY_E_TOTAL}
|
||||
docker exec -it relay_redis_1 redis-cli --pass test SET ${KEY_RECEIVED_TOTAL}${DATE1} ${RECEIVED_TOTAL}
|
||||
done
|
2
vendor/github.com/feditools/go-lib/Jenkinsfile
generated
vendored
2
vendor/github.com/feditools/go-lib/Jenkinsfile
generated
vendored
@ -1,6 +1,6 @@
|
||||
pipeline {
|
||||
environment {
|
||||
BUILD_IMAGE = 'gobuild:1.17'
|
||||
BUILD_IMAGE = 'gobuild:1.18'
|
||||
BUILD_ARGS = '-e GOCACHE=/gocache -e HOME=${WORKSPACE} -v /var/lib/jenkins/gocache:/gocache -v /var/lib/jenkins/go/pkg:/go/pkg'
|
||||
PATH = '/go/bin:~/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin'
|
||||
}
|
||||
|
1
vendor/github.com/feditools/go-lib/language/locales/active.af.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.af.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.ar.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.ar.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.ca.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.ca.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.cs.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.cs.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.da.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.da.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.de.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.de.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.el.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.el.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
39
vendor/github.com/feditools/go-lib/language/locales/active.es.yaml
generated
vendored
39
vendor/github.com/feditools/go-lib/language/locales/active.es.yaml
generated
vendored
@ -1,39 +0,0 @@
|
||||
---
|
||||
Account:
|
||||
one: Cuenta
|
||||
other: Cuentas
|
||||
AddOauth20Client:
|
||||
one: Añadir Cliente OAuth 2.0
|
||||
other: Añadir Clientes de OAuth 2.0
|
||||
Client:
|
||||
one: Cliente
|
||||
other: Clientes
|
||||
ClientID:
|
||||
one: ID de Cliente
|
||||
other: IDs de Cliente
|
||||
ClientSecret:
|
||||
one: Secreto de Cliente
|
||||
other: Secretos del Cliente
|
||||
Create: Crear
|
||||
Dashboard:
|
||||
one: Tablero
|
||||
other: Tableros
|
||||
Description:
|
||||
one: Descripción
|
||||
other: Descripciones
|
||||
HomeWeb: Inicio
|
||||
InvalidURI:
|
||||
one: URI Inválidas
|
||||
other: URIs Inválidas
|
||||
Login: Ingresar
|
||||
LooksGood: '¡Se ve bien!'
|
||||
Oauth: OAuth
|
||||
Oauth20Client:
|
||||
one: Cliente OAuth 2.0
|
||||
other: Clientes de OAuth 2.0
|
||||
Oauth20Settings: Configuración de OAuth 2.0
|
||||
RedirectURI:
|
||||
one: Redirigir URI
|
||||
other: Redirigir URIs
|
||||
Required: Requerido
|
||||
Unauthorized: No Autorizado
|
1
vendor/github.com/feditools/go-lib/language/locales/active.fi.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.fi.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.fr.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.fr.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.he.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.he.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.hu.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.hu.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
1
vendor/github.com/feditools/go-lib/language/locales/active.it.yaml
generated
vendored
1
vendor/github.com/feditools/go-lib/language/locales/active.it.yaml
generated
vendored
@ -1 +0,0 @@
|
||||
---
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user