Merge branch 'ds/commit-graph-genno-fix'
[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 #ifndef NO_GETTEXT
69 static int test_vsnprintf(const char *fmt, ...)
70 {
71         char buf[26];
72         int ret;
73         va_list ap;
74         va_start(ap, fmt);
75         ret = vsnprintf(buf, sizeof(buf), fmt, ap);
76         va_end(ap);
77         return ret;
78 }
79
80 static void init_gettext_charset(const char *domain)
81 {
82         setlocale(LC_CTYPE, "");
83         charset = locale_charset();
84         bind_textdomain_codeset(domain, charset);
85
86         /*
87          * Work around an old bug fixed in glibc 2.17 (released on
88          * 2012-12-24), at the cost of potentially making translated
89          * messages from external functions like perror() emitted in
90          * the wrong encoding.
91          *
92          * The bug affected e.g. git.git's own 7eb93c89651 ([PATCH]
93          * Simplify git script, 2005-09-07), which is the origin of
94          * the "David_K\345gedal" test string.
95          *
96          * See a much longer comment added to this file in 5e9637c6297
97          * (i18n: add infrastructure for translating Git with gettext,
98          * 2011-11-18) for more details.
99          */
100         if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
101                 setlocale(LC_CTYPE, "C");
102 }
103
104 void git_setup_gettext(void)
105 {
106         const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
107         char *p = NULL;
108
109         if (!podir)
110                 podir = p = system_path(GIT_LOCALE_PATH);
111
112         if (!is_directory(podir)) {
113                 free(p);
114                 return;
115         }
116
117         bindtextdomain("git", podir);
118         setlocale(LC_MESSAGES, "");
119         setlocale(LC_TIME, "");
120         init_gettext_charset("git");
121         textdomain("git");
122
123         free(p);
124 }
125
126 /* return the number of columns of string 's' in current locale */
127 int gettext_width(const char *s)
128 {
129         static int is_utf8 = -1;
130         if (is_utf8 == -1)
131                 is_utf8 = is_utf8_locale();
132
133         return is_utf8 ? utf8_strwidth(s) : strlen(s);
134 }
135 #endif
136
137 int is_utf8_locale(void)
138 {
139 #ifdef NO_GETTEXT
140         if (!charset) {
141                 const char *env = getenv("LC_ALL");
142                 if (!env || !*env)
143                         env = getenv("LC_CTYPE");
144                 if (!env || !*env)
145                         env = getenv("LANG");
146                 if (!env)
147                         env = "";
148                 if (strchr(env, '.'))
149                         env = strchr(env, '.') + 1;
150                 charset = xstrdup(env);
151         }
152 #endif
153         return is_encoding_utf8(charset);
154 }