Lazy translation during error response generation

Now when parameterized messages are added to an error response, they are
not immediately instantiated (translated). Instead the message id and
the parameters of the message are recorded. The instantiation of the
messages happens right before generating the final content of the
response.
This commit is contained in:
Veloman Yunkan 2024-01-09 23:13:23 +04:00
parent f298acd45f
commit 1553d52593
3 changed files with 39 additions and 12 deletions

View File

@ -107,6 +107,9 @@ public: // functions
std::string getText(const std::string& lang) const; std::string getText(const std::string& lang) const;
const std::string& getMsgId() const { return msgId; }
const Parameters& getParams() const { return params; }
private: // data private: // data
const std::string msgId; const std::string msgId;
const Parameters params; const Parameters params;

View File

@ -183,6 +183,18 @@ public:
return s.empty() ? Data(false) : Data(s); return s.empty() ? Data(false) : Data(s);
} }
static Data from(const ParameterizedMessage& pmsg)
{
Object obj;
for(const auto& kv : pmsg.getParams()) {
obj[kv.first] = kv.second;
}
return Object{
{ "msgid", pmsg.getMsgId() },
{ "params", Data(obj) }
};
}
private: private:
bool isString() const { return std::holds_alternative<std::string>(data); } bool isString() const { return std::holds_alternative<std::string>(data); }
bool isList() const { return std::holds_alternative<List>(data); } bool isList() const { return std::holds_alternative<List>(data); }
@ -192,6 +204,16 @@ private:
bool boolValue() const { return std::get<bool>(data); } bool boolValue() const { return std::get<bool>(data); }
const List& listValue() const { return std::get<List>(data); } const List& listValue() const { return std::get<List>(data); }
const Object& objectValue() const { return std::get<Object>(data); } const Object& objectValue() const { return std::get<Object>(data); }
const Data* get(const std::string& key) const
{
if ( !isObject() )
return nullptr;
const auto& obj = objectValue();
const auto it = obj.find(key);
return it != obj.end() ? &it->second : nullptr;
}
}; };
MustacheData ContentResponseBlueprint::Data::toMustache(const std::string& lang) const MustacheData ContentResponseBlueprint::Data::toMustache(const std::string& lang) const
@ -203,11 +225,22 @@ MustacheData ContentResponseBlueprint::Data::toMustache(const std::string& lang)
} }
return l; return l;
} else if ( this->isObject() ) { } else if ( this->isObject() ) {
const Data* msgId = this->get("msgid");
const Data* msgParams = this->get("params");
if ( msgId && msgId->isString() && msgParams && msgParams->isObject() ) {
std::map<std::string, std::string> params;
for(const auto& kv : msgParams->objectValue()) {
params[kv.first] = kv.second.stringValue();
}
const ParameterizedMessage msg(msgId->stringValue(), ParameterizedMessage::Parameters(params));
return msg.getText(lang);
} else {
kainjow::mustache::object o; kainjow::mustache::object o;
for ( const auto& kv : this->objectValue() ) { for ( const auto& kv : this->objectValue() ) {
o[kv.first] = kv.second.toMustache(lang); o[kv.first] = kv.second.toMustache(lang);
} }
return o; return o;
}
} else if ( this->isString() ) { } else if ( this->isString() ) {
return this->stringValue(); return this->stringValue();
} else { } else {
@ -229,11 +262,6 @@ ContentResponseBlueprint::ContentResponseBlueprint(const RequestContext* request
ContentResponseBlueprint::~ContentResponseBlueprint() = default; ContentResponseBlueprint::~ContentResponseBlueprint() = default;
std::string ContentResponseBlueprint::getMessage(const std::string& msgId) const
{
return getTranslatedString(m_request.get_user_language(), msgId);
}
std::unique_ptr<ContentResponse> ContentResponseBlueprint::generateResponseObject() const std::unique_ptr<ContentResponse> ContentResponseBlueprint::generateResponseObject() const
{ {
kainjow::mustache::data d = m_data->toMustache(m_request.get_user_language()); kainjow::mustache::data d = m_data->toMustache(m_request.get_user_language());
@ -255,8 +283,8 @@ HTTPErrorResponse::HTTPErrorResponse(const RequestContext& request,
Data::List emptyList; Data::List emptyList;
*this->m_data = Data(Data::Object{ *this->m_data = Data(Data::Object{
{"CSS_URL", Data::onlyAsNonEmptyValue(cssUrl) }, {"CSS_URL", Data::onlyAsNonEmptyValue(cssUrl) },
{"PAGE_TITLE", getMessage(pageTitleMsgId)}, {"PAGE_TITLE", Data::from(nonParameterizedMessage(pageTitleMsgId))},
{"PAGE_HEADING", getMessage(headingMsgId)}, {"PAGE_HEADING", Data::from(nonParameterizedMessage(headingMsgId))},
{"details", emptyList} {"details", emptyList}
}); });
} }
@ -278,8 +306,7 @@ UrlNotFoundResponse::UrlNotFoundResponse(const RequestContext& request)
HTTPErrorResponse& HTTPErrorResponse::operator+(const ParameterizedMessage& details) HTTPErrorResponse& HTTPErrorResponse::operator+(const ParameterizedMessage& details)
{ {
const std::string msg = details.getText(m_request.get_user_language()); (*m_data)["details"].push_back(Data::Object{{"p", Data::from(details)}});
(*m_data)["details"].push_back(Data::Object{{"p", msg}});
return *this; return *this;
} }

View File

@ -135,9 +135,6 @@ public: // functions
protected: // types protected: // types
class Data; class Data;
protected: // functions
std::string getMessage(const std::string& msgId) const;
protected: //data protected: //data
const RequestContext& m_request; const RequestContext& m_request;
const int m_httpStatusCode; const int m_httpStatusCode;