diff --git a/utils/value_tree_translator/main.cpp b/utils/value_tree_translator/main.cpp index 5ee75a1d..580a0fcf 100644 --- a/utils/value_tree_translator/main.cpp +++ b/utils/value_tree_translator/main.cpp @@ -44,23 +44,24 @@ void header() { piCout << Bold << "PIP ValueTree translator"; piCout << Cyan << "Version" << Bold << PIPVersion() << NewLine; piCout << Green << Bold << "Usage:" << Default - << "\"pip_vtt [-hHq] -l -o [] [] [...]\"" << NewLine; + << "\"pip_vtt [-hHqn] -l -o [] [] [...]\"" << NewLine; } void usage() { header(); piCout << Green << Bold << "Details:"; piCout << Bold << "Debug control"; - piCout << "-h " << Green << "- display this message and exit"; - piCout << "-H " << Green << "- display details help"; - piCout << "-q " << Green << "- quiet, no debug output to console"; + piCout << "-h " << Green << "- display this message and exit"; + piCout << "-H " << Green << "- display details help"; + piCout << "-q " << Green << "- quiet, no debug output to console"; piCout << ""; piCout << Bold << "Output control"; - piCout << "-l " << Green << "- translation language (e.g. en_US, ru_RU)"; - piCout << "-o " << Green << "- output file for translation (QtLinguist *.ts file)"; + piCout << "-l " << Green << "- translation language (e.g. en_US, ru_RU)"; + piCout << "-n, --no-obsolete " << Green << "- drop unused translations in output file"; + piCout << "-o " << Green << "- output file for translation (QtLinguist *.ts file)"; piCout << ""; piCout << Bold << "Input control"; - piCout << " " << Green << "- add file or dir translation"; + piCout << " " << Green << "- add file or dir translation"; } void help() { @@ -74,20 +75,25 @@ void printError(const PIString & msg) { PISet strings; +PIMap locations; -void gatherStrings(const PIValueTree & vt) { +void addString(const PIString & s, const PIString & loc) { + if (s.isEmpty()) return; + strings << s; + locations[s.hash()] = loc; +} + +void gatherStrings(const PIValueTree & vt, const PIString & loc) { const static PIStringList attrs({Attribute::prefix, Attribute::suffix}); for (const auto & c: vt.children()) { - if (c.isArray()) return; - if (c.name().isNotEmpty()) strings << c.name(); - if (c.comment().isNotEmpty()) strings << c.comment(); + addString(c.name(), loc); + addString(c.comment(), loc); for (const auto & a: attrs) { if (c.attributes().contains(a)) { - PIString sa = c.attributes().value(a).toString(); - if (sa.isNotEmpty()) strings << sa; + addString(c.attributes().value(a).toString(), loc); } } - gatherStrings(c); + if (!c.isArray()) gatherStrings(c, loc); } } @@ -97,6 +103,8 @@ struct TSMessage { PIString source; PIString translation; PIString type; + PIString filename; + PIString line; }; PIMap readTS(const PIString & path) { @@ -131,8 +139,18 @@ PIMap readTS(const PIString & path) { } else if (line.startsWith("")) { line.cutLeft(8).cutRight(9); msg.source = line; + } else if (line.startsWith("').cutLeft(8); + while (trs.isNotEmpty()) { + PIString t = trs.takeCWord(); + trs.cutLeft(1); + PIString v = trs.takeRange('\"', '\"'); + if (t == "filename") msg.filename = v; + if (t == "line") msg.line = v; + if (trs.size_s() <= 2) break; + } } else if (line.startsWith("'); + PIString trs = line.takeRange('<', '>').cutLeft(11); while (trs.isNotEmpty()) { PIString t = trs.takeCWord(); trs.cutLeft(1); @@ -159,6 +177,7 @@ int main(int argc, char * argv[]) { cli.addArgument("help"); cli.addArgument("Help"); cli.addArgument("quiet"); + cli.addArgument("no-obsolete"); if (cli.hasArgument("Help")) { help(); return 0; @@ -187,12 +206,14 @@ int main(int argc, char * argv[]) { piCout << Cyan << Bold << "Read" << files.size_s() << "files ..."; + PIDir out_dir(PIFile::FileInfo(out_path).dir()); for (const auto & p: files) { PIString ext = PIFile::FileInfo(p).extension().toLowerCase().trim(); PIFile f(p, PIIODevice::ReadOnly); - if (ext == "conf") gatherStrings(PIValueTreeConversions::fromText(PIString::fromUTF8(f.readAll()))); - if (ext == "json") gatherStrings(PIValueTreeConversions::fromJSON(PIJSON::fromJSON(PIString::fromUTF8(f.readAll())))); - if (ext == "bin") gatherStrings(piDeserialize(f.readAll())); + if (ext == "conf") gatherStrings(PIValueTreeConversions::fromText(PIString::fromUTF8(f.readAll())), out_dir.relative(p)); + if (ext == "json") + gatherStrings(PIValueTreeConversions::fromJSON(PIJSON::fromJSON(PIString::fromUTF8(f.readAll()))), out_dir.relative(p)); + if (ext == "bin") gatherStrings(piDeserialize(f.readAll()), PIString()); } piCout << Cyan << Bold << "Reading done"; @@ -213,23 +234,38 @@ int main(int argc, char * argv[]) { } outf.clear(); PIIOTextStream ts(&outf); + auto writeTSMessage = [&ts](const PIString & s, const TSMessage & m) { + ts << " \n"; + ts << " " << s << "\n"; + if (m.filename.isNotEmpty()) { + ts << " \n"; + } + ts << " " << m.translation << "\n"; + ts << " \n"; + }; ts << "\n"; ts << "\n"; ts << "\n"; ts << "\n"; ts << " " << context << "\n"; for (const auto & s: strings) { - ts << " \n"; - ts << " " << s.first << "\n"; - ts << " " << m.translation << "\n"; - ts << " \n"; } ts << "\n"; ts << "\n";