/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "localization.h"
#include
#include
#include
#include
const char *Localize(const char *pStr, const char *pContext)
{
const char *pNewStr = g_Localization.FindString(str_quickhash(pStr), str_quickhash(pContext));
return pNewStr ? pNewStr : pStr;
}
CLocConstString::CLocConstString(const char *pStr, const char *pContext)
{
m_pDefaultStr = pStr;
m_Hash = str_quickhash(m_pDefaultStr);
m_ContextHash = str_quickhash(pContext);
m_Version = -1;
}
void CLocConstString::Reload()
{
m_Version = g_Localization.Version();
const char *pNewStr = g_Localization.FindString(m_Hash, m_ContextHash);
m_pCurrentStr = pNewStr;
if(!m_pCurrentStr)
m_pCurrentStr = m_pDefaultStr;
}
CLocalizationDatabase::CLocalizationDatabase()
{
m_VersionCounter = 0;
m_CurrentVersion = 0;
}
void CLocalizationDatabase::AddString(const char *pOrgStr, const char *pNewStr, const char *pContext)
{
CString s;
s.m_Hash = str_quickhash(pOrgStr);
s.m_ContextHash = str_quickhash(pContext);
s.m_Replacement = *pNewStr ? pNewStr : pOrgStr;
m_Strings.add(s);
}
bool CLocalizationDatabase::Load(const char *pFilename, IStorage *pStorage, IConsole *pConsole)
{
// empty string means unload
if(pFilename[0] == 0)
{
m_Strings.clear();
m_CurrentVersion = 0;
return true;
}
// read file data into buffer
IOHANDLE File = pStorage->OpenFile(pFilename, IOFLAG_READ, IStorage::TYPE_ALL);
if(!File)
return false;
int FileSize = (int)io_length(File);
char *pFileData = (char *)mem_alloc(FileSize+1, 1);
io_read(File, pFileData, FileSize);
pFileData[FileSize] = 0;
io_close(File);
// init
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "loaded '%s'", pFilename);
pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "localization", aBuf);
m_Strings.clear();
// parse json data
json_settings JsonSettings;
mem_zero(&JsonSettings, sizeof(JsonSettings));
char aError[256];
json_value *pJsonData = json_parse_ex(&JsonSettings, pFileData, aError);
if(pJsonData == 0)
{
pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, pFilename, aError);
mem_free(pFileData);
return false;
}
// extract data
const json_value &rStart = (*pJsonData)["translated strings"];
if(rStart.type == json_array)
{
for(unsigned i = 0; i < rStart.u.array.length; ++i)
AddString((const char *)rStart[i]["or"], (const char *)rStart[i]["tr"], (const char *)rStart[i]["context"]);
}
// clean up
json_value_free(pJsonData);
mem_free(pFileData);
m_CurrentVersion = ++m_VersionCounter;
return true;
}
const char *CLocalizationDatabase::FindString(unsigned Hash, unsigned ContextHash)
{
CString String;
String.m_Hash = Hash;
sorted_array::range r = ::find_binary(m_Strings.all(), String);
if(r.empty())
return 0;
unsigned DefaultHash = str_quickhash("");
unsigned DefaultIndex = 0;
for(unsigned i = 0; i < r.size() && r.index(i).m_Hash == Hash; ++i)
{
const CString &rStr = r.index(i);
if(rStr.m_ContextHash == ContextHash)
return rStr.m_Replacement;
else if(rStr.m_ContextHash == DefaultHash)
DefaultIndex = i;
}
return r.index(DefaultIndex).m_Replacement;
}
CLocalizationDatabase g_Localization;