40 #include "compose.hpp"
43 #include "language_tag.h"
44 #include <boost/algorithm/string.hpp>
53 using boost::optional;
54 using boost::algorithm::trim;
58 static vector<LanguageTag::SubtagData> language_list;
59 static vector<LanguageTag::SubtagData> variant_list;
60 static vector<LanguageTag::SubtagData> region_list;
61 static vector<LanguageTag::SubtagData> script_list;
62 static vector<LanguageTag::SubtagData> extlang_list;
64 static vector<pair<string, string>> dcnc_list;
68 optional<LanguageTag::SubtagData>
69 find_in_list (vector<LanguageTag::SubtagData>
const& list,
string subtag)
71 for (
auto const& i: list) {
72 if (boost::iequals(i.subtag, subtag)) {
81 LanguageTag::Subtag::Subtag (
string subtag, SubtagType type)
84 if (!get_subtag_data(type, subtag)) {
85 throw LanguageTagError(String::compose(
"Unknown %1 string %2", subtag_type_name(type), subtag));
90 LanguageTag::LanguageTag (
string tag)
93 boost::split (parts, tag, boost::is_any_of(
"-"));
95 throw LanguageTagError (String::compose(
"Could not parse language tag %1", tag));
98 vector<string>::size_type p = 0;
99 _language = LanguageSubtag (parts[p]);
102 if (p == parts.size()) {
107 _script = ScriptSubtag (parts[p]);
111 if (p == parts.size()) {
116 _region = RegionSubtag (parts[p]);
120 if (p == parts.size()) {
126 _variants.push_back (VariantSubtag(parts[p]));
128 if (p == parts.size()) {
136 _extlangs.push_back (ExtlangSubtag(parts[p]));
138 if (p == parts.size()) {
144 if (p < parts.size()) {
145 throw LanguageTagError (String::compose(
"Unrecognised subtag %1", parts[p]));
151 LanguageTag::to_string ()
const
157 auto s = _language->subtag();
160 s +=
"-" + _script->subtag();
164 s +=
"-" + _region->subtag();
167 for (
auto i: _variants) {
168 s +=
"-" + i.subtag();
171 for (
auto i: _extlangs) {
172 s +=
"-" + i.subtag();
180 LanguageTag::set_language (LanguageSubtag language)
182 _language = language;
187 LanguageTag::set_script (ScriptSubtag script)
194 LanguageTag::set_region (RegionSubtag region)
201 LanguageTag::add_variant (VariantSubtag variant)
203 if (find(_variants.begin(), _variants.end(), variant) != _variants.end()) {
204 throw LanguageTagError (String::compose(
"Duplicate Variant subtag %1", variant.subtag()));
207 _variants.push_back (variant);
213 check_for_duplicates (vector<T>
const& subtags, dcp::LanguageTag::SubtagType type)
215 vector<T> sorted = subtags;
216 sort (sorted.begin(), sorted.end());
218 for (
auto const& i: sorted) {
219 if (last && i == *last) {
220 throw LanguageTagError (String::compose(
"Duplicate %1 subtag %2", dcp::LanguageTag::subtag_type_name(type), i.subtag()));
228 LanguageTag::set_variants (vector<VariantSubtag> variants)
230 check_for_duplicates (variants, SubtagType::VARIANT);
231 _variants = variants;
236 LanguageTag::add_extlang (ExtlangSubtag extlang)
238 if (find(_extlangs.begin(), _extlangs.end(), extlang) != _extlangs.end()) {
239 throw LanguageTagError (String::compose(
"Duplicate Extlang subtag %1", extlang.subtag()));
242 _extlangs.push_back (extlang);
247 LanguageTag::set_extlangs (vector<ExtlangSubtag> extlangs)
249 check_for_duplicates (extlangs, SubtagType::EXTLANG);
250 _extlangs = extlangs;
255 LanguageTag::description ()
const
263 for (
auto const& i: _variants) {
264 optional<SubtagData> variant = get_subtag_data (SubtagType::VARIANT, i.subtag());
265 DCP_ASSERT (variant);
266 d += variant->description +
" dialect of ";
269 auto language = get_subtag_data (SubtagType::LANGUAGE, _language->subtag());
270 DCP_ASSERT (language);
271 d += language->description;
274 auto script = get_subtag_data (SubtagType::SCRIPT, _script->subtag());
276 d +=
" written using the " + script->description +
" script";
280 auto region = get_subtag_data (SubtagType::REGION, _region->subtag());
282 d +=
" for " + region->description;
285 for (
auto const& i: _extlangs) {
286 auto extlang = get_subtag_data (SubtagType::EXTLANG, i.subtag());
287 DCP_ASSERT (extlang);
288 d +=
", " + extlang->description;
295 vector<LanguageTag::SubtagData>
const &
296 LanguageTag::get_all (SubtagType type)
299 case SubtagType::LANGUAGE:
300 return language_list;
301 case SubtagType::SCRIPT:
303 case SubtagType::REGION:
305 case SubtagType::VARIANT:
307 case SubtagType::EXTLANG:
311 return language_list;
316 LanguageTag::subtag_type_name (SubtagType type)
319 case SubtagType::LANGUAGE:
321 case SubtagType::SCRIPT:
323 case SubtagType::REGION:
325 case SubtagType::VARIANT:
327 case SubtagType::EXTLANG:
335 dcp::LanguageTag::VariantSubtag::operator== (VariantSubtag
const & other)
const
337 return subtag() == other.subtag();
342 dcp::LanguageTag::VariantSubtag::operator< (VariantSubtag
const & other)
const
344 return subtag() < other.subtag();
349 dcp::LanguageTag::ExtlangSubtag::operator== (ExtlangSubtag
const & other)
const
351 return subtag() == other.subtag();
356 dcp::LanguageTag::ExtlangSubtag::operator< (ExtlangSubtag
const & other)
const
358 return subtag() < other.subtag();
365 return a.to_string() == b.to_string();
372 return a.to_string() != b.to_string();
379 return a.to_string() < b.to_string();
386 os << tag.to_string();
391 vector<pair<LanguageTag::SubtagType, LanguageTag::SubtagData>>
392 LanguageTag::subtags ()
const
394 vector<pair<SubtagType, SubtagData>> s;
397 s.push_back (make_pair(SubtagType::LANGUAGE, *get_subtag_data(SubtagType::LANGUAGE, _language->subtag())));
401 s.push_back (make_pair(SubtagType::SCRIPT, *get_subtag_data(SubtagType::SCRIPT, _script->subtag())));
405 s.push_back (make_pair(SubtagType::REGION, *get_subtag_data(SubtagType::REGION, _region->subtag())));
408 for (
auto const& i: _variants) {
409 s.push_back (make_pair(SubtagType::VARIANT, *get_subtag_data(SubtagType::VARIANT, i.subtag())));
412 for (
auto const& i: _extlangs) {
413 s.push_back (make_pair(SubtagType::EXTLANG, *get_subtag_data(SubtagType::EXTLANG, i.subtag())));
420 optional<LanguageTag::SubtagData>
421 LanguageTag::get_subtag_data (LanguageTag::SubtagType type,
string subtag)
424 case SubtagType::LANGUAGE:
425 return find_in_list(language_list, subtag);
426 case SubtagType::SCRIPT:
427 return find_in_list(script_list, subtag);
428 case SubtagType::REGION:
429 return find_in_list(region_list, subtag);
430 case SubtagType::VARIANT:
431 return find_in_list(variant_list, subtag);
432 case SubtagType::EXTLANG:
433 return find_in_list(extlang_list, subtag);
441 LanguageTag::get_subtag_description (LanguageTag::SubtagType type,
string subtag)
443 auto data = get_subtag_data (type, subtag);
448 return data->description;
453 load_language_tag_list (boost::filesystem::path tags_directory,
string name, std::function<
void (std::string, std::string)> add)
457 throw FileError (
"Could not open tags file", tags_directory / name, errno);
463 char* r = fgets (buffer,
sizeof(buffer), f);
469 r = fgets (buffer,
sizeof(buffer), f);
472 throw FileError (
"Bad tags file", tags_directory / name, -1);
485 dcp::load_language_tag_lists (boost::filesystem::path tags_directory)
487 auto add_subtag = [](vector<LanguageTag::SubtagData>& list,
string a,
string b) {
491 load_language_tag_list (tags_directory,
"language", [&add_subtag](
string a,
string b) { add_subtag(language_list, a, b); });
492 load_language_tag_list (tags_directory,
"variant", [&add_subtag](
string a,
string b) { add_subtag(variant_list, a, b); });
493 load_language_tag_list (tags_directory,
"region", [&add_subtag](
string a,
string b) { add_subtag(region_list, a, b); });
494 load_language_tag_list (tags_directory,
"script", [&add_subtag](
string a,
string b) { add_subtag(script_list, a, b); });
495 load_language_tag_list (tags_directory,
"extlang", [&add_subtag](
string a,
string b) { add_subtag(extlang_list, a, b); });
497 load_language_tag_list (tags_directory,
"dcnc", [](
string a,
string b) { dcnc_list.push_back(make_pair(a, b)); });
501 vector<pair<string, string>> dcp::dcnc_tags ()
An exception related to a file.
Exceptions thrown by libdcp.
Namespace for everything in libdcp.
FILE * fopen_boost(boost::filesystem::path, std::string)