[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/i18n/RFC.md fully. Find ONE feature... #79
2 changed files with 91 additions and 2 deletions
68
service.go
68
service.go
|
|
@ -7,8 +7,10 @@ import (
|
|||
"path"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unicode"
|
||||
|
||||
"dappco.re/go/core"
|
||||
log "dappco.re/go/core/log"
|
||||
|
|
@ -391,7 +393,8 @@ func (s *Service) resolveWithFallback(messageID string, data any) string {
|
|||
|
||||
func (s *Service) tryResolve(lang, key string, data any) string {
|
||||
context, gender, location, formality := s.getEffectiveContextGenderLocationAndFormality(data)
|
||||
for _, lookupKey := range lookupVariants(key, context, gender, location, formality) {
|
||||
extra := s.getEffectiveContextExtra(data)
|
||||
for _, lookupKey := range lookupVariants(key, context, gender, location, formality, extra) {
|
||||
if text := s.resolveMessage(lang, lookupKey, data); text != "" {
|
||||
return text
|
||||
}
|
||||
|
|
@ -468,6 +471,14 @@ func (s *Service) getEffectiveContextGenderLocationAndFormality(data any) (strin
|
|||
return "", "", s.location, s.getEffectiveFormality(data)
|
||||
}
|
||||
|
||||
func (s *Service) getEffectiveContextExtra(data any) map[string]any {
|
||||
ctx, ok := data.(*TranslationContext)
|
||||
if !ok || ctx == nil || len(ctx.Extra) == 0 {
|
||||
return nil
|
||||
}
|
||||
return ctx.Extra
|
||||
}
|
||||
|
||||
func (s *Service) getEffectiveFormality(data any) Formality {
|
||||
if ctx, ok := data.(*TranslationContext); ok && ctx != nil {
|
||||
if ctx.Formality != FormalityNeutral {
|
||||
|
|
@ -497,7 +508,7 @@ func (s *Service) getEffectiveFormality(data any) Formality {
|
|||
return s.formality
|
||||
}
|
||||
|
||||
func lookupVariants(key, context, gender, location string, formality Formality) []string {
|
||||
func lookupVariants(key, context, gender, location string, formality Formality, extra map[string]any) []string {
|
||||
var variants []string
|
||||
if context != "" {
|
||||
if gender != "" && location != "" && formality != FormalityNeutral {
|
||||
|
|
@ -544,10 +555,63 @@ func lookupVariants(key, context, gender, location string, formality Formality)
|
|||
if formality != FormalityNeutral {
|
||||
variants = append(variants, key+"._"+formality.String())
|
||||
}
|
||||
if extraSuffix := lookupExtraSuffix(extra); extraSuffix != "" {
|
||||
base := slices.Clone(variants)
|
||||
var extraVariants []string
|
||||
for _, variant := range base {
|
||||
extraVariants = append(extraVariants, variant+extraSuffix)
|
||||
}
|
||||
variants = append(extraVariants, variants...)
|
||||
}
|
||||
variants = append(variants, key)
|
||||
return variants
|
||||
}
|
||||
|
||||
func lookupExtraSuffix(extra map[string]any) string {
|
||||
if len(extra) == 0 {
|
||||
return ""
|
||||
}
|
||||
keys := slices.Sorted(maps.Keys(extra))
|
||||
var b strings.Builder
|
||||
for _, key := range keys {
|
||||
name := lookupSegment(key)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
value := lookupSegment(core.Sprintf("%v", extra[key]))
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
b.WriteString("._")
|
||||
b.WriteString(name)
|
||||
b.WriteString("._")
|
||||
b.WriteString(value)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func lookupSegment(s string) string {
|
||||
s = core.Trim(s)
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
var b strings.Builder
|
||||
lastUnderscore := false
|
||||
for _, r := range core.Lower(s) {
|
||||
switch {
|
||||
case unicode.IsLetter(r), unicode.IsDigit(r):
|
||||
b.WriteRune(r)
|
||||
lastUnderscore = false
|
||||
case r == '_' || r == '-' || r == '.' || unicode.IsSpace(r):
|
||||
if !lastUnderscore {
|
||||
b.WriteByte('_')
|
||||
lastUnderscore = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Trim(b.String(), "_")
|
||||
}
|
||||
|
||||
func (s *Service) handleMissingKey(key string, args []any) string {
|
||||
switch s.mode {
|
||||
case ModeStrict:
|
||||
|
|
|
|||
|
|
@ -324,6 +324,31 @@ func TestServiceTranslationContextExtrasInTemplates(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServiceTranslationContextExtrasInLookup(t *testing.T) {
|
||||
svc, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() failed: %v", err)
|
||||
}
|
||||
|
||||
svc.AddMessages("en", map[string]string{
|
||||
"welcome._greeting": "hello",
|
||||
"welcome._greeting._region._europe": "bonjour",
|
||||
"welcome._greeting._region._americas": "howdy",
|
||||
})
|
||||
|
||||
if got := svc.T("welcome", C("greeting")); got != "hello" {
|
||||
t.Errorf("T(welcome, C(greeting)) = %q, want %q", got, "hello")
|
||||
}
|
||||
|
||||
if got := svc.T("welcome", C("greeting").Set("region", "europe")); got != "bonjour" {
|
||||
t.Errorf("T(welcome, C(greeting).Set(region, europe)) = %q, want %q", got, "bonjour")
|
||||
}
|
||||
|
||||
if got := svc.T("welcome", C("greeting").Set("region", "americas")); got != "howdy" {
|
||||
t.Errorf("T(welcome, C(greeting).Set(region, americas)) = %q, want %q", got, "howdy")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceSubjectCountPlurals(t *testing.T) {
|
||||
svc, err := New()
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue