diff --git a/doc/groff.texi b/doc/groff.texi
index 43a591ae..c170db33 100644
--- a/doc/groff.texi
+++ b/doc/groff.texi
@@ -7295,7 +7295,8 @@ powers of two for the configuration parameters; they are computationally
 easy to ``mask off'' and compare to zero.  To almost everyone else, the
 arrangement seems recondite and unfriendly.}  The entries in the table
 below are termed @dfn{values}, and the sum of the desired values is the
-@dfn{mode}.
+@dfn{mode}.  The default hyphenation mode depends on the language in use
+on the system; see the @code{hpf} request below.
 
 @table @code
 @item 0
@@ -7303,8 +7304,7 @@ disables hyphenation.
 
 @item 1
 enables hyphenation except after the first and before the last character
-of a word; this is the default if @var{mode} is omitted and also the
-start-up value of GNU @code{troff}.
+of a word.
 @end table
 
 The remaining values ``imply'' 1; that is, they enable hyphenation
@@ -7374,12 +7374,12 @@ s- plit- t- in- g
 @endExample
 
 @noindent
-instead of the correct `split- ting'.  U.S. English patterns as
-distributed with GNU @code{troff} need two characters at the beginning
-and three characters at the end; this means that value@tie{}4 of
-@code{hy} is mandatory.  Value@tie{}8 is possible as an additional
-restriction, but values@tie{}16 and@tie{}32 should be avoided, as should
-mode@tie{}1 (the default!).  Modes@tie{}4 and@tie{}6 are typical.
+instead of the correct `split- ting'.  English patterns as distributed
+with GNU @code{troff} need two characters at the beginning and three
+characters at the end; this means that value@tie{}4 of @code{hy} is
+mandatory.  Value@tie{}8 is possible as an additional restriction, but
+values@tie{}16 and@tie{}32 should be avoided, as should mode@tie{}1 (the
+default!).  Modes@tie{}4 and@tie{}6 are typical.
 
 A table of left and right minimum character counts for hyphenation as
 needed by the patterns distributed with GNU @code{troff} follows; see
@@ -7389,7 +7389,7 @@ the @cite{groff_tmac@r{(5)}} man page for more information on GNU
 @multitable {German traditional}    {pattern name}    {left min}    {right min}
 @headitem    language           @tab pattern name @tab left min @tab right min
 @item        Czech              @tab cs           @tab 2        @tab 2
-@item        U.S. English       @tab us           @tab 2        @tab 3
+@item        English            @tab en           @tab 2        @tab 3
 @item        French             @tab fr           @tab 2        @tab 3
 @item        German traditional @tab det          @tab 2        @tab 2
 @item        German reformed    @tab den          @tab 2        @tab 2
@@ -7476,15 +7476,32 @@ Character codes that would otherwise be invalid in GNU @code{troff} can
 be used.  By default, every code maps to itself except those for letters
 `A' to `Z', which map to those for `a' to `z'.
 
+@cindex localization
 @pindex troffrc
 @pindex troffrc-end
-@pindex hyphen.us
-@pindex hyphenex.us
+@pindex cs.tmac
+@pindex de.tmac
+@pindex en.tmac
+@pindex fr.tmac
+@pindex ja.tmac
+@pindex sv.tmac
+@pindex zh.tmac
+@tindex LC_ALL
+@tindex LANG
 The set of hyphenation patterns is associated with the language set by
 the @code{hla} request.  The @code{hpf} request is usually invoked by
-the @file{troffrc} or @file{troffrc-end} file; by default,
-@file{troffrc} loads hyphenation patterns and exceptions for U.S.
-English (in files @file{hyphen.us} and @file{hyphenex.us}).
+a localization file loaded by the @file{troffrc} or @file{troffrc-end}
+file.  By default, @file{troffrc} checks the environment variables
+@env{LC_ALL} and @env{LANG} (in that order) and attempts to load a
+localization file matching the first two characters of the variable's
+value.@footnote{As of @code{groff} 1.23.0, localization files for Czech
+(@code{cs}), German (@code{de}), English (@code{en}), French
+(@code{fr}), Japanese (@code{ja}), Swedish (@code{sv}), and Chinese
+(@code{zh}) exist.}  For Western languages, the localization file sets
+the hyphenation mode and loads hyphenation patterns and exceptions.  If
+the environment variables are not set, set to ``C'', or a localization
+file for the locale does not exist, the English localization file is
+used.
 
 A second call to @code{hpf} (for the same language) replaces the
 hyphenation patterns with the new ones.
@@ -7493,8 +7510,8 @@ Invoking @code{hpf} or @code{hpfa} causes an error if there is no
 hyphenation language.
 
 If no @code{hpf} request is specified (either in the document, in a
-@file{troffrc} or @file{troffrc-end} file, or in a macro package), GNU
-@code{troff} won't automatically hyphenate at all.
+file loaded at start-up, or in a macro package), GNU @code{troff} won't
+automatically hyphenate at all.
 @endDefreq
 
 @Defreq {hcode, c1 code1 [c2 code2] @dots{}}
@@ -7545,8 +7562,9 @@ Set the hyphenation language to @var{lang}.  Hyphenation exceptions
 specified with the @code{hw} request and hyphenation patterns and
 exceptions specified with the @code{hpf} and @code{hpfa} requests are
 associated with the hyphenation language.  The @code{hla} request is
-usually invoked by the @file{troffrc} or @file{troffrc-end} files;
-@file{troffrc} sets the default language to @samp{us} (U.S. English).
+usually invoked by a localization file, which is in turn loaded by the
+the @file{troffrc} or @file{troffrc-end} file; see the @code{hpf}
+request above.
 
 The hyphenation language is associated with the current environment
 (@pxref{Environments}).
@@ -7558,7 +7576,7 @@ register @samp{.hla}.
 @Example
 .ds curr_language \n[.hla]
 \*[curr_language]
-    @result{} us
+    @result{} en
 @endExample
 @endDefreq
 
@@ -15283,7 +15301,7 @@ implementations.
 @cindex hyphenation, incompatibilities with @acronym{AT&T} @code{troff}
 GNU @code{troff} does not always hyphenate words as @acronym{AT&T}
 @code{troff} does.  The @acronym{AT&T} implementation uses a set of
-hard-coded rules specific to U.S. English, while GNU @code{troff} uses
+hard-coded rules specific to English, while GNU @code{troff} uses
 language-specific hyphenation pattern files derived from @TeX{}.
 Furthermore, in old versions of @code{troff} there was a limited amount
 of space to store hyphenation exceptions (arguments to the @code{hw}
diff --git a/man/groff.7.man b/man/groff.7.man
index a815fd3b..1545735b 100644
--- a/man/groff.7.man
+++ b/man/groff.7.man
@@ -4865,7 +4865,7 @@ and at which positions within that word hyphenation is permissible.
 The default is
 .RB \[lq] 1 \[rq]
 for historical reasons,
-but this is not an appropriate value for the U.S.\& English hyphenation
+but this is not an appropriate value for the English hyphenation
 patterns used by
 .IR groff ,
 and macro packages often override it.
diff --git a/man/groff_diff.7.man b/man/groff_diff.7.man
index d7f135c3..3bc1b0f5 100644
--- a/man/groff_diff.7.man
+++ b/man/groff_diff.7.man
@@ -2159,14 +2159,15 @@ requests are associated with the hyphenation language.
 .
 The
 .B .hla
-request is usually invoked by the
+request is usually invoked by a localization file,
+which is in turn loaded by the
 .I troffrc
 or
 .I troffrc\-end
-files;
-.I troffrc
-sets the default language to \[lq]us\[rq]
-(U.S. English).
+file;
+see the
+.B .hpf
+request above.
 .
 .
 .IP
@@ -2308,19 +2309,47 @@ request.
 .
 The
 .B .hpf
-request is usually invoked by the
+request is usually invoked by a localization file loaded by the
 .I troffrc
 or
 .I troffrc\-end
-file;
-by default,
+file.
+.
+By default,
 .I troffrc
-loads hyphenation patterns and exceptions for U.S. English from the
-files
-.I hyphen.us
+checks the environment variables
+.I LC_ALL
 and
-.IR hyphenex.us ,
-respectively.
+.I LANG
+(in that order)
+and attempts to load a localization file matching the first two
+characters of the variable's value.
+.
+(As of @code{groff} 1.23.0, localization files for Czech
+.RI ( cs ),
+German
+.RI ( de ),
+English
+.RI ( en ),
+French
+.RI ( fr ),
+Japanese
+.RI ( ja ),
+Swedish
+.RI ( sv ),
+and Chinese
+.RI ( zh )
+exist.)
+.
+For Western languages,
+the localization file sets the hyphenation mode and loads hyphenation
+patterns and exceptions.
+.
+If the environment variables are not set,
+set to
+.RB \[lq] C \[rq],
+or a localization file for the locale does not exist,
+the English localization file is used.
 .
 .
 .IP
@@ -2341,11 +2370,7 @@ If no
 .B .hpf
 request is specified
 (either in the document,
-in a
-.I troffrc
-or
-.I troffrc\-end
-file,
+in a file loaded at start-up,
 or in a macro package),
 .I groff
 won't automatically hyphenate at all.
@@ -4594,7 +4619,7 @@ does not always hyphenate words as
 .RI AT&T\~ troff
 does.
 .
-The AT&T implementation uses a set of hard-coded rules specific to U.S.
+The AT&T implementation uses a set of hard-coded rules specific to
 English,
 while
 .I groff
diff --git a/src/roff/groff/groff.am b/src/roff/groff/groff.am
index 60872d02..f94a9beb 100644
--- a/src/roff/groff/groff.am
+++ b/src/roff/groff/groff.am
@@ -44,6 +44,7 @@ groff_TESTS = \
   src/roff/groff/tests/adjustment_works.sh \
   src/roff/groff/tests/do_not_loop_infinitely_when_breaking_cjk.sh \
   src/roff/groff/tests/dot-cp_register_works.sh \
+  src/roff/groff/tests/msoquiet_works.sh \
   src/roff/groff/tests/on_latin1_device_oq_is_0x27.sh \
   src/roff/groff/tests/recognize_end_of_sentence.sh \
   src/roff/groff/tests/regression_savannah_56555.sh \
@@ -52,6 +53,7 @@ groff_TESTS = \
   src/roff/groff/tests/regression_savannah_58337.sh \
   src/roff/groff/tests/regression_savannah_59202.sh \
   src/roff/groff/tests/smoke-test_html_device.sh \
+  src/roff/groff/tests/soquiet_works.sh \
   src/roff/groff/tests/string_case_xform_errors.sh \
   src/roff/groff/tests/string_case_xform_requests.sh \
   src/roff/groff/tests/string_case_xform_unicode_escape.sh \
diff --git a/src/roff/groff/tests/msoquiet_works.sh b/src/roff/groff/tests/msoquiet_works.sh
new file mode 100755
index 00000000..c232a1be
--- /dev/null
+++ b/src/roff/groff/tests/msoquiet_works.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of groff.
+#
+# groff is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+groff="${abs_top_builddir:-.}/test-groff"
+
+set -e
+
+DOC='.msoquiet nonexistent'
+
+OUTPUT=$(echo "$DOC" | "$groff" -Tascii 2>&1)
+
+echo "testing that .msoquiet of nonexistent file produces no warning" \
+  >&2
+test -z "$OUTPUT"
diff --git a/src/roff/groff/tests/soquiet_works.sh b/src/roff/groff/tests/soquiet_works.sh
new file mode 100755
index 00000000..8e8d71e7
--- /dev/null
+++ b/src/roff/groff/tests/soquiet_works.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of groff.
+#
+# groff is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# groff is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+groff="${abs_top_builddir:-.}/test-groff"
+
+set -e
+
+DOC='.soquiet nonexistent'
+
+OUTPUT=$(echo "$DOC" | "$groff" -Tascii 2>&1)
+
+echo "testing that .soquiet of nonexistent file produces no error" >&2
+test -z "$OUTPUT"
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index 02fa02e7..25e7a1e8 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -5956,9 +5956,7 @@ void while_continue_request()
   }
 }
 
-// .so
-
-void source()
+void do_source(bool quietly)
 {
   symbol nm = get_long_name(1);
   if (nm.is_null())
@@ -5971,11 +5969,34 @@ void source()
     if (fp)
       input_stack::push(new file_iterator(fp, nm.contents()));
     else
-      error("can't open '%1': %2", nm.contents(), strerror(errno));
+      // Suppress diagnostic only if we're operating quietly and it's an
+      // expected problem.
+      while (1) {
+	if (quietly)
+	  if ((EACCES == errno) || (ENOENT == errno))
+	    break;
+	error("can't open '%1': %2", nm.contents(), strerror(errno));
+	break;
+      }
     tok.next();
   }
 }
 
+// .so
+
+void source()
+{
+  do_source(0); // 0: not quietly
+}
+
+// .soquiet: like .so, but silently ignore files that can't be opened
+// due to their nonexistence or lack of permissions
+
+void source_quietly()
+{
+  do_source(1); // 1: quietly
+}
+
 // like .so but use popen()
 
 void pipe_source()
@@ -7775,7 +7796,7 @@ static void process_startup_file(const char *filename)
   mac_path = orig_mac_path;
 }
 
-void macro_source()
+void do_macro_source(bool quietly)
 {
   symbol nm = get_long_name(1);
   if (nm.is_null())
@@ -7815,12 +7836,35 @@ void macro_source()
       free(path);
     }
     else
-      warning(WARN_FILE, "can't open macro file '%1': %2",
-	      nm.contents(), strerror(errno));
+      // Suppress diagnostic only if we're operating quietly and it's an
+      // expected problem.
+      while (1) {
+	if (quietly)
+	  if ((EACCES == errno) || (ENOENT == errno))
+	    break;
+	warning(WARN_FILE, "can't open macro file '%1': %2",
+		nm.contents(), strerror(errno));
+	break;
+      }
     tok.next();
   }
 }
 
+// .mso
+
+void macro_source()
+{
+  do_macro_source(0); // 0: not quietly (if WARN_FILE enabled)
+}
+
+// .msoquiet: like .mso, but silently ignore files that can't be opened
+// due to their nonexistence or lack of permissions
+
+void macro_source_quietly()
+{
+  do_macro_source(1); // 1: quietly
+}
+
 static void process_input_file(const char *name)
 {
   FILE *fp;
@@ -8281,6 +8325,7 @@ void init_input_requests()
   init_request("lf", line_file);
   init_request("lsm", leading_spaces_macro);
   init_request("mso", macro_source);
+  init_request("msoquiet", macro_source_quietly);
   init_request("nop", nop_request);
   init_request("nroff", nroff_request);
   init_request("nx", next_file);
@@ -8302,6 +8347,7 @@ void init_input_requests()
   init_request("schar", define_special_character);
   init_request("shift", shift);
   init_request("so", source);
+  init_request("soquiet", source_quietly);
   init_request("spreadwarn", spreadwarn_request);
   init_request("stringdown", stringdown_request);
   init_request("stringup", stringup_request);
diff --git a/tmac/en.tmac b/tmac/en.tmac
new file mode 100644
index 00000000..0bc41967
--- /dev/null
+++ b/tmac/en.tmac
@@ -0,0 +1,41 @@
+.\" English localization for groff
+.\"
+.\" Copyright (C) 2021 Free Software Foundation, Inc.
+.\"
+.\" This file is part of groff.
+.\"
+.\" groff is free software; you can redistribute it and/or modify it
+.\" under the terms of the GNU General Public License as published by
+.\" the Free Software Foundation, either version 3 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" groff is distributed in the hope that it will be useful, but WITHOUT
+.\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+.\" or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+.\" License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program.  If not, see
+.\" <http://www.gnu.org/licenses/>.
+.\"
+.\" Please send comments to groff@gnu.org.
+.
+.ds locale english\"
+.
+.\" Set the minimum hyphenation mode that works with the patterns.
+.hy 4
+.
+.\" Set the hyphenation language to English.
+.do hla en
+.
+.\" Load hyphenation patterns and exceptions.
+.do hpf hyphen.en
+.do hpfa hyphenex.en
+.
+.
+.\" Local Variables:
+.\" mode: nroff
+.\" coding: latin-1
+.\" fill-column: 72
+.\" End:
+.\" vim: set filetype=groff textwidth=72:
diff --git a/tmac/hyphen.us b/tmac/hyphen.en
similarity index 100%
rename from tmac/hyphen.us
rename to tmac/hyphen.en
diff --git a/tmac/hyphenex.us b/tmac/hyphenex.en
similarity index 100%
rename from tmac/hyphenex.us
rename to tmac/hyphenex.en
diff --git a/tmac/tmac.am b/tmac/tmac.am
index 86204d42..1987b728 100644
--- a/tmac/tmac.am
+++ b/tmac/tmac.am
@@ -77,8 +77,9 @@ TMACNORMALFILES = \
   tmac/troffrc \
   tmac/troffrc-end \
   tmac/trans.tmac \
-  tmac/hyphen.us \
-  tmac/hyphenex.us \
+  tmac/en.tmac \
+  tmac/hyphen.en \
+  tmac/hyphenex.en \
   tmac/fr.tmac \
   tmac/hyphen.fr \
   tmac/sv.tmac \
diff --git a/tmac/troffrc b/tmac/troffrc
index 2ba343ef..c30ae736 100644
--- a/tmac/troffrc
+++ b/tmac/troffrc
@@ -54,12 +54,31 @@ troffrc!html
 .el \
 .	do tr \[char65]\~
 .
-.\" Set the hyphenation language to 'us'.
-.do hla us
 .
-.\" Load hyphenation patterns and exceptions.
-.do hpf hyphen.us
-.do hpfa hyphenex.us
+.\" Determine the groff locale from the environment if possible.  Try
+.\" LC_ALL first, then LANG.  "C" means English (en).  Otherwise, only
+.\" the first two characters of the locale name are used.
+.do ds troffrc!language \V[LC_ALL]
+.do if '\*[troffrc!language]'' \{\
+.	do ds troffrc!language \V[LANG]
+.	do if '\*[troffrc!language]'' \
+.		do ds troffrc!language C
+.\}
+.do if '\*[troffrc!language]'C' \
+.	do ds troffrc!language en
+.do length troffrc!lang_length \*[troffrc!language]
+.do if (\n[troffrc!lang_length] > 2) \
+.	do substring troffrc!language 0 1
+.\" XXX: Consider not merging this until we have a "quiet" version of
+.\" .mso (and .so).
+.do mso \*[troffrc!language].tmac
+.do rm troffrc!language
+.do rr troffrc!lang_length
+.\" If the configured system locale has no groff localization, fall back
+.\" to English.
+.do if !d locale \
+.	do mso en.tmac
+.
 .
 .\" Handle paper formats.
 .do mso papersize.tmac
