context.hpp (3426B)
1 #ifndef GUARD_UBIQUITOUSLY_HANGABLE_VANITORY_MAMMERS_6659 2 #define GUARD_UBIQUITOUSLY_HANGABLE_VANITORY_MAMMERS_6659 3 #pragma once 4 5 #include "libshit/except.hpp" 6 #include "libshit/nonowning_string.hpp" 7 #include "libshit/translate/base.hpp" 8 #include "libshit/translate/defines.hpp" 9 #include "libshit/translate/plural.hpp" 10 11 #include <boost/container/flat_map.hpp> 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <functional> 16 #include <iosfwd> 17 #include <map> 18 #include <string> 19 #include <type_traits> 20 #include <vector> 21 22 #if LIBSHIT_TRANSLATE_YAML 23 # include "libshit/yaml.hpp" 24 #endif 25 // IWYU pragma: no_forward_declare YAML::convert 26 27 namespace Libshit::Translate 28 { 29 class Node; 30 inline constexpr std::size_t MAX_CASES = 100; 31 32 struct LanguageInfo 33 { 34 ~LanguageInfo() noexcept = default; 35 36 // posix: lang[_territory][.codeset][@modifier] (eg. en_US.UTF-8, be_BY.UTF-8@latin) 37 // windows: lang[-script]-region[_shit] (eg. en-US, uz-Latn-UZ) 38 // wine ignores @modifier, generated locale has no script 39 // used by us: lang[_territory] 40 std::string name, en_name, iso_code; 41 std::string decimal_sep, digit_sep; 42 unsigned grouping = 3; 43 std::vector<std::string> cases; 44 std::vector<std::string> genders; 45 std::vector<NotNullSharedPtr<const ASTNode>> plural_exprs; 46 std::uint8_t plural_count = 1; 47 48 boost::container::flat_map<std::string, std::string> macros; 49 50 LIBSHIT_TRANSLATE_WITH_YAML(void Read(const YAML::Node& node)); 51 LIBSHIT_TRANSLATE_WITH_DUMP(void Dump(std::ostream& os) const); 52 }; 53 54 class Context : public RefCounted 55 { 56 public: 57 Context() noexcept; 58 // only public for tests 59 Context(const LanguageInfo& info); 60 ~Context() noexcept override; 61 62 // workaround having to include Node implementation... 63 template <bool B = true> 64 NotNullNodePtr operator[](StringView key) const 65 { return std::enable_if_t<B, const Context*>(this)->root[key]; } 66 67 LIBSHIT_TRANSLATE_WITH_YAML(void Load(std::istream& is, std::string dir = {})); 68 LIBSHIT_TRANSLATE_WITH_YAML(void Load(const std::string& fname)); 69 70 unsigned GetCaseId(Libshit::StringView str); 71 unsigned AtCaseId(Libshit::StringView str) const; 72 73 unsigned GetGenderId(Libshit::StringView str) const; 74 unsigned AtGenderId(Libshit::StringView str) const; 75 76 const LanguageInfo& GetInfo() const noexcept { return info; } 77 // warning: fucking slow 78 const std::vector<std::string>& GetNodePath(const Node* ptr); 79 80 NotNullNodePtr GetRoot() const noexcept; 81 82 LIBSHIT_TRANSLATE_WITH_DUMP(void Dump( 83 StringView ns, StringView name, std::ostream& cpp, std::ostream& hpp, 84 StringView hpp_name) const); 85 86 protected: 87 void Dispose() noexcept override; 88 89 LanguageInfo info; 90 NodePtr root; 91 92 private: 93 boost::container::flat_map<std::string, unsigned, std::less<>> 94 case_map, gender_map; 95 std::map<const Node*, std::vector<std::string>> invalid_cache; 96 }; 97 98 LIBSHIT_GEN_EXCEPTION_TYPE(TranslationError, std::runtime_error); 99 LIBSHIT_GEN_EXCEPTION_TYPE(LanguageInfoError, TranslationError); 100 } 101 102 #if LIBSHIT_TRANSLATE_YAML 103 namespace YAML 104 { 105 template <> struct convert<Libshit::Translate::LanguageInfo> 106 { 107 using LI = Libshit::Translate::LanguageInfo; 108 static bool decode(const Node& node, LI& li) 109 { 110 try { li.Read(node); return true; } 111 catch (const Libshit::Translate::TranslationError&) { return false; } 112 } 113 }; 114 } 115 #endif 116 117 #endif