Browse Source

Merge pull request #3595 from Kelimion/i18n-fix

Fix .mo parser: Number of plurals
Jeroen van Rijn 1 year ago
parent
commit
b51eb53d04

+ 3 - 3
core/text/i18n/gettext.odin

@@ -93,15 +93,15 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur
 
 		keys := bytes.split(key, zero)
 		vals := bytes.split(val, zero)
-	
-		if len(keys) != len(vals) || max(len(keys), len(vals)) > MAX_PLURALS {
+
+		if (len(keys) != 1 && len(keys) != 2) || len(vals) > MAX_PLURALS {
 			return translation, .MO_File_Incorrect_Plural_Count
 		}
 
 		for k in keys {
 			interned_key, _ := strings.intern_get(&translation.intern, string(k))
 
-			interned_vals := make([]string, len(keys))
+			interned_vals := make([]string, len(vals))
 			last_val: string
 
 			i := 0

BIN
tests/core/assets/I18N/plur.mo


+ 59 - 25
tests/core/text/i18n/test_core_text_i18n.odin

@@ -38,44 +38,75 @@ Test :: struct {
 Test_Suite :: struct {
 	file:    string,
 	loader:  proc(string, i18n.Parse_Options, proc(int) -> int, mem.Allocator) -> (^i18n.Translation, i18n.Error),
+	plural:  proc(int) -> int,
 	err:     i18n.Error,
 	options: i18n.Parse_Options,
 	tests:   []Test,
 }
 
+// Custom pluralizer for plur.mo
+plur_mo_pluralizer :: proc(n: int) -> (slot: int) {
+	switch {
+	case n == 1:                       return 0
+	case n != 0 && n % 1_000_000 == 0: return 1
+	case:                              return 2
+	}
+}
+
 TESTS := []Test_Suite{
+	{
+		file   = "assets/I18N/plur.mo",
+		loader = i18n.parse_mo_file,
+		plural = plur_mo_pluralizer,
+		tests  = {
+			// These are in the catalog.
+			{"", "Message1",                      "This is message 1",             1},
+			{"", "Message1",                      "This is message 1 - plural A",  1_000_000},
+			{"", "Message1",                      "This is message 1 - plural B",  42},
+			{"", "Message1/plural",               "This is message 1",             1},
+			{"", "Message1/plural",               "This is message 1 - plural A",  1_000_000},
+			{"", "Message1/plural",               "This is message 1 - plural B",  42},
+
+			// This isn't in the catalog, so should ruturn the key.
+			{"", "Come visit us on Discord!",     "Come visit us on Discord!",      1},
+		},
+	},
+
 	{
 		file   = "assets/I18N/nl_NL.mo",
 		loader = i18n.parse_mo_file,
+		plural = nil, // Default pluralizer
 		tests  = {
 			// These are in the catalog.
-			{ "", "There are 69,105 leaves here.", "Er zijn hier 69.105 bladeren.",  1 },
-			{ "", "Hellope, World!",               "Hallo, Wereld!",                 1 },
-			{ "", "There is %d leaf.\n",           "Er is %d blad.\n",               1 },
-			{ "", "There are %d leaves.\n",        "Er is %d blad.\n",               1 },
-			{ "", "There is %d leaf.\n",           "Er zijn %d bladeren.\n",        42 },
-			{ "", "There are %d leaves.\n",        "Er zijn %d bladeren.\n",        42 },
+			{"", "There are 69,105 leaves here.", "Er zijn hier 69.105 bladeren.",  1},
+			{"", "Hellope, World!",               "Hallo, Wereld!",                 1},
+			{"", "There is %d leaf.\n",           "Er is %d blad.\n",               1},
+			{"", "There are %d leaves.\n",        "Er is %d blad.\n",               1},
+			{"", "There is %d leaf.\n",           "Er zijn %d bladeren.\n",        42},
+			{"", "There are %d leaves.\n",        "Er zijn %d bladeren.\n",        42},
 
 			// This isn't in the catalog, so should ruturn the key.
-			{ "", "Come visit us on Discord!",     "Come visit us on Discord!",      1 },
+			{"", "Come visit us on Discord!",     "Come visit us on Discord!",      1},
 		},
 	},
 
+
 	// QT Linguist with default loader options.
 	{
 		file   = "assets/I18N/nl_NL-qt-ts.ts",
 		loader = i18n.parse_qt_linguist_file,
+		plural = nil, // Default pluralizer
 		tests  = {
 			// These are in the catalog.
-			{ "Page",          "Text for translation",           "Tekst om te vertalen",        1},
-			{ "Page",          "Also text to translate",         "Ook tekst om te vertalen",    1},
-			{ "installscript", "99 bottles of beer on the wall", "99 flessen bier op de muur",  1},
-			{ "apple_count",   "%d apple(s)",                    "%d appel",                    1},
-			{ "apple_count",   "%d apple(s)",                    "%d appels",                  42},
+			{"Page",          "Text for translation",           "Tekst om te vertalen",        1},
+			{"Page",          "Also text to translate",         "Ook tekst om te vertalen",    1},
+			{"installscript", "99 bottles of beer on the wall", "99 flessen bier op de muur",  1},
+			{"apple_count",   "%d apple(s)",                    "%d appel",                    1},
+			{"apple_count",   "%d apple(s)",                    "%d appels",                  42},
 
 			// These aren't in the catalog, so should ruturn the key.
-			{ "",              "Come visit us on Discord!",      "Come visit us on Discord!",  1 },
-			{ "Fake_Section",  "Come visit us on Discord!",      "Come visit us on Discord!",  1 },
+			{"",              "Come visit us on Discord!",      "Come visit us on Discord!",   1},
+			{"Fake_Section",  "Come visit us on Discord!",      "Come visit us on Discord!",   1},
 		},
 	},
 
@@ -83,21 +114,22 @@ TESTS := []Test_Suite{
 	{
 		file    = "assets/I18N/nl_NL-qt-ts.ts",
 		loader  = i18n.parse_qt_linguist_file,
+		plural = nil, // Default pluralizer
 		options = {merge_sections = true},
 		tests   = {
 			// All of them are now in section "", lookup with original section should return the key.
-			{ "",              "Text for translation",           "Tekst om te vertalen",        1},
-			{ "",              "Also text to translate",         "Ook tekst om te vertalen",    1},
-			{ "",              "99 bottles of beer on the wall", "99 flessen bier op de muur",  1},
-			{ "",              "%d apple(s)",                    "%d appel",                    1},
-			{ "",              "%d apple(s)",                    "%d appels",                  42},
+			{"",              "Text for translation",           "Tekst om te vertalen",            1},
+			{"",              "Also text to translate",         "Ook tekst om te vertalen",        1},
+			{"",              "99 bottles of beer on the wall", "99 flessen bier op de muur",      1},
+			{"",              "%d apple(s)",                    "%d appel",                        1},
+			{"",              "%d apple(s)",                    "%d appels",                      42},
 
 			// All of them are now in section "", lookup with original section should return the key.
-			{ "Page",          "Text for translation",           "Text for translation",            1},
-			{ "Page",          "Also text to translate",         "Also text to translate",          1},
-			{ "installscript", "99 bottles of beer on the wall", "99 bottles of beer on the wall",  1},
-			{ "apple_count",   "%d apple(s)",                    "%d apple(s)",                     1},
-			{ "apple_count",   "%d apple(s)",                    "%d apple(s)",                    42},
+			{"Page",          "Text for translation",           "Text for translation",            1},
+			{"Page",          "Also text to translate",         "Also text to translate",          1},
+			{"installscript", "99 bottles of beer on the wall", "99 bottles of beer on the wall",  1},
+			{"apple_count",   "%d apple(s)",                    "%d apple(s)",                     1},
+			{"apple_count",   "%d apple(s)",                    "%d apple(s)",                    42},
 		},
 	},
 
@@ -105,6 +137,7 @@ TESTS := []Test_Suite{
 	{
 		file    = "assets/I18N/duplicate-key.ts",
 		loader  = i18n.parse_qt_linguist_file,
+		plural = nil, // Default pluralizer
 		options = {merge_sections = true},
 		err     = .Duplicate_Key,
 	},
@@ -113,6 +146,7 @@ TESTS := []Test_Suite{
 	{
 		file    = "assets/I18N/duplicate-key.ts",
 		loader  = i18n.parse_qt_linguist_file,
+		plural = nil, // Default pluralizer
 	},
 }
 
@@ -122,7 +156,7 @@ tests :: proc(t: ^testing.T) {
 	err: i18n.Error
 
 	for suite in TESTS {
-		cat, err = suite.loader(suite.file, suite.options, nil, context.allocator)
+		cat, err = suite.loader(suite.file, suite.options, suite.plural, context.allocator)
 
 		msg := fmt.tprintf("Expected loading %v to return %v, got %v", suite.file, suite.err, err)
 		expect(t, err == suite.err, msg)