]> git.ipfire.org Git - thirdparty/git.git/blob - gettext.c
Git 2.30.9
[thirdparty/git.git] / gettext.c
1 /*
2 * Copyright (c) 2010 Ævar Arnfjörð Bjarmason
3 */
4
5 #include "cache.h"
6 #include "exec-cmd.h"
7 #include "gettext.h"
8 #include "strbuf.h"
9 #include "utf8.h"
10 #include "config.h"
11
12 #ifndef NO_GETTEXT
13 # include <locale.h>
14 # include <libintl.h>
15 # ifdef GIT_WINDOWS_NATIVE
16
17 static const char *locale_charset(void)
18 {
19 const char *env = getenv("LC_ALL"), *dot;
20
21 if (!env || !*env)
22 env = getenv("LC_CTYPE");
23 if (!env || !*env)
24 env = getenv("LANG");
25
26 if (!env)
27 return "UTF-8";
28
29 dot = strchr(env, '.');
30 return !dot ? env : dot + 1;
31 }
32
33 # elif defined HAVE_LIBCHARSET_H
34 # include <libcharset.h>
35 # else
36 # include <langinfo.h>
37 # define locale_charset() nl_langinfo(CODESET)
38 # endif
39 #endif
40
41 static const char *charset;
42
43 /*
44 * Guess the user's preferred languages from the value in LANGUAGE environment
45 * variable and LC_MESSAGES locale category if NO_GETTEXT is not defined.
46 *
47 * The result can be a colon-separated list like "ko:ja:en".
48 */
49 const char *get_preferred_languages(void)
50 {
51 const char *retval;
52
53 retval = getenv("LANGUAGE");
54 if (retval && *retval)
55 return retval;
56
57 #ifndef NO_GETTEXT
58 retval = setlocale(LC_MESSAGES, NULL);
59 if (retval && *retval &&
60 strcmp(retval, "C") &&
61 strcmp(retval, "POSIX"))
62 return retval;
63 #endif
64
65 return NULL;
66 }
67
68 int use_gettext_poison(void)
69 {
70 static int poison_requested = -1;
71 if (poison_requested == -1)
72 poison_requested = git_env_bool("GIT_TEST_GETTEXT_POISON", 0);
73 return poison_requested;
74 }
75
76 #ifndef NO_GETTEXT
77 static int test_vsnprintf(const char *fmt, ...)
78 {
79 char buf[26];
80 int ret;
81 va_list ap;
82 va_start(ap, fmt);
83 ret = vsnprintf(buf, sizeof(buf), fmt, ap);
84 va_end(ap);
85 return ret;
86 }
87
88 static void init_gettext_charset(const char *domain)
89 {
90 setlocale(LC_CTYPE, "");
91 charset = locale_charset();
92 bind_textdomain_codeset(domain, charset);
93
94 /*
95 * Work around an old bug fixed in glibc 2.17 (released on
96 * 2012-12-24), at the cost of potentially making translated
97 * messages from external functions like perror() emitted in
98 * the wrong encoding.
99 *
100 * The bug affected e.g. git.git's own 7eb93c89651 ([PATCH]
101 * Simplify git script, 2005-09-07), which is the origin of
102 * the "David_K\345gedal" test string.
103 *
104 * See a much longer comment added to this file in 5e9637c6297
105 * (i18n: add infrastructure for translating Git with gettext,
106 * 2011-11-18) for more details.
107 */
108 if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
109 setlocale(LC_CTYPE, "C");
110 }
111
112 int git_gettext_enabled = 0;
113
114 void git_setup_gettext(void)
115 {
116 const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
117 char *p = NULL;
118
119 if (!podir)
120 podir = p = system_path(GIT_LOCALE_PATH);
121
122 use_gettext_poison(); /* getenv() reentrancy paranoia */
123
124 if (!is_directory(podir)) {
125 free(p);
126 return;
127 }
128
129 bindtextdomain("git", podir);
130 setlocale(LC_MESSAGES, "");
131 setlocale(LC_TIME, "");
132 init_gettext_charset("git");
133 textdomain("git");
134
135 git_gettext_enabled = 1;
136
137 free(p);
138 }
139
140 /* return the number of columns of string 's' in current locale */
141 int gettext_width(const char *s)
142 {
143 static int is_utf8 = -1;
144 if (is_utf8 == -1)
145 is_utf8 = is_utf8_locale();
146
147 return is_utf8 ? utf8_strwidth(s) : strlen(s);
148 }
149 #endif
150
151 int is_utf8_locale(void)
152 {
153 #ifdef NO_GETTEXT
154 if (!charset) {
155 const char *env = getenv("LC_ALL");
156 if (!env || !*env)
157 env = getenv("LC_CTYPE");
158 if (!env || !*env)
159 env = getenv("LANG");
160 if (!env)
161 env = "";
162 if (strchr(env, '.'))
163 env = strchr(env, '.') + 1;
164 charset = xstrdup(env);
165 }
166 #endif
167 return is_encoding_utf8(charset);
168 }