fix: sync WebA labels and forward fixes
This commit is contained in:
parent
7bb7e11603
commit
4d3bbeabd8
11 changed files with 422 additions and 10 deletions
|
|
@ -2,6 +2,7 @@ package langpack
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store"
|
||||
|
|
@ -24,18 +25,41 @@ func (s *Service) GetLangPack(ctx context.Context, langPack, langCode string) (d
|
|||
|
||||
// GetDifference 返回从 fromVersion 到当前版本的语言包差异。
|
||||
func (s *Service) GetDifference(ctx context.Context, langPack, langCode string, fromVersion int) (domain.LangPack, error) {
|
||||
packName := normalizePack(langPack)
|
||||
code := normalizeCode(langCode)
|
||||
if s == nil || s.packs == nil {
|
||||
return domain.LangPack{LangPack: langPack, LangCode: langCode, FromVersion: fromVersion}, nil
|
||||
return domain.LangPack{LangPack: packName, LangCode: code, FromVersion: fromVersion}, nil
|
||||
}
|
||||
return s.packs.GetPack(ctx, normalizePack(langPack), normalizeCode(langCode), fromVersion)
|
||||
pack, err := s.packs.GetPack(ctx, packName, code, fromVersion)
|
||||
if err != nil {
|
||||
return domain.LangPack{}, err
|
||||
}
|
||||
return s.overlayWebAStrings(ctx, pack, packName, code, fromVersion)
|
||||
}
|
||||
|
||||
// GetStrings 返回指定 key 的语言包字符串。
|
||||
func (s *Service) GetStrings(ctx context.Context, langPack, langCode string, keys []string) (domain.LangPack, error) {
|
||||
packName := normalizePack(langPack)
|
||||
code := normalizeCode(langCode)
|
||||
if s == nil || s.packs == nil {
|
||||
return domain.LangPack{LangPack: langPack, LangCode: langCode}, nil
|
||||
return domain.LangPack{LangPack: packName, LangCode: code}, nil
|
||||
}
|
||||
return s.packs.GetStrings(ctx, normalizePack(langPack), normalizeCode(langCode), keys)
|
||||
pack, err := s.packs.GetStrings(ctx, packName, code, keys)
|
||||
if err != nil {
|
||||
return domain.LangPack{}, err
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
return s.overlayWebAStrings(ctx, pack, packName, code, 0)
|
||||
}
|
||||
missing := missingLangPackKeys(keys, pack.Strings)
|
||||
if len(missing) == 0 || !shouldOverlayWebA(packName) {
|
||||
return pack, nil
|
||||
}
|
||||
overlay, err := s.packs.GetStrings(ctx, "weba", code, missing)
|
||||
if err != nil {
|
||||
return domain.LangPack{}, err
|
||||
}
|
||||
return mergeMissingLangPackStrings(pack, overlay), nil
|
||||
}
|
||||
|
||||
func normalizePack(langPack string) string {
|
||||
|
|
@ -46,8 +70,76 @@ func normalizePack(langPack string) string {
|
|||
}
|
||||
|
||||
func normalizeCode(langCode string) string {
|
||||
if langCode == "" {
|
||||
code := strings.ToLower(strings.TrimSpace(langCode))
|
||||
if code == "" {
|
||||
return "en"
|
||||
}
|
||||
return langCode
|
||||
return strings.TrimSuffix(code, "-raw")
|
||||
}
|
||||
|
||||
func shouldOverlayWebA(langPack string) bool {
|
||||
switch strings.ToLower(langPack) {
|
||||
case "android", "ios", "tdesktop", "macos":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) overlayWebAStrings(ctx context.Context, pack domain.LangPack, langPack, langCode string, fromVersion int) (domain.LangPack, error) {
|
||||
if fromVersion != 0 || !shouldOverlayWebA(langPack) {
|
||||
return pack, nil
|
||||
}
|
||||
overlay, err := s.packs.GetPack(ctx, "weba", langCode, fromVersion)
|
||||
if err != nil {
|
||||
return domain.LangPack{}, err
|
||||
}
|
||||
return mergeMissingLangPackStrings(pack, overlay), nil
|
||||
}
|
||||
|
||||
func mergeMissingLangPackStrings(pack, overlay domain.LangPack) domain.LangPack {
|
||||
if len(overlay.Strings) == 0 {
|
||||
return pack
|
||||
}
|
||||
if pack.LangCode == "" {
|
||||
pack.LangCode = overlay.LangCode
|
||||
}
|
||||
if overlay.Version > pack.Version {
|
||||
pack.Version = overlay.Version
|
||||
}
|
||||
seen := make(map[string]struct{}, len(pack.Strings)+len(overlay.Strings))
|
||||
for _, item := range pack.Strings {
|
||||
seen[item.Key] = struct{}{}
|
||||
}
|
||||
for _, item := range overlay.Strings {
|
||||
if _, ok := seen[item.Key]; ok {
|
||||
continue
|
||||
}
|
||||
pack.Strings = append(pack.Strings, item)
|
||||
seen[item.Key] = struct{}{}
|
||||
}
|
||||
return pack
|
||||
}
|
||||
|
||||
func missingLangPackKeys(keys []string, strings []domain.LangPackString) []string {
|
||||
if len(keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
have := make(map[string]struct{}, len(strings))
|
||||
for _, item := range strings {
|
||||
have[item.Key] = struct{}{}
|
||||
}
|
||||
missing := make([]string, 0)
|
||||
seenMissing := make(map[string]struct{}, len(keys))
|
||||
for _, key := range keys {
|
||||
if _, ok := have[key]; ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := seenMissing[key]; ok {
|
||||
continue
|
||||
}
|
||||
missing = append(missing, key)
|
||||
seenMissing[key] = struct{}{}
|
||||
}
|
||||
return missing
|
||||
}
|
||||
|
|
|
|||
81
internal/app/langpack/service_test.go
Normal file
81
internal/app/langpack/service_test.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package langpack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store/memory"
|
||||
)
|
||||
|
||||
func TestServiceNormalizesWebARawLangCode(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
packs := memory.NewLangPackStore()
|
||||
svc := NewService(packs)
|
||||
seed := domain.LangPack{
|
||||
LangPack: "android",
|
||||
LangCode: "en",
|
||||
Version: 7,
|
||||
Strings: []domain.LangPackString{
|
||||
{Key: "LogOutTitle", Value: "Log Out"},
|
||||
{Key: "NewMessageTitle", Value: "New Message"},
|
||||
},
|
||||
}
|
||||
if err := packs.UpsertPack(ctx, seed); err != nil {
|
||||
t.Fatalf("seed langpack: %v", err)
|
||||
}
|
||||
webASeed := domain.LangPack{
|
||||
LangPack: "weba",
|
||||
LangCode: "en",
|
||||
Version: 12,
|
||||
Strings: []domain.LangPackString{
|
||||
{Key: "AccDescrPollVoteDown", Value: "Go to next unread poll vote"},
|
||||
{Key: "NewMessageTitle", Value: "New Message from WebA"},
|
||||
},
|
||||
}
|
||||
if err := packs.UpsertPack(ctx, webASeed); err != nil {
|
||||
t.Fatalf("seed weba langpack: %v", err)
|
||||
}
|
||||
|
||||
pack, err := svc.GetLangPack(ctx, "android", "EN-raw")
|
||||
if err != nil {
|
||||
t.Fatalf("get langpack: %v", err)
|
||||
}
|
||||
if pack.LangCode != "en" || pack.Version != webASeed.Version || len(pack.Strings) != len(seed.Strings)+1 {
|
||||
t.Fatalf("pack = %+v, want normalized en pack", pack)
|
||||
}
|
||||
if got := stringValue(pack.Strings, "AccDescrPollVoteDown"); got != "Go to next unread poll vote" {
|
||||
t.Fatalf("AccDescrPollVoteDown = %q, want WebA fallback", got)
|
||||
}
|
||||
if got := stringValue(pack.Strings, "NewMessageTitle"); got != "New Message" {
|
||||
t.Fatalf("NewMessageTitle = %q, want source pack to keep precedence", got)
|
||||
}
|
||||
|
||||
selected, err := svc.GetStrings(ctx, "android", "en-raw", []string{"LogOutTitle", "AccDescrPollVoteDown"})
|
||||
if err != nil {
|
||||
t.Fatalf("get strings: %v", err)
|
||||
}
|
||||
if got := stringValue(selected.Strings, "LogOutTitle"); got != "Log Out" {
|
||||
t.Fatalf("LogOutTitle = %q, want source pack value", got)
|
||||
}
|
||||
if got := stringValue(selected.Strings, "AccDescrPollVoteDown"); got != "Go to next unread poll vote" {
|
||||
t.Fatalf("AccDescrPollVoteDown = %q, want WebA fallback", got)
|
||||
}
|
||||
|
||||
notModified, err := svc.GetDifference(ctx, "android", "en-raw", seed.Version)
|
||||
if err != nil {
|
||||
t.Fatalf("get difference: %v", err)
|
||||
}
|
||||
if notModified.LangCode != "en" || len(notModified.Strings) != 0 {
|
||||
t.Fatalf("difference = %+v, want normalized not-modified source pack", notModified)
|
||||
}
|
||||
}
|
||||
|
||||
func stringValue(strings []domain.LangPackString, key string) string {
|
||||
for _, item := range strings {
|
||||
if item.Key == key {
|
||||
return item.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue