Skip to content

cjtoolkit/plural

Repository files navigation

Build Status

Plural

A lightweight plural rule system and generator

Installation

go get -u github.com/cjtoolkit/plural
go install github.com/cjtoolkit/plural/plural-gen

Example

Input

plural.toml

[[locale]]
code = "en"
functionName = "EnglishPlural"

[[locale]]
code = "fr"
functionName = "FrenchPlural"

[[locale]]
code = "cy"
functionName = "WelshPlural"

Generate

generate.go

//go:generate plural-gen example plural.toml

package example

Than run go generate generate.go

Output

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)
	})
}

Note

It's based on some of work of Nick Snyder's go-i18n

Releases

No releases published

Packages

No packages published