6 #ifndef SPIRIT_PO_CATALOG_HPP_INCLUDED
7 #define SPIRIT_PO_CATALOG_HPP_INCLUDED
11 #ifndef BOOST_SPIRIT_USE_PHOENIX_V3
12 #define BOOST_SPIRIT_USE_PHOENIX_V3
18 #if (!defined SPIRIT_PO_NO_EXCEPTIONS) && (defined SPIRIT_PO_NOEXCEPT)
19 #define SPIRIT_PO_NO_EXCEPTIONS
28 #include <boost/spirit/include/qi.hpp>
32 #include <unordered_map>
37 namespace spirit = boost::spirit;
38 namespace qi = spirit::qi;
44 template <
typename hashmap_type = default_hashmap_type,
typename pf_compiler = default_plural_forms::compiler>
51 #ifdef SPIRIT_PO_NO_EXCEPTIONS
52 boost::optional<std::string> error_message_;
62 const char EOT =
static_cast<char>(4);
68 return msgctxt + EOT +
id;
82 if (
msg.strings().size() == 1) {
return msg.strings()[0]; }
88 if (idx >=
msg.strings().size()) { idx = 0; }
89 return msg.strings()[idx];
96 if (!
msg.strings().size()) {
return; }
100 if (!
msg.strings()[0].size()) {
return; }
105 warning_channel_(
"Ignoring a message with an incorrect number of plural forms: plural = " + std::to_string(
msg.strings().size()) +
" msgid = '" +
msg.id +
"'");
116 if (!result.second) {
118 std::string warning =
"Overwriting a message: msgid = <<<" +
msg.id +
">>>";
119 if (
msg.context) { warning +=
" msgctxt = <<<" + *
msg.context +
">>>"; }
122 result.first->second = std::move(
msg);
127 #ifdef SPIRIT_PO_NO_EXCEPTIONS
131 explicit operator bool()
const {
132 return !error_message_;
135 std::string error()
const {
136 return *error_message_;
143 template <
typename Iterator>
151 typedef spirit::line_pos_iterator<Iterator> iterator_type;
155 std::size_t line_no = 0;
161 if (!qi::parse(it, end, grammar,
msg)) {
162 int err_line = it.position();
172 if (
msg.strings().size()) {
174 if (maybe_error.size()) {
195 "On input n = 1, returned plural = " + std::to_string(
singular_index_) +
", "
199 msg.line_no = line_no;
216 line_no = it.position();
218 if (!qi::parse(it, end, grammar,
msg)) {
219 int err_line = it.position();
221 "started at " + std::to_string(line_no) +
": , stopped at " + std::to_string(err_line) +
":\n"
225 if (!
msg.id.size()) {
226 int err_line = it.position();
228 "Started at " + std::to_string(line_no) +
": , stopped at " + std::to_string(err_line) +
":\n"
231 msg.line_no = line_no;
237 #ifdef SPIRIT_PO_DEBUG
240 if (!
p.second.strings().size()) {
SPIRIT_PO_CATALOG_FAIL((
"Internal catalog error: found a message id with no strings, msgid='" +
p.first +
"'")); }
242 SPIRIT_PO_CATALOG_FAIL((
"Internal catalog error: found a message id with wrong number of strings, msgid='" +
p.first +
"' num msgstr = " + std::to_string(
p.second.strings().size()) +
", catalog num_plural_forms = " + std::to_string(
metadata_.
num_plural_forms) +
"\nWhole message: " + debug_string(
p.second) ));
249 template <
typename Iterator>
251 spirit::line_pos_iterator<Iterator> it{
b};
252 spirit::line_pos_iterator<Iterator> end{
e};
256 template <
typename Iterator>
262 template <
typename Range>
264 auto it = boost::begin(range);
265 auto end = boost::end(range);
271 is.unsetf(std::ios::skipws);
272 spirit::istream_iterator it(is);
273 spirit::istream_iterator end;
291 const char *
gettext(
const char * msgid)
const {
294 return this->
get(it->second).c_str();
300 const char *
ngettext(
const char * msgid,
const char * msgid_plural,
uint plural)
const {
302 if (it !=
hashmap_.end() && it->second.is_plural()) {
303 return this->
get(it->second, plural).c_str();
305 return (plural == 1 ? msgid : msgid_plural);
309 const char *
pgettext(
const char * context,
const char * msgid)
const {
312 return this->
get(it->second).c_str();
318 const char *
npgettext(
const char * context,
const char * msgid,
const char * msgid_plural,
uint plural)
const {
320 if (it !=
hashmap_.end() && it->second.is_plural()) {
321 return this->
get(it->second, plural).c_str();
323 return (plural == 1 ? msgid : msgid_plural);
336 template <
typename S>
340 return this->
get(it->second);
342 return std::forward<S>(msgid);
346 template <
typename S1,
typename S2>
349 if (it !=
hashmap_.end() && it->second.is_plural()) {
350 return this->
get(it->second, plural);
353 return std::forward<S1>(msgid);
355 return std::forward<S2>(msgid_plural);
360 template <
typename S>
364 return this->
get(it->second);
366 return std::forward<S>(msgid);
370 template <
typename S1,
typename S2>
373 if (it !=
hashmap_.end() && it->second.is_plural()) {
374 return this->
get(it->second, plural);
377 return std::forward<S1>(msgid);
379 return std::forward<S2>(msgid_plural);
393 std::string
ngettext_str(std::string && msgid, std::string && msgid_plural,
uint plural)
const {
return this->
ngettext_str_impl(std::move(msgid), std::move(msgid_plural), plural); }
398 std::string
npgettext_str(
const std::string & context,
const std::string & msgid,
const std::string & msgid_plural,
uint plural)
const {
return this->
npgettext_str_impl(context, msgid, msgid_plural, plural); }
399 std::string
npgettext_str(
const std::string & context, std::string && msgid,
const std::string & msgid_plural,
uint plural)
const {
return this->
npgettext_str_impl(context, std::move(msgid), msgid_plural, plural); }
400 std::string
npgettext_str(
const std::string & context,
const std::string & msgid, std::string && msgid_plural,
uint plural)
const {
return this->
npgettext_str_impl(context, msgid, std::move(msgid_plural), plural); }
401 std::string
npgettext_str(
const std::string & context, std::string && msgid, std::string && msgid_plural,
uint plural)
const {
return this->
npgettext_str_impl(context, std::move(msgid), std::move(msgid_plural), plural); }
409 return it->second.line_no;
415 std::size_t
pgettext_line_no(
const std::string & context,
const std::string & msgid)
const {
418 return it->second.line_no;
450 template <
typename H,
typename P>
453 if (maybe_error.size()) {
456 for (
auto &
p : other.hashmap_) {
457 if (
p.first.size()) {
static catalog from_range(const Range &range, warning_channel_type w=warning_channel_type())
std::string ngettext_str(std::string &&msgid, const std::string &msgid_plural, uint plural) const
pf_compiler::result_type pf_function_object_
std::string pgettext_str(const std::string &context, std::string &&msgid) const
catalog(spirit::line_pos_iterator< Iterator > &it, spirit::line_pos_iterator< Iterator > &end, warning_channel_type warn_channel=warning_channel_type(), pf_compiler compiler=pf_compiler())
std::string pgettext_str(const std::string &context, const std::string &msgid) const
std::string npgettext_str(const std::string &context, const std::string &msgid, std::string &&msgid_plural, uint plural) const
std::size_t gettext_line_no(const std::string &msgid) const
catalog_metadata metadata_
std::string npgettext_str(const std::string &context, std::string &&msgid, const std::string &msgid_plural, uint plural) const
std::string gettext_str(std::string &&msgid) const
std::string pgettext_str_impl(const std::string &context, S &&msgid) const
std::string npgettext_str(const std::string &context, const std::string &msgid, const std::string &msgid_plural, uint plural) const
static catalog from_iterators(spirit::line_pos_iterator< Iterator > &b, spirit::line_pos_iterator< Iterator > &e, warning_channel_type w=warning_channel_type())
std::string ngettext_str(std::string &&msgid, std::string &&msgid_plural, uint plural) const
const char * npgettext(const char *context, const char *msgid, const char *msgid_plural, uint plural) const
const char * ngettext(const char *msgid, const char *msgid_plural, uint plural) const
std::string ngettext_str_impl(S1 &&msgid, S2 &&msgid_plural, uint plural) const
static catalog from_iterators(Iterator &b, Iterator &e, warning_channel_type w=warning_channel_type())
void set_warning_channel(const warning_channel_type &w)
const char * pgettext(const char *context, const char *msgid) const
static std::string form_index(const po_message &msg)
warning_channel_type warning_channel_
const hashmap_type & get_hashmap() const
std::string npgettext_str_impl(const std::string &context, S1 &&msgid, S2 &&msgid_plural, uint plural) const
std::string npgettext_str(const std::string &context, std::string &&msgid, std::string &&msgid_plural, uint plural) const
const std::string & get(const po_message &msg, uint plural) const
std::string ngettext_str(const std::string &msgid, const std::string &msgid_plural, uint plural) const
void merge(catalog< H, P > &&other)
std::string gettext_str(const std::string &msgid) const
std::size_t pgettext_line_no(const std::string &context, const std::string &msgid) const
static catalog from_istream(std::istream &is, warning_channel_type w=warning_channel_type())
std::string gettext_str_impl(S &&msgid) const
static std::string form_context_index(const std::string &msgctxt, const std::string &id)
const std::string & get(const po_message &msg) const
const char * gettext(const char *msgid) const
void insert_message(po_message &&msg)
const catalog_metadata & get_metadata() const
std::string ngettext_str(const std::string &msgid, std::string &&msgid_plural, uint plural) const
std::string id
Text to match against addon_info.tags()
std::string iterator_context(Iterator &it, Iterator &end)
std::function< void(const std::string &)> warning_channel_type
std::unordered_map< std::string, po_message > default_hashmap_type
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
#define SPIRIT_PO_CATALOG_FAIL(Message)
qi::rule< Iterator > skipped_block
qi::rule< Iterator, bool()> message_preamble
consume any number of non-white comment line (using #).
qi::rule< Iterator > ignored_comments
consume any number of blocks, consisting of any number of comments followed by a white line