blob: bb5ba1fe7cc5979255fe79fd8dfc0085fc8df8f1 [file] [log] [blame]
Jonathan Nieder30955222011-02-22 23:41:22 +00001/*
2 * Copyright (c) 2010 Ævar Arnfjörð Bjarmason
3 */
4
Dan Jacques226c0dd2018-04-10 11:05:44 -04005#include "cache.h"
Junio C Hamano92034a92018-05-08 15:59:17 +09006#include "exec-cmd.h"
Jonathan Nieder30955222011-02-22 23:41:22 +00007#include "gettext.h"
Nguyễn Thái Ngọc Duy754395d2012-09-04 17:39:35 +07008#include "strbuf.h"
9#include "utf8.h"
Ævar Arnfjörð Bjarmason6cdccfc2018-11-08 21:15:29 +000010#include "config.h"
Jonathan Nieder30955222011-02-22 23:41:22 +000011
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +010012#ifndef NO_GETTEXT
13# include <locale.h>
14# include <libintl.h>
Karsten Blees090d1e82019-07-03 13:46:04 -070015# ifdef GIT_WINDOWS_NATIVE
16
17static 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
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +010034# include <libcharset.h>
35# else
36# include <langinfo.h>
37# define locale_charset() nl_langinfo(CODESET)
38# endif
39#endif
40
Nguyễn Thái Ngọc Duye8c16722016-06-25 07:22:34 +020041static const char *charset;
42
Jeff King93f7d912015-02-25 22:04:16 -050043/*
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 */
49const 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
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +010068#ifndef NO_GETTEXT
Ævar Arnfjörð Bjarmason48ca53c2021-07-13 10:05:18 +020069__attribute__((format (printf, 1, 2)))
Nguyễn Thái Ngọc Duy9c0495d2013-12-01 09:45:38 +070070static int test_vsnprintf(const char *fmt, ...)
71{
72 char buf[26];
73 int ret;
74 va_list ap;
75 va_start(ap, fmt);
76 ret = vsnprintf(buf, sizeof(buf), fmt, ap);
77 va_end(ap);
78 return ret;
79}
80
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +010081static void init_gettext_charset(const char *domain)
82{
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +010083 setlocale(LC_CTYPE, "");
84 charset = locale_charset();
85 bind_textdomain_codeset(domain, charset);
Ævar Arnfjörð Bjarmason9371c0e2021-01-11 14:14:51 +010086
87 /*
88 * Work around an old bug fixed in glibc 2.17 (released on
89 * 2012-12-24), at the cost of potentially making translated
90 * messages from external functions like perror() emitted in
91 * the wrong encoding.
92 *
93 * The bug affected e.g. git.git's own 7eb93c89651 ([PATCH]
94 * Simplify git script, 2005-09-07), which is the origin of
95 * the "David_K\345gedal" test string.
96 *
97 * See a much longer comment added to this file in 5e9637c6297
98 * (i18n: add infrastructure for translating Git with gettext,
99 * 2011-11-18) for more details.
100 */
Nguyễn Thái Ngọc Duy9c0495d2013-12-01 09:45:38 +0700101 if (test_vsnprintf("%.*s", 13, "David_K\345gedal") < 0)
102 setlocale(LC_CTYPE, "C");
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100103}
104
105void git_setup_gettext(void)
106{
Dan Jacques226c0dd2018-04-10 11:05:44 -0400107 const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT);
Johannes Schindelin02102312018-04-21 13:14:28 +0200108 char *p = NULL;
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100109
110 if (!podir)
Johannes Schindelin02102312018-04-21 13:14:28 +0200111 podir = p = system_path(GIT_LOCALE_PATH);
Dan Jacques226c0dd2018-04-10 11:05:44 -0400112
Johannes Schindelin02102312018-04-21 13:14:28 +0200113 if (!is_directory(podir)) {
114 free(p);
Johannes Schindelincc5e1bf2018-04-21 13:14:08 +0200115 return;
Johannes Schindelin02102312018-04-21 13:14:28 +0200116 }
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100117
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100118 bindtextdomain("git", podir);
119 setlocale(LC_MESSAGES, "");
Jeff Kingaa1462c2015-06-25 12:55:45 -0400120 setlocale(LC_TIME, "");
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100121 init_gettext_charset("git");
122 textdomain("git");
Johannes Schindelin02102312018-04-21 13:14:28 +0200123
124 free(p);
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100125}
Nguyễn Thái Ngọc Duy754395d2012-09-04 17:39:35 +0700126
127/* return the number of columns of string 's' in current locale */
128int gettext_width(const char *s)
129{
130 static int is_utf8 = -1;
131 if (is_utf8 == -1)
Nguyễn Thái Ngọc Duye8c16722016-06-25 07:22:34 +0200132 is_utf8 = is_utf8_locale();
Nguyễn Thái Ngọc Duy754395d2012-09-04 17:39:35 +0700133
134 return is_utf8 ? utf8_strwidth(s) : strlen(s);
135}
Ævar Arnfjörð Bjarmason5e9637c2011-11-18 00:14:42 +0100136#endif
Nguyễn Thái Ngọc Duye8c16722016-06-25 07:22:34 +0200137
138int is_utf8_locale(void)
139{
140#ifdef NO_GETTEXT
141 if (!charset) {
142 const char *env = getenv("LC_ALL");
143 if (!env || !*env)
144 env = getenv("LC_CTYPE");
145 if (!env || !*env)
146 env = getenv("LANG");
147 if (!env)
148 env = "";
149 if (strchr(env, '.'))
150 env = strchr(env, '.') + 1;
151 charset = xstrdup(env);
152 }
153#endif
154 return is_encoding_utf8(charset);
155}