summaryrefslogtreecommitdiff
path: root/src/language.cpp
blob: 7256ebbbf854ac3cd07f99e1033124873fdb373e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "services.h"
#include <stack>

std::vector<Anope::string> languages;

void InitLanguages()
{
#if GETTEXT_FOUND
	languages.clear();
	spacesepstream sep(Config->Languages);
	Anope::string language;

	while (sep.GetToken(language))
	{
		if (!IsFile("languages/" + language + "/LC_MESSAGES/anope.mo"))
		{
			Log() << "Error loading language " << language << ", file does not exist!";
		}
		else
		{
			Log(LOG_DEBUG) << "Found language file " << language;
			languages.push_back(language);
		}
	}

	if (!bindtextdomain("anope", (services_dir + "/languages/").c_str()))
		Log() << "Error calling bindtextdomain, " << Anope::LastError();
	else
		Log(LOG_DEBUG) << "Successfully bound anope to " << services_dir << "/languages/";
#else
	Log() << "Can not load languages, gettext is not installed";
#endif
}

const Anope::string GetString(NickCore *nc, const char *string)
{
	return GetString("anope", nc ? nc->language : "", string);
}

const Anope::string GetString(const Anope::string &domain, const Anope::string &lang, const char *string)
{
	PushLanguage(domain, lang);
	const char *t_string = anope_gettext(string);
	PopLanguage();
	return t_string;
}

#if GETTEXT_FOUND
static std::stack<std::pair<Anope::string, Anope::string > > language_stack;

void PushLanguage(const Anope::string &domain, Anope::string language)
{
	if (language.empty() && !Config->NSDefLanguage.empty())
		language = Config->NSDefLanguage;
	
	language_stack.push(std::make_pair(domain, language));
}

void PopLanguage()
{
	language_stack.pop();
}

/* Used by gettext to make it always dynamically load language strings (so we can drop them in while Anope is running) */
extern "C" int _nl_msg_cat_cntr;

const char *anope_gettext(const char *string)
{
	std::pair<Anope::string, Anope::string> lang_info;
	if (!language_stack.empty())
		lang_info = language_stack.top();
	if (lang_info.first.empty() || lang_info.second.empty())
		return string;

	++_nl_msg_cat_cntr;
#ifdef _WIN32
	SetThreadLocale(MAKELCID(MAKELANGID(WindowsGetLanguage(lang_info.second.c_str()), SUBLANG_DEFAULT), SORT_DEFAULT));
#else
	/* First, set LANGUAGE env variable.
	 * Some systems (Debian) don't care about this, so we must setlocale LC_ALL aswell.
	 * BUT if this call fails because the LANGUAGE env variable is set, setlocale resets
	 * the locale to "C", which short circuits gettext and causes it to fail on systems that
	 * use the LANGUAGE env variable. We must reset the locale to en_US (or, anything not
	 * C or POSIX) then.
	 */
	setenv("LANGUAGE", lang_info.second.c_str(), 1);
	if (setlocale(LC_ALL, lang_info.second.c_str()) == NULL)
		setlocale(LC_ALL, "en_US");
#endif
	const char *translated_string = dgettext(lang_info.first.c_str(), string);
#ifdef _WIN32
	SetThreadLocale(MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), SORT_DEFAULT));
#else
	unsetenv("LANGUAGE");
	setlocale(LC_ALL, "");
#endif

	Anope::string translated = translated_string ? translated_string : "";

	if (Config->UseStrictPrivMsg)
		translated = translated.replace_all_cs("%R", "/");
	else
		translated = translated.replace_all_cs("%R", "/msg ");
	
	return translated.c_str();
}
#else
void PushLanguage(const Anope::string &, Anope::string)
{
}

void PopLanguage()
{
}

const char *anope_gettext(const char *string)
{
	Anope::string translated = string ? string : "";
	if (Config->UseStrictPrivMsg)
		translated = translated.replace_all_cs("%R", "/");
	else
		translated = translated.replace_all_cs("%R", "/msg ");
	return translated.c_str();
}
#endif

void SyntaxError(CommandSource &source, const Anope::string &command, const Anope::string &message)
{
	source.Reply(_("Syntax: \002%s\002"), message.c_str());
	source.Reply(_(LanguageString::MORE_INFO), source.owner->nick.c_str(), command.c_str());
}