From 093ef72e6489d96fb6ffae8d58d7cb1cb7ff77ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 22 Feb 2022 11:19:19 +0100 Subject: Prepare code for translation. --- module/calp/entry-points/benchmark.scm | 8 +- module/calp/entry-points/convert.scm | 13 +-- module/calp/entry-points/html.scm | 51 ++++++------ module/calp/entry-points/ical.scm | 8 +- module/calp/entry-points/import.scm | 38 +++++---- module/calp/entry-points/server.scm | 38 +++++---- module/calp/entry-points/terminal.scm | 7 +- module/calp/entry-points/text.scm | 15 ++-- module/calp/entry-points/tidsrapport.scm | 24 +++--- module/calp/html/caltable.scm | 4 + module/calp/html/components.scm | 3 +- module/calp/html/config.scm | 5 +- module/calp/html/util.scm | 5 +- module/calp/html/vcomponent.scm | 103 ++++++++++++++---------- module/calp/html/view/calendar.scm | 53 +++++++------ module/calp/html/view/calendar/week.scm | 9 ++- module/calp/html/view/search.scm | 13 +-- module/calp/main.scm | 118 ++++++++++++++-------------- module/calp/repl.scm | 9 ++- module/calp/server/routes.scm | 41 ++++++---- module/calp/server/server.scm | 1 + module/calp/terminal.scm | 54 ++++++++----- module/calp/translation.scm | 20 +++++ module/calp/util/config.scm | 12 +-- module/calp/util/exceptions.scm | 3 +- module/datetime/instance.scm | 5 +- module/datetime/timespec.scm | 3 +- module/datetime/zic.scm | 20 ++--- module/vcomponent/datetime/output.scm | 11 ++- module/vcomponent/formats/common/types.scm | 11 +-- module/vcomponent/formats/ical/output.scm | 3 +- module/vcomponent/formats/ical/parse.scm | 29 +++++-- module/vcomponent/formats/ical/types.scm | 8 +- module/vcomponent/formats/vdir/parse.scm | 3 +- module/vcomponent/formats/xcal/output.scm | 3 +- module/vcomponent/formats/xcal/parse.scm | 5 +- module/vcomponent/formats/xcal/types.scm | 3 +- module/vcomponent/util/instance.scm | 3 +- module/vcomponent/util/instance/methods.scm | 4 +- module/vcomponent/util/parse-cal-path.scm | 5 +- 40 files changed, 452 insertions(+), 319 deletions(-) create mode 100644 module/calp/translation.scm diff --git a/module/calp/entry-points/benchmark.scm b/module/calp/entry-points/benchmark.scm index 5db9b9df..31ea958a 100644 --- a/module/calp/entry-points/benchmark.scm +++ b/module/calp/entry-points/benchmark.scm @@ -5,6 +5,8 @@ :use-module (hnh util options) :use-module ((srfi srfi-41) :select (stream->list)) + :use-module (calp translation) + :use-module ((vcomponent util instance methods) :select (get-event-set)) :autoload (vcomponent util instance) (global-event-object) @@ -15,9 +17,9 @@ (define opt-spec `((enable-output (single-char #\o) (description - "Output is be default supressed, since many fields contain way to much data " - "to read. This turns it on again.")) - (help (single-char #\h) (description "Print this help.")))) + ,(_ "Output is by default supressed, since many fields contain way to much data to read. This turns it on again.") + )) + (help (single-char #\h) (description ,(_ "Print this help."))))) (define (main args) diff --git a/module/calp/entry-points/convert.scm b/module/calp/entry-points/convert.scm index 3f602b07..5f298de4 100644 --- a/module/calp/entry-points/convert.scm +++ b/module/calp/entry-points/convert.scm @@ -4,18 +4,19 @@ :use-module (hnh util options) :use-module (ice-9 getopt-long) :use-module (sxml simple) + :use-module (calp translation) ) (define opt-spec - `((from (single-char #\f) (value (options "xcal" "ical")) - (description "Input format (infered from " (i "infile") ")")) + `((from (single-char #\f) (value (options "xcal" "ical")) + (description ,(xml->sxml (_ "Input format (otherwise infered from infile)")))) (to (single-char #\t) (value (options "xcal" "ical")) - (description "Output format (infered from " (i "outfile") ")")) - (infile (value #t) (single-char #\i) (description "Input file")) - (outfile (value #t) (single-char #\o) (description "Output file")) - (help (single-char #\h) (description "Print this help.")))) + (description ,(xml->sxml (_ "Output format (otherwise infered from outfile)")))) + (infile (value #t) (single-char #\i) (description ,(_ "Input file"))) + (outfile (value #t) (single-char #\o) (description ,(_ "Output file"))) + (help (single-char #\h) (description ,(_ "Print this help."))))) (define (filename-to-type filename) diff --git a/module/calp/entry-points/html.scm b/module/calp/entry-points/html.scm index 7c4fe257..2a559794 100644 --- a/module/calp/entry-points/html.scm +++ b/module/calp/entry-points/html.scm @@ -18,9 +18,10 @@ :use-module ((vcomponent util instance methods) :select (get-calendars get-event-set)) - :use-module ((sxml simple) :select (sxml->xml)) + :use-module ((sxml simple) :select (sxml->xml xml->sxml)) :use-module ((sxml transformations) :select (href-transformer)) :use-module ((xdg basedir) :prefix xdg-) + :use-module (calp translation) :autoload (vcomponent util instance) (global-event-object) ) @@ -28,39 +29,35 @@ (define opt-spec `((from (value #t) (single-char #\F) - (description "Start date of output.") + (description ,(_ "Start date of output.")) ) (count (value #t) - (description "How many pages should be rendered." - "If --style=" (b "week") " and --from=" (b "2020-04-27") - " then --count=" (b 4) " would render the four pages " - "2020-04-27, 2020-05-04, 2020-05-11, and 2020-05-25. " - "Defaults to 12 to give a whole year when --style=" (b "month") "." - )) + (description ,(xml->sxml (_ "How many pages should be rendered. +If --style=week and --from=2020-04-27; +then --count=4 would render the four pages +2020-04-27, 2020-05-04, 2020-05-11, and 2020-05-25. +Defaults to 12 to give a whole year when --style=month")))) (target (single-char #\t) (value #t) - (description "Directory where html files should end up. Default to " (b "./html"))) + (description ,(xml->sxml (_ "Directory where html files should end up. Default to ./html")))) (style (value #t) (predicate ,(lambda (v) (memv (string->symbol v) '(small wide week table)))) - (description "How the body of the HTML page should be layed out. " - (br) (b "week") - " gives a horizontally scrolling page with 7 elements, " - "where each has events graphically laid out hour by hour." - (br) (b "table") - " gives a month in overview as a table. Each block contains " - "the events for the given day, in order of start time. They are " - "however not graphically sized. " - (br) (b "wide") - " is the same as week, but gives a full month.") - ) + (description ,(xml->sxml (_ "How the body of the HTML page should be layed out. +
week +gives a horizontally scrolling page with 7 elements, where each has events +graphically laid out hour by hour. +
table +gives a month in overview as a table. Each block contains the events for the +given day, in order of start time. They are however not graphically sized. +
wide +is the same as week, but gives a full month.
")))) (standalone - (description "Creates a standalone document instead of an HTML fragment " - "for embedding in a larger page. Currently only applies to the " - (i "small") "style")) + (description ,(xml->sxml (_ "Creates a standalone document instead of an HTML fragment +for embedding in a larger page. Currently only applies to the small style")))) - (help (single-char #\h) (description "Print this help.")))) + (help (single-char #\h) (description ,(_ "Print this help."))))) @@ -99,7 +96,7 @@ (stream-for-each (lambda (start-date) (define fname (path-append target-directory (date->string start-date "~1.xml"))) - (format (current-error-port) "Writing to [~a]~%" fname) + (format (current-error-port) (_ "Writing to [~a]~%") fname) (with-output-to-file fname (lambda () (sxml->xml (re-root-static (apply html-generate @@ -167,7 +164,7 @@ pre-start: (start-of-week start) post-end: (end-of-week (end-of-month start)))] [else - (error "Unknown html style: ~a" style)]) + (error (_ "Unknown html style: ~a") style)]) - ((@ (calp util time) report-time!) "all done") + ((@ (calp util time) report-time!) (_ "all done")) ) diff --git a/module/calp/entry-points/ical.scm b/module/calp/entry-points/ical.scm index 938b0b35..e164c340 100644 --- a/module/calp/entry-points/ical.scm +++ b/module/calp/entry-points/ical.scm @@ -5,14 +5,16 @@ :use-module (vcomponent formats ical output) :use-module (ice-9 getopt-long) :use-module (datetime) + :use-module (calp translation) + :use-module (calp translation) ) (define opt-spec - '((from (value #t) (single-char #\F)) + `((from (value #t) (single-char #\F)) (to (value #t) (single-char #\T) - (description "Returns all elements between these two dates.")) + (description ,(_ "Returns all elements between these two dates."))) (help (single-char #\h) - (description "Print this help.")))) + (description ,(_ "Print this help."))))) (define (main args) (define opts (getopt-long args (getopt-opt opt-spec))) diff --git a/module/calp/entry-points/import.scm b/module/calp/entry-points/import.scm index 441ff527..28fb72a6 100644 --- a/module/calp/entry-points/import.scm +++ b/module/calp/entry-points/import.scm @@ -11,16 +11,17 @@ :use-module (vcomponent) ;; :use-module ((vcomponent formats ical parse) :select (parse-cal-path)) :use-module ((vcomponent util parse-cal-path) :select (parse-cal-path)) + :use-module (calp translation) :autoload (vcomponent util instance) (global-event-object) ) (define options - '((calendar (value #t) (single-char #\c) - (description "Name of calendar to import into")) + `((calendar (value #t) (single-char #\c) + (description ,(_ "Name of calendar to import into"))) (file (value #t) (single-char #\f) - (description "ics file to import")) + (description ,(_ "ics file to import"))) (help (single-char #\h) - (description "Print this help.")))) + (description ,(_ "Print this help."))))) (define (main args) (define opts (getopt-long args (getopt-opt options))) @@ -39,27 +40,24 @@ (get-calendars global-event-object))))) (unless calendar - (format (current-error-port) "No calendar named ~s~%" cal-name) + (format (current-error-port) (_ "No calendar named ~s~%") cal-name) (throw 'return)) (let ((new-events (parse-cal-path fname))) - (format #t "About to the following ~a events into ~a~%~{~a~^~%~}~%" + (format #t (_ "About to import the following ~a events into ~a~%") (length (children new-events)) - (prop calendar 'NAME) + (prop calendar 'NAME)) + (format #t "~{~a~^~%~}~%" (map (extract 'SUMMARY) (children new-events))) - (format #t "Continue? [Y/n] ") + (format #t (_ "Continue? [Y/n] ")) - (let loop ((c #\space)) - (case c - [(#\n #\N) (throw 'return)] - [(#\y #\Y) (map (lambda (e) - (add-event calendar e) - (save-event e)) - (children new-events))] - [else - (let ((line (read-line))) - (loop (if (string-null? line) - #\Y (string-ref line 0))))])) - ))) + (let loop ((line (read-line))) + (case (if (string-null? line) 'yes (yes-no-check line)) + [(no) (throw 'return)] + [(yes) (map (lambda (e) + (add-event calendar e) + (save-event e)) + (children new-events))] + [else (loop line (read-line))]))))) diff --git a/module/calp/entry-points/server.scm b/module/calp/entry-points/server.scm index c9ff339a..d42a5d3a 100644 --- a/module/calp/entry-points/server.scm +++ b/module/calp/entry-points/server.scm @@ -6,6 +6,8 @@ :use-module (srfi srfi-1) :use-module (ice-9 getopt-long) + :use-module (calp translation) + :use-module (sxml simple) :use-module ((calp server server) :select (start-server)) @@ -13,25 +15,23 @@ (define options - '((port (value #t) (single-char #\p) - (description "Bind to TCP port, defaults to " (i 8080) "." - (br) "Can also be set through the config variable " - (i "port") ".")) + `((port (value #t) (single-char #\p) + (description ,(xml->sxml (_ "Bind to TCP port, defaults to 8080. +
Can also be set through the config variable +port.
")))) (addr (value #t) - - (description "Address to use, defaults to " (i "0.0.0.0") - " for IPv4, and " (i "[::]") " for IPv6.") - ) + (description ,(xml->sxml (_ "Address to use, defaults to 0.0.0.0 for IPv4, +and [::] for IPv6")))) ;; numbers as single-char doesn't work. - (six (description "Use IPv6.")) - (four (description "Use IPv4.")) - (sigusr (description "Reload events on SIGUSR1")) + (six (description ,(_ "Use IPv6."))) + (four (description ,(_ "Use IPv4."))) + (sigusr (description ,(_ "Reload events on SIGUSR1"))) (help (single-char #\h) - (description "Print this help.")))) + (description ,(_ "Print this help."))))) (define-config port 8080 - description: "Port to which the web server should bind.") + description: (_ "Port to which the web server should bind.")) (define-public (main args) @@ -60,18 +60,22 @@ "::" "0.0.0.0"))) (when (option-ref opts 'sigusr #f) - (display "Listening for SIGUSR1\n" (current-error-port)) + (format (current-error-port) (_ "Listening for SIGUSR1~%")) ;; NOTE this uses the main thread, and does therefore block HTTP requests ;; while reloading. However, it appears to not cause any race conditions. (sigaction SIGUSR1 (lambda _ - (display "Received SIGUSR1, reloading calendars\n" - (current-error-port)) + (format (current-error-port) (_ "Received SIGUSR1, reloading calendars~%")) ((@ (vcomponent util instance) reload))))) - (format #t "Starting server on ~a:~a~%I'm ~a, runing from ~a~%" + ;; Arguments are + ;; IP-address which we bind to + ;; Port which we listen to + ;; PID of this process + ;; PWD of this process + (format #t (_ "Starting server on ~a:~a~%I'm ~a, runing from ~a~%") addr port (getpid) (getcwd)) diff --git a/module/calp/entry-points/terminal.scm b/module/calp/entry-points/terminal.scm index b0be318c..dd35b8f3 100644 --- a/module/calp/entry-points/terminal.scm +++ b/module/calp/entry-points/terminal.scm @@ -6,12 +6,13 @@ :use-module (datetime) :use-module (vulgar) :use-module (hnh util options) + :use-module (calp translation) ) (define options - '((date (value #t) (single-char #\d) - (description "Which date to start on.")) - (help (single-char #\t) (description "Print this help.")) + `((date (value #t) (single-char #\d) + (description ,(_ "Which date to start on."))) + (help (single-char #\t) (description ,(_ "Print this help."))) )) (define (main args) diff --git a/module/calp/entry-points/text.scm b/module/calp/entry-points/text.scm index 0a5744b3..921afb80 100644 --- a/module/calp/entry-points/text.scm +++ b/module/calp/entry-points/text.scm @@ -4,16 +4,18 @@ :use-module (ice-9 getopt-long) :use-module (hnh util io) :use-module (hnh util options) + :use-module (calp translation) + :use-module (sxml simple) ) (define options - '((width (value #t) (single-char #\w) - (description "Width of written text, defaults to 70 chars.")) + `((width (value #t) (single-char #\w) + (description ,(_ "Width of written text, defaults to 70 chars."))) (file (value #t) (single-char #\f) - (description "Read from " (i "file") " instead of standard input.")) + (description ,(xml->sxml (_ "Read from file instead of standard input.")))) (help (single-char #\h) - (description "Prints this help.")))) + (description ,(_ "Prints this help."))))) (define (main args) (define opts (getopt-long args (getopt-opt options))) @@ -24,6 +26,9 @@ (for-each (lambda (l) (display l) (newline)) (flow-text - (with-input-from-port (open-input-port (option-ref opts 'file "-")) + (with-input-from-port (let ((fname (option-ref opts 'file "-"))) + (if (string=? fname "-") + (current-input-port) + (open-input-file fname))) (@ (ice-9 rdelim) read-string)) #:width (or (string->number (option-ref opts 'width "")) 70)))) diff --git a/module/calp/entry-points/tidsrapport.scm b/module/calp/entry-points/tidsrapport.scm index 5ff43cf7..a05c3b78 100644 --- a/module/calp/entry-points/tidsrapport.scm +++ b/module/calp/entry-points/tidsrapport.scm @@ -42,6 +42,8 @@ :use-module (hnh util) :use-module (hnh util options) :use-module (ice-9 getopt-long) + :use-module (calp translation) + :use-module (sxml simple) :use-module (datetime) ) @@ -165,20 +167,20 @@ trailer ) (define opt-spec - '((pdf (value #t) - (description "Input pdf fill")) + `((pdf (value #t) + (description ,(_ "Input pdf file"))) (output (single-char #\o) (value optional) - (description "Output file")) + (description ,(_ "Output file"))) (data (value optional) - (description "Static data to fill fields with") + (description ,(_ "Static data to fill fields with")) ) (template (value optional) - (description "Map between real field names and human readable names." (br) - "If data is given, but not trans, then data is assumed to be in a correct format")) + (description ,(xml->sxml (_ "Map between real field names and human readable names.
+If data is given, but not trans, then data is assumed to be in a correct format
")))) (search (value #t) (description - "Search term for dynamic filling. Supports basic globbing")))) + ,(_ "Search term for dynamic filling. Supports basic globbing"))))) (define (parse-search str) (cond [(string-match "\\{(.*)\\}" str) @@ -204,7 +206,7 @@ trailer (define template (call-with-input-file (or (option-ref opts 'template #f) - (error "Template required")) + (error (_ "Template required"))) read)) (define prepared-data @@ -232,9 +234,9 @@ trailer (define days (let ((days (assoc-ref group 'days))) (cond ((not (list? days)) - (error "Needs list, not pair")) + (error (_ "Needs list, not pair"))) ((null? days) - (error "Need more days")) + (error (_ "Need more days"))) ((and (list? (car days)) (eqv? '- (caar days))) (map (lambda (s) (string-append prefix (->string s))) (iota (1+ (- (list-ref (car days) 2) @@ -250,7 +252,7 @@ trailer ,@(build-alist work-hours days) (,sum ,(apply + work-hours)))) (or (assoc-ref template 'groups) - (error "Groups required in template")) + (error (_ "Groups required in template"))) search))) (define report diff --git a/module/calp/html/caltable.scm b/module/calp/html/caltable.scm index dd2d4b03..77580844 100644 --- a/module/calp/html/caltable.scm +++ b/module/calp/html/caltable.scm @@ -1,4 +1,5 @@ (define-module (calp html caltable) + :use-module (hnh util) :use-module (calp html util) :use-module (datetime) @@ -35,6 +36,7 @@ ;; making the text red for all holidays, or creating a yellow background ;; for events from a specific source. (time (@ (datetime ,(date->string date "~Y-~m-~d"))) + ;; TODO should this field be translated? ,(day date))))) (define month-start (start-of-month start-date)) @@ -49,11 +51,13 @@ ;; top row, names of week days ,@(map (lambda (d) `(div (@ (class "column-head")) + ;; TODO this SHOULD be translated ,(string-titlecase (week-day-name d 2)))) (weekday-list)) ;; left columun, week numbers ,@(map (lambda (v) `(div (@ (class "row-head")) ,v)) + ;; TODO translate this (map week-number (stream->list (stream-take-while (lambda (s) (date<= s post-end)) diff --git a/module/calp/html/components.scm b/module/calp/html/components.scm index 2f8c85ec..0d6fbf1c 100644 --- a/module/calp/html/components.scm +++ b/module/calp/html/components.scm @@ -2,6 +2,7 @@ :use-module (hnh util) :use-module (ice-9 curried-definitions) :use-module (ice-9 match) + :use-module (calp translation) :export (xhtml-doc) ) @@ -57,7 +58,7 @@ allow-other-keys: rest: args) (when (and onclick href) - (error "Only give one of onclick, href and submit.")) + (error (_ "Only give one of onclick, href and submit."))) (let ((body #f)) `(,(cond [href 'a] diff --git a/module/calp/html/config.scm b/module/calp/html/config.scm index 6bd1e0ec..08a4b2e8 100644 --- a/module/calp/html/config.scm +++ b/module/calp/html/config.scm @@ -1,11 +1,12 @@ (define-module (calp html config) :use-module (hnh util) :use-module (calp util config) + :use-module (calp translation) ) (define-public debug (make-parameter #f)) (define-config debug #f - description: "Places the generated thingy in debug mode" + description: (_ "Places the generated thingy in debug mode") post: debug) @@ -13,6 +14,6 @@ ;;; but this works for the time being. (define-public edit-mode (make-parameter #t)) (define-config edit-mode #t - description: "Makes the document editable" + description: (_ "Makes the document editable") post: edit-mode) diff --git a/module/calp/html/util.scm b/module/calp/html/util.scm index 75137d4e..aa3d9233 100644 --- a/module/calp/html/util.scm +++ b/module/calp/html/util.scm @@ -1,5 +1,6 @@ (define-module (calp html util) - :use-module (hnh util)) + :use-module (hnh util) + :use-module (calp translation)) (define-public (date-link date) @@ -30,6 +31,6 @@ #xFF)) "#000000" "#FFFFFF"))) (lambda args - (format (current-error-port) "Error calculating foreground color?~%~s~%" args) + (format (current-error-port) (_ "Error calculating foreground color?~%~s~%") args) "#FF0000" ))) diff --git a/module/calp/html/vcomponent.scm b/module/calp/html/vcomponent.scm index 16f418c5..ffdd37e2 100644 --- a/module/calp/html/vcomponent.scm +++ b/module/calp/html/vcomponent.scm @@ -24,6 +24,7 @@ )) :use-module ((calp util config) :select (get-config)) :use-module ((base64) :select (base64encode)) + :use-module (calp translation) ) ;; used by search view @@ -45,10 +46,13 @@ "unknown"))))) (time ,(let ((dt (prop event 'DTSTART))) (if (datetime? dt) - (datetime->string dt "~Y-~m-~d ~H:~M") - (date->string dt "~Y-~m-~d" )))) + ;; Compact event list date + time + (datetime->string dt (_ "~Y-~m-~d ~H:~M")) + ;; Compact event list date only + (date->string dt (_ "~Y-~m-~d") )))) (a (@ (href ,(date->string (as-date (prop event 'DTSTART)) "/week/~Y-~m-~d.html"))) - "View 📅") + ;; Button for viewing calendar, accompanied by a calendar icon + ,(_ "View") " 📅") (span ,(prop event 'SUMMARY))))) (cons (calendar-styles calendars) @@ -86,6 +90,7 @@ (data-property "summary")) ,(prop ev 'SUMMARY)))) (div + ;; TODO localize this? ,(call-with-values (lambda () (fmt-time-span ev)) (case-lambda [(start) `(div (time (@ (class "dtstart") @@ -118,7 +123,7 @@ (div (@ (class "fields")) ,(when (and=> (prop ev 'LOCATION) (negate string-null?)) - `(div (b "Plats: ") + `(div (b ,(_ "Location: ")) (div (@ (class "location") (data-property "location")) ,(string-map (lambda (c) (if (char=? c #\,) #\newline c)) (prop ev 'LOCATION))))) @@ -195,8 +200,10 @@ ,@(format-recurrence-rule ev))) ,(when (prop ev 'LAST-MODIFIED) - `(div (@ (class "last-modified")) "Senast Ă€ndrad " - ,(datetime->string (prop ev 'LAST-MODIFIED) "~1 ~H:~M")))) + `(div (@ (class "last-modified")) ,(_ "Last modified") " " + ,(datetime->string (prop ev 'LAST-MODIFIED) + ;; Last modified datetime + (_ "~1 ~H:~M"))))) )))) @@ -206,7 +213,9 @@ (define-public (fmt-day day) (let* (((date . events) day)) `(section (@ (class "text-day")) - (header (h2 ,(let ((s (date->string date "~Y-~m-~d"))) + (header (h2 ,(let ((s (date->string date + ;; Header for sidebar day + (_ "~Y-~m-~d")))) `(a (@ (href "#" ,s) (class "hidelink")) ,s)))) ,@(stream->list @@ -291,12 +300,13 @@ ;; TODO possibly unused? (define (repeat-info event) `(div (@ (class "eventtext")) - (h2 "Upprepningar") + (h2 ,(_ "Recurrences")) (table (@ (class "recur-components")) ,@((@@ (vcomponent recurrence internal) map-fields) (lambda (key value) `(tr (@ (class ,key)) (th ,key) (td + ;; TODO Should these date string be translated? ,(case key ((wkst) (week-day-name value)) ((until) (if (date? value) @@ -341,6 +351,7 @@ `(select (@ ,@args) (option "-") ,@(map (lambda (x) `(option (@ (value ,(car x))) ,(cadr x))) + ;; TODO translate '((MO "Monday") (TU "Tuesday") (WE "Wednesday") @@ -360,7 +371,8 @@ (div (@ (class " eventtext edit-tab ")) (form (@ (class "edit-form")) (select (@ (class "calendar-selection")) - (option "- Choose a Calendar -") + ;; NOTE flytta "muffarna" utanför + (option ,(_ "- Choose a Calendar -")) ,@(let ((dflt (get-config 'default-calendar))) (map (lambda (calendar) (define name (prop calendar 'NAME)) @@ -370,7 +382,7 @@ ,name)) calendars))) (h3 (input (@ (type "text") - (placeholder "Sammanfattning") + (placeholder ,(_ "Summary")) (name "summary") (required) (data-property "summary") ; (value ,(prop ev 'SUMMARY)) @@ -379,24 +391,24 @@ (div (@ (class "timeinput")) ,@(with-label - "Starttid" + (_ "Start time") '(date-time-input (@ (name "dtstart") (data-property "dtstart") ))) ,@(with-label - "Sluttid" + (_ "End time") '(date-time-input (@ (name "dtend") (data-property "dtend")))) (div (@ (class "checkboxes")) ,@(with-label - "Heldag?" + (_ "Whole day?") `(input (@ (type "checkbox") (name "wholeday") ))) ,@(with-label - "Upprepande?" + (_ "Recurring?") `(input (@ (type "checkbox") (name "has_repeats") )))) @@ -404,8 +416,8 @@ ) ,@(with-label - "Plats" - `(input (@ (placeholder "Plats") + (_ "Location") + `(input (@ (placeholder ,(_ "Location")) (name "location") (type "text") (data-property "location") @@ -413,20 +425,20 @@ ))) ,@(with-label - "Beskrivning" - `(textarea (@ (placeholder "Beskrivning") + (_ "Description") + `(textarea (@ (placeholder ,(_ "Description")) (data-property "description") (name "description")) ; ,(prop ev 'DESCRIPTION) )) ,@(with-label - "Kategorier" + (_ "Categories") `(input-list (@ (name "categories") (data-property "categories")) (input (@ (type "text") - (placeholder "Kattegori"))))) + (placeholder (_ "Category")))))) ;; TODO This should be a "list" where any field can be edited ;; directly. Major thing holding us back currently is that @@ -458,6 +470,7 @@ "â†ș") (span (@ (class "summary") (data-property "summary"))))) + ;; TODO should't the time tags contain something? (div (div (time (@ (class "dtstart") (data-property "dtstart") (data-fmt "~L~H:~M") @@ -474,7 +487,7 @@ ; "20:56" )) (div (@ (class "fields")) - (div (b "Plats: ") + (div (b ,("Location: ")) (div (@ (class "location") (data-property "location")) ; "AlsĂ€ttersgatan 13" @@ -496,7 +509,7 @@ ;; "varje vecka" ;; ".") (div (@ (class "last-modified")) - "Senast Ă€ndrad -" + ,(_ "Last Modified") " -" ; "2021-09-29 19:56" )))))) @@ -504,21 +517,21 @@ `(template (@ (id "vevent-edit-rrule")) (div (@ (class "eventtext")) - (h2 "Upprepningar") + (h2 ,(_ "Recurrences")) (dl - (dt "Frequency") + (dt ,(_ "Frequency")) (dd (select (@ (name "freq")) (option "-") ,@(map (lambda (x) `(option (@ (value ,x)) ,(string-titlecase (symbol->string x)))) '(SECONDLY MINUTELY HOURLY DAILY WEEKLY MONTHLY YEARLY)))) - (dt "Until") + (dt ,(_ "Until")) (dd (date-time-input (@ (name "until")))) - (dt "Conut") + (dt ,(_ "Conut")) (dd (input (@ (type "number") (name "count") (min 0)))) - (dt "Interval") + (dt ,(_ "Interval")) (dd (input (@ (type "number") (name "interval") ; min and max depend on FREQ ))) @@ -532,14 +545,14 @@ (dd (input-list (@ (name ,name)) (input (@ (type "number") (min ,min) (max ,max))))))) - '((bysecond "By Second" 0 60) - (byminute "By Minute" 0 59) - (byhour "By Hour" 0 23) - (bymonthday "By Month Day" -31 31) ; except 0 - (byyearday "By Year Day" -366 366) ; except 0 - (byweekno "By Week Number" -53 53) ; except 0 - (bymonth "By Month" 1 12) - (bysetpos "By Set Position" -366 366) ; except 0 + '((bysecond ,(_ "By Second") 0 60) + (byminute ,(_ "By Minute") 0 59) + (byhour ,(_ "By Hour") 0 23) + (bymonthday ,(_ "By Month Day") -31 31) ; except 0 + (byyearday ,(_ "By Year Day") -366 366) ; except 0 + (byweekno ,(_ "By Week Number") -53 53) ; except 0 + (bymonth ,(_ "By Month") 1 12) + (bysetpos ,(_ "By Set Position") -366 366) ; except 0 ))) ;; (dt "By Week Day") @@ -550,7 +563,7 @@ ;; ,(week-day-select '()) ;; )) - (dt "Weekstart") + (dt ,(_ "Weekstart")) (dd ,(week-day-select '((name "wkst"))))))) ) @@ -565,32 +578,36 @@ (nav (@ (class "popup-control")) (button (@ (class "close-button") - (title "StĂ€ng") + ;; Close this popup + (title ,(_ "Close")) (aria-label "Close")) "×") (button (@ (class "maximize-button") - (title "FullskĂ€rm") + ;; Make this popup occupy the entire screen + (title ,(_ "Fullscreen")) ;; (aria-label "") ) "🗖") (button (@ (class "remove-button") - (title "Ta Bort")) + ;; Remove/Trash the event this popup represent + ;; Think garbage can + (title ,(_ "Remove"))) "🗑")) (tab-group (@ (class "window-body")) (vevent-description - (@ (data-label "📅") (data-title "Översikt") + (@ (data-label "📅") (data-title ,(_ "Overview")) (class "vevent"))) (vevent-edit - (@ (data-label "🖊") (data-title "Redigera"))) + (@ (data-label "🖊") (data-title ,(_ "Edit")))) ;; (vevent-edit-rrule ;; (@ (data-label "â†ș") (data-title "Upprepningar"))) (vevent-changelog - (@ (data-label "📒") (date-title "Changelog"))) + (@ (data-label "📒") (date-title ,(_ "Changelog")))) ,@(when (debug) '((vevent-dl - (@ (data-label "🐾") (data-title "Debug"))))))))) + (@ (data-label "🐾") (data-title ,(_ "Debug")))))))))) diff --git a/module/calp/html/view/calendar.scm b/module/calp/html/view/calendar.scm index ecdce291..c7a5c8c2 100644 --- a/module/calp/html/view/calendar.scm +++ b/module/calp/html/view/calendar.scm @@ -27,6 +27,7 @@ :use-module ((vcomponent util group) :select (group-stream get-groups-between)) :use-module ((base64) :select (base64encode)) + :use-module (calp translation) ) @@ -72,10 +73,10 @@ ,display))) (unless next-start - (error 'html-generate "Next-start needs to be a procedure")) + (error 'html-generate (_ "Next-start needs to be a procedure"))) (unless prev-start - (error 'html-generate "Prev-start needs to be a procedure")) + (error 'html-generate (_ "Prev-start needs to be a procedure"))) (xhtml-doc (@ (lang sv)) @@ -86,9 +87,11 @@ (meta (@ (name viewport) (content "width=device-width, initial-scale=0.5"))) (meta (@ (name description) - (content "Calendar for the dates between " - ,(date->string start-date) " and " - ,(date->string end-date)))) + (content ,(format #f (_ "Calendar for the dates between ~a and ~a") + ;; start date metainfo + (date->string start-date (_ "~Y-~m-~d")) + ;; end date metainfo + (date->string end-date (_ "~Y-~m-~d")))))) ;; NOTE this is only for the time actually part of this calendar. ;; overflowing times from pre-start and post-end is currently ignored here. (meta (@ (name start-time) @@ -148,10 +151,12 @@ window.default_calendar='~a';" ;; Page footer (footer (@ (style "grid-area: footer")) - (span "Page generated " ,(date->string (current-date))) - (span "Current time " (current-time (@ (interval 1)))) + (span ,(_ "Page generated ") + ;; Generation data + ,(date->string (current-date) (_ "~Y-~m-~d"))) + (span ,(_ "Current time ") (current-time (@ (interval 1)))) (span (a (@ (href ,(repo-url))) - "Source Code"))) + ,(_ "Source Code")))) ;; Small calendar and navigation (nav (@ (class "calnav") (style "grid-area: nav")) @@ -161,10 +166,12 @@ window.default_calendar='~a';" (start-of-week start-date) start-date) "/week/~1.html") - "veckovy") + ;; Button to view week + (_ "Week")) ,(btn href: (date->string (set (day start-date) 1) "/month/~1.html") - "mĂ„nadsvy") + ;; button to view month + (_ "Month")) (today-button (a (@ (class "btn") @@ -173,7 +180,8 @@ window.default_calendar='~a';" [(month) "view=month"] [(week) "view=week"] [else ""])))) - "idag"))) + ;; Button to go to today + ,(_ "Today")))) (div (@ (id "jump-to")) ;; Firefox's accessability complain about each date @@ -193,9 +201,11 @@ window.default_calendar='~a';" ,(btn "➔")))) (details (@ (open) (style "grid-area: cal")) - (summary "Month overview") + (summary ,(_ "Month overview")) (div (@ (class "smallcall-head")) - ,(string-titlecase (date->string start-date "~B ~Y"))) + ,(string-titlecase (date->string start-date + ;; Header of small calendar + (_ "~B ~Y")))) ;; NOTE it might be a good idea to put the navigation buttons ;; earlier in the DOM-tree/tag order. At least Vimium's ;; @key{[[} keybind sometimes finds parts of events instead. @@ -220,17 +230,17 @@ window.default_calendar='~a';" (action "/search/text")) (input (@ (type "text") (name "q") - (placeholder "Sök"))) + ;; Search placeholder + (placeholder ,(_ "Search")))) (input (@ (type "submit") (value ">")))) ,(when (or (debug) (edit-mode)) `(details (@ (class "sliders")) - (summary "Option sliders") - + (summary ,(_ "Option sliders")) ,@(when (edit-mode) - `((label "Event blankspace") + `((label ,(_ "Event blankspace")) ,(slider-input variable: "editmode" min: 0 @@ -239,7 +249,7 @@ window.default_calendar='~a';" value: 1))) ,@(when (debug) - `((label "Fontsize") + `((label ,(_ "Fontsize")) ,(slider-input unit: "pt" min: 1 @@ -250,7 +260,7 @@ window.default_calendar='~a';" ;; List of calendars (details (@ (class "calendarlist")) - (summary "Calendar list") + (summary ,(_ "Calendar list")) (ul ,@(map (lambda (calendar) `(li (@ (data-calendar ,(base64encode (prop calendar 'NAME)))) @@ -276,7 +286,7 @@ window.default_calendar='~a';" ;; Events which started before our start point, ;; but "spill" into our time span. (section (@ (class "text-day")) - (header (h2 "Tidigare")) + (header (h2 ,(_ "Earlier"))) ;; TODO this group gets styles applied incorrectly. ;; Figure out way to merge it with the below call. ,@(stream->list @@ -284,8 +294,7 @@ window.default_calendar='~a';" (lambda (ev) (fmt-single-event ev `((id ,(html-id ev)) - (data-calendar ,(base64encode (or (prop (parent ev) 'NAME) - "unknown")))))) + (data-calendar ,(base64encode (or (prop (parent ev) 'NAME) "unknown")))))) (stream-take-while (compose (cut date/-time start-date) (extract 'DTSTART)) diff --git a/module/calp/html/view/calendar/week.scm b/module/calp/html/view/calendar/week.scm index 5b12a351..921bdb83 100644 --- a/module/calp/html/view/calendar/week.scm +++ b/module/calp/html/view/calendar/week.scm @@ -17,6 +17,7 @@ :select (make-block output-uid) ) ;; :use-module ((calp html components) ;; :select ()) + :use-module (calp translation) :use-module ((vcomponent util group) :select (group-stream get-groups-between)) ) @@ -30,7 +31,9 @@ (div (@ (class "days")) ;; Top left area (div (@ (class "week-indicator")) - (span (@ (style "font-size: 50%")) "v.") ; figure out if we want this... + (span (@ (style "font-size: 50%")) + ;; Week number prefix + ,(_ "v.")) ,@(->> (week-number start-date) number->string string->list (map (lambda (c) `(span ,(string c)))))) @@ -43,8 +46,10 @@ ,@(map (lambda (day-date) `(div (@ (class "meta")) (span (@ (class "daydate")) - ,(date->string day-date "~Y-~m-~d")) + ;; Week view header format + ,(date->string day-date (_ "~Y-~m-~d"))) (span (@ (class "dayname")) + ;; TODO translation here? ,(string-titlecase (date->string day-date "~a"))))) range) ,@(stream->list diff --git a/module/calp/html/view/search.scm b/module/calp/html/view/search.scm index 9b03151b..08436bc5 100644 --- a/module/calp/html/view/search.scm +++ b/module/calp/html/view/search.scm @@ -8,6 +8,7 @@ :select (xhtml-doc include-css)) :use-module ((calp html vcomponent) :select (compact-event-list)) + :use-module (calp translation) ) ;; Display the result of a search term, but doesn't do any searching @@ -24,25 +25,25 @@ errors has-query? search-term search-result page paginator) (xhtml-doc (@ (lang sv)) - (head (title "Search results") + (head (title ,(_ "Search results")) ,(include-css "/static/style.css")) (body - (a (@ (href ("/today"))) "Till Idag") - (h2 "Search term") + (a (@ (href ("/today"))) ,(_ "Show today")) + (h2 ,(_ "Search term")) (form (pre (textarea (@ (name "q") (rows 5) (spellcheck false) (style "width:100%")) ,(when has-query? (with-output-to-string (lambda () (pretty-print search-term)))))) - (label (@ (for "onlyfuture")) "limit to future occurences") + (label (@ (for "onlyfuture")) ,(_ "limit to future occurences")) (input (@ (name "onlyfuture") (id "onlyfuture") (type checkbox))) (input (@ (type submit)))) ,@(if errors - `((h2 "Error searching") + `((h2 ,(_ "Error searching")) (div (@ (class "error")) (pre ,errors))) - `((h2 "Result (page " ,page ")") + `((h2 ,(format #f (_ "Result (page ~a)") page)) (ul ,@(compact-event-list search-result)) (div (@ (class "paginator")) ,@(paginator->list diff --git a/module/calp/main.scm b/module/calp/main.scm index 0ae22927..ebff00fd 100644 --- a/module/calp/main.scm +++ b/module/calp/main.scm @@ -24,29 +24,31 @@ :use-module (statprof) :use-module (calp repl) + :use-module (sxml simple) :use-module ((xdg basedir) :prefix xdg-) + :use-module (calp translation) + ) (define options `((statprof (value display-style) - (description "Run the program within Guile's built in statical " - "profiler. Display style is one of " - (b "flat") " or " (b "tree") ".")) + (description ,(xml->sxml (_ "Run the program within Guile's built in statical +profiler. Display style is one of flat or tree.")))) (repl (value address) (description - "Start a Guile repl which can be connected to, defaults to the unix socket " - (i "/run/user/${UID}/calp-${PID}") ", but it can be bound to any unix or " - "TCP socket. ((@ (vcomponent util instance) global-event-object)) " - "should contain all events." - (br) - (b "Should NOT be used in production."))) + ,(xml->sxml (_ "Start a Guile repl which can be connected to, defaults to the +unix socket /run/user/${UID}/calp-${PID}, but it can be bound to any +unix or TCP socket. ((@ (vcomponent util instance) global-event-object)) should +contain all events. +
+Should NOT be used in production.
")))) (config (value #t) (description - "Path to alterantive configuration file to load instead of the default one. ")) + ,(_ "Path to alterantive configuration file to load instead of the default one."))) ;; Techical note: ;; Guile's getopt doesn't support repeating keys. Thereby the small jank, @@ -54,57 +56,54 @@ (option (single-char #\o) (value #t) (description - "Set configuration options, on the form " - (i "key") "=" (i "value") - " as if they were set in the config file. These options have " - "priority over those from the file. " - "Can " (i "not") " be given with an equal after --option." - (br) "Can be given multiple times.")) + ,(xml->sxml (_ "Set configuration options, on the form key=value +as if they were set in the config file. These options have priority over those +from the file. Can not be given with an equal after --option.
Can +be given multiple times.
")))) (version (single-char #\v) - (description "Display version, which is " ,(@ (calp) version) " btw.")) + (description ,(format #f (_ "Display version, which is ~a btw.") + (@ (calp) version)))) (update-zoneinfo) (help (single-char #\h) - (description "Print this help")) + (description ,(_ "Print this help"))) - (printconf (description "Print known configuration variables." - (br) (b "NOTE") ": " - "Only those configuration variables which are loaded " - "will be shown, more might be available")))) + (printconf (description ,(xml->sxml (_ "Print known configuration variables. +
NOTE: +Only those configuration variables which are loaded will be shown, more might be +available
")))))) (define module-help - '(*TOP* (br) - (center (b "Calp")) (br) (br) - "Usage: " (b "calp") " [ " (i flags) " ] " (i mode) " [ " (i "mode flags") " ]" (br) - - (hr) - (center (b "Modes")) (br) (br) - - (p (b "html") " reads calendar files from disk, and writes them to static HTML files.") - - (p (b "terminal") " loads the calendars, and startrs an interactive terminal interface.") - - "[UNTESTED]" (br) - (p (b "import") "s an calendar object into the database.") - - (p (b "text") " formats and justifies what it's given on standard input, " - "and writes it to standard output. Similar to this text.") - - (p (b "ical") " loads the calendar database, and imideately " - "reserializes it back into ICAL format. " - "Useful for merging calendars.") - - (p (b "benchmark") " " (i "module") (br) - "Runs the procedure 'run-benchmark' from the module (calp benchmark " (i "module") ").") - - (p (b "server") " starts an HTTP server which dynamicly loads and displays event. The " - (i "/month/{date}.html") " & " (i "/week/{date}.html") " runs the same output code as " - (b "html") ". While the " (i "/calendar/{uid}.ics") " uses the same code as " (b "ical") ".") - - (hr) (br) - (center (b "Flags")) (br))) + (xml->sxml + (string-append + "
+
" "Calp" "
+

+" (_ "Usage: calp [ flags ] mode [ mode flags ]") "
+
" +;; Header for following list of modes of operation + "
" (_ "Modes") "
+

" + (_ "

html reads calendar files from disk, and writes them to static HTML files.

") + (_ "

terminal loads the calendars, and starts an interactive terminal interface.

") + (_ "[UNTESTED]

imports a calendar object into the database.

") + (_ "

text formats and justifies what it's given on standard input, +and writes it to standard output. Similar to this text.

") + (_ "

ical loads the calendar database, and immediately +re-serializes it back into iCAL format. Useful for merging calendars.

") + (_ "

benchmark module
Runs the procedure 'run-benchmark' +from the module (calp benchmark module).

") + (_ "

server starts an HTTP server which dynamically loads and +displays events. The /month/{date}.html & /week/{date}.html runs +the same output code as html. While the /calendar/{uid}.ics uses +the same code as ical.

") + "

" + ;; Header for list of available flags. + ;; Actual list is auto generated elsewhere. + "
" (_ "Flags") "
+
"))) (define (ornull a b) (if (null? a) @@ -121,7 +120,7 @@ (if (file-exists? altconfig) altconfig (throw 'option-error - "Configuration file ~a missing" altconfig))] + (_ "Configuration file ~a missing") altconfig))] ;; altconfig could be placed in the list below. But I want to raise an error ;; if an explicitly given config is missing. [(find file-exists? @@ -166,7 +165,10 @@ )) (lambda args (format (current-error-port) - "Failed loading config file ~a~%~s~%" + ;; Two arguments: + ;; Configuration file path, + ;; thrown error arguments + (_ "Failed loading config file ~a~%~s~%") config-file args ))) @@ -207,13 +209,13 @@ (throw 'return)) (when (option-ref opts 'version #f) - (format #t "Calp version ~a~%" (@ (calp) version)) + (format #t (_ "Calp version ~a~%") (@ (calp) version)) (throw 'return)) (when (option-ref opts 'update-zoneinfo #f) (let* ((locations (list "/usr/libexec/calp/tzget" (path-append (xdg-data-home) "tzget"))) (filename (or (find file-exists? locations) - (error "tzget not installed, please put it in one of ~a" locations))) + (error (_ "tzget not installed, please put it in one of ~a") locations))) (pipe (open-input-pipe filename))) ;; (define path (read-line pipe)) @@ -245,7 +247,7 @@ ((benchmark) (@ (calp entry-points benchmark) main)) (else => (lambda (s) (format (current-error-port) - "Unsupported mode of operation: ~a~%" + (_ "Unsupported mode of operation: ~a~%") s) (exit 1)))) ropt)) @@ -260,7 +262,7 @@ (define-public (main args) - ((@ (calp util time) report-time!) "Program start") + ((@ (calp util time) report-time!) (_ "Program start")) (with-throw-handler #t (lambda () (dynamic-wind (lambda () 'noop) diff --git a/module/calp/repl.scm b/module/calp/repl.scm index e25c2649..9b2df13f 100644 --- a/module/calp/repl.scm +++ b/module/calp/repl.scm @@ -7,12 +7,13 @@ :use-module (ice-9 regex) :use-module ((calp util hooks) :select (shutdown-hook)) :use-module ((hnh util exceptions) :select (warning)) + :use-module (calp translation) ) (define-public (repl-start address) (define lst (string->list address)) (format (current-error-port) - "Starting REPL server at ~a~%" address) + (_ "Starting REPL server at ~a~%") address) (spawn-server (case (cond [(memv (car lst) '(#\. #\/)) 'UNIX] [(string-match "(\\d{1,3}\\.){3}\\d{1,3}(:\\d+)?" address) 'IPv4] @@ -22,16 +23,16 @@ [(UNIX) (add-hook! shutdown-hook (lambda () (catch 'system-error (lambda () (delete-file address)) (lambda (err proc fmt . args) - (warning "Failed to unlink ~a" address args) + (warning (_ "Failed to unlink ~a") address args) err)))) (make-unix-domain-server-socket path: address)] [(IPv4) (apply (case-lambda - [() (error "Empty address?")] + [() (error (_ "Empty address?"))] [(address) (make-tcp-server-socket host: address)] [(address port) (make-tcp-server-socket host: address port: port)]) (string-split address #\:))] ;; currently impossible - [(IPv6) (error "How did you get here?")])) + [(IPv6) (error (_ "How did you get here?"))])) ;; TODO setup repl environment here diff --git a/module/calp/server/routes.scm b/module/calp/server/routes.scm index 87af983a..2f3544ee 100644 --- a/module/calp/server/routes.scm +++ b/module/calp/server/routes.scm @@ -35,6 +35,7 @@ :use-module (calp html view calendar) :use-module ((calp html view search) :select (search-result-page)) + :use-module (calp translation) ) @@ -49,7 +50,9 @@ (define (directory-table dir) `(table (thead - (tr (th "") (th "Name") (th "Perm"))) + (tr (th "") (th ,(_ "Name")) + ;; File permissions, should be about as long as three digits + (th ,(_ "Perm")))) (tbody ,@(map (lambda (k) (let* ((stat (lstat (path-append dir k)))) @@ -63,7 +66,7 @@ (scm-error 'misc-error "directory-table" - "Scandir argument invalid or not directory: ~a" + (_ "Scandir argument invalid or not directory: ~a") (list dir) '()))))))) @@ -97,7 +100,7 @@ (GET "/" () (return '((content-type text/html)) (sxml->html-string - '(body (a (@ (href "/today")) "GĂ„ till idag") + '(body (a (@ (href "/today")) ,(_ "Go to Today")) (script "window.onload = function() { document.getElementsByTagName('a')[0].click();}"))))) @@ -150,7 +153,7 @@ (POST "/remove" (uid) (unless uid (return (build-response code: 400) - "uid required")) + (_ "uid required"))) (aif (get-event-by-uid global-event-object uid) (begin @@ -162,10 +165,10 @@ (set! (param (prop* it 'X-HNH-REMOVED) 'VALUE) "BOOLEAN") (unless ((@ (vcomponent formats vdir save-delete) save-event) it) (return (build-response code: 500) - "Saving event to disk failed.")) + (_ "Saving event to disk failed."))) (return (build-response code: 204))) (return (build-response code: 400) - (format #f "No event with UID '~a'" uid)))) + (format #f (_ "No event with UID '~a'") uid)))) ;; TODO this fails when dtstart is . ;; @var{cal} should be the name of the calendar encoded in base64. @@ -173,7 +176,7 @@ (unless (and cal data) (return (build-response code: 400) - "Both 'cal' and 'data' required\r\n")) + (string-append (_ "Both 'cal' and 'data' required") "\r\n"))) ;; NOTE that this leaks which calendar exists, @@ -186,7 +189,8 @@ (unless calendar (return (build-response code: 400) - (format #f "No calendar with name [~a]\r\n" calendar-name))) + (format #f "~@?\r\n" (_ "No calendar with name [~a]") + calendar-name))) ;; Expected form of data (but in XML) is: ;; @example @@ -215,11 +219,13 @@ #f)) (lambda (err port . args) (return (build-response code: 400) - (format #f "XML parse error ~{~a~}\r\n" args))))))) + (format #f "~a ~{~a~}\r\n" + (_ "XML parse error") + args))))))) (unless (eq? 'VEVENT (type event)) (return (build-response code: 400) - "Object not a VEVENT\r\n")) + (string-append (_ "Object not a VEVENT") "\r\n"))) ;; NOTE add-event uses the given UID if one is given, ;; but generates its own if not. It might be a good idea @@ -255,13 +261,14 @@ ;; since the two events are guaranteed to have the same UID. (unless ((@ (vcomponent formats vdir save-delete) save-event) event) (return (build-response code: 500) - "Saving event to disk failed.")) + (_ "Saving event to disk failed."))) (unless (eq? calendar (parent old-event)) ;; change to a new calendar (format (current-error-port) - "Unlinking old event from ~a~%" + ;; unlinks (removes) a single event, argument is a file name + (_ "Unlinking old event from ~a~%") (prop old-event '-X-HNH-FILENAME)) ;; NOTE that this may fail, leading to a duplicate event being ;; created (since we save beforehand). This is just a minor problem @@ -271,7 +278,7 @@ (format (current-error-port) - "Event updated ~a~%" (prop event 'UID)))] + (_ "Event updated ~a~%") (prop event 'UID)))] [else (parameterize ((warnings-are-errors #t)) @@ -287,10 +294,10 @@ ;; That would allow better asyncronous preformance. (unless ((@ (vcomponent formats vdir save-delete) save-event) event) (return (build-response code: 500) - "Saving event to disk failed.")) + (_ "Saving event to disk failed."))) (format (current-error-port) - "Event inserted ~a~%" (prop event 'UID))]) + (_ "Event inserted ~a~%") (prop event 'UID))]) (return '((content-type application/xml)) (with-output-to-string @@ -342,7 +349,7 @@ ;; and "program parent" into different fields. (lambda () (sxml->xml ((@ (vcomponent formats xcal output) vcomponent->sxcal) it))))) (return (build-response code: 404) - (format #f "No component with UID=~a found." uid)))) + (format #f (_ "No component with UID=~a found.") uid)))) (GET "/calendar/:uid{.*}.ics" (uid) (aif (get-event-by-uid global-event-object uid) @@ -351,7 +358,7 @@ (lambda () (print-components-with-fake-parent (list it))))) (return (build-response code: 404) - (format #f "No component with UID=~a found." uid)))) + (format #f (_ "No component with UID=~a found.") uid)))) (GET "/search/text" (q) (return (build-response diff --git a/module/calp/server/server.scm b/module/calp/server/server.scm index fc185033..b9d5c6d3 100644 --- a/module/calp/server/server.scm +++ b/module/calp/server/server.scm @@ -1,4 +1,5 @@ (define-module (calp server server) + :use-module (hnh util) :use-module (web server) :use-module ((calp server routes) :select (make-make-routes)) diff --git a/module/calp/terminal.scm b/module/calp/terminal.scm index cd1d0c9d..e982c468 100644 --- a/module/calp/terminal.scm +++ b/module/calp/terminal.scm @@ -26,6 +26,7 @@ #:use-module (oop goops) #:use-module (oop goops describe) + #:use-module (calp translation) #:autoload (vcomponent util instance) (global-event-object) @@ -71,7 +72,7 @@ " │ " (if (prop ev 'LOCATION) "" "\x1b[1;30m") (trim-to-width - (or (prop ev 'LOCATION) "INGEN LOKAL") location-width) + (or (prop ev 'LOCATION) (_ "NO LOCATION")) location-width) STR-RESET "\n"))) events @@ -122,7 +123,7 @@ (cls) - (display "== Day View ==\n") + (display (_ "== Day View ==\n")) (display-calendar-header! (current-page this)) @@ -135,22 +136,35 @@ ;; display highlighted event (unless (null? events) (let ((ev (list-ref events (active-element this)))) - (format #t "~a~%~% ~a~%~%~a\x1b[1mStart:\x1b[m ~a \x1b[1mSlut:\x1b[m ~a~%~%~a~%" - (prop ev '-X-HNH-FILENAME) - (prop ev 'SUMMARY) - (or (and=> (prop ev 'LOCATION) - (cut string-append "\x1b[1mPlats:\x1b[m " <> "\n")) "") - ;; NOTE RFC 5545 says that DTSTART and DTEND MUST - ;; have the same type. However we believe that is - ;; another story. + (format #t "~a" (prop ev '-X-HNH-FILENAME)) + (format #t "~%~%") + (format #t " ~a" (prop ev 'SUMMARY)) + (format #t "~%~%") + (awhen (prop ev 'LOCATION) + (format #t + "\x1b[1m~a:\x1b[m ~a~%" + (_ "Location") + it)) + ;; NOTE RFC 5545 says that DTSTART and DTEND MUST + ;; have the same type. However we believe that is + ;; another story. + (format #t "\x1b[1m~a:\x1b[m ~a " + (_ "Start") (let ((start (prop ev 'DTSTART))) (if (datetime? start) - (datetime->string (prop ev 'DTSTART) "~Y-~m-~d ~H:~M:~S") - (date->string start))) - (let ((end (prop ev 'DTEND))) - (if (datetime? end) - (datetime->string (prop ev 'DTEND) "~Y-~m-~d ~H:~M:~S") - (date->string end))) + (datetime->string (prop ev 'DTSTART) + ;; Event start date-time terminal view + (_ "~Y-~m-~d ~H:~M:~S")) + (date->string start)))) + (format #t "\x1b[1m~a:\x1b[m ~a~%~%" + (_ "End") + (let ((start (prop ev 'DTSTART))) + (if (datetime? start) + (datetime->string (prop ev 'DTSTART) + ;; Event end date-time terminal view + (_ "~Y-~m-~d ~H:~M:~S")) + (date->string start)))) + (format #t "~a~%" (unlines (take-to (flow-text (or (prop ev 'DESCRIPTION) "") #:width (min 70 width)) (- height 8 5 (length events) 5))))))) @@ -191,14 +205,14 @@ (active-element this) 0)) ((#\/) (set-cursor-pos 0 (1- height)) - (let ((search-term (get-line "quick search: "))) + (let ((search-term (get-line (_ "quick search: ")))) `(push ,(search-view (format #f "(regexp-exec (make-regexp \"~a\" regexp/icase) (prop event 'SUMMARY))" search-term) (get-event-set this))))) ((#\() (set-cursor-pos 0 (1- height)) - (let ((search-term (get-line "search: "))) + (let ((search-term (get-line (_ "search: ")))) `(push ,(search-view search-term (get-event-set this))))) (else (next-method)))) @@ -244,7 +258,7 @@ (cls) - (display "== Search View ==\n") + (display (_ "== Search View ==\n")) ;; display search term (format #t "~y" (search-term this)) @@ -300,7 +314,7 @@ 'DTSTART))))) ((#\h left) (set! (current-page this) = ((lambda (old) (max 0 (1- old)))))) ((#\l right) - (display "\n loading...\n") + (format #t "~% ~a~%" (_ "loading...")) (set! (current-page this) (next-page (slot-ref this 'search-result) (current-page this)))) diff --git a/module/calp/translation.scm b/module/calp/translation.scm new file mode 100644 index 00000000..c0392d95 --- /dev/null +++ b/module/calp/translation.scm @@ -0,0 +1,20 @@ +(define-module (calp translation) + :use-module (ice-9 i18n) + :use-module (ice-9 regex) + :use-module (ice-9 match) + :export (_ yes-no-check)) + +(bindtextdomain "calp" "/home/hugo/code/calp/localization/") + +(define (_ . msg) + ;; NOTE this doesn't squeese repeated whitespace + (string-map (match-lambda + (#\newline #\space) + (c c)) + (gettext (string-join msg) "calp"))) + +(define* (yes-no-check string #:optional (locale %global-locale)) + (cond ((string-match (locale-yes-regexp locale) string) 'yes) + ((string-match (locale-no-regexp locale) string) 'no) + (else #f))) + diff --git a/module/calp/util/config.scm b/module/calp/util/config.scm index 2fe2b9b0..2637cd85 100644 --- a/module/calp/util/config.scm +++ b/module/calp/util/config.scm @@ -9,6 +9,7 @@ :use-module (srfi srfi-1) :use-module (ice-9 format) ; for format-procedure :use-module (ice-9 curried-definitions) ; for ensure + :use-module (calp translation) :export (define-config) ) @@ -38,7 +39,7 @@ (define (define-config% name default-value kwargs) (for (key value) in (group kwargs 2) (set! ((or (hashq-ref config-properties key) - (error "Missing config protperty slot " key)) + (error (_ "Missing config protperty slot ") key)) name) value)) (set-config! name (get-config name default-value))) @@ -53,7 +54,7 @@ (define-public (set-config! name value) (hashq-set! config-values name (aif (pre name) - (or (it value) (error "Pre crashed for" name)) + (or (it value) (error (_ "Pre crashed for") name)) value)) (awhen (post name) (it value))) @@ -64,7 +65,7 @@ (if (eq? default %uniq) (let ((v (hashq-ref config-values key %uniq))) (when (eq? v %uniq) - (error "Missing config" key)) + (error (_ "Missing config") key)) v) (hashq-ref config-values key default))) @@ -112,7 +113,7 @@ (hash-map->list list config-values))) `(*TOP* - (header "Configuration variables") + (header ,(_ "Configuration variables")) (dl ,@(concatenate (for (module values) in groups @@ -124,7 +125,8 @@ `((dt ,key) (dd (p (@ (inline)) ,(or (description key) ""))) - (dt "V:") + ;; Configuration variable value indicator + (dt ,(_ "V:")) (dd ,(if (procedure? value) (format-procedure value) `(scheme ,value)) diff --git a/module/calp/util/exceptions.scm b/module/calp/util/exceptions.scm index 1268f9f5..0588840e 100644 --- a/module/calp/util/exceptions.scm +++ b/module/calp/util/exceptions.scm @@ -1,7 +1,8 @@ (define-module (calp util exceptions) :use-module (calp util config) + :use-module (calp translation) :use-module (hnh util exceptions)) (define-config warnings-are-errors #f - description: "Crash on warnings." + description: (_ "Crash on warnings.") post: warnings-are-errors) diff --git a/module/datetime/instance.scm b/module/datetime/instance.scm index 5ce312f2..2b060204 100644 --- a/module/datetime/instance.scm +++ b/module/datetime/instance.scm @@ -5,10 +5,11 @@ :use-module ((hnh util path) :select (path-append)) :use-module (datetime zic) :use-module ((xdg basedir) :prefix xdg-) + :use-module (calp translation) :export (zoneinfo)) (define-config tz-list '() - description: "List of default zoneinfo files to be parsed") + description: (_ "List of default zoneinfo files to be parsed")) ;; TODO see (vcomponent uil instance), this has a similar problem with early load ;; Takes a list of zoneinfo files relative @@ -24,7 +25,7 @@ (() (define tz-list (get-config 'tz-list)) (if (null? tz-list) - (warning "Default zoneinfo only available when tz-dir and tz-list are configured") + (warning (_ "Default zoneinfo only available when tz-dir and tz-list are configured")) (self tz-list))) ((file-list) (provide 'zoneinfo) diff --git a/module/datetime/timespec.scm b/module/datetime/timespec.scm index 712ff327..ea29a423 100644 --- a/module/datetime/timespec.scm +++ b/module/datetime/timespec.scm @@ -11,6 +11,7 @@ :use-module (datetime) :use-module (srfi srfi-1) :use-module (srfi srfi-9 gnu) + :use-module (calp translation) ) @@ -33,7 +34,7 @@ (define-public (timespec-add . specs) (unless (apply eqv? (map timespec-type specs)) - (warning "Adding timespecs of differing types")) + (warning (_ "Adding timespecs of differing types"))) (reduce (lambda (spec done) (cond diff --git a/module/datetime/zic.scm b/module/datetime/zic.scm index b07c2bfa..0362ec99 100644 --- a/module/datetime/zic.scm +++ b/module/datetime/zic.scm @@ -22,6 +22,7 @@ :use-module (srfi srfi-9 gnu) :use-module ((vcomponent recurrence internal) :select (byday make-recur-rule bymonthday)) + :use-module (calp translation) ) @@ -162,7 +163,7 @@ day: (string->number day)) time: (timespec-time timespec) tz: (case (timespec-type timespec) - [(#\s) (warning "what even is \"Standard time\"“") ""] + [(#\s) (warning (_ "what even is \"Standard time\"“")) ""] [(#\w) #f] ;; Since we might represent times before UTC existed ;; this is a bit of a lie. But it should work. @@ -258,8 +259,8 @@ ;; NOTE an earlier version of the code the parsers for those. ;; They were removed since they were unused, uneeded, and was ;; technical dept. - (error "Invalid key ~a. Note that leap seconds and -expries rules aren't yet implemented." type)] + (error (_ "Invalid key ~a. Note that leap seconds and +expries rules aren't yet implemented.") type)] ))])))))) @@ -295,7 +296,7 @@ expries rules aren't yet implemented." type)] (target (link-target link)) (target-item (hash-ref zones target #f))) (if (not target-item) - (warning "Unresolved link, target missing ~a -> ~a" name target) + (warning (_ "Unresolved link, target missing ~a -> ~a") name target) (hash-set! zones name target-item)))) (car it))) @@ -335,7 +336,7 @@ expries rules aren't yet implemented." type)] (set (day d) base-day)))])) tz: (case (timespec-type (rule-at rule)) ((#\w) #f) - ((#\s) (warning "what even is \"Standard time\"“") #f) + ((#\s) (warning (_ "what even is \"Standard time\"“")) #f) ((#\u #\g #\z) 'UTC)))) (let ((timespec (rule-at rule))) @@ -356,7 +357,7 @@ expries rules aren't yet implemented." type)] until: (let ((to (rule-to rule))) (case to ((maximum) #f) - ((minimum) (error "Check your input")) + ((minimum) (error (_ "Check your input"))) ((only) (datetime date: (date year: (rule-from rule) month: 1 day: 1))) @@ -380,7 +381,7 @@ expries rules aren't yet implemented." type)] ;; Sun>=8 (let* (((<> wday base-day) (rule-on rule))) (when (eq? '< <>) - (warning "Counting backward for RRULES unsupported")) + (warning (_ "Counting backward for RRULES unsupported"))) ;; NOTE this only realy works when base-day = 7n + 1, n ∈ N ;; something like Sun>=5 is hard to fix, since we can only ;; say which sunday in the month we want (first sunday, @@ -398,7 +399,8 @@ expries rules aren't yet implemented." type)] idx (+ idx 2))] [(#\z) ;; NOTE No zones seem to currently use %z formatting. - (warning "%z not yet implemented") + ;; '%z' is NOT a format string, but information about another format string. + (warning (_ "%z not yet implemented")) fmt-string] - [else (error "Invalid format char")]))) + [else (error (_ "Invalid format char"))]))) diff --git a/module/vcomponent/datetime/output.scm b/module/vcomponent/datetime/output.scm index fa662286..a0ab9941 100644 --- a/module/vcomponent/datetime/output.scm +++ b/module/vcomponent/datetime/output.scm @@ -5,6 +5,7 @@ :use-module (datetime) :use-module (vcomponent base) :use-module (text util) + :use-module (calp translation) ) (define-config summary-filter (lambda (_ a) a) @@ -14,13 +15,14 @@ pre: (ensure procedure?)) ;; ev → sxml +;; TODO translation (define-public (format-recurrence-rule ev) - `("Upprepas " + `(,(_ "Upprepas ") ,((@ (vcomponent recurrence display) format-recurrence-rule) (prop ev 'RRULE)) ,@(awhen (prop* ev 'EXDATE) (list - ", undantaget " + (_ ", undantaget ") (add-enumeration-punctuation (map (lambda (d) (if (date? d) @@ -43,7 +45,10 @@ (define-public (format-description ev str) (catch #t (lambda () ((get-config 'description-filter) ev str)) (lambda (err . args) - (warning "~a on formatting description, ~s" err args) + ;; Warning message for failure to format description. + ;; First argument is name of warning/error, + ;; second is error arguments + (warning (_ "~a on formatting description, ~s") err args) str))) ;; Takes an event, and returns a pretty string for the time interval diff --git a/module/vcomponent/formats/common/types.scm b/module/vcomponent/formats/common/types.scm index efe17f36..9768cf70 100644 --- a/module/vcomponent/formats/common/types.scm +++ b/module/vcomponent/formats/common/types.scm @@ -5,13 +5,14 @@ :use-module (datetime) :use-module (srfi srfi-9 gnu) :use-module (datetime timespec) + :use-module (calp translation) ) ;; BINARY (define (parse-binary props value) ;; p 30 (unless (string=? "BASE64" (hashq-ref props 'ENCODING)) - (warning "Binary field not marked ENCODING=BASE64")) + (warning (_ "Binary field not marked ENCODING=BASE64"))) ;; For icalendar no extra whitespace is allowed in a ;; binary field (except for line wrapping). This differs @@ -23,7 +24,7 @@ (cond [(string=? "TRUE" value) #t] [(string=? "FALSE" value) #f] - [else (warning "~a invalid boolean" value)])) + [else (warning (_ "~a invalid boolean") value)])) ;; CAL-ADDRESS ⇒ uri @@ -56,7 +57,7 @@ (define (parse-integer props value) (let ((n (string->number value))) (unless (integer? n) - (warning "Non integer as integer")) + (warning (_ "Non integer as integer"))) n)) ;; PERIOD @@ -87,7 +88,7 @@ (case (cadr rem) [(#\n #\N) (loop (cddr rem) (cons #\newline str) done)] [(#\; #\, #\\) => (lambda (c) (loop (cddr rem) (cons c str) done))] - [else => (lambda (c) (warning "Non-escapable character: ~a" c) + [else => (lambda (c) (warning (_ "Non-escapable character: ~a") c) (loop (cddr rem) str done))])] [(#\,) (loop (cdr rem) '() (cons (reverse-list->string str) done))] @@ -136,4 +137,4 @@ (define-public (get-parser type) (or (hashq-ref type-parsers type #f) - (error "No parser for type" type))) + (error (_ "No parser for type") type))) diff --git a/module/vcomponent/formats/ical/output.scm b/module/vcomponent/formats/ical/output.scm index fba8bffc..489cdc00 100644 --- a/module/vcomponent/formats/ical/output.scm +++ b/module/vcomponent/formats/ical/output.scm @@ -15,6 +15,7 @@ :use-module (vcomponent geo) :use-module (vcomponent formats ical types) :use-module (vcomponent recurrence) + :use-module (calp translation) :autoload (vcomponent util instance) (global-event-object) ) @@ -90,7 +91,7 @@ (get-writer 'TEXT)] [else - (warning "Unknown key ~a" key) + (warning (_ "Unknown key ~a") key) (get-writer 'TEXT)])) (catch #t #; 'wrong-type-arg diff --git a/module/vcomponent/formats/ical/parse.scm b/module/vcomponent/formats/ical/parse.scm index 34812a2c..8b6cffeb 100644 --- a/module/vcomponent/formats/ical/parse.scm +++ b/module/vcomponent/formats/ical/parse.scm @@ -9,6 +9,7 @@ :use-module (vcomponent base) :use-module (vcomponent geo) :use-module (vcomponent formats common types) + :use-module (calp translation) ) (define string->symbol @@ -120,7 +121,7 @@ (lambda (params value) (let ((vv (parser params value))) (when (list? vv) - (throw 'parse-error "List in enum field")) + (throw 'parse-error (_ "List in enum field"))) (let ((v (string->symbol vv))) (unless (memv v enum) (warning "~a ∉ { ~{~a~^, ~} }" @@ -155,7 +156,7 @@ (lambda (params value) (let ((v ((get-parser 'TEXT) params value))) (unless (= 1 (length v)) - (warning "List in non-list field: ~s" v)) + (warning (_ "List in non-list field: ~s") v)) (string-join v ",")))] ;; TEXT, but allow a list @@ -192,7 +193,7 @@ DRAFT FINAL CANCELED))] [(memv key '(REQUEST-STATUS)) - (throw 'parse-error "TODO Implement REQUEST-STATUS")] + (throw 'parse-error (_ "TODO Implement REQUEST-STATUS"))] [(memv key '(ACTION)) (enum-parser '(AUDIO DISPLAY EMAIL @@ -226,7 +227,7 @@ (compose car (get-parser 'TEXT))] [else - (warning "Unknown key ~a" key) + (warning (_ "Unknown key ~a") key) (compose car (get-parser 'TEXT))]))) ;; If we produced a list create multiple VLINES from it. @@ -273,9 +274,15 @@ (lambda (fmt . args) (let ((linedata (get-metadata head*))) (format - #f "WARNING parse error around ~a + #f + ;; arguments: + ;; linedata + ;; ~? + ;; source line + ;; source file + (_ "WARNING parse error around ~a ~? - line ~a ~a~%" + line ~a ~a~%") (get-string linedata) fmt args (get-line linedata) @@ -321,10 +328,16 @@ (lambda (err fmt . args) (let ((linedata (get-metadata head*))) (display (format - #f "ERROR parse error around ~a + #f + ;; arguments + ;; linedata + ;; ~? + ;; source line + ;; source file + (_ "ERROR parse error around ~a ~? line ~a ~a - Defaulting to string~%" + Defaulting to string~%") (get-string linedata) fmt args (get-line linedata) diff --git a/module/vcomponent/formats/ical/types.scm b/module/vcomponent/formats/ical/types.scm index 39b3b1e3..67f9f633 100644 --- a/module/vcomponent/formats/ical/types.scm +++ b/module/vcomponent/formats/ical/types.scm @@ -4,7 +4,9 @@ :use-module (hnh util exceptions) :use-module (base64) :use-module (datetime) - :use-module (datetime timespec)) + :use-module (datetime timespec) + :use-module (calp translation) + ) ;; TODO shouldn't these really take vline:s? @@ -35,7 +37,7 @@ ;; TODO (define (write-period _ value) - (warning "PERIOD writer not yet implemented") + (warning (_ "PERIOD writer not yet implemented")) (with-output-to-string (lambda () (write value)))) @@ -92,4 +94,4 @@ (define-public (get-writer type) (or (hashq-ref type-writers type #f) - (error "No writer for type" type))) + (error (_ "No writer for type") type))) diff --git a/module/vcomponent/formats/vdir/parse.scm b/module/vcomponent/formats/vdir/parse.scm index c4a48889..4fc96e71 100644 --- a/module/vcomponent/formats/vdir/parse.scm +++ b/module/vcomponent/formats/vdir/parse.scm @@ -15,6 +15,7 @@ :use-module ((hnh util path) :select (path-append)) :use-module (hnh util exceptions) :use-module (vcomponent base) + :use-module (calp translation) :use-module (vcomponent formats ical parse) ) @@ -58,7 +59,7 @@ ;; by RECURRENCE-ID. As far as I can tell this goes against ;; the standard. Section 3.8.4.4. (case (length events) - [(0) (warning "No events in component~%~a" + [(0) (warning (_ "No events in component~%~a") (prop item '-X-HNH-FILENAME))] [(1) (let ((child (car events))) diff --git a/module/vcomponent/formats/xcal/output.scm b/module/vcomponent/formats/xcal/output.scm index 81fab41c..26018d92 100644 --- a/module/vcomponent/formats/xcal/output.scm +++ b/module/vcomponent/formats/xcal/output.scm @@ -7,6 +7,7 @@ :use-module (ice-9 match) :use-module (datetime) :use-module (srfi srfi-1) + :use-module (calp translation) ) @@ -69,7 +70,7 @@ (get-writer 'TEXT)] [else - (warning "Unknown key ~a" key) + (warning (_ "Unknown key ~a") key) (get-writer 'TEXT)])) (writer ((@@ (vcomponent base) get-vline-parameters) vline) (value vline))) diff --git a/module/vcomponent/formats/xcal/parse.scm b/module/vcomponent/formats/xcal/parse.scm index 7dee8d67..66bb8460 100644 --- a/module/vcomponent/formats/xcal/parse.scm +++ b/module/vcomponent/formats/xcal/parse.scm @@ -9,6 +9,7 @@ :use-module (vcomponent formats common types) :use-module (datetime) :use-module (srfi srfi-1) + :use-module (calp translation) ) ;; symbol, ht, (list a) -> non-list @@ -83,7 +84,7 @@ (string->number value)) (else (throw 'key-error - "Invalid type ~a, with value ~a" + (_ "Invalid type ~a, with value ~a") type value)))))) ;; freq until count interval wkst @@ -153,7 +154,7 @@ (case tag-name [(request-status) ;; TODO - (warning "Request status not yet implemented") + (warning (_ "Request status not yet implemented")) #f] ((transp) (parse-enum diff --git a/module/vcomponent/formats/xcal/types.scm b/module/vcomponent/formats/xcal/types.scm index 05fbc8c6..8f13d3d1 100644 --- a/module/vcomponent/formats/xcal/types.scm +++ b/module/vcomponent/formats/xcal/types.scm @@ -2,6 +2,7 @@ :use-module (hnh util) :use-module (vcomponent formats ical types) :use-module (datetime) + :use-module (calp translation) ) (define (write-boolean _ v) @@ -51,4 +52,4 @@ (define-public (get-writer type) (or (hashq-ref sxml-writers type #f) - (error "No writer for type" type))) + (error (_ "No writer for type") type))) diff --git a/module/vcomponent/util/instance.scm b/module/vcomponent/util/instance.scm index 6e1e765f..d17b672a 100644 --- a/module/vcomponent/util/instance.scm +++ b/module/vcomponent/util/instance.scm @@ -2,6 +2,7 @@ :use-module (hnh util) :use-module ((calp util config) :select (get-config)) :use-module ((oop goops) :select (make)) + :use-module (calp translation) :export (global-event-object) ) @@ -18,5 +19,5 @@ (define-public (reload) (let ((new-value (make (@@ (vcomponent util instance methods) ) calendar-files: (get-config 'calendar-files)))) - (display "Reload done\n" (current-error-port)) + (format (current-error-port) (_ "Reload done~%")) (set! global-event-object new-value))) diff --git a/module/vcomponent/util/instance/methods.scm b/module/vcomponent/util/instance/methods.scm index 120ab2fe..e2e8a777 100644 --- a/module/vcomponent/util/instance/methods.scm +++ b/module/vcomponent/util/instance/methods.scm @@ -11,6 +11,8 @@ :use-module ((vcomponent datetime) :select (ev-time) args) (next-method) - (format (current-error-port) "Building from~%") + (format (current-error-port) (_ "Building from~%")) (for calendar in (slot-ref this 'calendar-files) (format (current-error-port) " - ~a~%" calendar)) diff --git a/module/vcomponent/util/parse-cal-path.scm b/module/vcomponent/util/parse-cal-path.scm index 11a32064..7a5fea29 100644 --- a/module/vcomponent/util/parse-cal-path.scm +++ b/module/vcomponent/util/parse-cal-path.scm @@ -2,6 +2,7 @@ :use-module (hnh util) :use-module ((calp util time) :select (report-time!)) :use-module (vcomponent base) + :use-module (calp translation) :use-module ((vcomponent formats ical parse) :select (parse-calendar)) :use-module ((vcomponent formats vdir parse) @@ -19,13 +20,13 @@ (set! (prop comp '-X-HNH-SOURCETYPE) 'file) comp) ] [(directory) - (report-time! "Parsing ~a" path) + (report-time! (_ "Parsing ~a") path) (let ((comp (parse-vdir path))) (set! (prop comp '-X-HNH-SOURCETYPE) 'vdir (prop comp '-X-HNH-DIRECTORY) path) comp)] [(block-special char-special fifo socket unknown symlink) - => (lambda (t) (error "Can't parse file of type " t))])) + => (lambda (t) (error (_ "Can't parse file of type ") t))])) (unless (prop cal "NAME") (set! (prop cal "NAME") -- cgit v1.2.3 From 46d854bf3bd0571cadce083cbe9e22693b0aee7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 22 Feb 2022 11:19:29 +0100 Subject: Initial swedish translation. --- po/sv.po | 1041 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1041 insertions(+) create mode 100644 po/sv.po diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 00000000..e759d3d8 --- /dev/null +++ b/po/sv.po @@ -0,0 +1,1041 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "Project-Id-Version: 1.0\n" + "Report-Msgid-Bugs-To: \n" + "POT-Creation-Date: 2022-02-21 16:45+0100\n" + "PO-Revision-Date: 2022-02-21 16:50+0100\n" + "Last-Translator: Hugo Hörnquist \n" + "Language-Team: No Team \n" + "Language: Swedish\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" + +#: module/calp/entry-points/benchmark.scm:20 +msgid "Output is by default supressed, since many fields contain way to " + "much data to read. This turns it on again." +msgstr "Som standard Ă€r utskrifter avstĂ€ngda, eftersom mĂ„nga fĂ€llt inehĂ„ller " + "aldelles för mycket data för att lĂ€sas. Det hĂ€r slĂ„r pĂ„ det igen." + +#: module/calp/entry-points/benchmark.scm:22 +#: module/calp/entry-points/ical.scm:17 module/calp/entry-points/import.scm:24 +#: module/calp/entry-points/terminal.scm:15 +#: module/calp/entry-points/convert.scm:19 module/calp/entry-points/html.scm:60 +#: module/calp/entry-points/server.scm:30 +msgid "Print this help." +msgstr "Visar den hĂ€r hjĂ€lpen." + +#: module/calp/entry-points/convert.scm:17 +msgid "Input file" +msgstr "Indatafil" + +#: module/calp/entry-points/tidsrapport.scm:173 +#: module/calp/entry-points/convert.scm:18 +msgid "Output file" +msgstr "Utdatafil" + +#: module/calp/entry-points/html.scm:32 +msgid "Start date of output." +msgstr "Startdatum för utdatan." + +#: module/calp/entry-points/html.scm:99 +#, scheme-format +msgid "Writing to [~a]~%" +msgstr "Skriver till [~a]~%" + +#: module/calp/entry-points/html.scm:167 +#, scheme-format +msgid "Unknown html style: ~a" +msgstr "OkĂ€nd html-stil: ~a" + +#: module/calp/entry-points/html.scm:169 +msgid "all done" +msgstr "Allt klart" + +#: module/calp/entry-points/ical.scm:15 +msgid "Returns all elements between these two dates." +msgstr "Returnerar alla element mellan de tvĂ„ datumen." + +#: module/calp/entry-points/import.scm:20 +msgid "Name of calendar to import into" +msgstr "Namn pĂ„ kalendar att importera till" + +#: module/calp/entry-points/import.scm:22 +msgid "ics file to import" +msgstr "ics-fil att importera" + +#: module/calp/entry-points/import.scm:43 +#, scheme-format +msgid "No calendar named ~s~%" +msgstr "Ingen kallender vid namn ~s~%" + +#: module/calp/entry-points/import.scm:48 +#, scheme-format +msgid "About to import the following ~a events into ~a~%" +msgstr "PĂ„ vĂ€g att importera ~a hĂ€ndelser till ~a~%" + +#: module/calp/entry-points/import.scm:54 +msgid "Continue? [Y/n] " +msgstr "FortsĂ€tt? [J/n]" + +#. numbers as single-char doesn't work. +#: module/calp/entry-points/server.scm:26 +msgid "Use IPv6." +msgstr "AnvĂ€nd IPv6." + +#: module/calp/entry-points/server.scm:27 +msgid "Use IPv4." +msgstr "AnvĂ€nd IPv4." + +#: module/calp/entry-points/server.scm:28 +msgid "Reload events on SIGUSR1" +msgstr "Ladda om hĂ€ndelser vid SIGUSR1 " + +#: module/calp/entry-points/server.scm:34 +msgid "Port to which the web server should bind." +msgstr "Port till vilken webservern ska binda." + +#: module/calp/entry-points/server.scm:63 +#, scheme-format +msgid "Listening for SIGUSR1~%" +msgstr "Vakar för SIGUSR1~%" + +#: module/calp/entry-points/server.scm:68 +#, scheme-format +msgid "Received SIGUSR1, reloading calendars~%" +msgstr "Mottog SIGUSR1, laddar om kallendar~%" + +#. Arguments are +#. IP-address which we bind to +#. Port which we listen to +#. PID of this process +#. PWD of this process +#: module/calp/entry-points/server.scm:78 +#, scheme-format +msgid "Starting server on ~a:~a~%I'm ~a, runing from ~a~%" +msgstr "Startar server pĂ„ ~a:~a~%Jag Ă€r ~a, körandes frĂ„n ~a~%" + +#: module/calp/entry-points/terminal.scm:14 +msgid "Which date to start on." +msgstr "Vilket datum att börja pĂ„." + +#: module/calp/entry-points/text.scm:14 +msgid "Width of written text, defaults to 70 chars." +msgstr "BrĂ€dd pĂ„ den \"tryckta\" texten; 70 tecken som standard." + +#: module/calp/entry-points/text.scm:18 +msgid "Prints this help." +msgstr "Visar den hĂ€r hjĂ€lpen." + +#: module/calp/entry-points/tidsrapport.scm:171 +msgid "Input pdf file" +msgstr "PDF-fil att arbeta pĂ„" + +#: module/calp/entry-points/tidsrapport.scm:176 +msgid "Static data to fill fields with" +msgstr "Statisk data att fylla fĂ€lten med" + +#: module/calp/entry-points/tidsrapport.scm:183 +msgid "Search term for dynamic filling. Supports basic globbing" +msgstr "Sökterm för dynamisk ifyllning. Stödjer grundlĂ€ggande \"globbar\"" + +#: module/calp/entry-points/tidsrapport.scm:209 +msgid "Template required" +msgstr "Mall krĂ€vs" + +#: module/calp/entry-points/tidsrapport.scm:237 +msgid "Needs list, not pair" +msgstr "Behöver lista, inte par" + +#: module/calp/entry-points/tidsrapport.scm:239 +msgid "Need more days" +msgstr "Behöver fler dagar" + +#: module/calp/entry-points/tidsrapport.scm:255 +msgid "Groups required in template" +msgstr "Grupper krĂ€vs i mallen" + +#. Week number prefix +#: module/calp/html/view/calendar/week.scm:36 +msgid "v." +msgstr "v." + +#: module/calp/html/view/calendar.scm:76 +msgid "Next-start needs to be a procedure" +msgstr "Next-start mĂ„ste vara en procedur" + +#: module/calp/html/view/calendar.scm:79 +msgid "Prev-start needs to be a procedure" +msgstr "Prev-start mĂ„ste vara en procedur" + +#: module/calp/html/view/calendar.scm:90 +#, scheme-format +msgid "Calendar for the dates between ~a and ~a" +msgstr "Kallender för tidsintervallet ~a till ~a" + +#: module/calp/html/view/calendar.scm:154 +msgid "Page generated " +msgstr "Sidan genererad " + +#: module/calp/html/view/calendar.scm:157 +msgid "Current time " +msgstr "Nuvarande tid " + +#: module/calp/html/view/calendar.scm:159 +msgid "Source Code" +msgstr "KĂ€llkod" + +#. Button to view week +#: module/calp/html/view/calendar.scm:170 +msgid "Week" +msgstr "Veckovy" + +#. button to view month +#: module/calp/html/view/calendar.scm:174 +msgid "Month" +msgstr "MĂ„nadsvy" + +#. Button to go to today +#: module/calp/html/view/calendar.scm:184 +msgid "Today" +msgstr "Idag" + +#: module/calp/html/view/calendar.scm:204 +msgid "Month overview" +msgstr "MĂ„naden i översikt" + +#. Header of small calendar +#: module/calp/html/view/calendar.scm:208 +#, scheme-format +msgid "~B ~Y" +msgstr "~B ~Y" + +#. Search placeholder +#: module/calp/html/view/calendar.scm:234 +msgid "Search" +msgstr "Sök" + +#: module/calp/html/view/calendar.scm:240 +msgid "Option sliders" +msgstr "InstĂ€llningsreglage" + +#: module/calp/html/view/calendar.scm:243 +msgid "Event blankspace" +msgstr "HĂ€ndelsetomrum" + +#: module/calp/html/view/calendar.scm:252 +msgid "Fontsize" +msgstr "Typsnittsstorlek" + +#: module/calp/html/view/calendar.scm:263 +msgid "Calendar list" +msgstr "Kallenderlista" + +#: module/calp/html/view/calendar.scm:289 +msgid "Earlier" +msgstr "Tidigare" + +#: module/calp/html/view/search.scm:28 +msgid "Search results" +msgstr "Sökresultat" + +#: module/calp/html/view/search.scm:31 +msgid "Show today" +msgstr "Till idag" + +#: module/calp/html/view/search.scm:32 +msgid "Search term" +msgstr "Sökterm" + +#: module/calp/html/view/search.scm:39 +msgid "limit to future occurences" +msgstr "BegrĂ€nsda till framtida instanser" + +#: module/calp/html/view/search.scm:43 +msgid "Error searching" +msgstr "Misslyckades söka" + +#: module/calp/html/view/search.scm:46 +#, scheme-format +msgid "Result (page ~a)" +msgstr "Resultat (sida ~a)" + +#: module/calp/html/components.scm:61 +msgid "Only give one of onclick, href and submit." +msgstr "onlick, href, och submit Ă€r ömsesidigt uteslutande." + +#: module/calp/html/config.scm:9 +msgid "Places the generated thingy in debug mode" +msgstr "Placerar den genererade mojĂ€ngen i debug-lĂ€ge" + +#: module/calp/html/config.scm:17 +msgid "Makes the document editable" +msgstr "Gör dokumentet redigerbart" + +#: module/calp/html/util.scm:34 +#, scheme-format +msgid "Error calculating foreground color?~%~s~%" +msgstr "Misslyckades berĂ€kna förgrundsfĂ€rg?~%~s~%" + +#. Compact event list date + time +#: module/calp/html/vcomponent.scm:50 +msgid "~Y-~m-~d ~H:~M" +msgstr "~Y-~m-~d ~H:~M" + +#. Button for viewing calendar, accompanied by a calendar icon +#: module/calp/html/vcomponent.scm:55 +msgid "View" +msgstr "Visa" + +#: module/calp/html/vcomponent.scm:126 +msgid "Location: " +msgstr "Plats: " + +#: module/calp/html/vcomponent.scm:203 +msgid "Last modified" +msgstr "Senast Ă€ndrad" + +#. Last modified datetime +#: module/calp/html/vcomponent.scm:206 +msgid "~1 ~H:~M" +msgstr "~1 ~H:~M" + +#: module/calp/html/vcomponent.scm:303 module/calp/html/vcomponent.scm:520 +msgid "Recurrences" +msgstr "Upprepningar" + +#. NOTE flytta "muffarna" utanför +#: module/calp/html/vcomponent.scm:375 +msgid "- Choose a Calendar -" +msgstr "- VĂ€lj en kallender -" + +#: module/calp/html/vcomponent.scm:385 +msgid "Summary" +msgstr "Sammanfattning" + +#: module/calp/html/vcomponent.scm:394 +msgid "Start time" +msgstr "Starttid" + +#: module/calp/html/vcomponent.scm:400 +msgid "End time" +msgstr "Sluttid" + +#: module/calp/html/vcomponent.scm:406 +msgid "Whole day?" +msgstr "Heldag?" + +#: module/calp/html/vcomponent.scm:411 +msgid "Recurring?" +msgstr "Upprepande?" + +#: module/calp/html/vcomponent.scm:419 module/calp/html/vcomponent.scm:420 +#: module/calp/terminal.scm:149 +msgid "Location" +msgstr "Plats" + +#: module/calp/html/vcomponent.scm:428 module/calp/html/vcomponent.scm:429 +msgid "Description" +msgstr "Beskrivning" + +#: module/calp/html/vcomponent.scm:436 +msgid "Categories" +msgstr "Kattegorier" + +#: module/calp/html/vcomponent.scm:441 +msgid "Category" +msgstr "Kattegori" + +#: module/calp/html/vcomponent.scm:522 +msgid "Frequency" +msgstr "Frekvens" + +#: module/calp/html/vcomponent.scm:528 +msgid "Until" +msgstr "Till och med" + +#: module/calp/html/vcomponent.scm:531 +msgid "Conut" +msgstr "Antal" + +#: module/calp/html/vcomponent.scm:534 +msgid "Interval" +msgstr "Intervall" + +#: module/calp/html/vcomponent.scm:548 +msgid "By Second" +msgstr "Per sekund" + +#: module/calp/html/vcomponent.scm:549 +msgid "By Minute" +msgstr "Per minut" + +#: module/calp/html/vcomponent.scm:550 +msgid "By Hour" +msgstr "Per timme" + +#: module/calp/html/vcomponent.scm:551 +msgid "By Month Day" +msgstr "Per mĂ„nadsdag" + +#. except 0 +#: module/calp/html/vcomponent.scm:552 +msgid "By Year Day" +msgstr "Per Ă„rsdag" + +#. except 0 +#: module/calp/html/vcomponent.scm:553 +msgid "By Week Number" +msgstr "Per veckonummer" + +#. except 0 +#: module/calp/html/vcomponent.scm:554 +msgid "By Month" +msgstr "Per mĂ„nad" + +#: module/calp/html/vcomponent.scm:555 +msgid "By Set Position" +msgstr "Per fix-position" + +#. (dt "By Week Day") +#. (dd (input-list (@ (name "byweekday")) +#. (input (@ (type number) +#. (min -53) (max 53) ; except 0 +#. )) +#. ,(week-day-select '()) +#. )) +#: module/calp/html/vcomponent.scm:566 +msgid "Weekstart" +msgstr "Veckobörjan" + +#. Close this popup +#: module/calp/html/vcomponent.scm:582 +msgid "Close" +msgstr "StĂ€ng" + +#. Make this popup occupy the entire screen +#: module/calp/html/vcomponent.scm:587 +msgid "Fullscreen" +msgstr "FullskĂ€rm" + +#. Remove/Trash the event this popup represent +#. Think garbage can +#: module/calp/html/vcomponent.scm:594 +msgid "Remove" +msgstr "Ta bort" + +#: module/calp/html/vcomponent.scm:599 +msgid "Overview" +msgstr "Översikt" + +#: module/calp/html/vcomponent.scm:603 +msgid "Edit" +msgstr "Redigera" + +#: module/calp/html/vcomponent.scm:609 +msgid "Changelog" +msgstr "HĂ€ndelseförlopp" + +#: module/calp/html/vcomponent.scm:613 +msgid "Debug" +msgstr "Debug" + +#: module/calp/server/routes.scm:53 +msgid "Name" +msgstr "Namn" + +#. File permissions, should be about as long as three digits +#: module/calp/server/routes.scm:55 +msgid "Perm" +msgstr "Mod" + +#: module/calp/server/routes.scm:69 +#, scheme-format +msgid "Scandir argument invalid or not directory: ~a" +msgstr "Scandir:s argument ogilgit eller inte katalog: ~a" + +#: module/calp/server/routes.scm:103 +msgid "Go to Today" +msgstr "GĂ„ till idag" + +#: module/calp/server/routes.scm:156 +msgid "uid required" +msgstr "uid krĂ€vs" + +#: module/calp/server/routes.scm:168 module/calp/server/routes.scm:264 +#: module/calp/server/routes.scm:297 +msgid "Saving event to disk failed." +msgstr "Misslyckades spara hĂ€ndelse till disk." + +#: module/calp/server/routes.scm:171 +#, scheme-format +msgid "No event with UID '~a'" +msgstr "Ingen hĂ€ndelse med UID '~a'" + +#: module/calp/server/routes.scm:179 +msgid "Both 'cal' and 'data' required" +msgstr "BĂ„de 'cal' och 'data' obligatoriska" + +#: module/calp/server/routes.scm:192 +#, scheme-format +msgid "No calendar with name [~a]" +msgstr "Ingen kallender heter [~a]" + +#: module/calp/server/routes.scm:223 +msgid "XML parse error" +msgstr "XML inlĂ€sningsfel" + +#: module/calp/server/routes.scm:228 +msgid "Object not a VEVENT" +msgstr "Objektet Ă€r inte ett VEVENT" + +#. unlinks (removes) a single event, argument is a file name +#: module/calp/server/routes.scm:271 +#, scheme-format +msgid "Unlinking old event from ~a~%" +msgstr "Tar bort den gamla hĂ€ndelsen frĂ„n ~a~%" + +#: module/calp/server/routes.scm:281 +#, scheme-format +msgid "Event updated ~a~%" +msgstr "HĂ€ndelse uppdaterad ~a~%" + +#: module/calp/server/routes.scm:300 +#, scheme-format +msgid "Event inserted ~a~%" +msgstr "HĂ€ndelse infogad ~a~%" + +#: module/calp/server/routes.scm:352 module/calp/server/routes.scm:361 +#, scheme-format +msgid "No component with UID=~a found." +msgstr "Hittade ingen komponent med UID=~a." + +#: module/calp/util/config.scm:42 +msgid "Missing config protperty slot " +msgstr "Skanat konfigurationsegenskapsfĂ€lt" + +#: module/calp/util/config.scm:57 +msgid "Pre crashed for" +msgstr "Pre krashade för" + +#: module/calp/util/config.scm:68 +msgid "Missing config" +msgstr "Saknad konfiguration" + +#: module/calp/util/config.scm:116 +msgid "Configuration variables" +msgstr "Konfigurationsvariabler" + +#. Configuration variable value indicator +#: module/calp/util/config.scm:129 +msgid "V:" +msgstr "V:" + +#: module/calp/util/exceptions.scm:7 +msgid "Crash on warnings." +msgstr "Krasha pĂ„ varningar" + +#: module/calp/terminal.scm:78 +msgid "NO LOCATION" +msgstr "INGEN PLATS" + +#: module/calp/terminal.scm:129 +msgid "== Day View ==\n" +msgstr "== Dagsvy ==\n" + +#: module/calp/terminal.scm:155 +msgid "Start" +msgstr "Start" + +#. Event start date-time terminal view +#. Event end date-time terminal view +#. Event start date-time terminal view +#. Event end date-time terminal view +#: module/calp/terminal.scm:160 module/calp/terminal.scm:168 +msgid "~Y-~m-~d ~H:~M:~S" +msgstr "~Y-~m-~d ~H:~M:~S" + +#: module/calp/terminal.scm:163 +msgid "End" +msgstr "Slut" + +#: module/calp/terminal.scm:211 +msgid "quick search: " +msgstr "Snabbsök: " + +#: module/calp/terminal.scm:218 +msgid "search: " +msgstr "sök: " + +#: module/calp/terminal.scm:264 +msgid "== Search View ==\n" +msgstr "== Sökvy ==\n" + +#: module/calp/repl.scm:16 +#, scheme-format +msgid "Starting REPL server at ~a~%" +msgstr "Startar REPL-server pĂ„ ~a~%" + +#: module/calp/repl.scm:26 +#, scheme-format +msgid "Failed to unlink ~a" +msgstr "Misslyckades med att avlĂ€nka ~a" + +#: module/calp/repl.scm:30 +msgid "Empty address?" +msgstr "Tom address?" + +#. currently impossible +#: module/calp/repl.scm:35 +msgid "How did you get here?" +msgstr "Hur hamnade du hĂ€r?" + +#: module/calp/main.scm:51 +msgid "Path to alterantive configuration file to load instead of the " + "default one." +msgstr "SökvĂ€g till alternativ konfigurationsfil." + +#: module/calp/main.scm:65 +#, scheme-format +msgid "Display version, which is ~a btw." +msgstr "Visar version, vilket Ă€r ~a helt apropĂ„." + +#: module/calp/main.scm:71 +msgid "Print this help" +msgstr "Visar den hĂ€r hjĂ€lpen." + +#: module/calp/main.scm:123 +#, scheme-format +msgid "Configuration file ~a missing" +msgstr "Konfigurationsfilen ~a saknas" + +#. Two arguments: +#. Configuration file path, +#. thrown error arguments +#: module/calp/main.scm:171 +#, scheme-format +msgid "Failed loading config file ~a~%~s~%" +msgstr "Misslyckades med att ladda konfigurationsfilen ~a~%~s~%" + +#: module/calp/main.scm:212 +#, scheme-format +msgid "Calp version ~a~%" +msgstr "Calp version ~a~%" + +#: module/calp/main.scm:218 +#, scheme-format +msgid "tzget not installed, please put it in one of ~a" +msgstr "tzget Ă€r inte intstalleratt, vĂ€nligen placera programmet i en av ~a" + +#: module/calp/main.scm:250 +#, scheme-format +msgid "Unsupported mode of operation: ~a~%" +msgstr "Orimligt subbkomando: ~a~%" + +#: module/calp/main.scm:265 +msgid "Program start" +msgstr "Programstart" + +#: module/datetime/instance.scm:28 +msgid "Default zoneinfo only available when tz-dir and tz-list are " + "configured" +msgstr "Standardzoninfo endast tillgĂ€ngligt nĂ€r tz-dir och tz-list Ă€r satta" + +#: module/datetime/zic.scm:166 module/datetime/zic.scm:339 +msgid "what even is \"Standard time\"“" +msgstr "Vad Ă€r ens \"Standardtid\"“" + +#. NOTE an earlier version of the code the parsers for those. +#. They were removed since they were unused, uneeded, and was +#. technical dept. +#: module/datetime/zic.scm:262 +#, scheme-format +msgid "Invalid key ~a. Note that leap seconds and\n" + "expries rules aren't yet implemented." +msgstr "Ogiltig nyckel ~a. Notera att skottsekunder och utgĂ„ngsreglerĂ€nnu " + "inte Ă€r implementerade." + +#: module/datetime/zic.scm:299 +#, scheme-format +msgid "Unresolved link, target missing ~a -> ~a" +msgstr "Ohanterad lĂ€nk, saknar mĂ„l ~a -> ~a" + +#: module/datetime/zic.scm:360 +msgid "Check your input" +msgstr "Kontrollera din input" + +#: module/datetime/zic.scm:384 +msgid "Counting backward for RRULES unsupported" +msgstr "Att rĂ€kna baklĂ€nges stdöjs inte för RRULES" + +#. NOTE No zones seem to currently use %z formatting. +#. '%z' is NOT a format string, but information about another format string. +#: module/datetime/zic.scm:403 +msgid "%z not yet implemented" +msgstr "%z Ă€nnu ej implementerat" + +#: module/datetime/zic.scm:406 +msgid "Invalid format char" +msgstr "Ogiltigt formatteringstecken" + +#: module/datetime/timespec.scm:37 +msgid "Adding timespecs of differing types" +msgstr "LĂ€gger till tidsspecifikationer av olika typer" + +#: module/vcomponent/datetime/output.scm:20 +msgid "Upprepas " +msgstr "" + +#: module/vcomponent/datetime/output.scm:25 +msgid ", undantaget " +msgstr "" + +#. Warning message for failure to format description. +#. First argument is name of warning/error, +#. second is error arguments +#: module/vcomponent/datetime/output.scm:51 +#, scheme-format +msgid "~a on formatting description, ~s" +msgstr "~a vid formattering av beskrivning, ~s" + +#: module/vcomponent/formats/common/types.scm:15 +msgid "Binary field not marked ENCODING=BASE64" +msgstr "BinĂ€rdatefĂ€lt ej markerat ENCODING=BASE64" + +#: module/vcomponent/formats/common/types.scm:27 +#, scheme-format +msgid "~a invalid boolean" +msgstr "~a Ă€r inte en giltig boolean" + +#: module/vcomponent/formats/common/types.scm:60 +msgid "Non integer as integer" +msgstr "Icke-heltag som heltal" + +#: module/vcomponent/formats/common/types.scm:91 +#, scheme-format +msgid "Non-escapable character: ~a" +msgstr "Tecken utan specialtolkning: ~a" + +#: module/vcomponent/formats/common/types.scm:140 +msgid "No parser for type" +msgstr "Ingen inlĂ€sare för typ" + +#: module/vcomponent/formats/ical/output.scm:94 +#: module/vcomponent/formats/ical/parse.scm:230 +#: module/vcomponent/formats/xcal/output.scm:73 +#, scheme-format +msgid "Unknown key ~a" +msgstr "OkĂ€nd nyckel ~a" + +#: module/vcomponent/formats/ical/parse.scm:124 +msgid "List in enum field" +msgstr "Lista in upprĂ€kningsinstansfĂ€lt" + +#: module/vcomponent/formats/ical/parse.scm:159 +#, scheme-format +msgid "List in non-list field: ~s" +msgstr "Lista i fĂ€lt för icke-lista: ~s" + +#: module/vcomponent/formats/ical/parse.scm:196 +msgid "TODO Implement REQUEST-STATUS" +msgstr "TODO implementera REQUEST-STATUS" + +#. arguments: +#. linedata +#. ~? +#. source line +#. source file +#: module/vcomponent/formats/ical/parse.scm:283 +#, scheme-format +msgid "WARNING parse error around ~a\n" + " ~?\n" + " line ~a ~a~%" +msgstr "VARNING inlĂ€sningsfel runt ~a ~? rad ~a ~a~%" + +#. arguments +#. linedata +#. ~? +#. source line +#. source file +#: module/vcomponent/formats/ical/parse.scm:337 +#, scheme-format +msgid "ERROR parse error around ~a\n" + " ~?\n" + " line ~a ~a\n" + " Defaulting to string~%" +msgstr "FEL inlĂ€sningsfel runt ~a ~? rad ~a ~a Faller tilbaka pĂ„ strĂ€ng~%" + +#: module/vcomponent/formats/ical/types.scm:40 +msgid "PERIOD writer not yet implemented" +msgstr "PERIOD-formaterrare Ă€nnu ej implementerad" + +#: module/vcomponent/formats/ical/types.scm:97 +#: module/vcomponent/formats/xcal/types.scm:55 +msgid "No writer for type" +msgstr "Ingen formatterare för typ" + +#: module/vcomponent/formats/vdir/parse.scm:62 +#, scheme-format +msgid "No events in component~%~a" +msgstr "Inga hĂ€ndelser i komponenten~%~a" + +#: module/vcomponent/formats/xcal/parse.scm:87 +#, scheme-format +msgid "Invalid type ~a, with value ~a" +msgstr "Ogiltig typ ~a, med vĂ€rde ~a" + +#. TODO +#: module/vcomponent/formats/xcal/parse.scm:157 +msgid "Request status not yet implemented" +msgstr "StatusbegĂ€ran Ă€nnu ej implementerad" + +#: module/vcomponent/util/instance/methods.scm:55 +#, scheme-format +msgid "Building from~%" +msgstr "Bygger frĂ„n~%" + +#: module/vcomponent/util/instance.scm:22 +#, scheme-format +msgid "Reload done~%" +msgstr "Omladdning fĂ€rdig~%" + +#: module/vcomponent/util/parse-cal-path.scm:23 +#, scheme-format +msgid "Parsing ~a" +msgstr "LĂ€ser ~a" + +#: module/vcomponent/util/parse-cal-path.scm:29 +msgid "Can't parse file of type " +msgstr "Kan inte lĂ€sa fil av typen " + +msgid "Can't give week together with day or time" +msgstr "Kan inte ge vecka tillsamans med dag eller tid" + +#: module/calp/html/vcomponent.scm:512 +msgid "Last Modified" +msgstr "Senast Ă€ndrad" + +#: module/calp/main.scm:84 +msgid "Usage: calp [ flags ] mode [ mode flags ]" +msgstr "AnvĂ€ndning: calp [ flaggor ] subkommando " + "[ Subkommandosflaggor ]" + +#. Header for following list of modes of operation +#: module/calp/main.scm:87 +msgid "Modes" +msgstr "Subkommandon" + +#: module/calp/main.scm:89 +msgid "

html reads calendar files from disk, and writes them to " + "static HTML files.

" +msgstr "

html lÀser kalenderfiler frÄn disk, och matar ur sig statiska " + "HTML-filer.

" + +#: module/calp/main.scm:90 +msgid "

terminal loads the calendars, and starts an interactive " + "terminal interface.

" +msgstr "

terminal laddar kalendrar, och startar ett en interaktiv " + "miljö i terminalen.

" + +#: module/calp/main.scm:94 +msgid "

ical loads the calendar database, and immediately\n" + "re-serializes it back into iCAL format. Useful for merging calendars." + "

" +msgstr "

ical laddar kallenderdatabasen, och Äterserialiserar den " + "omedelbart tillbaka till iCAL. AnvÀndbart för att slÄ samman " + "kallendrar.

" + +#. Header for list of available flags. +#. Actual list is auto generated elsewhere. +#: module/calp/main.scm:105 +msgid "Flags" +msgstr "Flaggor" + +#: module/calp/terminal.scm:320 +msgid "loading..." +msgstr "laddar..." + +#: module/datetime/instance.scm:12 +msgid "List of default zoneinfo files to be parsed" +msgstr "Lista av standardzoninfofiler att ladda" + +#: module/calp/main.scm:98 +msgid "

server starts an HTTP server which dynamically loads and\n" + "displays events. The /month/{date}.html & /week/{date}." + "html runs\n" + "the same output code as html. While the /calendar/{uid}." + "ics uses\n" + "the same code as ical.

" +msgstr "

server startar en HTTP-server vilken dynamiskt laddar och " + "visar hÀndelser. Addresserna /month/{date}.html & /" + "week/{date}.html kör samma utskriftskod som html. Emedans " + "/calendar/{uid}.ics delar kod med ical.

" + +#: module/calp/entry-points/text.scm:16 +msgid "Read from file instead of standard input." +msgstr "LÀs fran file istÀllet för standard-input." + +#: module/calp/entry-points/tidsrapport.scm:179 +msgid "Map between real field names and human readable names.
\n" + "If data is given, but not trans, then data is assumed to be in a " + "correct format
" +msgstr "ÖversĂ€ttningstabell mellan verkliga fĂ€ltnamn och mĂ€nskligt " + "lĂ€sbara namn.
Om data Àr given, men inte översÀttingstabellen, " + "sÄ antas datan redan ha korrekta nycklar
" + +#: module/calp/entry-points/convert.scm:14 +msgid "Input format (otherwise infered from infile)" +msgstr "Inputformat (hÀrleds annars frÄn infile)" + +#: module/calp/entry-points/convert.scm:16 +msgid "Output format (otherwise infered from outfile)" +msgstr "Utadataformat (hÀrleds annars frÄn outfile)" + +#: module/calp/entry-points/html.scm:35 +msgid "How many pages should be rendered.\n" + "If --style=week and --from=2020-04-27;\n" + "then --count=4 would render the four pages\n" + "2020-04-27, 2020-05-04, 2020-05-11, and 2020-05-25.\n" + "Defaults to 12 to give a whole year when --style=month" +msgstr "Antal sidor att rendera.Om --style=week och --" + "from=2020-04-27 kommer--count=4 rendera de fyra " + "sidorna2020-04-27, 2020-05-04, 2020-05-11, och 2020-05-25.Antar " + "vÀrdet 12 för att ge ett helt Är dÄ --style=month" + +#: module/calp/entry-points/html.scm:42 +msgid "Directory where html files should end up. Default to ./" + "html" +msgstr "Katalog dÀr html-filer ska placeras. Har standardvÀrder ./" + "html" + +#: module/calp/entry-points/html.scm:46 +msgid "How the body of the HTML page should be layed out.\n" + "
week\n" + "gives a horizontally scrolling page with 7 elements, where each has " + "events\n" + "graphically laid out hour by hour.\n" + "
table\n" + "gives a month in overview as a table. Each block contains the events " + "for the\n" + "given day, in order of start time. They are however not graphically " + "sized.\n" + "
wide\n" + "is the same as week, but gives a full month.
" +msgstr "Hur HTML-sidans komponenter ska placeras.
week ger " + "en horisentellt skrollande sida med 7 element, dÀr varje element har " + "hÀndelser grafiskt utlaggda.
table ger en mÄnadsöversikt " + "som en tabell, dÀr varje cell visar den dagens hÀndelser i ordning, " + "dock inte grafiskt skalade.
wide Motsvarande som week, " + "men för en hel mÄnad
" + +#: module/calp/entry-points/html.scm:57 +msgid "Creates a standalone document instead of an HTML fragment\n" + "for embedding in a larger page. Currently only applies to the " + "small style" +msgstr "Skapar ett fristÄende dokument istÀllet för ett HTML-fragment " + "för inbÀddning i andra sidor. Fungerar för nuvarande bara med stilen " + "small" + +#: module/calp/entry-points/server.scm:19 +msgid "Bind to TCP port, defaults to 8080.\n" + "
Can also be set through the config variable\n" + "port.
" +msgstr "Bind till en TCP-port, och blir 8080 om osatt.
Kan " + "Àven sÀttas genom konfigurationsfÀltet port.
" + +#: module/calp/entry-points/server.scm:23 +msgid "Address to use, defaults to 0.0.0.0 for IPv4,\n" + "and [::] for IPv6" +msgstr "Address att anvÀnda, utgÄr frÄn 0.0.0.0 för IPv4, samt " + "[::] för IPv6" + +#: module/calp/main.scm:38 +msgid "Run the program within Guile's built in statical\n" + "profiler. Display style is one of flat or tree." +msgstr "Kör programmet i Guiles inbyggda statiska profilerare.\n" + "Visningsstil Àr flat eller tree." + +#: module/calp/main.scm:42 +msgid "Start a Guile repl which can be connected to, defaults to " + "the\n" + "unix socket /run/user/${UID}/calp-${PID}, but it can be bound " + "to any\n" + "unix or TCP socket. ((@ (vcomponent util instance) global-event-" + "object)) should\n" + "contain all events.\n" + "
\n" + "Should NOT be used in production.
" +msgstr "Startar en Guile-REPL för anslutningar. Binder som standard " + "till unix-sockeln /run/user/${UID}/calp-${PID}, man kan " + "bindas till valfri unix eller TCP sockel. ((@ (vcomponent util " + "instance) global-event-object)) bör inehÄlla alla hÀndelser
Ska INTE anvÀndas i produktion.
" + +#: module/calp/main.scm:59 +msgid "Set configuration options, on the form key=value\n" + "as if they were set in the config file. These options have priority " + "over those\n" + "from the file. Can not be given with an equal after --" + "option.
Can\n" + "be given multiple times.
" +msgstr "SÀtter konfigurationsvariabler, pÄ formen nyckel=vÀrde, motsvarande om de hade satts i konfigurationsfilen. " + "Dock har de hÀr prioritet över dem frÄn filen.\n" + "Kan inte ges med ett lika-med-tecken efter --option.
Kan " + "ges flera gÄnger.
" + +#: module/calp/main.scm:73 +msgid "Print known configuration variables.\n" + "
NOTE:\n" + "Only those configuration variables which are loaded will be shown, " + "more might be\n" + "available
" +msgstr "Visar kÀnda konfigurationsvariabler.
NOTERA:\n" + "Endast de konfigurationsvariablerna vilka har laddats in kommer " + "visas, fler kan vara finnas
" + +#: module/calp/main.scm:91 +msgid "[UNTESTED]

imports a calendar object into the database." + "

" +msgstr "[OTESTAD]

importerar ett kallenderobjekt till " + "databasen.

" + +#: module/calp/main.scm:92 +msgid "

text formats and justifies what it's given on standard " + "input,\n" + "and writes it to standard output. Similar to this text.

" +msgstr "

text formatterar och justerar det den fÄr pÄ standard-" + "input, och skriver det till standard-output, pÄ motsvarande stil som " + "den hÀr texten.

" + +#: module/calp/main.scm:96 +msgid "

benchmark module
Runs the procedure 'run-" + "benchmark'\n" + "from the module (calp benchmark module).

" +msgstr "

benchmark modul
Kör proceduren 'run-benchmark' " + "frÄn modulen (calp benchmark modul).

" + +#. Week view header format +#. start date metainfo +#. end date metainfo +#. Generation data +#. Compact event list date only +#. Header for sidebar day +#. Week view header format +#. start date metainfo +#. end date metainfo +#. Generation data +#. Compact event list date only +#. Header for sidebar day +#: module/calp/html/view/calendar/week.scm:50 +#: module/calp/html/view/calendar.scm:92 module/calp/html/view/calendar.scm:94 +#: module/calp/html/view/calendar.scm:156 module/calp/html/vcomponent.scm:52 +#: module/calp/html/vcomponent.scm:218 +msgid "~Y-~m-~d" +msgstr "~Y-~m-~d" -- cgit v1.2.3 From d4759a55f59bac49f3912305f09ca71666d122be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 22 Feb 2022 11:52:33 +0100 Subject: Update makefile for localizations. --- .gitignore | 1 + Makefile | 18 +++++++++++++++++- po/.gitignore | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 po/.gitignore diff --git a/.gitignore b/.gitignore index b27c1c89..d6eec99c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.x /html coverage +localization diff --git a/Makefile b/Makefile index 978ecc85..fbbfbc6c 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,27 @@ GUILE_C_FLAGS = -Lmodule \ -Wmacro-use-before-definition -Warity-mismatch \ -Wduplicate-case-datum -Wbad-case-datum -all: $(GO_FILES) README static +# All po-files inside po/, except new.po, and hidden files +PO_FILES = $(shell find po -type f -name \*.po -and -not -name new.po -and -not -name .\*) +LOCALIZATIONS = $(PO_FILES:po/%.po=localization/%/LC_MESSAGES/calp.mo) + +all: $(GO_FILES) README static $(LOCALIZATIONS) + +XGETTEXT_FLAGS = --from-code=UTF-8 --add-comments --indent -k_ static: $(MAKE) -C static +po/%.po: $(SCM_FILES) + xgettext $(XGETTEXT_FLAGS) --output $@ -L scheme $^ --join-existing --omit-header + +po/new.po: $(SCM_FILES) + xgettext $(XGETTEXT_FLAGS) --output $@ -L scheme $^ + +localization/%/LC_MESSAGES/calp.mo: po/%.po + -@mkdir -p $(shell dirname $@) + msgfmt --check -o $@ $< + obj/%.go: module/%.scm @mkdir -p obj @echo guild compile $< diff --git a/po/.gitignore b/po/.gitignore new file mode 100644 index 00000000..6cf4a14e --- /dev/null +++ b/po/.gitignore @@ -0,0 +1 @@ +new.po -- cgit v1.2.3 From 37267bbcb42f985f5e00cea2a93cc40a3b8ca50b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 22 Feb 2022 17:50:29 +0100 Subject: Update (text module) to dispatch. (text module) now dispatch its functions to the correct (text module lang) module. --- module/text/numbers.scm | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/module/text/numbers.scm b/module/text/numbers.scm index aceb82cc..168d267e 100644 --- a/module/text/numbers.scm +++ b/module/text/numbers.scm @@ -1,8 +1,35 @@ +(define-module (text numbers) + :export (number->string-cardinal + number->string-ordinal + each-string)) -(eval-when (load) - (throw 'do-not-load-me - "Import (text numbers ) instead") - ) +(define (get mod-symb proc-symb) + (module-ref (resolve-interface `(text numbers ,mod-symb)) + proc-symb)) + +;; "sv_SE.UTF-8" +(define (resolve-language) + (string->symbol + (string-take + (or (getenv "LC_MESSAGES") + (getenv "LC_ALL") + "en") + 2))) + +(define* (number->string-cardinal + n #:optional (language (resolve-language))) + ((get language 'number->string-cardinal) n)) + +(define* (number->string-ordinal + n #:optional (language (resolve-language))) + ((get language 'number->string-ordinal) n)) + +;; TODO change API to allow language, and stop having random extra +;; arguments for implementations. +(define* (each-string count . args) + (define language (resolve-language)) + (apply (get language 'each-string) + count args)) ;; scheme@(guile-user)> (number->string-cardinal 123) ;; $10 = "hundratjugotre" -- cgit v1.2.3 From 3c9b8911b5952afe6ad69d04fbcbb7169bb0db3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 22 Feb 2022 18:02:12 +0100 Subject: Fix modularization of recurrence display. --- module/hnh/util/language.scm | 14 +++ module/vcomponent/recurrence/display.scm | 154 ++---------------------- module/vcomponent/recurrence/display/common.scm | 6 + module/vcomponent/recurrence/display/en.scm | 131 ++++++++++++++++++++ module/vcomponent/recurrence/display/sv.scm | 139 +++++++++++++++++++++ 5 files changed, 299 insertions(+), 145 deletions(-) create mode 100644 module/hnh/util/language.scm create mode 100644 module/vcomponent/recurrence/display/common.scm create mode 100644 module/vcomponent/recurrence/display/en.scm create mode 100644 module/vcomponent/recurrence/display/sv.scm diff --git a/module/hnh/util/language.scm b/module/hnh/util/language.scm new file mode 100644 index 00000000..9b61483c --- /dev/null +++ b/module/hnh/util/language.scm @@ -0,0 +1,14 @@ +(define-module (hnh util language) + :export (resolve-language)) + + +;; Locale objects, such as %global-locale, doesn't provide a way to access the language name, +;; This is for procedures which want to handle their translations manually. +(define (resolve-language) + "Returns a two character symbol representing the \"current\" language. e.g. en" + (string->symbol + (string-take + (or (getenv "LC_MESSAGES") + (getenv "LC_ALL") + "en") + 2))) diff --git a/module/vcomponent/recurrence/display.scm b/module/vcomponent/recurrence/display.scm index f5ce1c57..8a9f33e6 100644 --- a/module/vcomponent/recurrence/display.scm +++ b/module/vcomponent/recurrence/display.scm @@ -1,146 +1,10 @@ -;;; Commentary: -;; Pretty print a recurrence rule (in Swedish). Is currently missing a -;; number of ;; edge cases, and even more concerning limited events. -;; NOTE It would be preferable if this could share as much logic as possible -;; with the "real" generator. -;;; Code: - (define-module (vcomponent recurrence display) - :use-module (hnh util) - :use-module (vcomponent recurrence internal) - :use-module (text util) - :use-module (text numbers sv) - :use-module ((datetime) :select (time time->string - datetime->string - week-day-name - locale-month - )) - ) - - -(define (rrule-month->string n) - (locale-month n)) - -;; TODO this currently only groups on offsets, but not on days. -;; So 1MO, 1TU becomes "första mĂ„ndagen och tisdagen", which is good -;; but 1MO, -1MO doesn't become "första och sista mĂ„ndagen". -;; TODO also, grouping of -dagen. e.g. "första mĂ„n- och tisdagen" -(define (format-byday-list lst) - (let* ((groups (group-by car lst))) - (intersperse - " samt " - (map (lambda (group) - ;; TODO sort week days - (case (car group) - [(#f) - (list "varje " - (add-enumeration-punctuation - (map (lambda (d) (list (week-day-name (cdr d)))) - (cadr group) - )))] - [else - (list (number->string-ordinal - (car group) - a-form?: #t) - " " - (add-enumeration-punctuation - (map (lambda (d) (list (week-day-name (cdr d)) "en")) - (cadr group))))]) - ) - groups)))) - -(define* (format-bymonth-day lst optional: (final-delim "&")) - (list "den " - (add-enumeration-punctuation - (map number->string-ordinal lst) - final-delim))) - - -(define-public (format-recurrence-rule rrule) - (string-trim - (string-flatten - (list - (case (freq rrule) - [(YEARLY) - (list (awhen (byday rrule) (list " " (format-byday-list it))) - (awhen (bymonthday rrule) (list " " (format-bymonth-day it "eller"))) - (awhen (byyearday rrule) - (list " dag " (add-enumeration-punctuation it))) - (awhen (bymonth rrule) - ;; only `i' here if we have output something else beforehand - (list (when (or (byday rrule) - (bymonthday rrule) - (byyearday rrule)) - " i ") - (add-enumeration-punctuation - (map rrule-month->string it)))) - (awhen (byweekno rrule) - (map (lambda (v) (format #f " v.~a" v)) it)) - )] - [(MONTHLY) - (list - (awhen (byday rrule) (list (format-byday-list it))) - (awhen (bymonthday rrule) (cons " " (format-bymonth-day it))))] - [else '()]) - - ;; TODO my parser adds an implicit interval to every object - ;; this might be wrong - (cond [(and (eq? 'DAILY (freq rrule)) (= 1 (interval rrule))) - " dagligen"] - [(and (eq? 'YEARLY (freq rrule)) (= 1 (interval rrule))) - ", Ă„rligen"] - [(and (eq? 'MINUTELY (freq rrule)) - (zero? (modulo (interval rrule) 15))) - (list " " - (each-string (/ (interval rrule) 15)) - " kvart")] - [else - (list - " " - (each-string (interval rrule) (eq? 'YEARLY (freq rrule))) - " " - (case (freq rrule) - ;; p.44 RFC 5545 - [(SECONDLY) "sekund"] - [(MINUTELY) "minut"] - [(HOURLY) "timme"] - [(DAILY) "dag"] - - ;; day offsets CAN ONLY be present when FREQ is - ;; either MONTHLY or YEARLY - [(WEEKLY) (aif (byday rrule) - (add-enumeration-punctuation - (map (compose week-day-name cdr) it)) - "vecka")] - [(MONTHLY) "mĂ„nad"] - [(YEARLY) "Ă„r"] - [else "ERROR"] - ))]) - - (cond [(and (byminute rrule) - (byhour rrule)) - (list - " kl. " - (add-enumeration-punctuation - (map (lambda (pair) - (time->string - (time hour: (car pair) - minute: (cadr pair)) - "~H:~M")) - (cross-product (byhour rrule) - (byminute rrule)))))] - [(byhour rrule) - => (lambda (hours) - (list " kl. " (add-enumeration-punctuation hours)))] - [else '()]) - - (awhen (until rrule) - (format #f ", till och med ~a" - (datetime->string - ;; TODO ordinal on ~d? - it "den ~d ~B, ~Y kl. ~k:~M") - )) - (cond [(not (count rrule)) ""] - [(= 1 (count rrule)) (list ", totalt " (count rrule) " gĂ„ng")] - [(count rrule) (list ", totalt " (count rrule) " gĂ„nger")] - [else "ERROR"]))))) + :use-module (vcomponent recurrence display common) + :use-module (hnh util language) + :re-export (rrule-month->string) + :export (format-recurrence-rule)) + +(define* (format-recurrence-rule rrule #:optional (language (resolve-language))) + ((module-ref (resolve-interface `(vcomponent recurrence display ,language)) + 'format-recurrence-rule) + rrule)) diff --git a/module/vcomponent/recurrence/display/common.scm b/module/vcomponent/recurrence/display/common.scm new file mode 100644 index 00000000..c9d0f5e1 --- /dev/null +++ b/module/vcomponent/recurrence/display/common.scm @@ -0,0 +1,6 @@ +(define-module (vcomponent recurrence display common) + :use-module ((datetime) :select (locale-month)) + :export (rrule-month->string)) + +(define (rrule-month->string n) + (locale-month n)) diff --git a/module/vcomponent/recurrence/display/en.scm b/module/vcomponent/recurrence/display/en.scm new file mode 100644 index 00000000..be9bdf53 --- /dev/null +++ b/module/vcomponent/recurrence/display/en.scm @@ -0,0 +1,131 @@ +(define-module (vcomponent recurrence display en) + :use-module (hnh util) + :use-module (vcomponent recurrence internal) + :use-module (text util) + :use-module (text numbers) + :use-module (vcomponent recurrence display common) + :use-module ((datetime) :select (time time->string + datetime->string + week-day-name))) + + + +;; TODO this currently only groups on offsets, but not on days. +;; So 1MO, 1TU becomes "första mĂ„ndagen och tisdagen", which is good +;; but 1MO, -1MO doesn't become "första och sista mĂ„ndagen". +;; TODO also, grouping of -dagen. e.g. "första mĂ„n- och tisdagen" +(define (format-byday-list lst) + (let* ((groups (group-by car lst))) + (intersperse + " as well as " + (map (lambda (group) + ;; TODO sort week days + (case (car group) + [(#f) + (list "every " + (add-enumeration-punctuation + (map (lambda (d) (list (week-day-name (cdr d)))) + (cadr group) + )))] + [else + (list (number->string-ordinal (car group)) " " + (add-enumeration-punctuation + (map (lambda (d) (list (week-day-name (cdr d)) "en")) + (cadr group))))]) + ) + groups)))) + +(define (format-bymonth-day lst) + (list "the " + (add-enumeration-punctuation + (map number->string-ordinal lst)))) + + +(define-public (format-recurrence-rule rrule) + (string-trim + (string-flatten + (list + (case (freq rrule) + [(YEARLY) + (list (awhen (byday rrule) (list " " (format-byday-list it))) + (awhen (bymonthday rrule) (list " " (format-bymonth-day it))) + (awhen (byyearday rrule) + (list " day " (add-enumeration-punctuation it))) + (awhen (bymonth rrule) + ;; only `i' here if we have output something else beforehand + (list (when (or (byday rrule) + (bymonthday rrule) + (byyearday rrule)) + " in ") + (add-enumeration-punctuation + (map rrule-month->string it)))) + (awhen (byweekno rrule) + (map (lambda (v) (format #f " v.~a" v)) it)) + )] + [(MONTHLY) + (list + (awhen (byday rrule) (list (format-byday-list it))) + (awhen (bymonthday rrule) (format-bymonth-day it)))] + [else '()]) + + ;; TODO my parser adds an implicit interval to every object + ;; this might be wrong + (cond [(and (eq? 'DAILY (freq rrule)) (= 1 (interval rrule))) + " daily"] + [(and (eq? 'YEARLY (freq rrule)) (= 1 (interval rrule))) + ", yearly"] + [(and (eq? 'MINUTELY (freq rrule)) + (zero? (modulo (interval rrule) 15))) + (list " " + (each-string (/ (interval rrule) 15)) + " 15 minutes")] + [else + (list + " " + (each-string (interval rrule) (eq? 'YEARLY (freq rrule))) + " " + (case (freq rrule) + ;; p.44 RFC 5545 + [(SECONDLY) "second"] + [(MINUTELY) "minute"] + [(HOURLY) "hour"] + [(DAILY) "day"] + + ;; day offsets CAN ONLY be present when FREQ is + ;; either MONTHLY or YEARLY + [(WEEKLY) (aif (byday rrule) + (add-enumeration-punctuation + (map (compose week-day-name cdr) it)) + "week")] + [(MONTHLY) "month"] + [(YEARLY) "year"] + [else "ERROR"] + ))]) + + (cond [(and (byminute rrule) + (byhour rrule)) + (list + " at " + (add-enumeration-punctuation + (map (lambda (pair) + (time->string + (time hour: (car pair) + minute: (cdr pair)) + "~H:~M")) + (cross-product (byhour rrule) + (byminute rrule)))))] + [(byhour rrule) + => (lambda (hours) + (list " at " (add-enumeration-punctuation hours)))] + [else '()]) + + (awhen (until rrule) + (format #f ", until ~a" + (datetime->string + ;; TODO ordinal on ~d? + it "~B ~d, ~Y at ~k:~M") + )) + (cond [(not (count rrule)) ""] + [(= 1 (count rrule)) (list ", " (count rrule) " time in total")] + [(count rrule) (list ", " (count rrule) " times in total")] + [else "ERROR"]))))) diff --git a/module/vcomponent/recurrence/display/sv.scm b/module/vcomponent/recurrence/display/sv.scm new file mode 100644 index 00000000..fe580474 --- /dev/null +++ b/module/vcomponent/recurrence/display/sv.scm @@ -0,0 +1,139 @@ +;;; Commentary: +;; Pretty print a recurrence rule (in Swedish). Is currently missing a +;; number of ;; edge cases, and even more concerning limited events. +;; NOTE It would be preferable if this could share as much logic as possible +;; with the "real" generator. +;;; Code: + +(define-module (vcomponent recurrence display sv) + :use-module (hnh util) + :use-module (vcomponent recurrence internal) + :use-module (text util) + :use-module (text numbers sv) + :use-module (vcomponent recurrence display common) + :use-module ((datetime) :select (time time->string + datetime->string + week-day-name))) + +;; TODO this currently only groups on offsets, but not on days. +;; So 1MO, 1TU becomes "första mĂ„ndagen och tisdagen", which is good +;; but 1MO, -1MO doesn't become "första och sista mĂ„ndagen". +;; TODO also, grouping of -dagen. e.g. "första mĂ„n- och tisdagen" +(define (format-byday-list lst) + (let* ((groups (group-by car lst))) + (intersperse + " samt " + (map (lambda (group) + ;; TODO sort week days + (case (car group) + [(#f) + (list "varje " + (add-enumeration-punctuation + (map (lambda (d) (list (week-day-name (cdr d)))) + (cadr group) + )))] + [else + (list (number->string-ordinal + (car group) + a-form?: #t) + " " + (add-enumeration-punctuation + (map (lambda (d) (list (week-day-name (cdr d)) "en")) + (cadr group))))]) + ) + groups)))) + +(define* (format-bymonth-day lst optional: (final-delim "&")) + (list "den " + (add-enumeration-punctuation + (map number->string-ordinal lst) + final-delim))) + +(define-public (format-recurrence-rule rrule) + (string-trim + (string-flatten + (list + (case (freq rrule) + [(YEARLY) + (list (awhen (byday rrule) (list " " (format-byday-list it))) + (awhen (bymonthday rrule) (list " " (format-bymonth-day it "eller"))) + (awhen (byyearday rrule) + (list " dag " (add-enumeration-punctuation it))) + (awhen (bymonth rrule) + ;; only `i' here if we have output something else beforehand + (list (when (or (byday rrule) + (bymonthday rrule) + (byyearday rrule)) + " i ") + (add-enumeration-punctuation + (map rrule-month->string it)))) + (awhen (byweekno rrule) + (map (lambda (v) (format #f " v.~a" v)) it)) + )] + [(MONTHLY) + (list + (awhen (byday rrule) (list (format-byday-list it))) + (awhen (bymonthday rrule) (cons " " (format-bymonth-day it))))] + [else '()]) + + ;; TODO my parser adds an implicit interval to every object + ;; this might be wrong + (cond [(and (eq? 'DAILY (freq rrule)) (= 1 (interval rrule))) + " dagligen"] + [(and (eq? 'YEARLY (freq rrule)) (= 1 (interval rrule))) + ", Ă„rligen"] + [(and (eq? 'MINUTELY (freq rrule)) + (zero? (modulo (interval rrule) 15))) + (list " " + (each-string (/ (interval rrule) 15)) + " kvart")] + [else + (list + " " + (each-string (interval rrule) (eq? 'YEARLY (freq rrule))) + " " + (case (freq rrule) + ;; p.44 RFC 5545 + [(SECONDLY) "sekund"] + [(MINUTELY) "minut"] + [(HOURLY) "timme"] + [(DAILY) "dag"] + + ;; day offsets CAN ONLY be present when FREQ is + ;; either MONTHLY or YEARLY + [(WEEKLY) (aif (byday rrule) + (add-enumeration-punctuation + (map (compose week-day-name cdr) it)) + "vecka")] + [(MONTHLY) "mĂ„nad"] + [(YEARLY) "Ă„r"] + [else "ERROR"] + ))]) + + (cond [(and (byminute rrule) + (byhour rrule)) + (list + " kl. " + (add-enumeration-punctuation + (map (lambda (pair) + (time->string + (time hour: (car pair) + minute: (cadr pair)) + "~H:~M")) + (cross-product (byhour rrule) + (byminute rrule)))))] + [(byhour rrule) + => (lambda (hours) + (list " kl. " (add-enumeration-punctuation hours)))] + [else '()]) + + (awhen (until rrule) + (format #f ", till och med ~a" + (datetime->string + ;; TODO ordinal on ~d? + it "den ~d ~B, ~Y kl. ~k:~M") + )) + (cond [(not (count rrule)) ""] + [(= 1 (count rrule)) (list ", totalt " (count rrule) " gĂ„ng")] + [(count rrule) (list ", totalt " (count rrule) " gĂ„nger")] + [else "ERROR"]))))) -- cgit v1.2.3 From f5892169ee1b8da1bdf1666a36ff93a75e4b41b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 22 Feb 2022 18:44:26 +0100 Subject: Fix translation for (vcomponent datetime output). --- module/vcomponent/datetime/output.scm | 40 +++++++++++------- po/sv.po | 78 ++++++++++++++++++++++------------- 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/module/vcomponent/datetime/output.scm b/module/vcomponent/datetime/output.scm index a0ab9941..72ee8eb4 100644 --- a/module/vcomponent/datetime/output.scm +++ b/module/vcomponent/datetime/output.scm @@ -6,6 +6,7 @@ :use-module (vcomponent base) :use-module (text util) :use-module (calp translation) + :use-module ((vcomponent recurrence display) :select (format-recurrence-rule)) ) (define-config summary-filter (lambda (_ a) a) @@ -17,24 +18,30 @@ ;; ev → sxml ;; TODO translation (define-public (format-recurrence-rule ev) - `(,(_ "Upprepas ") - ,((@ (vcomponent recurrence display) format-recurrence-rule) - (prop ev 'RRULE)) + ;; [FRR] + ;; Part of the sentance "Repeated [every two weeks], except on ~a, ~a & ~a" + ;; See everything tagged [FRR] + `(,(_ "Repeated ") + ,(format-recurrence-rule (prop ev 'RRULE)) ,@(awhen (prop* ev 'EXDATE) (list - (_ ", undantaget ") + ;; See [FRR] + (_ ", except on ") (add-enumeration-punctuation (map (lambda (d) + ;; TODO show year if different from current year (if (date? d) - ;; NOTE possibly show year? - (date->string d "~e ~b") + ;; [FRR] Exception date without time + (date->string d (_ "~e ~b")) ;; NOTE only show time when it's different than the start time? ;; or possibly only when FREQ is hourly or lower. (if (memv ((@ (vcomponent recurrence internal) freq) - (prop ev 'RRULE)) - '(HOURLY MINUTELY SECONDLY)) - (datetime->string d "~e ~b ~k:~M") - (datetime->string d "~e ~b")))) + (prop ev 'RRULE)) + '(HOURLY MINUTELY SECONDLY)) + ;; [FRR] Exception date with time + (datetime->string d (_ "~e ~b ~k:~M")) + ;; [FRR] Exception date without time + (datetime->string d (_ "~e ~b"))))) (map value it))))) ".")) @@ -59,9 +66,9 @@ (cond [(prop ev 'DTEND) => (lambda (e) (if (date= e (date+ s (date day: 1))) - "~Y-~m-~d" ; start = end, only return one value - (values "~Y-~m-~d" - "~Y-~m-~d")))] + (_ "~Y-~m-~d") ; start = end, only return one value + (values (_ "~Y-~m-~d") + (_ "~Y-~m-~d"))))] ;; no end value, just return start [else (date->string s)]))] [else ; guaranteed datetime @@ -69,6 +76,9 @@ (e (prop ev 'DTEND))) (if e (let ((fmt-str (if (date= (get-date s) (get-date e)) - "~H:~M" "~Y-~m-~d ~H:~M"))) + (_ "~H:~M") + ;; Note the non-breaking space + (_ "~Y-~m-~d ~H:~M")))) (values fmt-str fmt-str)) - "~Y-~m-~d ~H:~M"))])) + ;; Note the non-breaking space + (_ "~Y-~m-~d ~H:~M")))])) diff --git a/po/sv.po b/po/sv.po index e759d3d8..d79de655 100644 --- a/po/sv.po +++ b/po/sv.po @@ -335,7 +335,7 @@ msgid "Recurring?" msgstr "Upprepande?" #: module/calp/html/vcomponent.scm:419 module/calp/html/vcomponent.scm:420 -#: module/calp/terminal.scm:149 +#: module/calp/terminal.scm:149 module/calp/terminal.scm:146 msgid "Location" msgstr "Plats" @@ -540,39 +540,38 @@ msgstr "V:" msgid "Crash on warnings." msgstr "Krasha pĂ„ varningar" -#: module/calp/terminal.scm:78 +#: module/calp/terminal.scm:78 module/calp/terminal.scm:75 msgid "NO LOCATION" msgstr "INGEN PLATS" -#: module/calp/terminal.scm:129 +#: module/calp/terminal.scm:129 module/calp/terminal.scm:126 msgid "== Day View ==\n" msgstr "== Dagsvy ==\n" -#: module/calp/terminal.scm:155 +#: module/calp/terminal.scm:155 module/calp/terminal.scm:152 msgid "Start" msgstr "Start" -#. Event start date-time terminal view -#. Event end date-time terminal view #. Event start date-time terminal view #. Event end date-time terminal view #: module/calp/terminal.scm:160 module/calp/terminal.scm:168 +#: module/calp/terminal.scm:157 module/calp/terminal.scm:165 msgid "~Y-~m-~d ~H:~M:~S" msgstr "~Y-~m-~d ~H:~M:~S" -#: module/calp/terminal.scm:163 +#: module/calp/terminal.scm:163 module/calp/terminal.scm:160 msgid "End" msgstr "Slut" -#: module/calp/terminal.scm:211 +#: module/calp/terminal.scm:211 module/calp/terminal.scm:208 msgid "quick search: " msgstr "Snabbsök: " -#: module/calp/terminal.scm:218 +#: module/calp/terminal.scm:218 module/calp/terminal.scm:215 msgid "search: " msgstr "sök: " -#: module/calp/terminal.scm:264 +#: module/calp/terminal.scm:264 module/calp/terminal.scm:261 msgid "== Search View ==\n" msgstr "== Sökvy ==\n" @@ -687,18 +686,11 @@ msgstr "Ogiltigt formatteringstecken" msgid "Adding timespecs of differing types" msgstr "LĂ€gger till tidsspecifikationer av olika typer" -#: module/vcomponent/datetime/output.scm:20 -msgid "Upprepas " -msgstr "" - -#: module/vcomponent/datetime/output.scm:25 -msgid ", undantaget " -msgstr "" - #. Warning message for failure to format description. #. First argument is name of warning/error, #. second is error arguments #: module/vcomponent/datetime/output.scm:51 +#: module/vcomponent/datetime/output.scm:58 #, scheme-format msgid "~a on formatting description, ~s" msgstr "~a vid formattering av beskrivning, ~s" @@ -833,8 +825,8 @@ msgstr "Subkommandon" #: module/calp/main.scm:89 msgid "

html reads calendar files from disk, and writes them to " "static HTML files.

" -msgstr "

html lÀser kalenderfiler frÄn disk, och matar ur sig statiska " - "HTML-filer.

" +msgstr "

html lÀser kalenderfiler frÄn disk, och matar ur sig " + "statiska HTML-filer.

" #: module/calp/main.scm:90 msgid "

terminal loads the calendars, and starts an interactive " @@ -856,7 +848,7 @@ msgstr "

ical laddar kallenderdatabasen, och Ă„terserialiserar den " msgid "Flags" msgstr "Flaggor" -#: module/calp/terminal.scm:320 +#: module/calp/terminal.scm:320 module/calp/terminal.scm:317 msgid "loading..." msgstr "laddar..." @@ -1021,12 +1013,6 @@ msgid "

benchmark module
Runs the procedure 'run-" msgstr "

benchmark modul
Kör proceduren 'run-benchmark' " "frÄn modulen (calp benchmark modul).

" -#. Week view header format -#. start date metainfo -#. end date metainfo -#. Generation data -#. Compact event list date only -#. Header for sidebar day #. Week view header format #. start date metainfo #. end date metainfo @@ -1036,6 +1022,42 @@ msgstr "

benchmark modul
Kör proceduren 'run-benchmark' " #: module/calp/html/view/calendar/week.scm:50 #: module/calp/html/view/calendar.scm:92 module/calp/html/view/calendar.scm:94 #: module/calp/html/view/calendar.scm:156 module/calp/html/vcomponent.scm:52 -#: module/calp/html/vcomponent.scm:218 +#: module/calp/html/vcomponent.scm:218 module/vcomponent/datetime/output.scm:69 +#: module/vcomponent/datetime/output.scm:70 +#: module/vcomponent/datetime/output.scm:71 msgid "~Y-~m-~d" msgstr "~Y-~m-~d" + +#. [FRR] +#. Part of the sentance "Repeated [every two weeks], except on ~a, ~a & ~a" +#. See everything tagged [FRR] +#: module/vcomponent/datetime/output.scm:24 +msgid "Repeated " +msgstr "Upprepas " + +#. See [FRR] +#: module/vcomponent/datetime/output.scm:29 +msgid ", except on " +msgstr ", undantaget " + +#. [FRR] Exception date without time +#: module/vcomponent/datetime/output.scm:35 +#: module/vcomponent/datetime/output.scm:44 +#, scheme-format +msgid "~e ~b" +msgstr "~e ~b" + +#. [FRR] Exception date with time +#: module/vcomponent/datetime/output.scm:42 +msgid "~e ~b ~k:~M" +msgstr "~e ~b ~k:~M" + +#: module/vcomponent/datetime/output.scm:79 +msgid "~H:~M" +msgstr "~H:~M" + +#. Note the non-breaking space +#: module/vcomponent/datetime/output.scm:81 +#: module/vcomponent/datetime/output.scm:84 +msgid "~Y-~m-~d ~H:~M" +msgstr "~Y-~m-~d ~H:~M" -- cgit v1.2.3