16#include <simgear/structure/exception.hxx>
17#include <simgear/debug/logstream.hxx>
34bool DefaultTranslationParser::asBoolean(
const string& str)
38 }
else if (str ==
"false") {
42 const string message = (
"invalid boolean value '" + str +
43 "' (expected 'true' or 'false')");
44 const sg_location location(getPath(), getLine(), getColumn());
45 throw sg_io_exception(message, location, SG_ORIGIN,
false);
48[[noreturn]]
void DefaultTranslationParser::parseError(
const string& message)
50 const sg_location location(getPath(), getLine(), getColumn());
51 throw sg_io_exception(message, location, SG_ORIGIN,
false);
55 const XMLAttributes& attrs)
58 const char* hasPluralStr = attrs.getValue(
"has-plural");
61 case State::LOOKING_FOR_RESOURCE_ELEMENT:
62 if (!std::strcmp(
name,
"resource")) {
63 _state = State::LOOKING_FOR_META_ELEMENT;
65 parseError(
"Expected the root element to be 'resource', "
66 "but found '" +
string(
name) +
"' instead");
69 case State::LOOKING_FOR_META_ELEMENT:
70 if (!std::strcmp(
name,
"meta")) {
71 _state = State::READING_META_ELEMENT;
73 parseError(
"Expected a 'meta' element here, but found '"
74 +
string(
name) +
"' instead");
77 case State::READING_META_ELEMENT:
78 allowedElement =
false;
80 for (
const string eltName : {
"file-type",
"format-version",
"description",
81 "language-description"}) {
82 if (
name == eltName) {
83 startElementInsideMeta(eltName);
84 allowedElement =
true;
89 if (!allowedElement) {
90 parseError(
"Unexpected element '" +
string(
name) +
91 "' inside 'meta' element");
94 case State::LOOKING_FOR_STRINGS_ELEMENT:
95 if (!std::strcmp(
name,
"strings")) {
96 _state = State::READING_STRINGS_ELEMENT;
98 parseError(
"Expected a 'strings' element after 'meta', but found '"
99 +
string(
name) +
"'");
102 case State::READING_STRINGS_ELEMENT:
103 _stringTagName =
name;
104 _hasPlural = hasPluralStr && asBoolean(hasPluralStr);
106 _state = State::READING_TRANSLATABLE_STRING;
108 case State::READING_FILE_TYPE_ELEMENT:
109 parseError(
"Unexpected element '" +
string(
name) +
110 "' inside <file-type>");
111 case State::READING_FORMAT_VERSION_ELEMENT:
112 parseError(
"Unexpected element '" +
string(
name) +
113 "' inside <format-version>");
114 case State::READING_TRANSLATABLE_STRING:
115 parseError(
"Unexpected element '" +
string(
name) +
116 "' inside translatable string '" + _stringTagName +
"'");
117 case State::AFTER_STRINGS_ELEMENT:
118 parseError(
"Unexpected element '" +
string(
name) +
119 "' after the 'strings' element");
123void DefaultTranslationParser::startElementInsideMeta(
const std::string&
name)
125 if (
name ==
"file-type") {
126 if (_foundFileType) {
127 parseError(
"Only one 'file-type' element is allowed inside 'meta'.");
130 _foundFileType =
true;
131 _state = State::READING_FILE_TYPE_ELEMENT;
132 }
else if (
name ==
"format-version") {
133 if (_foundFormatVersion) {
134 parseError(
"Only one 'format-version' element is allowed inside "
138 _foundFormatVersion =
true;
139 _state = State::READING_FORMAT_VERSION_ELEMENT;
147 const string expectedFileType =
"FlightGear default translation file";
148 const string expectedFormatVersion =
"1";
151 case State::LOOKING_FOR_RESOURCE_ELEMENT:
154 case State::LOOKING_FOR_META_ELEMENT:
155 parseError(
"Expected a 'meta' element as the first child of 'resource'");
156 case State::READING_FILE_TYPE_ELEMENT:
157 _fileType = std::move(_text);
159 if (_fileType != expectedFileType) {
160 parseError(
"Expected body of 'file-type' element to be '" +
161 expectedFileType +
"', not '" + _fileType +
"'");
164 _state = State::READING_META_ELEMENT;
166 case State::READING_FORMAT_VERSION_ELEMENT:
167 _formatVersion = std::move(_text);
169 if (_formatVersion != expectedFormatVersion) {
170 parseError(
"Expected body of 'format-version' element to be '" +
171 expectedFormatVersion +
"', not '" + _formatVersion +
175 _state = State::READING_META_ELEMENT;
177 case State::READING_META_ELEMENT:
178 if (!std::strcmp(
name,
"meta")) {
179 checkIfFormatIsSupported();
180 _state = State::LOOKING_FOR_STRINGS_ELEMENT;
184 case State::LOOKING_FOR_STRINGS_ELEMENT:
188 case State::READING_TRANSLATABLE_STRING:
189 _resource->addTranslationUnit(std::move(_stringTagName),
190 _nextIndex[_stringTagName]++,
191 std::move(_text), _hasPlural);
192 _state = State::READING_STRINGS_ELEMENT;
194 case State::READING_STRINGS_ELEMENT:
195 _state = State::AFTER_STRINGS_ELEMENT;
197 case State::AFTER_STRINGS_ELEMENT:
198 assert(!std::strcmp(
name,
"resource"));
204 _text += string(s, len);
210 SG_LOG(SG_GENERAL, SG_WARN,
"Warning: " << message <<
" (line " << line
211 <<
", column " << column <<
')');
214void DefaultTranslationParser::checkIfFormatIsSupported()
216 if (!_foundFileType) {
217 parseError(
"'file-type' element is required inside the 'meta' element");
218 }
else if (!_foundFormatVersion) {
219 parseError(
"'format-version' element is required inside the 'meta' "
Parse a FlightGear default translation file (e.g., menu.xml)
Class that holds translation units within a resource (“context”)
void endElement(const char *name) override
void data(const char *s, int len) override
void startElement(const char *name, const XMLAttributes &atts) override
DefaultTranslationParser(TranslationResource *resource)
void warning(const char *message, int line, int column) override
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...