[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/i18n/RFC.md fully. Find features de... #189

Merged
Virgil merged 1 commit from agent/read---spec-code-core-go-i18n-rfc-md-ful into dev 2026-04-02 09:44:02 +00:00
3 changed files with 114 additions and 0 deletions

60
i18n.go
View file

@ -10,6 +10,9 @@ import (
)
// T translates a message using the default service.
//
// Example:
// i18n.T("greeting")
func T(messageID string, args ...any) string {
if svc := Default(); svc != nil {
return svc.T(messageID, args...)
@ -18,6 +21,9 @@ func T(messageID string, args ...any) string {
}
// Translate translates a message using the default service and returns a Core result.
//
// Example:
// result := i18n.Translate("greeting")
func Translate(messageID string, args ...any) core.Result {
if svc := Default(); svc != nil {
return svc.Translate(messageID, args...)
@ -26,6 +32,9 @@ func Translate(messageID string, args ...any) core.Result {
}
// Raw translates without i18n.* namespace magic.
//
// Example:
// i18n.Raw("prompt.yes")
func Raw(messageID string, args ...any) string {
if svc := Default(); svc != nil {
return svc.Raw(messageID, args...)
@ -40,6 +49,9 @@ var ErrServiceNotInitialised = core.NewError("i18n: service not initialised")
var ErrServiceNotInitialized = ErrServiceNotInitialised
// SetLanguage sets the language for the default service.
//
// Example:
// _ = i18n.SetLanguage("fr")
func SetLanguage(lang string) error {
svc := Default()
if svc == nil {
@ -49,6 +61,9 @@ func SetLanguage(lang string) error {
}
// CurrentLanguage returns the current language code.
//
// Example:
// lang := i18n.CurrentLanguage()
func CurrentLanguage() string {
if svc := Default(); svc != nil {
return svc.Language()
@ -57,6 +72,9 @@ func CurrentLanguage() string {
}
// AvailableLanguages returns the loaded language tags on the default service.
//
// Example:
// langs := i18n.AvailableLanguages()
func AvailableLanguages() []string {
if svc := Default(); svc != nil {
langs := svc.AvailableLanguages()
@ -69,6 +87,9 @@ func AvailableLanguages() []string {
}
// SetMode sets the translation mode for the default service.
//
// Example:
// i18n.SetMode(i18n.ModeCollect)
func SetMode(m Mode) {
if svc := Default(); svc != nil {
svc.SetMode(m)
@ -76,6 +97,9 @@ func SetMode(m Mode) {
}
// SetFallback sets the fallback language for the default service.
//
// Example:
// i18n.SetFallback("en")
func SetFallback(lang string) {
if svc := Default(); svc != nil {
svc.SetFallback(lang)
@ -83,6 +107,9 @@ func SetFallback(lang string) {
}
// CurrentMode returns the current translation mode.
//
// Example:
// mode := i18n.CurrentMode()
func CurrentMode() Mode {
if svc := Default(); svc != nil {
return svc.Mode()
@ -91,6 +118,9 @@ func CurrentMode() Mode {
}
// CurrentFallback returns the current fallback language.
//
// Example:
// fallback := i18n.CurrentFallback()
func CurrentFallback() string {
if svc := Default(); svc != nil {
return svc.Fallback()
@ -99,6 +129,9 @@ func CurrentFallback() string {
}
// CurrentFormality returns the current default formality.
//
// Example:
// formality := i18n.CurrentFormality()
func CurrentFormality() Formality {
if svc := Default(); svc != nil {
return svc.Formality()
@ -107,6 +140,9 @@ func CurrentFormality() Formality {
}
// CurrentDebug reports whether debug mode is enabled on the default service.
//
// Example:
// debug := i18n.CurrentDebug()
func CurrentDebug() bool {
if svc := Default(); svc != nil {
return svc.Debug()
@ -130,6 +166,9 @@ func N(format string, value any, args ...any) string {
// Prompt translates a prompt key from the prompt namespace.
//
// Example:
// i18n.Prompt("confirm")
//
// Prompt("yes") // "y"
// Prompt("confirm") // "Are you sure?"
func Prompt(key string) string {
@ -142,6 +181,9 @@ func Prompt(key string) string {
// Lang translates a language label from the lang namespace.
//
// Example:
// i18n.Lang("de")
//
// Lang("de") // "German"
func Lang(key string) string {
key = normalizeLookupKey(key)
@ -166,6 +208,9 @@ func normalizeLookupKey(key string) string {
}
// AddHandler appends one or more handlers to the default service's handler chain.
//
// Example:
// i18n.AddHandler(MyHandler{})
func AddHandler(handlers ...KeyHandler) {
if svc := Default(); svc != nil {
svc.AddHandler(handlers...)
@ -173,6 +218,9 @@ func AddHandler(handlers ...KeyHandler) {
}
// SetHandlers replaces the default service's handler chain.
//
// Example:
// i18n.SetHandlers(i18n.LabelHandler{}, i18n.ProgressHandler{})
func SetHandlers(handlers ...KeyHandler) {
if svc := Default(); svc != nil {
svc.SetHandlers(handlers...)
@ -181,6 +229,9 @@ func SetHandlers(handlers ...KeyHandler) {
// LoadFS loads additional translations from an fs.FS into the default service.
//
// Example:
// i18n.LoadFS(os.DirFS("."), "locales")
//
// Call this from init() in packages that ship their own locale files:
//
// //go:embed locales/*.json
@ -196,6 +247,9 @@ func LoadFS(fsys fs.FS, dir string) {
}
// PrependHandler inserts one or more handlers at the start of the default service's handler chain.
//
// Example:
// i18n.PrependHandler(MyHandler{})
func PrependHandler(handlers ...KeyHandler) {
if svc := Default(); svc != nil {
svc.PrependHandler(handlers...)
@ -203,6 +257,9 @@ func PrependHandler(handlers ...KeyHandler) {
}
// CurrentHandlers returns a copy of the default service's handler chain.
//
// Example:
// handlers := i18n.CurrentHandlers()
func CurrentHandlers() []KeyHandler {
if svc := Default(); svc != nil {
return svc.Handlers()
@ -211,6 +268,9 @@ func CurrentHandlers() []KeyHandler {
}
// ClearHandlers removes all handlers from the default service.
//
// Example:
// i18n.ClearHandlers()
func ClearHandlers() {
if svc := Default(); svc != nil {
svc.ClearHandlers()

View file

@ -68,6 +68,9 @@ func IsRTLLanguage(lang string) bool {
}
// SetFormality sets the default formality level on the default service.
//
// Example:
// i18n.SetFormality(i18n.FormalityFormal)
func SetFormality(f Formality) {
if svc := Default(); svc != nil {
svc.SetFormality(f)
@ -75,6 +78,9 @@ func SetFormality(f Formality) {
}
// SetLocation sets the default location context on the default service.
//
// Example:
// i18n.SetLocation("workspace")
func SetLocation(location string) {
if svc := Default(); svc != nil {
svc.SetLocation(location)
@ -82,6 +88,9 @@ func SetLocation(location string) {
}
// CurrentLocation returns the current default location context.
//
// Example:
// location := i18n.CurrentLocation()
func CurrentLocation() string {
if svc := Default(); svc != nil {
return svc.Location()
@ -90,6 +99,9 @@ func CurrentLocation() string {
}
// Direction returns the text direction for the current language.
//
// Example:
// dir := i18n.Direction()
func Direction() TextDirection {
if svc := Default(); svc != nil {
return svc.Direction()
@ -98,14 +110,23 @@ func Direction() TextDirection {
}
// CurrentDirection returns the current default text direction.
//
// Example:
// dir := i18n.CurrentDirection()
func CurrentDirection() TextDirection {
return Direction()
}
// IsRTL returns true if the current language uses right-to-left text.
//
// Example:
// rtl := i18n.IsRTL()
func IsRTL() bool { return Direction() == DirRTL }
// CurrentPluralCategory returns the plural category for the current default language.
//
// Example:
// cat := i18n.CurrentPluralCategory(2)
func CurrentPluralCategory(n int) PluralCategory {
if svc := Default(); svc != nil {
return svc.PluralCategory(n)

View file

@ -103,12 +103,18 @@ var _ Translator = (*Service)(nil)
var _ core.Translator = (*Service)(nil)
// New creates a new i18n service with embedded locales.
//
// Example:
// svc, err := i18n.New(i18n.WithLanguage("en"))
func New(opts ...Option) (*Service, error) {
return NewWithLoader(NewFSLoader(localeFS, "locales"), opts...)
}
// NewService creates a new i18n service with embedded locales.
//
// Example:
// svc, err := i18n.NewService(i18n.WithFallback("en"))
//
// This is a named alias for New that keeps the constructor intent explicit
// for callers that prefer service-oriented naming.
func NewService(opts ...Option) (*Service, error) {
@ -116,16 +122,25 @@ func NewService(opts ...Option) (*Service, error) {
}
// NewWithFS creates a new i18n service loading locales from the given filesystem.
//
// Example:
// svc, err := i18n.NewWithFS(os.DirFS("."), "locales")
func NewWithFS(fsys fs.FS, dir string, opts ...Option) (*Service, error) {
return NewWithLoader(NewFSLoader(fsys, dir), opts...)
}
// NewServiceWithFS creates a new i18n service loading locales from the given filesystem.
//
// Example:
// svc, err := i18n.NewServiceWithFS(os.DirFS("."), "locales")
func NewServiceWithFS(fsys fs.FS, dir string, opts ...Option) (*Service, error) {
return NewWithFS(fsys, dir, opts...)
}
// NewWithLoader creates a new i18n service with a custom loader.
//
// Example:
// svc, err := i18n.NewWithLoader(loader)
func NewWithLoader(loader Loader, opts ...Option) (*Service, error) {
if loader == nil {
return nil, log.E("NewWithLoader", "nil loader", nil)
@ -199,11 +214,17 @@ func NewWithLoader(loader Loader, opts ...Option) (*Service, error) {
}
// NewServiceWithLoader creates a new i18n service with a custom loader.
//
// Example:
// svc, err := i18n.NewServiceWithLoader(loader)
func NewServiceWithLoader(loader Loader, opts ...Option) (*Service, error) {
return NewWithLoader(loader, opts...)
}
// Init initialises the default global service if none has been set via SetDefault.
//
// Example:
// if err := i18n.Init(); err != nil { return err }
func Init() error {
if defaultService.Load() != nil {
return nil
@ -232,6 +253,9 @@ func Init() error {
}
// Default returns the global i18n service, initialising if needed.
//
// Example:
// svc := i18n.Default()
// Returns nil if initialisation fails (error is logged).
func Default() *Service {
if svc := defaultService.Load(); svc != nil {
@ -244,6 +268,9 @@ func Default() *Service {
}
// SetDefault sets the global i18n service.
//
// Example:
// i18n.SetDefault(svc)
// Passing nil clears the default service.
func SetDefault(s *Service) {
defaultService.Store(s)
@ -259,6 +286,9 @@ func SetDefault(s *Service) {
}
// AddLoader loads translations from a Loader into the default service.
//
// Example:
// i18n.AddLoader(loader)
// Call this from init() in packages that ship their own locale files:
//
// //go:embed *.json
@ -1008,6 +1038,9 @@ func translateOK(messageID, value string) bool {
}
// LoadFS loads additional locale files from a filesystem.
//
// Example:
// _ = svc.LoadFS(os.DirFS("."), "locales")
// Deprecated: Use AddLoader(NewFSLoader(fsys, dir)) instead for proper grammar handling.
func (s *Service) LoadFS(fsys fs.FS, dir string) error {
loader := NewFSLoader(fsys, dir)