Add gettext support

This commit is contained in:
Mikko Ahlroth 2024-06-01 08:53:02 +03:00
parent ee06f93f65
commit 9aa372855b
22 changed files with 1052 additions and 82 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
*~
*.beam
*.ez
/build

View file

@ -1,5 +1,5 @@
name = "scriptorium"
version = "1.0.2"
version = "2.0.0"
target = "javascript"
gleam = "~> 1.1"
@ -30,6 +30,7 @@ gleam_javascript = "~> 0.8"
ranged_int = "~> 2.0"
bigi = "~> 3.0"
simplifile = "~> 1.7"
kielet = ">= 2.0.0 and < 3.0.0"
[dev-dependencies]
gleeunit = "~> 1.0"

View file

@ -11,8 +11,10 @@ packages = [
{ name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" },
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
{ name = "jot", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "B20A745707EE60B857249D4533656A52964EA024E844005C4AD8135ED432D66C" },
{ name = "kielet", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "nibble"], otp_app = "kielet", source = "hex", outer_checksum = "C6F91EECDC54EAE7C55DE1679C8E7CC4823259782DB13E656E4EC2A2590005B8" },
{ name = "lustre", version = "4.1.8", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "55C3D26AEE6BF6B859927616B1F5BC25841926E4EA6A2A72ECC90D6769560F04" },
{ name = "lustre_ssg", version = "0.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "jot", "lustre", "simplifile", "tom"], source = "local", path = "../ssg" },
{ name = "nibble", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "nibble", source = "hex", outer_checksum = "67C6BEBC1AB6D771AB893B4A7B3E66C92668C6E7774C335FEFCD545B06435FE5" },
{ name = "ranged_int", version = "2.0.0", build_tools = ["gleam"], requirements = ["bigi", "gleam_stdlib"], otp_app = "ranged_int", source = "hex", outer_checksum = "9FCDA804C1884015FC25F3F8BE429FC450D402F861B5C561464479F5B1162A41" },
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
@ -24,6 +26,7 @@ bigi = { version = "~> 3.0" }
gleam_javascript = { version = "~> 0.8" }
gleam_stdlib = { version = "~> 0.36 or ~> 1.0" }
gleeunit = { version = "~> 1.0" }
kielet = { version = ">= 2.0.0 and < 3.0.0" }
lustre = { version = "~> 4.1" }
lustre_ssg = { path = "../ssg" }
ranged_int = { version = "~> 2.0" }

263
priv/locale/autogen.pot Normal file
View file

@ -0,0 +1,263 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Mikko Ahlroth
# This file is distributed under the same license as the Scriptorium package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Scriptorium 2.0.0\n"
"Report-Msgid-Bugs-To: mikko@ahlroth.fi\n"
"POT-Creation-Date: 2024-05-30 21:47+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/scriptorium/parser.gleam:119
msgid "Menu parsing failed: {err}"
msgstr ""
#: src/scriptorium/renderer.gleam:177
msgid "Archives for {year}"
msgstr ""
#: src/scriptorium/renderer.gleam:206
msgid "Archives for {month} {year}"
msgstr ""
#: src/scriptorium/rendering/views/base.gleam:95
#: src/scriptorium/rendering/views/single_post.gleam:47
msgid "Tags"
msgstr ""
#: src/scriptorium/rendering/views/base.gleam:103
msgid "Archives"
msgstr ""
#: src/scriptorium/rendering/views/list_page.gleam:22
msgid "Pages"
msgstr ""
#: src/scriptorium/rendering/views/nav.gleam:20
msgid "Previous"
msgstr ""
#: src/scriptorium/rendering/views/nav.gleam:38
msgid "current page"
msgstr ""
#: src/scriptorium/rendering/views/nav.gleam:64
msgid "Next"
msgstr ""
#: src/scriptorium/rendering/views/single_post.gleam:70
msgid "Read more…"
msgstr ""
#: src/scriptorium/rendering/views/single_post.gleam:88
msgid "{date}, {time}"
msgstr ""
#: src/scriptorium/rendering/views/single_post.gleam:102
msgid "Posted on {datetime}."
msgstr ""
#: src/scriptorium/utils/date.gleam:126
msgid "January"
msgstr ""
#: src/scriptorium/utils/date.gleam:127
msgid "February"
msgstr ""
#: src/scriptorium/utils/date.gleam:128
msgid "March"
msgstr ""
#: src/scriptorium/utils/date.gleam:129
msgid "April"
msgstr ""
#: src/scriptorium/utils/date.gleam:130 src/scriptorium/utils/date.gleam:148
msgid "May"
msgstr ""
#: src/scriptorium/utils/date.gleam:131
msgid "June"
msgstr ""
#: src/scriptorium/utils/date.gleam:132
msgid "July"
msgstr ""
#: src/scriptorium/utils/date.gleam:133
msgid "August"
msgstr ""
#: src/scriptorium/utils/date.gleam:134
msgid "September"
msgstr ""
#: src/scriptorium/utils/date.gleam:135
msgid "October"
msgstr ""
#: src/scriptorium/utils/date.gleam:136
msgid "November"
msgstr ""
#: src/scriptorium/utils/date.gleam:137
msgid "December"
msgstr ""
#: src/scriptorium/utils/date.gleam:144
msgid "Jan"
msgstr ""
#: src/scriptorium/utils/date.gleam:145
msgid "Feb"
msgstr ""
#: src/scriptorium/utils/date.gleam:146
msgid "Mar"
msgstr ""
#: src/scriptorium/utils/date.gleam:147
msgid "Apr"
msgstr ""
#: src/scriptorium/utils/date.gleam:149
msgid "Jun"
msgstr ""
#: src/scriptorium/utils/date.gleam:150
msgid "Jul"
msgstr ""
#: src/scriptorium/utils/date.gleam:151
msgid "Aug"
msgstr ""
#: src/scriptorium/utils/date.gleam:152
msgid "Sep"
msgstr ""
#: src/scriptorium/utils/date.gleam:153
msgid "Oct"
msgstr ""
#: src/scriptorium/utils/date.gleam:154
msgid "Nov"
msgstr ""
#: src/scriptorium/utils/date.gleam:155
msgid "Dec"
msgstr ""
#: src/scriptorium/utils/date.gleam:161
msgid "{day} {month_short_str} {year}"
msgstr ""
#: src/scriptorium/utils/time.gleam:44
msgid "{h24_0}:{min_0}"
msgstr ""
#: src/scriptorium/utils/time.gleam:77
msgid "<00> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:78
msgid "<01> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:79
msgid "<02> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:80
msgid "<03> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:81
msgid "<04> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:82
msgid "<05> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:83
msgid "<06> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:84
msgid "<07> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:85
msgid "<08> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:86
msgid "<09> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:87
msgid "<10> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:88
msgid "<11> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:89
msgid "<12> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:90
msgid "<13> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:91
msgid "<14> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:92
msgid "<15> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:93
msgid "<16> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:94
msgid "<17> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:95
msgid "<18> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:96
msgid "<19> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:97
msgid "<20> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:98
msgid "<21> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:99
msgid "<22> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:100
msgid "<23> pm"
msgstr ""

Binary file not shown.

View file

@ -0,0 +1,264 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Mikko Ahlroth
# This file is distributed under the same license as the Scriptorium package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Scriptorium 2.0.0\n"
"Report-Msgid-Bugs-To: mikko@ahlroth.fi\n"
"POT-Creation-Date: 2024-05-30 21:47+0300\n"
"PO-Revision-Date: 2024-05-30 21:48+0300\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.4.4\n"
#: src/scriptorium/parser.gleam:119
msgid "Menu parsing failed: {err}"
msgstr "Valikon jäsentäminen epäonnistui: {err}"
#: src/scriptorium/renderer.gleam:177
msgid "Archives for {year}"
msgstr "Arkistot vuodelle {year}"
#: src/scriptorium/renderer.gleam:206
msgid "Archives for {month} {year}"
msgstr "Arkistot {month}lle {year}"
#: src/scriptorium/rendering/views/base.gleam:95
#: src/scriptorium/rendering/views/single_post.gleam:47
msgid "Tags"
msgstr "Tagit"
#: src/scriptorium/rendering/views/base.gleam:103
msgid "Archives"
msgstr "Arkistot"
#: src/scriptorium/rendering/views/list_page.gleam:22
msgid "Pages"
msgstr "Sivut"
#: src/scriptorium/rendering/views/nav.gleam:20
msgid "Previous"
msgstr "Edellinen"
#: src/scriptorium/rendering/views/nav.gleam:38
msgid "current page"
msgstr "tämä sivu"
#: src/scriptorium/rendering/views/nav.gleam:64
msgid "Next"
msgstr "Seuraava"
#: src/scriptorium/rendering/views/single_post.gleam:70
msgid "Read more…"
msgstr "Lue lisää…"
#: src/scriptorium/rendering/views/single_post.gleam:88
msgid "{date}, {time}"
msgstr "{date} klo {time}"
#: src/scriptorium/rendering/views/single_post.gleam:102
msgid "Posted on {datetime}."
msgstr "Julkaistu {datetime}."
#: src/scriptorium/utils/date.gleam:126
msgid "January"
msgstr "tammikuu"
#: src/scriptorium/utils/date.gleam:127
msgid "February"
msgstr "helmikuu"
#: src/scriptorium/utils/date.gleam:128
msgid "March"
msgstr "maaliskuu"
#: src/scriptorium/utils/date.gleam:129
msgid "April"
msgstr "huhtikuu"
#: src/scriptorium/utils/date.gleam:130 src/scriptorium/utils/date.gleam:148
msgid "May"
msgstr "toukokuu"
#: src/scriptorium/utils/date.gleam:131
msgid "June"
msgstr "kesäkuu"
#: src/scriptorium/utils/date.gleam:132
msgid "July"
msgstr "heinäkuu"
#: src/scriptorium/utils/date.gleam:133
msgid "August"
msgstr "elokuu"
#: src/scriptorium/utils/date.gleam:134
msgid "September"
msgstr "syyskuu"
#: src/scriptorium/utils/date.gleam:135
msgid "October"
msgstr "lokakuu"
#: src/scriptorium/utils/date.gleam:136
msgid "November"
msgstr "marraskuu"
#: src/scriptorium/utils/date.gleam:137
msgid "December"
msgstr "joulukuu"
#: src/scriptorium/utils/date.gleam:144
msgid "Jan"
msgstr "tammi"
#: src/scriptorium/utils/date.gleam:145
msgid "Feb"
msgstr "helmi"
#: src/scriptorium/utils/date.gleam:146
msgid "Mar"
msgstr "maalis"
#: src/scriptorium/utils/date.gleam:147
msgid "Apr"
msgstr "huhti"
#: src/scriptorium/utils/date.gleam:149
msgid "Jun"
msgstr "touko"
#: src/scriptorium/utils/date.gleam:150
msgid "Jul"
msgstr "kesä"
#: src/scriptorium/utils/date.gleam:151
msgid "Aug"
msgstr "heinä"
#: src/scriptorium/utils/date.gleam:152
msgid "Sep"
msgstr "syys"
#: src/scriptorium/utils/date.gleam:153
msgid "Oct"
msgstr "loka"
#: src/scriptorium/utils/date.gleam:154
msgid "Nov"
msgstr "marras"
#: src/scriptorium/utils/date.gleam:155
msgid "Dec"
msgstr "joulu"
#: src/scriptorium/utils/date.gleam:161
msgid "{day} {month_short_str} {year}"
msgstr "{day}.{month_no}.{year}"
#: src/scriptorium/utils/time.gleam:44
msgid "{h24_0}:{min_0}"
msgstr "{h24_0}:{min_0}"
#: src/scriptorium/utils/time.gleam:77
msgid "<00> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:78
msgid "<01> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:79
msgid "<02> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:80
msgid "<03> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:81
msgid "<04> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:82
msgid "<05> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:83
msgid "<06> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:84
msgid "<07> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:85
msgid "<08> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:86
msgid "<09> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:87
msgid "<10> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:88
msgid "<11> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:89
msgid "<12> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:90
msgid "<13> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:91
msgid "<14> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:92
msgid "<15> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:93
msgid "<16> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:94
msgid "<17> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:95
msgid "<18> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:96
msgid "<19> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:97
msgid "<20> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:98
msgid "<21> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:99
msgid "<22> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:100
msgid "<23> pm"
msgstr ""

263
priv/locale/messages.po Normal file
View file

@ -0,0 +1,263 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Mikko Ahlroth
# This file is distributed under the same license as the Scriptorium package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Scriptorium 2.0.0\n"
"Report-Msgid-Bugs-To: mikko@ahlroth.fi\n"
"POT-Creation-Date: 2024-05-30 21:47+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/scriptorium/parser.gleam:119
msgid "Menu parsing failed: {err}"
msgstr ""
#: src/scriptorium/renderer.gleam:177
msgid "Archives for {year}"
msgstr ""
#: src/scriptorium/renderer.gleam:206
msgid "Archives for {month} {year}"
msgstr ""
#: src/scriptorium/rendering/views/base.gleam:95
#: src/scriptorium/rendering/views/single_post.gleam:47
msgid "Tags"
msgstr ""
#: src/scriptorium/rendering/views/base.gleam:103
msgid "Archives"
msgstr ""
#: src/scriptorium/rendering/views/list_page.gleam:22
msgid "Pages"
msgstr ""
#: src/scriptorium/rendering/views/nav.gleam:20
msgid "Previous"
msgstr ""
#: src/scriptorium/rendering/views/nav.gleam:38
msgid "current page"
msgstr ""
#: src/scriptorium/rendering/views/nav.gleam:64
msgid "Next"
msgstr ""
#: src/scriptorium/rendering/views/single_post.gleam:70
msgid "Read more…"
msgstr ""
#: src/scriptorium/rendering/views/single_post.gleam:88
msgid "{date}, {time}"
msgstr ""
#: src/scriptorium/rendering/views/single_post.gleam:102
msgid "Posted on {datetime}."
msgstr ""
#: src/scriptorium/utils/date.gleam:126
msgid "January"
msgstr ""
#: src/scriptorium/utils/date.gleam:127
msgid "February"
msgstr ""
#: src/scriptorium/utils/date.gleam:128
msgid "March"
msgstr ""
#: src/scriptorium/utils/date.gleam:129
msgid "April"
msgstr ""
#: src/scriptorium/utils/date.gleam:130 src/scriptorium/utils/date.gleam:148
msgid "May"
msgstr ""
#: src/scriptorium/utils/date.gleam:131
msgid "June"
msgstr ""
#: src/scriptorium/utils/date.gleam:132
msgid "July"
msgstr ""
#: src/scriptorium/utils/date.gleam:133
msgid "August"
msgstr ""
#: src/scriptorium/utils/date.gleam:134
msgid "September"
msgstr ""
#: src/scriptorium/utils/date.gleam:135
msgid "October"
msgstr ""
#: src/scriptorium/utils/date.gleam:136
msgid "November"
msgstr ""
#: src/scriptorium/utils/date.gleam:137
msgid "December"
msgstr ""
#: src/scriptorium/utils/date.gleam:144
msgid "Jan"
msgstr ""
#: src/scriptorium/utils/date.gleam:145
msgid "Feb"
msgstr ""
#: src/scriptorium/utils/date.gleam:146
msgid "Mar"
msgstr ""
#: src/scriptorium/utils/date.gleam:147
msgid "Apr"
msgstr ""
#: src/scriptorium/utils/date.gleam:149
msgid "Jun"
msgstr ""
#: src/scriptorium/utils/date.gleam:150
msgid "Jul"
msgstr ""
#: src/scriptorium/utils/date.gleam:151
msgid "Aug"
msgstr ""
#: src/scriptorium/utils/date.gleam:152
msgid "Sep"
msgstr ""
#: src/scriptorium/utils/date.gleam:153
msgid "Oct"
msgstr ""
#: src/scriptorium/utils/date.gleam:154
msgid "Nov"
msgstr ""
#: src/scriptorium/utils/date.gleam:155
msgid "Dec"
msgstr ""
#: src/scriptorium/utils/date.gleam:161
msgid "{day} {month_short_str} {year}"
msgstr ""
#: src/scriptorium/utils/time.gleam:44
msgid "{h24_0}:{min_0}"
msgstr ""
#: src/scriptorium/utils/time.gleam:77
msgid "<00> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:78
msgid "<01> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:79
msgid "<02> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:80
msgid "<03> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:81
msgid "<04> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:82
msgid "<05> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:83
msgid "<06> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:84
msgid "<07> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:85
msgid "<08> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:86
msgid "<09> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:87
msgid "<10> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:88
msgid "<11> am"
msgstr ""
#: src/scriptorium/utils/time.gleam:89
msgid "<12> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:90
msgid "<13> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:91
msgid "<14> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:92
msgid "<15> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:93
msgid "<16> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:94
msgid "<17> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:95
msgid "<18> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:96
msgid "<19> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:97
msgid "<20> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:98
msgid "<21> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:99
msgid "<22> pm"
msgstr ""
#: src/scriptorium/utils/time.gleam:100
msgid "<23> pm"
msgstr ""

View file

@ -15,7 +15,7 @@ pub type BuildError {
/// Parse the blog's input files.
pub fn parse(config: Configuration) {
config.parser()
config.parser(config)
|> result.map_error(ParseError)
}

View file

@ -1,6 +1,7 @@
//// The configuration is the main way to customize Scriptorium's behaviour.
import gleam/option
import kielet/context.{type Context}
import scriptorium/compiler.{type CompileDatabase, type Compiler}
import scriptorium/models/database.{type Database}
import scriptorium/paths.{type PathConfiguration}
@ -22,7 +23,7 @@ pub type ParseError {
/// The parser
pub type Parser =
fn() -> Result(Database, ParseError)
fn(Configuration) -> Result(Database, ParseError)
/// Renders the content of the database into HTML.
pub type Renderer =
@ -90,17 +91,26 @@ pub type Author {
)
}
/// Localization related configuration.
pub type Localization {
Localization(
/// Language code of the blog, meaning the language of the content you are
/// writing. The language code must be according to
/// <https://datatracker.ietf.org/doc/html/rfc5646>.
language: String,
/// Context to use for gettext operations for translating built-in strings.
context: Context,
)
}
pub type Configuration {
Configuration(
/// Name of the blog.
blog_name: String,
/// Absolute URL of the blog, this is where you are deploying it.
blog_url: String,
/// Language code of the blog, meaning the language of the content you are
/// writing. The language code must be according to
/// <https://datatracker.ietf.org/doc/html/rfc5646>.
language: String,
author: Author,
l10n: Localization,
compiling: Compiling,
rendering: Rendering,
paths: PathConfiguration,

View file

@ -1,10 +1,14 @@
//// This module contains default configurations that can be used to create a
//// blog quickly.
import gleam/uri
import gleam/string
import gleam/uri
import kielet/context.{Context}
import scriptorium/compiler
import scriptorium/config.{type Configuration, Compiling, Configuration, Rendering}
import scriptorium/config.{
type Configuration, Compiling, Configuration, Localization, Rendering,
}
import scriptorium/l10n
import scriptorium/parser
import scriptorium/paths
import scriptorium/renderer
@ -35,7 +39,6 @@ pub fn default_config(
author: config.Author,
copyright: String,
) -> Configuration {
// Drop any trailing slash from the blog URL, otherwise a `blog_url` like
// "https://my.blog.example/" will end up having a root path of "/" instead
// of "".
@ -45,10 +48,15 @@ pub fn default_config(
}
let assert Ok(parsed_url) = uri.parse(blog_url)
let language_db = l10n.load_builtins()
Configuration(
blog_name: blog_name,
blog_url: blog_url,
language: language,
l10n: Localization(
language: language,
context: Context(language_db, language),
),
author: author,
compiling: Compiling(
database_compiler: compiler.compile,

View file

@ -0,0 +1,30 @@
import kielet/database
import kielet/language
import scriptorium/utils/priv
import simplifile
const locale_dir = "locale"
const locale_sub_dir = "LC_MESSAGES"
const locale_filename = "messages.mo"
/// Load builtin translations and return a translation database containing them.
pub fn load_builtins() -> database.Database {
let db = database.new()
let assert Ok(fi_data) =
simplifile.read_bits(
priv.path()
<> "/"
<> locale_dir
<> "/"
<> "fi"
<> "/"
<> locale_sub_dir
<> "/"
<> locale_filename,
)
let assert Ok(fi) = language.load("fi", fi_data)
database.add_language(db, fi)
}

View file

@ -4,7 +4,8 @@ import gleam/list
import gleam/regex
import gleam/result
import gleam/string
import scriptorium/config.{type ParseError, ParseError}
import kielet.{gettext as g_}
import scriptorium/config.{type Configuration, type ParseError, ParseError}
import scriptorium/models/database.{type Database}
import scriptorium/parser/common
import scriptorium/parser/menu
@ -16,10 +17,10 @@ import simplifile
const default_data_path = "./data"
/// The default parser.
pub fn default_parse() -> Result(Database, ParseError) {
pub fn default_parse(config: Configuration) -> Result(Database, ParseError) {
parse_posts(database.new(), post_path())
|> result.try(parse_pages(_, page_path()))
|> result.try(parse_menu(_, menu_path()))
|> result.try(parse_menu(_, menu_path(), config))
}
/// Parse posts from the given path into the database.
@ -97,7 +98,11 @@ pub fn parse_pages(db: Database, path: String) -> Result(Database, ParseError) {
}
/// Parse the menu from the given file into the database.
pub fn parse_menu(db: Database, file: String) -> Result(Database, ParseError) {
pub fn parse_menu(
db: Database,
file: String,
config: Configuration,
) -> Result(Database, ParseError) {
case simplifile.verify_is_file(file) {
Ok(True) -> {
use contents <- result.try(
@ -110,7 +115,11 @@ pub fn parse_menu(db: Database, file: String) -> Result(Database, ParseError) {
use menu <- result.try(
menu.parse(contents)
|> result.map_error(fn(err) {
ParseError("Menu parsing failed: " <> string.inspect(err))
ParseError(string.replace(
g_(config.l10n.context, "Menu parsing failed: {err}"),
"{err}",
string.inspect(err),
))
}),
)

View file

@ -5,6 +5,8 @@ import gleam/dict.{type Dict}
import gleam/int
import gleam/list
import gleam/result
import gleam/string
import kielet.{gettext as g_}
import lustre/element.{type Element}
import scriptorium/compiler.{
type CompileDatabase, type CompiledPage, type CompiledPost,
@ -171,7 +173,11 @@ fn render_year_pages(
config,
compiled_posts,
views,
"Archives for " <> int.to_string(year),
string.replace(
g_(config.l10n.context, "Archives for {year}"),
"{year}",
int.to_string(year),
),
config.paths.year(year),
element.none(),
)
@ -197,10 +203,12 @@ fn render_month_pages(
config,
compiled_posts,
views,
"Archives for "
<> date.month_to_string(month)
<> " "
<> int.to_string(year),
g_(config.l10n.context, "Archives for {month} {year}")
|> string.replace(
"{month}",
date.month_to_string(month, config.l10n.context),
)
|> string.replace("{year}", int.to_string(year)),
config.paths.month(year, month),
element.none(),
),

View file

@ -48,7 +48,7 @@ pub fn view(db: Database, config: Configuration) {
],
[
text(
date.month_to_string(month)
date.month_to_string(month, config.l10n.context)
<> " ("
<> int.to_string(ordered_tree.length(posts))
<> ")",

View file

@ -1,6 +1,7 @@
import gleam/dict
import gleam/list
import gleam/option
import kielet.{gettext as g_}
import lustre/attribute.{attribute, href, id, name, rel, role, type_}
import lustre/element.{type Element, text}
import lustre/element/html.{
@ -49,7 +50,7 @@ fn view(
prefix -> prefix <> " · " <> config.blog_name
}
html([attribute("lang", config.language)], [
html([attribute("lang", config.l10n.language)], [
head([], [
meta([attribute("charset", "utf-8")]),
meta([
@ -88,13 +89,21 @@ fn view(
case dict.size(database.tags(db)) {
0 -> element.none()
_ ->
nav([id("tags"), attribute("aria-label", "Tags")], [
pre_rendered.tags,
])
nav(
[
id("tags"),
attribute("aria-label", g_(config.l10n.context, "Tags")),
],
[pre_rendered.tags],
)
},
nav([id("archives"), attribute("aria-label", "Archives")], [
pre_rendered.archives,
]),
nav(
[
id("archives"),
attribute("aria-label", g_(config.l10n.context, "Archives")),
],
[pre_rendered.archives],
),
]),
footer([], [
p([], [

View file

@ -17,7 +17,7 @@ pub fn generate(_db: Database, config: Configuration) {
let now = luxon.utc_now()
let #(posts, _) = list.split(posts, config.rendering.posts_in_feed)
feed([attribute("xml:lang", config.language)], [
feed([attribute("xml:lang", config.l10n.language)], [
title([], config.blog_name),
updated([], luxon.to_iso(now)),
link([attribute("href", config.blog_url)]),

View file

@ -1,11 +1,12 @@
import gleam/list
import kielet.{gettext as g_}
import lustre/attribute.{attribute, class}
import lustre/element
import lustre/element/html.{footer, nav}
import scriptorium/config.{type Configuration}
import scriptorium/models/database.{type Database}
import scriptorium/rendering/views.{type ListInfo}
import scriptorium/rendering/views/nav
import lustre/attribute.{attribute, class}
import lustre/element
import lustre/element/html.{footer, nav}
pub fn generate(db: Database, config: Configuration) {
let single_post_renderer = config.rendering.views.single_post_list(db, config)
@ -15,9 +16,13 @@ pub fn generate(db: Database, config: Configuration) {
let footer = case info.total_pages > 1 {
True ->
nav([class("page-nav"), attribute("aria-label", "Pages")], [
footer([], [nav.view(info, info.root_path, config)]),
])
nav(
[
class("page-nav"),
attribute("aria-label", g_(config.l10n.context, "Pages")),
],
[footer([], [nav.view(info, info.root_path, config)])],
)
False -> none
}

View file

@ -1,10 +1,11 @@
import gleam/int
import gleam/list
import scriptorium/config.{type Configuration}
import scriptorium/rendering/views.{type ListInfo}
import kielet.{gettext as g_}
import lustre/attribute.{attribute, href}
import lustre/element.{text}
import lustre/element/html.{a, li, span, ul}
import scriptorium/config.{type Configuration}
import scriptorium/rendering/views.{type ListInfo}
pub fn view(list_info: ListInfo, root_path: String, config: Configuration) {
let page_range = list.range(1, list_info.total_pages)
@ -16,7 +17,7 @@ pub fn view(list_info: ListInfo, root_path: String, config: Configuration) {
nextprev_link(
list_info.current_page > 1,
list_info.current_page - 1,
"Previous",
g_(config.l10n.context, "Previous"),
"«",
root_path,
config,
@ -30,7 +31,13 @@ pub fn view(list_info: ListInfo, root_path: String, config: Configuration) {
let link_attributes = case page == list_info.current_page {
True -> [
attribute("aria-label", int.to_string(page) <> " (current page)"),
attribute(
"aria-label",
int.to_string(page)
<> " ("
<> g_(config.l10n.context, "current page")
<> ")",
),
attribute("aria-disabled", "true"),
]
False -> []
@ -54,7 +61,7 @@ pub fn view(list_info: ListInfo, root_path: String, config: Configuration) {
nextprev_link(
list_info.current_page < list_info.total_pages,
list_info.current_page + 1,
"Next",
g_(config.l10n.context, "Next"),
"»",
root_path,
config,

View file

@ -1,5 +1,8 @@
import gleam/list
import gleam/option
import gleam/string
import kielet.{gettext as g_}
import kielet/context.{type Context}
import lustre/attribute.{attribute, class, href}
import lustre/element.{type Element, text}
import lustre/element/html.{
@ -40,12 +43,8 @@ fn view(post: CompiledPost, is_full: Bool, _db: Database, config: Configuration)
article([class("post"), ..language], [
header([], [
wrap_heading(h2([], [text(post.orig.title)]), post_url, is_full),
p([class("post__time")], [
text("Posted on "),
post_time(post.orig),
text("."),
]),
nav([attribute("aria-label", "Tags")], [
p([class("post__time")], post_time(post.orig, config.l10n.context)),
nav([attribute("aria-label", g_(config.l10n.context, "Tags"))], [
ul(
[],
list.map(post.orig.tags, fn(tag) {
@ -67,7 +66,9 @@ fn view(post: CompiledPost, is_full: Bool, _db: Database, config: Configuration)
case is_full, post.content.short {
True, _ | False, option.None -> element.none()
False, option.Some(_) ->
footer([], [a([href(post_url)], [text("Read more…")])])
footer([], [
a([href(post_url)], [text(g_(config.l10n.context, "Read more…"))]),
])
},
])
}
@ -79,22 +80,27 @@ fn wrap_heading(heading: Element(Nil), post_url: String, is_full: Bool) {
}
}
fn post_time(post: Post) {
fn post_time(post: Post, context: Context) {
let post_date = post.get_date(post)
let date_str = date.format(post_date)
let time_str =
option.unwrap(
option.map(post.get_time(post), fn(t) { ", " <> time.format(t) }),
"",
)
let human_str = date_str <> time_str
let human_str = case post.get_time(post) {
option.Some(t) ->
g_(context, "{date}, {time}")
|> string.replace("{date}", date.format(post_date, context))
|> string.replace("{time}", time.format(t, context))
option.None -> date.format(post_date, context)
}
let datetime_str = case post.get_luxon(post) {
option.Some(lx) -> luxon.to_iso(lx)
option.None -> date.format_iso(post_date)
}
time([attribute("datetime", datetime_str)], [text(human_str)])
let datetime_el =
time([attribute("datetime", datetime_str)], [text(human_str)])
let format = g_(context, "Posted on {datetime}.")
string.split(format, "{datetime}")
|> list.map(text)
|> list.intersperse(datetime_el)
}

View file

@ -2,6 +2,8 @@ import gleam/bool
import gleam/int
import gleam/order.{type Order, Eq}
import gleam/string
import kielet.{gettext as g_}
import kielet/context.{type Context}
import scriptorium/utils/ints/day.{type Day}
pub type Month {
@ -118,31 +120,61 @@ pub fn month_to_int(month: Month) -> Int {
}
}
/// Convert a month to an English month name string.
pub fn month_to_string(month: Month) -> String {
/// Convert a month to a month name string.
pub fn month_to_string(month: Month, context: Context) -> String {
case month {
Jan -> "January"
Feb -> "February"
Mar -> "March"
Apr -> "April"
May -> "May"
Jun -> "June"
Jul -> "July"
Aug -> "August"
Sep -> "September"
Oct -> "October"
Nov -> "November"
Dec -> "December"
Jan -> g_(context, "January")
Feb -> g_(context, "February")
Mar -> g_(context, "March")
Apr -> g_(context, "April")
May -> g_(context, "May")
Jun -> g_(context, "June")
Jul -> g_(context, "July")
Aug -> g_(context, "August")
Sep -> g_(context, "September")
Oct -> g_(context, "October")
Nov -> g_(context, "November")
Dec -> g_(context, "December")
}
}
/// Format a date in the format "2 Aug 2024".
pub fn format(date: Date) -> String {
int.to_string(day.to_int(date.day))
<> " "
<> string.slice(month_to_string(date.month), 0, 3)
<> " "
<> int.to_string(date.year)
/// Convert a month to a short month name string.
pub fn month_to_short_string(month: Month, context: Context) -> String {
case month {
Jan -> g_(context, "Jan")
Feb -> g_(context, "Feb")
Mar -> g_(context, "Mar")
Apr -> g_(context, "Apr")
May -> g_(context, "May")
Jun -> g_(context, "Jun")
Jul -> g_(context, "Jul")
Aug -> g_(context, "Aug")
Sep -> g_(context, "Sep")
Oct -> g_(context, "Oct")
Nov -> g_(context, "Nov")
Dec -> g_(context, "Dec")
}
}
/// Format a date as a string.
pub fn format(date: Date, context: Context) -> String {
g_(context, "{day} {month_short_str} {year}")
|> string.replace("{day}", int.to_string(day.to_int(date.day)))
|> string.replace(
"{day_0}",
string.pad_left(int.to_string(day.to_int(date.day)), 2, "0"),
)
|> string.replace("{month_str}", month_to_string(date.month, context))
|> string.replace(
"{month_short_str}",
month_to_short_string(date.month, context),
)
|> string.replace("{month_no}", int.to_string(month_to_int(date.month)))
|> string.replace(
"{month_no0}",
string.pad_left(int.to_string(month_to_int(date.month)), 2, "0"),
)
|> string.replace("{year}", int.to_string(date.year))
}
/// Format a date in the ISO 8601 format.

View file

@ -8,7 +8,7 @@ pub type DateTime
/// Get a Luxon DateTime in the given timezone.
pub fn date_time_in_zone(date: Date, time: Time, tz: String) {
let datetime_str = date.format_iso(date) <> "T" <> time.format(time)
let datetime_str = date.format_iso(date) <> "T" <> time.format_iso(time)
do_date_time_in_zone(datetime_str, tz)
}

View file

@ -1,6 +1,8 @@
import gleam/int
import gleam/order.{type Order, Eq}
import gleam/string
import kielet.{gettext as g_}
import kielet/context.{type Context}
import scriptorium/utils/ints/hour.{type Hour}
import scriptorium/utils/ints/minute.{type Minute}
@ -32,8 +34,28 @@ pub fn parse(str: String) {
}
}
/// Format a time to an `hh:mm` format string.
pub fn format(time: Time) -> String {
/// Format a time to a string.
pub fn format(time: Time, context: Context) -> String {
let hrs = hour.to_int(time.hours)
let mins = minute.to_int(time.minutes)
let period = get_period(hrs, context)
g_(context, "{h24_0}:{min_0}")
|> string.replace("{h24_0}", pad(int.to_string(hrs)))
|> string.replace("{h24}", int.to_string(hrs))
|> string.replace("{h12_0}", pad(int.to_string(hrs % 12)))
|> string.replace("{h12}", int.to_string(hrs % 12))
|> string.replace("{min_0}", pad(int.to_string(mins)))
|> string.replace("{min}", int.to_string(mins))
|> string.replace(
"{period}",
string.slice(period, 5, string.length(period) - 5),
)
}
/// Format a time to an `hh:mm` 24 hour string.
pub fn format_iso(time: Time) {
pad(int.to_string(hour.to_int(time.hours)))
<> ":"
<> pad(int.to_string(minute.to_int(time.minutes)))
@ -49,3 +71,32 @@ pub fn nil_time() {
fn pad(part: String) {
string.pad_left(part, 2, "0")
}
fn get_period(hour: Int, context: Context) {
case hour {
0 -> g_(context, "<00> am")
1 -> g_(context, "<01> am")
2 -> g_(context, "<02> am")
3 -> g_(context, "<03> am")
4 -> g_(context, "<04> am")
5 -> g_(context, "<05> am")
6 -> g_(context, "<06> am")
7 -> g_(context, "<07> am")
8 -> g_(context, "<08> am")
9 -> g_(context, "<09> am")
10 -> g_(context, "<10> am")
11 -> g_(context, "<11> am")
12 -> g_(context, "<12> pm")
13 -> g_(context, "<13> pm")
14 -> g_(context, "<14> pm")
15 -> g_(context, "<15> pm")
16 -> g_(context, "<16> pm")
17 -> g_(context, "<17> pm")
18 -> g_(context, "<18> pm")
19 -> g_(context, "<19> pm")
20 -> g_(context, "<20> pm")
21 -> g_(context, "<21> pm")
22 -> g_(context, "<22> pm")
_ -> g_(context, "<23> pm")
}
}