change Translation.dat -> Translations.xml
Move GroupName translations out of code and into Translations.xml
This commit is contained in:
@@ -246,7 +246,7 @@ bool CourseLoaderCRS::LoadFromMsd( const CString &sPath, const MsdFile &msd, Cou
|
|||||||
LOG->Warn( "Unexpected value named '%s'", sValueName.c_str() );
|
LOG->Warn( "Unexpected value named '%s'", sValueName.c_str() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static TitleSubst tsub("courses");
|
static TitleSubst tsub("Courses");
|
||||||
|
|
||||||
TitleFields title;
|
TitleFields title;
|
||||||
title.Title = out.m_sMainTitle;
|
title.Title = out.m_sMainTitle;
|
||||||
|
|||||||
@@ -930,6 +930,27 @@ bool Regex::Compare(const CString &str, vector<CString> &matches)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Arguments and behavior are the same are similar to
|
||||||
|
// http://us3.php.net/manual/en/function.preg-replace.php
|
||||||
|
bool Regex::Replace(const CString &replacement, const CString &subject, CString &out)
|
||||||
|
{
|
||||||
|
vector<CString> matches;
|
||||||
|
if( !Compare(subject,matches) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out = replacement;
|
||||||
|
|
||||||
|
// TODO: optimize me by iterating only once over the string
|
||||||
|
for( int i=0; i<matches.size(); i++ )
|
||||||
|
{
|
||||||
|
CString sFrom = ssprintf( "\\${%d}", i );
|
||||||
|
CString sTo = matches[i];
|
||||||
|
out.Replace(sFrom, sTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -344,9 +344,11 @@ public:
|
|||||||
Regex(const Regex &rhs);
|
Regex(const Regex &rhs);
|
||||||
Regex &operator=(const Regex &rhs);
|
Regex &operator=(const Regex &rhs);
|
||||||
~Regex();
|
~Regex();
|
||||||
|
bool IsSet() const { return !pattern.empty(); }
|
||||||
void Set(const CString &str);
|
void Set(const CString &str);
|
||||||
bool Compare(const CString &str);
|
bool Compare(const CString &str);
|
||||||
bool Compare(const CString &str, vector<CString> &matches);
|
bool Compare(const CString &str, vector<CString> &matches);
|
||||||
|
bool Replace(const CString &replacement, const CString &subject, CString &out);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -769,7 +769,7 @@ void Song::TidyUpData()
|
|||||||
|
|
||||||
void Song::TranslateTitles()
|
void Song::TranslateTitles()
|
||||||
{
|
{
|
||||||
static TitleSubst tsub("songs");
|
static TitleSubst tsub("Songs");
|
||||||
|
|
||||||
TitleFields title;
|
TitleFields title;
|
||||||
title.LoadFromStrings( m_sMainTitle, m_sSubTitle, m_sArtist, m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit );
|
title.LoadFromStrings( m_sMainTitle, m_sSubTitle, m_sArtist, m_sMainTitleTranslit, m_sSubTitleTranslit, m_sArtistTranslit );
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "BackgroundUtil.h"
|
#include "BackgroundUtil.h"
|
||||||
#include "Profile.h"
|
#include "Profile.h"
|
||||||
#include "CourseLoaderCRS.h"
|
#include "CourseLoaderCRS.h"
|
||||||
|
#include "TitleSubstitution.h"
|
||||||
|
|
||||||
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
|
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
|
||||||
|
|
||||||
@@ -475,32 +476,12 @@ int SongManager::GetNumEditCourses( ProfileSlot slot ) const
|
|||||||
|
|
||||||
CString SongManager::ShortenGroupName( CString sLongGroupName )
|
CString SongManager::ShortenGroupName( CString sLongGroupName )
|
||||||
{
|
{
|
||||||
sLongGroupName.Replace( "Dance Dance Revolution", "DDR" );
|
static TitleSubst tsub("Groups");
|
||||||
sLongGroupName.Replace( "dance dance revolution", "DDR" );
|
|
||||||
sLongGroupName.Replace( "DANCE DANCE REVOLUTION", "DDR" );
|
TitleFields title;
|
||||||
sLongGroupName.Replace( "Pump It Up", "PIU" );
|
title.Title = sLongGroupName;
|
||||||
sLongGroupName.Replace( "pump it up", "PIU" );
|
tsub.Subst( title );
|
||||||
sLongGroupName.Replace( "PUMP IT UP", "PIU" );
|
return title.Title;
|
||||||
sLongGroupName.Replace( "ParaParaParadise", "PPP" );
|
|
||||||
sLongGroupName.Replace( "paraparaparadise", "PPP" );
|
|
||||||
sLongGroupName.Replace( "PARAPARAPARADISE", "PPP" );
|
|
||||||
sLongGroupName.Replace( "Para Para Paradise", "PPP" );
|
|
||||||
sLongGroupName.Replace( "para para paradise", "PPP" );
|
|
||||||
sLongGroupName.Replace( "PARA PARA PARADISE", "PPP" );
|
|
||||||
sLongGroupName.Replace( "Dancing Stage", "DS" );
|
|
||||||
sLongGroupName.Replace( "dancing stage", "DS" );
|
|
||||||
sLongGroupName.Replace( "DANCING STAGE", "DS" );
|
|
||||||
sLongGroupName.Replace( "Ez2dancer", "EZ2" );
|
|
||||||
sLongGroupName.Replace( "Ez 2 Dancer", "EZ2");
|
|
||||||
sLongGroupName.Replace( "Technomotion", "TM");
|
|
||||||
sLongGroupName.Replace( "Techno Motion", "TM");
|
|
||||||
sLongGroupName.Replace( "Dance Station 3DDX", "3DDX");
|
|
||||||
sLongGroupName.Replace( "DS3DDX", "3DDX");
|
|
||||||
sLongGroupName.Replace( "BeatMania", "BM");
|
|
||||||
sLongGroupName.Replace( "Beatmania", "BM");
|
|
||||||
sLongGroupName.Replace( "BEATMANIA", "BM");
|
|
||||||
sLongGroupName.Replace( "beatmania", "BM");
|
|
||||||
return sLongGroupName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SongManager::GetNumStagesForSong( const Song* pSong )
|
int SongManager::GetNumStagesForSong( const Song* pSong )
|
||||||
|
|||||||
@@ -4,182 +4,155 @@
|
|||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
#include "RageLog.h"
|
#include "RageLog.h"
|
||||||
#include "FontCharAliases.h"
|
#include "FontCharAliases.h"
|
||||||
|
|
||||||
#include "RageFile.h"
|
#include "RageFile.h"
|
||||||
|
#include "Foreach.h"
|
||||||
|
#include "XmlFile.h"
|
||||||
|
|
||||||
#define TRANSLATION_PATH "Data/Translation.dat"
|
static const CString TRANSLATIONS_PATH = "Data/Translations.xml";
|
||||||
|
static const CString ERASE_MARKER = "-erase-";
|
||||||
|
|
||||||
struct TitleTrans
|
struct TitleTrans
|
||||||
{
|
{
|
||||||
Regex TitleFrom, SubFrom, ArtistFrom;
|
Regex TitleFrom, SubFrom, ArtistFrom;
|
||||||
TitleFields Dest;
|
TitleFields Replacement;
|
||||||
|
|
||||||
/* If this is true, no translit fields will be generated automatically. */
|
/* If this is true, no translit fields will be generated automatically. */
|
||||||
bool translit;
|
bool translit;
|
||||||
TitleTrans() { translit = true; }
|
TitleTrans() { translit = true; }
|
||||||
|
|
||||||
TitleTrans( const TitleFields &tf, bool translit_):
|
TitleTrans( const TitleFields &tf, bool translit_):
|
||||||
Dest(tf), translit(translit_) { }
|
Replacement(tf), translit(translit_) { }
|
||||||
|
|
||||||
bool Matches( const TitleFields &tf );
|
bool Matches( const TitleFields &tf, TitleFields &to );
|
||||||
|
|
||||||
|
void LoadFromNode( const XNode* pNode );
|
||||||
};
|
};
|
||||||
|
|
||||||
vector<TitleTrans> ttab;
|
vector<TitleTrans> ttab;
|
||||||
|
|
||||||
bool TitleTrans::Matches( const TitleFields &tf )
|
bool TitleTrans::Matches( const TitleFields &from, TitleFields &to )
|
||||||
{
|
{
|
||||||
if( !TitleFrom.Compare(tf.Title) )
|
if( !TitleFrom.Replace(Replacement.Title, from.Title, to.Title) )
|
||||||
return false; /* no match */
|
return false; /* no match */
|
||||||
if( !SubFrom.Compare(tf.Subtitle) )
|
if( !SubFrom.Replace(Replacement.Subtitle, from.Subtitle, to.Subtitle) )
|
||||||
return false; /* no match */
|
return false; /* no match */
|
||||||
if( !ArtistFrom.Compare(tf.Artist) )
|
if( !ArtistFrom.Replace(Replacement.Artist, from.Artist, to.Artist) )
|
||||||
return false; /* no match */
|
return false; /* no match */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TitleTrans::LoadFromNode( const XNode* pNode )
|
||||||
|
{
|
||||||
|
ASSERT( pNode->m_sName == "Translation" );
|
||||||
|
|
||||||
|
FOREACH_CONST_Attr( pNode, attr )
|
||||||
|
{
|
||||||
|
/* Surround each regex with ^(...)$, to force all comparisons to default
|
||||||
|
* to being a full-line match. (Add ".*" manually if this isn't wanted.) */
|
||||||
|
if( attr->m_sName == "DontTransliterate" ) translit = false;
|
||||||
|
else if( attr->m_sName == "TitleFrom" ) TitleFrom = "^(" + attr->m_sValue + ")$";
|
||||||
|
else if( attr->m_sName == "ArtistFrom" ) ArtistFrom = "^(" + attr->m_sValue + ")$";
|
||||||
|
else if( attr->m_sName == "SubtitleFrom") SubFrom = "^(" + attr->m_sValue + ")$";
|
||||||
|
else if( attr->m_sName == "TitleTo") Replacement.Title = attr->m_sValue;
|
||||||
|
else if( attr->m_sName == "ArtistTo") Replacement.Artist = attr->m_sValue;
|
||||||
|
else if( attr->m_sName == "SubtitleTo") Replacement.Subtitle = attr->m_sValue;
|
||||||
|
else if( attr->m_sName == "TitleTransTo") Replacement.TitleTranslit = attr->m_sValue;
|
||||||
|
else if( attr->m_sName == "ArtistTransTo") Replacement.ArtistTranslit = attr->m_sValue;
|
||||||
|
else if( attr->m_sName == "SubtitleTransTo") Replacement.SubtitleTranslit= attr->m_sValue;
|
||||||
|
else
|
||||||
|
LOG->Warn( "Unknown TitleSubst tag: \"%s\"", attr->m_sName.c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TitleSubst::AddTrans(const TitleTrans &tr)
|
void TitleSubst::AddTrans(const TitleTrans &tr)
|
||||||
{
|
{
|
||||||
|
ASSERT( tr.TitleFrom.IsSet() || tr.SubFrom.IsSet() || tr.ArtistFrom.IsSet() );
|
||||||
ttab.push_back(new TitleTrans(tr));
|
ttab.push_back(new TitleTrans(tr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleSubst::Subst( TitleFields &tf )
|
void TitleSubst::Subst( TitleFields &tf )
|
||||||
{
|
{
|
||||||
for(unsigned i = 0; i < ttab.size(); ++i)
|
FOREACH_CONST( TitleTrans*, ttab, iter )
|
||||||
{
|
{
|
||||||
if(!ttab[i]->Matches(tf))
|
TitleTrans* tt = *iter;
|
||||||
|
|
||||||
|
TitleFields to;
|
||||||
|
if(!tt->Matches(tf,to))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* The song matches. Replace whichever strings aren't empty. */
|
/* The song matches. Replace whichever strings aren't empty. */
|
||||||
if( !ttab[i]->Dest.Title.empty() && tf.Title != ttab[i]->Dest.Title )
|
if( !tt->Replacement.Title.empty() && tf.Title != tt->Replacement.Title )
|
||||||
{
|
{
|
||||||
if( ttab[i]->translit )
|
if( tt->translit )
|
||||||
tf.TitleTranslit = tf.Title;
|
tf.TitleTranslit = tf.Title;
|
||||||
tf.Title = (ttab[i]->Dest.Title != "-erase-")? ttab[i]->Dest.Title: CString("");
|
tf.Title = (tt->Replacement.Title != ERASE_MARKER)? to.Title : CString();
|
||||||
FontCharAliases::ReplaceMarkers( tf.Title );
|
FontCharAliases::ReplaceMarkers( tf.Title );
|
||||||
}
|
}
|
||||||
if( !ttab[i]->Dest.Subtitle.empty() && tf.Subtitle != ttab[i]->Dest.Subtitle )
|
if( !tt->Replacement.Subtitle.empty() && tf.Subtitle != tt->Replacement.Subtitle )
|
||||||
{
|
{
|
||||||
if( ttab[i]->translit )
|
if( tt->translit )
|
||||||
tf.SubtitleTranslit = tf.Subtitle;
|
tf.SubtitleTranslit = tf.Subtitle;
|
||||||
tf.Subtitle = (ttab[i]->Dest.Subtitle != "-erase-")? ttab[i]->Dest.Subtitle: CString("");
|
tf.Subtitle = (tt->Replacement.Subtitle != ERASE_MARKER)? to.Subtitle : CString();
|
||||||
FontCharAliases::ReplaceMarkers( tf.Subtitle );
|
FontCharAliases::ReplaceMarkers( tf.Subtitle );
|
||||||
}
|
}
|
||||||
if( !ttab[i]->Dest.Artist.empty() && tf.Artist != ttab[i]->Dest.Artist )
|
if( !tt->Replacement.Artist.empty() && tf.Artist != tt->Replacement.Artist )
|
||||||
{
|
{
|
||||||
if( ttab[i]->translit )
|
if( tt->translit )
|
||||||
tf.ArtistTranslit = tf.Artist;
|
tf.ArtistTranslit = tf.Artist;
|
||||||
tf.Artist = (ttab[i]->Dest.Artist != "-erase-")? ttab[i]->Dest.Artist: CString("");
|
tf.Artist = (tt->Replacement.Artist != ERASE_MARKER)? to.Artist : CString();
|
||||||
FontCharAliases::ReplaceMarkers( tf.Artist );
|
FontCharAliases::ReplaceMarkers( tf.Artist );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These are used when applying kanji to a field that doesn't have the
|
/* These are used when applying kanji to a field that doesn't have the
|
||||||
* correct data. Should be used sparingly. */
|
* correct data. Should be used sparingly. */
|
||||||
if( !ttab[i]->Dest.TitleTranslit.empty() )
|
if( !tt->Replacement.TitleTranslit.empty() )
|
||||||
{
|
{
|
||||||
tf.TitleTranslit = (ttab[i]->Dest.TitleTranslit != "-erase-")? ttab[i]->Dest.TitleTranslit: CString("");
|
tf.TitleTranslit = (tt->Replacement.TitleTranslit != ERASE_MARKER)? tt->Replacement.TitleTranslit : CString();
|
||||||
FontCharAliases::ReplaceMarkers( tf.TitleTranslit );
|
FontCharAliases::ReplaceMarkers( tf.TitleTranslit );
|
||||||
}
|
}
|
||||||
if( !ttab[i]->Dest.SubtitleTranslit.empty() )
|
if( !tt->Replacement.SubtitleTranslit.empty() )
|
||||||
{
|
{
|
||||||
tf.SubtitleTranslit = (ttab[i]->Dest.SubtitleTranslit != "-erase-")? ttab[i]->Dest.SubtitleTranslit: CString("");
|
tf.SubtitleTranslit = (tt->Replacement.SubtitleTranslit != ERASE_MARKER)? tt->Replacement.SubtitleTranslit : CString();
|
||||||
FontCharAliases::ReplaceMarkers( tf.SubtitleTranslit );
|
FontCharAliases::ReplaceMarkers( tf.SubtitleTranslit );
|
||||||
}
|
}
|
||||||
if( !ttab[i]->Dest.ArtistTranslit.empty() )
|
if( !tt->Replacement.ArtistTranslit.empty() )
|
||||||
{
|
{
|
||||||
tf.ArtistTranslit = (ttab[i]->Dest.ArtistTranslit != "-erase-")? ttab[i]->Dest.ArtistTranslit: CString("");
|
tf.ArtistTranslit = (tt->Replacement.ArtistTranslit != ERASE_MARKER)? tt->Replacement.ArtistTranslit : CString();
|
||||||
FontCharAliases::ReplaceMarkers( tf.ArtistTranslit );
|
FontCharAliases::ReplaceMarkers( tf.ArtistTranslit );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break; // Matched once. Done.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TitleSubst::TitleSubst(const CString §ion)
|
TitleSubst::TitleSubst(const CString §ion)
|
||||||
{
|
{
|
||||||
Load( TRANSLATION_PATH, section);
|
Load( TRANSLATIONS_PATH, section);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleSubst::Load(const CString &filename, const CString §ion)
|
void TitleSubst::Load(const CString &filename, const CString §ion)
|
||||||
{
|
{
|
||||||
RageFile f;
|
XNode xml;
|
||||||
if( !f.Open(filename) )
|
if( !xml.LoadFromFile(filename) )
|
||||||
{
|
{
|
||||||
LOG->Trace("Error opening %s: %s", filename.c_str(), f.GetError().c_str() );
|
// LoadFromFile will show its own error
|
||||||
|
//LOG->Trace("Error opening %s: %s", filename.c_str(), f.GetError().c_str() );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CString CurrentSection;
|
XNode *pGroup = xml.GetChild( section );
|
||||||
TitleTrans tr;
|
if( pGroup == NULL )
|
||||||
|
return;
|
||||||
while (!f.AtEOF())
|
FOREACH_Child( pGroup, child )
|
||||||
{
|
{
|
||||||
CString line;
|
if( child->m_sName != "Translation" )
|
||||||
int ret = f.GetLine( line );
|
|
||||||
if( ret == 0 )
|
|
||||||
break;
|
|
||||||
if( ret == -1 )
|
|
||||||
{
|
|
||||||
LOG->Trace("Error reading %s: %s", filename.c_str(), f.GetError().c_str() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(line.size() > 0 && utf8_get_char(line.c_str()) == 0xFEFF)
|
|
||||||
{
|
|
||||||
/* Annoying header that Windows puts on UTF-8 plaintext
|
|
||||||
* files; remove it. */
|
|
||||||
line.erase(0, utf8_get_char_len(line[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
TrimLeft(line);
|
|
||||||
TrimRight(line);
|
|
||||||
|
|
||||||
if(line.size() == 0) continue; /* blank */
|
|
||||||
if(line[0] == '#') continue; /* comment */
|
|
||||||
|
|
||||||
if(!line.CompareNoCase("DontTransliterate"))
|
|
||||||
{
|
|
||||||
tr.translit = false;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
size_t pos = line.find_first_of(':');
|
TitleTrans tr;
|
||||||
if(pos != string::npos)
|
tr.LoadFromNode( child );
|
||||||
{
|
AddTrans(tr);
|
||||||
/* x: y */
|
|
||||||
CString id = line.substr(0, pos);
|
|
||||||
CString txt = line.substr(pos+1);
|
|
||||||
TrimLeft(txt);
|
|
||||||
|
|
||||||
/* Surround each regex with ^(...)$, to force all comparisons to default
|
|
||||||
* to being a full-line match. (Add ".*" manually if this isn't wanted.) */
|
|
||||||
if(!id.CompareNoCase("TitleFrom")) tr.TitleFrom = "^(" + txt + ")$";
|
|
||||||
else if(!id.CompareNoCase("ArtistFrom")) tr.ArtistFrom = "^(" + txt + ")$";
|
|
||||||
else if(!id.CompareNoCase("SubtitleFrom")) tr.SubFrom = "^(" + txt + ")$";
|
|
||||||
else if(!id.CompareNoCase("TitleTo")) tr.Dest.Title = txt;
|
|
||||||
else if(!id.CompareNoCase("ArtistTo")) tr.Dest.Artist = txt;
|
|
||||||
else if(!id.CompareNoCase("SubtitleTo")) tr.Dest.Subtitle = txt;
|
|
||||||
else if(!id.CompareNoCase("TitleTransTo")) tr.Dest.TitleTranslit = txt;
|
|
||||||
else if(!id.CompareNoCase("ArtistTransTo")) tr.Dest.ArtistTranslit = txt;
|
|
||||||
else if(!id.CompareNoCase("SubtitleTransTo")) tr.Dest.SubtitleTranslit = txt;
|
|
||||||
else
|
|
||||||
LOG->Warn( "Unknown TitleSubst tag: \"%s\"", id.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the translation if this is a terminator (*) or section
|
|
||||||
* marker ([foo]). */
|
|
||||||
if(line[0] == '*' || line[0] == '[')
|
|
||||||
{
|
|
||||||
if(!CurrentSection.CompareNoCase(section))
|
|
||||||
AddTrans(tr);
|
|
||||||
|
|
||||||
/* Reset. */
|
|
||||||
tr = TitleTrans();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(line[0] == '[' && line[line.size()-1] == ']')
|
|
||||||
{
|
|
||||||
CurrentSection = line.substr(1, line.size()-2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user