diff --git a/pkg/i18n/i18n.go b/pkg/i18n/i18n.go index a2a18ed8..04f6163f 100644 --- a/pkg/i18n/i18n.go +++ b/pkg/i18n/i18n.go @@ -513,7 +513,7 @@ func L(word string) string { // Use this for direct key lookups without auto-composition. // // i18n._("cli.success") // Raw lookup -// i18n.T("core.label.status") // Smart: returns "Status:" +// i18n.T("i18n.label.status") // Smart: returns "Status:" func _(messageID string, args ...any) string { if svc := Default(); svc != nil { return svc.Raw(messageID, args...) @@ -626,25 +626,25 @@ func (s *Service) PluralCategory(n int) PluralCategory { // // The core.* namespace provides auto-composed grammar shortcuts: // -// T("core.label.status") // → "Status:" -// T("core.progress.build") // → "Building..." -// T("core.progress.check", "config") // → "Checking config..." -// T("core.count.file", 5) // → "5 files" -// T("core.done.delete", "file") // → "File deleted" -// T("core.fail.delete", "file") // → "Failed to delete file" +// T("i18n.label.status") // → "Status:" +// T("i18n.progress.build") // → "Building..." +// T("i18n.progress.check", "config") // → "Checking config..." +// T("i18n.count.file", 5) // → "5 files" +// T("i18n.done.delete", "file") // → "File deleted" +// T("i18n.fail.delete", "file") // → "Failed to delete file" // // For semantic intents, pass a Subject: // // T("core.delete", S("file", "config.yaml")) // → "Delete config.yaml?" // -// Use _() for raw key lookup without core.* magic. +// Use _() for raw key lookup without i18n.* magic. func (s *Service) T(messageID string, args ...any) string { s.mu.RLock() defer s.mu.RUnlock() - // Handle core.* namespace magic - if strings.HasPrefix(messageID, "core.") { - if result := s.handleCoreNamespace(messageID, args); result != "" { + // Handle i18n.* namespace magic + if strings.HasPrefix(messageID, "i18n.") { + if result := s.handleI18nNamespace(messageID, args); result != "" { if s.debug { return debugFormat(messageID, result) } @@ -672,19 +672,19 @@ func (s *Service) T(messageID string, args ...any) string { return text } -// handleCoreNamespace processes core.* namespace patterns. +// handleI18nNamespace processes i18n.* namespace patterns. // Returns empty string if pattern not recognized. // Must be called with s.mu.RLock held. -func (s *Service) handleCoreNamespace(key string, args []any) string { - // core.label.{word} → Label(word) - if strings.HasPrefix(key, "core.label.") { - word := strings.TrimPrefix(key, "core.label.") +func (s *Service) handleI18nNamespace(key string, args []any) string { + // i18n.label.{word} → Label(word) + if strings.HasPrefix(key, "i18n.label.") { + word := strings.TrimPrefix(key, "i18n.label.") return Label(word) } - // core.progress.{verb} → Progress(verb) or ProgressSubject(verb, subj) - if strings.HasPrefix(key, "core.progress.") { - verb := strings.TrimPrefix(key, "core.progress.") + // i18n.progress.{verb} → Progress(verb) or ProgressSubject(verb, subj) + if strings.HasPrefix(key, "i18n.progress.") { + verb := strings.TrimPrefix(key, "i18n.progress.") if len(args) > 0 { if subj, ok := args[0].(string); ok { return ProgressSubject(verb, subj) @@ -693,9 +693,9 @@ func (s *Service) handleCoreNamespace(key string, args []any) string { return Progress(verb) } - // core.count.{noun} → "N noun(s)" - if strings.HasPrefix(key, "core.count.") { - noun := strings.TrimPrefix(key, "core.count.") + // i18n.count.{noun} → "N noun(s)" + if strings.HasPrefix(key, "i18n.count.") { + noun := strings.TrimPrefix(key, "i18n.count.") if len(args) > 0 { count := toInt(args[0]) return fmt.Sprintf("%d %s", count, Pluralize(noun, count)) @@ -703,9 +703,9 @@ func (s *Service) handleCoreNamespace(key string, args []any) string { return noun } - // core.done.{verb} → ActionResult(verb, subj) - if strings.HasPrefix(key, "core.done.") { - verb := strings.TrimPrefix(key, "core.done.") + // i18n.done.{verb} → ActionResult(verb, subj) + if strings.HasPrefix(key, "i18n.done.") { + verb := strings.TrimPrefix(key, "i18n.done.") if len(args) > 0 { if subj, ok := args[0].(string); ok { return ActionResult(verb, subj) @@ -714,9 +714,9 @@ func (s *Service) handleCoreNamespace(key string, args []any) string { return Title(PastTense(verb)) } - // core.fail.{verb} → ActionFailed(verb, subj) - if strings.HasPrefix(key, "core.fail.") { - verb := strings.TrimPrefix(key, "core.fail.") + // i18n.fail.{verb} → ActionFailed(verb, subj) + if strings.HasPrefix(key, "i18n.fail.") { + verb := strings.TrimPrefix(key, "i18n.fail.") if len(args) > 0 { if subj, ok := args[0].(string); ok { return ActionFailed(verb, subj) @@ -725,16 +725,6 @@ func (s *Service) handleCoreNamespace(key string, args []any) string { return ActionFailed(verb, "") } - // core.{intent} with Subject → C(intent, subject).Question - if len(args) > 0 { - if subject, ok := args[0].(*Subject); ok { - s.mu.RUnlock() - result := s.C(key, subject) - s.mu.RLock() - return result.Question - } - } - return "" } diff --git a/pkg/i18n/i18n_test.go b/pkg/i18n/i18n_test.go index 772e7018..a16dea6d 100644 --- a/pkg/i18n/i18n_test.go +++ b/pkg/i18n/i18n_test.go @@ -140,16 +140,16 @@ func TestPluralization(t *testing.T) { require.NoError(t, err) SetDefault(svc) - // Singular - uses core.count.* magic - result := svc.T("core.count.item", 1) + // Singular - uses i18n.count.* magic + result := svc.T("i18n.count.item", 1) assert.Equal(t, "1 item", result) // Plural - result = svc.T("core.count.item", 5) + result = svc.T("i18n.count.item", 5) assert.Equal(t, "5 items", result) // Zero uses plural - result = svc.T("core.count.item", 0) + result = svc.T("i18n.count.item", 0) assert.Equal(t, "0 items", result) } @@ -320,7 +320,7 @@ func TestDebugMode(t *testing.T) { }) } -func TestCoreNamespaceMagic(t *testing.T) { +func TestI18nNamespaceMagic(t *testing.T) { svc, err := New() require.NoError(t, err) SetDefault(svc) @@ -331,16 +331,16 @@ func TestCoreNamespaceMagic(t *testing.T) { args []any expected string }{ - {"label", "core.label.status", nil, "Status:"}, - {"label version", "core.label.version", nil, "Version:"}, - {"progress", "core.progress.build", nil, "Building..."}, - {"progress check", "core.progress.check", nil, "Checking..."}, - {"progress with subject", "core.progress.check", []any{"config"}, "Checking config..."}, - {"count singular", "core.count.file", []any{1}, "1 file"}, - {"count plural", "core.count.file", []any{5}, "5 files"}, - {"done", "core.done.delete", []any{"file"}, "File deleted"}, - {"done build", "core.done.build", []any{"project"}, "Project built"}, - {"fail", "core.fail.delete", []any{"file"}, "Failed to delete file"}, + {"label", "i18n.label.status", nil, "Status:"}, + {"label version", "i18n.label.version", nil, "Version:"}, + {"progress", "i18n.progress.build", nil, "Building..."}, + {"progress check", "i18n.progress.check", nil, "Checking..."}, + {"progress with subject", "i18n.progress.check", []any{"config"}, "Checking config..."}, + {"count singular", "i18n.count.file", []any{1}, "1 file"}, + {"count plural", "i18n.count.file", []any{5}, "5 files"}, + {"done", "i18n.done.delete", []any{"file"}, "File deleted"}, + {"done build", "i18n.done.build", []any{"project"}, "Project built"}, + {"fail", "i18n.fail.delete", []any{"file"}, "Failed to delete file"}, } for _, tt := range tests { @@ -351,15 +351,15 @@ func TestCoreNamespaceMagic(t *testing.T) { } } -func TestRawBypassesCoreNamespace(t *testing.T) { +func TestRawBypassesI18nNamespace(t *testing.T) { svc, err := New() require.NoError(t, err) - // Raw() should return key as-is since core.label.status isn't in JSON - result := svc.Raw("core.label.status") - assert.Equal(t, "core.label.status", result) + // Raw() should return key as-is since i18n.label.status isn't in JSON + result := svc.Raw("i18n.label.status") + assert.Equal(t, "i18n.label.status", result) // T() should compose it - result = svc.T("core.label.status") + result = svc.T("i18n.label.status") assert.Equal(t, "Status:", result) } diff --git a/pkg/i18n/intents_test.go b/pkg/i18n/intents_test.go index 2e6d8da0..389d8624 100644 --- a/pkg/i18n/intents_test.go +++ b/pkg/i18n/intents_test.go @@ -265,12 +265,12 @@ func TestIntentT_Integration(t *testing.T) { svc, err := New() require.NoError(t, err) - // Using T with core.* prefix and Subject should return Question form - result := svc.T("core.delete", S("file", "config.yaml")) - assert.Equal(t, "Delete config.yaml?", result) + // Using C with intent key and Subject + composed := svc.C("core.delete", S("file", "config.yaml")) + assert.Equal(t, "Delete config.yaml?", composed.Question) // Using T with regular key should work normally - result = svc.T("cmd.dev.short") + result := svc.T("cmd.dev.short") assert.Equal(t, "Multi-repo development workflow", result) }