summaryrefslogtreecommitdiff
path: root/templates
diff options
context:
space:
mode:
Diffstat (limited to 'templates')
-rw-r--r--templates/_cancelled_departure.html.ep4
-rw-r--r--templates/_checked_in.html.ep126
-rw-r--r--templates/_format_train.html.ep2
-rw-r--r--templates/_history_stats.html.ep26
-rw-r--r--templates/_history_trains.html.ep12
-rw-r--r--templates/_map.html.ep13
-rw-r--r--templates/_public_status_card.html.ep14
-rw-r--r--templates/_suggestions_dbris.html.ep54
-rw-r--r--templates/_suggestions_efa.html.ep53
-rw-r--r--templates/_wagons.html.ep8
-rw-r--r--templates/about.html.ep33
-rw-r--r--templates/account.html.ep89
-rw-r--r--templates/add_intransit.html.ep93
-rw-r--r--templates/add_journey.html.ep38
-rw-r--r--templates/api_documentation.html.ep24
-rw-r--r--templates/cancelled.html.ep4
-rw-r--r--templates/changelog.html.ep61
-rw-r--r--templates/departures.html.ep32
-rw-r--r--templates/edit_journey.html.ep8
-rw-r--r--templates/history_by_month.html.ep2
-rw-r--r--templates/history_by_year.html.ep4
-rw-r--r--templates/history_map.html.ep12
-rw-r--r--templates/journey.html.ep245
-rw-r--r--templates/landingpage.html.ep57
-rw-r--r--templates/language.html.ep76
-rw-r--r--templates/layouts/default.html.ep18
-rw-r--r--templates/login.html.ep10
-rw-r--r--templates/passengerrights.html.ep12
-rw-r--r--templates/polyline.gpx.ep20
-rw-r--r--templates/register.html.ep18
-rw-r--r--templates/select_backend.html.ep14
31 files changed, 837 insertions, 345 deletions
diff --git a/templates/_cancelled_departure.html.ep b/templates/_cancelled_departure.html.ep
index 79492a5..db6cc5c 100644
--- a/templates/_cancelled_departure.html.ep
+++ b/templates/_cancelled_departure.html.ep
@@ -1,9 +1,9 @@
<div class="card">
<div class="card-content">
- <span class="card-title">Zugausfall</span>
+ <span class="card-title">Fahrtausfall</span>
<p>Die Abfahrt von <%= $journey->{train_type} %> <%= $journey->{train_no} %>
in <a href="/s/<%= $journey->{dep_eva} %>"><%= $journey->{dep_name} %></a>
- entfällt. Der Zugausfall auf der Fahrt nach <%= $journey->{arr_name} %> wurde bereits dokumentiert.
+ entfällt. Der Ausfall der Fahrt nach <%= $journey->{arr_name} %> wurde bereits dokumentiert.
</p>
% if (my @connections = @{stash('connections_iris') // []}) {
<p>Alternative Reisemöglichkeiten:</p>
diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep
index 988bf39..69754e3 100644
--- a/templates/_checked_in.html.ep
+++ b/templates/_checked_in.html.ep
@@ -4,7 +4,7 @@
<div class="card-content">
<i class="material-icons right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
% if (not $journey->{arr_name}) {
- <span class="card-title center-align">Ziel wählen</span>
+ <span class="card-title center-align"><%= L('status.select-destination') %></span>
% }
<span class="card-title center-align">
%= include '_format_train', journey => $journey
@@ -19,26 +19,26 @@
data-dest="<%= $journey->{arr_name} %>"
>
% if ($journey->{boarding_countdown} > 60) {
- Einfahrt in <%= journeys->min_to_human(int($journey->{boarding_countdown} / 60)) %><br/>
+ <%= L('status.boarding-in.pre') %> <%= journeys->min_to_human(int($journey->{boarding_countdown} / 60)) %> <%= L('status.boarding-in.post') %><br/>
% }
% elsif ($journey->{boarding_countdown} > 0) {
- Fährt ein<br/>
+ <%= L('status.boarding-soon') %><br/>
% }
% if ($journey->{departure_countdown} > 60) {
- Abfahrt in <%= journeys->min_to_human(int($journey->{departure_countdown} / 60)) %>
+ <%= L('status.departure-in.pre') %> <%= journeys->min_to_human(int($journey->{departure_countdown} / 60)) %> <%= L('status.departure-in.post') %>
% }
% elsif ($journey->{departure_countdown} > 0) {
- Abfahrt in weniger als einer Minute
+ %= L('status.departure-soon')
% }
% elsif (defined $journey->{arrival_countdown}) {
% if ($journey->{arrival_countdown} > 60) {
- Ankunft in <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %>
+ <%= L('status.arrival-in.pre') %> <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %> <%= L('status.arrival-in.post') %>
% }
% elsif ($journey->{arrival_countdown} > 0) {
- Ankunft in weniger als einer Minute
+ %= L('status.arrival-soon')
% }
% else {
- Ziel erreicht
+ %= L('status.arrived')
% }
% if ($journey->{arrival_countdown} < (60 * 15) and $journey->{arr_platform}) {
% if ($journey->{arr_direction} and $journey->{arr_direction} eq 'r') {
@@ -48,7 +48,7 @@
<br/>◀ <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %>
% }
% else {
- <br/>auf <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %>
+ <br/><%= L('status.arrive-on.pre') %> <%= $journey->{platform_type} %> <%= $journey->{arr_platform} %> <%= L('status.arrive-on.post') %>
% }
% }
% }
@@ -63,7 +63,7 @@
<br/>◀ <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %>
% }
% else {
- <br/>von <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %>
+ <br/><%= L('status.depart-from.pre') %> <%= $journey->{platform_type} %> <%= $journey->{dep_platform} %> <%= L('status.depart-from.post') %>
% }
% }
% if (my $wr = $journey->{wagonorder}) {
@@ -202,8 +202,11 @@
% if (@{$journey->{messages} // []} or @{$journey->{extra_data}{qos_msg} // []} or not $journey->{extra_data}{rt}) {
<p style="margin-bottom: 2ex;">
<ul>
- % if (not $journey->{extra_data}{rt}) {
- <li><i class="material-icons tiny">gps_off</i> Keine Echtzeitdaten vorhanden
+ % if ($journey->{extra_data}{manual}) {
+ <li><i class="material-icons tiny">gps_off</i> Manueller Checkin ohne Echtzeitdaten
+ % }
+ % elsif (not $journey->{extra_data}{rt}) {
+ <li><i class="material-icons tiny">gps_off</i> <%= L('status.realtime-unavailable') %>
% }
% for my $message (reverse @{$journey->{messages} // []}) {
% if ($journey->{sched_departure}->epoch - $message->[0]->epoch < 1800) {
@@ -232,8 +235,7 @@
% }
% if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} <= 0) {
<p style="margin-top: 2ex;">
- Der automatische Checkout erfolgt wegen teilweise langsamer
- Echtzeitdatenupdates erst etwa zehn Minuten nach der Ankunft.
+ %= L('status.delayed-auto-checkout')
</p>
% }
% elsif (not $journey->{arr_name}) {
@@ -272,7 +274,7 @@
% }
% else {
<a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
- <i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
+ <i class="material-icons left" aria-hidden="true">undo</i> <%= L('status.undo') %>
</a>
% }
% if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} <= 0) {
@@ -281,7 +283,7 @@
style="margin-right: 0;"
data-station="<%= $journey->{arr_name}%>">
<i class="material-icons left">done</i>
- Auschecken
+ %= L('status.check-out')
</a>
% }
% elsif ($journey->{arr_name}) {
@@ -308,12 +310,12 @@
data-url="<%= url_for('/status')->to_abs->scheme('https') %>/<%= $user->{name} %>/<%= $journey->{sched_departure}->epoch %>?token=<%= $journey->{dep_eva} %>-<%= $journey->{timestamp}->epoch % 337 %>"
% }
>
- <i class="material-icons left" aria-hidden="true">share</i> Teilen
+ <i class="material-icons left" aria-hidden="true">share</i> <%= L('status.share') %>
</a>
% }
% else {
<a class="right" href="/journey/visibility">
- <i class="material-icons left"><%= visibility_icon($journey_visibility) %></i> Sichtbarkeit
+ <i class="material-icons left"><%= visibility_icon($journey_visibility) %></i> <%= L('status.privacy-level') %>
</a>
% }
</div>
@@ -325,7 +327,7 @@
<div class="card" style="margin-top: <%= scalar @{stash('timeline') // []} ? '1.5rem' : '3em' %>;">
<div class="card-content">
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
- <span class="card-title">Meldungen</span>
+ <span class="card-title"><%= L('status.messages') %></span>
% if (@{$journey->{extra_data}{him_msg} // []}) {
<p style="margin-bottom: 2ex;">
<ul>
@@ -356,55 +358,69 @@
<div class="card" style="margin-top: 3em;">
<div class="card-content">
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
- <span class="card-title">Karte</span>
+ <span class="card-title"><%= L('status.map') %></span>
<div id="map" style="height: 70vh;">
</div>
- %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups')
+ %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups'), markers => stash('markers')
</div>
</div>
- <div class="card" style="margin-top: 3em;">
- <div class="card-content">
- <i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
- <span class="card-title">Ziel ändern?</span>
- <div class="targetlist">
- % for my $station (@{$journey->{route_after}}) {
- % my $is_dest = ($journey->{arr_name} and $station->[0] eq $journey->{arr_name});
- <a class="action-checkout tablerow" style="<%= $is_dest? 'font-weight: bold;' : '' %>" data-station="<%= $station->[1] // $station->[0] %>">
- <span><%= $station->[0] %></span>
- <span>
- %= include '_show_load_icons', station => $station
- % if ($station->[2]{isCancelled}) {
- entfällt
- % }
- % elsif ($station->[2]{rt_arr} or $station->[2]{sched_arr}) {
- %= ($station->[2]{rt_arr} || $station->[2]{sched_arr})->strftime('%H:%M')
- % }
- % elsif ($station->[2]{rt_dep} or $station->[2]{sched_dep}) {
- (<%= ($station->[2]{rt_dep} || $station->[2]{sched_dep})->strftime('%H:%M') %>)
- % }
- % elsif ($station->[2]{isAdditional}) {
- Zusatzhalt
- % }
- </span>
+ % if ($journey->{extra_data}{manual}) {
+ <div class="card" style="margin-top: 3em;">
+ <div class="card-content">
+ <i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
+ <span class="card-title">Manueller Checkin</span>
+ </div>
+ <div class="card-action">
+ <a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
+ <i class="material-icons left" aria-hidden="true">undo</i> <%= L('status.undo-checkin') %>
</a>
- <a class="nonflex" href="<%= resolve_sb_template($user->{sb_template}, name => $station->[0], eva => $station->[1], tt => $journey->{train_type} // q{x}, tn => $journey->{train_no}, id => $journey->{train_id} =~ s{[ #|]}{x}gr, dbris => $journey->{is_dbris} ? $journey->{backend_name} : q{}, efa => $journey->{is_efa} ? $journey->{backend_name} : q{}, hafas => $journey->{is_hafas} ? $journey->{backend_name} : q{}, is_iris => $journey->{is_iris}, motis => $journey->{is_motis} ? $journey->{backend_name} : q{}) %>"><i class="material-icons tiny"><%= $journey->{is_hafas} ? 'directions' : 'train' %></i></a>
- % }
</div>
</div>
- <div class="card-action">
- <a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
- <i class="material-icons left" aria-hidden="true">undo</i> Checkin Rückgängig
- </a>
+ % }
+ % else {
+ <div class="card" style="margin-top: 3em;">
+ <div class="card-content">
+ <i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
+ <span class="card-title"><%= L('status.change-destination') %></span>
+ <div class="targetlist">
+ % for my $station (@{$journey->{route_after}}) {
+ % my $is_dest = ($journey->{arr_name} and $station->[0] eq $journey->{arr_name});
+ <a class="action-checkout tablerow" style="<%= $is_dest? 'font-weight: bold;' : '' %>" data-station="<%= $station->[1] // $station->[0] %>">
+ <span><%= $station->[0] %></span>
+ <span>
+ %= include '_show_load_icons', station => $station
+ % if ($station->[2]{isCancelled}) {
+ entfällt
+ % }
+ % elsif ($station->[2]{rt_arr} or $station->[2]{sched_arr}) {
+ %= ($station->[2]{rt_arr} || $station->[2]{sched_arr})->strftime('%H:%M')
+ % }
+ % elsif ($station->[2]{rt_dep} or $station->[2]{sched_dep}) {
+ (<%= ($station->[2]{rt_dep} || $station->[2]{sched_dep})->strftime('%H:%M') %>)
+ % }
+ % elsif ($station->[2]{isAdditional}) {
+ Zusatzhalt
+ % }
+ </span>
+ </a>
+ <a class="nonflex" href="<%= resolve_sb_template($user->{sb_template}, name => $station->[0], eva => $station->[1], tt => $journey->{train_type} // q{x}, tn => $journey->{train_no}, id => $journey->{train_id} =~ s{[ #|]}{x}gr, dbris => $journey->{is_dbris} ? $journey->{backend_name} : q{}, efa => $journey->{is_efa} ? $journey->{backend_name} : q{}, hafas => $journey->{is_hafas} ? $journey->{backend_name} : q{}, is_iris => $journey->{is_iris}, motis => $journey->{is_motis} ? $journey->{backend_name} : q{}) %>"><i class="material-icons tiny"><%= $journey->{is_hafas} ? 'directions' : 'train' %></i></a>
+ % }
+ </div>
+ </div>
+ <div class="card-action">
+ <a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
+ <i class="material-icons left" aria-hidden="true">undo</i> <%= L('status.undo-checkin') %>
+ </a>
+ </div>
</div>
- </div>
+ % }
<p>
- Falls das Backend ausgefallen ist oder die Fahrt aus anderen
- Gründen verloren ging:
+ %= L('status.force-checkout-lead')
</p>
<p class="center-align">
<a class="action-checkout waves-light btn"
data-force="1" data-station="<%= $journey->{arr_name}
- %>">Ohne Echtzeitdaten auschecken</a>
+ %>"><%= L('status.force-checkout') %></a>
</p>
% }
</div>
diff --git a/templates/_format_train.html.ep b/templates/_format_train.html.ep
index e82f3f9..cb81211 100644
--- a/templates/_format_train.html.ep
+++ b/templates/_format_train.html.ep
@@ -1,7 +1,7 @@
% if ($journey->{extra_data}{wagonorder_pride}) {
🏳️‍🌈
% }
-<span class="dep-line <%= $journey->{train_type} // q{} %>">
+<span class="dep-line <%= ($journey->{train_type} // q{}) =~ tr{a-zA-Z_-}{}cdr %>">
% if (not $journey->{is_motis}) {
<%= $journey->{train_type} %>
% }
diff --git a/templates/_history_stats.html.ep b/templates/_history_stats.html.ep
index cbdbb13..e24e699 100644
--- a/templates/_history_stats.html.ep
+++ b/templates/_history_stats.html.ep
@@ -2,22 +2,23 @@
<div class="col s12">
<table class="striped">
<tr>
- <th scope="row">Fahrten</th>
+ <th scope="row"><%= L('stats.trips') %></th>
<td><%= $stats->{num_trains} %></td>
</tr>
<tr>
- <th scope="row">Entfernung</th>
- <td>ca. <%= sprintf('%.f', $stats->{km_route}) %> km
- (Luftlinie: <%= sprintf('%.f', $stats->{km_beeline}) %> km)</td>
+ <th scope="row"><%= L('stats.distance') %></th>
+ <td>≈ <%= sprintf('%.f', $stats->{km_route}) %> km
+ <%= L('journey.beeline.pre') %><%= sprintf('%.f', $stats->{km_beeline}) %> km<%= L('journey.beeline.post') %></td>
</tr>
<tr>
- <th scope="row">Fahrtzeit</th>
- <td><%= $stats->{min_travel_real_strf} %> Stunden
- (nach Fahrplan: <%= $stats->{min_travel_sched_strf} %>)</td>
+ <th scope="row"><%= L('stats.time') %></th>
+ <td><%= $stats->{min_travel_real_strf} %> <%= L('stats.hours') %>
+ (<%= L('stats.per-schedule') %>: <%= $stats->{min_travel_sched_strf} %>)</td>
</tr>
<tr>
- <th scope="row">Wartezeit (nur Umstiege)</th>
- <td><%= $stats->{min_interchange_real_strf} %> Stunden
+ <th scope="row"><%= L('stats.transfer-time') %></th>
+ <td><%= $stats->{min_interchange_real_strf} %> <%= L('stats.hours') %>
+ <!--
% if (@{$stats->{inconsistencies}}) {
<br/><br/>Für Wartezeitberechnung nicht berücksichtigte Fahrten:<br/>
% for my $field (@{$stats->{inconsistencies}}) {
@@ -25,12 +26,13 @@
(Konflikt: <a href="/journey/<%= $field->{conflict}{id} %>"><%= $field->{conflict}{train} %> an <%= $field->{conflict}{arr} %></a>)<br/>
% }
% }
+ -->
</td>
</tr>
<tr>
- <th scope="row">Kumulierte Verspätung</th>
- <td>Bei Abfahrt: <%= $stats->{delay_dep_strf} %> Stunden<br/>
- Bei Ankunft: <%= $stats->{delay_arr_strf} %> Stunden</td>
+ <th scope="row"><%= L('stats.total-delay') %></th>
+ <td><%= L('stats.on-dep') %>: <%= $stats->{delay_dep_strf} %> <%= L('stats.hours') %><br/>
+ <%= L('stats.on-arr') %>: <%= $stats->{delay_arr_strf} %> <%= L('stats.hours') %></td>
</tr>
</table>
</div>
diff --git a/templates/_history_trains.html.ep b/templates/_history_trains.html.ep
index 7ae2a1d..166d74d 100644
--- a/templates/_history_trains.html.ep
+++ b/templates/_history_trains.html.ep
@@ -16,8 +16,8 @@
% }
<li class="collection-item">
<a href="<%= $detail_link %>">
- <span class="dep-line <%= $travel->{type} // q{} %>">
- % if (not $travel->{is_motis}) {
+ <span class="dep-line <%= ($travel->{type} // q{}) =~ tr{a-zA-Z_-}{}cdr %>">
+ % if (length($travel->{type}) < 5 and not $travel->{is_motis}) {
<%= $travel->{type} %>
% }
<%= $travel->{line} // $travel->{no}%>
@@ -37,8 +37,8 @@
<i class="material-icons">timer_off</i>
% } else {
%= $travel->{rt_arrival}->strftime('%H:%M');
- % if ($travel->{sched_arrival} != $travel->{rt_arrival}) {
- (<%= sprintf('%+d', ($travel->{rt_arrival}->epoch - $travel->{sched_arrival}->epoch) / 60) %>)
+ % if ($travel->{delay_arr} and int($travel->{delay_arr} / 60)) {
+ (<%= sprintf('%+d', $travel->{delay_arr} / 60) %>)
% }
% }
% }
@@ -55,8 +55,8 @@
% }
% else {
<%= $travel->{rt_departure}->strftime('%H:%M') %>
- % if ($travel->{sched_departure} != $travel->{rt_departure}) {
- (<%= sprintf('%+d', ($travel->{rt_departure}->epoch - $travel->{sched_departure}->epoch) / 60) %>)
+ % if ($travel->{delay_dep} and int($travel->{delay_dep} / 60)) {
+ (<%= sprintf('%+d', $travel->{delay_dep} / 60) %>)
% }
% }
<strong><%= $travel->{from_name} %></strong>
diff --git a/templates/_map.html.ep b/templates/_map.html.ep
index 223bd68..93f116a 100644
--- a/templates/_map.html.ep
+++ b/templates/_map.html.ep
@@ -39,6 +39,15 @@ var pl;
% }
% }
+% for my $marker (@{stash('markers') // []}) {
+ % if ($marker->[0] and $marker->[0][0] and $marker->[1]) {
+ {
+ const marker = L.marker([<%= $marker->[0][0] %>, <%= $marker->[0][1] %>]).addTo(map);
+ marker.bindPopup('<%= $marker->[1] %>');
+ }
+ % }
+% }
+
% if (my $b = stash('bounds')) {
map.fitBounds([[<%= $b->[0][0] %>,<%= $b->[0][1] %>],[<%= $b->[1][0] %>,<%= $b->[1][1] %>]]);
% }
@@ -48,8 +57,8 @@ for (var station_id in stations) {
color: '#f03',
opacity: 0.7,
fillColor: '#f03',
- fillOpacity: 0.5,
- radius: 250
+ fillOpacity: 0.2,
+ radius: 200
}).bindPopup(stations[station_id][1]).addTo(map);
}
diff --git a/templates/_public_status_card.html.ep b/templates/_public_status_card.html.ep
index 32b193a..ca5ddf8 100644
--- a/templates/_public_status_card.html.ep
+++ b/templates/_public_status_card.html.ep
@@ -11,7 +11,7 @@
<a href="/status/<%= $name %>"><%= $name %></a>: <%= include '_format_train', journey => $journey %>
% }
% else {
- <a href="/p/<%= $name %>"><%= $name %></a> ist unterwegs
+ <a href="/p/<%= $name %>"><%= $name %></a> <%= L('status.is-checked-in') %>
% }
<i class="material-icons right"><%= visibility_icon($journey->{effective_visibility_str}) %></i>
% if (not $journey->{extra_data}{rt}) {
@@ -41,10 +41,10 @@
% }
% elsif (defined $journey->{arrival_countdown}) {
% if ($journey->{arrival_countdown} > 60) {
- Ankunft in <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %>
+ <%= L('status.arrival-in.pre') %> <%= journeys->min_to_human(int($journey->{arrival_countdown} / 60)) %> <%= L('status.arrival-in.post') %>
% }
% elsif ($journey->{arrival_countdown} > 0) {
- Ankunft in weniger als einer Minute
+ %= L('status.arrival-soon')
% }
% else {
Ziel erreicht
@@ -54,7 +54,7 @@
% }
% }
% elsif ($journey->{arr_name}) {
- Ankunft in mehr als zwei Stunden
+ %= L('status.arrival-unknown')
% }
</div>
<div class="progress" style="height: 1ex;">
@@ -216,14 +216,14 @@
% }
% else {
<div class="wagons" style="margin-top: 2ex;">
- Wagen:<br/>
+ <%= L('status.carriages') %>:<br/>
%= include '_wagons', wagongroups => $journey->{wagongroups};
</div>
% }
% }
% if (not stash('from_timeline')) {
<div style="margin-top: 2ex;">
- Route:<br/>
+ <%= L('status.route') %>:<br/>
% my $before = 1;
% my $within = 0;
% my $at_startstop = 0;
@@ -280,7 +280,7 @@
<span class="card-title">Aktuell nicht eingecheckt</span>
% }
% else {
- <span class="card-title"><a href="/p/<%= $name %>"><%= $name %></a> ist gerade nicht eingecheckt</span>
+ <span class="card-title"><a href="/p/<%= $name %>"><%= $name %></a> <%= L('status.is-not-checked-in') %></span>
% }
<div>
% if ($journey->{arr_name}) {
diff --git a/templates/_suggestions_dbris.html.ep b/templates/_suggestions_dbris.html.ep
new file mode 100644
index 0000000..175a57b
--- /dev/null
+++ b/templates/_suggestions_dbris.html.ep
@@ -0,0 +1,54 @@
+<ul class="collection departures connections">
+ % for my $res (@{$suggestions}) {
+ % my ($dep, $dest) = @{$res};
+ % my $row_class = '';
+ % my $link_class = 'action-checkin';
+ % if ($dep->is_cancelled) {
+ % $row_class = 'cancelled';
+ % $link_class = 'action-cancelled-from';
+ % }
+ % if ($checkin_from) {
+ <li class="collection-item <%= $row_class %> <%= $link_class %>"
+ data-dbris="<%= $dbris %>"
+ data-station="<%= $dep->stop_eva %>"
+ data-train="<%= $dep->id %>"
+ data-suffix="<%= $dep->maybe_line_no %>"
+ data-ts="<%= ($dep->sched_dep // $dep->dep)->epoch %>"
+ data-dest="<%= $dest->{name} %>">
+ % }
+ % else {
+ <li class="collection-item <%= $row_class %>">
+ % }
+ <a class="dep-time" href="#">
+ % if ($dep->is_cancelled) {
+ %= $dep->sched_dep->strftime('%H:%M')
+ % }
+ % else {
+ %= $dep->dep->strftime('%H:%M')
+ % }
+ % if ($dep->delay) {
+ %= sprintf('(%+d)', $dep->delay)
+ % }
+ </a>
+ <span class="connect-platform-wrapper">
+ % if ($dep->platform) {
+ <span>
+ % if (($dep->type // q{}) =~ m{ ast | bus | ruf }ix) {
+ Steig
+ % }
+ % else {
+ Gleis
+ % }
+ %= $dep->platform
+ </span>
+ % }
+ <span class="dep-line <%= $dep->type // q{} %>">
+ %= $dep->line
+ </span>
+ </span>
+ <span class="dep-dest">
+ %= $dest->{name}
+ </span>
+ </li>
+ % }
+</ul>
diff --git a/templates/_suggestions_efa.html.ep b/templates/_suggestions_efa.html.ep
new file mode 100644
index 0000000..68fb4a9
--- /dev/null
+++ b/templates/_suggestions_efa.html.ep
@@ -0,0 +1,53 @@
+<ul class="collection departures connections">
+ % for my $res (@{$suggestions}) {
+ % my ($dep, $dest) = @{$res};
+ % my $row_class = '';
+ % my $link_class = 'action-checkin';
+ % if ($dep->is_cancelled) {
+ % $row_class = 'cancelled';
+ % $link_class = 'action-cancelled-from';
+ % }
+ % if ($checkin_from) {
+ <li class="collection-item <%= $row_class %> <%= $link_class %>"
+ data-efa="<%= $efa %>"
+ data-station="<%= $dep->stop_id_num %>"
+ data-train="<%= $dep->id %>"
+ data-ts="<%= ($dep->sched_datetime // $dep->datetime)->epoch %>"
+ data-dest="<%= $dest->{name} %>">
+ % }
+ % else {
+ <li class="collection-item <%= $row_class %>">
+ % }
+ <a class="dep-time" href="#">
+ % if ($dep->is_cancelled) {
+ %= $dep->sched_datetime->strftime('%H:%M')
+ % }
+ % else {
+ %= $dep->datetime->strftime('%H:%M')
+ % }
+ % if ($dep->delay) {
+ %= sprintf('(%+d)', $dep->delay)
+ % }
+ </a>
+ <span class="connect-platform-wrapper">
+ % if ($dep->platform) {
+ <span>
+ % if (($dep->type // q{}) =~ m{ ast | bus | ruf }ix) {
+ Steig
+ % }
+ % else {
+ Gleis
+ % }
+ %= $dep->platform
+ </span>
+ % }
+ <span class="dep-line <%= ($dep->type // q{}) =~ tr{a-zA-Z_-}{}cdr %>">
+ %= $dep->line
+ </span>
+ </span>
+ <span class="dep-dest">
+ %= $dest->{name}
+ </span>
+ </li>
+ % }
+</ul>
diff --git a/templates/_wagons.html.ep b/templates/_wagons.html.ep
index 4090f11..3f906c0 100644
--- a/templates/_wagons.html.ep
+++ b/templates/_wagons.html.ep
@@ -7,12 +7,12 @@
% elsif ($wagon_number and my $group_name = app->ice_name->{$wagon_number}) {
„<%= $group_name %>“
% }
- als <b><%= $wagongroup->{type} // $journey->{type} %> <%= $wagongroup->{no} %></b>
+ <%= L('wagons.name-as-type') %> <b><%= $wagongroup->{type} // $journey->{type} %> <%= $wagongroup->{no} %></b>
% if ($wagongroup->{from}) {
- von <b><%= $wagongroup->{from} %></b>
+ <%= L('wagons.from.pre') %> <b><%= $wagongroup->{from} %></b> <%= L('wagons.from.post') %>
% }
% if ($wagongroup->{to}) {
- nach <b><%= $wagongroup->{to} %></b>
+ <%= L('wagons.to.pre') %> <b><%= $wagongroup->{to} %></b> <%= L('wagons.to.post') %>
% }
<br/>
% for my $wagon (@{$wagongroup->{wagons}}) {
@@ -24,7 +24,7 @@
% }
%= $wagon->{type}
% if ($wagon->{number}) {
- – Wagen <%= $wagon->{number} %>
+ – <%= L('wagons.carriage') %> <%= $wagon->{number} %>
% }
<br/>
% }
diff --git a/templates/about.html.ep b/templates/about.html.ep
index 3167d91..a76cb94 100644
--- a/templates/about.html.ep
+++ b/templates/about.html.ep
@@ -1,47 +1,42 @@
<div class="row">
<div class="col s12">
<a href="https://finalrewind.org/projects/travelynx">travelynx</a> v<%= stash('version') // '???' %><br/>
- Entwickelt von <a href="https://finalrewind.org">derf</a>
- und <a href="https://github.com/derf/travelynx/graphs/contributors">weiteren</a><br/>
- <a href="<%= app->config->{ref}{source} // 'https://git.finalrewind.org/travelynx' %>">Quelltext</a> lizensiert unter AGPL v3<br/><br/>
- Backends:
+ <%= L('about.developed-by.lead') %> <a href="https://finalrewind.org">derf</a>
+ <%= L('about.developed-by.and') %> <a href="https://github.com/derf/travelynx/graphs/contributors"><%= L('about.developed-by.others') %></a> <%= L('about.developed-by.tail') %> <%= L('about.developed-by.tail') %><br/>
+ <a href="<%= app->config->{ref}{source} // 'https://git.finalrewind.org/travelynx' %>"><%= L('about.source-code') %></a> <%= L('about.licence-agplv3') %><br/><br/>
+ <%= L('about.data-sources') %>:
<a href="https://finalrewind.org/projects/Travel-Status-DE-DBRIS/">Travel::Status::DE::DBRIS</a>
v<%= $Travel::Status::DE::DBRIS::VERSION %>,
+ <a href="https://finalrewind.org/projects/Travel-Status-DE-EFA/">Travel::Status::DE::EFA</a>
+ v<%= $Travel::Status::DE::EFA::VERSION %>,
<a href="https://finalrewind.org/projects/Travel-Status-DE-HAFAS/">Travel::Status::DE::HAFAS</a>
- v<%= $Travel::Status::DE::HAFAS::VERSION %> und
+ v<%= $Travel::Status::DE::HAFAS::VERSION %>,
<a href="https://finalrewind.org/projects/Travel-Status-DE-IRIS/">Travel::Status::DE::IRIS</a>
- v<%= $Travel::Status::DE::IRIS::VERSION %><br/>
- Haltestellendaten
- © DB Station&amp;Service AG,
- Europaplatz 1,
- 10557 Berlin, lizensiert unter CC-BY 4.0
+ v<%= $Travel::Status::DE::IRIS::VERSION %><%= L('about.data-sources.last-and') %>
+ <a href="https://finalrewind.org/projects/Travel-Status-MOTIS/">Travel::Status::MOTIS</a>
+ v<%= $Travel::Status::MOTIS::VERSION %><br/>
</div>
</div>
<div class="row">
<div class="col s12">
<p>
- Travelynx ist ein kostenfreies, privat betriebenes Projekt ohne
- Verfügbarkeitsgarantie. Unangekündigte Downtimes oder eine
- kurzfristige Einstellung dieser Seite sind nicht vorgesehen, aber
- möglich. Feature Requests, Bug Reports und sonstige Nachrichten
- werden je nach Kapazität und Motivation zeitnah, verzögert oder gar
- nicht bearbeitet / beantwortet.
+ %= L('about.disclaimer')
</p>
</div>
</div>
<div class="row">
<div class="col s12 m12 l4 center-align" style="margin-top: 1em;">
- <a href="https://social.skyshaper.org/derf" class="waves-effect waves-light btn"><i class="material-icons left">message</i>Kontakt</a>
+ <a href="https://social.skyshaper.org/derf" class="waves-effect waves-light btn"><i class="material-icons left">message</i><%= L('about.contact') %></a>
</div>
<div class="col s12 m12 l4 center-align" style="margin-top: 1em;">
% if (my $issue_url = app->config->{ref}{issues}) {
- <a href="<%= $issue_url %>" class="waves-effect waves-light btn"><i class="material-icons left">bug_report</i>Bugs?</a>
+ <a href="<%= $issue_url %>" class="waves-effect waves-light btn"><i class="material-icons left">bug_report</i><%= L('about.bugs') %></a>
% }
</div>
<div class="col s12 m12 l4 center-align" style="margin-top: 1em;">
- <a href="/changelog" class="waves-effect waves-light btn"><i class="material-icons left">list</i>Changelog</a>
+ <a href="/changelog" class="waves-effect waves-light btn"><i class="material-icons left">list</i><%= L('about.changelog') %></a>
</div>
</div>
diff --git a/templates/account.html.ep b/templates/account.html.ep
index e4bf38d..17f708f 100644
--- a/templates/account.html.ep
+++ b/templates/account.html.ep
@@ -8,31 +8,34 @@
<div class="card success-color">
<div class="card-content white-text">
% if ($success eq 'name') {
- <span class="card-title">Name geändert</span>
+ <span class="card-title"><%= L('account.changed-name') %></span>
% }
% elsif ($success eq 'mail') {
- <span class="card-title">Mail-Adresse geändert</span>
+ <span class="card-title"><%= L('account.changed-mail') %></span>
% }
% elsif ($success eq 'password') {
- <span class="card-title">Passwort geändert</span>
+ <span class="card-title"><%= L('account.changed-password') %></span>
+ % }
+ % elsif ($success eq 'language') {
+ <span class="card-title"><%= L('account.changed-language') %></span>
% }
% elsif ($success eq 'privacy') {
- <span class="card-title">Einstellungen zu öffentlichen Account-Daten geändert</span>
+ <span class="card-title"><%= L('account.changed-privacy') %></span>
% }
% elsif ($success eq 'social') {
- <span class="card-title">Einstellungen zur Interaktionen mit anderen Accounts geändert</span>
+ <span class="card-title"><%= L('account.changed-social') %></span>
% }
% elsif ($success eq 'traewelling') {
- <span class="card-title">Träwelling-Verknüpfung aktualisiert</span>
+ <span class="card-title"><%= L('account.changed-traewelling') %></span>
% }
% elsif ($success eq 'use_history') {
- <span class="card-title">Einstellungen zu vorgeschlagenen Verbindungen geändert</span>
+ <span class="card-title"><%= L('account.changed-history') %></span>
% }
% elsif ($success eq 'webhook') {
- <span class="card-title">Web Hook aktualisiert</span>
+ <span class="card-title"><%= L('account.changed-webhook') %></span>
% }
% elsif ($success eq 'clear_notifications') {
- <span class="card-title">Benachrichtigungen gelesen</span>
+ <span class="card-title"><%= L('account.cleared-notifications') %></span>
% }
</div>
</div>
@@ -46,34 +49,38 @@
% my $use_history = users->use_history(uid => $acc->{id});
<div class="row">
<div class="col s12">
- <h2>Account</h2>
+ <h2><%= L('account.account') %></h2>
<table class="striped">
<tr>
- <th scope="row">Name</th>
+ <th scope="row"><%= L('account.name') %></th>
<td><a href="/account/name"><i class="material-icons">edit</i></a><%= $acc->{name} %></td>
</tr>
<tr>
- <th scope="row">Mail</th>
+ <th scope="row"><%= L('account.mail') %></th>
<td><a href="/account/mail"><i class="material-icons">edit</i></a><%= $acc->{email} %></td>
</tr>
<tr>
- <th scope="row">Passwort</th>
+ <th scope="row"><%= L('account.password') %></th>
<td><a href="/account/password"><i class="material-icons">edit</i></a></td>
</tr>
<tr>
- <th scope="row">Verbindungen</th>
+ <th scope="row"><%= L('account.language') %></th>
+ <td><a href="/account/language"><i class="material-icons">edit</i></a><%= $acc->{languages}[0] // q{} %></td>
+ </tr>
+ <tr>
+ <th scope="row"><%= L('account.connections') %></th>
<td>
<a href="/account/insight"><i class="material-icons">edit</i></a>
% if ($use_history & 0x03) {
- Vorschläge aktiv
+ %= L('account.connections.enabled')
% }
% else {
- <span style="color: #999999;">Vorschläge deaktiviert</span>
+ <span style="color: #999999;"><%= L('account.connections.disabled') %></span>
% }
</td>
</tr>
<tr>
- <th scope="row">Sichtbarkeit</th>
+ <th scope="row"><%= L('account.visibility') %></th>
<td>
<a href="/account/privacy"><i class="material-icons">edit</i></a>
<i class="material-icons">check</i><i class="material-icons"><%= visibility_icon($acc->{default_visibility_str}) %></i>
@@ -81,41 +88,41 @@
</td>
</tr>
<tr>
- <th scope="row">Interaktion</th>
+ <th scope="row"><%= L('account.interaction') %></th>
<td>
<a href="/account/social"><i class="material-icons">edit</i></a>
% if ($acc->{accept_follows}) {
- <span>Accounts können dir direkt folgen</span>
+ <span><%= L('account.interaction.accept-follows') %></span>
% }
% elsif ($acc->{accept_follow_requests}) {
- <span>Accounts können dir auf Anfrage folgen
+ <span><%= L('account.interaction.accept-follow-requests') %>
% if ($num_rx_follow_requests == 1) {
- – <a href="/account/social/follow-requests-received"><strong>eine</strong> offene Anfrage</a>
+ – <a href="/account/social/follow-requests-received"><strong><%= L('account.interaction.one') %></strong> <%= L('account.interaction.open-request') %></a>
% } elsif ($num_rx_follow_requests) {
- – <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> offene Anfragen</a>
+ – <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> <%= L('account.interaction.open-requests') %></a>
% }
</span>
% }
% else {
- <span style="color: #999999;">Accounts können dir nicht folgen</span>
+ <span style="color: #999999;"><%= L('account.interaction.disabled') %></span>
% }
</td>
</tr>
<tr>
- <th scope="row">Web Hook</th>
+ <th scope="row"><%= L('account.webhook') %></th>
<td>
<a href="/account/hooks"><i class="material-icons">edit</i></a>
% if (not $hook->{enabled}) {
- <span style="color: #999999;">Nicht eingerichtet</span>
+ <span style="color: #999999;"><%= L('account.webhook.disabled') %></span>
% }
% elsif ($hook->{latest_run}->epoch == 0) {
- Aktiv, noch nicht ausgeführt
+ <%= L('account.webhook.active-pending') %>
% }
% elsif ($hook->{errored}) {
- Aktiv, fehlerhaft <i class="material-icons" aria-hidden="true">error</i>
+ <%= L('account.webhook.active-error') %> <i class="material-icons" aria-hidden="true">error</i>
% }
% else {
- Aktiv
+ <%= L('account.webhook.active') %>
% }
</td>
</tr>
@@ -123,7 +130,7 @@
<tr>
<th scope="row">Träwelling</th>
<td>
- Wird wegen Inkompatibilität zwischen bahn.de und transitous derzeit nicht unterstützt
+ <%= L('account.traewelling.unsupported') %>
<!--
<a href="/account/traewelling"><i class="material-icons">edit</i></a>
% if (not ($traewelling->{token})) {
@@ -152,8 +159,8 @@
</tr>
% }
<tr>
- <th scope="row">Registriert am</th>
- <td><%= $acc->{registered_at}->strftime('%d.%m.%Y %H:%M') %></td>
+ <th scope="row"><%= L('account.registration-date') %></th>
+ <td><%= $acc->{registered_at}->strftime(L('strftime.datetime')) %></td>
</tr>
</table>
</div>
@@ -163,7 +170,7 @@
%= form_for 'logout' => begin
%= csrf_field
<button class="btn waves-effect waves-light" type="submit" name="action" value="logout">
- Abmelden
+ %= L('button.logout')
</button>
%= end
</div>
@@ -172,32 +179,32 @@
% if ($num_rx_follow_requests or $num_tx_follow_requests or $num_followers or $num_following or $num_blocked) {
<div class="row">
<div class="col s12">
- <h2>Interaktion</h2>
+ <h2><%= L('account.interaction') %></h2>
<p>
- <a href="/p/<%= $acc->{name} %>">Öffentliches Profil</a>
+ <a href="/p/<%= $acc->{name} %>"><%= L('account.profile') %></a>
</p>
<table class="striped">
<tr>
- <th scope="row">Anfragen</th>
+ <th scope="row"><%= L('account.interaction.requests') %></th>
<td>
% if ($num_rx_follow_requests == 0) {
- <span style="color: #999999;">keine eingehend</span>
+ <span style="color: #999999;"><%= L('account.interaction.requests.incoming.none') %></span>
% }
% elsif ($num_rx_follow_requests == 1) {
- <a href="/account/social/follow-requests-received"><strong>eine</strong> eingehend</a>
+ <a href="/account/social/follow-requests-received"><strong><%= L('account.interaction.one') %></strong> <%= L('account.interaction.requests.incoming.some') %></a>
% }
% else {
- <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> eingehend</a>
+ <a href="/account/social/follow-requests-received"><strong><%= $num_rx_follow_requests %></strong> <%= L('account.interaction.requests.incoming.some') %></a>
% }
<br/>
% if ($num_tx_follow_requests == 0) {
- <span style="color: #999999;">keine ausgehend</span>
+ <span style="color: #999999;"><%= L('account.interaction.requests.outgoing.none') %></span>
% }
% elsif ($num_tx_follow_requests == 1) {
- <a href="/account/social/follow-requests-sent"><strong>eine</strong> ausgehend</a>
+ <a href="/account/social/follow-requests-sent"><strong><%= L('account.interaction.one') %></strong> <%= L('account.interaction.requests.outgoing.some') %></a>
% }
% else {
- <a href="/account/social/follow-requests-sent"><strong><%= $num_tx_follow_requests %></strong> ausgehend</a>
+ <a href="/account/social/follow-requests-sent"><strong><%= $num_tx_follow_requests %></strong> <%= L('account.interaction.requests.outgoing.some') %></a>
% }
</td>
</tr>
diff --git a/templates/add_intransit.html.ep b/templates/add_intransit.html.ep
new file mode 100644
index 0000000..a044917
--- /dev/null
+++ b/templates/add_intransit.html.ep
@@ -0,0 +1,93 @@
+<h1>Manuell einchecken</h1>
+% if ($error) {
+ <div class="row">
+ <div class="col s12">
+ <div class="card caution-color">
+ <div class="card-content white-text">
+ <span class="card-title">Ungültige Eingabe</span>
+ <p><%= $error %></p>
+ </div>
+ </div>
+ </div>
+ </div>
+% }
+<div class="row">
+ <div class="col s12">
+ <p>
+ Falls die gesuchte Abfahrt nicht vom ausgewählten Backend verfügbar ist, z.B. da es sich um eine Sonderfahrt handelt, ist hier ein manueller Checkin möglich.
+ Nach dem Checkin werden alle Daten so beibehalten wie sie eingegeben wurden; Änderungen sind erst nach dem Auschecken möglich.
+ </p>
+ <ul>
+ <li>Eingabe der Fahrt als „Typ Linie Nummer“ oder „Typ Nummer“, z.B.
+ „ICE 100“, „S 1 31133“ oder „ABR RE11 26720“</li>
+ <li>Wenn Nummer nicht bekannt oder vorhanden: einen beliebigen Integer eintragen, z.B. „S 5X 0“ oder „U 11 0“</li>
+ <li>Zeitangaben im Format YYYY-MM-DDTHH:MM. Bei den Zwischenhalten kann auch nur HH:MM angegeben werden</li>
+ <li>Das ausgewählte Backend bestimmt die verfügbaren Halte für Start, Ziel und Route. Siehe auch <a href="/static/stops.csv">stops.csv</a></li>
+ </ul>
+ </div>
+</div>
+<div class="row">
+ <div class="col s12 center-align">
+ % if (current_user->{backend_id}) {
+ <a href="/account/select_backend?redirect_to=/checkin/add" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= current_user->{backend_name} %></a>
+ % }
+ % else {
+ <a href="/account/select_backend?redirect_to=/checkin/add" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">train</i>IRIS</a>
+ % }
+ </div>
+</div>
+%= form_for '/checkin/add' => (method => 'POST') => begin
+ %= csrf_field
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'train', id => 'train', class => 'validate', required => undef, pattern => '[0-9a-zA-Z]+ +[0-9a-zA-Z]* *[0-9]+'
+ <label for="train">Fahrt (Typ Linie Nummer)</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
+ <label for="dep_station">Start (Name oder ID)</label>
+ </div>
+ <div class="input-field col s12">
+ %= datetime_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef
+ <label for="sched_departure" class="active">Geplante Abfahrt</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
+ <label for="arr_station">Ziel (Name oder ID)</label>
+ </div>
+ <div class="input-field col s12">
+ %= datetime_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef
+ <label for="sched_arrival" class="active">Geplante Ankunft</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_area 'route', id => 'route', class => 'materialize-textarea'
+ <label for="route">Halte (optional)</label><br/>
+ Eine Station pro Zeile, wahlweise Unterwegshalte oder komplette Route<br/>
+ Format: <i>Name</i> oder <i>Name</i> @ <i>Zeitpunkt</i> (Format siehe oben, ein ggf. ausgelassenes Datum wird ergänzt)
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ %= text_field 'comment'
+ <label for="comment">Kommentar</label>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col s3 m3 l3">
+ </div>
+ <div class="col s6 m6 l6 center-align">
+ <button class="btn waves-effect waves-light" type="submit" name="action" value="save">
+ Einchecken
+ <i class="material-icons right">send</i>
+ </button>
+ </div>
+ <div class="col s3 m3 l3">
+ </div>
+ </div>
+%= end
diff --git a/templates/add_journey.html.ep b/templates/add_journey.html.ep
index c543781..94f9270 100644
--- a/templates/add_journey.html.ep
+++ b/templates/add_journey.html.ep
@@ -33,10 +33,22 @@
<li>Eingabe der Fahrt als „Typ Linie Nummer“ oder „Typ Nummer“, z.B.
„ICE 100“, „S 1 31133“ oder „ABR RE11 26720“</li>
<li>Wenn Nummer nicht bekannt oder vorhanden: einen beliebigen Integer eintragen, z.B. „S 5X 0“ oder „U 11 0“</li>
- <li>Zeitangaben im Format DD.MM.YYYY HH:MM</li>
+ <li>Zeitangaben im Format YYYY-MM-DDTHH:MM</li>
+ <li>Das ausgewählte Backend bestimmt die verfügbaren Halte für Start, Ziel und Route. Siehe auch <a href="/static/stops.csv">stops.csv</a></li>
</ul>
</div>
</div>
+<div class="row">
+ <div class="col s12 center-align">
+ % my $self_link = url_for('add_journey');
+ % if (current_user->{backend_id}) {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= current_user->{backend_name} %></a>
+ % }
+ % else {
+ <a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small btn-flat"><i class="material-icons left" aria-hidden="true">train</i>IRIS</a>
+ % }
+ </div>
+</div>
%= form_for '/journey/add' => (method => 'POST') => begin
%= csrf_field
<div class="row">
@@ -54,35 +66,37 @@
<div class="row">
<div class="input-field col s12">
%= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
- <label for="dep_station">Start (Name oder DS100)</label>
+ <label for="dep_station">Start (Name oder ID)</label>
</div>
<div class="input-field col s12">
- %= text_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
- <label for="sched_departure">Geplante Abfahrt</label>
+ %= datetime_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef
+ <label for="sched_departure" class="active">Geplante Abfahrt</label>
</div>
<div class="input-field col s12">
- %= text_field 'rt_departure', id => 'rt_departure', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
- <label for="rt_departure">Tatsächliche Abfahrt (wenn leer: pünktlich)</label>
+ %= datetime_field 'rt_departure', id => 'rt_departure', class => 'validate'
+ <label for="rt_departure" class="active">Tatsächliche Abfahrt (wenn leer: pünktlich)</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
%= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', autocomplete => 'off', required => undef
- <label for="arr_station">Ziel (Name oder DS100)</label>
+ <label for="arr_station">Ziel (Name oder ID)</label>
</div>
<div class="input-field col s12">
- %= text_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
- <label for="sched_arrival">Geplante Ankunft</label>
+ %= datetime_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef
+ <label for="sched_arrival" class="active">Geplante Ankunft</label>
</div>
<div class="input-field col s12">
- %= text_field 'rt_arrival', id => 'rt_arrival', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
- <label for="rt_arrival">Tatsächliche Ankunft (wenn leer: pünktlich)</label>
+ %= datetime_field 'rt_arrival', id => 'rt_arrival', class => 'validate'
+ <label for="rt_arrival" class="active">Tatsächliche Ankunft (wenn leer: pünktlich)</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
%= text_area 'route', id => 'route', class => 'materialize-textarea'
- <label for="route">Unterwegshalte (optional, eine Station pro Zeile, DS100 möglich)</label>
+ <label for="route">Halte (optional)</label><br/>
+ Eine Station pro Zeile, wahlweise Unterwegshalte oder komplette Route<br/>
+ Format: <i>Name</i> oder <i>Name</i> @ <i>Zeitpunkt</i> (inkl. Datum, siehe oben)
</div>
</div>
<div class="row">
diff --git a/templates/api_documentation.html.ep b/templates/api_documentation.html.ep
index 099474c..6db9536 100644
--- a/templates/api_documentation.html.ep
+++ b/templates/api_documentation.html.ep
@@ -89,23 +89,25 @@
<div class="col s12">
<p>
Checkin per API. Sobald eine Zielstation bekannt ist, erfolgt der
- Checkout wie beim Webinterface automatisch zehn Minuten nach Ankunft.
- Bitte beachten: Es wird nicht überprüft, ob die angegebene Zielstation
- in der vorgesehenen Route der Fahrt vorkommt oder nicht.
+ Checkout wie beim Webinterface automatisch spätestens eine halbe
+ Stunde nach Ankunft. Bitte beachten: Es wird nicht überprüft, ob
+ die angegebene Zielstation in der vorgesehenen Route der Fahrt
+ vorkommt oder nicht.
</p>
<p>
- Falls du zum Checkinzeitpunkt bereits in eine andere Fahrt eingecheckt
- bist, wirst du zunächst am gewählten Startbahnhof aus diesem ausgecheckt.
- Der Checkout erfolgt unabhängig davon, ob die vorherige Fahrt an dieser
- Station verkehrt oder nicht. Falls nach einem Checkin ohne Zielwahl
- innerhalb von 48 Stunden kein Zielbahnhof nachgetragen wird, wird der
- Checkin automatisch rückgängig gemacht.
+ Falls du zum Checkinzeitpunkt bereits in eine andere Fahrt
+ eingecheckt bist, wirst du zunächst am gewählten Startbahnhof aus
+ diesem ausgecheckt. Der Checkout erfolgt unabhängig davon, ob die
+ vorherige Fahrt an dieser Station verkehrt oder nicht. Falls nach
+ einem Checkin ohne Zielwahl innerhalb von 48 Stunden kein
+ Zielbahnhof nachgetragen wird, wird der Checkin automatisch
+ rückgängig gemacht.
</p>
<p>
Das Verhalten des Checkout-Endpunkts hängt vom Zeitpunkt ab. Wenn die
Fahrt den angegebenen Zielbahnhof bereits erreicht hat, wird dort
- ausgecheckt. Andernfalls wird das Reiseziel aktualisiert und etwa zehn
- Minuten nach Ankunft automatisch ausgecheckt.
+ ausgecheckt. Andernfalls wird das Reiseziel aktualisiert und
+ spätestens eine halbe Stunde nach Ankunft automatisch ausgecheckt.
</p>
<p style="font-family: Monospace;">
curl -X POST -H "Content-Type: application/json" -d '{"token":"<%= $uid %>-<%= $token->{travel} // 'TOKEN' %>"}' <%= $api_root %>/travel
diff --git a/templates/cancelled.html.ep b/templates/cancelled.html.ep
index 4fab434..fe0b958 100644
--- a/templates/cancelled.html.ep
+++ b/templates/cancelled.html.ep
@@ -1,7 +1,7 @@
-<h1>Zugausfälle</h1>
+<h1>Ausfälle</h1>
<div class="row">
<div class="col s12">
- Die folgenden Zugfahrten haben nicht stattgefunden.
+ Die folgenden Fahrten haben nicht wie geplant stattgefunden.
</div>
</div>
diff --git a/templates/changelog.html.ep b/templates/changelog.html.ep
index dc454c5..042a46e 100644
--- a/templates/changelog.html.ep
+++ b/templates/changelog.html.ep
@@ -2,6 +2,67 @@
<div class="row">
<div class="col s12 m1 l1">
+ 2.17
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="<%= L('changelog.added') %>">add</i>
+ %= L('changelog.2-17.1')
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.16
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="<%= L('changelog.added') %>">add</i>
+ %= L('changelog.2-16.1')
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="<%= L('changelog.bugfix') %>">build</i>
+ %= L('changelog.2-16.2')
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
+ 2.15
+ </div>
+ <div class="col s12 m11 l11">
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Manuelle Checkins. Diese verhalten sich analog zu manuell
+ eingetragenen Fahrten, werden jedoch bis zur planmäßigen
+ Ankunftszeit als Checkin behandelt. Manuelle Echtzeitdaten-Updates
+ werden nicht unterstützt. Manuelle Checkins sind nur an Halten
+ möglich, die dem ausgewählten Backend bekannt sind. Ggf. wird
+ dieses Feature später um eine Möglichkeit für Echtzeitdaten-Updates
+ und/oder eine API erweitert.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Neues Feature">add</i>
+ Erfassung des Betreibers einer Fahrt, sofern verfügbar.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Verbesserung">star</i>
+ EFA-Backends werden nun fast vollständig unterstützt und sind nicht
+ mehr experimentell.
+ </p>
+ <p>
+ <i class="material-icons left" aria-label="Bugfix">build</i>
+ Das manuelle Eintragen von Fahrten ist nun wieder möglich. Zudem
+ kann dabei nun ein beliebiges Backend ausgewählt werden; das
+ ausgewählte Backend bestimmt die verfügbaren Halte.
+ </p>
+ </div>
+</div>
+
+<div class="row">
+ <div class="col s12 m1 l1">
2.14
</div>
<div class="col s12 m11 l11">
diff --git a/templates/departures.html.ep b/templates/departures.html.ep
index 16b5f3c..0d57039 100644
--- a/templates/departures.html.ep
+++ b/templates/departures.html.ep
@@ -81,14 +81,7 @@
</div>
</div>
% }
-% elsif ($user_status->{timestamp_delta} < 180) {
- <div class="row">
- <div class="col s12">
- %= include '_checked_out', journey => $user_status;
- </div>
- </div>
-% }
-% elsif (not param('train') and (@{stash('connections_iris') // []} or @{stash('connections_hafas') // []}) ) {
+% elsif (not param('train') and (@{stash('connections_iris') // []} or @{stash('connections_hafas') // []} or @{stash('suggestions') // []}) ) {
% $have_connections = 1;
<div class="row">
<div class="col s12">
@@ -99,6 +92,21 @@
% if (@{stash('connections_hafas') // []}) {
%= include '_connections_hafas', connections => stash('connections_hafas'), checkin_from => $eva;
% }
+ % if (@{stash('suggestions') // []}) {
+ % if ($dbris) {
+ %= include '_suggestions_dbris', suggestions => stash('suggestions'), checkin_from => $eva;
+ % }
+ % elsif ($efa) {
+ %= include '_suggestions_efa', suggestions => stash('suggestions'), checkin_from => $eva;
+ % }
+ % }
+ </div>
+ </div>
+% }
+% if (not $user_status->{checked_in} and $user_status->{timestamp_delta} < 180) {
+ <div class="row">
+ <div class="col s12">
+ %= include '_checked_out', journey => $user_status;
</div>
</div>
% }
@@ -190,3 +198,11 @@
% }
</div>
</div>
+
+% if (not $user_status->{checked_in}) {
+ <div class="row">
+ <div class="col s12 center-align">
+ <a class="btn-small" href="<%= url_for('checkinadd')->query({dbris => $dbris, efa => $efa, hafas => $hafas, motis => $motis, dep_station => $station}) %>"><i class="material-icons left" aria-hidden="true">add</i><span>manuell einchecken</span></a>
+ </div>
+ </div>
+% }
diff --git a/templates/edit_journey.html.ep b/templates/edit_journey.html.ep
index cb867e5..57941c0 100644
--- a/templates/edit_journey.html.ep
+++ b/templates/edit_journey.html.ep
@@ -69,13 +69,13 @@
<tr>
<th scope="row">Geplante Abfahrt</th>
<td class="input-field">
- %= text_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
+ %= text_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?'
</td>
</tr>
<tr>
<th scope="row">Tatsächliche Abfahrt</th>
<td class="input-field">
- %= text_field 'rt_departure', id => 'real_departure', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
+ %= text_field 'rt_departure', id => 'real_departure', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?'
</td>
</tr>
<tr>
@@ -87,13 +87,13 @@
<tr>
<th scope="row">Geplante Ankunft</th>
<td class="input-field">
- %= text_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
+ %= text_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?'
</td>
</tr>
<tr>
<th scope="row">Tatsächliche Ankunft</th>
<td class="input-field">
- %= text_field 'rt_arrival', id => 'real_arrival', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
+ %= text_field 'rt_arrival', id => 'real_arrival', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9](:[0-9][0-9])?'
</td>
</tr>
<tr>
diff --git a/templates/history_by_month.html.ep b/templates/history_by_month.html.ep
index c3b1004..dec4c8b 100644
--- a/templates/history_by_month.html.ep
+++ b/templates/history_by_month.html.ep
@@ -6,7 +6,7 @@
<div class="row">
<div class="col s12 m12 l12 center-align">
- <a href="/history/map?filter_from=<%= $filter_from->strftime('%d.%m.%Y') %>&amp;filter_to=<%= $filter_to->strftime('%d.%m.%Y') %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
+ <a href="/history/map?filter_from=<%= $filter_from->strftime('%F') %>&amp;filter_to=<%= $filter_to->strftime('%F') %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
</div>
</div>
diff --git a/templates/history_by_year.html.ep b/templates/history_by_year.html.ep
index 6aa0c2d..1557b77 100644
--- a/templates/history_by_year.html.ep
+++ b/templates/history_by_year.html.ep
@@ -7,7 +7,7 @@
<div class="row">
% if (stash('have_review')) {
<div class="col s12 m12 l5 center-align">
- <a href="/history/map?filter_from=1.1.<%= $year %>&amp;filter_to=31.12.<%= $year %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
+ <a href="/history/map?filter_from=<%= $year %>-01-01&amp;filter_to=<%= $year %>-12-31" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
</div>
<div class="col s12 m12 l2">&nbsp;</div>
<div class="col s12 m12 l5 center-align">
@@ -16,7 +16,7 @@
% }
% else {
<div class="col s12 m12 l12 center-align">
- <a href="/history/map?filter_from=1.1.<%= $year %>&amp;filter_to=31.12.<%= $year %>" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
+ <a href="/history/map?filter_from=<%= $year %>-01-01&amp;filter_to=<%= $year %>-12-31" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
</div>
% }
</div>
diff --git a/templates/history_map.html.ep b/templates/history_map.html.ep
index 57ba81f..6620cb2 100644
--- a/templates/history_map.html.ep
+++ b/templates/history_map.html.ep
@@ -88,14 +88,14 @@
</p>
<div class="row">
<div class="input-field col s12">
- %= text_field 'filter_from', id => 'filter_from', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9]( +[0-9][0-9]:[0-9][0-9])?'
- <label for="filter_from">Abfahrt ab (DD.MM.YYYY)</label>
+ %= date_field 'filter_from', id => 'filter_from', class => 'validate'
+ <label for="filter_from" class="active">Abfahrt ab</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
- %= text_field 'filter_to', id => 'filter_to', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9]( +[0-9][0-9]:[0-9][0-9])?'
- <label for="filter_to">Abfahrt bis (DD.MM.YYYY)</label>
+ %= date_field 'filter_to', id => 'filter_to', class => 'validate'
+ <label for="filter_to" class="active">Abfahrt bis</label>
</div>
</div>
<div class="row">
@@ -116,8 +116,8 @@
<div class="row">
<div class="col s12">
<p>
- Die eingezeichneten Routen stammen aus dem HAFAS und sind im Detail
- oft fehlerbehaftet.
+ Die eingezeichneten Routen stammen aus dem Backend, mit dem die Fahrt aufgezeichnet wurde.
+ Die Datenqualität variiert.
</p>
</div>
</div>
diff --git a/templates/journey.html.ep b/templates/journey.html.ep
index 45a1598..09ad76d 100644
--- a/templates/journey.html.ep
+++ b/templates/journey.html.ep
@@ -3,8 +3,8 @@
<div class="col s12">
<div class="card caution-color">
<div class="card-content white-text">
- <span class="card-title">Fehler</span>
- <p>Fahrt nicht gefunden.</p>
+ <span class="card-title"><%= L('header.error') %></span>
+ <p><%= L('journey.not-found') %></p>
</div>
</div>
</div>
@@ -15,29 +15,17 @@
<div class="col s12">
<p>
% if (my $name = stash('username')) {
- <b><a href="/p/<%= $name %>"><%= $name %></a></b>s
+ Checkin von <b><a href="/p/<%= $name %>"><%= $name %></a></b>
% }
- % if ($journey->{cancelled}) {
- Ausgefallene Fahrt
+ % elsif ($journey->{cancelled}) {
+ <b>Ausgefallene Fahrt</b> vom <%= $journey->{checkin}->strftime('%d.%m.%Y um %H:%M Uhr') %>
% }
% else {
- Fahrt
+ Checkin vom <%= $journey->{checkin}->strftime('%d.%m.%Y um %H:%M Uhr') %>
% }
% if ($journey->{edited} & 0x0020) {
% }
- von
- <b><%= $journey->{from_name} %></b>
- % if ($journey->{edited} & 0x0004) {
- ∗
- % }
- nach
- <b><%= $journey->{to_name} %></b>
- % if ($journey->{edited} & 0x0400) {
- ∗
- % }
- am
- <b><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></b>
% if (my $v = stash('journey_visibility')) {
% if (stash('username')) {
<i class="material-icons right"><%= visibility_icon($v) %></i>
@@ -67,9 +55,9 @@
%= end
</div>
% }
- <table class="striped">
+ <table class="striped journey">
<tr>
- <th scope="row">Fahrt</th>
+ <th scope="row"><%= L('journey.trip') %></th>
<td>
<%= $journey->{type} %> <%= $journey->{no} %>
% if ($journey->{line}) {
@@ -78,19 +66,48 @@
</td>
</tr>
<tr>
- <th scope="row">Abfahrt</th>
+ <th scope="row"><%= L('journey.from') %></th>
+ <td>
+ %= $journey->{from_name}
+ % if ($journey->{from_platform} and $journey->{to_platform}) {
+ (<%= $journey->{from_platform} %>)
+ % }
+ % if ($journey->{edited} & 0x0004) {
+ ∗
+ % }
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><%= L('journey.to') %></th>
+ <td>
+ <%= $journey->{to_name} %>
+ % if ($journey->{from_platform} and $journey->{to_platform}) {
+ (<%= $journey->{to_platform} %>)
+ % }
+ % if ($journey->{edited} & 0x0400) {
+ ∗
+ % }
+ </td>
+ </tr>
+ <tr>
+ <th scope="row"><%= L('journey.departure') %></th>
<td>
% if ($journey->{cancelled}) {
<i class="material-icons">cancel</i>
- (Plan: <%= $journey->{sched_departure}->strftime('%H:%M'); %>)
+ (Plan: <%= $journey->{sched_departure}->strftime('%d.%m.%Y %H:%M'); %>)
% }
- % elsif ($journey->{rt_departure} != $journey->{sched_departure}) {
- %= ($journey->{rt_departure}->epoch % 60) ? $journey->{rt_departure}->strftime('%H:%M:%S') : $journey->{rt_departure}->strftime('%H:%M');
- (<%= sprintf('%+d', ($journey->{rt_departure}->epoch - $journey->{sched_departure}->epoch) / 60) %>,
- Plan: <%= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%H:%M:%S') : $journey->{sched_departure}->strftime('%H:%M'); %>)
+ % elsif ($journey->{delay_dep}) {
+ %= ($journey->{rt_departure}->epoch % 60) ? $journey->{rt_departure}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{rt_departure}->strftime('%d.%m.%Y %H:%M')
+ % if (int(abs($journey->{delay_dep}) / 60)) {
+ (<%= sprintf('%+d', ($journey->{rt_departure}->epoch - $journey->{sched_departure}->epoch) / 60) %>, Plan:
+ % }
+ % else {
+ (Plan:
+ % }
+ %= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%H:%M:%S)') : $journey->{sched_departure}->strftime('%H:%M)')
% }
% else {
- %= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%H:%M:%S') : $journey->{sched_departure}->strftime('%H:%M');
+ %= ($journey->{sched_departure}->epoch % 60) ? $journey->{sched_departure}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{sched_departure}->strftime('%d.%m.%Y %H:%M');
% }
% if ($journey->{edited} & 0x0003) {
@@ -98,24 +115,29 @@
</td>
</tr>
<tr>
- <th scope="row">Ankunft</th>
+ <th scope="row"><%= L('journey.arrival') %></th>
<td>
% if ($journey->{cancelled}) {
<i class="material-icons">cancel</i>
% if ($journey->{sched_arrival}->epoch != 0) {
- (Plan: <%= $journey->{sched_arrival}->strftime('%H:%M'); %>)
+ (Plan: <%= $journey->{sched_arrival}->strftime('%d.%m.%Y %H:%M'); %>)
% }
% }
% elsif ($journey->{rt_arrival}->epoch == 0 and $journey->{sched_arrival}->epoch == 0) {
<i class="material-icons">timer_off</i>
% }
- % elsif ($journey->{rt_arrival} != $journey->{sched_arrival}) {
- %= ($journey->{rt_arrival}->epoch % 60) ? $journey->{rt_arrival}->strftime('%H:%M:%S') : $journey->{rt_arrival}->strftime('%H:%M');
- (<%= sprintf('%+d', ($journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch) / 60) %>,
- Plan: <%= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%H:%M:%S') : $journey->{sched_arrival}->strftime('%H:%M'); %>)
+ % elsif ($journey->{delay_arr}) {
+ %= ($journey->{rt_arrival}->epoch % 60) ? $journey->{rt_arrival}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{rt_arrival}->strftime('%d.%m.%Y %H:%M')
+ % if (int(abs($journey->{delay_arr}) / 60)) {
+ (<%= sprintf('%+d', ($journey->{rt_arrival}->epoch - $journey->{sched_arrival}->epoch) / 60) %>, Plan:
+ % }
+ % else {
+ (Plan:
+ % }
+ %= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%H:%M:%S)') : $journey->{sched_arrival}->strftime('%H:%M)')
% }
% else {
- %= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%H:%M:%S') : $journey->{sched_arrival}->strftime('%H:%M');
+ %= ($journey->{sched_arrival}->epoch % 60) ? $journey->{sched_arrival}->strftime('%d.%m.%Y %H:%M:%S') : $journey->{sched_arrival}->strftime('%d.%m.%Y %H:%M');
% }
% if ($journey->{edited} & 0x0300) {
@@ -123,7 +145,7 @@
</td>
</tr>
<tr>
- <th scope="row">Strecke</th>
+ <th scope="row"><%= L('journey.distance') %></th>
<td>
% if ($journey->{skip_route}) {
<i class="material-icons right">location_off</i>
@@ -131,10 +153,10 @@
% }
% if ($journey->{km_route} > 0.1) {
ca. <%= sprintf_km($journey->{km_route}) %>
- (Luftlinie: <%= sprintf_km($journey->{km_beeline}) %>)
+ <%= L('journey.beeline.pre') %><%= sprintf_km($journey->{km_beeline}) %><%= L('journey.beeline.post') %>
% }
% elsif ($journey->{km_beeline} > 0.1) {
- (Luftlinie: <%= sprintf_km($journey->{km_beeline}) %>)
+ <%= L('journey.beeline.pre') %><%= sprintf_km($journey->{km_beeline}) %><%= L('journey.beeline.post') %>
% }
% else {
?
@@ -145,7 +167,7 @@
</td>
</tr>
<tr>
- <th scope="row">Tempo</th>
+ <th scope="row"><%= L('journey.speed') %></th>
<td>
% if ($journey->{skip_route}) {
<i class="material-icons right">location_off</i>
@@ -168,7 +190,7 @@
</tr>
% if ($journey->{user_data}{operator} or scalar @{ $journey->{user_data}{operators} // [] }) {
<tr>
- <th scope="row">Betrieb</th>
+ <th scope="row"><%= L('journey.operator') %></th>
<td>
%= $journey->{user_data}{operator} // join(q{, }, @{$journey->{user_data}{operators}})
</td>
@@ -176,7 +198,7 @@
% }
% if ($journey->{messages} and @{$journey->{messages}}) {
<tr>
- <th scope="row">Meldungen</th>
+ <th scope="row"><%= L('journey.messages') %></th>
<td>
% for my $message (@{$journey->{messages} // []}) {
% my ($ts, $msg) = @{$message};
@@ -187,7 +209,7 @@
% }
% if ($journey->{user_data}{him_msg} and @{$journey->{user_data}{him_msg}}) {
<tr>
- <th scope="row">Meldungen</th>
+ <th scope="row"><%= L('journey.messages') %></th>
<td>
% for my $message (@{$journey->{user_data}{him_msg} // []}) {
<i class="material-icons tiny"><%= ($message->{prio} and $message->{prio} eq 'HOCH') ? 'warning' : 'info' %></i> <%= $message->{header} %> <%= $message->{lead} %><br/>
@@ -197,7 +219,7 @@
% }
% if ($journey->{user_data} and $journey->{user_data}{comment}) {
<tr>
- <th scope="row">Kommentar</th>
+ <th scope="row"><%= L('journey.comment') %></th>
<td>
<%= $journey->{user_data}{comment} %>
</td>
@@ -205,7 +227,7 @@
% }
% if ($journey->{user_data} and $journey->{user_data}{wagongroups} and not exists $journey->{user_data}{wagons}) {
<tr>
- <th scope="row">Rollmaterial</th>
+ <th scope="row"><%= L('journey.carriages') %></th>
<td class="wagons">
%= include '_wagons', wagongroups => $journey->{user_data}{wagongroups};
</td>
@@ -213,7 +235,7 @@
% }
% elsif ($journey->{user_data} and $journey->{user_data}{wagons}) {
<tr>
- <th scope="row">Rollmaterial</th>
+ <th scope="row"><%= L('journey.carriages') %></th>
<td class="wagons">
% for my $wagongroup (@{$journey->{user_data}{wagongroups} // []}) {
Wagenverbund <%= $wagongroup %><br/>
@@ -230,16 +252,17 @@
</tr>
% }
<tr>
- <th scope="row">Route</th>
- <td>
+ <th scope="row"><%= L('journey.route') %></th>
+ <td class="route">
% my $before = 1;
% my $within = 0;
% my $at_startstop = 0;
+ % my $i = 0;
% for my $station (@{$journey->{route}}) {
- % if (($station->[1] and $station->[1] == $journey->{from_eva}) or $station->[0] eq $journey->{from_name}) {
+ % if ($i == $journey->{route_dep_index}) {
% $within = 1; $at_startstop = 1;
% }
- % elsif (($station->[1] and $station->[1] == $journey->{to_eva}) or $station->[0] eq $journey->{to_name}) {
+ % elsif ($i == $journey->{route_arr_index}) {
% $within = 0; $at_startstop = 1;
% }
% else {
@@ -247,10 +270,10 @@
% }
<span style="color: #808080;">
% if ($before and $station->[2]{sched_dep}) {
- %= $station->[2]{sched_dep}->strftime('%H:%M')
+ %= $station->[2]{sched_dep_dt}->strftime('%H:%M')
% }
% elsif (not $before and $station->[2]{sched_arr}) {
- %= $station->[2]{sched_arr}->strftime('%H:%M')
+ %= $station->[2]{sched_arr_dt}->strftime('%H:%M')
% }
</span>
% if ($at_startstop or $within) {
@@ -259,6 +282,12 @@
% else {
<span style="color: #808080;"><%= $station->[0] %></span>
% }
+ % if ($station->[2]{isAdditional}) {
+ <span style="color: #808080;">⊕</span>
+ % }
+ % elsif ($station->[2]{isCancelled}) {
+ <span style="color: #808080;">∅</span>
+ % }
% if ($journey->{edited} & 0x0010) {
% }
@@ -276,6 +305,7 @@
% $before = 0;
% }
<br/>
+ % $i += 1;
% }
</td>
</tr>
@@ -293,62 +323,99 @@
</div>
</div>
% if (not stash('readonly')) {
- % if (stash('with_share')) {
- <div class="row">
- <div class="col s12 m6 l6">
- </div>
- <div class="col s12 m6 l6 center-align">
+ <div class="row">
+ <div class="col s12 m6 l4 center-align">
+ <a class="btn waves-effect waves-light" href="<%= url_for('journey', id => $journey->{id}, format => 'json' ) %>">
+ <i class="material-icons left" aria-hidden="true">file_download</i>
+ %= L('journey.export')
+ </a>
+ </div>
+ <div class="col s12 m6 l4 center-align">
+ %= form_for '/journey/edit' => (method => 'POST') => begin
+ %= hidden_field 'journey_id' => param('journey_id')
+ <button class="btn waves-effect waves-light" type="submit" name="action" value="edit">
+ <i class="material-icons left" aria-hidden="true">edit</i>
+ %= L('journey.edit')
+ </button>
+ %= end
+ </div>
+ <div class="col s12 m6 l4 center-align">
+ % if (stash('with_share')) {
<a class="btn waves-effect waves-light action-share"
% if (stash('journey_visibility') eq 'public') {
data-url="<%= url_for('public_journey', name => current_user()->{name}, id => $journey->{id} )->to_abs->scheme('https'); %>"
% }
% else {
- data-url="<%= url_for('public_journey', name => current_user()->{name}, id => $journey->{id} )->to_abs->scheme('https'); %>?token=<%= $journey->{from_eva} %>-<%= $journey->{checkin_ts} % 337 %>-<%= $journey->{sched_dep_ts} %>"
+ data-url="<%= url_for('public_journey', name => current_user()->{name}, id => $journey->{id} )->to_abs->scheme('https'); %>?token=<%= $journey->{from_eva} %>-<%= $journey->{checkin_ts} % 337 %>-<%= int($journey->{sched_dep_ts}) %>"
% }
data-text="<%= stash('share_text') %>"
>
- <i class="material-icons left" aria-hidden="true">share</i> Teilen
+ <i class="material-icons left" aria-hidden="true">share</i>
+ %= L('journey.share')
</a>
- </div>
- </div>
- % }
- <div class="row hide-on-small-only">
- <div class="col s12 m6 l6 center-align">
- <a class="waves-effect waves-light red btn action-delete"
- data-id="<%= $journey->{id} %>"
- data-checkin="<%= $journey->{checkin}->epoch %>"
- data-checkout="<%= $journey->{checkout}->epoch %>">
- <i class="material-icons left">delete_forever</i>
- Löschen
- </a>
- </div>
- <div class="col s12 m6 l6 center-align">
- %= form_for '/journey/edit' => (method => 'POST') => begin
- %= hidden_field 'journey_id' => param('journey_id')
- <button class="btn waves-effect waves-light" type="submit" name="action" value="edit">
- <i class="material-icons left" aria-hidden="true">edit</i>
- Bearbeiten
- </button>
- %= end
+ % }
</div>
</div>
- <div class="row hide-on-med-and-up">
- <div class="col s12 m6 l6 center-align">
- %= form_for '/journey/edit' => (method => 'POST') => begin
- %= hidden_field 'journey_id' => param('journey_id')
- <button class="btn waves-effect waves-light" type="submit" name="action" value="edit">
- <i class="material-icons left" aria-hidden="true">edit</i>
- Bearbeiten
- </button>
- %= end
+ % if ($journey->{polyline} or $journey->{km_route} > 0.1) {
+ <h2><%= L('journey.map-data') %>
+ % if ($journey->{edited} & 0x0040) {
+ ∗
+ % }
+ </h2>
+ <div class="row">
+ <div class="col s12 m6 l6 center-align">
+ <a class="btn waves-effect waves-light" href="<%= url_for('polyline_download', id => $journey->{id}, format => 'json' ) %>">
+ <i class="material-icons left" aria-label="<%= L('journey.map.download') %>">file_download</i>
+ JSON
+ </a>
+ </div>
+ <div class="col s12 m6 l6 center-align">
+ <a class="btn waves-effect waves-light" href="<%= url_for('polyline_download', id => $journey->{id}, format => 'gpx' ) %>">
+ <i class="material-icons left" aria-label="<%= L('journey.map.download') %>">file_download</i>
+ GPX
+ </a>
+ </div>
</div>
- <div class="col s12 m6 l6 center-align" style="margin-top: 1em;">
+ <div class="row">
+ <div class="col s12">
+ %= L('journey.map.info.download')
+ %= L('journey.map.info.upload')
+ </div>
+ </div>
+ %= form_for '/polyline/set' => (method => 'post', enctype => 'multipart/form-data') => begin
+ %= csrf_field
+ %= hidden_field id => $journey->{id}
+ <div class="row">
+ <div class="col s12">
+ <div class="file-field input-field">
+ <div class="btn">
+ <span><i class="material-icons left" aria-label="<%= L('journey.map.upload') %>">file_upload</i> GPX</span>
+ <input type="file">
+ </div>
+ <div class="file-path-wrapper">
+ <input class="file-path validate" type="text" name="file">
+ </div>
+ %= file_field 'file'
+ </div>
+ </div>
+ <div class="col s12 m6 center-align">
+ %= submit_button L('journey.map.upload-full'), class => 'waves-effect waves-light btn', name => 'upload-full'
+ </div>
+ <div class="col s12 m6 center-align">
+ %= submit_button L('journey.map.upload-partial'), class => 'waves-effect waves-light btn', name => 'upload-partial'
+ </div>
+ </div>
+ %= end
+ % }
+ <h2><%= L('journey.danger') %></h2>
+ <div class="row">
+ <div class="col s12 m12 l12 center-align" style="margin-top: 1em;">
<a class="waves-effect waves-light red btn action-delete"
data-id="<%= $journey->{id} %>"
data-checkin="<%= $journey->{checkin}->epoch %>"
data-checkout="<%= $journey->{checkout}->epoch %>">
<i class="material-icons left" aria-hidden="true">delete_forever</i>
- Löschen
+ %= L('journey.delete')
</a>
</div>
</div>
diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep
index 5ca0e9e..ba0433f 100644
--- a/templates/landingpage.html.ep
+++ b/templates/landingpage.html.ep
@@ -55,22 +55,22 @@
%= form_for 'list_departures' => begin
<div class="card">
<div class="card-content">
- <span class="card-title">Hallo, <%= $user->{name} %>!</span>
- <p>Du bist gerade nicht eingecheckt.</p>
+ <span class="card-title"><%= L('landingpage.greeting-prefix') %> <%= $user->{name} %><%= L('landingpage.greeting-suffix') %></span>
+ <p><%= L('landingpage.not-checked-in') %>.</p>
<div class="geolocation" data-recent="<%= join('|', map { $_->{external_id_or_eva} . ';' . $_->{name} . ';' . $_->{dbris} . ';' . $_->{efa} . ';' . $_->{hafas} . ';' . $_->{motis} } @{stash('recent_targets') // []} ) %>" data-backend="<%= $user->{backend_id} %>">
- <a class="btn waves-effect waves-light btn-flat request">Stationen in der Umgebung abfragen</a>
+ <a class="btn waves-effect waves-light btn-flat request"><%= L('landingpage.stop-geosearch') %></a>
</div>
%= hidden_field backend_dbris => $user->{backend_dbris}
<div class="input-field">
%= text_field 'station', id => 'station', class => 'autocomplete contrast-color-text', autocomplete => 'off', required => undef
- <label for="station">Manuelle Eingabe</label>
+ <label for="station"><%= L('landingpage.manual-stop-entry') %></label>
</div>
</div>
<div class="card-action">
<a href="/account/select_backend?redirect_to=/" class="btn btn-flat"><i class="material-icons left" aria-hidden="true"><%= $user->{backend_hafas} ? 'directions' : 'train' %></i><%= $user->{backend_name} // 'IRIS' %></a>
<button class="btn right waves-effect waves-light btn-flat" type="submit" name="action" value="departures">
<i class="material-icons left" aria-hidden="true">send</i>
- Abfahrten
+ %= L('landingpage.departures')
</button>
</div>
</div>
@@ -97,45 +97,36 @@
</div>
</div>
% }
- <h2 style="margin-left: 0.75rem;">Letzte Fahrten</h2>
- %= include '_history_trains', date_format => '%d.%m.%Y', journeys => [journeys->get(uid => $user->{id}, limit => 5, with_datetime => 1)];
+ <h2 style="margin-left: 0.75rem;"><%= L('landingpage.latest-trips') %></h2>
+ %= include '_history_trains', date_format => L('landingpage.date-format'), journeys => [journeys->get(uid => $user->{id}, limit => 5, with_datetime => 1)];
% }
% else {
<div class="row">
<div class="col s12">
<p>
- Travelynx erlaubt das Einchecken in Verkehrsmittel (Busse,
- Bahnen, Züge) unter anderem in Deutschland, Österreich, der
- Schweiz, Luxemburg, Irland, Dänemark und Teilen der USA. So
- können die eigenen Fahrten später inklusive Echtzeitdaten und
- eingetragenen Servicemeldungen nachvollzogen und brennende
- Fragen wie „Wie viele Stunden war ich letzten Monat unterwegs?“
- beantwortet werden.
+ %= L('landingpage.about')
</p>
<p>
- Die Idee dazu kommt von <a
- href="https://traewelling.de/">Träwelling</a>.
+ %= L('landingpage.traewelling.pre')
+ <a href="https://traewelling.de/">Träwelling</a>
+ %= L('landingpage.traewelling.post')
</p>
<p>
- Features:
+ %= L('landingpage.features')
<ul>
- <li>Protokoll von Fahrplan- und Echtzeitdaten an Start- und
- Zielbahnhof</li>
- <li>Teilen von aktuellen und vergangenen Fahrten mit anderen Personen</li>
- <li>Web-Hooks und <a href="/api">API</a> zum automatisierten Einchecken und Auslesen des aktuellen Status</li>
- <li>Statistiken über Reisezeiten und Verspätungen</li>
- <li>Unterstützung beim Ausfüllen von Fahrgastrechteformularen</li>
- <li>Optional: Öffentlicher Reisestatus und öffentliche Angaben zu vergangenen Fahrten</li>
- <!-- <li>Optional: Verknüpfung mit Träwelling</li> -->
+ <li><%= L('landingpage.features.log') %></li>
+ <li><%= L('landingpage.features.share') %></li>
+ <li><%= L('landingpage.features.api-pre') %> <a href="/api"><%= L('landingpage.features.api-link') %></a> <%= L('landingpage.features.api-post') %></li>
+ <li><%= L('landingpage.features.stats') %></li>
+ <li><%= L('landingpage.features.passenger-rights') %></li>
+ <li><%= L('landingpage.features.public') %></li>
</ul>
</p>
<p>
- Travelynx ist ein kostenfreies, privat betriebenes Projekt ohne
- Verfügbarkeitsgarantie. Unangekündigte Downtimes oder eine
- kurzfristige Einstellung dieser Seite sind nicht vorgesehen, aber
- möglich. Wer mag, kann auch den
- <a href="https://finalrewind.org/projects/travelynx">Quelltext</a>
- laden und eine eigene Instanz aufsetzen.
+ %= L('landingpage.disclaimer.lead')
+ %= L('landingpage.disclaimer.source-pre')
+ <a href="https://finalrewind.org/projects/travelynx"><%= L('landingpage.disclaimer.source-link') %></a>
+ %= L('landingpage.disclaimer.source-post')
</p>
</div>
</div>
@@ -144,9 +135,9 @@
</div>
<div class="col s10 m10 l6 center-align">
% if (not app->config->{registration}{disabled}) {
- <a href="/register" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">add</i>Registrieren</a>
+ <a href="/register" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">add</i><%= L('button.register') %></a>
% }
- <a href="/login" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">account_circle</i>Anmelden</a>
+ <a href="/login" class="waves-effect waves-light btn"><i class="material-icons left" aria-hidden="true">account_circle</i><%= L('button.login') %></a>
</div>
<div class="col s1 m1 l3">
</div>
diff --git a/templates/language.html.ep b/templates/language.html.ep
new file mode 100644
index 0000000..0d14fe6
--- /dev/null
+++ b/templates/language.html.ep
@@ -0,0 +1,76 @@
+<h1><%= L('language.language') %></h1>
+%= form_for '/account/language' => (method => 'POST') => begin
+ %= csrf_field
+ <div class="row">
+ <div class="input-field col s12">
+ <div>
+ <label>
+ %= radio_button language => 'none'
+ <span>–: <%= L('language.browser-default') %></span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ <div>
+ <label>
+ %= radio_button language => 'de-DE'
+ <span>de-DE: Deutsch (hochdeutsch)</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ <div>
+ <label>
+ %= radio_button language => 'en-GB'
+ <span>en-GB: English (Great Britain)</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ <div>
+ <label>
+ %= radio_button language => 'fr-FR'
+ <span>fr-FR: français</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ <div>
+ <label>
+ %= radio_button language => 'hu-HU'
+ <span>hu-HU: magyar</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="input-field col s12">
+ <div>
+ <label>
+ %= radio_button language => 'pl-PL'
+ <span>pl-PL: Polski</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col s3 m3 l3">
+ </div>
+ <div class="col s6 m6 l6 center-align">
+ <button class="btn waves-effect waves-light" type="submit" name="action" value="save">
+ Speichern
+ <i class="material-icons right">send</i>
+ </button>
+ </div>
+ <div class="col s3 m3 l3">
+ </div>
+ </div>
+%= end
diff --git a/templates/layouts/default.html.ep b/templates/layouts/default.html.ep
index e67f99c..81dfea0 100644
--- a/templates/layouts/default.html.ep
+++ b/templates/layouts/default.html.ep
@@ -13,7 +13,7 @@
% while (my ($key, $value) = each %{stash('opengraph') // {}}) {
<meta property="og:<%= $key %>" content="<%= $value %>">
% }
- % my $av = 'v92'; # asset version
+ % my $av = 'v99'; # asset version
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/static/<%= $av %>/icons/icon-96x96.png" sizes="96x96">
@@ -90,7 +90,7 @@
</div>
</li>
% if ($acc) {
- <li class="<%= navbar_class('/history') %>"><a href='/history' title="Vergangene Zugfahrten"><i class="material-icons" aria-label="Vergangene Zugfahrten">history</i></a></li>
+ <li class="<%= navbar_class('/history') %>"><a href='/history' title="Vergangene Fahrten"><i class="material-icons" aria-label="Vergangene Fahrten">history</i></a></li>
<li class="<%= navbar_class('/account') %>"><a href="/account" title="Account"><i class="material-icons" aria-label="Account"><%= $acc->{notifications} ? 'notifications' : 'account_circle' %></i></a></li>
% }
% else {
@@ -131,21 +131,21 @@
<div class="col s12 center-align grey-text">
<a href="/about">travelynx</a> v<%= $version // '???' %>
<span style="margin-left: 0.5em; margin-right: 0.5em;">–</span>
- <a href="/impressum">Impressum</a>
+ <a href="/impressum"><%= L('footer.imprint') %></a>
<span style="margin-left: 0.5em; margin-right: 0.5em;">–</span>
- <a href="/impressum">Datenschutz</a>
+ <a href="/impressum"><%= L('footer.privacy') %></a>
<span style="margin-left: 0.5em; margin-right: 0.5em;">–</span>
- <a href="/legend">Legende</a>
+ <a href="/legend"><%= L('footer.legend') %></a>
</div>
</div>
<div class="row">
<div class="col s12 center-align grey-text config">
- Farbschema:
- <a onClick="javascript:setTheme('light')">hell</a>
+ <%= L('footer.colour-scheme') %>:
+ <a onClick="javascript:setTheme('light')"><%= L('footer.colour-scheme.light') %></a>
·
- <a onClick="javascript:setTheme('dark')">dunkel</a>
+ <a onClick="javascript:setTheme('dark')"><%= L('footer.colour-scheme.dark') %></a>
·
- <a onClick="javascript:setTheme('default')">automatisch</a>
+ <a onClick="javascript:setTheme('default')"><%= L('footer.colour-scheme.auto') %></a>
</div>
</div>
</div>
diff --git a/templates/login.html.ep b/templates/login.html.ep
index 3a9cc1f..21f14d3 100644
--- a/templates/login.html.ep
+++ b/templates/login.html.ep
@@ -75,7 +75,9 @@
</div>
<div class="row">
<div class="col s12 m12 l12">
- Mit der Anmeldung stimmst du den <a href="/tos">Nutzungsbedingungen</a> zu.
+ %= L('login.accept-tos-pre')
+ <a href="/tos"><%= L('login.tos') %></a>
+ %= L('login.accept-tos-post')
</div>
</div>
<div class="row">
@@ -83,7 +85,7 @@
</div>
<div class="col s6 m6 l6 center-align">
<button class="btn waves-effect waves-light" type="submit" name="action" value="login">
- Anmelden
+ %= L('button.login')
<i class="material-icons right">send</i>
</button>
</div>
@@ -95,7 +97,7 @@
</div>
<div class="col s6 m6 l6 center-align">
<a href="/recover">
- Passwort vergessen
+ %= L('login.forgot-password')
</a>
</div>
<div class="col s3 m3 l3">
@@ -104,7 +106,7 @@
% if (app->config->{registration}{disabled}) {
<div class="row" style="margin-top: 2em;">
<div class="col s12 center-align">
- <em>Diese Instanz erlaubt derzeit keine Registrierung neuer Accounts</em>
+ <em><%= L('login.registration-disabled') %></em>
</div>
</div>
% }
diff --git a/templates/passengerrights.html.ep b/templates/passengerrights.html.ep
index c189657..bf9e5de 100644
--- a/templates/passengerrights.html.ep
+++ b/templates/passengerrights.html.ep
@@ -3,13 +3,13 @@
<div class="col s12">
<p>
Ab 60 Minuten Verspätung am Ziel besteht in einigen Fällen ein
- Entschädigungsanspruch gegenüber dem Eisenbahnverkehrsunternehmen.
+ Entschädigungsanspruch gegenüber dem Verkehrsunternehmen.
Dieser kann mit dem Fahrgastrechteformular oder online geltend
gemacht werden.
</p>
<p>
- Die folgenden Zugfahrten sind wahrscheinliche Kandidaten dafür.
- Details zur jeweiligen Zugfahrt sind bereits im Formular eingetragen.
+ Die folgenden Fahrten sind wahrscheinliche Kandidaten dafür.
+ Details zur jeweiligen Fahrt sind bereits im Formular eingetragen.
</p>
</div>
</div>
@@ -20,7 +20,7 @@
<thead>
<tr>
<th>Datum</th>
- <th>Zug</th>
+ <th>Fahrt</th>
<th>Grund</th>
<th>Formular</th>
</tr>
@@ -79,7 +79,7 @@
<p>
Bei Abo-Tickets besteht teilweise die Möglichkeit, bereits ab 20
Minuten Verspätung Fahrten gesammelt zu Entschädigungszwecken
- einzureichen. Die folgenden Zugfahrten sind Kandidaten dafür.
+ einzureichen. Die folgenden Fahrten sind Kandidaten dafür.
Fahrten mit einer Verspätung von 60 Minuten oder mehr werden hier
nicht aufgeführt.
</p>
@@ -92,7 +92,7 @@
<thead>
<tr>
<th>Datum</th>
- <th>Zug</th>
+ <th>Fahrt</th>
<th>Verspätung</th>
</tr>
</thead>
diff --git a/templates/polyline.gpx.ep b/templates/polyline.gpx.ep
new file mode 100644
index 0000000..a243926
--- /dev/null
+++ b/templates/polyline.gpx.ep
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx
+ xmlns="http://www.topografix.com/GPX/1/1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
+ version="1.1"
+ creator="travelynx <%= $version %>">
+ <trk>
+ <name><%= $name %></name>
+ <trkseg>
+ % for my $entry (@{$polyline // []}) {
+ <trkpt lon="<%= $entry->[0] %>" lat="<%= $entry->[1] %>">
+ % if ($entry->[2]) {
+ <name><%= $entry->[2] %></name>
+ % }
+ </trkpt>
+ % }
+ </trkseg>
+ </trk>
+</gpx>
diff --git a/templates/register.html.ep b/templates/register.html.ep
index f9a486a..e7064da 100644
--- a/templates/register.html.ep
+++ b/templates/register.html.ep
@@ -8,27 +8,29 @@
<div class="input-field col l6 m12 s12">
<i class="material-icons prefix">account_circle</i>
%= text_field 'user', id => 'account', class => 'validate', required => undef, pattern => '[0-9a-zA-Z_-]+', maxlength => 60, autocomplete => 'username'
- <label for="account">Name (alphanumerisch)</label>
+ <label for="account"><%= L('register.name') %></label>
</div>
<div class="input-field col l6 m12 s12">
<i class="material-icons prefix">email</i>
%= email_field 'email', id => 'email', class => 'validate', required => undef, maxlength => 250
- <label for="email">Mail-Adresse</label>
+ <label for="email"><%= L('register.mail') %></label>
</div>
<div class="input-field col l6 m12 s12">
<i class="material-icons prefix">lock</i>
%= password_field 'password', id => 'password', class => 'validate', required => undef, minlength => 8, maxlength => 10000, autocomplete => 'new-password'
- <label for="password">Passwort</label>
+ <label for="password"><%= L('register.password') %></label>
</div>
<div class="input-field col l6 m12 s12">
<i class="material-icons prefix">lock</i>
%= password_field 'password2', id => 'password2', class => 'validate', required => undef, minlength => 8, maxlength => 10000, autocomplete => 'new-password'
- <label for="password2">Passwort wiederholen</label>
+ <label for="password2"><%= L('register.repeat-password') %></label>
</div>
</div>
<div class="row">
<div class="col s12 m12 l12">
- Mit deiner Registrierung stimmst du den <a href="/tos">Nutzungsbedingungen</a> zu.
+ %= L('register.accept-tos-pre')
+ <a href="/tos"><%= L('register.tos') %></a>
+ %= L('register.accept-tos-post')
</div>
</div>
<div class="row">
@@ -36,7 +38,7 @@
</div>
<div class="col s6 m6 l6 center-align">
<button class="btn waves-effect waves-light" type="submit" name="action" value="register">
- Registrieren
+ %= L('button.register')
<i class="material-icons right">send</i>
</button>
</div>
@@ -47,9 +49,7 @@
<div class="row">
<div class="col s12">
<p>
- Nach der Registrierung wird ein für 48 Stunden gültiger
- Bestätigungslink an die angegebene Mail-Adresse geschickt. Eine
- Anmeldung ist erst nach Bestätigung der Mail-Adresse möglich.
+ %= L('register.expect-confirmation-link')
</p>
<p>
Die Mail-Adresse wird ausschließlich zur Bestätigung der Anmeldung,
diff --git a/templates/select_backend.html.ep b/templates/select_backend.html.ep
index e3db44d..999a689 100644
--- a/templates/select_backend.html.ep
+++ b/templates/select_backend.html.ep
@@ -11,6 +11,20 @@
% if (stash('redirect_to')) {
%= hidden_field 'redirect_to' => stash('redirect_to')
% }
+ % if (@{stash('frequent') // []}) {
+ <div class="row">
+ <div class="col s12">
+ <h3>Häufig genutzt</h3>
+ <p style="text-align: justify;">
+ Die folgenden Backends wurden innerhalb der letzten vier
+ Monate für Checkins verwendet.
+ </p>
+ </div>
+ </div>
+ % for my $backend (@{ stash('frequent') // [] }) {
+ %= include '_backend_line', user => $user, backend => $backend
+ % }
+ % }
% if (@{stash('suggestions') // []}) {
<div class="row">
<div class="col s12">