Skip to content

Commit

Permalink
add reporter for missing ntfn translations
Browse files Browse the repository at this point in the history
  • Loading branch information
chappjc committed Sep 15, 2022
1 parent edf3537 commit 7389105
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 39 deletions.
2 changes: 1 addition & 1 deletion client/core/core_test.go
Expand Up @@ -1194,7 +1194,7 @@ func newTestRig() *testRig {
newCrypter: func([]byte) encrypt.Crypter { return crypter },
reCrypter: func([]byte, []byte) (encrypt.Crypter, error) { return crypter, crypter.recryptErr },

locale: enUS,
locale: originLocale,
localePrinter: message.NewPrinter(language.AmericanEnglish),

fiatRateSources: make(map[string]*commonRateSource),
Expand Down
69 changes: 56 additions & 13 deletions client/core/locale_ntfn.go
Expand Up @@ -10,10 +10,18 @@ import (
type translation struct {
subject string
template string

// stale is used to indicate that a translation has changed, is only
// partially translated, or just needs review, and should be updated. This
// is useful when it's better than falling back to english, but it allows
// these translations to be identified programmatically.
stale bool
}

// enUS is the American English translations.
var enUS = map[Topic]*translation{
const originLang = "en-US"

// originLocale is the American English translations.
var originLocale = map[Topic]*translation{
// [host]
TopicAccountRegistered: {
subject: "Account registered",
Expand Down Expand Up @@ -74,7 +82,7 @@ var enUS = map[Topic]*translation{
subject: "Send error",
template: "Error encountered while sending %s: %v",
},
// [ticker, coin ID]
// [value string, ticker, destination address, coin ID]
TopicSendSuccess: {
subject: "Send Successful",
template: "Sending %s %s to %s has completed successfully. Coin ID = %s",
Expand Down Expand Up @@ -386,15 +394,17 @@ var ptBR = map[Topic]*translation{
subject: "Erro ao Destravar Carteira",
template: "Conectado com carteira para completar o registro em %s, mas falha ao destrancar: %v",
},
// [ticker, error], RETRANSLATE.
// [ticker, error]
TopicSendError: {
subject: "Erro Retirada",
template: "Erro encontrado durante retirada de %s: %v",
stale: true,
},
// [ticker, coin ID], RETRANSLATE.
// [value string, ticker, destination address, coin ID]
TopicSendSuccess: {
template: "Retirada de %s %s (%s) foi completada com sucesso. ID da moeda = %s",
subject: "Retirada Enviada",
stale: true,
},
// [error]
TopicOrderLoadFailure: {
Expand Down Expand Up @@ -688,15 +698,17 @@ var zhCN = map[Topic]*translation{
subject: "解锁钱包时出错",
template: "与 decred 钱包连接以在 %s 上完成注册,但无法解锁: %v", // alt. 已连接到 Decred 钱包以在 %s 完成注册,但无法解锁:%v
},
// [ticker, error], RETRANSLATE.
// [ticker, error]
TopicSendError: {
subject: "提款错误",
template: "在 %s 提取过程中遇到错误: %v", // alt. 删除 %s 时遇到错误: %v
stale: true,
},
// [ticker, coin ID], RETRANSLATE.
// [value string, ticker, destination address, coin ID]
TopicSendSuccess: {
subject: "提款已发送",
template: "%s %s (%s) 的提款已成功完成。硬币 ID = %s",
stale: true,
},
// [error]
TopicOrderLoadFailure: {
Expand Down Expand Up @@ -989,15 +1001,17 @@ var plPL = map[Topic]*translation{
subject: "Błąd odblokowywania portfela",
template: "Połączono z portfelem Decred, aby dokończyć rejestrację na %s, lecz próba odblokowania portfela nie powiodła się: %v",
},
// [ticker, error], RETRANSLATE.
// [ticker, error]
TopicSendError: {
subject: "Błąd wypłaty środków",
template: "Wystąpił błąd przy wypłacaniu %s: %v",
stale: true,
},
// [ticker, coin ID], RETRANSLATE.
// [value string, ticker, destination address, coin ID]
TopicSendSuccess: {
subject: "Wypłata zrealizowana",
template: "Wypłata %s %s (%s) została zrealizowana pomyślnie. ID monety = %s",
stale: true,
},
// [error]
TopicOrderLoadFailure: {
Expand Down Expand Up @@ -1250,10 +1264,10 @@ var plPL = map[Topic]*translation{
}

var locales = map[string]map[Topic]*translation{
language.AmericanEnglish.String(): enUS,
language.BrazilianPortuguese.String(): ptBR,
"zh-CN": zhCN, // language.SimplifiedChinese is zh-Hans
"pl-PL": plPL, // language.Polish is pl
originLang: originLocale,
"pt-BR": ptBR,
"zh-CN": zhCN,
"pl-PL": plPL,
}

func init() {
Expand All @@ -1266,3 +1280,32 @@ func init() {
}
}
}

// CheckTopicLangs is used to report missing notification translations.
func CheckTopicLangs() (missing, stale map[string][]Topic) {
missing = make(map[string][]Topic, len(locales)-1)
stale = make(map[string][]Topic, len(locales)-1)

for lang, translations := range locales {
if lang == originLang {
continue
}
var missingTopics, staleTopics []Topic
for topic := range originLocale {
t, found := translations[topic]
if !found {
missingTopics = append(missingTopics, topic)
} else if t.stale {
staleTopics = append(staleTopics, topic)
}
}
if len(missingTopics) > 0 {
missing[lang] = missingTopics
}
if len(staleTopics) > 0 {
stale[lang] = staleTopics
}
}

return
}
40 changes: 18 additions & 22 deletions client/core/localetest/main.go
Expand Up @@ -2,32 +2,28 @@ package main

import (
"fmt"
"os"

"golang.org/x/text/language"
"golang.org/x/text/message"
"decred.org/dcrdex/client/core"
)

const key = "key"

func main() {
icelandicTmpl := "%.2f gígavött"
englishTmpl := "%.2f gigawatts"

err := message.SetString(language.Icelandic, key, icelandicTmpl)
if err != nil {
panic(err.Error())
missing, stale := core.CheckTopicLangs()
if len(missing) == 0 && len(stale) == 0 {
fmt.Println("No missing or stale notification translations!")
os.Exit(0)
}
err = message.SetString(language.AmericanEnglish, key, englishTmpl)
if err != nil {
panic(err.Error())
for lang, topics := range missing {
fmt.Printf("%d missing notification translations for %v\n", len(topics), lang)
for i := range topics {
fmt.Printf("[%v] Translation missing for topic %v\n", lang, topics[i])
}
}

icelandicPrinter := message.NewPrinter(language.Icelandic)
englishPrinter := message.NewPrinter(language.AmericanEnglish)

fmt.Println("Icelandic (using key):", icelandicPrinter.Sprintf(key, 1.21))
fmt.Println("Icelandic (direct): ", icelandicPrinter.Sprintf(icelandicTmpl, 1.21))

fmt.Println("English (using key): ", englishPrinter.Sprintf(key, 1.21))
fmt.Println("English (direct): ", englishPrinter.Sprintf(englishTmpl, 1.21))
for lang, topics := range stale {
fmt.Printf("%d stale notification translations for %v\n", len(topics), lang)
for i := range topics {
fmt.Printf("[%v] Translation stale for topic %v\n", lang, topics[i])
}
}
// os.Exit(1) // if we want this to be fatal
}
8 changes: 6 additions & 2 deletions client/core/notification.go
Expand Up @@ -104,8 +104,12 @@ func (c *Core) AckNotes(ids []dex.Bytes) {
func (c *Core) formatDetails(topic Topic, args ...interface{}) (translatedSubject, details string) {
trans, found := c.locale[topic]
if !found {
c.log.Errorf("no translation found for topic %q", topic)
return string(topic), "translation error"
c.log.Errorf("No translation found for topic %q", topic)
originTrans := originLocale[topic]
if originTrans == nil {
return string(topic), "translation error"
}
return originTrans.subject, fmt.Sprintf(originTrans.template, args...)
}
return trans.subject, c.localePrinter.Sprintf(string(topic), args...)
}
Expand Down
2 changes: 1 addition & 1 deletion docs/wiki/Localization-and-Translation.md
Expand Up @@ -18,7 +18,7 @@ The new HTML strings map must then be listed in <https://github.com/decred/dcrde

## Step 2 - Notifications

The notification strings involved editing [client/core/locale_ntfn.go](https://github.com/decred/dcrdex/blob/master/client/core/locale_ntfn.go) with a new `var zhCN map[Topic]*translation`. These translations correspond to the English strings in the `enUS` map in the same file.
The notification strings involved editing [client/core/locale_ntfn.go](https://github.com/decred/dcrdex/blob/master/client/core/locale_ntfn.go) with a new `var zhCN map[Topic]*translation`. These translations correspond to the English strings in the `originLocale` map in the same file.

Note how in **client/core/locale_ntfn.go** there are "printf" specifiers like `%s` and `%d`. These define the formatting for various runtime data, such as integer numbers, identifier strings, etc. Because sentence structure varies between languages the order of those specifiers can be explicitly defined like `%[3]s` (the third argument given to printf in the code) instead of relying on the position of those specifiers in the formatting string. This is necessary because the code that executes the printing always provides the values in a particular order, which may not be the same order in a translated string.

Expand Down
3 changes: 3 additions & 0 deletions run_tests.sh
Expand Up @@ -35,6 +35,9 @@ done

cd "$dir"

# Print missing Core notification translations.
go run ./client/core/localetest/main.go

# -race in go tests above requires cgo, but disable it for the compile tests below
export CGO_ENABLED=0
go build ./...
Expand Down

0 comments on commit 7389105

Please sign in to comment.