Add locale parsing
This commit is contained in:
parent
bd7dbb9228
commit
25edf46db3
68
locale/locale.go
Normal file
68
locale/locale.go
Normal 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
106
locale/locale_test.go
Normal 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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user