40 #include "compose.hpp"
45 #include <boost/algorithm/string.hpp>
54 using boost::algorithm::trim;
55 using boost::optional;
59 static vector<LanguageTag::SubtagData> language_list;
60 static vector<LanguageTag::SubtagData> variant_list;
61 static vector<LanguageTag::SubtagData> region_list;
62 static vector<LanguageTag::SubtagData> script_list;
63 static vector<LanguageTag::SubtagData> extlang_list;
65 static vector<pair<string, string>> dcnc_list;
69 optional<LanguageTag::SubtagData>
70 find_in_list (vector<LanguageTag::SubtagData>
const& list,
string subtag)
72 for (
auto const& i: list) {
73 if (boost::iequals(i.subtag, subtag)) {
82 LanguageTag::Subtag::Subtag (
string subtag, SubtagType type)
85 if (!get_subtag_data(type, subtag)) {
86 throw LanguageTagError(String::compose(
"Unknown %1 string %2", subtag_type_name(type), subtag));
91 LanguageTag::LanguageTag (
string tag)
94 boost::split (parts, tag, boost::is_any_of(
"-"));
96 throw LanguageTagError (String::compose(
"Could not parse language tag %1", tag));
99 vector<string>::size_type p = 0;
100 _language = LanguageSubtag (parts[p]);
103 if (p == parts.size()) {
108 _script = ScriptSubtag (parts[p]);
112 if (p == parts.size()) {
117 _region = RegionSubtag (parts[p]);
121 if (p == parts.size()) {
127 _variants.push_back (VariantSubtag(parts[p]));
129 if (p == parts.size()) {
137 _extlangs.push_back (ExtlangSubtag(parts[p]));
139 if (p == parts.size()) {
145 if (p < parts.size()) {
146 throw LanguageTagError (String::compose(
"Unrecognised subtag %1", parts[p]));
152 LanguageTag::to_string ()
const
158 auto s = _language->subtag();
161 s +=
"-" + _script->subtag();
165 s +=
"-" + _region->subtag();
168 for (
auto i: _variants) {
169 s +=
"-" + i.subtag();
172 for (
auto i: _extlangs) {
173 s +=
"-" + i.subtag();
181 LanguageTag::set_language (LanguageSubtag language)
183 _language = language;
188 LanguageTag::set_script (ScriptSubtag script)
195 LanguageTag::set_region (RegionSubtag region)
202 LanguageTag::add_variant (VariantSubtag variant)
204 if (find(_variants.begin(), _variants.end(), variant) != _variants.end()) {
205 throw LanguageTagError (String::compose(
"Duplicate Variant subtag %1", variant.subtag()));
208 _variants.push_back (variant);
214 check_for_duplicates (vector<T>
const& subtags, dcp::LanguageTag::SubtagType type)
216 vector<T> sorted = subtags;
217 sort (sorted.begin(), sorted.end());
219 for (
auto const& i: sorted) {
220 if (last && i == *last) {
221 throw LanguageTagError (String::compose(
"Duplicate %1 subtag %2", dcp::LanguageTag::subtag_type_name(type), i.subtag()));
229 LanguageTag::set_variants (vector<VariantSubtag> variants)
231 check_for_duplicates (variants, SubtagType::VARIANT);
232 _variants = variants;
237 LanguageTag::add_extlang (ExtlangSubtag extlang)
239 if (find(_extlangs.begin(), _extlangs.end(), extlang) != _extlangs.end()) {
240 throw LanguageTagError (String::compose(
"Duplicate Extlang subtag %1", extlang.subtag()));
243 _extlangs.push_back (extlang);
248 LanguageTag::set_extlangs (vector<ExtlangSubtag> extlangs)
250 check_for_duplicates (extlangs, SubtagType::EXTLANG);
251 _extlangs = extlangs;
256 LanguageTag::description ()
const
264 for (
auto const& i: _variants) {
265 optional<SubtagData> variant = get_subtag_data (SubtagType::VARIANT, i.subtag());
266 DCP_ASSERT (variant);
267 d += variant->description +
" dialect of ";
270 auto language = get_subtag_data (SubtagType::LANGUAGE, _language->subtag());
271 DCP_ASSERT (language);
272 d += language->description;
275 auto script = get_subtag_data (SubtagType::SCRIPT, _script->subtag());
277 d +=
" written using the " + script->description +
" script";
281 auto region = get_subtag_data (SubtagType::REGION, _region->subtag());
283 d +=
" for " + region->description;
286 for (
auto const& i: _extlangs) {
287 auto extlang = get_subtag_data (SubtagType::EXTLANG, i.subtag());
288 DCP_ASSERT (extlang);
289 d +=
", " + extlang->description;
296 vector<LanguageTag::SubtagData>
const &
297 LanguageTag::get_all (SubtagType type)
300 case SubtagType::LANGUAGE:
301 return language_list;
302 case SubtagType::SCRIPT:
304 case SubtagType::REGION:
306 case SubtagType::VARIANT:
308 case SubtagType::EXTLANG:
312 return language_list;
317 LanguageTag::subtag_type_name (SubtagType type)
320 case SubtagType::LANGUAGE:
322 case SubtagType::SCRIPT:
324 case SubtagType::REGION:
326 case SubtagType::VARIANT:
328 case SubtagType::EXTLANG:
339 return a.to_string() == b.to_string();
346 return a.to_string() != b.to_string();
353 return a.to_string() < b.to_string();
360 os << tag.to_string();
365 vector<pair<LanguageTag::SubtagType, LanguageTag::SubtagData>>
366 LanguageTag::subtags ()
const
368 vector<pair<SubtagType, SubtagData>> s;
371 s.push_back (make_pair(SubtagType::LANGUAGE, *get_subtag_data(SubtagType::LANGUAGE, _language->subtag())));
375 s.push_back (make_pair(SubtagType::SCRIPT, *get_subtag_data(SubtagType::SCRIPT, _script->subtag())));
379 s.push_back (make_pair(SubtagType::REGION, *get_subtag_data(SubtagType::REGION, _region->subtag())));
382 for (
auto const& i: _variants) {
383 s.push_back (make_pair(SubtagType::VARIANT, *get_subtag_data(SubtagType::VARIANT, i.subtag())));
386 for (
auto const& i: _extlangs) {
387 s.push_back (make_pair(SubtagType::EXTLANG, *get_subtag_data(SubtagType::EXTLANG, i.subtag())));
394 optional<LanguageTag::SubtagData>
395 LanguageTag::get_subtag_data (LanguageTag::SubtagType type,
string subtag)
398 case SubtagType::LANGUAGE:
399 return find_in_list(language_list, subtag);
400 case SubtagType::SCRIPT:
401 return find_in_list(script_list, subtag);
402 case SubtagType::REGION:
403 return find_in_list(region_list, subtag);
404 case SubtagType::VARIANT:
405 return find_in_list(variant_list, subtag);
406 case SubtagType::EXTLANG:
407 return find_in_list(extlang_list, subtag);
415 LanguageTag::get_subtag_description (LanguageTag::SubtagType type,
string subtag)
417 auto data = get_subtag_data (type, subtag);
422 return data->description;
427 load_language_tag_list (boost::filesystem::path tags_directory,
string name, std::function<
void (std::string, std::string)> add)
429 File f(tags_directory / name,
"r");
431 throw FileError (
"Could not open tags file", tags_directory / name, errno);
436 char* r = f.gets(buffer,
sizeof(buffer));
442 r = f.gets(buffer,
sizeof(buffer));
444 throw FileError (
"Bad tags file", tags_directory / name, -1);
454 dcp::load_language_tag_lists (boost::filesystem::path tags_directory)
456 auto add_subtag = [](vector<LanguageTag::SubtagData>& list,
string a,
string b) {
460 load_language_tag_list (tags_directory,
"language", [&add_subtag](
string a,
string b) { add_subtag(language_list, a, b); });
461 load_language_tag_list (tags_directory,
"variant", [&add_subtag](
string a,
string b) { add_subtag(variant_list, a, b); });
462 load_language_tag_list (tags_directory,
"region", [&add_subtag](
string a,
string b) { add_subtag(region_list, a, b); });
463 load_language_tag_list (tags_directory,
"script", [&add_subtag](
string a,
string b) { add_subtag(script_list, a, b); });
464 load_language_tag_list (tags_directory,
"extlang", [&add_subtag](
string a,
string b) { add_subtag(extlang_list, a, b); });
466 load_language_tag_list (tags_directory,
"dcnc", [](
string a,
string b) { dcnc_list.push_back(make_pair(a, b)); });
470 vector<pair<string, string>> dcp::dcnc_tags ()
An exception related to a file.
Exceptions thrown by libdcp.
Namespace for everything in libdcp.