Add locale parsing

This commit is contained in:
Sasha Koshka 2024-04-26 18:51:01 -04:00
parent bd7dbb9228
commit 25edf46db3
2 changed files with 174 additions and 0 deletions

68
locale/locale.go Normal file
View File

@ -0,0 +1,68 @@
// Package locale defines a Locale type that represents a POSIX locale value, as
// required by desktop-entry-spec.
package locale
import "fmt"
import "strings"
type localeError string
func (err localeError) Error () string { return string(err) }
const (
// ErrUnexpectedRune indicates an unexpected rune was encountered while
// parsing a locale string.
ErrUnexpectedRune = localeError("unexpected rune")
// ErrLangEmpty indicates that a lang value was not specified.
ErrLangEmpty = localeError("lang empty")
)
// Locale represents a POSIX locale value.
type Locale struct {
Lang string
Country string
Encoding string
Modifier string
}
// String returns the string representation of the Locale. Unspecified values
// are left out.
func (locale Locale) String () string {
str := locale.Lang
if locale.Country != "" {
str = fmt.Sprint(str, "_", locale.Country)
}
if locale.Encoding != "" {
str = fmt.Sprint(str, ".", locale.Encoding)
}
if locale.Modifier != "" {
str = fmt.Sprint(str, "@", locale.Modifier)
}
return str
}
// Parse parses a formatted locale string and returns the corresponding Locale.
func Parse (value string) (Locale, error) {
locale := Locale { }
value, locale.Modifier, _ = strings.Cut(value, "@")
value, locale.Encoding, _ = strings.Cut(value, ".")
value, locale.Country, _ = strings.Cut(value, "_")
locale.Lang = value
if hasIllegalRunes(locale.Lang) ||
hasIllegalRunes(locale.Country) ||
hasIllegalRunes(locale.Encoding) ||
hasIllegalRunes(locale.Modifier) {
return Locale { }, ErrUnexpectedRune
}
if locale.Lang == "" {
return Locale { }, ErrLangEmpty
}
return locale, nil
}
func hasIllegalRunes (value string) bool {
return strings.ContainsAny(value, "@._ ")
}

106
locale/locale_test.go Normal file
View File

@ -0,0 +1,106 @@
package locale
import "testing"
func TestString (test *testing.T) {
testCase := func (correct string, locale Locale) {
got := locale.String()
if got != correct {
test.Fatalf("expected:\n\t%s\ngot:\n\t%s\n", correct, got)
}
}
testCase("lang_COUNTRY.ENCODING@MODIFIER", Locale {
Lang: "lang",
Country: "COUNTRY",
Encoding: "ENCODING",
Modifier: "MODIFIER",
})
testCase("lang.ENCODING@MODIFIER", Locale {
Lang: "lang",
Encoding: "ENCODING",
Modifier: "MODIFIER",
})
testCase("lang_COUNTRY@MODIFIER", Locale {
Lang: "lang",
Country: "COUNTRY",
Modifier: "MODIFIER",
})
testCase("lang_COUNTRY.ENCODING", Locale {
Lang: "lang",
Country: "COUNTRY",
Encoding: "ENCODING",
})
testCase("lang_COUNTRY", Locale {
Lang: "lang",
Country: "COUNTRY",
})
testCase("lang.ENCODING", Locale {
Lang: "lang",
Encoding: "ENCODING",
})
testCase("lang@MODIFIER", Locale {
Lang: "lang",
Modifier: "MODIFIER",
})
}
func TestParse (test *testing.T) {
testCase := func (input string, correct Locale) {
got, err := Parse(input)
if err != nil {
test.Fatal(err)
}
if got != correct {
test.Fatalf("expected:\n\t%v\ngot:\n\t%v\n", correct, got)
}
}
testCase("lang_COUNTRY.ENCODING@MODIFIER", Locale {
Lang: "lang",
Country: "COUNTRY",
Encoding: "ENCODING",
Modifier: "MODIFIER",
})
testCase("lang.ENCODING@MODIFIER", Locale {
Lang: "lang",
Encoding: "ENCODING",
Modifier: "MODIFIER",
})
testCase("lang_COUNTRY@MODIFIER", Locale {
Lang: "lang",
Country: "COUNTRY",
Modifier: "MODIFIER",
})
testCase("lang_COUNTRY.ENCODING", Locale {
Lang: "lang",
Country: "COUNTRY",
Encoding: "ENCODING",
})
testCase("lang_COUNTRY", Locale {
Lang: "lang",
Country: "COUNTRY",
})
testCase("lang.ENCODING", Locale {
Lang: "lang",
Encoding: "ENCODING",
})
testCase("lang@MODIFIER", Locale {
Lang: "lang",
Modifier: "MODIFIER",
})
}
func TestParseErr (test *testing.T) {
testCase := func (input string, correct error) {
_, err := Parse(input)
if err != correct {
test.Fatalf("expected:\n\t%v\ngot:\n\t%v\n", correct, err)
}
}
testCase("lang.ENCODING.MODIFIER", ErrUnexpectedRune)
testCase("lang@COUNTRY.ENCODING", ErrUnexpectedRune)
testCase("lang.@COUNTRY.ENCODING", ErrUnexpectedRune)
testCase("_COUNTRY.ENCODING@MODIFIER", ErrLangEmpty)
}