//apl-translate.cpp

#include "stdafx.h"
#include "resource.h"
#include <locale.h>
#include "aplAggr.h"
#include <map>

#ifdef _MFC_VER
	#include "atlbase.h"

	#ifdef _DEBUG
		#define new DEBUG_NEW
	#endif
#else
#ifndef __linux__
	#include <winnls.h>
#endif
	#include <wctype.h>
	#include <qglobal.h>
	#include <QCoreApplication>
	#include <QLocale>
	#include <QString>
	#include <QSettings>
#endif


#ifdef _MFC_VER
unsigned long CaplTranslate_m_cur_lang = -1; // текущий язык для которого зачитан xml с переводом
CaplStrStrMap CaplTranslate_m_map;
#else
CString CaplTranslate_m_cur_lang{_T("")}; // текущий язык для которого зачитан xml с переводом
CString CaplTranslate_m_new_lang{_T("")}; // новый язык, который прочитан из настроек или установлен из приложения
CString CaplTranslate_m_sys_lang{_T("")}; // язык системы
CString CaplTranslate_m_ini_path{_T(PARAMS_APP_INI ".ini")}; // путь к ini, в котором хранится язык интерфейса

bool global_TranslateInited(false);
QMap<QString, SAPLanguage*> global_Langs;
aplTestInit globalTestInitTranslate(&global_TranslateInited, true);

// Статическая переменная CaplTranslate_m_map заменена на динамическую, т.к. в windows и в linux разный порядок
//	создания и удаления статических объектов-классов из статических библиотек. В windows сначала создаются все объекты
//	в библиотеках, потом в exe. В linux наоборот, сначала создаются объекты в exe, потом в бибиотеках.
//	Удаляются наоборот: в windows сначала в exe, потом в бибиотеках. В linux сначала в бибиотеках, потом в exe.
//	Т.е. если CaplTranslate_m_map задавать статикой, то она или там, или там будет удалена до объектов приложений в exe,
//	что вызовет падение при попытке перевода из их деструктора.
// А вот простые типы (int double и указатели) создаются компилятором, поэтому указатель равен 0 до вызжова конструкторов
//	всех статических объектов. Поэтому динамическое создание с проверкой if(p!=0)p=new AAA(); работает корректно
//	в любой ОС. А вот удалять этот объект не стоит; если в приложении остались работающие нити, то можно нарваться
//	на одновременный доступ к памяти из разных нитей, а критические секции применять нельзя - у них неизвестно когда
//	будет вызван деструктор.
CaplStrStrMap *gl_pTranslateMap{0};
#endif

bool CaplTranslate::m_Suppress = false;
bool CaplTranslate::m_bTranslate = false;
bool CaplTranslate::m_bShowStringId = false;

typedef std::map<long, CString> TMapLongToStr;
typedef std::map<long, CString>::iterator TMapLongToStr_it;

bool LoadXmlToMap(LPCTSTR filename, TMapLongToStr &mapStr, bool hide_mode = true);

SAPLanguage apl_langs[] = {
	SAPLanguage(	0x0436,	_T("af-ZA"),		_T("Afrikaans (South Africa)"),							_T("af")		)
	, SAPLanguage(	0x041c,	_T("sq-AL"),		_T("Albanian (Albania)"),								_T("sq")		)
	, SAPLanguage(	0x0484, _T("gsw-FR"),		_T("Alsatian (France)"),								_T("")			)
	, SAPLanguage(	0x045e, _T("am-ET"),		_T("Amharic (Ethiopia)"),								_T("am")		)
	, SAPLanguage(	0x1401, _T("ar-DZ"),		_T("Arabic (Algeria)"),									_T("ar")		)
	, SAPLanguage(	0x3c01, _T("ar-BH"),		_T("Arabic (Bahrain)"),									_T("ar")		)
	, SAPLanguage(	0x0c01, _T("ar-EG"),		_T("Arabic (Egypt)"),									_T("ar")		)
	, SAPLanguage(	0x0801, _T("ar-IQ"),		_T("Arabic (Iraq)"),									_T("ar")		)
	, SAPLanguage(	0x2c01, _T("ar-JO"),		_T("Arabic (Jordan)"),									_T("ar")		)
	, SAPLanguage(	0x3401, _T("ar-KW"),		_T("Arabic (Kuwait)"),									_T("ar")		)
	, SAPLanguage(	0x3001, _T("ar-LB"),		_T("Arabic (Lebanon)"),									_T("ar")		)
	, SAPLanguage(	0x1001, _T("ar-LY"),		_T("Arabic (Libya)"),									_T("ar")		)
	, SAPLanguage(	0x1801, _T("ar-MA"),		_T("Arabic (Morocco)"),									_T("ar")		)
	, SAPLanguage(	0x2001, _T("ar-OM"),		_T("Arabic (Oman)"),									_T("ar")		)
	, SAPLanguage(	0x4001, _T("ar-QA"),		_T("Arabic (Qatar)"),									_T("ar")		)
	, SAPLanguage(	0x0401, _T("ar-SA"),		_T("Arabic (Saudi Arabia)"),							_T("ar")		)
	, SAPLanguage(	0x2801, _T("ar-SY"),		_T("Arabic (Syria)"),									_T("ar")		)
	, SAPLanguage(	0x1c01, _T("ar-TN"),		_T("Arabic (Tunisia)"),									_T("ar")		)
	, SAPLanguage(	0x3801, _T("ar-AE"),		_T("Arabic (U.A.E.)"),									_T("ar")		)
	, SAPLanguage(	0x2401, _T("ar-YE"),		_T("Arabic (Yemen)"),									_T("ar")		)
	, SAPLanguage(	0x042b, _T("hy-AM"),		_T("Armenian (Armenia)"),								_T("hy")		)
	, SAPLanguage(	0x044d, _T("as-IN"),		_T("Assamese (India)"),									_T("")			)
	, SAPLanguage(	0x082c, _T("az-Cyrl-AZ"),	_T("Azeri (Azerbaijan, Cyrillic)"),						_T("")			)
	, SAPLanguage(	0x042c, _T("az-Latn-AZ"),	_T("Azeri (Azerbaijan, Latin)"),						_T("az")		)
	, SAPLanguage(	0x046d, _T("ba-RU"),		_T("Bashkir (Russia)"),									_T("ba")		)
	, SAPLanguage(	0x042d, _T("eu-ES"),		_T("Basque (Basque)"),									_T("eu")		)
	, SAPLanguage(	0x0423, _T("be-BY"),		_T("Belarusian (Belarus)"),								_T("be")		)
	, SAPLanguage(	0x0445, _T("bn-IN"),		_T("Bengali (India)"),									_T("bn")		)
	, SAPLanguage(	0x201a, _T("bs-Cyrl-BA"),	_T("Bosnian (Bosnia and Herzegovina, Cyrillic)"),		_T("")			)
	, SAPLanguage(	0x141a, _T("bs-Latn-BA"),	_T("Bosnian (Bosnia and Herzegovina, Latin)"),			_T("bs-Latn")	)
	, SAPLanguage(	0x047e, _T("br-FR"),		_T("Breton (France)"),									_T("")			)
	, SAPLanguage(	0x0402, _T("bg-BG"),		_T("Bulgarian (Bulgaria)"),								_T("bg")		)
	, SAPLanguage(	0x0403, _T("ca-ES"),		_T("Catalan (Catalan)"),								_T("ca")		)
	, SAPLanguage(	0x0c04, _T("zh-HK"),		_T("Chinese (Hong Kong SAR, PRC)"),						_T("zh-CHS")	)
	, SAPLanguage(	0x1404, _T("zh-MO"),		_T("Chinese (Macao SAR)"),								_T("zh-CHS")	)
	, SAPLanguage(	0x0804, _T("zh-CN"),		_T("Chinese (PRC)"),									_T("zh-CHS")	)
	, SAPLanguage(	0x1004, _T("zh-SG"),		_T("Chinese (Singapore)"),								_T("zh-CHS")	)
	, SAPLanguage(	0x0404, _T("zh-TW"),		_T("Chinese (Taiwan)"),									_T("zh-CHS")	)
	, SAPLanguage(	0x101a, _T("hr-BA"),		_T("Croatian (Bosnia and Herzegovina, Latin)"), 		_T("")			)
	, SAPLanguage(	0x041a, _T("hr-HR"),		_T("Croatian (Croatia)"),								_T("hr")		)
	, SAPLanguage(	0x0405, _T("cs-CZ"),		_T("Czech (Czech Republic)"),							_T("cs")		)
	, SAPLanguage(	0x0406, _T("da-DK"),		_T("Danish (Denmark)"),									_T("da")		)
	, SAPLanguage(	0x048c, _T("gbz-AF"),		_T("Dari (Afghanistan)"),								_T("")			)
	, SAPLanguage(	0x0465, _T("dv-MV"),		_T("Divehi (Maldives)"),								_T("")			)
	, SAPLanguage(	0x0813, _T("nl-BE"),		_T("Dutch (Belgium)"),									_T("nl")		)
	, SAPLanguage(	0x0413, _T("nl-NL"),		_T("Dutch (Netherlands)"),								_T("nl")		)
	, SAPLanguage(	0x0c09, _T("en-AU"),		_T("English (Australia)"),								_T("en")		)
	, SAPLanguage(	0x2809, _T("en-BZ"),		_T("English (Belize)"),									_T("en")		)
	, SAPLanguage(	0x1009, _T("en-CA"),		_T("English (Canada)"),									_T("en")		)
	, SAPLanguage(	0x2409, _T("en-029"),		_T("English (Caribbean)"),								_T("en")		)
	, SAPLanguage(	0x4009, _T("en-IN"),		_T("English (India)"),									_T("en")		)
	, SAPLanguage(	0x1809, _T("en-IE"),		_T("English (Ireland)"),								_T("en")		)
	, SAPLanguage(	0x2009, _T("en-JM"),		_T("English (Jamaica)"),								_T("en")		)
	, SAPLanguage(	0x4409, _T("en-MY"),		_T("English (Malaysia)"),								_T("en")		)
	, SAPLanguage(	0x1409, _T("en-NZ"),		_T("English (New Zealand)"),							_T("en")		)
	, SAPLanguage(	0x3409, _T("en-PH"),		_T("English (Philippines)"),							_T("en")		)
	, SAPLanguage(	0x4809, _T("en-SG"),		_T("English (Singapore)"),								_T("en")		)
	, SAPLanguage(	0x1c09, _T("en-ZA"),		_T("English (South Africa)"),							_T("en")		)
	, SAPLanguage(	0x2c09, _T("en-TT"),		_T("English (Trinidad and Tobago)"),					_T("en")		)
	, SAPLanguage(	0x0809, _T("en-GB"),		_T("English (United Kingdom)"),							_T("en")		)
	, SAPLanguage(	0x0409, _T("en-US"),		_T("English (United States)"),							_T("en")		)
	, SAPLanguage(	0x3009, _T("en-ZW"),		_T("English (Zimbabwe)"),								_T("en")		)
	, SAPLanguage(	0x0425, _T("et-EE"),		_T("Estonian (Estonia)"),								_T("et")		)
	, SAPLanguage(	0x0438, _T("fo-FO"),		_T("Faroese (Faroe Islands)"),							_T("")			)
	, SAPLanguage(	0x0464, _T("fil-PH"),		_T("Filipino (Philippines)"),							_T("")			)
	, SAPLanguage(	0x040b, _T("fi-FI"),		_T("Finnish (Finland)"),								_T("fi")		)
	, SAPLanguage(	0x080c, _T("fr-BE"),		_T("French (Belgium)"),									_T("fr")		)
	, SAPLanguage(	0x0c0c, _T("fr-CA"),		_T("French (Canada)"),									_T("fr")		)
	, SAPLanguage(	0x040c, _T("fr-FR"),		_T("French (France)"),									_T("fr")		)
	, SAPLanguage(	0x140c, _T("fr-LU"),		_T("French (Luxembourg)"),								_T("fr")		)
	, SAPLanguage(	0x180c, _T("fr-MC"),		_T("French (Monaco)"),									_T("fr")		)
	, SAPLanguage(	0x100c, _T("fr-CH"),		_T("French (Switzerland)"),								_T("fr")		)
	, SAPLanguage(	0x0462, _T("fy-NL"),		_T("Frisian (Netherlands)"),							_T("")			)
	, SAPLanguage(	0x0456, _T("gl-ES"),		_T("Galician (Spain)"),									_T("gl")		)
	, SAPLanguage(	0x0437, _T("ka-GE"),		_T("Georgian (Georgia)"),								_T("ka")		)
	, SAPLanguage(	0x0c07, _T("de-AT"),		_T("German (Austria)"),									_T("de")		)
	, SAPLanguage(	0x0407, _T("de-DE"),		_T("German (Germany)"),									_T("de")		)
	, SAPLanguage(	0x1407, _T("de-LI"),		_T("German (Liechtenstein)"),							_T("de")		)
	, SAPLanguage(	0x1007, _T("de-LU"),		_T("German (Luxembourg)"),								_T("de")		)
	, SAPLanguage(	0x0807, _T("de-CH"),		_T("German (Switzerland)"),								_T("de")		)
	, SAPLanguage(	0x0408, _T("el-GR"),		_T("Greek (Greece)"),									_T("el")		)
	, SAPLanguage(	0x046f, _T("kl-GL"),		_T("Greenlandic (Greenland)"),							_T("")			)
	, SAPLanguage(	0x0447, _T("gu-IN"),		_T("Gujarati (India)"),									_T("gu")		)
	, SAPLanguage(	0x0468, _T("ha-Latn-NG"),	_T("Hausa (Nigeria, Latin)"),							_T("")			)
	, SAPLanguage(	0x040d, _T("he-IL"),		_T("Hebrew (Israel)"),									_T("he")		)
	, SAPLanguage(	0x0439, _T("hi-IN"),		_T("Hindi (India)"),									_T("hi")		)
	, SAPLanguage(	0x040e, _T("hu-HU"),		_T("Hungarian (Hungary)"),								_T("hu")		)
	, SAPLanguage(	0x040f, _T("is-IS"),		_T("Icelandic (Iceland)"),								_T("is")		)
	, SAPLanguage(	0x0470, _T("ig-NG"),		_T("Igbo (Nigeria)"),									_T("")			)
	, SAPLanguage(	0x0421, _T("id-ID"),		_T("Indonesian (Indonesia)"),							_T("id")		)
	, SAPLanguage(	0x085d, _T("iu-Latn-CA"),	_T("Inuktitut (Canada, Latin)"),						_T("")			)
	, SAPLanguage(	0x045d, _T("iu-Cans-CA"),	_T("Inuktitut (Canada, Syllabics)"),					_T("")			)
	, SAPLanguage(	0x083c, _T("ga-IE"),		_T("Irish (Ireland)"),									_T("ga")		)
	, SAPLanguage(	0x0410, _T("it-IT"),		_T("Italian (Italy)"),									_T("it")		)
	, SAPLanguage(	0x0810, _T("it-CH"),		_T("Italian (Switzerland)"),							_T("it")		)
	, SAPLanguage(	0x0411, _T("ja-JP"),		_T("Japanese (Japan)"),									_T("ja")		)
	, SAPLanguage(	0x044b, _T("kn-IN"),		_T("Kannada (India)"),									_T("kn")		)
	, SAPLanguage(	0x043f, _T("kk-KZ"),		_T("Kazakh (Kazakhstan)"),								_T("kk")		)
	, SAPLanguage(	0x0453, _T("kh-KH"),		_T("Khmer (Cambodia)"),									_T("")			)
	, SAPLanguage(	0x0486, _T("qut-GT"),		_T("K'iche (Guatemala)"),								_T("")			)
	, SAPLanguage(	0x0487, _T("rw-RW"),		_T("Kinyarwanda (Rwanda)"),								_T("")			)
	, SAPLanguage(	0x0457, _T("kok-IN"),		_T("Konkani (India)"),									_T("")			)
	, SAPLanguage(	0x0812, _T(""),				_T("Korean (Johab)"),									_T("ko")		)
	, SAPLanguage(	0x0412, _T("ko-KR"),		_T("Korean (Korea)"),									_T("ko")		)
	, SAPLanguage(	0x0440, _T("ky-KG"),		_T("Kyrgyz (Kyrgyzstan)"),								_T("ky")		)
	, SAPLanguage(	0x0454, _T("lo-LA"),		_T("Lao (Lao PDR)"),									_T("lo")		)
	, SAPLanguage(	0x0426, _T("lv-LV"),		_T("Latvian (Latvia)"),									_T("lv")		)
	, SAPLanguage(	0x0427, _T("lt-LT"),		_T("Lithuanian (Lithuania)"),							_T("lt")		)
	, SAPLanguage(	0x082e, _T("dsb-DE"),		_T("Lower Sorbian (Germany)"),							_T("")			)
	, SAPLanguage(	0x046e, _T("lb-LU"),		_T("Luxembourgish (Luxembourg)"),						_T("lb")		)
	, SAPLanguage(	0x042f, _T("mk-MK"),		_T("Macedonian (Macedonia, FYROM)"),					_T("mk")		)
	, SAPLanguage(	0x083e, _T("ms-BN"),		_T("Malay (Brunei Darussalam)"),						_T("ms")		)
	, SAPLanguage(	0x043e, _T("ms-MY"),		_T("Malay (Malaysia)"),									_T("ms")		)
	, SAPLanguage(	0x044c, _T("ml-IN"),		_T("Malayalam (India)"),								_T("ml")		)
	, SAPLanguage(	0x043a, _T("mt-MT"),		_T("Maltese (Malta)"),									_T("mt")		)
	, SAPLanguage(	0x0481, _T("mi-NZ"),		_T("Maori (New Zealand)"),								_T("mi")		)
	, SAPLanguage(	0x047a, _T("arn-CL"),		_T("Mapudungun (Chile)"),								_T("")			)
	, SAPLanguage(	0x044e, _T("mr-IN"),		_T("Marathi (India)"),									_T("mr")		)
	, SAPLanguage(	0x047c, _T("moh-CA"),		_T("Mohawk (Canada)"),									_T("")			)
	, SAPLanguage(	0x0450, _T("mn-Cyrl-MN"),	_T("Mongolian (Mongolia)"),								_T("mn")		)
	, SAPLanguage(	0x0850, _T("mn-Mong-CN"),	_T("Mongolian (PRC)"),									_T("")			)
	, SAPLanguage(	0x0461, _T("ne-NP"),		_T("Nepali (Nepal)"),									_T("ne")		)
	, SAPLanguage(	0x0414, _T("nb-NO"),		_T("Norwegian (Bokm?l, Norway)"),						_T("no")		)
	, SAPLanguage(	0x0814, _T("nn-NO"),		_T("Norwegian (Nynorsk, Norway)"),						_T("no")		)
	, SAPLanguage(	0x0482, _T("oc-FR"),		_T("Occitan (France)"),									_T("")			)
	, SAPLanguage(	0x0448, _T("or-IN"),		_T("Oriya (India)"),									_T("")			)
	, SAPLanguage(	0x0463, _T("ps-AF"),		_T("Pashto (Afghanistan)"),								_T("")			)
	, SAPLanguage(	0x0429, _T("fa-IR"),		_T("Persian (Iran)"),									_T("fa")		)
	, SAPLanguage(	0x0415, _T("pl-PL"),		_T("Polish (Poland)"),									_T("pl")		)
	, SAPLanguage(	0x0416, _T("pt-BR"),		_T("Portuguese (Brazil)"),								_T("pt")		)
	, SAPLanguage(	0x0816, _T("pt-PT"),		_T("Portuguese (Portugal)"),							_T("pt")		)
	, SAPLanguage(	0x0446, _T("pa-IN"),		_T("Punjabi (India)"),									_T("pa")		)
	, SAPLanguage(	0x046b, _T("quz-BO"),		_T("Quechua (Bolivia)"),								_T("")			)
	, SAPLanguage(	0x086b, _T("quz-EC"),		_T("Quechua (Ecuador)"),								_T("")			)
	, SAPLanguage(	0x0c6b, _T("quz-PE"),		_T("Quechua (Peru)"),									_T("")			)
	, SAPLanguage(	0x0418, _T("ro-RO"),		_T("Romanian (Romania)"),								_T("ro")		)
	, SAPLanguage(	0x0417, _T("rm-CH"),		_T("Romansh (Switzerland)"),							_T("")			)
	, SAPLanguage(	0x0419, _T("ru-RU"),		_T("Russian (Russia)"),									_T("ru")		)
	, SAPLanguage(	0x243b, _T("smn-FI"),		_T("Sami (Inari, Finland)"),							_T("")			)
	, SAPLanguage(	0x103b, _T("smj-NO"),		_T("Sami (Lule, Norway)"),								_T("")			)
	, SAPLanguage(	0x143b, _T("smj-SE"),		_T("Sami (Lule, Sweden)"),								_T("")			)
	, SAPLanguage(	0x0c3b, _T("se-FI"),		_T("Sami (Northern, Finland)"),							_T("")			)
	, SAPLanguage(	0x043b, _T("se-NO"),		_T("Sami (Northern, Norway)"),							_T("")			)
	, SAPLanguage(	0x083b, _T("se-SE"),		_T("Sami (Northern, Sweden)"),							_T("")			)
	, SAPLanguage(	0x203b, _T("sms-FI"),		_T("Sami (Skolt, Finland)"),							_T("")			)
	, SAPLanguage(	0x183b, _T("sma-NO"),		_T("Sami (Southern, Norway)"),							_T("")			)
	, SAPLanguage(	0x1c3b, _T("sma-SE"),		_T("Sami (Southern, Sweden)"),							_T("")			)
	, SAPLanguage(	0x044f, _T("sa-IN"),		_T("Sanskrit (India)"),									_T("")			)
	, SAPLanguage(	0x1c1a, _T("sr-Cyrl-BA"),	_T("Serbian (Bosnia and Herzegovina, Cyrillic)"),		_T("sr-Cyrl")	)
	, SAPLanguage(	0x181a, _T("sr-Latn-BA"),	_T("Serbian (Bosnia and Herzegovina, Latin)"),			_T("sr-Latn")	)
	, SAPLanguage(	0x0c1a, _T("sr-Cyrl-CS"),	_T("Serbian (Serbia, Cyrillic)"),						_T("sr-Cyrl")	)
	, SAPLanguage(	0x081a, _T("sr-Latn-CS"),	_T("Serbian (Serbia, Latin)"),							_T("sr-Latn")	)
	, SAPLanguage(	0x046c, _T("ns-ZA"),		_T("Sesotho sa Leboa/Northern Sotho (South Africa)"),	_T("")			)
	, SAPLanguage(	0x0432, _T("tn-ZA"),		_T("Setswana/Tswana (South Africa)"),					_T("")			)
	, SAPLanguage(	0x045b, _T("si-LK"),		_T("Sinhala (Sri Lanka)"),								_T("si")		)
	, SAPLanguage(	0x041b, _T("sk-SK"),		_T("Slovak (Slovakia)"),								_T("sk")		)
	, SAPLanguage(	0x0424, _T("sl-SI"),		_T("Slovenian (Slovenia)"),								_T("sl")		)
	, SAPLanguage(	0x2c0a, _T("es-AR"),		_T("Spanish (Argentina)"),								_T("es")		)
	, SAPLanguage(	0x400a, _T("es-BO"),		_T("Spanish (Bolivia)"),								_T("es")		)
	, SAPLanguage(	0x340a, _T("es-CL"),		_T("Spanish (Chile)"),									_T("es")		)
	, SAPLanguage(	0x240a, _T("es-CO"),		_T("Spanish (Colombia)"),								_T("es")		)
	, SAPLanguage(	0x140a, _T("es-CR"),		_T("Spanish (Costa Rica)"),								_T("es")		)
	, SAPLanguage(	0x1c0a, _T("es-DO"),		_T("Spanish (Dominican Republic)"),						_T("es")		)
	, SAPLanguage(	0x300a, _T("es-EC"),		_T("Spanish (Ecuador)"),								_T("es")		)
	, SAPLanguage(	0x440a, _T("es-SV"),		_T("Spanish (El Salvador)"),							_T("es")		)
	, SAPLanguage(	0x100a, _T("es-GT"),		_T("Spanish (Guatemala)"),								_T("es")		)
	, SAPLanguage(	0x480a, _T("es-HN"),		_T("Spanish (Honduras)"),								_T("es")		)
	, SAPLanguage(	0x080a, _T("es-MX"),		_T("Spanish (Mexico)"),									_T("es")		)
	, SAPLanguage(	0x4c0a, _T("es-NI"),		_T("Spanish (Nicaragua)"),								_T("es")		)
	, SAPLanguage(	0x180a, _T("es-PA"),		_T("Spanish (Panama)"),									_T("es")		)
	, SAPLanguage(	0x3c0a, _T("es-PY"),		_T("Spanish (Paraguay)"),								_T("es")		)
	, SAPLanguage(	0x280a, _T("es-PE"),		_T("Spanish (Peru)"),									_T("es")		)
	, SAPLanguage(	0x500a, _T("es-PR"),		_T("Spanish (Puerto Rico)"),							_T("es")		)
	, SAPLanguage(	0x0c0a, _T("es-ES"),		_T("Spanish (Spain)"),									_T("es")		)
	, SAPLanguage(	0x040a, _T("es-ES_tradnl"), _T("Spanish (Spain, Traditional Sort)"),				_T("es")		)
	, SAPLanguage(	0x540a, _T("es-US"),		_T("Spanish (United States)"),							_T("es")		)
	, SAPLanguage(	0x380a, _T("es-UY"),		_T("Spanish (Uruguay)"),								_T("es")		)
	, SAPLanguage(	0x200a, _T("es-VE"),		_T("Spanish (Venezuela)"),								_T("es")		)
	, SAPLanguage(	0x0441, _T("sw-KE"),		_T("Swahili (Kenya)"),									_T("sw")		)
	, SAPLanguage(	0x081d, _T("sv-FI"),		_T("Swedish (Finland)"),								_T("sv")		)
	, SAPLanguage(	0x041d, _T("sv-SE"),		_T("Swedish (Sweden)"),									_T("sv")		)
	, SAPLanguage(	0x045a, _T("syr-SY"),		_T("Syriac (Syria)"),									_T("")			)
	, SAPLanguage(	0x0428, _T("tg-Cyrl-TJ"),	_T("Tajik (Tajikistan)"),								_T("tg")		)
	, SAPLanguage(	0x085f, _T("tmz-Latn-DZ"),	_T("Tamazight (Algeria, Latin)"),						_T("")			)
	, SAPLanguage(	0x0449, _T("ta-IN"),		_T("Tamil (India)"),									_T("ta")		)
	, SAPLanguage(	0x0444, _T("tt-RU"),		_T("Tatar (Russia)"),									_T("tt")		)
	, SAPLanguage(	0x044a, _T("te-IN"),		_T("Telugu (India)"),									_T("te")		)
	, SAPLanguage(	0x041e, _T("th-TH"),		_T("Thai (Thailand)"),									_T("th")		)
	, SAPLanguage(	0x0851, _T("bo-BT"),		_T("Tibetan (Bhutan)"),									_T("")			)
	, SAPLanguage(	0x0451, _T("bo-CN"),		_T("Tibetan (PRC)"),									_T("")			)
	, SAPLanguage(	0x041f, _T("tr-TR"),		_T("Turkish (Turkey)"),									_T("tr")		)
	, SAPLanguage(	0x0442, _T("tk-TM"),		_T("Turkmen (Turkmenistan)"),							_T("")			)
	, SAPLanguage(	0x0480, _T("ug-CN"),		_T("Uighur (PRC)"),										_T("")			)
	, SAPLanguage(	0x0422, _T("uk-UA"),		_T("Ukrainian (Ukraine)"),								_T("uk")		)
	, SAPLanguage(	0x042e, _T("wen-DE"),		_T("Upper Sorbian (Germany)"),							_T("")			)
	, SAPLanguage(	0x0820, _T("tr-IN"),		_T("Urdu (India)"),										_T("ur")		)
	, SAPLanguage(	0x0420, _T("ur-PK"),		_T("Urdu (Pakistan)"),									_T("ur")		)
	, SAPLanguage(	0x0843, _T("uz-Cyrl-UZ"),	_T("Uzbek (Uzbekistan, Cyrillic)"),						_T("")			)
	, SAPLanguage(	0x0443, _T("uz-Latn-UZ"),	_T("Uzbek (Uzbekistan, Latin)"),						_T("uz")		)
	, SAPLanguage(	0x042a, _T("vi-VN"),		_T("Vietnamese (Vietnam)"),								_T("vi")		)
	, SAPLanguage(	0x0452, _T("cy-GB"),		_T("Welsh (United Kingdom)"),							_T("cy")		)
	, SAPLanguage(	0x0488, _T("wo-SN"),		_T("Wolof (Senegal)"),									_T("")			)
	, SAPLanguage(	0x0434, _T("xh-ZA"),		_T("Xhosa/isiXhosa (South Africa)"),					_T("xh")		)
	, SAPLanguage(	0x0485, _T("sah-RU"),		_T("Yakut (Russia)"),									_T("sah")		)
	, SAPLanguage(	0x0478, _T("ii-CN"),		_T("Yi (PRC)"),											_T("")			)
	, SAPLanguage(	0x046a, _T("yo-NG"),		_T("Yoruba (Nigeria)"),									_T("")			)
	, SAPLanguage(	0x0435, _T("zu-ZA"),		_T("Zulu/isiZulu (South Africa)"),						_T("zu")		)
};

#ifdef _MFC_VER
/*
bool LoadXmlToMap(LPCTSTR filename, TMapLongToStr &mapStr)
{
	mapStr.clear();

	if (!filename)
		return false;

	CString sPath = filename;

	CaplXMLFile file;
	file.m_bIgnoreQuotesInContent = true;
	if (!file.LoadFromFile(sPath, true, false))
		return false;

	if(file.root.subnodes.GetSize() != 1)
	{
		return false;
	}

	CaplXMLNode *pRootNode = file.root.subnodes[0];
	if (pRootNode==NULL)
		return false;

	if(pRootNode->name != "strings")
	{
		return false;
	}

	// читаем строки
	long nCurNum(1), nMaxNum(1);
	for(int i=0; i<pRootNode->subnodes.GetSize(); ++i)
	{
		CaplXMLNode *pNode = pRootNode->subnodes[i];
		if (pNode && !pNode->name.IsEmpty() && pNode->name.CompareNoCase(_T("s"))==0)
		{
			nCurNum = pNode->GetLongParam(_T("id"));
			if (nCurNum==0)
				nCurNum = nMaxNum++;
			while(mapStr.find(nCurNum)!=mapStr.end())
				nCurNum = nMaxNum++;

			mapStr[nCurNum] = pNode->text;
		}
	}

	return true;
}
*/

unsigned long CaplTranslate::GetSystemLocale()
{
	CWinApp *app = AfxGetApp();
	if (0 == app) return -1; // вызвали слишком рано, еще ничего не проинициализировано.

	return GetThreadLocale();
}
#else


LPCTSTR CaplTranslate::GetSystemLocale()
{
	CaplTranslate_m_sys_lang = QS2CS(QLocale::system().name());
	return CaplTranslate_m_sys_lang;
}

#endif

CaplTranslate::CaplTranslate()
{
	// ЯАИ: не нужно сбрасывать, если кто-то создаст CaplTranslate CaplTranslate::m_bTranslate = false;
}

CaplTranslate::~CaplTranslate()
{
#ifndef _MFC_VER
//TODO: DIV: Раскомментарить удаление, если будут проблемы с освобождением памяти при завершении процессов
//	if(gl_pTranslateMap != 0){delete gl_pTranslateMap; gl_pTranslateMap=0;}
#endif

}

#ifdef _MFC_VER

unsigned long CaplTranslate::GetGurLocale(){return CaplTranslate_m_cur_lang;}

#else

LPCTSTR CaplTranslate::GetGurLocale()
{
	if(CaplTranslate_m_cur_lang.IsEmpty()) return 0;
	return CaplTranslate_m_cur_lang;
}
bool CaplTranslate::SetIniPath(LPCTSTR iniPath)
{
	CaplTranslate_m_ini_path = iniPath;
	return true;
}
LPCWSTR CaplTranslate::GetLangTitul(LPCWSTR name)
{
	if(!global_TranslateInited) return _T("");
	CString sname(name); sname.Replace(_T('_'), _T('-'));
	auto it = global_Langs.find(CS2QS(sname));
	if(it==global_Langs.end()) return name;
	return it.value()->description;
}
LPCWSTR CaplTranslate::GetLangShort(LPCWSTR name)
{
	if(!global_TranslateInited) return _T("");
	CString sname(name); sname.Replace(_T('_'), _T('-'));
	auto it = global_Langs.find(CS2QS(sname));
	if(it==global_Langs.end()) return name;
	return it.value()->trans;
}

#endif

bool CaplTranslate::Init(bool hide_mode, CString *errMess)
{
	//CString bbb="z\\o1\\o77\\o376x";
	//CString bbb="zrrr\nddd\\x1\\r\\x77\\xfeqqq\a";
	//char *ccc=aplConvertSpecSymbols((char*)LPCSTR(bbb));

	//CaplTranslate_m_map.Add("Трам-пам-пам!","Turum-purum!");
	if(m_Suppress) return false;

#ifdef _MFC_VER
	unsigned long cur_locale = GetSystemLocale();
	if (-1==(int)cur_locale)
		return false;

	//cur_locale=0x409;
	if(cur_locale==0x0419)// Текущий язык - русский
	{
		CString s1;
		s1.LoadString(module_inst,IDS_APL_CUR_LANG);
		s1.MakeLower();
		if(s1==_T("english"))
		{
			cur_locale=0x409; // перевод был заменой ресурсов.
		}
		else
		{
			CaplTranslate_m_cur_lang=0;
			CaplTranslate::m_bTranslate = false;
			return true;  // Текущий язык русский - перевод не требуется.
		}
	}
#else
	if(!global_TranslateInited) return false;

	if(errMess!=0) hide_mode = false; // для Qt этот флаг только мешает выводить сообщение в строчку.
	if(global_Langs.size()==0)
	{
		for(int i=0; i<APL_LANG_COUNT; ++i)
		{
			global_Langs.insert(CS2QS(apl_langs[i].name), &(apl_langs[i]));
		}
	}

	if(gl_pTranslateMap == 0)
		gl_pTranslateMap = new CaplStrStrMap();

	GetSystemLocale();

	if (CaplTranslate_m_new_lang.IsEmpty() && (CaplTranslate_m_sys_lang.IsEmpty() || CaplTranslate_m_sys_lang=="C")) // непонятно, что куда переводить
		return false;

	if (CaplTranslate_m_new_lang.IsEmpty() && !CaplTranslate_m_sys_lang.IsEmpty())
		CaplTranslate_m_new_lang = CaplTranslate_m_sys_lang; // тепкущий язык не задан, используем системный

	//cur_locale=0x409;
	if(CaplTranslate_m_new_lang==_T("ru_RU"))
	{
		if(CaplTranslate_m_cur_lang != CaplTranslate_m_new_lang) // раньше был загружен переод для другого языка
		{
			gl_pTranslateMap->Clear();
			CaplTranslate_m_cur_lang = CaplTranslate_m_new_lang;
		}
		CaplTranslate::m_bTranslate = false;
		return true;  // Текущий язык русский - перевод не требуется.
	}
#endif

	CaplTranslate::m_bTranslate = true;

#ifdef _MFC_VER
	if(CaplTranslate_m_cur_lang==cur_locale) return true; //язык не изменился

	CaplTranslate_m_cur_lang=cur_locale;
	CaplTranslate_m_map.Clear();
#else
	if(gl_pTranslateMap==0) return false;
	gl_pTranslateMap->Clear();
#endif

	//текущий язык не русский - надо читать словарь,
	// определяем добавку к файлу
	CString sFileNameLangAdd;
#ifdef _MFC_VER
   if( cur_locale== 0x009) sFileNameLangAdd+=_T("#en.xml");
   else if( cur_locale== 0x409) sFileNameLangAdd+=_T("#en-US.xml");
   //else if( cur_locale== 0x409) sFileNameLangAdd+="#en.xml";
/*
	   else 
	   {
#ifdef _MFC_VER
		   if(!hide_mode)AfxMessageBox(_T("Unknown language! Could not form translation filename!\n see CaplTranslate::Init()"),
			   MB_OK|MB_ICONSTOP);
#else
           if(!hide_mode) TRACE("Unknown language! Could not form translation filename!\n see CaplTranslate::Init()");
#endif
		   return false;
	   }
*/
#else
	CString new_lang_mod = CaplTranslate_m_new_lang;
	new_lang_mod.Replace(_T("_"), _T("-"));
	sFileNameLangAdd.Format(_T("#%s.xml"), (LPCTSTR)new_lang_mod);
#endif

	//пробуем зачитать словарь.
	
   TMapLongToStr mapStr1, mapStr2;

    CString fname,path,buf;
#ifdef _MFC_VER
	CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
    if(0!=app) buf=app->m_pszHelpFilePath;
	int i=buf.ReverseFind(aplDirRazd);
	if(i>0) path=buf.Left(i+1);
#else
	aplGetModuleFilePath(path);
	if(path.Right(1) != aplDirRazd) path += aplDirRazd;
#endif

	CString fmask=path+_T("translate#*.xml");

	// тут, похоже, перебираются все xml с переводами
	// Если находится русский, то зачитывается он и по его шаблону читается файл с переводами
    CFileFind finder;
	CString sError;
	BOOL bWorking = finder.FindFile(fmask);
	while (bWorking)
	{
	   bWorking = finder.FindNextFile();
	   fname=finder.GetFilePath();
	   int iRu = fname.Find(_T("#ru-RU"));
	   if(iRu<0 && fname.Find(_T('#'))>=0) continue;
		// Возможно это xml c русским языком
	   //if(!CaplTranslate::LoadXml(fname,sa1,hide_mode))
	   if(!LoadXmlToMap(fname,mapStr1))
	   {
		   continue; // Это неправильный xml
	   }

	   // Русский нашли, ищем для него файл с переводом.
	   buf=fname.Left((fname.GetLength()-iRu)<0?4:iRu); // - '.xml' или '#ru-RU.xml'
	   fname=buf+sFileNameLangAdd;

	   // старый код
	   //if(!CaplTranslate::LoadXml(fname,sa2,hide_mode))
	   if(sFileNameLangAdd.IsEmpty() || !LoadXmlToMap(fname,mapStr2))
	   {
			// новый код - получаем имя файла по таблице
		   bool bLoad = false;
		   CString sAdd;
#ifdef _MFC_VER
		   for(int i=0; i<APL_LANG_COUNT; ++i)
		   {
				if ((int)cur_locale==apl_langs[i].id)
				{
					sAdd = apl_langs[i].name;
					break;
				}
		   }
#else
		   sAdd = new_lang_mod;
#endif
		   if (!sAdd.IsEmpty())
		   {
			   fname.Format(_T("%s#%s.xml"), LPCTSTR(buf), LPCTSTR(sAdd));
			   bLoad = LoadXmlToMap(fname,mapStr2);
		   }

		   if (!bLoad)
		   {
			   // Это неправильный xml
			   if(!hide_mode)
			   {
				   buf=_T("Could not find translation data file!\n\n");
				   buf+=fname;
#ifdef _MFC_VER
				   AfxMessageBox(buf,MB_OK|MB_ICONWARNING);
#else
				   if(errMess!=0) *errMess+=buf;
				   else aplMessagePrint(buf, MB_ICONWARNING);
#endif
			   }
			   continue; 
		   }
	   }
	   //if(sa1.GetSize()!=sa2.GetSize())
/*
		if(mapStr1.size()!=mapStr2.size())
		{
            if(!hide_mode)
            {
#ifdef _MFC_VER
                AfxMessageBox(_T("Dictionary damaged! (Files are not corresponding each other)\nLocalization impossible!\nRussian interface will be used!"),MB_ICONSTOP|MB_OK);
#else
                TRACE("Dictionary damaged! (Files are not corresponding each other)\nLocalization impossible!\nRussian interface will be used!");
#endif
            }
            CaplTranslate_m_cur_lang=0;
			return false;
		}
*/
		int count_not_found = 0;
		int count_dubles = 0;
		CString sMsg1 = _T("Could not find translation for strings:\r\n");
		CString sMsg2 = _T("Found different translation variants in different files for strings:\r\n");
		//for(i=0;i<sa1.GetSize();i++)
		for(TMapLongToStr_it it=mapStr1.begin(); it!=mapStr1.end(); ++it)
		{
			TMapLongToStr_it itf = mapStr2.find(it->first);
			if (itf==mapStr2.end())
			{
				if (!hide_mode)
				{
					count_not_found++;
					if(count_not_found <=5)
					{
						buf.Format(_T("[#%d] %s\r\n"), it->first, (LPCTSTR)it->second);
						sMsg1 += buf;
					}
				}
			}
			else
			{
#ifdef _MFC_VER
				int j= CaplTranslate_m_map.FindByIn(it->second);
#else
				int j= gl_pTranslateMap->FindByIn(it->second);
#endif
				if(j>=0)
				{
#ifdef _MFC_VER
					if (itf->second != CaplTranslate_m_map.GetAt(j)->val && !hide_mode && sError.IsEmpty())
#else
					if (itf->second != gl_pTranslateMap->GetAt(j)->val && !hide_mode && sError.IsEmpty())
#endif
					{
						if (!hide_mode)
						{
							count_dubles++;
							if(count_dubles <= 5)
							{
								sMsg2+=_T("\"");
								sMsg2+= it->second;
								sMsg2+=_T("\"\n");
							}
						}
					}
				}
				else 
				{
#ifdef _MFC_VER
					if(!m_bShowStringId) CaplTranslate_m_map.Add(it->second,itf->second);
#else
					if(!m_bShowStringId) gl_pTranslateMap->Add(it->second,itf->second);
#endif
					else
					{
						CString sOut;
						sOut.Format(_T("[%i] "),it->first);
						sOut+=itf->second;
#ifdef _MFC_VER
						CaplTranslate_m_map.Add(it->second,sOut);
#else
						gl_pTranslateMap->Add(it->second,sOut);
#endif
					}
				}
			}

/*
			int j= CaplTranslate_m_map.FindByIn(sa1[i]);
			if(j>=0)
			{
				if (sa2[i]!= CaplTranslate_m_map.GetAt(j)->val && !hide_mode)
				{
					buf=_T("For string \"");
					buf+=sa1[i];
					buf+=_T("\"\n\nfound different translation variants in different files!");
#ifdef _MFC_VER
					AfxMessageBox(buf);
#else
                    TRACE(buf);
#endif
				}
			}
			else 
			{
				CaplTranslate_m_map.Add(sa1[i],sa2[i]);
			}
*/
		}
		if(count_not_found > 5)
		{
			sMsg1 += _T("and other");
		}
		if(count_dubles > 5)
		{
			sMsg2 += _T("and other");
		}
		buf = _T("");
		if(count_not_found > 0) buf += sMsg1;
		if(count_dubles > 0) buf += sMsg2;

		if(count_not_found > 0 || count_dubles > 0)
		{
#ifdef _MFC_VER
			if(!hide_mode) AfxMessageBox(buf, MB_ICONERROR);
#else
			if(errMess!=0)*errMess+=buf;
			else
			{
				TRACE(buf);
				APL_STOP_IF_DEBUG
			}
#endif
		}
	}

#ifdef _MFC_VER
	if(CaplTranslate_m_map.GetSize()<1)
#else
	if(gl_pTranslateMap->GetSize()<1)
#endif
	{
        if(!hide_mode)
        {
			CString mess = _T("Dictionary not found!\nLocalization impossible!\nRussian interface will be used!");
#ifdef _MFC_VER
			AfxMessageBox(mess, MB_ICONSTOP|MB_OK);
#else
			if(errMess!=0)*errMess = mess;
			else aplMessagePrint(mess, MB_ICONWARNING);
#endif
        }
#ifdef _MFC_VER
        CaplTranslate_m_cur_lang=0;
#else
		CaplTranslate_m_cur_lang.Empty();
#endif
		m_bTranslate=false;
		return false;
	}
#ifndef _MFC_VER
	CaplTranslate_m_cur_lang = CaplTranslate_m_new_lang;
#endif

	return true;
}

// Используется в ILS
void CaplTranslate::AddStringTranslationPair(const CString& sStr, const CString& sTtranslation)
{
#ifdef _MFC_VER
	int j = CaplTranslate_m_map.FindByIn(sStr);
	if (j >= 0)
		CaplTranslate_m_map.SetAt(j, sTtranslation);
	else
		CaplTranslate_m_map.Add(sStr, sTtranslation);
#else
	if(gl_pTranslateMap==0) return;
	int i= gl_pTranslateMap->FindByIn(sStr);
	if(i>=0) gl_pTranslateMap->SetAt(i, sStr);
	else gl_pTranslateMap->Add(sStr, sTtranslation);
#endif
}

 

LPCTSTR CaplTranslate::Translate(LPCTSTR str)
{
	if(!IsNeedTranslate()) return str;

	if(0==str) return str;
	if(_T('\0')==str[0]) return str;

#ifdef _MFC_VER
	int i= CaplTranslate_m_map.FindByIn(str);
	if(i>=0) return CaplTranslate_m_map.GetAt(i)->val;
#else
	if(gl_pTranslateMap==0) return str;
	int i= gl_pTranslateMap->FindByIn(str);
	if(i>=0) return gl_pTranslateMap->GetAt(i)->val;
#endif
	return str;
}

bool LoadXmlToMap(LPCTSTR filename, TMapLongToStr &mapStr, bool hide_mode /*= true*/)
{
	CString buf,buf1;
#ifdef _UNICODE
	CaplStringFile file;
	file.SetEncodingIfNotBOM(aplUTF8);
	if (!file.Open(filename, CaplFile::modeRead | CaplFile::shareDenyWrite | CaplFile::typeUnicode))
#else
	CaplFile file;
	if(!file.Open(filename,CaplFile::modeRead|CaplFile::shareDenyWrite))
#endif
	{
		if(!hide_mode)
		{
			buf=_T("Error open file \"");
			buf+=filename;
			buf+=_T("\"\n\n Localization impossible! Using Russian interface!");
#ifdef _MFC_VER
			AfxMessageBox(buf,MB_ICONSTOP|MB_OK);
#else
			APL_STOP_IF_DEBUG
			TRACE(buf);
#endif
		}
		return false;
	}

	int i,j;
	bool bConvertFrom_utf8=false;
	if(file.ReadString(buf))
	{
		i=buf.Find(_T("encoding=\""));
		if(i>0)
		{
			j=buf.Find(_T("\""),i+10);
			if(j>0)
			{
				buf1=buf.Mid(i+10,j-i-10);
				buf1.MakeLower();

				if(buf1==_T("utf-8")) bConvertFrom_utf8=true;
			}
		}
	}

	if(!file.ReadString(buf))
	{
		file.Close();
		return false;
	}
	i=buf.Find(_T("<strings>"));
	if(i<0)
	{
		file.Close();
		return false;
	}

#ifdef _MFC_VER
#ifndef _UNICODE
	int m_stmp_len=0;
#endif
#else
	if(!bConvertFrom_utf8) {ASSERT(FALSE);} // по сути, чтобы gcc не ругался  на неиспользуемую переменную
#endif

	LPWSTR m_stmp=0; 
	CString tmpStr;

	int iStart, iEnd;
	long nCurNum(0), nMaxNum(1);
	std::map<CString, CString> attrs;	// атрибуты тэга
	CString sId = _T("id");	// идентификатор строки
	while (file.ReadString(buf))
	{
		attrs.clear();

		iStart=buf.Find(_T("<s"));
		if(iStart<0) continue;
		iEnd = buf.Find(_T("/>"), iStart);//проверяем, может нет тела и есть завершающий символ
		if (iEnd > -1)
		{
			continue;
		}
		iEnd=buf.Find(_T(">"), iStart);
		if(iEnd<0) continue;
		j=buf.Find(_T("</s>"),iEnd+1);

		// заполняем карту атрибутов
		if ((iEnd-iStart)>2)
		{
			// какие-то атрибуты скорее всего есть
			CString sAttrs = buf.Mid(iStart+2, iEnd-iStart-2);
			int i=0, iCur(0);
			CString sParam, sRightPart;
			sParam = sAttrs.Tokenize(_T("="), i);
			while(!sParam.IsEmpty())
			{
				iCur = i;

				sParam.Trim();
				if (sParam.IsEmpty())
					break;

				sRightPart = sAttrs.Tokenize(_T("="), i);
				if (sRightPart.IsEmpty())
				{
					// больше нет параметров
					sRightPart = sAttrs.Right(sAttrs.GetLength()-iCur);
					sRightPart.Trim(_T(" \""));
					attrs.insert(std::make_pair(sParam, CaplTranslate::ConvertSpecSymbols(LPTSTR((LPCTSTR)sRightPart))));
					sParam.Empty();
				}
				else
				{
					// делим текущий токен на значение текущего параметра и имя следующего
					sRightPart.TrimRight(_T(" \t\r\n"));
					int iF(-1);
					for(iF=sRightPart.GetLength()-1; iF>0; iF--)
					{
						if (!_isalnum(sRightPart[iF]))
							break;
					}

					if (iF<0)
					{
						// чо-то не так, считаем все это значением текущего параметра и останавливаем перебор
						sRightPart = sAttrs.Right(sAttrs.GetLength()-iCur);
						sRightPart.Trim(_T(" \""));
						attrs.insert(std::make_pair(sParam, CaplTranslate::ConvertSpecSymbols(LPTSTR((LPCTSTR)sRightPart))));
						sParam.Empty();
					}
					else
					{
						CString sValue = sRightPart.Left(iF);
						sValue.Trim(_T(" \""));
						attrs.insert(std::make_pair(sParam, CaplTranslate::ConvertSpecSymbols(LPTSTR((LPCTSTR)sValue))));
						sParam = sRightPart.Right(sRightPart.GetLength()-iF-1);
					}
				}
			}
		}

		// если завершающего тега нет, то берем строки дальше, пока не найдем его
		// проверять на новый тег <s> не будем
		if(j<0)
		{			
			while(file.ReadString(tmpStr))
			{
				buf += tmpStr;

				// ищем тег в подстроке
				j = tmpStr.Find(_T("</s>"));
				if(j >= 0)
				{
					// теперь рассчитаем индекс в итоговой строке
					j = buf.GetLength() - tmpStr.GetLength() + j;
					break;
				}
			}			
		}

		if(j<iEnd) continue;
		buf1=buf.Mid(iEnd+1,j-iEnd-1);
#ifdef _MFC_VER
#ifndef _UNICODE
		if(bConvertFrom_utf8)
		{
			int len= MultiByteToWideChar(CP_UTF8, 0, buf1, -1, NULL, 0);

			if(m_stmp_len<(len + 1))
			{
				if(m_stmp!=0) delete m_stmp;
				m_stmp=new wchar_t[len*2 + 1];
				m_stmp_len=len + 1;
			}

			MultiByteToWideChar(CP_UTF8, 0, buf1, -1, m_stmp, len);
			m_stmp[len]= _T('\0');
			buf1 = (LPCSTR)CaplStringAdapter(m_stmp);
		}
#endif
#endif
		buf1.Replace(_T("&apos;"),_T("'"));
		buf1.Replace(_T("&amp;"),_T("&"));
		buf1.Replace(_T("&lt;"),_T("<"));
		buf1.Replace(_T("&gt;"),_T(">"));
		buf1.Replace(_T("&quot;"),_T("\""));

		// ищем значение атрибута "id"
		std::map<CString, CString>::iterator it_attr = attrs.find(sId);
		if (it_attr!=attrs.end())
#ifndef __linux__
			nCurNum = __atol(it_attr->second);
#else
			nCurNum = atol(CaplStringAdapter(it_attr->second));
#endif

		if (nCurNum==0)
			nCurNum = nMaxNum++;
		while(mapStr.find(nCurNum)!=mapStr.end())
			nCurNum = nMaxNum++;

		mapStr[nCurNum] = CaplTranslate::ConvertSpecSymbols(buf1.GetBuffer());
		buf1.ReleaseBuffer();

		//strarray.Add(ConvertSpecSymbols(buf1.GetBuffer()));
	}
	if(m_stmp!=0) delete m_stmp;

	file.Close();

	return true;
}

bool CaplTranslate::LoadXml(LPCTSTR filename,CStringArray &strarray,bool hide_mode)
{
	CString buf,buf1;
#if defined(_MFC_VER) && defined(_UNICODE)
	CaplStringFile file;
	if (!file.Open(filename, CaplFile::modeRead | CaplFile::shareDenyWrite | CaplFile::typeUnicode))
#else
	CaplFile file;
    if(!file.Open(filename,CaplFile::modeRead|CaplFile::shareDenyWrite))
#endif
	{
		if(!hide_mode)
		{
			buf=_T("Error open file \"");
			buf+=filename;
			buf+=_T("\"\n\n Localization impossible! Using Russian interface!");
#ifdef _MFC_VER
			AfxMessageBox(buf,MB_ICONSTOP|MB_OK);
#else
            APL_STOP_IF_DEBUG
			TRACE(buf);
#endif
		}
		return false;
	}

	int i,j;
	bool bConvertFrom_utf8=false;
	if(file.ReadString(buf))
	{
		i=buf.Find(_T("encoding=\""));
		if(i>0)
		{
			j=buf.Find(_T("\""),i+10);
			if(j>0)
			{
				buf1=buf.Mid(i+10,j-i-10);
				buf1.MakeLower();

				if(buf1==_T("utf-8")) bConvertFrom_utf8=true;
			}
		}
	}

	if(!file.ReadString(buf))
	{
		file.Close();
		return false;
	}
	i=buf.Find(_T("<strings>"));
	if(i<0)
	{
		file.Close();
		return false;
	}
	
#ifdef _MFC_VER
#ifndef _UNICODE
	int m_stmp_len=0;
#endif
#else
	if(!bConvertFrom_utf8) {ASSERT(FALSE);} // по сути, чтобы gcc не ругался  на неиспользуемую переменную
#endif

	LPWSTR m_stmp=0; 
	CString tmpStr;

#ifdef USE_APL_STRING_AS_CSTRING
	CString tmpStr1;
#endif

	int iStart, iEnd;
	while (file.ReadString(buf))
	{
		iStart=buf.Find(_T("<s"));
		if(iStart<0) continue;
		iEnd = buf.Find(_T("/>"), iStart);//проверяем, может нет тела и есть завершающий символ
		if (iEnd > -1)
		{
			continue;
		}
		iEnd=buf.Find(_T(">"), iStart);
		if(iEnd<0) continue;
		j = buf.Find(_T("</s>"), i + 3);

		// если завершающего тега нет, то берем строки дальше, пока не найдем его
		// проверять на новый тег <s> не будем
		if(j<0)
		{			
			while(file.ReadString(tmpStr))
			{
				buf += tmpStr;

				// ищем тег в подстроке
				j = tmpStr.Find(_T("</s>"));
				if(j >= 0)
				{
					// теперь рассчитаем индекс в итоговой строке
					j = buf.GetLength() - tmpStr.GetLength() + j;
					break;
				}
			}			
		}

		if(j<iEnd) continue;
		buf1=buf.Mid(iEnd+1,j-iEnd-1);
#ifdef _MFC_VER
		if(bConvertFrom_utf8)
		{
#ifdef _UNICODE
			int len = buf1.GetLength();
#else
			int len= MultiByteToWideChar(CP_UTF8, 0, buf1, -1, NULL, 0);
			
			if(m_stmp_len<(len + 1))
			{
				if(m_stmp!=0) delete m_stmp;
				m_stmp=new wchar_t[len*2 + 1];
				m_stmp_len=len + 1;
			}

			MultiByteToWideChar(CP_UTF8, 0, buf1, -1, m_stmp, len);
			m_stmp[len]= _T('\0');
			buf1=m_stmp;
#endif
		}
#endif
		buf1.Replace(_T("&apos;"),_T("'"));
		buf1.Replace(_T("&amp;"),_T("&"));
		buf1.Replace(_T("&lt;"),_T("<"));
		buf1.Replace(_T("&gt;"),_T(">"));
		buf1.Replace(_T("&quot;"),_T("\""));

#ifdef USE_APL_STRING_AS_CSTRING 
		// Такая фигня т.к. Вместо класса CStringArray используется шаблон
		tmpStr1=ConvertSpecSymbols(buf1.GetBuffer()); 
		strarray.Add(tmpStr1);
#else
        strarray.Add(ConvertSpecSymbols(buf1.GetBuffer()));
#endif
	}
	if(m_stmp!=0) delete m_stmp;

	file.Close();
	
	return true;
}

TCHAR* CaplTranslate::ConvertSpecSymbols(TCHAR *buf)
{
	if(0==buf) return 0;
	TCHAR c;
	int i=0,j=0;
	while(buf[i]!=_T('\0'))
	{
		c=buf[i];
		if(c!=_T('\\'))
		{
			if(i!=j) buf[j]=buf[i];
			i++;j++; 
			continue;
		}

		// это '\\'
		c=buf[i+1];
		if (c==_T('\0'))
		{
			// ну ведь может же строка оканчиваться на '\\'
			if(i!=j) buf[j]=buf[i];
			i++;j++; 
			continue;
		}


		if(c==_T('o') || c==_T('O'))
		{
			//число в восьмиричной системе системе аналогично без о
			i++;
			c=buf[i+1];
		}

		if(c>=_T('0') && c<=_T('7'))
		{
			//число в восьмиричной системе системе
			char v,v1;
			v=c-_T('0');
			i++;
			c=buf[i+1];
			if(c>=_T('0') && c<=_T('7'))
			{
				v1=c-_T('0');
				v=(v<<3)|v1;

				i++;
				c=buf[i+1];
				if(c>=_T('0') && c<=_T('7'))
				{
					v1=c-_T('0');
					v=(v<<3)|v1;
					i++;
				}
			}
			buf[j]=v;
			i++;j++;
			continue;
		}

		if(c==_T('x') || c==_T('X'))
		{
			//число в шестнадцатиричной системе
			TCHAR v,c1=buf[i+2];

			if(c1>=_T('0') && c1<=_T('9')) c1-=_T('0');
			else if(c1>=_T('a') && c1<=_T('z')) c1-=(_T('a')-10);
			else if(c1>=_T('A') && c1<=_T('Z')) c1-=(_T('a')-10);
			
			TCHAR c2=buf[i+3];
			bool bIs2Sym=true;

			if(c2>=_T('0') && c2<=_T('9')) c2-=_T('0');
			else if(c2>=_T('a') && c2<=_T('z')) c2-=(_T('a')-10);
			else if(c2>=_T('A') && c2<=_T('Z')) c2-=(_T('a')-10);
			else bIs2Sym=false;

			if (bIs2Sym) {v=(c1<<4)|c2; i++;}
			else v=c1;

			buf[j]=v;
			i+=3;
			j++;
			continue;
		}

		switch(c)
		{
		case _T('a'): buf[j]=_T('\a'); break;
		case _T('b'): buf[j]=_T('\b'); break;
		case _T('f'): buf[j]=_T('\f'); break;
		case _T('n'): buf[j]=_T('\n'); break;
		case _T('r'): buf[j]=_T('\r'); break;
		case _T('t'): buf[j]=_T('\t'); break;
		case _T('v'): buf[j]=_T('\v'); break;
		case _T('\''): buf[j]=_T('\''); break;
		case _T('"'): buf[j]=_T('"'); break;
		case _T('?'): buf[j]=_T('?'); break;
		case _T('\\'): buf[j] = _T('\\'); break;
		default:
			// ну ведь может же в строке попасться '\\'
			if(i!=j) buf[j]=buf[i];
			i++;j++; 
			continue;
			break;
		}
		i+=2;
		j++;

	}
	if(i!=j) buf[j]=_T('\0');

	return buf;

}


int CaplTranslate::GetNumLangs()
{
    CString sPath;
    aplGetModuleFilePath(sPath);
#ifdef _MFC_VER
    TIntSet lang_nums;
    return GetTranslateFiles(sPath, lang_nums);
#else
    TWStrSet langs;
    return GetTranslateFiles(sPath, langs);
#endif
}


//**********************************************************************************
#ifdef _MFC_VER
int CaplTranslate::GetTranslateFiles(LPCTSTR pszPath, TIntSet& lang_nums)
#else
int CaplTranslate::GetTranslateFiles(LPCTSTR pszPath, TWStrSet &langs)
#endif
{
#ifdef _MFC_VER
	lang_nums.clear();
#else
	langs.clear();
#endif

	if (pszPath==NULL)
		return 0;

	bool needRus(true);
	CString sTransFolder = pszPath;
	CString sLangMask;
	sLangMask.Format(_T("%s\\translate#*.xml"), LPCTSTR(sTransFolder));

	CString sCurPath;
	CFileFind find_file;
	BOOL bFind = find_file.FindFile(sLangMask);
	while(bFind)
	{
		bFind = find_file.FindNextFile();

		sCurPath = find_file.GetFileTitle();
		int iFind = sCurPath.ReverseFind('#');
		if (iFind>0)
		{
			sCurPath = sCurPath.Right(sCurPath.GetLength()-iFind-1);
#ifdef _MFC_VER
			// ищем соотв. индекс
			for(int i=0; i<APL_LANG_COUNT; ++i)
			{
				if (apl_langs[i].name==sCurPath)
				{
					lang_nums.insert(i);
					break;
				}
			}
#else
			sCurPath.Replace(_T('-'), _T('_'));
			langs.insert((LPCWSTR)sCurPath);
			if(sCurPath==_T("ru_RU"))needRus=false;
#endif
		}
		else
		{
			// это русский (translate.xml)
#ifdef _MFC_VER
			for(int i=0; i<APL_LANG_COUNT; ++i)
			{
				if (apl_langs[i].id==0x0419)
				{
					lang_nums.insert(i);
					break;
				}
			}
#else
			langs.insert(_T("ru_RU"));
			needRus=false;
#endif
		}
	}
#ifdef _MFC_VER
	return lang_nums.size();
#else
	// добавляем русский язык, если его не было
	if(needRus) langs.insert(_T("ru_RU"));
	return langs.size();
#endif
}

//**********************************************************************************

#ifdef _MFC_VER
unsigned long CaplTranslate::GetGlobalUILang()
{
	CRegKey key;
	DWORD dval;
	unsigned long curUILang(0);

	// читаем из реестра
	LONG res = key.Open(HKEY_CURRENT_USER, _T("SOFTWARE\\CALS Centre \"Applied Logistic\"\\Settings"), KEY_ALL_ACCESS);
	if (res == ERROR_SUCCESS)
	{
		if (key.QueryDWORDValue(_T("DefLangCode"), dval) == ERROR_SUCCESS)
		{ 
			curUILang = (unsigned long)dval;
		}
	}
	else
	{
		// если в реестре нет - читаем из локального профиля
		CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
		if(0!=app)	curUILang = app->GetProfileInt(_T("Settings"), _T("DefLangCode"), 0);
	}

	return curUILang;
}

void CaplTranslate::SetGlobalUILang(unsigned long ulLang, bool bUpdateLocalUILang /*= true*/)
{
	CRegKey key;
	LONG res = key.Open(HKEY_CURRENT_USER, _T("SOFTWARE\\CALS Centre \"Applied Logistic\"\\Settings"), KEY_ALL_ACCESS);
	if (res == ERROR_SUCCESS)
	{
		// пишем в глобальную переменную в реестр
		key.SetDWORDValue(_T("DefLangCode"), (DWORD)ulLang);
	}

	if (bUpdateLocalUILang)
	{
		// пишем в локальный профиль
		CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
		if(0!=app) app->WriteProfileInt(_T("Settings"), _T("DefLangCode"), ulLang);
	}
}
#else
LPCTSTR CaplTranslate::GetGlobalUILang()
{
	CaplTranslate_m_new_lang.Empty();
	if(!CaplTranslate_m_ini_path.IsEmpty())
	{
		CaplINI ini(CaplTranslate_m_ini_path);
		CaplTranslate_m_new_lang = ini.GetString(_T("Options"),_T("DefLang"), _T(""));
		CaplTranslate_m_new_lang.Replace(_T("-"), _T("_"));
	}
	if(CaplTranslate_m_new_lang.IsEmpty())
	{
		/* резервное место хранения - в реестре и в .config/APL/ - пока не нужно
		QSettings settings_user(QSettings::UserScope, "APL", "APL");
		CaplTranslate_m_new_lang = QS2CS(settings_user.value("Options/DefLang", "").toString());
		*/

		/*		На будущее - если нигде нет языка, сделать чтение из PSS ной ветки реестра и перекодирование
		// читаем из реестра
		LONG res = key.Open(HKEY_CURRENT_USER, _T("SOFTWARE\\CALS Centre \"Applied Logistic\"\\Settings"), KEY_ALL_ACCESS);
		if (res == ERROR_SUCCESS)
		{
			if (key.QueryDWORDValue(_T("DefLangCode"), dval) == ERROR_SUCCESS)
			{
				curUILang = (unsigned long)dval;
			}
		}
		else
		{
			// если в реестре нет - читаем из локального профиля
			CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
			if(0!=app) curUILang = app->GetProfileInt(_T("Settings"), _T("DefLangCode"), 0);
		}
		*/
	}
	return CaplTranslate_m_new_lang;
}

void CaplTranslate::SetGlobalUILang(LPCTSTR uiLang, bool /*bUpdateLocalUILang*/ /*= true*/)
{
	CaplTranslate_m_new_lang = uiLang;
	CaplTranslate_m_new_lang.Replace(_T('-'), _T('_'));
	if(!CaplTranslate_m_ini_path.IsEmpty())
	{
		CaplINI ini(CaplTranslate_m_ini_path);
		ini.WriteString(_T("Options"),_T("DefLang"), CaplTranslate_m_new_lang);
	}
	else
	{
		/* резервное место хранения - в реестре и в .config/APL/ - пока не нужно
		QSettings settings_user(QSettings::UserScope, "APL", "APL");
		settings_user.setValue("Options/DefLang", CS2QS(CaplTranslate_m_new_lang));
		*/
	}
}
#endif

//********************************************************************************************************************************
//********************************************************************************************************************************
//********************************************************************************************************************************


bool CaplTranslate::SetCurLocaleFromReg(bool hide_mode, CString *errMess)
{
#ifndef _UNICODE
	// В ANSI версии при переключении потока на английский системные функции воспринимают
	// русские символы как кодировку 1252 и получаются кракозябры. Например, в диалоге выбора файлов.
	// Поэтому возможность перевода лучше отключить нафиг 
	return false;   
#endif
#ifdef _MFC_VER
	LCID curThreadlocale=GetThreadLocale(); 

	DWORD curUILang=ReadUILangFromReg(); // Читаем из реестра
	if(0==curUILang)
	{
		//При первом запуске установим тек. язык равный тек. локали, если это русский или английский
		if(curThreadlocale==0x0419)  curUILang=APL_ALP_LANG_CODE_RUSSIAN; // Текущий язык - русский
		else curUILang=APL_ALP_LANG_CODE_ENGLISH; //для нерусской локали тек. язык - английский
	}

	if(curThreadlocale!=curUILang)
	{
		OSVERSIONINFO os;
		os.dwOSVersionInfoSize = sizeof(os);
		GetVersionEx(&os);
		if(os.dwMajorVersion>=6)
		{
			SetThreadLocale(MAKELCID(MAKELANGID(curUILang, SUBLANG_DEFAULT), SORT_DEFAULT));
			SetThreadUILanguage(MAKELANGID(curUILang, SUBLANG_NEUTRAL));
		}
		else
		{
			SetThreadLocale(MAKELCID(MAKELANGID(curUILang, SUBLANG_DEFAULT), SORT_DEFAULT));
		}
	}

	if(curUILang==APL_ALP_LANG_CODE_RUSSIAN) // Ничего переводить не надо 
	{
		CaplTranslate_m_cur_lang=0;
		m_bTranslate=false;
		return true;
	}
#else

	GetGlobalUILang(); // Читаем язык из файла, заданного функцией CaplTranslate::SetIniPath
	if(CaplTranslate_m_new_lang.IsEmpty())
	{
		//При первом запуске установим тек. язык равный тек. локали, если это русский, или английский для остальных
		GetSystemLocale();
		if(CaplTranslate_m_sys_lang == _T("ru_RU"))CaplTranslate_m_new_lang = CaplTranslate_m_sys_lang;
		else CaplTranslate_m_new_lang = _T("en_US"); //для нерусской локали тек. язык - английский
	}
	QLocale::setDefault(QLocale(CS2QS(CaplTranslate_m_new_lang)));
#ifndef __linux__
	// Если под виндой будут сбои в переводе, можно еще установить SetThreadLocale
	// Но придется перебирать apl_langs и по строке искать числовое значение кодировки
#endif

#endif
	return CaplTranslate::Init(hide_mode, errMess);
}

//********************************************************************************************************************************

#ifdef _MFC_VER
DWORD CaplTranslate::ReadUILangFromReg()
{
	CRegKey key;
	DWORD dval;
	DWORD curUILang(0);

	// читаем из реестра
	LONG res = key.Open(HKEY_CURRENT_USER, _T("Software\\CALS Centre \"Applied Logistic\"\\Settings"), KEY_ALL_ACCESS);
	if (res == ERROR_SUCCESS)
	{
		if (ERROR_SUCCESS==key.QueryDWORDValue(_T("DefLangCode"), dval) )
		{ 
			curUILang = dval;
		}
		
		if (ERROR_SUCCESS==key.QueryDWORDValue(_T("bShowStringId"), dval))
		{ 
			if(0==dval) m_bShowStringId=false; else m_bShowStringId=true;
		}		
	}

	if(0==curUILang)
	{
		LONG res = key.Open(HKEY_CURRENT_USER, _T("Software\\CALS Centre \"Applied Logistic\"\\Модуль PDM\\Settings"), KEY_ALL_ACCESS);
		if (res == ERROR_SUCCESS)
		{
			if (key.QueryDWORDValue(_T("DefLangCode"), dval) == ERROR_SUCCESS)
			{ 
				curUILang = dval;
			}
		}
		key.Close();

	}
	if(0==curUILang)
	{
		// если в реестре нет - читаем из локального профиля текущего приложения
		CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
		if(0!=app) curUILang = app->GetProfileInt(_T("Settings"), _T("DefLangCode"), 0);
	}

	return curUILang;
}

//********************************************************************************************************************************

void CaplTranslate::SaveUILangToReg(DWORD ulLang)
{
	CRegKey key;
	LONG res = key.Open(HKEY_CURRENT_USER, _T("Software\\CALS Centre \"Applied Logistic\"\\Settings"), KEY_ALL_ACCESS);
	if (res != ERROR_SUCCESS)
	{
		res=key.Create(HKEY_CURRENT_USER, _T("Software\\CALS Centre \"Applied Logistic\"\\Settings"),REG_NONE,REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS);
		if (res != ERROR_SUCCESS) return;
	}

	// пишем в глобальную переменную в реестр
	key.SetDWORDValue(_T("DefLangCode"), (DWORD)ulLang);
}
#endif


void CaplTranslate::SaveShowStringId(bool bShowStringId)
{
#ifdef _MFC_VER
	DWORD dwVal= bShowStringId ? 1 : 0;

	CRegKey key;
	LONG res = key.Open(HKEY_CURRENT_USER, _T("Software\\CALS Centre \"Applied Logistic\"\\Settings"), KEY_ALL_ACCESS);
	if (res != ERROR_SUCCESS) return;

	// пишем в глобальную переменную в реестр
	key.SetDWORDValue(_T("bShowStringId"), dwVal);
#else
	Q_UNUSED(bShowStringId);
#endif
}

#ifndef _MFC_VER
#ifdef _UNICODE
CStringA aplTranslate(LPCSTR stringA)
{
	CString strW(stringA);
	CaplStringAdapter ad(CaplTranslate::Translate(strW));
	return CStringA((LPCSTR)ad);
}
#endif
#endif


#ifndef _MFC_VER
// Объект нужен для очистки памяти при любом порядке удаления глобальных переменных.
// Сделать вызов, если будут проблемы с освобождением памяти при завершении процессов
// CaplTranslate gl_TranslateResetter;
#endif

