Browse Source

Fix .mo contexts

Fixes #3590

- `get("key")`
- `get("context", "key")`
Jeroen van Rijn 1 year ago
parent
commit
6139da3d41

+ 23 - 15
core/text/i18n/gettext.odin

@@ -60,10 +60,6 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur
 	translation.pluralize = pluralizer
 	strings.intern_init(&translation.intern, allocator, allocator)
 
-	// Gettext MO files only have one section.
-	translation.k_v[""] = {}
-	section := &translation.k_v[""]
-
 	for n := u32(0); n < count; n += 1 {
 		/*
 			Grab string's original length and offset.
@@ -83,37 +79,49 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur
 		max_offset := int(max(o_offset + o_length + 1, t_offset + t_length + 1))
 		if len(data) < max_offset { return translation, .Premature_EOF }
 
-		key := data[o_offset:][:o_length]
-		val := data[t_offset:][:t_length]
+		key_data := data[o_offset:][:o_length]
+		val_data := data[t_offset:][:t_length]
 
 		/*
 			Could be a pluralized string.
 		*/
 		zero := []byte{0}
-
-		keys := bytes.split(key, zero)
-		vals := bytes.split(val, zero)
+		keys := bytes.split(key_data, zero); defer delete(keys)
+		vals := bytes.split(val_data, zero); defer delete(vals)
 
 		if (len(keys) != 1 && len(keys) != 2) || len(vals) > MAX_PLURALS {
 			return translation, .MO_File_Incorrect_Plural_Count
 		}
 
+		section_name := ""
 		for k in keys {
-			interned_key, _ := strings.intern_get(&translation.intern, string(k))
+			key := string(k)
+
+			// Scan for <context>EOT<key>
+			for ch, i in k {
+				if ch == 0x04 {
+					section_name = string(k[:i])
+					key          = string(k[i+1:])
+					break
+				}
+			}
+			section_name, _ = strings.intern_get(&translation.intern, section_name)
+			if section_name not_in translation.k_v {
+				translation.k_v[section_name] = {}
+			}
 
+			interned_key, _ := strings.intern_get(&translation.intern, string(key))
 			interned_vals := make([]string, len(vals))
 			last_val: string
 
-			i := 0
-			for v in vals {
+			for v, i in vals {
 				interned_vals[i], _ = strings.intern_get(&translation.intern, string(v))
 				last_val = interned_vals[i]
-				i += 1
 			}
+
+			section := &translation.k_v[section_name]
 			section[interned_key] = interned_vals
 		}
-		delete(vals)
-		delete(keys)
 	}
 	return
 }

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


+ 18 - 0
tests/core/assets/I18N/mixed_context.po

@@ -0,0 +1,18 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.1.0\n"
+"PO-Revision-Date: 2024-04-13 11:13+0200\n"
+"Last-Translator: Someone <[email protected]>\n"
+"Language-Team: English\n"
+"Language: en_IE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Context"
+msgid "Message1"
+msgstr "This is message 1 with Context"
+
+msgid "Message1"
+msgstr "This is message 1 without Context"

+ 17 - 0
tests/core/assets/I18N/plur.po

@@ -0,0 +1,17 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.1.0\n"
+"PO-Revision-Date: 2024-04-13 11:13+0200\n"
+"Last-Translator: Someone <[email protected]>\n"
+"Language-Team: English\n"
+"Language: it_IT\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2);\n"
+
+msgid "Message1"
+msgid_plural "Message1/plural"
+msgstr[0] "This is message 1"
+msgstr[1] "This is message 1 - plural A"
+msgstr[2] "This is message 1 - plural B"

+ 14 - 0
tests/core/text/i18n/test_core_text_i18n.odin

@@ -72,6 +72,20 @@ TESTS := []Test_Suite{
 		},
 	},
 
+	{
+		file   = "assets/I18N/mixed_context.mo",
+		loader = i18n.parse_mo_file,
+		plural = nil,
+		tests  = {
+			// These are in the catalog.
+			{"",        "Message1",               "This is message 1 without Context", 1},
+			{"Context", "Message1",               "This is message 1 with Context",    1},
+
+			// 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,