mirror of
https://github.com/vim/vim.git
synced 2025-07-24 10:45:12 -04:00
patch 8.2.1269: language and locale code spread out
Problem: Language and locale code spread out. Solution: Move relevant code to src/locale.c. (Yegappan Lakshmanan, closes #6509)
This commit is contained in:
parent
e7e4838f25
commit
054f14bbe5
2
Filelist
2
Filelist
@ -76,6 +76,7 @@ SRC_ALL = \
|
|||||||
src/json_test.c \
|
src/json_test.c \
|
||||||
src/kword_test.c \
|
src/kword_test.c \
|
||||||
src/list.c \
|
src/list.c \
|
||||||
|
src/locale.c \
|
||||||
src/keymap.h \
|
src/keymap.h \
|
||||||
src/macros.h \
|
src/macros.h \
|
||||||
src/main.c \
|
src/main.c \
|
||||||
@ -247,6 +248,7 @@ SRC_ALL = \
|
|||||||
src/proto/insexpand.pro \
|
src/proto/insexpand.pro \
|
||||||
src/proto/json.pro \
|
src/proto/json.pro \
|
||||||
src/proto/list.pro \
|
src/proto/list.pro \
|
||||||
|
src/proto/locale.pro \
|
||||||
src/proto/main.pro \
|
src/proto/main.pro \
|
||||||
src/proto/map.pro \
|
src/proto/map.pro \
|
||||||
src/proto/mark.pro \
|
src/proto/mark.pro \
|
||||||
|
@ -751,6 +751,7 @@ OBJ = \
|
|||||||
$(OUTDIR)/insexpand.o \
|
$(OUTDIR)/insexpand.o \
|
||||||
$(OUTDIR)/json.o \
|
$(OUTDIR)/json.o \
|
||||||
$(OUTDIR)/list.o \
|
$(OUTDIR)/list.o \
|
||||||
|
$(OUTDIR)/locale.o \
|
||||||
$(OUTDIR)/main.o \
|
$(OUTDIR)/main.o \
|
||||||
$(OUTDIR)/map.o \
|
$(OUTDIR)/map.o \
|
||||||
$(OUTDIR)/mark.o \
|
$(OUTDIR)/mark.o \
|
||||||
|
@ -70,6 +70,7 @@ SRC = arabic.c \
|
|||||||
insexpand.c \
|
insexpand.c \
|
||||||
json.c \
|
json.c \
|
||||||
list.c \
|
list.c \
|
||||||
|
locale.c \
|
||||||
main.c \
|
main.c \
|
||||||
map.c \
|
map.c \
|
||||||
mark.c \
|
mark.c \
|
||||||
|
@ -773,6 +773,7 @@ OBJ = \
|
|||||||
$(OUTDIR)\insexpand.obj \
|
$(OUTDIR)\insexpand.obj \
|
||||||
$(OUTDIR)\json.obj \
|
$(OUTDIR)\json.obj \
|
||||||
$(OUTDIR)\list.obj \
|
$(OUTDIR)\list.obj \
|
||||||
|
$(OUTDIR)\locale.obj \
|
||||||
$(OUTDIR)\main.obj \
|
$(OUTDIR)\main.obj \
|
||||||
$(OUTDIR)\map.obj \
|
$(OUTDIR)\map.obj \
|
||||||
$(OUTDIR)\mark.obj \
|
$(OUTDIR)\mark.obj \
|
||||||
@ -1669,6 +1670,8 @@ $(OUTDIR)/json.obj: $(OUTDIR) json.c $(INCL)
|
|||||||
|
|
||||||
$(OUTDIR)/list.obj: $(OUTDIR) list.c $(INCL)
|
$(OUTDIR)/list.obj: $(OUTDIR) list.c $(INCL)
|
||||||
|
|
||||||
|
$(OUTDIR)/locale.obj: $(OUTDIR) locale.c $(INCL)
|
||||||
|
|
||||||
$(OUTDIR)/main.obj: $(OUTDIR) main.c $(INCL) $(CUI_INCL)
|
$(OUTDIR)/main.obj: $(OUTDIR) main.c $(INCL) $(CUI_INCL)
|
||||||
|
|
||||||
$(OUTDIR)/map.obj: $(OUTDIR) map.c $(INCL)
|
$(OUTDIR)/map.obj: $(OUTDIR) map.c $(INCL)
|
||||||
@ -1939,6 +1942,7 @@ proto.h: \
|
|||||||
proto/insexpand.pro \
|
proto/insexpand.pro \
|
||||||
proto/json.pro \
|
proto/json.pro \
|
||||||
proto/list.pro \
|
proto/list.pro \
|
||||||
|
proto/locale.pro \
|
||||||
proto/main.pro \
|
proto/main.pro \
|
||||||
proto/map.pro \
|
proto/map.pro \
|
||||||
proto/mark.pro \
|
proto/mark.pro \
|
||||||
|
@ -345,6 +345,7 @@ SRC = \
|
|||||||
insexpand.c \
|
insexpand.c \
|
||||||
json.c \
|
json.c \
|
||||||
list.c \
|
list.c \
|
||||||
|
locale.c \
|
||||||
main.c \
|
main.c \
|
||||||
map.c \
|
map.c \
|
||||||
mark.c \
|
mark.c \
|
||||||
@ -460,6 +461,7 @@ OBJ = \
|
|||||||
insexpand.obj \
|
insexpand.obj \
|
||||||
json.obj \
|
json.obj \
|
||||||
list.obj \
|
list.obj \
|
||||||
|
locale.obj \
|
||||||
main.obj \
|
main.obj \
|
||||||
map.obj \
|
map.obj \
|
||||||
mark.obj \
|
mark.obj \
|
||||||
@ -865,6 +867,10 @@ list.obj : list.c vim.h [.auto]config.h feature.h os_unix.h \
|
|||||||
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
|
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
|
||||||
beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
|
beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
|
||||||
globals.h
|
globals.h
|
||||||
|
locale.obj : locale.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||||
|
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
|
||||||
|
beval.h [.proto]gui_beval.pro alloc.h ex_cmds.h spell.h proto.h \
|
||||||
|
globals.h
|
||||||
main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h \
|
main.obj : main.c vim.h [.auto]config.h feature.h os_unix.h \
|
||||||
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
|
ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \
|
||||||
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
|
[.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h \
|
||||||
|
10
src/Makefile
10
src/Makefile
@ -1647,6 +1647,7 @@ BASIC_SRC = \
|
|||||||
insexpand.c \
|
insexpand.c \
|
||||||
json.c \
|
json.c \
|
||||||
list.c \
|
list.c \
|
||||||
|
locale.c \
|
||||||
main.c \
|
main.c \
|
||||||
map.c \
|
map.c \
|
||||||
mark.c \
|
mark.c \
|
||||||
@ -1798,6 +1799,7 @@ OBJ_COMMON = \
|
|||||||
objects/indent.o \
|
objects/indent.o \
|
||||||
objects/insexpand.o \
|
objects/insexpand.o \
|
||||||
objects/list.o \
|
objects/list.o \
|
||||||
|
objects/locale.o \
|
||||||
objects/map.o \
|
objects/map.o \
|
||||||
objects/mark.o \
|
objects/mark.o \
|
||||||
objects/match.o \
|
objects/match.o \
|
||||||
@ -1973,6 +1975,7 @@ PRO_AUTO = \
|
|||||||
insexpand.pro \
|
insexpand.pro \
|
||||||
json.pro \
|
json.pro \
|
||||||
list.pro \
|
list.pro \
|
||||||
|
locale.pro \
|
||||||
main.pro \
|
main.pro \
|
||||||
map.pro \
|
map.pro \
|
||||||
mark.pro \
|
mark.pro \
|
||||||
@ -3378,6 +3381,9 @@ objects/kword_test.o: kword_test.c
|
|||||||
objects/list.o: list.c
|
objects/list.o: list.c
|
||||||
$(CCC) -o $@ list.c
|
$(CCC) -o $@ list.c
|
||||||
|
|
||||||
|
objects/locale.o: locale.c
|
||||||
|
$(CCC) -o $@ locale.c
|
||||||
|
|
||||||
objects/main.o: main.c
|
objects/main.o: main.c
|
||||||
$(CCC) -o $@ main.c
|
$(CCC) -o $@ main.c
|
||||||
|
|
||||||
@ -3968,6 +3974,10 @@ objects/list.o: list.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
|||||||
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
||||||
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
||||||
proto.h globals.h
|
proto.h globals.h
|
||||||
|
objects/locale.o: locale.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
||||||
|
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
||||||
|
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
||||||
|
proto.h globals.h
|
||||||
objects/main.o: main.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
objects/main.o: main.c vim.h protodef.h auto/config.h feature.h os_unix.h \
|
||||||
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
|
||||||
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
|
||||||
|
@ -52,6 +52,7 @@ help.c | vim help related functions
|
|||||||
highlight.c | syntax highlighting
|
highlight.c | syntax highlighting
|
||||||
indent.c | text indentation
|
indent.c | text indentation
|
||||||
insexpand.c | Insert mode completion
|
insexpand.c | Insert mode completion
|
||||||
|
locale.c | locale/language handling
|
||||||
map.c | mapping and abbreviations
|
map.c | mapping and abbreviations
|
||||||
mark.c | marks
|
mark.c | marks
|
||||||
match.c | highlight matching
|
match.c | highlight matching
|
||||||
|
502
src/ex_cmds2.c
502
src/ex_cmds2.c
@ -996,505 +996,3 @@ ex_checktime(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
no_check_timestamps = save_no_check_timestamps;
|
no_check_timestamps = save_no_check_timestamps;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
|
||||||
&& (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
|
|
||||||
# define HAVE_GET_LOCALE_VAL
|
|
||||||
static char_u *
|
|
||||||
get_locale_val(int what)
|
|
||||||
{
|
|
||||||
char_u *loc;
|
|
||||||
|
|
||||||
// Obtain the locale value from the libraries.
|
|
||||||
loc = (char_u *)setlocale(what, NULL);
|
|
||||||
|
|
||||||
# ifdef MSWIN
|
|
||||||
if (loc != NULL)
|
|
||||||
{
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
// setocale() returns something like "LC_COLLATE=<name>;LC_..." when
|
|
||||||
// one of the values (e.g., LC_CTYPE) differs.
|
|
||||||
p = vim_strchr(loc, '=');
|
|
||||||
if (p != NULL)
|
|
||||||
{
|
|
||||||
loc = ++p;
|
|
||||||
while (*p != NUL) // remove trailing newline
|
|
||||||
{
|
|
||||||
if (*p < ' ' || *p == ';')
|
|
||||||
{
|
|
||||||
*p = NUL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
return loc;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef MSWIN
|
|
||||||
/*
|
|
||||||
* On MS-Windows locale names are strings like "German_Germany.1252", but
|
|
||||||
* gettext expects "de". Try to translate one into another here for a few
|
|
||||||
* supported languages.
|
|
||||||
*/
|
|
||||||
static char_u *
|
|
||||||
gettext_lang(char_u *name)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
static char *(mtable[]) = {
|
|
||||||
"afrikaans", "af",
|
|
||||||
"czech", "cs",
|
|
||||||
"dutch", "nl",
|
|
||||||
"german", "de",
|
|
||||||
"english_united kingdom", "en_GB",
|
|
||||||
"spanish", "es",
|
|
||||||
"french", "fr",
|
|
||||||
"italian", "it",
|
|
||||||
"japanese", "ja",
|
|
||||||
"korean", "ko",
|
|
||||||
"norwegian", "no",
|
|
||||||
"polish", "pl",
|
|
||||||
"russian", "ru",
|
|
||||||
"slovak", "sk",
|
|
||||||
"swedish", "sv",
|
|
||||||
"ukrainian", "uk",
|
|
||||||
"chinese_china", "zh_CN",
|
|
||||||
"chinese_taiwan", "zh_TW",
|
|
||||||
NULL};
|
|
||||||
|
|
||||||
for (i = 0; mtable[i] != NULL; i += 2)
|
|
||||||
if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
|
|
||||||
return (char_u *)mtable[i + 1];
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(FEAT_MULTI_LANG) || defined(PROTO)
|
|
||||||
/*
|
|
||||||
* Return TRUE when "lang" starts with a valid language name.
|
|
||||||
* Rejects NULL, empty string, "C", "C.UTF-8" and others.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
is_valid_mess_lang(char_u *lang)
|
|
||||||
{
|
|
||||||
return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Obtain the current messages language. Used to set the default for
|
|
||||||
* 'helplang'. May return NULL or an empty string.
|
|
||||||
*/
|
|
||||||
char_u *
|
|
||||||
get_mess_lang(void)
|
|
||||||
{
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
# ifdef HAVE_GET_LOCALE_VAL
|
|
||||||
# if defined(LC_MESSAGES)
|
|
||||||
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);
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
p = mch_getenv((char_u *)"LC_ALL");
|
|
||||||
if (!is_valid_mess_lang(p))
|
|
||||||
{
|
|
||||||
p = mch_getenv((char_u *)"LC_MESSAGES");
|
|
||||||
if (!is_valid_mess_lang(p))
|
|
||||||
p = mch_getenv((char_u *)"LANG");
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
# ifdef MSWIN
|
|
||||||
p = gettext_lang(p);
|
|
||||||
# endif
|
|
||||||
return is_valid_mess_lang(p) ? p : NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Complicated #if; matches with where get_mess_env() is used below.
|
|
||||||
#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
|
||||||
&& defined(LC_MESSAGES))) \
|
|
||||||
|| ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
|
||||||
&& !defined(LC_MESSAGES))
|
|
||||||
/*
|
|
||||||
* Get the language used for messages from the environment.
|
|
||||||
*/
|
|
||||||
static char_u *
|
|
||||||
get_mess_env(void)
|
|
||||||
{
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
p = mch_getenv((char_u *)"LC_ALL");
|
|
||||||
if (p == NULL || *p == NUL)
|
|
||||||
{
|
|
||||||
p = mch_getenv((char_u *)"LC_MESSAGES");
|
|
||||||
if (p == NULL || *p == NUL)
|
|
||||||
{
|
|
||||||
p = mch_getenv((char_u *)"LANG");
|
|
||||||
if (p != NULL && VIM_ISDIGIT(*p))
|
|
||||||
p = NULL; // ignore something like "1043"
|
|
||||||
# ifdef HAVE_GET_LOCALE_VAL
|
|
||||||
if (p == NULL || *p == NUL)
|
|
||||||
p = get_locale_val(LC_CTYPE);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(FEAT_EVAL) || defined(PROTO)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set the "v:lang" variable according to the current locale setting.
|
|
||||||
* Also do "v:lc_time"and "v:ctype".
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
set_lang_var(void)
|
|
||||||
{
|
|
||||||
char_u *loc;
|
|
||||||
|
|
||||||
# ifdef HAVE_GET_LOCALE_VAL
|
|
||||||
loc = get_locale_val(LC_CTYPE);
|
|
||||||
# else
|
|
||||||
// setlocale() not supported: use the default value
|
|
||||||
loc = (char_u *)"C";
|
|
||||||
# endif
|
|
||||||
set_vim_var_string(VV_CTYPE, loc, -1);
|
|
||||||
|
|
||||||
// When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
|
|
||||||
// back to LC_CTYPE if it's empty.
|
|
||||||
# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
|
|
||||||
loc = get_locale_val(LC_MESSAGES);
|
|
||||||
# else
|
|
||||||
loc = get_mess_env();
|
|
||||||
# endif
|
|
||||||
set_vim_var_string(VV_LANG, loc, -1);
|
|
||||||
|
|
||||||
# ifdef HAVE_GET_LOCALE_VAL
|
|
||||||
loc = get_locale_val(LC_TIME);
|
|
||||||
# endif
|
|
||||||
set_vim_var_string(VV_LC_TIME, loc, -1);
|
|
||||||
|
|
||||||
# ifdef HAVE_GET_LOCALE_VAL
|
|
||||||
loc = get_locale_val(LC_COLLATE);
|
|
||||||
# else
|
|
||||||
// setlocale() not supported: use the default value
|
|
||||||
loc = (char_u *)"C";
|
|
||||||
# endif
|
|
||||||
set_vim_var_string(VV_COLLATE, loc, -1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
|
|
||||||
/*
|
|
||||||
* ":language": Set the language (locale).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ex_language(exarg_T *eap)
|
|
||||||
{
|
|
||||||
char *loc;
|
|
||||||
char_u *p;
|
|
||||||
char_u *name;
|
|
||||||
int what = LC_ALL;
|
|
||||||
char *whatstr = "";
|
|
||||||
# ifdef LC_MESSAGES
|
|
||||||
# define VIM_LC_MESSAGES LC_MESSAGES
|
|
||||||
# else
|
|
||||||
# define VIM_LC_MESSAGES 6789
|
|
||||||
# endif
|
|
||||||
|
|
||||||
name = eap->arg;
|
|
||||||
|
|
||||||
// Check for "messages {name}", "ctype {name}" or "time {name}" argument.
|
|
||||||
// Allow abbreviation, but require at least 3 characters to avoid
|
|
||||||
// confusion with a two letter language name "me" or "ct".
|
|
||||||
p = skiptowhite(eap->arg);
|
|
||||||
if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
|
|
||||||
{
|
|
||||||
if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
|
|
||||||
{
|
|
||||||
what = VIM_LC_MESSAGES;
|
|
||||||
name = skipwhite(p);
|
|
||||||
whatstr = "messages ";
|
|
||||||
}
|
|
||||||
else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
|
|
||||||
{
|
|
||||||
what = LC_CTYPE;
|
|
||||||
name = skipwhite(p);
|
|
||||||
whatstr = "ctype ";
|
|
||||||
}
|
|
||||||
else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
|
|
||||||
{
|
|
||||||
what = LC_TIME;
|
|
||||||
name = skipwhite(p);
|
|
||||||
whatstr = "time ";
|
|
||||||
}
|
|
||||||
else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0)
|
|
||||||
{
|
|
||||||
what = LC_COLLATE;
|
|
||||||
name = skipwhite(p);
|
|
||||||
whatstr = "collate ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*name == NUL)
|
|
||||||
{
|
|
||||||
# ifndef LC_MESSAGES
|
|
||||||
if (what == VIM_LC_MESSAGES)
|
|
||||||
p = get_mess_env();
|
|
||||||
else
|
|
||||||
# endif
|
|
||||||
p = (char_u *)setlocale(what, NULL);
|
|
||||||
if (p == NULL || *p == NUL)
|
|
||||||
p = (char_u *)"Unknown";
|
|
||||||
smsg(_("Current %slanguage: \"%s\""), whatstr, p);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
# ifndef LC_MESSAGES
|
|
||||||
if (what == VIM_LC_MESSAGES)
|
|
||||||
loc = "";
|
|
||||||
else
|
|
||||||
# endif
|
|
||||||
{
|
|
||||||
loc = setlocale(what, (char *)name);
|
|
||||||
# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
|
|
||||||
// Make sure strtod() uses a decimal point, not a comma.
|
|
||||||
setlocale(LC_NUMERIC, "C");
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
if (loc == NULL)
|
|
||||||
semsg(_("E197: Cannot set language to \"%s\""), name);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
# ifdef HAVE_NL_MSG_CAT_CNTR
|
|
||||||
// Need to do this for GNU gettext, otherwise cached translations
|
|
||||||
// will be used again.
|
|
||||||
extern int _nl_msg_cat_cntr;
|
|
||||||
|
|
||||||
++_nl_msg_cat_cntr;
|
|
||||||
# endif
|
|
||||||
// Reset $LC_ALL, otherwise it would overrule everything.
|
|
||||||
vim_setenv((char_u *)"LC_ALL", (char_u *)"");
|
|
||||||
|
|
||||||
if (what != LC_TIME && what != LC_COLLATE)
|
|
||||||
{
|
|
||||||
// Tell gettext() what to translate to. It apparently doesn't
|
|
||||||
// use the currently effective locale. Also do this when
|
|
||||||
// FEAT_GETTEXT isn't defined, so that shell commands use this
|
|
||||||
// value.
|
|
||||||
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
|
|
||||||
// current locale. This call avoids that.
|
|
||||||
setlocale(LC_CTYPE, "C");
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
if (what != LC_CTYPE)
|
|
||||||
{
|
|
||||||
char_u *mname;
|
|
||||||
# ifdef MSWIN
|
|
||||||
mname = gettext_lang(name);
|
|
||||||
# else
|
|
||||||
mname = name;
|
|
||||||
# endif
|
|
||||||
vim_setenv((char_u *)"LC_MESSAGES", mname);
|
|
||||||
# ifdef FEAT_MULTI_LANG
|
|
||||||
set_helplang_default(mname);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef FEAT_EVAL
|
|
||||||
// Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
|
|
||||||
set_lang_var();
|
|
||||||
# endif
|
|
||||||
# ifdef FEAT_TITLE
|
|
||||||
maketitle();
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char_u **locales = NULL; // Array of all available locales
|
|
||||||
|
|
||||||
static int did_init_locales = FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return an array of strings for all available locales + NULL for the
|
|
||||||
* last element. Return NULL in case of error.
|
|
||||||
*/
|
|
||||||
static char_u **
|
|
||||||
find_locales(void)
|
|
||||||
{
|
|
||||||
garray_T locales_ga;
|
|
||||||
char_u *loc;
|
|
||||||
char_u *locale_list;
|
|
||||||
# ifdef MSWIN
|
|
||||||
size_t len = 0;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Find all available locales by running command "locale -a". If this
|
|
||||||
// doesn't work we won't have completion.
|
|
||||||
# ifndef MSWIN
|
|
||||||
locale_list = get_cmd_output((char_u *)"locale -a",
|
|
||||||
NULL, SHELL_SILENT, NULL);
|
|
||||||
# else
|
|
||||||
// Find all available locales by examining the directories in
|
|
||||||
// $VIMRUNTIME/lang/
|
|
||||||
{
|
|
||||||
int options = WILD_SILENT|WILD_USE_NL|WILD_KEEP_ALL;
|
|
||||||
expand_T xpc;
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
ExpandInit(&xpc);
|
|
||||||
xpc.xp_context = EXPAND_DIRECTORIES;
|
|
||||||
locale_list = ExpandOne(&xpc, (char_u *)"$VIMRUNTIME/lang/*",
|
|
||||||
NULL, options, WILD_ALL);
|
|
||||||
ExpandCleanup(&xpc);
|
|
||||||
if (locale_list == NULL)
|
|
||||||
// Add a dummy input, that will be skipped lated but we need to
|
|
||||||
// have something in locale_list so that the C locale is added at
|
|
||||||
// the end.
|
|
||||||
locale_list = vim_strsave((char_u *)".\n");
|
|
||||||
p = locale_list;
|
|
||||||
// find the last directory delimiter
|
|
||||||
while (p != NULL && *p != NUL)
|
|
||||||
{
|
|
||||||
if (*p == '\n')
|
|
||||||
break;
|
|
||||||
if (*p == '\\')
|
|
||||||
len = p - locale_list;
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
if (locale_list == NULL)
|
|
||||||
return NULL;
|
|
||||||
ga_init2(&locales_ga, sizeof(char_u *), 20);
|
|
||||||
|
|
||||||
// Transform locale_list string where each locale is separated by "\n"
|
|
||||||
// into an array of locale strings.
|
|
||||||
loc = (char_u *)strtok((char *)locale_list, "\n");
|
|
||||||
|
|
||||||
while (loc != NULL)
|
|
||||||
{
|
|
||||||
int ignore = FALSE;
|
|
||||||
|
|
||||||
# ifdef MSWIN
|
|
||||||
if (len > 0)
|
|
||||||
loc += len + 1;
|
|
||||||
// skip locales with a dot (which indicates the charset)
|
|
||||||
if (vim_strchr(loc, '.') != NULL)
|
|
||||||
ignore = TRUE;
|
|
||||||
# endif
|
|
||||||
if (!ignore)
|
|
||||||
{
|
|
||||||
if (ga_grow(&locales_ga, 1) == FAIL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
loc = vim_strsave(loc);
|
|
||||||
if (loc == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
|
|
||||||
}
|
|
||||||
loc = (char_u *)strtok(NULL, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef MSWIN
|
|
||||||
// Add the C locale
|
|
||||||
if (ga_grow(&locales_ga, 1) == OK)
|
|
||||||
((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] =
|
|
||||||
vim_strsave((char_u *)"C");
|
|
||||||
# endif
|
|
||||||
|
|
||||||
vim_free(locale_list);
|
|
||||||
if (ga_grow(&locales_ga, 1) == FAIL)
|
|
||||||
{
|
|
||||||
ga_clear(&locales_ga);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
|
|
||||||
return (char_u **)locales_ga.ga_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Lazy initialization of all available locales.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
init_locales(void)
|
|
||||||
{
|
|
||||||
if (!did_init_locales)
|
|
||||||
{
|
|
||||||
did_init_locales = TRUE;
|
|
||||||
locales = find_locales();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# if defined(EXITFREE) || defined(PROTO)
|
|
||||||
void
|
|
||||||
free_locales(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (locales != NULL)
|
|
||||||
{
|
|
||||||
for (i = 0; locales[i] != NULL; i++)
|
|
||||||
vim_free(locales[i]);
|
|
||||||
VIM_CLEAR(locales);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function given to ExpandGeneric() to obtain the possible arguments of the
|
|
||||||
* ":language" command.
|
|
||||||
*/
|
|
||||||
char_u *
|
|
||||||
get_lang_arg(expand_T *xp UNUSED, int idx)
|
|
||||||
{
|
|
||||||
if (idx == 0)
|
|
||||||
return (char_u *)"messages";
|
|
||||||
if (idx == 1)
|
|
||||||
return (char_u *)"ctype";
|
|
||||||
if (idx == 2)
|
|
||||||
return (char_u *)"time";
|
|
||||||
if (idx == 3)
|
|
||||||
return (char_u *)"collate";
|
|
||||||
|
|
||||||
init_locales();
|
|
||||||
if (locales == NULL)
|
|
||||||
return NULL;
|
|
||||||
return locales[idx - 4];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function given to ExpandGeneric() to obtain the available locales.
|
|
||||||
*/
|
|
||||||
char_u *
|
|
||||||
get_locales(expand_T *xp UNUSED, int idx)
|
|
||||||
{
|
|
||||||
init_locales();
|
|
||||||
if (locales == NULL)
|
|
||||||
return NULL;
|
|
||||||
return locales[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
564
src/locale.c
Normal file
564
src/locale.c
Normal file
@ -0,0 +1,564 @@
|
|||||||
|
/* vi:set ts=8 sts=4 sw=4 noet:
|
||||||
|
*
|
||||||
|
* VIM - Vi IMproved by Bram Moolenaar
|
||||||
|
*
|
||||||
|
* Do ":help uganda" in Vim to read copying and usage conditions.
|
||||||
|
* Do ":help credits" in Vim to see a list of people who contributed.
|
||||||
|
* See README.txt for an overview of the Vim source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* locale.c: functions for language/locale configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vim.h"
|
||||||
|
|
||||||
|
#if (defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
||||||
|
&& (defined(FEAT_EVAL) || defined(FEAT_MULTI_LANG))
|
||||||
|
# define HAVE_GET_LOCALE_VAL
|
||||||
|
static char_u *
|
||||||
|
get_locale_val(int what)
|
||||||
|
{
|
||||||
|
char_u *loc;
|
||||||
|
|
||||||
|
// Obtain the locale value from the libraries.
|
||||||
|
loc = (char_u *)setlocale(what, NULL);
|
||||||
|
|
||||||
|
# ifdef MSWIN
|
||||||
|
if (loc != NULL)
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
// setocale() returns something like "LC_COLLATE=<name>;LC_..." when
|
||||||
|
// one of the values (e.g., LC_CTYPE) differs.
|
||||||
|
p = vim_strchr(loc, '=');
|
||||||
|
if (p != NULL)
|
||||||
|
{
|
||||||
|
loc = ++p;
|
||||||
|
while (*p != NUL) // remove trailing newline
|
||||||
|
{
|
||||||
|
if (*p < ' ' || *p == ';')
|
||||||
|
{
|
||||||
|
*p = NUL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MSWIN
|
||||||
|
/*
|
||||||
|
* On MS-Windows locale names are strings like "German_Germany.1252", but
|
||||||
|
* gettext expects "de". Try to translate one into another here for a few
|
||||||
|
* supported languages.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
gettext_lang(char_u *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static char *(mtable[]) = {
|
||||||
|
"afrikaans", "af",
|
||||||
|
"czech", "cs",
|
||||||
|
"dutch", "nl",
|
||||||
|
"german", "de",
|
||||||
|
"english_united kingdom", "en_GB",
|
||||||
|
"spanish", "es",
|
||||||
|
"french", "fr",
|
||||||
|
"italian", "it",
|
||||||
|
"japanese", "ja",
|
||||||
|
"korean", "ko",
|
||||||
|
"norwegian", "no",
|
||||||
|
"polish", "pl",
|
||||||
|
"russian", "ru",
|
||||||
|
"slovak", "sk",
|
||||||
|
"swedish", "sv",
|
||||||
|
"ukrainian", "uk",
|
||||||
|
"chinese_china", "zh_CN",
|
||||||
|
"chinese_taiwan", "zh_TW",
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
for (i = 0; mtable[i] != NULL; i += 2)
|
||||||
|
if (STRNICMP(mtable[i], name, STRLEN(mtable[i])) == 0)
|
||||||
|
return (char_u *)mtable[i + 1];
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(FEAT_MULTI_LANG) || defined(PROTO)
|
||||||
|
/*
|
||||||
|
* Return TRUE when "lang" starts with a valid language name.
|
||||||
|
* Rejects NULL, empty string, "C", "C.UTF-8" and others.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
is_valid_mess_lang(char_u *lang)
|
||||||
|
{
|
||||||
|
return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Obtain the current messages language. Used to set the default for
|
||||||
|
* 'helplang'. May return NULL or an empty string.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
get_mess_lang(void)
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
# ifdef HAVE_GET_LOCALE_VAL
|
||||||
|
# if defined(LC_MESSAGES)
|
||||||
|
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);
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
p = mch_getenv((char_u *)"LC_ALL");
|
||||||
|
if (!is_valid_mess_lang(p))
|
||||||
|
{
|
||||||
|
p = mch_getenv((char_u *)"LC_MESSAGES");
|
||||||
|
if (!is_valid_mess_lang(p))
|
||||||
|
p = mch_getenv((char_u *)"LANG");
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
# ifdef MSWIN
|
||||||
|
p = gettext_lang(p);
|
||||||
|
# endif
|
||||||
|
return is_valid_mess_lang(p) ? p : NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Complicated #if; matches with where get_mess_env() is used below.
|
||||||
|
#if (defined(FEAT_EVAL) && !((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
||||||
|
&& defined(LC_MESSAGES))) \
|
||||||
|
|| ((defined(HAVE_LOCALE_H) || defined(X_LOCALE)) \
|
||||||
|
&& !defined(LC_MESSAGES))
|
||||||
|
/*
|
||||||
|
* Get the language used for messages from the environment.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
get_mess_env(void)
|
||||||
|
{
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
p = mch_getenv((char_u *)"LC_ALL");
|
||||||
|
if (p == NULL || *p == NUL)
|
||||||
|
{
|
||||||
|
p = mch_getenv((char_u *)"LC_MESSAGES");
|
||||||
|
if (p == NULL || *p == NUL)
|
||||||
|
{
|
||||||
|
p = mch_getenv((char_u *)"LANG");
|
||||||
|
if (p != NULL && VIM_ISDIGIT(*p))
|
||||||
|
p = NULL; // ignore something like "1043"
|
||||||
|
# ifdef HAVE_GET_LOCALE_VAL
|
||||||
|
if (p == NULL || *p == NUL)
|
||||||
|
p = get_locale_val(LC_CTYPE);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(FEAT_EVAL) || defined(PROTO)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the "v:lang" variable according to the current locale setting.
|
||||||
|
* Also do "v:lc_time"and "v:ctype".
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
set_lang_var(void)
|
||||||
|
{
|
||||||
|
char_u *loc;
|
||||||
|
|
||||||
|
# ifdef HAVE_GET_LOCALE_VAL
|
||||||
|
loc = get_locale_val(LC_CTYPE);
|
||||||
|
# else
|
||||||
|
// setlocale() not supported: use the default value
|
||||||
|
loc = (char_u *)"C";
|
||||||
|
# endif
|
||||||
|
set_vim_var_string(VV_CTYPE, loc, -1);
|
||||||
|
|
||||||
|
// When LC_MESSAGES isn't defined use the value from $LC_MESSAGES, fall
|
||||||
|
// back to LC_CTYPE if it's empty.
|
||||||
|
# if defined(HAVE_GET_LOCALE_VAL) && defined(LC_MESSAGES)
|
||||||
|
loc = get_locale_val(LC_MESSAGES);
|
||||||
|
# else
|
||||||
|
loc = get_mess_env();
|
||||||
|
# endif
|
||||||
|
set_vim_var_string(VV_LANG, loc, -1);
|
||||||
|
|
||||||
|
# ifdef HAVE_GET_LOCALE_VAL
|
||||||
|
loc = get_locale_val(LC_TIME);
|
||||||
|
# endif
|
||||||
|
set_vim_var_string(VV_LC_TIME, loc, -1);
|
||||||
|
|
||||||
|
# ifdef HAVE_GET_LOCALE_VAL
|
||||||
|
loc = get_locale_val(LC_COLLATE);
|
||||||
|
# else
|
||||||
|
// setlocale() not supported: use the default value
|
||||||
|
loc = (char_u *)"C";
|
||||||
|
# endif
|
||||||
|
set_vim_var_string(VV_COLLATE, loc, -1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
|
||||||
|
/*
|
||||||
|
* Setup to use the current locale (for ctype() and many other things).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
init_locale(void)
|
||||||
|
{
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
|
||||||
|
# ifdef FEAT_GUI_GTK
|
||||||
|
// Tell Gtk not to change our locale settings.
|
||||||
|
gtk_disable_setlocale();
|
||||||
|
# endif
|
||||||
|
# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
|
||||||
|
// Make sure strtod() uses a decimal point, not a comma.
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef MSWIN
|
||||||
|
// Apparently MS-Windows printf() may cause a crash when we give it 8-bit
|
||||||
|
// text while it's expecting text in the current locale. This call avoids
|
||||||
|
// that.
|
||||||
|
setlocale(LC_CTYPE, "C");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef FEAT_GETTEXT
|
||||||
|
{
|
||||||
|
int mustfree = FALSE;
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
# ifdef DYNAMIC_GETTEXT
|
||||||
|
// Initialize the gettext library
|
||||||
|
dyn_libintl_init();
|
||||||
|
# endif
|
||||||
|
// expand_env() doesn't work yet, because g_chartab[] is not
|
||||||
|
// initialized yet, call vim_getenv() directly
|
||||||
|
p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
|
||||||
|
if (p != NULL && *p != NUL)
|
||||||
|
{
|
||||||
|
vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
|
||||||
|
bindtextdomain(VIMPACKAGE, (char *)NameBuff);
|
||||||
|
}
|
||||||
|
if (mustfree)
|
||||||
|
vim_free(p);
|
||||||
|
textdomain(VIMPACKAGE);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ":language": Set the language (locale).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ex_language(exarg_T *eap)
|
||||||
|
{
|
||||||
|
char *loc;
|
||||||
|
char_u *p;
|
||||||
|
char_u *name;
|
||||||
|
int what = LC_ALL;
|
||||||
|
char *whatstr = "";
|
||||||
|
# ifdef LC_MESSAGES
|
||||||
|
# define VIM_LC_MESSAGES LC_MESSAGES
|
||||||
|
# else
|
||||||
|
# define VIM_LC_MESSAGES 6789
|
||||||
|
# endif
|
||||||
|
|
||||||
|
name = eap->arg;
|
||||||
|
|
||||||
|
// Check for "messages {name}", "ctype {name}" or "time {name}" argument.
|
||||||
|
// Allow abbreviation, but require at least 3 characters to avoid
|
||||||
|
// confusion with a two letter language name "me" or "ct".
|
||||||
|
p = skiptowhite(eap->arg);
|
||||||
|
if ((*p == NUL || VIM_ISWHITE(*p)) && p - eap->arg >= 3)
|
||||||
|
{
|
||||||
|
if (STRNICMP(eap->arg, "messages", p - eap->arg) == 0)
|
||||||
|
{
|
||||||
|
what = VIM_LC_MESSAGES;
|
||||||
|
name = skipwhite(p);
|
||||||
|
whatstr = "messages ";
|
||||||
|
}
|
||||||
|
else if (STRNICMP(eap->arg, "ctype", p - eap->arg) == 0)
|
||||||
|
{
|
||||||
|
what = LC_CTYPE;
|
||||||
|
name = skipwhite(p);
|
||||||
|
whatstr = "ctype ";
|
||||||
|
}
|
||||||
|
else if (STRNICMP(eap->arg, "time", p - eap->arg) == 0)
|
||||||
|
{
|
||||||
|
what = LC_TIME;
|
||||||
|
name = skipwhite(p);
|
||||||
|
whatstr = "time ";
|
||||||
|
}
|
||||||
|
else if (STRNICMP(eap->arg, "collate", p - eap->arg) == 0)
|
||||||
|
{
|
||||||
|
what = LC_COLLATE;
|
||||||
|
name = skipwhite(p);
|
||||||
|
whatstr = "collate ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*name == NUL)
|
||||||
|
{
|
||||||
|
# ifndef LC_MESSAGES
|
||||||
|
if (what == VIM_LC_MESSAGES)
|
||||||
|
p = get_mess_env();
|
||||||
|
else
|
||||||
|
# endif
|
||||||
|
p = (char_u *)setlocale(what, NULL);
|
||||||
|
if (p == NULL || *p == NUL)
|
||||||
|
p = (char_u *)"Unknown";
|
||||||
|
smsg(_("Current %slanguage: \"%s\""), whatstr, p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# ifndef LC_MESSAGES
|
||||||
|
if (what == VIM_LC_MESSAGES)
|
||||||
|
loc = "";
|
||||||
|
else
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
loc = setlocale(what, (char *)name);
|
||||||
|
# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
|
||||||
|
// Make sure strtod() uses a decimal point, not a comma.
|
||||||
|
setlocale(LC_NUMERIC, "C");
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
if (loc == NULL)
|
||||||
|
semsg(_("E197: Cannot set language to \"%s\""), name);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# ifdef HAVE_NL_MSG_CAT_CNTR
|
||||||
|
// Need to do this for GNU gettext, otherwise cached translations
|
||||||
|
// will be used again.
|
||||||
|
extern int _nl_msg_cat_cntr;
|
||||||
|
|
||||||
|
++_nl_msg_cat_cntr;
|
||||||
|
# endif
|
||||||
|
// Reset $LC_ALL, otherwise it would overrule everything.
|
||||||
|
vim_setenv((char_u *)"LC_ALL", (char_u *)"");
|
||||||
|
|
||||||
|
if (what != LC_TIME && what != LC_COLLATE)
|
||||||
|
{
|
||||||
|
// Tell gettext() what to translate to. It apparently doesn't
|
||||||
|
// use the currently effective locale. Also do this when
|
||||||
|
// FEAT_GETTEXT isn't defined, so that shell commands use this
|
||||||
|
// value.
|
||||||
|
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
|
||||||
|
// current locale. This call avoids that.
|
||||||
|
setlocale(LC_CTYPE, "C");
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
if (what != LC_CTYPE)
|
||||||
|
{
|
||||||
|
char_u *mname;
|
||||||
|
# ifdef MSWIN
|
||||||
|
mname = gettext_lang(name);
|
||||||
|
# else
|
||||||
|
mname = name;
|
||||||
|
# endif
|
||||||
|
vim_setenv((char_u *)"LC_MESSAGES", mname);
|
||||||
|
# ifdef FEAT_MULTI_LANG
|
||||||
|
set_helplang_default(mname);
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef FEAT_EVAL
|
||||||
|
// Set v:lang, v:lc_time, v:collate and v:ctype to the final result.
|
||||||
|
set_lang_var();
|
||||||
|
# endif
|
||||||
|
# ifdef FEAT_TITLE
|
||||||
|
maketitle();
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char_u **locales = NULL; // Array of all available locales
|
||||||
|
|
||||||
|
static int did_init_locales = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return an array of strings for all available locales + NULL for the
|
||||||
|
* last element. Return NULL in case of error.
|
||||||
|
*/
|
||||||
|
static char_u **
|
||||||
|
find_locales(void)
|
||||||
|
{
|
||||||
|
garray_T locales_ga;
|
||||||
|
char_u *loc;
|
||||||
|
char_u *locale_list;
|
||||||
|
# ifdef MSWIN
|
||||||
|
size_t len = 0;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Find all available locales by running command "locale -a". If this
|
||||||
|
// doesn't work we won't have completion.
|
||||||
|
# ifndef MSWIN
|
||||||
|
locale_list = get_cmd_output((char_u *)"locale -a",
|
||||||
|
NULL, SHELL_SILENT, NULL);
|
||||||
|
# else
|
||||||
|
// Find all available locales by examining the directories in
|
||||||
|
// $VIMRUNTIME/lang/
|
||||||
|
{
|
||||||
|
int options = WILD_SILENT|WILD_USE_NL|WILD_KEEP_ALL;
|
||||||
|
expand_T xpc;
|
||||||
|
char_u *p;
|
||||||
|
|
||||||
|
ExpandInit(&xpc);
|
||||||
|
xpc.xp_context = EXPAND_DIRECTORIES;
|
||||||
|
locale_list = ExpandOne(&xpc, (char_u *)"$VIMRUNTIME/lang/*",
|
||||||
|
NULL, options, WILD_ALL);
|
||||||
|
ExpandCleanup(&xpc);
|
||||||
|
if (locale_list == NULL)
|
||||||
|
// Add a dummy input, that will be skipped lated but we need to
|
||||||
|
// have something in locale_list so that the C locale is added at
|
||||||
|
// the end.
|
||||||
|
locale_list = vim_strsave((char_u *)".\n");
|
||||||
|
p = locale_list;
|
||||||
|
// find the last directory delimiter
|
||||||
|
while (p != NULL && *p != NUL)
|
||||||
|
{
|
||||||
|
if (*p == '\n')
|
||||||
|
break;
|
||||||
|
if (*p == '\\')
|
||||||
|
len = p - locale_list;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
if (locale_list == NULL)
|
||||||
|
return NULL;
|
||||||
|
ga_init2(&locales_ga, sizeof(char_u *), 20);
|
||||||
|
|
||||||
|
// Transform locale_list string where each locale is separated by "\n"
|
||||||
|
// into an array of locale strings.
|
||||||
|
loc = (char_u *)strtok((char *)locale_list, "\n");
|
||||||
|
|
||||||
|
while (loc != NULL)
|
||||||
|
{
|
||||||
|
int ignore = FALSE;
|
||||||
|
|
||||||
|
# ifdef MSWIN
|
||||||
|
if (len > 0)
|
||||||
|
loc += len + 1;
|
||||||
|
// skip locales with a dot (which indicates the charset)
|
||||||
|
if (vim_strchr(loc, '.') != NULL)
|
||||||
|
ignore = TRUE;
|
||||||
|
# endif
|
||||||
|
if (!ignore)
|
||||||
|
{
|
||||||
|
if (ga_grow(&locales_ga, 1) == FAIL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
loc = vim_strsave(loc);
|
||||||
|
if (loc == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] = loc;
|
||||||
|
}
|
||||||
|
loc = (char_u *)strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef MSWIN
|
||||||
|
// Add the C locale
|
||||||
|
if (ga_grow(&locales_ga, 1) == OK)
|
||||||
|
((char_u **)locales_ga.ga_data)[locales_ga.ga_len++] =
|
||||||
|
vim_strsave((char_u *)"C");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
vim_free(locale_list);
|
||||||
|
if (ga_grow(&locales_ga, 1) == FAIL)
|
||||||
|
{
|
||||||
|
ga_clear(&locales_ga);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
((char_u **)locales_ga.ga_data)[locales_ga.ga_len] = NULL;
|
||||||
|
return (char_u **)locales_ga.ga_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lazy initialization of all available locales.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
init_locales(void)
|
||||||
|
{
|
||||||
|
if (!did_init_locales)
|
||||||
|
{
|
||||||
|
did_init_locales = TRUE;
|
||||||
|
locales = find_locales();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# if defined(EXITFREE) || defined(PROTO)
|
||||||
|
void
|
||||||
|
free_locales(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (locales != NULL)
|
||||||
|
{
|
||||||
|
for (i = 0; locales[i] != NULL; i++)
|
||||||
|
vim_free(locales[i]);
|
||||||
|
VIM_CLEAR(locales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function given to ExpandGeneric() to obtain the possible arguments of the
|
||||||
|
* ":language" command.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
get_lang_arg(expand_T *xp UNUSED, int idx)
|
||||||
|
{
|
||||||
|
if (idx == 0)
|
||||||
|
return (char_u *)"messages";
|
||||||
|
if (idx == 1)
|
||||||
|
return (char_u *)"ctype";
|
||||||
|
if (idx == 2)
|
||||||
|
return (char_u *)"time";
|
||||||
|
if (idx == 3)
|
||||||
|
return (char_u *)"collate";
|
||||||
|
|
||||||
|
init_locales();
|
||||||
|
if (locales == NULL)
|
||||||
|
return NULL;
|
||||||
|
return locales[idx - 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function given to ExpandGeneric() to obtain the available locales.
|
||||||
|
*/
|
||||||
|
char_u *
|
||||||
|
get_locales(expand_T *xp UNUSED, int idx)
|
||||||
|
{
|
||||||
|
init_locales();
|
||||||
|
if (locales == NULL)
|
||||||
|
return NULL;
|
||||||
|
return locales[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
53
src/main.c
53
src/main.c
@ -34,9 +34,6 @@
|
|||||||
static int file_owned(char *fname);
|
static int file_owned(char *fname);
|
||||||
#endif
|
#endif
|
||||||
static void mainerr(int, char_u *);
|
static void mainerr(int, char_u *);
|
||||||
# if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
|
|
||||||
static void init_locale(void);
|
|
||||||
# endif
|
|
||||||
static void early_arg_scan(mparm_T *parmp);
|
static void early_arg_scan(mparm_T *parmp);
|
||||||
#ifndef NO_VIM_MAIN
|
#ifndef NO_VIM_MAIN
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
@ -1716,56 +1713,6 @@ getout(int exitval)
|
|||||||
mch_exit(exitval);
|
mch_exit(exitval);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
|
|
||||||
/*
|
|
||||||
* Setup to use the current locale (for ctype() and many other things).
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
init_locale(void)
|
|
||||||
{
|
|
||||||
setlocale(LC_ALL, "");
|
|
||||||
|
|
||||||
# ifdef FEAT_GUI_GTK
|
|
||||||
// Tell Gtk not to change our locale settings.
|
|
||||||
gtk_disable_setlocale();
|
|
||||||
# endif
|
|
||||||
# if defined(FEAT_FLOAT) && defined(LC_NUMERIC)
|
|
||||||
// Make sure strtod() uses a decimal point, not a comma.
|
|
||||||
setlocale(LC_NUMERIC, "C");
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef MSWIN
|
|
||||||
// Apparently MS-Windows printf() may cause a crash when we give it 8-bit
|
|
||||||
// text while it's expecting text in the current locale. This call avoids
|
|
||||||
// that.
|
|
||||||
setlocale(LC_CTYPE, "C");
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef FEAT_GETTEXT
|
|
||||||
{
|
|
||||||
int mustfree = FALSE;
|
|
||||||
char_u *p;
|
|
||||||
|
|
||||||
# ifdef DYNAMIC_GETTEXT
|
|
||||||
// Initialize the gettext library
|
|
||||||
dyn_libintl_init();
|
|
||||||
# endif
|
|
||||||
// expand_env() doesn't work yet, because g_chartab[] is not
|
|
||||||
// initialized yet, call vim_getenv() directly
|
|
||||||
p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
|
|
||||||
if (p != NULL && *p != NUL)
|
|
||||||
{
|
|
||||||
vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
|
|
||||||
bindtextdomain(VIMPACKAGE, (char *)NameBuff);
|
|
||||||
}
|
|
||||||
if (mustfree)
|
|
||||||
vim_free(p);
|
|
||||||
textdomain(VIMPACKAGE);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the name of the display, before gui_prepare() removes it from
|
* Get the name of the display, before gui_prepare() removes it from
|
||||||
* argv[]. Used for the xterm-clipboard display.
|
* argv[]. Used for the xterm-clipboard display.
|
||||||
|
@ -101,6 +101,7 @@ extern int _stricoll(char *a, char *b);
|
|||||||
# include "insexpand.pro"
|
# include "insexpand.pro"
|
||||||
# include "json.pro"
|
# include "json.pro"
|
||||||
# include "list.pro"
|
# include "list.pro"
|
||||||
|
# include "locale.pro"
|
||||||
# include "blob.pro"
|
# include "blob.pro"
|
||||||
# include "main.pro"
|
# include "main.pro"
|
||||||
# include "map.pro"
|
# include "map.pro"
|
||||||
|
@ -15,10 +15,4 @@ void ex_pyxfile(exarg_T *eap);
|
|||||||
void ex_pyx(exarg_T *eap);
|
void ex_pyx(exarg_T *eap);
|
||||||
void ex_pyxdo(exarg_T *eap);
|
void ex_pyxdo(exarg_T *eap);
|
||||||
void ex_checktime(exarg_T *eap);
|
void ex_checktime(exarg_T *eap);
|
||||||
char_u *get_mess_lang(void);
|
|
||||||
void set_lang_var(void);
|
|
||||||
void ex_language(exarg_T *eap);
|
|
||||||
void free_locales(void);
|
|
||||||
char_u *get_lang_arg(expand_T *xp, int idx);
|
|
||||||
char_u *get_locales(expand_T *xp, int idx);
|
|
||||||
/* vim: set ft=c : */
|
/* vim: set ft=c : */
|
||||||
|
9
src/proto/locale.pro
Normal file
9
src/proto/locale.pro
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* locale.c */
|
||||||
|
char_u *get_mess_lang(void);
|
||||||
|
void set_lang_var(void);
|
||||||
|
void init_locale(void);
|
||||||
|
void ex_language(exarg_T *eap);
|
||||||
|
void free_locales(void);
|
||||||
|
char_u *get_lang_arg(expand_T *xp, int idx);
|
||||||
|
char_u *get_locales(expand_T *xp, int idx);
|
||||||
|
/* vim: set ft=c : */
|
@ -754,6 +754,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1269,
|
||||||
/**/
|
/**/
|
||||||
1268,
|
1268,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user