diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 16:36:38 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 16:36:38 +0200 |
| commit | 0b6ae26f3b4c3c8278e569fa6644a544e996c25d (patch) | |
| tree | 6c0e8dd23fa243e6bf7e6473aebae3f13ea20dea /test | |
| parent | e2705119ba718d40ff4f29c00027c2dfecef01ce (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 'test')
| -rw-r--r-- | test/controllers/page_translations_controller_test.rb | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/test/controllers/page_translations_controller_test.rb b/test/controllers/page_translations_controller_test.rb new file mode 100644 index 0000000..d84ac45 --- /dev/null +++ b/test/controllers/page_translations_controller_test.rb | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | require 'test_helper' | ||
| 2 | |||
| 3 | class PageTranslationsControllerTest < ActionController::TestCase | ||
| 4 | test "index lists the default locale's existing translation and flags a missing one" do | ||
| 5 | login_as :quentin | ||
| 6 | node = Node.root.children.create!(:slug => "translations_index_test") | ||
| 7 | node.publish_draft! | ||
| 8 | |||
| 9 | get :index, params: { :node_id => node.id } | ||
| 10 | |||
| 11 | assert_response :success | ||
| 12 | assert_equal [:en], assigns(:translations).map { |t| t[:locale] } | ||
| 13 | assert_equal false, assigns(:translations).first[:exists] | ||
| 14 | end | ||
| 15 | |||
| 16 | test "update creates a first-time translation on a fresh draft, leaving head untouched" do | ||
| 17 | login_as :quentin | ||
| 18 | node = Node.root.children.create!(:slug => "translations_create_test") | ||
| 19 | Globalize.with_locale(:de) { node.draft.update!(:title => "Deutscher Titel") } | ||
| 20 | node.publish_draft! | ||
| 21 | |||
| 22 | patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "English Title" } } | ||
| 23 | |||
| 24 | node.reload | ||
| 25 | assert_not_nil node.draft | ||
| 26 | assert_includes node.draft.translated_locales, :en | ||
| 27 | assert_not_includes node.head.translated_locales, :en | ||
| 28 | end | ||
| 29 | |||
| 30 | test "no route exists for the default locale under the translations resource" do | ||
| 31 | login_as :quentin | ||
| 32 | node = Node.root.children.create!(:slug => "translations_route_constraint_test") | ||
| 33 | |||
| 34 | assert_raises(ActionController::UrlGenerationError) do | ||
| 35 | patch :update, params: { :node_id => node.id, :translation_locale => "de", :page => { :title => "x" } } | ||
| 36 | end | ||
| 37 | end | ||
| 38 | |||
| 39 | test "update with Save + Unlock + Exit unlocks the node and redirects to nodes#show" do | ||
| 40 | login_as :quentin | ||
| 41 | node = Node.root.children.create!(:slug => "translations_exit_test") | ||
| 42 | |||
| 43 | patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "x" }, :commit => "Save + Unlock + Exit" } | ||
| 44 | |||
| 45 | assert_nil node.reload.lock_owner | ||
| 46 | assert_redirected_to node_path(node) | ||
| 47 | end | ||
| 48 | |||
| 49 | test "update saves the translation onto the draft" do | ||
| 50 | login_as :quentin | ||
| 51 | node = Node.root.children.create!(:slug => "translations_update_test") | ||
| 52 | Globalize.with_locale(:en) { node.draft.update!(:title => "Original") } | ||
| 53 | |||
| 54 | patch :update, params: { :node_id => node.id, :translation_locale => "en", :page => { :title => "Revised" } } | ||
| 55 | |||
| 56 | assert_equal "Revised", Globalize.with_locale(:en) { node.draft.reload.title } | ||
| 57 | end | ||
| 58 | |||
| 59 | test "destroy refuses to remove the only remaining translation" do | ||
| 60 | login_as :quentin | ||
| 61 | node = Node.root.children.create!(:slug => "translations_destroy_last_test") | ||
| 62 | Globalize.with_locale(:en) { node.draft.update!(:title => "Only translation") } | ||
| 63 | node.draft.translations.where(:locale => :de).delete_all | ||
| 64 | |||
| 65 | delete :destroy, params: { :node_id => node.id, :translation_locale => "en" } | ||
| 66 | |||
| 67 | assert_equal "Can't remove the only remaining translation.", flash[:error] | ||
| 68 | end | ||
| 69 | |||
| 70 | test "destroy is a safe no-op, not a false success, when the translation doesn't exist" do | ||
| 71 | login_as :quentin | ||
| 72 | node = Node.root.children.create!(:slug => "translations_destroy_missing_test") | ||
| 73 | |||
| 74 | delete :destroy, params: { :node_id => node.id, :translation_locale => "en" } | ||
| 75 | |||
| 76 | assert_match(/No EN translation exists/, flash[:error]) | ||
| 77 | end | ||
| 78 | end | ||
