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