Enable loading of po files in addons
This commit is contained in:
parent
6c32ccb3c3
commit
fffe3d5d7a
2 changed files with 162 additions and 0 deletions
|
@ -1724,6 +1724,16 @@
|
|||
91B621F41B76BCB000B00E0F /* ucs4_iterator_base.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ucs4_iterator_base.hpp; sourceTree = "<group>"; };
|
||||
91B621F51B76BCB000B00E0F /* unicode_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode_cast.hpp; sourceTree = "<group>"; };
|
||||
91B621F61B76BCB000B00E0F /* unicode_types.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode_types.hpp; sourceTree = "<group>"; };
|
||||
91BE78371DD8F5DE00528C21 /* catalog.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catalog.hpp; sourceTree = "<group>"; };
|
||||
91BE78381DD8F5DE00528C21 /* catalog_metadata.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catalog_metadata.hpp; sourceTree = "<group>"; };
|
||||
91BE78391DD8F5DE00528C21 /* default_plural_forms_compiler.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = default_plural_forms_compiler.hpp; sourceTree = "<group>"; };
|
||||
91BE783A1DD8F5DE00528C21 /* default_plural_forms_expressions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = default_plural_forms_expressions.hpp; sourceTree = "<group>"; };
|
||||
91BE783B1DD8F5DE00528C21 /* exceptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = exceptions.hpp; sourceTree = "<group>"; };
|
||||
91BE783C1DD8F5DE00528C21 /* po_grammar.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = po_grammar.hpp; sourceTree = "<group>"; };
|
||||
91BE783D1DD8F5DE00528C21 /* po_message.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = po_message.hpp; sourceTree = "<group>"; };
|
||||
91BE783E1DD8F5DE00528C21 /* po_message_adapted.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = po_message_adapted.hpp; sourceTree = "<group>"; };
|
||||
91BE783F1DD8F5DE00528C21 /* version.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = version.hpp; sourceTree = "<group>"; };
|
||||
91BE78401DD8F5DE00528C21 /* spirit_po.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = spirit_po.hpp; sourceTree = "<group>"; };
|
||||
91C548CE1D8866ED00FE6A7B /* campaignd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = campaignd; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
91C548CF1D886AF000FE6A7B /* send_receive_wml_helpers.ipp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = send_receive_wml_helpers.ipp; sourceTree = "<group>"; };
|
||||
91C548D01D886AF000FE6A7B /* server_base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = server_base.cpp; sourceTree = "<group>"; };
|
||||
|
@ -3095,6 +3105,8 @@
|
|||
B52EE8C5121359A600CFBDAB /* sound_music_track.hpp */,
|
||||
B559999D0EC62181008DD061 /* soundsource.cpp */,
|
||||
B559999C0EC62181008DD061 /* soundsource.hpp */,
|
||||
91BE78361DD8F5DE00528C21 /* spirit_po */,
|
||||
91BE78401DD8F5DE00528C21 /* spirit_po.hpp */,
|
||||
B559999B0EC62181008DD061 /* statistics.cpp */,
|
||||
B559999A0EC62181008DD061 /* statistics.hpp */,
|
||||
B55999990EC62181008DD061 /* statistics_dialog.cpp */,
|
||||
|
@ -3603,6 +3615,22 @@
|
|||
path = xBRZ;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
91BE78361DD8F5DE00528C21 /* spirit_po */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
91BE78371DD8F5DE00528C21 /* catalog.hpp */,
|
||||
91BE78381DD8F5DE00528C21 /* catalog_metadata.hpp */,
|
||||
91BE78391DD8F5DE00528C21 /* default_plural_forms_compiler.hpp */,
|
||||
91BE783A1DD8F5DE00528C21 /* default_plural_forms_expressions.hpp */,
|
||||
91BE783B1DD8F5DE00528C21 /* exceptions.hpp */,
|
||||
91BE783C1DD8F5DE00528C21 /* po_grammar.hpp */,
|
||||
91BE783D1DD8F5DE00528C21 /* po_message.hpp */,
|
||||
91BE783E1DD8F5DE00528C21 /* po_message_adapted.hpp */,
|
||||
91BE783F1DD8F5DE00528C21 /* version.hpp */,
|
||||
);
|
||||
path = spirit_po;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
91EF6BF01C9E217C00E2A733 /* utils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
|
@ -15,14 +15,18 @@
|
|||
#include "global.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <boost/locale.hpp>
|
||||
// including boost/thread fixes linking of boost locale for msvc on boost 1.60
|
||||
#include <boost/thread.hpp>
|
||||
#include <set>
|
||||
|
||||
#include "spirit_po.hpp"
|
||||
|
||||
#define DBG_G LOG_STREAM(debug, lg::general())
|
||||
#define LOG_G LOG_STREAM(info, lg::general())
|
||||
#define WRN_G LOG_STREAM(warn, lg::general())
|
||||
|
@ -66,6 +70,135 @@ namespace
|
|||
|
||||
std::string name_;
|
||||
};
|
||||
class wesnoth_message_format : public bl::message_format<char>
|
||||
{
|
||||
using po_catalog = spirit_po::catalog<>;
|
||||
public:
|
||||
wesnoth_message_format(std::locale base, const std::set<std::string>& domains, const std::set<std::string>& paths)
|
||||
: base_loc_(base)
|
||||
{
|
||||
const bl::info& inf = std::use_facet<bl::info>(base);
|
||||
if(inf.language() == "c") {
|
||||
return;
|
||||
}
|
||||
std::string lang_name_short = inf.language();
|
||||
std::string lang_name_long = lang_name_short;
|
||||
if(!inf.country().empty()) {
|
||||
lang_name_long += '_';
|
||||
lang_name_long += inf.country();
|
||||
}
|
||||
if(!inf.variant().empty()) {
|
||||
lang_name_long += '@';
|
||||
lang_name_long += inf.variant();
|
||||
lang_name_short += '@';
|
||||
lang_name_short += inf.variant();
|
||||
}
|
||||
DBG_G << "Loading po files for language " << lang_name_long << '\n';
|
||||
for(auto& domain : domains) {
|
||||
DBG_G << "Searching for po files for domain " << domain << '\n';
|
||||
std::string path;
|
||||
for(auto base_path : paths) {
|
||||
DBG_G << "Searching in dir " << base_path << '\n';
|
||||
if(base_path[base_path.length()-1] != '/') {
|
||||
base_path += '/';
|
||||
}
|
||||
base_path += domain;
|
||||
base_path += '/';
|
||||
path = base_path + lang_name_long + ".po";
|
||||
DBG_G << " Trying path " << path << '\n';
|
||||
if(filesystem::file_exists(path)) {
|
||||
break;
|
||||
}
|
||||
path = base_path + lang_name_short + ".po";
|
||||
DBG_G << " Trying path " << path << '\n';
|
||||
if(filesystem::file_exists(path)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!filesystem::file_exists(path)) {
|
||||
continue;
|
||||
}
|
||||
std::ifstream po_file;
|
||||
po_file.exceptions(std::ios::badbit);
|
||||
LOG_G << "Loading language file from " << path << '\n';
|
||||
try {
|
||||
po_file.open(path);
|
||||
const po_catalog& cat = po_catalog::from_istream(po_file);
|
||||
extra_messages_.emplace(get_base().domain(domain), cat);
|
||||
} catch(spirit_po::catalog_exception& e) {
|
||||
throw_po_error(lang_name_long, domain, e.what());
|
||||
} catch(std::ios::failure& e) {
|
||||
throw_po_error(lang_name_long, domain, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NORETURN static void throw_po_error(const std::string& lang, const std::string& dom, const std::string& detail) {
|
||||
std::ostringstream err;
|
||||
err << "Error opening language file for " << lang << ", textdomain " << dom
|
||||
<< ":\n " << detail << '\n';
|
||||
ERR_G << err.rdbuf() << std::flush;
|
||||
throw game::error(err.str());
|
||||
}
|
||||
|
||||
const char* get(int domain_id, const char* ctx, const char* id) const override
|
||||
{
|
||||
auto& base = get_base();
|
||||
const char* msg = base.get(domain_id, ctx, id);
|
||||
if(msg == nullptr) {
|
||||
auto iter = extra_messages_.find(domain_id);
|
||||
if(iter == extra_messages_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto& catalog = iter->second;
|
||||
const char* lookup = ctx ? catalog.pgettext(ctx, id) : catalog.gettext(id);
|
||||
if(lookup != id) {
|
||||
// (p)gettext returns the input pointer if the string was not found
|
||||
msg = lookup;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
const char* get(int domain_id, const char* ctx, const char* sid, int n) const override
|
||||
{
|
||||
auto& base = get_base();
|
||||
const char* msg = base.get(domain_id, ctx, sid, n);
|
||||
if(msg == nullptr) {
|
||||
auto iter = extra_messages_.find(domain_id);
|
||||
if(iter == extra_messages_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto& catalog = iter->second;
|
||||
const char* lookup = ctx ? catalog.npgettext(ctx, sid, sid, n) : catalog.ngettext(sid, sid, n);
|
||||
if(lookup != sid) {
|
||||
// n(p)gettext returns one of the input pointers if the string was not found
|
||||
msg = lookup;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
int domain(const std::string& domain) const override
|
||||
{
|
||||
auto& base = get_base();
|
||||
return base.domain(domain);
|
||||
}
|
||||
|
||||
const char* convert(const char* msg, std::string& buffer) const override
|
||||
{
|
||||
auto& base = get_base();
|
||||
return base.convert(msg, buffer);
|
||||
}
|
||||
private:
|
||||
const bl::message_format<char>& get_base() const
|
||||
{
|
||||
return std::use_facet<bl::message_format<char>>(base_loc_);
|
||||
}
|
||||
|
||||
std::locale base_loc_;
|
||||
std::map<int, po_catalog> extra_messages_;
|
||||
};
|
||||
struct translation_manager
|
||||
{
|
||||
translation_manager()
|
||||
|
@ -158,6 +291,7 @@ namespace
|
|||
{
|
||||
LOG_G << "attempting to generate locale by name '" << current_language_ << "'\n";
|
||||
current_locale_ = generator_.generate(current_language_);
|
||||
current_locale_ = std::locale(current_locale_, new wesnoth_message_format(current_locale_, loaded_domains_, loaded_paths_));
|
||||
const bl::info& info = std::use_facet<bl::info>(current_locale_);
|
||||
LOG_G << "updated locale to '" << current_language_ << "' locale is now '" << current_locale_.name() << "' ( "
|
||||
<< "name='" << info.name()
|
||||
|
|
Loading…
Add table
Reference in a new issue