intl.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,270 行 · 第 1/5 页
CPP
2,270 行
numStrings; // +08: number of strings in the file
size_t32 ofsOrigTable, // +0C: start of original string table
ofsTransTable; // +10: start of translated string table
size_t32 nHashSize, // +14: hash table size
ofsHashTable; // +18: offset of hash table start
};
// all data is stored here, NULL if no data loaded
size_t8 *m_pData;
// amount of memory pointed to by m_pData.
size_t32 m_nSize;
// data description
size_t32 m_numStrings; // number of strings in this domain
wxMsgTableEntry *m_pOrigTable, // pointer to original strings
*m_pTransTable; // translated
wxString m_charset;
// swap the 2 halves of 32 bit integer if needed
size_t32 Swap(size_t32 ui) const
{
return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) |
((ui >> 8) & 0xff00) | (ui >> 24)
: ui;
}
const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const
{
const wxMsgTableEntry * const ent = pTable + n;
// this check could fail for a corrupt message catalog
size_t32 ofsString = Swap(ent->ofsString);
if ( ofsString + Swap(ent->nLen) > m_nSize)
{
return NULL;
}
return (const char *)(m_pData + ofsString);
}
bool m_bSwapped; // wrong endianness?
DECLARE_NO_COPY_CLASS(wxMsgCatalogFile)
};
// ----------------------------------------------------------------------------
// wxMsgCatalog corresponds to one loaded message catalog.
//
// This is a "low-level" class and is used only by wxLocale (that's why
// it's designed to be stored in a linked list)
// ----------------------------------------------------------------------------
class wxMsgCatalog
{
public:
// load the catalog from disk (szDirPrefix corresponds to language)
bool Load(const wxChar *szDirPrefix, const wxChar *szName,
const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false);
// get name of the catalog
wxString GetName() const { return m_name; }
// get the translated string: returns NULL if not found
const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const;
// public variable pointing to the next element in a linked list (or NULL)
wxMsgCatalog *m_pNext;
private:
wxMessagesHash m_messages; // all messages in the catalog
wxString m_name; // name of the domain
wxPluralFormsCalculatorPtr m_pluralFormsCalculator;
};
// ----------------------------------------------------------------------------
// global variables
// ----------------------------------------------------------------------------
// the list of the directories to search for message catalog files
static wxArrayString s_searchPrefixes;
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxMsgCatalogFile class
// ----------------------------------------------------------------------------
wxMsgCatalogFile::wxMsgCatalogFile()
{
m_pData = NULL;
m_nSize = 0;
}
wxMsgCatalogFile::~wxMsgCatalogFile()
{
wxDELETEA(m_pData);
}
// return all directories to search for given prefix
static wxString GetAllMsgCatalogSubdirs(const wxChar *prefix,
const wxChar *lang)
{
wxString searchPath;
// search first in prefix/fr/LC_MESSAGES, then in prefix/fr and finally in
// prefix (assuming the language is 'fr')
searchPath << prefix << wxFILE_SEP_PATH << lang << wxFILE_SEP_PATH
<< wxT("LC_MESSAGES") << wxPATH_SEP
<< prefix << wxFILE_SEP_PATH << lang << wxPATH_SEP
<< prefix << wxPATH_SEP;
return searchPath;
}
// construct the search path for the given language
static wxString GetFullSearchPath(const wxChar *lang)
{
wxString searchPath;
// first take the entries explicitly added by the program
size_t count = s_searchPrefixes.Count();
for ( size_t n = 0; n < count; n++ )
{
searchPath << GetAllMsgCatalogSubdirs(s_searchPrefixes[n], lang)
<< wxPATH_SEP;
}
// TODO: use wxStandardPaths instead of all this mess!!
// LC_PATH is a standard env var containing the search path for the .mo
// files
#ifndef __WXWINCE__
const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH"));
if ( pszLcPath != NULL )
searchPath << GetAllMsgCatalogSubdirs(pszLcPath, lang);
#endif
#ifdef __UNIX__
// add some standard ones and the one in the tree where wxWin was installed:
searchPath
<< GetAllMsgCatalogSubdirs(wxString(wxGetInstallPrefix()) + wxT("/share/locale"), lang)
<< GetAllMsgCatalogSubdirs(wxT("/usr/share/locale"), lang)
<< GetAllMsgCatalogSubdirs(wxT("/usr/lib/locale"), lang)
<< GetAllMsgCatalogSubdirs(wxT("/usr/local/share/locale"), lang);
#endif // __UNIX__
// then take the current directory
// FIXME it should be the directory of the executable
#if defined(__WXMAC__)
searchPath << GetAllMsgCatalogSubdirs(wxGetCwd(), lang);
// generic search paths could be somewhere in the system folder preferences
#elif defined(__WXMSW__)
// look in the directory of the executable
wxString path;
wxSplitPath(wxGetFullModuleName(), &path, NULL, NULL);
searchPath << GetAllMsgCatalogSubdirs(path, lang);
#else // !Mac, !MSW
searchPath << GetAllMsgCatalogSubdirs(wxT("."), lang);
#endif // platform
return searchPath;
}
// open disk file and read in it's contents
bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName,
wxPluralFormsCalculatorPtr& rPluralFormsCalculator)
{
wxString searchPath;
#if wxUSE_FONTMAP
// first look for the catalog for this language and the current locale:
// notice that we don't use the system name for the locale as this would
// force us to install catalogs in different locations depending on the
// system but always use the canonical name
wxFontEncoding encSys = wxLocale::GetSystemEncoding();
if ( encSys != wxFONTENCODING_SYSTEM )
{
wxString fullname(szDirPrefix);
fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys);
searchPath << GetFullSearchPath(fullname) << wxPATH_SEP;
}
#endif // wxUSE_FONTMAP
searchPath += GetFullSearchPath(szDirPrefix);
const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_'));
if ( sublocale )
{
// also add just base locale name: for things like "fr_BE" (belgium
// french) we should use "fr" if no belgium specific message catalogs
// exist
searchPath << GetFullSearchPath(wxString(szDirPrefix).
Left((size_t)(sublocale - szDirPrefix)))
<< wxPATH_SEP;
}
// don't give translation errors here because the wxstd catalog might
// not yet be loaded (and it's normal)
//
// (we're using an object because we have several return paths)
NoTransErr noTransErr;
wxLogVerbose(_("looking for catalog '%s' in path '%s'."),
szName, searchPath.c_str());
wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""),
szName, searchPath.c_str());
wxFileName fn(szName);
fn.SetExt(_T("mo"));
wxString strFullName;
if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) {
wxLogVerbose(_("catalog file for domain '%s' not found."), szName);
wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName);
return false;
}
// open file
wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str());
wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str());
wxFile fileMsg(strFullName);
if ( !fileMsg.IsOpened() )
return false;
// get the file size (assume it is less than 4Gb...)
wxFileOffset nSize = fileMsg.Length();
if ( nSize == wxInvalidOffset )
return false;
// read the whole file in memory
m_pData = new size_t8[nSize];
if ( fileMsg.Read(m_pData, (size_t)nSize) != nSize ) {
wxDELETEA(m_pData);
return false;
}
// examine header
bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader);
wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData;
if ( bValid ) {
// we'll have to swap all the integers if it's true
m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW;
// check the magic number
bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC;
}
if ( !bValid ) {
// it's either too short or has incorrect magic number
wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str());
wxDELETEA(m_pData);
return false;
}
// initialize
m_numStrings = Swap(pHeader->numStrings);
m_pOrigTable = (wxMsgTableEntry *)(m_pData +
Swap(pHeader->ofsOrigTable));
m_pTransTable = (wxMsgTableEntry *)(m_pData +
Swap(pHeader->ofsTransTable));
m_nSize = (size_t32)nSize;
// now parse catalog's header and try to extract catalog charset and
// plural forms formula from it:
const char* headerData = StringAtOfs(m_pOrigTable, 0);
if (headerData && headerData[0] == 0)
{
// Extract the charset:
wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0));
int begin = header.Find(wxT("Content-Type: text/plain; charset="));
if (begin != wxNOT_FOUND)
{
begin += 34; //strlen("Content-Type: text/plain; charset=")
size_t end = header.find('\n', begin);
if (end != size_t(-1))
{
m_charset.assign(header, begin, end - begin);
if (m_charset == wxT("CHARSET"))
{
// "CHARSET" is not valid charset, but lazy translator
m_charset.Clear();
}
}
}
// else: incorrectly filled Content-Type header
// Extract plural forms:
begin = header.Find(wxT("Plural-Forms:"));
if (begin != wxNOT_FOUND)
{
begin += 13;
size_t end = header.find('\n', begin);
if (end != size_t(-1))
{
wxString pfs(header, begin, end - begin);
wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator
::make(pfs.ToAscii());
if (pCalculator != 0)
{
rPluralFormsCalculator.reset(pCalculator);
}
else
{
wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str());
}
}
}
if (rPluralFormsCalculator.get() == NULL)
{
rPluralFormsCalculator.reset(wxPluralFormsCalculator::make());
}
}
// everything is fine
return true;
}
void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
const wxString& msgIdCharset,
bool convertEncoding) const
{
#if wxUSE_FONTMAP
// determine if we need any conversion at all
if ( convertEncoding )
{
wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset);
if ( encCat == wxLocale::GetSystemEncoding() )
{
// no need to convert
convertEncoding = false;
}
}
#endif // wxUSE_FONTMAP
#if wxUSE_WCHAR_T
// conversion to use to convert catalog strings to the GUI encoding
wxMBConv *inputConv,
*csConv = NULL; // another ptr just to be able to delete it later
if ( convertEncoding )
{
if ( m_charset.empty() )
inputConv = wxConvCurrent;
else
inputConv =
csConv = new wxCSConv(m_charset);
}
else // no need to convert the encoding
{
// we still need the conversion for Unicode build
#if wxUSE_UNICODE
inputConv = wxConvCurrent;
#else // !wxUSE_UNICODE
inputConv = NULL;
#endif
}
// conversion to apply to msgid strings before looking them up: we only
// need it if the msgids are neither in 7 bit ASCII nor in the same
// encoding as the catalog
wxCSConv *sourceConv = msgIdCharset.empty() || (msgIdCharset == m_charset)
? NULL
: new wxCSConv(msgIdCharset);
#elif wxUSE_FONTMAP
wxASSERT_MSG( msgIdCharset == NULL,
_T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") );
wxEncodingConverter converter;
if ( convertEncoding )
{
wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM;
wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(m_charset, false);
if ( enc == wxFONTENCODING_SYSTEM )
{
convertEncoding = false; // unknown encoding
}
else
{
targetEnc = wxLocale::GetSystemEncoding();
if (targetEnc == wxFONTENCODING_SYSTEM)
{
wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc);
if (a[0] == enc)
// no conversion needed, locale uses native encoding
convertEncoding = false;
if (a.GetCount() == 0)
// we don't know common equiv. under this platform
convertEncoding = false;
targetEnc = a[0];
}
}
if ( convertEncoding )
{
converter.Init(enc, targetEnc);
}
}
#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
(void)convertEncoding; // get rid of warnings about unused parameter
for (size_t32 i = 0; i < m_numStrings; i++)
{
const char *data = StringAtOfs(m_pOrigTable, i);
#if wxUSE_UNICODE
wxString msgid(data, *inputConv);
#else // ASCII
wxString msgid;
#if wxUSE_WCHAR_T
if ( inputConv && sourceConv )
msgid = wxString(inputConv->cMB2WC(data), *sourceConv);
else
#endif
msgid = data;
#endif // wxUSE_UNICODE
data = StringAtOfs(m_pTransTable, i);
size_t length = Swap(m_pTransTable[i].nLen);
size_t offset = 0;
size_t index = 0;
while (offset < length)
{
wxString msgstr;
#if wxUSE_WCHAR_T
#if wxUSE_UNICODE
msgstr = wxString(data + offset, *inputConv);
#else
if ( inputConv )
msgstr = wxString(inputConv->cMB2WC(data + offset), wxConvLocal);
else
msgstr = wxString(data + offset);
#endif
#else // !wxUSE_WCHAR_T
#if wxUSE_FONTMAP
if ( convertEncoding )
msgstr = wxString(converter.Convert(data + offset));
else
#endif
msgstr = wxString(data + offset);
#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T
if ( !msgstr.empty() )
{
hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr;
}
offset += strlen(data + offset) + 1;
++index;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?