2025-03-21 14:14:03 +03:00
module namespace page = 'http://ossetic-studies.org/ns/abaevdict-site';
declare namespace tei = "http://www.tei-c.org/ns/1.0";
import module namespace abv-m = 'http://ossetic-studies.org/ns/abaevdict-mod' at './abv-mod.xqm';
2025-03-22 23:43:48 +03:00
2025-03-21 14:14:03 +03:00
(: =========================================================== :)
(: ================== GLOBAL VARIABLES ======================= :)
(: =========================================================== :)
(: Number of items per page :)
declare variable $page:items as xs:integer := 20;
(: These variables are declared in module scope because they are needed in
different places, but they are still dynamically evaluated :)
declare variable $page:lookup := doc('abaevdict_index/lookup.xml')/tei:table/tei:entry;
2025-03-22 00:08:52 +03:00
declare variable $page:lookup-all := doc('abaevdict_index/lookup.xml')/tei:table/*;
2025-03-21 14:14:03 +03:00
declare variable $page:total := ceiling(count($page:lookup) div $page:items);
2025-03-22 00:08:52 +03:00
(: This is still called sorted, because I haven't changed the code.
But it's now equal to lookup, because the lookup itself is now sorted. :)
declare variable $page:sorted := $page:lookup;
2025-03-21 14:14:03 +03:00
(: =============================================================== :)
(: ======================= COMMON STUFF ========================== :)
(: =============================================================== :)
declare function page:head($title as xs:string, $script as node()* := ()) {
<head>
<script src="/static/jquery-3.7.1.min.js">
</script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"/>
<link rel="stylesheet" href="{web:create-url('/static/abaev-html.css')}"/>
{$script}
<title>{$title}</title>
</head>
};
(: Navigation header :)
2025-03-21 19:46:07 +03:00
declare function page:header($lang as xs:string, $href-other as xs:string) {
2025-03-21 14:14:03 +03:00
<header>
<nav>
2025-03-21 22:44:51 +03:00
<ul class="abv-brand">
<li><img class="abv-logo" src="/static/Abaev_logo.png" alt="Abaevdict logo"></img>
<strong>{
2025-03-21 19:46:07 +03:00
switch($lang)
case 'ru' return 'ИЭСОЯ В . И. Абаева'
2025-03-22 23:43:48 +03:00
default return `Abaevdict`
2025-03-21 19:46:07 +03:00
}</strong><i> β</i></li>
<li>{
(element {if ($lang = 'ru') then 'mark' else 'a'}{
if ($lang != 'ru') then
(attribute onclick {`window.location='{$href-other}'+window.location.search;`},
attribute href {'#'}) else (),
'ru'
}, ' / ',
element {if ($lang = 'ru') then 'a' else 'mark'}{
if ($lang = 'ru') then
(attribute onclick {`window.location='{$href-other}'+window.location.search;`},
attribute href {'#'}) else (),
'en'
})
}
</li>
2025-03-21 14:14:03 +03:00
</ul>
<ul>
2025-03-22 23:43:48 +03:00
<li>
<form role="search" action="./search/new" id="abv-search">
{if (session:get('searchQuery')) then
<button onclick="location.href='./search/clear'" type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
<path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/>
</svg>
</button>
else
<select name="searchType" required="1">
<option selected="1" value="full">All</option>
<option value="form">Forms</option>
<option value="sense">Senses</option>
<option value="example">Examples</option>
<option value="translation">Translations</option>
<option value="mentioned">Mentioned</option>
<option value="gloss">Glosses</option>
<option value="etym">Etymology</option>
</select>
}
<input name="searchQuery"
placeholder="{if ($lang = 'ru') then 'Искать' else 'Search'}"
value="{session:get('searchQuery')}"
aria-label="Search" />
{if (not(session:get('searchQuery'))) then
<button type="submit">
<svg xmlns="http://www.w3.org/2000/svg"
width="16" height="16"
viewBox="0 0 16 16"
fill="currentColor" class="bi bi-search">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001q.044.06.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1 1 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0"/>
</svg>
</button>
else
(
if (session:get('searchN') > 1) then
<button type="button" onclick="location.href='./search/prev'">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8"/>
</svg>
</button>,
<button disabled="true">{session:get('searchN')}/{array:size(session:get('searchData'))}</button>
,
if (session:get('searchN') and session:get('searchN') < array:size(session:get('searchData'))) then
<button type="button" onclick="location.href='./search/next'">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-right" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8"/>
</svg>
</button>
)
}
</form>
</li>
2025-03-21 19:46:07 +03:00
<li><a href="./home">{
switch($lang)
case 'ru' return 'Главная'
default return 'Home'
}
</a></li>
<li><a href="./dict">{switch($lang)
case 'ru' return 'Словарь'
default return 'Dictionary'
}
</a></li>
<li><a href="./index">{switch($lang)
case 'ru' return 'Указатель'
default return 'Index'
}</a></li>
<li><a href="#">{switch($lang)
case 'ru' return 'Литература'
default return 'References'
}</a></li>
2025-03-21 14:14:03 +03:00
</ul>
</nav>
</header>
};
2025-03-21 19:46:07 +03:00
declare function page:invert-lang($lang as xs:string) as xs:string {
if($lang = 'en') then 'ru' else 'en'
};
2025-03-22 23:43:48 +03:00
(: =============================================================== :)
(: ======================= SEARCH ENTRYPOINT ===================== :)
(: =============================================================== :)
declare %rest:path("/search/{$path=.+}")
%rest:GET
function page:search-default($path as xs:string) {
web:forward(`/en/search/{$path}`)
};
declare %rest:path("{$lang}/search/new")
%rest:query-param("searchType", "{$searchType}", 'full')
%rest:query-param("searchQuery", "{$searchQuery}")
%output:method("html")
%output:html-version('5')
function page:search($lang, $searchType, $searchQuery) {
let $r1 := session:set('searchType', $searchType)
let $r2 := session:set('searchQuery', $searchQuery)
let $r3 := session:set('searchN', 1)
let $sd := abv-m:search($lang,$searchType,$searchQuery)
let $r4 := session:set('searchData',
$sd)
return page:by-id($lang, $sd(1)('entry_id'), string-join($sd(1)('path')?*,"|"))
};
declare %rest:path("{$lang}/search/next")
%output:method("html")
%output:html-version('5')
function page:search-next($lang) {
let $n := session:get('searchN')+1
let $r1 := session:set('searchN', $n)
let $sd := session:get('searchData')
return page:by-id($lang, $sd($n)('entry_id'), string-join($sd($n)('path')?*,"|"))
};
declare %rest:path("{$lang}/search/prev")
%output:method("html")
%output:html-version('5')
function page:search-prev($lang) {
let $n := session:get('searchN')-1
let $r1 := session:set('searchN', $n)
let $sd := session:get('searchData')
return page:by-id($lang, $sd($n)('entry_id'), string-join($sd($n)('path')?*,"|"))
};
declare %rest:path("{$lang}/search/clear")
%output:method("html")
%output:html-version('5')
function page:clearSearch($lang) {
let $r1 := session:delete('searchType')
let $r2 := session:delete('searchQuery')
let $r3 := session:delete('searchN')
let $r4 := session:delete('searchData')
return web:redirect('../dict')
};
2025-03-21 19:46:07 +03:00
(: =============================================================== :)
(: ======================= HOMEPAGE ============================== :)
(: =============================================================== :)
2025-03-22 00:11:15 +03:00
declare %rest:path("{$lang}")
%output:method("html")
%output:html-version('5')
function page:zero($lang) {
page:home($lang)
};
declare %rest:path("/")
%output:method("html")
%output:html-version('5')
function page:zero() {
page:zero('en')
};
2025-03-21 19:46:07 +03:00
declare %rest:path("{$lang}/home")
%output:method("html")
%output:html-version('5')
function page:home($lang) {
<html>
{page:head(if ($lang='ru') then 'ИЭСОЯ — Главная' else 'Abaevdict — Home',())}
<body>
{page:header($lang,`../{page:invert-lang($lang)}/home`)}
<main>
{
switch($lang)
case "ru" return (
<p>
Вы находитесь на сайте электронной двуязычной версии
<a href="https://ironau.ru/iesoja.html">Историко-этимологического
словаря осетинского языка</a> (ИЭСОЯ) В . И. Абаева.
Оцифровка и перевод словаря выполнены группой сотрудников, студентов и аспирантов
<a href="https://tipl.philol.msu.ru/">отделения теоретической и
прикладной лингвистики</a> МГУ имени М . В . Ломоносова и
<a href="https://iling-ran.ru/web/ru/departments/indo-european/iranian">
сектора иранских языков</a> Института языкознания Р А Н .
</p>,
<p>
Электронная версия словаря и перевод III и IV томов выполнены за счёт
гранта Российского научного фонда №
<a href="https://rscf.ru/project/22-28-01639/">22-28-01639</a>.
</p>,
<p>
Мы выражаем особую благодарность Амирхану Михайловичу Торчинову, который
выступил инициатором этого проекта и продолжает оказывать нам неоценимую
поддержку в нашей работе. Мы также благодарны московской осетинской общине за
поддержку перевода I– II томов словаря и помощь в печатном издании их английской
версии, в особенности Александру Тотоонову, Валерию Дзгоеву, Олегу Пухову,
Владиславу Хаблиеву, Руслану Бестолову, Виталию Даурову, Игорю Дзуцеву, Марине
Каболовой, Владимиру Туганову, Зоинбеку Абаеву, Виктору Джиоеву, Владимиру
Бароеву и Борису Базаеву.
</p>,
<p>
Электронная версия словаря основана на адаптации системы XML-разметки
<a href="https://tei-c.org/">TEI P5</a>. Сервер базы данных использует систему
<a href="https://basex.org">BaseX</a>. Модель разметки словаря и реализация её
программного отображения разработаны О . И. Беляевым. В с е исходные
данные доступны в <a href="https://code.cucurri.ru/abaevdict">репозиториях</a>
проекта.
</p>,
<p>
2025-03-21 22:48:00 +03:00
Дизайн и эмблема сайта выполнены А . А . Осиповой.
</p>,
<p>
2025-03-21 19:46:07 +03:00
В предыдущей версии электронного словаря использовалась реляционная
<a href="https://ossetic.iranic.space">модель</a> представления данных,
разработанная Ю. Ю. Макаровым (ИЯз Р А Н , Кембриджский университет)
на платформе OnLex.
</p>,
<h5>Как ссылаться</h5>,
<blockquote>Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // <i>IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop</i>. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12– 19.
</blockquote>,
<h5>Участники проекта</h5>,
<table>
<tbody>
<tr>
<th scope="row">Научный руководитель</th>
<td>О . И. Беляев</td>
<td>(МГУ имени
М . В . Ломоносова, ИЯз Р А Н )</td>
</tr>
<tr>
<th scope="row">Основные участники</th>
<td>Ю. В . Синицына</td>
<td>(МГУ имени
М . В . Ломоносова)</td>
</tr>
<tr>
<td></td>
<td>И. А . Хомченкова</td>
<td>(МГУ имени М . В . Ломоносова, ИРЯ Р А Н )</td>
</tr>
<tr>
<th>Оцифровка и перевод</th>
<td>В . В . Дьячков</td>
<td>(ИЯз Р А Н )</td>
</tr>
<tr>
<td></td>
<td>А . А . Осипова</td>
<td>(МГУ имени М . В . Ломоносова)</td>
</tr>
<tr>
<td></td>
<td>А . О . Бадеев</td>
<td>(ИЯз Р А Н , НИУ ВШЭ)</td>
</tr>
<tr>
<td></td>
<td>Д. А . Алексеев</td>
<td>(МГУ имени М . В . Ломоносова)</td>
</tr>
</tbody>
</table>)
default return
(
<p>
This is the website of the electronic version of V. I. Abaev's
<a href="https://ironau.ru/iesoja.html">Historical-Etymological Dictionary
of Ossetic</a> (HEDO). Its digitization and English translation have been
carried out by staff members and students of the
<a href="https://tipl.philol.msu.ru/">department of theoretical and applied
linguistics</a>, Lomonosov Moscow State University, and the <a
href="https://iling-ran.ru/web/ru/departments/indo-european/iranian">
Department of Iranian languages</a>, Institute of Linguistics RAS.
</p>,
<p>
The electronic version of the dictionary and the translation of vols. 3 and 4
have been supported by the Russian Science Foundation, project no.
<a href="https://rscf.ru/project/22-28-01639/">22-28-01639</a>.
</p>,
<p>
We are deeply grateful to Amirkhan Torchinov, who has been the initiator of this
project and is still providing us with invaluable support in our work. We are
also grateful to the Ossetian community of Moscow for their support of the
translation of vols. 1 and 2 and the help in publishing its preliminary English
version; in particular, to Alexander Totoonov, Valery Dzgoev, Oleg Pukhov,
Vladislav Khabliev, Ruslan Bestolov, Vitaly Daurov, Igor Dzutsev, Marina
Kabolova, Vladimir Tuganov, Zoinbek Abaev, Viktor Dzhioev, Vladimir
Baroev and Boris Bazaev.
</p>,
<p>
The electronic edition of the dictionary is based on an adaptation of the
XML-based <a href="https://tei-c.org/">TEI P5</a> markup system. The database
server runs on <a href="https://basex.org">BaseX</a>. The markup model and its
software realization have been developed by Oleg Belyaev. All sources are
available in our <a href="https://code.cucurri.ru/abaevdict">repositories</a>.
</p>,
<p>
2025-03-21 22:48:00 +03:00
Site design and logo are by Anna Osipova.
</p>,
<p>
2025-03-21 19:46:07 +03:00
The previous version of the electronic dictionary used a relational
data <a href="https://ossetic.iranic.space">model</a> developed by Yury Makarov
(IL RAS, Cambridge University) using the OnLex platform.
</p>,
<h5>How to cite</h5>,
<blockquote>Belyaev, Oleg, Irina Khomchenkova, Julia Sinitsyna, Vadim Dyachkov. Digitizing print dictionaries using TEI: The Abaev Dictionary Project // <i>IWCLUL 2021: The Seventh International Workshop on Computational Linguistics of Uralic Languages. Proceedings of the Workshop</i>. Stroudsburg, USA: Association for Computational Linguistics, 2021. P. 12– 19.
</blockquote>,
<h5>Project participants</h5>,
<table>
<tbody>
<tr>
<th scope="row">Project leader</th>
<td>Oleg Belyaev</td>
<td>(Lomonosov MSU, IL RAS)</td>
</tr>
<tr>
<th scope="row">Core team</th>
<td>Irina Khomchenkova</td>
<td>(Lomonosov MSU, Vinogradov RLI RAS)</td>
</tr>
<tr>
<td></td>
<td>Julia Sinitsyna</td>
<td>(Lomonosov MSU)</td>
</tr>
<tr>
<th>Digitization and translation</th>
<td>Vadim Dyachkov</td>
<td>(IL RAS, LLACAN CNRS)</td>
</tr>
<tr>
<td></td>
<td>Anna Osipova</td>
<td>(Lomonosov MSU)</td>
</tr>
<tr>
<td></td>
<td>Artyom Badeev</td>
<td>(IL RAS, HSE University)</td>
</tr>
<tr>
<td></td>
<td>Danil Alekseev</td>
<td>(Lomonosov MSU)</td>
</tr>
</tbody>
</table>)
}
</main>
</body>
</html>
};
declare %rest:path("home")
%output:method("html")
%output:html-version('5')
function page:home() {
page:home('en')
};
2025-03-21 14:14:03 +03:00
(: =============================================================== :)
2025-03-21 19:46:07 +03:00
(: ======================= THE DICTIONARY ======================== :)
2025-03-21 14:14:03 +03:00
(: =============================================================== :)
(: If no language defined, default to English :)
declare %rest:path("dict")
%output:method("html")
%output:html-version('5')
function page:dict() {
web:forward('/en/dict')
};
(: The main dictionary view :)
declare %rest:path("{$lang}/dict")
%rest:query-param("page","{$p}", 1)
2025-03-22 23:43:48 +03:00
%rest:query-param("xpath","{$xpath}", '')
%rest:query-param("entry","{$entry}", '')
2025-03-21 14:14:03 +03:00
%output:method("html")
%output:html-version('5')
2025-03-22 23:43:48 +03:00
function page:dict($lang, $p, $xpath, $entry) {
2025-03-21 14:14:03 +03:00
<html>
{page:head('HEDO – Dictionary',
(<script src="/static/infinite-scroll.pkgd.min.js">
</script>,
<script src="/static/plotly-3.0.1.min.js" charset="utf-8"></script>,
<script src="/static/abaev.js"></script>))}
<body>
2025-03-21 19:46:07 +03:00
{page:header($lang,`../{page:invert-lang($lang)}/dict`)}
2025-03-21 14:14:03 +03:00
<!-- Sidebar with entry list -->
<button id="open-leftbar">
{html:doc('../static/chevron-right.svg')}
</button>
<button id="close-leftbar">
{html:doc('../static/chevron-left.svg')}
</button>
<aside id="leftbar">
2025-03-22 00:08:52 +03:00
<fieldset>
<input type="text" id="filter-entries"
placeholder="{if ($lang = 'ru') then 'Быстрый фильтр' else 'Quick filter…'}"/>
<label>
<input id="show-re" type="checkbox" role="switch"></input>
{if ($lang = 'ru') then 'Производные' else 'Show subentries'}
</label>
</fieldset>
2025-03-21 14:14:03 +03:00
<nav id="entrylist">
<ul>
2025-03-22 00:08:52 +03:00
{for $doc in $page:lookup-all
let $id := if ($doc/name() = 'entry') then $doc/@xml:id
else $doc/@corresp
return element li {
if ($doc/name() = 're') then
(attribute hidden {'true'},
attribute class {'abv-menu-re'}) else (),
attribute id {`link_{$id}`},
<a href="./dict/{$id}">
2025-03-21 14:14:03 +03:00
{$doc/text()}
</a>
2025-03-22 00:08:52 +03:00
}
2025-03-21 14:14:03 +03:00
}
</ul>
</nav>
</aside>
<!-- The dictionary itself. The entries are displayed as articles retrieved
from the database in HTML. On-the-fly generation is only when required -->
<main>
{for $doc at $i in $page:sorted
where $i > ($p - 1) * $page:items and $i <= $p * $page:items
2025-03-22 23:43:48 +03:00
let $html := if ($xpath != '' and $entry = $doc/@xml:id)
then abv-m:mark-element(doc(`abaevdict_{$lang}/xml/{$doc/@xml:id}.xml`),$xpath) => abv-m:make-html($lang)
else doc(`abaevdict_{$lang}/html/{$doc/@xml:id}.html`)
2025-03-21 22:44:51 +03:00
return if (doc('abaevdict_index/mentioned_en.xml')/
2025-03-21 22:57:14 +03:00
lang-index/lang[@id != 'os' and
not(starts-with(@id,'os-'))]/word/entry[@id=string($doc/@xml:id)]) then
2025-03-21 22:44:51 +03:00
$html transform with {insert nodes (<br/>,
<a class="abv-map" data-abv-entry="{$doc/@xml:id}">
<img src="/static/map.png"></img></a>) as last
into ./article[1]/h6[1]}
else $html
}
2025-03-21 14:14:03 +03:00
</main>
<!-- Footer for page navigation -->
<footer>
<nav class="pagination">
<ul>
<li>
{if ($p > 1) then <a href="?page={$p - 1}">Previous page</a> else ()}
</li>
</ul>
<!-- <ul><li>Page {$p} of {$page:total}</li></ul> -->
2025-03-21 22:44:51 +03:00
<ul class="abv-nextpage">
2025-03-21 14:14:03 +03:00
<li>
{if ($p < $page:total) then
<a class="pagination__next" href="?page={$p + 1}">Next page</a> else ()}
</li>
</ul>
</nav>
</footer>
<!-- Modal for map display -->
<dialog id="modal_map">
<article>
<header><button class="abv-close-map" aria-label="Close" rel="prev"></button>
<p>Map</p>
</header>
<p>
<div id="map_display" style="width:100%;height:80%;"></div>
</p>
<footer><button class="abv-close-map">Close</button></footer>
</article>
</dialog>
</body>
</html>
};
(: == ENTRY BY ID == :)
(: English as default language :)
declare %rest:path("dict/{$id}")
2025-03-22 23:43:48 +03:00
%rest:query-param("xpath", "{$xpath}")
2025-03-21 14:14:03 +03:00
%output:method("html")
%output:html-version('5')
2025-03-22 23:43:48 +03:00
function page:by-id($id, $xpath) {
page:by-id('en', $id, $xpath)
2025-03-21 14:14:03 +03:00
};
declare %rest:path("{$lang}/dict/{$id}")
2025-03-22 23:43:48 +03:00
%rest:query-param("xpath", "{$xpath}")
2025-03-21 14:14:03 +03:00
%output:method("html")
%output:html-version('5')
2025-03-22 23:43:48 +03:00
function page:by-id($lang, $id, $xpath) {
2025-03-22 18:32:43 +03:00
(: let $doc-index := index-of($page:sorted, $page:sorted[@xml:id=`{$id}`]) :)
let $doc-index := index-where($page:sorted, fn { ./@xml:id=$id })
2025-03-21 14:14:03 +03:00
let $pagenum := ceiling($doc-index div $page:items)
2025-03-22 23:43:48 +03:00
return web:redirect('../dict',
{'page': $pagenum,
'entry': web:decode-url($id),
'xpath': $xpath},
web:decode-url($id))
2025-03-21 14:14:03 +03:00
};
2025-03-21 19:46:07 +03:00
(: =============================================================== :)
(: ======================= THE INDEX ============================= :)
(: =============================================================== :)
2025-03-21 14:14:03 +03:00
(: Mentioned index :)
declare %rest:path("{$lang}/index")
%output:method("html")
%output:html-version('5')
function page:index($lang) {
let $mlangs := doc(`abaevdict_index/langnames.xml`)/csv[1]/record
return
<html>
{page:head('HEDO – Index', <script src="/static/abaev-index.js"></script>)}
<body>
2025-03-21 19:46:07 +03:00
{page:header($lang,`../{page:invert-lang($lang)}/index`)}
2025-03-21 14:14:03 +03:00
<main>
<div class="index">
<div class="langs">
<label>Languages</label>
<select id="abv-select-lang" size="99999">
{
for $mlang in $mlangs
let $mlang-id := $mlang/code/text()
let $mlang-name := if ($lang = 'ru') then $mlang/ru/text() else $mlang/en/text()
where $mlang-name != ''
2025-03-21 15:38:12 +03:00
order by $mlang-name
2025-03-21 14:14:03 +03:00
return
<option value="{$mlang-id}">
{
$mlang-name
}
</option>
}
</select>
</div>
<div class="forms">
<Label>Forms</Label>
<select id="abv-select-word" size="99999">
</select>
</div>
<div class="entries">
<Label>Entries</Label>
<select id="abv-select-entry" size="99999">
</select>
</div>
</div>
</main>
</body>
</html>
};
(: Default to English :)
declare %rest:path("index")
%output:method("html")
%output:html-version('5')
function page:index() {
page:index('en')
};