-*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
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. >
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");
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
# 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);
}
}
+#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.
*/
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.