locale.go

 1package i18n
 2
 3import (
 4	"strings"
 5
 6	"golang.org/x/text/language"
 7)
 8
 9// Locale represents a language/region configuration.
10type Locale struct {
11	// Tag is the BCP 47 language tag
12	Tag language.Tag
13
14	// Code is the short language code (e.g., "en", "es", "de")
15	Code string
16
17	// Name is the English name of the language
18	Name string
19
20	// NativeName is the language's name in its own language
21	NativeName string
22
23	// Direction is the text direction ("ltr" or "rtl")
24	Direction string
25
26	// PluralFunc is the plural rule function for this language
27	PluralFunc PluralFunc
28}
29
30// ParseLocale parses a language code and returns a Locale.
31// Supports formats like "en", "en-US", "en_US".
32func ParseLocale(code string) (*Locale, error) {
33	if code == "" {
34		return nil, ErrInvalidLocale
35	}
36
37	// Normalize separators
38	code = strings.ReplaceAll(code, "_", "-")
39
40	// Parse language tag
41	tag, err := language.Parse(code)
42	if err != nil {
43		return nil, ErrInvalidLocale
44	}
45
46	// Extract base language
47	base, _ := tag.Base()
48	langCode := base.String()
49
50	// Look up in registry
51	if locale, ok := GetLanguage(langCode); ok {
52		return locale, nil
53	}
54
55	// Return a basic locale if not registered
56	return &Locale{
57		Tag:        tag,
58		Code:       langCode,
59		Name:       langCode,
60		NativeName: langCode,
61		Direction:  "ltr",
62		PluralFunc: DefaultPlural,
63	}, nil
64}
65
66// String returns the string representation of the locale.
67func (l *Locale) String() string {
68	return l.Code
69}
70
71// IsRTL returns true if the locale uses right-to-left text direction.
72func (l *Locale) IsRTL() bool {
73	return l.Direction == "rtl"
74}