Locale::Po4a::TransTractor(3pm)

НАЗВА
Locale::Po4a::TransTractor — загальний засіб перекладу-видобування.

ОПИС
Метою проєкту po4a (PO для усього) є спрощення перекладу (та, що ще цікавіше, супровід перекладів) за допомогою інструментів gettext у областях, де такий переклад спочатку не передбачався, зокрема у документації.

Цей клас є предком будь-якого обробника po4a, що використовується для обробки документа, пошуку придатних до перекладу рядків, видобування цих рядків до файла PO і для заміни рядків перекладами у документі-результаті.

Формально, вхідними є такі аргументи:

-   документ для перекладу;

-   файл PO, який містить переклади, які слід використати.

На виході матимемо ось що:

-   інший файл PO, який є результатом видобування придатних до перекладу рядків із вхідного документа;

-   перекладений документ, який має ту саму структуру, що і вхідних, але усі придатні до перекладу рядки у ньому замінено перекладами, знайденими у файлі PO, який було передано як вхідні дані.

Ось графічна схема роботи:

   Вхідний документ --\                             /---> Вихідний документ
                     \                           /       (перекладений)
                      +-> функція parse() ------+
                     /                           \
 Вхідний PO --------/                             \---> Вихідний PO
                                                         (видобутий)

ФУНКЦІЇ, ЯКІ ВАШ ОБРОБНИК МАЄ ПЕРЕВИЗНАЧИТИ

parse()
    Тут відбувається уся справа: обробка вхідних документів, створення виведених даних та видобування придатних до перекладу рядків. Усе це доволі просто зробити за допомогою функцій, які представлено у розділі ВНУТРІШНІ ФУНКЦІЇ нижче. Див. також розділ КОРОТКИЙ ОПИС, де наведено приклад.

    Ця функція викликається нижче функцією process(), але якщо ви захочете використати функцію new() і додати дані до вашого документа вручну, вам слід викликати цю функцію власноруч.

docheader()
    Ця функція повертає заголовок, який слід додати до створеного документа із належним обрамленням, щоб бути коментарем мовою перекладу. Див. розділ Навчання розробників основам створення придатного для перекладу коду з підручника з po4a(7), щоб дізнатися більше про те, де її використовують.

КОРОТКИЙ ОПИС
Нижче наведено приклад коду обробки списку абзаців, кожен з яких починається з «<p>». З міркувань простоти, будемо вважати, що документ має коректне форматування, тобто у ньому є лише теґи «<p>», і ці теґи розташовано на самому початку кожного абзацу.

 sub parse {
   my $self = shift;

   PARAGRAPH: while (1) {
       my ($paragraph,$pararef)=("","");
       my $first=1;
       my ($line,$lref)=$self->shiftline();
       while (defined($line)) {
           if ($line =~ m/<p>/ && !$first--; ) {
               # Бачимо <p> не вперше.
               # Повторно передаємо поточний рядок на вхід,
               #  і передаємо зібраний абзац на вихід
               $self->unshiftline($line,$lref);

               # Тепер, коли документ сформовано, перекладаємо його:
               #   - Вилучаємо початковий теґ
               $paragraph =~ s/^<p>//s;

               #   - виштовхуємо на вихід початковий теґ (неперекладений) і
               #     решту абзацу (перекладену)
               $self->pushline(  "<p>"
                               . $self->translate($paragraph,$pararef)
                               );

               next PARAGRAPH;
           } else {
               # Дописати до абзацу
               $paragraph .= $line;
               $pararef = $lref unless(length($pararef));
           }

           # Повторно започатковуємо цикл
           ($line,$lref)=$self->shiftline();
       }
       # Не отримати визначеного рядка? Кінець файла вхідних даних.
       return;
   }
 }

Після реалізації функції parse ви можете використовувати ваш клас document за допомогою відкритого (public) інтерфейсу, який представлено у наступному розділі.

ВІДКРИТИЙ ІНТЕРФЕЙС для скриптів, які використовують ваш обробник

  Конструктор

process(%)
    Ця функція може виконувати усі дії, які слід виконати з документом po4a за один виклик. Її аргументи слід запакувати як хеш. ДІЇ:

    а)  Читає усі файли PO, вказані у po_in_name

    б)  Читає усі початкові документи, вказані у file_in_name

    в)  Обробляє документ

    г)  Читає і дописує вказані додатки

    д)  Записує перекладений документ до file_out_name (якщо вказано)

    е)  Записує видобутий файл PO до po_out_name (якщо вказано)

    АРГУМЕНТИ, окрім тих, які приймаються new() (із очікуваним типом):

    file_in_name (@)
        Список назв файлів, з яких слід прочитати вхідні дані документа.

    file_in_charset ($)
        Кодування символів, яке використано у вхідному документі (якщо його не вказано, функція спробує визначити його за вхідним документом).

    file_out_name ($)
        Назва файла, до якого слід записати вихідний документ.

    file_out_charset ($)
        Таблиця кодування, яку використано у вихідному документі (якщо не вказано, буде використано таблицю кодування з файла PO).

    po_in_name (@)
        Список назв файлів, з яких слід прочитати вхідні дані PO, які містять переклади, які буде використано для перекладу документа.

    po_out_name ($)
        Назва файла, до якого слід записати дані PO, що містять рядки, видобуті з вхідного документа.

    addendum (@)
        Список назв файлів, з яких слід прочитати додатки.

    addendum_charset ($)
        Кодування символів додатків.

new(%)
    Створити документ po4a. Прийнятні параметри (але у хеші):

    verbose ($)
        Встановлює рівень докладності.

    debug ($)
        Встановлює рівень діагностики.

  Робота з файлами документів

read($$)
    Додати іще один вхідний документ наприкінці наявного масиву "@{$self->{TT}{doc_in}}". Аргументом є назва файла, з якого слід прочитати дані. Якщо вказано другий аргумент, він вважається назвою файла, який слід використовувати у посиланнях.

    Цей масив "@{$self->{TT}{doc_in}}" містить дані вхідного документа у форматі масиву рядків із різним призначенням.
     * Рядок $textline містить кожен з рядків вхідних текстових даних.
     * Рядок "$filename:$linenum" містить його розташування у тексті і
       називається «прив'язка» ("linenum" починається з 1).

    Будь ласка, зауважте, що функція не обробляє будь-що. Функцію parse() слід використовувати після завершення пакування вхідних файлів до документа.

write($)
    Записати перекладений документ до файла із вказаною назвою.

    Ці дані перекладеного документа можна отримати так:
     * "$self->docheader()" містить текст заголовка для додатка, а
     * "@{$self->{TT}{doc_out}}" містить кожен з рядків основного перекладеного тексту у форматі масиву.

  Робота з файлами PO

readpo($)
    Додати вміст файла (назва якого передається як аргументи) до наявного файла вхідних даних PO. Старий вміст файла не відкидається.

writepo($)
    Записати видобуті дані PO до файла із вказаною назвою.

stats()
    Повертає деякі статистичні дані щодо поточного стану перекладу. Будь ласка, зауважте, що ці статистичні дані — це не ті дані, які виводить команда msgfmt --statistic. Це статистичні дані щодо використання файла PO, тоді як дані msgfmt — це звіт щодо стану файла. Є обгорткою до функції Locale::Po4a::Po::stats_get, застосованою до файла PO вхідних даних. Приклад використання:

        [звичайне використання документа po4a...]

        ($percent,$hit,$queries) = $document->stats();
        print "Знайдено переклади $percent\%  ($hit з $queries) рядків.\n";

is_po_uptodate()
    Повертає ($uptodate, $diagnostic), де $uptodate вказує на те, чи збігаються файл po вхідних даних і файл po вихідних даних (якщо ні, це означає, що файл po вхідних даних слід оновити) і $diagnostic є рядком, який пояснює, чому файл po втратив актуальність, якщо це трапилося.

  Робота із додатками

addendum($)
    Будь ласка, зверніться до розділу po4a(7), щоб дізнатися більше про додатки та те, як перекладачі мають їх писати. Щоб застосувати додаток до перекладеного документа, просто передайте його назву цій функції, ось і усе. ;)

    Ця функція повертає ненульове ціле число, якщо станеться помилка.

ВНУТРІШНІ ФУНКЦІЇ, які використовуються для написання похідних обробників

  Отримуємо вхідні дані, надаємо результати
Передбачено чотири функції для отримання вхідних даних і повернення вихідних даних. Вони дуже подібні до функцій shift/unshift та push/pop у Perl.

 * shift у Perl повертає перший запис масиву і викидає його з масиву.
 * unshift у Perl дописує запис на початку масиву як його перший запис.
 * pop у Perl повертає останній запис масиву і викидає його з масиву.
 * push у Perl дописує запис до масиву наприкінці.

Перша пара працює із вхідними даними, а друга — з вихідними. Мнемоніка: у вхідних даних вас цікавитиме перший рядок, який дає shift, у вихідних ви додаєте результат наприкінці, як це робить push.

shiftline()
    Ця функція повертає перший рядок для обробки і відповідне посилання (запаковане до масиву) з масиву "@{$self->{TT}{doc_in}}" і викидає з цього масиву два перших записи. Тут дані посилання надаються рядком "$filename:$linenum".

unshiftline($$)
    Скасовує зсування останнього зсунутого рядка вхідного документа і його прив'язки на початку "{$self->{TT}{doc_in}}".

pushline($)
    Вставити новий рядок наприкінці "{$self->{TT}{doc_out}}".

popline()
    Виштовхнути останній вставлений рядок з кінця "{$self->{TT}{doc_out}}".

  Позначення придатних до перекладу рядків
Одну функцію передбачено для обробки тексту, який має бути перекладено.

translate($$$)
    Обов'язкові аргументи:

    -   Рядок для перекладу

    -   Посилання цього рядка (тобто розташування рядка у файлі вхідних даних)

    -   Тип цього рядка (тобто текстовий опис його структурної ролі; використовується у Locale::Po4a::Po::gettextization(); див. також po4a(7), розділ Перетворення на формат gettextization: як це працює?)

    Ця функція також може приймати додаткові аргументи. Їх має бути упорядковано як хеш. Приклад:

      $self->translate("string","ref","type",
                       'wrap' => 1);

    wrap
        булеве значення, яке вказує на те, чи розглядаєте ви пробіли як неважливу частину рядка. Якщо має значення «yes» («так»), функція переводить рядок у канонічну форму, перш ніж шукати переклад або видобувати його, а потім виконує перенесення рядків у перекладі.

    wrapcol
        позиція, на якій слід переносити рядки (типове значення: 76).

    comment
        додатковий коментар, який буде дописано до запису.

    Дії:

    -   Вставляє рядок, посилання і тип до po_out.

    -   Повертає переклад рядка (знайдений у po_in), щоб обробник міг зібрати doc_out.

    -   Обробляє кодування для перекодовування рядків до надсилання їх до po_out і перед повертанням перекладів.

  Інші функції

verbose()
    Повертає значення, яке вказує, чи було передано під час створення TransTractor параметр докладного режиму повідомлень.

debug()
    Повертає значення, яке вказує, чи було передано під час створення TransTractor параметр режиму діагностики.

detected_charset($)
    Ця функція повідомляє TransTractor, що у вхідному документі було виявлено нове кодування (перший аргумент). Кодування, зазвичай, можна прочитати із заголовка документа. Використовуватиметься лише перше кодування, яке буде отримано з аргументів process() або визначено з документа.

get_out_charset()
    Ця функція повертає кодування, яке слід використовувати у виведеному документі (зазвичай, корисно для заміни виявленого кодування вхідного документа, де його було визначено).

    Функція використовуватиме для виведення кодування, вказане у рядку команди. Якщо кодування не вказано, буде використано кодування з вхідного файла PO. Якщо ж у цьому файлі лишатиметься типове значення кодування, «CHARSET», функція поверне значення кодування вхідного документа, отже ніякого перекодування не виконуватиметься.

recode_skipped_text($)
    Ця функція повертає перекодований текст, переданий їй як аргумент, з кодування вхідного документа у кодування вихідного документа. У такому перекодуванні немає потреби, якщо рядок перекладається (translate() сама усе перекодовує), але воно потрібне, якщо ви пропускаєте рядок із вхідного документа і хочете, щоб вихідний документ був однорідним у сенсі загального кодування.

МАЙБУТНІ НАПРЯМКИ
Недоліком поточної реалізації TransTractor є те, що модуль не здатен обробляти перекладені документи, у яких містяться переклади усіма мовами, наприклад, шаблони debconf або файли .desktop.

Для усування цієї проблеми достатньо змінити у інтерфейсі таке:

-   отримати хеш як po_in_name (один список на мову)

-   додати аргумент для перекладу, щоб вказати мову перекладу

-   створити функцію pushline_all, яка виконуватиме pushline своїх даних для усіх мов з використанням map-подібного синтаксису:

        $self->pushline_all({ "Description[".$langcode."]=".
                              $self->translate($line,$ref,$langcode)
                            });

Побачимо, чи цього досить ;)

АВТОРИ
 Denis Barbier <barbier@linuxfr.org>
 Martin Quinson (mquinson#debian.org)
 Jordi Vilalta <jvprat@gmail.com>