locale: Add support for localized string list

This commit is contained in:
Sasha Koshka 2024-10-21 21:13:49 -04:00
parent 1055173246
commit 33a1d1bac1

View File

@ -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.
// 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;
};