From 0780131c0020d3a2a57145fa4f0d1a6d26ecf20a Mon Sep 17 00:00:00 2001 From: Mikhail Chekan Date: Tue, 7 Sep 2021 01:46:34 +0800 Subject: [PATCH 1/4] Initial l18n support --- go.mod | 4 +- go.sum | 11 + help/en/attachment.myco | 8 +- help/en/mycomarkup.myco | 4 +- help/en/telegram.myco | 1 + help/help.go | 1 + help/ru.myco | 9 + help/ru/attachment.myco | 34 + help/ru/hypha.myco | 35 + help/ru/lock.myco | 27 + help/ru/mycomarkup.myco | 397 ++++++++++ help/ru/recent_changes.myco | 20 + help/ru/sibling_hyphae_section.myco | 13 + help/ru/telegram.myco | 40 + help/ru/top_bar.myco | 54 ++ help/ru/whitelist.myco | 17 + l18n/l18n.go | 524 +++++++++++++ l18n/util.go | 105 +++ l18n_src/en/admin.json | 33 + l18n_src/en/auth.json | 35 + l18n_src/en/edit.json | 38 + l18n_src/en/help.json | 24 + l18n_src/en/ui.json | 130 ++++ l18n_src/ru/admin.json | 33 + l18n_src/ru/auth.json | 35 + l18n_src/ru/edit.json | 38 + l18n_src/ru/help.json | 24 + l18n_src/ru/ui.json | 134 ++++ main.go | 1 + shroom/init.go | 3 +- views/admin.qtpl | 88 +-- views/admin.qtpl.go | 592 ++++++++------ views/auth.qtpl | 88 ++- views/auth.qtpl.go | 571 ++++++++------ views/history.qtpl | 23 +- views/history.qtpl.go | 378 ++++----- views/hypha.qtpl | 40 +- views/hypha.qtpl.go | 422 ++++++---- views/modal.qtpl | 45 +- views/modal.qtpl.go | 396 +++++----- views/mutators.qtpl | 84 +- views/mutators.qtpl.go | 410 +++++----- views/nav.qtpl | 35 +- views/nav.qtpl.go | 194 ++--- views/readers.qtpl | 52 +- views/readers.qtpl.go | 515 +++++++------ views/stuff.qtpl | 101 +-- views/stuff.qtpl.go | 1103 ++++++++++++++++----------- web/admin.go | 29 +- web/auth.go | 36 +- web/backlinks.go | 12 +- web/history.go | 14 +- web/mutators.go | 49 +- web/readers.go | 25 +- web/search.go | 7 +- web/stuff.go | 44 +- web/web.go | 10 +- 57 files changed, 4981 insertions(+), 2214 deletions(-) create mode 100644 help/ru.myco create mode 100644 help/ru/attachment.myco create mode 100644 help/ru/hypha.myco create mode 100644 help/ru/lock.myco create mode 100644 help/ru/mycomarkup.myco create mode 100644 help/ru/recent_changes.myco create mode 100644 help/ru/sibling_hyphae_section.myco create mode 100644 help/ru/telegram.myco create mode 100644 help/ru/top_bar.myco create mode 100644 help/ru/whitelist.myco create mode 100644 l18n/l18n.go create mode 100644 l18n/util.go create mode 100644 l18n_src/en/admin.json create mode 100644 l18n_src/en/auth.json create mode 100644 l18n_src/en/edit.json create mode 100644 l18n_src/en/help.json create mode 100644 l18n_src/en/ui.json create mode 100644 l18n_src/ru/admin.json create mode 100644 l18n_src/ru/auth.json create mode 100644 l18n_src/ru/edit.json create mode 100644 l18n_src/ru/help.json create mode 100644 l18n_src/ru/ui.json diff --git a/go.mod b/go.mod index 00311a3..4575763 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,18 @@ module github.com/bouncepaw/mycorrhiza go 1.16 require ( - github.com/bouncepaw/mycomarkup/v2 v2.0.2 + github.com/bouncepaw/mycomarkup/v2 v2.0.3 github.com/go-ini/ini v1.62.0 github.com/gorilla/feeds v1.1.1 github.com/gorilla/mux v1.8.0 github.com/kr/pretty v0.2.1 // indirect + github.com/m1/go-localize v0.0.0-20210411165534-07d5b914f3cd // indirect github.com/smartystreets/goconvey v1.6.4 // indirect github.com/valyala/quicktemplate v1.6.3 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b + golang.org/x/text v0.3.7 gopkg.in/ini.v1 v1.62.0 // indirect ) diff --git a/go.sum b/go.sum index f5e8b57..157cf01 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,10 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/bouncepaw/mycomarkup/v2 v2.0.2 h1:BT7waogdo7KH7PVqksfmj60j8MFCcmu998oKaPnTfh0= github.com/bouncepaw/mycomarkup/v2 v2.0.2/go.mod h1:sIvtvJFGG61ZeSUC+fNBrFmrQ2xBpTMZezk/QtxiQbk= +github.com/bouncepaw/mycomarkup/v2 v2.0.3 h1:qIO69XA9lZA87HbMPXhk9R4OL0aF0JJQcKOTx3ZjMIo= +github.com/bouncepaw/mycomarkup/v2 v2.0.3/go.mod h1:sIvtvJFGG61ZeSUC+fNBrFmrQ2xBpTMZezk/QtxiQbk= github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU= github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -18,6 +22,8 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/m1/go-localize v0.0.0-20210411165534-07d5b914f3cd h1:y6swOilsqshR8eD/JPntnJAin2bJ/VxQQjDclhjXjmc= +github.com/m1/go-localize v0.0.0-20210411165534-07d5b914f3cd/go.mod h1:eH5LIPfi8y08l9hAmci8sa+jZduTW0iMZM5FW62+RaE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= @@ -46,7 +52,12 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlA golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/help/en/attachment.myco b/help/en/attachment.myco index c55bb14..714a8bd 100644 --- a/help/en/attachment.myco +++ b/help/en/attachment.myco @@ -11,10 +11,10 @@ You can upload any file, but only those listed below will be displayed on the we ## How to add an attachment? For non-existent hyphae, upload a file in the //Upload a media// section. -For any hyphae, upload a file in the //Attachment// tab. +For any hyphae, upload a file in the //Manage attachment// tab. -## Attachment tab -Every hypha has the //Attachment// tab. Click it to see what is out there. +## Attachment management +Every hypha has the //Manage attachment// section. Click it to see what is out there. You can upload a new file, you can //delete// the attachment (it is called //unattaching//) and see some file stats (size and type). @@ -31,4 +31,4 @@ If a hypha has an attachment, here is what the text part might be about: * Some meta data. * Things above combined. -The attachment //should not// be an illustration. \ No newline at end of file +The attachment //should not// be an illustration of the text part. In this case it is better to put it into a subhypha and embed it into the markup. \ No newline at end of file diff --git a/help/en/mycomarkup.myco b/help/en/mycomarkup.myco index 18f77f7..5c038a3 100644 --- a/help/en/mycomarkup.myco +++ b/help/en/mycomarkup.myco @@ -111,7 +111,7 @@ You don't have to write the full hypha name in every link, you can use **relativ Consider you are editing a hypha called //fruit/apple//. -To link //fruit/pear// (a sister hypha) you can write `[\[../pear]]`. To link //fruit/apple/red// (a subhypha) you can write `[\[./red]]`. You can do the same in rocket links, image galleries, transclusion and everywhere else you write hypha names. +To link //fruit/pear// (a sibling hypha) you can write `[\[../pear]]`. To link //fruit/apple/red// (a subhypha) you can write `[\[./red]]`. You can do the same in rocket links, image galleries, transclusion and everywhere else you write hypha names. There is also a way to link the wiki's non-hypha pages. For example, to link the Recent changes page, you can write `[\[/recent-changes]]`. You should use that rather than write the site's full URL because it may change in the future. @@ -132,7 +132,7 @@ There are six levels of **headings**. They consist of some hash signs followed b ###### level 6 ``` -There is an invisible link denoted by the § sign near every heading. You can reveal it with a mouse. If you click it, the URL in the browser will change to the URL leading to that very heading. Try that on headings in this article. +There is an invisible link denoted by the § sign near every heading (right after the heading text). You can reveal it with a mouse. If you click it, the URL in the browser will change to the URL leading to that very heading. Try that on headings in this article. ## Codeblock Use **codeblocks** to show code or any other preformatted text. Codeblocks start with triple backticks on column 1 and end similarly. You can write any text after the backticks, it is ignored. Put the preformatted text between them. diff --git a/help/en/telegram.myco b/help/en/telegram.myco index e396b51..7a9c9df 100644 --- a/help/en/telegram.myco +++ b/help/en/telegram.myco @@ -32,6 +32,7 @@ If both fields are both set, the engine will enable Telegram authorization. On login and register pages there is a blue button. If a user clicks it, they are prompted to give the authorization permission to your bot. The user's @username will be used as wiki username. Telegram users are part of the //editor// user group by default. Telegram users can use the wiki just like everyone else. ## Limitations +* You should host your wiki using a public IP or domain name. Private-hosted (i.e. localhost or LAN) wikis are not supported, obviously. * Telegram does not support HTTP wikis, you //must// use HTTPS. ** One way of setting up HTTPS is using [[https://certbot.eff.org | certbot]] and a reverse proxy such as [[https://nginx.org | nginx]]. * Telegram users without @username cannot authorize. diff --git a/help/help.go b/help/help.go index bc12477..583f9c4 100644 --- a/help/help.go +++ b/help/help.go @@ -6,6 +6,7 @@ import ( ) //go:embed en en.myco +//go:embed ru ru.myco var fs embed.FS // Get determines what help text you need and returns it. The path is a substring from URL, it follows this form: diff --git a/help/ru.myco b/help/ru.myco new file mode 100644 index 0000000..aead2f4 --- /dev/null +++ b/help/ru.myco @@ -0,0 +1,9 @@ +# Справка + +Это документация к **вики-движку Микориза** версии **1.5** ([[https://mycorrhiza.wiki | официальная вики]]). + +**Выберите тему из списка.** + +В настоящее время документация охватывает не всё, что должна охватить, но в будущем это наверняка изменится. + +Если вы хотите внести правки в эту документацию, создайте pull request или issue в [[https://github.com/bouncepaw/mycorrhiza | репозитории на GitHub]]. diff --git a/help/ru/attachment.myco b/help/ru/attachment.myco new file mode 100644 index 0000000..f2d4041 --- /dev/null +++ b/help/ru/attachment.myco @@ -0,0 +1,34 @@ +# Справка: Вложение +В контексте гиф **вложение** – это содержимое, представленное в виде ином, чем [[/help/ru/mycomarkup | микоразметка]]. Чаще всего это изображение, видео или аудио. + +## Поддерживаемые типы вложений +Вы можете загружать любые файлы, но только перечисленные ниже будут отображаться на странице. Но в то же время вы можете скачивать неподдерживаемые вложения. + +* **Изображения:** jpg, gif, png, webp, svg, ico +* **Видео:** ogg, webm, mp4 +* **Аудио:** ogg, webm, mp3 + +## Как добавить вложение? +Для несуществующих гиф, загрузите файл в разделе //Загрузить медиа//. + +Также для всех гиф есть ссылка //Вложение// в подвале. + +## Управление вложением +У каждой гифы есть раздел //Вложение//. Нажмите на ссылку в подвале, чтобы увидеть, что в нём находится. + +Здесь вы можете загрузить новый файл, //удалить// вложение (здесь это называется //открепление//) и посмотреть свойства файла (размер и тип). + +## Об именовании гиф с вложениями +В большинстве случаев название гифы не должно просто копировать название файла. Если вы загружаете фотографию розы, не называйте её `rose.jpg`, нет. Назовите её `фотография розы` или `фото розы` или как-нибудь иначе. В работе с Микоризой вам очень редко понадобится обращаться к расширениям файлов. + +Конечно, это не правило, скорее просто соглашение. + +## Что поместить в текстовую часть? +Если у гиф есть вложение, о чём может быть текстовая часть: +* Текстовое описание или представление изображения. +* Транскрипт песни. +* Анализ вложения. +* Какие-нибудь метаданные. +* Сочетание перечисленного выше. + +Вложение //не должно// быть иллюстрацией текстовой части. В подобных случаях лучше загрузить его в подгифу и добавить ссылку в разметку. \ No newline at end of file diff --git a/help/ru/hypha.myco b/help/ru/hypha.myco new file mode 100644 index 0000000..23df7ba --- /dev/null +++ b/help/ru/hypha.myco @@ -0,0 +1,35 @@ +# Справка: Гифа +**Гифа** (//англ.// hypha, //мн.// hyphae) – основная единица содержимого, используемая в Микоризе. + +## Структура гифы +Гифа состоит из двух частей: +* **Вложение.** Определённый вид медиаданных. Гифа может содержать только одно вложение. См. [[/help/ru/attachment | Вложение]], чтобы узнать больше. +* **Текстовая часть.** Это либо описание вложения, либо самостоятельная единица текста, будь то статья, дневник или стих. Пишется с помощью специальной разметки, называемой [[/help/ru/mycomarkup | микоразметкой]]. + +Эти части сами по себе необязательны. Вы можете разместить картинку без описания, статью без вложения и т.д. Можете использовать обе части вместе. Но минимум одна из них обязана присутствовать. + +## Как создать гифу? +Некоторые ссылки в вики окрашены красным. Это означает, что они ведут на ещё не существующую гифу. Если вы пройдёте по ссылке, вы увидите специальную страницу, на которой можно загрузить вложение или перейти в текстовый редактор. Таким образом и создаются гифы. + +Вы можете создавать подобные красные ссылки и переходить по ним, чтобы создавать новые гифы. + +Как вариант, можно прописать нужный адрес в браузере, чтобы перейти сразу на страницу создания. + +## Названия гиф +Названия гиф регистронезависимы. Это значит, что названия //amanita muscaria// и //Amanita Muscaria// указывают на одну и ту же гифу. Также эквивалентны пробел и знак подчёркивания (//amanita muscaria// = //amanita_muscaria//). Канонические названия пишутся полностью в нижнем регистре и через подчёркивания. + +Есть символы, которые нельзя использовать в названии: `?!:#@><*|"'&%{}\\` Остальные можно. + +## Генеалогия +**Подгифа** – это гифа, название которой начинается с названия другой гифы, после чего через косую черту (слэш) следует собственная часть названия. Например, гифа //Фрукт/Яблоко// является подгифой для //Фрукт//. Подгиф может быть сколько угодно, а подгифы могут содержать свои подгифы. + +Так, **надгифа** (superhypha) – обратное подгифе: //Фрукт// – надгифа для //Фрукт/Яблоко//. Существует лишь одна надгифа. + +**Гифы-сиблинги** – гифы, являющиеся подгифами одной и той же гифы. Например, //Фрукт/Яблоко// и //Фрукт/Груша// приходятся сиблингами. + +## Слово +Английское слово //hypha// произносится как /ˈhaɪfə/. Множественная форма – //hyphae//. Произносите её как /ˈhaɪfi/. + +Слово «гифа» происходит из микологии, науки о грибах. Им обозначают тонкие белые нити, формирующие мицелий. См. [[https://en.wikipedia.org/wiki/Hypha | эту статью на Википедии]], чтобы узнать больше о настоящих гифах. + +Рассматривайте гифы Микоризы как малые элементы, из которых строится ваша вики. \ No newline at end of file diff --git a/help/ru/lock.myco b/help/ru/lock.myco new file mode 100644 index 0000000..c824abc --- /dev/null +++ b/help/ru/lock.myco @@ -0,0 +1,27 @@ +# Блокировка +//Эта статья предназначена для администраторов вики.// + +Иногда вы можете захотеть, чтобы доступ к вики имели только авторизованные пользователи. В таких случаях пригодится **блокировка**. + +## Включение +Чтобы включить блокировку, в `config.ini` поменяйте значение `Locked` на `true`. `UseAuth` также должен быть `true`. +```ini +... +[Authorization] +UseAuth = true +Locked = true +... +``` + +Перезагрузите вики. + +## Применение +Когда неавторизованные гости зайдут на вашу вики, они увидят что-то похожее на это: +img { +https://mycorrhiza.wiki/binary/release/1.3/lock_screenshot +} + +После авторизации они смогут просматривать вики. Но зарегистрироваться отсюда они не могут. Поддерживается авторизация через [[/help/ru/telegram | Телеграм]]. + +## См. также +=> /help/ru/whitelist Белый список \ No newline at end of file diff --git a/help/ru/mycomarkup.myco b/help/ru/mycomarkup.myco new file mode 100644 index 0000000..037a89b --- /dev/null +++ b/help/ru/mycomarkup.myco @@ -0,0 +1,397 @@ +# Микоразметка +**Микоразметка** это собственный язык разметки в Микоризе. + +Это единственная поддерживаемая разметка; другие разметки, будь то Markdown, Creole и прочие, не поддерживаются. + +Документ в микоразметке (чаще всего это текстовая часть гифы) состоит из //блоков//. Для разных задач существуют разные блоки. + +## Содержание +=> /help/ru/mycomarkup#Абзац Абзац +=> /help/ru/mycomarkup#Внутритекстовая_ссылка Внутритекстовая ссылка +=> /help/ru/mycomarkup#Ссылка_ракета Ссылка-ракета +=> /help/ru/mycomarkup#Заголовок Заголовок +=> /help/ru/mycomarkup#Код_блок Код-блок +=> /help/ru/mycomarkup#Горизонтальная_черта Горизонтальная черта +=> /help/ru/mycomarkup#Галерея_изображений Галерея изображений +=> /help/ru/mycomarkup#Список Список +=> /help/ru/mycomarkup#Цитата Цитата +=> /help/ru/mycomarkup#Таблица Таблица +=> /help/ru/mycomarkup#Трансклюзия Трансклюзия + +## Абзац +**Абзацы** – самые распространённые блоки. Вы будете использовать их чаще остальных. + +Чтобы создать абзац, просто напишите текст. Абзацы отделяются друг от друга пустыми строками. + +* {``` +Первый абзац + +Второй абзац +Вторая строка второго абзаца +```} +* { +Первый абзац + +Второй абзац +Вторая строка второго абзаца +} + +Вы можете применять стили к содержимому абзаца. +* {``` +Вы можете использовать //курсив//, **жирный**, `моноширинный`, ++выделенный++, ^^надстрочный^^, __подчёркнутый__, ,,подстрочный,, или ~~зачёркнутый~~ текст. А также вы можете их ++//сочетать//++! +```} +* Вы можете использовать //курсив//, **жирный**, `моноширинный`, ++выделенный++, ^^надстрочный^^, __подчёркнутый__, ,,подстрочный,, или ~~зачёркнутый~~ текст. А также вы можете их ++//сочетать//++! + +Используйте обратный слэш (`\`), чтобы отменить стиль. +* {``` +Это не \//курсив\// +```} +* Это не \//курсив\// + +Вы можете не закрывать декоратор, и тогда стиль будет действовать до конца строки +* {``` +Это //курсив +А это – нет +```} +* { +Это //курсив +А это – нет +} + +Вы можете добавлять ссылки. +* {``` +Просто абзац с парой [[https://example.org | ссылок]], ведущих [[никуда]]. +```} +* Просто абзац с парой [[https://example.org | ссылок]], ведущих [[никуда]]. + +## Ссылка +### Внутритекстовая ссылка +**Внутритекстовые ссылки** размещаются внутри абзацев. + +Внешние ссылки можно помещать как есть, если они содержат протокольную часть. Такие ссылки называются автоссылками. Но иногда они могут работать не совсем, как от них ожидается. Автоссылки поддерживаются для протоколов https, http, gemini, gopher и ftp. +* {``` +https://example.org +```} +* https://example.org + +Оборачивайте ссылки на гифы и внешние ресурсы в `[\[` и `]]`. +* {``` +По ссылкам откроются [[гифа]] и [[https://example.org]]. +```} +* По ссылкам откроются [[гифа]] и [[https://example.org]]. + +Если вы хотите поменять отображаемый текст у ссылки, пропишите его после `|`. +* {``` +Ссылка на [[гифа | другую гифу]] и [[https://example.org | какой-то сайт]]. +```} +* Ссылка на [[гифа | другую гифу]] и [[https://example.org | какой-то сайт]]. + +Так как названия гиф не чувствительны к регистру, эти ссылки функционально одинаковы: `[[гифа]]`, `[[Гифа]]`, `[[ГИФА]]`. + +### Ссылка-ракета +**Ссылки-ракеты** – особые ссылки. Они занимают целую строку. Они не согласуются с обычными внутритекстовыми ссылками. Ссылки-ракеты взяты из разметки [[https://gemini.circumlunar.space/docs/gemtext.gmi | gemtext]]. + +Отображаемый текст пишется после первого пробела, не `|`. Если вы пишете ссылку на гифу с пробелами в названии, замените пробелы на _. + +* {``` +=> гифа +=> гифа_с_пробелами +=> https://example.org +=> https://example.org Отображаемый текст +```} +* { +=> гифа +=> гифа_с_пробелами +=> https://example.org +=> https://example.org Отображаемый текст +} + +### Относительная адресация +Необязательно писать полное название гифы в каждой ссылке, достаточно использовать **относительные** ссылки. + +Допустим, вы редактируете гифу под названием //фрукт/яблоко//. + +Чтобы сослаться на //фрукт/груша// (гифа-сиблинг), можно написать `[\[../груша]]`. Чтобы сослаться на //фрукт/яблоко/красный// (подгифа), можно написать `[\[./красный]]`. То же самое можно делать с ссылками-ракетами, галереями, трансклюзиями и прочими местами, использующими названия гиф. + +Также есть возможность ссылаться на страницы вики, не являющиеся гифами. Например, чтобы сделать ссылку на страницу с недавними изменениями, вы можете написать `[\[/recent-changes]]`. Лучше писать так вместо того, чтобы указывать полный адрес сайта, так как в будущем он может поменяться. + +### Цвета ссылок +Ссылки могут иметь разные цвета. Синие ссылки ведут на //существующие// страницы, когда как красные ведут на //отсутствующие//. Все внешние ссылки считаются существующими, следовательно, они всегда синие. Внутренние ссылки на гифы всегда проверяются на существование. + +Заметьте, что посещённые синие ссылки окрашиваются в пурпурный, но всё равно называются синими. Более того, синие ссылки имеют жёлтый цвет в стандартной тёмной теме. + +## Заголовок +Есть шесть уровней **заголовков**. Они начинаются с одного или более знака решётки, после через пробел пишется текст заголовка. Вы можете оформлять заголовок также, как абзац. Желательно не использовать заголовки 1 уровня, потому что на этом уровне уже находится название гифы. + +``` +# уровень 1 +## уровень 2 +### уровень 3 +#### уровень 4 +##### уровень 5 +###### уровень 6 +``` + +Рядом с каждым заголовком (сразу после его текста) есть невидимая ссылка в виде знака §. Она появляется при наведении курсора. Если вы нажмёте на ссылку, URL в адресной строке заменится на URL, ведущий на соответствующий заголовок этой страницы. Попробуйте проделать это с заголовками в этой статье. + +## Код-блок +Используйте **код-блоки** для отображения кода или иного преформатированного текста. Код-блоки начинаются с трёх обратных кавычек в начале строки и заканчиваются тем же образом. После обратных кавычек в пределах строки можно писать любой текст, он игнорируется. Преформатированный текст пишется между строк с кавычками. + +Примерно так, но без пробела в начале: +``` + ``` + оно преформатированное + видите? + ``` +``` + +``` +оно преформатированное + видите? +``` + +## Горизонтальная черта +Пропишите четыре дефиса, чтобы вставить **горизонтальную черту**. + +* {``` +---- +```} +* ---- + +## Галерея изображений +Используйте **галереи изображений**, чтобы встраивать изображения в страницу. Изображения могут быть гифами или внешними файлами. В примере ниже вы можете заменить URL названием гифы. Если эта гифа — изображение, оно появится в галерее. + +Для изображения можно задать описание и определить размер. + +* {``` +img { +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg { + Описание //здесь// +} +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 100 { Размер } +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 50*50 +} +```} +* { +img { +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg { + Описание //здесь// +} +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 100 { Размер } +https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 50*50 { Квадрат } +} +} + +Если вы встраиваете гифу под названием //гифа-изображение//, разметка будет выглядеть так: +* {``` +img { +гифа-изображение +} +```} + +Если вы пропишете одно единственное изображение, оно будет отображаться без декораций: +* {``` +img { https://mycorrhiza.wiki/static/favicon.ico } +```} +* {img { https://mycorrhiza.wiki/static/favicon.ico }} + +## Список +**Списки** используются отображения упорядоченных или древовидных данных. Они весьма распространены. + +Каждый пункт списка начинается со звёздочки и пробела: +* {``` +* раз +* два +* три +```} +* { +* раз +* два +* три +} + +Если после звёздочки прописать точки, список становится нумерованным: +* {``` +*. раз +*. два +*. три +```} +* { +*. раз +*. два +*. три +} + +Если вы пропишете `x` или `v`, вы превратите пункты в соответственно незавершённные и завершённые пункты списка дел (T\ODO). +* {``` +*v Готово +*x Не готово +**v Очень готово +** Круто +```} +* { +*v Готово +*x Не готово +**v Очень готово +** Круто +} + +В пунктах списка поддерживается вся микоразметка. Если вы хотите прописать многострочный пунт, оберните его содержимое в фигурные скобки. + +* {``` +* { +## Заголовок +Текст +} +* Не многострочное +```} +* { +* { +## Заголовок +Текст +} +* Не многострочное +} + +## Цитата +Начните строку с `>`, чтобы поместить её в цитату. + +* {``` +> ## Заголовок +> +> Абзац +> > Вложенная цитата +```} +* { +> ## Заголовок +> +> Абзац +> > Вложенная цитата +} + +## Таблица +**Таблицы** прописываются в блоке вида `table {...}`. Обе ограничивающие части блока должны размещаться на своих строках. На первой строке вы можете прописать заголовок таблицы. + +``` +Пустая таблица: +table { +} +``` +Пустая таблица: +table { +} + +``` +table { Пустая таблица с заголовком +} +``` +table { Пустая таблица с заголовком +} + +Ячейки-заголовки начинаются с !, обычные – с |. Ряды таблицы отделяются переносами строки: + +``` +table { +! Понедельник ! Пятница +| день тяжёлый | день весёлый +} +``` +table { +! Понедельник ! Пятница +| день тяжёлый | день весёлый +} + +Ячейки таблицы поддерживают всё форматирование абзаца: + +``` +table { +! Понедельник ! Пятница +| день тяжёлый | //день весёлый// +} +``` +table { +! Понедельник ! Пятница +| день тяжёлый | //день весёлый// +} + +Если вы хотите, чтобы ячейка занимала несколько столбцов, пропишите символ начала этой ячейки нужное число раз подряд (без пробелов): + +``` +table { +! Понедельник ! Пятница +|| нормальный день +} +``` +table { +! Понедельник ! Пятница +|| нормальный день +} + +Пока что объединение ячеек по вертикали не поддерживается. + +Если вы хотите прописать многострочную ячейку, оберните её содержимое в `{}` и продолжите таблицу после этого блока: +``` +table { +| a | b +| { в этой ячейке +целых //два// абзаца! } | d +} +``` +table { +| a | b +| { в этой ячейке +целых //два// абзаца! } | d +} + +Вертикальные черты в начале строки можно опустить, они будут вставлены автоматически: +``` +table { +a | b +c | d +} +``` +table { +a | b +c | d +} + +## Трансклюзия +**Трансклюзия** – механизм включения содержимого других гиф в одну гифу. + +Чтобы включить гифу под названием `йогурт`, напишите строку такого вида: +``` +<= йогурт +``` + +Строки-трансклюзии начинаются с перевёрнутой ракеты (`<=`), после которой пишется ноль или более пробелов. Текст до переноса строки или вертикальной черты (`|`) называется //целью// или //целевой гифой//. Если есть вертикальная черта, текст после неё называется //селектором//. Если черты нет, //селектор// пустой. И //цель//, и //селектор// проходят обрезку непечатных символов (strip) с обеих сторон перед дальнейшей обработкой. + +``` +<= целевая гифа +<= целевая гифа | +<= целевая гифа | селектор +``` + +Заметьте, с релиза 1.2 семантика и синтаксис трансклюзии изменились. Если вы ранее использовали трансклюзию, обновите ваши гифы. Пока что движок будет предупреждать о трансклюзиях со старым синтаксисом через двоеточие. + +### Селектор +//Селектор// определяет, какая часть //целевой гифы// транклюзируется. Парсер распознаёт следующие ключевые слова: + +* **full.** Транклюзировать весь документ. +* **text.** Транклюзировать весь текст. +* **attachment.** Транклюзировать только вложение. +* **description.** Транклюзировать только первый абзац. +* **overview.** Объединяет **attachment** и **description**. + +Если найдено только одно из них, транклюзируется соответствующая часть. Если найдено несколько, производится б__о__льшая трансклюзия. Если не найдено ни одно, неявно подразумевается **overview**. + +К этому же, если прописано слово **blend**, трансклюзия отображается без стандартных серой рамки и ссылки на //целевую гифу//. + +Ниже приведена настоящая трансклюзия гифы. Она выдаст ошибку, если в вашей вики нет такой гифы. +<= u + +Рекурсивная трансклюзия поддерживается, но ограничена тремя итерациями. + +## См. также +=> https://mycorrhiza.wiki/hypha/essay/why_mycomarkup Почему была создана микоразметка \ No newline at end of file diff --git a/help/ru/recent_changes.myco b/help/ru/recent_changes.myco new file mode 100644 index 0000000..e87d010 --- /dev/null +++ b/help/ru/recent_changes.myco @@ -0,0 +1,20 @@ +# Недавние изменения +**Недавние изменения** это специальная страница, которая содержит список последних правок в вики. По умолчанию ссылка на эту страницу помещена в [[/help/ru/top_bar | верхнюю панель]]. Также вы можете быстро перейти сюда, нажав горячие клавиши `g r`. + +Обычно увлечённые и ответственные вики-редакторы регулярно заходят на эту страницу. + +=> /recent-changes Посмотреть недавние изменения на этой вики + +По умолчанию на странице приводится 20 последних правок. Там же вы можете выбрать другое число: 50 или 100. + +Правки сгруппированы по дате. + +Каждая правка имеет следующие свойства: +* **Время по UTC.** +* **Хэш коммита.** Играет роль идентификатора правки. +* **Автор,** если есть. +* **Затронутые гифы.** Большая часть действий затрагивает одну гифу (например, само редактирование), но некоторые затрагивают больше (например, рекурсивное редактирование или переименование). +* **Сообщение.** Оно поясняет, что это за правка. Формат сообщения относительно регулярен и его можно пропарсить. + +## См. также +=> /help/ru/feeds Ленты \ No newline at end of file diff --git a/help/ru/sibling_hyphae_section.myco b/help/ru/sibling_hyphae_section.myco new file mode 100644 index 0000000..3150294 --- /dev/null +++ b/help/ru/sibling_hyphae_section.myco @@ -0,0 +1,13 @@ +# Раздел с гифами-сиблингами +В правой (или нижней на небольших экранах) части страницы с гифой размещается особый раздел, перечисляющий **гифы-сиблинги**. + +> **Гифы-сиблинги** – гифы, являющиеся подгифами одной и той же гифы. Например, //Фрукт/Яблоко// и //Фрукт/Груша// приходятся сиблингами. + +Гифы-сиблинги приводятся в алфавитном порядке. Название гифы, которую вы просматриваете, также входит в список. Остальные пункты списка – ссылки на другие гифы. + +Иногда рядом с ссылками приводятся числа: +* **Нет числа.** У гифы нет подгиф. +* **Одно число.** Оно обозначает, сколько у гифы прямых подгиф. +* **Два числа.** Первое – количество прямых подгиф. Второе, в скобках – количество непрямых подгиф. + +Для гифы //Фрукт//, подгифы //Фрукт/Яблоко// и //Фрукт/Груша// будут прямыми, а подгифы //Фрукт/Яблоко/Красное// и //Фрукт/Яблоко/Зелёное// – непрямыми. \ No newline at end of file diff --git a/help/ru/telegram.myco b/help/ru/telegram.myco new file mode 100644 index 0000000..fce2a10 --- /dev/null +++ b/help/ru/telegram.myco @@ -0,0 +1,40 @@ +# Авторизация через Телеграм +//Эта статья предназначена для администраторов вики.// + +Если вы хотите, можете разрешить пользователям входить на вашу вики с помощью **Телеграм**. + +Телеграм (Telegram) – проприетарное приложение для обмена сообщениями с полмиллиарда пользователей по всему миру. Узнайте больше на [[https://telegram.org]]. + +## Настройка интеграции с Телеграм +Чтобы включить Телеграм-авторизацию, необходимо создать Телеграм-бота и связать его с вашей вики. + +### Создание бота +Откройте чат с [[https://t.me/botfather | @BotFather]], ботом для создания других ботов. Создайте в нём бота. В следующих шагах вам понадобятся его имя (username) и ключ (token). Также вы можете задать его аватар, будет здорово, если он будет совпадать с логотипом вашей вики. + +Создав бота, отправьте команду `/setdomain` и пропишите домен вашей вики. + +Вам не нужно будет //размещать// этого бота. Достаточно лишь того, что он будет создан в BotFather. Вы также можете переиспользовать ранее созданного бота. + +### Конфигурация +В секции `[Telegram]` файла `config.ini` впишите имя бота (без @) и его ключ: + +``` +[Telegram] +TelegramBotName = your_bot +TelegramBotToken = 0000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +``` + +Затем перезагрузите вики. + +Если обе опции прописаны, движок включит авториазцию через Telegram. + +## Использование +На страницах входа и регистрации появится синяя кнопка. После её нажатия пользователю предложат связаться с вашим ботом, чтобы подтвердить авторизацию. Имя пользователя в Телеграм (@username) будет переиспользовано в качестве имени в вики. По умолчанию пользователи Телеграм принадлежат к группе //редакторов (editor)//. Они могут использовать вики наравне с остальными. + +## Ограничения +* Ваша вики должна размещаться на публичном домене или белом IP-адресе. Приватно размещённые вики (например, в localhost или локальной сети) не поддерживаются. +* Телеграм не поддерживает вики на HTTP, вы //обязаны// использовать HTTPS. +** Один из способов настроить HTTPS – использовать [[https://certbot.eff.org | certbot]] в связке с обратным прокси, например, [[https://nginx.org | nginx]]. +* Телеграм-пользователи без @имени не смогут авторизоваться. +* Телеграм-пользователи с именем, уже занятым на вики, также не смогут авторизоваться. +* В целом, это экспериментальная функция. Применяйте её на свой страх и риск. diff --git a/help/ru/top_bar.myco b/help/ru/top_bar.myco new file mode 100644 index 0000000..57e67e3 --- /dev/null +++ b/help/ru/top_bar.myco @@ -0,0 +1,54 @@ +# Верхняя панель +**Верхняя панель** есть абсолютно на каждой странице вики. Это главный способ навигации. + +На больших экранах панель разделена на две строки. +* Первая строка +** Ссылка на [[/ | главную страницу]] +** Поисковая строка +** //Если включена авторизация,// +*** //Если произведён вход,// +**** Ссылка на гифу с профилем вашего пользователя +**** //Для админов,// ссылка на панель администратора +*** //Если входа не было,// +**** Ссылка на вход +**** Ссылка на регистрацию +* Вторая строка, часто используемые ссылки. По умолчанию содержит: +** Недавние изменения +** Все гифы +** Случайная гифа +** Справка + +На небольших экранах, раздел авторизации и часто используемые ссылки спрятаны в меню. Нажмите на кнопку, чтобы их увидеть. Если ваш браузер не поддерживает JavaScript, они будут перечислены как есть. + +## Использование верхней панели +Предполагается, что администраторы вики сконфигурируют ссылки верхней панели под себя. Вот что вам стоит туда поместить: +* Популярные статьи +* Списки чего-либо +* Недавние изменения +* Что вам угодно, но не так много, конечно. Пространство панели ограничено. + +## Конфигурация ссылок +//Этот раздел предназначен для администраторов вики.// + +Чтобы поменять стандартные ссылки, сначала нужно выбрать гифу, где вы собираетесь хранить конфигурацию. Хорошим выбором может быть подгифа гифы с профилем администратора. Пропишите адрес гифы в разделе `[Hyphae]` файла `config.ini`: +```ini +... +[Hyphae] +HeaderLinksHypha = u/admin/header_links +... +``` + +Затем перезагрузите вики. + +---- + +Отредактируйте гифу. Вы можете поместить в неё любую разметку. Для генерации верхней панели используются ссылки-ракеты: + +```myco +=> /recent-changes История правок +=> Хайлайты +=> Философия Наши взгляды на жизнь +=> Статьи +``` + +Пока что, чтобы изменения вступили в силу, модератор или администратор должен открыть [[/update-header-links]]. \ No newline at end of file diff --git a/help/ru/whitelist.myco b/help/ru/whitelist.myco new file mode 100644 index 0000000..a53af1a --- /dev/null +++ b/help/ru/whitelist.myco @@ -0,0 +1,17 @@ +# Белый список +//Эта статья предназначена для администраторов вики.// + +Если вы хотите ограничить круг лиц, способных авторизоваться на вашей вики, вам пригодится **белый список**. + +Чтобы его включить, в секции `[Authorization]` файла `config.ini` пропишите значение `true` в `UseWhiteList`, а в поле `WhiteList` перечислите все разрешённые имена пользователей через запятую: +``` +... +[Authorization] +UseWhiteList = true +WhiteList = fish,pesce,рыба +... +``` + +Затем перезагрузите вики. + +С этого момента можно использовать только указанные имена, т.е. регистрироваться и заходить можно только под ними. С остальными именами этого не получится. \ No newline at end of file diff --git a/l18n/l18n.go b/l18n/l18n.go new file mode 100644 index 0000000..dea0f32 --- /dev/null +++ b/l18n/l18n.go @@ -0,0 +1,524 @@ +// Code generated by go-localize; DO NOT EDIT. +// This file was generated by robots at +// 2021-09-27 16:30:27.741694276 +0800 +08 m=+0.002576981 + +package l18n + +import ( + "bytes" + "fmt" + "strings" + "text/template" +) + +var localizations = map[string]string{ + "en.admin.newuser_create": "Create", + "en.admin.newuser_title": "New user", + "en.admin.panel_about": "About this wiki", + "en.admin.panel_reindex": "Reindex hyphae", + "en.admin.panel_safe": "Safe things", + "en.admin.panel_shutdown": "Shutdown wiki", + "en.admin.panel_title": "Administrative functions", + "en.admin.panel_unsafe": "Dangerous things", + "en.admin.panel_updateheader": "Update header links", + "en.admin.panel_userlist": "User list", + "en.admin.panel_users": "Manage users", + "en.admin.user_delete": "Delete", + "en.admin.user_delete_heading": "Delete user", + "en.admin.user_delete_tip": "Remove the user from the database. Changes made by the user will be preserved. It will be possible to take this username later.", + "en.admin.user_delete_warn": "Are you sure you want to delete {{.name}} from the database? This action is irreversible.", + "en.admin.user_group_heading": "Change group", + "en.admin.user_title": "User %s", + "en.admin.user_update": "Update", + "en.admin.users_actions": "Actions", + "en.admin.users_create": "Create a new user", + "en.admin.users_edit": "Edit", + "en.admin.users_group": "Group", + "en.admin.users_name": "Name", + "en.admin.users_notime": "unknown", + "en.admin.users_password": "Password", + "en.admin.users_registered": "Registered at", + "en.admin.users_reindex": "Reindex users", + "en.admin.users_title": "Manage users", + "en.auth.cookie_tip": "By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.", + "en.auth.error_password": "Wrong password.", + "en.auth.error_telegram": "Could not authorize using Telegram.", + "en.auth.error_username": "Unknown username.", + "en.auth.go_back": "Go back", + "en.auth.go_home": "Go home", + "en.auth.go_login": "Go to the login page", + "en.auth.lock_title": "Locked", + "en.auth.login_button": "Log in", + "en.auth.login_header": "Log in to {{.name}}", + "en.auth.login_title": "Login", + "en.auth.logout_anon": "You cannot log out because you are not logged in.", + "en.auth.logout_button": "Confirm", + "en.auth.logout_header": "Log out?", + "en.auth.logout_title": "Logout?", + "en.auth.noauth": "Authentication is disabled. You can make edits anonymously.", + "en.auth.noregister": "Registrations are currently closed. Administrators can make an account for you by hand; contact them.", + "en.auth.password": "Password", + "en.auth.password_tip": "The server stores your password in an encrypted form; even administrators cannot read it.", + "en.auth.register_button": "Register", + "en.auth.register_header": "Register on {{.name}}", + "en.auth.register_title": "Register", + "en.auth.telegram_tip": "You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.", + "en.auth.try_again": "Try again", + "en.auth.username": "Username", + "en.edit.actions": "Actions", + "en.edit.bold": "Bold", + "en.edit.bullets": "Bullet list", + "en.edit.code": "Code block", + "en.edit.date": "Insert current date", + "en.edit.heading": "Heading", + "en.edit.help": "{{.link}} about mycomarkup", + "en.edit.help_link": "Learn more", + "en.edit.highlight": "Highlight", + "en.edit.hr": "Horizontal bar", + "en.edit.italic": "Italic", + "en.edit.link": "Link", + "en.edit.link_title": "Title", + "en.edit.markup": "Markup", + "en.edit.mono": "Monospace", + "en.edit.new_hypha": "You are creating a new hypha.", + "en.edit.numbers": "Number list", + "en.edit.preview": "Preview", + "en.edit.preview_tip": "Note that the hypha hasn't been saved yet. Here's the preview:", + "en.edit.preview_title": "Preview of %s", + "en.edit.rocket": "Rocketlink", + "en.edit.save": "Save", + "en.edit.selflink": "Link yourself", + "en.edit.strike": "Strikethrough", + "en.edit.sub": "Subtext", + "en.edit.super": "Supertext", + "en.edit.tag": "Describe your changes:", + "en.edit.time": "Insert current time", + "en.edit.title": "Edit %s", + "en.edit.transclude": "Transclusion", + "en.edit.underline": "Underline", + "en.help.attachment": "Attachment", + "en.help.configuration": "Configuration (for administrators)", + "en.help.empty_error_line_1": "Try finding a different entry that would help you.", + "en.help.empty_error_line_2a": "If you want to write this entry by yourself, consider", + "en.help.empty_error_line_2b": "to Mycorrhiza Wiki directly.", + "en.help.empty_error_link": "contributing", + "en.help.empty_error_title": "This entry does not exist!", + "en.help.entry_not_found": "Entry not found", + "en.help.hypha": "Hypha", + "en.help.interface": "Interface", + "en.help.lock": "Lock", + "en.help.main": "Main", + "en.help.mycomarkup": "Mycomarkup", + "en.help.recent_changes": "Recent changes", + "en.help.sibling_hyphae": "Sibling hyphae", + "en.help.special_pages": "Special pages", + "en.help.telegram": "Telegram authorization", + "en.help.title": "Help", + "en.help.top_bar": "Top bar", + "en.help.topics": "Help topics", + "en.help.whitelist": "Whitelist", + "en.ui.about_admins": "Administrators:", + "en.ui.about_homepage": "Home page:", + "en.ui.about_hyphae": "See {{.link}} for information about hyphae on this wiki.", + "en.ui.about_noauth": "This wiki does not use authorization", + "en.ui.about_title": "About {{.name}}", + "en.ui.about_usercount": "User count:", + "en.ui.about_version": "{{.pre}}Mycorrhiza Wiki{{.post}} version:", + "en.ui.admin_panel": "Admin panel", + "en.ui.ask_delete": "Delete %s?", + "en.ui.ask_delete_tip": "In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.", + "en.ui.ask_delete_verb": "delete", + "en.ui.ask_really": "Do you really want to {{.verb}} hypha {{.name}}?", + "en.ui.ask_rename": "Rename %s", + "en.ui.ask_unattach": "Unattach %s?", + "en.ui.ask_unattach_verb": "unattach", + "en.ui.attach_empty": "This hypha has no attachment, you can upload it here.", + "en.ui.attach_include": "Include", + "en.ui.attach_include_tip": "This attachment is an image. To include it in a hypha, use a syntax like this:", + "en.ui.attach_link": "What are attachments?", + "en.ui.attach_new": "Attach", + "en.ui.attach_new_tip": "You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.", + "en.ui.attach_remove": "Unattach", + "en.ui.attach_remove_button": "Unattach", + "en.ui.attach_remove_tip": "Please note that you don't have to unattach before uploading a new attachment.", + "en.ui.attach_size_value": "{{.n}} byte%s", + "en.ui.attach_size_value+one": "", + "en.ui.attach_size_value+other": "s", + "en.ui.attach_stat": "Stat", + "en.ui.attach_stat_mime": "MIME type:", + "en.ui.attach_stat_size": "File size:", + "en.ui.attach_tip": "You can manage the hypha's attachment on this page.", + "en.ui.attach_title": "Attachment of {{.name}}", + "en.ui.attach_upload": "Upload", + "en.ui.attachment_link": "Manage attachment", + "en.ui.backlinks_desc": "Hyphae which have a link to the selected hypha are listed below.", + "en.ui.backlinks_link": "{{.n}} backlink%s", + "en.ui.backlinks_link+one": "", + "en.ui.backlinks_link+other": "s", + "en.ui.backlinks_query": "Backlinks to ‘{{.query}}’", + "en.ui.backlinks_title": "Backlinks to {{.query}}", + "en.ui.cancel": "Cancel", + "en.ui.close_dialog": "Close this dialog", + "en.ui.confirm": "Confirm", + "en.ui.delete_link": "Delete", + "en.ui.diff_title": "Diff of {{.name}} at {{.rev}}", + "en.ui.edit_link": "Edit text", + "en.ui.error": "Error", + "en.ui.error_go_back": "Go back to the hypha.", + "en.ui.error_text_fetch": "Could not fetch text data", + "en.ui.error_try_again": "Try again", + "en.ui.header_no_rights": "You must be a moderator to update header links.", + "en.ui.history_link": "View history", + "en.ui.history_title": "History of %s", + "en.ui.list_desc": "This wiki has {{.n}} %s.", + "en.ui.list_desc+one": "hypha", + "en.ui.list_desc+other": "hyphae", + "en.ui.list_heading": "List of hyphae", + "en.ui.list_title": "List of pages", + "en.ui.login": "Login", + "en.ui.media_download": "Download media", + "en.ui.media_noaudio": "Your browser does not support audio.", + "en.ui.media_noaudio_link": "Download audio", + "en.ui.media_novideo": "Your browser does not support video.", + "en.ui.media_novideo_link": "Download video", + "en.ui.no_rights": "Not enough rights", + "en.ui.notexist_heading": "This hypha does not exist", + "en.ui.notexist_login": "Log in to your account, if you have one", + "en.ui.notexist_media": "Upload a media", + "en.ui.notexist_media_tip1": "Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.", + "en.ui.notexist_norights": "You are not authorized to create new hyphae. Here is what you can do:", + "en.ui.notexist_register": "Register a new account", + "en.ui.notexist_write": "Write a text", + "en.ui.notexist_write_button": "Create", + "en.ui.notexist_write_myco": "Mycomarkup", + "en.ui.notexist_write_tip1": "Write a note, a diary, an article, a story or anything textual using {{.myco}}. Full history of edits to the document will be saved.", + "en.ui.notexist_write_tip2": "Make sure to follow this wiki's writing conventions if there are any.", + "en.ui.random_no_hyphae": "There are no hyphae", + "en.ui.random_no_hyphae_tip": "It is impossible to display a random hypha because the wiki does not contain any hyphae", + "en.ui.recent_count_post": "recent changes", + "en.ui.recent_count_pre": "See", + "en.ui.recent_empty": "Could not find any recent changes.", + "en.ui.recent_heading": "Recent Changes", + "en.ui.recent_subscribe": "Subscribe via {{.rss}}, {{.atom}} or {{.json}}", + "en.ui.recent_subscribe_json": "JSON feed", + "en.ui.recent_title": "{{.n}} recent change%s", + "en.ui.recent_title+one": "", + "en.ui.recent_title+other": "s", + "en.ui.register": "Register", + "en.ui.reindex_no_rights": "You must be an admin to reindex hyphae.", + "en.ui.rename_link": "Rename", + "en.ui.rename_recurse": "Rename subhyphae too", + "en.ui.rename_tip": "If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.", + "en.ui.rename_to": "New name", + "en.ui.revision_no_text": "This hypha had no text at this revision.", + "en.ui.revision_title": "{{.name}} at {{.rev}}", + "en.ui.revision_warning": "Please note that viewing attachments of hyphae is not supported in history for now.", + "en.ui.search_results_desc": "Every hypha name has been compared with the query. Hyphae that have matched the query are listed below.", + "en.ui.search_results_query": "Search results for ‘{{.query}}’", + "en.ui.search_results_title": "Search: {{.query}}", + "en.ui.sibling_hyphae": "Sibling hyphae", + "en.ui.subhyphae": "Subhyphae", + "en.ui.text_link": "View markup", + "en.ui.title_search": "Search by title", + "en.ui.users_admins": "Admins", + "en.ui.users_editors": "Editors", + "en.ui.users_heading": "List of users", + "en.ui.users_moderators": "Moderators", + "en.ui.users_title": "User list", + "ru.admin.newuser_create": "Создать", + "ru.admin.newuser_title": "Новый пользователь", + "ru.admin.panel_about": "Об этой вики", + "ru.admin.panel_reindex": "Reindex hyphae", + "ru.admin.panel_safe": "Безопасные действия", + "ru.admin.panel_shutdown": "Отключить вики", + "ru.admin.panel_title": "Панель администратора", + "ru.admin.panel_unsafe": "Опасные действия", + "ru.admin.panel_updateheader": "Обновить ссылки верхней панели", + "ru.admin.panel_userlist": "Список пользователей", + "ru.admin.panel_users": "Менеджер пользователей", + "ru.admin.user_delete": "Удалить", + "ru.admin.user_delete_heading": "Удалить пользователя", + "ru.admin.user_delete_tip": "Удаляет пользователя из базы данных. Правки пользователя будут сохранены. Имя пользователя освободится для повторной регистрации.", + "ru.admin.user_delete_warn": "Вы уверены, что хотите удалить {{.name}} из базы данных? Это действие нельзя отменить.", + "ru.admin.user_group_heading": "Изменить группу", + "ru.admin.user_title": "Пользователь %s", + "ru.admin.user_update": "Обновить", + "ru.admin.users_actions": "Действия", + "ru.admin.users_create": "Создать пользователя", + "ru.admin.users_edit": "Изменить", + "ru.admin.users_group": "Группа", + "ru.admin.users_name": "Имя", + "ru.admin.users_notime": "неизвестно", + "ru.admin.users_password": "Пароль", + "ru.admin.users_registered": "Время создания", + "ru.admin.users_reindex": "Переиндексировать пользователей", + "ru.admin.users_title": "Менеджер пользователей", + "ru.auth.cookie_tip": "Отправляя эту форму, вы разрешаете вики хранить cookie в вашем браузере. Это позволит движку связывать ваши правки с вашей учётной записью. Вы будете авторизованы, пока не выйдете из учётной записи.", + "ru.auth.error_password": "Неверный пароль.", + "ru.auth.error_telegram": "Не удалось авторизоваться через Телеграм.", + "ru.auth.error_username": "Неизвестное имя пользователя.", + "ru.auth.go_back": "Назад", + "ru.auth.go_home": "Домой", + "ru.auth.go_login": "На страницу входа", + "ru.auth.lock_title": "Доступ закрыт", + "ru.auth.login_button": "Войти", + "ru.auth.login_header": "Вход в «{{.name}}»", + "ru.auth.login_title": "Вход", + "ru.auth.logout_anon": "Вы не можете выйти, потому что ещё не вошли.", + "ru.auth.logout_button": "Подтвердить", + "ru.auth.logout_header": "Выйти?", + "ru.auth.logout_title": "Выйти?", + "ru.auth.noauth": "Аутентификация отключена. Вы можете делать правки анонимно.", + "ru.auth.noregister": "Регистрация в текущее время недоступна. Администраторы могут вручную создать вам учётную запись, свяжитесь с ними.", + "ru.auth.password": "Пароль", + "ru.auth.password_tip": "Сервер хранит ваш пароль в зашифрованном виде, даже администраторы не смогут его прочесть.", + "ru.auth.register_button": "Зарегистрироваться", + "ru.auth.register_header": "Регистрация на «{{.name}}»", + "ru.auth.register_title": "Регистрация", + "ru.auth.telegram_tip": "Вы можете войти с помощью Телеграм. Это сработает, если у вашего профиля есть @имя, и оно не занято в этой вики.", + "ru.auth.try_again": "Ещё раз", + "ru.auth.username": "Логин", + "ru.edit.actions": "Действия", + "ru.edit.bold": "Жирный", + "ru.edit.bullets": "Маркир. список", + "ru.edit.code": "Код-блок", + "ru.edit.date": "Текущая дата", + "ru.edit.heading": "Заголовок", + "ru.edit.help": "{{.link}} о микоразметке", + "ru.edit.help_link": "Подробнее", + "ru.edit.highlight": "Выделение", + "ru.edit.hr": "Гориз. черта", + "ru.edit.italic": "Курсив", + "ru.edit.link": "Ссылка", + "ru.edit.link_title": "Текст", + "ru.edit.markup": "Разметка", + "ru.edit.mono": "Моноширинный", + "ru.edit.new_hypha": "Вы создаёте новую гифу.", + "ru.edit.numbers": "Нумер. список", + "ru.edit.preview": "Предпросмотр", + "ru.edit.preview_tip": "Заметьте, эта гифа ещё не сохранена. Вот её предпросмотр:", + "ru.edit.preview_title": "Предпросмотр «%s»", + "ru.edit.rocket": "Ссылка-ракета", + "ru.edit.save": "Сохранить", + "ru.edit.selflink": "Ссылка на вас", + "ru.edit.strike": "Зачёркнутый", + "ru.edit.sub": "Подстрочный", + "ru.edit.super": "Надстрочный", + "ru.edit.tag": "Опишите ваши правки:", + "ru.edit.time": "Текущее время", + "ru.edit.title": "Редактирование «%s»", + "ru.edit.transclude": "Трансклюзия", + "ru.edit.underline": "Подчеркивание", + "ru.help.attachment": "Вложение", + "ru.help.configuration": "Конфигурация (для администраторов)", + "ru.help.empty_error_line_1": "Попробуйте поискать другую страницу, способную вам помочь.", + "ru.help.empty_error_line_2a": "Если вы хотите написать эту страницу сами, будем рады вашим правкам в ", + "ru.help.empty_error_line_2b": "Микоризы.", + "ru.help.empty_error_link": "репозитории", + "ru.help.empty_error_title": "Этой страницы не существует!", + "ru.help.entry_not_found": "Запись не найдена", + "ru.help.hypha": "Гифа", + "ru.help.interface": "Интерфейс", + "ru.help.lock": "Блокировка", + "ru.help.main": "Введение", + "ru.help.mycomarkup": "Микоразметка", + "ru.help.recent_changes": "Недавние изменения", + "ru.help.sibling_hyphae": "Гифы-сиблинги", + "ru.help.special_pages": "Специальные страницы", + "ru.help.telegram": "Авторизация через Телеграм", + "ru.help.title": "Справка", + "ru.help.top_bar": "Верхняя панель", + "ru.help.topics": "Темы справки", + "ru.help.whitelist": "Белый список", + "ru.ui.about_admins": "Администраторы:", + "ru.ui.about_homepage": "Домашняя гифа:", + "ru.ui.about_hyphae": "См. {{.link}}, чтобы узнать о гифах в этой вики.", + "ru.ui.about_noauth": "В этой вики нет авторизации", + "ru.ui.about_title": "О вики «{{.name}}»", + "ru.ui.about_usercount": "Число пользователей:", + "ru.ui.about_version": "Версия {{.pre}}Микоризы{{.post}}:", + "ru.ui.admin_panel": "Администрирование", + "ru.ui.ask_delete": "Удалить «%s»?", + "ru.ui.ask_delete_tip": "В этой версии Микоризы нельзя отменить удаление гифы, но её история останется доступной.", + "ru.ui.ask_delete_verb": "удалить", + "ru.ui.ask_really": "Вы действительно хотите {{.verb}} гифу «{{.name}}»?", + "ru.ui.ask_rename": "Переименовать «%s»", + "ru.ui.ask_unattach": "Открепить «%s»?", + "ru.ui.ask_unattach_verb": "открепить", + "ru.ui.attach_empty": "Эта гифа не имеет вложения, здесь вы можете его загрузить.", + "ru.ui.attach_include": "Добавление", + "ru.ui.attach_include_tip": "Это вложение – изображение. Чтобы добавить его в текст гифы, используйте синтаксис ниже:", + "ru.ui.attach_link": "Что такое вложение?", + "ru.ui.attach_new": "Прикрепить", + "ru.ui.attach_new_tip": "Вы можете загрузить новое вложение. Пожалуйста, не загружайте слишком большие изображения без необходимости, чтобы впоследствии не ждать её долгую загрузку.", + "ru.ui.attach_remove": "Открепить", + "ru.ui.attach_remove_button": "Открепить", + "ru.ui.attach_remove_tip": "Заметьте, чтобы заменить вложение, вам не нужно его перед этим откреплять.", + "ru.ui.attach_size_value": "{{.n}} %s", + "ru.ui.attach_size_value+few": "байта", + "ru.ui.attach_size_value+many": "байт", + "ru.ui.attach_size_value+one": "байт", + "ru.ui.attach_stat": "Свойства", + "ru.ui.attach_stat_mime": "MIME-тип:", + "ru.ui.attach_stat_size": "Размер файла:", + "ru.ui.attach_tip": "На этой странице вы можете управлять вложением.", + "ru.ui.attach_title": "Вложение «{{.name}}»", + "ru.ui.attach_upload": "Загрузить", + "ru.ui.attachment_link": "Вложение", + "ru.ui.backlinks_desc": "Ниже перечислены гифы, содержащие ссылку на выбранную гифу.", + "ru.ui.backlinks_link": "{{.n}} %s сюда", + "ru.ui.backlinks_link+few": "ссылки", + "ru.ui.backlinks_link+many": "ссылок", + "ru.ui.backlinks_link+one": "ссылка", + "ru.ui.backlinks_query": "Обратные ссылки на «{{.query}}»", + "ru.ui.backlinks_title": "Обратные ссылки на {{.query}}", + "ru.ui.cancel": "Отмена", + "ru.ui.close_dialog": "Закрыть этот диалог", + "ru.ui.confirm": "Применить", + "ru.ui.delete_link": "Удалить", + "ru.ui.diff_title": "Разница для «{{.name}}» из {{.rev}}", + "ru.ui.edit_link": "Редактировать", + "ru.ui.error": "Ошибка", + "ru.ui.error_go_back": "Вернуться к гифе.", + "ru.ui.error_text_fetch": "Не удалось получить текстовые данные", + "ru.ui.error_try_again": "Попробуйте ещё раз", + "ru.ui.header_no_rights": "Вы должны быть модератором, чтобы обновить ссылки в заголовке.", + "ru.ui.history_link": "История", + "ru.ui.history_title": "История «%s»", + "ru.ui.list_desc": "В этой вики {{.n}} %s.", + "ru.ui.list_desc+few": "гифы", + "ru.ui.list_desc+many": "гиф", + "ru.ui.list_desc+one": "гифа", + "ru.ui.list_heading": "Список гиф", + "ru.ui.list_title": "Список страниц", + "ru.ui.login": "Войти", + "ru.ui.media_download": "Скачать медиа", + "ru.ui.media_noaudio": "Ваш браузер не поддерживает аудио.", + "ru.ui.media_noaudio_link": "Скачать аудио", + "ru.ui.media_novideo": "Ваш браузер не поддерживает видео.", + "ru.ui.media_novideo_link": "Скачать видео", + "ru.ui.no_rights": "Недостаточно прав", + "ru.ui.notexist_heading": "Эта гифа не существует", + "ru.ui.notexist_login": "Войти в свою учётную запись, если она у вас есть", + "ru.ui.notexist_media": "Загрузить медиа", + "ru.ui.notexist_media_tip1": "Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные – просто скачать. Позже вы можете дописать пояснение к этому медиа.", + "ru.ui.notexist_norights": "У вас нет прав для создания новых гиф. Вы можете:", + "ru.ui.notexist_register": "Создать новую учётную запись", + "ru.ui.notexist_write": "Написать текст", + "ru.ui.notexist_write_button": "Создать", + "ru.ui.notexist_write_myco": "микоразметки", + "ru.ui.notexist_write_tip1": "Напишите заметку, дневник, статью, рассказ или иной текст с помощью {{.myco}}. Сохраняется полная история правок документа.", + "ru.ui.notexist_write_tip2": "Не забывайте следовать правилам оформления этой вики, если они имеются.", + "ru.ui.random_no_hyphae": "В этой вики нет гиф", + "ru.ui.random_no_hyphae_tip": "Невозможно отобразить случайную гифу, потому что вики не содержит ни одной гифы", + "ru.ui.recent_count_post": "недавних изменений", + "ru.ui.recent_count_pre": "Отобразить", + "ru.ui.recent_empty": "Не удалось найти последние изменения.", + "ru.ui.recent_heading": "Недавние изменения", + "ru.ui.recent_subscribe": "Подписаться через {{.rss}}, {{.atom}} или {{.json}}", + "ru.ui.recent_subscribe_json": "JSON-ленту", + "ru.ui.recent_title": "{{.n}} %s", + "ru.ui.recent_title+few": "недавних изменения", + "ru.ui.recent_title+many": "недавних изменений", + "ru.ui.recent_title+one": "недавнее изменение", + "ru.ui.register": "Регистрация", + "ru.ui.reindex_no_rights": "Вы должны быть администратором, чтобы переиндексировать гифы.", + "ru.ui.rename_link": "Переименовать", + "ru.ui.rename_recurse": "Также переименовать подгифы", + "ru.ui.rename_tip": "Если вы переименуете эту гифу, сломаются все ссылки, ведущие на неё, а также исходящие относительные ссылки. Также вы потеряете всю текущую историю для нового названия. Переименовывайте аккуратно.", + "ru.ui.rename_to": "Новое название", + "ru.ui.revision_no_text": "В этой ревизии гифы не было текста.", + "ru.ui.revision_title": "{{.name}} из {{.rev}}", + "ru.ui.revision_warning": "Обратите внимание, просмотр вложений в истории гифы пока что недоступен.", + "ru.ui.search_results_desc": "Название каждой из существующих гиф сопоставлено с запросом. Подходящие гифы приведены ниже.", + "ru.ui.search_results_query": "Результаты поиска для «{{.query}}»", + "ru.ui.search_results_title": "Поиск: {{.query}}", + "ru.ui.sibling_hyphae": "Гифы-сиблинги", + "ru.ui.subhyphae": "Подгифы", + "ru.ui.text_link": "Посмотреть разметку", + "ru.ui.title_search": "Поиск по названию", + "ru.ui.users_admins": "Администраторы", + "ru.ui.users_editors": "Редакторы", + "ru.ui.users_heading": "Список пользователей", + "ru.ui.users_moderators": "Модераторы", + "ru.ui.users_title": "Список пользователей", +} + +type Replacements map[string]interface{} + +type Localizer struct { + Locale string + FallbackLocale string + Localizations map[string]string +} + +func New(locale string, fallbackLocale string) *Localizer { + t := &Localizer{Locale: locale, FallbackLocale: fallbackLocale} + t.Localizations = localizations + return t +} + +func (t Localizer) SetLocales(locale, fallback string) Localizer { + t.Locale = locale + t.FallbackLocale = fallback + return t +} + +func (t Localizer) SetLocale(locale string) Localizer { + t.Locale = locale + return t +} + +func (t Localizer) SetFallbackLocale(fallback string) Localizer { + t.FallbackLocale = fallback + return t +} + +func (t Localizer) GetWithLocale(locale, key string, replacements ...*Replacements) string { + str, ok := t.Localizations[t.getLocalizationKey(locale, key)] + if !ok { + str, ok = t.Localizations[t.getLocalizationKey(t.FallbackLocale, key)] + if !ok { + return key + } + } + + // If the str doesn't have any substitutions, no need to + // template.Execute. + if strings.Index(str, "}}") == -1 { + return str + } + + return t.replace(str, replacements...) +} + +func (t Localizer) Get(key string, replacements ...*Replacements) string { + str := t.GetWithLocale(t.Locale, key, replacements...) + return str +} + +func (t Localizer) getLocalizationKey(locale string, key string) string { + return fmt.Sprintf("%v.%v", locale, key) +} + +func (t Localizer) replace(str string, replacements ...*Replacements) string { + b := &bytes.Buffer{} + tmpl, err := template.New("").Parse(str) + if err != nil { + return str + } + + replacementsMerge := Replacements{} + for _, replacement := range replacements { + for k, v := range *replacement { + replacementsMerge[k] = v + } + } + + err = template.Must(tmpl, err).Execute(b, replacementsMerge) + if err != nil { + return str + } + buff := b.String() + return buff +} diff --git a/l18n/util.go b/l18n/util.go new file mode 100644 index 0000000..5701548 --- /dev/null +++ b/l18n/util.go @@ -0,0 +1,105 @@ +package l18n + +import ( + "fmt" + "golang.org/x/text/feature/plural" + "golang.org/x/text/language" + "net/http" + "strings" +) + +// matcher is a language.Matcher configured for all supported languages. +var locales = language.NewMatcher([]language.Tag{ + language.Make("en"), + language.Make("ru"), +}) + +// GetLocalizer takes a HTTP request and picks the most appropriate localizer (with English fallback) +func FromRequest(r *http.Request) *Localizer { + t, _, _ := language.ParseAcceptLanguage(r.Header.Get("Accept-Language")) + tag, _, _ := locales.Match(t...) + // TODO: support subtags such as en-US, en-GB, zh-Hans + base, _ := tag.Base() + return New(base.String(), "en") +} + +var formNames = map[plural.Form]string{ + plural.Other: "other", + plural.Zero: "zero", + plural.One: "one", + plural.Two: "two", + plural.Few: "few", + plural.Many: "many", +} + +func (t Localizer) rawPlural(lang, rawKey string, n int) (string, bool) { + key := t.getLocalizationKey(lang, rawKey) + str, ok := t.Localizations[key] + if !ok { + return key, false + } + var ( + formIdx = plural.Cardinal.MatchPlural(language.Make(lang), n, 0, 0, 0, 0) + form = formNames[formIdx] + ) + plural, plOk := t.Localizations[fmt.Sprintf("%v+%v", key, form)] + if !plOk { + return key, false + } + return fmt.Sprintf(str, plural), true +} + +// GetPlural gets a translated string respecting locale-specific plural rules. Technically, it replaces %s token with +form subkey and proceed as usual. +func (t Localizer) GetPlural(key string, n int, replacements ...*Replacements) string { + str, ok := t.rawPlural(t.Locale, key, n) + if !ok { + str, ok = t.rawPlural(t.FallbackLocale, key, n) + if !ok { + return key + } + } + + // As in the original, we skip templating if have nothing to replace (however, it's strange case for plurals) + if strings.Index(str, "}}") == -1 { + return str + } + + return t.replace(str, append(replacements, &Replacements{"n": n})...) +} + +// GetPlural64 is ditto for int64 +func (t Localizer) GetPlural64(key string, n int64, replacements ...*Replacements) string { + str, ok := t.rawPlural(t.Locale, key, int(n%1000000)) + if !ok { + str, ok = t.rawPlural(t.FallbackLocale, key, int(n%1000000)) + if !ok { + return key + } + } + + // As in the original, we skip templating if have nothing to replace (however, it's strange case for plurals) + if strings.Index(str, "}}") == -1 { + return str + } + + return t.replace(str, append(replacements, &Replacements{"n": n})...) +} + +func getLocalizationKey(locale string, key string) string { + return fmt.Sprintf("%v.%v", locale, key) +} + +/* chekoopa: Missing translation features: +- history records (they use Git description, the possible solution is to parse and translate) +- history dates (HistoryWithRevisions doesn't consider locale, Monday package is bad idea) +- probably error messages (which are scattered across the code) +- default top bar (it is static from one-shot cfg.SetDefaultHeaderLinks, but it is possible to track default-ness in templates) + - alt solution is implementing "special" links +- dynamic UI (JS are static, though we may send some strings through templates) +- help switches, like, + - "Read in your language" + - "Try reading it in English", if no page found in a foreign locale +- feeds (it seems diffcult to pull locale here) + We do not translate: +- stdout traces (logging is English-only) +*/ diff --git a/l18n_src/en/admin.json b/l18n_src/en/admin.json new file mode 100644 index 0000000..76e2679 --- /dev/null +++ b/l18n_src/en/admin.json @@ -0,0 +1,33 @@ +{ + "panel_title": "Administrative functions", + "panel_safe": "Safe things", + "panel_unsafe": "Dangerous things", + "panel_about": "About this wiki", + "panel_userlist": "User list", + "panel_updateheader": "Update header links", + "panel_users": "Manage users", + "panel_shutdown": "Shutdown wiki", + "panel_reindex": "Reindex hyphae", + + "users_title": "Manage users", + "users_create": "Create a new user", + "users_reindex": "Reindex users", + "users_name": "Name", + "users_password": "Password", + "users_group": "Group", + "users_registered": "Registered at", + "users_actions": "Actions", + "users_notime": "unknown", + "users_edit": "Edit", + + "user_title": "User %s", + "user_group_heading": "Change group", + "user_update": "Update", + "user_delete_heading": "Delete user", + "user_delete_tip": "Remove the user from the database. Changes made by the user will be preserved. It will be possible to take this username later.", + "user_delete_warn": "Are you sure you want to delete {{.name}} from the database? This action is irreversible.", + "user_delete": "Delete", + + "newuser_title": "New user", + "newuser_create": "Create" +} diff --git a/l18n_src/en/auth.json b/l18n_src/en/auth.json new file mode 100644 index 0000000..307420a --- /dev/null +++ b/l18n_src/en/auth.json @@ -0,0 +1,35 @@ +{ + "username": "Username", + "password": "Password", + + "register_title": "Register", + "register_header": "Register on {{.name}}", + "register_button": "Register", + + "login_title": "Login", + "login_header": "Log in to {{.name}}", + "login_button": "Log in", + + "logout_title": "Logout?", + "logout_header": "Log out?", + "logout_button": "Confirm", + "logout_anon": "You cannot log out because you are not logged in.", + + "lock_title": "Locked", + + "password_tip": "The server stores your password in an encrypted form; even administrators cannot read it.", + "cookie_tip": "By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.", + "telegram_tip": "You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.", + + "noauth": "Authentication is disabled. You can make edits anonymously.", + "noregister": "Registrations are currently closed. Administrators can make an account for you by hand; contact them.", + + "error_username": "Unknown username.", + "error_password": "Wrong password.", + "error_telegram": "Could not authorize using Telegram.", + + "go_back": "Go back", + "go_home": "Go home", + "go_login": "Go to the login page", + "try_again": "Try again" +} diff --git a/l18n_src/en/edit.json b/l18n_src/en/edit.json new file mode 100644 index 0000000..b9625d8 --- /dev/null +++ b/l18n_src/en/edit.json @@ -0,0 +1,38 @@ +{ + "title": "Edit %s", + + "new_hypha": "You are creating a new hypha.", + "tag": "Describe your changes:", + "save": "Save", + "preview": "Preview", + "preview_title": "Preview of %s", + "preview_tip": "Note that the hypha hasn't been saved yet. Here's the preview:", + + "markup": "Markup", + "actions": "Actions", + + "link": "Link", + "link_title": "Title", + "heading": "Heading", + "bold": "Bold", + "italic": "Italic", + "highlight": "Highlight", + "underline": "Underline", + "mono": "Monospace", + "super": "Supertext", + "sub": "Subtext", + "strike": "Strikethrough", + "rocket": "Rocketlink", + "transclude": "Transclusion", + "hr": "Horizontal bar", + "code": "Code block", + "bullets": "Bullet list", + "numbers": "Number list", + + "help": "{{.link}} about mycomarkup", + "help_link": "Learn more", + + "selflink": "Link yourself", + "date": "Insert current date", + "time": "Insert current time" +} diff --git a/l18n_src/en/help.json b/l18n_src/en/help.json new file mode 100644 index 0000000..3c6d2d8 --- /dev/null +++ b/l18n_src/en/help.json @@ -0,0 +1,24 @@ +{ + "title": "Help", + "entry_not_found": "Entry not found", + "empty_error_title": "This entry does not exist!", + "empty_error_line_1": "Try finding a different entry that would help you.", + "empty_error_line_2a": "If you want to write this entry by yourself, consider", + "empty_error_link": "contributing", + "empty_error_line_2b": "to Mycorrhiza Wiki directly.", + + "topics": "Help topics", + "main": "Main", + "hypha": "Hypha", + "attachment": "Attachment", + "mycomarkup": "Mycomarkup", + "interface": "Interface", + "top_bar": "Top bar", + "sibling_hyphae": "Sibling hyphae", + "special_pages": "Special pages", + "recent_changes": "Recent changes", + "configuration": "Configuration (for administrators)", + "lock": "Lock", + "whitelist": "Whitelist", + "telegram": "Telegram authorization" +} diff --git a/l18n_src/en/ui.json b/l18n_src/en/ui.json new file mode 100644 index 0000000..019f004 --- /dev/null +++ b/l18n_src/en/ui.json @@ -0,0 +1,130 @@ +{ + "login": "Login", + "register": "Register", + "title_search": "Search by title", + "admin_panel": "Admin panel", + + "search_results_title": "Search: {{.query}}", + "search_results_query": "Search results for ‘{{.query}}’", + "search_results_desc": "Every hypha name has been compared with the query. Hyphae that have matched the query are listed below.", + + "backlinks_title": "Backlinks to {{.query}}", + "backlinks_query": "Backlinks to ‘{{.query}}’", + "backlinks_desc": "Hyphae which have a link to the selected hypha are listed below.", + + "list_title": "List of pages", + "list_heading": "List of hyphae", + "list_desc": "This wiki has {{.n}} %s.", + "list_desc+one": "hypha", + "list_desc+other": "hyphae", + + "edit_link": "Edit text", + "history_link": "View history", + "rename_link": "Rename", + "delete_link": "Delete", + "text_link": "View markup", + "attachment_link": "Manage attachment", + "backlinks_link": "{{.n}} backlink%s", + "backlinks_link+one": "", + "backlinks_link+other": "s", + + "sibling_hyphae": "Sibling hyphae", + "subhyphae": "Subhyphae", + + "random_no_hyphae": "There are no hyphae", + "random_no_hyphae_tip": "It is impossible to display a random hypha because the wiki does not contain any hyphae", + + "error": "Error", + "error_text_fetch": "Could not fetch text data", + "error_try_again": "Try again", + "error_go_back": "Go back to the hypha.", + + "ask_rename": "Rename %s", + "rename_to": "New name", + "rename_recurse": "Rename subhyphae too", + "rename_tip": "If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.", + + "ask_delete": "Delete %s?", + "ask_delete_tip": "In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.", + "ask_unattach": "Unattach %s?", + "ask_really": "Do you really want to {{.verb}} hypha {{.name}}?", + "ask_delete_verb": "delete", + "ask_unattach_verb": "unattach", + + "history_title": "History of %s", + + "recent_title": "{{.n}} recent change%s", + "recent_title+one": "", + "recent_title+other": "s", + "recent_heading": "Recent Changes", + "recent_count_pre": "See", + "recent_count_post": "recent changes", + "recent_subscribe": "Subscribe via {{.rss}}, {{.atom}} or {{.json}}", + "recent_subscribe_json": "JSON feed", + "recent_empty": "Could not find any recent changes.", + + "diff_title": "Diff of {{.name}} at {{.rev}}", + + "revision_title": "{{.name}} at {{.rev}}", + "revision_warning": "Please note that viewing attachments of hyphae is not supported in history for now.", + "revision_no_text": "This hypha had no text at this revision.", + + "about_title": "About {{.name}}", + "about_version": "{{.pre}}Mycorrhiza Wiki{{.post}} version:", + "about_usercount": "User count:", + "about_homepage": "Home page:", + "about_admins": "Administrators:", + "about_noauth": "This wiki does not use authorization", + "about_hyphae": "See {{.link}} for information about hyphae on this wiki.", + + "users_title": "User list", + "users_heading": "List of users", + "users_admins": "Admins", + "users_moderators": "Moderators", + "users_editors": "Editors", + + "no_rights": "Not enough rights", + "reindex_no_rights": "You must be an admin to reindex hyphae.", + "header_no_rights": "You must be a moderator to update header links.", + + "notexist_heading": "This hypha does not exist", + "notexist_norights": "You are not authorized to create new hyphae. Here is what you can do:", + "notexist_login": "Log in to your account, if you have one", + "notexist_register": "Register a new account", + "notexist_write": "Write a text", + "notexist_write_tip1": "Write a note, a diary, an article, a story or anything textual using {{.myco}}. Full history of edits to the document will be saved.", + "notexist_write_myco": "Mycomarkup", + "notexist_write_tip2": "Make sure to follow this wiki's writing conventions if there are any.", + "notexist_write_button": "Create", + "notexist_media": "Upload a media", + "notexist_media_tip1": "Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.", + + "media_download": "Download media", + "media_novideo": "Your browser does not support video.", + "media_novideo_link": "Download video", + "media_noaudio": "Your browser does not support audio.", + "media_noaudio_link": "Download audio", + + "attach_title": "Attachment of {{.name}}", + "attach_empty": "This hypha has no attachment, you can upload it here.", + "attach_tip": "You can manage the hypha's attachment on this page.", + "attach_link": "What are attachments?", + "attach_upload": "Upload", + "attach_stat": "Stat", + "attach_stat_size": "File size:", + "attach_size_value": "{{.n}} byte%s", + "attach_size_value+one": "", + "attach_size_value+other": "s", + "attach_stat_mime": "MIME type:", + "attach_include": "Include", + "attach_include_tip": "This attachment is an image. To include it in a hypha, use a syntax like this:", + "attach_new": "Attach", + "attach_new_tip": "You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.", + "attach_remove": "Unattach", + "attach_remove_tip": "Please note that you don't have to unattach before uploading a new attachment.", + "attach_remove_button": "Unattach", + + "close_dialog": "Close this dialog", + "confirm": "Confirm", + "cancel": "Cancel" +} diff --git a/l18n_src/ru/admin.json b/l18n_src/ru/admin.json new file mode 100644 index 0000000..2355934 --- /dev/null +++ b/l18n_src/ru/admin.json @@ -0,0 +1,33 @@ +{ + "panel_title": "Панель администратора", + "panel_safe": "Безопасные действия", + "panel_unsafe": "Опасные действия", + "panel_about": "Об этой вики", + "panel_userlist": "Список пользователей", + "panel_updateheader": "Обновить ссылки верхней панели", + "panel_users": "Менеджер пользователей", + "panel_shutdown": "Отключить вики", + "panel_reindex": "Reindex hyphae", + + "users_title": "Менеджер пользователей", + "users_create": "Создать пользователя", + "users_reindex": "Переиндексировать пользователей", + "users_name": "Имя", + "users_password": "Пароль", + "users_group": "Группа", + "users_registered": "Время создания", + "users_actions": "Действия", + "users_notime": "неизвестно", + "users_edit": "Изменить", + + "user_title": "Пользователь %s", + "user_group_heading": "Изменить группу", + "user_update": "Обновить", + "user_delete_heading": "Удалить пользователя", + "user_delete_tip": "Удаляет пользователя из базы данных. Правки пользователя будут сохранены. Имя пользователя освободится для повторной регистрации.", + "user_delete_warn": "Вы уверены, что хотите удалить {{.name}} из базы данных? Это действие нельзя отменить.", + "user_delete": "Удалить", + + "newuser_title": "Новый пользователь", + "newuser_create": "Создать" +} diff --git a/l18n_src/ru/auth.json b/l18n_src/ru/auth.json new file mode 100644 index 0000000..008bb35 --- /dev/null +++ b/l18n_src/ru/auth.json @@ -0,0 +1,35 @@ +{ + "username": "Логин", + "password": "Пароль", + + "register_title": "Регистрация", + "register_header": "Регистрация на «{{.name}}»", + "register_button": "Зарегистрироваться", + + "login_title": "Вход", + "login_header": "Вход в «{{.name}}»", + "login_button": "Войти", + + "logout_title": "Выйти?", + "logout_header": "Выйти?", + "logout_button": "Подтвердить", + "logout_anon": "Вы не можете выйти, потому что ещё не вошли.", + + "lock_title": "Доступ закрыт", + + "password_tip": "Сервер хранит ваш пароль в зашифрованном виде, даже администраторы не смогут его прочесть.", + "cookie_tip": "Отправляя эту форму, вы разрешаете вики хранить cookie в вашем браузере. Это позволит движку связывать ваши правки с вашей учётной записью. Вы будете авторизованы, пока не выйдете из учётной записи.", + "telegram_tip": "Вы можете войти с помощью Телеграм. Это сработает, если у вашего профиля есть @имя, и оно не занято в этой вики.", + + "noauth": "Аутентификация отключена. Вы можете делать правки анонимно.", + "noregister": "Регистрация в текущее время недоступна. Администраторы могут вручную создать вам учётную запись, свяжитесь с ними.", + + "error_username": "Неизвестное имя пользователя.", + "error_password": "Неверный пароль.", + "error_telegram": "Не удалось авторизоваться через Телеграм.", + + "go_back": "Назад", + "go_home": "Домой", + "go_login": "На страницу входа", + "try_again": "Ещё раз" +} diff --git a/l18n_src/ru/edit.json b/l18n_src/ru/edit.json new file mode 100644 index 0000000..f80caaa --- /dev/null +++ b/l18n_src/ru/edit.json @@ -0,0 +1,38 @@ +{ + "title": "Редактирование «%s»", + + "new_hypha": "Вы создаёте новую гифу.", + "tag": "Опишите ваши правки:", + "save": "Сохранить", + "preview": "Предпросмотр", + "preview_title": "Предпросмотр «%s»", + "preview_tip": "Заметьте, эта гифа ещё не сохранена. Вот её предпросмотр:", + + "markup": "Разметка", + "actions": "Действия", + + "link": "Ссылка", + "link_title": "Текст", + "heading": "Заголовок", + "bold": "Жирный", + "italic": "Курсив", + "highlight": "Выделение", + "underline": "Подчеркивание", + "mono": "Моноширинный", + "super": "Надстрочный", + "sub": "Подстрочный", + "strike": "Зачёркнутый", + "rocket": "Ссылка-ракета", + "transclude": "Трансклюзия", + "hr": "Гориз. черта", + "code": "Код-блок", + "bullets": "Маркир. список", + "numbers": "Нумер. список", + + "help": "{{.link}} о микоразметке", + "help_link": "Подробнее", + + "selflink": "Ссылка на вас", + "date": "Текущая дата", + "time": "Текущее время" +} diff --git a/l18n_src/ru/help.json b/l18n_src/ru/help.json new file mode 100644 index 0000000..a48ebac --- /dev/null +++ b/l18n_src/ru/help.json @@ -0,0 +1,24 @@ +{ + "title": "Справка", + "entry_not_found": "Запись не найдена", + "empty_error_title": "Этой страницы не существует!", + "empty_error_line_1": "Попробуйте поискать другую страницу, способную вам помочь.", + "empty_error_line_2a": "Если вы хотите написать эту страницу сами, будем рады вашим правкам в ", + "empty_error_link": "репозитории", + "empty_error_line_2b": "Микоризы.", + + "topics": "Темы справки", + "main": "Введение", + "hypha": "Гифа", + "attachment": "Вложение", + "mycomarkup": "Микоразметка", + "interface": "Интерфейс", + "top_bar": "Верхняя панель", + "sibling_hyphae": "Гифы-сиблинги", + "special_pages": "Специальные страницы", + "recent_changes": "Недавние изменения", + "configuration": "Конфигурация (для администраторов)", + "lock": "Блокировка", + "whitelist": "Белый список", + "telegram": "Авторизация через Телеграм" +} diff --git a/l18n_src/ru/ui.json b/l18n_src/ru/ui.json new file mode 100644 index 0000000..a2d30d0 --- /dev/null +++ b/l18n_src/ru/ui.json @@ -0,0 +1,134 @@ +{ + "login": "Войти", + "register": "Регистрация", + "title_search": "Поиск по названию", + "admin_panel": "Администрирование", + + "search_results_title": "Поиск: {{.query}}", + "search_results_query": "Результаты поиска для «{{.query}}»", + "search_results_desc": "Название каждой из существующих гиф сопоставлено с запросом. Подходящие гифы приведены ниже.", + + "backlinks_title": "Обратные ссылки на {{.query}}", + "backlinks_query": "Обратные ссылки на «{{.query}}»", + "backlinks_desc": "Ниже перечислены гифы, содержащие ссылку на выбранную гифу.", + + "list_title": "Список страниц", + "list_heading": "Список гиф", + "list_desc": "В этой вики {{.n}} %s.", + "list_desc+one": "гифа", + "list_desc+few": "гифы", + "list_desc+many": "гиф", + + "edit_link": "Редактировать", + "history_link": "История", + "rename_link": "Переименовать", + "delete_link": "Удалить", + "text_link": "Посмотреть разметку", + "attachment_link": "Вложение", + "backlinks_link": "{{.n}} %s сюда", + "backlinks_link+one": "ссылка", + "backlinks_link+few": "ссылки", + "backlinks_link+many": "ссылок", + + "sibling_hyphae": "Гифы-сиблинги", + "subhyphae": "Подгифы", + + "random_no_hyphae": "В этой вики нет гиф", + "random_no_hyphae_tip": "Невозможно отобразить случайную гифу, потому что вики не содержит ни одной гифы", + + "error": "Ошибка", + "error_text_fetch": "Не удалось получить текстовые данные", + "error_try_again": "Попробуйте ещё раз", + "error_go_back": "Вернуться к гифе.", + + "ask_rename": "Переименовать «%s»", + "rename_to": "Новое название", + "rename_recurse": "Также переименовать подгифы", + "rename_tip": "Если вы переименуете эту гифу, сломаются все ссылки, ведущие на неё, а также исходящие относительные ссылки. Также вы потеряете всю текущую историю для нового названия. Переименовывайте аккуратно.", + + "ask_delete": "Удалить «%s»?", + "ask_delete_tip": "В этой версии Микоризы нельзя отменить удаление гифы, но её история останется доступной.", + "ask_unattach": "Открепить «%s»?", + "ask_really": "Вы действительно хотите {{.verb}} гифу «{{.name}}»?", + "ask_delete_verb": "удалить", + "ask_unattach_verb": "открепить", + + "history_title": "История «%s»", + + "recent_title": "{{.n}} %s", + "recent_title+one": "недавнее изменение", + "recent_title+few": "недавних изменения", + "recent_title+many": "недавних изменений", + "recent_heading": "Недавние изменения", + "recent_count_pre": "Отобразить", + "recent_count_post": "недавних изменений", + "recent_subscribe": "Подписаться через {{.rss}}, {{.atom}} или {{.json}}", + "recent_subscribe_json": "JSON-ленту", + "recent_empty": "Не удалось найти последние изменения.", + + "diff_title": "Разница для «{{.name}}» из {{.rev}}", + + "revision_title": "{{.name}} из {{.rev}}", + "revision_warning": "Обратите внимание, просмотр вложений в истории гифы пока что недоступен.", + "revision_no_text": "В этой ревизии гифы не было текста.", + + "about_title": "О вики «{{.name}}»", + "about_version": "Версия {{.pre}}Микоризы{{.post}}:", + "about_usercount": "Число пользователей:", + "about_homepage": "Домашняя гифа:", + "about_admins": "Администраторы:", + "about_noauth": "В этой вики нет авторизации", + "about_hyphae": "См. {{.link}}, чтобы узнать о гифах в этой вики.", + + "users_title": "Список пользователей", + "users_heading": "Список пользователей", + "users_admins": "Администраторы", + "users_moderators": "Модераторы", + "users_editors": "Редакторы", + + "no_rights": "Недостаточно прав", + "reindex_no_rights": "Вы должны быть администратором, чтобы переиндексировать гифы.", + "header_no_rights": "Вы должны быть модератором, чтобы обновить ссылки в заголовке.", + + "notexist_heading": "Эта гифа не существует", + "notexist_norights": "У вас нет прав для создания новых гиф. Вы можете:", + "notexist_login": "Войти в свою учётную запись, если она у вас есть", + "notexist_register": "Создать новую учётную запись", + "notexist_write": "Написать текст", + "notexist_write_tip1": "Напишите заметку, дневник, статью, рассказ или иной текст с помощью {{.myco}}. Сохраняется полная история правок документа.", + "notexist_write_myco": "микоразметки", + "notexist_write_tip2": "Не забывайте следовать правилам оформления этой вики, если они имеются.", + "notexist_write_button": "Создать", + "notexist_media": "Загрузить медиа", + "notexist_media_tip1": "Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные – просто скачать. Позже вы можете дописать пояснение к этому медиа.", + + "media_download": "Скачать медиа", + "media_novideo": "Ваш браузер не поддерживает видео.", + "media_novideo_link": "Скачать видео", + "media_noaudio": "Ваш браузер не поддерживает аудио.", + "media_noaudio_link": "Скачать аудио", + + "attach_title": "Вложение «{{.name}}»", + "attach_empty": "Эта гифа не имеет вложения, здесь вы можете его загрузить.", + "attach_tip": "На этой странице вы можете управлять вложением.", + "attach_link": "Что такое вложение?", + "attach_upload": "Загрузить", + "attach_stat": "Свойства", + "attach_stat_size": "Размер файла:", + "attach_size_value": "{{.n}} %s", + "attach_size_value+one": "байт", + "attach_size_value+few": "байта", + "attach_size_value+many": "байт", + "attach_stat_mime": "MIME-тип:", + "attach_include": "Добавление", + "attach_include_tip": "Это вложение – изображение. Чтобы добавить его в текст гифы, используйте синтаксис ниже:", + "attach_new": "Прикрепить", + "attach_new_tip": "Вы можете загрузить новое вложение. Пожалуйста, не загружайте слишком большие изображения без необходимости, чтобы впоследствии не ждать её долгую загрузку.", + "attach_remove": "Открепить", + "attach_remove_tip": "Заметьте, чтобы заменить вложение, вам не нужно его перед этим откреплять.", + "attach_remove_button": "Открепить", + + "close_dialog": "Закрыть этот диалог", + "confirm": "Применить", + "cancel": "Отмена" +} diff --git a/main.go b/main.go index 4fb2e6e..0d8c443 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,6 @@ //go:generate qtc -dir=views //go:generate qtc -dir=tree +//go:generate go-localize -input l18n_src -output l18n // Command mycorrhiza is a program that runs a mycorrhiza wiki. package main diff --git a/shroom/init.go b/shroom/init.go index b681a67..5219b65 100644 --- a/shroom/init.go +++ b/shroom/init.go @@ -17,7 +17,8 @@ func init() { if h := hyphae.ByName(hyphaName); h.Exists { rawText, err = FetchTextPart(h) if h.BinaryPath != "" { - binaryBlock = views.AttachmentHTML(h) + // the view is localized, but we can't pass it, so... + binaryBlock = views.AttachmentHTMLRaw(h) } } else { err = errors.New("Hypha " + hyphaName + " does not exist") diff --git a/views/admin.qtpl b/views/admin.qtpl index 698114c..921c1e0 100644 --- a/views/admin.qtpl +++ b/views/admin.qtpl @@ -1,31 +1,33 @@ +{% import "fmt" %} {% import "github.com/bouncepaw/mycorrhiza/cfg" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} -{% func AdminPanelHTML() %} +{% func AdminPanelHTML(lc *l18n.Localizer) %}
-

Administrative functions

+

{%s lc.Get("admin.panel_title") %}

-

Safe things

+

{%s lc.Get("admin.panel_safe") %}

-

Dangerous things

+

{%s lc.Get("admin.panel_unsafe") %}

- Shutdown wiki + {%s lc.Get("admin.panel_shutdown") %}
- Reindex hyphae + {%s lc.Get("admin.panel_reindex") %}
@@ -34,14 +36,14 @@
{% endfunc %} -{% func AdminUsersPanelHTML(userList []*user.User) %} +{% func AdminUsersPanelHTML(userList []*user.User, lc *l18n.Localizer) %}
-

Manage users

+

{%s lc.Get("admin.users_title") %}

- Create a new user - + {%s lc.Get("admin.users_create") %} +

@@ -49,10 +51,10 @@ - - - - + + + + @@ -64,13 +66,13 @@ {% endfor %} @@ -80,31 +82,31 @@ {% endfunc %} -{% func AdminUserNewHTML(f util.FormData) %} +{% func AdminUserNewHTML(f util.FormData, lc *l18n.Localizer) %}
-

New user

+

{%s lc.Get("admin.newuser_title") %}

{% if f.HasError() %}
- Error: + {%s lc.Get("ui.error") %}: {%s f.Error() %}
{% endif %}
- +
- +
- + +
- Reindex hyphae + `) +//line views/admin.qtpl:30 + qw422016.E().S(lc.Get("admin.panel_reindex")) +//line views/admin.qtpl:30 + qw422016.N().S(`
@@ -60,46 +102,58 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
`) -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 } -//line views/admin.qtpl:35 -func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 +func WriteAdminPanelHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { +//line views/admin.qtpl:37 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:35 - StreamAdminPanelHTML(qw422016) -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 + StreamAdminPanelHTML(qw422016, lc) +//line views/admin.qtpl:37 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 } -//line views/admin.qtpl:35 -func AdminPanelHTML() string { -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 +func AdminPanelHTML(lc *l18n.Localizer) string { +//line views/admin.qtpl:37 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:35 - WriteAdminPanelHTML(qb422016) -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 + WriteAdminPanelHTML(qb422016, lc) +//line views/admin.qtpl:37 qs422016 := string(qb422016.B) -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 return qs422016 -//line views/admin.qtpl:35 +//line views/admin.qtpl:37 } -//line views/admin.qtpl:37 -func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User) { -//line views/admin.qtpl:37 +//line views/admin.qtpl:39 +func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User, lc *l18n.Localizer) { +//line views/admin.qtpl:39 qw422016.N().S(`
-

Manage users

+

`) +//line views/admin.qtpl:42 + qw422016.E().S(lc.Get("admin.users_title")) +//line views/admin.qtpl:42 + qw422016.N().S(`

- Create a new user - + `) +//line views/admin.qtpl:45 + qw422016.E().S(lc.Get("admin.users_create")) +//line views/admin.qtpl:45 + qw422016.N().S(` +
@@ -107,418 +161,512 @@ func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User)
NameGroupRegistered at{%s lc.Get("admin.users_name") %}{%s lc.Get("admin.users_group") %}{%s lc.Get("admin.users_registered") %}
{%s u.Group %} {% if u.RegisteredAt.IsZero() %} - unknown + {%s lc.Get("admin.users_notime") %} {% else %} {%s u.RegisteredAt.UTC().Format("2006-01-02 15:04") %} {% endif %} - Edit + {%s lc.Get("admin.users_edit") %}
- - - - + + + + `) -//line views/admin.qtpl:59 +//line views/admin.qtpl:61 for _, u := range userList { -//line views/admin.qtpl:59 +//line views/admin.qtpl:61 qw422016.N().S(` `) -//line views/admin.qtpl:76 +//line views/admin.qtpl:78 } -//line views/admin.qtpl:76 +//line views/admin.qtpl:78 qw422016.N().S(`
NameGroupRegistered at`) +//line views/admin.qtpl:54 + qw422016.E().S(lc.Get("admin.users_name")) +//line views/admin.qtpl:54 + qw422016.N().S(``) +//line views/admin.qtpl:55 + qw422016.E().S(lc.Get("admin.users_group")) +//line views/admin.qtpl:55 + qw422016.N().S(``) +//line views/admin.qtpl:56 + qw422016.E().S(lc.Get("admin.users_registered")) +//line views/admin.qtpl:56 + qw422016.N().S(`
`) -//line views/admin.qtpl:62 +//line views/admin.qtpl:64 qw422016.E().S(u.Name) -//line views/admin.qtpl:62 +//line views/admin.qtpl:64 qw422016.N().S(` `) -//line views/admin.qtpl:64 +//line views/admin.qtpl:66 qw422016.E().S(u.Group) -//line views/admin.qtpl:64 +//line views/admin.qtpl:66 qw422016.N().S(` `) -//line views/admin.qtpl:66 - if u.RegisteredAt.IsZero() { -//line views/admin.qtpl:66 - qw422016.N().S(` - unknown - `) //line views/admin.qtpl:68 - } else { + if u.RegisteredAt.IsZero() { //line views/admin.qtpl:68 qw422016.N().S(` `) //line views/admin.qtpl:69 - qw422016.E().S(u.RegisteredAt.UTC().Format("2006-01-02 15:04")) + qw422016.E().S(lc.Get("admin.users_notime")) //line views/admin.qtpl:69 qw422016.N().S(` `) //line views/admin.qtpl:70 - } + } else { //line views/admin.qtpl:70 + qw422016.N().S(` + `) +//line views/admin.qtpl:71 + qw422016.E().S(u.RegisteredAt.UTC().Format("2006-01-02 15:04")) +//line views/admin.qtpl:71 + qw422016.N().S(` + `) +//line views/admin.qtpl:72 + } +//line views/admin.qtpl:72 qw422016.N().S(` Edit +//line views/admin.qtpl:75 + qw422016.N().S(`/edit">`) +//line views/admin.qtpl:75 + qw422016.E().S(lc.Get("admin.users_edit")) +//line views/admin.qtpl:75 + qw422016.N().S(`
`) -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 } -//line views/admin.qtpl:81 -func WriteAdminUsersPanelHTML(qq422016 qtio422016.Writer, userList []*user.User) { -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 +func WriteAdminUsersPanelHTML(qq422016 qtio422016.Writer, userList []*user.User, lc *l18n.Localizer) { +//line views/admin.qtpl:83 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:81 - StreamAdminUsersPanelHTML(qw422016, userList) -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 + StreamAdminUsersPanelHTML(qw422016, userList, lc) +//line views/admin.qtpl:83 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 } -//line views/admin.qtpl:81 -func AdminUsersPanelHTML(userList []*user.User) string { -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 +func AdminUsersPanelHTML(userList []*user.User, lc *l18n.Localizer) string { +//line views/admin.qtpl:83 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:81 - WriteAdminUsersPanelHTML(qb422016, userList) -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 + WriteAdminUsersPanelHTML(qb422016, userList, lc) +//line views/admin.qtpl:83 qs422016 := string(qb422016.B) -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 return qs422016 -//line views/admin.qtpl:81 +//line views/admin.qtpl:83 } -//line views/admin.qtpl:83 -func StreamAdminUserNewHTML(qw422016 *qt422016.Writer, f util.FormData) { -//line views/admin.qtpl:83 +//line views/admin.qtpl:85 +func StreamAdminUserNewHTML(qw422016 *qt422016.Writer, f util.FormData, lc *l18n.Localizer) { +//line views/admin.qtpl:85 qw422016.N().S(`
-

New user

+

`) +//line views/admin.qtpl:88 + qw422016.E().S(lc.Get("admin.newuser_title")) +//line views/admin.qtpl:88 + qw422016.N().S(`

`) -//line views/admin.qtpl:88 +//line views/admin.qtpl:90 if f.HasError() { -//line views/admin.qtpl:88 +//line views/admin.qtpl:90 qw422016.N().S(`
- Error: + `) +//line views/admin.qtpl:92 + qw422016.E().S(lc.Get("ui.error")) +//line views/admin.qtpl:92 + qw422016.N().S(`: `) -//line views/admin.qtpl:91 +//line views/admin.qtpl:93 qw422016.E().S(f.Error()) -//line views/admin.qtpl:91 +//line views/admin.qtpl:93 qw422016.N().S(`
`) -//line views/admin.qtpl:93 +//line views/admin.qtpl:95 } -//line views/admin.qtpl:93 +//line views/admin.qtpl:95 qw422016.N().S(`
- +
- +
- +
- - Cancel + + `) +//line views/admin.qtpl:122 + qw422016.E().S(lc.Get("ui.cancel")) +//line views/admin.qtpl:122 + qw422016.N().S(`
`) -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 } -//line views/admin.qtpl:126 -func WriteAdminUserNewHTML(qq422016 qtio422016.Writer, f util.FormData) { -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 +func WriteAdminUserNewHTML(qq422016 qtio422016.Writer, f util.FormData, lc *l18n.Localizer) { +//line views/admin.qtpl:128 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:126 - StreamAdminUserNewHTML(qw422016, f) -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 + StreamAdminUserNewHTML(qw422016, f, lc) +//line views/admin.qtpl:128 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 } -//line views/admin.qtpl:126 -func AdminUserNewHTML(f util.FormData) string { -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 +func AdminUserNewHTML(f util.FormData, lc *l18n.Localizer) string { +//line views/admin.qtpl:128 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:126 - WriteAdminUserNewHTML(qb422016, f) -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 + WriteAdminUserNewHTML(qb422016, f, lc) +//line views/admin.qtpl:128 qs422016 := string(qb422016.B) -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 return qs422016 -//line views/admin.qtpl:126 +//line views/admin.qtpl:128 } -//line views/admin.qtpl:128 -func StreamAdminUserEditHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData) { -//line views/admin.qtpl:128 +//line views/admin.qtpl:130 +func StreamAdminUserEditHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { +//line views/admin.qtpl:130 qw422016.N().S(`

`) -//line views/admin.qtpl:133 +//line views/admin.qtpl:135 qw422016.E().S(u.Name) -//line views/admin.qtpl:133 +//line views/admin.qtpl:135 qw422016.N().S(`

-

Change group

+

`) +//line views/admin.qtpl:138 + qw422016.E().S(lc.Get("admin.user_group_heading")) +//line views/admin.qtpl:138 + qw422016.N().S(`

`) -//line views/admin.qtpl:138 +//line views/admin.qtpl:140 if f.HasError() { -//line views/admin.qtpl:138 +//line views/admin.qtpl:140 qw422016.N().S(`
- Error: + `) +//line views/admin.qtpl:142 + qw422016.E().S(lc.Get("ui.error")) +//line views/admin.qtpl:142 + qw422016.N().S(`: `) -//line views/admin.qtpl:141 +//line views/admin.qtpl:143 qw422016.E().S(f.Error()) -//line views/admin.qtpl:141 +//line views/admin.qtpl:143 qw422016.N().S(`
`) -//line views/admin.qtpl:143 +//line views/admin.qtpl:145 } -//line views/admin.qtpl:143 +//line views/admin.qtpl:145 qw422016.N().S(`
- anon editor trusted moderator admin
- +
-

Delete user

-

Remove the user from the database. Changes made by the user will - be preserved. It will be possible to take this username later.

+

`) +//line views/admin.qtpl:163 + qw422016.E().S(lc.Get("admin.user_delete_heading")) +//line views/admin.qtpl:163 + qw422016.N().S(`

+

`) +//line views/admin.qtpl:164 + qw422016.E().S(lc.Get("admin.user_delete_tip")) +//line views/admin.qtpl:164 + qw422016.N().S(`

Delete +//line views/admin.qtpl:165 + qw422016.N().S(`/delete">`) +//line views/admin.qtpl:165 + qw422016.E().S(lc.Get("admin.user_delete")) +//line views/admin.qtpl:165 + qw422016.N().S(`
`) -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 } -//line views/admin.qtpl:167 -func WriteAdminUserEditHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData) { -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 +func WriteAdminUserEditHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { +//line views/admin.qtpl:168 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/admin.qtpl:167 - StreamAdminUserEditHTML(qw422016, u, f) -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 + StreamAdminUserEditHTML(qw422016, u, f, lc) +//line views/admin.qtpl:168 qt422016.ReleaseWriter(qw422016) -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 } -//line views/admin.qtpl:167 -func AdminUserEditHTML(u *user.User, f util.FormData) string { -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 +func AdminUserEditHTML(u *user.User, f util.FormData, lc *l18n.Localizer) string { +//line views/admin.qtpl:168 qb422016 := qt422016.AcquireByteBuffer() -//line views/admin.qtpl:167 - WriteAdminUserEditHTML(qb422016, u, f) -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 + WriteAdminUserEditHTML(qb422016, u, f, lc) +//line views/admin.qtpl:168 qs422016 := string(qb422016.B) -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 qt422016.ReleaseByteBuffer(qb422016) -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 return qs422016 -//line views/admin.qtpl:167 +//line views/admin.qtpl:168 } -//line views/admin.qtpl:169 -func StreamAdminUserDeleteHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData) { -//line views/admin.qtpl:169 +//line views/admin.qtpl:170 +func StreamAdminUserDeleteHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { +//line views/admin.qtpl:170 qw422016.N().S(`
-

Delete user

+

`) +//line views/admin.qtpl:173 + qw422016.E().S(lc.Get("admin.user_delete_heading")) +//line views/admin.qtpl:173 + qw422016.N().S(`

`) -//line views/admin.qtpl:174 +//line views/admin.qtpl:175 if f.HasError() { -//line views/admin.qtpl:174 +//line views/admin.qtpl:175 qw422016.N().S(`
- Error: + `) +//line views/admin.qtpl:177 + qw422016.E().S(lc.Get("ui.error")) +//line views/admin.qtpl:177 + qw422016.N().S(`: `) -//line views/admin.qtpl:177 +//line views/admin.qtpl:178 qw422016.E().S(f.Error()) -//line views/admin.qtpl:177 +//line views/admin.qtpl:178 qw422016.N().S(`
`) -//line views/admin.qtpl:179 +//line views/admin.qtpl:180 } -//line views/admin.qtpl:179 +//line views/admin.qtpl:180 qw422016.N().S(` -

Are you sure you want to delete `) -//line views/admin.qtpl:181 - qw422016.E().S(u.Name) -//line views/admin.qtpl:181 - qw422016.N().S(` - from the database? This action is irreversible.

+

`) +//line views/admin.qtpl:182 + qw422016.N().S(lc.Get("admin.user_delete_warn", &l18n.Replacements{"name": fmt.Sprintf("%s", u.Name)})) +//line views/admin.qtpl:182 + qw422016.N().S(`

- + Cancel + qw422016.N().S(`/edit">`) +//line views/admin.qtpl:186 + qw422016.E().S(lc.Get("ui.cancel")) +//line views/admin.qtpl:186 + qw422016.N().S(`
@@ -527,22 +675,22 @@ func StreamAdminUserDeleteHTML(qw422016 *qt422016.Writer, u *user.User, f util.F } //line views/admin.qtpl:190 -func WriteAdminUserDeleteHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData) { +func WriteAdminUserDeleteHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) { //line views/admin.qtpl:190 qw422016 := qt422016.AcquireWriter(qq422016) //line views/admin.qtpl:190 - StreamAdminUserDeleteHTML(qw422016, u, f) + StreamAdminUserDeleteHTML(qw422016, u, f, lc) //line views/admin.qtpl:190 qt422016.ReleaseWriter(qw422016) //line views/admin.qtpl:190 } //line views/admin.qtpl:190 -func AdminUserDeleteHTML(u *user.User, f util.FormData) string { +func AdminUserDeleteHTML(u *user.User, f util.FormData, lc *l18n.Localizer) string { //line views/admin.qtpl:190 qb422016 := qt422016.AcquireByteBuffer() //line views/admin.qtpl:190 - WriteAdminUserDeleteHTML(qb422016, u, f) + WriteAdminUserDeleteHTML(qb422016, u, f, lc) //line views/admin.qtpl:190 qs422016 := string(qb422016.B) //line views/admin.qtpl:190 diff --git a/views/auth.qtpl b/views/auth.qtpl index 5a20cdd..8051285 100644 --- a/views/auth.qtpl +++ b/views/auth.qtpl @@ -1,65 +1,69 @@ {% import "net/http" %} {% import "github.com/bouncepaw/mycorrhiza/cfg" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% func RegisterHTML(rq *http.Request) %} +{% code + lc := l18n.FromRequest(rq) +%}
{% if cfg.AllowRegistration %} - {%= telegramWidgetHTML() %} + {%= telegramWidgetHTML(lc) %} {% elseif cfg.UseAuth %} -

Registrations are currently closed. Administrators can make an account for you by hand; contact them.

-

← Go back

+

{%s lc.Get("auth.noregister") %}

+

← {%s lc.Get("auth.go_back") %}

{% else %} -

Authentication is disabled. You can make edits anonymously.

-

← Go back

+

{%s lc.Get("auth.noauth") %}

+

← {%s lc.Get("auth.go_back") %}

{% endif %}
{% endfunc %} -{% func LoginHTML() %} +{% func LoginHTML(lc *l18n.Localizer) %}
{% if cfg.UseAuth %} - {%= telegramWidgetHTML() %} + {%= telegramWidgetHTML(lc) %} {% else %} -

Authentication is disabled. You can make edits anonymously.

-

← Go home

+

{%s lc.Get("auth.noauth") %}

+

← {%s lc.Get("auth.go_home") %}

{% endif %}
@@ -67,56 +71,56 @@ {% endfunc %} Telegram auth widget was requested by Yogurt. As you can see, we don't offer user administrators control over it. Of course we don't. -{% func telegramWidgetHTML() %} +{% func telegramWidgetHTML(lc *l18n.Localizer) %} {% if cfg.TelegramEnabled %} -

You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.

+

{%s lc.Get("auth.telegram_tip") %}

{% endif %} {% endfunc %} -{% func LoginErrorHTML(err string) %} +{% func LoginErrorHTML(err string, lc *l18n.Localizer) %}
{% switch err %} {% case "unknown username" %} -

Unknown username.

+

{%s lc.Get("auth.error_username") %}

{% case "wrong password" %} -

Wrong password.

+

{%s lc.Get("auth.error_password") %}

{% default %}

{%s err %}

{% endswitch %} -

← Try again

+

← {%s lc.Get("auth.try_again") %}

{% endfunc %} -{% func LogoutHTML(can bool) %} +{% func LogoutHTML(can bool, lc *l18n.Localizer) %}
{% if can %} -

Log out?

-

Confirm

-

Cancel

+

{%s lc.Get("auth.logout_header") %}

+

{%s lc.Get("auth.logout_button") %}

+

{%s lc.Get("ui.cancel") %}

{% else %} -

You cannot log out because you are not logged in.

-

Login

-

← Home

+

{%s lc.Get("auth.logout_anon") %}

+

{%s lc.Get("auth.login_title") %}

+

← {%s lc.Get("auth.go_home") %}

{% endif %}
{% endfunc %} -{% func LockHTML() %} +{% func LockHTML(lc *l18n.Localizer) %} - 🔒 Locked + 🔒 {%s lc.Get("auth.lock_title") %} @@ -124,19 +128,19 @@ Telegram auth widget was requested by Yogurt. As you can see, we don't offer use

🔒

-

Locked

+

{%s lc.Get("auth.lock_title") %}

- {%= telegramWidgetHTML() %} + {%= telegramWidgetHTML(lc) %}
diff --git a/views/auth.qtpl.go b/views/auth.qtpl.go index fab2f12..7e3b53e 100644 --- a/views/auth.qtpl.go +++ b/views/auth.qtpl.go @@ -10,403 +10,524 @@ import "net/http" //line views/auth.qtpl:2 import "github.com/bouncepaw/mycorrhiza/cfg" -//line views/auth.qtpl:4 +//line views/auth.qtpl:3 +import "github.com/bouncepaw/mycorrhiza/l18n" + +//line views/auth.qtpl:5 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/auth.qtpl:4 +//line views/auth.qtpl:5 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/auth.qtpl:4 +//line views/auth.qtpl:5 func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) { -//line views/auth.qtpl:4 +//line views/auth.qtpl:5 + qw422016.N().S(` +`) +//line views/auth.qtpl:7 + lc := l18n.FromRequest(rq) + +//line views/auth.qtpl:8 qw422016.N().S(`
`) -//line views/auth.qtpl:8 +//line views/auth.qtpl:12 if cfg.AllowRegistration { -//line views/auth.qtpl:8 +//line views/auth.qtpl:12 qw422016.N().S(` `) -//line views/auth.qtpl:26 - streamtelegramWidgetHTML(qw422016) -//line views/auth.qtpl:26 +//line views/auth.qtpl:30 + streamtelegramWidgetHTML(qw422016, lc) +//line views/auth.qtpl:30 qw422016.N().S(` `) -//line views/auth.qtpl:27 +//line views/auth.qtpl:31 } else if cfg.UseAuth { -//line views/auth.qtpl:27 +//line views/auth.qtpl:31 qw422016.N().S(` -

Registrations are currently closed. Administrators can make an account for you by hand; contact them.

+

`) +//line views/auth.qtpl:32 + qw422016.E().S(lc.Get("auth.noregister")) +//line views/auth.qtpl:32 + qw422016.N().S(`

← Go back

+//line views/auth.qtpl:33 + qw422016.N().S(`">← `) +//line views/auth.qtpl:33 + qw422016.E().S(lc.Get("auth.go_back")) +//line views/auth.qtpl:33 + qw422016.N().S(`

`) -//line views/auth.qtpl:30 +//line views/auth.qtpl:34 } else { -//line views/auth.qtpl:30 +//line views/auth.qtpl:34 qw422016.N().S(` -

Authentication is disabled. You can make edits anonymously.

+

`) +//line views/auth.qtpl:35 + qw422016.E().S(lc.Get("auth.noauth")) +//line views/auth.qtpl:35 + qw422016.N().S(`

← Go back

+//line views/auth.qtpl:36 + qw422016.N().S(`">← `) +//line views/auth.qtpl:36 + qw422016.E().S(lc.Get("auth.go_back")) +//line views/auth.qtpl:36 + qw422016.N().S(`

`) -//line views/auth.qtpl:33 +//line views/auth.qtpl:37 } -//line views/auth.qtpl:33 +//line views/auth.qtpl:37 qw422016.N().S(`
`) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 } -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 func WriteRegisterHTML(qq422016 qtio422016.Writer, rq *http.Request) { -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 StreamRegisterHTML(qw422016, rq) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 } -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 func RegisterHTML(rq *http.Request) string { -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 WriteRegisterHTML(qb422016, rq) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 qs422016 := string(qb422016.B) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 return qs422016 -//line views/auth.qtpl:37 +//line views/auth.qtpl:41 } -//line views/auth.qtpl:39 -func StreamLoginHTML(qw422016 *qt422016.Writer) { -//line views/auth.qtpl:39 +//line views/auth.qtpl:43 +func StreamLoginHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { +//line views/auth.qtpl:43 qw422016.N().S(`
`) -//line views/auth.qtpl:43 +//line views/auth.qtpl:47 if cfg.UseAuth { -//line views/auth.qtpl:43 +//line views/auth.qtpl:47 qw422016.N().S(` `) -//line views/auth.qtpl:59 - streamtelegramWidgetHTML(qw422016) -//line views/auth.qtpl:59 +//line views/auth.qtpl:63 + streamtelegramWidgetHTML(qw422016, lc) +//line views/auth.qtpl:63 qw422016.N().S(` `) -//line views/auth.qtpl:60 +//line views/auth.qtpl:64 } else { -//line views/auth.qtpl:60 +//line views/auth.qtpl:64 qw422016.N().S(` -

Authentication is disabled. You can make edits anonymously.

-

← Go home

+

`) +//line views/auth.qtpl:65 + qw422016.E().S(lc.Get("auth.noauth")) +//line views/auth.qtpl:65 + qw422016.N().S(`

+

← `) +//line views/auth.qtpl:66 + qw422016.E().S(lc.Get("auth.go_home")) +//line views/auth.qtpl:66 + qw422016.N().S(`

`) -//line views/auth.qtpl:63 +//line views/auth.qtpl:67 } -//line views/auth.qtpl:63 +//line views/auth.qtpl:67 qw422016.N().S(`
`) -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 } -//line views/auth.qtpl:67 -func WriteLoginHTML(qq422016 qtio422016.Writer) { -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 +func WriteLoginHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { +//line views/auth.qtpl:71 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:67 - StreamLoginHTML(qw422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 + StreamLoginHTML(qw422016, lc) +//line views/auth.qtpl:71 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 } -//line views/auth.qtpl:67 -func LoginHTML() string { -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 +func LoginHTML(lc *l18n.Localizer) string { +//line views/auth.qtpl:71 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:67 - WriteLoginHTML(qb422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 + WriteLoginHTML(qb422016, lc) +//line views/auth.qtpl:71 qs422016 := string(qb422016.B) -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 return qs422016 -//line views/auth.qtpl:67 +//line views/auth.qtpl:71 } // Telegram auth widget was requested by Yogurt. As you can see, we don't offer user administrators control over it. Of course we don't. -//line views/auth.qtpl:70 -func streamtelegramWidgetHTML(qw422016 *qt422016.Writer) { -//line views/auth.qtpl:70 +//line views/auth.qtpl:74 +func streamtelegramWidgetHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { +//line views/auth.qtpl:74 qw422016.N().S(` `) -//line views/auth.qtpl:71 +//line views/auth.qtpl:75 if cfg.TelegramEnabled { -//line views/auth.qtpl:71 +//line views/auth.qtpl:75 qw422016.N().S(` -

You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.

+

`) +//line views/auth.qtpl:76 + qw422016.E().S(lc.Get("auth.telegram_tip")) +//line views/auth.qtpl:76 + qw422016.N().S(`

`) -//line views/auth.qtpl:74 +//line views/auth.qtpl:78 } -//line views/auth.qtpl:74 +//line views/auth.qtpl:78 qw422016.N().S(` `) -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 } -//line views/auth.qtpl:75 -func writetelegramWidgetHTML(qq422016 qtio422016.Writer) { -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 +func writetelegramWidgetHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { +//line views/auth.qtpl:79 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:75 - streamtelegramWidgetHTML(qw422016) -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 + streamtelegramWidgetHTML(qw422016, lc) +//line views/auth.qtpl:79 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 } -//line views/auth.qtpl:75 -func telegramWidgetHTML() string { -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 +func telegramWidgetHTML(lc *l18n.Localizer) string { +//line views/auth.qtpl:79 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:75 - writetelegramWidgetHTML(qb422016) -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 + writetelegramWidgetHTML(qb422016, lc) +//line views/auth.qtpl:79 qs422016 := string(qb422016.B) -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 return qs422016 -//line views/auth.qtpl:75 +//line views/auth.qtpl:79 } -//line views/auth.qtpl:77 -func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) { -//line views/auth.qtpl:77 +//line views/auth.qtpl:81 +func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string, lc *l18n.Localizer) { +//line views/auth.qtpl:81 qw422016.N().S(`
`) -//line views/auth.qtpl:81 +//line views/auth.qtpl:85 switch err { -//line views/auth.qtpl:82 - case "unknown username": -//line views/auth.qtpl:82 - qw422016.N().S(` -

Unknown username.

- `) -//line views/auth.qtpl:84 - case "wrong password": -//line views/auth.qtpl:84 - qw422016.N().S(` -

Wrong password.

- `) //line views/auth.qtpl:86 - default: + case "unknown username": //line views/auth.qtpl:86 qw422016.N().S(`

`) //line views/auth.qtpl:87 - qw422016.E().S(err) + qw422016.E().S(lc.Get("auth.error_username")) //line views/auth.qtpl:87 qw422016.N().S(`

`) //line views/auth.qtpl:88 - } + case "wrong password": //line views/auth.qtpl:88 + qw422016.N().S(` +

`) +//line views/auth.qtpl:89 + qw422016.E().S(lc.Get("auth.error_password")) +//line views/auth.qtpl:89 + qw422016.N().S(`

+ `) +//line views/auth.qtpl:90 + default: +//line views/auth.qtpl:90 + qw422016.N().S(` +

`) +//line views/auth.qtpl:91 + qw422016.E().S(err) +//line views/auth.qtpl:91 + qw422016.N().S(`

+ `) +//line views/auth.qtpl:92 + } +//line views/auth.qtpl:92 qw422016.N().S(` -

← Try again

+

← `) +//line views/auth.qtpl:93 + qw422016.E().S(lc.Get("auth.try_again")) +//line views/auth.qtpl:93 + qw422016.N().S(`

`) -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 } -//line views/auth.qtpl:93 -func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) { -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 +func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string, lc *l18n.Localizer) { +//line views/auth.qtpl:97 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:93 - StreamLoginErrorHTML(qw422016, err) -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 + StreamLoginErrorHTML(qw422016, err, lc) +//line views/auth.qtpl:97 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 } -//line views/auth.qtpl:93 -func LoginErrorHTML(err string) string { -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 +func LoginErrorHTML(err string, lc *l18n.Localizer) string { +//line views/auth.qtpl:97 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:93 - WriteLoginErrorHTML(qb422016, err) -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 + WriteLoginErrorHTML(qb422016, err, lc) +//line views/auth.qtpl:97 qs422016 := string(qb422016.B) -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 return qs422016 -//line views/auth.qtpl:93 +//line views/auth.qtpl:97 } -//line views/auth.qtpl:95 -func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) { -//line views/auth.qtpl:95 +//line views/auth.qtpl:99 +func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool, lc *l18n.Localizer) { +//line views/auth.qtpl:99 qw422016.N().S(`
`) -//line views/auth.qtpl:99 +//line views/auth.qtpl:103 if can { -//line views/auth.qtpl:99 - qw422016.N().S(` -

Log out?

-

Confirm

-

Cancel

- `) //line views/auth.qtpl:103 + qw422016.N().S(` +

`) +//line views/auth.qtpl:104 + qw422016.E().S(lc.Get("auth.logout_header")) +//line views/auth.qtpl:104 + qw422016.N().S(`

+

`) +//line views/auth.qtpl:105 + qw422016.E().S(lc.Get("auth.logout_button")) +//line views/auth.qtpl:105 + qw422016.N().S(`

+

`) +//line views/auth.qtpl:106 + qw422016.E().S(lc.Get("ui.cancel")) +//line views/auth.qtpl:106 + qw422016.N().S(`

+ `) +//line views/auth.qtpl:107 } else { -//line views/auth.qtpl:103 +//line views/auth.qtpl:107 qw422016.N().S(` -

You cannot log out because you are not logged in.

-

Login

-

← Home

+

`) +//line views/auth.qtpl:108 + qw422016.E().S(lc.Get("auth.logout_anon")) +//line views/auth.qtpl:108 + qw422016.N().S(`

+

`) +//line views/auth.qtpl:109 + qw422016.E().S(lc.Get("auth.login_title")) +//line views/auth.qtpl:109 + qw422016.N().S(`

+

← `) +//line views/auth.qtpl:110 + qw422016.E().S(lc.Get("auth.go_home")) +//line views/auth.qtpl:110 + qw422016.N().S(`

`) -//line views/auth.qtpl:107 +//line views/auth.qtpl:111 } -//line views/auth.qtpl:107 +//line views/auth.qtpl:111 qw422016.N().S(`
`) -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 } -//line views/auth.qtpl:111 -func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) { -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 +func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool, lc *l18n.Localizer) { +//line views/auth.qtpl:115 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:111 - StreamLogoutHTML(qw422016, can) -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 + StreamLogoutHTML(qw422016, can, lc) +//line views/auth.qtpl:115 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 } -//line views/auth.qtpl:111 -func LogoutHTML(can bool) string { -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 +func LogoutHTML(can bool, lc *l18n.Localizer) string { +//line views/auth.qtpl:115 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:111 - WriteLogoutHTML(qb422016, can) -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 + WriteLogoutHTML(qb422016, can, lc) +//line views/auth.qtpl:115 qs422016 := string(qb422016.B) -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 return qs422016 -//line views/auth.qtpl:111 +//line views/auth.qtpl:115 } -//line views/auth.qtpl:113 -func StreamLockHTML(qw422016 *qt422016.Writer) { -//line views/auth.qtpl:113 +//line views/auth.qtpl:117 +func StreamLockHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { +//line views/auth.qtpl:117 qw422016.N().S(` - 🔒 Locked + 🔒 `) +//line views/auth.qtpl:123 + qw422016.E().S(lc.Get("auth.lock_title")) +//line views/auth.qtpl:123 + qw422016.N().S(` @@ -414,53 +535,69 @@ func StreamLockHTML(qw422016 *qt422016.Writer) {

🔒

-

Locked

+

`) +//line views/auth.qtpl:131 + qw422016.E().S(lc.Get("auth.lock_title")) +//line views/auth.qtpl:131 + qw422016.N().S(`

`) -//line views/auth.qtpl:139 - streamtelegramWidgetHTML(qw422016) -//line views/auth.qtpl:139 +//line views/auth.qtpl:143 + streamtelegramWidgetHTML(qw422016, lc) +//line views/auth.qtpl:143 qw422016.N().S(`
`) -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 } -//line views/auth.qtpl:144 -func WriteLockHTML(qq422016 qtio422016.Writer) { -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 +func WriteLockHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { +//line views/auth.qtpl:148 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/auth.qtpl:144 - StreamLockHTML(qw422016) -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 + StreamLockHTML(qw422016, lc) +//line views/auth.qtpl:148 qt422016.ReleaseWriter(qw422016) -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 } -//line views/auth.qtpl:144 -func LockHTML() string { -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 +func LockHTML(lc *l18n.Localizer) string { +//line views/auth.qtpl:148 qb422016 := qt422016.AcquireByteBuffer() -//line views/auth.qtpl:144 - WriteLockHTML(qb422016) -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 + WriteLockHTML(qb422016, lc) +//line views/auth.qtpl:148 qs422016 := string(qb422016.B) -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 qt422016.ReleaseByteBuffer(qb422016) -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 return qs422016 -//line views/auth.qtpl:144 +//line views/auth.qtpl:148 } diff --git a/views/history.qtpl b/views/history.qtpl index 9625b33..dd6f9ce 100644 --- a/views/history.qtpl +++ b/views/history.qtpl @@ -1,8 +1,10 @@ +// TODO: l18n {% import "fmt" %} {% import "net/http" %} {% import "time" %} {% import "github.com/bouncepaw/mycorrhiza/cfg" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/hyphae" %} {% import "github.com/bouncepaw/mycorrhiza/history" %} @@ -10,6 +12,7 @@ {% func PrimitiveDiffHTML(rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) %} {% code +lc := l18n.FromRequest(rq) text, err := history.PrimitiveDiffAtRevision(h.TextPartPath(), hash) if err != nil { text = err.Error() @@ -18,20 +21,20 @@ if err != nil {
-

Diff {%s= beautifulLink(h.Name) %} at {%s hash %}

+

{%s= lc.Get("ui.diff_title", &l18n.Replacements{"name": beautifulLink(h.Name), "rev": hash}) %}

{%s text %}
{% endfunc %} -{% func RecentChangesHTML(n int) %} +{% func RecentChangesHTML(n int, lc *l18n.Localizer) %}
-

Recent Changes

+

{%s lc.Get("ui.recent_heading") %}

-

Subscribe via RSS, Atom or JSON feed.

+

{%s= lc.Get("ui.recent_subscribe", &l18n.Replacements{"rss": "RSS", "atom": "Atom", "json": fmt.Sprintf("%s", lc.Get("ui.recent_subscribe_json"))}) %}

{% comment %} Here I am, willing to add some accessibility using ARIA. Turns out, @@ -61,7 +64,7 @@ if err != nil { %}
{% if len(changes) == 0 %} -

Could not find any recent changes.

+

{%s lc.Get("ui.recent_empty") %}

{% else %} {% for i, entry := range changes %} @@ -80,7 +83,7 @@ if err != nil { {% endfor %} {% endif %} - {%s= helpTopicBadgeHTML("en", "recent_changes") %} + {%s= helpTopicBadgeHTML(lc.Locale, "recent_changes") %}
@@ -109,11 +112,11 @@ if err != nil {
{% endfunc %} -{% func HistoryHTML(rq *http.Request, hyphaName, list string) %} +{% func HistoryHTML(rq *http.Request, hyphaName, list string, lc *l18n.Localizer) %}
-

History of {%s= beautifulLink(hyphaName) %}

+

{%s= fmt.Sprintf(lc.Get("ui.history_title"), beautifulLink(hyphaName)) %}

{%s= list %}
diff --git a/views/history.qtpl.go b/views/history.qtpl.go index d5ef401..5d3d92c 100644 --- a/views/history.qtpl.go +++ b/views/history.qtpl.go @@ -1,432 +1,454 @@ // Code generated by qtc from "history.qtpl". DO NOT EDIT. // See https://github.com/valyala/quicktemplate for details. -//line views/history.qtpl:1 -package views - -//line views/history.qtpl:1 -import "fmt" +// TODO: l18n //line views/history.qtpl:2 -import "net/http" +package views + +//line views/history.qtpl:2 +import "fmt" //line views/history.qtpl:3 +import "net/http" + +//line views/history.qtpl:4 import "time" -//line views/history.qtpl:5 +//line views/history.qtpl:6 import "github.com/bouncepaw/mycorrhiza/cfg" -//line views/history.qtpl:6 -import "github.com/bouncepaw/mycorrhiza/user" - //line views/history.qtpl:7 -import "github.com/bouncepaw/mycorrhiza/hyphae" +import "github.com/bouncepaw/mycorrhiza/l18n" //line views/history.qtpl:8 +import "github.com/bouncepaw/mycorrhiza/user" + +//line views/history.qtpl:9 +import "github.com/bouncepaw/mycorrhiza/hyphae" + +//line views/history.qtpl:10 import "github.com/bouncepaw/mycorrhiza/history" -//line views/history.qtpl:11 +//line views/history.qtpl:13 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/history.qtpl:11 +//line views/history.qtpl:13 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/history.qtpl:11 +//line views/history.qtpl:13 func StreamPrimitiveDiffHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) { -//line views/history.qtpl:11 +//line views/history.qtpl:13 qw422016.N().S(` `) -//line views/history.qtpl:13 +//line views/history.qtpl:15 + lc := l18n.FromRequest(rq) text, err := history.PrimitiveDiffAtRevision(h.TextPartPath(), hash) if err != nil { text = err.Error() } -//line views/history.qtpl:17 +//line views/history.qtpl:20 qw422016.N().S(`
-

Diff `) -//line views/history.qtpl:21 - qw422016.N().S(beautifulLink(h.Name)) -//line views/history.qtpl:21 - qw422016.N().S(` at `) -//line views/history.qtpl:21 - qw422016.E().S(hash) -//line views/history.qtpl:21 +

`) +//line views/history.qtpl:24 + qw422016.N().S(lc.Get("ui.diff_title", &l18n.Replacements{"name": beautifulLink(h.Name), "rev": hash})) +//line views/history.qtpl:24 qw422016.N().S(`

`)
-//line views/history.qtpl:22
+//line views/history.qtpl:25
 	qw422016.E().S(text)
-//line views/history.qtpl:22
+//line views/history.qtpl:25
 	qw422016.N().S(`
`) -//line views/history.qtpl:26 +//line views/history.qtpl:29 } -//line views/history.qtpl:26 +//line views/history.qtpl:29 func WritePrimitiveDiffHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) { -//line views/history.qtpl:26 +//line views/history.qtpl:29 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:26 +//line views/history.qtpl:29 StreamPrimitiveDiffHTML(qw422016, rq, h, u, hash) -//line views/history.qtpl:26 +//line views/history.qtpl:29 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:26 +//line views/history.qtpl:29 } -//line views/history.qtpl:26 +//line views/history.qtpl:29 func PrimitiveDiffHTML(rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) string { -//line views/history.qtpl:26 +//line views/history.qtpl:29 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:26 +//line views/history.qtpl:29 WritePrimitiveDiffHTML(qb422016, rq, h, u, hash) -//line views/history.qtpl:26 +//line views/history.qtpl:29 qs422016 := string(qb422016.B) -//line views/history.qtpl:26 +//line views/history.qtpl:29 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:26 +//line views/history.qtpl:29 return qs422016 -//line views/history.qtpl:26 +//line views/history.qtpl:29 } -//line views/history.qtpl:28 -func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) { -//line views/history.qtpl:28 +//line views/history.qtpl:31 +func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int, lc *l18n.Localizer) { +//line views/history.qtpl:31 qw422016.N().S(`
-

Recent Changes

+

`) +//line views/history.qtpl:34 + qw422016.E().S(lc.Get("ui.recent_heading")) +//line views/history.qtpl:34 + qw422016.N().S(`

-

Subscribe via RSS, Atom or JSON feed.

- - `) -//line views/history.qtpl:55 - qw422016.N().S(` +

`) +//line views/history.qtpl:51 + qw422016.N().S(lc.Get("ui.recent_subscribe", &l18n.Replacements{"rss": "RSS", "atom": "Atom", "json": fmt.Sprintf("%s", lc.Get("ui.recent_subscribe_json"))})) +//line views/history.qtpl:51 + qw422016.N().S(`

`) //line views/history.qtpl:58 + qw422016.N().S(` + + `) +//line views/history.qtpl:61 changes := history.RecentChanges(n) var year, day int var month time.Month -//line views/history.qtpl:61 +//line views/history.qtpl:64 qw422016.N().S(`
`) -//line views/history.qtpl:63 +//line views/history.qtpl:66 if len(changes) == 0 { -//line views/history.qtpl:63 +//line views/history.qtpl:66 qw422016.N().S(` -

Could not find any recent changes.

+

`) +//line views/history.qtpl:67 + qw422016.E().S(lc.Get("ui.recent_empty")) +//line views/history.qtpl:67 + qw422016.N().S(`

`) -//line views/history.qtpl:65 +//line views/history.qtpl:68 } else { -//line views/history.qtpl:65 +//line views/history.qtpl:68 qw422016.N().S(` `) -//line views/history.qtpl:66 +//line views/history.qtpl:69 for i, entry := range changes { -//line views/history.qtpl:66 +//line views/history.qtpl:69 qw422016.N().S(` `) -//line views/history.qtpl:68 +//line views/history.qtpl:71 y, m, d := entry.Time.UTC().Date() -//line views/history.qtpl:68 +//line views/history.qtpl:71 qw422016.N().S(` `) -//line views/history.qtpl:69 +//line views/history.qtpl:72 if d != day || m != month || y != year { -//line views/history.qtpl:69 +//line views/history.qtpl:72 qw422016.N().S(`

`) -//line views/history.qtpl:71 +//line views/history.qtpl:74 qw422016.E().S(fmt.Sprintf("%04d-%02d-%02d", y, m, d)) -//line views/history.qtpl:71 +//line views/history.qtpl:74 qw422016.N().S(`

`) -//line views/history.qtpl:73 +//line views/history.qtpl:76 year, month, day = y, m, d -//line views/history.qtpl:73 +//line views/history.qtpl:76 qw422016.N().S(` `) -//line views/history.qtpl:74 +//line views/history.qtpl:77 } -//line views/history.qtpl:74 +//line views/history.qtpl:77 qw422016.N().S(`
`) -//line views/history.qtpl:78 +//line views/history.qtpl:81 qw422016.N().S(recentChangesEntry(entry)) -//line views/history.qtpl:78 +//line views/history.qtpl:81 qw422016.N().S(`
`) -//line views/history.qtpl:81 +//line views/history.qtpl:84 } -//line views/history.qtpl:81 +//line views/history.qtpl:84 qw422016.N().S(` `) -//line views/history.qtpl:82 +//line views/history.qtpl:85 } -//line views/history.qtpl:82 +//line views/history.qtpl:85 qw422016.N().S(` `) -//line views/history.qtpl:83 - qw422016.N().S(helpTopicBadgeHTML("en", "recent_changes")) -//line views/history.qtpl:83 +//line views/history.qtpl:86 + qw422016.N().S(helpTopicBadgeHTML(lc.Locale, "recent_changes")) +//line views/history.qtpl:86 qw422016.N().S(`
`) -//line views/history.qtpl:87 +//line views/history.qtpl:90 } -//line views/history.qtpl:87 -func WriteRecentChangesHTML(qq422016 qtio422016.Writer, n int) { -//line views/history.qtpl:87 +//line views/history.qtpl:90 +func WriteRecentChangesHTML(qq422016 qtio422016.Writer, n int, lc *l18n.Localizer) { +//line views/history.qtpl:90 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:87 - StreamRecentChangesHTML(qw422016, n) -//line views/history.qtpl:87 +//line views/history.qtpl:90 + StreamRecentChangesHTML(qw422016, n, lc) +//line views/history.qtpl:90 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:87 +//line views/history.qtpl:90 } -//line views/history.qtpl:87 -func RecentChangesHTML(n int) string { -//line views/history.qtpl:87 +//line views/history.qtpl:90 +func RecentChangesHTML(n int, lc *l18n.Localizer) string { +//line views/history.qtpl:90 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:87 - WriteRecentChangesHTML(qb422016, n) -//line views/history.qtpl:87 +//line views/history.qtpl:90 + WriteRecentChangesHTML(qb422016, n, lc) +//line views/history.qtpl:90 qs422016 := string(qb422016.B) -//line views/history.qtpl:87 +//line views/history.qtpl:90 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:87 +//line views/history.qtpl:90 return qs422016 -//line views/history.qtpl:87 +//line views/history.qtpl:90 } -//line views/history.qtpl:89 +//line views/history.qtpl:92 func streamrecentChangesEntry(qw422016 *qt422016.Writer, rev history.Revision) { -//line views/history.qtpl:89 +//line views/history.qtpl:92 qw422016.N().S(`
`) -//line views/history.qtpl:94 +//line views/history.qtpl:97 qw422016.E().S(rev.Hash) -//line views/history.qtpl:94 +//line views/history.qtpl:97 qw422016.N().S(` `) -//line views/history.qtpl:96 +//line views/history.qtpl:99 if rev.Username != "anon" { -//line views/history.qtpl:96 +//line views/history.qtpl:99 qw422016.N().S(` `) -//line views/history.qtpl:100 +//line views/history.qtpl:103 } -//line views/history.qtpl:100 +//line views/history.qtpl:103 qw422016.N().S(`
`) -//line views/history.qtpl:104 +//line views/history.qtpl:107 qw422016.N().S(rev.HyphaeLinksHTML()) -//line views/history.qtpl:104 +//line views/history.qtpl:107 qw422016.N().S(` `) -//line views/history.qtpl:107 +//line views/history.qtpl:110 qw422016.E().S(rev.Message) -//line views/history.qtpl:107 +//line views/history.qtpl:110 qw422016.N().S(`
`) -//line views/history.qtpl:110 +//line views/history.qtpl:113 } -//line views/history.qtpl:110 +//line views/history.qtpl:113 func writerecentChangesEntry(qq422016 qtio422016.Writer, rev history.Revision) { -//line views/history.qtpl:110 +//line views/history.qtpl:113 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:110 +//line views/history.qtpl:113 streamrecentChangesEntry(qw422016, rev) -//line views/history.qtpl:110 +//line views/history.qtpl:113 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:110 +//line views/history.qtpl:113 } -//line views/history.qtpl:110 +//line views/history.qtpl:113 func recentChangesEntry(rev history.Revision) string { -//line views/history.qtpl:110 +//line views/history.qtpl:113 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:110 +//line views/history.qtpl:113 writerecentChangesEntry(qb422016, rev) -//line views/history.qtpl:110 +//line views/history.qtpl:113 qs422016 := string(qb422016.B) -//line views/history.qtpl:110 +//line views/history.qtpl:113 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:110 +//line views/history.qtpl:113 return qs422016 -//line views/history.qtpl:110 +//line views/history.qtpl:113 } -//line views/history.qtpl:112 -func StreamHistoryHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, list string) { -//line views/history.qtpl:112 +//line views/history.qtpl:115 +func StreamHistoryHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, list string, lc *l18n.Localizer) { +//line views/history.qtpl:115 qw422016.N().S(`
-

History of `) -//line views/history.qtpl:116 - qw422016.N().S(beautifulLink(hyphaName)) -//line views/history.qtpl:116 +

`) +//line views/history.qtpl:119 + qw422016.N().S(fmt.Sprintf(lc.Get("ui.history_title"), beautifulLink(hyphaName))) +//line views/history.qtpl:119 qw422016.N().S(`

`) -//line views/history.qtpl:117 +//line views/history.qtpl:120 qw422016.N().S(list) -//line views/history.qtpl:117 +//line views/history.qtpl:120 qw422016.N().S(`
`) -//line views/history.qtpl:121 +//line views/history.qtpl:124 } -//line views/history.qtpl:121 -func WriteHistoryHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, list string) { -//line views/history.qtpl:121 +//line views/history.qtpl:124 +func WriteHistoryHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, list string, lc *l18n.Localizer) { +//line views/history.qtpl:124 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/history.qtpl:121 - StreamHistoryHTML(qw422016, rq, hyphaName, list) -//line views/history.qtpl:121 +//line views/history.qtpl:124 + StreamHistoryHTML(qw422016, rq, hyphaName, list, lc) +//line views/history.qtpl:124 qt422016.ReleaseWriter(qw422016) -//line views/history.qtpl:121 +//line views/history.qtpl:124 } -//line views/history.qtpl:121 -func HistoryHTML(rq *http.Request, hyphaName, list string) string { -//line views/history.qtpl:121 +//line views/history.qtpl:124 +func HistoryHTML(rq *http.Request, hyphaName, list string, lc *l18n.Localizer) string { +//line views/history.qtpl:124 qb422016 := qt422016.AcquireByteBuffer() -//line views/history.qtpl:121 - WriteHistoryHTML(qb422016, rq, hyphaName, list) -//line views/history.qtpl:121 +//line views/history.qtpl:124 + WriteHistoryHTML(qb422016, rq, hyphaName, list, lc) +//line views/history.qtpl:124 qs422016 := string(qb422016.B) -//line views/history.qtpl:121 +//line views/history.qtpl:124 qt422016.ReleaseByteBuffer(qb422016) -//line views/history.qtpl:121 +//line views/history.qtpl:124 return qs422016 -//line views/history.qtpl:121 +//line views/history.qtpl:124 } diff --git a/views/hypha.qtpl b/views/hypha.qtpl index 5816ba1..d6a86e1 100644 --- a/views/hypha.qtpl +++ b/views/hypha.qtpl @@ -3,41 +3,43 @@ {% import "github.com/bouncepaw/mycorrhiza/cfg" %} {% import "github.com/bouncepaw/mycorrhiza/hyphae" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} -{% func beautifulLink(hyphaName string) %} -{%s util.BeautifulName(hyphaName) %}{% endfunc %} +{% func beautifulLink(hyphaName string) %}{%s util.BeautifulName(hyphaName) %}{% endfunc %} -{% func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) %} +{% func mycoLink(lc *l18n.Localizer) %}{%s lc.Get("ui.notexist_write_myco") %}{% endfunc %} + +{% func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) %}
-

This hypha does not exist

+

{%s lc.Get("ui.notexist_heading") %}

{% if cfg.UseAuth && u.Group == "anon" %} -

You are not authorized to create new hyphae. Here is what you can do:

+

{%s lc.Get("ui.notexist_norights") %}

{% else %}
-

📝 Write a text

-

Write a note, a diary, an article, a story or anything textual using Mycomarkup. Full history of edits to the document will be saved.

-

Make sure to follow this wiki's writing conventions if there are any.

- Create +

📝 {%s lc.Get("ui.notexist_write") %}

+

{%s= lc.Get("ui.notexist_write_tip1", &l18n.Replacements{"myco": mycoLink(lc)}) %}

+

{%s lc.Get("ui.notexist_write_tip2") %}

+ {%s lc.Get("ui.notexist_write_button") %}
-

🖼 Upload a media

-

Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.

+

🖼 {%s lc.Get("ui.notexist_media") %}

+

{%s lc.Get("ui.notexist_media_tip1") %}

- +
@@ -73,7 +75,9 @@ {% endfunc %} -{% func AttachmentHTML(h *hyphae.Hypha) %} +{% func AttachmentHTMLRaw(h *hyphae.Hypha) %}{%= AttachmentHTML(h, l18n.New("en", "en")) %}{% endfunc %} + +{% func AttachmentHTML(h *hyphae.Hypha, lc *l18n.Localizer) %} {% switch filepath.Ext(h.BinaryPath) %} {% case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico" %} @@ -85,7 +89,7 @@
@@ -93,13 +97,13 @@
{% default %} {% endswitch %} {% endfunc %} diff --git a/views/hypha.qtpl.go b/views/hypha.qtpl.go index 7d029bf..2751956 100644 --- a/views/hypha.qtpl.go +++ b/views/hypha.qtpl.go @@ -17,29 +17,31 @@ import "github.com/bouncepaw/mycorrhiza/cfg" import "github.com/bouncepaw/mycorrhiza/hyphae" //line views/hypha.qtpl:6 -import "github.com/bouncepaw/mycorrhiza/user" +import "github.com/bouncepaw/mycorrhiza/l18n" //line views/hypha.qtpl:7 +import "github.com/bouncepaw/mycorrhiza/user" + +//line views/hypha.qtpl:8 import "github.com/bouncepaw/mycorrhiza/util" -//line views/hypha.qtpl:9 +//line views/hypha.qtpl:10 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/hypha.qtpl:9 +//line views/hypha.qtpl:10 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/hypha.qtpl:9 +//line views/hypha.qtpl:10 func streambeautifulLink(qw422016 *qt422016.Writer, hyphaName string) { -//line views/hypha.qtpl:9 - qw422016.N().S(` -`) +//line views/hypha.qtpl:12 + qw422016.E().S(lc.Get("ui.notexist_write_myco")) +//line views/hypha.qtpl:12 + qw422016.N().S(``) +//line views/hypha.qtpl:12 +} + +//line views/hypha.qtpl:12 +func writemycoLink(qq422016 qtio422016.Writer, lc *l18n.Localizer) { +//line views/hypha.qtpl:12 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/hypha.qtpl:12 + streammycoLink(qw422016, lc) +//line views/hypha.qtpl:12 + qt422016.ReleaseWriter(qw422016) +//line views/hypha.qtpl:12 +} + +//line views/hypha.qtpl:12 +func mycoLink(lc *l18n.Localizer) string { +//line views/hypha.qtpl:12 + qb422016 := qt422016.AcquireByteBuffer() +//line views/hypha.qtpl:12 + writemycoLink(qb422016, lc) +//line views/hypha.qtpl:12 + qs422016 := string(qb422016.B) +//line views/hypha.qtpl:12 + qt422016.ReleaseByteBuffer(qb422016) +//line views/hypha.qtpl:12 + return qs422016 +//line views/hypha.qtpl:12 +} + +//line views/hypha.qtpl:14 +func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) { +//line views/hypha.qtpl:14 qw422016.N().S(`
-

This hypha does not exist

+

`) +//line views/hypha.qtpl:16 + qw422016.E().S(lc.Get("ui.notexist_heading")) +//line views/hypha.qtpl:16 + qw422016.N().S(`

`) -//line views/hypha.qtpl:15 +//line views/hypha.qtpl:17 if cfg.UseAuth && u.Group == "anon" { -//line views/hypha.qtpl:15 +//line views/hypha.qtpl:17 qw422016.N().S(` -

You are not authorized to create new hyphae. Here is what you can do:

+

`) +//line views/hypha.qtpl:18 + qw422016.E().S(lc.Get("ui.notexist_norights")) +//line views/hypha.qtpl:18 + qw422016.N().S(`

`) -//line views/hypha.qtpl:21 +//line views/hypha.qtpl:23 } else { -//line views/hypha.qtpl:21 +//line views/hypha.qtpl:23 qw422016.N().S(`
-

📝 Write a text

-

Write a note, a diary, an article, a story or anything textual using Mycomarkup. Full history of edits to the document will be saved.

-

Make sure to follow this wiki's writing conventions if there are any.

+

📝 `) +//line views/hypha.qtpl:27 + qw422016.E().S(lc.Get("ui.notexist_write")) +//line views/hypha.qtpl:27 + qw422016.N().S(`

+

`) +//line views/hypha.qtpl:28 + qw422016.N().S(lc.Get("ui.notexist_write_tip1", &l18n.Replacements{"myco": mycoLink(lc)})) +//line views/hypha.qtpl:28 + qw422016.N().S(`

+

`) +//line views/hypha.qtpl:29 + qw422016.E().S(lc.Get("ui.notexist_write_tip2")) +//line views/hypha.qtpl:29 + qw422016.N().S(`

Create +//line views/hypha.qtpl:30 + qw422016.N().S(`">`) +//line views/hypha.qtpl:30 + qw422016.E().S(lc.Get("ui.notexist_write_button")) +//line views/hypha.qtpl:30 + qw422016.N().S(`
-

🖼 Upload a media

-

Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.

+

🖼 `) +//line views/hypha.qtpl:34 + qw422016.E().S(lc.Get("ui.notexist_media")) +//line views/hypha.qtpl:34 + qw422016.N().S(`

+

`) +//line views/hypha.qtpl:35 + qw422016.E().S(lc.Get("ui.notexist_media_tip1")) +//line views/hypha.qtpl:35 + qw422016.N().S(`

- +
`) -//line views/hypha.qtpl:44 +//line views/hypha.qtpl:46 } -//line views/hypha.qtpl:44 +//line views/hypha.qtpl:46 qw422016.N().S(`
`) -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 } -//line views/hypha.qtpl:46 -func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h *hyphae.Hypha, u *user.User) { -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 +func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) { +//line views/hypha.qtpl:48 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:46 - streamnonExistentHyphaNotice(qw422016, h, u) -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 + streamnonExistentHyphaNotice(qw422016, h, u, lc) +//line views/hypha.qtpl:48 qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 } -//line views/hypha.qtpl:46 -func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) string { -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 +func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) string { +//line views/hypha.qtpl:48 qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:46 - writenonExistentHyphaNotice(qb422016, h, u) -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 + writenonExistentHyphaNotice(qb422016, h, u, lc) +//line views/hypha.qtpl:48 qs422016 := string(qb422016.B) -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 return qs422016 -//line views/hypha.qtpl:46 +//line views/hypha.qtpl:48 } -//line views/hypha.qtpl:48 +//line views/hypha.qtpl:50 func StreamNaviTitleHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:48 +//line views/hypha.qtpl:50 qw422016.N().S(` `) -//line views/hypha.qtpl:50 +//line views/hypha.qtpl:52 var ( prevAcc = "/hypha/" parts = strings.Split(h.Name, "/") ) -//line views/hypha.qtpl:54 +//line views/hypha.qtpl:56 qw422016.N().S(`

`) -//line views/hypha.qtpl:56 +//line views/hypha.qtpl:58 qw422016.N().S(``) -//line views/hypha.qtpl:58 +//line views/hypha.qtpl:60 qw422016.N().S(cfg.NaviTitleIcon) -//line views/hypha.qtpl:58 +//line views/hypha.qtpl:60 qw422016.N().S(``) -//line views/hypha.qtpl:62 +//line views/hypha.qtpl:64 for i, part := range parts { -//line views/hypha.qtpl:63 +//line views/hypha.qtpl:65 if i > 0 { -//line views/hypha.qtpl:63 +//line views/hypha.qtpl:65 qw422016.N().S(``) -//line views/hypha.qtpl:65 +//line views/hypha.qtpl:67 } -//line views/hypha.qtpl:65 +//line views/hypha.qtpl:67 qw422016.N().S(``) -//line views/hypha.qtpl:68 - qw422016.N().S(util.BeautifulName(part)) -//line views/hypha.qtpl:68 - qw422016.N().S(``) //line views/hypha.qtpl:70 + qw422016.N().S(util.BeautifulName(part)) +//line views/hypha.qtpl:70 + qw422016.N().S(``) +//line views/hypha.qtpl:72 prevAcc += part + "/" -//line views/hypha.qtpl:71 +//line views/hypha.qtpl:73 } -//line views/hypha.qtpl:72 +//line views/hypha.qtpl:74 qw422016.N().S(`

`) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 } -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 func WriteNaviTitleHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 StreamNaviTitleHTML(qw422016, h) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 } -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 func NaviTitleHTML(h *hyphae.Hypha) string { -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 WriteNaviTitleHTML(qb422016, h) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 qs422016 := string(qb422016.B) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 return qs422016 -//line views/hypha.qtpl:74 +//line views/hypha.qtpl:76 } -//line views/hypha.qtpl:76 -func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:76 +//line views/hypha.qtpl:78 +func StreamAttachmentHTMLRaw(qw422016 *qt422016.Writer, h *hyphae.Hypha) { +//line views/hypha.qtpl:78 + StreamAttachmentHTML(qw422016, h, l18n.New("en", "en")) +//line views/hypha.qtpl:78 +} + +//line views/hypha.qtpl:78 +func WriteAttachmentHTMLRaw(qq422016 qtio422016.Writer, h *hyphae.Hypha) { +//line views/hypha.qtpl:78 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/hypha.qtpl:78 + StreamAttachmentHTMLRaw(qw422016, h) +//line views/hypha.qtpl:78 + qt422016.ReleaseWriter(qw422016) +//line views/hypha.qtpl:78 +} + +//line views/hypha.qtpl:78 +func AttachmentHTMLRaw(h *hyphae.Hypha) string { +//line views/hypha.qtpl:78 + qb422016 := qt422016.AcquireByteBuffer() +//line views/hypha.qtpl:78 + WriteAttachmentHTMLRaw(qb422016, h) +//line views/hypha.qtpl:78 + qs422016 := string(qb422016.B) +//line views/hypha.qtpl:78 + qt422016.ReleaseByteBuffer(qb422016) +//line views/hypha.qtpl:78 + return qs422016 +//line views/hypha.qtpl:78 +} + +//line views/hypha.qtpl:80 +func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha, lc *l18n.Localizer) { +//line views/hypha.qtpl:80 qw422016.N().S(` `) -//line views/hypha.qtpl:77 +//line views/hypha.qtpl:81 switch filepath.Ext(h.BinaryPath) { -//line views/hypha.qtpl:79 +//line views/hypha.qtpl:83 case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico": -//line views/hypha.qtpl:79 +//line views/hypha.qtpl:83 qw422016.N().S(`
`) -//line views/hypha.qtpl:84 +//line views/hypha.qtpl:88 case ".ogg", ".webm", ".mp4": -//line views/hypha.qtpl:84 +//line views/hypha.qtpl:88 qw422016.N().S(`
`) -//line views/hypha.qtpl:92 +//line views/hypha.qtpl:96 case ".mp3": -//line views/hypha.qtpl:92 +//line views/hypha.qtpl:96 qw422016.N().S(`
`) -//line views/hypha.qtpl:100 +//line views/hypha.qtpl:104 default: -//line views/hypha.qtpl:100 +//line views/hypha.qtpl:104 qw422016.N().S(`

Download media

+//line views/hypha.qtpl:106 + qw422016.N().S(`">`) +//line views/hypha.qtpl:106 + qw422016.E().S(lc.Get("ui.media_download")) +//line views/hypha.qtpl:106 + qw422016.N().S(`

`) -//line views/hypha.qtpl:104 +//line views/hypha.qtpl:108 } -//line views/hypha.qtpl:104 +//line views/hypha.qtpl:108 qw422016.N().S(` `) -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 } -//line views/hypha.qtpl:105 -func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) { -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 +func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha, lc *l18n.Localizer) { +//line views/hypha.qtpl:109 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/hypha.qtpl:105 - StreamAttachmentHTML(qw422016, h) -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 + StreamAttachmentHTML(qw422016, h, lc) +//line views/hypha.qtpl:109 qt422016.ReleaseWriter(qw422016) -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 } -//line views/hypha.qtpl:105 -func AttachmentHTML(h *hyphae.Hypha) string { -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 +func AttachmentHTML(h *hyphae.Hypha, lc *l18n.Localizer) string { +//line views/hypha.qtpl:109 qb422016 := qt422016.AcquireByteBuffer() -//line views/hypha.qtpl:105 - WriteAttachmentHTML(qb422016, h) -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 + WriteAttachmentHTML(qb422016, h, lc) +//line views/hypha.qtpl:109 qs422016 := string(qb422016.B) -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 qt422016.ReleaseByteBuffer(qb422016) -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 return qs422016 -//line views/hypha.qtpl:105 +//line views/hypha.qtpl:109 } diff --git a/views/modal.qtpl b/views/modal.qtpl index 2f9f91a..2a0378d 100644 --- a/views/modal.qtpl +++ b/views/modal.qtpl @@ -1,44 +1,55 @@ +{% import "fmt" %} {% import "net/http" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) %} +{% code + lc := l18n.FromRequest(rq) +%} {%= modalBegin( "delete-confirm", hyphaName, "", - "Delete "+beautifulLink(hyphaName)+"?") %} -{%= modalReallyWant(hyphaName, "unattach") %} -

In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.

-{%= modalEnd(hyphaName, true) %} + fmt.Sprintf(lc.Get("ui.ask_delete"), beautifulLink(hyphaName))) %} +{%= modalReallyWant(hyphaName, lc.Get("ui.ask_delete_verb"), lc) %} +

{%s lc.Get("ui.ask_delete_tip") %}

+{%= modalEnd(hyphaName, true, lc) %} {% endfunc %} {% func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) %} +{% code + lc := l18n.FromRequest(rq) +%} {%= modalBegin( "unattach", hyphaName, "", - "Unattach "+beautifulLink(hyphaName)+"?") %} -{%= modalReallyWant(hyphaName, "unattach") %} -{%= modalEnd(hyphaName, true) %} + fmt.Sprintf(lc.Get("ui.ask_unattach"), beautifulLink(hyphaName))) %} +{%= modalReallyWant(hyphaName, lc.Get("ui.ask_unattach_verb"), lc) %} +{%= modalEnd(hyphaName, true, lc) %} {% endfunc %} {% func RenameAskHTML(rq *http.Request, hyphaName string, isOld bool) %} +{% code + lc := l18n.FromRequest(rq) +%} {%= modalBegin( "rename-confirm", hyphaName, ` method="post" enctype="multipart/form-data"`, - "Rename "+beautifulLink(hyphaName)) %} - + fmt.Sprintf(lc.Get("ui.ask_rename"), beautifulLink(hyphaName))) %} + - + -

If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.

-{%= modalEnd(hyphaName, false) %} +

{%s lc.Get("ui.rename_tip") %}

+{%= modalEnd(hyphaName, false, lc) %} {% endfunc %} -{% func modalReallyWant(hyphaName, verb string) %} - +{% func modalReallyWant(hyphaName, verb string, lc *l18n.Localizer) %} + {% endfunc %} {% func modalBegin(path, hyphaName, formAttrs, legend string) %} @@ -49,9 +60,9 @@ {%s= legend %} {% endfunc %} -{% func modalEnd(hyphaName string, shouldFocusOnConfirm bool) %} - - Cancel +{% func modalEnd(hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) %} + + {%s lc.Get("ui.cancel") %} diff --git a/views/modal.qtpl.go b/views/modal.qtpl.go index 9b82733..85bb49f 100644 --- a/views/modal.qtpl.go +++ b/views/modal.qtpl.go @@ -5,333 +5,377 @@ package views //line views/modal.qtpl:1 +import "fmt" + +//line views/modal.qtpl:2 import "net/http" //line views/modal.qtpl:3 +import "github.com/bouncepaw/mycorrhiza/l18n" + +//line views/modal.qtpl:5 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/modal.qtpl:3 +//line views/modal.qtpl:5 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/modal.qtpl:3 +//line views/modal.qtpl:5 func StreamDeleteAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) { -//line views/modal.qtpl:3 +//line views/modal.qtpl:5 qw422016.N().S(` `) -//line views/modal.qtpl:4 - streammodalBegin(qw422016, - "delete-confirm", - hyphaName, - "", - "Delete "+beautifulLink(hyphaName)+"?") +//line views/modal.qtpl:7 + lc := l18n.FromRequest(rq) + //line views/modal.qtpl:8 qw422016.N().S(` `) //line views/modal.qtpl:9 - streammodalReallyWant(qw422016, hyphaName, "unattach") -//line views/modal.qtpl:9 - qw422016.N().S(` -

In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.

-`) -//line views/modal.qtpl:11 - streammodalEnd(qw422016, hyphaName, true) -//line views/modal.qtpl:11 + streammodalBegin(qw422016, + "delete-confirm", + hyphaName, + "", + fmt.Sprintf(lc.Get("ui.ask_delete"), beautifulLink(hyphaName))) +//line views/modal.qtpl:13 qw422016.N().S(` `) -//line views/modal.qtpl:12 -} - -//line views/modal.qtpl:12 -func WriteDeleteAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) { -//line views/modal.qtpl:12 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/modal.qtpl:12 - StreamDeleteAskHTML(qw422016, rq, hyphaName, isOld) -//line views/modal.qtpl:12 - qt422016.ReleaseWriter(qw422016) -//line views/modal.qtpl:12 -} - -//line views/modal.qtpl:12 -func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) string { -//line views/modal.qtpl:12 - qb422016 := qt422016.AcquireByteBuffer() -//line views/modal.qtpl:12 - WriteDeleteAskHTML(qb422016, rq, hyphaName, isOld) -//line views/modal.qtpl:12 - qs422016 := string(qb422016.B) -//line views/modal.qtpl:12 - qt422016.ReleaseByteBuffer(qb422016) -//line views/modal.qtpl:12 - return qs422016 -//line views/modal.qtpl:12 -} - //line views/modal.qtpl:14 -func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) { + streammodalReallyWant(qw422016, hyphaName, lc.Get("ui.ask_delete_verb"), lc) //line views/modal.qtpl:14 qw422016.N().S(` -`) +

`) //line views/modal.qtpl:15 + qw422016.E().S(lc.Get("ui.ask_delete_tip")) +//line views/modal.qtpl:15 + qw422016.N().S(`

+`) +//line views/modal.qtpl:16 + streammodalEnd(qw422016, hyphaName, true, lc) +//line views/modal.qtpl:16 + qw422016.N().S(` +`) +//line views/modal.qtpl:17 +} + +//line views/modal.qtpl:17 +func WriteDeleteAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) { +//line views/modal.qtpl:17 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/modal.qtpl:17 + StreamDeleteAskHTML(qw422016, rq, hyphaName, isOld) +//line views/modal.qtpl:17 + qt422016.ReleaseWriter(qw422016) +//line views/modal.qtpl:17 +} + +//line views/modal.qtpl:17 +func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) string { +//line views/modal.qtpl:17 + qb422016 := qt422016.AcquireByteBuffer() +//line views/modal.qtpl:17 + WriteDeleteAskHTML(qb422016, rq, hyphaName, isOld) +//line views/modal.qtpl:17 + qs422016 := string(qb422016.B) +//line views/modal.qtpl:17 + qt422016.ReleaseByteBuffer(qb422016) +//line views/modal.qtpl:17 + return qs422016 +//line views/modal.qtpl:17 +} + +//line views/modal.qtpl:19 +func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) { +//line views/modal.qtpl:19 + qw422016.N().S(` +`) +//line views/modal.qtpl:21 + lc := l18n.FromRequest(rq) + +//line views/modal.qtpl:22 + qw422016.N().S(` +`) +//line views/modal.qtpl:23 streammodalBegin(qw422016, "unattach", hyphaName, "", - "Unattach "+beautifulLink(hyphaName)+"?") -//line views/modal.qtpl:19 + fmt.Sprintf(lc.Get("ui.ask_unattach"), beautifulLink(hyphaName))) +//line views/modal.qtpl:27 qw422016.N().S(` `) -//line views/modal.qtpl:20 - streammodalReallyWant(qw422016, hyphaName, "unattach") -//line views/modal.qtpl:20 +//line views/modal.qtpl:28 + streammodalReallyWant(qw422016, hyphaName, lc.Get("ui.ask_unattach_verb"), lc) +//line views/modal.qtpl:28 qw422016.N().S(` `) -//line views/modal.qtpl:21 - streammodalEnd(qw422016, hyphaName, true) -//line views/modal.qtpl:21 +//line views/modal.qtpl:29 + streammodalEnd(qw422016, hyphaName, true, lc) +//line views/modal.qtpl:29 qw422016.N().S(` `) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 } -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 func WriteUnattachAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) { -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 StreamUnattachAskHTML(qw422016, rq, hyphaName, isOld) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 qt422016.ReleaseWriter(qw422016) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 } -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) string { -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 qb422016 := qt422016.AcquireByteBuffer() -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 WriteUnattachAskHTML(qb422016, rq, hyphaName, isOld) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 qs422016 := string(qb422016.B) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 qt422016.ReleaseByteBuffer(qb422016) -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 return qs422016 -//line views/modal.qtpl:22 +//line views/modal.qtpl:30 } -//line views/modal.qtpl:24 +//line views/modal.qtpl:32 func StreamRenameAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) { -//line views/modal.qtpl:24 +//line views/modal.qtpl:32 qw422016.N().S(` `) -//line views/modal.qtpl:25 +//line views/modal.qtpl:34 + lc := l18n.FromRequest(rq) + +//line views/modal.qtpl:35 + qw422016.N().S(` +`) +//line views/modal.qtpl:36 streammodalBegin(qw422016, "rename-confirm", hyphaName, ` method="post" enctype="multipart/form-data"`, - "Rename "+beautifulLink(hyphaName)) -//line views/modal.qtpl:29 + fmt.Sprintf(lc.Get("ui.ask_rename"), beautifulLink(hyphaName))) +//line views/modal.qtpl:40 qw422016.N().S(` - + - + -

If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.

+

`) +//line views/modal.qtpl:47 + qw422016.E().S(lc.Get("ui.rename_tip")) +//line views/modal.qtpl:47 + qw422016.N().S(`

`) -//line views/modal.qtpl:37 - streammodalEnd(qw422016, hyphaName, false) -//line views/modal.qtpl:37 +//line views/modal.qtpl:48 + streammodalEnd(qw422016, hyphaName, false, lc) +//line views/modal.qtpl:48 qw422016.N().S(` `) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 } -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 func WriteRenameAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) { -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 StreamRenameAskHTML(qw422016, rq, hyphaName, isOld) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 qt422016.ReleaseWriter(qw422016) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 } -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 func RenameAskHTML(rq *http.Request, hyphaName string, isOld bool) string { -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 qb422016 := qt422016.AcquireByteBuffer() -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 WriteRenameAskHTML(qb422016, rq, hyphaName, isOld) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 qs422016 := string(qb422016.B) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 qt422016.ReleaseByteBuffer(qb422016) -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 return qs422016 -//line views/modal.qtpl:38 +//line views/modal.qtpl:49 } -//line views/modal.qtpl:40 -func streammodalReallyWant(qw422016 *qt422016.Writer, hyphaName, verb string) { -//line views/modal.qtpl:40 +//line views/modal.qtpl:51 +func streammodalReallyWant(qw422016 *qt422016.Writer, hyphaName, verb string, lc *l18n.Localizer) { +//line views/modal.qtpl:51 qw422016.N().S(` - + `) -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 } -//line views/modal.qtpl:42 -func writemodalReallyWant(qq422016 qtio422016.Writer, hyphaName, verb string) { -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 +func writemodalReallyWant(qq422016 qtio422016.Writer, hyphaName, verb string, lc *l18n.Localizer) { +//line views/modal.qtpl:53 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/modal.qtpl:42 - streammodalReallyWant(qw422016, hyphaName, verb) -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 + streammodalReallyWant(qw422016, hyphaName, verb, lc) +//line views/modal.qtpl:53 qt422016.ReleaseWriter(qw422016) -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 } -//line views/modal.qtpl:42 -func modalReallyWant(hyphaName, verb string) string { -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 +func modalReallyWant(hyphaName, verb string, lc *l18n.Localizer) string { +//line views/modal.qtpl:53 qb422016 := qt422016.AcquireByteBuffer() -//line views/modal.qtpl:42 - writemodalReallyWant(qb422016, hyphaName, verb) -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 + writemodalReallyWant(qb422016, hyphaName, verb, lc) +//line views/modal.qtpl:53 qs422016 := string(qb422016.B) -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 qt422016.ReleaseByteBuffer(qb422016) -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 return qs422016 -//line views/modal.qtpl:42 +//line views/modal.qtpl:53 } -//line views/modal.qtpl:44 +//line views/modal.qtpl:55 func streammodalBegin(qw422016 *qt422016.Writer, path, hyphaName, formAttrs, legend string) { -//line views/modal.qtpl:44 +//line views/modal.qtpl:55 qw422016.N().S(`
`) -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 } -//line views/modal.qtpl:59 -func writemodalEnd(qq422016 qtio422016.Writer, hyphaName string, shouldFocusOnConfirm bool) { -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 +func writemodalEnd(qq422016 qtio422016.Writer, hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) { +//line views/modal.qtpl:70 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/modal.qtpl:59 - streammodalEnd(qw422016, hyphaName, shouldFocusOnConfirm) -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 + streammodalEnd(qw422016, hyphaName, shouldFocusOnConfirm, lc) +//line views/modal.qtpl:70 qt422016.ReleaseWriter(qw422016) -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 } -//line views/modal.qtpl:59 -func modalEnd(hyphaName string, shouldFocusOnConfirm bool) string { -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 +func modalEnd(hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) string { +//line views/modal.qtpl:70 qb422016 := qt422016.AcquireByteBuffer() -//line views/modal.qtpl:59 - writemodalEnd(qb422016, hyphaName, shouldFocusOnConfirm) -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 + writemodalEnd(qb422016, hyphaName, shouldFocusOnConfirm, lc) +//line views/modal.qtpl:70 qs422016 := string(qb422016.B) -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 qt422016.ReleaseByteBuffer(qb422016) -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 return qs422016 -//line views/modal.qtpl:59 +//line views/modal.qtpl:70 } diff --git a/views/mutators.qtpl b/views/mutators.qtpl index f387d8d..1fa64ec 100644 --- a/views/mutators.qtpl +++ b/views/mutators.qtpl @@ -1,37 +1,39 @@ +{% import "fmt" %} {% import "net/http" %} {% import "github.com/bouncepaw/mycorrhiza/cfg" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} -{% func Toolbar(u *user.User) %} +{% func Toolbar(u *user.User, lc *l18n.Localizer) %}
{%= viewScripts() %} {% endfunc %} -{% func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) %} +{% func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) %} {% code siblings, subhyphae, _, _ := tree.Tree(h.Name) %}
-

Please note that viewing attachments of hyphae is not supported in history for now.

+

{%s lc.Get("ui.revision_warning") %}

{%s= NaviTitleHTML(h) %} {%s= contents %}
-{%= SubhyphaeHTML(subhyphae) %} +{%= SubhyphaeHTML(subhyphae, lc) %}
-{%= siblingHyphaeHTML(siblings) %} +{%= siblingHyphaeHTML(siblings, lc) %}
{%= viewScripts() %} {% endfunc %} diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index 283b972..30c9b6a 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -23,216 +23,293 @@ import "github.com/bouncepaw/mycorrhiza/cfg" import "github.com/bouncepaw/mycorrhiza/hyphae" //line views/readers.qtpl:8 -import "github.com/bouncepaw/mycorrhiza/mimetype" +import "github.com/bouncepaw/mycorrhiza/l18n" //line views/readers.qtpl:9 -import "github.com/bouncepaw/mycorrhiza/tree" +import "github.com/bouncepaw/mycorrhiza/mimetype" //line views/readers.qtpl:10 -import "github.com/bouncepaw/mycorrhiza/user" +import "github.com/bouncepaw/mycorrhiza/tree" //line views/readers.qtpl:11 +import "github.com/bouncepaw/mycorrhiza/user" + +//line views/readers.qtpl:12 import "github.com/bouncepaw/mycorrhiza/util" -//line views/readers.qtpl:13 +//line views/readers.qtpl:14 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line views/readers.qtpl:13 +//line views/readers.qtpl:14 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line views/readers.qtpl:13 +//line views/readers.qtpl:14 func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) { -//line views/readers.qtpl:13 +//line views/readers.qtpl:14 + qw422016.N().S(` +`) +//line views/readers.qtpl:16 + lc := l18n.FromRequest(rq) + +//line views/readers.qtpl:17 qw422016.N().S(`
-

Attachment of `) -//line views/readers.qtpl:16 - qw422016.N().S(beautifulLink(h.Name)) -//line views/readers.qtpl:16 +

`) +//line views/readers.qtpl:20 + qw422016.N().S(lc.Get("ui.attach_title", &l18n.Replacements{"name": beautifulLink(h.Name)})) +//line views/readers.qtpl:20 qw422016.N().S(`

`) -//line views/readers.qtpl:17 +//line views/readers.qtpl:21 if h.BinaryPath == "" { -//line views/readers.qtpl:17 +//line views/readers.qtpl:21 qw422016.N().S(` -

This hypha has no attachment, you can upload it here. What are attachments?

+

`) +//line views/readers.qtpl:22 + qw422016.E().S(lc.Get("ui.attach_empty")) +//line views/readers.qtpl:22 + qw422016.N().S(` `) +//line views/readers.qtpl:22 + qw422016.E().S(lc.Get("ui.attach_link")) +//line views/readers.qtpl:22 + qw422016.N().S(`

`) -//line views/readers.qtpl:19 +//line views/readers.qtpl:23 } else { -//line views/readers.qtpl:19 +//line views/readers.qtpl:23 qw422016.N().S(` -

You can manage the hypha's attachment on this page. What are attachments?

+

`) +//line views/readers.qtpl:24 + qw422016.E().S(lc.Get("ui.attach_tip")) +//line views/readers.qtpl:24 + qw422016.N().S(` `) +//line views/readers.qtpl:24 + qw422016.E().S(lc.Get("ui.attach_link")) +//line views/readers.qtpl:24 + qw422016.N().S(`

`) -//line views/readers.qtpl:21 +//line views/readers.qtpl:25 } -//line views/readers.qtpl:21 +//line views/readers.qtpl:25 qw422016.N().S(`
`) -//line views/readers.qtpl:25 +//line views/readers.qtpl:29 if h.BinaryPath != "" { -//line views/readers.qtpl:25 +//line views/readers.qtpl:29 qw422016.N().S(` `) -//line views/readers.qtpl:27 +//line views/readers.qtpl:31 mime := mimetype.FromExtension(path.Ext(h.BinaryPath)) fileinfo, err := os.Stat(h.BinaryPath) -//line views/readers.qtpl:28 +//line views/readers.qtpl:32 qw422016.N().S(` `) -//line views/readers.qtpl:29 +//line views/readers.qtpl:33 if err == nil { -//line views/readers.qtpl:29 +//line views/readers.qtpl:33 qw422016.N().S(`
- Stat - -

MIME type: `) -//line views/readers.qtpl:33 + `) +//line views/readers.qtpl:35 + qw422016.E().S(lc.Get("ui.attach_stat")) +//line views/readers.qtpl:35 + qw422016.N().S(` +

+

`) +//line views/readers.qtpl:37 + qw422016.E().S(lc.Get("ui.attach_stat_mime")) +//line views/readers.qtpl:37 + qw422016.N().S(` `) +//line views/readers.qtpl:37 qw422016.E().S(mime) -//line views/readers.qtpl:33 +//line views/readers.qtpl:37 qw422016.N().S(`

`) -//line views/readers.qtpl:35 +//line views/readers.qtpl:39 } -//line views/readers.qtpl:35 +//line views/readers.qtpl:39 qw422016.N().S(` `) -//line views/readers.qtpl:37 +//line views/readers.qtpl:41 if strings.HasPrefix(mime, "image/") { -//line views/readers.qtpl:37 +//line views/readers.qtpl:41 qw422016.N().S(`
- Include - -
img { `)
-//line views/readers.qtpl:41
+			`)
+//line views/readers.qtpl:43
+			qw422016.E().S(lc.Get("ui.attach_include"))
+//line views/readers.qtpl:43
+			qw422016.N().S(`
+			
+			
img { `)
+//line views/readers.qtpl:45
 			qw422016.E().S(h.Name)
-//line views/readers.qtpl:41
+//line views/readers.qtpl:45
 			qw422016.N().S(` }
`) -//line views/readers.qtpl:43 +//line views/readers.qtpl:47 } -//line views/readers.qtpl:43 +//line views/readers.qtpl:47 qw422016.N().S(` `) -//line views/readers.qtpl:44 +//line views/readers.qtpl:48 } -//line views/readers.qtpl:44 +//line views/readers.qtpl:48 qw422016.N().S(` `) -//line views/readers.qtpl:46 +//line views/readers.qtpl:50 if u.CanProceed("upload-binary") { -//line views/readers.qtpl:46 +//line views/readers.qtpl:50 qw422016.N().S(` `) -//line views/readers.qtpl:59 +//line views/readers.qtpl:63 } -//line views/readers.qtpl:59 +//line views/readers.qtpl:63 qw422016.N().S(` `) -//line views/readers.qtpl:61 +//line views/readers.qtpl:65 if h.BinaryPath != "" && u.CanProceed("unattach-confirm") { -//line views/readers.qtpl:61 +//line views/readers.qtpl:65 qw422016.N().S(` `) -//line views/readers.qtpl:69 +//line views/readers.qtpl:73 } -//line views/readers.qtpl:69 +//line views/readers.qtpl:73 qw422016.N().S(`
`) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 } -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 func WriteAttachmentMenuHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) { -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 StreamAttachmentMenuHTML(qw422016, rq, h, u) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 } -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 func AttachmentMenuHTML(rq *http.Request, h *hyphae.Hypha, u *user.User) string { -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 WriteAttachmentMenuHTML(qb422016, rq, h, u) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 qs422016 := string(qb422016.B) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 return qs422016 -//line views/readers.qtpl:74 +//line views/readers.qtpl:78 } // If `contents` == "", a helpful message is shown instead. -//line views/readers.qtpl:77 -func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:77 +//line views/readers.qtpl:81 +func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) { +//line views/readers.qtpl:81 qw422016.N().S(` `) -//line views/readers.qtpl:79 +//line views/readers.qtpl:83 siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name) u := user.FromRequest(rq) -//line views/readers.qtpl:81 +//line views/readers.qtpl:85 qw422016.N().S(`
@@ -241,265 +318,273 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph
`) -//line views/readers.qtpl:88 +//line views/readers.qtpl:92 if u.CanProceed("edit") { -//line views/readers.qtpl:88 +//line views/readers.qtpl:92 qw422016.N().S(`
Edit text +//line views/readers.qtpl:93 + qw422016.N().S(`">`) +//line views/readers.qtpl:93 + qw422016.E().S(lc.Get("ui.edit_link")) +//line views/readers.qtpl:93 + qw422016.N().S(`
`) -//line views/readers.qtpl:90 +//line views/readers.qtpl:94 } -//line views/readers.qtpl:90 +//line views/readers.qtpl:94 qw422016.N().S(` `) -//line views/readers.qtpl:91 +//line views/readers.qtpl:95 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:91 +//line views/readers.qtpl:95 qw422016.N().S(` `) -//line views/readers.qtpl:92 +//line views/readers.qtpl:96 if h.Exists { -//line views/readers.qtpl:92 +//line views/readers.qtpl:96 qw422016.N().S(` `) -//line views/readers.qtpl:93 +//line views/readers.qtpl:97 qw422016.N().S(contents) -//line views/readers.qtpl:93 +//line views/readers.qtpl:97 qw422016.N().S(` `) -//line views/readers.qtpl:94 +//line views/readers.qtpl:98 } else { -//line views/readers.qtpl:94 +//line views/readers.qtpl:98 qw422016.N().S(` `) -//line views/readers.qtpl:95 - streamnonExistentHyphaNotice(qw422016, h, u) -//line views/readers.qtpl:95 +//line views/readers.qtpl:99 + streamnonExistentHyphaNotice(qw422016, h, u, lc) +//line views/readers.qtpl:99 qw422016.N().S(` `) -//line views/readers.qtpl:96 +//line views/readers.qtpl:100 } -//line views/readers.qtpl:96 +//line views/readers.qtpl:100 qw422016.N().S(`
`) -//line views/readers.qtpl:99 +//line views/readers.qtpl:103 if prevHyphaName != "" { -//line views/readers.qtpl:99 +//line views/readers.qtpl:103 qw422016.N().S(` `) -//line views/readers.qtpl:101 +//line views/readers.qtpl:105 } -//line views/readers.qtpl:101 +//line views/readers.qtpl:105 qw422016.N().S(` `) -//line views/readers.qtpl:102 +//line views/readers.qtpl:106 if nextHyphaName != "" { -//line views/readers.qtpl:102 +//line views/readers.qtpl:106 qw422016.N().S(` `) -//line views/readers.qtpl:104 +//line views/readers.qtpl:108 } -//line views/readers.qtpl:104 +//line views/readers.qtpl:108 qw422016.N().S(`
`) -//line views/readers.qtpl:106 - StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:106 +//line views/readers.qtpl:110 + StreamSubhyphaeHTML(qw422016, subhyphae, lc) +//line views/readers.qtpl:110 qw422016.N().S(`
`) -//line views/readers.qtpl:111 +//line views/readers.qtpl:115 streamhyphaInfo(qw422016, rq, h) -//line views/readers.qtpl:111 +//line views/readers.qtpl:115 qw422016.N().S(`
`) -//line views/readers.qtpl:114 - streamsiblingHyphaeHTML(qw422016, siblings) -//line views/readers.qtpl:114 +//line views/readers.qtpl:118 + streamsiblingHyphaeHTML(qw422016, siblings, lc) +//line views/readers.qtpl:118 qw422016.N().S(` `) -//line views/readers.qtpl:116 +//line views/readers.qtpl:120 streamviewScripts(qw422016) -//line views/readers.qtpl:116 - qw422016.N().S(` -`) -//line views/readers.qtpl:117 -} - -//line views/readers.qtpl:117 -func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) { -//line views/readers.qtpl:117 - qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:117 - StreamHyphaHTML(qw422016, rq, h, contents) -//line views/readers.qtpl:117 - qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:117 -} - -//line views/readers.qtpl:117 -func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string { -//line views/readers.qtpl:117 - qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:117 - WriteHyphaHTML(qb422016, rq, h, contents) -//line views/readers.qtpl:117 - qs422016 := string(qb422016.B) -//line views/readers.qtpl:117 - qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:117 - return qs422016 -//line views/readers.qtpl:117 -} - -//line views/readers.qtpl:119 -func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:119 +//line views/readers.qtpl:120 qw422016.N().S(` `) //line views/readers.qtpl:121 +} + +//line views/readers.qtpl:121 +func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) { +//line views/readers.qtpl:121 + qw422016 := qt422016.AcquireWriter(qq422016) +//line views/readers.qtpl:121 + StreamHyphaHTML(qw422016, rq, lc, h, contents) +//line views/readers.qtpl:121 + qt422016.ReleaseWriter(qw422016) +//line views/readers.qtpl:121 +} + +//line views/readers.qtpl:121 +func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) string { +//line views/readers.qtpl:121 + qb422016 := qt422016.AcquireByteBuffer() +//line views/readers.qtpl:121 + WriteHyphaHTML(qb422016, rq, lc, h, contents) +//line views/readers.qtpl:121 + qs422016 := string(qb422016.B) +//line views/readers.qtpl:121 + qt422016.ReleaseByteBuffer(qb422016) +//line views/readers.qtpl:121 + return qs422016 +//line views/readers.qtpl:121 +} + +//line views/readers.qtpl:123 +func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) { +//line views/readers.qtpl:123 + qw422016.N().S(` +`) +//line views/readers.qtpl:125 siblings, subhyphae, _, _ := tree.Tree(h.Name) -//line views/readers.qtpl:122 +//line views/readers.qtpl:126 qw422016.N().S(`
-

Please note that viewing attachments of hyphae is not supported in history for now.

+

`) +//line views/readers.qtpl:130 + qw422016.E().S(lc.Get("ui.revision_warning")) +//line views/readers.qtpl:130 + qw422016.N().S(`

`) -//line views/readers.qtpl:127 +//line views/readers.qtpl:131 qw422016.N().S(NaviTitleHTML(h)) -//line views/readers.qtpl:127 +//line views/readers.qtpl:131 qw422016.N().S(` `) -//line views/readers.qtpl:128 +//line views/readers.qtpl:132 qw422016.N().S(contents) -//line views/readers.qtpl:128 +//line views/readers.qtpl:132 qw422016.N().S(`
`) -//line views/readers.qtpl:130 - StreamSubhyphaeHTML(qw422016, subhyphae) -//line views/readers.qtpl:130 +//line views/readers.qtpl:134 + StreamSubhyphaeHTML(qw422016, subhyphae, lc) +//line views/readers.qtpl:134 qw422016.N().S(`
`) -//line views/readers.qtpl:132 - streamsiblingHyphaeHTML(qw422016, siblings) -//line views/readers.qtpl:132 +//line views/readers.qtpl:136 + streamsiblingHyphaeHTML(qw422016, siblings, lc) +//line views/readers.qtpl:136 qw422016.N().S(`
`) -//line views/readers.qtpl:134 +//line views/readers.qtpl:138 streamviewScripts(qw422016) -//line views/readers.qtpl:134 +//line views/readers.qtpl:138 qw422016.N().S(` `) -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 } -//line views/readers.qtpl:135 -func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) { -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 +func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) { +//line views/readers.qtpl:139 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:135 - StreamRevisionHTML(qw422016, rq, h, contents, revHash) -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 + StreamRevisionHTML(qw422016, rq, lc, h, contents, revHash) +//line views/readers.qtpl:139 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 } -//line views/readers.qtpl:135 -func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) string { -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 +func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) string { +//line views/readers.qtpl:139 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:135 - WriteRevisionHTML(qb422016, rq, h, contents, revHash) -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 + WriteRevisionHTML(qb422016, rq, lc, h, contents, revHash) +//line views/readers.qtpl:139 qs422016 := string(qb422016.B) -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 return qs422016 -//line views/readers.qtpl:135 +//line views/readers.qtpl:139 } -//line views/readers.qtpl:137 +//line views/readers.qtpl:141 func streamviewScripts(qw422016 *qt422016.Writer) { -//line views/readers.qtpl:137 +//line views/readers.qtpl:141 qw422016.N().S(` `) -//line views/readers.qtpl:138 +//line views/readers.qtpl:142 for _, scriptPath := range cfg.ViewScripts { -//line views/readers.qtpl:138 +//line views/readers.qtpl:142 qw422016.N().S(` `) -//line views/readers.qtpl:140 +//line views/readers.qtpl:144 } -//line views/readers.qtpl:140 +//line views/readers.qtpl:144 qw422016.N().S(` `) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 } -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 func writeviewScripts(qq422016 qtio422016.Writer) { -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 streamviewScripts(qw422016) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 qt422016.ReleaseWriter(qw422016) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 } -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 func viewScripts() string { -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 qb422016 := qt422016.AcquireByteBuffer() -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 writeviewScripts(qb422016) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 qs422016 := string(qb422016.B) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 qt422016.ReleaseByteBuffer(qb422016) -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 return qs422016 -//line views/readers.qtpl:141 +//line views/readers.qtpl:145 } diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 644484b..0a70705 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -3,10 +3,11 @@ {% import "github.com/bouncepaw/mycorrhiza/hyphae" %} {% import "github.com/bouncepaw/mycorrhiza/user" %} {% import "github.com/bouncepaw/mycorrhiza/util" %} +{% import "github.com/bouncepaw/mycorrhiza/l18n" %} -{% func BaseHTML(title, body string, u *user.User, headElements ...string) %} +{% func BaseHTML(title, body string, lc *l18n.Localizer, u *user.User, headElements ...string) %} - + @@ -27,7 +28,7 @@
  • @@ -35,19 +36,19 @@ @@ -73,7 +74,7 @@

    - +
    @@ -85,11 +86,11 @@ {% endfunc %} -{% func TitleSearchHTML(query string, generator func(string) <-chan string) %} +{% func TitleSearchHTML(query string, generator func(string) <-chan string, lc *l18n.Localizer) %}
    -

    Search results for ‘{%s query %}’

    -

    Every hypha name has been compared with the query. Hyphae that have matched the query are listed below.

    +

    {%s lc.Get("ui.search_results_query", &l18n.Replacements{"query": query})%}

    +

    {%s lc.Get("ui.search_results_desc")%}