diff --git a/src/server/i18n.h b/include/i18n.h similarity index 63% rename from src/server/i18n.h rename to include/i18n.h index 1e42cac6..0b15729e 100644 --- a/src/server/i18n.h +++ b/include/i18n.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 Veloman Yunkan + * Copyright 2024 Veloman Yunkan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,29 +17,15 @@ * MA 02110-1301, USA. */ -#ifndef KIWIX_SERVER_I18N -#define KIWIX_SERVER_I18N +#ifndef KIWIX_I18N +#define KIWIX_I18N #include #include -#include namespace kiwix { -struct I18nString { - const char* const key; - const char* const value; -}; - -struct I18nStringTable { - const char* const lang; - const size_t entryCount; - const I18nString* const entries; - - const char* get(const std::string& key) const; -}; - std::string getTranslatedString(const std::string& lang, const std::string& key); namespace i18n @@ -70,28 +56,6 @@ private: const std::string m_lang; }; -class GetTranslatedStringWithMsgId -{ - typedef kainjow::mustache::basic_data MustacheString; - typedef std::pair MsgIdAndTranslation; - -public: - explicit GetTranslatedStringWithMsgId(const std::string& lang) : m_lang(lang) {} - - MsgIdAndTranslation operator()(const std::string& key) const - { - return {key, getTranslatedString(m_lang, key)}; - } - - MsgIdAndTranslation operator()(const std::string& key, const Parameters& params) const - { - return {key, expandParameterizedString(m_lang, key, params)}; - } - -private: - const std::string m_lang; -}; - } // namespace i18n class ParameterizedMessage @@ -121,18 +85,8 @@ inline ParameterizedMessage nonParameterizedMessage(const std::string& msgId) return ParameterizedMessage(msgId, noParams); } -struct LangPreference -{ - const std::string lang; - const float preference; -}; - -typedef std::vector UserLangPreferences; - -UserLangPreferences parseUserLanguagePreferences(const std::string& s); - -std::string selectMostSuitableLanguage(const UserLangPreferences& prefs); +std::string translateBookCategory(const std::string& lang, const std::string& category); } // namespace kiwix -#endif // KIWIX_SERVER_I18N +#endif // KIWIX_I18N diff --git a/include/meson.build b/include/meson.build index 03e6f046..4735c222 100644 --- a/include/meson.build +++ b/include/meson.build @@ -10,7 +10,8 @@ headers = [ 'kiwixserve.h', 'name_mapper.h', 'tools.h', - 'version.h' + 'version.h', + 'i18n.h' ] install_headers(headers, subdir:'kiwix') diff --git a/scripts/kiwix-compile-i18n b/scripts/kiwix-compile-i18n index 90b01ed1..1519bb6b 100755 --- a/scripts/kiwix-compile-i18n +++ b/scripts/kiwix-compile-i18n @@ -61,7 +61,7 @@ lang_table_entry_cxx_template = ''' cxxfile_template = '''// This file is automatically generated. Do not modify it. -#include "server/i18n.h" +#include "server/i18n_utils.h" namespace kiwix { namespace i18n { diff --git a/src/html_dumper.cpp b/src/html_dumper.cpp index 4896821b..e0b7cdd7 100644 --- a/src/html_dumper.cpp +++ b/src/html_dumper.cpp @@ -3,7 +3,7 @@ #include "tools/otherTools.h" #include "tools.h" #include "tools/regexTools.h" -#include "server/i18n.h" +#include "server/i18n_utils.h" namespace kiwix { @@ -77,7 +77,7 @@ std::string HTMLDumper::dumpPlainHTML(kiwix::Filter filter) const const auto tags = bookObj.getTags(); const auto downloadAvailable = (bookObj.getUrl() != ""); std::string faviconAttr = "style=background-image:url(" + bookIconUrl + ")"; - + booksData.push_back(kainjow::mustache::object{ {"id", contentId}, {"title", bookTitle}, diff --git a/src/search_renderer.cpp b/src/search_renderer.cpp index e64eb561..9a24e51e 100644 --- a/src/search_renderer.cpp +++ b/src/search_renderer.cpp @@ -32,7 +32,7 @@ #include "libkiwix-resources.h" #include "tools/stringTools.h" -#include "server/i18n.h" +#include "server/i18n_utils.h" namespace kiwix { diff --git a/src/server/i18n.cpp b/src/server/i18n.cpp index 5b948f26..f1975f40 100644 --- a/src/server/i18n.cpp +++ b/src/server/i18n.cpp @@ -17,7 +17,7 @@ * MA 02110-1301, USA. */ -#include "i18n.h" +#include "i18n_utils.h" #include "tools/otherTools.h" @@ -193,4 +193,13 @@ std::string selectMostSuitableLanguage(const UserLangPreferences& prefs) return bestLangSoFar; } +std::string translateBookCategory(const std::string& lang, const std::string& category) +{ + try { + return getTranslatedString(lang, "book-category." + category); + } catch (...) { + return category; + } +} + } // namespace kiwix diff --git a/src/server/i18n_utils.h b/src/server/i18n_utils.h new file mode 100644 index 00000000..c9672501 --- /dev/null +++ b/src/server/i18n_utils.h @@ -0,0 +1,83 @@ +/* + * Copyright 2022 Veloman Yunkan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef KIWIX_SERVER_I18N_UTILS +#define KIWIX_SERVER_I18N_UTILS + +#include "i18n.h" +#include + +namespace kiwix +{ + +struct I18nString { + const char* const key; + const char* const value; +}; + +struct I18nStringTable { + const char* const lang; + const size_t entryCount; + const I18nString* const entries; + + const char* get(const std::string& key) const; +}; + +namespace i18n +{ + +class GetTranslatedStringWithMsgId +{ + typedef kainjow::mustache::basic_data MustacheString; + typedef std::pair MsgIdAndTranslation; + +public: + explicit GetTranslatedStringWithMsgId(const std::string& lang) : m_lang(lang) {} + + MsgIdAndTranslation operator()(const std::string& key) const + { + return {key, getTranslatedString(m_lang, key)}; + } + + MsgIdAndTranslation operator()(const std::string& key, const Parameters& params) const + { + return {key, expandParameterizedString(m_lang, key, params)}; + } + +private: + const std::string m_lang; +}; + +} // namespace i18n + +struct LangPreference +{ + const std::string lang; + const float preference; +}; + +typedef std::vector UserLangPreferences; + +UserLangPreferences parseUserLanguagePreferences(const std::string& s); + +std::string selectMostSuitableLanguage(const UserLangPreferences& prefs); + +} // namespace kiwix + +#endif // KIWIX_SERVER_I18N_UTILS diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index ccc94a49..d908a24e 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -54,7 +54,7 @@ extern "C" { #include "search_renderer.h" #include "opds_dumper.h" #include "html_dumper.h" -#include "i18n.h" +#include "i18n_utils.h" #include #include diff --git a/src/server/request_context.cpp b/src/server/request_context.cpp index d879240c..ff3ebbeb 100644 --- a/src/server/request_context.cpp +++ b/src/server/request_context.cpp @@ -28,7 +28,7 @@ #include #include "tools/stringTools.h" -#include "i18n.h" +#include "i18n_utils.h" namespace kiwix { diff --git a/src/server/response.h b/src/server/response.h index 11808f0d..b4c9925f 100644 --- a/src/server/response.h +++ b/src/server/response.h @@ -27,7 +27,7 @@ #include #include "byte_range.h" #include "etag.h" -#include "i18n.h" +#include "i18n_utils.h" #include diff --git a/src/tools/otherTools.cpp b/src/tools/otherTools.cpp index 0c6eb36c..e125c2df 100644 --- a/src/tools/otherTools.cpp +++ b/src/tools/otherTools.cpp @@ -32,7 +32,7 @@ #endif #include "tools/stringTools.h" -#include "server/i18n.h" +#include "server/i18n_utils.h" #include "libkiwix-resources.h" #include diff --git a/static/skin/i18n/en.json b/static/skin/i18n/en.json index 3c7aa39e..9345a1cb 100644 --- a/static/skin/i18n/en.json +++ b/static/skin/i18n/en.json @@ -60,4 +60,22 @@ , "preview-book": "Preview" , "non-translated-text": "{{MSG}}" , "unknown-error": "Unknown error" + , "book-category.gutenberg": "Gutenberg" + , "book-category.iFixit": "iFixit" + , "book-category.mooc": "MOOC" + , "book-category.phet": "Phet" + , "book-category.stack_exchange": "Stack Exchange" + , "book-category.ted": "Ted" + , "book-category.vikidia": "Vikidia" + , "book-category.wikibooks": "Wikibooks" + , "book-category.wikihow": "wikiHow" + , "book-category.wikinews": "Wikinews" + , "book-category.wikipedia": "Wikipedia" + , "book-category.wikiquote": "Wikiquote" + , "book-category.wikisource": "Wikisource" + , "book-category.wikispecies": "Wikispecies" + , "book-category.wikiversity": "Wikiversity" + , "book-category.wikivoyage": "Wikivoyage" + , "book-category.wiktionary": "Wiktionary" + , "book-category.other": "Other" } diff --git a/static/skin/i18n/qqq.json b/static/skin/i18n/qqq.json index 9a8c5c14..f41c5d7a 100644 --- a/static/skin/i18n/qqq.json +++ b/static/skin/i18n/qqq.json @@ -62,5 +62,23 @@ "download-links-title": "Title for no-js download page", "preview-book": "Tooltip of book-tile leading to the book", "non-translated-text": "{{ignored}}\nUsed to display text that is generated at runtime and cannot be translated. Nothing to translate about this one.", - "unknown-error": "Unknown error" + "unknown-error": "Unknown error", + "book-category.gutenberg": "Name for the category of books from the Gutenberg project", + "book-category.iFixit": "Name for the category of iFixit books", + "book-category.mooc": "Name for the category of MOOC books", + "book-category.phet": "Name for the category of Phet books", + "book-category.stack_exchange": "Name for the category of books from the Stack Exchange network books", + "book-category.ted": "Name for the category of Ted books", + "book-category.vikidia": "Name for the category of Vikidia books", + "book-category.wikibooks": "Name for the category of Wikibooks books books", + "book-category.wikihow": "Name for the category of wikiHow books", + "book-category.wikinews": "Name for the category of Wikinews books", + "book-category.wikipedia": "Name for the category of Wikipedia books", + "book-category.wikiquote": "Name for the category of Wikiquote books", + "book-category.wikisource": "Name for the category of Wikisource books", + "book-category.wikispecies": "Name for the category of Wikispecies books", + "book-category.wikiversity": "Name for the category of Wikiversity books", + "book-category.wikivoyage": "Name for the category of Wikivoyage books", + "book-category.wiktionary": "Name for the category of Wiktionary books", + "book-category.other": "Books not belonging to any special category are listed under this one" } diff --git a/static/skin/i18n/test.json b/static/skin/i18n/test.json index 29c2e961..f997ef5e 100644 --- a/static/skin/i18n/test.json +++ b/static/skin/i18n/test.json @@ -47,4 +47,22 @@ , "empty-search-results-page-header": "[I18N TESTING] No results were found for \"{{{SEARCH_PATTERN}}}\"" , "search-result-book-info": "from [I18N TESTING] {{BOOK_TITLE}}" , "word-count": "{{COUNT}} [I18N TESTING] words" + , "book-category.gutenberg": "[I18N] Gutenberg [TESTING]" + , "book-category.iFixit": "[I18N] iFixit [TESTING]" + , "book-category.mooc": "[I18N] MOOC [TESTING]" + , "book-category.phet": "[I18N] Phet [TESTING]" + , "book-category.stack_exchange": "[I18N] Stack Exchange [TESTING]" + , "book-category.ted": "[I18N] Ted [TESTING]" + , "book-category.vikidia": "[I18N] Vikidia [TESTING]" + , "book-category.wikibooks": "[I18N] Wikibooks [TESTING]" + , "book-category.wikihow": "[I18N] wikiHow [TESTING]" + , "book-category.wikinews": "[I18N] Wikinews [TESTING]" + , "book-category.wikipedia": "[I18N] Wikipedia [TESTING]" + , "book-category.wikiquote": "[I18N] Wikiquote [TESTING]" + , "book-category.wikisource": "[I18N] Wikisource [TESTING]" + , "book-category.wikispecies": "[I18N] Wikispecies [TESTING]" + , "book-category.wikiversity": "[I18N] Wikiversity [TESTING]" + , "book-category.wikivoyage": "[I18N] Wikivoyage [TESTING]" + , "book-category.wiktionary": "[I18N] Wiktionary [TESTING]" + , "book-category.other": "[I18N] Other [TESTING]" } diff --git a/test/i18n.cpp b/test/i18n.cpp index 4e891d6e..a40e01eb 100644 --- a/test/i18n.cpp +++ b/test/i18n.cpp @@ -1,4 +1,4 @@ -#include "../src/server/i18n.h" +#include "../src/server/i18n_utils.h" #include "gtest/gtest.h" using namespace kiwix; @@ -48,3 +48,17 @@ TEST(ParameterizedMessage, messagesWithParameters) EXPECT_EQ(msg.getText("test"), "Filter [I18N] by [TESTING] tag \"\""); } } + +TEST(I18n, translateBookCategory) +{ + + EXPECT_EQ(translateBookCategory("en", "ted"), "Ted"); + EXPECT_EQ(translateBookCategory("test", "ted"), "[I18N] Ted [TESTING]"); + + EXPECT_EQ(translateBookCategory("en", "stack_exchange"), "Stack Exchange"); + EXPECT_EQ(translateBookCategory("test", "stack_exchange"), "[I18N] Stack Exchange [TESTING]"); + + // unknown categories are simply not translated + EXPECT_EQ(translateBookCategory("en", "Qwerty"), "Qwerty"); + EXPECT_EQ(translateBookCategory("test", "Qwerty"), "Qwerty"); +} diff --git a/test/otherTools.cpp b/test/otherTools.cpp index 1e38bbb1..3ffca045 100644 --- a/test/otherTools.cpp +++ b/test/otherTools.cpp @@ -20,7 +20,7 @@ #include "gtest/gtest.h" #include "../src/tools/otherTools.h" #include "zim/suggestion_iterator.h" -#include "../src/server/i18n.h" +#include "../src/server/i18n_utils.h" #include