瀏覽代碼

[i18n] Allow multiple sections.

Jeroen van Rijn 3 年之前
父節點
當前提交
ba23bfb7b9
共有 2 個文件被更改,包括 54 次插入14 次删除
  1. 6 5
      core/i18n/gettext.odin
  2. 48 9
      core/i18n/i18n.odin

+ 6 - 5
core/i18n/gettext.odin

@@ -57,6 +57,10 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo
 	translation.pluralize = pluralizer
 	translation.pluralize = pluralizer
 	strings.intern_init(&translation.intern, allocator, allocator)
 	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 {
 	for n := u32(0); n < count; n += 1 {
 		/*
 		/*
 			Grab string's original length and offset.
 			Grab string's original length and offset.
@@ -94,7 +98,7 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo
 		for k in keys {
 		for k in keys {
 			interned_key := strings.intern_get(&translation.intern, string(k))
 			interned_key := strings.intern_get(&translation.intern, string(k))
 
 
-			interned_vals: [MAX_PLURALS]string = {}
+			interned_vals := make([]string, len(keys))
 			last_val: string
 			last_val: string
 
 
 			i := 0
 			i := 0
@@ -103,10 +107,7 @@ parse_mo_from_slice :: proc(data: []u8, pluralizer: proc(int) -> int = nil, allo
 				last_val = interned_vals[i]
 				last_val = interned_vals[i]
 				i += 1
 				i += 1
 			}
 			}
-			for ; i < MAX_PLURALS; i += 1 {
-				interned_vals[i] = last_val
-			}
-			translation.k_v[interned_key] = interned_vals
+			section[interned_key] = interned_vals
 		}
 		}
 		delete(vals)
 		delete(vals)
 		delete(keys)
 		delete(keys)

+ 48 - 9
core/i18n/i18n.odin

@@ -15,18 +15,19 @@ import "core:strings"
 	- Support for more translation catalog file formats.
 	- Support for more translation catalog file formats.
 */
 */
 
 
-MAX_PLURALS :: 10
-
 /*
 /*
 	Currently active catalog.
 	Currently active catalog.
 */
 */
 ACTIVE: ^Translation
 ACTIVE: ^Translation
 
 
+// Allow between 1 and 255 plural forms. Default: 10.
+MAX_PLURALS :: min(max(#config(ODIN_i18N_MAX_PLURAL_FORMS, 10), 1), 255)
+
 /*
 /*
 	The main data structure. This can be generated from various different file formats, as long as we have a parser for them.
 	The main data structure. This can be generated from various different file formats, as long as we have a parser for them.
 */
 */
 Translation :: struct {
 Translation :: struct {
-	k_v:    map[string][MAX_PLURALS]string,
+	k_v:    map[string]map[string][]string,
 	intern: strings.Intern,
 	intern: strings.Intern,
 
 
 	pluralize: proc(number: int) -> int,
 	pluralize: proc(number: int) -> int,
@@ -64,7 +65,25 @@ Error :: enum {
 	- get(key, number), which returns the appropriate plural from the active catalog, or
 	- get(key, number), which returns the appropriate plural from the active catalog, or
 	- get(key, number, catalog) to grab text from a specific one.
 	- get(key, number, catalog) to grab text from a specific one.
 */
 */
-get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) {
+get_single_section :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) {
+	/*
+		A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule.
+	*/
+	plural := 1 if number != 1 else 0
+
+	if catalog.pluralize != nil {
+		plural = catalog.pluralize(number)
+	}
+	return get_by_slot(key, plural, catalog)
+}
+
+/*
+	Several ways to use:
+	- get(section, key), which defaults to the singular form and i18n.ACTIVE catalog, or
+	- get(section, key, number), which returns the appropriate plural from the active catalog, or
+	- get(section, key, number, catalog) to grab text from a specific one.
+*/
+get_by_section :: proc(section, key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value: string) {
 	/*
 	/*
 		A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule.
 		A lot of languages use singular for 1 item and plural for 0 or more than 1 items. This is our default pluralize rule.
 	*/
 	*/
@@ -75,6 +94,19 @@ get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value:
 	}
 	}
 	return get_by_slot(key, plural, catalog)
 	return get_by_slot(key, plural, catalog)
 }
 }
+get :: proc{get_single_section, get_by_section}
+
+/*
+	Several ways to use:
+	- get_by_slot(key), which defaults to the singular form and i18n.ACTIVE catalog, or
+	- get_by_slot(key, slot), which returns the requested plural from the active catalog, or
+	- get_by_slot(key, slot, catalog) to grab text from a specific one.
+
+	If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string.
+*/
+get_by_slot_single_section :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) {
+	return get_by_slot_by_section("", key, slot, catalog)
+}
 
 
 /*
 /*
 	Several ways to use:
 	Several ways to use:
@@ -84,10 +116,10 @@ get :: proc(key: string, number := 0, catalog: ^Translation = ACTIVE) -> (value:
 
 
 	If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string.
 	If a file format parser doesn't (yet) support plural slots, each of the slots will point at the same string.
 */
 */
-get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) {
-	if catalog == nil {
+get_by_slot_by_section :: proc(section, key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (value: string) {
+	if catalog == nil || section not_in catalog.k_v {
 		/*
 		/*
-			Return the key if the catalog catalog hasn't been initialized yet.
+			Return the key if the catalog catalog hasn't been initialized yet, or the section is not present.
 		*/
 		*/
 		return key
 		return key
 	}
 	}
@@ -95,12 +127,13 @@ get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (
 	/*
 	/*
 		Return the translation from the requested slot if this key is known, else return the key.
 		Return the translation from the requested slot if this key is known, else return the key.
 	*/
 	*/
-	if translations, ok := catalog.k_v[key]; ok {
-		plural := min(max(0, slot), MAX_PLURALS - 1)
+	if translations, ok := catalog.k_v[section][key]; ok {
+		plural := min(max(0, slot), len(catalog.k_v[section][key]) - 1)
 		return translations[plural]
 		return translations[plural]
 	}
 	}
 	return key
 	return key
 }
 }
+get_by_slot :: proc{get_by_slot_single_section, get_by_slot_by_section}
 
 
 /*
 /*
 	Same for destroy:
 	Same for destroy:
@@ -110,6 +143,12 @@ get_by_slot :: proc(key: string, slot := 0, catalog: ^Translation = ACTIVE) -> (
 destroy :: proc(catalog: ^Translation = ACTIVE) {
 destroy :: proc(catalog: ^Translation = ACTIVE) {
 	if catalog != nil {
 	if catalog != nil {
 		strings.intern_destroy(&catalog.intern)
 		strings.intern_destroy(&catalog.intern)
+		for section in &catalog.k_v {
+			for key in &catalog.k_v[section] {
+				delete(catalog.k_v[section][key])
+			}
+			delete(catalog.k_v[section])
+		}
 		delete(catalog.k_v)
 		delete(catalog.k_v)
 		free(catalog)
 		free(catalog)
 	}
 	}