winix/templates/locale.cpp

693 lines
12 KiB
C++
Executable File

/*
* This file is a part of Winix
* and is not publicly distributed
*
* Copyright (c) 2010-2012, Tomasz Sowa
* All rights reserved.
*
*/
#include <algorithm>
#include "locale.h"
#include "core/log.h"
#include "utf8/utf8.h"
Locale::Locale()
{
locale_files.push_back(L"en");
loc_tab.resize(locale_files.size());
loc_tab_multi.resize(locale_files.size());
default_lang = 0;
current_lang = 0;
input_as_utf8 = false;
}
void Locale::SetLocaleFiles(const std::vector<std::wstring> & files)
{
locale_files = files;
if( locale_files.empty() )
locale_files.push_back(L"en");
loc_tab.resize(locale_files.size());
loc_tab_multi.resize(locale_files.size());
}
void Locale::ReadFile(const char * dir, const char * dir_def, size_t lang, const char * file)
{
if( lang >= loc_tab.size() )
return;
loc_tab[lang].clear();
bool read = false;
if( dir_def && ReadFile(dir_def, lang, file) )
read = true;
if( dir && ReadFile(dir, lang, file) )
read = true;
if( !read )
log << log1 << "Locale: can't open locale's file: " << file << logend;
}
bool Locale::ReadFile(const char * dir, size_t lang, const char * file)
{
bool read = false;
file_name = dir;
file_name += '/';
file_name += file; // !! dodac sprawdzenie poprawnosci nazwy pliku (czy nie zawiera specjalnych znakow)
loc_parser.SplitSingle(true);
loc_parser.UTF8(input_as_utf8);
loc_parser.SetSpace(space);
if( loc_parser.Parse(file_name) == PT::SpaceParser::ok )
{
read = true;
AddLocale(lang);
log << log3 << "Locale: read locale from: " << file_name << logend;
}
return read;
}
void Locale::AddLocale(size_t lang)
{
PT::Space::TableSingle::iterator i = space.table_single.begin();
for( ; i != space.table_single.end() ; ++i)
loc_tab[lang][i->first] = i->second;
// lists
PT::Space::Table::iterator i2 = space.table.begin();
for( ; i2 != space.table.end() ; ++i2)
loc_tab_multi[lang][i2->first] = i2->second;
}
void Locale::ReadSubstTable(const char * dir, const char * dir_def)
{
bool read = false;
subst_url.clear();
subst_smalllet.clear();
subst_capitallet.clear();
subst_sort.clear();
if( dir_def && ReadSubstTable(dir_def) )
read = true;
if( dir && ReadSubstTable(dir) )
read = true;
if( !read )
log << log1 << "Locale: can't open file for characters substitution" << logend;
}
bool Locale::ReadSubstTable(const char * dir)
{
bool read = false;
file_name = dir;
file_name += '/';
file_name += "substitute";
loc_parser.SplitSingle(true);
loc_parser.UTF8(input_as_utf8);
if( loc_parser.Parse(file_name) == PT::SpaceParser::ok )
{
read = true;
CreateSubstVector(subst_url, space.table_single[L"url_original"], space.table_single[L"url_changeto"]);
CreateSubstVector(subst_smalllet, space.table_single[L"smallleters"], space.table_single[L"capitalics"]);
CreateSubstVector(subst_capitallet, space.table_single[L"capitalics"], space.table_single[L"smallleters"]);
CreateSubstSortVector(subst_sort, space.table[L"sort"]);
log << log3 << "Locale: read characters substitution tables from: " << file_name << logend;
}
return read;
}
void Locale::CreateSubstVector(std::vector<SubstItem> & vect, const std::wstring & tab1, const std::wstring & tab2)
{
size_t i, min_size = (tab1.size() < tab2.size()) ? tab1.size() : tab2.size();
SubstItem s;
vect.clear();
if( min_size == 0 )
return;
vect.reserve(min_size);
for(i=0 ; i<min_size ; ++i)
{
s.from = tab1[i];
s.to = tab2[i];
vect.push_back(s);
}
std::sort(vect.begin(), vect.end());
}
void Locale::CreateSubstSortVector(std::vector<SubstItem> & vect, std::vector<std::wstring> & tab)
{
SubstItem s;
vect.clear();
if( tab.empty() )
return;
vect.reserve(tab.size());
for(size_t i=0 ; i<tab.size() ; ++i)
{
if( tab[i].size() >= 3 )
{
s.from = tab[i][0];
s.to = tab[i][1];
s.index = Toi(&tab[i][2]);
vect.push_back(s);
}
}
std::sort(vect.begin(), vect.end());
}
void Locale::Read(const char * dir, const char * dir_def)
{
for(size_t i=0 ; i<locale_files.size() ; ++i)
{
PT::WideToUTF8(locale_files[i], locale_filea);
ReadFile(dir, dir_def, i, locale_filea.c_str());
}
ReadSubstTable(dir, dir_def);
}
void Locale::Read(const std::string & dir, const std::string & dir_def)
{
if( dir_def.empty() )
Read(dir.c_str());
else
Read(dir.c_str(), dir_def.c_str());
}
void Locale::Read(const wchar_t * dir, const wchar_t * dir_def)
{
PT::WideToUTF8(dir, adir1);
if( !dir_def )
{
Read(adir1.c_str());
}
else
{
PT::WideToUTF8(dir_def, adir2);
Read(adir1.c_str(), adir2.c_str());
}
}
void Locale::Read(const std::wstring & dir, const std::wstring & dir_def)
{
if( dir_def.empty() )
Read(dir.c_str());
else
Read(dir.c_str(), dir_def.c_str());
}
size_t Locale::Size() const
{
return loc_tab.size();
}
void Locale::SetLang(size_t lang)
{
current_lang = lang;
if( current_lang >= loc_tab.size() )
current_lang = loc_tab.size() - 1;
}
size_t Locale::GetLang() const
{
return current_lang;
}
void Locale::SetLangDef(size_t lang)
{
default_lang = lang;
if( default_lang >= loc_tab.size() )
default_lang = loc_tab.size() - 1;
}
size_t Locale::GetLangDef() const
{
return default_lang;
}
bool Locale::IsKey(const wchar_t * key)
{
key_str = key;
return IsKey(key_str);
}
bool Locale::IsKey(const wchar_t * key, size_t lang)
{
key_str = key;
return IsKey(key_str, lang);
}
bool Locale::IsKey(const std::wstring & key) const
{
return IsKey(key, current_lang);
}
bool Locale::IsKey(const std::wstring & key, size_t lang) const
{
if( lang >= loc_tab.size() )
return false;
// looking in the 'lang' language
PT::Space::TableSingle::const_iterator i = loc_tab[lang].find(key);
if( i != loc_tab[lang].end() )
return true;
if( lang == default_lang )
return false;
if( default_lang >= loc_tab.size() )
return false;
// looking in a default language
i = loc_tab[default_lang].find(key);
if( i != loc_tab[default_lang].end() )
return true;
// there is no such a key
return false;
}
bool Locale::IsKeyLang(const wchar_t * key, size_t lang)
{
key_str = key;
return IsKeyLang(key_str, lang);
}
bool Locale::IsKeyLang(const std::wstring & key, size_t lang) const
{
if( lang >= loc_tab.size() )
return false;
// looking in the 'lang' language
PT::Space::TableSingle::const_iterator i = loc_tab[lang].find(key);
return i != loc_tab[lang].end();
}
const std::wstring & Locale::Get(const wchar_t * key)
{
key_str = key;
return Get(key_str);
}
const std::wstring & Locale::Get(const wchar_t * key, size_t lang)
{
key_str = key;
return Get(key_str, lang);
}
const std::wstring & Locale::Get(const std::wstring & key) const
{
return Get(key, current_lang);
}
const std::wstring & Locale::Get(const std::wstring & key, size_t lang) const
{
if( lang >= loc_tab.size() )
return empty;
// looking in the 'lang' language
PT::Space::TableSingle::const_iterator i = loc_tab[lang].find(key);
if( i != loc_tab[lang].end() )
return i->second;
if( lang == default_lang )
return empty;
if( default_lang >= loc_tab.size() )
return empty;
// looking in a default language
i = loc_tab[default_lang].find(key);
if( i != loc_tab[default_lang].end() )
return i->second;
// there is no such a key
return empty;
}
bool Locale::IsKeyLangList(const wchar_t * key, size_t lang)
{
key_str = key;
return IsKeyLangList(key_str, lang);
}
bool Locale::IsKeyLangList(const std::wstring & key, size_t lang) const
{
if( lang >= loc_tab_multi.size() )
return false;
// looking in the 'lang' language
PT::Space::Table::const_iterator i = loc_tab_multi[lang].find(key);
return i != loc_tab_multi[lang].end();
}
const std::vector<std::wstring> & Locale::GetList(const std::wstring & key) const
{
return GetList(key, current_lang);
}
const std::vector<std::wstring> & Locale::GetList(const std::wstring & key, size_t lang) const
{
if( lang >= loc_tab_multi.size() )
return empty_list;
// looking in the 'lang' language
PT::Space::Table::const_iterator i = loc_tab_multi[lang].find(key);
if( i != loc_tab_multi[lang].end() )
return i->second;
if( lang == default_lang )
return empty_list;
if( default_lang >= loc_tab_multi.size() )
return empty_list;
// looking in a default language
i = loc_tab_multi[default_lang].find(key);
if( i != loc_tab_multi[default_lang].end() )
return i->second;
// there is no such a key
return empty_list;
}
size_t Locale::FileNameToLang(const std::wstring & str) const
{
for(size_t i=0 ; i<locale_files.size() ; ++i)
{
if( locale_files[i] == str )
return i;
}
// we have at least one item "en"
return 0;
}
const std::wstring & Locale::LangToFileName(size_t lang) const
{
if( lang >=locale_files.size() )
return empty;
return locale_files[lang];
}
void Locale::UTF8(bool utf)
{
input_as_utf8 = utf;
}
/*
binary search in vect
vect should be sorted by 'from'
if the 'val' is found in vect[].from then its index is returned (index to vect table)
else vect.size() is returned
*/
size_t Locale::SubstFindIndex(const std::vector<SubstItem> & vect, wchar_t val)
{
if( vect.empty() )
return vect.size();
size_t o1 = 0;
size_t o2 = vect.size() - 1;
if( val < vect[o1].from )
return vect.size();
if( val == vect[o1].from )
return o1;
if( val > vect[o2].from )
return vect.size();
if( val == vect[o2].from )
return o2;
while( o1 + 1 < o2 )
{
size_t o = (o1 + o2) / 2;
if( val == vect[o].from )
return o;
if( val < vect[o].from )
o2 = o;
else
o1 = o;
}
return vect.size();
}
/*
binary search in vect
vect should be sorted by 'from'
if the 'val' is found in vect[].from then vect[].to is returned
else 'val' is returned
*/
wchar_t Locale::SubstFind(const std::vector<SubstItem> & vect, wchar_t val)
{
size_t i = SubstFindIndex(vect, val);
if( i == vect.size() )
{
return val;
}
else
{
return vect[i].to;
}
}
wchar_t Locale::UrlSubst(wchar_t c)
{
return SubstFind(subst_url, c);
}
void Locale::UrlSubst(std::wstring & str)
{
for(size_t i=0 ; i<str.size() ; ++i)
str[i] = UrlSubst(str[i]);
}
wchar_t Locale::ToSmall(wchar_t c)
{
if( c>='A' && c<='Z' )
return c - 'A' + 'a';
return SubstFind(subst_capitallet, c);
}
void Locale::ToSmall(std::wstring & str)
{
for(size_t i=0 ; i<str.size() ; ++i)
str[i] = ToSmall(str[i]);
}
wchar_t Locale::ToCapital(wchar_t c)
{
if( c>='a' && c<='z' )
return c - 'a' + 'A';
return SubstFind(subst_smalllet, c);
}
void Locale::ToCapital(std::wstring & str)
{
for(size_t i=0 ; i<str.size() ; ++i)
str[i] = ToCapital(str[i]);
}
/*
comparing lexicographically two characters
return value:
less than 0 if c1 is 'less' than c2
zero if they are equal
greater than 0 if c1 is 'greater' than c2
capital letters are treated equaly as small ones
but they will appear first (before the small ones)
*/
int Locale::Compare(wchar_t c1, wchar_t c2)
{
SubstItem s1, s2;
s1.from = c1;
s1.to = c1;
s1.index = 0;
s2.from = c2;
s2.to = c2;
s2.index = 0;
if( !((c1>='a' && c1<='z') || (c1>='A' && c1<='Z')) )
{
size_t i1 = SubstFindIndex(subst_sort, c1);
if( i1 < subst_sort.size() )
{
s1.to = subst_sort[i1].to;
s1.index = subst_sort[i1].index;
}
}
if( !((c2>='a' && c2<='z') || (c2>='A' && c2<='Z')) )
{
size_t i2 = SubstFindIndex(subst_sort, c2);
if( i2 < subst_sort.size() )
{
s2.to = subst_sort[i2].to;
s2.index = subst_sort[i2].index;
}
}
wchar_t small1 = ToSmall(s1.to);
wchar_t small2 = ToSmall(s2.to);
if( small1 == small2 )
{
if( s1.index != s2.index )
return s1.index - s2.index;
// this will sort capital letters at the end (after small ones)
return s1.to - s2.to;
}
return small1 - small2;
}
/*
comparing lexicographically two strings
return value:
less than 0 if str1 is 'less' than str2
zero if they are equal
greater than 0 if str1 is 'greater' than str2
*/
int Locale::Compare(const std::wstring & str1, const std::wstring & str2)
{
size_t i1 = 0;
size_t i2 = 0;
for( ; i1 < str1.size() && i2 < str2.size() ; ++i1, ++i2)
{
int res = Compare(str1[i1], str2[i2]);
if( res != 0 )
return res;
}
if( str1.size() < str2.size() )
return -1;
if( str1.size() > str2.size() )
return 1;
return 0;
}