650 lines
19 KiB
C++
650 lines
19 KiB
C++
// LanguagesDlg.cpp : implementation file
|
|
|
|
#define CO_EXIST_WITH_MFC
|
|
#include "global.h"
|
|
#include "stdafx.h"
|
|
#include "smpackage.h"
|
|
#include "Foreach.h"
|
|
#include "LanguagesDlg.h"
|
|
#include "SpecialFiles.h"
|
|
#include "RageUtil.h"
|
|
#include "IniFile.h"
|
|
#include "languagesdlg.h"
|
|
#include "SMPackageUtil.h"
|
|
#include "CreateLanguageDlg.h"
|
|
#include "RageFile.h"
|
|
#include "languagesdlg.h"
|
|
#include "RageFileManager.h"
|
|
#include ".\languagesdlg.h"
|
|
#include "CsvFile.h"
|
|
#include "archutils/Win32/DialogUtil.h"
|
|
#include "LocalizedString.h"
|
|
#include "arch/Dialog/Dialog.h"
|
|
#include "archutils/Win32/SpecialDirs.h"
|
|
#include "archutils/Win32/GotoURL.h"
|
|
#include "archutils/Win32/ErrorStrings.h"
|
|
|
|
// LanguagesDlg dialog
|
|
|
|
IMPLEMENT_DYNAMIC(LanguagesDlg, CDialog)
|
|
LanguagesDlg::LanguagesDlg(CWnd* pParent /*=NULL*/)
|
|
: CDialog(LanguagesDlg::IDD, pParent)
|
|
{
|
|
}
|
|
|
|
LanguagesDlg::~LanguagesDlg()
|
|
{
|
|
}
|
|
|
|
void LanguagesDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
DDX_Control(pDX, IDC_LIST_THEMES, m_listThemes);
|
|
DDX_Control(pDX, IDC_LIST_LANGUAGES, m_listLanguages);
|
|
DDX_Control(pDX, IDC_CHECK_EXPORT_ALREADY_TRANSLATED, m_buttonExportAlreadyTranslated);
|
|
}
|
|
|
|
BOOL LanguagesDlg::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
DialogUtil::LocalizeDialogAndContents( *this );
|
|
|
|
vector<RString> vs;
|
|
GetDirListing( SpecialFiles::THEMES_DIR+"*", vs, true );
|
|
StripCvsAndSvn( vs );
|
|
FOREACH_CONST( RString, vs, s )
|
|
m_listThemes.AddString( *s );
|
|
if( !vs.empty() )
|
|
m_listThemes.SetSel( 0 );
|
|
|
|
OnSelchangeListThemes();
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
}
|
|
|
|
static RString GetCurrentString( const CListBox &list )
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
int iSel = list.GetCurSel();
|
|
if( iSel == LB_ERR )
|
|
return RString();
|
|
CString s;
|
|
list.GetText( list.GetCurSel(), s );
|
|
return RString( s );
|
|
}
|
|
|
|
static void SelectString( CListBox &list, const RString &sToSelect )
|
|
{
|
|
for( int i=0; i<list.GetCount(); i++ )
|
|
{
|
|
CString s;
|
|
list.GetText( i, s );
|
|
if( s == sToSelect )
|
|
{
|
|
list.SetCurSel( i );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LanguagesDlg::OnSelchangeListThemes()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
m_listLanguages.ResetContent();
|
|
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
if( !sTheme.empty() )
|
|
{
|
|
RString sLanguagesDir = SpecialFiles::THEMES_DIR + sTheme + "/" + SpecialFiles::LANGUAGES_SUBDIR;
|
|
|
|
vector<RString> vs;
|
|
GetDirListing( sLanguagesDir+"*.ini", vs, false );
|
|
FOREACH_CONST( RString, vs, s )
|
|
{
|
|
RString sIsoCode = GetFileNameWithoutExtension(*s);
|
|
RString sLanguage = SMPackageUtil::GetLanguageDisplayString(sIsoCode);
|
|
m_listLanguages.AddString( ConvertUTF8ToACP(sLanguage) );
|
|
}
|
|
if( !vs.empty() )
|
|
m_listLanguages.SetSel( 0 );
|
|
}
|
|
|
|
OnSelchangeListLanguages();
|
|
}
|
|
|
|
static RString GetLanguageFile( const RString &sTheme, const RString &sLanguage )
|
|
{
|
|
return SpecialFiles::THEMES_DIR + sTheme + "/" + SpecialFiles::LANGUAGES_SUBDIR + sLanguage + ".ini";
|
|
}
|
|
|
|
static int GetNumValuesInIniFile( const RString &sIniFile )
|
|
{
|
|
int count = 0;
|
|
IniFile ini;
|
|
ini.ReadFile( sIniFile );
|
|
FOREACH_CONST_Child( &ini, key )
|
|
{
|
|
FOREACH_CONST_Attr( key, value )
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int GetNumIntersectingIniValues( const RString &sIniFile1, const RString &sIniFile2 )
|
|
{
|
|
int count = 0;
|
|
IniFile ini1;
|
|
ini1.ReadFile( sIniFile1 );
|
|
IniFile ini2;
|
|
ini2.ReadFile( sIniFile2 );
|
|
FOREACH_CONST_Child( &ini1, key1 )
|
|
{
|
|
const XNode *key2 = ini2.GetChild( key1->m_sName );
|
|
if( key2 == NULL )
|
|
continue;
|
|
FOREACH_CONST_Attr( key1, attr1 )
|
|
{
|
|
if( key2->GetAttr(attr1->first) == NULL)
|
|
continue;
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void LanguagesDlg::OnSelchangeListLanguages()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
int iTotalStrings = -1;
|
|
int iNeedTranslation = -1;
|
|
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
RString sLanguage = GetCurrentString( m_listLanguages );
|
|
|
|
if( !sTheme.empty() )
|
|
{
|
|
RString sBaseLanguageFile = GetLanguageFile( sTheme, SpecialFiles::BASE_LANGUAGE );
|
|
iTotalStrings = GetNumValuesInIniFile( sBaseLanguageFile );
|
|
|
|
if( !sLanguage.empty() )
|
|
{
|
|
sLanguage = SMPackageUtil::GetLanguageCodeFromDisplayString( sLanguage );
|
|
|
|
RString sLanguageFile = GetLanguageFile( sTheme, sLanguage );
|
|
iNeedTranslation = iTotalStrings - GetNumIntersectingIniValues( sBaseLanguageFile, sLanguageFile );
|
|
}
|
|
}
|
|
|
|
GetDlgItem(IDC_STATIC_TOTAL_STRINGS )->SetWindowText( ssprintf(iTotalStrings==-1?"":"%d",iTotalStrings) );
|
|
GetDlgItem(IDC_STATIC_NEED_TRANSLATION )->SetWindowText( ssprintf(iNeedTranslation==-1?"":"%d",iNeedTranslation) );
|
|
|
|
GetDlgItem(IDC_BUTTON_CREATE)->EnableWindow( !sTheme.empty() );
|
|
GetDlgItem(IDC_BUTTON_DELETE)->EnableWindow( !sLanguage.empty() );
|
|
GetDlgItem(IDC_BUTTON_EXPORT)->EnableWindow( !sLanguage.empty() );
|
|
GetDlgItem(IDC_BUTTON_IMPORT)->EnableWindow( !sLanguage.empty() );
|
|
GetDlgItem(IDC_CHECK_LANGUAGE)->EnableWindow( !sLanguage.empty() );
|
|
GetDlgItem(IDC_CHECK_EXPORT_ALREADY_TRANSLATED)->EnableWindow( !sLanguage.empty() );
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(LanguagesDlg, CDialog)
|
|
ON_LBN_SELCHANGE(IDC_LIST_THEMES, OnSelchangeListThemes)
|
|
ON_LBN_SELCHANGE(IDC_LIST_LANGUAGES, OnSelchangeListLanguages)
|
|
ON_BN_CLICKED(IDC_BUTTON_CREATE, OnBnClickedButtonCreate)
|
|
ON_BN_CLICKED(IDC_BUTTON_DELETE, OnBnClickedButtonDelete)
|
|
ON_BN_CLICKED(IDC_BUTTON_EXPORT, OnBnClickedButtonExport)
|
|
ON_BN_CLICKED(IDC_BUTTON_IMPORT, OnBnClickedButtonImport)
|
|
ON_BN_CLICKED(IDC_CHECK_LANGUAGE, OnBnClickedCheckLanguage)
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
// LanguagesDlg message handlers
|
|
|
|
void LanguagesDlg::OnBnClickedButtonCreate()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
CreateLanguageDlg dlg;
|
|
int nResponse = dlg.DoModal();
|
|
if( nResponse != IDOK )
|
|
return;
|
|
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
ASSERT( !sTheme.empty() );
|
|
|
|
RString sLanguageFile = GetLanguageFile( sTheme, RString(dlg.m_sChosenLanguageCode) );
|
|
|
|
// create empty file
|
|
RageFile file;
|
|
file.Open( sLanguageFile, RageFile::WRITE );
|
|
file.Close(); // flush file
|
|
|
|
OnSelchangeListThemes();
|
|
SelectString( m_listLanguages, SMPackageUtil::GetLanguageDisplayString(RString(dlg.m_sChosenLanguageCode)) );
|
|
OnSelchangeListLanguages();
|
|
}
|
|
|
|
static LocalizedString THIS_WILL_PERMANENTLY_DELETE( "LanguagesDlg", "This will permanently delete '%s'. Continue?" );
|
|
void LanguagesDlg::OnBnClickedButtonDelete()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
ASSERT( !sTheme.empty() );
|
|
RString sLanguage = GetCurrentString( m_listLanguages );
|
|
ASSERT( !sLanguage.empty() );
|
|
sLanguage = SMPackageUtil::GetLanguageCodeFromDisplayString( sLanguage );
|
|
|
|
RString sLanguageFile = GetLanguageFile( sTheme, sLanguage );
|
|
|
|
RString sMessage = ssprintf(THIS_WILL_PERMANENTLY_DELETE.GetValue(),sLanguageFile.c_str());
|
|
Dialog::Result ret = Dialog::AbortRetry( sMessage );
|
|
if( ret != Dialog::retry )
|
|
return;
|
|
|
|
FILEMAN->Remove( sLanguageFile );
|
|
|
|
OnSelchangeListThemes();
|
|
}
|
|
|
|
struct TranslationLine
|
|
{
|
|
RString sSection, sID, sBaseLanguage, sCurrentLanguage;
|
|
};
|
|
|
|
static LocalizedString FAILED_TO_SAVE ( "LanguagesDlg", "Failed to save '%s'." );
|
|
static LocalizedString THERE_ARE_NO_STRINGS_TO_EXPORT ( "LanguagesDlg", "There are no strings to export for this language." );
|
|
static LocalizedString EXPORTED_TO_YOUR_DESKTOP ( "LanguagesDlg", "Exported to your Desktop as '%s'." );
|
|
void LanguagesDlg::OnBnClickedButtonExport()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
ASSERT( !sTheme.empty() );
|
|
RString sLanguage = GetCurrentString( m_listLanguages );
|
|
ASSERT( !sLanguage.empty() );
|
|
sLanguage = SMPackageUtil::GetLanguageCodeFromDisplayString( sLanguage );
|
|
|
|
RString sBaseLanguageFile = GetLanguageFile( sTheme, SpecialFiles::BASE_LANGUAGE );
|
|
RString sLanguageFile = GetLanguageFile( sTheme, sLanguage );
|
|
|
|
bool bExportAlreadyTranslated = !!m_buttonExportAlreadyTranslated.GetCheck();
|
|
|
|
CsvFile csv;
|
|
IniFile ini1;
|
|
ini1.ReadFile( sBaseLanguageFile );
|
|
IniFile ini2;
|
|
ini2.ReadFile( sLanguageFile );
|
|
int iNumExpored = 0;
|
|
|
|
vector<RString> vs;
|
|
vs.push_back( "Section" );
|
|
vs.push_back( "ID" );
|
|
vs.push_back( "Base Language Value" );
|
|
vs.push_back( "Localized Value" );
|
|
csv.m_vvs.push_back( vs );
|
|
|
|
FOREACH_CONST_Child( &ini1, key )
|
|
{
|
|
FOREACH_CONST_Attr( key, value )
|
|
{
|
|
TranslationLine tl;
|
|
tl.sSection = key->m_sName;
|
|
tl.sID = value->first;
|
|
tl.sBaseLanguage = value->second->GetValue<RString>();
|
|
ini2.GetValue( tl.sSection, tl.sID, tl.sCurrentLanguage );
|
|
|
|
// don't export empty strings
|
|
RString sBaseLanguageTrimmed = tl.sBaseLanguage;
|
|
TrimLeft( sBaseLanguageTrimmed, " " );
|
|
TrimRight( sBaseLanguageTrimmed, " " );
|
|
if( sBaseLanguageTrimmed.empty() )
|
|
continue;
|
|
|
|
bool bAlreadyTranslated = !tl.sCurrentLanguage.empty();
|
|
if( !bAlreadyTranslated || bExportAlreadyTranslated )
|
|
{
|
|
vector<RString> vs;
|
|
vs.push_back( tl.sSection );
|
|
vs.push_back( tl.sID );
|
|
vs.push_back( tl.sBaseLanguage );
|
|
vs.push_back( tl.sCurrentLanguage );
|
|
csv.m_vvs.push_back( vs );
|
|
iNumExpored++;
|
|
}
|
|
}
|
|
}
|
|
|
|
RageFileOsAbsolute file;
|
|
RString sFile = sTheme+"-"+sLanguage+".csv";
|
|
RString sFullFile = SpecialDirs::GetDesktopDir() + sFile;
|
|
file.Open( sFullFile, RageFile::WRITE );
|
|
if( iNumExpored == 0 )
|
|
{
|
|
Dialog::OK( THERE_ARE_NO_STRINGS_TO_EXPORT.GetValue() );
|
|
return;
|
|
}
|
|
|
|
if( csv.WriteFile(file) )
|
|
Dialog::OK( ssprintf(EXPORTED_TO_YOUR_DESKTOP.GetValue(),sFile.c_str()) );
|
|
else
|
|
Dialog::OK( ssprintf(FAILED_TO_SAVE.GetValue(),sFullFile.c_str()) );
|
|
}
|
|
|
|
static LocalizedString ERROR_READING_FILE ( "LanguagesDlg", "Error reading file '%s'." );
|
|
static LocalizedString ERROR_PARSING_FILE ( "LanguagesDlg", "Error parsing file '%s'." );
|
|
static LocalizedString IMPORTING_THESE_STRINGS_WILL_OVERRIDE ( "LanguagesDlg", "Importing these strings will override all data in '%s'. Continue?" );
|
|
static LocalizedString ERROR_READING ( "LanguagesDlg", "Error reading '%s'." );
|
|
static LocalizedString ERROR_READING_EACH_LINE_MUST_HAVE ( "LanguagesDlg", "Error reading line '%s' from '%s': Each line must have either 3 or 4 values. This row has %d values." );
|
|
static LocalizedString IMPORTED_STRINGS_INTO ( "LanguagesDlg", "Imported %d strings into '%s'.\n - %d were added.\n - %d were modified\n - %d were unchanged\n - %d empty strings were ignored" );
|
|
void LanguagesDlg::OnBnClickedButtonImport()
|
|
{
|
|
// TODO: Add your control notification handler code here
|
|
CFileDialog dialog (
|
|
TRUE, // file open?
|
|
NULL, // default file extension
|
|
NULL, // default file name
|
|
OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // flags
|
|
"CSV file (*.csv)|*.csv|||"
|
|
);
|
|
int iRet = dialog.DoModal();
|
|
RString sCsvFile = dialog.GetPathName();
|
|
if( iRet != IDOK )
|
|
return;
|
|
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
ASSERT( !sTheme.empty() );
|
|
RString sLanguage = GetCurrentString( m_listLanguages );
|
|
ASSERT( !sLanguage.empty() );
|
|
sLanguage = SMPackageUtil::GetLanguageCodeFromDisplayString( sLanguage );
|
|
|
|
RageFileOsAbsolute cvsFile;
|
|
if( !cvsFile.Open(sCsvFile) )
|
|
{
|
|
Dialog::OK( ssprintf(ERROR_READING_FILE.GetValue(),sCsvFile.c_str()) );
|
|
return;
|
|
}
|
|
CsvFile csv;
|
|
if( !csv.ReadFile(cvsFile) )
|
|
{
|
|
Dialog::OK( ssprintf(ERROR_PARSING_FILE.GetValue(),sCsvFile.c_str()) );
|
|
return;
|
|
}
|
|
|
|
RString sLanguageFile = GetLanguageFile( sTheme, sLanguage );
|
|
|
|
{
|
|
Dialog::Result ret = Dialog::AbortRetry( ssprintf(IMPORTING_THESE_STRINGS_WILL_OVERRIDE.GetValue(),sLanguageFile.c_str()) );
|
|
if( ret != Dialog::retry )
|
|
return;
|
|
}
|
|
|
|
IniFile ini;
|
|
if( !ini.ReadFile(sLanguageFile) )
|
|
{
|
|
Dialog::OK( ssprintf(ERROR_READING.GetValue(),sLanguageFile.c_str()) );
|
|
return;
|
|
}
|
|
|
|
int iNumImported = 0;
|
|
int iNumAdded = 0;
|
|
int iNumModified = 0;
|
|
int iNumUnchanged = 0;
|
|
int iNumIgnored = 0;
|
|
FOREACH_CONST( CsvFile::StringVector, csv.m_vvs, line )
|
|
{
|
|
int iLineIndex = line - csv.m_vvs.begin();
|
|
|
|
// Skip the header row
|
|
if( iLineIndex == 0 )
|
|
continue;
|
|
|
|
TranslationLine tl;
|
|
int iNumValues = line->size();
|
|
if( iNumValues != 3 && iNumValues != 4 )
|
|
{
|
|
Dialog::OK( ssprintf(ERROR_READING_EACH_LINE_MUST_HAVE.GetValue(),
|
|
join(",",*line).c_str(),
|
|
sCsvFile.c_str(),
|
|
iNumValues) );
|
|
return;
|
|
}
|
|
tl.sSection = (*line)[0];
|
|
tl.sID = (*line)[1];
|
|
tl.sBaseLanguage = (*line)[2];
|
|
tl.sCurrentLanguage = iNumValues == 4 ? (*line)[3] : RString();
|
|
|
|
if( tl.sCurrentLanguage.empty() )
|
|
{
|
|
iNumIgnored++;
|
|
}
|
|
else
|
|
{
|
|
RString sOldCurrentLanguage;
|
|
bool bExists = ini.GetValue( tl.sSection, tl.sID, sOldCurrentLanguage );
|
|
if( bExists )
|
|
{
|
|
if( sOldCurrentLanguage == tl.sCurrentLanguage )
|
|
iNumUnchanged++;
|
|
else
|
|
iNumModified++;
|
|
}
|
|
else
|
|
{
|
|
iNumAdded++;
|
|
}
|
|
|
|
ini.SetValue( tl.sSection, tl.sID, tl.sCurrentLanguage );
|
|
iNumImported++;
|
|
}
|
|
}
|
|
|
|
if( ini.WriteFile(sLanguageFile) )
|
|
Dialog::OK( ssprintf(IMPORTED_STRINGS_INTO.GetValue(),iNumImported,sLanguageFile.c_str(),iNumAdded,iNumModified,iNumUnchanged,iNumIgnored) );
|
|
else
|
|
Dialog::OK( ssprintf(FAILED_TO_SAVE.GetValue(),sLanguageFile.c_str()) );
|
|
|
|
OnSelchangeListThemes();
|
|
}
|
|
|
|
void GetAllMatches( const RString &sRegex, const RString &sString, vector<RString> &asOut )
|
|
{
|
|
Regex re( sRegex + "(.*)$");
|
|
RString sMatch( sString );
|
|
while(1)
|
|
{
|
|
vector<RString> asMatches;
|
|
if( !re.Compare(sMatch, asMatches) )
|
|
break;
|
|
asOut.push_back( asMatches[0] );
|
|
sMatch = asMatches[1];
|
|
}
|
|
}
|
|
|
|
void DumpList( const vector<RString> &asList, RageFile &file )
|
|
{
|
|
RString sLine;
|
|
FOREACH_CONST( RString, asList, s )
|
|
{
|
|
if( sLine.size() + s->size() > 100 )
|
|
{
|
|
file.PutLine( sLine );
|
|
sLine = "";
|
|
}
|
|
|
|
if( sLine.size() )
|
|
sLine += ", ";
|
|
else
|
|
sLine += " ";
|
|
|
|
sLine += *s;
|
|
}
|
|
|
|
file.PutLine( sLine );
|
|
}
|
|
|
|
void LanguagesDlg::OnBnClickedCheckLanguage()
|
|
{
|
|
RString sTheme = GetCurrentString( m_listThemes );
|
|
ASSERT( !sTheme.empty() );
|
|
RString sLanguage = GetCurrentString( m_listLanguages );
|
|
ASSERT( !sLanguage.empty() );
|
|
sLanguage = SMPackageUtil::GetLanguageCodeFromDisplayString( sLanguage );
|
|
|
|
RString sBaseLanguageFile = GetLanguageFile( sTheme, SpecialFiles::BASE_LANGUAGE );
|
|
RString sLanguageFile = GetLanguageFile( sTheme, sLanguage );
|
|
|
|
IniFile ini1;
|
|
ini1.ReadFile( sBaseLanguageFile );
|
|
IniFile ini2;
|
|
ini2.ReadFile( sLanguageFile );
|
|
|
|
RageFileOsAbsolute file;
|
|
RString sFile = sTheme+"-"+sLanguage+" check.txt";
|
|
RString sFullFile = SpecialDirs::GetDesktopDir() + sFile;
|
|
file.Open( sFullFile, RageFile::WRITE );
|
|
|
|
{
|
|
FOREACH_CONST_Child( &ini1, key )
|
|
{
|
|
FOREACH_CONST_Attr( key, value )
|
|
{
|
|
const RString &sSection = key->m_sName;
|
|
const RString &sID = value->first;
|
|
const RString &sBaseLanguage = value->second->GetValue<RString>();
|
|
RString sCurrentLanguage;
|
|
ini2.GetValue( sSection, sID, sCurrentLanguage );
|
|
|
|
if( sCurrentLanguage.empty() )
|
|
continue;
|
|
|
|
/* Check &FOO;, %{foo}, %-1.2f, %. Some mismatches here are normal, particularly in
|
|
* languages with substantially different word order rules than English. */
|
|
{
|
|
RString sRegex = "(&[A-Za-z]+;|%{[A-Za-z]+}|%[+-]?[0-9]*.?[0-9]*[sidf]|%)";
|
|
vector<RString> asMatchesBase;
|
|
GetAllMatches( sRegex, sBaseLanguage, asMatchesBase );
|
|
|
|
vector<RString> asMatches;
|
|
GetAllMatches( sRegex, sCurrentLanguage, asMatches );
|
|
|
|
if( asMatchesBase.size() != asMatches.size() ||
|
|
!std::equal(asMatchesBase.begin(), asMatchesBase.end(), asMatches.begin()) )
|
|
{
|
|
file.PutLine( ssprintf("Entity/substitution mismatch in section [%s] (%s):", sSection.c_str(), sID.c_str()) );
|
|
file.PutLine( ssprintf(" %s", sCurrentLanguage.c_str()) );
|
|
file.PutLine( ssprintf(" %s", sBaseLanguage.c_str()) );
|
|
}
|
|
}
|
|
|
|
/* Check "foo::bar", "foo\nbar" and double quotes. Check these independently
|
|
* of the above. */
|
|
{
|
|
RString sRegex = "(\"|::|\\n)";
|
|
vector<RString> asMatchesBase;
|
|
GetAllMatches( sRegex, sBaseLanguage, asMatchesBase );
|
|
|
|
vector<RString> asMatches;
|
|
GetAllMatches( sRegex, sCurrentLanguage, asMatches );
|
|
|
|
if( asMatchesBase.size() != asMatches.size() ||
|
|
!std::equal(asMatchesBase.begin(), asMatchesBase.end(), asMatches.begin()) )
|
|
{
|
|
file.PutLine( ssprintf("Quote/line break mismatch in section [%s] (%s):", sSection.c_str(), sID.c_str()) );
|
|
file.PutLine( ssprintf(" %s", sCurrentLanguage.c_str()) );
|
|
file.PutLine( ssprintf(" %s", sBaseLanguage.c_str()) );
|
|
}
|
|
}
|
|
|
|
/* Check that both end in a period or both don't end an a period. */
|
|
{
|
|
RString sBaseLanguage2 = sBaseLanguage;
|
|
TrimRight( sBaseLanguage2, " " );
|
|
RString sCurrentLanguage2 = sCurrentLanguage;
|
|
TrimRight( sCurrentLanguage2, " " );
|
|
|
|
if( (sBaseLanguage2.Right(1) == ".") ^ (sCurrentLanguage2.Right(1) == ".") )
|
|
{
|
|
file.PutLine( ssprintf("Period mismatch in section [%s] (%s):", sSection.c_str(), sID.c_str()) );
|
|
file.PutLine( ssprintf(" %s", sCurrentLanguage.c_str()) );
|
|
file.PutLine( ssprintf(" %s", sBaseLanguage.c_str()) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
FOREACH_CONST_Child( &ini2, key )
|
|
{
|
|
FOREACH_CONST_Attr( key, value )
|
|
{
|
|
const RString &sSection = key->m_sName;
|
|
const RString &sID = value->first;
|
|
const RString &sCurrentLanguage = value->second->GetValue<RString>();
|
|
if( utf8_is_valid(sCurrentLanguage) )
|
|
continue;
|
|
|
|
/* The text isn't valid UTF-8. We don't know what encoding it is; guess that it's
|
|
* ISO-8859-1 and convert it so it'll display correctly and can be pasted into
|
|
* the file. Don't include the original text: if we include multiple encodings
|
|
* in the resulting text file, editors won't understand the encoding of the
|
|
* file and will pick one arbitrarily. */
|
|
file.PutLine( ssprintf("Incorrect encoding in section [%s]:", sSection.c_str()) );
|
|
wstring wsConverted = ConvertCodepageToWString( sCurrentLanguage, 1252 );
|
|
RString sConverted = WStringToRString( wsConverted );
|
|
file.PutLine( ssprintf("%s=%s", sID.c_str(), sConverted.c_str()) );
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
FOREACH_CONST_Child( &ini2, key )
|
|
{
|
|
vector<RString> asList;
|
|
const RString &sSection = key->m_sName;
|
|
FOREACH_CONST_Attr( key, value )
|
|
{
|
|
const RString &sID = value->first;
|
|
RString sCurrentLanguage;
|
|
if( ini1.GetValue(sSection, sID, sCurrentLanguage) )
|
|
continue;
|
|
|
|
asList.push_back( sID );
|
|
}
|
|
if( !asList.empty() )
|
|
{
|
|
file.PutLine( ssprintf("Obsolete translation in section [%s]:", sSection.c_str()) );
|
|
DumpList( asList, file );
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
FOREACH_CONST_Child( &ini1, key )
|
|
{
|
|
vector<RString> asList;
|
|
const RString &sSection = key->m_sName;
|
|
FOREACH_CONST_Attr( key, value )
|
|
{
|
|
const RString &sID = value->first;
|
|
const RString &sBaseText = value->second->GetValue<RString>();
|
|
if( sBaseText.empty() )
|
|
continue;
|
|
RString sCurrentLanguage;
|
|
if( ini2.GetValue(sSection, sID, sCurrentLanguage) )
|
|
continue;
|
|
|
|
asList.push_back( sID );
|
|
}
|
|
if( !asList.empty() )
|
|
{
|
|
file.PutLine( ssprintf("Not translated in section [%s]:", sSection.c_str()) );
|
|
DumpList( asList, file );
|
|
}
|
|
}
|
|
}
|
|
|
|
file.Close();
|
|
|
|
GotoURL( ssprintf("file://%s", sFullFile.c_str()) );
|
|
}
|