1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-13 05:50:27 +00:00

Add locale system

This commit is contained in:
Timur Ismagilov 2020-07-18 22:23:56 +05:00
parent 3a04f7e80a
commit 02f6a74c91
19 changed files with 379 additions and 65 deletions

View File

@ -6,6 +6,8 @@ import (
"log"
"os"
"path/filepath"
"github.com/bouncepaw/mycorrhiza/plugin/lang"
)
type MyceliumConfig struct {
@ -23,20 +25,18 @@ const (
)
var (
DescribeHyphaHerePattern = "Describe %s here"
WikiDir string
configJsonPath string
Locale map[string]string
WikiDir string
configJsonPath string
// Default values that can be overriden in config.json
Address = "0.0.0.0:80"
TitleEditTemplate = `Edit %s`
TitleTemplate = `%s`
GenericErrorMsg = `<b>Sorry, something went wrong</b>`
SiteTitle = `MycorrhizaWiki`
Theme = `default-light`
HomePage = `/Home`
BinaryLimit int64 = 10 << 20
Mycelia = []MyceliumConfig{
Address = "0.0.0.0:80"
LocaleName = "en"
SiteTitle = `MycorrhizaWiki`
Theme = `default-light`
HomePage = `/Home`
BinaryLimit int64 = 10 << 20
Mycelia = []MyceliumConfig{
{[]string{"main"}, "main"},
{[]string{"sys", "system"}, "system"},
}
@ -63,16 +63,13 @@ func readConfig() bool {
}
cfg := struct {
Address string `json:"address"`
Theme string `json:"theme"`
SiteTitle string `json:"site-title"`
HomePage string `json:"home-page"`
BinaryLimitMB int64 `json:"binary-limit-mb"`
Mycelia []MyceliumConfig `json:"mycelia"`
TitleTemplates struct {
EditHypha string `json:"edit-hypha"`
ViewHypha string `json:"view-hypha"`
} `json:"title-templates"`
Address string `json:"address"`
Theme string `json:"theme"`
SiteTitle string `json:"site-title"`
HomePage string `json:"home-page"`
BinaryLimitMB int64 `json:"binary-limit-mb"`
LocaleName string `json:"locale"`
Mycelia []MyceliumConfig `json:"mycelia"`
}{}
err = json.Unmarshal(configJsonContents, &cfg)
@ -84,11 +81,16 @@ func readConfig() bool {
Address = cfg.Address
Theme = cfg.Theme
SiteTitle = cfg.SiteTitle
TitleEditTemplate = cfg.TitleTemplates.EditHypha
TitleTemplate = cfg.TitleTemplates.ViewHypha
HomePage = "/" + cfg.HomePage
BinaryLimit = 1024 * cfg.BinaryLimitMB
Mycelia = cfg.Mycelia
switch cfg.LocaleName {
case "en":
Locale = lang.EnglishMap
default:
Locale = lang.EnglishMap
}
return true
}

View File

@ -82,5 +82,5 @@ func (h *Hypha) TextContent() string {
}
return string(contents)
}
return fmt.Sprintf(cfg.DescribeHyphaHerePattern, h.FullName)
return fmt.Sprintf(cfg.Locale["edit/box/help pattern"], h.FullName)
}

View File

@ -60,7 +60,7 @@ func main() {
r := mux.NewRouter()
r.HandleFunc("/favicon.ico", func(w http.ResponseWriter, rq *http.Request) {
http.ServeFile(w, rq, filepath.Join(filepath.Dir(cfg.WikiDir), "favicon.ico"))
http.ServeFile(w, rq, filepath.Join(cfg.WikiDir, "favicon.ico"))
})
IdempotentRouterBoiler(r, "binary", HandlerBinary)

31
plugin/lang/en.go Normal file
View File

@ -0,0 +1,31 @@
package lang
var EnglishMap = map[string]string{
"edit hypha title template": "Edit %s at MycorrhizaWiki",
"view hypha title template": "%s at MycorrhizaWiki",
"this site runs myco wiki": `<p>This website runs <a href="https://github.com/bouncepaw/mycorrhiza">MycorrhizaWiki</a></p>`,
"generic error msg": `<b>Sorry, something went wrong</b>`,
"edit/text mime type": "Text MIME-type",
"edit/text mime type/tip": "We support <code>text/markdown</code>, <code>text/creole</code> and <code>text/gemini</code>",
"edit/revision comment": "Revision comment",
"edit/revision comment/tip": "Please make your comment helpful",
"edit/revision comment/new": "Create %s",
"edit/revision comment/old": "Update %s",
"edit/tags": "Edit tags",
"edit/tags/tip": "Tags are separated by commas, whitespace is ignored",
"edit/upload file": "Upload file",
"edit/upload file/tip": "Only images are fully supported for now",
"edit/box": "Edit box",
"edit/box/title": "Edit %s",
"edit/box/help pattern": "Describe %s here",
"edit/cancel": "Cancel",
"update ok/title": "Saved %s",
"update ok/msg": "Saved successfully. <a href='/%s'>Go back</a>",
}

View File

@ -11,59 +11,59 @@ import (
"github.com/bouncepaw/mycorrhiza/mycelium"
)
func titleTemplateView(name string) string {
return fmt.Sprintf(cfg.Locale["view hypha title template"], name)
}
// HyphaEdit renders hypha editor.
func HyphaEdit(h *fs.Hypha) []byte { //
hyphaData := map[string]string{
hyphaData := map[string]interface{}{
"Name": h.FullName,
"Tags": h.TagsJoined(),
"TextMime": h.TextMime(),
"Text": h.TextContent(),
"Locale": cfg.Locale,
}
return layout("edit/index").
withMap(hyphaData).
wrapInBase(map[string]string{
"Title": fmt.Sprintf(cfg.TitleEditTemplate, h.FullName),
"Title": fmt.Sprintf(cfg.Locale["edit hypha title template"], h.FullName),
})
}
// HyphaUpdateOk is used to inform that update was successful.
func HyphaUpdateOk(h *fs.Hypha) []byte { //
return layout("update_ok").
withMap(map[string]string{"Name": h.FullName}).
withMap(map[string]interface{}{
"Name": h.FullName,
"Locale": cfg.Locale,
}).
Bytes()
}
// Hypha404 renders 404 page for nonexistent page.
func Hypha404(name, _ string) []byte {
return layout("view/404").
withMap(map[string]string{
withMap(map[string]interface{}{
"PageTitle": name,
"Tree": hyphaTree(name),
"Locale": cfg.Locale,
}).
wrapInBase(map[string]string{
"Title": fmt.Sprintf(cfg.TitleTemplate, name),
"Title": titleTemplateView(name),
})
}
// HyphaPage renders hypha viewer.
func HyphaPage(name, content string) []byte {
return layout("view/index").
withMap(map[string]string{
withMap(map[string]interface{}{
"Content": content,
"Tree": hyphaTree(name),
"Locale": cfg.Locale,
}).
wrapInBase(map[string]string{
"Title": fmt.Sprintf(cfg.TitleTemplate, name),
})
}
// hyphaGeneric is used when building renderers for all types of hypha pages
func hyphaGeneric(name, content, templateName string) []byte {
return layout(templateName).
withString(content).
wrapInBase(map[string]string{
"Title": fmt.Sprintf(cfg.TitleTemplate, name),
"Sidebar": hyphaTree(name),
"Title": titleTemplateView(name),
})
}
@ -72,9 +72,10 @@ func (lyt *Layout) wrapInBase(keys map[string]string) []byte {
if lyt.invalid {
return lyt.Bytes()
}
page := map[string]string{
"Title": cfg.SiteTitle,
page := map[string]interface{}{
"Content": lyt.String(),
"Locale": cfg.Locale,
"Title": cfg.SiteTitle,
"SiteTitle": cfg.SiteTitle,
}
for key, val := range keys {
@ -122,7 +123,7 @@ func (lyt *Layout) withString(data string) *Layout {
return lyt
}
func (lyt *Layout) withMap(data map[string]string) *Layout {
func (lyt *Layout) withMap(data map[string]interface{}) *Layout {
if lyt.invalid {
return lyt
}

View File

@ -4,10 +4,7 @@
"site-title": "🍄 MycorrhizaWiki",
"home-page": "Home",
"binary-limit-mb": 10,
"title-templates": {
"edit-hypha": "Edit %s at MycorrhizaWiki",
"view-hypha": "%s at MycorrhizaWiki"
},
"locale": "en",
"mycelia": [
{
"names": ["main"],

View File

@ -0,0 +1,27 @@
# Plugin system RFC
MycorrhizaWiki engine does not provide all the functionality a wiki may need and not need. Instead, it relies on the system of plugins.
This document is up-to-date.
## Types of plugins
- **Parser.** They add support for displaying different MIME-types.
- **Language.** They provide i18n support.
## Default plugins
Default MycorrhizaWiki distributive is shipped with several plugins installed.
- **parser/markdown.** Support for `text/markdown`. This parser is powered by [russross/blackfriday](https://github.com/russross/blackfriday); this parser is ok, I guess.
- **parser/creole.** Support for `text/creole`. *Note:* there is no standard Creole MIME type. This parser is powered by [m4tty/cajun](https://github.com/m4tty/cajun); this library is somewhat outdated. Perhaps we'll reimplement it.
- **parser/gemini.** Support for `text/gemini`.
- **language/en.** Support for English language.
## Plugin implementation
All plugins are written in Go and are compiled together with MycorrhizaWiki. If a wiki's admin decides to add a plugin, they shall recompile the engine with the plugin.
> Reminds of [something](http://suckless.org/), right?
*But compiling the engine just to add a plugin is stupid!!* Not really. Also, it makes the architecture more simple and secure.
*What if an admin doesn't know how to program?* Plugin installation is basically limited to putting some files into a folder, editing the config and running a shell command. No programming required to install a plugin.
See `plugin` directory at the root of the repo to get inspired by the present parsers.

View File

@ -0,0 +1,27 @@
# Plugin system RFC
MycorrhizaWiki engine does not provide all the functionality a wiki may need and not need. Instead, it relies on the system of plugins.
This document is up-to-date.
## Types of plugins
- **Parser.** They add support for displaying different MIME-types.
- **Language.** They provide i18n support.
## Default plugins
Default MycorrhizaWiki distributive is shipped with several plugins installed.
- **parser/markdown.** Support for `text/markdown`. This parser is powered by [russross/blackfriday](https://github.com/russross/blackfriday); this parser is ok, I guess.
- **parser/creole.** Support for `text/creole`. *Note:* there is no standard Creole MIME type. This parser is powered by [m4tty/cajun](https://github.com/m4tty/cajun); this library is somewhat outdated. Perhaps we'll reimplement it.
- **parser/gemini.** Support for `text/gemini`.
- **lang/en.** Support for English language.
## Plugin implementation
All plugins are written in Go and are compiled together with MycorrhizaWiki. If a wiki's admin decides to add a plugin, they shall recompile the engine with the plugin.
> Reminds of [something](http://suckless.org/), right?
*But compiling the engine just to add a plugin is stupid!!* Not really. Also, it makes the architecture more simple and secure.
*What if an admin doesn't know how to program?* Plugin installation is basically limited to putting some files into a folder, editing the config and running a shell command. No programming required to install a plugin.
See `plugin` directory at the root of the repo to get inspired by the present parsers.

View File

@ -0,0 +1,32 @@
# Plugin system RFC
MycorrhizaWiki engine does not provide all the functionality a wiki may need and not need. Instead, it relies on the system of plugins.
This document is up-to-date.
## Types of plugins
- **Parser.** They add support for displaying different MIME-types.
- **Language.** They provide i18n support.
## Default plugins
Default MycorrhizaWiki distributive is shipped with several plugins installed.
- **parser/markdown.** Support for `text/markdown`. This parser is powered by [russross/blackfriday](https://github.com/russross/blackfriday); this parser is ok, I guess.
- **parser/creole.** Support for `text/creole`. *Note:* there is no standard Creole MIME type. This parser is powered by [m4tty/cajun](https://github.com/m4tty/cajun); this library is somewhat outdated. Perhaps we'll reimplement it.
- **parser/gemini.** Support for `text/gemini`.
- **lang/en.** Support for English language.
## Plugin implementation
All plugins are written in Go and are compiled together with MycorrhizaWiki. If a wiki's admin decides to add a plugin, they shall recompile the engine with the plugin.
> Reminds of [something](http://suckless.org/), right?
*But compiling the engine just to add a plugin is stupid!!* Not really. Also, it makes the architecture more simple and secure.
*What if an admin doesn't know how to program?* Plugin installation is basically limited to putting some files into a folder, editing the config and running a shell command. No programming required to install a plugin.
See `plugin` directory at the root of the repo to get inspired by the present parsers.
## Possible future plugins
- **Utilites.** Plugins that can do different things and provide their own hypha interface in `:spec` mycelium.
- **Macros.** Dynamic content parts that are generated when page is accessed: TOC, meta information accessors, etc.

View File

@ -0,0 +1,32 @@
# Plugin system RFC
MycorrhizaWiki engine does not provide all the functionality a wiki may need and not need. Instead, it relies on the system of plugins.
This document is up-to-date.
## Types of plugins
- **Parser.** They add support for displaying different MIME-types.
- **Language.** They provide i18n support.
## Default plugins
Default MycorrhizaWiki distributive is shipped with several plugins installed.
- **parser/markdown.** Support for `text/markdown`. This parser is powered by [russross/blackfriday](https://github.com/russross/blackfriday); this parser is ok, I guess.
- **parser/creole.** Support for `text/creole`. *Note:* there is no standard Creole MIME type. This parser is powered by [m4tty/cajun](https://github.com/m4tty/cajun); this library is somewhat outdated. Perhaps we'll reimplement it.
- **parser/gemini.** Support for `text/gemini`.
- **lang/en.** Support for English language.
## Plugin implementation
All plugins are written in Go and are compiled together with MycorrhizaWiki. If a wiki's admin decides to add a plugin, they shall recompile the engine with the plugin.
> Reminds of [something](http://suckless.org/), right?
*But compiling the engine just to add a plugin is stupid!!* Not really. Also, it makes the architecture more simple and secure.
*What if an admin doesn't know how to program?* Plugin installation is basically limited to putting some files into a folder, editing the config and running a shell command. No programming required to install a plugin.
See `plugin` directory at the root of the repo to get inspired by the present parsers.
## Possible future plugins
- **Utilites.** Plugins that can do different things and provide their own hypha interface in `:spec` mycelium.
- **Macros.** Dynamic content parts that are generated when page is accessed: TOC, meta information accessors, etc.

View File

@ -27,6 +27,58 @@
"binary_mime": "",
"text_name": "2.markdown",
"binary_name": ""
},
"3": {
"tags": [
""
],
"name": "Plugin",
"comment": "Update :Main/Doc/Plugin",
"author": "",
"time": 1594999571,
"text_mime": "text/markdown",
"binary_mime": "",
"text_name": "3.markdown",
"binary_name": ""
},
"4": {
"tags": [
""
],
"name": "Plugin",
"comment": "Update :Main/Doc/Plugin",
"author": "",
"time": 1595001530,
"text_mime": "text/markdown",
"binary_mime": "",
"text_name": "4.markdown",
"binary_name": ""
},
"5": {
"tags": [
""
],
"name": "Plugin",
"comment": "Update :Main/Doc/Plugin",
"author": "",
"time": 1595092102,
"text_mime": "text/markdown",
"binary_mime": "",
"text_name": "5.markdown",
"binary_name": ""
},
"6": {
"tags": [
""
],
"name": "Plugin",
"comment": "Update :Main/Doc/Plugin",
"author": "",
"time": 1595092219,
"text_mime": "text/markdown",
"binary_mime": "",
"text_name": "6.markdown",
"binary_name": ""
}
}
}

7
wiki/main/doc/user/1.txt Normal file
View File

@ -0,0 +1,7 @@
Unlike earliest wiki engines, MycorrhizaWiki supports authorization system and non-authorized edits are disabled by default. Anyone can get an account on a MycorrhizaWiki wiki by signing up. There must be a form for that.
* Each user is part of one or more user groups.
* Each user has a username. Usernames follow the same naming conventions as hyphae but additionally the forward slash / character is prohibited in usernames. Please note that usernames are case-insensitive, thus //shroom// and //Shroom// mean the same; spaces and underscores are also the same, //amanita muscaria// = //amanita_muscaria//.
* Password chosen by the user is not directly stored on the server. Only its hash is salted so even if a server is hacked, a hacker won't get the passwords. There are no restrictions on passwords. Server administrator doesn't have access to the password as well.
* Each user gets their own hypha in the //:user// mycelium. The hypha has the same name as the user. Subhyphae can also be added.
* If an authenticated user makes an edit, the fact that they have made the edit is stored in the revision history.

9
wiki/main/doc/user/2.txt Normal file
View File

@ -0,0 +1,9 @@
This document is not up-to-date. Information here will be true once we finish its development :)
Unlike earliest wiki engines, MycorrhizaWiki supports authorization system and non-authorized edits are disabled by default. Anyone can get an account on a MycorrhizaWiki wiki by signing up. There must be a form for that.
* Each user is part of one or more user groups.
* Each user has a username. Usernames follow the same naming conventions as hyphae but additionally the forward slash / character is prohibited in usernames. Please note that usernames are case-insensitive, thus //shroom// and //Shroom// mean the same; spaces and underscores are also the same, //amanita muscaria// = //amanita_muscaria//.
* Password chosen by the user is not directly stored on the server. Only its hash is salted so even if a server is hacked, a hacker won't get the passwords. There are no restrictions on passwords. Server administrator doesn't have access to the password as well.
* Each user gets their own hypha in the //:user// mycelium. The hypha has the same name as the user. Subhyphae can also be added.
* If an authenticated user makes an edit, the fact that they have made the edit is stored in the revision history.

View File

@ -0,0 +1,32 @@
{
"views": 0,
"deleted": false,
"revisions": {
"1": {
"tags": [
""
],
"name": "User",
"comment": "Update :Main/Doc/User",
"author": "",
"time": 1594749111,
"text_mime": "text/creole",
"binary_mime": "",
"text_name": "1.txt",
"binary_name": ""
},
"2": {
"tags": [
""
],
"name": "User",
"comment": "Update :Main/Doc/User",
"author": "",
"time": 1595092543,
"text_mime": "text/creole",
"binary_mime": "",
"text_name": "2.txt",
"binary_name": ""
}
}
}

View File

@ -0,0 +1,51 @@
# Wikilink RFC
*This page is not up-to-date. One day, features defined here shall be implemented.*
All parsers for MycorrhizaWiki provide hyperlink support. Usually, they follow HTML convention.
- `http://example.org/absolute-path`
- `/rooted-path`
- `same-folder-path`
- `../parent-folder-path`
This is not really convenient for wikis where most of links are either rooted or links to children!
All parsers of MycorrhizaWiki are expected to support these types of links and convert them to rooted paths.
- `http://example.org/absolute-path`
- `hypha in main mycelium`
- `::hypha in the same mycelium`
- `:mycelium/hypha in an explicit mycelium`
- `/subhypha`
- `./subhypha`
- `../sibling-hypha`
**TODO:** create a package that implements this thing. NB: to generate a correct link, it is required to know full name of hypha where the link is used.
## Markdown extension
> This is an extension to markdown's syntax that is used in MycorrhizaWiki and nowhere else.
Text wrapped in `[[` and `]]` is a link that has same text and url. *For some reason it's not possible in Markdown without duplicating url*
```
[[x]] == [x](x)
```
## Examples
All examples assume that `:example/test` is the current hypha.
```
wikilink actual path
foo == /foo
::foo == /:example/foo
:bar/foo == /:bar/foo
/baz == /:example/test/baz
./baz == /:example/test/baz
../qux == /:example/qux
http://example.org == http://example.org
gemini://example.org == gemini://example.org
mailto:me@example.org == mailto:me@example.org
```

View File

@ -27,6 +27,19 @@
"binary_mime": "",
"text_name": "2.markdown",
"binary_name": ""
},
"3": {
"tags": [
""
],
"name": "Wikilink",
"comment": "Update :Main/Doc/Wikilink",
"author": "",
"time": 1595092265,
"text_mime": "text/markdown",
"binary_mime": "",
"text_name": "3.markdown",
"binary_name": ""
}
}
}

View File

@ -17,7 +17,7 @@
<!-- <main> and <aside> are in .Content -->
{{ .Content }}
<footer>
<p>This website runs <a href='https://github.com/bouncepaw/mycorrhiza'>MycorrhizaWiki</a></p>
{{index .Locale "this site runs mycowiki"}}
</footer>
<script src="/:sys/theme/default-light/main.js?action=raw"></script>
</body>

View File

@ -5,38 +5,39 @@
id="edit-form">
<aside class="sidebar hidden_mobile" id="sidebar"><!-- TODO: i18n -->
<fieldset><!-- TODO: make this thing work with radiobuttons that are generated automatically for all supported mimes -->
<legend>Text MIME-type</legend>
<p>Good types are <code>text/markdown</code> and <code>text/plain</code></p>
<legend>{{index .Locale "edit/text mime type"}}</legend>
<p>{{index .Locale "edit/text mime type/tip"}}
<input type="text" name="text_mime" value="{{ .TextMime }}" id="text_mime"/>
</fieldset>
<fieldset>
<legend>Revision comment</legend>
<p>Please make your comment helpful</p>
<input type="text" name="comment" value="Update {{ .Name }}" id="comment"/>
<legend>{{index .Locale "edit/revision comment"}}</legend>
<p>{{index .Locale "edit/revision comment/tip"}}</p>
<input type="text" name="comment" id="comment"
value='{{printf (index .Locale "edit/revision comment/old") .Name}}'/>
</fieldset>
<fieldset>
<legend>Edit tags</legend>
<p>Tags are separated by commas, whitespace is ignored</p>
<legend>{{index .Locale "edit/tags"}}</legend>
<p>{{index .Locale "edit/tags/tip"}}</p>
<input type="text" name="tags" value="{{ .Tags }}" id="tags"/>
</fieldset>
<fieldset>
<legend>Upload file</legend>
<p>Only images are supported for now</p>
<legend>{{index .Locale "edit/upload file"}}</legend>
<p>{{index .Locale "edit/upload file/tip"}}</p>
<input type="file" name="binary" id="binary"/>
</fieldset>
<p>
<input type="submit" value="update" form="edit-form"/>
<a href="?">Cancel</a>
<a href="?">{{index .Locale "edit/cancel"}}</a>
</p>
</aside>
<main class="main">
<h1 class="page__title">Edit {{ .Name }}</h1>
<h1 class="page__title">{{printf (index .Locale "edit/box/title") .Name}}</h1>
<fieldset>
<legend>Edit box</legend>
<legend>{{index .Locale "edit/box"}}</legend>
<textarea class="edit-box__text" name="text">{{ .Text }}</textarea>
</fieldset>
</main>

View File

@ -1,9 +1,9 @@
<html>
<head>
<title>Saved {{ .Name }}</title>
<title>{{printf (index .Locale "update ok/title") .Name}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p>Saved successfully. <a href="/{{ .Name }}">Go back</a></p>
<p>{{printf (index .Locale "update ok/msg") .Name}}</p>
</body>
</html>