diff --git a/env.lua b/env.lua index 73663aa..2f1c9a6 100644 --- a/env.lua +++ b/env.lua @@ -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 = { diff --git a/gemwriter.lua b/gemwriter.lua index ef5b156..9557927 100644 --- a/gemwriter.lua +++ b/gemwriter.lua @@ -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 - lang = require("lang." .. writer.conf.app_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,40 +142,23 @@ 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 + -- 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 + else + writer.conf.cap_id = cap_id 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 - else - writer.conf.cap_id = cap_id - end - local cap_label = "%[" .. env.toml_vars.capsules .. "%." .. - tostring(cap_id) .. "%]" - if (string.find(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) + local cap_label = "%[" .. env.toml_vars.capsules .. "%." .. + tostring(cap_id) .. "%]" + 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(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 - writer.load_config(args[2]) + 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 diff --git a/lang/en.lua b/lang/en.lua deleted file mode 100644 index 71222a2..0000000 --- a/lang/en.lua +++ /dev/null @@ -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 = [[ - - {{ log_title }} - {{ log_subtitle }} - {{ feed_date }} - - {{ log_author }} - - {{ feed_url }} - - -]] - -en.atom_entry = [[ - - {{ post_url }} - - <![CDATA[{{ post_title }}]] .. "]]>" .. [[ - - - {{ post_date }} - - {{ post_author }} - - - - " .. [[ - - - - " .. [[ - - - -]] - -en.atom_footer = [[]] - -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 diff --git a/lang/en_US.lua b/lang/en_US.lua new file mode 100644 index 0000000..b7b8080 --- /dev/null +++ b/lang/en_US.lua @@ -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 = [[ + + {{ title }} + {{ subtitle }} + {{ date }} + + {{ author }} + + {{ feed_url }} + + +]] + +en.atom_entry = [[ + + {{ url }} + + <![CDATA[{{ title }}]] .. "]]>" .. [[ + + + {{ date }} + + {{ author }} + + + + " .. [[ + + + + " .. [[ + + + +]] + +en.atom_footer = [[]] + +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 diff --git a/lang/fr.lua b/lang/fr.lua deleted file mode 100644 index d1f5cd8..0000000 --- a/lang/fr.lua +++ /dev/null @@ -1,157 +0,0 @@ -local fr = {} - --- Templates -fr.tpl_vars = { - post = { - -- It might not be really necessary to mention post/feed/log each time - -- since those occur in different templates? - -- This would make the french translated tags much cleaner, because the - -- proper way to do this translation would be "auteur_de_l'article" - -- (author_of_the_post). - author = "{{ auteur_article }}", - content = "{{ contenu_article }}", - date = "{{ date_article }}", - summary = "{{ résumé_article }}", - -- This is not used in the templates. - tags = "{{ tags_article }}", - title = "{{ titre_article }}", - url = "{{ url_article }}", - }, - feed = { - date = "{{ date_flux }}", - url = "{{ url_flux }}", - }, - index = { - posts = "{{ articles }}", - }, - log = { - -- The concept of a "gemlog" does not have a French translation - -- as far as I know, so I used 'capsule' instead of 'log'. - author = "{{ auteur_capsule }}", - subtitle = "{{ sous_titre_capsule }}", - title = "{{ titre_capsule }}", - log_url = "{{ url_capsule }}", - }, -} - -fr.atom_header = [[ - - {{ titre_capsule }} - {{ sous_titre_capsule }} - {{ date_flux }} - - {{ auteur_capsule }} - - {{ url_flux }} - - -]] - -fr.atom_entry = [[ - - {{ url_article }} - - <![CDATA[{{ titre_article }}]] .. "]]>" .. [[ - - - {{ date_article }} - - {{ auteur_article }} - - - - " .. [[ - - - - " .. [[ - - - -]] - -fr.atom_footer = [[]] - -fr.post = [[--- -date: {{ date_article }} ---- - -# {{ titre_article }} - - - - -## Liens - -=> gemini:// lien -=> gemini:// lien (image) -=> https:// lien (https)]] - -fr.index = [[ -# {{ titre_capsule }} -{{ articles }} -]] - -fr.page = [[ -# {{ titre_article }} - -## Titre de niveau 2 -### Titre de niveau 3 - -Liste : - -* -* -* - -``` -Texte préformaté -``` - - -## Liens - -=> gemini:// lien -=> gemini:// lien (image) -=> https:// lien (https)]] - --- App command options and messages output --- These probably should always stay untranslated, because having a CLI's --- entire command line change depending on the language would be a mess. --- Imagine writing bash in french… -fr.opts = { - config = "config", - page = "page", - post = "post", - index = "index", - publish = "publish", - help = "help", - version = "version", -} - -fr.msgs = { - add_gemtext = "Créé ", - help = [[ [options] [capsule] [titre] - -Options : - -config Générer un dossier de configuration -page [capsule] [titre] Ajouter une nouvelle page avec le titre fourni -post [capsule] [titre] Ajouter un nouvel article avec le titre fourni -index Générer une page d'accueil et un flux d'articles -publish Générer les pages puis les publier via scp -help Afficher ce message d'aide -version Afficher les informations de version]], - index = "Flux et page d'accueil créés.", - 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 : -]], - publish = "Capsule publiée.", -} - -fr.errs = { - invalid_cap_id = "Erreur: Identifiant de capsule inconnu.", -} - -return fr diff --git a/lang/fr_FR.lua b/lang/fr_FR.lua new file mode 100644 index 0000000..c2b0a73 --- /dev/null +++ b/lang/fr_FR.lua @@ -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 = [[ + + {{ titre }} + {{ sous_titre }} + {{ date }} + + {{ auteur }} + + {{ url_flux }} + + +]] + +fr.atom_entry = [[ + + {{ url }} + + <![CDATA[{{ titre }}]] .. "]]>" .. [[ + + + {{ date }} + + {{ auteur }} + + + + " .. [[ + + + + " .. [[ + + + +]] + +fr.atom_footer = [[]] + +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 diff --git a/readme.md b/readme.md index 2c22147..7de3296 100644 --- a/readme.md +++ b/readme.md @@ -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,13 @@ version Print version info 4. Publish your capsule: `gemwriter publish` +## Credits + +Special thanks to the following contributors: + +- [lucidiot](https://tilde.town/~lucidiot/) — French translation + + ## License BSD-3-Clause diff --git a/util.lua b/util.lua index e4409a3..1e9c825 100644 --- a/util.lua +++ b/util.lua @@ -139,6 +139,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 = ""