diff --git a/conf/bnetd.conf.in b/conf/bnetd.conf.in index 52250d9..e8f1872 100644 --- a/conf/bnetd.conf.in +++ b/conf/bnetd.conf.in @@ -128,6 +128,9 @@ newsfile = news.txt helpfile = bnhelp.conf tosfile = termsofservice.txt +# Do localization by a game language or by user country? +localize_by_country = true + # # ############################################################################## diff --git a/conf/bnetd.conf.win32 b/conf/bnetd.conf.win32 index c65a56b..b6bce9e 100644 --- a/conf/bnetd.conf.win32 +++ b/conf/bnetd.conf.win32 @@ -106,6 +106,9 @@ newsfile = news.txt helpfile = bnhelp.conf tosfile = termsofservice.txt +# Do localization by a game language or by user country? +localize_by_country = true + # # ############################################################################## diff --git a/src/bnetd/channel.cpp b/src/bnetd/channel.cpp index 57d8792..d8caa47 100644 --- a/src/bnetd/channel.cpp +++ b/src/bnetd/channel.cpp @@ -762,7 +762,7 @@ namespace pvpgn if ((conn_get_wol(me) == 0)) { if (!heard && (type == message_type_talk || type == message_type_emote)) - message_send_text(me, message_type_info, me, "No one hears you."); + message_send_text(me, message_type_info, me, localize(c, "No one hears you.")); } #ifdef WITH_LUA diff --git a/src/bnetd/command.cpp b/src/bnetd/command.cpp index 6be2cf5..e68a1b1 100644 --- a/src/bnetd/command.cpp +++ b/src/bnetd/command.cpp @@ -4633,7 +4633,7 @@ namespace pvpgn char const * filename; std::FILE * fp; - filename = i18n_filename(prefs_get_motdfile(), conn_get_gamelang(c)); + filename = i18n_filename(prefs_get_motdfile(), conn_get_gamelang_localized(c)); if (fp = std::fopen(filename, "r")) { @@ -4656,7 +4656,7 @@ namespace pvpgn const char * filename = NULL; std::FILE * fp; - filename = i18n_filename(prefs_get_tosfile(), conn_get_gamelang(c)); + filename = i18n_filename(prefs_get_tosfile(), conn_get_gamelang_localized(c)); /* FIXME: if user enters relative path to tos file in config, above routine will fail */ diff --git a/src/bnetd/connection.cpp b/src/bnetd/connection.cpp index 0ffd930..65cdca1 100644 --- a/src/bnetd/connection.cpp +++ b/src/bnetd/connection.cpp @@ -128,8 +128,7 @@ namespace pvpgn return; } if (filename = prefs_get_motdfile()) { - t_tag gamelang = conn_get_gamelang(c); - std::string lang_filename = i18n_filename(filename, gamelang); + std::string lang_filename = i18n_filename(filename, conn_get_gamelang_localized(c)); if (fp = std::fopen(lang_filename.c_str(), "r")) { message_send_file(c, fp); diff --git a/src/bnetd/file.cpp b/src/bnetd/file.cpp index 1094c11..0c02197 100644 --- a/src/bnetd/file.cpp +++ b/src/bnetd/file.cpp @@ -51,7 +51,7 @@ namespace pvpgn namespace bnetd { - static char const * file_get_info(char const * rawname, unsigned int * len, bn_long * modtime); + static char const * file_get_info(t_connection * c, char const * rawname, unsigned int * len, bn_long * modtime); /* Requested files aliases */ const char * requestfiles[] = { @@ -64,7 +64,7 @@ namespace pvpgn NULL, NULL }; - static const char * file_find_localized(const char *rawname) + static const char * file_find_localized(t_connection * c, const char *rawname) { const char ** pattern, **alias; @@ -74,20 +74,25 @@ namespace pvpgn if (!std::strncmp(rawname, *pattern, std::strlen(*pattern))) { t_gamelang lang; - // when file transferring by bnftp protofol client doesn't provide a language - // but we can extract it from the filename + if (lang = conn_get_gamelang_localized(c)) + return i18n_filename(*alias, lang); + + // FIXME: when file is transferring by bnftp protofol client doesn't provide a language + // but we can extract it from the filename, so do it in next code // if there is no country tag in the file (just in case to prevent crash from invalid filename) if ((strlen(*pattern) + 4) > strlen(rawname)) return NULL; - // get language tag from the file name + // get language tag from the file name (like "termsofservice-ruRU.txt") + // (it used in War3) char langstr[5]; strncpy(langstr, rawname + std::strlen(*pattern), 4); langstr[4] = 0; lang = tag_str_to_uint(langstr); - // if language is invalid then try find it by code + // if language is invalid then try find it by country (like "tos_USA.txt") + // (it used in D1, SC, War2) if (!tag_check_gamelang(lang)) { strncpy(langstr, rawname + std::strlen(*pattern), 3); @@ -101,7 +106,7 @@ namespace pvpgn return NULL; } - static char const * file_get_info(char const * rawname, unsigned int * len, bn_long * modtime) + static char const * file_get_info(t_connection * c, char const * rawname, unsigned int * len, bn_long * modtime) { const char *filename; t_bnettime bt; @@ -128,7 +133,7 @@ namespace pvpgn } - filename = file_find_localized(rawname); + filename = file_find_localized(c, rawname); // if localized file not found in "i18n" if (!filename || stat(filename, &sfile) < 0) { @@ -148,7 +153,7 @@ namespace pvpgn } - extern int file_to_mod_time(char const * rawname, bn_long * modtime) + extern int file_to_mod_time(t_connection * c, char const * rawname, bn_long * modtime) { char const * filename; unsigned int len; @@ -164,7 +169,7 @@ namespace pvpgn return -1; } - if (!(filename = file_get_info(rawname, &len, modtime))) + if (!(filename = file_get_info(c, rawname, &len, modtime))) return -1; xfree((void *)filename); /* avoid warning */ @@ -204,7 +209,7 @@ namespace pvpgn packet_set_size(rpacket, sizeof(t_server_file_reply)); packet_set_type(rpacket, SERVER_FILE_REPLY); - if ((filename = file_get_info(rawname, &filelen, &rpacket->u.server_file_reply.timestamp))) + if ((filename = file_get_info(c, rawname, &filelen, &rpacket->u.server_file_reply.timestamp))) { if (!(fp = std::fopen(filename, "rb"))) { diff --git a/src/bnetd/file.h b/src/bnetd/file.h index f878013..23f13c3 100644 --- a/src/bnetd/file.h +++ b/src/bnetd/file.h @@ -33,7 +33,7 @@ namespace pvpgn namespace bnetd { - extern int file_to_mod_time(char const * rawname, bn_long * modtime); + extern int file_to_mod_time(t_connection * c, char const * rawname, bn_long * modtime); extern int file_send(t_connection * c, char const * rawname, unsigned int adid, unsigned int etag, unsigned int startoffset, int need_header); } diff --git a/src/bnetd/handle_bnet.cpp b/src/bnetd/handle_bnet.cpp index 6456edc..a0a0015 100644 --- a/src/bnetd/handle_bnet.cpp +++ b/src/bnetd/handle_bnet.cpp @@ -582,7 +582,7 @@ namespace pvpgn bn_int_set(&rpacket->u.server_authreq_109.sessionkey, conn_get_sessionkey(c)); bn_int_set(&rpacket->u.server_authreq_109.sessionnum, conn_get_sessionnum(c)); - file_to_mod_time(versioncheck_get_mpqfile(vc), &rpacket->u.server_authreq_109.timestamp); + file_to_mod_time(c, versioncheck_get_mpqfile(vc), &rpacket->u.server_authreq_109.timestamp); packet_append_string(rpacket, versioncheck_get_mpqfile(vc)); packet_append_string(rpacket, versioncheck_get_eqn(vc)); eventlog(eventlog_level_debug, __FUNCTION__, "[%d] selected \"%s\" \"%s\"", conn_get_socket(c), versioncheck_get_mpqfile(vc), versioncheck_get_eqn(vc)); @@ -649,7 +649,7 @@ namespace pvpgn if ((rpacket = packet_create(packet_class_bnet))) { packet_set_size(rpacket, sizeof(t_server_authreq1)); packet_set_type(rpacket, SERVER_AUTHREQ1); - file_to_mod_time(versioncheck_get_mpqfile(vc), &rpacket->u.server_authreq1.timestamp); + file_to_mod_time(c, versioncheck_get_mpqfile(vc), &rpacket->u.server_authreq1.timestamp); packet_append_string(rpacket, versioncheck_get_mpqfile(vc)); packet_append_string(rpacket, versioncheck_get_eqn(vc)); eventlog(eventlog_level_debug, __FUNCTION__, "[%d] selected \"%s\" \"%s\"", conn_get_socket(c), versioncheck_get_mpqfile(vc), versioncheck_get_eqn(vc)); @@ -1219,7 +1219,7 @@ namespace pvpgn if ((rpacket = packet_create(packet_class_bnet))) { packet_set_size(rpacket, sizeof(t_server_iconreply)); packet_set_type(rpacket, SERVER_ICONREPLY); - file_to_mod_time(prefs_get_iconfile(), &rpacket->u.server_iconreply.timestamp); + file_to_mod_time(c, prefs_get_iconfile(), &rpacket->u.server_iconreply.timestamp); /* battle.net sends different file on iconreq for WAR3 and W3XP [Omega] */ if ((conn_get_clienttag(c) == CLIENTTAG_WARCRAFT3_UINT) || (conn_get_clienttag(c) == CLIENTTAG_WAR3XP_UINT)) @@ -1397,7 +1397,7 @@ namespace pvpgn * timestamp doesn't work correctly and starcraft * needs name in client locale or displays hostname */ - file_to_mod_time(tosfile, &rpacket->u.server_fileinforeply.timestamp); + file_to_mod_time(c, tosfile, &rpacket->u.server_fileinforeply.timestamp); packet_append_string(rpacket, tosfile); conn_push_outqueue(c, rpacket); packet_del_ref(rpacket); @@ -2770,7 +2770,7 @@ namespace pvpgn char * buff, *line; std::FILE * fp; - filename = i18n_filename(prefs_get_motdw3file(), conn_get_gamelang(c)); + filename = i18n_filename(prefs_get_motdw3file(), conn_get_gamelang_localized(c)); if (fp = std::fopen(filename, "r")) { @@ -3211,7 +3211,7 @@ namespace pvpgn packet_set_type(rpacket, SERVER_ADREPLY); bn_int_set(&rpacket->u.server_adreply.adid, ad->getId()); bn_int_set(&rpacket->u.server_adreply.extensiontag, ad->getExtensionTag()); - file_to_mod_time(ad->getFilename(), &rpacket->u.server_adreply.timestamp); + file_to_mod_time(c, ad->getFilename(), &rpacket->u.server_adreply.timestamp); packet_append_string(rpacket, ad->getFilename()); packet_append_string(rpacket, ad->getLink()); conn_push_outqueue(c, rpacket); diff --git a/src/bnetd/helpfile.cpp b/src/bnetd/helpfile.cpp index 64c6154..14a36af 100644 --- a/src/bnetd/helpfile.cpp +++ b/src/bnetd/helpfile.cpp @@ -49,16 +49,15 @@ namespace pvpgn static std::FILE* get_hfd(t_connection * c) { - if (t_gamelang lang = conn_get_gamelang(c)) + t_gamelang lang = conn_get_gamelang_localized(c); + + std::map<t_gamelang, std::FILE*>::iterator it = hfd_list.find(lang); + if (it != hfd_list.end()) { - std::map<t_gamelang, std::FILE*>::iterator it = hfd_list.find(lang); - if (it != hfd_list.end()) - { - return it->second; - } - // return enUS if language is not specified in language list - return hfd_list[languages[0]]; + return it->second; } + // return enUS if language is not specified in language list + return hfd_list[languages[0]]; } extern int helpfile_init(char const *filename) diff --git a/src/bnetd/i18n.cpp b/src/bnetd/i18n.cpp index 8679756..e50fc3b 100644 --- a/src/bnetd/i18n.cpp +++ b/src/bnetd/i18n.cpp @@ -269,7 +269,7 @@ namespace pvpgn { format = fmt; - if (t_gamelang lang = conn_get_gamelang(c)) + if (t_gamelang lang = conn_get_gamelang_localized(c)) if (!(format = _find_string(fmt, lang))) format = fmt; @@ -326,11 +326,21 @@ namespace pvpgn for (int i = 0; i < (sizeof(countries) / sizeof(*countries)); i++) if (strcasecmp(code, countries[i][0]) == 0) - return tag_str_to_uint(countries[i][0]); + return tag_str_to_uint(countries[i][1]); - return tag_str_to_uint(countries[0][0]); // default + return tag_str_to_uint(countries[0][1]); // default } + extern t_gamelang conn_get_gamelang_localized(t_connection * c) + { + t_gamelang lang = conn_get_gamelang(c); + + if (prefs_get_localize_by_country()) + if (const char * country = conn_get_country(c)) + lang = lang_find_by_country(country); + + return lang; + } } } diff --git a/src/bnetd/i18n.h b/src/bnetd/i18n.h index a2f2f9b..5047bf6 100644 --- a/src/bnetd/i18n.h +++ b/src/bnetd/i18n.h @@ -48,6 +48,7 @@ namespace pvpgn extern const char * i18n_filename(const char * filename, t_tag gamelang); extern t_gamelang lang_find_by_country(const char * code); + extern t_gamelang conn_get_gamelang_localized(t_connection * c); extern std::string _localize(t_connection * c, const char * func, const char *fmt, const fmt::ArgList &args); FMT_VARIADIC(std::string, _localize, t_connection *, const char *, const char *) diff --git a/src/bnetd/prefs.cpp b/src/bnetd/prefs.cpp index 3d0731c..8f3202b 100644 --- a/src/bnetd/prefs.cpp +++ b/src/bnetd/prefs.cpp @@ -163,6 +163,7 @@ namespace pvpgn unsigned int max_connections; unsigned int sync_on_logoff; char const * irc_network_name; + unsigned int localize_by_country; char const * apiregaddrs; char const * wolv1addrs; @@ -664,6 +665,11 @@ namespace pvpgn static int conf_set_irc_network_name(const char *valstr); static const char *conf_get_irc_network_name(void); + static int conf_set_localize_by_country(const char *valstr); + static const char *conf_get_localize_by_country(void); + static int conf_setdef_localize_by_country(void); + + static int conf_setdef_apireg_addrs(void); static int conf_set_apireg_addrs(const char *valstr); static const char *conf_get_apireg_addrs(void); @@ -829,6 +835,7 @@ namespace pvpgn { "sync_on_logoff", conf_set_sync_on_logoff, conf_get_sync_on_logoff, conf_setdef_sync_on_logoff }, { "ladder_prefix", conf_set_ladder_prefix, conf_get_ladder_prefix, conf_setdef_ladder_prefix }, { "irc_network_name", conf_set_irc_network_name, conf_get_irc_network_name, conf_setdef_irc_network_name }, + { "localize_by_country", conf_set_localize_by_country, conf_get_localize_by_country, conf_setdef_localize_by_country }, { "apiregaddrs", conf_set_apireg_addrs, conf_get_apireg_addrs, conf_setdef_apireg_addrs }, { "wgameresaddrs", conf_set_wgameres_addrs, conf_get_wgameres_addrs, conf_setdef_wgameres_addrs }, @@ -3478,6 +3485,28 @@ namespace pvpgn return prefs_runtime_config.irc_network_name; } + + extern unsigned int prefs_get_localize_by_country(void) + { + return prefs_runtime_config.localize_by_country; + } + + static int conf_set_localize_by_country(const char *valstr) + { + return conf_set_bool(&prefs_runtime_config.localize_by_country, valstr, 0); + } + + static int conf_setdef_localize_by_country(void) + { + return conf_set_bool(&prefs_runtime_config.localize_by_country, NULL, 0); + } + + static const char* conf_get_localize_by_country(void) + { + return conf_get_bool(prefs_runtime_config.localize_by_country); + } + + /** * Westwood Online Extensions */ diff --git a/src/bnetd/prefs.h b/src/bnetd/prefs.h index b5855d0..f9dfbdc 100644 --- a/src/bnetd/prefs.h +++ b/src/bnetd/prefs.h @@ -179,6 +179,7 @@ namespace pvpgn extern unsigned int prefs_get_max_connections(void); extern unsigned int prefs_get_sync_on_logoff(void); extern char const * prefs_get_irc_network_name(void); + extern unsigned int prefs_get_localize_by_country(void); /** * Westwood Online Extensions