diff --git a/README.md b/README.md index 3e7f8b22..e6d4d308 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,7 @@ Files extensions: * .presets - Predefined format presets * .items - Input file items * .progress - Compiled progress function into windows DLL +* .language - Language translation strings Use only UTF-8 compatible text editors (e.g. Notepad) to edit xml configuration files. @@ -181,6 +182,10 @@ Use only UTF-8 compatible text editors (e.g. Notepad) to edit xml configuration https://github.com/wieslawsoltes/BatchEncoder/tree/master/config +### Default language files + +https://github.com/wieslawsoltes/BatchEncoder/tree/master/lang + ## Format specification ### Template format diff --git a/build.cake b/build.cake index 81eef690..451361fb 100644 --- a/build.cake +++ b/build.cake @@ -81,6 +81,7 @@ var packageBinariesAction = new Action ((configuration, platform) CopyFiles("./config/*.options", outputDir); CopyFiles("./config/*.formats", outputDir); CopyFiles("./config/*.items", outputDir); + CopyFiles("./lang/*.language", outputDir); CopyFiles("./scripts/*.ps1", outputDir); Zip(outputDir, outputZip); }); diff --git a/setup/setup.iss b/setup/setup.iss index 4b5f9168..2e8e3cdd 100644 --- a/setup/setup.iss +++ b/setup/setup.iss @@ -48,6 +48,7 @@ Name: main; Description: Main Program; Types: full compact custom Name: docs; Description: Documents; Types: full Name: config; Description: Configuration; Types: full compact Name: progress; Description: Progress Functions; Types: full compact +Name: lang; Description: Languages; Types: full compact Name: scripts; Description: Scripts; Types: full [Tasks] @@ -64,6 +65,7 @@ Source: {#BasePath}\config\*.options; DestDir: {app}; Flags: ignoreversion; Comp Source: {#BasePath}\config\*.formats; DestDir: {app}; Flags: ignoreversion; Components: config Source: {#BasePath}\config\*.items; DestDir: {app}; Flags: ignoreversion; Components: config Source: {#BasePath}\src\bin\{#ProgramConfiguration}\{#ProgramBuild}\*.progress; DestDir: {app}; Flags: ignoreversion; Components: progress +Source: {#BasePath}\lang\*.language; DestDir: {app}; Flags: ignoreversion; Components: lang Source: {#BasePath}\scripts\*.ps1; DestDir: {app}; Flags: ignoreversion; Components: scripts [INI] diff --git a/src/BatchEncoder.vcxproj b/src/BatchEncoder.vcxproj index 1ee9c26b..7b300ca4 100644 --- a/src/BatchEncoder.vcxproj +++ b/src/BatchEncoder.vcxproj @@ -132,7 +132,8 @@ copy /-Y ..\config\*.options $(OutDir) copy /-Y ..\config\*.formats $(OutDir) -copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\lang\*.language $(OutDir) @@ -170,7 +171,8 @@ copy /-Y ..\config\*.items $(OutDir) copy /-Y ..\config\*.options $(OutDir) copy /-Y ..\config\*.formats $(OutDir) -copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\lang\*.language $(OutDir) @@ -209,7 +211,8 @@ copy /-Y ..\config\*.items $(OutDir) copy /-Y ..\config\*.options $(OutDir) copy /-Y ..\config\*.formats $(OutDir) -copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\lang\*.language $(OutDir) @@ -249,7 +252,8 @@ copy /-Y ..\config\*.items $(OutDir) copy /-Y ..\config\*.options $(OutDir) copy /-Y ..\config\*.formats $(OutDir) -copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\config\*.items $(OutDir) +copy /-Y ..\lang\*.language $(OutDir) @@ -298,6 +302,9 @@ copy /-Y ..\config\*.items $(OutDir) + + + @@ -348,4 +355,4 @@ copy /-Y ..\config\*.items $(OutDir) - + \ No newline at end of file diff --git a/src/BatchEncoder.vcxproj.filters b/src/BatchEncoder.vcxproj.filters index 34e81bf1..c10b4d29 100644 --- a/src/BatchEncoder.vcxproj.filters +++ b/src/BatchEncoder.vcxproj.filters @@ -158,6 +158,15 @@ Header Files\Configuration + + Header Files\Configuration + + + Header Files\Configuration + + + Header Files\Configuration + Header Files @@ -255,4 +264,4 @@ Resource Files - + \ No newline at end of file diff --git a/src/Configuration.h b/src/Configuration.h index 8c169d4b..87576ed2 100644 --- a/src/Configuration.h +++ b/src/Configuration.h @@ -10,4 +10,7 @@ #include "configuration\FormatsList.h" #include "configuration\Item.h" #include "configuration\ItemsList.h" +#include "configuration\StringsMap.h" +#include "configuration\Language.h" +#include "configuration\LanguagesList.h" #include "configuration\Configuration.h" diff --git a/src/XmlConfiguration.cpp b/src/XmlConfiguration.cpp index 05aa6c32..b1ae02f2 100644 --- a/src/XmlConfiguration.cpp +++ b/src/XmlConfiguration.cpp @@ -45,6 +45,18 @@ void XmlConfiguration::GetOptions(tinyxml2::XMLElement *pOptionsElem, COptions & { tinyxml2::XMLElement *pOptionElem; + // option: SelectedLanguage + pOptionElem = pOptionsElem->FirstChildElement("SelectedLanguage"); + if (pOptionElem) + { + const char *tmpBuff = pOptionElem->GetText(); + m_Options.szSelectedLanguage = ToCString(tmpBuff); + } + else + { + m_Options.szSelectedLanguage = _T(""); + } + // option: SelectedFormat pOptionElem = pOptionsElem->FirstChildElement("SelectedFormat"); if (pOptionElem) @@ -219,6 +231,12 @@ void XmlConfiguration::SetOptions(tinyxml2::XMLElement *pOptionsElem, COptions & tinyxml2::XMLElement *pOptionElem; CUtf8String szBuffUtf8; + // option: SelectedLanguage + pOptionElem = this->NewElement("SelectedLanguage"); + pOptionElem->LinkEndChild(this->NewText(szBuffUtf8.Create(m_Options.szSelectedLanguage))); + pOptionsElem->LinkEndChild(pOptionElem); + szBuffUtf8.Clear(); + // option: SelectedFormat CString szSelectedFormat; szSelectedFormat.Format(_T("%d\0"), m_Options.nSelectedFormat); @@ -627,6 +645,107 @@ void XmlConfiguration::SetItems(tinyxml2::XMLElement *pItemsElem, CItemsList &m_ } } +void XmlConfiguration::GetLanguage(tinyxml2::XMLElement *pLanguageElem, CLanguage &m_Language) +{ + const char *pszId = pLanguageElem->Attribute("id"); + if (pszId != NULL) + { + m_Language.szId = ToCString(pszId); + } + + const char *pszOriginal = pLanguageElem->Attribute("original"); + if (pszOriginal != NULL) + { + m_Language.szOriginalName = ToCString(pszOriginal); + } + + const char *pszTranslated = pLanguageElem->Attribute("translated"); + if (pszTranslated != NULL) + { + m_Language.szTranslatedName = ToCString(pszTranslated); + } + + tinyxml2::XMLElement *pStringElem = pLanguageElem->FirstChildElement("String"); + for (pStringElem; pStringElem; pStringElem = pStringElem->NextSiblingElement()) + { + int nKey; + CString szValue; + + const char *pszKey = pStringElem->Attribute("key"); + if (pszKey != NULL) + { + _stscanf(ToCString(pszKey), _T("%x"), &nKey); + } + + const char *pszValue = pStringElem->Attribute("value"); + if (pszValue != NULL) + { + szValue = ToCString(pszValue); + } + + m_Language.m_Strings.InsertNode(nKey, szValue); + } +} + +void XmlConfiguration::SetLanguage(tinyxml2::XMLElement *pLanguageElem, CLanguage &m_Language) +{ + CUtf8String szBuffUtf8; + + pLanguageElem->SetAttribute("id", szBuffUtf8.Create(m_Language.szId)); + szBuffUtf8.Clear(); + + pLanguageElem->SetAttribute("original", szBuffUtf8.Create(m_Language.szOriginalName)); + szBuffUtf8.Clear(); + + pLanguageElem->SetAttribute("translated", szBuffUtf8.Create(m_Language.szTranslatedName)); + szBuffUtf8.Clear(); + + tinyxml2::XMLElement *pStringElem; + POSITION pos = m_Language.m_Strings.m_Map.GetStartPosition(); + int nKey; + while (pos != NULL) + { + CString rValue; + m_Language.m_Strings.m_Map.GetNextAssoc(pos, nKey, rValue); + + CString szKey; + szKey.Format(_T("%X"), nKey); + + pStringElem = this->NewElement("String"); + + pStringElem->SetAttribute("key", szBuffUtf8.Create(szKey)); + szBuffUtf8.Clear(); + + pStringElem->SetAttribute("value", szBuffUtf8.Create(rValue)); + szBuffUtf8.Clear(); + + pLanguageElem->LinkEndChild(pStringElem); + } +} + +void XmlConfiguration::GetLanguages(tinyxml2::XMLElement *pLanguagesElem, CLanguagesList &m_Languages) +{ + tinyxml2::XMLElement *pLanguageElem = pLanguagesElem->FirstChildElement("Language"); + for (pLanguageElem; pLanguageElem; pLanguageElem = pLanguageElem->NextSiblingElement()) + { + CLanguage language; + this->GetLanguage(pLanguageElem, language); + m_Languages.InsertNode(language); + } +} + +void XmlConfiguration::SetLanguages(tinyxml2::XMLElement *pLanguagesElem, CLanguagesList &m_Languages) +{ + int nLanguages = m_Languages.GetSize(); + for (int i = 0; i < nLanguages; i++) + { + CLanguage& language = m_Languages.GetData(i); + tinyxml2::XMLElement *pLanguageElem = this->NewElement("Language"); + this->SetLanguage(pLanguageElem, language); + pLanguagesElem->LinkEndChild(pLanguageElem); + } +} + void XmlConfiguration::GetOptions(COptions &m_Options) { tinyxml2::XMLElement *pOptionsElem = this->FirstChildElement("Options"); @@ -727,6 +846,46 @@ void XmlConfiguration::SetItems(CItemsList &m_Items) this->SetItems(pItemsElem, m_Items); } +void XmlConfiguration::GetLanguage(CLanguage &m_Language) +{ + tinyxml2::XMLElement *pLanguageElem = this->FirstChildElement("Language"); + if (pLanguageElem != NULL) + { + this->GetLanguage(pLanguageElem, m_Language); + } +} + +void XmlConfiguration::SetLanguage(CLanguage &m_Language) +{ + tinyxml2::XMLDeclaration* decl = this->NewDeclaration(UTF8_DOCUMENT_DECLARATION); + this->LinkEndChild(decl); + + tinyxml2::XMLElement *pLanguageElem = this->NewElement("Language"); + this->LinkEndChild(pLanguageElem); + + this->SetLanguage(pLanguageElem, m_Language); +} + +void XmlConfiguration::GetLanguages(CLanguagesList &m_Languages) +{ + tinyxml2::XMLElement *pLanguagesElem = this->FirstChildElement("Languages"); + if (pLanguagesElem != NULL) + { + this->GetLanguages(pLanguagesElem, m_Languages); + } +} + +void XmlConfiguration::SetLanguages(CLanguagesList &m_Languages) +{ + tinyxml2::XMLDeclaration* decl = this->NewDeclaration(UTF8_DOCUMENT_DECLARATION); + this->LinkEndChild(decl); + + tinyxml2::XMLElement *pLanguagesElem = this->NewElement("Languages"); + this->LinkEndChild(pLanguagesElem); + + this->SetLanguages(pLanguagesElem, m_Languages); +} + bool XmlConfiguration::Open(CString szFileName) { CStdioFile fp; diff --git a/src/XmlConfiguration.h b/src/XmlConfiguration.h index bd4d8686..be0c2897 100644 --- a/src/XmlConfiguration.h +++ b/src/XmlConfiguration.h @@ -27,6 +27,10 @@ private: void SetFormats(tinyxml2::XMLElement *pFormatsElem, CFormatsList &m_Formats); void GetItems(tinyxml2::XMLElement *pItemsElem, CItemsList &m_Items); void SetItems(tinyxml2::XMLElement *pItemsElem, CItemsList &m_Items); + void GetLanguage(tinyxml2::XMLElement *pLanguageElem, CLanguage &m_Language); + void SetLanguage(tinyxml2::XMLElement *pLanguageElem, CLanguage &m_Language); + void GetLanguages(tinyxml2::XMLElement *pLanguagesElem, CLanguagesList &m_Languages); + void SetLanguages(tinyxml2::XMLElement *pLanguagesElem, CLanguagesList &m_Languages); public: void GetOptions(COptions &m_Options); void SetOptions(COptions &m_Options); @@ -38,6 +42,10 @@ public: void SetFormats(CFormatsList &m_Formats); void GetItems(CItemsList &m_Items); void SetItems(CItemsList &m_Items); + void GetLanguage(CLanguage &m_Language); + void SetLanguage(CLanguage &m_Language); + void GetLanguages(CLanguagesList &m_Languages); + void SetLanguages(CLanguagesList &m_Languages); bool Open(CString szFileName); bool Save(CString szFileName); }; diff --git a/src/configuration/Configuration.h b/src/configuration/Configuration.h index 90982165..865b5a2b 100644 --- a/src/configuration/Configuration.h +++ b/src/configuration/Configuration.h @@ -6,6 +6,7 @@ #include "Options.h" #include "FormatsList.h" #include "ItemsList.h" +#include "LanguagesList.h" class CConfiguration { @@ -13,6 +14,7 @@ public: COptions m_Options; CFormatsList m_Formats; CItemsList m_Items; + CLanguagesList m_Languages; public: CConfiguration() { @@ -35,5 +37,6 @@ public: this->m_Options = other.m_Options; this->m_Formats = other.m_Formats; this->m_Items = other.m_Items; + this->m_Languages = other.m_Languages; } }; diff --git a/src/configuration/Language.h b/src/configuration/Language.h new file mode 100644 index 00000000..aea47880 --- /dev/null +++ b/src/configuration/Language.h @@ -0,0 +1,41 @@ +// Copyright (c) Wiesław Šoltés. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma once + +#include +#include +#include "StringsMap.h" + +class CLanguage +{ +public: + CString szId; + CString szOriginalName; + CString szTranslatedName; + CStringsMap m_Strings; +public: + CLanguage() + { + } + CLanguage(const CLanguage &other) + { + Copy(other); + } + CLanguage& operator=(const CLanguage &other) + { + Copy(other); + return *this; + } + virtual ~CLanguage() + { + } +public: + void Copy(const CLanguage &other) + { + this->szId = other.szId; + this->szOriginalName = other.szOriginalName; + this->szTranslatedName = other.szTranslatedName; + this->m_Strings = other.m_Strings; + } +}; diff --git a/src/configuration/LanguagesList.h b/src/configuration/LanguagesList.h new file mode 100644 index 00000000..f2208b8e --- /dev/null +++ b/src/configuration/LanguagesList.h @@ -0,0 +1,109 @@ +// Copyright (c) Wiesław Šoltés. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma once + +#include +#include +#include "Language.h" + +class CLanguagesList +{ +public: + CList m_Languages; +public: + void SetData(CLanguage& language, int idx) + { + m_Languages.SetAt(m_Languages.FindIndex(idx), language); + } + CLanguage& GetData(int idx) + { + return m_Languages.GetAt(m_Languages.FindIndex(idx)); + } +public: + CLanguagesList() + { + } + CLanguagesList(const CLanguagesList &other) + { + Copy(other); + } + CLanguagesList& operator=(const CLanguagesList &other) + { + Copy(other); + return *this; + } + virtual ~CLanguagesList() + { + if (m_Languages.GetCount() != 0) + m_Languages.RemoveAll(); + } +public: + void Copy(const CLanguagesList &other) + { + this->RemoveAllNodes(); + int nLanguages = (int)other.m_Languages.GetCount(); + for (int i = 0; i < nLanguages; i++) + { + CLanguage language = other.m_Languages.GetAt(other.m_Languages.FindIndex(i)); + this->InsertNode(language); + } + } +public: + bool IsEmpty() + { + return (m_Languages.GetCount() == 0) ? true : false; + } + int GetSize() + { + return (int)m_Languages.GetCount(); + } +public: + void InsertNode(CLanguage &language) + { + m_Languages.AddTail(language); + } +public: + void RemoveNode(int pstn = -1) + { + m_Languages.RemoveAt(m_Languages.FindIndex(pstn)); + } + void RemoveAllNodes(void) + { + if (m_Languages.GetCount() != 0) + m_Languages.RemoveAll(); + } +public: + void Copy(CLanguagesList& other) + { + int nLanguages = this->GetSize(); + for (int i = 0; i < nLanguages; i++) + { + CLanguage& language = this->GetData(i); + CLanguage copy = language; + other.InsertNode(copy); + } + } +public: + void SwapItems(int idx1, int idx2) + { + if ((idx1 < 0) || (idx2 < 0) || (idx1 >= GetSize()) || (idx2 >= GetSize())) + return; + CLanguage language1 = this->GetData(idx1); + CLanguage language2 = this->GetData(idx2); + this->SetData(language1, idx2); + this->SetData(language2, idx1); + } +public: + int GetLanguageById(CString szLanguageId) + { + int nCount = this->GetSize(); + for (int i = 0; i < nCount; i++) + { + CLanguage& language = this->GetData(i); + if (szLanguageId.CompareNoCase(language.szId) == 0) + return i; + } + return -1; + } +}; diff --git a/src/configuration/Options.h b/src/configuration/Options.h index 8ccc7ecf..7c6e6d23 100644 --- a/src/configuration/Options.h +++ b/src/configuration/Options.h @@ -8,6 +8,7 @@ class COptions { public: + CString szSelectedLanguage; int nSelectedFormat; CString szOutputPath; bool bOutputPathChecked; @@ -43,6 +44,7 @@ public: public: void Copy(const COptions &other) { + this->szSelectedLanguage = other.szSelectedLanguage; this->nSelectedFormat = other.nSelectedFormat; this->szOutputPath = other.szOutputPath; this->bOutputPathChecked = other.bOutputPathChecked; diff --git a/src/configuration/StringsMap.h b/src/configuration/StringsMap.h new file mode 100644 index 00000000..90950334 --- /dev/null +++ b/src/configuration/StringsMap.h @@ -0,0 +1,101 @@ +// Copyright (c) Wiesław Šoltés. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma once + +#include +#include + +class CStringsMap +{ +public: + CMap m_Map; +public: + void SetData(int nKey, CString szValue) + { + m_Map[nKey] = szValue; + } + CString GetData(int nKey) + { + return m_Map[nKey]; + } +public: + CStringsMap() + { + } + CStringsMap(const CStringsMap &other) + { + Copy(other); + } + CStringsMap& operator=(const CStringsMap &other) + { + Copy(other); + return *this; + } + virtual ~CStringsMap() + { + if (m_Map.GetCount() != 0) + m_Map.RemoveAll(); + } +public: + void Copy(const CStringsMap &other) + { + this->RemoveAllNodes(); + POSITION pos = other.m_Map.GetStartPosition(); + int nKey; + while (pos != NULL) + { + CString rValue; + other.m_Map.GetNextAssoc(pos, nKey, rValue); + this->InsertNode(nKey, rValue); + } + } +public: + bool IsEmpty() + { + return (m_Map.GetCount() == 0) ? true : false; + } + int GetSize() + { + return (int)m_Map.GetCount(); + } +public: + void InsertNode(int nKey, CString szValue) + { + m_Map[nKey] = szValue; + } +public: + void RemoveNode(int nKey) + { + m_Map.RemoveKey(nKey); + } + void RemoveAllNodes(void) + { + if (m_Map.GetCount() != 0) + m_Map.RemoveAll(); + } +public: + void Copy(CStringsMap& other) + { + POSITION pos = this->m_Map.GetStartPosition(); + int nKey; + while (pos != NULL) + { + CString rValue; + this->m_Map.GetNextAssoc(pos, nKey, rValue); + other.InsertNode(nKey, rValue); + } + } +public: + void SwapItems(int key1, int key2) + { + CString value1; + CString value2; + BOOL haveValue1 = this->m_Map.Lookup(key1, value1); + BOOL haveValue2 = this->m_Map.Lookup(key2, value2); + if (haveValue1 == FALSE || haveValue2 == FALSE) + return; + this->SetData(key2, value1); + this->SetData(key1, value2); + } +};