diff --git a/profile.d/lang.sh b/profile.d/lang.sh index 49cc23d..1dab605 100644 --- a/profile.d/lang.sh +++ b/profile.d/lang.sh @@ -37,14 +37,48 @@ load_conf lang # ------------------------------------------------------------------------------ -# check if a given locale is installed on the system +# check if a given locale is installed on the system. +# The comparison is tolerant to the various ways the codeset can be written +# across distributions (UTF-8, UTF8, utf8, utf-8, ISO-8859-1, iso88591, ...). +# On success the canonical name, exactly as the system spells it, is printed on +# stdout so callers can feed it verbatim to `export LANG=...` etc. +# Usage: canonical=$(locale_check ) || handle-missing locale_check() { - locale -a | grep -qx "$1" || { - disp W "Locale '$1' is not installed on this system." - return 1 - } - return 0 + local requested="$1" + [[ -z $requested ]] && { disp W "No locale given to check."; return 1; } + + # Split "lang_TERRITORY[.codeset][@modifier]" into base, codeset, modifier. + local req_body="$requested" req_cs="" req_mod="" + [[ $req_body == *@* ]] && { req_mod="${req_body##*@}"; req_body="${req_body%@*}"; } + [[ $req_body == *.* ]] && { req_cs="${req_body##*.}"; req_body="${req_body%.*}"; } + + # Normalise the codeset: lowercase then strip every non-alphanumeric char so + # that UTF-8, UTF8, utf8 and utf-8 all compare equal (likewise ISO variants). + local req_cs_norm="${req_cs,,}" + req_cs_norm="${req_cs_norm//[^a-z0-9]/}" + + local cand body cs mod cs_norm + while IFS= read -r cand; do + [[ -z $cand ]] && continue + body="$cand"; cs=""; mod="" + [[ $body == *@* ]] && { mod="${body##*@}"; body="${body%@*}"; } + [[ $body == *.* ]] && { cs="${body##*.}"; body="${body%.*}"; } + cs_norm="${cs,,}" + cs_norm="${cs_norm//[^a-z0-9]/}" + + # Base language and modifier must match exactly. + [[ $body == "$req_body" && $mod == "$req_mod" ]] || continue + # A requested codeset must match (normalised); if none was requested, + # accept any codeset the system provides. + [[ -z $req_cs_norm || $cs_norm == "$req_cs_norm" ]] || continue + + printf '%s\n' "$cand" + return 0 + done < <(locale -a 2>/dev/null) + + disp W "Locale '$requested' is not installed on this system." + return 1 } export -f locale_check @@ -85,7 +119,9 @@ setlocale() local loc=$1 [[ -z $loc ]] && disp E "No locale specified." && return 1 - locale_check "$loc" || return 1 + # Resolve to the exact spelling installed on this system, tolerant to the + # various codeset writings (UTF-8, UTF8, utf8, utf-8, ...). + loc=$(locale_check "$loc") || return 1 export LANG=$loc export LC_MESSAGES=$loc @@ -108,6 +144,7 @@ setc() { # Locale definitions export LC_ALL=C + export LANG=C disp I "Locale changed to standard C (POSIX)." } export -f setc