[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/i18n/RFC.md fully. Find ONE feature... #104
5 changed files with 173 additions and 33 deletions
82
context_map.go
Normal file
82
context_map.go
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
package i18n
|
||||
|
||||
import "dappco.re/go/core"
|
||||
|
||||
func mapValueString(values any, key string) (string, bool) {
|
||||
switch m := values.(type) {
|
||||
case map[string]any:
|
||||
raw, ok := m[key]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
text := core.Trim(core.Sprintf("%v", raw))
|
||||
if text == "" {
|
||||
return "", false
|
||||
}
|
||||
return text, true
|
||||
case map[string]string:
|
||||
text, ok := m[key]
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
text = core.Trim(text)
|
||||
if text == "" {
|
||||
return "", false
|
||||
}
|
||||
return text, true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func contextMapValues(values any) map[string]any {
|
||||
switch m := values.(type) {
|
||||
case map[string]any:
|
||||
return contextMapValuesAny(m)
|
||||
case map[string]string:
|
||||
return contextMapValuesString(m)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func contextMapValuesAny(values map[string]any) map[string]any {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
extra := make(map[string]any, len(values))
|
||||
for key, value := range values {
|
||||
switch key {
|
||||
case "Context", "Gender", "Location", "Formality":
|
||||
continue
|
||||
case "Extra", "extra", "Extras", "extras":
|
||||
mergeContextExtra(extra, value)
|
||||
continue
|
||||
default:
|
||||
extra[key] = value
|
||||
}
|
||||
}
|
||||
if len(extra) == 0 {
|
||||
return nil
|
||||
}
|
||||
return extra
|
||||
}
|
||||
|
||||
func contextMapValuesString(values map[string]string) map[string]any {
|
||||
if len(values) == 0 {
|
||||
return nil
|
||||
}
|
||||
extra := make(map[string]any, len(values))
|
||||
for key, value := range values {
|
||||
switch key {
|
||||
case "Context", "Gender", "Location", "Formality", "Extra", "extra", "Extras", "extras":
|
||||
continue
|
||||
default:
|
||||
extra[key] = value
|
||||
}
|
||||
}
|
||||
if len(extra) == 0 {
|
||||
return nil
|
||||
}
|
||||
return extra
|
||||
}
|
||||
13
handler.go
13
handler.go
|
|
@ -238,6 +238,8 @@ func subjectArgText(arg any) string {
|
|||
return ""
|
||||
case map[string]any:
|
||||
return contextArgText(v)
|
||||
case map[string]string:
|
||||
return contextArgText(v)
|
||||
case fmt.Stringer:
|
||||
return v.String()
|
||||
default:
|
||||
|
|
@ -245,15 +247,10 @@ func subjectArgText(arg any) string {
|
|||
}
|
||||
}
|
||||
|
||||
func contextArgText(values map[string]any) string {
|
||||
if len(values) == 0 {
|
||||
return ""
|
||||
}
|
||||
func contextArgText(values any) string {
|
||||
for _, key := range []string{"Subject", "subject", "Value", "value", "Text", "text", "Context", "context", "Noun", "noun"} {
|
||||
if raw, ok := values[key]; ok {
|
||||
if text := core.Trim(core.Sprintf("%v", raw)); text != "" {
|
||||
return text
|
||||
}
|
||||
if text, ok := mapValueString(values, key); ok {
|
||||
return text
|
||||
}
|
||||
}
|
||||
return ""
|
||||
|
|
|
|||
|
|
@ -63,6 +63,11 @@ func TestProgressHandler(t *testing.T) {
|
|||
if got != "Building project..." {
|
||||
t.Errorf("ProgressHandler.Handle(build, map[Subject:project]) = %q, want %q", got, "Building project...")
|
||||
}
|
||||
|
||||
got = h.Handle("i18n.progress.build", []any{map[string]string{"Subject": "project"}}, nil)
|
||||
if got != "Building project..." {
|
||||
t.Errorf("ProgressHandler.Handle(build, map[string]string[Subject:project]) = %q, want %q", got, "Building project...")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountHandler(t *testing.T) {
|
||||
|
|
@ -148,6 +153,11 @@ func TestDoneHandler(t *testing.T) {
|
|||
t.Errorf("DoneHandler.Handle(delete, map[Subject:config.yaml]) = %q, want %q", got, "Config.yaml deleted")
|
||||
}
|
||||
|
||||
got = h.Handle("i18n.done.delete", []any{map[string]string{"Subject": "config.yaml"}}, nil)
|
||||
if got != "Config.yaml deleted" {
|
||||
t.Errorf("DoneHandler.Handle(delete, map[string]string[Subject:config.yaml]) = %q, want %q", got, "Config.yaml deleted")
|
||||
}
|
||||
|
||||
// Without subject — just past tense
|
||||
got = h.Handle("i18n.done.delete", nil, nil)
|
||||
if got != "Deleted" {
|
||||
|
|
@ -182,6 +192,11 @@ func TestFailHandler(t *testing.T) {
|
|||
t.Errorf("FailHandler.Handle(push, map[Subject:commits]) = %q, want %q", got, "Failed to push commits")
|
||||
}
|
||||
|
||||
got = h.Handle("i18n.fail.push", []any{map[string]string{"Subject": "commits"}}, nil)
|
||||
if got != "Failed to push commits" {
|
||||
t.Errorf("FailHandler.Handle(push, map[string]string[Subject:commits]) = %q, want %q", got, "Failed to push commits")
|
||||
}
|
||||
|
||||
got = h.Handle("i18n.fail.push", nil, nil)
|
||||
if got != "Failed to push" {
|
||||
t.Errorf("FailHandler.Handle(push) = %q, want %q", got, "Failed to push")
|
||||
|
|
|
|||
70
service.go
70
service.go
|
|
@ -453,14 +453,14 @@ func (s *Service) getEffectiveContextGenderLocationAndFormality(data any) (strin
|
|||
var gender string
|
||||
location := s.location
|
||||
formality := s.formality
|
||||
if v, ok := m["Context"].(string); ok {
|
||||
context = core.Trim(v)
|
||||
if v, ok := mapValueString(m, "Context"); ok {
|
||||
context = v
|
||||
}
|
||||
if v, ok := m["Gender"].(string); ok {
|
||||
gender = core.Trim(v)
|
||||
if v, ok := mapValueString(m, "Gender"); ok {
|
||||
gender = v
|
||||
}
|
||||
if v, ok := m["Location"].(string); ok {
|
||||
location = core.Trim(v)
|
||||
if v, ok := mapValueString(m, "Location"); ok {
|
||||
location = v
|
||||
}
|
||||
if v, ok := m["Formality"]; ok {
|
||||
switch f := v.(type) {
|
||||
|
|
@ -479,6 +479,30 @@ func (s *Service) getEffectiveContextGenderLocationAndFormality(data any) (strin
|
|||
}
|
||||
return context, gender, location, formality
|
||||
}
|
||||
if m, ok := data.(map[string]string); ok {
|
||||
var context string
|
||||
var gender string
|
||||
location := s.location
|
||||
formality := s.formality
|
||||
if v, ok := mapValueString(m, "Context"); ok {
|
||||
context = v
|
||||
}
|
||||
if v, ok := mapValueString(m, "Gender"); ok {
|
||||
gender = v
|
||||
}
|
||||
if v, ok := mapValueString(m, "Location"); ok {
|
||||
location = v
|
||||
}
|
||||
if v, ok := mapValueString(m, "Formality"); ok {
|
||||
switch core.Lower(v) {
|
||||
case "formal":
|
||||
formality = FormalityFormal
|
||||
case "informal":
|
||||
formality = FormalityInformal
|
||||
}
|
||||
}
|
||||
return context, gender, location, formality
|
||||
}
|
||||
return "", "", s.location, s.getEffectiveFormality(data)
|
||||
}
|
||||
|
||||
|
|
@ -490,25 +514,9 @@ func (s *Service) getEffectiveContextExtra(data any) map[string]any {
|
|||
}
|
||||
return v.Extra
|
||||
case map[string]any:
|
||||
if len(v) == 0 {
|
||||
return nil
|
||||
}
|
||||
extra := make(map[string]any, len(v))
|
||||
for key, value := range v {
|
||||
switch key {
|
||||
case "Context", "Gender", "Location", "Formality":
|
||||
continue
|
||||
case "Extra", "extra", "Extras", "extras":
|
||||
mergeContextExtra(extra, value)
|
||||
continue
|
||||
default:
|
||||
extra[key] = value
|
||||
}
|
||||
}
|
||||
if len(extra) == 0 {
|
||||
return nil
|
||||
}
|
||||
return extra
|
||||
return contextMapValues(v)
|
||||
case map[string]string:
|
||||
return contextMapValues(v)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -563,6 +571,16 @@ func (s *Service) getEffectiveFormality(data any) Formality {
|
|||
}
|
||||
}
|
||||
}
|
||||
if m, ok := data.(map[string]string); ok {
|
||||
if f, ok := mapValueString(m, "Formality"); ok {
|
||||
switch core.Lower(f) {
|
||||
case "formal":
|
||||
return FormalityFormal
|
||||
case "informal":
|
||||
return FormalityInformal
|
||||
}
|
||||
}
|
||||
}
|
||||
return s.formality
|
||||
}
|
||||
|
||||
|
|
@ -690,6 +708,8 @@ func missingKeyArgs(args []any) map[string]any {
|
|||
switch v := args[0].(type) {
|
||||
case map[string]any:
|
||||
return v
|
||||
case map[string]string:
|
||||
return contextMapValues(v)
|
||||
case *TranslationContext:
|
||||
return missingKeyContextArgs(v)
|
||||
case *Subject:
|
||||
|
|
|
|||
|
|
@ -128,6 +128,32 @@ func TestServiceTMapContextNestedExtra(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestServiceTMapContextStringExtras(t *testing.T) {
|
||||
svc, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() failed: %v", err)
|
||||
}
|
||||
SetDefault(svc)
|
||||
|
||||
svc.AddMessages("en", map[string]string{
|
||||
"welcome._greeting": "hello",
|
||||
"welcome._greeting._region._europe": "bonjour",
|
||||
"welcome._greeting._region._americas": "howdy",
|
||||
})
|
||||
|
||||
if got := svc.T("welcome", map[string]string{"Context": "greeting"}); got != "hello" {
|
||||
t.Fatalf("T(welcome, map[string]string{Context:greeting}) = %q, want %q", got, "hello")
|
||||
}
|
||||
|
||||
if got := svc.T("welcome", map[string]string{"Context": "greeting", "region": "europe"}); got != "bonjour" {
|
||||
t.Fatalf("T(welcome, map[string]string{Context:greeting region:europe}) = %q, want %q", got, "bonjour")
|
||||
}
|
||||
|
||||
if got := svc.T("welcome", map[string]string{"Context": "greeting", "region": "americas"}); got != "howdy" {
|
||||
t.Fatalf("T(welcome, map[string]string{Context:greeting region:americas}) = %q, want %q", got, "howdy")
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceRaw(t *testing.T) {
|
||||
svc, err := New()
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue