chore(i18n): align public API with AX
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
cc1dd6b898
commit
f487e427e9
7 changed files with 76 additions and 8 deletions
|
|
@ -3,7 +3,6 @@ package i18n
|
|||
import (
|
||||
"maps"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
"unicode"
|
||||
|
||||
|
|
@ -702,7 +701,7 @@ func usesVowelSoundArticle(word string) bool {
|
|||
|
||||
func looksLikeFrenchPlural(word string) bool {
|
||||
trimmed := core.Trim(word)
|
||||
if trimmed == "" || strings.ContainsAny(trimmed, " \t") || isInitialism(trimmed) {
|
||||
if trimmed == "" || core.Contains(trimmed, " ") || core.Contains(trimmed, "\t") || isInitialism(trimmed) {
|
||||
return false
|
||||
}
|
||||
lower := core.Lower(trimmed)
|
||||
|
|
@ -1014,7 +1013,7 @@ func prefixWithArticle(article, word string) string {
|
|||
if article == "" || word == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.HasSuffix(article, "'") {
|
||||
if core.HasSuffix(article, "'") {
|
||||
return article + word
|
||||
}
|
||||
return article + " " + word
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ func (h NumericHandler) Handle(key string, args []any, next func() string) strin
|
|||
}
|
||||
|
||||
// DefaultHandlers returns the built-in i18n.* namespace handlers.
|
||||
//
|
||||
// handlers := i18n.DefaultHandlers()
|
||||
func DefaultHandlers() []KeyHandler {
|
||||
return []KeyHandler{
|
||||
LabelHandler{},
|
||||
|
|
|
|||
4
hooks.go
4
hooks.go
|
|
@ -29,6 +29,8 @@ type localeProviderRegistration struct {
|
|||
}
|
||||
|
||||
// LocaleProvider supplies one or more locale filesystems to the default service.
|
||||
//
|
||||
// i18n.RegisterLocaleProvider(myProvider)
|
||||
type LocaleProvider interface {
|
||||
LocaleSources() []FSSource
|
||||
}
|
||||
|
|
@ -72,6 +74,8 @@ func RegisterLocales(fsys fs.FS, dir string) {
|
|||
// RegisterLocaleProvider registers a provider that can contribute locale files.
|
||||
// This is useful for packages that need to expose multiple locale sources as a
|
||||
// single unit.
|
||||
//
|
||||
// i18n.RegisterLocaleProvider(myProvider)
|
||||
func RegisterLocaleProvider(provider LocaleProvider) {
|
||||
if provider == nil {
|
||||
return
|
||||
|
|
|
|||
4
i18n.go
4
i18n.go
|
|
@ -175,6 +175,8 @@ func CurrentDebug() bool {
|
|||
}
|
||||
|
||||
// State returns a copy-safe snapshot of the default service configuration.
|
||||
//
|
||||
// state := i18n.State()
|
||||
func State() ServiceState {
|
||||
return defaultServiceValue(defaultServiceStateSnapshot(), func(svc *Service) ServiceState {
|
||||
return svc.State()
|
||||
|
|
@ -182,6 +184,8 @@ func State() ServiceState {
|
|||
}
|
||||
|
||||
// CurrentState is a more explicit alias for State.
|
||||
//
|
||||
// state := i18n.CurrentState()
|
||||
func CurrentState() ServiceState {
|
||||
return State()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ import (
|
|||
)
|
||||
|
||||
// Service provides grammar-aware internationalisation.
|
||||
//
|
||||
// svc, err := i18n.New()
|
||||
// i18n.SetDefault(svc)
|
||||
type Service struct {
|
||||
loader Loader
|
||||
messages map[string]map[string]Message // lang -> key -> message
|
||||
|
|
@ -36,6 +39,8 @@ type Service struct {
|
|||
}
|
||||
|
||||
// Option configures a Service during construction.
|
||||
//
|
||||
// svc, err := i18n.New(i18n.WithLanguage("en"))
|
||||
type Option func(*Service)
|
||||
|
||||
// WithFallback sets the fallback language for missing translations.
|
||||
|
|
|
|||
18
state.go
18
state.go
|
|
@ -1,8 +1,6 @@
|
|||
package i18n
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"dappco.re/go/core"
|
||||
)
|
||||
|
||||
|
|
@ -55,6 +53,8 @@ func defaultServiceStateSnapshot() ServiceState {
|
|||
|
||||
// ServiceState captures the current configuration of a service in one
|
||||
// copy-safe snapshot.
|
||||
//
|
||||
// state := i18n.CurrentState()
|
||||
type ServiceState struct {
|
||||
Language string
|
||||
RequestedLanguage string
|
||||
|
|
@ -71,6 +71,9 @@ type ServiceState struct {
|
|||
}
|
||||
|
||||
// HandlerTypeNames returns the short type names of the snapshot's handlers.
|
||||
//
|
||||
// names := i18n.CurrentState().HandlerTypeNames()
|
||||
//
|
||||
// The returned slice is a fresh copy, so callers can inspect or mutate it
|
||||
// without affecting the snapshot.
|
||||
func (s ServiceState) HandlerTypeNames() []string {
|
||||
|
|
@ -89,6 +92,8 @@ func (s ServiceState) HandlerTypeNames() []string {
|
|||
}
|
||||
|
||||
// String returns a concise, stable summary of the service snapshot.
|
||||
//
|
||||
// fmt.Println(i18n.CurrentState().String())
|
||||
func (s ServiceState) String() string {
|
||||
langs := "[]"
|
||||
if len(s.AvailableLanguages) > 0 {
|
||||
|
|
@ -119,10 +124,11 @@ func (s ServiceState) String() string {
|
|||
|
||||
func shortHandlerTypeName(handler KeyHandler) string {
|
||||
name := core.Sprintf("%T", handler)
|
||||
if idx := strings.LastIndex(name, "."); idx >= 0 {
|
||||
name = name[idx+1:]
|
||||
parts := core.Split(name, ".")
|
||||
if len(parts) > 0 {
|
||||
name = parts[len(parts)-1]
|
||||
}
|
||||
return strings.TrimPrefix(name, "*")
|
||||
return core.TrimPrefix(name, "*")
|
||||
}
|
||||
|
||||
func (s *Service) State() ServiceState {
|
||||
|
|
@ -166,6 +172,8 @@ func (s *Service) String() string {
|
|||
}
|
||||
|
||||
// CurrentState is a more explicit alias for State.
|
||||
//
|
||||
// state := i18n.CurrentState()
|
||||
func (s *Service) CurrentState() ServiceState {
|
||||
return s.State()
|
||||
}
|
||||
|
|
|
|||
46
types.go
46
types.go
|
|
@ -17,6 +17,8 @@ import "sync"
|
|||
// --- Core Types ---
|
||||
|
||||
// Mode determines how the service handles missing translation keys.
|
||||
//
|
||||
// i18n.SetMode(i18n.ModeStrict)
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
|
|
@ -39,6 +41,8 @@ func (m Mode) String() string {
|
|||
}
|
||||
|
||||
// Formality represents the level of formality in translations.
|
||||
//
|
||||
// i18n.S("user", "Alex").Formal()
|
||||
type Formality int
|
||||
|
||||
const (
|
||||
|
|
@ -48,6 +52,8 @@ const (
|
|||
)
|
||||
|
||||
// TextDirection represents text directionality.
|
||||
//
|
||||
// if i18n.Direction() == i18n.DirRTL { /* ... */ }
|
||||
type TextDirection int
|
||||
|
||||
const (
|
||||
|
|
@ -56,6 +62,8 @@ const (
|
|||
)
|
||||
|
||||
// PluralCategory represents CLDR plural categories.
|
||||
//
|
||||
// cat := i18n.CurrentPluralCategory(2)
|
||||
type PluralCategory int
|
||||
|
||||
const (
|
||||
|
|
@ -68,6 +76,8 @@ const (
|
|||
)
|
||||
|
||||
// GrammaticalGender represents grammatical gender for nouns.
|
||||
//
|
||||
// i18n.S("user", "Alex").Gender("feminine")
|
||||
type GrammaticalGender int
|
||||
|
||||
const (
|
||||
|
|
@ -80,6 +90,8 @@ const (
|
|||
// --- Message Types ---
|
||||
|
||||
// Message represents a translation — either a simple string or plural forms.
|
||||
//
|
||||
// msg := i18n.Message{One: "{{.Count}} file", Other: "{{.Count}} files"}
|
||||
type Message struct {
|
||||
Text string // Simple string value (non-plural)
|
||||
Zero string // count == 0 (Arabic, Latvian, Welsh)
|
||||
|
|
@ -132,6 +144,8 @@ func (m Message) IsPlural() bool {
|
|||
// --- Subject Types ---
|
||||
|
||||
// Subject represents a typed subject with metadata for semantic translations.
|
||||
//
|
||||
// subj := i18n.S("file", "config.yaml").Count(3).In("workspace")
|
||||
type Subject struct {
|
||||
Noun string // The noun type (e.g., "file", "repo")
|
||||
Value any // The actual value (e.g., filename)
|
||||
|
|
@ -144,6 +158,8 @@ type Subject struct {
|
|||
// --- Intent Types ---
|
||||
|
||||
// IntentMeta defines the behaviour of an intent.
|
||||
//
|
||||
// intent := i18n.Intent{Meta: i18n.IntentMeta{Type: "action", Verb: "delete"}}
|
||||
type IntentMeta struct {
|
||||
Type string // "action", "question", "info"
|
||||
Verb string // Reference to verb key
|
||||
|
|
@ -153,6 +169,8 @@ type IntentMeta struct {
|
|||
}
|
||||
|
||||
// Composed holds all output forms for an intent after template resolution.
|
||||
//
|
||||
// composed := i18n.ComposeIntent(i18n.Intent{Question: "Delete {{.Subject}}?"}, i18n.S("file", "config.yaml"))
|
||||
type Composed struct {
|
||||
Question string // "Delete config.yaml?"
|
||||
Confirm string // "Really delete config.yaml?"
|
||||
|
|
@ -162,6 +180,8 @@ type Composed struct {
|
|||
}
|
||||
|
||||
// Intent defines a semantic intent with templates for all output forms.
|
||||
//
|
||||
// intent := i18n.Intent{Question: "Delete {{.Subject}}?"}
|
||||
type Intent struct {
|
||||
Meta IntentMeta
|
||||
Question string // Template for question form
|
||||
|
|
@ -186,6 +206,8 @@ type templateData struct {
|
|||
// --- Grammar Types ---
|
||||
|
||||
// GrammarData holds language-specific grammar forms loaded from JSON.
|
||||
//
|
||||
// i18n.SetGrammarData("en", &i18n.GrammarData{Articles: i18n.ArticleForms{IndefiniteDefault: "a"}})
|
||||
type GrammarData struct {
|
||||
Verbs map[string]VerbForms // verb -> forms
|
||||
Nouns map[string]NounForms // noun -> forms
|
||||
|
|
@ -197,12 +219,16 @@ type GrammarData struct {
|
|||
}
|
||||
|
||||
// VerbForms holds verb conjugations.
|
||||
//
|
||||
// forms := i18n.VerbForms{Past: "deleted", Gerund: "deleting"}
|
||||
type VerbForms struct {
|
||||
Past string // "deleted"
|
||||
Gerund string // "deleting"
|
||||
}
|
||||
|
||||
// NounForms holds plural and gender information for a noun.
|
||||
//
|
||||
// forms := i18n.NounForms{One: "file", Other: "files"}
|
||||
type NounForms struct {
|
||||
One string // Singular form
|
||||
Other string // Plural form
|
||||
|
|
@ -210,6 +236,8 @@ type NounForms struct {
|
|||
}
|
||||
|
||||
// ArticleForms holds article configuration for a language.
|
||||
//
|
||||
// articles := i18n.ArticleForms{IndefiniteDefault: "a", IndefiniteVowel: "an"}
|
||||
type ArticleForms struct {
|
||||
IndefiniteDefault string // "a"
|
||||
IndefiniteVowel string // "an"
|
||||
|
|
@ -218,12 +246,16 @@ type ArticleForms struct {
|
|||
}
|
||||
|
||||
// PunctuationRules holds language-specific punctuation patterns.
|
||||
//
|
||||
// rules := i18n.PunctuationRules{LabelSuffix: ":", ProgressSuffix: "..."}
|
||||
type PunctuationRules struct {
|
||||
LabelSuffix string // ":" (French uses " :")
|
||||
ProgressSuffix string // "..."
|
||||
}
|
||||
|
||||
// SignalData holds word lists used for disambiguation signals.
|
||||
//
|
||||
// signals := i18n.SignalData{VerbAuxiliaries: []string{"is", "was"}}
|
||||
type SignalData struct {
|
||||
NounDeterminers []string // Words that precede nouns: "the", "a", "this", "my", ...
|
||||
VerbAuxiliaries []string // Auxiliaries/modals before verbs: "is", "was", "will", ...
|
||||
|
|
@ -235,6 +267,8 @@ type SignalData struct {
|
|||
// --- Number Formatting ---
|
||||
|
||||
// NumberFormat defines locale-specific number formatting rules.
|
||||
//
|
||||
// fmt := i18n.NumberFormat{ThousandsSep: ",", DecimalSep: ".", PercentFmt: "%s%%"}
|
||||
type NumberFormat struct {
|
||||
ThousandsSep string // "," for en, "." for de
|
||||
DecimalSep string // "." for en, "," for de
|
||||
|
|
@ -244,12 +278,18 @@ type NumberFormat struct {
|
|||
// --- Function Types ---
|
||||
|
||||
// PluralRule determines the plural category for a count.
|
||||
//
|
||||
// rule := i18n.GetPluralRule("en")
|
||||
type PluralRule func(n int) PluralCategory
|
||||
|
||||
// MissingKeyHandler receives missing key events.
|
||||
//
|
||||
// i18n.OnMissingKey(func(m i18n.MissingKey) {})
|
||||
type MissingKeyHandler func(missing MissingKey)
|
||||
|
||||
// MissingKey is dispatched when a translation key is not found in ModeCollect.
|
||||
//
|
||||
// func handle(m i18n.MissingKey) { _ = m.Key }
|
||||
type MissingKey struct {
|
||||
Key string
|
||||
Args map[string]any
|
||||
|
|
@ -261,18 +301,24 @@ type MissingKey struct {
|
|||
|
||||
// KeyHandler processes translation keys before standard lookup.
|
||||
// Handlers form a chain; each can handle a key or delegate to the next.
|
||||
//
|
||||
// i18n.AddHandler(i18n.LabelHandler{})
|
||||
type KeyHandler interface {
|
||||
Match(key string) bool
|
||||
Handle(key string, args []any, next func() string) string
|
||||
}
|
||||
|
||||
// Loader provides translation data to the Service.
|
||||
//
|
||||
// svc, err := i18n.NewWithLoader(loader)
|
||||
type Loader interface {
|
||||
Load(lang string) (map[string]Message, *GrammarData, error)
|
||||
Languages() []string
|
||||
}
|
||||
|
||||
// Translator defines the interface for translation services.
|
||||
//
|
||||
// var t i18n.Translator = i18n.Default()
|
||||
type Translator interface {
|
||||
T(messageID string, args ...any) string
|
||||
SetLanguage(lang string) error
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue