TEST(TestPOUtils, General) { CPODocument a; EXPECT_TRUE(a.LoadFile(XBMC_REF_FILE_PATH("/language/Spanish/strings.po"))); EXPECT_TRUE(a.GetNextEntry()); EXPECT_EQ(ID_FOUND, a.GetEntryType()); EXPECT_EQ((uint32_t)0, a.GetEntryID()); a.ParseEntry(false); EXPECT_STREQ("", a.GetMsgctxt().c_str()); EXPECT_STREQ("Programs", a.GetMsgid().c_str()); EXPECT_STREQ("Programas", a.GetMsgstr().c_str()); EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); EXPECT_TRUE(a.GetNextEntry()); EXPECT_EQ(ID_FOUND, a.GetEntryType()); EXPECT_EQ((uint32_t)1, a.GetEntryID()); a.ParseEntry(false); EXPECT_STREQ("", a.GetMsgctxt().c_str()); EXPECT_STREQ("Pictures", a.GetMsgid().c_str()); EXPECT_STREQ("Imágenes", a.GetMsgstr().c_str()); EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); EXPECT_TRUE(a.GetNextEntry()); EXPECT_EQ(ID_FOUND, a.GetEntryType()); EXPECT_EQ((uint32_t)2, a.GetEntryID()); a.ParseEntry(false); EXPECT_STREQ("", a.GetMsgctxt().c_str()); EXPECT_STREQ("Music", a.GetMsgid().c_str()); EXPECT_STREQ("Música", a.GetMsgstr().c_str()); EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); }
/*! \brief Tries to load ids and strings from a strings.po file to the `strings` map. * It should only be called from the LoadStr2Mem function to have a fallback. \param pathname The directory name, where we look for the strings file. \param strings [out] The resulting strings map. \param encoding Encoding of the strings. For PO files we only use utf-8. \param offset An offset value to place strings from the id value. \param bSourceLanguage If we are loading the source English strings.po. \return false if no strings.po file was loaded. */ static bool LoadPO(const std::string &filename, std::map<uint32_t, LocStr>& strings, std::string &encoding, uint32_t offset = 0 , bool bSourceLanguage = false) { CPODocument PODoc; if (!PODoc.LoadFile(filename)) return false; int counter = 0; while ((PODoc.GetNextEntry())) { uint32_t id; if (PODoc.GetEntryType() == ID_FOUND) { bool bStrInMem = strings.find((id = PODoc.GetEntryID()) + offset) != strings.end(); PODoc.ParseEntry(bSourceLanguage); if (bSourceLanguage && !PODoc.GetMsgid().empty()) { if (bStrInMem && (strings[id + offset].strOriginal.empty() || PODoc.GetMsgid() == strings[id + offset].strOriginal)) continue; else if (bStrInMem) CLog::Log(LOGDEBUG, "POParser: id:%i was recently re-used in the English string file, which is not yet " "changed in the translated file. Using the English string instead", id); strings[id + offset].strTranslated = PODoc.GetMsgid(); counter++; } else if (!bSourceLanguage && !bStrInMem && !PODoc.GetMsgstr().empty()) { strings[id + offset].strTranslated = PODoc.GetMsgstr(); strings[id + offset].strOriginal = PODoc.GetMsgid(); counter++; } } else if (PODoc.GetEntryType() == MSGID_FOUND) { // TODO: implement reading of non-id based string entries from the PO files. // These entries would go into a separate memory map, using hash codes for fast look-up. // With this memory map we can implement using gettext(), ngettext(), pgettext() calls, // so that we don't have to use new IDs for new strings. Even we can start converting // the ID based calls to normal gettext calls. } else if (PODoc.GetEntryType() == MSGID_PLURAL_FOUND) { // TODO: implement reading of non-id based pluralized string entries from the PO files. // We can store the pluralforms for each language, in the langinfo.xml files. } } CLog::Log(LOGDEBUG, "LocalizeStrings: loaded %i strings from file %s", counter, filename.c_str()); return true; }
bool CLocalizeStrings::LoadPO(const CStdString &filename, CStdString &encoding, uint32_t offset /* = 0 */, bool bSourceLanguage) { CPODocument PODoc; if (!PODoc.LoadFile(filename)) return false; int counter = 0; while ((PODoc.GetNextEntry())) { uint32_t id; if (PODoc.GetEntryType() == ID_FOUND && m_strings.find((id = PODoc.GetEntryID()) + offset) == m_strings.end()) { PODoc.ParseEntry(bSourceLanguage); if (bSourceLanguage) { if (!PODoc.GetMsgid().empty()) { m_strings[id + offset] = PODoc.GetMsgid(); counter++; } } else { if (!PODoc.GetMsgstr().empty()) { m_strings[id + offset] = PODoc.GetMsgstr(); counter++; } } } else if (PODoc.GetEntryType() == MSGID_FOUND) { // TODO: implement reading of non-id based string entries from the PO files. // These entries would go into a separate memory map, using hash codes for fast look-up. // With this memory map we can implement using gettext(), ngettext(), pgettext() calls, // so that we don't have to use new IDs for new strings. Even we can start converting // the ID based calls to normal gettext calls. } else if (PODoc.GetEntryType() == MSGID_PLURAL_FOUND) { // TODO: implement reading of non-id based pluralized string entries from the PO files. // We can store the pluralforms for each language, in the langinfo.xml files. } } CLog::Log(LOGDEBUG, "POParser: loaded %i strings from file %s", counter, filename.c_str()); return true; }
void CWeatherJob::LoadLocalizedToken() { // We load the english strings in to get our tokens std::string language = LANGUAGE_DEFAULT; std::shared_ptr<CSettingString> languageSetting = std::static_pointer_cast<CSettingString>(CServiceBroker::GetSettings().GetSetting(CSettings::SETTING_LOCALE_LANGUAGE)); if (languageSetting != NULL) language = languageSetting->GetDefault(); // Try the strings PO file first CPODocument PODoc; if (PODoc.LoadFile(URIUtils::AddFileToFolder(CLangInfo::GetLanguagePath(language), "strings.po"))) { int counter = 0; while (PODoc.GetNextEntry()) { if (PODoc.GetEntryType() != ID_FOUND) continue; uint32_t id = PODoc.GetEntryID(); PODoc.ParseEntry(ISSOURCELANG); if (id > LOCALIZED_TOKEN_LASTID2) break; if ((LOCALIZED_TOKEN_FIRSTID <= id && id <= LOCALIZED_TOKEN_LASTID) || (LOCALIZED_TOKEN_FIRSTID2 <= id && id <= LOCALIZED_TOKEN_LASTID2) || (LOCALIZED_TOKEN_FIRSTID3 <= id && id <= LOCALIZED_TOKEN_LASTID3) || (LOCALIZED_TOKEN_FIRSTID4 <= id && id <= LOCALIZED_TOKEN_LASTID4)) { if (!PODoc.GetMsgid().empty()) { m_localizedTokens.insert(make_pair(PODoc.GetMsgid(), id)); counter++; } } } CLog::Log(LOGDEBUG, "POParser: loaded %i weather tokens", counter); return; } CLog::Log(LOGDEBUG, "Weather: no PO string file available, to load English tokens, " "fallback to strings.xml file"); // We load the tokens from the strings.xml file std::string strLanguagePath = URIUtils::AddFileToFolder(CLangInfo::GetLanguagePath(language), "strings.xml"); CXBMCTinyXML xmlDoc; if (!xmlDoc.LoadFile(strLanguagePath) || !xmlDoc.RootElement()) { CLog::Log(LOGERROR, "Weather: unable to load %s: %s at line %d", strLanguagePath.c_str(), xmlDoc.ErrorDesc(), xmlDoc.ErrorRow()); return; } TiXmlElement* pRootElement = xmlDoc.RootElement(); if (pRootElement->ValueStr() != "strings") return; const TiXmlElement *pChild = pRootElement->FirstChildElement(); while (pChild) { std::string strValue = pChild->ValueStr(); if (strValue == "string") { // Load new style language file with id as attribute const char* attrId = pChild->Attribute("id"); if (attrId && !pChild->NoChildren()) { int id = atoi(attrId); if ((LOCALIZED_TOKEN_FIRSTID <= id && id <= LOCALIZED_TOKEN_LASTID) || (LOCALIZED_TOKEN_FIRSTID2 <= id && id <= LOCALIZED_TOKEN_LASTID2) || (LOCALIZED_TOKEN_FIRSTID3 <= id && id <= LOCALIZED_TOKEN_LASTID3) || (LOCALIZED_TOKEN_FIRSTID4 <= id && id <= LOCALIZED_TOKEN_LASTID4)) { std::string utf8Label(pChild->FirstChild()->ValueStr()); if (!utf8Label.empty()) m_localizedTokens.insert(make_pair(utf8Label, id)); } } } pChild = pChild->NextSiblingElement(); } }
void CWeatherJob::LoadLocalizedToken() { // We load the english strings in to get our tokens // Try the strings PO file first CPODocument PODoc; if (PODoc.LoadFile("special://xbmc/language/English/strings.po")) { int counter = 0; while (PODoc.GetNextEntry()) { if (PODoc.GetEntryType() != ID_FOUND) continue; uint32_t id = PODoc.GetEntryID(); PODoc.ParseEntry(ISSOURCELANG); if (id > LOCALIZED_TOKEN_LASTID2) break; if ((LOCALIZED_TOKEN_FIRSTID <= id && id <= LOCALIZED_TOKEN_LASTID) || (LOCALIZED_TOKEN_FIRSTID2 <= id && id <= LOCALIZED_TOKEN_LASTID2) || (LOCALIZED_TOKEN_FIRSTID3 <= id && id <= LOCALIZED_TOKEN_LASTID3) || (LOCALIZED_TOKEN_FIRSTID4 <= id && id <= LOCALIZED_TOKEN_LASTID4)) { if (!PODoc.GetMsgid().empty()) { m_localizedTokens.insert(make_pair(PODoc.GetMsgid(), id)); counter++; } } } CLog::Log(LOGDEBUG, "POParser: loaded %i weather tokens", counter); return; } CLog::Log(LOGDEBUG, "Weather: no PO string file available, to load English tokens, " "fallback to strings.xml file"); // We load the tokens from the strings.xml file CStdString strLanguagePath = "special://xbmc/language/English/strings.xml"; CXBMCTinyXML xmlDoc; if (!xmlDoc.LoadFile(strLanguagePath) || !xmlDoc.RootElement()) { CLog::Log(LOGERROR, "Weather: unable to load %s: %s at line %d", strLanguagePath.c_str(), xmlDoc.ErrorDesc(), xmlDoc.ErrorRow()); return; } CStdString strEncoding; XMLUtils::GetEncoding(&xmlDoc, strEncoding); TiXmlElement* pRootElement = xmlDoc.RootElement(); if (pRootElement->Value() != CStdString("strings")) return; const TiXmlElement *pChild = pRootElement->FirstChildElement(); while (pChild) { CStdString strValue = pChild->Value(); if (strValue == "string") { // Load new style language file with id as attribute const char* attrId = pChild->Attribute("id"); if (attrId && !pChild->NoChildren()) { int id = atoi(attrId); if ((LOCALIZED_TOKEN_FIRSTID <= id && id <= LOCALIZED_TOKEN_LASTID) || (LOCALIZED_TOKEN_FIRSTID2 <= id && id <= LOCALIZED_TOKEN_LASTID2) || (LOCALIZED_TOKEN_FIRSTID3 <= id && id <= LOCALIZED_TOKEN_LASTID3) || (LOCALIZED_TOKEN_FIRSTID4 <= id && id <= LOCALIZED_TOKEN_LASTID4)) { CStdString utf8Label; if (strEncoding.IsEmpty()) // Is language file utf8? utf8Label=pChild->FirstChild()->Value(); else g_charsetConverter.stringCharsetToUtf8(strEncoding, pChild->FirstChild()->Value(), utf8Label); if (!utf8Label.IsEmpty()) m_localizedTokens.insert(make_pair(utf8Label, id)); } } } pChild = pChild->NextSiblingElement(); } }