nana/include/nana/internationalization.hpp

250 lines
6.6 KiB
C++

/*
* An Implementation of i18n
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/internationalization.hpp
*/
#ifndef NANA_INTERNATIONALIZATION_HPP
#define NANA_INTERNATIONALIZATION_HPP
#include <vector>
#include <sstream>
#include <functional>
#include <memory>
#include <nana/deploy.hpp>
namespace nana
{
class internationalization
{
friend class i18n_eval;
public:
/// Sets a handler to handle a msgid which hasn't been translated.
static void set_missing(std::function<void(const std::string& msgid_utf8)> handler);
void load(const std::string& file);
void load_utf8(const std::string& file);
template<typename ...Args>
::std::string get(std::string msgid_utf8, Args&&... args) const
{
std::vector<std::string> arg_strs;
#ifdef __cpp_fold_expressions
(_m_fetch_args(arg_strs, std::forward<Args>(args)),...);
#else
_m_fetch_args(arg_strs, std::forward<Args>(args)...);
#endif
auto msgstr = _m_get(std::move(msgid_utf8));
_m_replace_args(msgstr, &arg_strs);
return msgstr;
}
::std::string get(std::string msgid_utf8) const;
void set(std::string msgid_utf8, ::std::string msgstr);
template<typename ...Args>
::std::string operator()(std::string msgid_utf8, Args&&... args) const
{
return get(msgid_utf8, std::forward<Args>(args)...);
}
private:
std::string _m_get(std::string&& msgid) const;
void _m_replace_args(::std::string& str, std::vector<::std::string> * arg_strs) const;
#ifndef __cpp_fold_expressions
static void _m_fetch_args(std::vector<std::string>&); //Termination of _m_fetch_args
#endif
static void _m_fetch_args(std::vector<std::string>& v, const char* arg);
static void _m_fetch_args(std::vector<std::string>& v, const std::string& arg);
static void _m_fetch_args(std::vector<std::string>& v, std::string& arg);
static void _m_fetch_args(std::vector<std::string>& v, std::string&& arg);
static void _m_fetch_args(std::vector<std::string>& v, const wchar_t* arg);
static void _m_fetch_args(std::vector<std::string>& v, const std::wstring& arg);
static void _m_fetch_args(std::vector<std::string>& v, std::wstring& arg);
static void _m_fetch_args(std::vector<std::string>& v, std::wstring&& arg);
template<typename Arg>
static void _m_fetch_args(std::vector<std::string>& v, Arg&& arg)
{
std::stringstream ss;
ss << arg;
v.emplace_back(ss.str());
}
#ifndef __cpp_fold_expressions
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, const char* arg, Args&&... args) const
{
v.emplace_back(arg);
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, const std::string& arg, Args&&... args) const
{
v.emplace_back(arg);
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, std::string& arg, Args&&... args) const
{
v.emplace_back(arg);
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, std::string&& arg, Args&&... args) const
{
v.emplace_back(std::move(arg));
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, const wchar_t* arg, Args&&... args) const
{
v.emplace_back(to_utf8(arg));
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, const std::wstring& arg, Args&&... args) const
{
v.emplace_back(to_utf8(arg));
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, std::wstring& arg, Args&&... args) const
{
v.emplace_back(to_utf8(arg));
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, std::wstring&& arg, Args&&... args) const
{
v.emplace_back(to_utf8(arg));
_m_fetch_args(v, std::forward<Args>(args)...);
}
template<typename Arg, typename ...Args>
void _m_fetch_args(std::vector<std::string>& v, Arg&& arg, Args&&... args) const
{
std::stringstream ss;
ss << arg;
v.emplace_back(ss.str());
_m_fetch_args(v, std::forward<Args>(args)...);
}
#endif
};//end class internationalization
class i18n_eval
{
class eval_arg
{
public:
virtual ~eval_arg() = default;
virtual std::string eval() const = 0;
virtual std::unique_ptr<eval_arg> clone() const = 0;
};
class arg_string;
class arg_eval;
template<typename Return>
class arg_function: public eval_arg
{
public:
arg_function(std::function<Return()> fn)
: fn_(fn)
{}
std::string eval() const override
{
std::stringstream ss;
ss << fn_();
return ss.str();
}
std::unique_ptr<eval_arg> clone() const override
{
return std::unique_ptr<eval_arg>(new arg_function(*this));
}
private:
std::function<Return()> fn_;
};
public:
i18n_eval() = default;
template<typename ...Args>
i18n_eval(std::string msgid_utf8, Args&&... args)
: msgid_(std::move(msgid_utf8))
{
#ifdef __cpp_fold_expressions
(_m_fetch_args(std::forward<Args>(args)), ...);
#else
_m_fetch_args(std::forward<Args>(args)...);
#endif
}
i18n_eval(const i18n_eval&);
//Workaround for VC2013, becuase it can't specified a default explicit move-constructor
i18n_eval(i18n_eval&&); //= default
i18n_eval& operator=(const i18n_eval&);
i18n_eval& operator=(i18n_eval&& rhs);
std::string operator()() const;
private:
#ifndef __cpp_fold_expressions
void _m_fetch_args(){} //Termination of _m_fetch_args
template<typename Arg, typename ...Args>
void _m_fetch_args(Arg&& arg, Args&&... args)
{
_m_add_args(std::forward<Arg>(arg));
_m_fetch_args(std::forward<Args>(args)...);
}
#endif
template<typename Arg>
void _m_add_args(Arg&& arg)
{
std::stringstream ss;
ss << arg;
_m_add_args(ss.str());
}
template<typename Return>
void _m_add_args(std::function<Return()> fn)
{
args_.emplace_back(new arg_function<Return>(fn));
}
void _m_add_args(i18n_eval&);
void _m_add_args(const i18n_eval&);
void _m_add_args(i18n_eval&&);
void _m_add_args(std::string&);
void _m_add_args(const std::string&);
void _m_add_args(std::string&&);
void _m_add_args(const std::wstring&);
private:
std::string msgid_;
std::vector<std::unique_ptr<eval_arg>> args_;
};//end class i18n_eval;
}
#endif//NANA_I18N_HPP