summaryrefslogtreecommitdiff
path: root/app/views/nodes
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-13 16:36:38 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-13 16:36:38 +0200
commit0b6ae26f3b4c3c8278e569fa6644a544e996c25d (patch)
tree6c0e8dd23fa243e6bf7e6473aebae3f13ea20dea /app/views/nodes
parente2705119ba718d40ff4f29c00027c2dfecef01ce (diff)
Add per-node translation management: list, edit, destroy, compare
Replaces the old locale-switch-and-edit-the-same-screen workflow, which conflated presentation locale with content locale and let an editor silently drift into editing the wrong language with no persistent signal that anything had changed. Non-default-locale content now has its own explicit routes and screens, never sharing a route param with the ambient chrome locale. - PageTranslationsController: index/show/edit/update/destroy, scoped to Page.non_default_locales; update handles first-time creation too, so there's no separate new/create step. - Reads go through the actual PageTranslation row (Page#translation_summary), never through the Globalize fallback-bearing accessor -- fallback is correct for public rendering but wrong for editing, where a missing translation needs to look empty, not borrowed from another locale. - Translations ride on the page's own draft/head cycle; no independent publish state. - nodes#show gains a Translations section (per-locale Lock+Edit / Create+Lock, Destroy, a link into the read-only Compare view) and a locale indicator on its own default-locale content; nodes#edit, nodes#update, and nodes#autosave are pinned to the default locale via Globalize.with_locale regardless of the ambient route locale. - nodes#show no longer double-loads the node or calls wipe_draft! on every view (see previous commit for why that's now safe). - .preview_link_row is renamed .aligned_action_row now that it has a second real consumer.
Diffstat (limited to 'app/views/nodes')
-rw-r--r--app/views/nodes/show.html.erb49
1 files changed, 44 insertions, 5 deletions
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb
index 54bb38f..e6a922b 100644
--- a/app/views/nodes/show.html.erb
+++ b/app/views/nodes/show.html.erb
@@ -1,6 +1,6 @@
1<% locked_by_other = @node.locked? && @node.lock_owner != current_user %> 1<% locked_by_other = @node.locked? && @node.lock_owner != current_user %>
2<div id="page_editor" class="show_node"> 2<div id="page_editor" class="show_node">
3 <h1><%= title_for_node(@node) %></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="node_description">Status</div> 5 <div class="node_description">Status</div>
6 <div class="node_content node_info_group node_status"> 6 <div class="node_content node_info_group node_status">
@@ -70,6 +70,46 @@
70 <% end %> 70 <% end %>
71 </div> 71 </div>
72 72
73 <div class="node_description">Translations</div>
74 <div class="node_content node_info_group">
75 <div class="node_info_group_items">
76 <div class="node_info_item">
77 <span class="node_info_label"><%= I18n.default_locale.to_s.upcase %> (default)</span>
78 <%= @page.title %> — updated <%= @default_translation&.updated_at || @page.updated_at %>
79 </div>
80 <% @translations.each do |t| %>
81 <div class="node_info_item">
82 <span class="node_info_label"><%= t[:locale].to_s.upcase %></span>
83 <div class="aligned_action_row">
84 <% if t[:exists] %>
85 <%= link_to t[:title], node_translation_path(@node, t[:locale]) %> — updated <%= t[:updated_at] %>
86 <% if t[:outdated] %>
87 <span class="warning">may be outdated</span>
88 <% end %>
89 <% else %>
90 <span class="field_hint">Not yet translated.</span>
91 <% end %>
92 <% if locked_by_other %>
93 <span class="disabled_action"><%= t[:exists] ? "Lock + Edit" : "Create translation + Lock" %></span>
94 <% else %>
95 <%= link_to edit_node_translation_path(@node, t[:locale]), class: "action_button" do %>
96 <%= icon(t[:exists] ? "edit" : "language", library: "tabler", "aria-hidden": true) %>
97 <%= t[:exists] ? "Lock + Edit" : "Create translation + Lock" %>
98 <% end %>
99 <% if t[:exists] %>
100 <%= button_to node_translation_path(@node, t[:locale]), method: :delete,
101 form: { data: { confirm: "This cannot be undone. Continue?" }, class: 'button_to destructive' } do %>
102 <%= icon("trash", library: "tabler", "aria-hidden": true) %>
103 Destroy Translation
104 <% end %>
105 <% end %>
106 <% end %>
107 </div>
108 </div>
109 <% end %>
110 </div>
111 </div>
112
73 <div class="node_description">People</div> 113 <div class="node_description">People</div>
74 <div class="node_content node_info_group"> 114 <div class="node_content node_info_group">
75 <div class="node_info_group_items"> 115 <div class="node_info_group_items">
@@ -122,7 +162,7 @@
122 <div class="node_info_item"> 162 <div class="node_info_item">
123 <span class="node_info_label">Public Preview</span> 163 <span class="node_info_label">Public Preview</span>
124 <% if @node.draft.preview_token.present? %> 164 <% if @node.draft.preview_token.present? %>
125 <div class="preview_link_row"> 165 <div class="aligned_action_row">
126 <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %> 166 <%= link_to shared_preview_path(token: @node.draft.preview_token), shared_preview_url(token: @node.draft.preview_token), target: "_blank", rel: "noopener" %>
127 <%= 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' } %> 167 <%= 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' } %>
128 </div> 168 </div>
@@ -205,12 +245,11 @@
205 </div> 245 </div>
206 <% end %> 246 <% end %>
207 247
208 <div class="node_description">Abstract</div> 248 <div class="node_description">Abstract (<%= I18n.default_locale.to_s.upcase %>)</div>
209 <div class="node_content"><%= sanitize(@page.abstract) %></div> 249 <div class="node_content"><%= sanitize(@page.abstract) %></div>
210 250
211 <div class="node_description">Body</div> 251 <div class="node_description">Body (<%= I18n.default_locale.to_s.upcase %>)</div>
212 <div class="node_content"><%= sanitize(@page.body) %></div> 252 <div class="node_content"><%= sanitize(@page.body) %></div>
213 <%# Assets not yet addressed - no confirmed model/association seen for this page's attached assets %>
214 253
215 </div> 254 </div>
216</div> 255</div>