/* JOE's gettext() library. Why? Once again we can not rely on the
* system's or GNU's gettext being installed properly */
/* One modification from standard gettext: comments are allowed at
* the start of strings: "|comment|comment|comment|foo". The leading
* '|' is required to indicate the comment.
*
* Comments can be used to make two otherwise identical strings distinct.
*/
#include "types.h"
HASH *gettext_ht;
static const char *ignore_prefix(const char *set)
{
const char *s = zrchr(set, '|');
if (s)
++s;
else
s = set;
return s;
}
const char *my_gettext(const char *s)
{
if (gettext_ht) {
const char *r = (const char *)htfind(gettext_ht, s);
if (r)
s = r;
}
if (s[0] == '|')
s = ignore_prefix(s);
if (zstr(s, "%{")) {
char buf[128];
char name[80];
ptrdiff_t i, j;
/* Substitution */
i = 0;
while (*s)
if (s[0] == '%' && s[1] == '{') {
j = 0;
s += 2;
while (*s && *s != '}') {
name[j++] = *s++;
}
name[j] = 0;
if (*s == '}')
++s;
if (!strcmp(name, "abort")) {
strcpy(buf + i, aborthint);
i = zlen(buf);
} else if (!strcmp(name, "help")) {
strcpy(buf + i, helphint);
i = zlen(buf);
}
} else {
buf[i++] = *s++;
}
buf[i] = 0;
s = atom_add(buf);
}
return s;
}
/* Load a .po file, convert entries to local character set and add them to
* hash table */
static int load_po(FILE *f)
{
char buf[1024];
char msgid[1024];
char msgstr[1024];
char bf[8192];
struct charmap *po_map = locale_map;
int preload_flag = 0;
msgid[0] = 0;
msgstr[0] = 0;
while (preload_flag || fgets(buf,SIZEOF(buf)-1,f)) {
const char *p;
preload_flag = 0;
p = buf;
parse_ws(&p, '#');
if (!parse_field(&p, "msgid")) {
ptrdiff_t ofst = 0;
ptrdiff_t len;
msgid[0] = 0;
parse_ws(&p, '#');
while ((len = parse_string(&p, msgid + ofst, SIZEOF(msgid)-ofst)) >= 0) {
preload_flag = 0;
ofst += len;
parse_ws(&p, '#');
if (!*p) {
if (fgets(buf,SIZEOF(buf) - 1,f)) {
p = buf;
preload_flag = 1;
parse_ws(&p, '#');
} else {
goto bye;
}
}
}
} else if (!parse_field(&p, "msgstr")) {
ptrdiff_t ofst = 0;
ptrdiff_t len;
msgstr[0] = 0;
parse_ws(&p, '#');
while ((len = parse_string(&p, msgstr + ofst, SIZEOF(msgstr)-ofst)) >= 0) {
preload_flag = 0;
ofst += len;
parse_ws(&p, '#');
if (!*p) {
if (fgets(buf,SIZEOF(buf) - 1,f)) {
p = buf;
preload_flag = 1;
parse_ws(&p, '#');
} else {
break;
}
}
}
if (msgid[0] && msgstr[0]) {
/* Convert to locale character map */
my_iconv(bf, SIZEOF(bf), locale_map,msgstr,po_map);
/* Add to hash table */
htadd(gettext_ht, zdup(msgid), zdup(bf));
} else if (!msgid[0] && msgstr[0]) {
char *tp = zstr(msgstr, "charset=");
if (tp) {
/* Copy character set name up to next delimiter */
int x;
tp += SIZEOF("charset=") - 1;
while (*tp == ' ' || *tp == '\t') ++tp;
for (x = 0; tp[x] && tp[x] !='\n' && tp[x] != '\r' && tp[x] != ' ' &&
tp[x] != '\t' && tp[x] != ';' && tp[x] != ','; ++x)
msgid[x] = tp[x];
msgid[x] = 0;
po_map = find_charmap(msgid);
if (!po_map)
po_map = locale_map;
}
}
}
}
bye:
fclose(f);
return 0;
}
/* Initialize my_gettext(). Call after locale_map has been set. */
void init_gettext(const char *s)
{
FILE *f;
char buf[1024];
joe_snprintf_2(buf, SIZEOF(buf), "%slang/%s.po",JOEDATA,s);
if ((f = fopen(buf, "r"))) {
/* Try specific language, like en_GB */
gettext_ht = htmk(256);
load_po(f);
} else if (s[0] && s[1]) {
/* Try generic language, like en */
joe_snprintf_3(buf, SIZEOF(buf), "%slang/%c%c.po",JOEDATA,s[0],s[1]);
if ((f = fopen(buf, "r"))) {
gettext_ht = htmk(256);
load_po(f);
}
}
}