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) %}
Name | -Group | -Registered 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") %} | {% endfor %} @@ -80,31 +82,31 @@ {% endfunc %} -{% func AdminUserNewHTML(f util.FormData) %} +{% func AdminUserNewHTML(f util.FormData, lc *l18n.Localizer) %}
---|