Add support for gettext plurals to Lua API
This commit is contained in:
parent
116ff67c6e
commit
f866039e81
4 changed files with 125 additions and 11 deletions
|
@ -67,11 +67,10 @@ local function generate_objectives(cfg)
|
|||
local turn_limit = wesnoth.game_config.last_turn
|
||||
|
||||
if turn_limit >= current_turn then
|
||||
if turn_limit - current_turn + 1 > 1 then
|
||||
turn_counter = "<span foreground='white'><small> " .. string.format(tostring(_"(%d turns left)"), turn_limit - current_turn + 1) .. "</small></span>"
|
||||
else
|
||||
turn_counter = "<span foreground='white'><small> " .. _"(this turn left)" .. "</small></span>"
|
||||
end
|
||||
local turn_count = turn_limit - current_turn + 1
|
||||
turn_counter = _("(this turn left)", "(%d turns left)", turn_count)
|
||||
turn_counter = tostring(turn_counter):format(turn_count)
|
||||
turn_counter = "<span foreground='white'><small> " .. turn_counter .. "</small></span>"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -68,7 +68,13 @@ static int impl_gettext(lua_State *L)
|
|||
char const *m = luaL_checkstring(L, 2);
|
||||
char const *d = static_cast<char *>(lua_touserdata(L, 1));
|
||||
// Hidden metamethod, so d has to be a string. Use it to create a t_string.
|
||||
luaW_pushtstring(L, t_string(m, d));
|
||||
if(lua_isstring(L, 3)) {
|
||||
const char* pl = luaL_checkstring(L, 3);
|
||||
int count = luaL_checkinteger(L, 4);
|
||||
luaW_pushtstring(L, t_string(m, pl, count, d));
|
||||
} else {
|
||||
luaW_pushtstring(L, t_string(m, d));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
110
src/tstring.cpp
110
src/tstring.cpp
|
@ -45,6 +45,7 @@ namespace {
|
|||
const char UNTRANSLATABLE_PART = 0x02;
|
||||
const char TEXTDOMAIN_SEPARATOR = 0x03;
|
||||
const char ID_TRANSLATABLE_PART = 0x04;
|
||||
const char PLURAL_PART = 0x05;
|
||||
|
||||
std::vector<std::string> id_to_textdomain;
|
||||
std::map<std::string, unsigned int> textdomain_to_id;
|
||||
|
@ -70,18 +71,19 @@ t_string_base::walker::walker(const t_string_base& string) :
|
|||
}
|
||||
}
|
||||
|
||||
static std::string mark = std::string(TRANSLATABLE_PART, 1) + UNTRANSLATABLE_PART +
|
||||
ID_TRANSLATABLE_PART + PLURAL_PART;
|
||||
|
||||
void t_string_base::walker::update()
|
||||
{
|
||||
unsigned int id;
|
||||
|
||||
static std::string mark = std::string(TRANSLATABLE_PART, 1) + UNTRANSLATABLE_PART +
|
||||
ID_TRANSLATABLE_PART;
|
||||
|
||||
if(begin_ == string_.size())
|
||||
return;
|
||||
|
||||
switch(string_[begin_]) {
|
||||
case TRANSLATABLE_PART: {
|
||||
// Format: [TRANSLATABLE_PART]textdomain[TEXTDOMAIN_SEPARATOR]msgid[...]
|
||||
std::string::size_type textdomain_end =
|
||||
string_.find(TEXTDOMAIN_SEPARATOR, begin_ + 1);
|
||||
|
||||
|
@ -102,6 +104,7 @@ void t_string_base::walker::update()
|
|||
break;
|
||||
}
|
||||
case ID_TRANSLATABLE_PART:
|
||||
// Format: [ID_TRANSLATABLE_PART][2-byte textdomain ID]msgid[...]
|
||||
if(begin_ + 3 >= string_.size()) {
|
||||
ERR_CF << "Error: invalid string: " << string_ << std::endl;
|
||||
begin_ = string_.size();
|
||||
|
@ -139,12 +142,64 @@ void t_string_base::walker::update()
|
|||
begin_ += 1;
|
||||
break;
|
||||
|
||||
case PLURAL_PART:
|
||||
begin_ = string_.find_first_of(mark, end_ + 5);
|
||||
if(begin_ == PLURAL_PART) {
|
||||
ERR_CF << "Error: invalid string: " << string_ << std::endl;
|
||||
begin_ = string_.size();
|
||||
return;
|
||||
}
|
||||
update();
|
||||
break;
|
||||
|
||||
default:
|
||||
end_ = string_.size();
|
||||
translatable_ = false;
|
||||
textdomain_ = "";
|
||||
break;
|
||||
}
|
||||
|
||||
if(translatable_ && string_[end_] == PLURAL_PART) {
|
||||
// Format: [PLURAL_PART][4-byte count]msgid_plural[...]
|
||||
if(end_ + 5 >= string_.size()) {
|
||||
ERR_CF << "Error: invalid string: " << string_ << std::endl;
|
||||
begin_ = string_.size();
|
||||
return;
|
||||
}
|
||||
std::string::size_type real_end = string_.find_first_of(mark, end_ + 6);
|
||||
if(real_end < string_.size() && string_[real_end] == PLURAL_PART) {
|
||||
ERR_CF << "Error: invalid string: " << string_ << std::endl;
|
||||
begin_ = string_.size();
|
||||
return;
|
||||
}
|
||||
countable_ = true;
|
||||
count_ = *reinterpret_cast<const int32_t*>(string_.data() + end_ + 1);
|
||||
} else {
|
||||
countable_ = false;
|
||||
count_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string::const_iterator t_string_base::walker::plural_begin() const
|
||||
{
|
||||
if(!countable_) {
|
||||
return begin();
|
||||
}
|
||||
|
||||
return end() + 5;
|
||||
}
|
||||
|
||||
std::string::const_iterator t_string_base::walker::plural_end() const
|
||||
{
|
||||
if(!countable_) {
|
||||
return end();
|
||||
}
|
||||
|
||||
std::string::size_type pl_end = string_.find_first_of(mark, end_ + 5);
|
||||
if(pl_end == std::string::npos) {
|
||||
pl_end = string_.size();
|
||||
}
|
||||
return string_.begin() + pl_end;
|
||||
}
|
||||
|
||||
t_string_base::t_string_base() :
|
||||
|
@ -207,6 +262,43 @@ t_string_base::t_string_base(const std::string& string, const std::string& textd
|
|||
value_ += string;
|
||||
}
|
||||
|
||||
t_string_base::t_string_base(const std::string& sing, const std::string& pl, int count, const std::string& textdomain) :
|
||||
value_(1, ID_TRANSLATABLE_PART),
|
||||
translated_value_(),
|
||||
translation_timestamp_(0),
|
||||
translatable_(true),
|
||||
last_untranslatable_(false)
|
||||
{
|
||||
if (sing.empty() && pl.empty()) {
|
||||
value_.clear();
|
||||
translatable_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<std::string, unsigned int>::const_iterator idi = textdomain_to_id.find(textdomain);
|
||||
unsigned int id;
|
||||
|
||||
if(idi == textdomain_to_id.end()) {
|
||||
id = id_to_textdomain.size();
|
||||
textdomain_to_id[textdomain] = id;
|
||||
id_to_textdomain.push_back(textdomain);
|
||||
} else {
|
||||
id = idi->second;
|
||||
}
|
||||
|
||||
value_ += char(id & 0xff);
|
||||
value_ += char(id >> 8);
|
||||
value_ += sing;
|
||||
value_ += PLURAL_PART;
|
||||
|
||||
char count_val[4];
|
||||
*reinterpret_cast<int32_t*>(count_val) = count;
|
||||
for(char c : count_val) {
|
||||
value_ += c;
|
||||
}
|
||||
value_ += pl;
|
||||
}
|
||||
|
||||
t_string_base::t_string_base(const char* string) :
|
||||
value_(string),
|
||||
translated_value_(),
|
||||
|
@ -444,7 +536,12 @@ const std::string& t_string_base::str() const
|
|||
std::string part(w.begin(), w.end());
|
||||
|
||||
if(w.translatable()) {
|
||||
translated_value_ += translation::dsgettext(w.textdomain().c_str(), part.c_str());
|
||||
if(w.countable()) {
|
||||
std::string plural(w.plural_begin(), w.plural_end());
|
||||
translated_value_ += translation::dsngettext(w.textdomain().c_str(), part.c_str(), plural.c_str(), w.count());
|
||||
} else {
|
||||
translated_value_ += translation::dsgettext(w.textdomain().c_str(), part.c_str());
|
||||
}
|
||||
} else {
|
||||
translated_value_ += part;
|
||||
}
|
||||
|
@ -482,6 +579,11 @@ t_string::t_string(const std::string &o, const std::string &textdomain) : val_(n
|
|||
{
|
||||
}
|
||||
|
||||
t_string::t_string(const std::string &s, const std::string& pl, int c, const std::string &textdomain)
|
||||
: val_(new base(s, pl, c, textdomain))
|
||||
{
|
||||
}
|
||||
|
||||
t_string &t_string::operator=(const t_string &o)
|
||||
{
|
||||
val_ = o.val_;
|
||||
|
|
|
@ -34,9 +34,13 @@ public:
|
|||
bool eos() const { return begin_ == string_.size(); }
|
||||
bool last() const { return end_ == string_.size(); }
|
||||
bool translatable() const { return translatable_; }
|
||||
bool countable() const { return countable_; }
|
||||
int count() const { return count_; }
|
||||
const std::string& textdomain() const { return textdomain_; }
|
||||
std::string::const_iterator begin() const { return string_.begin() + begin_; }
|
||||
std::string::const_iterator end() const { return string_.begin() + end_; }
|
||||
std::string::const_iterator plural_begin() const;
|
||||
std::string::const_iterator plural_end() const;
|
||||
private:
|
||||
void update();
|
||||
|
||||
|
@ -44,7 +48,8 @@ public:
|
|||
std::string::size_type begin_;
|
||||
std::string::size_type end_;
|
||||
std::string textdomain_;
|
||||
bool translatable_;
|
||||
bool translatable_, countable_;
|
||||
int count_;
|
||||
};
|
||||
|
||||
friend class walker;
|
||||
|
@ -56,6 +61,7 @@ public:
|
|||
t_string_base(const t_string_base&);
|
||||
t_string_base(const std::string& string);
|
||||
t_string_base(const std::string& string, const std::string& textdomain);
|
||||
t_string_base(const std::string& sing, const std::string& pl, int count, const std::string& textdomain);
|
||||
t_string_base(const char* string);
|
||||
|
||||
static t_string_base from_serialized(const std::string& string);
|
||||
|
@ -129,6 +135,7 @@ public:
|
|||
t_string(const char *);
|
||||
t_string(const std::string &);
|
||||
t_string(const std::string &str, const std::string &textdomain);
|
||||
t_string(const std::string& sing, const std::string& pl, int count, const std::string& textdomain);
|
||||
|
||||
t_string &operator=(const char *o);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue