diff --git a/reactos/base/applications/rapps/available.cpp b/reactos/base/applications/rapps/available.cpp index ee750879875..95ad9156331 100644 --- a/reactos/base/applications/rapps/available.cpp +++ b/reactos/base/applications/rapps/available.cpp @@ -13,48 +13,49 @@ // CAvailableApplicationInfo CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam) + : m_Parser(sFileNameParam) { LicenseType = LICENSE_TYPE::None; sFileName = sFileNameParam; - RetrieveCategory(); + + RetrieveGeneralInfo(); } VOID CAvailableApplicationInfo::RefreshAppInfo() { - if (RetrieveGeneralInfo()) + if (szUrlDownload.IsEmpty()) { - RetrieveLicenseType(); - RetrieveLanguages(); - RetrieveInstalledStatus(); - if (m_IsInstalled) - { - RetrieveInstalledVersion(); - } + RetrieveGeneralInfo(); } } -BOOL CAvailableApplicationInfo::RetrieveGeneralInfo() +VOID CAvailableApplicationInfo::RetrieveGeneralInfo() { - if (szUrlDownload.IsEmpty()) - { - if (!GetString(L"Name", szName) - || !GetString(L"URLDownload", szUrlDownload)) - { - return FALSE; - } + Category = m_Parser.GetInt(L"Category"); - GetString(L"RegName", szRegName); - GetString(L"Version", szVersion); - GetString(L"License", szLicense); - GetString(L"Description", szDesc); - GetString(L"Size", szSize); - GetString(L"URLSite", szUrlSite); - GetString(L"CDPath", szCDPath); - GetString(L"Language", szRegName); - GetString(L"SHA1", szSHA1); - return TRUE; + if (!GetString(L"Name", szName) + || !GetString(L"URLDownload", szUrlDownload)) + { + return; + } + + GetString(L"RegName", szRegName); + GetString(L"Version", szVersion); + GetString(L"License", szLicense); + GetString(L"Description", szDesc); + GetString(L"Size", szSize); + GetString(L"URLSite", szUrlSite); + GetString(L"CDPath", szCDPath); + GetString(L"Language", szRegName); + GetString(L"SHA1", szSHA1); + + RetrieveLicenseType(); + RetrieveLanguages(); + RetrieveInstalledStatus(); + if (m_IsInstalled) + { + RetrieveInstalledVersion(); } - return FALSE; } VOID CAvailableApplicationInfo::RetrieveInstalledStatus() @@ -69,42 +70,45 @@ VOID CAvailableApplicationInfo::RetrieveInstalledVersion() || ::GetInstalledVersion(&szInstalledVersion, szName); } -BOOL CAvailableApplicationInfo::RetrieveLanguages() +VOID CAvailableApplicationInfo::RetrieveLanguages() { const WCHAR cDelimiter = L'|'; ATL::CStringW szBuffer; // TODO: Get multiline parameter - if (!ParserGetString(L"Languages", sFileName, szBuffer)) - return FALSE; + if (!m_Parser.GetString(L"Languages", szBuffer)) + { + m_HasLanguageInfo = FALSE; + return; + } // Parse parameter string - ATL::CStringW szLocale; + ATL::CStringW m_szLocale; for (INT i = 0; szBuffer[i] != UNICODE_NULL; ++i) { if (szBuffer[i] != cDelimiter) { - szLocale += szBuffer[i]; + m_szLocale += szBuffer[i]; } else { - Languages.Add(szLocale); - szLocale.Empty(); + Languages.Add(m_szLocale); + m_szLocale.Empty(); } } // For the text after delimiter - if (!szLocale.IsEmpty()) + if (!m_szLocale.IsEmpty()) { - Languages.Add(szLocale); + Languages.Add(m_szLocale); } - return TRUE; + m_HasLanguageInfo = TRUE; } VOID CAvailableApplicationInfo::RetrieveLicenseType() { - INT IntBuffer = ParserGetInt(L"LicenseType", sFileName); + INT IntBuffer = m_Parser.GetInt(L"LicenseType"); if (IntBuffer < 0 || IntBuffer > LICENSE_TYPE::Max) { @@ -116,11 +120,6 @@ VOID CAvailableApplicationInfo::RetrieveLicenseType() } } -VOID CAvailableApplicationInfo::RetrieveCategory() -{ - Category = ParserGetInt(L"Category", sFileName); -} - BOOL CAvailableApplicationInfo::HasLanguageInfo() const { return m_HasLanguageInfo; @@ -133,19 +132,52 @@ BOOL CAvailableApplicationInfo::HasNativeLanguage() const return FALSE; } - //TODO: make the actual check - return TRUE; + //Find locale code in the list + const INT nLanguagesSize = Languages.GetSize(); + for (INT i = 0; i < nLanguagesSize; ++i) + { + if (Languages[i] == CConfigParser::GetLocale()) + { + return TRUE; + } + } + + return FALSE; } BOOL CAvailableApplicationInfo::HasEnglishLanguage() const { + static ATL::CStringW szEnglishLocaleID; + const INT cchLocaleSize = m_Parser.GetLocaleSize(); if (!m_HasLanguageInfo) { return FALSE; } - //TODO: make the actual check - return TRUE; + //Get English locale code + if (szEnglishLocaleID.IsEmpty()) + { + INT result = GetLocaleInfoW(MAKELCID(LANG_ENGLISH, SORT_DEFAULT), LOCALE_ILANGUAGE, + szEnglishLocaleID.GetBuffer(cchLocaleSize), cchLocaleSize); + szEnglishLocaleID.ReleaseBuffer(); + if (result != ERROR_SUCCESS) + { + return FALSE; + } + + } + + //Find locale code in the list + const INT nLanguagesSize = Languages.GetSize(); + for (INT i = 0; i < nLanguagesSize; ++i) + { + if (Languages[i] == szEnglishLocaleID) + { + return TRUE; + } + } + + return FALSE; } BOOL CAvailableApplicationInfo::IsInstalled() const @@ -170,13 +202,14 @@ VOID CAvailableApplicationInfo::SetLastWriteTime(FILETIME* ftTime) inline BOOL CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString) { - if (!ParserGetString(lpKeyName, sFileName, ReturnedString)) + if (!m_Parser.GetString(lpKeyName, ReturnedString)) { ReturnedString.Empty(); return FALSE; } return TRUE; } +// CAvailableApplicationInfo // CAvailableApps CAvailableApps::CAvailableApps() @@ -277,7 +310,7 @@ BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnu do { - /* loop for all the cached entries */ + // loop for all the cached entries POSITION CurrentListPosition = m_InfoList.GetHeadPosition(); CAvailableApplicationInfo* Info = NULL; @@ -286,13 +319,13 @@ BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnu POSITION LastListPosition = CurrentListPosition; Info = m_InfoList.GetNext(CurrentListPosition); - /* do we already have this entry in cache? */ + // do we already have this entry in cache? if (Info->sFileName == FindFileData.cFileName) { - /* is it current enough, or the file has been modified since our last time here? */ + // is it current enough, or the file has been modified since our last time here? if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->ftCacheStamp) == 1) { - /* recreate our cache, this is the slow path */ + // recreate our cache, this is the slow path m_InfoList.RemoveAt(LastListPosition); delete Info; @@ -301,16 +334,16 @@ BOOL CAvailableApps::EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnu } else { - /* speedy path, compare directly, we already have the data */ + // speedy path, compare directly, we already have the data goto skip_if_cached; } } } - /* create a new entry */ + // create a new entry Info = new CAvailableApplicationInfo(FindFileData.cFileName); - /* set a timestamp for the next time */ + // set a timestamp for the next time Info->SetLastWriteTime(&FindFileData.ftLastWriteTime); m_InfoList.AddTail(Info); @@ -361,3 +394,112 @@ const LPCWSTR CAvailableApps::GetCabPathString() { return m_szPath.GetString(); } +// CAvailableApps + +// CConfigParser +ATL::CStringW CConfigParser::m_szLocale; +ATL::CStringW CConfigParser::m_szCachedINISectionLocale; +ATL::CStringW CConfigParser::m_szCachedINISectionLocaleNeutral; + +CConfigParser::CConfigParser(const ATL::CStringW& FileName) : szConfigPath(GetINIFullPath(FileName)) +{ + // we don't have cached section strings for the current system language, create them, lazy + CacheINILocaleLazy(); +} + +ATL::CStringW CConfigParser::GetINIFullPath(const ATL::CStringW& FileName) +{ + ATL::CStringW szDir; + static ATL::CStringW szBuffer; + + GetStorageDirectory(szDir); + szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName); + + return szBuffer; +} + +VOID CConfigParser::CacheINILocaleLazy() +{ + if (m_szLocale.IsEmpty()) + { + // TODO: Set default locale if call fails + // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, + m_szLocale.GetBuffer(m_cchLocaleSize), m_cchLocaleSize); + m_szLocale.ReleaseBuffer(); + m_szCachedINISectionLocale = L"Section." + m_szLocale; + + // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part + m_szCachedINISectionLocaleNeutral = m_szCachedINISectionLocale + m_szLocale.Right(2); + } +} + +const ATL::CStringW& CConfigParser::GetLocale() +{ + CacheINILocaleLazy(); + return m_szLocale; +} + +INT CConfigParser::GetLocaleSize() +{ + return m_cchLocaleSize; +} + +UINT CConfigParser::GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString) +{ + DWORD dwResult; + + LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH); + // 1st - find localized strings (e.g. "Section.0c0a") + dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocale.GetString(), + KeyName.GetString(), + NULL, + ResultStringBuffer, + MAX_PATH, + szConfigPath.GetString()); + + if (!dwResult) + { + // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a") + dwResult = GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral.GetString(), + KeyName.GetString(), + NULL, + ResultStringBuffer, + MAX_PATH, + szConfigPath.GetString()); + if (!dwResult) + { + // 3rd - if they weren't present fallback to standard english strings (just "Section") + dwResult = GetPrivateProfileStringW(L"Section", + KeyName.GetString(), + NULL, + ResultStringBuffer, + MAX_PATH, + szConfigPath.GetString()); + } + } + + ResultString.ReleaseBuffer(); + return (dwResult != 0 ? TRUE : FALSE); +} + +UINT CConfigParser::GetInt(const ATL::CStringW& KeyName) +{ + ATL::CStringW Buffer; + UNICODE_STRING BufferW; + ULONG Result; + + // grab the text version of our entry + if (!GetString(KeyName, Buffer)) + return FALSE; + + if (Buffer.IsEmpty()) + return FALSE; + + // convert it to an actual integer + RtlInitUnicodeString(&BufferW, Buffer.GetString()); + RtlUnicodeStringToInteger(&BufferW, 0, &Result); + + return (UINT) Result; +} +// CConfigParser diff --git a/reactos/base/applications/rapps/gui.cpp b/reactos/base/applications/rapps/gui.cpp index 01ce7d99af0..ac7e8ae1d6f 100644 --- a/reactos/base/applications/rapps/gui.cpp +++ b/reactos/base/applications/rapps/gui.cpp @@ -102,35 +102,50 @@ class CAvailableAppView static VOID InsertLanguageInfo_RichEdit(CAvailableApplicationInfo* Info) { + if (!Info->HasLanguageInfo()) + { + return; + } + const INT nTranslations = Info->Languages.GetSize(); ATL::CStringW szLangInfo; ATL::CStringW szLoadedTextAvailability; ATL::CStringW szLoadedAInfoText; szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES); + + //TODO: replace those hardcoded strings if (Info->HasNativeLanguage()) { szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION); + if (nTranslations > 1) + { + szLangInfo.Format(L" (+%d more)", nTranslations - 1); + } + else + { + szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE); + szLangInfo = L" (" + szLangInfo + L")"; + } } else if (Info->HasEnglishLanguage()) { szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION); + if (nTranslations > 1) + { + szLangInfo.Format(L" (+%d available)", nTranslations - 1); + } + else + { + szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE); + szLangInfo = L" (" + szLangInfo + L")"; + } } else { szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION); } - if (nTranslations > 1) - { - szLangInfo.Format(L" (+%d more)", nTranslations - 1); - } - else - { - szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE); - szLangInfo = L" (" + szLangInfo + L")"; - } - InsertRichEditText(szLoadedAInfoText, CFE_BOLD); InsertRichEditText(szLoadedTextAvailability, NULL); InsertRichEditText(szLangInfo, CFE_ITALIC); diff --git a/reactos/base/applications/rapps/lang/en-US.rc b/reactos/base/applications/rapps/lang/en-US.rc index a778fb34072..ccea543e400 100644 --- a/reactos/base/applications/rapps/lang/en-US.rc +++ b/reactos/base/applications/rapps/lang/en-US.rc @@ -228,9 +228,8 @@ END STRINGTABLE BEGIN - IDS_LANGUAGE_AVAILABLE_TRANSLATION "In your language" - IDS_LANGUAGE_NO_TRANSLATION "In your language" - IDS_LANGUAGE_NOT_AVAILABLE "No translations" - IDS_LANGUAGE_ENGLISH_TRANSLATION "In English" + IDS_LANGUAGE_AVAILABLE_TRANSLATION "Supports your language" + IDS_LANGUAGE_NO_TRANSLATION "Supports other languages" + IDS_LANGUAGE_ENGLISH_TRANSLATION "Supports English" IDS_LANGUAGE_SINGLE "Single language" END diff --git a/reactos/base/applications/rapps/lang/ru-RU.rc b/reactos/base/applications/rapps/lang/ru-RU.rc index 7f95c9ba890..4d25ead758b 100644 --- a/reactos/base/applications/rapps/lang/ru-RU.rc +++ b/reactos/base/applications/rapps/lang/ru-RU.rc @@ -223,4 +223,12 @@ BEGIN IDS_LICENSE_OPENSOURCE "Свободное ПО" IDS_LICENSE_FREEWARE "Бесплатное ПО" IDS_LICENSE_TRIAL "Пробная версия" +END + +STRINGTABLE +BEGIN + IDS_LANGUAGE_AVAILABLE_TRANSLATION "Доступно на вашем языке" + IDS_LANGUAGE_NO_TRANSLATION "Доступно на других языках" + IDS_LANGUAGE_ENGLISH_TRANSLATION "Доступно на Английском" + IDS_LANGUAGE_SINGLE "Один язык" END \ No newline at end of file diff --git a/reactos/base/applications/rapps/lang/uk-UA.rc b/reactos/base/applications/rapps/lang/uk-UA.rc index d54ecee50e9..7939972b8fd 100644 --- a/reactos/base/applications/rapps/lang/uk-UA.rc +++ b/reactos/base/applications/rapps/lang/uk-UA.rc @@ -231,4 +231,12 @@ BEGIN IDS_LICENSE_OPENSOURCE "Вільне ПЗ" IDS_LICENSE_FREEWARE "Безкоштовне ПЗ" IDS_LICENSE_TRIAL "Пробна версія" +END + +STRINGTABLE +BEGIN + IDS_LANGUAGE_AVAILABLE_TRANSLATION "Є переклад вашою мовою" + IDS_LANGUAGE_NO_TRANSLATION "Доступно іншими мовами" + IDS_LANGUAGE_ENGLISH_TRANSLATION "Є переклад Англійською" + IDS_LANGUAGE_SINGLE "Одна мова" END \ No newline at end of file diff --git a/reactos/base/applications/rapps/misc.cpp b/reactos/base/applications/rapps/misc.cpp index 707cc32d3fd..e991ce90152 100644 --- a/reactos/base/applications/rapps/misc.cpp +++ b/reactos/base/applications/rapps/misc.cpp @@ -15,12 +15,6 @@ #define EXTRACT_EXTRACTFILES 0x00000002 static HANDLE hLog = NULL; -ATL::CStringW szCachedINISectionLocale = L"Section."; -ATL::CStringW szCachedINISectionLocaleNeutral; -BYTE bCachedSectionStatus = FALSE; - -#define LOCALIZED_STRING_LEN MAX_PATH -#define STR_VERSION_CURRENT L"CURRENT" typedef struct { @@ -404,91 +398,4 @@ WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg) } -ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName) -{ - ATL::CStringW szDir; - static ATL::CStringW szBuffer; - GetStorageDirectory(szDir); - szBuffer.Format(L"%ls\\rapps\\%ls", szDir, FileName); - - return szBuffer; -} - -UINT ParserGetString(const ATL::CStringW& KeyName, const ATL::CStringW& FileName, ATL::CStringW& ResultString) -{ - ATL::CStringW FullFileName = GetINIFullPath(FileName); - DWORD dwResult; - - /* we don't have cached section strings for the current system language, create them */ - if (bCachedSectionStatus == FALSE) - { - ATL::CStringW szLocale; - const INT LocaleSize = 5; - - /* find out what is the current system lang code (e.g. "0a") and append it to SectionLocale */ - GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE, - szLocale.GetBuffer(LocaleSize), LocaleSize); - szLocale.ReleaseBuffer(); - - /* turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part */ - szCachedINISectionLocaleNeutral = szCachedINISectionLocale + szLocale.Right(2); - szCachedINISectionLocale += szLocale; - - /* finally, mark us as cache-friendly for the next time */ - bCachedSectionStatus = TRUE; - } - - LPWSTR ResultStringBuffer = ResultString.GetBuffer(MAX_PATH); - /* 1st - find localized strings (e.g. "Section.0c0a") */ - dwResult = GetPrivateProfileStringW(szCachedINISectionLocale.GetString(), - KeyName.GetString(), - NULL, - ResultStringBuffer, - LOCALIZED_STRING_LEN, - FullFileName.GetString()); - - if (!dwResult) - { - /* 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a") */ - dwResult = GetPrivateProfileStringW(szCachedINISectionLocaleNeutral.GetString(), - KeyName.GetString(), - NULL, - ResultStringBuffer, - LOCALIZED_STRING_LEN, - FullFileName.GetString()); - if (!dwResult) - { - /* 3rd - if they weren't present fallback to standard english strings (just "Section") */ - dwResult = GetPrivateProfileStringW(L"Section", - KeyName.GetString(), - NULL, - ResultStringBuffer, - LOCALIZED_STRING_LEN, - FullFileName.GetString()); - } - } - - ResultString.ReleaseBuffer(); - return (dwResult != 0 ? TRUE : FALSE); -} - -UINT ParserGetInt(const ATL::CStringW& KeyName, const ATL::CStringW& FileName) -{ - ATL::CStringW Buffer; - UNICODE_STRING BufferW; - ULONG Result; - - /* grab the text version of our entry */ - if (!ParserGetString(KeyName, FileName, Buffer)) - return FALSE; - - if (Buffer.IsEmpty()) - return FALSE; - - /* convert it to an actual integer */ - RtlInitUnicodeString(&BufferW, Buffer.GetString()); - RtlUnicodeStringToInteger(&BufferW, 0, &Result); - - return (UINT) Result; -} diff --git a/reactos/base/applications/rapps/rapps.h b/reactos/base/applications/rapps/rapps.h index f3d0d23ab70..93705497ac2 100644 --- a/reactos/base/applications/rapps/rapps.h +++ b/reactos/base/applications/rapps/rapps.h @@ -143,18 +143,38 @@ typedef struct } SETTINGS_INFO, *PSETTINGS_INFO; /* available.cpp */ +class CConfigParser +{ + // Loacale names cache + static ATL::CStringW m_szLocale; + const static INT m_cchLocaleSize = 5; + static ATL::CStringW m_szCachedINISectionLocale; + static ATL::CStringW m_szCachedINISectionLocaleNeutral; + + const LPCWSTR STR_VERSION_CURRENT = L"CURRENT"; + const ATL::CStringW szConfigPath; + + static ATL::CStringW GetINIFullPath(const ATL::CStringW& FileName); + static VOID CacheINILocaleLazy(); + +public: + static const ATL::CStringW& GetLocale(); + static INT CConfigParser::GetLocaleSize(); + + CConfigParser(const ATL::CStringW& FileName); + + UINT GetString(const ATL::CStringW& KeyName, ATL::CStringW& ResultString); + UINT GetInt(const ATL::CStringW& KeyName); +}; + typedef BOOL (CALLBACK *AVAILENUMPROC)(PAPPLICATION_INFO Info, LPCWSTR szFolderPath); struct CAvailableApplicationInfo : public APPLICATION_INFO { ATL::CStringW szInstalledVersion; - CAvailableApplicationInfo(const ATL::CStringW& sFileNameParam); // Load all info from the file VOID RefreshAppInfo(); - - - BOOL HasLanguageInfo() const; BOOL HasNativeLanguage() const; BOOL HasEnglishLanguage() const; @@ -169,17 +189,17 @@ private: BOOL m_IsInstalled = FALSE; BOOL m_HasLanguageInfo = FALSE; BOOL m_HasInstalledVersion = FALSE; + CConfigParser m_Parser; inline BOOL GetString(LPCWSTR lpKeyName, ATL::CStringW& ReturnedString); // Lazily load general info from the file - BOOL RetrieveGeneralInfo(); + VOID RetrieveGeneralInfo(); VOID RetrieveInstalledStatus(); VOID RetrieveInstalledVersion(); - BOOL RetrieveLanguages(); + VOID RetrieveLanguages(); VOID RetrieveLicenseType(); - VOID RetrieveCategory(); }; class CAvailableApps @@ -248,9 +268,6 @@ VOID InitLogs(VOID); VOID FreeLogs(VOID); BOOL WriteLogMessage(WORD wType, DWORD dwEventID, LPCWSTR lpMsg); -UINT ParserGetString(const ATL::CStringW& KeyName, const ATL::CStringW& FileName, ATL::CStringW& ReturnedString); -UINT ParserGetInt(const ATL::CStringW& KeyName, const ATL::CStringW& FileName); - /* settingsdlg.cpp */ VOID CreateSettingsDlg(HWND hwnd); diff --git a/reactos/base/applications/rapps/resource.h b/reactos/base/applications/rapps/resource.h index 9658732ac60..0a918bc9a76 100644 --- a/reactos/base/applications/rapps/resource.h +++ b/reactos/base/applications/rapps/resource.h @@ -181,9 +181,8 @@ /* Language related strings */ #define IDS_LANGUAGE_AVAILABLE_TRANSLATION 910 #define IDS_LANGUAGE_NO_TRANSLATION 911 -#define IDS_LANGUAGE_NOT_AVAILABLE 912 -#define IDS_LANGUAGE_ENGLISH_TRANSLATION 913 -#define IDS_LANGUAGE_SINGLE 914 +#define IDS_LANGUAGE_ENGLISH_TRANSLATION 912 +#define IDS_LANGUAGE_SINGLE 913 /* Accelerators */ #define HOTKEYS 715