From 9cc790869ed3905c78c7eeeb0bb44f800b3f2af4 Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:11:09 +0200 Subject: 3.15 --- shared/i18n.cpp | 751 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 751 insertions(+) create mode 100644 shared/i18n.cpp (limited to 'shared/i18n.cpp') diff --git a/shared/i18n.cpp b/shared/i18n.cpp new file mode 100644 index 00000000..537d9fb4 --- /dev/null +++ b/shared/i18n.cpp @@ -0,0 +1,751 @@ +// ************************************************************************** +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * +// * Copyright (C) 2008-2011 ZenJu (zhnmju123 AT gmx.de) * +// ************************************************************************** +// +#include "i18n.h" +#include +#include +#include +#include +#include +#include "../shared/standard_paths.h" +#include "../shared/string_conv.h" +#include "system_constants.h" +#include +#include +#include + +using ffs3::LocalizationInfo; + + +namespace +{ +//will receive their proper value in CustomLocale::CustomLocale() +wxString THOUSANDS_SEPARATOR = wxT(","); +wxString DECIMAL_POINT = wxT("."); + +typedef std::map Translation; +Translation activeTranslation; //map original text |-> translation + +int activeLanguage = wxLANGUAGE_ENGLISH; +} + + +wxString ffs3::getThousandsSeparator() +{ + return THOUSANDS_SEPARATOR; +} + + +wxString ffs3::getDecimalPoint() +{ + return DECIMAL_POINT; +} + + +const std::vector& LocalizationInfo::get() +{ + static LocalizationInfo instance; + return instance.locMapping; +} + + +LocalizationInfo::LocalizationInfo() +{ + ffs3::LocInfoLine newEntry; + + newEntry.languageID = wxLANGUAGE_CZECH; + newEntry.languageName = wxT("Čeština"); + newEntry.languageFile = wxT("czech.lng"); + newEntry.translatorName = wxT("ViCi"); + newEntry.languageFlag = wxT("czechRep.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_GERMAN; + newEntry.languageName = wxT("Deutsch"); + newEntry.languageFile = wxT("german.lng"); + newEntry.translatorName = wxT("ZenJu"); + newEntry.languageFlag = wxT("germany.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_ENGLISH_UK; + newEntry.languageName = wxT("English (UK)"); + newEntry.languageFile = wxT("english_uk.lng"); + newEntry.translatorName = wxT("Robert Readman"); + newEntry.languageFlag = wxT("england.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_ENGLISH; + newEntry.languageName = wxT("English (US)"); + newEntry.languageFile = wxT(""); + newEntry.translatorName = wxT("ZenJu"); + newEntry.languageFlag = wxT("usa.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_SPANISH; + newEntry.languageName = wxT("Español"); + newEntry.languageFile = wxT("spanish.lng"); + newEntry.translatorName = wxT("Alexis Martínez"); + newEntry.languageFlag = wxT("spain.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_GREEK; + newEntry.languageName = wxT("Ελληνικά"); + newEntry.languageFile = wxT("greek.lng"); + newEntry.translatorName = wxT("Γιώργος Γιαγλής"); + newEntry.languageFlag = wxT("greece.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_FRENCH; + newEntry.languageName = wxT("Français"); + newEntry.languageFile = wxT("french.lng"); + newEntry.translatorName = wxT("Jean-François Hartmann"); + newEntry.languageFlag = wxT("france.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_ITALIAN; + newEntry.languageName = wxT("Italiano"); + newEntry.languageFile = wxT("italian.lng"); + newEntry.translatorName = wxT("Emmo"); + newEntry.languageFlag = wxT("italy.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_HUNGARIAN; + newEntry.languageName = wxT("Magyar"); + newEntry.languageFile = wxT("hungarian.lng"); + newEntry.translatorName = wxT("Demon"); + newEntry.languageFlag = wxT("hungary.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_DUTCH; + newEntry.languageName = wxT("Nederlands"); + newEntry.languageFile = wxT("dutch.lng"); + newEntry.translatorName = wxT("Dion van Lieshout"); + newEntry.languageFlag = wxT("holland.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_POLISH; + newEntry.languageName = wxT("Polski"); + newEntry.languageFile = wxT("polish.lng"); + newEntry.translatorName = wxT("Wojtek Pietruszewski"); + newEntry.languageFlag = wxT("poland.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_PORTUGUESE; + newEntry.languageName = wxT("Português"); + newEntry.languageFile = wxT("portuguese.lng"); + newEntry.translatorName = wxT("QuestMark"); + newEntry.languageFlag = wxT("portugal.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_PORTUGUESE_BRAZILIAN; + newEntry.languageName = wxT("Português do Brasil"); + newEntry.languageFile = wxT("portuguese_br.lng"); + newEntry.translatorName = wxT("Edison Aranha"); + newEntry.languageFlag = wxT("brazil.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_RUSSIAN; + newEntry.languageName = wxT("Pусский"); + newEntry.languageFile = wxT("russian.lng"); + newEntry.translatorName = wxT("Fayzullin T.N. aka Svobodniy"); + newEntry.languageFlag = wxT("russia.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_ROMANIAN; + newEntry.languageName = wxT("Română"); + newEntry.languageFile = wxT("romanian.lng"); + newEntry.translatorName = wxT("Alexandru Bogdan Munteanu"); + newEntry.languageFlag = wxT("romania.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_SLOVENIAN; + newEntry.languageName = wxT("Slovenščina"); + newEntry.languageFile = wxT("slovenian.lng"); + newEntry.translatorName = wxT("Matej Badalic"); + newEntry.languageFlag = wxT("slovakia.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_FINNISH; + newEntry.languageName = wxT("Suomi"); + newEntry.languageFile = wxT("finnish.lng"); + newEntry.translatorName = wxT("Nalle Juslén"); + newEntry.languageFlag = wxT("finland.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_SWEDISH; + newEntry.languageName = wxT("Svenska"); + newEntry.languageFile = wxT("swedish.lng"); + newEntry.translatorName = wxT("Åke Engelbrektson"); + newEntry.languageFlag = wxT("sweden.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_TURKISH; + newEntry.languageName = wxT("Türkçe"); + newEntry.languageFile = wxT("turkish.lng"); + newEntry.translatorName = wxT("Kaya Zeren"); + newEntry.languageFlag = wxT("turkey.png"); + locMapping.push_back(newEntry); + + // newEntry.languageID = wxLANGUAGE_HEBREW; + // newEntry.languageName = wxT("עִבְרִית"); + // newEntry.languageFile = wxT("hebrew.lng"); + // newEntry.translatorName = wxT("Moshe Olshevsky"); + // newEntry.languageFlag = wxT("isreal.png"); + // locMapping.push_back(newEntry); + + // newEntry.languageID = wxLANGUAGE_ARABIC; + // newEntry.languageName = wxT("العربية"); + // newEntry.languageFile = wxT("arabic.lng"); + // newEntry.translatorName = wxT("Yousef Shamshoum"); + // newEntry.languageFlag = wxT("arabic-language.png"); + // locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_JAPANESE; + newEntry.languageName = wxT("日本語"); + newEntry.languageFile = wxT("japanese.lng"); + newEntry.translatorName = wxT("Tilt"); + newEntry.languageFlag = wxT("japan.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_CHINESE_TRADITIONAL; + newEntry.languageName = wxT("正體中文"); + newEntry.languageFile = wxT("chinese_traditional.lng"); + newEntry.translatorName = wxT("Carlos"); + newEntry.languageFlag = wxT("taiwan.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_CHINESE_SIMPLIFIED; + newEntry.languageName = wxT("简体中文"); + newEntry.languageFile = wxT("chinese_simple.lng"); + newEntry.translatorName = wxT("CyberCowBoy"); + newEntry.languageFlag = wxT("china.png"); + locMapping.push_back(newEntry); + + newEntry.languageID = wxLANGUAGE_KOREAN; + newEntry.languageName = wxT("한국어"); + newEntry.languageFile = wxT("korean.lng"); + newEntry.translatorName = wxT("Simon Park"); + newEntry.languageFlag = wxT("south_korea.png"); + locMapping.push_back(newEntry); +} + + +namespace +{ +int mapLanguageDialect(int language) +{ + switch (language) //map language dialects + { + //variants of wxLANGUAGE_GERMAN + case wxLANGUAGE_GERMAN_AUSTRIAN: + case wxLANGUAGE_GERMAN_BELGIUM: + case wxLANGUAGE_GERMAN_LIECHTENSTEIN: + case wxLANGUAGE_GERMAN_LUXEMBOURG: + case wxLANGUAGE_GERMAN_SWISS: + return wxLANGUAGE_GERMAN; + + //variants of wxLANGUAGE_FRENCH + case wxLANGUAGE_FRENCH_BELGIAN: + case wxLANGUAGE_FRENCH_CANADIAN: + case wxLANGUAGE_FRENCH_LUXEMBOURG: + case wxLANGUAGE_FRENCH_MONACO: + case wxLANGUAGE_FRENCH_SWISS: + return wxLANGUAGE_FRENCH; + + //variants of wxLANGUAGE_DUTCH + case wxLANGUAGE_DUTCH_BELGIAN: + return wxLANGUAGE_DUTCH; + + //variants of wxLANGUAGE_ITALIAN + case wxLANGUAGE_ITALIAN_SWISS: + return wxLANGUAGE_ITALIAN; + + //variants of wxLANGUAGE_CHINESE_SIMPLIFIED + case wxLANGUAGE_CHINESE: + case wxLANGUAGE_CHINESE_SINGAPORE: + return wxLANGUAGE_CHINESE_SIMPLIFIED; + + //variants of wxLANGUAGE_CHINESE_TRADITIONAL + case wxLANGUAGE_CHINESE_TAIWAN: + case wxLANGUAGE_CHINESE_HONGKONG: + case wxLANGUAGE_CHINESE_MACAU: + return wxLANGUAGE_CHINESE_TRADITIONAL; + + //variants of wxLANGUAGE_RUSSIAN + case wxLANGUAGE_RUSSIAN_UKRAINE: + return wxLANGUAGE_RUSSIAN; + + //variants of wxLANGUAGE_SPANISH + case wxLANGUAGE_SPANISH_ARGENTINA: + case wxLANGUAGE_SPANISH_BOLIVIA: + case wxLANGUAGE_SPANISH_CHILE: + case wxLANGUAGE_SPANISH_COLOMBIA: + case wxLANGUAGE_SPANISH_COSTA_RICA: + case wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC: + case wxLANGUAGE_SPANISH_ECUADOR: + case wxLANGUAGE_SPANISH_EL_SALVADOR: + case wxLANGUAGE_SPANISH_GUATEMALA: + case wxLANGUAGE_SPANISH_HONDURAS: + case wxLANGUAGE_SPANISH_MEXICAN: + case wxLANGUAGE_SPANISH_MODERN: + case wxLANGUAGE_SPANISH_NICARAGUA: + case wxLANGUAGE_SPANISH_PANAMA: + case wxLANGUAGE_SPANISH_PARAGUAY: + case wxLANGUAGE_SPANISH_PERU: + case wxLANGUAGE_SPANISH_PUERTO_RICO: + case wxLANGUAGE_SPANISH_URUGUAY: + case wxLANGUAGE_SPANISH_US: + case wxLANGUAGE_SPANISH_VENEZUELA: + return wxLANGUAGE_SPANISH; + + //variants of wxLANGUAGE_SWEDISH + case wxLANGUAGE_SWEDISH_FINLAND: + return wxLANGUAGE_SWEDISH; + + //case wxLANGUAGE_CZECH: + //case wxLANGUAGE_FINNISH: + //case wxLANGUAGE_GREEK: + //case wxLANGUAGE_JAPANESE: + //case wxLANGUAGE_POLISH: + //case wxLANGUAGE_SLOVENIAN: + //case wxLANGUAGE_HUNGARIAN: + //case wxLANGUAGE_PORTUGUESE: + //case wxLANGUAGE_PORTUGUESE_BRAZILIAN: + //case wxLANGUAGE_KOREAN: + + //variants of wxLANGUAGE_ARABIC + case wxLANGUAGE_ARABIC_ALGERIA: + case wxLANGUAGE_ARABIC_BAHRAIN: + case wxLANGUAGE_ARABIC_EGYPT: + case wxLANGUAGE_ARABIC_IRAQ: + case wxLANGUAGE_ARABIC_JORDAN: + case wxLANGUAGE_ARABIC_KUWAIT: + case wxLANGUAGE_ARABIC_LEBANON: + case wxLANGUAGE_ARABIC_LIBYA: + case wxLANGUAGE_ARABIC_MOROCCO: + case wxLANGUAGE_ARABIC_OMAN: + case wxLANGUAGE_ARABIC_QATAR: + case wxLANGUAGE_ARABIC_SAUDI_ARABIA: + case wxLANGUAGE_ARABIC_SUDAN: + case wxLANGUAGE_ARABIC_SYRIA: + case wxLANGUAGE_ARABIC_TUNISIA: + case wxLANGUAGE_ARABIC_UAE: + case wxLANGUAGE_ARABIC_YEMEN: + return wxLANGUAGE_ARABIC; + + //variants of wxLANGUAGE_ENGLISH_UK + case wxLANGUAGE_ENGLISH_AUSTRALIA: + case wxLANGUAGE_ENGLISH_NEW_ZEALAND: + case wxLANGUAGE_ENGLISH_TRINIDAD: + case wxLANGUAGE_ENGLISH_CARIBBEAN: + case wxLANGUAGE_ENGLISH_JAMAICA: + case wxLANGUAGE_ENGLISH_BELIZE: + case wxLANGUAGE_ENGLISH_EIRE: + case wxLANGUAGE_ENGLISH_SOUTH_AFRICA: + case wxLANGUAGE_ENGLISH_ZIMBABWE: + case wxLANGUAGE_ENGLISH_BOTSWANA: + case wxLANGUAGE_ENGLISH_DENMARK: + return wxLANGUAGE_ENGLISH_UK; + + default: + return language; + } +} + + +inline +void exchangeEscapeChars(wxString& data) +{ + wxString output; + + const wxChar* input = data.c_str(); + + wxChar value; + while ((value = *input) != wxChar(0)) + { + //read backslash + if (value == wxChar('\\')) + { + //read next character + ++input; + if ((value = *input) == wxChar(0)) + break; + + switch (value) + { + case wxChar('\\'): + output += wxChar('\\'); + break; + case wxChar('n'): + output += wxChar('\n'); + break; + case wxChar('t'): + output += wxChar('\t'); + break; + case wxChar('\"'): + output += wxChar('\"'); + break; + default: + output += value; + } + } + else + output += value; + + ++input; + } + data = output; +} + + +//workaround to get a FILE* from a unicode filename in a portable way +class UnicodeFileReader +{ +public: + UnicodeFileReader(const wxString& filename) : + inputFile(NULL) + { + wxFFile dummyFile(filename, wxT("rb")); + if (dummyFile.IsOpened()) + { + inputFile = dummyFile.fp(); + dummyFile.Detach(); + } + } + + ~UnicodeFileReader() + { + if (inputFile != NULL) + fclose(inputFile); + } + + bool isOkay() + { + return inputFile != NULL; + } + + bool getNextLine(wxString& line) + { + std::string output; + + while (true) + { + const int c = fgetc(inputFile); + if (c == EOF) + return false; + else if (c == 0xD) + { + //Delimiter: + //---------- + //Linux: 0xA \n + //Mac: 0xD \r + //Win: 0xD 0xA \r\n <- language files are in Windows format + + fgetc(inputFile); //discard the 0xA character + + line = wxString::FromUTF8(output.c_str(), output.length()); + return true; + } + output += static_cast(c); + } + } + +private: + FILE* inputFile; +}; + + +void loadTranslation(const wxString& filename, Translation& trans) //empty translation on error +{ + trans.clear(); + + UnicodeFileReader langFile(ffs3::getResourceDir() + wxT("Languages") + ffs3::zToWx(common::FILE_NAME_SEPARATOR) + filename); + if (langFile.isOkay()) + { + int rowNumber = 0; + wxString original; + wxString tmpString; + while (langFile.getNextLine(tmpString)) + { + exchangeEscapeChars(tmpString); + + if (rowNumber++ % 2 == 0) + original = tmpString; + else + { + const wxString& translation = tmpString; + + if (!original.empty() && !translation.empty()) + trans.insert(std::make_pair(original, translation)); + } + } + } +} +} + + +void ffs3::setLanguage(int language) +{ + static class StaticInit + { + public: + StaticInit() : loc(wxLANGUAGE_DEFAULT) //wxLocale: we need deferred initialization, sigh... + { + //::setlocale (LC_ALL, ""); -> implicitly called by wxLocale + const lconv* localInfo = ::localeconv(); + + //actually these two parameters are language dependent, but we take system setting to handle all kinds of language derivations + THOUSANDS_SEPARATOR = wxString::FromUTF8(localInfo->thousands_sep); + DECIMAL_POINT = wxString::FromUTF8(localInfo->decimal_point); + + // why not working? + // THOUSANDS_SEPARATOR = std::use_facet >(std::locale("")).thousands_sep(); + // DECIMAL_POINT = std::use_facet >(std::locale("")).decimal_point(); + } + private: + wxLocale loc; //required for RTL language support (and nothing else) + } dummy; + + activeLanguage = language; + + //default: english + wxString languageFile; + + //(try to) retrieve language filename + const int mappedLanguage = mapLanguageDialect(language); + for (std::vector::const_iterator i = LocalizationInfo::get().begin(); i != LocalizationInfo::get().end(); ++i) + if (i->languageID == mappedLanguage) + { + languageFile = i->languageFile; + break; + } + + //load language file into buffer + activeTranslation.clear(); + if (!languageFile.empty()) + { + loadTranslation(languageFile, activeTranslation); //empty translation on error + if (activeTranslation.empty()) + { + wxMessageBox(wxString(_("Error reading file:")) + wxT(" \"") + languageFile + wxT("\""), _("Error"), wxOK | wxICON_ERROR); + activeLanguage = wxLANGUAGE_ENGLISH; //reset to english language to show this error just once + } + } + else + ; //if languageFile is empty texts will be english per default +} + + +int ffs3::getLanguage() +{ + return activeLanguage; +} + + +int ffs3::retrieveSystemLanguage() +{ + return wxLocale::GetSystemLanguage(); +} + + + + +/* +typedef Zbase Wstring; + +const Wstring TK_TERNARY_QUEST = L"?"; +const Wstring TK_TERNARY_COLON = L":"; +const Wstring TK_OR = L"||"; +const Wstring TK_AND = L"&&"; +const Wstring TK_EQUAL = L"=="; +const Wstring TK_NOT_EQUAL = L"!="; +const Wstring TK_LESS = L"<"; +const Wstring TK_LESS_EQUAL = L"<="; +const Wstring TK_GREATER = L">"; +const Wstring TK_GREATER_EQUAL = L">="; +const Wstring TK_MODULUS = L"%"; +const Wstring TK_N = L"n"; +const Wstring TK_BRACKET_LEFT = L"("; +const Wstring TK_BRACKET_RIGHT = L")"; +const Wstring TK_FORM_COUNT = L"nplurals="; +const Wstring TK_PHRASE_BEGIN = L"plural="; + + +template +struct Expr +{ + typedef T ValueType; + virtual ValueType eval() const = 0; +}; + + +template +struct GenericBiExp : public Out +{ + GenericBiExp(const In& lhs, const In& rhs, BiOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) {} + virtual typename Out::ValueType eval() const { return biop_(lhs_.eval(), rhs_.eval()); } + const In& lhs_; + const In& rhs_; + BiOp biop_; +}; + +template +inline +GenericBiExp makeBiExp(const In& lhs, const In& rhs, BiOp biop) +{ + return GenericBiExp(lhs, rhs, biop); +} + +template +struct TernaryExp : public Out +{ + TernaryExp(const Expr& ifExp, const Out& thenExp, const Out& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) {} + virtual typename Out::ValueType eval() const { return ifExp_.eval() ? thenExp_.eval() : elseExp_.eval(); } + const Expr& ifExp_; + const Out& thenExp_; + const Out& elseExp_; +}; + +struct LiteralNumberEx : public Expr +{ + LiteralNumberEx(int n) : n_(n) {} + virtual ValueType eval() const { return n_; } + int n_; +}; + +struct NumberN : public Expr +{ + NumberN(int& n) : n_(n) {} + virtual ValueType eval() const { return n_; } + int& n_; +}; + + +class PluralForm +{ +public: + struct ParserError {}; + + PluralForm(const Wstring& phrase) //.po format,e.g.: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2) + { + Wstring tmp; + std::remove_copy_if(phrase.begin(), phrase.end(), std::back_inserter(tmp), std::iswspace); + + size_t pos = tmp.find(TK_FORM_COUNT); + if (pos == Wstring::npos) + throw ParserError(); + + count = tmp.substr(pos + TK_FORM_COUNT.size()).toNumber(); + + pos = tmp.find(TK_PHRASE_BEGIN); + if (pos == Wstring::npos) + throw ParserError(); + + expr = &parseNumber(tmp.substr(pos + TK_PHRASE_BEGIN.size())); + } + + int formCount() const { return count; } + + int getForm(int n) const { n_ = n ; return expr->eval(); } + +private: + const Expr& parseBool(const Wstring& phrase) + { + Wstring part1, part2; + if (trySplit(phrase, TK_OR, part1, part2)) + return manageObj(makeBiExp >(parseBool(part1), parseBool(part2), std::logical_or())); + else if (trySplit(phrase, TK_AND, part1, part2)) + return manageObj(makeBiExp >(parseBool(part1), parseBool(part2), std::logical_and())); + else if (trySplit(phrase, TK_EQUAL, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::equal_to())); + else if (trySplit(phrase, TK_NOT_EQUAL, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::not_equal_to())); + else if (trySplit(phrase, TK_LESS, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::less())); + else if (trySplit(phrase, TK_LESS_EQUAL, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::less_equal())); + else if (trySplit(phrase, TK_GREATER, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::greater())); + else if (trySplit(phrase, TK_GREATER_EQUAL, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::greater_equal())); + else + throw ParserError(); + } + + const Expr& parseNumber(const Wstring& phrase) + { + Wstring part1, part2; + + + if (trySplit(phrase, TK_TERNARY_QUEST, part1, part2, TO_LEFT)) + { + Wstring part3; + if (!trySplit(Wstring(part2), TK_TERNARY_COLON, part2, part3, TO_LEFT)) + throw ParserError(); + return manageObj(TernaryExp >(parseBool(part1), parseNumber(part2), parseNumber(part3))); + } + else if (trySplit(phrase, TK_MODULUS, part1, part2)) + return manageObj(makeBiExp >(parseNumber(part1), parseNumber(part2), std::modulus())); + else if (phrase == TK_N) + return manageObj(NumberN(n_)); + else //expect literal number + { + if (std::find_if(phrase.begin(), phrase.end(), std::not1(std::ptr_fun(std::iswdigit))) != phrase.end()) + throw ParserError(); + return manageObj(LiteralNumberEx(phrase.toNumber())); + } + } + + enum Associativity + { + TO_LEFT, + TO_RIGHT + }; + static bool trySplit(const Wstring& phrase, const Wstring& delimiter, Wstring& part1, Wstring& part2, Associativity assoc = TO_RIGHT) + { + size_t pos = assoc == TO_LEFT ? + phrase.find(delimiter) : //reverse [!] + phrase.rfind(delimiter); + if (pos == Wstring::npos) + return false; + + part1 = phrase.substr(0, pos); + part2 = phrase.substr(pos + delimiter.size()); + return true; + } + + template + const T& manageObj(const T& obj) + { + dump.push_back(obj); + return *boost::any_cast(&dump.back()); + } + + int count; + const Expr* expr; + mutable int n_; + + std::list dump; //manage polymorphc object lifetimes +}; + + + PluralForm dummy(L"nplurals=3; plural=n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 > 20) ? 1 : 2"); + int ddf = dummy.formCount(); + int kddf = dummy.getForm(0); +*/ + + + +wxString ffs3::translate(const wxString& original) //translate into currently selected language +{ + //look for translation in buffer table + const Translation::const_iterator i = activeTranslation.find(original); + if (i != activeTranslation.end()) + return i->second.c_str(); + + //fallback + return original; +} -- cgit