Перевод исходного кода на иностранный язык
У меня работает образовательный сайт, который учит программированию детям (12-15 лет).
Поскольку они не все говорят по-английски в источнике кода решений, мы используем имена переменных и функций во Франции.
Однако мы планируем перевести контент на другие языки (немецкий, испанский, английский). Для этого я хотел бы как можно быстрее перевести исходный код.
У нас в основном есть код C/С++.
Решение, которое я планирую использовать:
- извлекать все имена переменных/функций из исходного кода, их позицию в файле (где они объявлены, используются, вызывают...)
- удалить все языковые ключевые слова и библиотечные функции.
- попросите переводчика предоставить переводы для остальных имен
- заменить имена в файле
Есть ли какой-нибудь открытый код/проект с открытым исходным кодом, который может это сделать? (Для точек 1,2 и 4)
Если этого не происходит, самая сложная точка в первом: использование синтаксического анализатора C/С++ для создания синтаксического дерева, а затем извлечение переменных с их позицией, похоже, способ. У вас есть другие идеи?
Спасибо за любые советы.
Изменить:
Как отмечено в комментарии, мне также нужно будет позаботиться о комментариях, но их осталось лишь немного: полное решение уже объяснено в текстовом виде, а затем мы показываем код-источник с самообучаемой переменной/функцией имена. Исходный код редко бывает длиннее 30/40 строк, а хорошие имена должны быть понятны без комментариев, если вы уже знаете, что делает код.
Дополнительная информация: для людей, заинтересованных в веб-сайте, является учебной площадкой для международных олимпиад по информатике и C/С++ (по крайней мере, минимальным, необходимым для конкурса на программирование), не так сложно изучить 12 лет.
Ответы
Ответ 1
Вам действительно не нужен синтаксический анализатор C/С++, просто простой лексер, который дает вам элементы кода один за другим. Затем вы получаете много {
, [
, 213
, )
и т.д., Которые вы просто игнорируете и записываете в файл результатов. Вы переводите все, что состоит из только букв (кроме ключевых слов), и вы помещаете их в вывод.
Теперь, когда я думаю об этом, это так просто:
bool is_letter(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
bool is_keyword(string &s)
{
return s == "if" || s == "else" || s == "void" /* rest of them */;
}
void translateCode(istream &in, ostream &out)
{
while (!in.eof())
{
char c = in.get();
if (is_letter(c))
{
string name = "";
do
{
name += c;
c = in.get();
} while (is_letter(c) && !in.eof());
if (is_keyword(name))
out << name;
else
out << translate(name);
}
out << c; // even if is_letter(c) was true, there is a new c from the
// while inside that was read (which was not letter), but
// not written, so would be written here.
}
}
Я написал код в редакторе, поэтому могут быть небольшие ошибки. Скажите мне, если они есть, и я исправлю это.
Изменить: Объяснение:
То, что делает код, это просто прочитать входной символ по символу, выводя любые небуквенные символы, которые он читает (включая пробелы, вкладки и новые строки). Если он видит письмо, он начнет помещать все следующие буквы в одну строку (пока не достигнет другой небукты). Тогда, если строка была ключевым словом, она вывела бы ключевое слово. Если бы это было не так, перевести его и вывести его.
Выход будет иметь тот же формат, что и вход.
Ответ 2
Вы уверены, что для этого требуется полное синтаксическое дерево? Я думаю, что достаточно будет лексического анализа, чтобы найти идентификаторы, что намного проще. Затем исключайте ключевые слова и идентификаторы, которые также отображаются в заголовочных файлах.
В принципе возможно, что вы хотите, чтобы разные переменные с одним и тем же английским именем были переведены на разные слова на французском/немецком языке, но для образовательного использования риск возникновения этого явления, вероятно, достаточно мал, чтобы сначала игнорировать. Вы можете обойти проблему, написав исходные источники с некоторыми двусмысленными квази-венгерскими префиксами, а затем удалите их с тем же механизмом перевода для отображения англоязычным конечным пользователям.
Не забудьте, чтобы переводчики увидели имя, которое они переводили, с полным контекстом, прежде чем выбрать перевод.
Ответ 3
Я действительно думаю, что вы можете использовать clang (libclang), чтобы анализировать ваши источники и делать то, что вы хотите (см. здесь для получения дополнительной информации), хорошей новостью является то, что у них есть привязки к python, что облегчит вашу жизнь, если вы хотите получить доступ к службе перевода или что-то в этом роде.
Ответ 4
Я не думаю, что замена идентификаторов в коде - хорошая идея.
Во-первых, вы не получите достойных переводов. Очень важный момент заключается в том, что перевод (особенно автоматический или довольно тупой перевод) теряет и искажает информацию. На самом деле у вас может быть что-то хуже, чем оригинал.
Во-вторых, если код предназначен для компиляции снова, компилятор, возможно, не сможет скомпилировать код, содержащий неанглийские буквы в переведенных идентификаторах.
В-третьих, если вы заменяете идентификаторы чем-то другим, вам нужно убедиться, что вы не заменяете 2 или более разных идентификатора одним и тем же словом. Это либо сделает код не компилируемым, либо разрушит его логику.
В-четвертых, вы должны убедиться, что вы не переводите зарезервированные слова и идентификаторы из стандартной библиотеки языка. Перевод этих данных сделает код не компилируемым и нечитаемым. Не может быть очень тривиальной задачей различать идентификаторы, определенные программистом, от тех, которые предоставляются языком и его стандартной библиотекой.
Что бы я сделал вместо замены идентификаторов их переводами, предоставляйте переводы как комментарии рядом с ними, например:
void eat/*comer*/(int* food/*comida*/)
{
if (*food/*comida*/ <= 0)
{
printf("nothing to eat!"/*no hay que comer!*/);
exit/*salir*/(-1);
}
(*food/*comida*/)--;
}
Таким образом вы теряете информацию из-за неправильного перевода и не нарушаете код.