mirror of https://github.com/OpenMW/openmw.git
Separate l10n manager from lua
parent
de83a41de6
commit
3697c9266b
@ -0,0 +1,95 @@
|
|||||||
|
#include "manager.hpp"
|
||||||
|
|
||||||
|
#include <unicode/errorcode.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
|
namespace l10n
|
||||||
|
{
|
||||||
|
|
||||||
|
void Manager::setPreferredLocales(const std::vector<std::string>& langs)
|
||||||
|
{
|
||||||
|
mPreferredLocales.clear();
|
||||||
|
for (const auto& lang : langs)
|
||||||
|
mPreferredLocales.push_back(icu::Locale(lang.c_str()));
|
||||||
|
{
|
||||||
|
Log msg(Debug::Info);
|
||||||
|
msg << "Preferred locales:";
|
||||||
|
for (const icu::Locale& l : mPreferredLocales)
|
||||||
|
msg << " " << l.getName();
|
||||||
|
}
|
||||||
|
for (auto& [key, context] : mCache)
|
||||||
|
updateContext(key.first, *context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::readLangData(const std::string& name, MessageBundles& ctx, const icu::Locale& lang)
|
||||||
|
{
|
||||||
|
std::string path = "l10n/";
|
||||||
|
path.append(name);
|
||||||
|
path.append("/");
|
||||||
|
path.append(lang.getName());
|
||||||
|
path.append(".yaml");
|
||||||
|
if (!mVFS->exists(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctx.load(*mVFS->get(path), lang, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Manager::updateContext(const std::string& name, MessageBundles& ctx)
|
||||||
|
{
|
||||||
|
icu::Locale fallbackLocale = ctx.getFallbackLocale();
|
||||||
|
ctx.setPreferredLocales(mPreferredLocales);
|
||||||
|
int localeCount = 0;
|
||||||
|
bool fallbackLocaleInPreferred = false;
|
||||||
|
for (const icu::Locale& loc : ctx.getPreferredLocales())
|
||||||
|
{
|
||||||
|
if (!ctx.isLoaded(loc))
|
||||||
|
readLangData(name, ctx, loc);
|
||||||
|
if (ctx.isLoaded(loc))
|
||||||
|
{
|
||||||
|
localeCount++;
|
||||||
|
Log(Debug::Verbose) << "Language file \"l10n/" << name << "/" << loc.getName() << ".yaml\" is enabled";
|
||||||
|
if (loc == ctx.getFallbackLocale())
|
||||||
|
fallbackLocaleInPreferred = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ctx.isLoaded(ctx.getFallbackLocale()))
|
||||||
|
readLangData(name, ctx, ctx.getFallbackLocale());
|
||||||
|
if (ctx.isLoaded(ctx.getFallbackLocale()) && !fallbackLocaleInPreferred)
|
||||||
|
Log(Debug::Verbose) << "Fallback language file \"l10n/" << name << "/" << ctx.getFallbackLocale().getName()
|
||||||
|
<< ".yaml\" is enabled";
|
||||||
|
|
||||||
|
if (localeCount == 0)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "No language files for the preferred languages found in \"l10n/" << name << "\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<const MessageBundles> Manager::getContext(
|
||||||
|
const std::string& contextName, const std::string& fallbackLocaleName)
|
||||||
|
{
|
||||||
|
std::pair<std::string, std::string> key(contextName, fallbackLocaleName);
|
||||||
|
auto it = mCache.find(key);
|
||||||
|
if (it != mCache.end())
|
||||||
|
return it->second;
|
||||||
|
auto allowedChar = [](char c) {
|
||||||
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_';
|
||||||
|
};
|
||||||
|
bool valid = !contextName.empty();
|
||||||
|
for (char c : contextName)
|
||||||
|
valid = valid && allowedChar(c);
|
||||||
|
if (!valid)
|
||||||
|
throw std::runtime_error(std::string("Invalid l10n context name: ") + contextName);
|
||||||
|
icu::Locale fallbackLocale(fallbackLocaleName.c_str());
|
||||||
|
std::shared_ptr<MessageBundles> ctx = std::make_shared<MessageBundles>(mPreferredLocales, fallbackLocale);
|
||||||
|
{
|
||||||
|
Log msg(Debug::Verbose);
|
||||||
|
msg << "Fallback locale: " << fallbackLocale.getName();
|
||||||
|
}
|
||||||
|
updateContext(contextName, *ctx);
|
||||||
|
mCache.emplace(key, ctx);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef COMPONENTS_L10N_MANAGER_H
|
||||||
|
#define COMPONENTS_L10N_MANAGER_H
|
||||||
|
|
||||||
|
#include <components/l10n/messagebundles.hpp>
|
||||||
|
|
||||||
|
namespace VFS
|
||||||
|
{
|
||||||
|
class Manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace l10n
|
||||||
|
{
|
||||||
|
|
||||||
|
class Manager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Manager(const VFS::Manager* vfs)
|
||||||
|
: mVFS(vfs)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void dropCache() { mCache.clear(); }
|
||||||
|
void setPreferredLocales(const std::vector<std::string>& locales);
|
||||||
|
const std::vector<icu::Locale>& getPreferredLocales() const { return mPreferredLocales; }
|
||||||
|
|
||||||
|
std::shared_ptr<const MessageBundles> getContext(
|
||||||
|
const std::string& contextName, const std::string& fallbackLocale = "en");
|
||||||
|
|
||||||
|
private:
|
||||||
|
void readLangData(const std::string& name, MessageBundles& ctx, const icu::Locale& lang);
|
||||||
|
void updateContext(const std::string& name, MessageBundles& ctx);
|
||||||
|
|
||||||
|
const VFS::Manager* mVFS;
|
||||||
|
std::vector<icu::Locale> mPreferredLocales;
|
||||||
|
std::map<std::pair<std::string, std::string>, std::shared_ptr<MessageBundles>> mCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // COMPONENTS_L10N_MANAGER_H
|
@ -1,53 +1,16 @@
|
|||||||
#ifndef COMPONENTS_LUA_I18N_H
|
#ifndef COMPONENTS_LUA_L10N_H
|
||||||
#define COMPONENTS_LUA_I18N_H
|
#define COMPONENTS_LUA_L10N_H
|
||||||
|
|
||||||
#include "luastate.hpp"
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
#include <components/l10n/messagebundles.hpp>
|
namespace l10n
|
||||||
|
|
||||||
namespace VFS
|
|
||||||
{
|
{
|
||||||
class Manager;
|
class Manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace LuaUtil
|
namespace LuaUtil
|
||||||
{
|
{
|
||||||
|
sol::function initL10nLoader(sol::state& lua, l10n::Manager* manager);
|
||||||
class L10nManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
L10nManager(const VFS::Manager* vfs, LuaState* lua)
|
|
||||||
: mVFS(vfs)
|
|
||||||
, mLua(lua)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void init();
|
|
||||||
void clear() { mContexts.clear(); }
|
|
||||||
|
|
||||||
void setPreferredLocales(const std::vector<std::string>& locales);
|
|
||||||
const std::vector<icu::Locale>& getPreferredLocales() const { return mPreferredLocales; }
|
|
||||||
|
|
||||||
sol::object getContext(const std::string& contextName, const std::string& fallbackLocale = "en");
|
|
||||||
std::string translate(const std::string& contextName, const std::string& key);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Context
|
|
||||||
{
|
|
||||||
const std::string mName;
|
|
||||||
// Must be a shared pointer so that sol::make_object copies the pointer, not the data structure.
|
|
||||||
std::shared_ptr<l10n::MessageBundles> mMessageBundles;
|
|
||||||
|
|
||||||
void updateLang(L10nManager* manager);
|
|
||||||
void readLangData(L10nManager* manager, const icu::Locale& lang);
|
|
||||||
std::string translate(std::string_view key, const sol::object& data);
|
|
||||||
};
|
|
||||||
|
|
||||||
const VFS::Manager* mVFS;
|
|
||||||
LuaState* mLua;
|
|
||||||
std::vector<icu::Locale> mPreferredLocales;
|
|
||||||
std::map<std::string, Context> mContexts;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // COMPONENTS_LUA_I18N_H
|
#endif // COMPONENTS_LUA_L10N_H
|
||||||
|
Loading…
Reference in New Issue