2015-05-31 18:09:19 -07:00
|
|
|
// tinygettext - A gettext replacement that works directly on .po files
|
|
|
|
|
// Copyright (c) 2006 Ingo Ruhnke <grumbel@gmail.com>
|
2014-04-20 12:17:32 -07:00
|
|
|
//
|
2015-05-31 18:09:19 -07:00
|
|
|
// This software is provided 'as-is', without any express or implied
|
|
|
|
|
// warranty. In no event will the authors be held liable for any damages
|
|
|
|
|
// arising from the use of this software.
|
2014-04-20 12:17:32 -07:00
|
|
|
//
|
2015-05-31 18:09:19 -07:00
|
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
|
|
|
// including commercial applications, and to alter it and redistribute it
|
|
|
|
|
// freely, subject to the following restrictions:
|
2014-04-20 12:17:32 -07:00
|
|
|
//
|
2015-05-31 18:09:19 -07:00
|
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
|
|
|
// claim that you wrote the original software. If you use this software
|
|
|
|
|
// in a product, an acknowledgement in the product documentation would be
|
|
|
|
|
// appreciated but is not required.
|
|
|
|
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
// misrepresented as being the original software.
|
|
|
|
|
// 3. This notice may not be removed or altered from any source distribution.
|
2014-04-20 12:17:32 -07:00
|
|
|
|
2014-04-24 13:05:48 -07:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
2014-04-20 12:17:32 -07:00
|
|
|
#include <assert.h>
|
2015-01-21 12:37:37 -08:00
|
|
|
|
|
|
|
|
#include "tinygettext/log_stream.hpp"
|
|
|
|
|
#include "tinygettext/dictionary.hpp"
|
2014-04-20 12:17:32 -07:00
|
|
|
|
|
|
|
|
namespace tinygettext {
|
2015-03-24 10:47:08 -07:00
|
|
|
|
2020-12-07 05:15:31 -08:00
|
|
|
namespace {
|
|
|
|
|
|
2015-12-08 10:05:11 -08:00
|
|
|
std::ostream& operator<<(std::ostream& o, const std::vector<std::string>& v)
|
|
|
|
|
{
|
|
|
|
|
for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (it != v.begin())
|
|
|
|
|
o << ", ";
|
|
|
|
|
o << "'" << *it << "'";
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-07 05:15:31 -08:00
|
|
|
} // namespace
|
|
|
|
|
|
2014-04-20 12:17:32 -07:00
|
|
|
Dictionary::Dictionary(const std::string& charset_) :
|
|
|
|
|
entries(),
|
|
|
|
|
ctxt_entries(),
|
|
|
|
|
charset(charset_),
|
2015-03-24 10:47:08 -07:00
|
|
|
plural_forms(),
|
|
|
|
|
m_has_fallback(false),
|
|
|
|
|
m_fallback()
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Dictionary::~Dictionary()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
|
|
|
|
Dictionary::get_charset() const
|
|
|
|
|
{
|
|
|
|
|
return charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Dictionary::set_plural_forms(const PluralForms& plural_forms_)
|
|
|
|
|
{
|
|
|
|
|
plural_forms = plural_forms_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PluralForms
|
|
|
|
|
Dictionary::get_plural_forms() const
|
|
|
|
|
{
|
|
|
|
|
return plural_forms;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2015-12-08 10:05:11 -08:00
|
|
|
Dictionary::translate_plural(const std::string& msgid, const std::string& msgid_plural, int num) const
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
|
|
|
|
return translate_plural(entries, msgid, msgid_plural, num);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2015-12-08 10:05:11 -08:00
|
|
|
Dictionary::translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgid_plural, int count) const
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
Entries::const_iterator it = dict.find(msgid);
|
|
|
|
|
if (it != dict.end())
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
unsigned int n = plural_forms.get_plural(count);
|
|
|
|
|
const std::vector<std::string>& msgstrs = it->second;
|
2015-03-24 10:47:08 -07:00
|
|
|
if (n >= msgstrs.size())
|
2014-07-05 03:29:24 -07:00
|
|
|
{
|
|
|
|
|
log_error << "Plural translation not available (and not set to empty): '" << msgid << "'" << std::endl;
|
|
|
|
|
log_error << "Missing plural form: " << n << std::endl;
|
|
|
|
|
return msgid;
|
2015-03-24 10:47:08 -07:00
|
|
|
}
|
|
|
|
|
|
2014-04-20 12:17:32 -07:00
|
|
|
if (!msgstrs[n].empty())
|
|
|
|
|
return msgstrs[n];
|
|
|
|
|
else
|
|
|
|
|
if (count == 1) // default to english rules
|
|
|
|
|
return msgid;
|
|
|
|
|
else
|
|
|
|
|
return msgid_plural;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_info << "Couldn't translate: " << msgid << std::endl;
|
|
|
|
|
log_info << "Candidates: " << std::endl;
|
2015-12-08 10:05:11 -08:00
|
|
|
for (it = dict.begin(); it != dict.end(); ++it)
|
|
|
|
|
log_info << "'" << it->first << "'" << std::endl;
|
2014-04-20 12:17:32 -07:00
|
|
|
|
|
|
|
|
if (count == 1) // default to english rules
|
|
|
|
|
return msgid;
|
|
|
|
|
else
|
|
|
|
|
return msgid_plural;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2015-12-08 10:05:11 -08:00
|
|
|
Dictionary::translate(const std::string& msgid) const
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
|
|
|
|
return translate(entries, msgid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2015-12-08 10:05:11 -08:00
|
|
|
Dictionary::translate(const Entries& dict, const std::string& msgid) const
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
|
|
|
|
Entries::const_iterator i = dict.find(msgid);
|
|
|
|
|
if (i != dict.end() && !i->second.empty())
|
|
|
|
|
{
|
|
|
|
|
return i->second[0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_info << "Couldn't translate: " << msgid << std::endl;
|
2015-03-24 10:47:08 -07:00
|
|
|
|
|
|
|
|
if (m_has_fallback) return m_fallback->translate(msgid);
|
|
|
|
|
else return msgid;
|
|
|
|
|
}
|
2014-04-20 12:17:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2015-12-08 10:05:11 -08:00
|
|
|
Dictionary::translate_ctxt(const std::string& msgctxt, const std::string& msgid) const
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
CtxtEntries::const_iterator i = ctxt_entries.find(msgctxt);
|
2014-04-20 12:17:32 -07:00
|
|
|
if (i != ctxt_entries.end())
|
|
|
|
|
{
|
|
|
|
|
return translate(i->second, msgid);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_info << "Couldn't translate: " << msgid << std::endl;
|
|
|
|
|
return msgid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string
|
2015-03-24 10:47:08 -07:00
|
|
|
Dictionary::translate_ctxt_plural(const std::string& msgctxt,
|
2015-12-08 10:05:11 -08:00
|
|
|
const std::string& msgid, const std::string& msgidplural, int num) const
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
CtxtEntries::const_iterator i = ctxt_entries.find(msgctxt);
|
2014-04-20 12:17:32 -07:00
|
|
|
if (i != ctxt_entries.end())
|
|
|
|
|
{
|
|
|
|
|
return translate_plural(i->second, msgid, msgidplural, num);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_info << "Couldn't translate: " << msgid << std::endl;
|
|
|
|
|
if (num != 1) // default to english
|
|
|
|
|
return msgidplural;
|
|
|
|
|
else
|
|
|
|
|
return msgid;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-24 10:47:08 -07:00
|
|
|
|
2014-04-20 12:17:32 -07:00
|
|
|
void
|
2015-12-08 10:05:11 -08:00
|
|
|
Dictionary::add_translation(const std::string& msgid, const std::string& msgid_plural,
|
2014-04-20 12:17:32 -07:00
|
|
|
const std::vector<std::string>& msgstrs)
|
|
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
std::vector<std::string>& vec = entries[msgid];
|
|
|
|
|
if (vec.empty())
|
|
|
|
|
{
|
|
|
|
|
vec = msgstrs;
|
|
|
|
|
}
|
|
|
|
|
else if (vec != msgstrs)
|
|
|
|
|
{
|
|
|
|
|
log_warning << "collision in add_translation: '"
|
|
|
|
|
<< msgid << "', '" << msgid_plural
|
|
|
|
|
<< "' -> [" << vec << "] vs [" << msgstrs << "]" << std::endl;
|
|
|
|
|
vec = msgstrs;
|
|
|
|
|
}
|
2014-04-20 12:17:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Dictionary::add_translation(const std::string& msgid, const std::string& msgstr)
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string>& vec = entries[msgid];
|
2015-01-11 11:14:03 -08:00
|
|
|
if (vec.empty())
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
|
|
|
|
vec.push_back(msgstr);
|
|
|
|
|
}
|
2015-01-11 11:14:03 -08:00
|
|
|
else if (vec[0] != msgstr)
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-03-24 10:47:08 -07:00
|
|
|
log_warning << "collision in add_translation: '"
|
2014-04-20 12:17:32 -07:00
|
|
|
<< msgid << "' -> '" << msgstr << "' vs '" << vec[0] << "'" << std::endl;
|
|
|
|
|
vec[0] = msgstr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2015-03-24 10:47:08 -07:00
|
|
|
Dictionary::add_translation(const std::string& msgctxt,
|
2014-04-20 12:17:32 -07:00
|
|
|
const std::string& msgid, const std::string& msgid_plural,
|
|
|
|
|
const std::vector<std::string>& msgstrs)
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
|
|
|
|
|
if (vec.empty())
|
|
|
|
|
{
|
|
|
|
|
vec = msgstrs;
|
|
|
|
|
}
|
2015-12-08 10:05:11 -08:00
|
|
|
else if (vec != msgstrs)
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
log_warning << "collision in add_translation: '"
|
|
|
|
|
<< msgctxt << "', '" << msgid << "', '" << msgid_plural
|
|
|
|
|
<< "' -> [" << vec << "] vs [" << msgstrs << "]" << std::endl;
|
2014-04-20 12:17:32 -07:00
|
|
|
vec = msgstrs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr)
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
|
|
|
|
|
if (vec.empty())
|
|
|
|
|
{
|
|
|
|
|
vec.push_back(msgstr);
|
|
|
|
|
}
|
2015-12-08 10:05:11 -08:00
|
|
|
else if (vec[0] != msgstr)
|
2014-04-20 12:17:32 -07:00
|
|
|
{
|
2015-12-08 10:05:11 -08:00
|
|
|
log_warning << "collision in add_translation: '"
|
|
|
|
|
<< msgctxt << "', '" << msgid
|
|
|
|
|
<< "' -> '" << vec[0] << "' vs '" << msgstr << "'" << std::endl;
|
2014-04-20 12:17:32 -07:00
|
|
|
vec[0] = msgstr;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-03-24 10:47:08 -07:00
|
|
|
|
2014-04-20 12:17:32 -07:00
|
|
|
} // namespace tinygettext
|
|
|
|
|
|
|
|
|
|
/* EOF */
|