Add maintenance announcement tag helper

Change-Id: Ie4a18bf28e38613f9f2faded9c84be023f517b34
diff --git a/Changes b/Changes
index 4abafc8..9fdc46b 100644
--- a/Changes
+++ b/Changes
@@ -2,6 +2,7 @@
         - Update Piwik dependency to point to matomo.js. (diewald)
         - Add addon to title and description. (diewald)
         - Improve Dockerfile to enable docker-slim. (diewald)
+        - Introduce maintenance tag helper. (diewald)
 
 0.51 2023-09-27
         - Support defined log file in configuration. (diewald)
diff --git a/Makefile.PL b/Makefile.PL
index 3c72084..6039ff2 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -29,6 +29,7 @@
     'Mojolicious::Plugin::AutoSecrets' => 0.006,
     'Mojolicious::Plugin::TagHelpers::ContentBlock' => 0.11,
     'Cache::FastMmap' => 1.57,
+    'DateTime' => 1.63,
 
     # Required for Mojolicious::Plugin::CHI
     'Data::Serializer' => 0.65,
diff --git a/kalamar.dict b/kalamar.dict
index 98b3154..16c0a38 100644
--- a/kalamar.dict
+++ b/kalamar.dict
@@ -20,6 +20,12 @@
       $num =~ s/$THOUSAND_SEP_RE/$1\./g;
       return $num;
     },
+    numo => sub {
+      shift;
+      my %val = @_;
+      my $day = $val{day} or return '';
+        return $day . '.';
+    },
     about => 'Über KorAP',
     login => 'Anmelden',
     logout => 'Abmelden',
@@ -63,6 +69,11 @@
     privacy => 'Datenschutz',
     imprint => 'Impressum',
     settings => 'Einstellungen',
+    'oclock' => 'Uhr',
+    maintenanceWork => {
+      time => 'Wartungsfenster',
+      desc => 'Aufgrund von Wartungsarbeiten wird es zu Unterbrechungen des Dienstes kommen.',
+    },
     Template => {
       intro => 'de/intro',
       doc => {
@@ -105,7 +116,7 @@
       'annotation' => 'Annotationen',
       '#default-foundries' => 'Standard Foundries',
       'development' => 'Entwicklung',
-      'faq' => 'FAQ'
+      'faq' => 'FAQ',
     },
     QL => {
       cqp => 'CQP (neu)'
@@ -120,6 +131,19 @@
       $num =~ s/$THOUSAND_SEP_RE/$1\,/g;
       return $num;
     },
+    numo => sub {
+      shift;
+      my %val = @_;
+      my $day = $val{day} or return '';
+      if ($day > 3) {
+        return $day . 'th';
+      } elsif ($day == 3) {
+        return '3rd';
+      } elsif ($day == 2) {
+        return '2nd';
+      };
+      return '1st';
+    },
     about => 'About KorAP',
     login => 'Login',
     logout => 'Logout',
@@ -152,6 +176,7 @@
     },
     activateJS => 'To make use of all features, please activate JavaScript!',
     faq => 'FAQ',
+    'oclock' => 'o\'clock',
     underConstruction => 'Under Construction!',
     tutorial => 'Help and Documentation',
     korap => {
@@ -174,6 +199,10 @@
     privacy => 'Privacy',
     imprint => 'Imprint',
     settings => 'Settings',
+    maintenanceWork => {
+      time => 'Maintenance',
+      desc => 'Due to maintenance work the service will be interrupted.',
+    },
     Template => {
       intro => 'intro',
       doc => {
diff --git a/lib/Kalamar/Plugin/KalamarHelpers.pm b/lib/Kalamar/Plugin/KalamarHelpers.pm
index 4745860..74816b5 100644
--- a/lib/Kalamar/Plugin/KalamarHelpers.pm
+++ b/lib/Kalamar/Plugin/KalamarHelpers.pm
@@ -2,7 +2,7 @@
 use Mojo::ByteStream 'b';
 use Mojo::Base 'Mojolicious::Plugin';
 use Mojo::Util qw/deprecated/;
-
+use DateTime;
 
 sub register {
   my ($plugin, $mojo) = @_;
@@ -169,6 +169,41 @@
       );
     }
   );
+
+
+  # Maintenance announcement tag helper
+  # Use as '<%= korap_maintenance '2023-11-03', '13:00', '14:00' $>'
+  $mojo->helper(
+    korap_maintenance => sub {
+      my $c = shift;
+      my ($date, $start_time, $end_time) = @_;
+
+      if (!$date || !$start_time || !$end_time) {
+        return '';
+      };
+
+      my ($year, $month, $day) = split('-', $date);
+
+      if (!$year || !$month || !$day) {
+        return '';
+      };
+
+      my $dt = DateTime->new(
+        year => $year,
+        month => $month,
+        day => $day
+      );
+
+      $dt->set_locale($c->localize->locale->[0] // 'en');
+
+      return $c->include(
+        'partial/maintenance',
+        dt => $dt,
+        start_time => $start_time,
+        end_time => $end_time
+      )
+    }
+  );
 };
 
 
diff --git a/t/page.t b/t/page.t
index 8b0afd0..5fb2129 100644
--- a/t/page.t
+++ b/t/page.t
@@ -88,6 +88,22 @@
   ->text_is('div.logoaddon', 'Test')
   ;
 
+like($app->korap_maintenance('2023-10-03','13:00','15:00'), qr!<time datetime="2023-10-03">!);
+like($app->korap_maintenance('2023-10-03','13:00','15:00'), qr!Tuesday, 3rd October 2023!);
+like($app->korap_maintenance('2023-10-03','13:00','15:00'), qr!Maintenance 13:00 - 15:00 o&#39;clock!);
+like($app->korap_maintenance('2023-10-03','13:00','15:00'), qr!Due to maintenance work the service will be interrupted\.!);
+
+
+$c = $app->build_controller;
+$c->req->headers->accept_language('de-DE, en-US, en');
+$c->app($app);
+
+like($c->korap_maintenance('2023-10-03','13:00','15:00'), qr!<time datetime="2023-10-03">!);
+like($c->korap_maintenance('2023-10-03','13:00','15:00'), qr!Dienstag, 3\. Oktober 2023!);
+like($c->korap_maintenance('2023-10-03','13:00','15:00'), qr!Wartungsfenster 13:00 - 15:00 Uhr!);
+like($c->korap_maintenance('2023-10-03','13:00','15:00'), qr!Aufgrund von Wartungsarbeiten wird es zu Unterbrechungen des Dienstes kommen\.!);
+
+
 done_testing;
 
 1;
diff --git a/templates/partial/maintenance.html.ep b/templates/partial/maintenance.html.ep
new file mode 100644
index 0000000..39b9f50
--- /dev/null
+++ b/templates/partial/maintenance.html.ep
@@ -0,0 +1,5 @@
+  <dt class="maintenance"><time datetime="<%= $dt->ymd %>"><%= $dt->day_name %>, <%= loc('numo', day => $dt->day) %> <%= $dt->month_name %> <%= $dt->year %></time></dt>
+  <dd  class="maintenance">
+    <h4><%= loc 'maintenanceWork_time' %> <%= $start_time %> - <%= $end_time %> <%= loc('oclock') %></h4>
+    <p><%= loc 'maintenanceWork_desc' %></p>
+  </dd>