mirror of
https://github.com/anope/anope.git
synced 2026-06-12 19:14:47 +02:00
811ce26663
git-svn-id: svn://svn.anope.org/anope/trunk@4 31f1291d-b8d6-0310-a050-a5561fc1590b git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@2 5417fbe8-f217-4b02-8779-1006273d7864
266 lines
8.5 KiB
C
266 lines
8.5 KiB
C
/* Multi-language support.
|
|
*
|
|
* (C) 2003 Anope Team
|
|
* Contact us at info@anope.org
|
|
*
|
|
* Please read COPYING and README for furhter details.
|
|
*
|
|
* Based on the original code of Epona by Lara.
|
|
* Based on the original code of Services by Andy Church.
|
|
*
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#include "services.h"
|
|
#include "language.h"
|
|
|
|
/*************************************************************************/
|
|
|
|
/* The list of lists of messages. */
|
|
char **langtexts[NUM_LANGS];
|
|
|
|
/* The list of names of languages. */
|
|
char *langnames[NUM_LANGS];
|
|
|
|
/* Indexes of available languages: */
|
|
int langlist[NUM_LANGS];
|
|
|
|
/* Order in which languages should be displayed: (alphabetical) */
|
|
static int langorder[NUM_LANGS] = {
|
|
LANG_EN_US, /* English (US) */
|
|
LANG_FR, /* French */
|
|
LANG_DE, /* German */
|
|
LANG_IT, /* Italian */
|
|
LANG_JA_JIS, /* Japanese (JIS encoding) */
|
|
LANG_JA_EUC, /* Japanese (EUC encoding) */
|
|
LANG_JA_SJIS, /* Japanese (SJIS encoding) */
|
|
LANG_PT, /* Portugese */
|
|
LANG_ES, /* Spanish */
|
|
LANG_TR, /* Turkish */
|
|
LANG_CAT, /* Catalan */
|
|
LANG_GR, /* Greek */
|
|
LANG_NL, /* Dutch */
|
|
LANG_RU, /* Russian */
|
|
};
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Load a language file. */
|
|
|
|
static int read_int32(int32 * ptr, FILE * f)
|
|
{
|
|
int a = fgetc(f);
|
|
int b = fgetc(f);
|
|
int c = fgetc(f);
|
|
int d = fgetc(f);
|
|
if (a == EOF || b == EOF || c == EOF || d == EOF)
|
|
return -1;
|
|
*ptr = a << 24 | b << 16 | c << 8 | d;
|
|
return 0;
|
|
}
|
|
|
|
static void load_lang(int index, const char *filename)
|
|
{
|
|
char buf[256];
|
|
FILE *f;
|
|
int num, i;
|
|
|
|
if (debug) {
|
|
alog("debug: Loading language %d from file `languages/%s'",
|
|
index, filename);
|
|
}
|
|
snprintf(buf, sizeof(buf), "languages/%s", filename);
|
|
if (!(f = fopen(buf, "r"))) {
|
|
log_perror("Failed to load language %d (%s)", index, filename);
|
|
return;
|
|
} else if (read_int32(&num, f) < 0) {
|
|
alog("Failed to read number of strings for language %d (%s)",
|
|
index, filename);
|
|
return;
|
|
} else if (num != NUM_STRINGS) {
|
|
alog("Warning: Bad number of strings (%d, wanted %d) "
|
|
"for language %d (%s)", num, NUM_STRINGS, index, filename);
|
|
}
|
|
langtexts[index] = scalloc(sizeof(char *), NUM_STRINGS);
|
|
if (num > NUM_STRINGS)
|
|
num = NUM_STRINGS;
|
|
for (i = 0; i < num; i++) {
|
|
int32 pos, len;
|
|
fseek(f, i * 8 + 4, SEEK_SET);
|
|
if (read_int32(&pos, f) < 0 || read_int32(&len, f) < 0) {
|
|
alog("Failed to read entry %d in language %d (%s) TOC",
|
|
i, index, filename);
|
|
while (--i >= 0) {
|
|
if (langtexts[index][i])
|
|
free(langtexts[index][i]);
|
|
}
|
|
free(langtexts[index]);
|
|
langtexts[index] = NULL;
|
|
return;
|
|
}
|
|
if (len == 0) {
|
|
langtexts[index][i] = NULL;
|
|
} else if (len >= 65536) {
|
|
alog("Entry %d in language %d (%s) is too long (over 64k)--"
|
|
"corrupt TOC?", i, index, filename);
|
|
while (--i >= 0) {
|
|
if (langtexts[index][i])
|
|
free(langtexts[index][i]);
|
|
}
|
|
free(langtexts[index]);
|
|
langtexts[index] = NULL;
|
|
return;
|
|
} else if (len < 0) {
|
|
alog("Entry %d in language %d (%s) has negative length--"
|
|
"corrupt TOC?", i, index, filename);
|
|
while (--i >= 0) {
|
|
if (langtexts[index][i])
|
|
free(langtexts[index][i]);
|
|
}
|
|
free(langtexts[index]);
|
|
langtexts[index] = NULL;
|
|
return;
|
|
} else {
|
|
langtexts[index][i] = scalloc(len + 1, 1);
|
|
fseek(f, pos, SEEK_SET);
|
|
if (fread(langtexts[index][i], 1, len, f) != len) {
|
|
alog("Failed to read string %d in language %d (%s)",
|
|
i, index, filename);
|
|
while (--i >= 0) {
|
|
if (langtexts[index][i])
|
|
free(langtexts[index][i]);
|
|
}
|
|
free(langtexts[index]);
|
|
langtexts[index] = NULL;
|
|
return;
|
|
}
|
|
langtexts[index][i][len] = 0;
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Initialize list of lists. */
|
|
|
|
void lang_init()
|
|
{
|
|
int i, j, n = 0;
|
|
|
|
load_lang(LANG_CAT, "cat");
|
|
load_lang(LANG_DE, "de");
|
|
load_lang(LANG_EN_US, "en_us");
|
|
load_lang(LANG_ES, "es");
|
|
load_lang(LANG_FR, "fr");
|
|
load_lang(LANG_GR, "gr");
|
|
load_lang(LANG_PT, "pt");
|
|
load_lang(LANG_TR, "tr");
|
|
load_lang(LANG_IT, "it");
|
|
load_lang(LANG_NL, "nl");
|
|
load_lang(LANG_RU, "ru");
|
|
|
|
for (i = 0; i < NUM_LANGS; i++) {
|
|
if (langtexts[langorder[i]] != NULL) {
|
|
langnames[langorder[i]] = langtexts[langorder[i]][LANG_NAME];
|
|
langlist[n++] = langorder[i];
|
|
for (j = 0; j < NUM_STRINGS; j++) {
|
|
if (!langtexts[langorder[i]][j]) {
|
|
langtexts[langorder[i]][j] =
|
|
langtexts[DEF_LANGUAGE][j];
|
|
}
|
|
if (!langtexts[langorder[i]][j]) {
|
|
langtexts[langorder[i]][j] = langtexts[LANG_EN_US][j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while (n < NUM_LANGS)
|
|
langlist[n++] = -1;
|
|
|
|
/* Not what I intended to do, but these services are so archaïc
|
|
* that it's difficult to do more. */
|
|
if ((NSDefLanguage = langlist[NSDefLanguage]) < 0)
|
|
NSDefLanguage = DEF_LANGUAGE;
|
|
|
|
if (!langtexts[DEF_LANGUAGE])
|
|
fatal("Unable to load default language");
|
|
for (i = 0; i < NUM_LANGS; i++) {
|
|
if (!langtexts[i])
|
|
langtexts[i] = langtexts[DEF_LANGUAGE];
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* Format a string in a strftime()-like way, but heed the user's language
|
|
* setting for month and day names. The string stored in the buffer will
|
|
* always be null-terminated, even if the actual string was longer than the
|
|
* buffer size.
|
|
* Assumption: No month or day name has a length (including trailing null)
|
|
* greater than BUFSIZE.
|
|
*/
|
|
|
|
int strftime_lang(char *buf, int size, User * u, int format, struct tm *tm)
|
|
{
|
|
int language = u && u->na ? u->na->nc->language : NSDefLanguage;
|
|
char tmpbuf[BUFSIZE], buf2[BUFSIZE];
|
|
char *s;
|
|
int i, ret;
|
|
|
|
strscpy(tmpbuf, langtexts[language][format], sizeof(tmpbuf));
|
|
if ((s = langtexts[language][STRFTIME_DAYS_SHORT]) != NULL) {
|
|
for (i = 0; i < tm->tm_wday; i++)
|
|
s += strcspn(s, "\n") + 1;
|
|
i = strcspn(s, "\n");
|
|
strncpy(buf2, s, i);
|
|
buf2[i] = 0;
|
|
strnrepl(tmpbuf, sizeof(tmpbuf), "%a", buf2);
|
|
}
|
|
if ((s = langtexts[language][STRFTIME_DAYS_LONG]) != NULL) {
|
|
for (i = 0; i < tm->tm_wday; i++)
|
|
s += strcspn(s, "\n") + 1;
|
|
i = strcspn(s, "\n");
|
|
strncpy(buf2, s, i);
|
|
buf2[i] = 0;
|
|
strnrepl(tmpbuf, sizeof(tmpbuf), "%A", buf2);
|
|
}
|
|
if ((s = langtexts[language][STRFTIME_MONTHS_SHORT]) != NULL) {
|
|
for (i = 0; i < tm->tm_mon; i++)
|
|
s += strcspn(s, "\n") + 1;
|
|
i = strcspn(s, "\n");
|
|
strncpy(buf2, s, i);
|
|
buf2[i] = 0;
|
|
strnrepl(tmpbuf, sizeof(tmpbuf), "%b", buf2);
|
|
}
|
|
if ((s = langtexts[language][STRFTIME_MONTHS_LONG]) != NULL) {
|
|
for (i = 0; i < tm->tm_mon; i++)
|
|
s += strcspn(s, "\n") + 1;
|
|
i = strcspn(s, "\n");
|
|
strncpy(buf2, s, i);
|
|
buf2[i] = 0;
|
|
strnrepl(tmpbuf, sizeof(tmpbuf), "%B", buf2);
|
|
}
|
|
ret = strftime(buf, size, tmpbuf, tm);
|
|
if (ret == size)
|
|
buf[size - 1] = 0;
|
|
return ret;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* Send a syntax-error message to the user. */
|
|
|
|
void syntax_error(const char *service, User * u, const char *command,
|
|
int msgnum)
|
|
{
|
|
const char *str = getstring(u->na, msgnum);
|
|
notice_lang(service, u, SYNTAX_ERROR, str);
|
|
notice_lang(service, u, MORE_INFO, service, command);
|
|
}
|
|
|
|
/*************************************************************************/
|