Compare commits

..

5 Commits
main ... main

Author SHA1 Message Date
mio 3e3c8feef2 Fix truncated character in titles on index page 2023-07-16 00:03:38 +00:00
mio f47f31cf14 Add Esperanto translation (thanks wsinatra) 2022-08-09 04:13:37 +00:00
mio 4e1afaa621 Update lang files and readme
- Revise lang files: use `string.format()`, clean up template and
  message placeholders, include comments for translated lines
  (thanks to lucidiot for FR translation and suggestions)
- Clarify dependencies in build instructions
2022-08-07 00:14:10 +00:00
mio 9450de7fc3 Merge pull request 'Add French translation' (#1) from lucidiot/gemwriter:français into main
Reviewed-on: http://git.tilde.town/mio/gemwriter/pulls/1
2022-08-05 22:33:17 +00:00
lucidiot 75e9c66b52 Add French translation 2022-08-05 22:06:38 +00:00
8 changed files with 589 additions and 205 deletions

16
env.lua
View File

@ -5,7 +5,7 @@ env.app = {
name = "gemwriter",
exec_name = "gemwriter",
version = "0.3",
last_updated = "2022-08-05",
last_updated = "2022-08-06",
}
env.defaults = {
@ -18,6 +18,7 @@ env.defaults = {
page = "page.gmi",
post = "post.gmi",
},
lang_opts = { "en_US", "fr_FR" },
post_slug = "untitled",
post_slug_date_format = "%Y-%m-%d",
-- Atom feed date format
@ -27,13 +28,24 @@ env.defaults = {
page_slug = os.date("%Y%m%d-%H%M%S"),
}
-- Command-line keywords
env.cli_opts = {
config = "config",
page = "page",
post = "post",
index = "index",
publish = "publish",
help = "help",
version = "version",
}
-- Configurable settings
env.toml_vars = {
general = "general",
capsules = "capsules",
}
env.general = {
app_lang = "en",
app_lang = "en_US",
main_capsule = "main",
}
env.capsules = {

View File

@ -1,5 +1,5 @@
local env = require("env")
local lang = require("lang.en")
local lang = require("lang.en_US")
local util = require("util")
@ -8,11 +8,32 @@ writer.docs = {}
writer.conf = {}
writer.posts = {}
writer.docs.get_lang_opts = [[
Return a table of available language translations for the app interface.
]]
function writer.get_lang_opts()
local lang_opts = {}
for l = 1, #env.defaults.lang_opts do
if util.module_exists("lang." .. env.defaults.lang_opts[l]) then
table.insert(lang_opts, env.defaults.lang_opts[l])
end
end
return lang_opts
end
writer.docs.gen_config = [[
Generate a default config directory.
]]
function writer.gen_config()
writer.conf.config_dir = util.replace_shell_vars(env.defaults.config_dir)
function writer.gen_config(lang_pref)
-- Set lang
if lang_pref ~= nil and util.module_exists("lang." .. lang_pref) then
lang = require("lang." .. lang_pref)
env.defaults_toml = string.gsub(env.defaults_toml, env.general.app_lang,
lang_pref)
end
util.make_dir(writer.conf.config_dir)
for name, file in pairs(env.defaults.config_files) do
-- Check each file individually anyway to avoid overwriting existing
@ -106,7 +127,9 @@ function writer.parse_config(config_file)
end
-- Set lang
if util.module_exists("lang." .. writer.conf.app_lang) then
lang = require("lang." .. writer.conf.app_lang)
end
-- Custom templates override lang defaults (ignore config)
for name, file in pairs(env.defaults.config_files) do
@ -119,24 +142,9 @@ end
writer.docs.load_config = [[
Check whether there is an existing config and load it if found. Exit if a
capsule is not found.
Load an existing config. Exit if a capsule is not found.
]]
function writer.load_config(cap_id)
writer.conf.config_dir = util.replace_shell_vars(env.defaults.config_dir)
local config_file = util.read_file(writer.conf.config_dir .. "/" ..
env.defaults.config_files.config)
local config_new = false
-- No config found
if (config_file == "") and (not config_new) then
writer.gen_config()
config_new = true
end
-- Config found, read the configuration and load the values to an
-- associative table, writer.conf.
if (config_file ~= "") and (not config_new) then
-- Check capsule id exists, abort if no valid capsule found
if (cap_id == nil) or (string.find(cap_id, " ") ~= nil) then
writer.conf.cap_id = env.general.main_capsule
@ -145,14 +153,12 @@ function writer.load_config(cap_id)
end
local cap_label = "%[" .. env.toml_vars.capsules .. "%." ..
tostring(cap_id) .. "%]"
if (string.find(config_file, cap_label) == nil) and
if (string.find(writer.conf.config_file, cap_label) == nil) and
(writer.conf.cap_id ~= env.general.main_capsule) then
print(lang.errs.invalid_cap_id)
os.exit()
end
writer.parse_config(config_file)
end
writer.parse_config(writer.conf.config_file)
end
@ -348,40 +354,58 @@ cli.docs.handle_args = [[
any additional arguments to the functions.
]]
function cli.handle_args(args)
if (args[1] ~= lang.opts.help) and (args[1] ~= lang.opts.version) then
if (args[1] ~= env.cli_opts.help) or (args[1] ~= env.cli_opts.version) then
local config_new = false
writer.conf.config_dir = util.replace_shell_vars(env.defaults.config_dir)
writer.conf.config_file = util.read_file(writer.conf.config_dir .. "/" ..
env.defaults.config_files.config)
-- No config found
if (writer.conf.config_file == "") and (not config_new) then
writer.gen_config(args[2])
config_new = true
end
-- Config found, read the configuration and load the values to an
-- associative table, writer.conf.
if (writer.conf.config_file ~= "") and (not config_new) then
writer.load_config(args[2])
end
end
if (args[1] == lang.opts.index) or (args[1] == lang.opts.publish) then
if (args[1] == env.cli_opts.index) or (args[1] == env.cli_opts.publish) then
writer.posts = writer.get_posts_meta()
if writer.conf.cap.gen_index_page then writer.gen_index_page() end
if writer.conf.cap.gen_atom_feed then writer.gen_atom_feed() end
end
if args[1] == lang.opts.config then
writer.load_config()
print(lang.msgs.load_config .. writer.conf.config_dir)
if args[1] == env.cli_opts.config then
writer.gen_config(args[2])
print(string.format(lang.msgs.load_config, writer.conf.config_dir))
elseif (args[1] == lang.opts.post) or (args[1] == lang.opts.page) then
elseif (args[1] == env.cli_opts.post) or (args[1] == env.cli_opts.page) then
local file_name = ""
if args[3] ~= nil then
file_name = writer.add_gemtext(args[3], args[1])
else
file_name = writer.add_gemtext(args[2], args[1])
end
print(lang.msgs.add_gemtext .. file_name)
print(string.format(lang.msgs.add_gemtext, file_name))
elseif args[1] == lang.opts.index then
elseif args[1] == env.cli_opts.index then
print(lang.msgs.index)
elseif args[1] == lang.opts.publish then
elseif args[1] == env.cli_opts.publish then
writer.publish()
print(lang.msgs.publish)
elseif args[1] == lang.opts.help then
print(env.app.exec_name .. lang.msgs.help)
elseif args[1] == env.cli_opts.help then
print(string.format(lang.msgs.help_usage, env.app.exec_name) ..
string.format(lang.msgs.help_opts, env.cli_opts.config,
env.cli_opts.page, env.cli_opts.post, env.cli_opts.index,
env.cli_opts.publish, env.cli_opts.help, env.cli_opts.version) ..
string.format(lang.msgs.help_lang_opts,
table.concat(writer.get_lang_opts(), ", ")))
elseif args[1] == lang.opts.version then
elseif args[1] == env.cli_opts.version then
print(env.app.name .. " " .. env.app.version ..
" (" .. env.app.last_updated .. ")")
end

View File

@ -1,145 +0,0 @@
local en = {}
-- Templates
en.tpl_vars = {
post = {
author = "{{ post_author }}",
content = "{{ post_content }}",
date = "{{ post_date }}",
summary = "{{ post_summary }}",
tags = "{{ post_tags }}",
title = "{{ post_title }}",
url = "{{ post_url }}",
},
feed = {
date = "{{ feed_date }}",
url = "{{ feed_url }}",
},
index = {
posts = "{{ posts }}",
},
log = {
author = "{{ log_author }}",
subtitle = "{{ log_subtitle }}",
title = "{{ log_title }}",
log_url = "{{ log_url }}",
},
}
en.atom_header = [[<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ log_title }}</title>
<subtitle>{{ log_subtitle }}</subtitle>
<updated>{{ feed_date }}</updated>
<author>
<name>{{ log_author }}</name>
</author>
<id>{{ feed_url }}</id>
<link href="{{ log_url }}" rel="alternate"/>
<link href="{{ feed_url }}" rel="self" type="application/atom+xml"/>
]]
en.atom_entry = [[
<entry>
<id>{{ post_url }}</id>
<title>
<![CDATA[{{ post_title }}]] .. "]]>" .. [[
</title>
<updated>{{ post_date }}</updated>
<author>
<name>{{ post_author }}</name>
</author>
<link href="{{ post_url }}" rel="alternate"/>
<summary>
<![CDATA[{{ post_summary }}]] .. "]]>" .. [[
</summary>
<content>
<![CDATA[{{ post_content }}]] .. "]]>" .. [[
</content>
</entry>
]]
en.atom_footer = [[</feed>]]
en.post = [[---
date: {{ post_date }}
---
# {{ post_title }}
## Links
=> gemini:// link
=> gemini:// link (img)
=> https:// link (https)]]
en.index = [[
# {{ log_title }}
{{ posts }}
]]
en.page = [[
# {{ post_title }}
## Heading 2
### Heading 3
List:
*
*
*
```
Preformatted text
```
## Links
=> gemini:// link
=> gemini:// link (img)
=> https:// link (https)]]
-- App command options and messages output
en.opts = {
config = "config",
page = "page",
post = "post",
index = "index",
publish = "publish",
help = "help",
version = "version",
}
en.msgs = {
add_gemtext = "Created ",
help = [[ [options] [capsule] [title]
Options:
config Generate a config directory
page [capsule] [title] Add a new page with the given title
post [capsule] [title] Add a new gemlog post with the given title
index Generate an index page and feed of posts
publish Index and copy posts remotely using scp
help Show this help message
version Print version info]],
index = "Created index page and feed.",
load_config = [[Created config files. Please edit them with the correct
details before proceeding. The config files can be found at:
]],
publish = "Published capsule.",
}
en.errs = {
invalid_cap_id = "Error: unknown capsule id.",
}
return en

157
lang/en_US.lua 100644
View File

@ -0,0 +1,157 @@
local en = {}
-- Templates
en.tpl_vars = {
post = {
author = "{{ author }}",
content = "{{ content }}",
date = "{{ date }}",
summary = "{{ summary }}",
-- This is not used in the templates yet.
tags = "{{ tags }}",
title = "{{ title }}",
url = "{{ url }}",
},
feed = {
date = "{{ date }}",
url = "{{ feed_url }}",
},
index = {
posts = "{{ posts }}",
},
log = {
author = "{{ author }}",
subtitle = "{{ subtitle }}",
title = "{{ title }}",
url = "{{ log_url }}",
},
}
en.atom_header = [[<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ title }}</title>
<subtitle>{{ subtitle }}</subtitle>
<updated>{{ date }}</updated>
<author>
<name>{{ author }}</name>
</author>
<id>{{ feed_url }}</id>
<link href="{{ log_url }}" rel="alternate"/>
<link href="{{ feed_url }}" rel="self" type="application/atom+xml"/>
]]
en.atom_entry = [[
<entry>
<id>{{ url }}</id>
<title>
<![CDATA[{{ title }}]] .. "]]>" .. [[
</title>
<updated>{{ date }}</updated>
<author>
<name>{{ author }}</name>
</author>
<link href="{{ url }}" rel="alternate"/>
<summary>
<![CDATA[{{ summary }}]] .. "]]>" .. [[
</summary>
<content>
<![CDATA[{{ content }}]] .. "]]>" .. [[
</content>
</entry>
]]
en.atom_footer = [[</feed>]]
en.post = [[---
date: {{ date }}
---
# {{ title }}
## Links
=> gemini:// link
=> gemini:// link (img)
=> https:// link (https)]]
en.index = [[
# {{ title }}
{{ posts }}
]]
en.page = [[
# {{ title }}
## Heading 2
### Heading 3
List:
*
*
*
```
Preformatted text
```
## Links
=> gemini:// link
=> gemini:// link (img)
=> https:// link (https)]]
en.msgs = {}
-- %s: gemtext filename
en.msgs.add_gemtext = "Created %s."
-- %s: app executable name
en.msgs.help_usage = [[%s [options] [capsule] [title]
]]
-- %s: command-line options
-- (see env.lua env.cli_opts for the full list)
en.msgs.help_opts = [[
Options:
%s [lang] Generate a config directory
%s [capsule] [title] Add a new page with the given title
%s [capsule] [title] Add a new gemlog post with the given title
%s Generate an index page and feed of posts
%s Index and copy posts remotely using scp
%s Show this help message
%s Print version info
]]
-- %s: list of language codes
en.msgs.help_lang_opts = [[
Config language options:
%s]]
en.msgs.index = "Created index page and feed."
-- %s: config directory path
en.msgs.load_config = [[Created config files. Please edit them with the correct
details before proceeding. The config files can be found at:
%s]]
en.msgs.publish = "Published capsule."
en.errs = {
invalid_cap_id = "Error: unknown capsule id.",
}
return en

159
lang/eo.lua 100644
View File

@ -0,0 +1,159 @@
local eo = {}
-- Templates
eo.tpl_vars = {
post = {
author = "{{ aŭtoro }}",
content = "{{ entenaĵo }}",
date = "{{ dato }}",
summary = "{{ resumo }}",
-- This is not used in the templates yet.
tags = "{{ markoj }}",
title = "{{ titolo }}",
-- unuforma risurca lokindiko
url = "{{ url }}",
},
feed = {
date = "{{ dato }}",
url = "{{ XML-fluo_url }}",
},
index = {
posts = "{{ afiŝejo }}",
},
log = {
author = "{{ aŭtoro }}",
subtitle = "{{ subtitolo }}",
title = "{{ titolo }}",
url = "{{ protokolo_url }}",
},
}
eo.atom_header = [[<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ titolo }}</title>
<subtitle>{{ subtitolo }}</subtitle>
<updated>{{ dato }}</updated>
<author>
<name>{{ aŭtoro }}</name>
</author>
<id>{{ XML-fluo_url }}</id>
<link href="{{ protokolo_url }}" rel="alternate"/>
<link href="{{ XML-fluo_url }}" rel="self" type="application/atom+xml"/>
]]
eo.atom_entry = [[
<entry>
<id>{{ url }}</id>
<title>
<![CDATA[{{ titolo }}]] .. "]]>" .. [[
</title>
<updated>{{ dato }}</updated>
<author>
<name>{{ aŭtoro }}</name>
</author>
<link href="{{ url }}" rel="alternate"/>
<summary>
<![CDATA[{{ resumo }}]] .. "]]>" .. [[
</summary>
<content>
<![CDATA[{{ entenaĵo }}]] .. "]]>" .. [[
</content>
</entry>
]]
eo.atom_footer = [[</feed>]]
eo.post = [[---
date: {{ dato }}
---
# {{ titolo }}
## Ligiloj
=> gemini:// ligilo
=> gemini:// ligilo (bildo)
=> https:// ligilo (https)]]
eo.index = [[
# {{ titolo }}
{{ afiŝejo }}
]]
eo.page = [[
# {{ titolo }}
## supra paĝotitolo 2
### supra paĝotitolo 3
Tabelo:
*
*
*
```
antaŭformatita teksto
```
## Ligiloj
=> gemini:// ligilo
=> gemini:// ligilo (bildo)
=> https:// ligilo (https)]]
eo.msgs = {}
-- %s: gemtext filename
eo.msgs.add_gemtext = "Kreita %s."
-- %s: app executable name
eo.msgs.help_usage = [[%s [opcioj] [kapsulo] [titolo]
]]
-- %s: command-line options
-- (see env.lua env.cli_opts for the full list)
eo.msgs.help_opts = [[
Opcioj:
%s [lang] Generi agordan dosierujon
%s [kapsulo] [titolo] Aldonu novan paĝon kun la donita titolo
%s [kapsulo] [titolo] Aldonu novan gemlog-afiŝon kun la donita titolo
%s Generu indeksan paĝon kaj fonton de afiŝoj
%s Indeksu kaj kopiu afiŝojn malproksime uzante scp
%s Helpema helpo estas helpema
%s Presaĵversio-informoj
]]
-- %s: list of language codes
eo.msgs.help_lang_opts = [[
Agordu lingvo-opciojn:
%s]]
eo.msgs.index = "Kreita indeksa paĝo kaj feed"
-- %s: config directory path
eo.msgs.load_config = [[Kreis agordosierojn. Bonvolu redakti ilin per la ĝustaj
detaloj antaŭ ol daŭrigi. La agordosieroj troveblas ĉe:
%s]]
eo.msgs.publish = "Eldonita kapsulo."
eo.errs = {
invalid_cap_id = "Eraro: nekonata kapsula id.",
}
return eo

160
lang/fr_FR.lua 100644
View File

@ -0,0 +1,160 @@
local fr = {}
-- Templates
fr.tpl_vars = {
post = {
author = "{{ auteur }}",
content = "{{ contenu }}",
date = "{{ date }}",
summary = "{{ résumé }}",
-- This is not used in the templates yet.
tags = "{{ tags }}",
title = "{{ titre }}",
url = "{{ url }}",
},
feed = {
date = "{{ date }}",
url = "{{ url_flux }}",
},
index = {
posts = "{{ articles }}",
},
log = {
-- The concept of a "gemlog" does not have a French translation,
-- the closest term after some discussion might be "journal".
author = "{{ auteur }}",
subtitle = "{{ sous_titre }}",
title = "{{ titre }}",
log_url = "{{ url_journal }}",
},
}
fr.atom_header = [[<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{{ titre }}</title>
<subtitle>{{ sous_titre }}</subtitle>
<updated>{{ date }}</updated>
<author>
<name>{{ auteur }}</name>
</author>
<id>{{ url_flux }}</id>
<link href="{{ url_journal }}" rel="alternate"/>
<link href="{{ url_flux }}" rel="self" type="application/atom+xml"/>
]]
fr.atom_entry = [[
<entry>
<id>{{ url }}</id>
<title>
<![CDATA[{{ titre }}]] .. "]]>" .. [[
</title>
<updated>{{ date }}</updated>
<author>
<name>{{ auteur }}</name>
</author>
<link href="{{ url }}" rel="alternate"/>
<summary>
<![CDATA[{{ résumé }}]] .. "]]>" .. [[
</summary>
<content>
<![CDATA[{{ contenu }}]] .. "]]>" .. [[
</content>
</entry>
]]
fr.atom_footer = [[</feed>]]
fr.post = [[---
date: {{ date }}
---
# {{ titre }}
## Liens
=> gemini:// lien
=> gemini:// lien (image)
=> https:// lien (https)]]
fr.index = [[
# {{ titre }}
{{ articles }}
]]
fr.page = [[
# {{ titre }}
## Titre de niveau 2
### Titre de niveau 3
Liste :
*
*
*
```
Texte préformaté
```
## Liens
=> gemini:// lien
=> gemini:// lien (image)
=> https:// lien (https)]]
fr.msgs = {}
-- %s: gemtext filename
fr.msgs.add_gemtext = "%s créé."
-- %s: app executable name
fr.msgs.help_usage = [[%s [options] [capsule] [titre]
]]
-- %s: command-line options
-- (see env.lua env.cli_opts for the full list)
fr.msgs.help_opts = [[
Options :
%s [lang] Générer un dossier de configuration
%s [capsule] [titre] Ajouter une nouvelle page avec le titre fourni
%s [capsule] [titre] Ajouter un nouvel article avec le titre fourni
%s Générer une page d'accueil et un flux d'articles
%s Générer les pages puis les publier via scp
%s Afficher ce message d'aide
%s Afficher les informations de version
]]
-- %s: list of language codes
fr.msgs.help_lang_opts = [[
Langues disponibles :
%s]]
fr.msgs.index = "Flux et page d'accueil créés."
-- %s: config directory path
fr.msgs.load_config = [[Les fichiers de configuration ont été créés. Veuillez y
inscrire les valeurs correctes avant de continuer.
Les fichiers peuvent être trouvés dans :
%s]]
fr.msgs.publish = "Capsule publiée."
fr.errs = {
invalid_cap_id = "Erreur: Identifiant de capsule inconnu.",
}
return fr

View File

@ -6,7 +6,7 @@ A little command-line helper for publishing [Gemini] sites or "capsules".
```
Options:
config Generate a config directory
config [lang] Generate a config directory
page [capsule] [title] Add a new page with the given title
post [capsule] [title] Add a new gemlog post with the given title
index Generate an index page and feed of posts
@ -25,17 +25,20 @@ version Print version info
## Build
- Install Lua and [luastatic].
- Install Lua (including development libraries and headers) and [luastatic].
- Clone this repository and change into the directory. Run:
```
luastatic gemwriter.lua env.lua util.lua lang/en.lua \
/usr/lib/liblua.so -I/usr/include -o gemwriter
luastatic gemwriter.lua env.lua util.lua lang/*.lua \
/usr/lib/[arch]/liblua[5.x].a -I/usr/include/lua[5.x] -static \
-o gemwriter
```
The paths to `liblua.so` and the development headers (i.e.
`/usr/include/lua.h`) may need to be adjusted for your distribution.
Replace `[arch]` with the OS architecture, e.g. `x86_64-linux-gnu`, and
`[5.x]` with the Lua version. The paths to `liblua.a` and the development
headers (i.e. `/usr/include/lua[5.x]/lua.h`) may need to be adjusted for
your distribution.
- Move the `gemwriter` executable to a location in your `$PATH`.
@ -52,6 +55,14 @@ version Print version info
4. Publish your capsule: `gemwriter publish`
## Credits
Special thanks to the following contributors:
- [lucidiot](https://tilde.town/~lucidiot/) — French translation
- [wsinatra](http://lambdacreate.com/) — Esperanto translation
## License
BSD-3-Clause

14
util.lua 100644 → 100755
View File

@ -28,12 +28,8 @@ end
function util.extract_str(full_str, find_str, end_str)
local fi1, fi2 = string.find(full_str, find_str, 1)
local ei1, ei2 = string.find(full_str, end_str, fi2)
if end_str == "\n" then
return string.sub(full_str, fi2 + 1, ei1 - 2)
else
return string.sub(full_str, fi2 + 1, ei1 - 1)
end
end
function util.to_bool(str)
@ -139,6 +135,16 @@ function util.extract_file_date(dir, file)
end
function util.module_exists(mod)
local check, err = pcall(require, mod)
if check then do
return true end
else
return false
end
end
function util.read_file(file)
local fh = io.open(file, "r")
local text = ""