From af17f7ef0984e8634068702e70ab431c7acffde9 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 22 Jan 2020 18:44:15 +0100 Subject: [PATCH] luci-base: handle more po format features in po2lmo - Extract and store the plural calculation function in .lmo files - Handle plural translation messages - Handle translation contexts Signed-off-by: Jo-Philipp Wich (cherry picked from commit 9c1bac4168d151c2a3a5a1f957adbd68b6ae0746) --- modules/luci-base/src/po2lmo.c | 215 +++++++++++++++++++++------------ 1 file changed, 136 insertions(+), 79 deletions(-) diff --git a/modules/luci-base/src/po2lmo.c b/modules/luci-base/src/po2lmo.c index fd927cb52f..930ea12c7d 100644 --- a/modules/luci-base/src/po2lmo.c +++ b/modules/luci-base/src/po2lmo.c @@ -116,19 +116,30 @@ static void print_index(void *array, int n, FILE *out) } } +enum fieldtype { + UNSPEC = 0, + MSG_CTXT = 1, + MSG_ID = 2, + MSG_ID_PLURAL = 3, + MSG_STR = 4 +}; + int main(int argc, char *argv[]) { char line[4096]; char key[4096]; char val[4096]; char tmp[4096]; - int state = 0; int offset = 0; int length = 0; int n_entries = 0; void *array = NULL; lmo_entry_t *entry = NULL; uint32_t key_id, val_id; + enum fieldtype type = UNSPEC, prev_type = UNSPEC; + int plural_num = -1, prev_plural_num = -1; + char *ctxt = NULL, *id = NULL, *p; + int eof, esc; FILE *in; FILE *out; @@ -136,108 +147,154 @@ int main(int argc, char *argv[]) if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) ) usage(argv[0]); - memset(line, 0, sizeof(key)); - memset(key, 0, sizeof(val)); - memset(val, 0, sizeof(val)); + while (1) { + line[0] = 0; + eof = !fgets(line, sizeof(line), in); - while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) ) - { - if( state == 0 && strstr(line, "msgid \"") == line ) - { - switch(extract_string(line, key, sizeof(key))) - { - case -1: - die("Syntax error in msgid"); - case 0: - state = 1; - break; - default: - state = 2; - } + if (!strncmp(line, "msgctxt \"", 9)) { + free(ctxt); + type = MSG_CTXT; + ctxt = NULL; } - else if( state == 1 || state == 2 ) - { - if( strstr(line, "msgstr \"") == line || state == 2 ) - { - switch(extract_string(line, val, sizeof(val))) - { - case -1: - state = 4; - break; - default: - state = 3; - } - } - else - { - switch(extract_string(line, tmp, sizeof(tmp))) - { - case -1: - state = 2; - break; - default: - strcat(key, tmp); - } + else if (!strncmp(line, "msgid \"", 7)) { + if (prev_type != MSG_CTXT) { + free(ctxt); + ctxt = NULL; } + + free(id); + type = MSG_ID; + id = NULL; } - else if( state == 3 ) - { - switch(extract_string(line, tmp, sizeof(tmp))) - { - case -1: - state = 4; - break; - default: - strcat(val, tmp); - } + else if (!strncmp(line, "msgid_plural \"", 14)) { + type = MSG_ID_PLURAL; } + else if (!strncmp(line, "msgstr \"", 8) || !strncmp(line, "msgstr[", 7)) { + type = MSG_STR; - if( state == 4 ) - { - if( strlen(key) > 0 && strlen(val) > 0 ) - { - key_id = sfh_hash(key, strlen(key)); - val_id = sfh_hash(val, strlen(val)); + if (line[6] == '[') + plural_num = strtoul(line + 7, NULL, 10); + else + plural_num = -1; + } - if( key_id != val_id ) - { - n_entries++; - array = realloc(array, n_entries * sizeof(lmo_entry_t)); - entry = (lmo_entry_t *)array + n_entries - 1; + if (type != prev_type || plural_num != prev_plural_num || eof) { + switch (prev_type) { + case MSG_CTXT: + ctxt = strdup(val); + break; - if (!array) - die("Out of memory"); + case MSG_ID: + id = strdup(val); + break; + + case MSG_STR: + if (id && id[0] && val[0]) { + if (ctxt && ctxt[0] && prev_plural_num > -1) + snprintf(key, sizeof(key), "%s\1%s\2%d", ctxt, id, prev_plural_num); + else if (ctxt && ctxt[0]) + snprintf(key, sizeof(key), "%s\1%s", ctxt, id); + else if (prev_plural_num > -1) + snprintf(key, sizeof(key), "%s\2%d", id, prev_plural_num); + else + snprintf(key, sizeof(key), "%s", id); + + key_id = sfh_hash(key, strlen(key)); + val_id = sfh_hash(val, strlen(val)); + + if (key_id != val_id) { + n_entries++; + array = realloc(array, n_entries * sizeof(lmo_entry_t)); + entry = (lmo_entry_t *)array + n_entries - 1; - entry->key_id = key_id; - entry->val_id = val_id; - entry->offset = offset; - entry->length = strlen(val); + if (!array) + die("Out of memory"); - length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); + entry->key_id = key_id; + entry->val_id = prev_plural_num + 1; + entry->offset = offset; + entry->length = strlen(val); - print(val, length, 1, out); - offset += length; + length = strlen(val) + ((4 - (strlen(val) % 4)) % 4); + + print(val, length, 1, out); + offset += length; + } } + else if (id && id[0] == 0) { + for (id = val, p = val; *p; p++) { + if (esc) { + if (*p == 'n') { + p[-1] = 0; + + if (!strncasecmp(id, "Plural-Forms: ", 14)) { + id += 14; + + n_entries++; + array = realloc(array, n_entries * sizeof(lmo_entry_t)); + entry = (lmo_entry_t *)array + n_entries - 1; + + if (!array) + die("Out of memory"); + + entry->key_id = 0; + entry->val_id = 0; + entry->offset = offset; + entry->length = strlen(id); + + length = strlen(id) + ((4 - (strlen(id) % 4)) % 4); + + print(id, length, 1, out); + offset += length; + } + } + + id = p + 1; + esc = 0; + } + else if (*p == '\\') { + esc = 1; + } + } + + id = NULL; + } + + break; + + default: + break; } - state = 0; - memset(key, 0, sizeof(key)); - memset(val, 0, sizeof(val)); + val[0] = 0; + prev_type = type; + prev_plural_num = plural_num; } - memset(line, 0, sizeof(line)); + if (eof) + break; + + if (prev_type != UNSPEC) { + switch (extract_string(line, tmp, sizeof(tmp))) { + case -1: + type = UNSPEC; + plural_num = -1; + break; + + default: + strcat(val, tmp); + } + } } print_index(array, n_entries, out); - if( offset > 0 ) - { + if (offset > 0) { print_uint32(offset, out); fsync(fileno(out)); fclose(out); } - else - { + else { fclose(out); unlink(argv[2]); } -- 2.30.2