From 33a1d1bac18cf4e91479382951c5d0fd53df28f4 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Mon, 21 Oct 2024 21:13:49 -0400 Subject: [PATCH] locale: Add support for localized string list --- locale/string.ha | 83 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 15 deletions(-) diff --git a/locale/string.ha b/locale/string.ha index e276abd..073c736 100644 --- a/locale/string.ha +++ b/locale/string.ha @@ -1,26 +1,27 @@ // A string localized into multiple locales. export type string = [](locale, str); +// -------------------------------------------------------------------------- // +// The matching is done as follows. If LC_MESSAGES is of the form +// lang_COUNTRY.ENCODING@MODIFIER, then it will match a key of the form +// lang_COUNTRY@MODIFIER. If such a key does not exist, it will attempt to match +// lang_COUNTRY followed by lang@MODIFIER. Then, a match against lang by itself +// will be attempted. Finally, if no matching key is found the required key +// without a locale specified is used. The encoding from the LC_MESSAGES value +// is ignored when matching. +// +// If LC_MESSAGES does not have a MODIFIER field, then no key with a modifier +// will be matched. Similarly, if LC_MESSAGES does not have a COUNTRY field, +// then no key with a country specified will be matched. If LC_MESSAGES just has +// a lang field, then it will do a straight match to a key with a similar value. +// -------------------------------------------------------------------------- // + // Selects the most appropriate localized version of a [[string]] given a // [[locale]]. The matching algorithm used is the one specified by the // XDG Desktop Entry Specification, ยง5. If no suitable version is found, an // exact match with the C locale will be attempted. If there are none, void will // be returned. Memory is borrowed from the input. -export fn string_resolve(strin: string, local: locale) (str | void) = { - // The matching is done as follows. If LC_MESSAGES is of the form - // lang_COUNTRY.ENCODING@MODIFIER, then it will match a key of the form - // lang_COUNTRY@MODIFIER. If such a key does not exist, it will attempt - // to match lang_COUNTRY followed by lang@MODIFIER. Then, a match - // against lang by itself will be attempted. Finally, if no matching key - // is found the required key without a locale specified is used. The - // encoding from the LC_MESSAGES value is ignored when matching. - // - // If LC_MESSAGES does not have a MODIFIER field, then no key with a - // modifier will be matched. Similarly, if LC_MESSAGES does not have a - // COUNTRY field, then no key with a country specified will be matched. - // If LC_MESSAGES just has a lang field, then it will do a straight - // match to a key with a similar value. - +export fn string_resolve(strin: string, local: locale) (str | void) = { // lang_COUNTRY@MODIFIER let lang_country_modifier = local; lang_country_modifier.encoding = ""; @@ -65,3 +66,55 @@ export fn string_resolve(strin: string, local: locale) (str | void) = { fn string_resolve_exact(strin: string, local: locale) (str | void) = { for (let pair .. strin) if(equal(pair.0, local)) return pair.1; }; + +// A list of strings localized into multiple locales. +export type strings = [](locale, []str); + +// Selects the most appropriate localized version of a [[string]] given a +// [[locale]]. See the documentation for [[string_resolve]] for more +// information. +export fn strings_resolve(strins: strings, local: locale) ([]str | void) = { + // lang_COUNTRY@MODIFIER + let lang_country_modifier = local; + lang_country_modifier.encoding = ""; + match (strings_resolve_exact(strins, lang_country_modifier)) { + case let result: []str => return result; + case => void; + }; + + // lang_COUNTRY + let lang_country = local; + lang_country.modifier = ""; + match (strings_resolve_exact(strins, lang_country)) { + case let result: []str => return result; + case => void; + }; + + // lang@MODIFIER + let lang_modifier = lang_country_modifier; + lang_modifier.country = ""; + match (strings_resolve_exact(strins, lang_modifier)) { + case let result: []str => return result; + case => void; + }; + + // lang + let lang = lang_modifier; + lang.modifier = ""; + match (strings_resolve_exact(strins, lang)) { + case let result: []str => return result; + case => void; + }; + + // fallback to c locale + match (strings_resolve_exact(strins, c)) { + case let result: []str => return result; + case => void; + }; + + return void; +}; + +fn strings_resolve_exact(strins: strings, local: locale) ([]str | void) = { + for (let pair .. strins) if(equal(pair.0, local)) return pair.1; +};