summaryrefslogtreecommitdiff
path: root/src/plugins/generate-translations.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/generate-translations.c')
-rw-r--r--src/plugins/generate-translations.c242
1 files changed, 180 insertions, 62 deletions
diff --git a/src/plugins/generate-translations.c b/src/plugins/generate-translations.c
index 759e788a2..14a3c0a4d 100644
--- a/src/plugins/generate-translations.c
+++ b/src/plugins/generate-translations.c
@@ -22,11 +22,13 @@
#include "common/hercules.h"
#include "common/cbasetypes.h"
#include "common/memmgr.h"
+#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/strlib.h"
#include "common/sysinfo.h"
#include "map/atcommand.h"
#include "map/map.h"
+#include "map/npc.h"
#include "map/script.h"
#include "plugins/HPMHooking.h"
@@ -34,6 +36,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <time.h>
HPExport struct hplugin_info pinfo = {
"generate-translations", // Plugin name
@@ -45,14 +49,33 @@ HPExport struct hplugin_info pinfo = {
struct DBMap *translatable_strings; // string map parsed (used when exporting strings only)
/* Set during startup when attempting to export the lang, unset after server initialization is over */
FILE *lang_export_fp;
-char *lang_export_file;/* for lang_export_fp */
+char *lang_export_filepath;
+#define DIRECTORYNAME "generated_translations"
struct script_string_buf lang_export_line_buf;
struct script_string_buf lang_export_escaped_buf;
-int lang_export_stringcount;
+int lang_export_stringcount_total;
+int lang_export_stringcount_current;
/// Whether the translations template generator will automatically run.
bool generating_translations = false;
+bool createdirectory(const char *dirname)
+{
+#ifdef WIN32
+ if (!CreateDirectory(dirname, NULL)) {
+ if (ERROR_ALREADY_EXISTS != GetLastError())
+ return false;
+ }
+#else /* Not WIN32 */
+ struct stat st = { 0 };
+ if (stat(dirname, &st) == -1 ) {
+ if (mkdir(dirname, 0755) != 0)
+ return false;
+ }
+#endif // WIN32 check
+ return true;
+}
+
/**
* --generate-translations
*
@@ -61,49 +84,9 @@ bool generating_translations = false;
*/
CMDLINEARG(generatetranslations)
{
- lang_export_file = aStrdup("./generated_translations.pot");
-
- if ((lang_export_fp = fopen(lang_export_file, "wb")) == NULL) {
- ShowError("export-dialog: failed to open '%s' for writing\n", lang_export_file);
- } else {
- time_t t = time(NULL);
- struct tm *lt = localtime(&t);
- int year = lt->tm_year+1900;
- char timestring[128] = "";
- strftime(timestring, sizeof(timestring), "%Y-%m-%d %H:%M:%S%z", lt);
- fprintf(lang_export_fp,
- "# This file is part of Hercules.\n"
- "# http://herc.ws - http://github.com/HerculesWS/Hercules\n"
- "#\n"
- "# Copyright (C) 2013-%d Hercules Dev Team\n"
- "#\n"
- "# Hercules is free software: you can redistribute it and/or modify\n"
- "# it under the terms of the GNU General Public License as published by\n"
- "# the Free Software Foundation, either version 3 of the License, or\n"
- "# (at your option) any later version.\n"
- "#\n"
- "# This program is distributed in the hope that it will be useful,\n"
- "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
- "# GNU General Public License for more details.\n"
- "#\n"
- "# You should have received a copy of the GNU General Public License\n"
- "# along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
-
- "#,fuzzy\n"
- "msgid \"\"\n"
- "msgstr \"\"\n"
- "\"Project-Id-Version: %s\\n\"\n"
- "\"Report-Msgid-Bugs-To: dev@herc.ws\\n\"\n"
- "\"POT-Creation-Date: %s\\n\"\n"
- "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n"
- "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n"
- "\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n"
- "\"Language: \\n\"\n"
- "\"MIME-Version: 1.0\\n\"\n"
- "\"Content-Type: text/plain; charset=ISO-8859-1\\n\"\n"
- "\"Content-Transfer-Encoding: 8bit\\n\"\n\n",
- year, sysinfo->vcsrevision_scripts(), timestring);
+ if (!createdirectory(DIRECTORYNAME)) {
+ ShowError("generatetranslations: Unable to create output directory '%s'.\n", DIRECTORYNAME);
+ return false;
}
generating_translations = true;
return true;
@@ -188,7 +171,8 @@ void script_add_translatable_string_posthook(const struct script_string_buf *str
script->parser_current_npc_name ? script->parser_current_npc_name : "Unknown NPC",
VECTOR_DATA(lang_export_escaped_buf)
);
- lang_export_stringcount++;
+ lang_export_stringcount_total++;
+ lang_export_stringcount_current++;
VECTOR_TRUNCATE(lang_export_line_buf);
VECTOR_TRUNCATE(lang_export_escaped_buf);
}
@@ -214,44 +198,184 @@ void script_parser_clean_leftovers_posthook(void)
VECTOR_CLEAR(lang_export_escaped_buf);
}
+bool translations_enter_file(const char *filepath)
+{
+ const char *p = NULL;
+ int len, i;
+
+ if (!generating_translations)
+ return false;
+
+ p = filepath;
+ len = (int)strlen(filepath) + (int)strlen(DIRECTORYNAME) + (int)strlen(PATHSEP_STR);
+ lang_export_filepath = aCalloc(len + 4 + 1, sizeof(char)); // + ".pot"
+ strncat(lang_export_filepath, DIRECTORYNAME PATHSEP_STR, len);
+ lang_export_stringcount_current = 0;
+
+ i = (int)strlen(lang_export_filepath);
+ while (*p != '\0') {
+ if (Assert_chk(i < len)) {
+ aFree(lang_export_filepath);
+ lang_export_filepath = NULL;
+ return false;
+ }
+ if (*p == '.') {
+ lang_export_filepath[i] = '_';
+ } else if (*p == PATHSEP) {
+ if (!createdirectory(lang_export_filepath)) {
+ ShowError("generatetranslations: Unable to create output directory '%s'.\n", lang_export_filepath);
+ aFree(lang_export_filepath);
+ lang_export_filepath = NULL;
+ return false;
+ }
+ lang_export_filepath[i] = PATHSEP;
+ } else {
+ lang_export_filepath[i] = *p;
+ }
+ i++;
+ p++;
+ }
+ strncat(lang_export_filepath, ".pot", len + 4);
+
+ if ((lang_export_fp = fopen(lang_export_filepath, "wb")) == NULL) {
+ ShowError("export-dialog: failed to open '%s' for writing\n", lang_export_filepath);
+ aFree(lang_export_filepath);
+ lang_export_filepath = NULL;
+ return false;
+ }
+
+ {
+ time_t t = time(NULL);
+ struct tm *lt = localtime(&t);
+ int year = lt->tm_year+1900;
+ char timestring[128] = "";
+ strftime(timestring, sizeof(timestring), "%Y-%m-%d %H:%M:%S%z", lt);
+ fprintf(lang_export_fp,
+ "# This file is part of Hercules.\n"
+ "# http://herc.ws - http://github.com/HerculesWS/Hercules\n"
+ "#\n"
+ "# Copyright (C) 2013-%d Hercules Dev Team\n"
+ "#\n"
+ "# Hercules is free software: you can redistribute it and/or modify\n"
+ "# it under the terms of the GNU General Public License as published by\n"
+ "# the Free Software Foundation, either version 3 of the License, or\n"
+ "# (at your option) any later version.\n"
+ "#\n"
+ "# This program is distributed in the hope that it will be useful,\n"
+ "# but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "# GNU General Public License for more details.\n"
+ "#\n"
+ "# You should have received a copy of the GNU General Public License\n"
+ "# along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
+
+ "#,fuzzy\n"
+ "msgid \"\"\n"
+ "msgstr \"\"\n"
+ "\"Project-Id-Version: %s\\n\"\n"
+ "\"Report-Msgid-Bugs-To: dev@herc.ws\\n\"\n"
+ "\"POT-Creation-Date: %s\\n\"\n"
+ "\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n"
+ "\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n"
+ "\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n"
+ "\"Language: \\n\"\n"
+ "\"MIME-Version: 1.0\\n\"\n"
+ "\"Content-Type: text/plain; charset=ISO-8859-1\\n\"\n"
+ "\"Content-Transfer-Encoding: 8bit\\n\"\n\n",
+ year, sysinfo->vcsrevision_scripts(), timestring);
+ }
+ return true;
+}
+
+bool translations_leave_file(const char *filepath)
+{
+ if (lang_export_fp != NULL) {
+ fclose(lang_export_fp);
+ lang_export_fp = NULL;
+ }
+ if (lang_export_filepath != NULL) {
+ if (lang_export_stringcount_current == 0) {
+ remove(lang_export_filepath);
+ } else {
+ ShowMessage("\r");
+ ShowInfo("%s => %s (%d strings)\n", filepath, lang_export_filepath, lang_export_stringcount_current);
+ }
+ aFree(lang_export_filepath);
+ lang_export_filepath = NULL;
+ }
+ lang_export_stringcount_current = 0;
+ return true;
+}
+
+bool msg_config_read_prehook(const char **cfg_name, bool *allow_override)
+{
+ if (*allow_override) // allow_override is true in nested calls
+ return false;
+
+ translations_enter_file(*cfg_name);
+ return true;
+}
+
bool msg_config_read_posthook(bool retVal, const char *cfg_name, bool allow_override)
{
- static int called = 1;
+ int i;
if (!generating_translations || lang_export_fp == NULL)
return retVal;
- if (!retVal)
+ if (allow_override) // allow_override is true in nested calls
return retVal;
- if (++called == 1) { // Original
- int i;
+ if (retVal) {
for (i = 0; i < MAX_MSG; i++) {
if (atcommand->msg_table[0][i] == NULL)
continue;
- fprintf(lang_export_fp, "msgctxt \"messages.conf\"\n"
+ fprintf(lang_export_fp, "\n#: conf/messages.conf\n"
+ "# %d: %s\n"
+ "#, c-format\n"
+ "msgctxt \"messages.conf\"\n"
"msgid \"%s\"\n"
"msgstr \"\"\n",
+ i, atcommand->msg_table[0][i],
atcommand->msg_table[0][i]
);
- lang_export_stringcount++;
+ lang_export_stringcount_total++;
+ lang_export_stringcount_current++;
}
}
+ translations_leave_file(cfg_name);
+
+ return retVal;
+}
+
+int npc_parsesrcfile_prehook(const char **filepath, bool *runOnInit)
+{
+ translations_enter_file(*filepath);
+ return 0;
+}
+
+int npc_parsesrcfile_posthook(int retVal, const char *filepath, bool runOnInit)
+{
+ translations_leave_file(filepath);
return retVal;
}
HPExport void server_preinit(void)
{
addArg("--generate-translations", false, generatetranslations,
- "Creates './generated_translations.pot' file with all translateable strings from scripts, server terminates afterwards.");
+ "Creates 'generated_translations/**/*.pot' file with all translateable strings from scripts, server terminates afterwards.");
VECTOR_INIT(lang_export_line_buf);
VECTOR_INIT(lang_export_escaped_buf);
addHookPost(script, add_translatable_string, script_add_translatable_string_posthook);
addHookPre(script, parse, parse_script_prehook);
addHookPost(script, parser_clean_leftovers, script_parser_clean_leftovers_posthook);
+ addHookPre(atcommand, msg_read, msg_config_read_prehook);
addHookPost(atcommand, msg_read, msg_config_read_posthook);
- lang_export_stringcount = 0;
+ addHookPre(npc, parsesrcfile, npc_parsesrcfile_prehook);
+ addHookPost(npc, parsesrcfile, npc_parsesrcfile_posthook);
+ lang_export_stringcount_total = 0;
+ lang_export_stringcount_current = 0;
}
HPExport void plugin_init(void)
@@ -260,18 +384,12 @@ HPExport void plugin_init(void)
HPExport void server_online(void)
{
- if (generating_translations && lang_export_fp != NULL) {
- ShowInfo("Translations template exported to '%s' with %d strings.\n", lang_export_file, lang_export_stringcount);
- fclose(lang_export_fp);
- lang_export_fp = NULL;
+ if (generating_translations) {
+ ShowInfo("Translations template exported to '%s' with %d strings.\n", DIRECTORYNAME, lang_export_stringcount_total);
}
core->runflag = CORE_ST_STOP;
}
HPExport void plugin_final(void)
{
- if (lang_export_file != NULL) {
- aFree(lang_export_file);
- lang_export_file = NULL;
- }
}