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}