From 5d83d4040f0df52bab9e02f0d2329038a0802535 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 26 May 2025 16:46:09 +0300 Subject: [PATCH] Add support for showing gender-neutral translations https://github.com/webmin/webmin/discussions/2482 https://forum.virtualmin.com/t/on-the-rejection-of-gender-neutral-language/133527 https://github.com/webmin/webmin/commit/833292c0d1498889e3fc065c1a612682654190ac https://github.com/webmin/authentic-theme/commit/fe064dd57db4d80f5fe0add5e0b5c1bcef3378ca https://github.com/virtualmin/virtualmin-gpl/commit/4a19a6460baf3040c4887227917a979b0731c50e --- acl/acl-lib.pl | 3 +++ change-user/change.cgi | 2 ++ change-user/index.cgi | 12 +++++++++--- config-lib.pl | 3 +++ lang/en | 1 + web-lib-funcs.pl | 32 +++++++++++++++++++++++++++++++- 6 files changed, 49 insertions(+), 4 deletions(-) diff --git a/acl/acl-lib.pl b/acl/acl-lib.pl index 8fc1265a1..113c79265 100755 --- a/acl/acl-lib.pl +++ b/acl/acl-lib.pl @@ -88,6 +88,7 @@ while(my $l = <$fh>) { $user{'modules'} = $acl{$user[0]}; $user{'lang'} = $gconfig{"lang_$user[0]"}; $user{'langauto'} = $gconfig{"langauto_$user[0]"}; + $user{'langneutral'} = $gconfig{"langneutral_$user[0]"}; $user{'locale'} = $gconfig{"locale_$user[0]"}; $user{'dateformat'} = $gconfig{"dateformat_$user[0]"}; $user{'notabs'} = $gconfig{"notabs_$user[0]"}; @@ -707,6 +708,8 @@ else { $gconfig{"lang_".$user->{'name'}} = $user->{'lang'} if ($user->{'lang'}); delete($gconfig{"langauto_".$username}); $gconfig{"langauto_".$user->{'name'}} = $user->{'langauto'} if (defined($user->{'langauto'})); + delete($gconfig{"langneutral_".$username}); + $gconfig{"langneutral_".$user->{'name'}} = $user->{'langneutral'} if (defined($user->{'langneutral'})); delete($gconfig{"locale_".$username}); $gconfig{"locale_".$user->{'name'}} = $user->{'locale'} if (defined($user->{'locale'})); delete($gconfig{"dateformat_".$username}); diff --git a/change-user/change.cgi b/change-user/change.cgi index 49128a5c9..bd20de7cb 100755 --- a/change-user/change.cgi +++ b/change-user/change.cgi @@ -35,10 +35,12 @@ if ($access{'lang'}) { if ($in{'lang_def'}) { $user->{'lang'} = undef; $user->{'langauto'} = undef; + $user->{'langneutral'} = undef; } else { $user->{'lang'} = $in{'lang'}; $user->{'langauto'} = $in{'langauto'} ? 1 : 0; + $user->{'langneutral'} = $in{'langneutral'} ? 1 : 0; } } diff --git a/change-user/index.cgi b/change-user/index.cgi index df9005ddd..9f0782877 100755 --- a/change-user/index.cgi +++ b/change-user/index.cgi @@ -36,14 +36,19 @@ if ($access{'lang'}) { } my $ulangused = ($ulang && $ulang ne $glang); my $ulangauto = $user->{'langauto'}; + my $ulangneutral = $user->{'langneutral'}; if (!defined($user->{'langauto'})) { if ($ulangused) { $ulangauto = $ulinfo->{'auto'}; - } else { + } + else { $ulangauto = defined($gconfig{"langauto"}) ? $gconfig{"langauto"} : $linfo->{'auto'}; + } + } + if (!defined($user->{'langneutral'}) && $ulangused) { + $ulangneutral = $ulinfo->{'neutral'}; } - } print &ui_table_row($text{'index_lang'}, &ui_radio("lang_def", $ulang ? 0 : 1, [ [ 1, &text('index_langglobal2', $linfo->{'desc'}, @@ -53,7 +58,8 @@ if ($access{'lang'}) { [ map { [ $_->{'lang'}, $_->{'desc'} ] } &list_languages() ]) ." ". - &ui_checkbox("langauto", 1, $text{'langauto_include'}, $ulangauto), + &ui_checkbox("langneutral", 1, $text{'langneutral_include'}, $ulangneutral). + &ui_checkbox("langauto", 1, $text{'langauto_include'}, $ulangauto), undef, [ "valign=top","valign=top" ]); } diff --git a/config-lib.pl b/config-lib.pl index b180bb3e9..777df47a0 100755 --- a/config-lib.pl +++ b/config-lib.pl @@ -36,6 +36,7 @@ my ($configref, $file, $module, $canconfig, $cbox, $section) = @_; my %config = %$configref; my $auto = $gconfig{"langauto_$remote_user"}; +my $neutral = $gconfig{"langneutral_$remote_user"}; if (!defined($auto)) { my $glangauto = $gconfig{'langauto'}; if (defined($glangauto)) { @@ -55,6 +56,8 @@ foreach $o (@lang_order_list) { &read_file("$file.$o", \%info, \@info_order); &read_file("$file.$o.auto", \%info, \@info_order) if ($auto && -r "$file.$o.auto"); + &read_file("$file.$o.neutral", \%info, \@info_order) + if ($neutral && -r "$file.$o.neutral"); } # Call any config pre-load function diff --git a/lang/en b/lang/en index 7be99771e..2c4ba94b6 100644 --- a/lang/en +++ b/lang/en @@ -421,6 +421,7 @@ paginator_showing_start=Showing $1 to $2 of $3 items on page paginator_showing_end=of $1 pages paginator_nosearchrs=There are no results matching $1 query +langneutral_include=Include neutral translations langauto_include=Include machine translations file_truncated_message=fetched $1 of data, truncated $2 out of $3 diff --git a/web-lib-funcs.pl b/web-lib-funcs.pl index 9b4c33483..4fff0121b 100755 --- a/web-lib-funcs.pl +++ b/web-lib-funcs.pl @@ -5828,6 +5828,17 @@ if (!defined($auto)) { return $auto; } +=head2 load_language_neutral() + +Returns 1 or 0, if *.neutral files should be used based on user preference + +=cut +sub load_language_neutral +{ +my $neutral = $gconfig{"langneutral_$remote_user"}; +return $neutral; +} + =head2 load_language([module], [directory]) Returns a hashtable mapping text codes to strings in the appropriate language, @@ -5848,6 +5859,7 @@ my %text; my $root = $root_directory; my $ol = $gconfig{'overlang'}; my $auto = load_language_auto(); +my $neutral = load_language_neutral(); my ($dir) = ($_[1] || "lang"); # Read global lang files @@ -5856,13 +5868,18 @@ foreach my $o (@lang_order_list) { my $ok_auto; $ok_auto = &read_file_cached_with_stat("$root/$dir/$o.auto", \%text) if ($auto && -r "$root/$dir/$o.auto"); - return () if (!$ok && !$ok_auto && $o eq $default_lang); + my $ok_neutral; + $ok_neutral = &read_file_cached_with_stat("$root/$dir/$o.neutral", \%text) + if ($neutral && -r "$root/$dir/$o.neutral"); + return () if (!$ok && !$ok_auto && !$ok_neutral && $o eq $default_lang); } if ($ol) { foreach my $o (@lang_order_list) { &read_file_cached("$root/$ol/$o", \%text); &read_file_cached("$root/$ol/$o.auto", \%text) if ($auto && -r "$root/$ol/$o.auto"); + &read_file_cached("$root/$ol/$o.neutral", \%text) + if ($neutral && -r "$root/$ol/$o.neutral"); } } &read_file_cached("$config_directory/custom-lang", \%text); @@ -5880,12 +5897,16 @@ if ($_[0]) { &read_file_cached_with_stat("$mdir/$dir/$o", \%text); &read_file_cached_with_stat("$mdir/$dir/$o.auto", \%text) if($auto && -r "$mdir/$dir/$o.auto"); + &read_file_cached_with_stat("$mdir/$dir/$o.neutral", \%text) + if($neutral && -r "$mdir/$dir/$o.neutral"); } if ($ol) { foreach my $o (@lang_order_list) { &read_file_cached("$mdir/$ol/$o", \%text); &read_file_cached("$mdir/$ol/$o.auto", \%text) if ($auto && -r "$mdir/$ol/$o.auto"); + &read_file_cached("$mdir/$ol/$o.neutral", \%text) + if ($neutral && -r "$mdir/$ol/$o.neutral"); } } &read_file_cached("$config_directory/$_[0]/custom-lang", \%text); @@ -6070,6 +6091,7 @@ return () if ($mod =~ /^\./); my (%rv, $clone, $o); my $mdir = &module_root_directory($mod); my $auto = load_language_auto(); +my $neutral = load_language_neutral(); &read_file_cached("$mdir/module.info", \%rv) || return (); if (-l $mdir) { # A clone is a module that links to another directory under the root @@ -6088,6 +6110,8 @@ foreach $o (@lang_order_list) { &read_file_cached("$mdir/module.info.$o", \%rv); &read_file_cached("$mdir/module.info.$o.auto", \%rv) if ($auto && -r "$mdir/module.info.$o.auto"); + &read_file_cached("$mdir/module.info.$o.neutral", \%rv) + if ($neutral && -r "$mdir/module.info.$o.neutral"); } # Apply desc_$LANG overrides @@ -8976,9 +9000,14 @@ sub help_file my ($mod, $file, $forcedir) = @_; my $dir = $forcedir || &module_root_directory($mod)."/help"; my $auto = load_language_auto(); +my $neutral = load_language_neutral(); foreach my $o (@lang_order_list) { my $lang = "$dir/$file.$o.html"; + my $lang_neutral = "$dir/$file.$o.neutral.html"; my $lang_auto = "$dir/$file.$o.auto.html"; + if ($neutral && -r $lang_neutral) { + return $lang_neutral; + } if ($auto && !-r $lang && -r $lang_auto) { return $lang_auto; } @@ -9011,6 +9040,7 @@ if (-r $zip) { my @files; foreach my $o (@lang_order_list) { next if ($o eq "en"); + push(@files, $file.".".$o.".neutral.html"); push(@files, $file.".".$o.".auto.html"); push(@files, $file.".".$o.".html"); }