]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0867: MS-Windows: messages are not in the display language v9.2.0867
authorHirohito Higashi <h.east.727@gmail.com>
Mon, 27 Jul 2026 22:04:06 +0000 (22:04 +0000)
committerChristian Brabandt <cb@256bit.org>
Mon, 27 Jul 2026 22:07:22 +0000 (22:07 +0000)
Problem:  On MS-Windows the messages use the language of the regional
          format, not the language that Windows is displayed in
          (Markus Nißl)
Solution: Use the display language for the messages, with the other
          preferred languages as fall back.  Make ":language messages"
          overrule it (Hirohito Higashi).

fixes:  #20855
closes: #20860

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
runtime/doc/mlang.txt
src/locale.c
src/option.c
src/version.c

index 6f0bb3fe625bd8fd802ea9ad9115ee53ec2f412e..0c1747eed66de833e0cd7999fd747b550000f867 100644 (file)
@@ -1,4 +1,4 @@
-*mlang.txt*    For Vim version 9.2.  Last change: 2026 Feb 14
+*mlang.txt*    For Vim version 9.2.  Last change: 2026 Jul 28
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -122,6 +122,10 @@ If you write your own translations you need to generate the .po file and
 convert it to a .mo file.  You need to get the source distribution and read
 the file "src/po/README.txt".
 
+The language of the messages comes from the display language of Windows, not
+from the regional format.  The other locale categories, such as the one used
+for |strftime()|, do follow the regional format.
+
 To overrule the automatic choice of the language, set the $LANG variable to
 the language of your choice.  use "en" to disable translations. >
 
index eb1845fce523e6b4db25cd79e10093d9742908c4..0d217fd4343d9d03a02a07c2c8b34caf9a092d2d 100644 (file)
@@ -116,10 +116,12 @@ get_mess_lang(void)
     p = get_locale_val(LC_MESSAGES);
 #  else
     // This is necessary for Win32, where LC_MESSAGES is not defined and $LANG
-    // may be set to the LCID number.  LC_COLLATE is the best guess, LC_TIME
-    // and LC_MONETARY may be set differently for a Japanese working in the
-    // US.
-    p = get_locale_val(LC_COLLATE);
+    // may be set to the LCID number.  $LANG holds the display language, see
+    // set_init_lang_env().  Otherwise LC_COLLATE is the best guess, LC_TIME
+    // and LC_MONETARY may be set differently for a Japanese working in the US.
+    p = mch_getenv((char_u *)"LANG");
+    if (!is_valid_mess_lang(p))
+       p = get_locale_val(LC_COLLATE);
 #  endif
 # else
     p = mch_getenv((char_u *)"LC_ALL");
@@ -365,9 +367,6 @@ ex_language(exarg_T *eap)
                if (what == LC_ALL)
                {
                    vim_setenv((char_u *)"LANG", name);
-
-                   // Clear $LANGUAGE because GNU gettext uses it.
-                   vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
 # ifdef MSWIN
                    // Apparently MS-Windows printf() may cause a crash when
                    // we give it 8-bit text while it's expecting text in the
@@ -383,6 +382,8 @@ ex_language(exarg_T *eap)
 # else
                    mname = name;
 # endif
+                   // Clear $LANGUAGE because GNU gettext uses it.
+                   vim_setenv((char_u *)"LANGUAGE", (char_u *)"");
                    vim_setenv((char_u *)"LC_MESSAGES", mname);
 # ifdef FEAT_MULTI_LANG
                    set_helplang_default(mname);
index d4f63203dd06948d6a13de4381f9c8e39415d035..f511b8ea5dffe5ef2f597f7ab718682322c9ac85 100644 (file)
@@ -494,6 +494,64 @@ set_init_expand_env(void)
     }
 }
 
+#if defined(MSWIN) && defined(FEAT_GETTEXT)
+/*
+ * Get the display language of Windows and the languages to fall back on, as a
+ * colon separated list for gettext, e.g. "ja_JP:en_US".  The list stops after
+ * English, untranslated messages are English already.
+ * Returns NULL when it cannot be obtained.  The result must be freed.
+ */
+    static char_u *
+get_ui_langs(void)
+{
+    ULONG      num_languages = 0;
+    ULONG      bufsize = 0;
+    WCHAR      *buffer;
+    char_u     *langs = NULL;
+
+    if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num_languages, NULL,
+                                                                   &bufsize)
+           || bufsize == 0)
+       return NULL;
+
+    buffer = ALLOC_MULT(WCHAR, bufsize);
+    if (buffer == NULL)
+       return NULL;
+
+    if (GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &num_languages, buffer,
+                                                                   &bufsize))
+    {
+       // The list is NUL separated, the result needs the same room.
+       langs = alloc(bufsize);
+       if (langs != NULL)
+       {
+           char_u      *d = langs;
+           WCHAR       *s = buffer;
+
+           while (*s != L'\0')
+           {
+               bool    english = s[0] == L'e' && s[1] == L'n'
+                                       && (s[2] == L'\0' || s[2] == L'-');
+
+               if (d > langs)
+                   *d++ = ':';
+               // Locale names are ASCII, "en-US" becomes "en_US".
+               for ( ; *s != L'\0'; ++s)
+                   *d++ = *s == L'-' ? '_' : (char_u)*s;
+               ++s;
+
+               if (english)
+                   break;
+           }
+           *d = NUL;
+       }
+    }
+    vim_free(buffer);
+
+    return langs;
+}
+#endif
+
 /*
  * Initialize the 'LANG' environment variable to a default value.
  */
@@ -501,32 +559,27 @@ set_init_expand_env(void)
 set_init_lang_env(void)
 {
 #if defined(MSWIN) && defined(FEAT_GETTEXT)
-    // If $LANG isn't set, try to get a good value for it.  This makes the
-    // right language be used automatically.  Don't do this for English.
-    if (mch_getenv((char_u *)"LANG") == NULL)
-    {
-       char    buf[20];
-       long_u  n;
-
-       // Could use LOCALE_SISO639LANGNAME, but it's not in Win95.
-       // LOCALE_SABBREVLANGNAME gives us three letters, like "enu", we use
-       // only the first two.
-       n = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SABBREVLANGNAME,
-                                                            (LPTSTR)buf, 20);
-       if (n >= 2 && STRNICMP(buf, "en", 2) != 0)
-       {
-           // There are a few exceptions (probably more)
-           if (STRNICMP(buf, "cht", 3) == 0 || STRNICMP(buf, "zht", 3) == 0)
-               STRCPY(buf, "zh_TW");
-           else if (STRNICMP(buf, "chs", 3) == 0
-                                             || STRNICMP(buf, "zhc", 3) == 0)
-               STRCPY(buf, "zh_CN");
-           else if (STRNICMP(buf, "jp", 2) == 0)
-               STRCPY(buf, "ja");
-           else
-               buf[2] = NUL;           // truncate to two-letter code
-           vim_setenv((char_u *)"LANG", (char_u *)buf);
+    // If the language isn't set in the environment, use the display language
+    // of Windows.  Not the regional format, which is what the CRT would use
+    // for setlocale(LC_ALL, "").
+    if (mch_getenv((char_u *)"LANG") == NULL
+           && mch_getenv((char_u *)"LANGUAGE") == NULL
+           && mch_getenv((char_u *)"LC_ALL") == NULL
+           && mch_getenv((char_u *)"LC_MESSAGES") == NULL)
+    {
+       char_u  *langs = get_ui_langs();
+
+       if (langs != NULL && *langs != NUL)
+       {
+           char_u      *colon = vim_strchr(langs, ':');
+
+           // $LANGUAGE is the list gettext picks from, $LANG the language.
+           vim_setenv((char_u *)"LANGUAGE", langs);
+           if (colon != NULL)
+               *colon = NUL;
+           vim_setenv((char_u *)"LANG", langs);
        }
+       vim_free(langs);
     }
 #elif defined(MACOS_CONVERT)
     // Moved to os_mac_conv.c to avoid dependency problems.
index 48389e931f18c009a863d968d3988e920d78dfc8..af42c7cbd10ec6e6a3623c90a8c16c02590e4df9 100644 (file)
@@ -758,6 +758,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    867,
 /**/
     866,
 /**/