From cd705c115320ce964956836b37a68f42909aeb32 Mon Sep 17 00:00:00 2001 From: Dominic Date: Fri, 17 May 2024 21:29:22 +0200 Subject: [PATCH] language support --- src/iotro.rs | 140 +++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 12 +++- src/render/mod.rs | 4 +- src/time.rs | 20 ------- 4 files changed, 140 insertions(+), 36 deletions(-) diff --git a/src/iotro.rs b/src/iotro.rs index 2dd0634..683eb10 100644 --- a/src/iotro.rs +++ b/src/iotro.rs @@ -1,11 +1,125 @@ //! A module for writing intros and outros -use crate::{time::format_date_long, ProjectLecture, Resolution}; +use crate::{time::Date, ProjectLecture, Resolution}; +use anyhow::anyhow; +use std::{ + fmt::{self, Debug, Display, Formatter}, + str::FromStr +}; use svgwriter::{ tags::{Group, Rect, TagWithPresentationAttributes, Text}, Graphic }; +#[derive(Clone)] +pub struct Language<'a> { + lang: &'a str, + format_date_long: fn(Date) -> String, + // intro + lecture_from: &'a str, + video_created_by_us: &'a str, + // outro + video_created_by: &'a str, + our_website: &'a str, + download_videos: &'a str, + questions_feedback: &'a str +} + +pub const GERMAN: Language<'static> = Language { + lang: "de", + + // Format a date in DD. MMMM YYYY format. + format_date_long: |d: Date| { + let month = match d.month { + 1 => "Januar", + 2 => "Februar", + 3 => "März", + 4 => "April", + 5 => "Mai", + 6 => "Juni", + 7 => "Juli", + 8 => "August", + 9 => "September", + 10 => "Oktober", + 11 => "November", + 12 => "Dezember", + _ => unreachable!() + }; + format!("{:02}. {month} {:04}", d.day, d.year) + }, + + lecture_from: "Vorlesung vom", + video_created_by_us: "Video erstellt von der Video AG, Fachschaft I/1", + + video_created_by: "Video erstellt von der", + our_website: "Website der Fachschaft", + download_videos: "Videos herunterladen", + questions_feedback: "Fragen, Vorschläge und Feedback" +}; + +pub const BRITISH: Language<'static> = Language { + lang: "uk", + + // Format a date in DDth MMMM YYYY format. + format_date_long: |d: Date| { + let month = match d.month { + 1 => "January", + 2 => "February", + 3 => "March", + 4 => "April", + 5 => "May", + 6 => "June", + 7 => "July", + 8 => "August", + 9 => "September", + 10 => "October", + 11 => "November", + 12 => "December", + _ => unreachable!() + }; + let th = match d.day { + 1 | 21 | 31 => "st", + 2 | 22 => "nd", + 3 | 23 => "rd", + _ => "th" + }; + format!("{:02}{th} {month} {:04}", d.day, d.year) + }, + + lecture_from: "Lecture from", + video_created_by_us: "Video created by the Video AG, Fachschaft I/1", + video_created_by: "Video created by the", + our_website: "The Fachschaft's website", + download_videos: "Download videos", + questions_feedback: "Questions, Suggestions and Feedback" +}; + +impl FromStr for Language<'static> { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "de" => Ok(GERMAN), + "en" | "uk" => Ok(BRITISH), + lang => Err(anyhow!("Unknown language {lang:?}")) + } + } +} + +impl Display for Language<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(self.lang) + } +} + +impl Debug for Language<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Language") + .field("lang", &self.lang) + .finish_non_exhaustive() + } +} + #[repr(u16)] enum FontSize { Huge = 72, @@ -74,6 +188,7 @@ impl Iotro { pub(crate) fn intro(res: Resolution, lecture: &ProjectLecture) -> Graphic { use self::{FontSize::*, FontWeight::*}; + let lang = &lecture.lang; let mut intro = Iotro::new(res); intro.add_text(Huge, Bold, 110, &lecture.label); intro.add_text(Huge, SemiBold, 250, &lecture.docent); @@ -81,31 +196,30 @@ pub(crate) fn intro(res: Resolution, lecture: &ProjectLecture) -> Graphic { Huge, SemiBold, 460, - format!("Vorlesung vom {}", format_date_long(lecture.date)) - ); - intro.add_text( - Big, - Normal, - 870, - "Video erstellt von der Video AG, Fachschaft I/1" + format!( + "{} {}", + lang.lecture_from, + (lang.format_date_long)(lecture.date) + ) ); + intro.add_text(Big, Normal, 870, lang.video_created_by_us); intro.add_text(Big, Normal, 930, "https://video.fsmpi.rwth-aachen.de"); intro.add_text(Big, Normal, 990, "video@fsmpi.rwth-aachen.de"); intro.finish() } -pub(crate) fn outro(res: Resolution) -> Graphic { +pub(crate) fn outro(lang: &Language<'_>, res: Resolution) -> Graphic { use self::{FontSize::*, FontWeight::*}; let mut outro = Iotro::new(res); - outro.add_text(Large, SemiBold, 50, "Video erstellt von der"); + outro.add_text(Large, SemiBold, 50, lang.video_created_by); outro.add_text(Huge, Bold, 210, "Video AG, Fachschaft I/1"); - outro.add_text(Large, Normal, 360, "Website der Fachschaft:"); + outro.add_text(Large, Normal, 360, format!("{}:", lang.our_website)); outro.add_text(Large, Normal, 430, "https://www.fsmpi.rwth-aachen.de"); - outro.add_text(Large, Normal, 570, "Videos herunterladen:"); + outro.add_text(Large, Normal, 570, format!("{}:", lang.download_videos)); outro.add_text(Large, Normal, 640, "https://video.fsmpi.rwth-aachen.de"); - outro.add_text(Large, Normal, 780, "Fragen, Vorschläge und Feedback:"); + outro.add_text(Large, Normal, 780, format!("{}:", lang.questions_feedback)); outro.add_text(Large, Normal, 850, "video@fsmpi.rwth-aachen.de"); outro.finish() diff --git a/src/main.rs b/src/main.rs index c5f3550..f59f2fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ use crate::{ }; use camino::Utf8PathBuf as PathBuf; use clap::Parser; +use iotro::Language; use rational::Rational; use serde::{Deserialize, Serialize}; use serde_with::{serde_as, DisplayFromStr}; @@ -44,6 +45,10 @@ struct Args { #[clap(short, long, default_value = "Prof. E. Grädel")] docent: String, + /// The language of the lecture. Used for the intro and outro frame. + #[clap(short = 'L', long, default_value = "de")] + lang: Language<'static>, + /// The memory limit for external tools like ffmpeg. #[clap(short, long, default_value = "12G")] mem_limit: String, @@ -145,7 +150,9 @@ struct ProjectLecture { label: String, docent: String, #[serde_as(as = "DisplayFromStr")] - date: Date + date: Date, + #[serde_as(as = "DisplayFromStr")] + lang: Language<'static> } #[serde_as] @@ -271,7 +278,8 @@ fn main() { course, label: args.label, docent: args.docent, - date + date, + lang: args.lang }, source: ProjectSource { files, diff --git a/src/render/mod.rs b/src/render/mod.rs index 279f3c4..1bfd603 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -272,7 +272,9 @@ impl<'a> Renderer<'a> { let outro_svg = self.target.join("outro.svg"); fs::write( &outro_svg, - outro(source_res).to_string_pretty().into_bytes() + outro(&project.lecture.lang, source_res) + .to_string_pretty() + .into_bytes() )?; let outro_mkv = self.outro_mkv(); svg2mkv(metadata, outro_svg, outro_mkv, self.format, OUTRO_LEN)?; diff --git a/src/time.rs b/src/time.rs index d4d9a3d..74f665f 100644 --- a/src/time.rs +++ b/src/time.rs @@ -57,26 +57,6 @@ pub fn format_date(d: Date) -> String { format!("{:02}{:02}{:02}", d.year % 100, d.month, d.day) } -/// Format a date in DD. MMMM YYYY format. -pub fn format_date_long(d: Date) -> String { - let month = match d.month { - 1 => "Januar", - 2 => "Februar", - 3 => "März", - 4 => "April", - 5 => "Mai", - 6 => "Juni", - 7 => "Juli", - 8 => "August", - 9 => "September", - 10 => "Oktober", - 11 => "November", - 12 => "Dezember", - _ => unreachable!() - }; - format!("{:02}. {month} {:04}", d.day, d.year) -} - #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Time { pub seconds: u32,