// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
/** This tool is used to managed translation file.
* I work with two different file format :
* - phrase file witch contain a complex grammar description
* - string file withc contain only pair of identifier / string value.
*
* This tool can do 6 different work :
* - make diff string file file for each language from a reference string file.
*
* - merge the translated diff string file into there respective string file after
* translation
*
* - make diff phrase file for each language from a reference phrase file
*
* - merge the translated diff phrase file into there respective phrase file after
* translation
*
* - make clause diff for each language by examining phrase files. Add comments
* in the diff files for phrase parameter information.
*
* - merge clause diff in all the clause file.
*
* - remove "\*OLDVALUE: \*\/" from clause file or phrase file
*
*
* Before invocation, you must be in the translation repository (see localisation_system_in_ryzom.doc)
* Invocation should be as folow :
* trans_tool make_string_diff
* trans_tool merge_string_diff
* trans_tool make_words_diff
* trans_tool merge_words_diff
* trans_tool make_phrase_diff
* trans_tool merge_phrase_diff
* trans_tool make_clause_diff
* trans_tool merge_clause_diff
* trans_tool clean_string_diff
* trans_tool clean_words_diff
* trans_tool clean_clause_diff
* trans_tool clean_phrase_diff
* trans_tool make_phrase_diff_old
* trans_tool merge_phrase_diff_old
* trans_tool forget_phrase_diff
* trans_tool update_phrase_work
* trans_tool inject_clause
* trans_tool sort_trans_phrase
* trans_tool make_worksheet_diff
* trans_tool merge_worksheet_diff
* trans_tool crop_lines
* trans_tool extract_bot_names
* trans_tool extract_new_sheet_names
*/
#include "nel/misc/app_context.h"
#include "nel/misc/i18n.h"
#include "nel/misc/file.h"
#include "nel/misc/path.h"
#include "nel/misc/diff_tool.h"
#include "nel/misc/algo.h"
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace NLMISC;
using namespace STRING_MANAGER;
int extractBotNames(int argc, char *argv[]);
int extractNewSheetNames(int argc, char *argv[]);
const std::string addDir("work/");
const std::string diffDir("diff/");
const std::string transDir("translated/");
const std::string historyDir("history/");
string diffVersion;
#ifdef NL_DEBUG
# define LOG nldebug
#else
# define LOG printf
#endif
enum TDiffCommand
{
diff_none,
diff_add,
diff_changed,
diff_removed,
diff_swap
};
struct TDiffInfo
{
TDiffCommand Command;
uint Index1;
uint Index2;
};
/// Store the list of language extracted from the languages.txt file
vector Languages;
void showUsage(char *exeName)
{
LOG("%s usage : \n", exeName);
LOG(" %s []\n", exeName);
LOG(" Where command can be :\n");
LOG(" make_string_diff\n");
LOG(" merge_string_diff\n");
LOG(" clean_string_diff\n");
LOG(" make_phrase_diff\n");
LOG(" merge_phrase_diff\n");
LOG(" clean_phrase_diff\n");
LOG(" make_clause_diff\n");
LOG(" merge_clause_diff\n");
LOG(" clean_clause_diff\n");
LOG(" make_phrase_diff_old\n");
LOG(" merge_phrase_diff_old\n");
LOG(" forget_phrase_diff\n");
LOG(" inject_clause\n");
LOG(" sort_trans_phrase\n");
LOG(" make_worksheet_diff \n");
LOG(" merge_worksheet_diff \n");
LOG(" crop_lines \n");
LOG(" extract_bot_names [-r]\n");
LOG(" extract_new_sheet_names [-r]\n");
LOG("\n");
LOG("Language code are ISO 639-2 + optionally ISO 3166 country code.\n");
LOG("Reference language is always the first language in languages.txt\n");
}
void verifyVersion(ucstring& doc, int versionId)
{
ucstring version1("// DIFF_VERSION 1\r\n");
ucstring::size_type version1Size = version1.size();
ucstring version2("// DIFF_VERSION 2\r\n");
ucstring::size_type version2Size = version2.size();
switch (versionId)
{
case 1:
if (doc.size() < version1Size|| doc.substr(0, version1Size) != version1 )
{
nlerror("Loading wrong diff version");
nlassert(0);
}
doc = doc.substr(version1Size);
break;
case 2:
if (doc.size() < version2Size || doc.substr(0, version2Size) != version2 )
{
nlerror("Loading wrong diff version");
nlassert(0);
}
doc = doc.substr(version2Size);
break;
default:
nlassert(0);
}
}
bool readPhraseFile1(const std::string &filename, vector &phrases, bool forceRehash)
{
ucstring doc;
CI18N::readTextFile(filename, doc, false, false, false, CI18N::LINE_FMT_CRLF);
verifyVersion(doc, 1);
return readPhraseFileFromString(doc, filename, phrases, forceRehash);
}
bool readPhraseFile2(const std::string &filename, vector &phrases, bool forceRehash)
{
ucstring doc;
CI18N::readTextFile(filename, doc, false, false, false, CI18N::LINE_FMT_CRLF);
verifyVersion(doc, 2);
return readPhraseFileFromString(doc, filename, phrases, forceRehash);
}
void getPathContentFiltered(const string &baseName, const string &ext, vector &result)
{
CPath::getPathContent(diffDir, false, false, true, result);
uint i;
for (i=0; i>8) & 0xff, fp);
}
fclose(fp);
}
}
*/
bool mergeStringDiff(vector &strings, const string &language, const string &baseName, const string &ext, bool onlyTranslated, bool archiveDiff = false)
{
vector diffs;
getPathContentFiltered(diffDir+baseName+language+"_diff_", ext, diffs);
for (uint i=0; i diff;
if (!loadStringFile(diffs[i], diff, false))
return false;
for (uint j=0; j::IDiffCallback
{
public:
void run(const vector &addition, vector &reference, vector &diff)
{
TStringDiffContext context(addition, reference, diff);
CMakeDiff differ;
differ.makeDiff(this, context);
}
void onEquivalent(uint addIndex, uint refIndex, TStringDiffContext &context)
{
// nothing to do
}
void onAdd(uint addIndex, uint refIndex, TStringDiffContext &context)
{
TStringInfo si = context.Addition[addIndex];
char temp[1024];
sprintf(temp, "// DIFF ADD %u ", addIndex);
si.Comments = ucstring(temp) + nl + si.Comments;
nlinfo("Added %s at %u", si.Identifier.c_str(), addIndex);
context.Diff.push_back(si);
}
void onRemove(uint addIndex, uint refIndex, TStringDiffContext &context)
{
TStringInfo si = context.Reference[refIndex];
char temp[1024];
sprintf(temp, "// DIFF REMOVED %u ", addIndex);
// NB : on vire les commentaires car il pourrais contenir des merdes..
si.Comments = ucstring(temp) + nl;
nlinfo("Removed %s at %u", si.Identifier.c_str(), addIndex);
context.Diff.push_back(si);
}
void onChanged(uint addIndex, uint refIndex, TStringDiffContext &context)
{
TStringInfo si = context.Addition[addIndex];
char temp[1024];
sprintf(temp, "// DIFF CHANGED %u ", addIndex);
si.Comments = ucstring(temp) + nl + si.Comments;
si.Comments = si.Comments + ucstring("/* OLD VALUE : [") + context.Reference[refIndex].Text + "] */" + nl;
nlinfo("Changed %s at %u", si.Identifier.c_str(), addIndex);
context.Diff.push_back(si);
}
void onSwap(uint newIndex, uint refIndex, TStringDiffContext &context)
{
TStringInfo si;
char temp[1024];
sprintf(temp, "// DIFF SWAP %u %u (swaping %s and %s)", newIndex, refIndex, context.Reference[newIndex].Identifier.c_str(), context.Reference[refIndex].Identifier.c_str());
// sprintf(temp, "// DIFF SWAP %u %u", newIndex, refIndex);
si.Comments = ucstring(temp) + nl +nl;
context.Diff.push_back(si);
}
};
void makeStringDiff(const vector &addition, vector &reference, vector &diff)
{
// just building the object will to the job !
CMakeStringDiff differ;
differ.run(addition, reference, diff);
/*
// compare the reference an addition file, remove any equivalent strings.
uint addCount=0, refCount=0;
while (addCount < addition.size() || refCount < reference.size())
{
bool equal = true;
if (addCount != addition.size() && refCount != reference.size())
{
equal = addition[addCount].HashValue == reference[refCount].HashValue;
}
vector::iterator it;
if (addCount == addition.size()
||
(
!equal
// && find_if(addition.begin()+addCount, addition.end(), TFindStringInfo(reference[refCount].Identifier)) == addition.end()
&& find_if(addition.begin(), addition.end(), TFindStringInfo(reference[refCount].Identifier)) == addition.end()
)
)
{
// this can only be removed elements
TStringInfo si = reference[refCount];
char temp[1024];
sprintf(temp, "// DIFF REMOVED %u ", addCount);
// NB : on vire les commentaires car il pourrais contenir des merdes..
si.Comments = ucstring(temp) + nl;
nlinfo("Removed %s at %u", si.Identifier.c_str(), addCount);
diff.push_back(si);
++refCount;
}
else if (refCount == reference.size()
||
(
!equal
// && find_if(reference.begin()+refCount, reference.end(), TFindStringInfo(addition[addCount].Identifier)) == reference.end()
&& find_if(reference.begin(), reference.end(), TFindStringInfo(addition[addCount].Identifier)) == reference.end()
)
)
{
// this can only be addition
TStringInfo si = addition[addCount];
char temp[1024];
sprintf(temp, "// DIFF ADD %u ", addCount);
si.Comments = ucstring(temp) + nl + si.Comments;
nlinfo("Added %s at %u", si.Identifier.c_str(), addCount);
diff.push_back(si);
++addCount;
}
else if (addition[addCount].Identifier != reference[refCount].Identifier)
{
// swap two element.
vector::iterator it = find_if(reference.begin(), reference.end(), TFindStringInfo(addition[addCount].Identifier));
if (it == reference.end())
{
// addition
TStringInfo si = addition[addCount];
char temp[1024];
sprintf(temp, "// DIFF ADD %u ", addCount);
si.Comments = ucstring(temp) + nl + si.Comments;
nlinfo("Added %s at %u", si.Identifier.c_str(), addCount);
diff.push_back(si);
++addCount;
}
else
{
nlassert(it != reference.begin()+refCount);
swap(*it, reference[refCount]);
TStringInfo si;
char temp[1024];
sprintf(temp, "// DIFF SWAP %u %u", it - reference.begin(), refCount);
si.Comments = ucstring(temp) + nl;
diff.push_back(si);
}
}
else if (addition[addCount].HashValue != reference[refCount].HashValue)
{
// changed element
TStringInfo si = addition[addCount];
char temp[1024];
sprintf(temp, "// DIFF CHANGED %u ", addCount);
si.Comments = ucstring(temp) + nl + si.Comments;
si.Comments = si.Comments + ucstring("// OLD VALUE : [") + reference[refCount].Text + ']' + nl;
nlinfo("Changed %s at %u", si.Identifier.c_str(), addCount);
diff.push_back(si);
++refCount;
++addCount;
}
else
{
// same entry
nlinfo("Same %s at %u", addition[addCount].Identifier.c_str(), addCount);
addCount++;
refCount++;
}
}
*/
}
int makeStringDiff(int argc, char *argv[])
{
// this will generate diff from 'addition' directory
// for the reference .uxt file
// with the same file in the 'translated' directory.
// NB : we use standard C file access because there are mutiple file with the same name in different place.
vector addition;
LOG("Generating string diffs\nLoading the working file for language %s\n", Languages[0].c_str());
// load the addition file
std::string addFile(Languages[0]+".uxt");
if (!loadStringFile(addDir+addFile, addition, true))
{
LOG("Error loading file %s\n", (addDir+addFile).c_str());
return 1;
}
// for each language
for (uint l=0; l reference;
// load the reference file
std::string refFile(Languages[l]+".uxt");
if (!loadStringFile(transDir+refFile, reference, false))
{
LOG("Error loading file %s\n", (transDir+refFile).c_str());
return 1;
}
// load any not merged diff file
if (!mergeStringDiff(reference, Languages[l], "", ".uxt", false))
{
LOG("Error will mergin diff file(s)\n");
return 1;
}
vector diff;
makeStringDiff(addition, reference, diff);
if (diff.empty())
{
LOG("No difference for %s.\n", Languages[l].c_str());
}
else
{
LOG("Writing difference file for %s.\n", Languages[l].c_str());
// build the diff file for each language.
ucstring str = prepareStringFile(diff, false);
// add the tag for non translation
str += nl + ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE")+nl+ucstring("// DIFF NOT TRANSLATED")+nl;
std::string diffName(diffDir+Languages[l]+"_diff_"+diffVersion+".uxt");
CI18N::writeTextFile(diffName, str);
}
}
return 0;
}
/*
Remove the OLD VALUE from a file.
*/
void cleanComment(const std::string & filename)
{
ucstring text;
uint nbOldValue=0;
CI18N::readTextFile(filename, text, false, false, false, CI18N::LINE_FMT_CRLF);
ucstring newText;
ucstring::size_type last = 0;
while ( last != ucstring::npos)
{
ucstring::size_type commentBegin = text.find(ucstring("/* OLD VALUE :"), last);
if (commentBegin == ucstring::npos)
{
newText += text.substr(last);
last = ucstring::npos;
}
else
{
ucstring::size_type size = commentBegin - last;
ucstring toAdd = text.substr(last, size);
newText += toAdd;
ucstring::size_type commentEnd = text.find(ucstring("*/"), commentBegin);
if (commentEnd != ucstring::npos) { commentEnd += 4; }
last = commentEnd;
++nbOldValue;
}
}
text = newText;
newText = ucstring("");
last = 0;
while ( last != ucstring::npos)
{
ucstring::size_type commentBegin = text.find(ucstring("//"), last);
if (commentBegin == ucstring::npos)
{
newText += text.substr(last);
last = ucstring::npos;
}
else
{
ucstring::size_type size = commentBegin - last;
ucstring toAdd = text.substr(last, size);
newText += toAdd;
// case where // is the part of an url and isn't a comment
if (commentBegin > 4 && text.substr(commentBegin-1, 1) == ucstring(":"))
{
newText += "//";
last = commentBegin+2;
}
else
{
ucstring::size_type commentEnd = text.find(ucstring("\n"), commentBegin);
if (commentEnd != ucstring::npos)
{
commentEnd += 1;
ucstring comment = text.substr(commentBegin, commentEnd - commentBegin);
if (comment.find(ucstring("// HASH_VALUE")) != ucstring::npos
|| comment.find(ucstring("// DIFF")) != ucstring::npos
|| comment.find(ucstring("// REMOVE")) != ucstring::npos
|| comment.find(ucstring("// INDEX")) != ucstring::npos
)
{
newText += comment;
}
}
last = commentEnd;
++nbOldValue;
}
}
}
nlinfo("cleaning : %s, (%d comments deleted)...\n", filename.c_str(), nbOldValue);
CI18N::writeTextFile(filename , newText);
}
/*
REMOVE OLDVALUE: from a diff string file
*/
int cleanStringDiff(int argc, char *argv[])
{
LOG("Cleaning string diffs\n");
uint i,l;
for (l=0; l diffs;
getPathContentFiltered(diffDir+Languages[l]+"_diff_", ".uxt", diffs);
for (i=0; i translated;
if (!loadStringFile(filename, translated, false))
{
LOG("Error will loading file %s\n", filename.c_str());
return 1;
}
// append the translated diffs
mergeStringDiff(translated, Languages[l], "", ".uxt", true, true);
// prepare the addition string
ucstring str = prepareStringFile(translated, true);
{
// backup the original file
ucstring old;
CI18N::readTextFile(filename, old, false, true, false, CI18N::LINE_FMT_CRLF);
if (old != str)
CFile::moveFile((historyDir+CFile::getFilenameWithoutExtension(filename)+"_"+diffVersion+"."+CFile::getExtension(filename)).c_str(), filename.c_str());
}
CI18N::writeTextFile(filename, str);
}
return 0;
}
/*
struct TFindPhrase : unary_function
{
string Identifier;
TFindPhrase (const string &identifier)
: Identifier(identifier)
{}
bool operator () (const TPhrase &phrase)
{
return phrase.Identifier == Identifier;
}
};
*/
bool mergePhraseDiff2(vector &phrases, const string &language, bool onlyTranslated, bool archiveDiff);
bool mergePhraseDiff(vector &phrases, const string &language, bool onlyTranslated, bool archiveDiff = false)
{
vector diffs;
getPathContentFiltered(diffDir+"phrase_"+language+"_diff_", ".txt", diffs);
for (uint i=0; i diff;
if (!readPhraseFile1(diffs[i], diff, false))
return false;
for (uint j=0; j::IDiffCallback
{
public:
void run(const vector &addition, vector &reference, vector &diff)
{
TPhraseDiffContext context(addition, reference, diff);
CMakeDiff differ;
differ.makeDiff(this, context);
}
void onEquivalent(uint addIndex, uint refIndex, TPhraseDiffContext &context)
{
// nothing to do
}
void onAdd(uint addIndex, uint refIndex, TPhraseDiffContext &context)
{
TPhrase phrase = context.Addition[addIndex];
char temp[1024];
sprintf(temp, "// DIFF ADD %u ", addIndex);
phrase.Comments = ucstring(temp) + nl + phrase.Comments;
nlinfo("Added %s at %u", phrase.Identifier.c_str(), addIndex);
context.Diff.push_back(phrase);
}
void onRemove(uint addIndex, uint refIndex, TPhraseDiffContext &context)
{
TPhrase phrase = context.Reference[refIndex];
char temp[1024];
sprintf(temp, "// DIFF REMOVED %u ", addIndex);
// NB : on vire les commentaires car il pourrai contenir des merdes..
phrase.Comments = ucstring(temp) + nl;
for (uint i=0; i tempV;
tempV.push_back(context.Reference[refIndex]);
ucstring tempT = preparePhraseFile(tempV, false);
CI18N::removeCComment(tempT);
phrase.Comments = ucstring("// DIFF CHANGED ") + toString(addIndex) + nl + phrase.Comments;
phrase.Comments = phrase.Comments + ucstring("/* OLD VALUE : ["+nl) + tabLines(1, tempT) +nl + "] */" + nl;
phrase.Comments = phrase.Comments + chg;
nlinfo("Changed %s at %u", phrase.Identifier.c_str(), addIndex);
context.Diff.push_back(phrase);
}
void onSwap(uint newIndex, uint refIndex, TPhraseDiffContext &context)
{
TPhrase phrase;
char temp[1024];
sprintf(temp, "// DIFF SWAP %u %u (swaping %s and %s)", newIndex, refIndex, context.Reference[newIndex].Identifier.c_str(), context.Reference[refIndex].Identifier.c_str());
nldebug("Swap for %u %u", newIndex, refIndex);
phrase.Comments = ucstring(temp) + nl;
context.Diff.push_back(phrase);
}
};
int makePhraseDiff(int argc, char *argv[])
{
// Generate the diff file from phrase_.txt compared to the same file in translated.
// The diff is generated only from the reference language for and all the languages
LOG("Generating phrase diffs\nLoading the working file for language %s\n", Languages[0].c_str());
vector addition;
// read addition
if (!readPhraseFile(addDir+"phrase_"+Languages[0]+".txt", addition, true))
{
LOG("Error will loading file %s", (addDir+"phrase_"+Languages[0]+".txt").c_str());
return 1;
}
for (uint l =0; l reference;
// read the reference file
if (!readPhraseFile(transDir+"phrase_"+Languages[l]+".txt", reference, false))
{
LOG("Error will loading file %s", (transDir+"phrase_"+Languages[l]+".txt").c_str());
return 1;
}
if (!mergePhraseDiff(reference, Languages[l], false))
{
LOG("Error will merging phrase diff for language %s\n", Languages[l].c_str());
return 1;
}
// compare the reference an addition file, remove any equivalent strings.
uint addCount=0, refCount=0;
vector diff;
CMakePhraseDiff differ;
differ.run(addition, reference, diff);
if (diff.empty())
{
LOG("No difference for language %s\n", Languages[l].c_str());
}
else
{
LOG("Writing difference file for language %s\n", Languages[l].c_str());
ucstring text;
text += "// DIFF_VERSION 1\r\n";
text += preparePhraseFile(diff, false);
// add the tag for non translation
text += nl + ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE")+nl+ucstring("// DIFF NOT TRANSLATED")+nl;
CI18N::writeTextFile(diffDir+"phrase_"+Languages[l]+"_diff_"+diffVersion+".txt", text);
}
}
return 0;
}
/*
REMOVE OLDVALUE: from a diff clause file
*/
int cleanPhraseDiff(int argc, char *argv[])
{
LOG("Cleaning phrase diffs\n");
uint i,l;
for (l=0; l diffs;
getPathContentFiltered(diffDir+"phrase_"+Languages[l]+"_diff_", ".txt", diffs);
for (i=0; i reference;
ucstring doc;
if (!readPhraseFile(transDir+basename+".txt", reference, false))
{
LOG("Error will loading file %s", (transDir+basename+".txt").c_str());
return 1;
}
switch(version)
{
case 1:
if (!mergePhraseDiff(reference, Languages[l], true, true))
{
LOG("Error will merging phrase diff");
return 1;
}
break;
case 2:
if (!mergePhraseDiff2(reference, Languages[l], true, true))
{
LOG("Error will merging phrase diff");
return 1;
}
break;
default:
nlassert(0);
}
ucstring str = preparePhraseFile(reference, true);
{
// backup the original file
ucstring old;
CI18N::readTextFile(filename, old, false, true, false, CI18N::LINE_FMT_CRLF);
if (old != str)
CFile::moveFile((historyDir+CFile::getFilenameWithoutExtension(filename)+"_"+diffVersion+"."+CFile::getExtension(filename)).c_str(), filename.c_str());
}
CI18N::writeTextFile(transDir+basename+".txt", str);
}
return 0;
}
int makeClauseDiff(int argc, char *argv[])
{
// this will generate diff from 'addition' directory
// for all the clause_.txt file
// with the same file in the 'translated' directory.
// NB : we use standard C file access because there are mutiple file with the same name in different place.
LOG("Generating clause diffs\n");
uint i,l;
for (l=0; l addition;
vector reference;
vector phrases;
std::vector warnings;
// load the reference file
std::string refFile(basename+".txt");
if (!loadStringFile(transDir+refFile, reference, false))
{
LOG("Error will loading file %s", (transDir+refFile).c_str());
return 1;
}
// load the addition file
std::string addFile("phrase_"+Languages[l]+".txt");
if (!readPhraseFile(transDir+addFile, phrases, true))
{
LOG("Error will loading file %s", (transDir+addFile).c_str());
return 1;
}
// extract all the clauses from the phrases file
vector::iterator first(phrases.begin()), last(phrases.end());
for (; first != last; ++first)
{
TPhrase &p = *first;
for (i=0; i::const_iterator first2 = addition.begin();
vector::const_iterator last2 = addition.end();
for ( ;first2!=last2 && first2->Identifier != si.Identifier; ++first2) {}
bool isAllreadyThere = first2 != last2;
if (isAllreadyThere)
{
warnings.push_back("The clause " +si.Identifier +" in the phrase " + p.Identifier +" exists more than once.");
}
else
{
addition.push_back(si);
}
}
}
}
if (!warnings.empty())
{
std::vector::const_iterator first = warnings.begin();
std::vector::const_iterator last = warnings.end();
for (;first != last; ++first) { nlwarning("%s", first->c_str()); }
return -1;
}
mergeStringDiff(reference, Languages[l], "clause_", ".txt", false);
vector diff;
makeStringDiff(addition, reference, diff);
if (diff.empty())
{
LOG("No difference for language %s\n", Languages[l].c_str());
}
else
{
LOG("Writing difference file for %s.\n", Languages[l].c_str());
// build the diff file for each language.
ucstring str = prepareStringFile(diff, false);
// add the tag for non translation
str += nl + ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE")+nl+ucstring("// DIFF NOT TRANSLATED")+nl;
std::string diffName(diffDir+"clause_"+Languages[l]+"_diff_"+diffVersion+".txt");
CI18N::writeTextFile(diffName, str);
}
}
return 0;
}
/*
REMOVE OLDVALUE: from a diff clause file
*/
int cleanClauseDiff(int argc, char *argv[])
{
LOG("Cleaning clause diffs\n");
uint i,l;
for (l=0; l diffs;
getPathContentFiltered(diffDir+"clause_"+Languages[l]+"_diff_", ".txt", diffs);
for (i=0; i translated;
if (!loadStringFile(filename, translated, false))
{
LOG("Error will loading file %s", filename.c_str());
return 1;
}
// append the translated diffs
mergeStringDiff(translated, Languages[l], "clause_", ".txt", true, true);
// prepare the addition string
ucstring str = prepareStringFile(translated, true);
{
// backup the original file
ucstring old;
CI18N::readTextFile(filename, old, false, true, false, CI18N::LINE_FMT_CRLF);
if (old != str)
CFile::moveFile((historyDir+CFile::getFilenameWithoutExtension(filename)+"_"+diffVersion+"."+CFile::getExtension(filename)).c_str(), filename.c_str());
}
CI18N::writeTextFile(filename, str);
}
return 0;
return 0;
}
bool mergeWorksheetDiff(const std::string filename, TWorksheet &sheet, bool onlyTranslated, bool archiveDiff)
{
std::string fn(CFile::getFilenameWithoutExtension(filename)), ext(CFile::getExtension(filename));
vector fileList;
getPathContentFiltered(diffDir+fn+"_diff_", ext, fileList);
uint i;
for (i=0; i 0);
sheet.Data.erase(sheet.Data.begin() + diffInfo.Index1);
break;
case diff_swap:
nlassertex(diffInfo.Index1 < sheet.Data.size(),
("SWAP cmd in diff file, first index reference row %u, but worksheet only contains %u entries",
diffInfo.Index1, sheet.Data.size()));
// nlassertex(diffInfo.Index1 > 0);
nlassertex(diffInfo.Index2 < sheet.Data.size(),
("SWAP cmd in diff file, second index reference row %u, but worksheet only contains %u entries",
diffInfo.Index1, sheet.Data.size()));
// nlassertex(diffInfo.Index2 > 0);
swap(sheet[diffInfo.Index1], sheet[diffInfo.Index2]);
break;
default:
nlassert(false);
}
}
if (archiveDiff)
{
// move the diff file in the history dir
CFile::moveFile((historyDir+CFile::getFilename(fileList[i])).c_str(), fileList[i].c_str());
}
}
return true;
}
bool mergeSheetDiff(const string &type, TWorksheet &sheet, const string &language, bool onlyTranslated, bool archiveDiff)
{
return mergeWorksheetDiff(type+"_words_"+language+".txt", sheet, onlyTranslated, archiveDiff);
}
class CMakeWordsDiff : public TWorkSheetDiff::IDiffCallback
{
public:
void run(const TWorksheet &addition, TWorksheet &reference, TWorksheet &diff)
{
TWordsDiffContext context(addition, reference, diff);
TWorkSheetDiff differ;
differ.makeDiff(this, context, true);
}
void onEquivalent(uint addIndex, uint refIndex, TWordsDiffContext &context)
{
// nothing to do
}
void onAdd(uint addIndex, uint refIndex, TWordsDiffContext &context)
{
TWorksheet::TRow row(context.Reference.ColCount+1);
for (uint j=0; j diffs;
getPathContentFiltered(diffDir+"clause_"+Languages[l]+"_diff_", ".txt", diffs);
for (i=0; i 0)
CI18N::writeTextFile(transDir+filename, str, false);
return 0;
}
int makeWordsDiff(int argc, char *argv[])
{
vector fileList;
CPath::getPathContent(addDir, false, false, true, fileList);
// filter in words file only
uint i;
for (i=0; i fileList;
CPath::getPathContent(addDir, false, false, true, fileList);
// filter in words file only
for (uint i=0; i count(c2.Conditions.begin(), c2.Conditions.end(), '&');
}
};
int recupAround(int argc, char *argv[])
{
string clause1(diffDir+"clause_en_diff_3E896220.txt");
string clause2(addDir+"clause_en_diff_3E7B4CE4 TRANSLATED.txt");
vector reference;
loadStringFile(clause1, reference, true);
vector around;
loadStringFile(clause2, around, true, '[', ']', true);
vector result;
nlassert(reference.size() == around.size());
for (uint i=0; i lines;
explode(text, std::string("\n"), lines);
text.clear();
if (lines.size() > nbLines)
{
for (uint i=0; i files;
uint i;
// move en.uxt file to wk.uxt
CFile::moveFile((CPath::standardizePath(addDir)+"wk.uxt").c_str(), (CPath::standardizePath(addDir)+"en.uxt").c_str());
files.clear();
CPath::getPathContent(addDir, true, false, true, files);
string strreplaced("_en.txt");
string strtoreplace("_wk.txt");
for (i=0; i > & outputResult);
void assertUniq(const vector& reference)
{
std::set< std::string > phraseIdentifier;
std::set< std::string > clauseIdentifier;
vector::const_iterator first( reference.begin() );
vector::const_iterator last( reference.end() );
for( ; first != last; ++first)
{
if ( phraseIdentifier.find(first->Identifier) != phraseIdentifier.end())
{
nlwarning("Phrase %s defined more than once.", first->Identifier.c_str());
exit(-1);
}
else
{
phraseIdentifier.insert(first->Identifier);
vector::const_iterator first2( first->Clauses.begin() );
vector::const_iterator last2( first->Clauses.end() );
for( ; first2 != last2; ++first2)
{
if (clauseIdentifier.find(first2->Identifier) != clauseIdentifier.end() )
{
nlwarning("Clause %s defined more than once.", first2->Identifier.c_str());
exit(-1);
}
}
}
}
}
void mergePhraseDiff2Impl(vector& reference, const vector& addition)
{
assertUniq(reference);
assertUniq(addition);
typedef std::map TMap;
TMap phrases;
{
vector::const_iterator first( reference.begin() );
vector::const_iterator last( reference.end() );
for( ; first != last ; ++first )
{
std::string identifier = first->Identifier;
phrases[identifier] = *first;
}
}
{
vector::const_iterator first( addition.begin() );
vector::const_iterator last( addition.end() );
for( ; first != last ; ++first )
{
if ( first->Comments.find(ucstring("DIFF CHANGED")) != ucstring::npos)
{
nlassert( phrases.find(first->Identifier) != phrases.end() );
phrases[first->Identifier] = *first;
}
else if ( first->Comments.find(ucstring("DIFF ADD")) != ucstring::npos)
{
nlassert( phrases.find(first->Identifier) == phrases.end() );
phrases[first->Identifier] = *first;
}
else if ( first->Comments.find(ucstring("DIFF REMOVED")) != ucstring::npos)
{
nlassert( phrases.find(first->Identifier) != phrases.end() );
phrases.erase( phrases.find(first->Identifier));
}
else
{
// nlassert(0 && "INVALID DIFF COMMAND");
}
}
}
{
reference.clear();
reference.reserve(phrases.size());
TMap::const_iterator first( phrases.begin() );
TMap::const_iterator last( phrases.end() );
for( ; first != last; ++first) { reference.push_back(first->second); }
}
}
void removeHashValueComment(ucstring & comments)
{
ucstring::size_type first;
ucstring::size_type last;
first = comments.rfind(ucstring("// HASH_VALUE"));
if (first != ucstring::npos)
{
last = comments.find(ucstring("\n"), first);
if (last != ucstring::npos)
{
last += 1;
ucstring tmp1 = comments.substr(0, first);
ucstring tmp2 = last !=comments.size()
? comments.substr(last)
: ucstring("");
comments = tmp1 + tmp2;
}
else
{
comments = comments.substr(0, first);
}
}
else
{
//comments = comments;
}
}
bool updateClauseHashValue(const std::map >& validValues, const std::string & dirPath = "")
{
for (uint l=0; l clauses;
std::string refFile(basename+".txt");
if (!loadStringFile(transDir+refFile, clauses, false))
{
LOG("Error will loading file %s", (transDir+refFile).c_str());
return false;
}
bool changed = false;
for ( uint i=0; i < clauses.size() ; ++i)
{
std::string Identifier = clauses[i].Identifier;
if ( validValues.find(Identifier) != validValues.end())
{
if (!validValues.find(Identifier)->second.second
|| clauses[i].HashValue == validValues.find(Identifier)->second.second)
{
clauses[i].HashValue = validValues.find(Identifier)->second.first;
removeHashValueComment(clauses[i].Comments);
changed = true;
}
}
}
if (!changed)
{
nlwarning("Clauses file don't need update for language %s\n", Languages[l].c_str());
}
else
{
nlinfo("Updating hashcode of clause file for %s.\n", Languages[l].c_str());
// build the diff file for each language.
ucstring str = prepareStringFile(clauses, false);
std::string clauseName(dirPath+ transDir + basename +".txt");
CFile::createDirectoryTree( CFile::getPath(clauseName) );
CI18N::writeTextFile(clauseName, str);
}
}
return true;
}
ucstring preparePhraseFile2(const vector &phrases, bool removeDiffComments)
{
ucstring ret;
vector::const_iterator first(phrases.begin()), last(phrases.end());
for (; first != last; ++first)
{
const TPhrase &p = *first;
if (removeDiffComments)
{
string comment = p.Comments.toString();
vector lines;
explode(comment, std::string("\n"), lines, true);
uint i;
for (i=0; i > & validValues, const std::string & dirPath = "")
{
for (uint l=0; l phrases;
std::string refFile(basename+".txt");
if (!readPhraseFile(transDir+refFile, phrases, false))
{
LOG("Error will loading file %s", (transDir+refFile).c_str());
return false;
}
bool changed = false;
for ( uint i=0; i < phrases.size() ; ++i)
{
std::string Identifier = phrases[i].Identifier;
if ( validValues.find(Identifier) != validValues.end())
{
if (!validValues.find(Identifier)->second.second || phrases[i].HashValue == validValues.find(Identifier)->second.second )
{
phrases[i].HashValue = validValues.find(Identifier)->second.first;
removeHashValueComment(phrases[i].Comments);
changed = true;
}
}
}
if (!changed)
{
nlinfo("Phrase file don't need update for language %s\n", Languages[l].c_str());
}
else
{
nlinfo("Updating hashcode of phrase file for %s.\n", Languages[l].c_str());
// build the diff file for each language.
ucstring str = preparePhraseFile(phrases, false);
std::string pharseName(dirPath+ transDir + basename +".txt");
CFile::createDirectoryTree( CFile::getPath(pharseName) );
CI18N::writeTextFile(pharseName, str);
}
}
return true;
}
bool sortTransPhrase()
{
for (uint l=0; l phrases;
vector phrases2;
std::map phraseMap;
std::string refFile(basename+".txt");
if (!readPhraseFile(transDir+refFile, phrases, false))
{
LOG("Error will loading file %s", (transDir+refFile).c_str());
return false;
}
{
std::vector::const_iterator first(phrases.begin());
std::vector::const_iterator last(phrases.end());
for ( ; first != last; ++first)
{
phraseMap[first->Identifier] = *first;
}
}
{
std::map::const_iterator first(phraseMap.begin());
std::map::const_iterator last(phraseMap.end());
for ( ; first != last; ++first)
{
phrases2.push_back( first->second);
}
}
nlinfo("Updating hashcode of phrase file for %s.\n", Languages[l].c_str());
// build the diff file for each language.
ucstring str = preparePhraseFile(phrases2, false);
std::string pharseName(transDir+refFile);
CFile::createDirectoryTree( CFile::getPath(pharseName) );
CI18N::writeTextFile(pharseName, str);
}
return true;
}
void patchWorkFile(vector &updatedPhrase, const std::string & filename)
{
ucstring text;
if ( updatedPhrase.empty() ) { return; }
CI18N::readTextFile(filename, text, false, false, false, CI18N::LINE_FMT_CRLF);
vector::const_iterator first(updatedPhrase.begin());
vector::const_iterator last(updatedPhrase.end());
for (; first != last; ++first)
{
ucstring::size_type firstFun = text.find( ucstring(first->Identifier));
if (firstFun == ucstring::npos)
{
nlwarning("Error can't patch %s: %s not found", filename.c_str(), first->Identifier.c_str());
}
else
{
ucstring::size_type lastFun = text.find( ucstring("}") , firstFun);
if (lastFun == ucstring::npos)
{
nlwarning("Error can't patch %s: syntax error near %s", filename.c_str(), first->Identifier.c_str());
}
else
{
std::vector param;
param.push_back(*first);
ucstring before = text.substr(0,firstFun);
ucstring str = preparePhraseFile2(param, false);
ucstring after = text.substr(lastFun+1);
text = "";
text += before;
text += str;
text += after;
}
}
}
CI18N::writeTextFile( filename, text);
}
int updatePhraseWork()
{
std::string saveDir = diffDir + "update_"+ diffVersion + "/";
vector transPhrase;
std::map transPhraseMap;
std::map > validClauseHashValue;
std::map > validPhraseHashValue;
std::vector< std::pair > outputResult;
if (!readPhraseFile(transDir+"phrase_wk.txt", transPhrase, false))
{
LOG("Error will loading file %s", (addDir+"phrase_"+Languages[0]+".txt").c_str());
return 1;
}
{
std::vector::const_iterator first(transPhrase.begin());
std::vector::const_iterator last(transPhrase.end());
for (; first != last;++first)
{
transPhraseMap[first->Identifier] = *first;
}
}
preprocessTextFile(addDir+"phrase_wk.txt", outputResult);
uint firstFile = 0;
uint lastFile = (uint)outputResult.size();
for (; firstFile != lastFile ; ++firstFile)
{
ucstring doc = outputResult[firstFile].first;
std::vector phrases;
readPhraseFileFromString(outputResult[firstFile].first, outputResult[firstFile].second, phrases, true);
std::vector::iterator first(phrases.begin());
std::vector::iterator last(phrases.end());
std::vector updatedPhrases;
for (; first != last; ++first)
{
if (transPhraseMap.find(first->Identifier) != transPhraseMap.end() )
{
TPhrase workPhrase = *first;
TPhrase& transPhrase = transPhraseMap[first->Identifier];
if (first->HashValue == transPhrase.HashValue)
{
uint64 oldHash = transPhrase.HashValue;
uint64 newHash = STRING_MANAGER::makePhraseHash(transPhrase);
if (newHash != transPhrase.HashValue)
{
//translation phrase_wk.txt has been manually changed
validPhraseHashValue[transPhrase.Identifier] = std::pair(newHash, oldHash);
std::vector::iterator firstClause ( transPhrase.Clauses.begin() );
std::vector::iterator lastClause ( transPhrase.Clauses.end() );
for (; firstClause != lastClause; ++firstClause)
{
uint64 clauseHashValue = CI18N::makeHash(firstClause->Text);
validClauseHashValue[firstClause->Identifier] = std::pair(clauseHashValue, firstClause->HashValue);
firstClause->HashValue = clauseHashValue;
}
updatedPhrases.push_back(transPhrase);
updatedPhrases.back().Comments= ucstring("");
}
}
}
}
std::string newFile = saveDir + outputResult[firstFile].second;
std::string oldFile = outputResult[firstFile].second;
CFile::createDirectoryTree(CFile::getPath(newFile));
if ( CFile::copyFile(newFile, oldFile) )
{
patchWorkFile(updatedPhrases, newFile);
}
else
{
nlwarning("Can't copy %s", newFile.c_str());
}
}
updatePhraseHashValue(validPhraseHashValue, saveDir);
updateClauseHashValue(validClauseHashValue, saveDir);
return 0;
}
bool mergePhraseDiff2(vector &phrases, const string &language, bool onlyTranslated, bool archiveDiff = false)
{
vector diffs;
getPathContentFiltered(diffDir+"phrase_"+language+"_diff_", ".txt", diffs);
for (uint i=0; i diff;
if (!readPhraseFile2(diffs[i], diff, false))
return false;
mergePhraseDiff2Impl(phrases, diff);
if (archiveDiff)
{
// move the diff file in the history dir
CFile::moveFile((historyDir+CFile::getFilename(diffs[i])).c_str(), diffs[i].c_str());
}
}
return true;
}
class CMakePhraseDiff2
{
public:
class CPhraseEqual
{
public:
CPhraseEqual(){}
bool operator()( const TPhrase& left, const TPhrase& right) const;
// bool clausesEqual( const std::vector& left, const std::vector& right) const;
// bool clauseEqual(const TClause& left, const TClause& right) const;
};
void run(const vector &addition, vector &reference, vector &diff);
void onEquivalent(uint addIndex, uint refIndex, TPhraseDiffContext &context);
void onAdd(uint addIndex, uint refIndex, TPhraseDiffContext &context);
void onRemove(uint addIndex, uint refIndex, TPhraseDiffContext &context);
void onChanged(uint addIndex, uint refIndex, TPhraseDiffContext &context);
};
void CMakePhraseDiff2::run(const vector &addition, vector &reference, vector &diff)
{
TPhraseDiffContext context(addition, reference, diff);
std::set phraseIdentifier;
std::map mapAdd;
std::map mapRef;
{
uint first = 0;
uint last = (uint)reference.size();
for ( ;first != last; ++first)
{
std::string Identifier(reference[first].Identifier);
mapRef[Identifier] = first;
phraseIdentifier.insert(Identifier);
}
}
{
uint first = 0;
uint last = (uint)addition.size();
for ( ;first != last; ++first)
{
std::string Identifier(addition[first].Identifier);
mapAdd[Identifier] = first;
phraseIdentifier.insert(Identifier);
}
}
if (mapAdd.size() != addition.size())
{
nlwarning("Phrases are defined more than once in works directory");
}
if (mapAdd.size() != addition.size())
{
nlwarning("Phrases are defined more than once in translation directory");
}
std::set::iterator first(phraseIdentifier.begin());
std::set::iterator last(phraseIdentifier.end());
for (; first != last; ++first)
{
if ( mapAdd.find(*first) != mapAdd.end()
&& mapRef.find(*first) != mapRef.end())
{
if ( CPhraseEqual()(addition[mapAdd[*first]], reference[mapRef[*first]]) )
{
onEquivalent(mapAdd[*first], mapRef[*first], context);
}
else
{
onChanged(mapAdd[*first], mapRef[*first], context);
}
}
else if ( mapAdd.find(*first) != mapAdd.end()
&& mapRef.find(*first) == mapRef.end())
{
onAdd(mapAdd[*first], 0, context);
}
else if ( mapAdd.find(*first) == mapAdd.end()
&& mapRef.find(*first) != mapRef.end())
{
onRemove(0, mapRef[*first], context);
}
}
}
void CMakePhraseDiff2::onEquivalent(uint addIndex, uint refIndex, TPhraseDiffContext &context)
{
// nothing to do
}
void CMakePhraseDiff2::onAdd(uint addIndex, uint refIndex, TPhraseDiffContext &context)
{
TPhrase phrase = context.Addition[addIndex];
char temp[1024];
sprintf(temp, "// DIFF ADD");
phrase.Comments = ucstring(temp) + nl + phrase.Comments;
nlinfo("Added %s at %u", phrase.Identifier.c_str(), addIndex);
context.Diff.push_back(phrase);
}
void CMakePhraseDiff2::onRemove(uint addIndex, uint refIndex, TPhraseDiffContext &context)
{
TPhrase phrase = context.Reference[refIndex];
char temp[1024];
sprintf(temp, "// DIFF REMOVED");
// NB : on vire les commentaires car il pourrai contenir des merdes..
phrase.Comments = ucstring(temp) + nl;
for (uint i=0; i tempV;
tempV.push_back(context.Reference[refIndex]);
ucstring tempT = preparePhraseFile(tempV, false);
CI18N::removeCComment(tempT);
phrase.Comments = ucstring("// DIFF CHANGED ") + toString(addIndex) + nl + phrase.Comments;
phrase.Comments = phrase.Comments + ucstring("/* OLD VALUE : ["+nl) + tabLines(1, tempT) +nl + "] */" + nl;
phrase.Comments = phrase.Comments + chg;
nlinfo("Changed %s at %u", phrase.Identifier.c_str(), addIndex);
context.Diff.push_back(phrase);
}
bool CMakePhraseDiff2::CPhraseEqual::operator()( const TPhrase& left, const TPhrase& right) const
{
bool identifierOk = left.Identifier == right.Identifier;
// bool parameterOk = left.Parameters == right.Parameters;
// bool commentsOk = left.Comments == right.Comments;
// bool clausesOk = clausesEqual(left.Clauses, right.Clauses);
bool hashOk = left.HashValue== right.HashValue;
return identifierOk && hashOk;// && parameterOk && clausesOk;
}
/*
bool CMakePhraseDiff2::CPhraseEqual::clausesEqual( const std::vector& left, const std::vector& right) const
{
std::vector::const_iterator first1(left.begin());
std::vector::const_iterator last1(left.end());
std::vector::const_iterator first2(right.begin());
if (left.size() != right.size()) return false;
for ( ; first1 != last1 && !clauseEqual(*first1, *first2); ++first1, ++first2){}
return first1 == last1;
}
bool CMakePhraseDiff2::CPhraseEqual::clauseEqual(const TClause& left, const TClause& right) const
{
return left.Identifier != right.Identifier
&& left.Conditions != right.Conditions
&& left.Text != right.Text
&& left.Comments != right.Comments
&& left.HashValue != right.HashValue;
}
*/
int makePhraseDiff2(int argc, char *argv[])
{
// Generate the diff file from phrase_.txt compared to the same file in translated.
// The diff is generated only from the reference language for and all the languages
LOG("Generating phrase diffs\nLoading the working file for language %s\n", Languages[0].c_str());
vector addition;
// read addition
if (!readPhraseFile(addDir+"phrase_"+Languages[0]+".txt", addition, true))
{
LOG("Error will loading file %s", (addDir+"phrase_"+Languages[0]+".txt").c_str());
return 1;
}
for (uint l =0; l reference;
// read the reference file
if (!readPhraseFile(transDir+"phrase_"+Languages[l]+".txt", reference, false))
{
LOG("Error will loading file %s", (transDir+"phrase_"+Languages[l]+".txt").c_str());
return 1;
}
if (!mergePhraseDiff2(reference, Languages[l], false))
{
LOG("Error will merging phrase diff for language %s\n", Languages[l].c_str());
return 1;
}
// compare the reference an addition file, remove any equivalent strings.
uint addCount=0, refCount=0;
vector diff;
CMakePhraseDiff2 differ;
differ.run(addition, reference, diff);
if (diff.empty())
{
LOG("No difference for language %s\n", Languages[l].c_str());
}
else
{
LOG("Writing difference file for language %s\n", Languages[l].c_str());
ucstring text;
text += "// DIFF_VERSION 2\r\n";
text += preparePhraseFile(diff, false);
// add the tag for non translation
text += nl + ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE")+nl+ucstring("// DIFF NOT TRANSLATED")+nl;
CI18N::writeTextFile(diffDir+"phrase_"+Languages[l]+"_diff_"+diffVersion+".txt", text);
}
}
return 0;
}
int forgetPhraseDiff(int argc, char *argv[])
{
// merge all the phrase diff back into there repective translated phrase.
LOG("forgeting phrase diffs\n");
std::string basename("phrase_"+Languages[0]);
string filename = transDir+basename+".txt";
// build the addition diff
vector reference;
if (!readPhraseFile(transDir+basename+".txt", reference, false))
{
LOG("Error will loading file %s", (transDir+basename+".txt").c_str());
return 1;
}
//assert only change
std::vector diffs;
getPathContentFiltered(diffDir+"phrase_wk_diff_", ".txt", diffs);
std::vector newPhrase;
for (uint i=0; i subDiff;
if (!readPhraseFile2(diffs[i], subDiff, false))
return false;
std::copy (subDiff.begin (), subDiff.end (), std::back_inserter (newPhrase));
}
// a optimiser par une map
std::map > validClauseHashValue;
std::map > validPhraseHashValue;
for (uint i=0; i < newPhrase.size() ; ++i)
{
for (uint j=0; j < reference.size() ; ++j)
{
if (newPhrase[i].Identifier == reference[j].Identifier)
{
uint64 newPhraseHash = STRING_MANAGER::makePhraseHash( newPhrase[i] );
uint64 oldPhraseHash = reference[j].HashValue;
validPhraseHashValue[newPhrase[i].Identifier] = std::pair(newPhraseHash, oldPhraseHash);
for (uint k=0; k < newPhrase[i].Clauses.size() ; ++k)
{
if (reference[j] .Clauses.size() != newPhrase[i].Clauses.size())
{
nlwarning("Want to forget minor update but phrase %s changes too much. The number of clauses has changed.", newPhrase[i].Identifier.c_str() );
exit(-1);
}
const TClause& newClause = newPhrase[i].Clauses[k];
const TClause& oldClause = reference[j].Clauses[k];
if (!newClause.Identifier.empty() )
{
if (newClause.Identifier != oldClause.Identifier)
{
nlwarning("Want to forget minor update but phrase %s changes too much. Clauses order or clause identifier changed (%s).", newPhrase[i].Identifier.c_str(), newClause.Identifier.c_str());
exit(-1);
}
uint64 newClauseHashValue = CI18N::makeHash(newClause.Text);
uint64 oldClauseHashValue = CI18N::makeHash(oldClause.Text);
validClauseHashValue[ newClause.Identifier ] = std::pair(newClauseHashValue, oldClauseHashValue);
}
}
}
}
}
if (!mergePhraseDiff2(reference, Languages[0], true, false))
{
LOG("Error will merging phrase diff");
return 1;
}
ucstring str = preparePhraseFile(reference, true);
CI18N::writeTextFile(transDir+basename+".txt", str);
updatePhraseHashValue(validPhraseHashValue);
// updateClauseHashValue(validClauseHashValue);
for (uint i=0; i > & outputResult
)
{
//nlinfo("preprocessing %s", filename.c_str());
ucstring result;
std::string fullName;
fullName = filename;
if (fullName.empty())
return;
NLMISC::CIFile file;
/// Open a file for reading. false if failed. close() if a file was opened.
if (!file.open (fullName))
{
nlwarning("Can't open %s", fullName.c_str());
return ;
}
// Fast read all the text in binary mode.
std::string text;
text.resize(file.getFileSize());
file.serialBuffer((uint8*)(&text[0]), (uint)text.size());
// Transform the string in ucstring according to format header
if (!text.empty())
CI18N::readTextBuffer((uint8*)&text[0], (uint)text.size(), result, false);
ucstring final;
// parse the file, looking for preprocessor command.
ucstring::size_type pos = 0;
ucstring::size_type lastPos = 0;
ucstring includeCmd("#include");
ucstring current;
while ( pos != ucstring::npos)
{
pos = result.find(ucstring("\n"), pos);
if (pos != ucstring::npos) { ++pos; }
ucstring line( result.substr(lastPos, pos - lastPos) );
if ( line.find(includeCmd) != ucstring::npos)
{
ucstring::size_type firstFilename = line.find(ucstring("\""));
ucstring::size_type lastFilename = line.find(ucstring("\""), firstFilename+1);
ucstring name = line.substr(firstFilename +1, lastFilename - firstFilename -1);
string subFilename = name.toString();
{
CIFile testFile;
if (!testFile.open(subFilename))
{
// try to open the include file relative to current file
subFilename = CFile::getPath(filename)+subFilename;
}
}
preprocessTextFile(subFilename, outputResult);
}
else
{
current += line;
}
lastPos = pos;
}
outputResult.push_back( std::pair ( current, fullName ) );
}
int mergePhraseDiff(int argc, char *argv[])
{
// merge all the phrase diff back into there repective translated phrase.
uint l;
LOG("Merging phrase diffs\n");
for (l=0; l reference;
if (!readPhraseFile(transDir+basename+".txt", reference, false))
{
LOG("Error will loading file %s", (transDir+basename+".txt").c_str());
return 1;
}
if (!mergePhraseDiff(reference, Languages[l], true, true))
{
LOG("Error will merging phrase diff");
return 1;
}
ucstring str = preparePhraseFile(reference, true);
{
// backup the original file
ucstring old;
CI18N::readTextFile(filename, old, false, true, false, CI18N::LINE_FMT_CRLF);
if (old != str)
CFile::moveFile((historyDir+CFile::getFilenameWithoutExtension(filename)+"_"+diffVersion+"."+CFile::getExtension(filename)).c_str(), filename.c_str());
}
CI18N::writeTextFile(transDir+basename+".txt", str);
}
return 0;
}
int injectClause()
{
uint l;
LOG("Update translation from clauses.\n");
for (l=0; l clauses;
vector phrases;
// load the clause file
std::string clausePath( transDir+"clause_"+Languages[l]+".txt" );
if (!loadStringFile(clausePath, clauses, false))
{
LOG("Error will loading file %s", clausePath.c_str());
return 1;
}
// load the phrase file
std::string phrasePath( transDir+"phrase_"+Languages[l]+".txt" );
if (!readPhraseFile(phrasePath, phrases, false))
{
LOG("Error will loading file %s", phrasePath.c_str());
return 1;
}
vector::iterator first(phrases.begin());
vector::iterator last(phrases.end());
for ( ; first != last; ++first)
{
vector::iterator firstClause( first->Clauses.begin());
vector::iterator lastClause( first->Clauses.end());
for ( ; firstClause != lastClause; ++firstClause)
{
uint64 hashValue = CI18N::makeHash(firstClause->Text);
vector::iterator firstRefClause(clauses.begin());
vector::iterator lastRefClause(clauses.end());
for ( ; firstRefClause != lastRefClause ; ++firstRefClause)
{
if (hashValue == firstRefClause->HashValue && firstClause->Text != firstRefClause->Text)
{
firstClause->Text = firstRefClause->Text;
firstClause->HashValue = CI18N::makeHash(firstClause->Text);
firstRefClause->HashValue = firstClause->HashValue;
nlinfo("update clause %s from clause file %s.", firstClause->Identifier.c_str(), clausePath.c_str());
}
}
}
}
std::string desDir(diffDir + "inject_clause_" + diffVersion + "/");
CFile::createDirectoryTree(desDir+ CFile::getPath(phrasePath));
ucstring str = preparePhraseFile(phrases, true);
CI18N::writeTextFile(desDir + phrasePath, str);
str = prepareStringFile(clauses, true);
CI18N::writeTextFile(desDir + clausePath, str);
}
return 0;
}
int main(int argc, char *argv[])
{
NLMISC::CApplicationContext context;
/* createDebug();
CStdDisplayer *display = new CStdDisplayer;
NLMISC::InfoLog->addDisplayer(display);
NLMISC::WarningLog->addDisplayer(display);
NLMISC::ErrorLog->addDisplayer(display);
*/
/* for (uint i=0; i<20; ++i)
{
uint64 hash = makeHash(ucstring("Bonjour le monde !"));
nldebug("%s", hashToString(hash).c_str());
hash = makeHash(ucstring("Une autre clef"));
nldebug("%s", hashToString(hash).c_str());
}
*/
if (argc < 2)
{
showUsage(argv[0]);
return 1;
}
std::string argv1(argv[1]);
// create the diff version.
char temp[16];
sprintf(temp, "%8.8X", (uint) ::time(NULL));
diffVersion = temp;
if (strcmp(argv[1], "make_work") == 0)
{
return makeWork();
}
// generic worksheet comparison
if (strcmp(argv[1], "make_worksheet_diff") == 0)
{
if (argc != 3)
{
showUsage(argv[0]);
return 1;
}
return makeWorksheetDiff(argc, argv, argv[2], argv[2], true);
}
else if (strcmp(argv[1], "merge_worksheet_diff") == 0)
{
if (argc != 3)
{
showUsage(argv[0]);
return 1;
}
return mergeWorksheetDiff(argc, argv, argv[2], argv[2]);
}
else if (strcmp(argv[1], "crop_lines") == 0)
{
if (argc != 4)
{
showUsage(argv[0]);
return 1;
}
uint nbLines;
NLMISC::fromString(argv[3], nbLines);
cropLines(argv[2], nbLines);
return 0;
}
else if (strcmp(argv[1], "extract_bot_names") == 0)
return extractBotNames(argc, argv);
else if (strcmp(argv[1], "extract_new_sheet_names") == 0)
return extractNewSheetNames(argc, argv);
if (argc != 2)
{
showUsage(argv[0]);
return 1;
}
// if (strcmp(argv[1], "yann") == 0)
// return mergeYannTaf();
string currentPath("./");
CPath::addSearchPath(currentPath+addDir, true, false);
CPath::addSearchPath(currentPath+diffDir, true, false);
// CPath::addSearchPath(currentPath+transDir, true, false);
if (readLanguages() != 0)
{
LOG("Error will loading language file (language.txt)");
return 1;
}
if (strcmp(argv[1], "make_string_diff") == 0)
return makeStringDiff(argc, argv);
else if (strcmp(argv[1], "merge_string_diff") == 0)
return mergeStringDiff(argc, argv);
else if (strcmp(argv[1], "clean_string_diff") == 0)
return cleanStringDiff(argc, argv);
else if (argv1 == "make_phrase_diff_old")
return makePhraseDiff(argc, argv);
else if (argv1 == "merge_phrase_diff_old")
return mergePhraseDiff(argc, argv, 1);
else if (argv1 == "make_phrase_diff")
return makePhraseDiff2(argc, argv);
else if (argv1 == "merge_phrase_diff")
return mergePhraseDiff(argc, argv, 2);
else if (argv1 == "forget_phrase_diff")
return forgetPhraseDiff(argc, argv);
else if (argv1 == "update_phrase_work")
return updatePhraseWork();
else if (argv1 == "clean_phrase_diff")
return cleanPhraseDiff(argc, argv);
else if (argv1 == "inject_clause")
return injectClause();
else if (argv1 == "sort_trans_phrase")
return sortTransPhrase();
else if (strcmp(argv[1], "make_clause_diff") == 0)
return makeClauseDiff(argc, argv);
else if (strcmp(argv[1], "merge_clause_diff") == 0)
return mergeClauseDiff(argc, argv);
else if (argv1 == "clean_clause_diff")
return cleanClauseDiff(argc, argv);
else if (strcmp(argv[1], "make_words_diff") == 0)
return makeWordsDiff(argc, argv);
else if (strcmp(argv[1], "merge_words_diff") == 0)
return mergeWordsDiff(argc, argv);
else if (strcmp(argv[1], "clean_words_diff") == 0)
return cleanWordsDiff(argc, argv);
else if (strcmp(argv[1], "recup_around") == 0)
return recupAround(argc, argv);
else if (strcmp(argv[1], "add_string_number") == 0)
return addStringNumber();
return -1;
}
int addStringNumber()
{
vector strings;
LOG("Generating string diffs\nLoading the working file for language %s\n", Languages[0].c_str());
// load the addition file
std::string addFile(Languages[0]+".uxt");
if (!loadStringFile(addDir+addFile, strings, true))
{
LOG("Error loading file %s\n", (addDir+addFile).c_str());
return 1;
}
ucstring str = prepareStringFile(strings, false);
string filename = addDir+Languages[0]+".uxt";
CI18N::writeTextFile(filename, str);
return 0;
}