A lightweight plural rule system and generator
go get -u github.com/cjtoolkit/plural
go install github.com/cjtoolkit/plural/plural-gen
plural.toml
[[locale]]
code = "en"
functionName = "EnglishPlural"
[[locale]]
code = "fr"
functionName = "FrenchPlural"
[[locale]]
code = "cy"
functionName = "WelshPlural"
generate.go
//go:generate plural-gen example plural.toml
package example
Than run go generate generate.go
plural.go
// Code generated by plural-gen. DO NOT EDIT.
// Source: locale/plural.toml
package example
import (
"github.com/cjtoolkit/plural"
)
// en
func EnglishPlural() plural.PluralGroup {
return plural.PluralGroup{
Cardinal: plural.NewPluralSpec([]plural.Plural{plural.One, plural.Other}, func(ops *plural.Operands) plural.Plural {
// i = 1 and v = 0
if plural.IntEqualsAny(ops.I, 1) && plural.IntEqualsAny(ops.V, 0) {
return plural.One
}
return plural.Other
}),
Ordinal: plural.NewPluralSpec([]plural.Plural{plural.One, plural.Two, plural.Few, plural.Other}, func(ops *plural.Operands) plural.Plural {
// n % 10 = 1 and n % 100 != 11
if ops.NmodEqualsAny(10, 1) && !ops.NmodEqualsAny(100, 11) {
return plural.One
}
// n % 10 = 2 and n % 100 != 12
if ops.NmodEqualsAny(10, 2) && !ops.NmodEqualsAny(100, 12) {
return plural.Two
}
// n % 10 = 3 and n % 100 != 13
if ops.NmodEqualsAny(10, 3) && !ops.NmodEqualsAny(100, 13) {
return plural.Few
}
return plural.Other
}),
}
}
// fr
func FrenchPlural() plural.PluralGroup {
return plural.PluralGroup{
Cardinal: plural.NewPluralSpec([]plural.Plural{plural.One, plural.Other}, func(ops *plural.Operands) plural.Plural {
// i = 0,1
if plural.IntEqualsAny(ops.I, 0, 1) {
return plural.One
}
return plural.Other
}),
Ordinal: plural.NewPluralSpec([]plural.Plural{plural.One, plural.Other}, func(ops *plural.Operands) plural.Plural {
// n = 1
if ops.NequalsAny(1) {
return plural.One
}
return plural.Other
}),
}
}
// cy
func WelshPlural() plural.PluralGroup {
return plural.PluralGroup{
Cardinal: plural.NewPluralSpec([]plural.Plural{plural.Zero, plural.One, plural.Two, plural.Few, plural.Many, plural.Other}, func(ops *plural.Operands) plural.Plural {
// n = 0
if ops.NequalsAny(0) {
return plural.Zero
}
// n = 1
if ops.NequalsAny(1) {
return plural.One
}
// n = 2
if ops.NequalsAny(2) {
return plural.Two
}
// n = 3
if ops.NequalsAny(3) {
return plural.Few
}
// n = 6
if ops.NequalsAny(6) {
return plural.Many
}
return plural.Other
}),
Ordinal: plural.NewPluralSpec([]plural.Plural{plural.Zero, plural.One, plural.Two, plural.Few, plural.Many, plural.Other}, func(ops *plural.Operands) plural.Plural {
// n = 0,7,8,9
if ops.NequalsAny(0, 7, 8, 9) {
return plural.Zero
}
// n = 1
if ops.NequalsAny(1) {
return plural.One
}
// n = 2
if ops.NequalsAny(2) {
return plural.Two
}
// n = 3,4
if ops.NequalsAny(3, 4) {
return plural.Few
}
// n = 5,6
if ops.NequalsAny(5, 6) {
return plural.Many
}
return plural.Other
}),
}
}
plural_test.go
// Code generated by plural-gen. DO NOT EDIT.
// Source: locale/plural.toml
package example
import (
"testing"
"github.com/cjtoolkit/plural"
"github.com/cjtoolkit/plural/pluralTestUtil"
)
// Test en
func TestEnglishPlural(t *testing.T) {
group := EnglishPlural()
t.Run("Cardinal", func(t *testing.T) {
var tests []pluralTestUtil.PluralTest
tests = pluralTestUtil.AppendIntegerTests(tests, plural.One, []string{"1"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
pluralTestUtil.Run(t, "EnglishPlural (Cardinal)", group.Cardinal, tests)
})
t.Run("Ordinal", func(t *testing.T) {
var tests []pluralTestUtil.PluralTest
tests = pluralTestUtil.AppendIntegerTests(tests, plural.One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Two, []string{"2", "22", "32", "42", "52", "62", "72", "82", "102", "1002"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Few, []string{"3", "23", "33", "43", "53", "63", "73", "83", "103", "1003"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Other, []string{"0", "4~18", "100", "1000", "10000", "100000", "1000000"})
pluralTestUtil.Run(t, "EnglishPlural (Ordinal)", group.Ordinal, tests)
})
}
// Test fr
func TestFrenchPlural(t *testing.T) {
group := FrenchPlural()
t.Run("Cardinal", func(t *testing.T) {
var tests []pluralTestUtil.PluralTest
tests = pluralTestUtil.AppendIntegerTests(tests, plural.One, []string{"0", "1"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.One, []string{"0.0~1.5"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Other, []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
pluralTestUtil.Run(t, "FrenchPlural (Cardinal)", group.Cardinal, tests)
})
t.Run("Ordinal", func(t *testing.T) {
var tests []pluralTestUtil.PluralTest
tests = pluralTestUtil.AppendIntegerTests(tests, plural.One, []string{"1"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
pluralTestUtil.Run(t, "FrenchPlural (Ordinal)", group.Ordinal, tests)
})
}
// Test cy
func TestWelshPlural(t *testing.T) {
group := WelshPlural()
t.Run("Cardinal", func(t *testing.T) {
var tests []pluralTestUtil.PluralTest
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Zero, []string{"0"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Zero, []string{"0.0", "0.00", "0.000", "0.0000"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.One, []string{"1"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.One, []string{"1.0", "1.00", "1.000", "1.0000"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Two, []string{"2"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Two, []string{"2.0", "2.00", "2.000", "2.0000"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Few, []string{"3"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Few, []string{"3.0", "3.00", "3.000", "3.0000"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Many, []string{"6"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Many, []string{"6.0", "6.00", "6.000", "6.0000"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Other, []string{"4", "5", "7~20", "100", "1000", "10000", "100000", "1000000"})
tests = pluralTestUtil.AppendDecimalTests(tests, plural.Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
pluralTestUtil.Run(t, "WelshPlural (Cardinal)", group.Cardinal, tests)
})
t.Run("Ordinal", func(t *testing.T) {
var tests []pluralTestUtil.PluralTest
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Zero, []string{"0", "7~9"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.One, []string{"1"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Two, []string{"2"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Few, []string{"3", "4"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Many, []string{"5", "6"})
tests = pluralTestUtil.AppendIntegerTests(tests, plural.Other, []string{"10~25", "100", "1000", "10000", "100000", "1000000"})
pluralTestUtil.Run(t, "WelshPlural (Ordinal)", group.Ordinal, tests)
})
}
It's based on some of work of Nick Snyder's go-i18n