first release of translation facility

* runtime - loading and translating
 * design-time - works with *.ts file (pip_tr utility)
 * compile-time - CMake macro for compile *.ts
This commit is contained in:
2024-11-05 13:49:00 +03:00
parent 73ed51e3d4
commit 57f8c1313e
52 changed files with 1571 additions and 480 deletions

139
utils/translator/parser.cpp Normal file
View File

@@ -0,0 +1,139 @@
#include "parser.h"
#include "piliterals_string.h"
#include "pistringlist.h"
PIString fromCode(const PIString & in) {
return in.replacedAll("\\n", '\n')
.replaceAll("\\r", '\r')
.replaceAll("\\t", '\t')
.replaceAll("\\\"", '"')
.replaceAll("\\'", '\'')
.replaceAll("\\\\", '\\');
}
void gatherStrings(TSFile::Content & content, const PIString & file, const PIString & file_loc, int & count_all, int & count_new) {
static const PIStringList methods({"PITranslator::tr", "PITranslator::trNoOp", "piTr", "piTrNoOp"});
static const PIStringList literals({"_tr", "_trNoOp"});
PIString source, context;
int pos = -1, ppos = 0, line = -1;
int len = 0;
auto isCLetter = [](const PIChar c) { return c.isAlpha() || c.isDigit() || c == '_'; };
auto add = [&content, file_loc, &count_all, &count_new](const PIString & source, const PIString & context, int line) {
if (source.isEmpty()) return;
++count_all;
if (content.contexts[context].confirm(fromCode(source), file_loc, line)) ++count_new;
// piCout << "Context = \"" << context << "\", message = \"" << source << "\" (" << file_loc << ":" << line << ")";
};
// piCout << "file" << file_loc;
for (const auto & kw: methods) {
// piCout << "method" << kw;
for (;;) {
source.clear();
context.clear();
pos = file.find(kw, pos + 1);
if (pos < 0) break;
if (pos > 0) {
auto pc = file[pos - 1];
if (isCLetter(pc) || pc == ':') {
pos += kw.size_s();
continue;
}
}
pos += kw.size_s();
if (pos < file.size_s() - 1) {
auto pc = file[pos];
if (isCLetter(pc) || pc == ':') {
pos += kw.size_s();
continue;
}
}
// piCout << "PITranslator" << pos;
pos = file.find('(', pos);
if (pos < 0) break;
// piCout << "(" << pos;
pos += 1;
pos = file.findRange('"', '"', '\\', pos, &len);
if (pos < 0) break;
// piCout << "\"" << pos;
source = file.mid(pos, len);
pos += len + 1;
line = file.lineNumber(pos);
ppos = pos;
while (pos < file.size_s()) {
if (!file[pos].isSpace() && file[pos] != '\n' && file[pos] != '\r') break;
++pos;
}
if (pos < file.size_s()) {
// piCout << "check comma" << file[pos];
if (file[pos] == ',') {
pos += 1;
pos = file.findRange('"', '"', '\\', pos, &len);
// piCout << "check range" << file.mid(pos, len);
if (pos >= 0) {
context = file.mid(pos, len);
pos += len + 1;
ppos = pos;
}
}
}
pos = ppos;
add(source, context, line);
}
}
for (const auto & kw: literals) {
// piCout << "literal" << kw;
pos = -1;
for (;;) {
source.clear();
context.clear();
pos = file.find('"', pos + 1);
if (pos < 0) break;
pos = file.findRange('"', '"', '\\', pos, &len);
if (pos < 0) break;
// piCout << "\"" << pos;
source = file.mid(pos, len);
pos += len + 1;
if (file.mid(pos, kw.size_s()) == kw) {
// piCout << "line" << file.lineNumber(pos);
pos += kw.size_s();
if (pos < file.size_s() - 1) {
auto pc = file[pos];
if (isCLetter(pc) || pc == ':') {
continue;
}
}
ppos = pos;
while (pos < file.size_s()) {
if (!file[pos].isSpace() && file[pos] != '\n' && file[pos] != '\r') break;
++pos;
}
if (pos < file.size_s()) {
// piCout << "check comma" << file[pos];
if (file[pos] == '(') {
pos += 1;
pos = file.findRange('"', '"', '\\', pos, &len);
// piCout << "check range" << file.mid(pos, len);
if (pos >= 0) {
context = file.mid(pos, len);
pos += len + 1;
ppos = pos;
}
}
}
pos = ppos;
if (source.isEmpty()) continue;
line = file.lineNumber(pos);
add(source, context, line);
}
}
}
}