1
0
mirror of https://github.com/anope/anope.git synced 2026-06-12 19:14:47 +02:00
Files
anope/language.c
T
dane dane@31f1291d-b8d6-0310-a050-a5561fc1590b 811ce26663 BUILD : 1.6.0 (4) BUGS : none NOTES : File cleanup and new AnopeManager script (bin/am) to work with Anope source control. Version schema change with no impact on cpp directives.
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
2004-03-28 23:00:59 +00:00

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);
}
/*************************************************************************/