Автоматизированный способ извлечения строк для Perl/Mason i18n?
В настоящее время я работаю над интернационализацией очень большого веб-приложения на Perl / Mason как команды из одного (делает ли это марш смерти??). Приложению около 20 лет, и оно написано в относительно старомодном стиле Perl; он не использует Moose или другой модуль OO. В настоящее время я планирую использовать Locale::Maketext::Gettext для поиска сообщений и использовать файлы каталога GNU Gettext.
Я пытался разработать некоторые инструменты, чтобы помочь в извлечении строк из нашей большой базы кода. В настоящее время все, что у меня есть, - это относительно простой Perl-скрипт для анализа исходного кода в поисках строковых литералов, запроса пользователю некоторого контекста и того, должна ли строка быть помечена для перевода, и отметьте его, если так.
Там слишком много шума с точки зрения строк, которые мне нужно пометить, по сравнению со строками, которые я могу игнорировать. Многие строки в источнике не ориентированы на пользователя, такие как ключи хеша или сравнения типов, такие как
if (ref($db_obj) eq 'A::Type::Of::Db::Module')
Я применяю некоторую эвристику к каждой предложенной строке, чтобы посмотреть, смогу ли я игнорировать ее с нуля (например, я игнорирую строки, которые используются для поиска по хешу, поскольку в нашей кодовой базе 99% времени они не предназначены для пользователя). Тем не менее, несмотря на все это, около 90% строк, которые моя программа показывает мне, это те, которые меня не волнуют.
Есть ли лучший способ, которым я мог бы помочь автоматизировать мою задачу извлечения строк (то есть что-то более умное, чем захват каждого строкового литерала из источника)? Существуют ли какие-либо коммерческие программы, которые делают это, которые могут обрабатывать как Perl, так и Mason?
ТАКЖЕ, у меня была (довольно глупая) идея для превосходного инструмента, рабочий процесс которого я изложил ниже. Стоит ли пытаться реализовать что-то подобное (что, вероятно, очень быстро позаботится о 80% работы), или я должен просто подчиниться трудному, надоедливому, ручному процессу извлечения строк?
- Начните с извлечения КАЖДОГО строкового литерала из источника и поместите его в PO-файл Gettext.
- Затем напишите плагин Mason для анализа HTML-кода для каждой страницы, обслуживаемой приложением, с целью отметить строки, которые видит пользователь.
- Используйте чертовски приложение и постарайтесь охватить все варианты использования, создавая хранилище пользовательских строк.
- Учитывая это хранилище строк, которое видел пользователь, выполняйте нечеткие сопоставления со строками в файле каталога и отслеживайте записи каталога, которые имеют совпадения из пользовательского интерфейса.
- В конце концов, все, что не найдено в файле каталога, скорее всего, не предназначено для пользователя, поэтому удалите его из каталога.
2 ответа
Я не знаю инструментов Perl, которые бы интеллектуально извлекали строки, которые могут нуждаться в интернационализации, а не в тех, которые не нужны Вы должны пометить их в коде по мере их написания, но, как вы сказали, это не было сделано.
Вы можете использовать PPI для интеллектуального извлечения строк.
#!/usr/bin/env perl
use strict;
use warnings;
use Carp;
use PPI;
my $doc = PPI::Document->new(shift);
# See PPI::Node for docs on find
my $strings = $doc->find(sub {
my($top, $element) = @_;
print ref $element, "\n";
# Look for any quoted string or here doc.
# Does not pick up unquoted hash keys.
return $element->isa("PPI::Token::Quote") ||
$element->isa("PPI::Token::HereDoc");
});
# Display the content and location.
for my $string (@$strings) {
my($line, $row, $col) = @{ $string->location };
print "Found string at line $line starting at character $col.\n";
printf "String content: '%s'\n", string_content($string);
}
# *sigh* PPI::Token::HereDoc doesn't have a string method
sub string_content {
my $string = shift;
return $string->isa("PPI::Token::Quote") ? $string->string :
$string->isa("PPI::Token::HereDoc") ? $string->heredoc :
croak "$string is neither a here-doc nor a quote";
}
Вы можете более тщательно изучить токены, окружающие строки, чтобы определить, является ли это чем-то значительным. См. PPI::Element и PPI::Node для более подробной информации. Или вы можете проверить содержимое строки, чтобы определить, является ли она значимой.
Я не могу идти намного дальше, потому что "значительный" зависит от вас.
Наш механизм поиска исходного кода обычно используется для эффективного поиска больших баз кода с использованием индексов, построенных на лексемах языков, которые он знает. Этот список языков довольно широк, включая Java, C#, COBOL и... Perl. Экстракторы лексем точны в языке (потому что они "украдены" из нашего DMS Software Reengineering Toolkit, системы преобразования программ, не зависящей от языка, где точность является фундаментальной).
Учитывая индексированную кодовую базу, можно затем вводить запросы, чтобы найти произвольные последовательности лексем, несмотря на языковой пробел; можно регистрировать попадания таких запросов и их местоположение.
Чрезвычайно короткий запрос:
S
поисковая система находит все лексические элементы, которые классифицируются как строки (ключевые слова, имена переменных, комментарии игнорируются; только строки!). (Обычно люди пишут более сложные запросы с ограничениями регулярных выражений, такими как S=*Hello, чтобы найти строки, заканчивающиеся на "Hello")
Здесь уместно то, что поисковая система исходного кода точно знает лексический синтаксис строк в Perl (включая, в частности, элементы интерполированных строк и все причудливые escape-последовательности). Таким образом, запрос выше найдет все строки в Perl; при входе в систему вы получаете все строки и их местоположение.
Этот трюк на самом деле работает для любого языка, который понимает поисковая система, так что это довольно общий способ извлечения строк для таких задач интернационализации.