Compare commits

..

2 Commits

Author SHA1 Message Date
tomasz.sowa b82a36142c allow to use multiple locale directories
remove config options:
- locale_dir
- locale_dir_default

add a config option:
- locale_dirs - a list of directories with locale files (translations)

We start reading locale from the first directory and files with the same name
in each directory are concatenated.
2026-06-21 23:36:29 +02:00
tomasz.sowa d35854691c allow to use multiple directories in html and txt templates
remove from the config:
templates_dir, templates_dir_default, txt_templates_dir, txt_templates_dir_default

add to the config:
html_templates_dirs - a list of directories with html templates
txt_templates_dirs - a list of directories with txt templates

We search from the last directory to the first one.
2026-06-21 01:59:32 +02:00
8 changed files with 134 additions and 133 deletions
+7 -7
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2008-2022, Tomasz Sowa * Copyright (c) 2008-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -180,10 +180,9 @@ void Config::AssignValues()
image_quality = Int(L"image_quality", 92); image_quality = Int(L"image_quality", 92);
convert_cmd = Text(L"convert_cmd", L"/usr/local/bin/convert"); convert_cmd = Text(L"convert_cmd", L"/usr/local/bin/convert");
templates_dir = Text(L"templates_dir"); ListText(L"html_templates_dirs", html_templates_dirs);
templates_dir_default = Text(L"templates_dir_default"); ListText(L"txt_templates_dirs", txt_templates_dirs);
txt_templates_dir = Text(L"txt_templates_dir");
txt_templates_dir_default = Text(L"txt_templates_dir_default");
templates_fun_prefix = Text(L"templates_fun_prefix", L"fun_"); templates_fun_prefix = Text(L"templates_fun_prefix", L"fun_");
templates_fun_postfix = Text(L"templates_fun_postfix", L".html"); templates_fun_postfix = Text(L"templates_fun_postfix", L".html");
templates_index = Text(L"templates_index", L"index.html"); templates_index = Text(L"templates_index", L"index.html");
@@ -267,8 +266,7 @@ void Config::AssignValues()
html_filter_orphans_mode_str = Text(L"html_filter_orphans_mode_str", L"nbsp"); html_filter_orphans_mode_str = Text(L"html_filter_orphans_mode_str", L"nbsp");
html_filter_nofilter_tag = Text(L"html_filter_nofilter_tag", L"nofilter"); html_filter_nofilter_tag = Text(L"html_filter_nofilter_tag", L"nofilter");
locale_dir = Text(L"locale_dir"); ListText(L"locale_dirs", locale_dirs);
locale_dir_default = Text(L"locale_dir_default");
locale_max_id = Size(L"locale_max_id", 100); locale_max_id = Size(L"locale_max_id", 100);
locale_default_id = Size(L"locale_default_id", 0); locale_default_id = Size(L"locale_default_id", 0);
ListText(L"locale_files", locale_files); ListText(L"locale_files", locale_files);
@@ -523,6 +521,8 @@ bool Config::ListText(const std::wstring & name, std::vector<std::wstring> & lis
return space.to_list(name, list); return space.to_list(name, list);
} }
bool Config::HasValue(const wchar_t * name, const wchar_t * value) bool Config::HasValue(const wchar_t * name, const wchar_t * value)
{ {
return space.has_value(name, value); return space.has_value(name, value);
+14 -11
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2008-2022, Tomasz Sowa * Copyright (c) 2008-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -186,11 +186,13 @@ public:
// default: 3 // default: 3
size_t fcgi_cannot_create_request_delay; size_t fcgi_cannot_create_request_delay;
std::wstring templates_dir; // html templates directories
std::wstring templates_dir_default; // html templates from winix // by default a file from the last directory is chosen
std::vector<std::wstring> html_templates_dirs;
std::wstring txt_templates_dir; // txt (notifications) templates directories
std::wstring txt_templates_dir_default; // txt (notifications) templates from winix // by default a file from the last directory is chosen
std::vector<std::wstring> txt_templates_dirs;
// prefix and postfix for functions templates // prefix and postfix for functions templates
// default: // default:
@@ -590,14 +592,15 @@ public:
// default: /usr/local/bin/convert // default: /usr/local/bin/convert
std::wstring convert_cmd; std::wstring convert_cmd;
// directory with locale files // directories with locale files
std::wstring locale_dir; // we start reading locale from the first directory
// and files with the same name in each directory are concatenated
// directory with default locale files (those from winix) std::vector<std::wstring> locale_dirs;
std::wstring locale_dir_default;
// locale files (e.g. "en", "pl") // locale files (e.g. "en", "pl")
// default: only one item: en // default: "en"
// a locale file should define winix_locale_id integer parameter
// and it should be smaller or equal to locale_max_id
std::vector<std::wstring> locale_files; std::vector<std::wstring> locale_files;
// a maximum value of a locale identifier // a maximum value of a locale identifier
+2 -2
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2008-2024, Tomasz Sowa * Copyright (c) 2008-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -97,7 +97,7 @@ bool Notify::Init()
if( !thread_manager->Add(&notify_thread, L"notifications") ) if( !thread_manager->Add(&notify_thread, L"notifications") )
return false; return false;
patterns.SetDirectories(config->txt_templates_dir, config->txt_templates_dir_default); patterns.SetDirectories(config->txt_templates_dirs);
patterns.SetLocale(&TemplatesFunctions::locale); patterns.SetLocale(&TemplatesFunctions::locale);
patterns.SetLocaleFilter(&TemplatesFunctions::locale_filter); patterns.SetLocaleFilter(&TemplatesFunctions::locale_filter);
+68 -78
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2010-2021, Tomasz Sowa * Copyright (c) 2010-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -49,13 +49,18 @@ Locale::Locale()
} }
void Locale::SetDirectories(const std::vector<std::wstring> & dirs)
{
directories = dirs;
}
void Locale::SetLocaleFiles(const std::vector<std::wstring> & files) void Locale::SetLocaleFiles(const std::vector<std::wstring> & files)
{ {
locale_files = files; locale_files = files;
} }
void Locale::SetLocaleMaxId(size_t max_id) void Locale::SetLocaleMaxId(size_t max_id)
{ {
if( max_id > 1000 ) if( max_id > 1000 )
@@ -72,8 +77,6 @@ void Locale::SetLocaleMaxId(size_t max_id)
} }
bool Locale::HasLanguage(size_t lang_id) bool Locale::HasLanguage(size_t lang_id)
{ {
if( lang_id < locale_indices.size() ) if( lang_id < locale_indices.size() )
@@ -83,34 +86,38 @@ return false;
} }
void Locale::ReadFile(const std::wstring & file)
void Locale::ReadFile(const char * dir, const char * dir_def, const char * file)
{ {
bool read = false; bool read = false;
temp_space.clear(); temp_space.clear();
if( dir_def && ReadFile(dir_def, file) ) for(const std::wstring & dir : directories)
read = true; {
if( ReadFile(dir, file) )
if( dir && ReadFile(dir, file) )
read = true; read = true;
}
if( read ) if( read )
{
AddLocale(file); AddLocale(file);
}
else else
{
log << log1 << "Locale: can't open locale's file: " << file << logend; log << log1 << "Locale: can't open locale's file: " << file << logend;
}
temp_space.clear();
} }
bool Locale::ReadFile(const char * dir, const char * file) bool Locale::ReadFile(const std::wstring & dir, const std::wstring & file)
{ {
bool read = false; bool read = false;
file_name = dir; pt::wide_to_utf8(dir, file_name);
file_name += '/'; file_name += '/';
file_name += file; pt::wide_to_utf8(file, file_name, false);
pt::SpaceParser::Status status = loc_parser.parse_space_file(file_name, temp_space, false); pt::SpaceParser::Status status = loc_parser.parse_space_file(file_name, temp_space, false);
@@ -125,23 +132,24 @@ bool read = false;
log << log1 << "Locale: syntax error in: " << file_name << " in line: " << loc_parser.get_last_parsed_line() << logend; log << log1 << "Locale: syntax error in: " << file_name << " in line: " << loc_parser.get_last_parsed_line() << logend;
} }
return read; file_name.clear();
return read;
} }
void Locale::AddLocale(const char * file) void Locale::AddLocale(const std::wstring & file)
{ {
std::wstring * id_str = temp_space.get_wstr(L"winix_locale_id"); std::wstring * id_str = temp_space.get_wstr(L"winix_locale_id");
if( !id_str ) if( !id_str )
{ {
log << log1 << "Locale: winix_locale_id field should be defined in locale file: " log << log1 << "Locale: winix_locale_id field should be defined in a locale file: "
<< file << " (skipping)" << logend; << file << " (skipping this file)" << logend;
return; return;
} }
size_t id = (size_t)Tol(*id_str); size_t id = (size_t)pt::to_ul(*id_str);
if( id >= locale_indices.size() ) if( id >= locale_indices.size() )
{ {
@@ -155,32 +163,35 @@ void Locale::AddLocale(const char * file)
void Locale::ReadSubstTable(const char * dir, const char * dir_def) void Locale::ReadSubstTable()
{ {
bool read = false; bool read = false;
temp_space.clear(); temp_space.clear();
subst_url.clear(); subst_url.clear();
subst_smalllet.clear(); subst_smalllet.clear();
subst_capitallet.clear(); subst_capitallet.clear();
subst_sort.clear(); subst_sort.clear();
if( dir_def && ReadSubstTable(dir_def) ) for(const std::wstring & dir : directories)
read = true; {
if( ReadSubstTable(dir) )
if( dir && ReadSubstTable(dir) )
read = true; read = true;
}
if( !read ) if( !read )
log << log1 << "Locale: can't open file for characters substitution" << logend; {
log << log1 << "Locale: can't open a file for characters substitution" << logend;
}
temp_space.clear();
} }
bool Locale::ReadSubstTable(const char * dir) bool Locale::ReadSubstTable(const std::wstring & dir)
{ {
bool read = false; bool read = false;
file_name = dir; pt::wide_to_utf8(dir, file_name);
file_name += '/'; file_name += '/';
file_name += "substitute"; file_name += "substitute";
@@ -199,7 +210,8 @@ bool read = false;
log << log3 << "Locale: read characters substitution tables from: " << file_name << logend; log << log3 << "Locale: read characters substitution tables from: " << file_name << logend;
} }
return read; file_name.clear();
return read;
} }
@@ -254,58 +266,36 @@ void Locale::CreateSubstSortVector(std::vector<SubstItem> & vect, std::vector<st
} }
void Locale::Read(const char * dir, const char * dir_def) void Locale::ReadLocales()
{ {
for(size_t & index : locale_indices)
index = size_t(-1);
for(const std::wstring & file : locale_files)
{
ReadFile(file);
}
ReadSubstTable();
}
void Locale::Clear()
{
directories.clear();
locale_files.clear();
locale_indices.clear();
locale_tab.clear(); locale_tab.clear();
default_lang = 0;
current_lang = 0;
for(size_t i=0 ; i<locale_indices.size() ; ++i) subst_url.clear();
locale_indices[i] = size_t(-1); subst_smalllet.clear();
subst_capitallet.clear();
for(size_t i=0 ; i<locale_files.size() ; ++i) subst_sort.clear();
{
pt::wide_to_utf8(locale_files[i], locale_filea);
ReadFile(dir, dir_def, 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::wide_to_utf8(dir, adir1);
if( !dir_def )
{
Read(adir1.c_str());
}
else
{
pt::wide_to_utf8(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());
}
void Locale::SetCurLang(size_t lang_id) void Locale::SetCurLang(size_t lang_id)
{ {
+17 -14
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2010-2018, Tomasz Sowa * Copyright (c) 2010-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -53,8 +53,11 @@ public:
Locale(); Locale();
// locale directories
void SetDirectories(const std::vector<std::wstring> & dirs);
// locale files // locale files
// those files will be reading from directories specified in Read() method // those files will be reading from directories specified above
// default one item: en // default one item: en
void SetLocaleFiles(const std::vector<std::wstring> & files); void SetLocaleFiles(const std::vector<std::wstring> & files);
@@ -73,11 +76,11 @@ public:
size_t GetDefLang() const; size_t GetDefLang() const;
// reading locales // reading locales
// you should call SetLocaleFiles() beforehand // you should call SetDirectories(), SetLocaleFiles() and SetLocaleMaxId() beforehand
void Read(const char * dir, const char * dir_def = 0); void ReadLocales();
void Read(const std::string & dir, const std::string & dir_def);
void Read(const wchar_t * dir, const wchar_t * dir_def = 0); // clear directories, files and read translations
void Read(const std::wstring & dir, const std::wstring & dir_def); void Clear();
// returns true if a language with lang_id exists // returns true if a language with lang_id exists
bool HasLanguage(size_t lang_id); bool HasLanguage(size_t lang_id);
@@ -208,11 +211,11 @@ private:
bool operator<(const SubstItem & arg) const { return from < arg.from; } bool operator<(const SubstItem & arg) const { return from < arg.from; }
}; };
void AddLocale(const char * file); void AddLocale(const std::wstring & file);
void ReadFile(const char * dir, const char * dir_def, const char * file); void ReadFile(const std::wstring & file);
bool ReadFile(const char * dir, const char * file); bool ReadFile(const std::wstring & dir, const std::wstring & file);
void ReadSubstTable(const char * dir, const char * dir_def); void ReadSubstTable();
bool ReadSubstTable(const char * dir); bool ReadSubstTable(const std::wstring & dir);
void CreateSubstVector(std::vector<SubstItem> & vect, const std::wstring & tab1, const std::wstring & tab2); void CreateSubstVector(std::vector<SubstItem> & vect, const std::wstring & tab1, const std::wstring & tab2);
void CreateSubstSortVector(std::vector<SubstItem> & vect, std::vector<std::wstring> & tab); void CreateSubstSortVector(std::vector<SubstItem> & vect, std::vector<std::wstring> & tab);
size_t SubstFindIndex(const std::vector<SubstItem> & vect, wchar_t val); size_t SubstFindIndex(const std::vector<SubstItem> & vect, wchar_t val);
@@ -221,6 +224,8 @@ private:
bool GetListInLanguage(const std::wstring & key, size_t lang_id, std::vector<std::wstring> & list) const; bool GetListInLanguage(const std::wstring & key, size_t lang_id, std::vector<std::wstring> & list) const;
bool IsListInLanguage(const std::wstring & key, size_t lang_id) const; bool IsListInLanguage(const std::wstring & key, size_t lang_id) const;
// directories
std::vector<std::wstring> directories;
// locale files // locale files
std::vector<std::wstring> locale_files; std::vector<std::wstring> locale_files;
@@ -252,11 +257,9 @@ private:
pt::Space temp_space; pt::Space temp_space;
pt::SpaceParser loc_parser; pt::SpaceParser loc_parser;
std::string locale_filea;
std::string file_name; std::string file_name;
std::wstring key_str; std::wstring key_str;
const std::wstring empty; // used when returning a non existing key from loc_tab (or in LangToFileName) const std::wstring empty; // used when returning a non existing key from loc_tab (or in LangToFileName)
std::string adir1, adir2;
std::wstring pattern_value; std::wstring pattern_value;
}; };
+8 -5
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2011-2015, Tomasz Sowa * Copyright (c) 2011-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -59,13 +59,16 @@ void Patterns::SetDeleteWhiteItems(bool del_white)
} }
void Patterns::SetDirectories(const std::wstring & tmpl_dir, const std::wstring & tmpl_dir_def) void Patterns::SetDirectories(const std::vector<std::wstring> & tmpl_dirs)
{ {
templates_dir = tmpl_dir; templates_dirs = tmpl_dirs;
templates_dir_def = tmpl_dir_def;
} }
void Patterns::ClearDirectories()
{
templates_dirs.clear();
}
void Patterns::SetLocale(Locale * plocale) void Patterns::SetLocale(Locale * plocale)
@@ -138,7 +141,7 @@ void Patterns::ReadPatterns(Template & templ)
* pattern_parser.SetCommentary() is set beforehand * pattern_parser.SetCommentary() is set beforehand
*/ */
pattern_parser.DeleteWhiteTextItems(del_white_items); pattern_parser.DeleteWhiteTextItems(del_white_items);
pattern_parser.Directory(templates_dir, templates_dir_def); pattern_parser.SetDirectories(templates_dirs);
pattern_parser.SetLogger(&log); pattern_parser.SetLogger(&log);
if( ezc_blocks ) if( ezc_blocks )
+4 -3
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2011-2018, Tomasz Sowa * Copyright (c) 2011-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -53,7 +53,8 @@ public:
Patterns(); Patterns();
void SetDeleteWhiteItems(bool del_white); void SetDeleteWhiteItems(bool del_white);
void SetDirectories(const std::wstring & tmpl_dir, const std::wstring & tmpl_dir_def); void SetDirectories(const std::vector<std::wstring> & tmpl_dirs);
void ClearDirectories();
/* /*
setting locale and locale_filter setting locale and locale_filter
@@ -151,7 +152,7 @@ public:
private: private:
bool del_white_items; bool del_white_items;
std::wstring templates_dir, templates_dir_def; std::vector<std::wstring> templates_dirs;
Locale * locale; Locale * locale;
LocaleFilter * locale_filter; LocaleFilter * locale_filter;
+4 -3
View File
@@ -5,7 +5,7 @@
*/ */
/* /*
* Copyright (c) 2008-2024, Tomasz Sowa * Copyright (c) 2008-2026, Tomasz Sowa
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -678,10 +678,11 @@ void Templates::CreateFunctions()
void Templates::ReadLocale() void Templates::ReadLocale()
{ {
TemplatesFunctions::locale.SetDirectories(config->locale_dirs);
TemplatesFunctions::locale.SetLocaleFiles(config->locale_files); TemplatesFunctions::locale.SetLocaleFiles(config->locale_files);
TemplatesFunctions::locale.SetLocaleMaxId(config->locale_max_id); TemplatesFunctions::locale.SetLocaleMaxId(config->locale_max_id);
TemplatesFunctions::locale.SetDefLang(config->locale_default_id); TemplatesFunctions::locale.SetDefLang(config->locale_default_id);
TemplatesFunctions::locale.Read(config->locale_dir, config->locale_dir_default); TemplatesFunctions::locale.ReadLocales();
log << log3 << "Templates: there are " << TemplatesFunctions::locale.Size() << " locales" << logend; log << log3 << "Templates: there are " << TemplatesFunctions::locale.Size() << " locales" << logend;
} }
@@ -868,7 +869,7 @@ void Templates::Init()
{ {
using namespace TemplatesFunctions; using namespace TemplatesFunctions;
patterns.SetDirectories(config->templates_dir, config->templates_dir_default); patterns.SetDirectories(config->html_templates_dirs);
pattern_cacher.SetWhenDelete(config->pattern_cacher_when_delete, config->pattern_cacher_how_many_delete); pattern_cacher.SetWhenDelete(config->pattern_cacher_when_delete, config->pattern_cacher_how_many_delete);
CreateFunctions(); // create functions first (functions will be cached by patterns) CreateFunctions(); // create functions first (functions will be cached by patterns)
ReadTemplates(); ReadTemplates();