The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
catalog_metadata.hpp
Go to the documentation of this file.
1// (C) Copyright 2015 - 2017 Christopher Beck
2
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#ifndef SPIRIT_PO_CATALOG_METADATA_HPP_INCLUDED
7#define SPIRIT_PO_CATALOG_METADATA_HPP_INCLUDED
8
9#ifndef BOOST_SPIRIT_USE_PHOENIX_V3
10#define BOOST_SPIRIT_USE_PHOENIX_V3
11#endif
12
14
15#include <boost/spirit/include/qi.hpp>
16#include <boost/fusion/include/std_pair.hpp>
17#include <string>
18
19namespace spirit_po {
20
21namespace qi = boost::spirit::qi;
22
23typedef unsigned int uint;
24typedef std::pair<uint, std::string> num_plurals_info;
25
27 std::string project_id;
28 std::string language;
29 std::string language_team;
30 std::string last_translator;
31
34
35 std::string charset;
36
45
46private:
47 std::string find_header_line(const std::string & header, const std::string & label) {
48 std::size_t idx = header.find(label);
49 if (idx == std::string::npos) {
50 return "";
51 }
52 auto it = header.begin() + idx + label.size();
53 while (it != header.end() && *it == ' ') { ++it; }
54
55 auto e = it;
56 while (e != header.end() && *e != '\n') { ++e; }
57 return std::string(it, e);
58 }
59
60 template <typename Iterator>
61 struct num_plurals_grammar : qi::grammar<Iterator, num_plurals_info()> {
62 qi::rule<Iterator, num_plurals_info()> main;
64 using qi::lit;
65 main = qi::skip(' ') [ lit("nplurals=") >> qi::uint_ >> lit(';') >> lit("plural=") ] >> (*qi::char_);
66 }
67 };
68
69#define SPIRIT_PO_DEFAULT_CHARSET "UTF-8"
70
71 template <typename Iterator>
72 struct content_type_grammar : qi::grammar<Iterator, std::string()> {
73 qi::rule<Iterator, std::string()> main;
75 using qi::lit;
76 using qi::omit;
77 using qi::skip;
78 main = skip(' ')[ omit[ *(qi::char_ - ';') >> lit(';') ] >> ((lit("charset=") >> *(qi::char_)) | qi::attr(SPIRIT_PO_DEFAULT_CHARSET)) ];
79 }
80 };
81
82public:
83 // nonempty return is an error message
84 std::string parse_header(const std::string & header) {
85 const char * const default_charset = SPIRIT_PO_DEFAULT_CHARSET;
86#undef SPIRIT_PO_DEFAULT_CHARSET
87
88 project_id = find_header_line(header, "Project-Id-Version:");
89 language = find_header_line(header, "Language:");
90 language_team = find_header_line(header, "Language-Team:");
91 last_translator = find_header_line(header, "Last-Translator:");
92
93 std::string content_type_line = find_header_line(header, "Content-Type:");
94 if (content_type_line.size()) {
95 auto it = content_type_line.begin();
96 auto end = content_type_line.end();
97 content_type_grammar<decltype(it)> gram;
98 std::string ct;
99 if (qi::parse(it, end, gram, ct)) {
100 charset = ct;
101 if (charset != "ASCII" && charset != "UTF-8") {
102 return "PO file declared charset of '" + charset + "', but spirit_po only supports UTF-8 and ASCII for this.";
103 }
104 }
105 } else {
106 // Assume defaults for charset
107 charset = default_charset;
108 }
109
110 std::string content_transfer_encoding = find_header_line(header, "Content-Transfer-Encoding:");
111 if (content_transfer_encoding.size()) {
112 auto it = content_transfer_encoding.begin();
113 auto end = content_transfer_encoding.end();
114 if (!qi::phrase_parse(it, end, qi::lit("8bit"), qi::ascii::space)) {
115 return "PO header 'Content-Transfer-Encoding' must be '8bit' if specified, but PO file declared '" + content_transfer_encoding + "'";
116 }
117 }
118
119 std::string num_plurals_line = find_header_line(header, "Plural-Forms:");
120
121 if (num_plurals_line.size()) {
122 auto it = num_plurals_line.begin();
123 auto end = num_plurals_line.end();
124
125 num_plurals_grammar<decltype(it)> gram;
126 num_plurals_info info;
127 if (qi::parse(it, end, gram, info)) {
128 num_plural_forms = info.first;
129 plural_forms_function_string = info.second;
130 } else {
133 return "Failed to parse Plural-Forms entry -- stopped at:\n" + string_iterator_context(num_plurals_line, it);
134 }
135 } else {
138 }
139 return "";
140 }
141
142 // check if this metadata is compatible with another metadata (number of plural forms, maybe other criteria)
143 // return a nonempty string containing error message if they are not compatible.
144 std::string check_compatibility(const catalog_metadata & other) const {
145 if (num_plural_forms != other.num_plural_forms) {
146 return std::string{"Num plural forms mismatch. this = "} + std::to_string(num_plural_forms) + " other = " + std::to_string(other.num_plural_forms);
147 }
148 return "";
149 }
150};
151
152} // end namespace spirit_po
153
154#endif // SPIRIT_PO_CATALOG_METADATA_HPP_INCLUDED
#define SPIRIT_PO_DEFAULT_CHARSET
std::string label
What to show in the filter's drop-down list.
Definition manager.cpp:201
std::string string_iterator_context(const std::string &str, std::string::const_iterator it)
std::pair< uint, std::string > num_plurals_info
unsigned int uint
Definition catalog.hpp:39
qi::rule< Iterator, num_plurals_info()> main
std::string parse_header(const std::string &header)
std::string check_compatibility(const catalog_metadata &other) const
std::string find_header_line(const std::string &header, const std::string &label)
#define e