diff --git a/doc/release-notes/rl-2505.section.md b/doc/release-notes/rl-2505.section.md index defb47f1e5b6..fb46f6ac04d6 100644 --- a/doc/release-notes/rl-2505.section.md +++ b/doc/release-notes/rl-2505.section.md @@ -374,6 +374,7 @@ - `i18n.extraLocales` should now be the preferred way to install additional locales. - `i18n.supportedLocales` is now considered an implementation detail and will be hidden from the documentation. But the option will still continue to work. - `i18n.supportedLocales` will now trigger a warning when it omits any locale set in `i18n.defaultLocale`, `i18n.extraLocales` or `i18n.extraLocaleSettings`. + - The options `i18n.defaultCharset` & `i18n.localeCharsets` were added, and they complement `i18n.defaultLocale` & `i18n.extraLocaleSettings` respectively - allowing to control the character set used per locale setting. - `titaniumenv`, `titanium`, and `titanium-alloy` have been removed due to lack of maintenance in Nixpkgs []{#sec-nixpkgs-release-25.05-incompatibilities-titanium-removed}. diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix index 42b91ff9628a..22a47d5bdffa 100644 --- a/nixos/modules/config/i18n.nix +++ b/nixos/modules/config/i18n.nix @@ -5,15 +5,19 @@ ... }: let + sanitizeUTF8Capitalization = + lang: (lib.replaceStrings [ "utf8" "utf-8" "UTF8" ] [ "UTF-8" "UTF-8" "UTF-8" ] lang); aggregatedLocales = - (builtins.map - (l: (lib.replaceStrings [ "utf8" "utf-8" "UTF8" ] [ "UTF-8" "UTF-8" "UTF-8" ] l) + "/UTF-8") - ( - [ config.i18n.defaultLocale ] - ++ (lib.optionals (builtins.isList config.i18n.extraLocales) config.i18n.extraLocales) - ++ (lib.attrValues (lib.filterAttrs (n: v: n != "LANGUAGE") config.i18n.extraLocaleSettings)) - ) - ) + [ + "${config.i18n.defaultLocale}/${config.i18n.defaultCharset}" + ] + ++ lib.pipe config.i18n.extraLocaleSettings [ + (lib.mapAttrs (n: v: (sanitizeUTF8Capitalization v))) + (lib.mapAttrsToList (LCRole: lang: lang + "/" + (config.i18n.localeCharsets.${LCRole} or "UTF-8"))) + ] + ++ (builtins.map sanitizeUTF8Capitalization ( + lib.optionals (builtins.isList config.i18n.extraLocales) config.i18n.extraLocales + )) ++ (lib.optional (builtins.isString config.i18n.extraLocales) config.i18n.extraLocales); in { @@ -48,16 +52,24 @@ in default = "en_US.UTF-8"; example = "nl_NL.UTF-8"; description = '' - The default locale. It determines the language for program - messages, the format for dates and times, sort order, and so on. - It also determines the character set, such as UTF-8. + The default locale. It determines the language for program messages, + the format for dates and times, sort order, and so on. Setting the + default character set is done via {option}`i18n.defaultCharset`. + ''; + }; + defaultCharset = lib.mkOption { + type = lib.types.str; + default = "UTF-8"; + example = "ISO-8859-8"; + description = '' + The default locale character set. ''; }; extraLocales = lib.mkOption { type = lib.types.either (lib.types.listOf lib.types.str) (lib.types.enum [ "all" ]); default = [ ]; - example = [ "nl_NL.UTF-8" ]; + example = [ "nl_NL.UTF-8/UTF-8" ]; description = '' Additional locales that the system should support, besides the ones configured with {option}`i18n.defaultLocale` and @@ -74,9 +86,24 @@ in LC_TIME = "de_DE.UTF-8"; }; description = '' - A set of additional system-wide locale settings other than - `LANG` which can be configured with - {option}`i18n.defaultLocale`. + A set of additional system-wide locale settings other than `LANG` + which can be configured with {option}`i18n.defaultLocale`. Note that + the `/UTF-8` suffix used in {option}`i18n.extraLocales` indicates a + character set, and it must not be added manually here. To use a + non-`UTF-8` character set such as ISO-XXXX-8, the + {option}`i18n.localeCharsets` can be used. + ''; + }; + localeCharsets = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + example = { + LC_MESSAGES = "ISO-8859-15"; + LC_TIME = "ISO-8859-1"; + }; + description = '' + Per each {option}`i18n.extraLocaleSettings`, choose the character set + to use for it. Essentially defaults to UTF-8 for all of them. ''; }; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 3eb2327baf63..03a736fdd7dc 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -994,6 +994,7 @@ in orthanc = runTest ./orthanc.nix; owncast = handleTest ./owncast.nix { }; outline = handleTest ./outline.nix { }; + i18n = runTest ./i18n.nix; image-contents = handleTest ./image-contents.nix { }; openvscode-server = handleTest ./openvscode-server.nix { }; open-webui = runTest ./open-webui.nix; diff --git a/nixos/tests/i18n.nix b/nixos/tests/i18n.nix new file mode 100644 index 000000000000..a0493b7c62f5 --- /dev/null +++ b/nixos/tests/i18n.nix @@ -0,0 +1,43 @@ +{ lib, ... }: +{ + name = "glibLocales-custom-builds"; + meta.maintainers = with lib.maintainers; [ doronbehar ]; + + nodes = { + nonUTF8Charset = { + i18n = { + defaultLocale = "en_US"; + defaultCharset = "ISO-8859-1"; + }; + }; + extraLocales1 = { + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocales = [ + "nl_NL.UTF-8/UTF-8" + ]; + }; + }; + extraLocaleSettings = { + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_MESSAGES = "en_US.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; + }; + }; + localeCharsets = { + i18n = { + defaultLocale = "en_US.UTF-8"; + extraLocaleSettings = { + LC_TIME = "de_DE"; + }; + localeCharsets = { + LC_TIME = "ISO-8859-1"; + }; + }; + }; + }; + testScript = { nodes, ... }: ""; +}