Руководство по созданию новой языковой пары

From Apertium
Jump to navigation Jump to search

Руководство по созданию новой языковой пары

В этом руководстве описывается порядок создания новой языковой пары для системы машинного перевода Apertium. От Вас не требуются какие-либо лингвистические знания или знания по машинному переводу, кроме как способности различать части речи (отличать существительные от глаголов, например).

Введение

Как Вы только что узнали, Apertium является системой машинного перевода. Но если быть более точным, то Apertium следует назвать не системой, а платформой машинного перевода. Он обеспечивает Вас "движком" машинного перевода (англ. "engine". Можно также перевести как "ядро", "механизм" и т.п.) и набором инструментов, с помощью которых Вы можете строить свои собственные системы машинного перевода. Единственное, что Вы должны сделать, это написать данные. На базовом уровне эти данные состоят из трёх словарей и некоторого набора правил (обеспечивающих перестановку слов и другие грамматические трансформации).

За более подробной информацией, как всё это работает, обращайтесь к веб-сайту проекта apertium.sourceforge.net.

Что Вам потребуется

  • lttoolbox (>= 3.0.0)
  • libxml utils (xmllint и др.)
  • apertium (>= 3.0.0)
  • текстовый редактор (или специализированный XML-редактор, если таковой Вам больше по душе)

Это руководство не описывает порядок установки этих пакетов, за подробной информацией обращайтесь к разделу документации веб-сайта Apertium.

Из чего состоит языковая пара?

Apertium представляет собой систему машинного перевода поверхностно-трансферного типа. Следовательно, в основном он имеет дело со словарями и правилами поверхностного трансфера. На практике поверхностный трансфер отличается от глубокого тем, что при нём не выполняется полный синтаксический разбор предложений, а правила, в отличии от операций на дереве синтаксического разбора, представляют собой операции с группами лексических единиц. Этих словарей три:

  1. Морфологический словарь для языка xx: он содержит информацию о словоизменении (склонении или спряжении) на языке xx. В нашем примере этот словарь будет называться так: apertium-sh-en.sh.dix
  2. Морфологический словарь для языка yy: он, в свою очередь, содержит информацию о словоизменении (склонении или спряжении) на языке yy. В нашем примере он имеет следующее название: apertium-sh-en.en.dix
  3. Двуязычный словарь: содержит переводные соответствия слов и символов двух языков. Он будет называться так: apertium-sh-en.sh-en.dix

В языковой паре любой из языков, составляющих эту пару, может быть как входным, так и выходным языком, т.е. эти термины употребляются условно.

Составляющими языковую пару являются также два файла с правилами трансфера. Это правила, которые управляют перестановкой слов в предложениях, например chat noir -> cat black -> black cat. Также эти правила обеспечивают в предложении согласование рода, числа и т.д. Они же могут использоваться и для вставки или удаления лексических единиц, как это будет описано ниже. Это следующие файлы:

  • правила трансфера языка xx на язык yy: эти правила описывают, каким изменениям подвергнутся предложения языка xx при переводе на язык yy. В нашем примере это следующий файл: apertium-sh-en.sh-en.t1x
  • правила трансфера языка yy на язык xx: этот файл содержит правила, описывающие преобразования, которые должны быть осуществлены при переводе с языка yy на язык xx. В нашем примере этот файл будет называться так: apertium-sh-en.en-sh.t1x

Многие из существующих языковых пар содержат и другие файлы, но мы не будем рассматривать их в данном руководстве. Эти файлы требуются для создания функциональной системы.

Языковая пара

Как уже можно было догадаться по названиям файлов, для описания порядка создания базовой системы в этом руководстве будут использоваться примеры перевода с сербохорватского на английский язык. Заметим, что это не идеальная пара, так как система работает лучше с родственными языками. Однако в случае простых примеров, приводимых здесь, мы не столкнёмся с какими-либо проблемами.

Краткое замечание о терминах

Перед тем как продолжить, следует пояснить значение некоторых терминов.

Первым из них является лемма. Лемма — это каноническая форма слова, слово без грамматической информации. Например, леммой слова cats является cat. В английском языке лемма рассматриваемого существительного как правило совпадает с его формой единственного числа. В русском и татарском языках лемма существительного имеет вид его формы именительного падежа единственного числа. Для глаголов в английском языке лемма будет иметь вид инфинитива без to (или просто инфинитива в русском и татарском языках). Например, леммой слова was будет be, также как леммой слова был будет быть, или леммой слова булды будет булырга.

Вторым термином является термин символ. В контексте Apertium`а символ означает грамматический знак. Слово cats есть существительное множественного числа, следовательно, он будет иметь символ существительного и символ множественного числа. На входе и выходе модулей Apertium`а эти символы обычно заключаются в угловые скобки, как показано ниже:

  • <n>; для существительного
  • <pl>; для множественного числа

Другими примерами символов являются <sg> (единственное число), <p1> (первое лицо), <pri> (настоящее время изъявительное наклонение) и др. Стоит заметить, что во многих из существующих языковых пар символы имеют вид акронимов или сокращений каталанских слов. Например, vbhaver — от vb (verb, глагол) и haver ("иметь" на каталанском). Символы определяются в тегах <sdef> и используются в тегах <s>.

Третьим же термином является парадигма. В контексте системы Apertium парадигма является примером склонения/спряжения определённой группы слов. В морфологическом словаре леммы (см. выше) ссылаются на парадигмы, что позволяет нам показать все словоформы этих лемм без необходимости записи всех возможных окончаний.

Примером использования парадигмы может служить следующее. Допустим, мы хотим добавить в словарь прилагательные happy и lazy. Вместо записи одинаковых окончаний:

  • happy, happ (y, ier, iest)
  • lazy, laz (y, ier, iest)

мы можем записать окончания форм слова happy, а потом сказать "lazy изменяется как happy", или "shy изменяется как happy", "naughty изменяется как happy", "friendly изменяется как happy" и т.д. В этом примере happy и будет парадигмой, моделью изменения всех остальных. Точное описание определения парадигм будет дано позже. Парадигмы определяются в тегах <pardef> и используются в тегах <par>.

Начало работы

Одноязычные словари

See also: List of dictionaries and Incubator

Начнём с создания нашего первого словаря входного языка. Словарь является XML-файлом. Откройте Ваш текстовый редактор и наберите следующее:

<?xml version="1.0" encoding="UTF-8"?>
<dictionary>

</dictionary>

Так, теперь файл определяет, что мы хотим начать создание словаря. Что бы этот файл был более полезным, мы должны добавить в него ещё несколько записей, первой из которых будет алфавит. Он определяет набор букв, которые могут использоваться в словаре для сербохорватского языка. Он выглядит как показано ниже и содержит все буквы сербохорватского алфавита:

<alphabet>ABCČĆDDžĐEFGHIJKLLjMNNjOPRSŠTUVZŽabcčćddžđefghijklljmnnjoprsštuvzž</alphabet>

Добавьте алфавит после тега <dictionary>.

Далее нам необходимо определить некоторые символы. Начнём с более простых — существительное (n) в единственном (sg) и множественном (pl) числах.

<sdefs>
   <sdef n="n"/>
   <sdef n="sg"/>
   <sdef n="pl"/>
</sdefs>

Имена символов не обязательно должны быть такими краткими, их можно даже писать полностью, но так как делать это придётся много раз, есть смысл в сокращении.

К сожалению, всё не так просто — существительные в сербохорватском языке имеют не только категорию числа, но и категории рода и падежа. Однако для нашего примера мы будем предполагать, что существительное является существительным мужского рода и что он в именительном падеже (пример можно найти в конце этого документа).

Следующим шагом определим раздел для парадигм,

<pardefs>

</pardefs>

и раздел для словаря:

<section id="main" type="standard">

</section>

Есть два вида разделов: первый — стандартный раздел. Он содержит слова, энклитики и т.д. Второй — безусловный раздел, содержащий знаки препинания и т.п. В нашем примере нет безусловного раздела, хотя он будет показан позднее.

Таким образом, наш файл будет выглядеть так:

<?xml version="1.0" encoding="UTF-8"?>
<dictionary>
   <sdefs>
     <sdef n="n"/>
     <sdef n="sg"/>
     <sdef n="pl"/>
   </sdefs>
   <pardefs>

   </pardefs>
   <section id="main" type="standard">

   </section>
</dictionary>

Теперь у нас есть скелет словаря, и мы можем начать с добавлением существительного. Им будет слово 'gramofon'.

Так как ранее определённых парадигм у нас нет, первым делом мы должны определить парадигму.

Напомним, что мы имеем ввиду мужской род и именительный падеж. Формой единственного числа является 'gramofon', формой множественного числа — 'gramofoni'. Таким образом:

<pardef n="gramofon__n">
   <e>
     <p>
       <l/>
       <r><s n="n"/><s n="sg"/></r>
     </p>
   </e>
   <e>
     <p>
       <l>i</l>
       <r><s n="n"/><s n="pl"/></r>
     </p>
   </e>
</pardef>

Заметьте: '<l/>' (который эквивалентен <l></l>) означает, что в единственном числе к основе ничего не присоединяется.

Всё это может показаться довольно многословным способом описания, но для такого описания есть причины и к нему быстро привыкаешь. Вы, наверное, уже задаётесь вопросом, что означают все эти <e>, <l> и <r>?

  • e означает запись (entry). Образно это можно также назвать словарной статьёй.
  • p означает пару (pair).
  • l означает влево (left).
  • r означает вправо (right).

Почему влево и вправо? Морфологические словари позднее будут скомпилированы в конечные автоматы. Их компиляция слева направо создаёт анализы слов, а справа налево — слова из анализов. Например:

* gramofoni (слева направо) gramofon<n><pl> (анализ)
* gramofon<n><pl> (справа налево) gramofoni (генерирование)

Мы определили парадигму, теперь требуется соотнести её с леммой — gramofon. Это действие выполняется в ранее определённом разделе (section).

Записью, которую нужно добавить в </dictionary>

Теперь мы должны добавить запись (в <section>) для осуществления перевода двух слов:

<e><p><l>gramofon<s n="n"/></l><r>gramophone<s n="n"/></r></p></e>

Так как в словаре таких записей очень много, для удобочитаемости их обычно пишут в одну строку. Снова вопросы о 'l' и 'r', да? Всё довольно просто — мы компилируем слева направо для создания сербохорватско → английского словаря, и справа налево для создания английско → сербохорватского словаря.

Когда всё это сделано, выполните следующие команды:

$ lt-comp lr apertium-sh-en.sh.dix sh-en.automorf.bin
$ lt-comp rl apertium-sh-en.en.dix sh-en.autogen.bin

$ lt-comp lr apertium-sh-en.en.dix en-sh.automorf.bin
$ lt-comp rl apertium-sh-en.sh.dix en-sh.autogen.bin

$ lt-comp lr apertium-sh-en.sh-en.dix sh-en.autobil.bin
$ lt-comp rl apertium-sh-en.sh-en.dix en-sh.autobil.bin

для создания морфологических анализаторов (automorf), морфологических генераторов (autogen) и поисковиков слов (autobil), слово "bil" означает "bilingual", т.е. "двуязычный".

Правила трансфера

Теперь мы имеем два морфологических словаря и один двуязычный словарь. Всё что нам ещё нужно сделать это правила трансфера для существительных. Файлы с правилами трансфера имеют свой собственный DTD (transfer.dtd), который может быть найден в пакете Apertium. Если Вам нужно написать правило трансфера, то часто имеет смысл сначала обратиться к файлам с правилами для других языковых пар, так как многие правила могут быть использованы для разных языковых пар. Или же эти правила можно использовать в модифицированном виде. Например, правило, приведённое ниже, может быть использовано для всех нуль-субъектных языков.

"Скелет" файла такой же:

<?xml version="1.0" encoding="UTF-8"?>
<transfer>

</transfer>

Так как мы не учитываем падежи (т.е. возможное изменение падежей при переводе), нам необходимо создать правило, которое просто "брало" бы грамматические символы на входе и, в свою очередь, выдавало их.

Сначала нам следует определить категории и атрибуты. Категории и атрибуты позволяют объединять грамматические символы. С помощью категорий мы можем объединять символы для их "сведения воедино" (например, категория 'n.*' объединяет все существительные). Атрибуты позволяют нам объединять символы, из которых мы далее можем выбрать нужный нам (например, 'sg' и 'pl' могут быть объединены атрибутом 'number').

Добавим необходимые разделы:

<section-def-cats>

</section-def-cats>
<section-def-attrs>

</section-def-attrs>

Существительные в нашем примере изменяются только по числам (что мы уже много раз повторяли), следовательно, необходимо добавить категорию для существительных и атрибут числа. Достаточно следующих записей:

В раздел section-def-cats добавьте:

<def-cat n="nom">
   <cat-item tags="n.*"/>
</def-cat>

Категория "покрывает" все существительные (леммы, за которыми следует <n> и за ним ещё что-нибудь) и ссылается на них как "nom" (Вы увидите далее, как это применяется).

В раздел section-def-attrs добавьте:

<def-attr n="nbr">
   <attr-item tags="sg"/>
   <attr-item tags="pl"/>
</def-attr>

а также

<def-attr n="a_nom">
   <attr-item tags="n"/>
</def-attr>

Первая запись определяет атрибут nbr (number=число), которое может быть либо единственным (sg), либо множественным (pl).

Вторая запись определяет атрибут a_nom (атрибут существительное).

Далее нам необходимо добавить раздел для глобальных переменных:

<section-def-vars>

</section-def-vars>

Эти переменные используются для сохранения атрибутов или их передачи между несколькими правилами. Пока нам нужна только одна,

<def-var n="number"/>

И наконец, необходимо добавить само правило, которое позволяло бы принимать существительное и затем выводить его в правильной форме. Нам нужен раздел для правил...

<section-rules>

</section-rules>

На этот раз я сначала покажу правило, и только затем дам к нему пояснения.

<rule>
   <pattern>
     <pattern-item n="nom"/>
   </pattern>
   <action>
     <out>
       <lu>
         <clip pos="1" side="tl" part="lem"/>
         <clip pos="1" side="tl" part="a_nom"/>
         <clip pos="1" side="tl" part="nbr"/>
       </lu>
     </out>
   </action>
</rule>

Первый тег понятен — он определяет правило. Второй тег, pattern, (означает следюущее: "применять это правило, если обнаружен этот шаблон". В этом примере шаблон состоит из одного существительного (определённого категорией nom). Заметьте, что шаблоны накладываются в режиме "длиннейший совпадающий". Так, если у Вас есть три правила, первый из которых относится к соединениям слов, соответствующих шаблону "<prn><vblex><n>", второй — шаблону "<prn><vblex>" и третий — шаблону "<n>", накладываемым шаблоном и применяемым (в случае соответствия соединения слов этому шаблону) правилом будет первый.

Каждому шаблону соответствует определённое действие, которое генерирует соответствующие выводные данные. Выводными данными (выводом) является лексическая единица (lu, lexical unit).

Тег clip позволяет пользователю выбирать атрибуты или части лексической единицы входного (side="sl") или выходного (side="tl") языка и манипулировать ими.

Скомпилируем и проверим файл. Правила трансфера компилируются так:

$ apertium-preprocess-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin

что создаст файл sh-en.t1x.bin.

Теперь всё готово для проверки нашей системы машинного перевода. У нас ещё нет одного важного компонента, а именно разметчика по частям речи или частеречного теггера (PoS tagger, part-of-speech tagger), однако вскоре этот вопрос будет пояснён. Пока мы можем проверить систему и без него.

Сначала проанализируем слово "gramofoni":

$ echo "gramofoni" | lt-proc sh-en.automorf.bin 
^gramofon/gramofon<n><pl>$

После этого теггер по частям речи должен выбрать правильный вариант (правильную часть речи), но так как теггера пока у нас нет, мы можем использовать маленький gawk-скрипт (спасибо Sergio), который будет выдавать первый из полученных результатов (на самом деле и результат-то у нас будет всего один).

$ echo "gramofoni" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
^gramofon<n><pl>$

Теперь обработаем результат с помощью правила трансфера:

$ echo "gramofoni" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin

Что выдаст следующее:

^gramophone<n><pl>$^@
  • 'gramophone' есть лемма (lem) выходного языка (side="tl") в позиции 1 (pos="1").
  • '<n>' есть a_nom (существительное) выходного языка в позции 1.
  • '<pl>' есть атрибут числа (nbr) выходного языка в позиции 1.

Попробуйте закомментировать одну из этих clip-строк, перекомпилировать файл и посмотреть, что произойдёт.

Теперь у нас есть вывод трансфера, и единственное, что остаётся сделать, это сгенерировать словоформы (т.е. должным образом склонённые или спряжённые формы) на выходном языке. Для этого используется тот же самый lt-proc, но в другом режиме — в режиме генерирования.

$ echo "gramofoni" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin | \
  lt-proc -g sh-en.autogen.bin

gramophones\@

Вуаля. Теперь у Вас есть система машинного перевода, которая переводит сербохорватское существительное на английский язык. Очевидно, что пользы от такой системы не так много, однако вскоре мы перейдём к более сложному материалу. Ах да, о символе '@' тоже не беспокойтесь, скоро я объясню, что это такое.

Попробуйте найти/вспомнить другие слова, которые склоняются так же, как слово "gramofon". О порядке их добавления — нам нужно добавлять только записи (entries, которые мы образно назвали "словарными статьями") в главном разделе одноязычного и двуязычного словарей, а не парадигмы.

Добавим глаголы

Так, теперь наша система может переводить существительные. Однако проку от этого не много, ведь мы хотим переводить и глаголы, и даже целые предложения! Начнём с глагола "to see". В сербохорватском ему соответствует "videti". Сербохорватский язык есть т.н. нуль-субъектный язык (на сербохорватском перед личными формами глаголов личные местоимения как правило не используются). Английский же не является таковым. Так, например: Английское "I see" будет переведено на сербохорватский как "vidim".

  • Vidim
  • see<p1><sg>
  • I see

Примечание: <p1> означает первое лицо

Другими примерами нуль-субъектных языков могут служить испанский, румынский и польский. Это будет важно при написании правил трансфера для глаголов. "Нуль-субъектность" сербохорватского языка означает также, что если в сербохорватский морфологический словарь мы добавим только глагол, то в английский морфологический словарь нужно будет добавить не только глагол, но и личные местоимения.

Остальными формами глагола видеть являются: vidiš, vidi, vidimo, vidite, и vide. Соответственно: you see (единственное число), he sees, we see, you see (множественное число), и they see.

There are two forms of you see, one is plural and formal singular (vidite) and the other is singular and informal (vidiš).

Мы постараемся перевести сербохорватское "Vidim gramofoni" в английское "I see gramophones". В целях экономии времени мы добавим в словарь только достаточную для перевода информацию и оставим описание парадигмы (добавление остальных личных форм глагола) как упражнение для самостоятельной работы читателя.

Внимательный читатель наверное заметил, что мы не можем перевести "vidim gramofoni", ибо это предложение грамматически некорректно. Грамматически правильным предложением является "vidim gramofone", так как существительное должно быть в винительном падеже. Да, мы добавим форму винительного падежа, однако информацию о падеже добавлять не будем (в этом нет необходимости) - нужное нам слово будет фигурировать как второй вариант множественного числа. Для этого скопируйте (другими словами "клонируйте") блок 'e' для формы множественного числа и исправьте там букву 'i' (в теге <l>) на 'e'.

Прежде всего мы должны добавить несколько новых символов. Для начала символ для глагола ('verb'), который мы будем называть "vblex" (lexical verb=знаменательный глагол, как противоположное модальным глаголам и др. типам глаголов. Наряду с числом (number) у глаголов есть категории лица ('person') и времени ('tense'), так что добавим эти символы тоже. Напомним, что мы хотели перевести "I see" - значит для для лица мы добавим "p1", т.е. 'первое лицо', а для времени - "pri", т.е. 'present indicative'.

<sdef n="vblex"/>
<sdef n="p1"/>
<sdef n="pri"/>

После этого (как и в случае существительных) мы добавим парадигму спряжения глагола. Первой строкой будет:

<pardef n="vid/eti__vblex">

Знаком '/' разграничивается основа слова, к которой присоединяются содержимые тегов <l>.

Затем флексия для первого лица единственного числа:

<e>
   <p>
     <l>im</l>
     <r>eti<s n="vblex"/><s n="pri"/><s n="p1"/><s n="sg"/></r>
   </p>
</e>

The 'im' denotes the ending (as in 'vidim'), it is necessary to add 'eti' to the <r> section, as this will be chopped off by the definition. The rest is fairly straightforward, 'vblex' is lexical verb, 'pri' is present indicative tense, 'p1' is first person and 'sg' is singular. We can also add the plural which will be the same, except 'imo' instead of 'im' and 'pl' instead of 'sg'.

After this we need to add a lemma, paradigm mapping to the main section:

<e lm="videti"><i>vid</i><par n="vid/eti__vblex"/></e>

Note: the content of <i> </i> is the root, not the lemma.

Thats the work on the Serbo-Croatian dictionary done for now. Lets compile it then test it.

$ lt-comp lr apertium-sh-en.sh.dix sh-en.automorf.bin
main@standard 23 25
$ echo "vidim" | lt-proc sh-en.automorf.bin
^vidim/videti<vblex><pri><p1><sg>$
$ echo "vidimo" | lt-proc sh-en.automorf.bin
^vidimo/videti<vblex><pri><p1><pl>$

Ok, so now we do the same for the English dictionary (remember to add the same symbol definitions here as you added to the Serbo-Croatian one).

The paradigm is:

<pardef n="s/ee__vblex">

because the past tense is 'saw'. Now, we can do one of two things, we can add both first and second person, but they are the same form. In fact, all forms (except third person singular) of the verb 'to see' are 'see'. So instead we make one entry for 'see' and give it only the 'pri' symbol.

<e>
   <p>
     <l>ee</l>
     <r>ee<s n="vblex"/><s n="pri"/></r>
   </p>
</e>

and as always, an entry in the main section:

<e lm="see"><i>s</i><par n="s/ee__vblex"/></e>

Then lets save, recompile and test:

$ lt-comp lr apertium-sh-en.en.dix en-sh.automorf.bin
main@standard 18 19

$ echo "see" | lt-proc en-sh.automorf.bin
^see/see<vblex><pri>$

Now for the obligatory entry in the bilingual dictionary:

<e><p><l>videti<s n="vblex"/></l><r>see<s n="vblex"/></r></p></e>

(again, don't forget to add the sdefs from earlier)

And recompile:

$ lt-comp lr apertium-sh-en.sh-en.dix sh-en.autobil.bin
main@standard 18 18
$ lt-comp rl apertium-sh-en.sh-en.dix en-sh.autobil.bin
main@standard 18 18

Now to test:

$ echo "vidim" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin

^see<vblex><pri><p1><sg>$^@

We get the analysis passed through correctly, but when we try and generate a surface form from this, we get a '#', like below:

$ echo "vidim" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin | \
  lt-proc -g sh-en.autogen.bin
#see\@

This '#' means that the generator cannot generate the correct lexical form because it does not contain it. Why is this?

Basically the analyses don't match, the 'see' in the dictionary is see<vblex><pri>, but the see delivered by the transfer is see<vblex><pri><p1><sg>. The Serbo-Croatian side has more information than the English side requires. You can test this by adding the missing symbols to the English dictionary, and then recompiling, and testing again.

However, a more paradigmatic way of taking care of this is by writing a rule. So, we open up the rules file (apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin in case you forgot).

We need to add a new category for 'verb'.

<def-cat n="vrb">
   <cat-item tags="vblex.*"/>
</def-cat>

We also need to add attributes for tense and for person. We'll make it really simple for now, you can add p2 and p3, but I won't in order to save space.

<def-attr n="temps">
   <attr-item tags="pri"/>
</def-attr>

<def-attr n="pers">
   <attr-item tags="p1"/>
</def-attr>

We should also add an attribute for verbs.

<def-attr n="a_verb">
   <attr-item tags="vblex"/>
</def-attr>

Now onto the rule:

<rule>
   <pattern>
     <pattern-item n="vrb"/>
   </pattern>
   <action>
     <out>
       <lu>
         <clip pos="1" side="tl" part="lem"/>
         <clip pos="1" side="tl" part="a_verb"/>
         <clip pos="1" side="tl" part="temps"/>
       </lu>
     </out>
   </action>
</rule>

Remember when you tried commenting out the 'clip' tags in the previous rule example and they disappeared from the transfer, well, thats pretty much what we're doing here. We take in a verb with a full analysis, but only output a partial analysis (lemma + verb tag + tense tag).

So now, if we recompile that, we get:

$ echo "vidim" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin
^see<vblex><pri>$^@

and:

$ echo "vidim" | lt-proc sh-en.automorf.bin  | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin | \
  lt-proc -g sh-en.autogen.bin
see\@

Try it with 'vidimo' (we see) to see if you get the correct output.

Now try it with "vidim gramofone":

$ echo "vidim gramofoni" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin | \
  lt-proc -g sh-en.autogen.bin
see gramophones\@

But what about personal pronouns?

Well, thats great, but we're still missing the personal pronoun that is necessary in English. In order to add it in, we first need to edit the English morphological dictionary.

As before, the first thing to do is add the necessary symbols:

<sdef n="prn"/>
<sdef n="subj"/>

Of the two symbols, prn is pronoun, and subj is subject (as in the subject of a sentence).

Because there is no root, or 'lemma' for personal subject pronouns, we just add the pardef as follows:

<pardef n="prsubj__prn">
   <e>
     <p>
       <l>I</l>
       <r>prpers<s n="prn"/><s n="subj"/><s n="p1"/><s n="sg"/></r>
     </p>
   </e>
</pardef>

With 'prsubj' being 'personal subject'. The rest of them (You, We etc.) are left as an exercise to the reader.

We can add an entry to the main section as follows:

<e lm="personal subject pronouns"><i/><par n="prsubj__prn"/></e>

So, save, recompile and test, and we should get something like:

$ echo "I" | lt-proc en-sh.automorf.bin
^I/PRPERS<prn><subj><p1><sg>$

(Note: it's in capitals because 'I' is in capitals).

Now we need to amend the 'verb' rule to output the subject personal pronoun along with the correct verb form.

First, add a category (this must be getting pretty pedestrian by now):

<def-cat n="prpers">
   <cat-item lemma="prpers" tags="prn.*"/>
</def-cat>

Now add the types of pronoun as attributes, we might as well add the 'obj' type as we're at it, although we won't need to use it for now:

<def-attr n="tipus_prn">
   <attr-item tags="prn.subj"/>
   <attr-item tags="prn.obj"/>
</def-attr>

And now to input the rule:

<rule>
   <pattern>
     <pattern-item n="vrb"/>
   </pattern>
   <action>
     <out>
       <lu>
         <lit v="prpers"/>
         <lit-tag v="prn"/>
         <lit-tag v="subj"/>
         <clip pos="1" side="tl" part="pers"/>
         <clip pos="1" side="tl" part="nbr"/>
       </lu>
       <b/>
       <lu>
         <clip pos="1" side="tl" part="lem"/>
         <clip pos="1" side="tl" part="a_verb"/>
         <clip pos="1" side="tl" part="temps"/>
       </lu>
     </out>
   </action>
</rule>

This is pretty much the same rule as before, only we made a couple of small changes.

We needed to output:

^prpers<prn><subj><p1><sg>$ ^see<vblex><pri>$

so that the generator could choose the right pronoun and the right form of the verb.

So, a quick rundown:

  • <lit>, prints a literal string, in this case "prpers"
  • <lit-tag>, prints a literal tag, because we can't get the tags from the verb, we add these ourself, "prn" for pronoun, and "subj" for subject.
  • , prints a blank, a space.

Note that we retrieved the information for number and tense directly from the verb.

So, now if we recompile and test that again:

$ echo "vidim gramofone" | lt-proc sh-en.automorf.bin  | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin | \
  lt-proc -g sh-en.autogen.bin
I see gramophones

Which, while it isn't exactly prize-winning prose (much like this HOWTO), is a fairly accurate translation.

So tell me about the record player (Multiwords)

While gramophone is an English word, it isn't the best translation. Gramophone is typically used for the very old kind, you know with the needle instead of the stylus, and no powered amplification. A better translation would be 'record player'. Although this is more than one word, we can treat it as if it is one word by using multiword (multipalabra) constructions.

We don't need to touch the Serbo-Croatian dictionary, just the English one and the bilingual one, so open it up.

The plural of 'record player' is 'record players', so it takes the same paradigm as gramophone (gramophone__n) — in that we just add 's'. All we need to do is add a new element to the main section.

<e lm="record player"><i>record<b/>player</i><par n="gramophone__n"/></e>

The only thing different about this is the use of the tag, although this isn't entirely new as we saw it in use in the rules file.

So, recompile and test in the orthodox fashion:

$ echo "vidim gramofone" | lt-proc sh-en.automorf.bin | \
  gawk 'BEGIN{RS="$"; FS="/";}{nf=split($1,COMPONENTS,"^"); for(i = 1; i<nf; i++) printf COMPONENTS[i]; if($2 != "") printf("^%s$",$2);}' | \
  apertium-transfer apertium-sh-en.sh-en.t1x sh-en.t1x.bin sh-en.autobil.bin  | \
  lt-proc -g sh-en.autogen.bin
I see record players

Perfect. A big benefit of using multiwords is that you can translate idiomatic expressions verbatim, without having to do word-by-word translation. For example the English phrase, "at the moment" would be translated into Serbo-Croatian as "trenutno" (trenutak = moment, trenutno being adverb of that) — it would not be possible to translate this English phrase word-by-word into Serbo-Croatian.

Dealing with minor variation

Serbo-Croatian typically has a few ways of writing each word because of dialectal variation. It has a cool phonetic writing system so you write how you speak. For example, people speaking in Ijekavian would say "rječnik", while someone speaking Ekavian would say "rečnik", which reflects the differences in pronunciation of the proto-Slavic vowel yat.

Analysis

There should be a fairly easy way of dealing with this, and there is, using paradigms again. Paradigms aren't only used for adding grammatical symbols, but they can also be used to replace any character/symbol with another. For example, here is a paradigm for accepting both "e" and "je" in the analysis. The paradigm should, as with the others go into the monolingual dictionary for Serbo-Croatian.

  <pardef n="e_je__yat">
    <e>
      <p>
        <l>e</l>
        <r>e</r>
      </p>
    </e>
    <e>
      <p>
        <l>je</l>
        <r>e</r>
      </p>
    </e>
  </pardef>

Then in the "main section":

    <e lm="rečnik"><i>r</i><par n="e_je__yat"/><i>čni</i><par n="rečni/k__n"/></e>

This only allows us to analyse both forms however... more work is necessary if we want to generate both forms.

Generation

See also