mirror of https://github.com/OpenMW/openmw.git
Merge branch 'l10n' into 'master'
Separate l10n manager from lua See merge request OpenMW/openmw!2451focus_on_focal
commit
e16c451d08
@ -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
|
||||
#define COMPONENTS_LUA_I18N_H
|
||||
#ifndef COMPONENTS_LUA_L10N_H
|
||||
#define COMPONENTS_LUA_L10N_H
|
||||
|
||||
#include "luastate.hpp"
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
#include <components/l10n/messagebundles.hpp>
|
||||
|
||||
namespace VFS
|
||||
namespace l10n
|
||||
{
|
||||
class Manager;
|
||||
}
|
||||
|
||||
namespace LuaUtil
|
||||
{
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
sol::function initL10nLoader(sol::state& lua, l10n::Manager* manager);
|
||||
}
|
||||
|
||||
#endif // COMPONENTS_LUA_I18N_H
|
||||
#endif // COMPONENTS_LUA_L10N_H
|
||||
|
Loading…
Reference in New Issue