diff options
| -rw-r--r-- | app/views/nodes/_node_list.html.erb | 16 | ||||
| -rw-r--r-- | app/views/nodes/chapters.html.erb | 4 | ||||
| -rw-r--r-- | app/views/nodes/drafts.html.erb | 2 | ||||
| -rw-r--r-- | app/views/nodes/edit.html.erb | 70 | ||||
| -rw-r--r-- | app/views/nodes/index.html.erb | 16 | ||||
| -rw-r--r-- | app/views/nodes/mine.html.erb | 2 | ||||
| -rw-r--r-- | app/views/nodes/new.html.erb | 24 | ||||
| -rw-r--r-- | app/views/nodes/show.html.erb | 148 | ||||
| -rw-r--r-- | app/views/nodes/sitemap.html.erb | 2 | ||||
| -rw-r--r-- | app/views/nodes/tags.html.erb | 2 | ||||
| -rw-r--r-- | app/views/nodes/trashed.html.erb | 24 | ||||
| -rw-r--r-- | config/locales/de.yml | 171 | ||||
| -rw-r--r-- | config/locales/en.yml | 171 | ||||
| -rw-r--r-- | test/controllers/nodes_controller_test.rb | 7 |
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 | ||
