1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /** This tool is used to managed translation file.
24 * I work with two different file format :
25 * - phrase file witch contain a complex grammar description
26 * - string file withc contain only pair of identifier / string value.
28 * This tool can do 6 different work :
29 * - make diff string file file for each language from a reference string file.
31 * - merge the translated diff string file into there respective string file after
34 * - make diff phrase file for each language from a reference phrase file
36 * - merge the translated diff phrase file into there respective phrase file after
39 * - make clause diff for each language by examining phrase files. Add comments
40 * in the diff files for phrase parameter information.
42 * - merge clause diff in all the clause file.
44 * - remove "\*OLDVALUE: \*\/" from clause file or phrase file
47 * Before invocation, you must be in the translation repository (see localisation_system_in_ryzom.doc)
48 * Invocation should be as folow :
49 * trans_tool make_string_diff
50 * trans_tool merge_string_diff
51 * trans_tool make_words_diff
52 * trans_tool merge_words_diff
53 * trans_tool make_phrase_diff
54 * trans_tool merge_phrase_diff
55 * trans_tool make_clause_diff
56 * trans_tool merge_clause_diff
57 * trans_tool clean_string_diff
58 * trans_tool clean_words_diff
59 * trans_tool clean_clause_diff
60 * trans_tool clean_phrase_diff
61 * trans_tool make_phrase_diff_old
62 * trans_tool merge_phrase_diff_old
63 * trans_tool forget_phrase_diff
64 * trans_tool update_phrase_work
65 * trans_tool inject_clause
66 * trans_tool sort_trans_phrase
67 * trans_tool make_worksheet_diff
68 * trans_tool merge_worksheet_diff
69 * trans_tool crop_lines
70 * trans_tool extract_bot_names
71 * trans_tool extract_new_sheet_names
75 #include "nel/misc/app_context.h"
76 #include "nel/misc/i18n.h"
77 #include "nel/misc/common.h"
78 #include "nel/misc/file.h"
79 #include "nel/misc/path.h"
80 #include "nel/misc/diff_tool.h"
81 #include "nel/misc/algo.h"
90 using namespace NLMISC
;
91 using namespace STRING_MANAGER
;
93 int extractBotNames(int argc
, char *argv
[]);
94 int extractNewSheetNames(int argc
, char *argv
[]);
95 const std::string
addDir("work/");
96 const std::string
diffDir("diff/");
97 const std::string
transDir("translated/");
98 const std::string
historyDir("history/");
120 TDiffCommand Command
;
125 /// Store the list of language extracted from the languages.txt file
126 vector
<string
> Languages
;
129 void showUsage(char *exeName
)
131 LOG("%s usage : \n", exeName
);
132 LOG(" %s <command> [<filename>]\n", exeName
);
133 LOG(" Where command can be :\n");
134 LOG(" make_string_diff\n");
135 LOG(" merge_string_diff\n");
136 LOG(" clean_string_diff\n");
137 LOG(" make_phrase_diff\n");
138 LOG(" merge_phrase_diff\n");
139 LOG(" clean_phrase_diff\n");
140 LOG(" make_clause_diff\n");
141 LOG(" merge_clause_diff\n");
142 LOG(" clean_clause_diff\n");
143 LOG(" make_phrase_diff_old\n");
144 LOG(" merge_phrase_diff_old\n");
145 LOG(" forget_phrase_diff\n");
146 LOG(" inject_clause\n");
147 LOG(" sort_trans_phrase\n");
148 LOG(" make_worksheet_diff <filename>\n");
149 LOG(" merge_worksheet_diff <filename>\n");
150 LOG(" crop_lines <filename> <nbLines>\n");
151 LOG(" extract_bot_names [-r]\n");
152 LOG(" extract_new_sheet_names [-r]\n");
154 LOG("Language code are ISO 639-2 + optionally ISO 3166 country code.\n");
155 LOG("Reference language is always the first language in languages.txt\n");
158 void verifyVersion(ucstring
& doc
, int versionId
)
160 ucstring
version1("// DIFF_VERSION 1\n");
161 ucstring::size_type version1Size
= version1
.size();
162 ucstring
version2("// DIFF_VERSION 2\n");
163 ucstring::size_type version2Size
= version2
.size();
168 if (doc
.size() < version1Size
|| doc
.substr(0, version1Size
) != version1
)
170 nlerror("Loading wrong diff version");
173 doc
= doc
.substr(version1Size
);
177 if (doc
.size() < version2Size
|| doc
.substr(0, version2Size
) != version2
)
179 nlerror("Loading wrong diff version");
182 doc
= doc
.substr(version2Size
);
191 bool readPhraseFile1(const std::string
&filename
, vector
<TPhrase
> &phrases
, bool forceRehash
)
195 CI18N::readTextFile(filename
, doc
, false, false, CI18N::LINE_FMT_LF
);
196 verifyVersion(doc
, 1);
197 return readPhraseFileFromString(doc
, filename
, phrases
, forceRehash
);
200 bool readPhraseFile2(const std::string
&filename
, vector
<TPhrase
> &phrases
, bool forceRehash
)
204 CI18N::readTextFile(filename
, doc
, false, false, CI18N::LINE_FMT_LF
);
205 verifyVersion(doc
, 2);
206 return readPhraseFileFromString(doc
, filename
, phrases
, forceRehash
);
211 void getPathContentFiltered(const string
&baseName
, const string
&ext
, vector
<string
> &result
)
213 CPath::getPathContent(diffDir
, false, false, true, result
);
216 for (i
=0; i
<result
.size(); ++i
)
218 if (result
[i
].find(baseName
) != 0 || result
[i
].rfind(ext
) != result
[i
].size()-ext
.size())
220 // remove it from the list
221 result
.erase(result
.begin()+i
);
228 bool parseDiffCommandFromComment(const ucstring
&comments
, TDiffInfo
&diffInfo
)
230 ucstring::size_type pos
= comments
.find(ucstring("DIFF "));
231 if (pos
== string::npos
)
235 ucstring::const_iterator
it(comments
.begin()+pos
), last(comments
.end());
238 if (!CI18N::parseLabel(it
, last
, commandStr
))
241 CI18N::skipWhiteSpace(it
, last
);
242 if (commandStr
== "SWAP")
243 diffInfo
.Command
= diff_swap
;
244 else if (commandStr
== "ADD")
245 diffInfo
.Command
= diff_add
;
246 else if (commandStr
== "CHANGED")
247 diffInfo
.Command
= diff_changed
;
248 else if (commandStr
== "REMOVED")
249 diffInfo
.Command
= diff_removed
;
250 else if (commandStr
== "KEEP")
251 diffInfo
.Command
= diff_keep
;
254 nlwarning("Invalid diff command '%s'", commandStr
.c_str());
255 diffInfo
.Command
= diff_none
;
259 CI18N::skipWhiteSpace(it
, last
);
260 // ok, parse the index.
262 if (!CI18N::parseLabel(it
, last
, indexStr
))
265 NLMISC::fromString(indexStr
, diffInfo
.Index1
);
267 if (diffInfo
.Command
== diff_swap
)
269 CI18N::skipWhiteSpace(it
, last
);
270 if (!CI18N::parseLabel(it
, last
, indexStr
))
273 NLMISC::fromString(indexStr
, diffInfo
.Index2
);
279 /// Read the languages.txt file.
282 // read the language list file
284 CI18N::readTextFile("languages.txt", f
);
289 LOG("Error : the file languages.txt is missing or empty !\n");
293 ucstring::const_iterator
first(f
.begin()), last(f
.end());
294 while (first
!= last
)
296 CI18N::skipWhiteSpace(first
, last
);
298 // read a language code
299 while (*first
!= ' ' && *first
!= '\n' && *first
!= '\r' && *first
!= '\t')
300 lang
+= char(*first
++);
304 LOG("Adding language %s\n", lang
.c_str());
305 Languages
.push_back(lang
);
309 CI18N::skipWhiteSpace(first
, last
);
311 if (Languages
.empty())
313 LOG("Error : the file languages.txt is empty !\n");
317 LOG("Found %u language code\n", (uint
) Languages
.size());
323 /*void appendToFile(const std::string &filename, const ucstring &text)
325 if (!CFile::fileExists(filename))
327 // create the new translatio file
328 CI18N::writeTextFile(filename, text);
332 // append to the existing file
333 FILE *fp = nlfopen(filename, "ab");
335 for (uint i=0; i<text.size(); ++i)
337 fputc(text[i] & 0xff, fp);
338 fputc((text[i]>>8) & 0xff, fp);
347 bool mergeStringDiff(vector
<TStringInfo
> &strings
, const string
&language
, const string
&baseName
, const string
&ext
, bool onlyTranslated
, bool archiveDiff
= false)
349 vector
<string
> diffs
;
351 getPathContentFiltered(diffDir
+baseName
+language
+"_diff_", ext
, diffs
);
353 for (uint i
=0; i
<diffs
.size(); ++i
)
357 // Check if the diff is translated
359 CI18N::readTextFile(diffs
[i
], text
, false, false, CI18N::LINE_FMT_LF
);
360 if (text
.find(ucstring("DIFF NOT TRANSLATED")) != ucstring::npos
)
362 LOG("Diff file [%s] is not translated, merging it later.\n", CFile::getFilename(diffs
[i
]).c_str());
363 for (i
=i
+1; i
<diffs
.size(); ++i
)
364 LOG(" Merge of Diff file [%s] delayed.\n", CFile::getFilename(diffs
[i
]).c_str());
369 // we found a diff file for the addition file.
370 LOG("Adding %s diff as reference\n", diffs
[i
].c_str());
371 vector
<TStringInfo
> diff
;
372 if (!loadStringFile(diffs
[i
], diff
, false))
375 for (uint j
=0; j
<diff
.size(); ++j
)
377 /* TDiffCommand command;
382 if (!parseDiffCommandFromComment(diff
[j
].Comments
, diffInfo
))
385 switch(diffInfo
.Command
)
388 nlassertex(diffInfo
.Index1
< strings
.size(), ("Index %u out of max Range %u", diffInfo
.Index1
, strings
.size()));
389 nlassertex(diffInfo
.Index2
< strings
.size(), ("Index %u out of max Range %u", diffInfo
.Index2
, strings
.size()));
390 swap(strings
[diffInfo
.Index1
], strings
[diffInfo
.Index2
]);
391 // remove the swap from the comments
392 diff
[j
].Comments
= diff
[j
].Comments
.substr(diff
[j
].Comments
.find(nl
)+nl
.length());
393 if (!diff
[j
].Comments
.empty())
397 nlassert(diffInfo
.Index1
<= strings
.size());
398 strings
.insert(strings
.begin()+diffInfo
.Index1
, diff
[j
]);
401 nlassert(diffInfo
.Index1
< strings
.size());
402 strings
[diffInfo
.Index1
] = diff
[j
];
405 nlassert(diffInfo
.Index1
< strings
.size());
406 strings
.erase(strings
.begin()+diffInfo
.Index1
);
409 nlassert(diffInfo
.Index1
< strings
.size());
410 strings
[diffInfo
.Index1
].HashValue
= diff
[j
].HashValue
;
419 // move the diff file in the history dir
420 CFile::moveFile(historyDir
+CFile::getFilename(diffs
[i
]), diffs
[i
]);
428 class CMakeStringDiff
: CMakeDiff
<TStringInfo
, TStringDiffContext
>::IDiffCallback
431 void run(const vector
<TStringInfo
> &addition
, vector
<TStringInfo
> &reference
, vector
<TStringInfo
> &diff
)
433 TStringDiffContext
context(addition
, reference
, diff
);
435 CMakeDiff
<TStringInfo
, TStringDiffContext
> differ
;
436 differ
.makeDiff(this, context
);
439 void onEquivalent(uint addIndex
, uint refIndex
, TStringDiffContext
&context
)
444 void onAdd(uint addIndex
, uint refIndex
, TStringDiffContext
&context
)
446 TStringInfo si
= context
.Addition
[addIndex
];
448 sprintf(temp
, "// DIFF ADD %u ", addIndex
);
449 si
.Comments
= ucstring(temp
) + nl
+ si
.Comments
;
451 nlinfo("Added %s at %u", si
.Identifier
.c_str(), addIndex
);
452 context
.Diff
.push_back(si
);
455 void onRemove(uint addIndex
, uint refIndex
, TStringDiffContext
&context
)
457 TStringInfo si
= context
.Reference
[refIndex
];
459 sprintf(temp
, "// DIFF REMOVED %u ", addIndex
);
460 // NB : on vire les commentaires car il pourrais contenir des merdes..
461 si
.Comments
= ucstring(temp
) + nl
;
463 nlinfo("Removed %s at %u", si
.Identifier
.c_str(), addIndex
);
464 context
.Diff
.push_back(si
);
467 void onChanged(uint addIndex
, uint refIndex
, TStringDiffContext
&context
)
469 TStringInfo si
= context
.Addition
[addIndex
];
471 sprintf(temp
, "// DIFF CHANGED %u ", addIndex
);
472 si
.Comments
= ucstring(temp
) + nl
+ si
.Comments
;
473 si
.Comments
= si
.Comments
+ ucstring("/* OLD VALUE : [") + context
.Reference
[refIndex
].Text
+ "] */" + nl
;
475 nlinfo("Changed %s at %u", si
.Identifier
.c_str(), addIndex
);
476 context
.Diff
.push_back(si
);
479 void onSwap(uint newIndex
, uint refIndex
, TStringDiffContext
&context
)
483 sprintf(temp
, "// DIFF SWAP %u %u (swaping %s and %s)", newIndex
, refIndex
, context
.Reference
[newIndex
].Identifier
.c_str(), context
.Reference
[refIndex
].Identifier
.c_str());
484 // sprintf(temp, "// DIFF SWAP %u %u", newIndex, refIndex);
486 si
.Comments
= ucstring(temp
) + nl
+ nl
;
487 context
.Diff
.push_back(si
);
492 void makeStringDiff(const vector
<TStringInfo
> &addition
, vector
<TStringInfo
> &reference
, vector
<TStringInfo
> &diff
)
494 // just building the object will to the job !
495 CMakeStringDiff differ
;
496 differ
.run(addition
, reference
, diff
);
499 // compare the reference an addition file, remove any equivalent strings.
500 uint addCount=0, refCount=0;
502 while (addCount < addition.size() || refCount < reference.size())
505 if (addCount != addition.size() && refCount != reference.size())
507 equal = addition[addCount].HashValue == reference[refCount].HashValue;
510 vector<TStringInfo>::iterator it;
512 if (addCount == addition.size()
516 // && find_if(addition.begin()+addCount, addition.end(), TFindStringInfo(reference[refCount].Identifier)) == addition.end()
517 && find_if(addition.begin(), addition.end(), TFindStringInfo(reference[refCount].Identifier)) == addition.end()
521 // this can only be removed elements
522 TStringInfo si = reference[refCount];
524 sprintf(temp, "// DIFF REMOVED %u ", addCount);
525 // NB : on vire les commentaires car il pourrais contenir des merdes..
526 si.Comments = ucstring(temp) + nl;
528 nlinfo("Removed %s at %u", si.Identifier.c_str(), addCount);
532 else if (refCount == reference.size()
536 // && find_if(reference.begin()+refCount, reference.end(), TFindStringInfo(addition[addCount].Identifier)) == reference.end()
537 && find_if(reference.begin(), reference.end(), TFindStringInfo(addition[addCount].Identifier)) == reference.end()
541 // this can only be addition
542 TStringInfo si = addition[addCount];
544 sprintf(temp, "// DIFF ADD %u ", addCount);
545 si.Comments = ucstring(temp) + nl + si.Comments;
547 nlinfo("Added %s at %u", si.Identifier.c_str(), addCount);
551 else if (addition[addCount].Identifier != reference[refCount].Identifier)
554 vector<TStringInfo>::iterator it = find_if(reference.begin(), reference.end(), TFindStringInfo(addition[addCount].Identifier));
555 if (it == reference.end())
558 TStringInfo si = addition[addCount];
560 sprintf(temp, "// DIFF ADD %u ", addCount);
561 si.Comments = ucstring(temp) + nl + si.Comments;
563 nlinfo("Added %s at %u", si.Identifier.c_str(), addCount);
569 nlassert(it != reference.begin()+refCount);
571 swap(*it, reference[refCount]);
575 sprintf(temp, "// DIFF SWAP %u %u", it - reference.begin(), refCount);
577 si.Comments = ucstring(temp) + nl;
581 else if (addition[addCount].HashValue != reference[refCount].HashValue)
584 TStringInfo si = addition[addCount];
586 sprintf(temp, "// DIFF CHANGED %u ", addCount);
587 si.Comments = ucstring(temp) + nl + si.Comments;
588 si.Comments = si.Comments + ucstring("// OLD VALUE : [") + reference[refCount].Text + ']' + nl;
590 nlinfo("Changed %s at %u", si.Identifier.c_str(), addCount);
598 nlinfo("Same %s at %u", addition[addCount].Identifier.c_str(), addCount);
606 int makeStringDiff(int argc
, char *argv
[], const std::string
&baseName
)
608 // this will generate diff from 'addition' directory
609 // for the reference <lang>.uxt file
610 // with the same file in the 'translated' directory.
612 // NB : we use standard C file access because there are mutiple file with the same name in different place.
614 vector
<TStringInfo
> addition
;
616 LOG("Generating string diffs\nLoading the working file for language %s\n", Languages
[0].c_str());
617 // load the addition file
618 std::string addFile
= baseName
+ Languages
[0] + ".uxt";
619 if (!loadStringFile(addDir
+addFile
, addition
, true))
621 LOG("Error loading file %s\n", (addDir
+addFile
).c_str());
626 for (uint l
=0; l
<Languages
.size(); ++l
)
628 LOG("Diffing with language %s...\n", Languages
[l
].c_str());
634 std::string addFile
= baseName
+ Languages
[0] + ".uxt";
635 if (!loadStringFile(transDir
+addFile
, addition
, true))
637 LOG("Error loading file %s\n", (transDir
+addFile
).c_str());
642 vector
<TStringInfo
> reference
;
643 // load the reference file
644 std::string refFile
= baseName
+ Languages
[l
] + ".uxt";
645 if (!loadStringFile(transDir
+refFile
, reference
, false))
647 LOG("Error loading file %s\n", (transDir
+refFile
).c_str());
651 // load any not merged diff file
652 if (!mergeStringDiff(reference
, Languages
[l
], baseName
, ".uxt", false))
654 LOG("Error will mergin diff file(s)\n");
658 vector
<TStringInfo
> diff
;
659 makeStringDiff(addition
, reference
, diff
);
663 LOG("No difference for %s.\n", Languages
[l
].c_str());
667 LOG("Writing difference file for %s.\n", Languages
[l
].c_str());
668 // build the diff file for each language.
669 ucstring str
= prepareStringFile(diff
, false);
671 // add the tag for non translation
672 str
+= nl
+ ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE") + nl
+ ucstring("// DIFF NOT TRANSLATED") + nl
;
674 std::string diffName
= diffDir
+ baseName
+ Languages
[l
] + "_diff_" + diffVersion
+ ".uxt";
675 CI18N::writeTextFile(diffName
, str
);
684 Remove the OLD VALUE from a file.
686 void cleanComment(const std::string
& filename
)
691 CI18N::readTextFile(filename
, text
, false, false, CI18N::LINE_FMT_LF
);
694 ucstring::size_type last
= 0;
695 while ( last
!= ucstring::npos
)
697 ucstring::size_type commentBegin
= text
.find(ucstring("/* OLD VALUE :"), last
);
698 if (commentBegin
== ucstring::npos
)
700 newText
+= text
.substr(last
);
701 last
= ucstring::npos
;
705 ucstring::size_type size
= commentBegin
- last
;
706 ucstring toAdd
= text
.substr(last
, size
);
708 ucstring::size_type commentEnd
= text
.find(ucstring("*/"), commentBegin
);
709 if (commentEnd
!= ucstring::npos
) { commentEnd
+= 2 + nl
.size(); }
717 while ( last
!= ucstring::npos
)
719 ucstring::size_type commentBegin
= text
.find(ucstring("//"), last
);
720 if (commentBegin
== ucstring::npos
)
722 newText
+= text
.substr(last
);
723 last
= ucstring::npos
;
727 ucstring::size_type size
= commentBegin
- last
;
728 ucstring toAdd
= text
.substr(last
, size
);
730 // case where // is the part of an url and isn't a comment
731 if (commentBegin
> 4 && text
.substr(commentBegin
-1, 1) == ucstring(":"))
734 last
= commentBegin
+2;
738 ucstring::size_type commentEnd
= text
.find(ucstring("\n"), commentBegin
);
739 if (commentEnd
!= ucstring::npos
)
742 ucstring comment
= text
.substr(commentBegin
, commentEnd
- commentBegin
);
743 if (comment
.find(ucstring("// HASH_VALUE")) != ucstring::npos
744 || comment
.find(ucstring("// DIFF")) != ucstring::npos
745 || comment
.find(ucstring("// REMOVE")) != ucstring::npos
746 || comment
.find(ucstring("// INDEX")) != ucstring::npos
757 nlinfo("cleaning : %s, (%d comments deleted)...\n", filename
.c_str(), nbOldValue
);
758 CI18N::writeTextFile(filename
, newText
);
762 REMOVE OLDVALUE: from a diff string file
764 int cleanStringDiff(int argc
, char *argv
[], const std::string
&baseName
)
767 LOG("Cleaning string diffs\n");
771 for (l
=0; l
<Languages
.size(); ++l
)
774 vector
<string
> diffs
;
776 getPathContentFiltered(diffDir
+ baseName
+ Languages
[l
] + "_diff_", ".uxt", diffs
);
777 for (i
=0; i
<diffs
.size(); ++i
)
779 cleanComment(diffs
[i
]);
785 int mergeStringDiff(int argc
, char *argv
[], const std::string
&baseName
)
787 LOG("Merging string diffs\n");
791 for (l
=0; l
<Languages
.size(); ++l
)
793 LOG("Merging for language %s...\n", Languages
[l
].c_str());
794 string filename
= transDir
+ baseName
+ Languages
[l
] + ".uxt";
795 // load the translated file
796 vector
<TStringInfo
> translated
;
797 if (!loadStringFile(filename
, translated
, false))
799 LOG("Error will loading file %s\n", filename
.c_str());
803 // append the translated diffs
804 mergeStringDiff(translated
, Languages
[l
], baseName
, ".uxt", true, true);
806 // prepare the addition string
807 ucstring str
= prepareStringFile(translated
, true);
810 // backup the original file
812 CI18N::readTextFile(filename
, old
, true, false, CI18N::LINE_FMT_LF
);
814 CFile::moveFile(historyDir
+CFile::getFilenameWithoutExtension(filename
)+"_"+diffVersion
+"."+CFile::getExtension(filename
), filename
);
817 CI18N::writeTextFile(filename
, str
);
825 struct TFindPhrase : unary_function<TPhrase, bool>
828 TFindPhrase (const string &identifier)
829 : Identifier(identifier)
831 bool operator () (const TPhrase &phrase)
833 return phrase.Identifier == Identifier;
839 bool mergePhraseDiff2(vector
<TPhrase
> &phrases
, const string
&language
, bool onlyTranslated
, bool archiveDiff
);
840 bool mergePhraseDiff(vector
<TPhrase
> &phrases
, const string
&language
, bool onlyTranslated
, bool archiveDiff
= false)
842 vector
<string
> diffs
;
844 getPathContentFiltered(diffDir
+"phrase_"+language
+"_diff_", ".txt", diffs
);
846 for (uint i
=0; i
<diffs
.size(); ++i
)
850 // Check if the diff is translated
852 CI18N::readTextFile(diffs
[i
], text
, false, false, CI18N::LINE_FMT_LF
);
853 verifyVersion(text
, 1);
854 if (text
.find(ucstring("DIFF NOT TRANSLATED")) != ucstring::npos
)
856 LOG("Diff file [%s] is not translated, merging it later.\n", CFile::getFilename(diffs
[i
]).c_str());
857 for (i
=i
+1; i
<diffs
.size(); ++i
)
858 LOG(" Merge of Diff file [%s] delayed.\n", CFile::getFilename(diffs
[i
]).c_str());
863 // we found a diff file for the addition file.
864 LOG("Adding %s diff as reference\n", diffs
[i
].c_str());
865 vector
<TPhrase
> diff
;
866 if (!readPhraseFile1(diffs
[i
], diff
, false))
869 for (uint j
=0; j
<diff
.size(); ++j
)
871 /* TDiffCommand command;
876 if (!parseDiffCommandFromComment(diff
[j
].Comments
, diffInfo
))
878 if (j
== diff
.size()-1)
882 nlwarning("Failed to parse diff command in '%s'", diff
[j
].Identifier
.c_str());
887 switch(diffInfo
.Command
)
890 nlassertex(diffInfo
.Index1
<= phrases
.size(),
891 ("In SWAP, Index1 (%u) is not less than number of phrase (%u)", diffInfo
.Index1
, phrases
.size()));
892 nlassertex(diffInfo
.Index2
<= phrases
.size(),
893 ("In SWAP Index2 (%u) is not less than number of phrase (%u)", diffInfo
.Index2
, phrases
.size()));
894 swap(phrases
[diffInfo
.Index1
], phrases
[diffInfo
.Index2
]);
895 // remove the swap from the comments
896 diff
[j
].Comments
= diff
[j
].Comments
.substr(diff
[j
].Comments
.find(nl
)+2);
900 nlassertex(diffInfo
.Index1
<= phrases
.size(),
901 ("In ADD, Index1 (%u) is not less than number of phrase (%u)", diffInfo
.Index1
, phrases
.size()));
902 phrases
.insert(phrases
.begin()+diffInfo
.Index1
, diff
[j
]);
905 nlassertex(diffInfo
.Index1
< phrases
.size(),
906 ("In CHANGED, Index1 (%u) is not less than number of phrase (%u)", diffInfo
.Index1
, phrases
.size()));
907 phrases
[diffInfo
.Index1
] = diff
[j
];
910 nlassertex(diffInfo
.Index1
< phrases
.size(),
911 ("In REMOVED, Index1 (%u) is not less than number of phrase (%u)", diffInfo
.Index1
, phrases
.size()));
912 phrases
.erase(phrases
.begin()+diffInfo
.Index1
);
915 nlassertex(diffInfo
.Index1
< phrases
.size(),
916 ("In KEEP, Index1 (%u) is not less than number of phrase (%u)", diffInfo
.Index1
, phrases
.size()));
917 phrases
[diffInfo
.Index1
].HashValue
= diff
[j
].HashValue
;
918 phrases
[diffInfo
.Index1
].Comments
= diff
[j
].Comments
;
927 // move the diff file in the history dir
928 CFile::moveFile(historyDir
+CFile::getFilename(diffs
[i
]), diffs
[i
]);
937 class CMakePhraseDiff
: CMakeDiff
<TPhrase
, TPhraseDiffContext
>::IDiffCallback
940 void run(const vector
<TPhrase
> &addition
, vector
<TPhrase
> &reference
, vector
<TPhrase
> &diff
)
942 TPhraseDiffContext
context(addition
, reference
, diff
);
944 CMakeDiff
<TPhrase
, TPhraseDiffContext
> differ
;
945 differ
.makeDiff(this, context
);
948 void onEquivalent(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
952 void onAdd(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
954 TPhrase phrase
= context
.Addition
[addIndex
];
956 sprintf(temp
, "// DIFF ADD %u ", addIndex
);
957 phrase
.Comments
= ucstring(temp
) + nl
+ phrase
.Comments
;
959 nlinfo("Added %s at %u", phrase
.Identifier
.c_str(), addIndex
);
960 context
.Diff
.push_back(phrase
);
962 void onRemove(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
964 TPhrase phrase
= context
.Reference
[refIndex
];
966 sprintf(temp
, "// DIFF REMOVED %u ", addIndex
);
967 // NB : on vire les commentaires car il pourrai contenir des merdes..
968 phrase
.Comments
= ucstring(temp
) + nl
;
969 for (uint i
=0; i
<phrase
.Clauses
.size(); ++i
)
970 phrase
.Clauses
[i
].Comments
.erase();
972 nlinfo("Removed %s at %u", phrase
.Identifier
.c_str(), addIndex
);
973 context
.Diff
.push_back(phrase
);
975 void onChanged(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
978 // check what is changed.
979 if (context
.Addition
[addIndex
].Parameters
!= context
.Reference
[refIndex
].Parameters
)
980 chg
+= "// Parameter list changed." + nl
;
981 if (context
.Addition
[addIndex
].Clauses
.size() != context
.Reference
[refIndex
].Clauses
.size())
982 chg
+= "// Clause list changed." + nl
;
985 for (uint i
=0; i
<context
.Addition
[addIndex
].Clauses
.size(); ++i
)
987 if (context
.Addition
[addIndex
].Clauses
[i
].Identifier
!= context
.Reference
[refIndex
].Clauses
[i
].Identifier
)
988 chg
+= ucstring("// Clause ") + toString(i
) + " : identifier changed." + nl
;
989 else if (context
.Addition
[addIndex
].Clauses
[i
].Conditions
!= context
.Reference
[refIndex
].Clauses
[i
].Conditions
)
990 chg
+= ucstring("// Clause ") + toString(i
) + " : condition changed." + nl
;
991 else if (context
.Addition
[addIndex
].Clauses
[i
].Text
!= context
.Reference
[refIndex
].Clauses
[i
].Text
)
992 chg
+= ucstring("// Clause ") + toString(i
) + " : text changed." + nl
;
998 chg
= ucstring("// WARNING : Hash code changed ! check translation workflow.") + nl
;
1000 nldebug("Changed detected : %s", chg
.toString().c_str());
1003 TPhrase phrase
= context
.Addition
[addIndex
];
1004 vector
<TPhrase
> tempV
;
1005 tempV
.push_back(context
.Reference
[refIndex
]);
1006 ucstring tempT
= preparePhraseFile(tempV
, false);
1007 CI18N::removeCComment(tempT
);
1008 phrase
.Comments
= ucstring("// DIFF CHANGED ") + toString(addIndex
) + nl
+ phrase
.Comments
;
1009 phrase
.Comments
= phrase
.Comments
+ ucstring("/* OLD VALUE : [" + nl
) + tabLines(1, tempT
) + nl
+ "] */" + nl
;
1010 phrase
.Comments
= phrase
.Comments
+ chg
;
1012 nlinfo("Changed %s at %u", phrase
.Identifier
.c_str(), addIndex
);
1013 context
.Diff
.push_back(phrase
);
1016 void onSwap(uint newIndex
, uint refIndex
, TPhraseDiffContext
&context
)
1020 sprintf(temp
, "// DIFF SWAP %u %u (swaping %s and %s)", newIndex
, refIndex
, context
.Reference
[newIndex
].Identifier
.c_str(), context
.Reference
[refIndex
].Identifier
.c_str());
1022 nldebug("Swap for %u %u", newIndex
, refIndex
);
1023 phrase
.Comments
= ucstring(temp
) + nl
;
1024 context
.Diff
.push_back(phrase
);
1031 int makePhraseDiff(int argc
, char *argv
[])
1033 // Generate the diff file from phrase_<lang>.txt compared to the same file in translated.
1034 // The diff is generated only from the reference language for and all the languages
1036 LOG("Generating phrase diffs\nLoading the working file for language %s\n", Languages
[0].c_str());
1039 vector
<TPhrase
> addition
;
1042 if (!readPhraseFile(addDir
+"phrase_"+Languages
[0]+".txt", addition
, true))
1044 LOG("Error will loading file %s", (addDir
+"phrase_"+Languages
[0]+".txt").c_str());
1048 for (uint l
=0; l
<Languages
.size(); ++l
)
1050 LOG("Diffing with language %s...\n", Languages
[l
].c_str());
1054 // read the language 0 translated version as addition for other language
1055 if (!readPhraseFile(transDir
+"phrase_"+Languages
[0]+".txt", addition
, true))
1057 LOG("Error will loading file %s", (addDir
+"phrase_"+Languages
[0]+".txt").c_str());
1061 vector
<TPhrase
> reference
;
1062 // read the reference file
1063 if (!readPhraseFile(transDir
+"phrase_"+Languages
[l
]+".txt", reference
, false))
1065 LOG("Error will loading file %s", (transDir
+"phrase_"+Languages
[l
]+".txt").c_str());
1069 if (!mergePhraseDiff(reference
, Languages
[l
], false))
1071 LOG("Error will merging phrase diff for language %s\n", Languages
[l
].c_str());
1075 // compare the reference an addition file, remove any equivalent strings.
1076 uint addCount
=0, refCount
=0;
1077 vector
<TPhrase
> diff
;
1079 CMakePhraseDiff differ
;
1080 differ
.run(addition
, reference
, diff
);
1084 LOG("No difference for language %s\n", Languages
[l
].c_str());
1088 LOG("Writing difference file for language %s\n", Languages
[l
].c_str());
1090 text
+= "// DIFF_VERSION 1\n";
1091 text
+= preparePhraseFile(diff
, false);
1092 // add the tag for non translation
1093 text
+= nl
+ ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE") + nl
+ ucstring("// DIFF NOT TRANSLATED") + nl
;
1094 CI18N::writeTextFile(diffDir
+"phrase_"+Languages
[l
]+"_diff_"+diffVersion
+".txt", text
);
1103 REMOVE OLDVALUE: from a diff clause file
1105 int cleanPhraseDiff(int argc
, char *argv
[])
1108 LOG("Cleaning phrase diffs\n");
1112 for (l
=0; l
<Languages
.size(); ++l
)
1115 vector
<string
> diffs
;
1117 getPathContentFiltered(diffDir
+"phrase_"+Languages
[l
]+"_diff_", ".txt", diffs
);
1118 for (i
=0; i
<diffs
.size(); ++i
)
1120 cleanComment(diffs
[i
]);
1128 int mergePhraseDiff(int argc
, char *argv
[], int version
)
1130 // merge all the phrase diff back into there repective translated phrase.
1133 LOG("Merging phrase diffs\n");
1135 for (l
=0; l
<Languages
.size(); ++l
)
1137 LOG("Merging for language %s...\n", Languages
[l
].c_str());
1138 std::string
basename("phrase_"+Languages
[l
]);
1139 string filename
= transDir
+basename
+".txt";
1140 // build the addition diff
1141 vector
<TPhrase
> reference
;
1146 if (!readPhraseFile(transDir
+basename
+".txt", reference
, false))
1148 LOG("Error will loading file %s", (transDir
+basename
+".txt").c_str());
1156 if (!mergePhraseDiff(reference
, Languages
[l
], true, true))
1158 LOG("Error will merging phrase diff");
1165 if (!mergePhraseDiff2(reference
, Languages
[l
], true, true))
1167 LOG("Error will merging phrase diff");
1177 ucstring str
= preparePhraseFile(reference
, true);
1180 // backup the original file
1182 CI18N::readTextFile(filename
, old
, true, false, CI18N::LINE_FMT_LF
);
1184 CFile::moveFile(historyDir
+CFile::getFilenameWithoutExtension(filename
)+"_"+diffVersion
+"."+CFile::getExtension(filename
), filename
);
1187 CI18N::writeTextFile(transDir
+basename
+".txt", str
);
1195 int makeClauseDiff(int argc
, char *argv
[])
1197 // this will generate diff from 'addition' directory
1198 // for all the clause_<lang>.txt file
1199 // with the same file in the 'translated' directory.
1201 // NB : we use standard C file access because there are mutiple file with the same name in different place.
1203 LOG("Generating clause diffs\n");
1207 for (l
=0; l
<Languages
.size(); ++l
)
1209 LOG("Diffing with language %s...\n", Languages
[l
].c_str());
1210 std::string
basename("clause_"+Languages
[l
]);
1211 vector
<TStringInfo
> addition
;
1212 vector
<TStringInfo
> reference
;
1213 vector
<TPhrase
> phrases
;
1214 std::vector
<std::string
> warnings
;
1216 // load the reference file
1217 std::string
refFile(basename
+".txt");
1218 if (!loadStringFile(transDir
+refFile
, reference
, false))
1220 LOG("Error will loading file %s", (transDir
+refFile
).c_str());
1224 // load the addition file
1225 std::string
addFile("phrase_"+Languages
[l
]+".txt");
1226 if (!readPhraseFile(transDir
+addFile
, phrases
, true))
1228 LOG("Error will loading file %s", (transDir
+addFile
).c_str());
1232 // extract all the clauses from the phrases file
1233 vector
<TPhrase
>::iterator
first(phrases
.begin()), last(phrases
.end());
1234 for (; first
!= last
; ++first
)
1236 TPhrase
&p
= *first
;
1237 for (i
=0; i
<p
.Clauses
.size(); ++i
)
1240 si
.Comments
= p
.Clauses
[i
].Comments
;
1241 si
.Identifier
= p
.Clauses
[i
].Identifier
;
1242 si
.Text
= p
.Clauses
[i
].Text
;
1243 si
.HashValue
= CI18N::makeHash(si
.Text
);
1246 if (!si
.Identifier
.empty())
1248 vector
<TStringInfo
>::const_iterator first2
= addition
.begin();
1249 vector
<TStringInfo
>::const_iterator last2
= addition
.end();
1250 for ( ;first2
!=last2
&& first2
->Identifier
!= si
.Identifier
; ++first2
) {}
1251 bool isAllreadyThere
= first2
!= last2
;
1252 if (isAllreadyThere
)
1254 warnings
.push_back("The clause " +si
.Identifier
+" in the phrase " + p
.Identifier
+" exists more than once.");
1258 addition
.push_back(si
);
1264 if (!warnings
.empty())
1266 std::vector
<std::string
>::const_iterator first
= warnings
.begin();
1267 std::vector
<std::string
>::const_iterator last
= warnings
.end();
1268 for (;first
!= last
; ++first
) { nlwarning("%s", first
->c_str()); }
1271 mergeStringDiff(reference
, Languages
[l
], "clause_", ".txt", false);
1273 vector
<TStringInfo
> diff
;
1275 makeStringDiff(addition
, reference
, diff
);
1279 LOG("No difference for language %s\n", Languages
[l
].c_str());
1283 LOG("Writing difference file for %s.\n", Languages
[l
].c_str());
1284 // build the diff file for each language.
1285 ucstring str
= prepareStringFile(diff
, false);
1287 // add the tag for non translation
1288 str
+= nl
+ ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE") + nl
+ ucstring("// DIFF NOT TRANSLATED") + nl
;
1290 std::string
diffName(diffDir
+"clause_"+Languages
[l
]+"_diff_"+diffVersion
+".txt");
1291 CI18N::writeTextFile(diffName
, str
);
1300 REMOVE OLDVALUE: from a diff clause file
1302 int cleanClauseDiff(int argc
, char *argv
[])
1305 LOG("Cleaning clause diffs\n");
1309 for (l
=0; l
<Languages
.size(); ++l
)
1312 std::string
basename("clause_"+Languages
[l
]);
1314 vector
<string
> diffs
;
1316 getPathContentFiltered(diffDir
+"clause_"+Languages
[l
]+"_diff_", ".txt", diffs
);
1317 for (i
=0; i
<diffs
.size(); ++i
)
1319 cleanComment(diffs
[i
]);
1325 int mergeClauseDiff(int argc
, char *argv
[])
1327 LOG("Merging clause diffs\n");
1328 // for each language
1330 for (l
=0; l
<Languages
.size(); ++l
)
1332 LOG("Merging for language %s...\n", Languages
[l
].c_str());
1333 string filename
= transDir
+"clause_"+Languages
[l
]+".txt";
1334 // load the translated file
1335 vector
<TStringInfo
> translated
;
1336 if (!loadStringFile(filename
, translated
, false))
1338 LOG("Error will loading file %s", filename
.c_str());
1342 // append the translated diffs
1343 mergeStringDiff(translated
, Languages
[l
], "clause_", ".txt", true, true);
1345 // prepare the addition string
1346 ucstring str
= prepareStringFile(translated
, true);
1349 // backup the original file
1351 CI18N::readTextFile(filename
, old
, true, false, CI18N::LINE_FMT_LF
);
1353 CFile::moveFile(historyDir
+CFile::getFilenameWithoutExtension(filename
)+"_"+diffVersion
+"."+CFile::getExtension(filename
), filename
);
1356 CI18N::writeTextFile(filename
, str
);
1364 bool mergeWorksheetDiff(const std::string filename
, TWorksheet
&sheet
, bool onlyTranslated
, bool archiveDiff
)
1366 std::string
fn(CFile::getFilenameWithoutExtension(filename
)), ext(CFile::getExtension(filename
));
1367 vector
<string
> fileList
;
1368 getPathContentFiltered(diffDir
+fn
+"_diff_", ext
, fileList
);
1371 for (i
=0; i
<fileList
.size(); ++i
)
1376 CI18N::readTextFile(fileList
[i
], text
, false, false, CI18N::LINE_FMT_LF
);
1377 if (text
.find(ucstring("DIFF NOT TRANSLATED")) != ucstring::npos
)
1379 LOG("Diff file [%s] is not translated, merging it later.\n", CFile::getFilename(fileList
[i
]).c_str());
1380 for (i
=i
+1; i
<fileList
.size(); ++i
)
1381 LOG(" Merge of Diff file [%s] delayed.\n", CFile::getFilename(fileList
[i
]).c_str());
1387 if (!loadExcelSheet(fileList
[i
], diff
, false))
1389 makeHashCode(diff
, false);
1392 if (!diff
.findCol(ucstring("DIFF_CMD"), cmdCol
))
1394 LOG("Can't find DIFF_CMD column in %s ! Invalid diff file.\n", CFile::getFilename(fileList
[i
]).c_str());
1399 if (!diff
.findCol(ucstring("*HASH_VALUE"), hashCol
))
1402 // we found a diff file for the addition file.
1403 LOG("Adding %s diff as reference\n", fileList
[i
].c_str());
1405 for (uint j
=1; j
<diff
.Data
.size(); ++j
)
1408 if (!parseDiffCommandFromComment(diff
.getData(j
, cmdCol
), diffInfo
))
1410 if (diff
.getData(j
, cmdCol
).find(ucstring("REMOVE THE FOLOWING TWO LINE WHEN TRANSLATION IS DONE")) == ucstring::npos
1411 && diff
.getData(j
, cmdCol
).find(ucstring("DIFF NOT TRANSLATED")) == ucstring::npos
)
1417 switch(diffInfo
.Command
)
1421 nlassertex(diffInfo
.Index1
<= sheet
.Data
.size(),
1422 ("ADD cmd in diff file reference row %u, but worksheet only contains %u entries",
1423 diffInfo
.Index1
, sheet
.Data
.size()));
1424 TWorksheet::TRow
row(sheet
.ColCount
);
1425 sheet
.Data
.insert(sheet
.Data
.begin()+diffInfo
.Index1
, row
);
1426 for (uint k
=0; k
<diff
.ColCount
; ++k
)
1429 sheet
.setData(diffInfo
.Index1
, diff
.Data
[0][k
], diff
.Data
[j
][k
]);
1435 nlassertex(diffInfo
.Index1
<= sheet
.Data
.size(),
1436 ("CHANGED cmd in diff file reference row %u, but worksheet only contains %u entries",
1437 diffInfo
.Index1
, sheet
.Data
.size()));
1438 for (uint k
=0; k
<diff
.ColCount
; ++k
)
1441 sheet
.setData(diffInfo
.Index1
, diff
.Data
[0][k
], diff
.Data
[j
][k
]);
1446 nlassertex(diffInfo
.Index1
< sheet
.Data
.size(),
1447 ("REMOVE cmd in diff file reference row %u, but worksheet only contains %u entries",
1448 diffInfo
.Index1
, sheet
.Data
.size()));
1449 // nlassertex(diffInfo.Index1 > 0);
1450 sheet
.Data
.erase(sheet
.Data
.begin() + diffInfo
.Index1
);
1453 nlassertex(diffInfo
.Index1
< sheet
.Data
.size(),
1454 ("SWAP cmd in diff file, first index reference row %u, but worksheet only contains %u entries",
1455 diffInfo
.Index1
, sheet
.Data
.size()));
1456 // nlassertex(diffInfo.Index1 > 0);
1457 nlassertex(diffInfo
.Index2
< sheet
.Data
.size(),
1458 ("SWAP cmd in diff file, second index reference row %u, but worksheet only contains %u entries",
1459 diffInfo
.Index1
, sheet
.Data
.size()));
1460 // nlassertex(diffInfo.Index2 > 0);
1461 swap(sheet
[diffInfo
.Index1
], sheet
[diffInfo
.Index2
]);
1465 nlassertex(diffInfo
.Index1
<= sheet
.Data
.size(),
1466 ("KEEP cmd in diff file reference row %u, but worksheet only contains %u entries",
1467 diffInfo
.Index1
, sheet
.Data
.size()));
1470 nlerror("Hash column not available, keep not implemented");
1474 sheet
.setData(diffInfo
.Index1
, diff
.Data
[0][hashCol
], diff
.Data
[j
][hashCol
]);
1486 // move the diff file in the history dir
1487 CFile::moveFile(historyDir
+CFile::getFilename(fileList
[i
]), fileList
[i
]);
1496 bool mergeSheetDiff(const string
&type
, TWorksheet
&sheet
, const string
&language
, bool onlyTranslated
, bool archiveDiff
)
1498 return mergeWorksheetDiff(type
+"_words_"+language
+".txt", sheet
, onlyTranslated
, archiveDiff
);
1502 class CMakeWordsDiff
: public TWorkSheetDiff::IDiffCallback
1505 void run(const TWorksheet
&addition
, TWorksheet
&reference
, TWorksheet
&diff
)
1507 TWordsDiffContext
context(addition
, reference
, diff
);
1509 TWorkSheetDiff differ
;
1510 differ
.makeDiff(this, context
, true);
1513 void onEquivalent(uint addIndex
, uint refIndex
, TWordsDiffContext
&context
)
1517 void onAdd(uint addIndex
, uint refIndex
, TWordsDiffContext
&context
)
1519 TWorksheet::TRow
row(context
.Reference
.ColCount
+1);
1520 for (uint j
=0; j
<context
.Addition
.ColCount
; ++j
)
1523 if (context
.Reference
.findCol(context
.Addition
.Data
[0][j
], colIndex
))
1525 row
[colIndex
+1] = context
.Addition
.Data
[addIndex
][j
];
1529 sprintf(temp
, "DIFF ADD %u ", addIndex
);
1530 row
[0] = ucstring(temp
);
1532 nlinfo("Added %s at %u", row
[2].toString().c_str(), addIndex
);
1533 context
.Diff
.insertRow((uint
)context
.Diff
.Data
.size(), row
);
1535 void onRemove(uint addIndex
, uint refIndex
, TWordsDiffContext
&context
)
1537 TWorksheet::TRow
row(context
.Reference
.ColCount
+1);
1538 for (uint j
=0; j
<context
.Reference
.ColCount
; ++j
)
1541 if (context
.Reference
.findCol(context
.Reference
.Data
[0][j
], colIndex
))
1543 row
[colIndex
+1] = context
.Reference
.Data
[refIndex
][j
];
1547 sprintf(temp
, "DIFF REMOVED %u ", refIndex
);
1548 row
[0] = ucstring(temp
);
1550 nlinfo("Removed %s at %u", row
[2].toString().c_str(), refIndex
);
1551 context
.Diff
.insertRow((uint
)context
.Diff
.Data
.size(), row
);
1553 void onChanged(uint addIndex
, uint refIndex
, TWordsDiffContext
&context
)
1555 TWorksheet::TRow row
; //(context.Reference.ColCount+1);
1556 // copy the old content (this fill data in column that don't exist in addition worksheet)
1557 row
= context
.Reference
.Data
[refIndex
];
1558 row
.insert(row
.begin(), ucstring());
1561 for (uint j
=0; j
<context
.Addition
.ColCount
; ++j
)
1564 if (context
.Reference
.findCol(context
.Addition
.Data
[0][j
], colIndex
))
1566 row
[colIndex
+1] = context
.Addition
.Data
[addIndex
][j
];
1571 sprintf(temp
, "DIFF CHANGED %u ", addIndex
);
1574 nlinfo("Changed %s at %u", row
[2].toString().c_str(), addIndex
);
1575 context
.Diff
.insertRow((uint
)context
.Diff
.Data
.size(), row
);
1578 void onSwap(uint newIndex
, uint refIndex
, TWordsDiffContext
&context
)
1580 TWorksheet::TRow
row(context
.Reference
.ColCount
+1);
1583 sprintf(temp
, "DIFF SWAP %u %u", newIndex
, refIndex
);
1586 nlinfo("Swap %u with %u", newIndex
, refIndex
);
1587 context
.Diff
.insertRow((uint
)context
.Diff
.Data
.size(), row
);
1593 REMOVE OLDVALUE: from a diff words file
1595 int cleanWordsDiff(int argc
, char *argv
[])
1598 LOG("Cleaning words diffs\n");
1602 for (l
=0; l
<Languages
.size(); ++l
)
1605 vector
<string
> diffs
;
1607 getPathContentFiltered(diffDir
+"clause_"+Languages
[l
]+"_diff_", ".txt", diffs
);
1608 for (i
=0; i
<diffs
.size(); ++i
)
1610 cleanComment(diffs
[i
]);
1617 int makeWorksheetDiff(int argc
, char *argv
[], const std::string
&additionFilename
, const std::string
&referenceFilename
, bool firstLanguage
)
1621 LOG("ERROR : makeWorksheetDiff need a worksheet file in parameter !");
1624 std::string filename = argv[2];
1626 LOG("Loading working for %s...\n", referenceFilename
.c_str());
1628 // loads the working file
1629 TWorksheet addition
;
1632 if (!loadExcelSheet(addDir
+ additionFilename
, addition
))
1637 if (!loadExcelSheet(transDir
+ additionFilename
, addition
))
1641 makeHashCode(addition
, true);
1643 TWorksheet reference
;
1644 if (CFile::fileExists(transDir
+referenceFilename
))
1647 if (!loadExcelSheet(transDir
+referenceFilename
, reference
))
1649 LOG("Error reading worksheet file '%s'", (transDir
+referenceFilename
).c_str());
1653 if (!CFile::fileExists(transDir
+referenceFilename
))
1655 // init the reference column with addition column
1656 TWorksheet::TRow
row(addition
.ColCount
);
1657 for (uint j
=0; j
<addition
.ColCount
; ++j
)
1659 nldebug("Adding column %s into reference sheet", addition
.Data
[0][j
].toString().c_str());
1660 row
[j
] = addition
.Data
[0][j
];
1661 reference
.insertColumn(0);
1663 reference
.insertRow(0, row
);
1665 makeHashCode(reference
, false);
1667 mergeWorksheetDiff(referenceFilename
, reference
, false, false);
1668 // mergeSheetDiff(type, reference, Languages[l], false, false);
1670 // generate the diff
1672 TWorksheet::TRow
row(reference
.ColCount
+1);
1673 // create the needed column.
1674 row
[0] = ucstring("DIFF_CMD");
1675 diff
.insertColumn(0);
1676 for (uint j
=0; j
<reference
.ColCount
; ++j
)
1678 row
[j
+1] = reference
.Data
[0][j
];
1679 diff
.insertColumn(j
+1);
1681 diff
.insertRow(0, row
);
1683 CMakeWordsDiff differ
;
1684 differ
.run(addition
, reference
, diff
);
1687 // write the diff file
1688 if (diff
.Data
.size() <= 1)
1690 LOG("No difference for '%s'.\n", referenceFilename
.c_str());
1694 LOG("Writing difference file for %s.\n", referenceFilename
.c_str());
1695 // build the diff file for each language.
1696 ucstring str
= prepareExcelSheet(diff
);
1698 // add the tag for non translation
1699 str
+= ucstring ("REMOVE THE FOLOWING TWO LINE WHEN TRANSLATION IS DONE") + nl
+ ucstring("DIFF NOT TRANSLATED") + nl
;
1701 string
fn(CFile::getFilenameWithoutExtension(referenceFilename
)), ext(CFile::getExtension(referenceFilename
));
1702 std::string
diffName(diffDir
+fn
+"_diff_"+diffVersion
+"."+ext
);
1703 CI18N::writeTextFile(diffName
, str
);
1710 int mergeWorksheetDiff(int argc
, char *argv
[], const std::string
&filename
, const string
&additionFile
)
1714 LOG("ERROR : mergeWorksheetDiff need a worksheet file in parameter !");
1717 std::string filename = argv[2];
1719 LOG("Merging for file '%s'...\n", filename
.c_str());
1720 // string filename = transDir+types[t]+"_words_"+Languages[l]+".txt";
1721 // load the translated file
1722 TWorksheet translated
;
1723 if (!CFile::fileExists(transDir
+filename
) || !loadExcelSheet(transDir
+filename
, translated
))
1725 // there is no translated file yet, build one from the working file.
1727 string addfn
= addDir
+additionFile
;
1728 CI18N::readTextFile(addfn
, str
, false, false, CI18N::LINE_FMT_LF
);
1729 str
= str
.substr(0, str
.find(nl
)+2);
1730 CI18N::writeTextFile(transDir
+filename
, str
);
1732 bool res
= loadExcelSheet(transDir
+filename
, translated
);
1736 makeHashCode(translated
, false);
1738 // append the translated diffs
1739 mergeWorksheetDiff(filename
, translated
, true, true);
1740 // mergeSheetDiff(types[t], translated, Languages[l], true, true);
1742 // prepare the addition string
1743 ucstring str
= prepareExcelSheet(translated
);
1746 // backup the original file
1748 CI18N::readTextFile(transDir
+filename
, old
, true, false, CI18N::LINE_FMT_LF
);
1751 string
fn(CFile::getFilenameWithoutExtension(filename
)), ext(CFile::getExtension(filename
));
1752 CFile::moveFile((historyDir
+fn
+"_"+diffVersion
+"."+ext
).c_str(), (transDir
+filename
).c_str());
1756 if (translated
.size() > 0)
1757 CI18N::writeTextFile(transDir
+filename
, str
);
1763 int makeWordsDiff(int argc
, char *argv
[])
1765 vector
<string
> fileList
;
1766 CPath::getPathContent(addDir
, false, false, true, fileList
);
1768 // filter in words file only
1770 for (i
=0; i
<fileList
.size(); ++i
)
1772 if (fileList
[i
].find("_words_"+Languages
[0]+".txt") == string::npos
|| fileList
[i
].find(".#") != string::npos
)
1774 fileList
.erase(fileList
.begin()+i
);
1781 // for each word file
1782 for (uint i
=0; i
<fileList
.size(); ++i
)
1785 type
= CFile::getFilename(fileList
[i
]);
1786 type
= type
.substr(0, type
.find("_") );
1788 for (uint l
=0; l
<Languages
.size(); ++l
)
1790 LOG("Diffing for language %s, type %s...\n", Languages
[l
].c_str(), type
.c_str());
1793 ret
+= makeWorksheetDiff(argc
, argv
, CFile::getFilename(fileList
[i
]), CFile::getFilename(fileList
[i
]), true);
1795 ret
+= makeWorksheetDiff(argc
, argv
, CFile::getFilename(fileList
[i
]), type
+"_words_"+Languages
[l
]+".txt", false);
1803 int mergeWordsDiff(int argc
, char *argv
[])
1805 LOG("Merging words diffs\n");
1809 vector
<string
> fileList
;
1810 CPath::getPathContent(addDir
, false, false, true, fileList
);
1812 // filter in words file only
1813 for (uint i
=0; i
<fileList
.size(); ++i
)
1815 if (fileList
[i
].find("_words_"+Languages
[0]+".txt") == string::npos
)
1817 fileList
.erase(fileList
.begin()+i
);
1822 // for each language
1823 for (uint l
=0; l
<Languages
.size(); ++l
)
1826 for (uint i
=0; i
<fileList
.size(); ++i
)
1829 type
= CFile::getFilename(fileList
[i
]);
1830 type
= type
.substr(0, type
.find("_") );
1832 ret
+= mergeWorksheetDiff(argc
, argv
, type
+"_words_"+Languages
[l
]+".txt", CFile::getFilename(fileList
[i
]));
1851 string Step0ProgDesc
;
1856 bool operator() (const TClause
&c1
, const TClause
&c2
)
1858 return count(c1
.Conditions
.begin(), c1
.Conditions
.end(), '&') > count(c2
.Conditions
.begin(), c2
.Conditions
.end(), '&');
1862 int recupAround(int argc
, char *argv
[])
1864 string
clause1(diffDir
+"clause_en_diff_3E896220.txt");
1865 string
clause2(addDir
+"clause_en_diff_3E7B4CE4 TRANSLATED.txt");
1867 vector
<TStringInfo
> reference
;
1868 loadStringFile(clause1
, reference
, true);
1869 vector
<TStringInfo
> around
;
1870 loadStringFile(clause2
, around
, true, '[', ']', true);
1872 vector
<TStringInfo
> result
;
1874 nlassert(reference
.size() == around
.size());
1876 for (uint i
=0; i
<reference
.size(); ++i
)
1878 TStringInfo si
= reference
[i
];
1879 si
.Text
= around
[i
].Text2
;
1880 si
.Comments
= around
[i
].Comments
;
1882 result
.push_back(si
);
1885 ucstring str
= prepareStringFile(result
, false);
1887 CI18N::writeTextFile(addDir
+"test_clause.txt", str
);
1892 //int mergeYannTaf();
1893 int addStringNumber();
1896 void cropLines(const std::string
&filename
, uint32 nbLines
)
1900 LOG("Cropping %u lines from file '%s'\n", nbLines
, filename
.c_str());
1902 CI18N::readTextFile(filename
, utext
, false, false, CI18N::LINE_FMT_LF
);
1904 string text
= utext
.toUtf8();
1906 vector
<string
> lines
;
1907 explode(text
, std::string("\n"), lines
);
1910 if (lines
.size() > nbLines
)
1912 for (uint i
=0; i
<lines
.size()-nbLines
; ++i
)
1913 text
+= lines
[i
] + "\n";
1916 utext
.fromUtf8(text
);
1918 CI18N::writeTextFile(filename
, utext
);
1925 vector
<string
> files
;
1928 // move en.uxt file to wk.uxt
1929 CFile::moveFile((CPath::standardizePath(addDir
)+"wk.uxt").c_str(), (CPath::standardizePath(addDir
)+"en.uxt").c_str());
1932 CPath::getPathContent(addDir
, true, false, true, files
);
1934 string
strreplaced("_en.txt");
1935 string
strtoreplace("_wk.txt");
1937 for (i
=0; i
<files
.size(); ++i
)
1939 if (testWildCard(CFile::getFilename(files
[i
]).c_str(), "*_en.txt"))
1941 std::string filename
= files
[i
];
1942 nlinfo("checking file '%s'", filename
.c_str());
1944 // change #include "*_en.txt" into #include "*_wk.txt"
1947 CI18N::readTextFile(filename
, utext
, false, false, CI18N::LINE_FMT_LF
);
1948 string text
= utext
.toUtf8();
1950 bool changedFile
= false;
1952 string::size_type p
= 0;
1953 while ( (p
=text
.find("#include", p
)) != string::npos
)
1955 string::size_type start
= p
, end
;
1956 while (start
< text
.size() && text
[start
++] != '"')
1959 while (end
< text
.size() && text
[end
] != '"')
1962 string includefilename
= text
.substr(start
, end
-start
);
1964 if (testWildCard(includefilename
.c_str(), "*_en.txt"))
1966 string originalfilename
= includefilename
;
1967 includefilename
.replace(includefilename
.size()-strreplaced
.size(), strreplaced
.size(), strtoreplace
);
1968 text
.replace(start
, end
-start
, includefilename
);
1970 nlinfo("replaced '#include \"%s\"' into '#include \"%s\"'", originalfilename
.c_str(), includefilename
.c_str());
1979 utext
.fromUtf8(text
);
1980 CI18N::writeTextFile(filename
, utext
);
1984 std::string movetofilename
= filename
;
1985 movetofilename
.replace(movetofilename
.size()-strreplaced
.size(), strreplaced
.size(), strtoreplace
);
1987 if (CFile::moveFile(movetofilename
.c_str(), filename
.c_str()))
1989 nlinfo("moved file '%s' to '%s'", filename
.c_str(), movetofilename
.c_str());
1993 nlwarning("FAILED to move file '%s' to '%s'", filename
.c_str(), movetofilename
.c_str());
1998 // move en.uxt file to wk.uxt
1999 CFile::moveFile((CPath::standardizePath(transDir
)+"wk.uxt").c_str(), (CPath::standardizePath(transDir
)+"en.uxt").c_str());
2002 CPath::getPathContent(transDir
, true, false, true, files
);
2004 for (i
=0; i
<files
.size(); ++i
)
2006 if (testWildCard(CFile::getFilename(files
[i
]).c_str(), "*_en.txt"))
2008 std::string filename
= files
[i
];
2009 nlinfo("checking file '%s'", filename
.c_str());
2012 std::string movetofilename
= filename
;
2013 movetofilename
.replace(movetofilename
.size()-strreplaced
.size(), strreplaced
.size(), strtoreplace
);
2015 nlinfo("moved file '%s' to '%s'", filename
.c_str(), movetofilename
.c_str());
2017 CFile::moveFile(movetofilename
.c_str(), filename
.c_str());
2025 void preprocessTextFile(const std::string
&filename
,
2026 std::vector
< std::pair
<ucstring
, std::string
> > & outputResult
);
2028 void assertUniq(const vector
<TPhrase
>& reference
)
2031 std::set
< std::string
> phraseIdentifier
;
2032 std::set
< std::string
> clauseIdentifier
;
2033 vector
<TPhrase
>::const_iterator
first( reference
.begin() );
2034 vector
<TPhrase
>::const_iterator
last( reference
.end() );
2035 for( ; first
!= last
; ++first
)
2037 if ( phraseIdentifier
.find(first
->Identifier
) != phraseIdentifier
.end())
2039 nlwarning("Phrase %s defined more than once.", first
->Identifier
.c_str());
2044 phraseIdentifier
.insert(first
->Identifier
);
2045 vector
<TClause
>::const_iterator
first2( first
->Clauses
.begin() );
2046 vector
<TClause
>::const_iterator
last2( first
->Clauses
.end() );
2047 for( ; first2
!= last2
; ++first2
)
2049 if (clauseIdentifier
.find(first2
->Identifier
) != clauseIdentifier
.end() )
2051 nlwarning("Clause %s defined more than once.", first2
->Identifier
.c_str());
2061 void mergePhraseDiff2Impl(vector
<TPhrase
>& reference
, const vector
<TPhrase
>& addition
)
2063 assertUniq(reference
);
2064 assertUniq(addition
);
2066 typedef std::map
<std::string
, TPhrase
> TMap
;
2071 vector
<TPhrase
>::const_iterator
first( reference
.begin() );
2072 vector
<TPhrase
>::const_iterator
last( reference
.end() );
2073 for( ; first
!= last
; ++first
)
2075 std::string identifier
= first
->Identifier
;
2076 phrases
[identifier
] = *first
;
2081 vector
<TPhrase
>::const_iterator
first( addition
.begin() );
2082 vector
<TPhrase
>::const_iterator
last( addition
.end() );
2083 for( ; first
!= last
; ++first
)
2085 if ( first
->Comments
.find(ucstring("DIFF CHANGED")) != ucstring::npos
)
2087 nlassert( phrases
.find(first
->Identifier
) != phrases
.end() );
2088 phrases
[first
->Identifier
] = *first
;
2090 else if ( first
->Comments
.find(ucstring("DIFF ADD")) != ucstring::npos
)
2092 nlassert( phrases
.find(first
->Identifier
) == phrases
.end() );
2093 phrases
[first
->Identifier
] = *first
;
2095 else if ( first
->Comments
.find(ucstring("DIFF REMOVED")) != ucstring::npos
)
2097 nlassert( phrases
.find(first
->Identifier
) != phrases
.end() );
2098 phrases
.erase( phrases
.find(first
->Identifier
));
2100 else if ( first
->Comments
.find(ucstring("DIFF KEEP")) != ucstring::npos
)
2102 nlassert( phrases
.find(first
->Identifier
) != phrases
.end() );
2103 phrases
[first
->Identifier
].HashValue
= first
->HashValue
;
2104 phrases
[first
->Identifier
].Comments
= first
->Comments
;
2108 // nlassert(0 && "INVALID DIFF COMMAND");
2115 reference
.reserve(phrases
.size());
2116 TMap::const_iterator
first( phrases
.begin() );
2117 TMap::const_iterator
last( phrases
.end() );
2118 for( ; first
!= last
; ++first
) { reference
.push_back(first
->second
); }
2123 void removeHashValueComment(ucstring
& comments
)
2125 ucstring::size_type first
;
2126 ucstring::size_type last
;
2127 first
= comments
.rfind(ucstring("// HASH_VALUE"));
2128 if (first
!= ucstring::npos
)
2130 last
= comments
.find(ucstring("\n"), first
);
2131 if (last
!= ucstring::npos
)
2134 ucstring tmp1
= comments
.substr(0, first
);
2135 ucstring tmp2
= last
!=comments
.size()
2136 ? comments
.substr(last
)
2138 comments
= tmp1
+ tmp2
;
2142 comments
= comments
.substr(0, first
);
2147 //comments = comments;
2152 bool updateClauseHashValue(const std::map
<std::string
, std::pair
<uint64
, uint64
> >& validValues
, const std::string
& dirPath
= "")
2155 for (uint l
=0; l
<Languages
.size() ; ++l
)
2158 std::string
basename("clause_"+Languages
[l
]);
2159 vector
<TStringInfo
> clauses
;
2160 std::string
refFile(basename
+".txt");
2161 if (!loadStringFile(transDir
+refFile
, clauses
, false))
2163 LOG("Error will loading file %s", (transDir
+refFile
).c_str());
2167 bool changed
= false;
2168 for ( uint i
=0; i
< clauses
.size() ; ++i
)
2170 std::string Identifier
= clauses
[i
].Identifier
;
2171 if ( validValues
.find(Identifier
) != validValues
.end())
2173 if (!validValues
.find(Identifier
)->second
.second
2174 || clauses
[i
].HashValue
== validValues
.find(Identifier
)->second
.second
)
2176 clauses
[i
].HashValue
= validValues
.find(Identifier
)->second
.first
;
2177 removeHashValueComment(clauses
[i
].Comments
);
2185 nlwarning("Clauses file don't need update for language %s\n", Languages
[l
].c_str());
2189 nlinfo("Updating hashcode of clause file for %s.\n", Languages
[l
].c_str());
2190 // build the diff file for each language.
2191 ucstring str
= prepareStringFile(clauses
, false);
2192 std::string
clauseName(dirPath
+ transDir
+ basename
+".txt");
2193 CFile::createDirectoryTree( CFile::getPath(clauseName
) );
2194 CI18N::writeTextFile(clauseName
, str
);
2201 ucstring
preparePhraseFile2(const vector
<TPhrase
> &phrases
, bool removeDiffComments
)
2204 vector
<TPhrase
>::const_iterator
first(phrases
.begin()), last(phrases
.end());
2205 for (; first
!= last
; ++first
)
2207 const TPhrase
&p
= *first
;
2209 if (removeDiffComments
)
2211 string comment
= p
.Comments
.toString();
2212 vector
<string
> lines
;
2213 explode(comment
, std::string("\n"), lines
, true);
2216 for (i
=0; i
<lines
.size(); ++i
)
2218 if (lines
[i
].find("// DIFF ") != string::npos
)
2220 lines
.erase(lines
.begin()+i
);
2226 for (i
=0; i
<lines
.size(); ++i
)
2228 comment
+= lines
[i
] + "\n";
2230 p
.Comments
= ucstring(comment
);
2234 if (!p
.Identifier
.empty() || !p
.Clauses
.empty())
2236 /*if (p.Comments.find(ucstring("// HASH_VALUE ")) == ucstring::npos)
2238 // add the hash value.
2239 ret += ucstring("// HASH_VALUE ")+CI18N::hashToString(p.HashValue) + nl;
2241 ret
+= p
.Identifier
+ "("+p
.Parameters
+ ")" + nl
;
2244 for (uint i
=0; i
<p
.Clauses
.size(); ++i
)
2246 const TClause
&c
= p
.Clauses
[i
];
2247 if (!c
.Comments
.empty())
2249 ucstring comment
= tabLines(1, c
.Comments
);
2250 if (comment
[comment
.size()-1] == ucchar(' ')) comment
=comment
.substr(0, comment
.size() - 1);
2251 ret
+= comment
; // + '\r'+'\n';
2253 if (!c
.Conditions
.empty())
2255 ucstring cond
= tabLines(1, c
.Conditions
);
2260 ucstring text
= CI18N::makeMarkedString('[', ']', c
.Text
);;
2262 // add new line and tab after each \n tag
2263 ucstring::size_type pos
;
2264 const ucstring
nlTag("\\n");
2265 while ((pos
= text
.find(nlTag
)) != ucstring::npos
)
2267 text2
+= text
.substr(0, pos
+2) + nl
;
2268 text
= text
.substr(pos
+2);
2270 text2
+= text
;//.substr(0, pos+2);
2274 text
= tabLines(3, text
);
2275 // remove begin tabs
2276 text
= text
.substr(3);
2277 ret
+= '\t' + (c
.Identifier
.empty()? "" : c
.Identifier
+ ' ' )+ text
+ nl
+ nl
;
2287 bool updatePhraseHashValue(const std::map
<std::string
, std::pair
<uint64
, uint64
> > & validValues
, const std::string
& dirPath
= "")
2290 for (uint l
=0; l
<Languages
.size() ; ++l
)
2293 std::string
basename("phrase_"+Languages
[l
]);
2294 vector
<TPhrase
> phrases
;
2295 std::string
refFile(basename
+".txt");
2296 if (!readPhraseFile(transDir
+refFile
, phrases
, false))
2298 LOG("Error will loading file %s", (transDir
+refFile
).c_str());
2302 bool changed
= false;
2303 for ( uint i
=0; i
< phrases
.size() ; ++i
)
2305 std::string Identifier
= phrases
[i
].Identifier
;
2306 if ( validValues
.find(Identifier
) != validValues
.end())
2308 if (!validValues
.find(Identifier
)->second
.second
|| phrases
[i
].HashValue
== validValues
.find(Identifier
)->second
.second
)
2311 phrases
[i
].HashValue
= validValues
.find(Identifier
)->second
.first
;
2312 removeHashValueComment(phrases
[i
].Comments
);
2320 nlinfo("Phrase file don't need update for language %s\n", Languages
[l
].c_str());
2324 nlinfo("Updating hashcode of phrase file for %s.\n", Languages
[l
].c_str());
2325 // build the diff file for each language.
2326 ucstring str
= preparePhraseFile(phrases
, false);
2327 std::string
pharseName(dirPath
+ transDir
+ basename
+".txt");
2328 CFile::createDirectoryTree( CFile::getPath(pharseName
) );
2329 CI18N::writeTextFile(pharseName
, str
);
2337 bool sortTransPhrase()
2340 for (uint l
=0; l
<Languages
.size() ; ++l
)
2343 std::string
basename("phrase_"+Languages
[l
]);
2344 vector
<TPhrase
> phrases
;
2345 vector
<TPhrase
> phrases2
;
2346 std::map
<std::string
, TPhrase
> phraseMap
;
2347 std::string
refFile(basename
+".txt");
2348 if (!readPhraseFile(transDir
+refFile
, phrases
, false))
2350 LOG("Error will loading file %s", (transDir
+refFile
).c_str());
2356 std::vector
<TPhrase
>::const_iterator
first(phrases
.begin());
2357 std::vector
<TPhrase
>::const_iterator
last(phrases
.end());
2358 for ( ; first
!= last
; ++first
)
2360 phraseMap
[first
->Identifier
] = *first
;
2364 std::map
<std::string
, TPhrase
>::const_iterator
first(phraseMap
.begin());
2365 std::map
<std::string
, TPhrase
>::const_iterator
last(phraseMap
.end());
2366 for ( ; first
!= last
; ++first
)
2368 phrases2
.push_back( first
->second
);
2372 nlinfo("Updating hashcode of phrase file for %s.", Languages
[l
].c_str());
2373 // build the diff file for each language.
2374 ucstring str
= preparePhraseFile(phrases2
, false);
2375 std::string
pharseName(transDir
+refFile
);
2376 CFile::createDirectoryTree( CFile::getPath(pharseName
) );
2377 CI18N::writeTextFile(pharseName
, str
);
2385 void patchWorkFile(vector
<TPhrase
> &updatedPhrase
, const std::string
& filename
)
2388 if ( updatedPhrase
.empty() ) { return; }
2389 CI18N::readTextFile(filename
, text
, false, false, CI18N::LINE_FMT_LF
);
2390 vector
<TPhrase
>::const_iterator
first(updatedPhrase
.begin());
2391 vector
<TPhrase
>::const_iterator
last(updatedPhrase
.end());
2392 for (; first
!= last
; ++first
)
2395 ucstring::size_type firstFun
= text
.find( ucstring(first
->Identifier
));
2396 if (firstFun
== ucstring::npos
)
2398 nlwarning("Error can't patch %s: %s not found", filename
.c_str(), first
->Identifier
.c_str());
2402 ucstring::size_type lastFun
= text
.find( ucstring("}") , firstFun
);
2403 if (lastFun
== ucstring::npos
)
2405 nlwarning("Error can't patch %s: syntax error near %s", filename
.c_str(), first
->Identifier
.c_str());
2409 std::vector
<TPhrase
> param
;
2410 param
.push_back(*first
);
2412 ucstring before
= text
.substr(0,firstFun
);
2413 ucstring str
= preparePhraseFile2(param
, false);
2414 ucstring after
= text
.substr(lastFun
+1);
2422 CI18N::writeTextFile( filename
, text
);
2426 int updatePhraseWork()
2428 std::string saveDir
= diffDir
+ "update_"+ diffVersion
+ "/";
2429 vector
<TPhrase
> transPhrase
;
2430 std::map
<std::string
, TPhrase
> transPhraseMap
;
2431 std::map
<std::string
, std::pair
<uint64
,uint64
> > validClauseHashValue
;
2432 std::map
<std::string
, std::pair
<uint64
, uint64
> > validPhraseHashValue
;
2433 std::vector
< std::pair
<ucstring
, std::string
> > outputResult
;
2435 if (!readPhraseFile(transDir
+"phrase_wk.txt", transPhrase
, false))
2437 LOG("Error will loading file %s", (addDir
+"phrase_"+Languages
[0]+".txt").c_str());
2442 std::vector
<TPhrase
>::const_iterator
first(transPhrase
.begin());
2443 std::vector
<TPhrase
>::const_iterator
last(transPhrase
.end());
2444 for (; first
!= last
;++first
)
2446 transPhraseMap
[first
->Identifier
] = *first
;
2450 preprocessTextFile(addDir
+"phrase_wk.txt", outputResult
);
2453 uint lastFile
= (uint
)outputResult
.size();
2454 for (; firstFile
!= lastFile
; ++firstFile
)
2456 ucstring doc
= outputResult
[firstFile
].first
;
2457 std::vector
<TPhrase
> phrases
;
2458 readPhraseFileFromString(outputResult
[firstFile
].first
, outputResult
[firstFile
].second
, phrases
, true);
2460 std::vector
<TPhrase
>::iterator
first(phrases
.begin());
2461 std::vector
<TPhrase
>::iterator
last(phrases
.end());
2462 std::vector
<TPhrase
> updatedPhrases
;
2463 for (; first
!= last
; ++first
)
2465 if (transPhraseMap
.find(first
->Identifier
) != transPhraseMap
.end() )
2467 TPhrase workPhrase
= *first
;
2468 TPhrase
& transPhrase
= transPhraseMap
[first
->Identifier
];
2469 if (first
->HashValue
== transPhrase
.HashValue
)
2471 uint64 oldHash
= transPhrase
.HashValue
;
2472 uint64 newHash
= STRING_MANAGER::makePhraseHash(transPhrase
);
2473 if (newHash
!= transPhrase
.HashValue
)
2475 //translation phrase_wk.txt has been manually changed
2476 validPhraseHashValue
[transPhrase
.Identifier
] = std::pair
<uint64
, uint64
>(newHash
, oldHash
);
2477 std::vector
<TClause
>::iterator
firstClause ( transPhrase
.Clauses
.begin() );
2478 std::vector
<TClause
>::iterator
lastClause ( transPhrase
.Clauses
.end() );
2479 for (; firstClause
!= lastClause
; ++firstClause
)
2481 uint64 clauseHashValue
= CI18N::makeHash(firstClause
->Text
);
2483 validClauseHashValue
[firstClause
->Identifier
] = std::pair
<uint64
, uint64
>(clauseHashValue
, firstClause
->HashValue
);
2484 firstClause
->HashValue
= clauseHashValue
;
2486 updatedPhrases
.push_back(transPhrase
);
2487 updatedPhrases
.back().Comments
.clear();
2494 std::string newFile
= saveDir
+ outputResult
[firstFile
].second
;
2495 std::string oldFile
= outputResult
[firstFile
].second
;
2496 CFile::createDirectoryTree(CFile::getPath(newFile
));
2497 if ( CFile::copyFile(newFile
, oldFile
) )
2500 patchWorkFile(updatedPhrases
, newFile
);
2504 nlwarning("Can't copy %s", newFile
.c_str());
2509 updatePhraseHashValue(validPhraseHashValue
, saveDir
);
2510 updateClauseHashValue(validClauseHashValue
, saveDir
);
2517 bool mergePhraseDiff2(vector
<TPhrase
> &phrases
, const string
&language
, bool onlyTranslated
, bool archiveDiff
= false)
2519 vector
<string
> diffs
;
2521 getPathContentFiltered(diffDir
+"phrase_"+language
+"_diff_", ".txt", diffs
);
2523 for (uint i
=0; i
<diffs
.size(); ++i
)
2527 // Check if the diff is translated
2529 CI18N::readTextFile(diffs
[i
], text
, false, false, CI18N::LINE_FMT_LF
);
2530 verifyVersion(text
, 2);
2531 if (text
.find(ucstring("DIFF NOT TRANSLATED")) != ucstring::npos
)
2533 LOG("Diff file [%s] is not translated, merging it later.\n", CFile::getFilename(diffs
[i
]).c_str());
2534 for (i
=i
+1; i
<diffs
.size(); ++i
)
2535 LOG(" Merge of Diff file [%s] delayed.\n", CFile::getFilename(diffs
[i
]).c_str());
2542 // we found a diff file for the addition file.
2543 LOG("Adding %s diff as reference\n", diffs
[i
].c_str());
2544 vector
<TPhrase
> diff
;
2545 if (!readPhraseFile2(diffs
[i
], diff
, false))
2549 mergePhraseDiff2Impl(phrases
, diff
);
2554 // move the diff file in the history dir
2555 CFile::moveFile((historyDir
+CFile::getFilename(diffs
[i
])).c_str(), diffs
[i
].c_str());
2564 class CMakePhraseDiff2
2574 bool operator()( const TPhrase
& left
, const TPhrase
& right
) const;
2576 // bool clausesEqual( const std::vector<TClause>& left, const std::vector<TClause>& right) const;
2578 // bool clauseEqual(const TClause& left, const TClause& right) const;
2582 void run(const vector
<TPhrase
> &addition
, vector
<TPhrase
> &reference
, vector
<TPhrase
> &diff
);
2584 void onEquivalent(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
);
2586 void onAdd(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
);
2588 void onRemove(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
);
2590 void onChanged(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
);
2600 void CMakePhraseDiff2::run(const vector
<TPhrase
> &addition
, vector
<TPhrase
> &reference
, vector
<TPhrase
> &diff
)
2603 TPhraseDiffContext
context(addition
, reference
, diff
);
2605 std::set
<std::string
> phraseIdentifier
;
2606 std::map
<std::string
, uint
> mapAdd
;
2607 std::map
<std::string
, uint
> mapRef
;
2611 uint last
= (uint
)reference
.size();
2613 for ( ;first
!= last
; ++first
)
2615 std::string
Identifier(reference
[first
].Identifier
);
2616 mapRef
[Identifier
] = first
;
2617 phraseIdentifier
.insert(Identifier
);
2623 uint last
= (uint
)addition
.size();
2625 for ( ;first
!= last
; ++first
)
2627 std::string
Identifier(addition
[first
].Identifier
);
2628 mapAdd
[Identifier
] = first
;
2629 phraseIdentifier
.insert(Identifier
);
2633 if (mapAdd
.size() != addition
.size())
2635 nlwarning("Phrases are defined more than once in works directory");
2638 if (mapAdd
.size() != addition
.size())
2640 nlwarning("Phrases are defined more than once in translation directory");
2644 std::set
<std::string
>::iterator
first(phraseIdentifier
.begin());
2645 std::set
<std::string
>::iterator
last(phraseIdentifier
.end());
2647 for (; first
!= last
; ++first
)
2649 if ( mapAdd
.find(*first
) != mapAdd
.end()
2650 && mapRef
.find(*first
) != mapRef
.end())
2653 if ( CPhraseEqual()(addition
[mapAdd
[*first
]], reference
[mapRef
[*first
]]) )
2655 onEquivalent(mapAdd
[*first
], mapRef
[*first
], context
);
2659 onChanged(mapAdd
[*first
], mapRef
[*first
], context
);
2662 else if ( mapAdd
.find(*first
) != mapAdd
.end()
2663 && mapRef
.find(*first
) == mapRef
.end())
2665 onAdd(mapAdd
[*first
], 0, context
);
2667 else if ( mapAdd
.find(*first
) == mapAdd
.end()
2668 && mapRef
.find(*first
) != mapRef
.end())
2670 onRemove(0, mapRef
[*first
], context
);
2678 void CMakePhraseDiff2::onEquivalent(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
2682 void CMakePhraseDiff2::onAdd(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
2684 TPhrase phrase
= context
.Addition
[addIndex
];
2686 sprintf(temp
, "// DIFF ADD");
2687 phrase
.Comments
= ucstring(temp
) + nl
+ phrase
.Comments
;
2689 nlinfo("Added %s at %u", phrase
.Identifier
.c_str(), addIndex
);
2690 context
.Diff
.push_back(phrase
);
2693 void CMakePhraseDiff2::onRemove(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
2695 TPhrase phrase
= context
.Reference
[refIndex
];
2697 sprintf(temp
, "// DIFF REMOVED");
2698 // NB : on vire les commentaires car il pourrai contenir des merdes..
2699 phrase
.Comments
= ucstring(temp
) + nl
;
2700 for (uint i
=0; i
<phrase
.Clauses
.size(); ++i
)
2701 phrase
.Clauses
[i
].Comments
.erase();
2703 nlinfo("Removed %s at %u", phrase
.Identifier
.c_str(), addIndex
);
2704 context
.Diff
.push_back(phrase
);
2707 void CMakePhraseDiff2::onChanged(uint addIndex
, uint refIndex
, TPhraseDiffContext
&context
)
2710 // check what is changed.
2711 if (context
.Addition
[addIndex
].Parameters
!= context
.Reference
[refIndex
].Parameters
)
2712 chg
+= "// Parameter list changed." + nl
;
2713 if (context
.Addition
[addIndex
].Clauses
.size() != context
.Reference
[refIndex
].Clauses
.size())
2714 chg
+= "// Clause list changed." + nl
;
2717 for (uint i
=0; i
<context
.Addition
[addIndex
].Clauses
.size(); ++i
)
2719 if (context
.Addition
[addIndex
].Clauses
[i
].Identifier
!= context
.Reference
[refIndex
].Clauses
[i
].Identifier
)
2720 chg
+= ucstring("// Clause ") + toString(i
) + " : identifier changed." + nl
;
2721 else if (context
.Addition
[addIndex
].Clauses
[i
].Conditions
!= context
.Reference
[refIndex
].Clauses
[i
].Conditions
)
2722 chg
+= ucstring("// Clause ") + toString(i
) + " : condition changed." + nl
;
2723 else if (context
.Addition
[addIndex
].Clauses
[i
].Text
!= context
.Reference
[refIndex
].Clauses
[i
].Text
)
2724 chg
+= ucstring("// Clause ") + toString(i
) + " : text changed." + nl
;
2730 chg
= ucstring("// WARNING : Hash code changed ! check translation workflow.") + nl
;
2732 nldebug("Changed detected : %s", chg
.toString().c_str());
2735 TPhrase phrase
= context
.Addition
[addIndex
];
2736 vector
<TPhrase
> tempV
;
2737 tempV
.push_back(context
.Reference
[refIndex
]);
2738 ucstring tempT
= preparePhraseFile(tempV
, false);
2739 CI18N::removeCComment(tempT
);
2740 phrase
.Comments
= ucstring("// DIFF CHANGED ") + toString(addIndex
) + nl
+ phrase
.Comments
;
2741 phrase
.Comments
= phrase
.Comments
+ ucstring("/* OLD VALUE : [" + nl
) + tabLines(1, tempT
) + nl
+ "] */" + nl
;
2742 phrase
.Comments
= phrase
.Comments
+ chg
;
2744 nlinfo("Changed %s at %u", phrase
.Identifier
.c_str(), addIndex
);
2745 context
.Diff
.push_back(phrase
);
2749 bool CMakePhraseDiff2::CPhraseEqual::operator()( const TPhrase
& left
, const TPhrase
& right
) const
2751 bool identifierOk
= left
.Identifier
== right
.Identifier
;
2752 // bool parameterOk = left.Parameters == right.Parameters;
2753 // bool commentsOk = left.Comments == right.Comments;
2754 // bool clausesOk = clausesEqual(left.Clauses, right.Clauses);
2755 bool hashOk
= left
.HashValue
== right
.HashValue
;
2757 return identifierOk
&& hashOk
;// && parameterOk && clausesOk;
2761 bool CMakePhraseDiff2::CPhraseEqual::clausesEqual( const std::vector<TClause>& left, const std::vector<TClause>& right) const
2763 std::vector<TClause>::const_iterator first1(left.begin());
2764 std::vector<TClause>::const_iterator last1(left.end());
2765 std::vector<TClause>::const_iterator first2(right.begin());
2767 if (left.size() != right.size()) return false;
2769 for ( ; first1 != last1 && !clauseEqual(*first1, *first2); ++first1, ++first2){}
2771 return first1 == last1;
2774 bool CMakePhraseDiff2::CPhraseEqual::clauseEqual(const TClause& left, const TClause& right) const
2776 return left.Identifier != right.Identifier
2777 && left.Conditions != right.Conditions
2778 && left.Text != right.Text
2779 && left.Comments != right.Comments
2780 && left.HashValue != right.HashValue;
2787 int makePhraseDiff2(int argc
, char *argv
[])
2789 // Generate the diff file from phrase_<lang>.txt compared to the same file in translated.
2790 // The diff is generated only from the reference language for and all the languages
2792 LOG("Generating phrase diffs\nLoading the working file for language %s\n", Languages
[0].c_str());
2795 vector
<TPhrase
> addition
;
2798 if (!readPhraseFile(addDir
+"phrase_"+Languages
[0]+".txt", addition
, true))
2800 LOG("Error will loading file %s", (addDir
+"phrase_"+Languages
[0]+".txt").c_str());
2804 for (uint l
=0; l
<Languages
.size(); ++l
)
2806 LOG("Diffing with language %s...\n", Languages
[l
].c_str());
2810 // read the language 0 translated version as addition for other language
2811 if (!readPhraseFile(transDir
+"phrase_"+Languages
[0]+".txt", addition
, true))
2813 LOG("Error will loading file %s", (addDir
+"phrase_"+Languages
[0]+".txt").c_str());
2817 vector
<TPhrase
> reference
;
2818 // read the reference file
2819 if (!readPhraseFile(transDir
+"phrase_"+Languages
[l
]+".txt", reference
, false))
2821 LOG("Error will loading file %s", (transDir
+"phrase_"+Languages
[l
]+".txt").c_str());
2825 if (!mergePhraseDiff2(reference
, Languages
[l
], false))
2827 LOG("Error will merging phrase diff for language %s\n", Languages
[l
].c_str());
2831 // compare the reference an addition file, remove any equivalent strings.
2832 uint addCount
=0, refCount
=0;
2833 vector
<TPhrase
> diff
;
2835 CMakePhraseDiff2 differ
;
2836 differ
.run(addition
, reference
, diff
);
2840 LOG("No difference for language %s\n", Languages
[l
].c_str());
2844 LOG("Writing difference file for language %s\n", Languages
[l
].c_str());
2846 text
+= "// DIFF_VERSION 2\n";
2847 text
+= preparePhraseFile(diff
, false);
2848 // add the tag for non translation
2849 text
+= nl
+ ucstring ("// REMOVE THE FOLOWING LINE WHEN TRANSLATION IS DONE") + nl
+ ucstring("// DIFF NOT TRANSLATED") + nl
;
2850 CI18N::writeTextFile(diffDir
+"phrase_"+Languages
[l
]+"_diff_"+diffVersion
+".txt", text
);
2859 int forgetPhraseDiff(int argc
, char *argv
[])
2861 // merge all the phrase diff back into there repective translated phrase.
2863 LOG("forgeting phrase diffs\n");
2865 std::string
basename("phrase_"+Languages
[0]);
2866 string filename
= transDir
+basename
+".txt";
2867 // build the addition diff
2868 vector
<TPhrase
> reference
;
2871 if (!readPhraseFile(transDir
+basename
+".txt", reference
, false))
2873 LOG("Error will loading file %s", (transDir
+basename
+".txt").c_str());
2876 //assert only change
2878 std::vector
<std::string
> diffs
;
2879 getPathContentFiltered(diffDir
+"phrase_wk_diff_", ".txt", diffs
);
2880 std::vector
<TPhrase
> newPhrase
;
2881 for (uint i
=0; i
<diffs
.size(); ++i
)
2883 // we found a diff file for the addition file.
2884 LOG("Adding %s diff as reference\n", diffs
[i
].c_str());
2885 vector
<TPhrase
> subDiff
;
2886 if (!readPhraseFile2(diffs
[i
], subDiff
, false))
2888 std::copy (subDiff
.begin (), subDiff
.end (), std::back_inserter (newPhrase
));
2891 // a optimiser par une map
2892 std::map
<std::string
, std::pair
<uint64
, uint64
> > validClauseHashValue
;
2893 std::map
<std::string
, std::pair
<uint64
, uint64
> > validPhraseHashValue
;
2894 for (uint i
=0; i
< newPhrase
.size() ; ++i
)
2896 for (uint j
=0; j
< reference
.size() ; ++j
)
2898 if (newPhrase
[i
].Identifier
== reference
[j
].Identifier
)
2902 uint64 newPhraseHash
= STRING_MANAGER::makePhraseHash( newPhrase
[i
] );
2903 uint64 oldPhraseHash
= reference
[j
].HashValue
;
2904 validPhraseHashValue
[newPhrase
[i
].Identifier
] = std::pair
<uint64
, uint64
>(newPhraseHash
, oldPhraseHash
);
2906 for (uint k
=0; k
< newPhrase
[i
].Clauses
.size() ; ++k
)
2908 if (reference
[j
] .Clauses
.size() != newPhrase
[i
].Clauses
.size())
2910 nlwarning("Want to forget minor update but phrase %s changes too much. The number of clauses has changed.", newPhrase
[i
].Identifier
.c_str() );
2913 const TClause
& newClause
= newPhrase
[i
].Clauses
[k
];
2914 const TClause
& oldClause
= reference
[j
].Clauses
[k
];
2916 if (!newClause
.Identifier
.empty() )
2918 if (newClause
.Identifier
!= oldClause
.Identifier
)
2920 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());
2923 uint64 newClauseHashValue
= CI18N::makeHash(newClause
.Text
);
2924 uint64 oldClauseHashValue
= CI18N::makeHash(oldClause
.Text
);
2925 validClauseHashValue
[ newClause
.Identifier
] = std::pair
<uint64
, uint64
>(newClauseHashValue
, oldClauseHashValue
);
2933 if (!mergePhraseDiff2(reference
, Languages
[0], true, false))
2935 LOG("Error will merging phrase diff");
2938 ucstring str
= preparePhraseFile(reference
, true);
2939 CI18N::writeTextFile(transDir
+basename
+".txt", str
);
2942 updatePhraseHashValue(validPhraseHashValue
);
2943 // updateClauseHashValue(validClauseHashValue);
2946 for (uint i
=0; i
<diffs
.size(); ++i
)
2948 std::string diffHistory
= historyDir
+ CFile::getFilename(diffs
[i
]);
2949 CFile::moveFile(diffHistory
.c_str(), diffs
[i
].c_str());
2955 void preprocessTextFile(const std::string
&filename
,
2956 std::vector
< std::pair
<ucstring
, std::string
> > & outputResult
2960 //nlinfo("preprocessing %s", filename.c_str());
2962 std::string fullName
;
2963 fullName
= filename
;
2965 if (fullName
.empty())
2968 NLMISC::CIFile file
;
2970 /// Open a file for reading. false if failed. close() if a file was opened.
2971 if (!file
.open (fullName
))
2973 nlwarning("Can't open %s", fullName
.c_str());
2979 // Fast read all the text in binary mode.
2981 text
.resize(file
.getFileSize());
2982 file
.serialBuffer((uint8
*)(&text
[0]), (uint
)text
.size());
2985 // Transform the string in ucstring according to format header
2987 CI18N::readTextBuffer((uint8
*)&text
[0], (uint
)text
.size(), result
);
2992 // parse the file, looking for preprocessor command.
2993 ucstring::size_type pos
= 0;
2994 ucstring::size_type lastPos
= 0;
2995 ucstring
includeCmd("#include");
2998 while ( pos
!= ucstring::npos
)
3000 pos
= result
.find(ucstring("\n"), pos
);
3001 if (pos
!= ucstring::npos
) { ++pos
; }
3003 ucstring
line( result
.substr(lastPos
, pos
- lastPos
) );
3006 if ( line
.find(includeCmd
) != ucstring::npos
)
3008 ucstring::size_type firstFilename
= line
.find(ucstring("\""));
3009 ucstring::size_type lastFilename
= line
.find(ucstring("\""), firstFilename
+1);
3011 ucstring name
= line
.substr(firstFilename
+1, lastFilename
- firstFilename
-1);
3012 string subFilename
= name
.toString();
3014 if (!CFile::fileExists(subFilename
))
3016 // try to open the include file relative to current file
3017 subFilename
= CFile::getPath(filename
)+subFilename
;
3019 if (!CFile::fileExists(subFilename
))
3021 nlwarning("Unable to open %s", subFilename
.c_str());
3022 subFilename
.clear();
3026 preprocessTextFile(subFilename
, outputResult
);
3036 outputResult
.push_back( std::pair
<ucstring
, std::string
> ( current
, fullName
) );
3039 int mergePhraseDiff(int argc
, char *argv
[])
3041 // merge all the phrase diff back into there repective translated phrase.
3044 LOG("Merging phrase diffs\n");
3046 for (l
=0; l
<Languages
.size(); ++l
)
3048 LOG("Merging for language %s...\n", Languages
[l
].c_str());
3049 std::string
basename("phrase_"+Languages
[l
]);
3050 string filename
= transDir
+basename
+".txt";
3051 // build the addition diff
3052 vector
<TPhrase
> reference
;
3054 if (!readPhraseFile(transDir
+basename
+".txt", reference
, false))
3056 LOG("Error will loading file %s", (transDir
+basename
+".txt").c_str());
3060 if (!mergePhraseDiff(reference
, Languages
[l
], true, true))
3062 LOG("Error will merging phrase diff");
3067 ucstring str
= preparePhraseFile(reference
, true);
3070 // backup the original file
3072 CI18N::readTextFile(filename
, old
, true, false, CI18N::LINE_FMT_LF
);
3074 CFile::moveFile((historyDir
+CFile::getFilenameWithoutExtension(filename
)+"_"+diffVersion
+"."+CFile::getExtension(filename
)).c_str(), filename
.c_str());
3077 CI18N::writeTextFile(transDir
+basename
+".txt", str
);
3089 LOG("Update translation from clauses.\n");
3091 for (l
=0; l
<Languages
.size(); ++l
)
3094 nlinfo("Update phrase %s", Languages
[l
].c_str());
3095 vector
<TStringInfo
> clauses
;
3096 vector
<TPhrase
> phrases
;
3098 // load the clause file
3099 std::string
clausePath( transDir
+"clause_"+Languages
[l
]+".txt" );
3100 if (!loadStringFile(clausePath
, clauses
, false))
3102 LOG("Error will loading file %s", clausePath
.c_str());
3106 // load the phrase file
3107 std::string
phrasePath( transDir
+"phrase_"+Languages
[l
]+".txt" );
3108 if (!readPhraseFile(phrasePath
, phrases
, false))
3110 LOG("Error will loading file %s", phrasePath
.c_str());
3114 vector
<TPhrase
>::iterator
first(phrases
.begin());
3115 vector
<TPhrase
>::iterator
last(phrases
.end());
3117 for ( ; first
!= last
; ++first
)
3119 vector
<TClause
>::iterator
firstClause( first
->Clauses
.begin());
3120 vector
<TClause
>::iterator
lastClause( first
->Clauses
.end());
3121 for ( ; firstClause
!= lastClause
; ++firstClause
)
3123 vector
<TStringInfo
>::iterator
firstRefClause(clauses
.begin());
3124 vector
<TStringInfo
>::iterator
lastRefClause(clauses
.end());
3125 for ( ; firstRefClause
!= lastRefClause
; ++firstRefClause
)
3127 if (firstClause
->Identifier
== firstRefClause
->Identifier
&& firstClause
->Text
!= firstRefClause
->Text
)
3129 firstClause
->Text
= firstRefClause
->Text
;
3130 firstClause
->HashValue
= CI18N::makeHash(firstClause
->Text
);
3131 firstRefClause
->HashValue
= firstClause
->HashValue
;
3133 nlinfo("update clause %s from clause file %s.", firstClause
->Identifier
.c_str(), clausePath
.c_str());
3139 std::string
desDir(diffDir
+ "inject_clause_" + diffVersion
+ "/");
3140 CFile::createDirectoryTree(desDir
+ CFile::getPath(phrasePath
));
3141 ucstring str
= preparePhraseFile(phrases
, true);
3142 CI18N::writeTextFile(desDir
+ phrasePath
, str
);
3144 str
= prepareStringFile(clauses
, true);
3145 CI18N::writeTextFile(desDir
+ clausePath
, str
);
3153 int main(int argc
, char *argv
[])
3155 NLMISC::CApplicationContext context
;
3157 CStdDisplayer *display = new CStdDisplayer;
3158 NLMISC::InfoLog->addDisplayer(display);
3159 NLMISC::WarningLog->addDisplayer(display);
3160 NLMISC::ErrorLog->addDisplayer(display);
3163 /* for (uint i=0; i<20; ++i)
3165 uint64 hash = makeHash(ucstring("Bonjour le monde !"));
3166 nldebug("%s", hashToString(hash).c_str());
3167 hash = makeHash(ucstring("Une autre clef"));
3168 nldebug("%s", hashToString(hash).c_str());
3177 std::string
argv1(argv
[1]);
3179 // create the diff version.
3181 sprintf(temp
, "%8.8X", (uint
) ::time(NULL
));
3184 if (strcmp(argv
[1], "make_work") == 0)
3189 // generic worksheet comparison
3190 if (strcmp(argv
[1], "make_worksheet_diff") == 0)
3198 return makeWorksheetDiff(argc
, argv
, argv
[2], argv
[2], true);
3200 else if (strcmp(argv
[1], "merge_worksheet_diff") == 0)
3208 return mergeWorksheetDiff(argc
, argv
, argv
[2], argv
[2]);
3210 else if (strcmp(argv
[1], "crop_lines") == 0)
3219 NLMISC::fromString(argv
[3], nbLines
);
3221 cropLines(argv
[2], nbLines
);
3225 else if (strcmp(argv
[1], "extract_bot_names") == 0)
3226 return extractBotNames(argc
, argv
);
3227 else if (strcmp(argv
[1], "extract_new_sheet_names") == 0)
3228 return extractNewSheetNames(argc
, argv
);
3239 // if (strcmp(argv[1], "yann") == 0)
3240 // return mergeYannTaf();
3243 string
currentPath("./");
3244 CPath::addSearchPath(currentPath
+addDir
, true, false);
3245 CPath::addSearchPath(currentPath
+diffDir
, true, false);
3246 // CPath::addSearchPath(currentPath+transDir, true, false);
3247 if (readLanguages() != 0)
3249 LOG("Error will loading language file (language.txt)");
3253 if (strcmp(argv
[1], "make_string_diff") == 0)
3254 return makeStringDiff(argc
, argv
, "");
3255 else if (strcmp(argv
[1], "merge_string_diff") == 0)
3256 return mergeStringDiff(argc
, argv
, "");
3257 else if (strcmp(argv
[1], "clean_string_diff") == 0)
3258 return cleanStringDiff(argc
, argv
, "");
3260 else if (strcmp(argv
[1], "make_r2_string_diff") == 0)
3261 return makeStringDiff(argc
, argv
, "r2_");
3262 else if (strcmp(argv
[1], "merge_r2_string_diff") == 0)
3263 return mergeStringDiff(argc
, argv
, "r2_");
3264 else if (strcmp(argv
[1], "clean_r2_string_diff") == 0)
3265 return cleanStringDiff(argc
, argv
, "r2_");
3267 else if (argv1
== "make_phrase_diff_old")
3268 return makePhraseDiff(argc
, argv
);
3269 else if (argv1
== "merge_phrase_diff_old")
3270 return mergePhraseDiff(argc
, argv
, 1);
3273 else if (argv1
== "make_phrase_diff")
3274 return makePhraseDiff2(argc
, argv
);
3275 else if (argv1
== "merge_phrase_diff")
3276 return mergePhraseDiff(argc
, argv
, 2);
3277 else if (argv1
== "forget_phrase_diff")
3278 return forgetPhraseDiff(argc
, argv
);
3279 else if (argv1
== "update_phrase_work")
3280 return updatePhraseWork();
3281 else if (argv1
== "clean_phrase_diff")
3282 return cleanPhraseDiff(argc
, argv
);
3284 else if (argv1
== "inject_clause")
3285 return injectClause();
3287 else if (argv1
== "sort_trans_phrase")
3288 return sortTransPhrase();
3290 else if (strcmp(argv
[1], "make_clause_diff") == 0)
3291 return makeClauseDiff(argc
, argv
);
3292 else if (strcmp(argv
[1], "merge_clause_diff") == 0)
3293 return mergeClauseDiff(argc
, argv
);
3294 else if (argv1
== "clean_clause_diff")
3295 return cleanClauseDiff(argc
, argv
);
3297 else if (strcmp(argv
[1], "make_words_diff") == 0)
3298 return makeWordsDiff(argc
, argv
);
3299 else if (strcmp(argv
[1], "merge_words_diff") == 0)
3300 return mergeWordsDiff(argc
, argv
);
3301 else if (strcmp(argv
[1], "clean_words_diff") == 0)
3302 return cleanWordsDiff(argc
, argv
);
3304 else if (strcmp(argv
[1], "recup_around") == 0)
3305 return recupAround(argc
, argv
);
3306 else if (strcmp(argv
[1], "add_string_number") == 0)
3307 return addStringNumber();
3316 int addStringNumber()
3318 vector
<TStringInfo
> strings
;
3320 LOG("Generating string diffs\nLoading the working file for language %s\n", Languages
[0].c_str());
3321 // load the addition file
3322 std::string
addFile(Languages
[0]+".uxt");
3323 if (!loadStringFile(addDir
+addFile
, strings
, true))
3325 LOG("Error loading file %s\n", (addDir
+addFile
).c_str());
3329 ucstring str
= prepareStringFile(strings
, false);
3331 string filename
= addDir
+Languages
[0]+".uxt";
3332 CI18N::writeTextFile(filename
, str
);