summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-25 02:23:13 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-25 02:23:13 +0200
commit0a5d7806700bb3154529b99abc75d37ccc46faff (patch)
tree16c4b705d824c83c5887ae7661928c0c4f93c2c3
parent90207029de7474082310d0725801d60f7145fa98 (diff)
Extract admin strings to i18n: the nodes cluster
-rw-r--r--app/views/nodes/_node_list.html.erb16
-rw-r--r--app/views/nodes/chapters.html.erb4
-rw-r--r--app/views/nodes/drafts.html.erb2
-rw-r--r--app/views/nodes/edit.html.erb70
-rw-r--r--app/views/nodes/index.html.erb16
-rw-r--r--app/views/nodes/mine.html.erb2
-rw-r--r--app/views/nodes/new.html.erb24
-rw-r--r--app/views/nodes/show.html.erb148
-rw-r--r--app/views/nodes/sitemap.html.erb2
-rw-r--r--app/views/nodes/tags.html.erb2
-rw-r--r--app/views/nodes/trashed.html.erb24
-rw-r--r--config/locales/de.yml171
-rw-r--r--config/locales/en.yml171
-rw-r--r--test/controllers/nodes_controller_test.rb7
14 files changed, 499 insertions, 160 deletions
diff --git a/app/views/nodes/_node_list.html.erb b/app/views/nodes/_node_list.html.erb
index f7210f12..1e5d0ed9 100644
--- a/app/views/nodes/_node_list.html.erb
+++ b/app/views/nodes/_node_list.html.erb
@@ -3,23 +3,23 @@
3 <%= hidden_field_tag "kinds[]", kind %> 3 <%= hidden_field_tag "kinds[]", kind %>
4 <% end %> 4 <% end %>
5 <%= hidden_field_tag :tags, params[:tags] if params[:tags].present? %> 5 <%= hidden_field_tag :tags, params[:tags] if params[:tags].present? %>
6 <%= text_field_tag :q, params[:q], placeholder: "Search title, abstract, body…" %> 6 <%= text_field_tag :q, params[:q], placeholder: t(".search_placeholder") %>
7 <%= button_tag type: "submit", class: "action_button" do %> 7 <%= button_tag type: "submit", class: "action_button" do %>
8 <%= icon("search", library: "tabler", "aria-hidden": true) %> Search 8 <%= icon("search", library: "tabler", "aria-hidden": true) %> <%= t("admin.common.search") %>
9 <% end %> 9 <% end %>
10 <% if params[:q].present? || params[:kinds].present? || params[:tags].present? %> 10 <% if params[:q].present? || params[:kinds].present? || params[:tags].present? %>
11 <%= link_to "Reset", url_for(controller: params[:controller], action: params[:action]) %> 11 <%= link_to t("admin.common.reset"), url_for(controller: params[:controller], action: params[:action]) %>
12 <% end %> 12 <% end %>
13<% end %> 13<% end %>
14 14
15<%= will_paginate @nodes %> 15<%= will_paginate @nodes %>
16<table class="node_table"> 16<table class="node_table">
17 <tr class="header"> 17 <tr class="header">
18 <th class="node_id">ID</th> 18 <th class="node_id"><%= t("admin.columns.id") %></th>
19 <th class="title">Title</th> 19 <th class="title"><%= t("admin.columns.title") %></th>
20 <th class="actions">Actions</th> 20 <th class="actions"><%= t("admin.columns.actions") %></th>
21 <th class="editor">Locked by</th> 21 <th class="editor"><%= t("admin.columns.locked_by") %></th>
22 <th class="revision">Rev.</th> 22 <th class="revision"><%= t("admin.columns.rev") %></th>
23 </tr> 23 </tr>
24 <% @nodes.each do |node| %> 24 <% @nodes.each do |node| %>
25 <tr class="<%= cycle("even", "odd") %>"> 25 <tr class="<%= cycle("even", "odd") %>">
diff --git a/app/views/nodes/chapters.html.erb b/app/views/nodes/chapters.html.erb
index 543bc53c..def56659 100644
--- a/app/views/nodes/chapters.html.erb
+++ b/app/views/nodes/chapters.html.erb
@@ -1,10 +1,10 @@
1<h1>Chapters</h1> 1<h1><%= t(".title") %></h1>
2 2
3<%= form_tag chapters_nodes_path, method: :get, class: "node_search_form" do %> 3<%= form_tag chapters_nodes_path, method: :get, class: "node_search_form" do %>
4 <label><%= check_box_tag 'kinds[]', 'erfa', @kind_keys.include?('erfa') %> Erfa</label> 4 <label><%= check_box_tag 'kinds[]', 'erfa', @kind_keys.include?('erfa') %> Erfa</label>
5 <label><%= check_box_tag 'kinds[]', 'chaostreff', @kind_keys.include?('chaostreff') %> Chaostreff</label> 5 <label><%= check_box_tag 'kinds[]', 'chaostreff', @kind_keys.include?('chaostreff') %> Chaostreff</label>
6 <%= button_tag type: "submit", class: "action_button" do %> 6 <%= button_tag type: "submit", class: "action_button" do %>
7 <%= icon("filter", library: "tabler", "aria-hidden": true) %> Filter 7 <%= icon("filter", library: "tabler", "aria-hidden": true) %> <%= t(".filter") %>
8 <% end %> 8 <% end %>
9<% end %> 9<% end %>
10 10
diff --git a/app/views/nodes/drafts.html.erb b/app/views/nodes/drafts.html.erb
index 6d0830c9..84ba0e07 100644
--- a/app/views/nodes/drafts.html.erb
+++ b/app/views/nodes/drafts.html.erb
@@ -1,3 +1,3 @@
1<h1>Nodes with drafts or autosaves</h1> 1<h1><%= t(".title") %></h1>
2 2
3<%= render 'node_list' %> 3<%= render 'node_list' %>
diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb
index 4d58e62c..1d07a21e 100644
--- a/app/views/nodes/edit.html.erb
+++ b/app/views/nodes/edit.html.erb
@@ -1,18 +1,18 @@
1<h1><%= title_for_node(@node) %></h1> 1<h1><%= title_for_node(@node) %></h1>
2 2
3<div class="node_action_bar"> 3<div class="node_action_bar">
4 <%= button_to 'Unlock + Back', unlock_node_path(@node), method: :put, 4 <%= button_to t(".unlock_back"), unlock_node_path(@node), method: :put,
5 form: { class: 'button_to state_changing' }, 5 form: { class: 'button_to state_changing' },
6 disabled: @node.autosave.present? %> 6 disabled: @node.autosave.present? %>
7 7
8 <% if @node.autosave || (@node.draft && @node.head) %> 8 <% if @node.autosave || (@node.draft && @node.head) %>
9 <%= button_to revert_node_path(@node), method: :put, 9 <%= button_to revert_node_path(@node), method: :put,
10 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %> 10 form: { data: { confirm: t(".confirm_discard") }, class: 'button_to destructive' } do %>
11 <%= icon("trash", library: "tabler", "aria-hidden": true) %> 11 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
12 <%= @node.draft && !@node.autosave ? "Destroy Draft" : "Discard Autosave" %> 12 <%= @node.draft && !@node.autosave ? t(".destroy_draft") : t(".discard_autosave") %>
13 <% end %> 13 <% end %>
14 <% if pair = @node.available_layer_pairs.find { |p| p.include?(:autosave) } %> 14 <% if pair = @node.available_layer_pairs.find { |p| p.include?(:autosave) } %>
15 <%= button_to 'What changed?', 15 <%= button_to t(".what_changed"),
16 diff_node_revisions_path(@node), 16 diff_node_revisions_path(@node),
17 method: :get, 17 method: :get,
18 params: { start_revision: pair.first, end_revision: pair.last }, 18 params: { start_revision: pair.first, end_revision: pair.last },
@@ -20,9 +20,9 @@
20 <% end %> 20 <% end %>
21 <% end %> 21 <% end %>
22 22
23 <%= submit_tag "Save Draft", form: dom_id(@node, :edit) %> 23 <%= submit_tag t(".save_draft"), form: dom_id(@node, :edit) %>
24 <%= submit_tag "Save + Unlock + Exit", form: dom_id(@node, :edit) %> 24 <%= submit_tag t(".save_unlock_exit"), form: dom_id(@node, :edit) %>
25 <%= link_to "Preview", preview_page_path(@page), target: "_blank", rel: "noopener", class: "preview_link" %> 25 <%= link_to t(".preview"), preview_page_path(@page), target: "_blank", rel: "noopener", class: "preview_link" %>
26</div> 26</div>
27 27
28<div id="admin_layout"> 28<div id="admin_layout">
@@ -37,13 +37,13 @@
37 <div id="edit_grid"> 37 <div id="edit_grid">
38 38
39 <div id="main_fields"> 39 <div id="main_fields">
40 <div class="layout_row_label">Title</div> 40 <div class="layout_row_label"><%= t("admin.columns.title") %></div>
41 <div class="layout_row_content"><%= d.text_field :title %></div> 41 <div class="layout_row_content"><%= d.text_field :title %></div>
42 42
43 <div class="layout_row_label">Abstract</div> 43 <div class="layout_row_label"><%= t(".abstract") %></div>
44 <div class="layout_row_content"><%= d.text_area :abstract %></div> 44 <div class="layout_row_content"><%= d.text_area :abstract %></div>
45 45
46 <div class="layout_row_label">Attachments</div> 46 <div class="layout_row_label"><%= t(".attachments") %></div>
47 <div class="layout_row_content"> 47 <div class="layout_row_content">
48 <div id="related_assets" 48 <div id="related_assets"
49 data-search-url="<%= search_node_related_assets_path(@node) %>" 49 data-search-url="<%= search_node_related_assets_path(@node) %>"
@@ -61,18 +61,18 @@
61 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span> 61 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span>
62 <%= image_tag related.asset.upload.url(:thumb) %> 62 <%= image_tag related.asset.upload.url(:thumb) %>
63 <button type="button" class="related_asset_set_headline" 63 <button type="button" class="related_asset_set_headline"
64 aria-pressed="<%= related.headline? %>" aria-label="Set as headline image" 64 aria-pressed="<%= related.headline? %>" aria-label="<%= t('.set_headline_label') %>"
65 title="Use this photo as the page's headline image"> 65 title="<%= t(".set_headline_title") %>">
66 <%= icon("star", library: "tabler", "aria-hidden": true) %> 66 <%= icon("star", library: "tabler", "aria-hidden": true) %>
67 </button> 67 </button>
68 <button type="button" class="related_asset_remove" aria-label="Remove image"> 68 <button type="button" class="related_asset_remove" aria-label="<%= t('.remove_image_label') %>">
69 <%= icon("x", library: "tabler", "aria-hidden": true) %> 69 <%= icon("x", library: "tabler", "aria-hidden": true) %>
70 </button> 70 </button>
71 </li> 71 </li>
72 <% end %> 72 <% end %>
73 </ul> 73 </ul>
74 <p class="field_hint">The starred image or PDF becomes this page's headline on the public site. If none is starred, visitors get a link to browse all attached images instead.</p> 74 <p class="field_hint"><%= t(".headline_hint") %></p>
75 <%= text_field_tag nil, nil, id: "related_asset_search_term", placeholder: "Search images to attach…", autocomplete: "off" %> 75 <%= text_field_tag nil, nil, id: "related_asset_search_term", placeholder: t(".attach_search_placeholder"), autocomplete: "off" %>
76 <div id="related_asset_search_results" class="search_results"></div> 76 <div id="related_asset_search_results" class="search_results"></div>
77 </div> 77 </div>
78 </div> 78 </div>
@@ -81,10 +81,10 @@
81 <li> 81 <li>
82 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span> 82 <span class="related_asset_handle"><%= icon("grip-vertical", library: "tabler", "aria-hidden": true) %></span>
83 <img src=""> 83 <img src="">
84 <button type="button" class="related_asset_set_headline" aria-pressed="false" aria-label="Set as headline image"> 84 <button type="button" class="related_asset_set_headline" aria-pressed="false" aria-label="<%= t('.set_headline_label') %>">
85 <%= icon("star", library: "tabler", "aria-hidden": true) %> 85 <%= icon("star", library: "tabler", "aria-hidden": true) %>
86 </button> 86 </button>
87 <button type="button" class="related_asset_remove" aria-label="Remove image"> 87 <button type="button" class="related_asset_remove" aria-label="<%= t('.remove_image_label') %>">
88 <%= icon("x", library: "tabler", "aria-hidden": true) %> 88 <%= icon("x", library: "tabler", "aria-hidden": true) %>
89 </button> 89 </button>
90 </li> 90 </li>
@@ -92,9 +92,9 @@
92 </div> 92 </div>
93 93
94 <details id="metadata_details"> 94 <details id="metadata_details">
95 <summary>Metadata (slug, parent, tags, template, author, images)</summary> 95 <summary><%= t(".metadata_summary") %></summary>
96 <div id="metadata"> 96 <div id="metadata">
97 <div class="layout_row_label">Slug</div> 97 <div class="layout_row_label"><%= t(".slug") %></div>
98 <div class="layout_row_content"> 98 <div class="layout_row_content">
99 <%= f.text_field( 99 <%= f.text_field(
100 :staged_slug, :value => @node.staged_slug || @node.slug 100 :staged_slug, :value => @node.staged_slug || @node.slug
@@ -102,10 +102,10 @@
102 %> 102 %>
103 </div> 103 </div>
104 104
105 <div class="layout_row_label">parent</div> 105 <div class="layout_row_label"><%= t(".parent") %></div>
106 <div class="layout_row_content"> 106 <div class="layout_row_content">
107 <%= text_field_tag :move_to_search_term, @node.parent.title rescue "" %> 107 <%= text_field_tag :move_to_search_term, @node.parent.title rescue "" %>
108 <p class="field_hint">Start typing to find a new parent for this node.</p> 108 <p class="field_hint"><%= t(".parent_hint") %></p>
109 <div id="move_to_search_results" class="search_results"></div> 109 <div id="move_to_search_results" class="search_results"></div>
110 <%= f.hidden_field( 110 <%= f.hidden_field(
111 :staged_parent_id, 111 :staged_parent_id,
@@ -114,22 +114,22 @@
114 %> 114 %>
115 </div> 115 </div>
116 116
117 <div class="layout_row_label">Tags</div> 117 <div class="layout_row_label"><%= t(".tags") %></div>
118 <div class="layout_row_content"> 118 <div class="layout_row_content">
119 <%= text_field_tag :tag_list, @page.tag_list.join(', ') %> 119 <%= text_field_tag :tag_list, @page.tag_list.join(', ') %>
120 <span class="field_hint">Comma separated, lowercase.</span> 120 <span class="field_hint"><%= t(".tags_hint") %></span>
121 </div> 121 </div>
122 122
123 <div class="layout_row_label">Publish at</div> 123 <div class="layout_row_label"><%= t(".publish_at") %></div>
124 <div class="layout_row_content"><%= d.datetime_select :published_at, :value => @page.published_at %></div> 124 <div class="layout_row_content"><%= d.datetime_select :published_at, :value => @page.published_at %></div>
125 125
126 <div class="layout_row_label">Template</div> 126 <div class="layout_row_label"><%= t(".template") %></div>
127 <div class="layout_row_content"> 127 <div class="layout_row_content">
128 <%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %> 128 <%= d.select :template_name, custom_page_templates, {:prompt => 'Select Template'} %>
129 <span class="field_hint">Set automatically based on how this node was created - change it if needed.</span> 129 <span class="field_hint"><%= t(".template_hint") %></span>
130 </div> 130 </div>
131 131
132 <div class="layout_row_label">Author</div> 132 <div class="layout_row_label"><%= t(".author") %></div>
133 <div class="layout_row_content"> 133 <div class="layout_row_content">
134 <%= d.select :user_id, user_list, 134 <%= d.select :user_id, user_list,
135 :selected => @page.user_id || @node.draft&.user_id || @node.head&.user_id %> 135 :selected => @page.user_id || @node.draft&.user_id || @node.head&.user_id %>
@@ -139,13 +139,13 @@
139 </details> 139 </details>
140 140
141 <div id="content"> 141 <div id="content">
142 <div class="layout_row_label">Body</div> 142 <div class="layout_row_label"><%= t(".body") %></div>
143 <div class="body_toolbar_row"> 143 <div class="body_toolbar_row">
144 <button type="button" id="preview_toggle" class="view_toggle" aria-pressed="false" aria-label="Toggle live preview" title="Toggle live preview"> 144 <button type="button" id="preview_toggle" class="view_toggle" aria-pressed="false" aria-label="<%= t('admin.common.toggle_preview') %>" title="<%= t('admin.common.toggle_preview') %>">
145 <%= icon("layout-sidebar-right", library: "tabler", "aria-hidden": true) %> <span>Live preview</span> 145 <%= icon("layout-sidebar-right", library: "tabler", "aria-hidden": true) %> <span><%= t(".live_preview") %></span>
146 </button> 146 </button>
147 <button type="button" id="preview_force_render" class="view_toggle" style="display:none" aria-label="Force preview render" title="Force preview render"> 147 <button type="button" id="preview_force_render" class="view_toggle" style="display:none" aria-label="<%= t('admin.common.force_render') %>" title="<%= t('admin.common.force_render') %>">
148 <%= icon("refresh", library: "tabler", "aria-hidden": true) %> <span>Force refresh</span> 148 <%= icon("refresh", library: "tabler", "aria-hidden": true) %> <span><%= t(".force_refresh") %></span>
149 </button> 149 </button>
150 </div> 150 </div>
151 151
@@ -154,7 +154,7 @@
154 <div class="layout_row_content"><%= d.text_area :body, :class => 'with_editor' %></div> 154 <div class="layout_row_content"><%= d.text_area :body, :class => 'with_editor' %></div>
155 </div> 155 </div>
156 <div id="preview_panel" style="display:none"> 156 <div id="preview_panel" style="display:none">
157 <iframe id="live_preview_iframe" title="Live preview" data-src="<%= preview_page_path(@page, :locale => I18n.default_locale) %>"></iframe> 157 <iframe id="live_preview_iframe" title="<%= t('.live_preview') %>" data-src="<%= preview_page_path(@page, :locale => I18n.default_locale) %>"></iframe>
158 </div> 158 </div>
159 </div> 159 </div>
160 </div> 160 </div>
@@ -162,8 +162,8 @@
162 <% end %> 162 <% end %>
163 163
164 <div class="node_action_bar"> 164 <div class="node_action_bar">
165 <%= f.submit 'Save Draft' %> 165 <%= f.submit t(".save_draft") %>
166 <%= f.submit 'Save + Unlock + Exit' %> 166 <%= f.submit t(".save_unlock_exit") %>
167 </div> 167 </div>
168 <% end %> 168 <% end %>
169</div> 169</div>
diff --git a/app/views/nodes/index.html.erb b/app/views/nodes/index.html.erb
index 3bb251c5..7ab5679e 100644
--- a/app/views/nodes/index.html.erb
+++ b/app/views/nodes/index.html.erb
@@ -1,20 +1,20 @@
1<h1>Nodes</h1> 1<h1><%= t(".title") %></h1>
2 2
3<div> 3<div>
4 <%= link_to new_node_path, class: 'action_button' do %> 4 <%= link_to new_node_path, class: 'action_button' do %>
5 <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create node 5 <%= icon("plus", library: "tabler", "aria-hidden": true) %> <%= t(".create_node") %>
6 <% end %> 6 <% end %>
7 <span class="field_hint">Creates a node with no parent or kind set — for a specific page, use the wizard's create flow or "add child" from an existing node instead.</span> 7 <span class="field_hint"><%= t(".create_hint") %></span>
8</div> 8</div>
9 9
10<%= will_paginate @nodes %> 10<%= will_paginate @nodes %>
11 <table class="node_table"> 11 <table class="node_table">
12 <tr class="header"> 12 <tr class="header">
13 <th class="node_id">ID</th> 13 <th class="node_id"><%= t("admin.columns.id") %></th>
14 <th class="title">Title</th> 14 <th class="title"><%= t("admin.columns.title") %></th>
15 <th class="actions">Actions</th> 15 <th class="actions"><%= t("admin.columns.actions") %></th>
16 <th class="editor">Locked by</th> 16 <th class="editor"><%= t("admin.columns.locked_by") %></th>
17 <th class="revision">Rev.</th> 17 <th class="revision"><%= t("admin.columns.rev") %></th>
18 </tr> 18 </tr>
19 <% @nodes.each do |node| %> 19 <% @nodes.each do |node| %>
20 <tr class="<%= cycle("even", "odd") %>"> 20 <tr class="<%= cycle("even", "odd") %>">
diff --git a/app/views/nodes/mine.html.erb b/app/views/nodes/mine.html.erb
index fc5680a9..84ba0e07 100644
--- a/app/views/nodes/mine.html.erb
+++ b/app/views/nodes/mine.html.erb
@@ -1,3 +1,3 @@
1<h1>My work</h1> 1<h1><%= t(".title") %></h1>
2 2
3<%= render 'node_list' %> 3<%= render 'node_list' %>
diff --git a/app/views/nodes/new.html.erb b/app/views/nodes/new.html.erb
index f9efbf50..b56bbeed 100644
--- a/app/views/nodes/new.html.erb
+++ b/app/views/nodes/new.html.erb
@@ -1,4 +1,4 @@
1<h1>Create new node</h1> 1<h1><%= t(".title") %></h1>
2 2
3<% if @node.errors.any? %> 3<% if @node.errors.any? %>
4 <div class="error_messages"> 4 <div class="error_messages">
@@ -9,7 +9,7 @@
9<%= form_tag nodes_path do %> 9<%= form_tag nodes_path do %>
10<div id="new_node"> 10<div id="new_node">
11 11
12 <div class="layout_row_label">Type</div> 12 <div class="layout_row_label"><%= t(".type") %></div>
13 <div class="layout_row_content"> 13 <div class="layout_row_content">
14 <% CccConventions::NODE_KINDS.each do |kind, config| %> 14 <% CccConventions::NODE_KINDS.each do |kind, config| %>
15 <p> 15 <p>
@@ -23,14 +23,14 @@
23 <% end %> 23 <% end %>
24 </div> 24 </div>
25 25
26 <div class="layout_row_label">Title</div> 26 <div class="layout_row_label"><%= t("admin.columns.title") %></div>
27 <div class="layout_row_content"> 27 <div class="layout_row_content">
28 <%= text_field_tag :title, nil, required: true %> 28 <%= text_field_tag :title, nil, required: true %>
29 <span class="field_hint">A URL slug will be generated from this automatically. You can review or adjust it afterward under the "metadata" section's Slug field.</span> 29 <span class="field_hint"><%= t(".slug_hint") %></span>
30 </div> 30 </div>
31 31
32 <div id="parent_search_field" style="<%= @selected_kind == "generic" ? "" : "display: none;" %>"> 32 <div id="parent_search_field" style="<%= @selected_kind == "generic" ? "" : "display: none;" %>">
33 <div class="layout_row_label">Parent</div> 33 <div class="layout_row_label"><%= t(".parent") %></div>
34 <div class="layout_row_content"> 34 <div class="layout_row_content">
35 <%= text_field_tag :parent_search_term, @parent&.title %> 35 <%= text_field_tag :parent_search_term, @parent&.title %>
36 <%= hidden_field_tag :parent_id, @parent&.id, data: { unique_name: @parent&.computed_unique_name } %> 36 <%= hidden_field_tag :parent_id, @parent&.id, data: { unique_name: @parent&.computed_unique_name } %>
@@ -38,18 +38,18 @@
38 </div> 38 </div>
39 </div> 39 </div>
40 40
41 <div class="layout_row_label">Resulting path</div> 41 <div class="layout_row_label"><%= t(".resulting_path") %></div>
42 <div class="layout_row_content"> 42 <div class="layout_row_content">
43 <span id="resulting_path">—</span> 43 <span id="resulting_path">—</span>
44 <button type="button" id="copy_resulting_path" class="unselected copy_button" data-copy-target="#resulting_path"> 44 <button type="button" id="copy_resulting_path" class="unselected copy_button" data-copy-target="#resulting_path">
45 <span class="copy_button_label">copy</span> 45 <span class="copy_button_label"><%= t(".copy") %></span>
46 </button> 46 </button>
47 47
48 <span class="field_hint">This preview updates as you type. The final path can still be changed afterward by editing the title (for the last segment) or moving the node to a different parent (for everything before it).</span> 48 <span class="field_hint"><%= t(".path_hint") %></span>
49 </div> 49 </div>
50 50
51 <% if @attach_asset %> 51 <% if @attach_asset %>
52 <div class="layout_row_label">attachment</div> 52 <div class="layout_row_label"><%= t(".attachment") %></div>
53 <div class="layout_row_content"> 53 <div class="layout_row_content">
54 <ul class="thumbnail_list"> 54 <ul class="thumbnail_list">
55 <li> 55 <li>
@@ -60,14 +60,14 @@
60 :target => "_blank", :rel => "noopener" %> 60 :target => "_blank", :rel => "noopener" %>
61 </li> 61 </li>
62 </ul> 62 </ul>
63 <span class="field_hint">This asset will automatically be attached to the new page.</span> 63 <span class="field_hint"><%= t(".attach_hint") %></span>
64 <label><%= check_box_tag :asset_headline, "1" %> as the page's headline</label> 64 <label><%= check_box_tag :asset_headline, "1" %> <%= t(".as_headline") %></label>
65 <%= hidden_field_tag :asset_id, @attach_asset.id %> 65 <%= hidden_field_tag :asset_id, @attach_asset.id %>
66 </div> 66 </div>
67 <% end %> 67 <% end %>
68 68
69 <div class="layout_row_label"></div> 69 <div class="layout_row_label"></div>
70 <div class="layout_row_content"><%= submit_tag "Create" %></div> 70 <div class="layout_row_content"><%= submit_tag t("admin.common.create") %></div>
71 71
72</div> 72</div>
73<% end %> 73<% end %>
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb
index e37f5034..a337b555 100644
--- a/app/views/nodes/show.html.erb
+++ b/app/views/nodes/show.html.erb
@@ -2,24 +2,24 @@
2<div id="admin_layout" class="show_node"> 2<div id="admin_layout" class="show_node">
3 <h1><%= title_for_node(@node) %> <small>(<%= I18n.default_locale.to_s.upcase %>)</small></h1> 3 <h1><%= title_for_node(@node) %> <small>(<%= I18n.default_locale.to_s.upcase %>)</small></h1>
4 <div id="content"> 4 <div id="content">
5 <div class="layout_row_label">Status</div> 5 <div class="layout_row_label"><%= t(".status") %></div>
6 <div class="layout_row_content info_group node_status"> 6 <div class="layout_row_content info_group node_status">
7 <div class="info_group_items"> 7 <div class="info_group_items">
8 <div class="info_item"> 8 <div class="info_item">
9 <span class="info_label">Head</span> 9 <span class="info_label"><%= t(".head") %></span>
10 <%= @node.head ? "#{@node.head.title} (rev #{@node.head.revision}, #{@node.head.updated_at})" : "none — never published" %> 10 <%= @node.head ? t(".head_line", :title => @node.head.title, :rev => @node.head.revision, :time => @node.head.updated_at) : t(".never_published") %>
11 </div> 11 </div>
12 <div class="info_item"> 12 <div class="info_item">
13 <span class="info_label">Draft</span> 13 <span class="info_label"><%= t(".draft") %></span>
14 <%= @node.draft ? "#{@node.draft.title} (rev #{@node.draft.revision}, saved #{@node.draft.updated_at})" : "none" %> 14 <%= @node.draft ? t(".draft_line", :title => @node.draft.title, :rev => @node.draft.revision, :time => @node.draft.updated_at) : t(".none") %>
15 </div> 15 </div>
16 <div class="info_item"> 16 <div class="info_item">
17 <span class="info_label">Autosave</span> 17 <span class="info_label"><%= t(".autosave") %></span>
18 <%= @node.autosave ? "#{@node.autosave.title} (unsaved, #{@node.autosave.updated_at})" : "none" %> 18 <%= @node.autosave ? t(".autosave_line", :title => @node.autosave.title, :time => @node.autosave.updated_at) : t(".none") %>
19 </div> 19 </div>
20 </div> 20 </div>
21 21
22 <% edit_label = @node.autosave ? "Continue Editing" : (@node.draft ? "Edit Draft" : "Edit") %> 22 <% edit_label = @node.autosave ? t(".continue_editing") : (@node.draft ? t(".edit_draft") : t(".lock_edit")) %>
23 <div class="info_group_items"> 23 <div class="info_group_items">
24 <div class="info_item"> 24 <div class="info_item">
25 <% if locked_by_other %> 25 <% if locked_by_other %>
@@ -27,17 +27,17 @@
27 <% else %> 27 <% else %>
28 <%= link_to edit_node_path(@node), class: "action_button" do %> 28 <%= link_to edit_node_path(@node), class: "action_button" do %>
29 <%= icon("edit", library: "tabler", "aria-hidden": true) %> 29 <%= icon("edit", library: "tabler", "aria-hidden": true) %>
30 <%= @node.autosave ? "Continue Editing" : (@node.draft ? "Edit Draft" : "Lock + Edit") %> 30 <%= edit_label %>
31 <% end %> 31 <% end %>
32 <% if !@node.draft && !@node.autosave %> 32 <% if !@node.draft && !@node.autosave %>
33 <span class="field_hint">Nothing pending — this will start a fresh draft.</span> 33 <span class="field_hint"><%= t(".fresh_draft_hint") %></span>
34 <% end %> 34 <% end %>
35 <% end %> 35 <% end %>
36 </div> 36 </div>
37 37
38 <% @node.available_layer_pairs.each do |pair| %> 38 <% @node.available_layer_pairs.each do |pair| %>
39 <div class="info_item"> 39 <div class="info_item">
40 <%= button_to "Diff #{pair.first.to_s.capitalize} vs. #{pair.last.to_s.capitalize}", 40 <%= button_to t(".diff_layers", :from => t(".layer_#{pair.first}"), :to => t(".layer_#{pair.last}")),
41 diff_node_revisions_path(@node), 41 diff_node_revisions_path(@node),
42 method: :get, 42 method: :get,
43 params: { start_revision: pair.first, end_revision: pair.last }, 43 params: { start_revision: pair.first, end_revision: pair.last },
@@ -48,26 +48,26 @@
48 <% unless locked_by_other %> 48 <% unless locked_by_other %>
49 <% if @node.draft && !@node.autosave && !@node.in_trash? && !@node.trash_node? %> 49 <% if @node.draft && !@node.autosave && !@node.in_trash? && !@node.trash_node? %>
50 <div class="info_item"> 50 <div class="info_item">
51 <%= button_to 'Publish', publish_node_path(@node), method: :put, 51 <%= button_to t(".publish"), publish_node_path(@node), method: :put,
52 form: { data: { confirm: "Publish this draft?" }, class: 'button_to state_changing' } %> 52 form: { data: { confirm: t(".confirm_publish") }, class: 'button_to state_changing' } %>
53 </div> 53 </div>
54 <% end %> 54 <% end %>
55 <% if @node.autosave || (@node.draft && @node.head) %> 55 <% if @node.autosave || (@node.draft && @node.head) %>
56 <div class="info_item"> 56 <div class="info_item">
57 <%= button_to revert_node_path(@node), method: :put, 57 <%= button_to revert_node_path(@node), method: :put,
58 params: { return_to: request.path }, 58 params: { return_to: request.path },
59 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %> 59 form: { data: { confirm: t("admin.common.confirm_irreversible") }, class: 'button_to destructive' } do %>
60 <%= icon("trash", library: "tabler", "aria-hidden": true) %> 60 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
61 <%= @node.draft && !@node.autosave ? "Destroy Draft" : "Discard Autosave" %> 61 <%= @node.draft && !@node.autosave ? t(".destroy_draft") : t(".discard_autosave") %>
62 <% end %> 62 <% end %>
63 </div> 63 </div>
64 <% end %> 64 <% end %>
65 <% unless @node.trash_node? || @node.in_trash? || @node.root? %> 65 <% unless @node.trash_node? || @node.in_trash? || @node.root? %>
66 <div class="info_item"> 66 <div class="info_item">
67 <%= button_to trash_node_path(@node), method: :put, 67 <%= button_to trash_node_path(@node), method: :put,
68 form: { data: { confirm: "Move this page and everything beneath it to the Trash? All published content in it will go offline." }, class: 'button_to destructive' } do %> 68 form: { data: { confirm: t(".confirm_trash") }, class: 'button_to destructive' } do %>
69 <%= icon("trash", library: "tabler", "aria-hidden": true) %> 69 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
70 Move to Trash 70 <%= t(".move_to_trash") %>
71 <% end %> 71 <% end %>
72 </div> 72 </div>
73 <% end %> 73 <% end %>
@@ -75,79 +75,77 @@
75 </div> 75 </div>
76 76
77 <% if locked_by_other %> 77 <% if locked_by_other %>
78 <span class="field_hint">Locked — see People below to unlock before editing, publishing, or discarding.</span> 78 <span class="field_hint"><%= t(".locked_hint") %></span>
79 <% end %> 79 <% end %>
80 </div> 80 </div>
81 81
82 <% if @node.in_trash? %> 82 <% if @node.in_trash? %>
83 <div class="layout_row_label">Trash</div> 83 <div class="layout_row_label"><%= t(".trash") %></div>
84 <div class="layout_row_content info_group"> 84 <div class="layout_row_content info_group">
85 <div class="info_group_items"> 85 <div class="info_group_items">
86 <% if (entry = @node.last_trash_entry) && entry.metadata.dig("path", "from") %> 86 <% if (entry = @node.last_trash_entry) && entry.metadata.dig("path", "from") %>
87 <div class="info_item"> 87 <div class="info_item">
88 <span class="info_label">Was at</span> 88 <span class="info_label"><%= t(".was_at") %></span>
89 <%= entry.metadata.dig("path", "from") %> 89 <%= entry.metadata.dig("path", "from") %>
90 </div> 90 </div>
91 <% end %> 91 <% end %>
92 <div class="info_item"> 92 <div class="info_item">
93 <span class="info_label">Restore to</span> 93 <span class="info_label"><%= t(".restore_to") %></span>
94 <% suggestion = @node.suggested_restore_parent %> 94 <% suggestion = @node.suggested_restore_parent %>
95 <%= form_tag restore_from_trash_node_path(@node), :method => :put, :class => "aligned_action_row" do %> 95 <%= form_tag restore_from_trash_node_path(@node), :method => :put, :class => "aligned_action_row" do %>
96 <div class="restore_picker"> 96 <div class="restore_picker">
97 <%= text_field_tag :restore_search_term, 97 <%= text_field_tag :restore_search_term,
98 suggestion && (suggestion.head&.title || suggestion.draft&.title || suggestion.slug), 98 suggestion && (suggestion.head&.title || suggestion.draft&.title || suggestion.slug),
99 :placeholder => "Search for a new parent…" %> 99 :placeholder => t(".restore_placeholder") %>
100 <div id="restore_search_results" class="search_results"></div> 100 <div id="restore_search_results" class="search_results"></div>
101 </div> 101 </div>
102 <%= hidden_field_tag :parent_id, suggestion&.id %> 102 <%= hidden_field_tag :parent_id, suggestion&.id %>
103 <%= submit_tag "Restore here", :class => "action_button action_button_no_margin_top" %> 103 <%= submit_tag t(".restore_here"), :class => "action_button action_button_no_margin_top" %>
104 <% end %> 104 <% end %>
105 <span class="field_hint">Restored pages come back unpublished. Republish each page deliberately.</span> 105 <span class="field_hint"><%= t(".restore_hint") %></span>
106 </div> 106 </div>
107 </div> 107 </div>
108 <div class="info_group_items"> 108 <div class="info_group_items">
109 <div class="info_item"> 109 <div class="info_item">
110 <% doomed_below = @node.descendants.count %> 110 <% doomed_below = @node.descendants.count %>
111 <%= button_to node_path(@node), method: :delete, 111 <%= button_to node_path(@node), method: :delete,
112 form: { data: { confirm: doomed_below > 0 ? 112 form: { data: { confirm: t(".confirm_delete", :count => doomed_below) },
113 "Delete this page and the #{doomed_below} pages beneath it permanently? This cannot be undone." :
114 "Delete this page permanently? This cannot be undone." },
115 class: 'button_to destructive' } do %> 113 class: 'button_to destructive' } do %>
116 <%= icon("trash-x", library: "tabler", "aria-hidden": true) %> 114 <%= icon("trash-x", library: "tabler", "aria-hidden": true) %>
117 Delete permanently<%= " (including #{doomed_below} beneath)" if doomed_below > 0 %> 115 <%= t(".delete_permanently") %><%= " " + t(".including_beneath", :count => doomed_below) if doomed_below > 0 %>
118 <% end %> 116 <% end %>
119 </div> 117 </div>
120 </div> 118 </div>
121 </div> 119 </div>
122 <% end %> 120 <% end %>
123 121
124 <div class="layout_row_label">Translations</div> 122 <div class="layout_row_label"><%= t(".translations") %></div>
125 <div class="layout_row_content info_group"> 123 <div class="layout_row_content info_group">
126 <div class="info_group_items"> 124 <div class="info_group_items">
127 <% @translations.each do |t| %> 125 <% @translations.each do |translation| %>
128 <div class="info_item"> 126 <div class="info_item">
129 <span class="info_label"><%= t[:locale].to_s.upcase %></span> 127 <span class="info_label"><%= translation[:locale].to_s.upcase %></span>
130 <div class="aligned_action_row"> 128 <div class="aligned_action_row">
131 <% if t[:exists] %> 129 <% if translation[:exists] %>
132 <%= link_to t[:title], node_translation_path(@node, t[:locale]) %> — updated <%= t[:updated_at] %> 130 <%= link_to translation[:title], node_translation_path(@node, translation[:locale]) %> <%= t(".updated", :time => translation[:updated_at]) %>
133 <% if t[:outdated] %> 131 <% if translation[:outdated] %>
134 <span class="warning">may be outdated</span> 132 <span class="warning"><%= t(".may_be_outdated") %></span>
135 <% end %> 133 <% end %>
136 <% else %> 134 <% else %>
137 <span class="field_hint">Not yet translated.</span> 135 <span class="field_hint"><%= t(".not_yet_translated") %></span>
138 <% end %> 136 <% end %>
139 <% if locked_by_other %> 137 <% if locked_by_other %>
140 <span class="disabled_action"><%= t[:exists] ? "Lock + Edit" : "Create translation + Lock" %></span> 138 <span class="disabled_action"><%= translation[:exists] ? t(".lock_edit") : t(".create_translation") %></span>
141 <% else %> 139 <% else %>
142 <%= link_to edit_node_translation_path(@node, t[:locale]), class: "action_button" do %> 140 <%= link_to edit_node_translation_path(@node, translation[:locale]), class: "action_button" do %>
143 <%= icon(t[:exists] ? "edit" : "language", library: "tabler", "aria-hidden": true) %> 141 <%= icon(translation[:exists] ? "edit" : "language", library: "tabler", "aria-hidden": true) %>
144 <%= t[:exists] ? "Lock + Edit" : "Create translation + Lock" %> 142 <%= translation[:exists] ? t(".lock_edit") : t(".create_translation") %>
145 <% end %> 143 <% end %>
146 <% if t[:exists] %> 144 <% if translation[:exists] %>
147 <%= button_to node_translation_path(@node, t[:locale]), method: :delete, 145 <%= button_to node_translation_path(@node, translation[:locale]), method: :delete,
148 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %> 146 form: { data: { confirm: t("admin.common.confirm_irreversible") }, class: 'button_to destructive' } do %>
149 <%= icon("trash", library: "tabler", "aria-hidden": true) %> 147 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
150 Destroy Translation 148 <%= t(".destroy_translation") %>
151 <% end %> 149 <% end %>
152 <% end %> 150 <% end %>
153 <% end %> 151 <% end %>
@@ -157,20 +155,20 @@
157 </div> 155 </div>
158 </div> 156 </div>
159 157
160 <div class="layout_row_label">People</div> 158 <div class="layout_row_label"><%= t(".people") %></div>
161 <div class="layout_row_content info_group"> 159 <div class="layout_row_content info_group">
162 <div class="info_group_items"> 160 <div class="info_group_items">
163 <div class="info_item"> 161 <div class="info_item">
164 <span class="info_label">Author</span> 162 <span class="info_label"><%= t(".author") %></span>
165 <%= @page.user.try(:login) %> 163 <%= @page.user.try(:login) %>
166 </div> 164 </div>
167 <div class="info_item"> 165 <div class="info_item">
168 <span class="info_label">Editor</span> 166 <span class="info_label"><%= t(".editor") %></span>
169 <%= @page.editor.try(:login) %> 167 <%= @page.editor.try(:login) %>
170 </div> 168 </div>
171 <% if @node.locked? %> 169 <% if @node.locked? %>
172 <div class="info_item"> 170 <div class="info_item">
173 <span class="info_label">Locked by</span> 171 <span class="info_label"><%= t("admin.columns.locked_by") %></span>
174 <span class="warning"><%= @node.lock_owner.login %></span> 172 <span class="warning"><%= @node.lock_owner.login %></span>
175 <%= unlock_link %> 173 <%= unlock_link %>
176 </div> 174 </div>
@@ -178,54 +176,54 @@
178 </div> 176 </div>
179 </div> 177 </div>
180 178
181 <div class="layout_row_label">Dates</div> 179 <div class="layout_row_label"><%= t(".dates") %></div>
182 <div class="layout_row_content info_group"> 180 <div class="layout_row_content info_group">
183 <div class="info_group_items"> 181 <div class="info_group_items">
184 <div class="info_item"> 182 <div class="info_item">
185 <span class="info_label">Last updated</span> 183 <span class="info_label"><%= t(".last_updated") %></span>
186 <%= @page.updated_at %> 184 <%= @page.updated_at %>
187 </div> 185 </div>
188 <% if @page.published_at.present? %> 186 <% if @page.published_at.present? %>
189 <div class="info_item"> 187 <div class="info_item">
190 <span class="info_label"><%= @page.public? ? 'Published at' : 'Will publish at' %></span> 188 <span class="info_label"><%= @page.public? ? t(".published_at") : t(".will_publish_at") %></span>
191 <%= @page.published_at %> 189 <%= @page.published_at %>
192 </div> 190 </div>
193 <% end %> 191 <% end %>
194 </div> 192 </div>
195 </div> 193 </div>
196 194
197 <div class="layout_row_label">Links</div> 195 <div class="layout_row_label"><%= t(".links") %></div>
198 <div class="layout_row_content info_group"> 196 <div class="layout_row_content info_group">
199 <div class="info_group_items"> 197 <div class="info_group_items">
200 <div class="info_item"> 198 <div class="info_item">
201 <span class="info_label">Public</span> 199 <span class="info_label"><%= t(".public") %></span>
202 <%= link_to @page.public_link, content_url(@node.unique_path) %> 200 <%= link_to @page.public_link, content_url(@node.unique_path) %>
203 </div> 201 </div>
204 <% if @node.draft %> 202 <% if @node.draft %>
205 <div class="info_item"> 203 <div class="info_item">
206 <span class="info_label">Admin Preview</span> 204 <span class="info_label"><%= t(".admin_preview") %></span>
207 <%= link_to preview_page_path(@node.draft), preview_page_path(@node.draft) %> 205 <%= link_to preview_page_path(@node.draft), preview_page_path(@node.draft) %>
208 </div> 206 </div>
209 <div class="info_item"> 207 <div class="info_item">
210 <span class="info_label">Public Preview</span> 208 <span class="info_label"><%= t(".public_preview") %></span>
211 <% if @node.draft.preview_token.present? %> 209 <% if @node.draft.preview_token.present? %>
212 <div class="aligned_action_row"> 210 <div class="aligned_action_row">
213 <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %> 211 <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %>
214 <%= button_to 'Revoke', revoke_shared_preview_node_path(@node), method: :put, form: { data: { confirm: "Revoke this preview link? Anyone currently using it will immediately lose access." }, class: 'button_to state_changing' } %> 212 <%= button_to t(".revoke"), revoke_shared_preview_node_path(@node), method: :put, form: { data: { confirm: t(".confirm_revoke") }, class: 'button_to state_changing' } %>
215 </div> 213 </div>
216 <% else %> 214 <% else %>
217 <%= button_to 'Create public preview link', generate_shared_preview_node_path(@node), method: :put, form: { class: 'button_to state_changing' } %> 215 <%= button_to t(".create_preview_link"), generate_shared_preview_node_path(@node), method: :put, form: { class: 'button_to state_changing' } %>
218 <% end %> 216 <% end %>
219 </div> 217 </div>
220 <% end %> 218 <% end %>
221 </div> 219 </div>
222 </div> 220 </div>
223 221
224 <div class="layout_row_label">History</div> 222 <div class="layout_row_label"><%= t(".history") %></div>
225 <div class="layout_row_content info_group"> 223 <div class="layout_row_content info_group">
226 <details> 224 <details>
227 <summary> 225 <summary>
228 <%= pluralize(@node.pages.count, 'published revision', 'published revisions') %> 226 <%= t(".published_revisions", :count => @node.pages.count) %>
229 </summary> 227 </summary>
230 <ul> 228 <ul>
231 <% @node.pages.order(:revision).each do |page| %> 229 <% @node.pages.order(:revision).each do |page| %>
@@ -236,11 +234,11 @@
236 <% end %> 234 <% end %>
237 </ul> 235 </ul>
238 </details> 236 </details>
239 <p class="revisions_full_history_link"><%= link_to 'Revision history (diff / restore)', node_revisions_path(@node) %> | <%= link_to t("node_actions.heading"), admin_log_path(:node_id => @node.id) %></p> 237 <p class="revisions_full_history_link"><%= link_to t(".revision_history"), node_revisions_path(@node) %> | <%= link_to t("node_actions.heading"), admin_log_path(:node_id => @node.id) %></p>
240 </div> 238 </div>
241 239
242 240
243 <div class="layout_row_label">Tags</div> 241 <div class="layout_row_label"><%= t(".tags") %></div>
244 <div class="layout_row_content info_group"> 242 <div class="layout_row_content info_group">
245 <% if @page.tag_list.any? %> 243 <% if @page.tag_list.any? %>
246 <ul class="tag_pill_list"> 244 <ul class="tag_pill_list">
@@ -249,11 +247,11 @@
249 <% end %> 247 <% end %>
250 </ul> 248 </ul>
251 <% else %> 249 <% else %>
252 <span class="field_hint">No tags.</span> 250 <span class="field_hint"><%= t(".no_tags") %></span>
253 <% end %> 251 <% end %>
254 </div> 252 </div>
255 253
256 <div class="layout_row_label">Attachments</div> 254 <div class="layout_row_label"><%= t(".attachments") %></div>
257 <div class="layout_row_content info_group"> 255 <div class="layout_row_content info_group">
258 <% if @page.assets.any? %> 256 <% if @page.assets.any? %>
259 <% headline_asset_id = @page.headline_asset&.id %> 257 <% headline_asset_id = @page.headline_asset&.id %>
@@ -262,7 +260,7 @@
262 <li class="<%= "is_headline" if asset.id == headline_asset_id %>"> 260 <li class="<%= "is_headline" if asset.id == headline_asset_id %>">
263 <%= link_to image_tag(asset.upload.url(:thumb)), asset_path(asset) %> 261 <%= link_to image_tag(asset.upload.url(:thumb)), asset_path(asset) %>
264 <% if asset.id == headline_asset_id %> 262 <% if asset.id == headline_asset_id %>
265 <span class="headline_indicator" title="This page's headline image"> 263 <span class="headline_indicator" title="<%= t('.headline_title')%>">
266 <%= icon("star", library: "tabler", "aria-hidden": true) %> 264 <%= icon("star", library: "tabler", "aria-hidden": true) %>
267 </span> 265 </span>
268 <% end %> 266 <% end %>
@@ -272,38 +270,38 @@
272 <% end %> 270 <% end %>
273 <p class="add_attachments"> 271 <p class="add_attachments">
274 <%= link_to new_asset_path(:node_id => @node.id), class: 'action_button' do %> 272 <%= link_to new_asset_path(:node_id => @node.id), class: 'action_button' do %>
275 <%= icon("paperclip", library: "tabler", "aria-hidden": true) %> Upload new attachment 273 <%= icon("paperclip", library: "tabler", "aria-hidden": true) %> <%= t(".upload_attachment") %>
276 <% end %> 274 <% end %>
277 <span class="field_hint">To add or remove existing attachments, edit this node instead.</span> 275 <span class="field_hint"><%= t(".attachments_hint") %></span>
278 </p> 276 </p>
279 </div> 277 </div>
280 278
281 <div class="layout_row_label">Events</div> 279 <div class="layout_row_label"><%= t(".events") %></div>
282 <div class="layout_row_content info_group"> 280 <div class="layout_row_content info_group">
283 <ul> 281 <ul>
284 <% @node.events.order(:start_time).each do |event| %> 282 <% @node.events.order(:start_time).each do |event| %>
285 <li> 283 <li>
286 <%= event_schedule_text(event) %> 284 <%= event_schedule_text(event) %>
287 [<%= link_to 'show', event_path(event, return_to: request.path) %> 285 [<%= link_to t(".show_link"), event_path(event, return_to: request.path) %>
288 | <%= link_to 'edit', edit_event_path(event, return_to: request.path) %>] 286 | <%= link_to t(".edit_link"), edit_event_path(event, return_to: request.path) %>]
289 </li> 287 </li>
290 <% end %> 288 <% end %>
291 </ul> 289 </ul>
292 <% mapping = default_event_tag_mapping(@page) %> 290 <% mapping = default_event_tag_mapping(@page) %>
293 <p class="add_events"> 291 <p class="add_events">
294 <%= link_to new_event_path(node_id: @node.id, tag_list: mapping&.last, auto_tag_source: mapping&.first, return_to: request.path), class: 'action_button' do %> 292 <%= link_to new_event_path(node_id: @node.id, tag_list: mapping&.last, auto_tag_source: mapping&.first, return_to: request.path), class: 'action_button' do %>
295 <%= icon("calendar-plus", library: "tabler", "aria-hidden": true) %> Add event 293 <%= icon("calendar-plus", library: "tabler", "aria-hidden": true) %> <%= t(".add_event") %>
296 <% end %> 294 <% end %>
297 </p> 295 </p>
298 </div> 296 </div>
299 297
300 <% matches = matching_node_kinds(@node) %> 298 <% matches = matching_node_kinds(@node) %>
301 <% if @node.children.any? || matches.any? %> 299 <% if @node.children.any? || matches.any? %>
302 <div class="layout_row_label">Children</div> 300 <div class="layout_row_label"><%= t(".children") %></div>
303 <div class="layout_row_content info_group"> 301 <div class="layout_row_content info_group">
304 <% if @node.children.any? %> 302 <% if @node.children.any? %>
305 <details> 303 <details>
306 <summary><%= pluralize(@node.children.count, 'child', 'children') %></summary> 304 <summary><%= t(".children_count", :count => @node.children.count) %></summary>
307 <ul> 305 <ul>
308 <% @node.children.order(:slug).each do |child| %> 306 <% @node.children.order(:slug).each do |child| %>
309 <li><%= link_to (child.head&.title || child.draft&.title || child.slug), node_path(child) %></li> 307 <li><%= link_to (child.head&.title || child.draft&.title || child.slug), node_path(child) %></li>
@@ -317,7 +315,7 @@
317 <% link_params = { kind: kind } %> 315 <% link_params = { kind: kind } %>
318 <% link_params[:parent_id] = @node.id if kind == "generic" %> 316 <% link_params[:parent_id] = @node.id if kind == "generic" %>
319 <%= link_to new_node_path(link_params), class: 'action_button' do %> 317 <%= link_to new_node_path(link_params), class: 'action_button' do %>
320 <%= icon("text-plus", library: "tabler", "aria-hidden": true) %> Add child type <%= resolve_kind_text(config[:label]) %> 318 <%= icon("text-plus", library: "tabler", "aria-hidden": true) %> <%= t(".add_child", :kind => resolve_kind_text(config[:label])) %>
321 <% end %> 319 <% end %>
322 <% end %> 320 <% end %>
323 </p> 321 </p>
@@ -325,10 +323,10 @@
325 </div> 323 </div>
326 <% end %> 324 <% end %>
327 325
328 <div class="layout_row_label">Abstract (<%= I18n.default_locale.to_s.upcase %>)</div> 326 <div class="layout_row_label"><%= t(".abstract_locale", :lang => I18n.default_locale.to_s.upcase) %></div>
329 <div class="layout_row_content"><%= sanitize(@page.abstract) %></div> 327 <div class="layout_row_content"><%= sanitize(@page.abstract) %></div>
330 328
331 <div class="layout_row_label">Body (<%= I18n.default_locale.to_s.upcase %>)</div> 329 <div class="layout_row_label"><%= t(".body_locale", :lang => I18n.default_locale.to_s.upcase) %></div>
332 <div class="layout_row_content"><%= sanitize(@page.body) %></div> 330 <div class="layout_row_content"><%= sanitize(@page.body) %></div>
333 331
334 </div> 332 </div>
diff --git a/app/views/nodes/sitemap.html.erb b/app/views/nodes/sitemap.html.erb
index a799c179..f749a803 100644
--- a/app/views/nodes/sitemap.html.erb
+++ b/app/views/nodes/sitemap.html.erb
@@ -1,4 +1,4 @@
1<h1>Sitemap</h1> 1<h1><%= t(".title") %></h1>
2 2
3<div id="sitemap"> 3<div id="sitemap">
4<% 4<%
diff --git a/app/views/nodes/tags.html.erb b/app/views/nodes/tags.html.erb
index 0ebc6ce6..7cf7386c 100644
--- a/app/views/nodes/tags.html.erb
+++ b/app/views/nodes/tags.html.erb
@@ -1,3 +1,3 @@
1<h1>Nodes tagged: <%= params[:tags] %></h1> 1<h1><%= t(".title", :tag => params[:tags]) %></h1>
2 2
3<%= render 'node_list' %> 3<%= render 'node_list' %>
diff --git a/app/views/nodes/trashed.html.erb b/app/views/nodes/trashed.html.erb
index 9a4808e6..a3c2cf41 100644
--- a/app/views/nodes/trashed.html.erb
+++ b/app/views/nodes/trashed.html.erb
@@ -1,42 +1,40 @@
1<h1>Trash</h1> 1<h1><%= t(".title") %></h1>
2 2
3<% if @nodes.empty? %> 3<% if @nodes.empty? %>
4 <p class="field_hint">The Trash is empty.</p> 4 <p class="field_hint"><%= t(".empty") %></p>
5<% else %> 5<% else %>
6 <%= will_paginate @nodes %> 6 <%= will_paginate @nodes %>
7 <table id="trashed_node_list"> 7 <table id="trashed_node_list">
8 <tr> 8 <tr>
9 <th>Title</th> 9 <th><%= t("admin.columns.title") %></th>
10 <th>Was at</th> 10 <th><%= t(".was_at") %></th>
11 <th>Trashed</th> 11 <th><%= t(".trashed") %></th>
12 <th>Actions</th> 12 <th><%= t("admin.columns.actions") %></th>
13 </tr> 13 </tr>
14 <% @nodes.each do |node| %> 14 <% @nodes.each do |node| %>
15 <% entry = node.last_trash_entry %> 15 <% entry = node.last_trash_entry %>
16 <tr> 16 <tr>
17 <% doomed_below = node.descendants.count %> 17 <% doomed_below = node.descendants.count %>
18 <td> 18 <td>
19 <%= link_to (node.draft&.title || node.slug), node_path(node) %><%= " (+ #{doomed_below} beneath)" if doomed_below > 0 %> 19 <%= link_to (node.draft&.title || node.slug), node_path(node) %><%= " " + t(".beneath", :count => doomed_below) if doomed_below > 0 %>
20 </td> 20 </td>
21 <td><%= entry&.metadata&.dig("path", "from") %></td> 21 <td><%= entry&.metadata&.dig("path", "from") %></td>
22 <td> 22 <td>
23 <% if entry %> 23 <% if entry %>
24 <%= entry.occurred_at.strftime("%Y-%m-%d %H:%M") %> by <%= entry.actor_name %> 24 <%= t(".trashed_by", :time => entry.occurred_at.strftime("%Y-%m-%d %H:%M"), :actor => entry.actor_name) %>
25 <% end %> 25 <% end %>
26 </td> 26 </td>
27 <td> 27 <td>
28 <%= button_to node_path(node), method: :delete, 28 <%= button_to node_path(node), method: :delete,
29 form: { data: { confirm: doomed_below > 0 ? 29 form: { data: { confirm: t(".confirm_delete", :title => (node.draft&.title || node.slug), :count => doomed_below) },
30 "Delete \"#{node.draft&.title || node.slug}\" and the #{doomed_below} pages beneath it permanently? This cannot be undone." :
31 "Delete \"#{node.draft&.title || node.slug}\" permanently? This cannot be undone." },
32 class: 'button_to destructive' } do %> 30 class: 'button_to destructive' } do %>
33 <%= icon("trash-x", library: "tabler", "aria-hidden": true) %> 31 <%= icon("trash-x", library: "tabler", "aria-hidden": true) %>
34 Delete permanently 32 <%= t(".delete_permanently") %>
35 <% end %> 33 <% end %>
36 </td> 34 </td>
37 </tr> 35 </tr>
38 <% end %> 36 <% end %>
39 </table> 37 </table>
40 <%= will_paginate @nodes %> 38 <%= will_paginate @nodes %>
41 <p class="field_hint">To restore a page, open it and pick a new parent in its Trash section.</p> 39 <p class="field_hint"><%= t(".restore_hint") %></p>
42<% end %> 40<% end %>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 7d49a872..3be58e54 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -187,3 +187,174 @@ de:
187 disable_second_factor: "Zweiten Faktor entfernen" 187 disable_second_factor: "Zweiten Faktor entfernen"
188 reset_second_factor: "Zweiten Faktor zurücksetzen" 188 reset_second_factor: "Zweiten Faktor zurücksetzen"
189 reset_confirm: "Zweiten Faktor von %{login} zurücksetzen? Die Anmeldung ist danach nur mit Passwort möglich." 189 reset_confirm: "Zweiten Faktor von %{login} zurücksetzen? Die Anmeldung ist danach nur mit Passwort möglich."
190
191 admin:
192 common:
193 create: "Anlegen"
194 edit: "Bearbeiten"
195 destroy: "Löschen"
196 search: "Suchen"
197 reset: "Zurücksetzen"
198 confirm_irreversible: "Das kann nicht rückgängig gemacht werden. Fortfahren?"
199 toggle_preview: "Live-Vorschau umschalten"
200 force_render: "Vorschau neu rendern"
201 columns:
202 id: "ID"
203 title: "Titel"
204 actions: "Aktionen"
205 locked_by: "Gesperrt von"
206 rev: "Rev."
207 path: "Pfad"
208 nodes:
209 index:
210 title: "Nodes"
211 create_node: "Node anlegen"
212 create_hint: "Legt einen Node ohne Eltern-Node und Art an. Für eine konkrete Seite besser den Anlege-Dialog oder \"Kind hinzufügen\" an einem bestehenden Node verwenden."
213 new:
214 title: "Neuen Node anlegen"
215 type: "Art"
216 slug_hint: "Der URL-Slug wird daraus automatisch erzeugt. Er lässt sich danach im Abschnitt \"Metadata\" unter Slug prüfen und anpassen."
217 parent: "Eltern-Node"
218 resulting_path: "Kompletter Pfad"
219 copy: "kopieren"
220 path_hint: "Diese Vorschau aktualisiert sich beim Tippen. Der endgültige Pfad lässt sich später ändern: über den Titel (letztes Segment) oder durch Verschieben unter einen anderen Eltern-Nodes (alles davor)."
221 attachment: "Anhang"
222 attach_hint: "Dieses Asset wird der neuen Seite automatisch angehängt."
223 as_headline: "als Aufmacher der Seite"
224 edit:
225 save_draft: "Entwurf speichern"
226 save_unlock_exit: "Speichern + Entsperren + Verlassen"
227 preview: "Vorschau ↗"
228 abstract: "Abstract"
229 attachments: "Anhänge"
230 headline_hint: "Das markierte Bild oder PDF wird der Aufmacher dieser Seite auf der öffentlichen Website. Ist nichts markiert, bekommen Besucher stattdessen einen Link auf alle angehängten Bilder."
231 metadata_summary: "Metadaten (Slug, Eltern-Node, Tags, Template, Autor, Bilder)"
232 slug: "Slug"
233 parent: "Eltern-Node"
234 parent_hint: "Tippen, um einen neuen Eltern-Node für diesen Node zu finden."
235 tags: "Tags"
236 tags_hint: "Kommagetrennt, Kleinschreibung."
237 publish_at: "Veröffentlichen am"
238 template: "Template"
239 template_hint: "Wird beim Anlegen automatisch gesetzt — bei Bedarf ändern."
240 author: "Autor"
241 body: "Text"
242 live_preview: "Live-Vorschau"
243 force_refresh: "Neu laden"
244 unlock_back: "Entsperren + Zurück"
245 what_changed: "Was hat sich geändert?"
246 confirm_discard: "Das kann nicht rückgängig gemacht werden. Fortfahren?"
247 destroy_draft: "Entwurf löschen"
248 discard_autosave: "Autosave verwerfen"
249 attach_search_placeholder: "Bilder zum Anhängen suchen…"
250 set_headline_label: "Als Aufmacherbild setzen"
251 set_headline_title: "Dieses Foto als Aufmacherbild der Seite verwenden"
252 remove_image_label: "Bild entfernen"
253 show:
254 status: "Status"
255 head: "Head"
256 draft: "Entwurf"
257 autosave: "Autosave"
258 head_line: "%{title} (Rev %{rev}, %{time})"
259 draft_line: "%{title} (Rev %{rev}, gespeichert %{time})"
260 autosave_line: "%{title} (ungespeichert, %{time})"
261 never_published: "keine — nie veröffentlicht"
262 none: "keine"
263 continue_editing: "Weiter bearbeiten"
264 edit_draft: "Entwurf bearbeiten"
265 lock_edit: "Sperren + Bearbeiten"
266 fresh_draft_hint: "Nichts offen — hier beginnt ein neuer Entwurf."
267 diff_layers: "Diff %{from} vs. %{to}"
268 layer_head: "Head"
269 layer_draft: "Entwurf"
270 layer_autosave: "Autosave"
271 publish: "Veröffentlichen"
272 confirm_publish: "Diesen Entwurf veröffentlichen?"
273 destroy_draft: "Entwurf löschen"
274 discard_autosave: "Autosave verwerfen"
275 confirm_trash: "Diese Seite und alles darunter in den Papierkorb verschieben? Alle veröffentlichten Inhalte darin gehen offline."
276 move_to_trash: "In den Papierkorb"
277 locked_hint: "Gesperrt — zum Bearbeiten, Veröffentlichen oder Verwerfen erst unter Personen entsperren."
278 trash: "Papierkorb"
279 was_at: "War unter"
280 restore_to: "Wiederherstellen nach"
281 restore_placeholder: "Neuen Eltern-Node suchen…"
282 restore_here: "Hierhin wiederherstellen"
283 restore_hint: "Wiederhergestellte Seiten kommen unveröffentlicht zurück. Jede (Unter-)Seite muss einzeln neu veröffentlicht werden."
284 confirm_delete:
285 one: "Diese Seite endgültig löschen? Das kann nicht rückgängig gemacht werden."
286 other: "Diese Seite und die %{count} Seiten darunter endgültig löschen? Das kann nicht rückgängig gemacht werden."
287 delete_permanently: "Endgültig löschen"
288 including_beneath:
289 one: "(inkl. 1 darunter)"
290 other: "(inkl. %{count} darunter)"
291 translations: "Übersetzungen"
292 updated: "— aktualisiert %{time}"
293 may_be_outdated: "womöglich veraltet"
294 not_yet_translated: "Noch nicht übersetzt."
295 create_translation: "Übersetzung anlegen + Sperren"
296 destroy_translation: "Übersetzung löschen"
297 people: "Personen"
298 author: "Autor"
299 editor: "Editor"
300 dates: "Daten"
301 last_updated: "Zuletzt geändert"
302 published_at: "Veröffentlicht am"
303 will_publish_at: "Wird veröffentlicht am"
304 links: "Links"
305 public: "Öffentlich"
306 admin_preview: "Admin-Vorschau"
307 public_preview: "Öffentliche Vorschau"
308 revoke: "Zurückziehen"
309 confirm_revoke: "Diesen Vorschau-Link zurückziehen? Wer ihn gerade nutzt, verliert sofort den Zugriff."
310 create_preview_link: "Öffentlichen Vorschau-Link erzeugen"
311 history: "Verlauf"
312 published_revisions:
313 one: "1 veröffentlichte Revision"
314 other: "%{count} veröffentlichte Revisionen"
315 revision_history: "Revisionsübersicht (Diff / Wiederherstellen)"
316 tags: "Tags"
317 no_tags: "Keine Tags."
318 attachments: "Anhänge"
319 headline_title: "Aufmacherbild dieser Seite"
320 upload_attachment: "Neuen Anhang hochladen"
321 attachments_hint: "Zum Hinzufügen oder Entfernen bestehender Anhänge diesen Node bearbeiten."
322 events: "Termine"
323 show_link: "anzeigen"
324 edit_link: "bearbeiten"
325 add_event: "Termin hinzufügen"
326 children: "Kinder"
327 children_count:
328 one: "1 Kind"
329 other: "%{count} Kinder"
330 add_child: "Kind vom Typ %{kind} anlegen"
331 abstract_locale: "Abstract (%{lang})"
332 body_locale: "Text (%{lang})"
333 drafts:
334 title: "Nodes mit Entwürfen oder Autosaves"
335 mine:
336 title: "Meine Arbeit"
337 tags:
338 title: "Nodes mit Tag: %{tag}"
339 sitemap:
340 title: "Sitemap"
341 chapters:
342 title: "Chapters"
343 filter: "Filter"
344 node_list:
345 search_placeholder: "Titel, Abstract, Text durchsuchen…"
346 trashed:
347 title: "Papierkorb"
348 empty: "Der Papierkorb ist leer."
349 was_at: "War unter"
350 trashed: "Gelöscht"
351 beneath:
352 one: "(+ 1 darunter)"
353 other: "(+ %{count} darunter)"
354 trashed_by: "%{time} von %{actor}"
355 confirm_delete:
356 zero: "\"%{title}\" endgültig löschen? Das kann nicht rückgängig gemacht werden."
357 one: "\"%{title}\" und die 1 Seite darunter endgültig löschen? Das kann nicht rückgängig gemacht werden."
358 other: "\"%{title}\" und die %{count} Seiten darunter endgültig löschen? Das kann nicht rückgängig gemacht werden."
359 delete_permanently: "Endgültig löschen"
360 restore_hint: "Zum Wiederherstellen eine Seite öffnen und in ihrem Papierkorb-Abschnitt einen neuen Eltern-Node wählen."
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ea94952a..a15c7dd9 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -139,3 +139,174 @@ en:
139 disable_second_factor: "Disable second factor" 139 disable_second_factor: "Disable second factor"
140 reset_second_factor: "Reset second factor" 140 reset_second_factor: "Reset second factor"
141 reset_confirm: "Reset %{login}'s second factor? They will log in with password only afterwards." 141 reset_confirm: "Reset %{login}'s second factor? They will log in with password only afterwards."
142
143 admin:
144 common:
145 create: "Create"
146 edit: "Edit"
147 destroy: "Destroy"
148 search: "Search"
149 reset: "Reset"
150 confirm_irreversible: "This cannot be undone. Continue?"
151 toggle_preview: "Toggle live preview"
152 force_render: "Force preview render"
153 columns:
154 id: "ID"
155 title: "Title"
156 actions: "Actions"
157 locked_by: "Locked by"
158 rev: "Rev."
159 path: "Path"
160 nodes:
161 index:
162 title: "Nodes"
163 create_node: "Create node"
164 create_hint: "Creates a node with no parent or kind set — for a specific page, use the wizard's create flow or \"add child\" from an existing node instead."
165 new:
166 title: "Create new node"
167 type: "Type"
168 slug_hint: "A URL slug will be generated from this automatically. You can review or adjust it afterward under the \"metadata\" section's Slug field."
169 parent: "Parent"
170 resulting_path: "Resulting path"
171 copy: "copy"
172 path_hint: "This preview updates as you type. The final path can still be changed afterward by editing the title (for the last segment) or moving the node to a different parent (for everything before it)."
173 attachment: "attachment"
174 attach_hint: "This asset will automatically be attached to the new page."
175 as_headline: "as the page's headline"
176 edit:
177 save_draft: "Save Draft"
178 save_unlock_exit: "Save + Unlock + Exit"
179 preview: "Preview ↗"
180 abstract: "Abstract"
181 attachments: "Attachments"
182 headline_hint: "The starred image or PDF becomes this page's headline on the public site. If none is starred, visitors get a link to browse all attached images instead."
183 metadata_summary: "Metadata (slug, parent, tags, template, author, images)"
184 slug: "Slug"
185 parent: "parent"
186 parent_hint: "Start typing to find a new parent for this node."
187 tags: "Tags"
188 tags_hint: "Comma separated, lowercase."
189 publish_at: "Publish at"
190 template: "Template"
191 template_hint: "Set automatically based on how this node was created - change it if needed."
192 author: "Author"
193 body: "Body"
194 live_preview: "Live preview"
195 force_refresh: "Force refresh"
196 unlock_back: "Unlock + Back"
197 what_changed: "What changed?"
198 confirm_discard: "This cannot be undone. Continue?"
199 destroy_draft: "Destroy Draft"
200 discard_autosave: "Discard Autosave"
201 attach_search_placeholder: "Search images to attach…"
202 set_headline_label: "Set as headline image"
203 set_headline_title: "Use this photo as the page's headline image"
204 remove_image_label: "Remove image"
205 show:
206 status: "Status"
207 head: "Head"
208 draft: "Draft"
209 autosave: "Autosave"
210 head_line: "%{title} (rev %{rev}, %{time})"
211 draft_line: "%{title} (rev %{rev}, saved %{time})"
212 autosave_line: "%{title} (unsaved, %{time})"
213 never_published: "none — never published"
214 none: "none"
215 continue_editing: "Continue Editing"
216 edit_draft: "Edit Draft"
217 lock_edit: "Lock + Edit"
218 fresh_draft_hint: "Nothing pending — this will start a fresh draft."
219 diff_layers: "Diff %{from} vs. %{to}"
220 layer_head: "Head"
221 layer_draft: "Draft"
222 layer_autosave: "Autosave"
223 publish: "Publish"
224 confirm_publish: "Publish this draft?"
225 destroy_draft: "Destroy Draft"
226 discard_autosave: "Discard Autosave"
227 confirm_trash: "Move this page and everything beneath it to the Trash? All published content in it will go offline."
228 move_to_trash: "Move to Trash"
229 locked_hint: "Locked — see People below to unlock before editing, publishing, or discarding."
230 trash: "Trash"
231 was_at: "Was at"
232 restore_to: "Restore to"
233 restore_placeholder: "Search for a new parent…"
234 restore_here: "Restore here"
235 restore_hint: "Restored pages come back unpublished. Republish each page deliberately."
236 confirm_delete:
237 one: "Delete this page permanently? This cannot be undone."
238 other: "Delete this page and the %{count} pages beneath it permanently? This cannot be undone."
239 delete_permanently: "Delete permanently"
240 including_beneath:
241 one: "(including 1 beneath)"
242 other: "(including %{count} beneath)"
243 translations: "Translations"
244 updated: "— updated %{time}"
245 may_be_outdated: "may be outdated"
246 not_yet_translated: "Not yet translated."
247 create_translation: "Create translation + Lock"
248 destroy_translation: "Destroy Translation"
249 people: "People"
250 author: "Author"
251 editor: "Editor"
252 dates: "Dates"
253 last_updated: "Last updated"
254 published_at: "Published at"
255 will_publish_at: "Will publish at"
256 links: "Links"
257 public: "Public"
258 admin_preview: "Admin Preview"
259 public_preview: "Public Preview"
260 revoke: "Revoke"
261 confirm_revoke: "Revoke this preview link? Anyone currently using it will immediately lose access."
262 create_preview_link: "Create public preview link"
263 history: "History"
264 published_revisions:
265 one: "1 published revision"
266 other: "%{count} published revisions"
267 revision_history: "Revision history (diff / restore)"
268 tags: "Tags"
269 no_tags: "No tags."
270 attachments: "Attachments"
271 headline_title: "This page's headline image"
272 upload_attachment: "Upload new attachment"
273 attachments_hint: "To add or remove existing attachments, edit this node instead."
274 events: "Events"
275 show_link: "show"
276 edit_link: "edit"
277 add_event: "Add event"
278 children: "Children"
279 children_count:
280 one: "1 child"
281 other: "%{count} children"
282 add_child: "Add child type %{kind}"
283 abstract_locale: "Abstract (%{lang})"
284 body_locale: "Body (%{lang})"
285 drafts:
286 title: "Nodes with drafts or autosaves"
287 mine:
288 title: "My work"
289 tags:
290 title: "Nodes tagged: %{tag}"
291 sitemap:
292 title: "Sitemap"
293 chapters:
294 title: "Chapters"
295 filter: "Filter"
296 node_list:
297 search_placeholder: "Search title, abstract, body…"
298 trashed:
299 title: "Trash"
300 empty: "The Trash is empty."
301 was_at: "Was at"
302 trashed: "Trashed"
303 beneath:
304 one: "(+ 1 beneath)"
305 other: "(+ %{count} beneath)"
306 trashed_by: "%{time} by %{actor}"
307 confirm_delete:
308 zero: "Delete \"%{title}\" permanently? This cannot be undone."
309 one: "Delete \"%{title}\" and the 1 page beneath it permanently? This cannot be undone."
310 other: "Delete \"%{title}\" and the %{count} pages beneath it permanently? This cannot be undone."
311 delete_permanently: "Delete permanently"
312 restore_hint: "To restore a page, open it and pick a new parent in its Trash section."
diff --git a/test/controllers/nodes_controller_test.rb b/test/controllers/nodes_controller_test.rb
index de536278..8b59fc37 100644
--- a/test/controllers/nodes_controller_test.rb
+++ b/test/controllers/nodes_controller_test.rb
@@ -438,7 +438,8 @@ class NodesControllerTest < ActionController::TestCase
438 438
439 get :show, params: { id: node.id } 439 get :show, params: { id: node.id }
440 assert_response :success 440 assert_response :success
441 assert_select "a", text: "Add event" 441 assert_select "a", text: I18n.t("nodes.show.add_event")
442
442 assert_select "a[href*='tag_list=open-day']" 443 assert_select "a[href*='tag_list=open-day']"
443 assert_select "a[href*='auto_tag_source=erfa-detail']" 444 assert_select "a[href*='auto_tag_source=erfa-detail']"
444 end 445 end
@@ -449,7 +450,7 @@ class NodesControllerTest < ActionController::TestCase
449 450
450 get :show, params: { id: node.id } 451 get :show, params: { id: node.id }
451 assert_response :success 452 assert_response :success
452 assert_select "a", text: "Add event" 453 assert_select "a", text: I18n.t("nodes.show.add_event")
453 assert_select "a[href*='tag_list=']", count: 0 454 assert_select "a[href*='tag_list=']", count: 0
454 end 455 end
455 456
@@ -600,7 +601,7 @@ class NodesControllerTest < ActionController::TestCase
600 assert_includes assigns(:nodes), presse_node 601 assert_includes assigns(:nodes), presse_node
601 assert_not_includes assigns(:nodes), erfa_node 602 assert_not_includes assigns(:nodes), erfa_node
602 603
603 assert_select "h1", "Nodes tagged: pressemitteilung" 604 assert_select "h1", :text => I18n.t("nodes.tags.title", :tag => "pressemitteilung"), :count => 1
604 assert_select "h1", :text => "Chapters", :count => 0 605 assert_select "h1", :text => "Chapters", :count => 0
605 end 606 end
606 607