#include #include #include "localesmgr.h" #include #include #include #include #include "../nu/regexp.h" #include "../Agave/language/api_language.h" #include struct StringEntry { uint32_t id; wchar_t *string; }; typedef PtrList StringTable; struct StringTableData { wchar_t *id; StringTable entries; }; typedef PtrList StringTables; StringTables stringTables; void LocalesAcceleratorSectionXmlCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { const wchar_t *section = params->getItemValue(L"section"); if (!section) LocalesManager::setAcceleratorSection(L"general"); else LocalesManager::setAcceleratorSection(section); } void LocalesAcceleratorSectionXmlCallback::xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag) { LocalesManager::setAcceleratorSection(L""); } void StringTableXmlCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { const wchar_t *section = params->getItemValue(L"id"); if (!section) LocalesManager::SetStringTable(L"nullsoft.wasabi"); else LocalesManager::SetStringTable(section); } void StringTableXmlCallback::xmlReaderOnEndElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag) { LocalesManager::SetStringTable(L""); } void StringTableEntryXmlCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { const wchar_t *b = params->getItemValue(L"id"); const wchar_t *a = params->getItemValue(L"string"); if (b && a) LocalesManager::AddString(WTOI(b), a); } /* ------------------------------------------------------------ */ void LocalesAcceleratorXmlCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { const wchar_t *b = params->getItemValue(L"bind"); const wchar_t *a = params->getItemValue(L"action"); if (b && a) LocalesManager::addAccelerator(b, a); } /* ------------------------------------------------------------ */ void LocalesTranslationXmlCallback::xmlReaderOnStartElementCallback(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params) { const wchar_t *f = params->getItemValue(L"from"); const wchar_t *t = params->getItemValue(L"to"); if (f && t) LocalesManager::addTranslation(f, t); } int LocalesSkinCallback::skincb_onUnloading() { LocalesManager::ResetStrings(); LocalesManager::resetAll(); return 0; } int LocalesSkinCallback::skincb_onReset() { // return 0; } int LocalesSkinCallback::skincb_onReload() { //LocalesManager::load(); return 0; } int LocalesSkinCallback::skincb_onBeforeLoadingElements() { LocalesManager::load(); return 0; } int LocalesSkinCallback::skincb_onGuiLoaded() { LocalesManager::LoadStringTables(); return 0; } int LocalesSkinCallback::skincb_onLoaded() { // TODO: load string table? return 0; } /* ------------------------------------------------------------ */ void LocalesManager::init() { WASABI_API_SYSCB->syscb_registerCallback(&localesSkinCallback); //load(); } void LocalesManager::load() { #ifdef LOCALES_CUSTOM_LOAD LOCALES_CUSTOM_LOAD(localePath); // TODO: benski> don't load this here. we should set up a syscallback for skin load (maybe skincb_onBeforeLoadingElements?) // and also we should call deinit() on skin unload (skincb_onReload, skincb_onReset, skincb_onUnloading?) StringPathCombine filetoload(localePath, L"Wasabi.xml"); /* PathParserW pp(localeName); localeName = pp.getLastString(); int p = localeName.lFindChar('.'); if (p > 0) localeName.trunc(p); */ #else wchar_t tmpbuf[WA_MAX_PATH] = L"english"; WASABI_API_CONFIG->getStringPrivate(L"LocaleFile", tmpbuf, WA_MAX_PATH, L"english"); // FG> ok I have no idea why it doesn't work when i read from cfg instead of stringprivate and frankly i don't have time for this // so for now it'll work with both a cfgitem and a stringprivate, i couldn't desync them so it should be ok in the meantime. /* const GUID options_guid = { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; CfgItem *item = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid); if (item != NULL) item->getData("Language", tmpbuf, WA_MAX_PATH-1);*/ localeName = tmpbuf; englishLocale = !WCSICMP(localeName, L"english"); loadFile(L"english"); StringW filetoload = localeName; if (englishLocale) filetoload.trunc(0); #endif if (!filetoload.isempty()) loadFile(filetoload); #ifdef WASABI_API_WNDMGR if (WASABI_API_WNDMGR) WASABI_API_WNDMGR->wndTrackInvalidateAll(); #endif } void LocalesManager::deinit() { resetAll(); WASABI_API_SYSCB->syscb_deregisterCallback(&localesSkinCallback); } void LoadXmlFile(obj_xml *parser, const wchar_t *filename); void LocalesManager::LoadStringTables() { StringPathCombine genericStringTable(localePath, L"stringtable.xml"); LoadStringTable(genericStringTable); StringPathCombine skinStringTable(localePath, WASABI_API_SKIN->getSkinName()); skinStringTable.AppendPath(L"stringtable.xml"); LoadStringTable(skinStringTable); } void LocalesManager::LoadStringTable(const wchar_t *name) { waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); if (parserFactory) { obj_xml *parser = (obj_xml *)parserFactory->getInterface(); if (parser) { { const wchar_t *file = Wasabi::Std::filename(name); int fnlen = wcslen(file); StringW path = name; path.trunc( -fnlen); XMLAutoInclude include(parser, path); parser->xmlreader_registerCallback(L"WinampLocaleDefinition\fStringTable", &stringTableXmlCallback); parser->xmlreader_registerCallback(L"WinampLocaleDefinition\fStringTable\fStringEntry", &stringTableXmlEntryCallback); parser->xmlreader_open(); #ifdef LOCALES_CUSTOM_LOAD LoadXmlFile(parser, name); #else LoadXmlFile(parser, StringPrintfW(L"Locales/%s.xml", name)); #endif parser->xmlreader_unregisterCallback(&stringTableXmlCallback); parser->xmlreader_unregisterCallback(&stringTableXmlEntryCallback); } parser->xmlreader_close(); parserFactory->releaseInterface(parser); parser = 0; } } } void LocalesManager::loadFile(const wchar_t *name) { waServiceFactory *parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID); if (parserFactory) { obj_xml *parser = (obj_xml *)parserFactory->getInterface(); if (parser) { { const wchar_t *file = Wasabi::Std::filename(name); int fnlen = wcslen(file); StringW path = name; path.trunc( -fnlen); XMLAutoInclude include(parser, path); parser->xmlreader_registerCallback(L"WinampLocaleDefinition\faccelerators", &accelSectionXmlCallback); parser->xmlreader_registerCallback(L"WinampLocaleDefinition\faccelerators\faccelerator", &accelXmlCallback); parser->xmlreader_registerCallback(L"WinampLocaleDefinition\ftranslations\ftranslation", &transXmlCallback); parser->xmlreader_open(); #ifdef LOCALES_CUSTOM_LOAD LoadXmlFile(parser, name); #else LoadXmlFile(parser, StringPrintfW(L"Locales/%s.xml", name)); #endif parser->xmlreader_unregisterCallback(&accelSectionXmlCallback); parser->xmlreader_unregisterCallback(&accelXmlCallback); parser->xmlreader_unregisterCallback(&transXmlCallback); } parser->xmlreader_close(); parserFactory->releaseInterface(parser); parser = 0; } } } void LocalesManager::addTranslation(const wchar_t *from, const wchar_t *to) { LocTrans *t = translationsList.findItem(from); if (t) translationsList.removeItem(t); translationsList.addItem(new LocTrans(from, to)); } const wchar_t *LocalesManager::lookupString(const wchar_t *from) { if (from == NULL) return NULL; if (*from == L'@') { const wchar_t *findPound = wcschr(from, L'#'); if (findPound && (findPound-from) < 128) { wchar_t table[128] = {0}; memcpy(table, from+1, sizeof(wchar_t)*(findPound-from-1)); table[findPound-from-1]=0; const wchar_t *string = GetString(table, WTOI(findPound+1)); if (string) return string; } } return from; } const wchar_t *LocalesManager::getTranslation(const wchar_t *from) { if (!from) return NULL; LocTrans *t = translationsList.findItem(from); if (t == NULL) { return from; } return t->getTo(); } void LocalesManager::addAccelerator(const wchar_t *bind, const wchar_t *action) { LocAccel *a = acceleratorsList.findItem(bind); if (a) // Martin> shouldn't we also check here if it is the same section? // Hm, now that i look closer, we search our list for a wchar_t but we store LocAccels in the list - does this work? acceleratorsList.removeItem(a); acceleratorsList.addItem(new LocAccel(curSection, bind, action)); } void LocalesManager::addAcceleratorFromSkin(const wchar_t *bind, const wchar_t *action) { //TODO> use binary search int l = acceleratorsList.getNumItems(); for (int i = 0;i < l;i++) { if (0 == WCSICMP(acceleratorsList[i]->getSection(), curSection) && 0 == WCSICMP(acceleratorsList[i]->getKey(), bind)) return; } acceleratorsList.addItem(new LocAccel(curSection, bind, action)); } const wchar_t *LocalesManager::getBindFromAction(int action) { //TODO> use binary search int l = acceleratorsList.getNumItems(); for (int i = 0;i < l;i++) { if (acceleratorsList[i]->getActionNum() == action && action != ACTION_NONE) return acceleratorsList[i]->getRealKey(); } return NULL; } const wchar_t *LocalesManager::translateAccelerator(const wchar_t *section, const wchar_t *key) { //TODO> use binary search int l = acceleratorsList.getNumItems(); for (int i = 0;i < l;i++) { if (!WCSICMP(acceleratorsList[i]->getSection(), section)) if (!WCSICMP(acceleratorsList[i]->getKey(), key)) return acceleratorsList[i]->getAction(); } return NULL; } #if 0 void LocalesManager::setNewLocaleFile(const wchar_t *name) { //WASABI_API_CONFIG->setStringPrivate(L"LocaleFile", name); resetAll(); init(); } #endif void LocalesManager::resetAll() { translationsList.deleteAll(); acceleratorsList.deleteAll(); } void LocalesManager::SetStringTable(const wchar_t *table) { curTable = table; } void LocalesManager::setAcceleratorSection(const wchar_t *section) { curSection = section; } const wchar_t *LocalesManager::getLocaleRoot() { return localePath; } void LocalesManager::ResetStrings() { for (int i=0;i!=stringTables.getNumItems();i++) { FREE(stringTables[i]->id); for (int j=0;j!=stringTables[i]->entries.getNumItems();j++) { FREE(stringTables[i]->entries[j]->string); } } stringTables.removeAll(); } const wchar_t *LocalesManager::GetString(const wchar_t *table, uint32_t id) { if (!table) return 0; if (!_wcsicmp(table, L"gen_ff")) return WASABI_API_LNGSTRINGW(id); for (int i=0;i!=stringTables.getNumItems();i++) { if (!wcscmp(table, stringTables[i]->id)) { for (int j=0;j!=stringTables[i]->entries.getNumItems();j++) { if (id == stringTables[i]->entries[j]->id) return stringTables[i]->entries[j]->string; } } } return 0; } void LocalesManager::AddString(const wchar_t *table, uint32_t id, const wchar_t *string) { for (int i=0;i!=stringTables.getNumItems();i++) { if (!wcscmp(table, stringTables[i]->id)) { for (int j=0;j!=stringTables[i]->entries.getNumItems();j++) { if (id == stringTables[i]->entries[j]->id) { FREE(stringTables[i]->entries[j]->string); stringTables[i]->entries[j]->string=WCSDUP(string); return; } } StringEntry *newEntry = new StringEntry; newEntry->id = id; newEntry->string = WCSDUP(string); stringTables[i]->entries.addItem(newEntry); return; } } StringTableData *newTable = new StringTableData; newTable->id = WCSDUP(table); StringEntry *newEntry = new StringEntry; newEntry->id = id; newEntry->string = WCSDUP(string); stringTables.addItem(newTable); newTable->entries.addItem(newEntry); } void LocalesManager::AddString(uint32_t id, const wchar_t *string) { AddString(curTable, id, string); } LocalesAcceleratorXmlCallback LocalesManager::accelXmlCallback; LocalesAcceleratorSectionXmlCallback LocalesManager::accelSectionXmlCallback; LocalesTranslationXmlCallback LocalesManager::transXmlCallback; PtrListSorted > LocalesManager::translationsList; PtrListSorted > LocalesManager::acceleratorsList; StringW LocalesManager::localePath; //int LocalesManager::localeListLoaded = 0, LocalesManager::curLocaleNum = -1, LocalesManager::englishLocale; //PtrList LocalesManager::loadableLocalesList; StringW LocalesManager::curSection; LocalesSkinCallback LocalesManager::localesSkinCallback; StringW LocalesManager::curTable; StringTableXmlCallback LocalesManager::stringTableXmlCallback; StringTableEntryXmlCallback LocalesManager::stringTableXmlEntryCallback;