[agent/codex:gpt-5.4-mini] Read ~/spec/code/core/go/i18n/RFC.md fully. Find ONE feature... #13
6 changed files with 82 additions and 6 deletions
|
|
@ -35,6 +35,9 @@ func MergeGrammarData(lang string, data *GrammarData) {
|
|||
maps.Copy(existing.Verbs, data.Verbs)
|
||||
maps.Copy(existing.Nouns, data.Nouns)
|
||||
maps.Copy(existing.Words, data.Words)
|
||||
if data.Number != (NumberFormat{}) {
|
||||
existing.Number = data.Number
|
||||
}
|
||||
}
|
||||
|
||||
// IrregularVerbs returns a copy of the irregular verb forms map.
|
||||
|
|
|
|||
14
loader.go
14
loader.go
|
|
@ -222,6 +222,20 @@ func flattenWithGrammar(prefix string, data map[string]any, out map[string]Messa
|
|||
continue
|
||||
}
|
||||
|
||||
// Number formatting rules
|
||||
if grammar != nil && fullKey == "gram.number" {
|
||||
if thousands, ok := v["thousands"].(string); ok {
|
||||
grammar.Number.ThousandsSep = thousands
|
||||
}
|
||||
if decimal, ok := v["decimal"].(string); ok {
|
||||
grammar.Number.DecimalSep = decimal
|
||||
}
|
||||
if percent, ok := v["percent"].(string); ok {
|
||||
grammar.Number.PercentFmt = percent
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// CLDR plural object
|
||||
if isPluralObject(v) {
|
||||
msg := Message{}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,17 @@ func TestFSLoaderLoad(t *testing.T) {
|
|||
t.Errorf("punct.progress = %q, want '...'", grammar.Punct.ProgressSuffix)
|
||||
}
|
||||
|
||||
// Number formatting from gram.number
|
||||
if grammar.Number.ThousandsSep != "," {
|
||||
t.Errorf("number.thousands = %q, want ','", grammar.Number.ThousandsSep)
|
||||
}
|
||||
if grammar.Number.DecimalSep != "." {
|
||||
t.Errorf("number.decimal = %q, want '.'", grammar.Number.DecimalSep)
|
||||
}
|
||||
if grammar.Number.PercentFmt != "%s%%" {
|
||||
t.Errorf("number.percent = %q, want '%%s%%%%'", grammar.Number.PercentFmt)
|
||||
}
|
||||
|
||||
// Words from gram.word.*
|
||||
if len(grammar.Words) == 0 {
|
||||
t.Error("grammar has 0 words")
|
||||
|
|
@ -135,6 +146,11 @@ func TestFlattenWithGrammar(t *testing.T) {
|
|||
"label": ":",
|
||||
"progress": "...",
|
||||
},
|
||||
"number": map[string]any{
|
||||
"thousands": ",",
|
||||
"decimal": ".",
|
||||
"percent": "%s%%",
|
||||
},
|
||||
"article": map[string]any{
|
||||
"indefinite": map[string]any{
|
||||
"default": "a",
|
||||
|
|
@ -179,6 +195,11 @@ func TestFlattenWithGrammar(t *testing.T) {
|
|||
t.Errorf("punct.label = %q, want ':'", grammar.Punct.LabelSuffix)
|
||||
}
|
||||
|
||||
// Number formatting extracted
|
||||
if grammar.Number.ThousandsSep != "," {
|
||||
t.Errorf("number.thousands = %q, want ','", grammar.Number.ThousandsSep)
|
||||
}
|
||||
|
||||
// Articles extracted
|
||||
if grammar.Articles.IndefiniteDefault != "a" {
|
||||
t.Errorf("article.indefinite.default = %q, want 'a'", grammar.Articles.IndefiniteDefault)
|
||||
|
|
@ -188,6 +209,9 @@ func TestFlattenWithGrammar(t *testing.T) {
|
|||
if msg, ok := messages["prompt.yes"]; !ok || msg.Text != "y" {
|
||||
t.Errorf("prompt.yes not flattened correctly, got %+v", messages["prompt.yes"])
|
||||
}
|
||||
if _, ok := messages["gram.number.thousands"]; ok {
|
||||
t.Error("gram.number.thousands should not be flattened into messages")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFlattenPluralObject(t *testing.T) {
|
||||
|
|
|
|||
20
numbers.go
20
numbers.go
|
|
@ -9,15 +9,27 @@ import (
|
|||
|
||||
func getNumberFormat() NumberFormat {
|
||||
lang := currentLangForGrammar()
|
||||
if idx := indexAny(lang, "-_"); idx > 0 {
|
||||
lang = lang[:idx]
|
||||
}
|
||||
if fmt, ok := numberFormats[lang]; ok {
|
||||
if fmt, ok := getLocaleNumberFormat(lang); ok {
|
||||
return fmt
|
||||
}
|
||||
if idx := indexAny(lang, "-_"); idx > 0 {
|
||||
if fmt, ok := getLocaleNumberFormat(lang[:idx]); ok {
|
||||
return fmt
|
||||
}
|
||||
}
|
||||
return numberFormats["en"]
|
||||
}
|
||||
|
||||
func getLocaleNumberFormat(lang string) (NumberFormat, bool) {
|
||||
if data := GetGrammarData(lang); data != nil && data.Number != (NumberFormat{}) {
|
||||
return data.Number, true
|
||||
}
|
||||
if fmt, ok := numberFormats[lang]; ok {
|
||||
return fmt, true
|
||||
}
|
||||
return NumberFormat{}, false
|
||||
}
|
||||
|
||||
// FormatNumber formats an integer with locale-specific thousands separators.
|
||||
func FormatNumber(n int64) string {
|
||||
return formatIntWithSep(n, getNumberFormat().ThousandsSep)
|
||||
|
|
|
|||
|
|
@ -143,3 +143,25 @@ func TestFormatOrdinal(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNumberFromLocale(t *testing.T) {
|
||||
svc, err := New()
|
||||
if err != nil {
|
||||
t.Fatalf("New() failed: %v", err)
|
||||
}
|
||||
SetDefault(svc)
|
||||
|
||||
if err := SetLanguage("fr"); err != nil {
|
||||
t.Fatalf("SetLanguage(fr) failed: %v", err)
|
||||
}
|
||||
|
||||
if got := FormatNumber(1234567); got != "1 234 567" {
|
||||
t.Errorf("FormatNumber(fr) = %q, want %q", got, "1 234 567")
|
||||
}
|
||||
if got := FormatDecimal(1234.56); got != "1 234,56" {
|
||||
t.Errorf("FormatDecimal(fr) = %q, want %q", got, "1 234,56")
|
||||
}
|
||||
if got := FormatPercent(0.85); got != "85 %" {
|
||||
t.Errorf("FormatPercent(fr) = %q, want %q", got, "85 %")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
5
types.go
5
types.go
|
|
@ -52,7 +52,7 @@ type TextDirection int
|
|||
|
||||
const (
|
||||
DirLTR TextDirection = iota // Left-to-right
|
||||
DirRTL // Right-to-left
|
||||
DirRTL // Right-to-left
|
||||
)
|
||||
|
||||
// PluralCategory represents CLDR plural categories.
|
||||
|
|
@ -193,6 +193,7 @@ type GrammarData struct {
|
|||
Words map[string]string // base word translations
|
||||
Punct PunctuationRules // language-specific punctuation
|
||||
Signals SignalData // disambiguation signal word lists
|
||||
Number NumberFormat // locale-specific number formatting
|
||||
}
|
||||
|
||||
// VerbForms holds verb conjugations.
|
||||
|
|
@ -385,7 +386,7 @@ var irregularVerbs = map[string]VerbForms{
|
|||
"rebel": {Past: "rebelled", Gerund: "rebelling"}, "excel": {Past: "excelled", Gerund: "excelling"},
|
||||
"cancel": {Past: "cancelled", Gerund: "cancelling"}, "travel": {Past: "travelled", Gerund: "travelling"},
|
||||
"label": {Past: "labelled", Gerund: "labelling"}, "model": {Past: "modelled", Gerund: "modelling"},
|
||||
"level": {Past: "levelled", Gerund: "levelling"},
|
||||
"level": {Past: "levelled", Gerund: "levelling"},
|
||||
"format": {Past: "formatted", Gerund: "formatting"},
|
||||
"analyse": {Past: "analysed", Gerund: "analysing"},
|
||||
"organise": {Past: "organised", Gerund: "organising"},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue