From baace1fa5df46694ddd515dc3bbca59b22df8692 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Sat, 25 Jul 2026 03:51:44 +0200 Subject: Extract flashes to i18n and stop dispatching on submit labels --- app/controllers/application_controller.rb | 2 +- app/controllers/assets_controller.rb | 12 ++--- app/controllers/events_controller.rb | 6 +-- app/controllers/nodes_controller.rb | 45 ++++++++-------- app/controllers/occurrences_controller.rb | 4 +- app/controllers/otp_challenges_controller.rb | 6 +-- app/controllers/otp_enrollments_controller.rb | 11 ++-- app/controllers/page_translations_controller.rb | 14 ++--- app/controllers/revisions_controller.rb | 4 +- app/controllers/sessions_controller.rb | 8 +-- app/controllers/users_controller.rb | 8 +-- app/views/nodes/edit.html.erb | 4 +- app/views/page_translations/edit.html.erb | 2 +- config/locales/de.yml | 62 ++++++++++++++++++++++ config/locales/en.yml | 62 ++++++++++++++++++++++ test/controllers/assets_controller_test.rb | 2 +- test/controllers/events_controller_test.rb | 2 +- test/controllers/nodes_controller_test.rb | 10 ++-- .../page_translations_controller_test.rb | 4 +- test/controllers/users_controller_test.rb | 18 +++---- 20 files changed, 205 insertions(+), 81 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6d46d522..0a7ba109 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -40,7 +40,7 @@ class ApplicationController < ActionController::Base return unless logged_in? return unless current_user.otp_required? && !current_user.otp_enrolled? return if %w[otp_enrollments otp_challenges sessions users].include?(controller_name) - flash[:error] = "Your account requires a second factor -- set it up to continue." + flash[:error] = t("flash.common.otp_required") redirect_to edit_user_path(current_user) end end diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb index 7edd9c05..f1c259e3 100644 --- a/app/controllers/assets_controller.rb +++ b/app/controllers/assets_controller.rb @@ -49,7 +49,7 @@ class AssetsController < ApplicationController respond_to do |format| if @asset.save - flash[:notice] = 'Asset was successfully created.' + flash[:notice] = t("flash.assets.created") NodeAction.record!(:participants => [@asset], :user => current_user, :action => "asset_create", :asset_name => @asset.name, @@ -72,7 +72,7 @@ class AssetsController < ApplicationController respond_to do |format| if @asset.update(asset_params) - flash[:notice] = 'Asset was successfully updated.' + flash[:notice] = t("flash.assets.updated") format.html { redirect_to(@asset) } format.xml { head :ok } else @@ -105,14 +105,14 @@ class AssetsController < ApplicationController :headline => params[:headline].present?) flash[:notice] = if result[:attached].zero? - "Asset saved — it was already attached to “#{node.title}”." + t("flash.assets.already_attached", :title => node.title) else - "Asset was successfully created and attached to “#{node.title}”." + t("flash.assets.attached", :title => node.title) end case result[:headline] - when :set then flash[:notice] += " It is now the page's headline." + when :set then flash[:notice] += " " + t("flash.common.now_headline") when :kept_existing then flash[:headline_kept_path] = node_path(node) - when :not_eligible then flash[:error] = "This asset type cannot be a headline." + when :not_eligible then flash[:error] = t("flash.common.headline_ineligible") end rescue LockedByAnotherUser flash[:locked_by] = node.lock_owner&.login diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index be3f5476..f2c710bd 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -43,7 +43,7 @@ class EventsController < ApplicationController ) if params[:tag_list].present? && params[:auto_tag_source].present? - flash.now[:notice] = "Tag '#{params[:tag_list]}' was pre-filled because this page is tagged '#{params[:auto_tag_source]}'. You can remove it below." + flash.now[:notice] = t("flash.events.tag_prefilled", :tag => params[:tag_list], :source => params[:auto_tag_source]) end respond_to do |format| @@ -65,7 +65,7 @@ class EventsController < ApplicationController respond_to do |format| if @event.save - flash[:notice] = 'Event was successfully created.' + flash[:notice] = t("flash.events.created") format.html { redirect_to(safe_return_to(params[:return_to] || (@event.node ? edit_node_path(@event.node) : edit_event_path(@event)))) } format.xml { render :xml => @event, :status => :created, :location => @event } else @@ -82,7 +82,7 @@ class EventsController < ApplicationController respond_to do |format| if @event.update(event_params) - flash[:notice] = 'Event was successfully updated.' + flash[:notice] = t("flash.events.updated") format.html { redirect_to(safe_return_to(params[:return_to] || events_path)) } format.xml { head :ok } else diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb index ce8f0538..50b30881 100644 --- a/app/controllers/nodes_controller.rb +++ b/app/controllers/nodes_controller.rb @@ -55,9 +55,9 @@ class NodesController < ApplicationController if params[:asset_id].present? && (asset = Asset.find(params[:asset_id])) result = @node.attach_asset!(asset, :user => current_user, :headline => params[:asset_headline].present?) - flash[:notice] = "Page created with “#{asset.name}” attached." - flash[:notice] += " It is the page's headline." if result[:headline] == :set - flash[:error] = "This asset type cannot be a headline." if result[:headline] == :not_eligible + flash[:notice] = t("flash.nodes.created_with_attachment", :name => asset.name) + flash[:notice] += " " + t("flash.common.now_headline") if result[:headline] == :set + flash[:error] = t("flash.common.headline_ineligible") if result[:headline] == :not_eligible end redirect_to(edit_node_path(@node)) @@ -83,14 +83,12 @@ class NodesController < ApplicationController @page = @node.autosave || @node.draft || @node.head if @node.autosave - flash.now[:notice] = - "This page has unsaved changes from a previous session, shown below. " \ - "Save to keep them, or use \"Discard Autosave\" below to go back to the last saved version." + flash.now[:notice] = t("flash.nodes.autosave_banner") elsif freshly_locked - flash.now[:notice] ||= "Node locked and ready to edit" + flash.now[:notice] ||= t("flash.nodes.locked_ready") end rescue LockedByAnotherUser => e - flash[:error] = e.message + flash[:error] = t("flash.common.locked_by_other") redirect_to(request.referer || node_path(@node)) end @@ -99,7 +97,7 @@ class NodesController < ApplicationController @node.autosave!( page_params.merge(:tag_list => params[:tag_list]), current_user ) @node.save_draft!(current_user) - flash[:notice] = "Draft saved. Publish your changes in the Status section once you're done." + flash[:notice] = t("flash.nodes.draft_saved") flash[:status_path] = node_path(@node) if @node.draft.translated_locales.size > 1 @@ -112,7 +110,7 @@ class NodesController < ApplicationController end end - if params[:commit] == "Save + Unlock + Exit" + if params[:unlock_exit].present? @node.unlock! redirect_to node_path(@node) else @@ -156,13 +154,16 @@ class NodesController < ApplicationController def trash if @node.trash!(current_user) - flash[:notice] = "Page has been moved to the Trash" + flash[:notice] = t("flash.nodes.trashed") redirect_to trashed_nodes_path else - flash[:notice] = "Page is already in the Trash" + flash[:notice] = t("flash.nodes.already_trashed") redirect_to node_path(@node) end - rescue ActiveRecord::RecordInvalid, LockedByAnotherUser => e + rescue LockedByAnotherUser + flash[:error] = t("flash.common.locked_by_other") + redirect_to node_path(@node) + rescue ActiveRecord::RecordInvalid => e flash[:error] = e.message redirect_to node_path(@node) end @@ -170,10 +171,10 @@ class NodesController < ApplicationController def restore_from_trash parent = Node.find(params[:parent_id]) @node.restore_from_trash!(parent, current_user) - flash[:notice] = "Page has been restored from the Trash" + flash[:notice] = t("flash.nodes.restored") redirect_to node_path(@node) rescue ActiveRecord::RecordNotFound - flash[:error] = "Restore target not found" + flash[:error] = t("flash.nodes.restore_target_missing") redirect_to node_path(@node) rescue ActiveRecord::RecordInvalid => e flash[:error] = e.message @@ -182,7 +183,7 @@ class NodesController < ApplicationController def destroy @node.destroy_from_trash!(current_user) - flash[:notice] = "Page has been permanently deleted" + flash[:notice] = t("flash.nodes.deleted") redirect_to trashed_nodes_path rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotDestroyed => e @@ -192,15 +193,15 @@ class NodesController < ApplicationController def publish @node.publish_draft!(current_user) - flash[:notice] = "Draft has been published" + flash[:notice] = t("flash.nodes.published") redirect_to node_path(@node) end def unlock if @node.unlock! - flash[:notice] = "Node unlocked" + flash[:notice] = t("flash.nodes.unlocked") else - flash[:notice] = "Already unlocked" + flash[:notice] = t("flash.nodes.already_unlocked") end redirect_to node_path(@node) @@ -210,9 +211,9 @@ class NodesController < ApplicationController @node = Node.find(params[:id]) if @node.draft @node.draft.ensure_preview_token! - flash[:notice] = "Shareable preview link created - see below." + flash[:notice] = t("flash.nodes.preview_created") else - flash[:notice] = "Create or edit a draft first - shared preview links are only available for pages with an active draft." + flash[:notice] = t("flash.nodes.preview_needs_draft") end redirect_to node_path(@node) end @@ -220,7 +221,7 @@ class NodesController < ApplicationController def revoke_shared_preview @node = Node.find(params[:id]) @node.draft.revoke_preview_token! if @node.draft - flash[:notice] = "Shareable preview link revoked." + flash[:notice] = t("flash.nodes.preview_revoked") redirect_to node_path(@node) end diff --git a/app/controllers/occurrences_controller.rb b/app/controllers/occurrences_controller.rb index 0f30ce38..2e3c2ec1 100644 --- a/app/controllers/occurrences_controller.rb +++ b/app/controllers/occurrences_controller.rb @@ -49,7 +49,7 @@ class OccurrencesController < ApplicationController respond_to do |format| if @occurrence.save - flash[:notice] = 'Occurrence was successfully created.' + flash[:notice] = t("flash.occurrences.created") format.html { redirect_to(@occurrence) } format.xml { render :xml => @occurrence, :status => :created, :location => @occurrence } else @@ -66,7 +66,7 @@ class OccurrencesController < ApplicationController respond_to do |format| if @occurrence.update(occurrence_params) - flash[:notice] = 'Occurrence was successfully updated.' + flash[:notice] = t("flash.occurrences.updated") format.html { redirect_to(@occurrence) } format.xml { head :ok } else diff --git a/app/controllers/otp_challenges_controller.rb b/app/controllers/otp_challenges_controller.rb index e31c36ca..eeaeac20 100644 --- a/app/controllers/otp_challenges_controller.rb +++ b/app/controllers/otp_challenges_controller.rb @@ -19,7 +19,7 @@ class OtpChallengesController < ApplicationController session[:otp_attempts] = session[:otp_attempts].to_i + 1 if session[:otp_attempts] > MAX_ATTEMPTS clear_pending - flash[:error] = "Too many attempts -- log in again." + flash[:error] = t("flash.otp.too_many_attempts") return redirect_to login_path end @@ -28,10 +28,10 @@ class OtpChallengesController < ApplicationController reset_session self.current_user = user session[:logged_in_at] = Time.now.to_i - flash[:notice] = "Logged in successfully" + flash[:notice] = t("flash.common.logged_in") redirect_to safe_return_to(return_to, :default => admin_path) else - flash.now[:error] = "That code did not match." + flash.now[:error] = t("flash.otp.code_mismatch") render :new end end diff --git a/app/controllers/otp_enrollments_controller.rb b/app/controllers/otp_enrollments_controller.rb index 7a31d1e1..54b82214 100644 --- a/app/controllers/otp_enrollments_controller.rb +++ b/app/controllers/otp_enrollments_controller.rb @@ -15,7 +15,7 @@ class OtpEnrollmentsController < ApplicationController # unattended logged-in session cannot be enrolled onto a stranger's phone. def create unless User.authenticate(current_user.login, params[:current_password].to_s) - flash[:error] = "Wrong password." + flash[:error] = t("flash.otp.wrong_password") return redirect_to edit_user_path(current_user) end current_user.begin_otp_enrollment! @@ -25,11 +25,10 @@ class OtpEnrollmentsController < ApplicationController # Confirms with the first generated code. def update if current_user.confirm_otp_enrollment!(params[:code]) - flash[:notice] = "Second factor enabled. The code you just entered is " \ - "spent -- wait for the next one before logging in with it." + flash[:notice] = t("flash.otp.enabled") redirect_to edit_user_path(current_user) else - flash.now[:error] = "That code did not match. Rescan or wait for the next code." + flash.now[:error] = t("flash.otp.code_mismatch_rescan") render :show end end @@ -38,11 +37,11 @@ class OtpEnrollmentsController < ApplicationController def destroy unless User.authenticate(current_user.login, params[:current_password].to_s) && current_user.verify_otp!(params[:code]) - flash[:error] = "Password or code wrong -- second factor unchanged." + flash[:error] = t("flash.otp.wrong_credentials") return redirect_to edit_user_path(current_user) end current_user.disable_otp!(:actor => current_user) - flash[:notice] = "Second factor disabled." + flash[:notice] = t("flash.otp.disabled") redirect_to edit_user_path(current_user) end end diff --git a/app/controllers/page_translations_controller.rb b/app/controllers/page_translations_controller.rb index 38a7c4f9..e5ca57e0 100644 --- a/app/controllers/page_translations_controller.rb +++ b/app/controllers/page_translations_controller.rb @@ -16,14 +16,14 @@ class PageTranslationsController < ApplicationController @page = @node.draft || @node.head @translation = @page.translations.find_by(:locale => @locale) rescue LockedByAnotherUser => e - flash[:error] = e.message + flash[:error] = t("flash.common.locked_by_other") redirect_to node_path(@node) end def update Globalize.with_locale(@locale) { @node.autosave!(translation_params, current_user) } @node.save_draft!(current_user) - flash[:notice] = "#{@locale.upcase} translation saved. Publish the draft to make it live." + flash[:notice] = t("flash.page_translations.saved", :lang => @locale.upcase) if params[:commit] == "Save + Unlock + Exit" @node.unlock! @@ -32,7 +32,7 @@ class PageTranslationsController < ApplicationController redirect_to edit_node_translation_path(@node, @locale) end rescue LockedByAnotherUser => e - flash[:error] = e.message + flash[:error] = t("flash.common.locked_by_other") redirect_to node_path(@node) end @@ -40,7 +40,7 @@ class PageTranslationsController < ApplicationController Globalize.with_locale(@locale) { @node.autosave!(translation_params, current_user) } head :ok rescue LockedByAnotherUser => e - render plain: e.message, status: :locked + render plain: t("flash.common.locked_by_other"), status: :locked rescue ActiveRecord::RecordInvalid => e render plain: e.message, status: :unprocessable_entity rescue StandardError => e @@ -50,12 +50,12 @@ class PageTranslationsController < ApplicationController def destroy base = @node.draft || @node.head unless base && base.translated_locales.include?(@locale) - flash[:error] = "No #{@locale.to_s.upcase} translation exists to remove." + flash[:error] = t("flash.page_translations.none_to_remove", :lang => @locale.to_s.upcase) return redirect_to node_path(@node) end if (base.translated_locales - [@locale]).empty? - flash[:error] = "Can't remove the only remaining translation." + flash[:error] = t("flash.page_translations.last_translation") return redirect_to node_path(@node) end @@ -63,7 +63,7 @@ class PageTranslationsController < ApplicationController draft.translations.where(:locale => @locale).delete_all draft.reload - flash[:notice] = "#{@locale.upcase} translation removed from the draft. Publish to make this permanent." + flash[:notice] = t("flash.page_translations.removed", :lang => @locale.upcase) redirect_to node_path(@node) rescue LockedByAnotherUser => e flash[:error] = e.message diff --git a/app/controllers/revisions_controller.rb b/app/controllers/revisions_controller.rb index c1237a95..9f920b03 100644 --- a/app/controllers/revisions_controller.rb +++ b/app/controllers/revisions_controller.rb @@ -26,7 +26,7 @@ class RevisionsController < ApplicationController @end = @node.resolve_page_reference(params[:end_revision]) if @start.nil? || @end.nil? - flash[:error] = "That comparison is no longer available." + flash[:error] = t("flash.revisions.unavailable") redirect_to(node_path(@node)) and return end @@ -50,7 +50,7 @@ class RevisionsController < ApplicationController def restore page = Page.find(params[:id]) page.node.restore_revision! page.revision, current_user - flash[:notice] = "Revision #{page.revision} restored" + flash[:notice] = t("flash.revisions.restored", :rev => page.revision) redirect_to node_path(page.node) end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 49d33810..bb63c51e 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -32,10 +32,10 @@ class SessionsController < ApplicationController session[:logged_in_at] = Time.now.to_i if user.otp_required? - flash[:error] = "Your account requires a second factor -- set it up now." + flash[:error] = t("flash.sessions.otp_setup_now") redirect_to edit_user_path(user) else - flash[:notice] = "Logged in successfully" + flash[:notice] = t("flash.common.logged_in") redirect_to safe_return_to(return_to, :default => admin_path) end end @@ -48,14 +48,14 @@ class SessionsController < ApplicationController def destroy logout_killing_session! - flash[:notice] = "You have been logged out." + flash[:notice] = t("flash.sessions.logged_out") redirect_back_or_default('/login') end protected # Track failed login attempts def note_failed_signin - flash[:error] = "login not successful" + flash[:error] = t("flash.sessions.failed") logger.warn "Failed login for '#{params[:login]}'" \ "from #{request.remote_ip} at #{Time.now.utc}" end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 08541b0c..12531d86 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -22,7 +22,7 @@ class UsersController < ApplicationController @user = User.new user_params if @user.save - flash[:notice] = "User created #{@user.login}" + flash[:notice] = t("flash.users.created", :login => @user.login) redirect_to user_path(@user) else render :new @@ -37,7 +37,7 @@ class UsersController < ApplicationController permitted.delete(:admin) unless current_user.is_admin? if @user.update(permitted) - flash[:notice] = "Updated user #{@user.login}" + flash[:notice] = t("flash.users.updated", :login => @user.login) redirect_to user_path(@user) else render :edit @@ -55,7 +55,7 @@ class UsersController < ApplicationController def reset_otp return deny_user_access unless current_user.admin? @user.disable_otp!(:actor => current_user) - flash[:notice] = "Second factor reset for #{@user.login}" + flash[:notice] = t("flash.users.otp_reset", :login => @user.login) redirect_to edit_user_path(@user) end @@ -79,7 +79,7 @@ class UsersController < ApplicationController end def deny_user_access - flash[:notice] = "Sorry, you need to be an admin for this action" + flash[:notice] = t("flash.common.admin_required") redirect_to users_path end end diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb index 1d07a21e..b65416e1 100644 --- a/app/views/nodes/edit.html.erb +++ b/app/views/nodes/edit.html.erb @@ -21,7 +21,7 @@ <% end %> <%= submit_tag t(".save_draft"), form: dom_id(@node, :edit) %> - <%= submit_tag t(".save_unlock_exit"), form: dom_id(@node, :edit) %> + <%= submit_tag t(".save_unlock_exit"), name: "unlock_exit", form: dom_id(@node, :edit) %> <%= link_to t(".preview"), preview_page_path(@page), target: "_blank", rel: "noopener", class: "preview_link" %> @@ -163,7 +163,7 @@
<%= f.submit t(".save_draft") %> - <%= f.submit t(".save_unlock_exit") %> + <%= f.submit t(".save_unlock_exit"), name: "unlock_exit"%>
<% end %> diff --git a/app/views/page_translations/edit.html.erb b/app/views/page_translations/edit.html.erb index 2b2ce137..ac91d22c 100644 --- a/app/views/page_translations/edit.html.erb +++ b/app/views/page_translations/edit.html.erb @@ -15,7 +15,7 @@ form: { class: 'button_to state_changing' }, disabled: @node.autosave.present? %> <%= submit_tag "Save #{@locale.to_s.upcase} translation", form: "translation_edit_form" %> - <%= submit_tag "Save + Unlock + Exit", form: "translation_edit_form" %> + <%= submit_tag "Save + Unlock + Exit", name: "unlock_exit", form: "translation_edit_form" %> <%= link_to "Preview ↗", preview_page_path(@page, :locale => @locale), target: "_blank", rel: "noopener", class: "preview_link" %> diff --git a/config/locales/de.yml b/config/locales/de.yml index ab7852ce..3e0dfdd7 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -374,3 +374,65 @@ de: other: "\"%{title}\" und die %{count} Seiten darunter endgültig löschen? Das kann nicht rückgängig gemacht werden." delete_permanently: "Endgültig löschen" restore_hint: "Zum Wiederherstellen eine Seite öffnen und in ihrem Papierkorb-Abschnitt einen neuen Eltern-Node wählen." + + flash: + common: + logged_in: "Erfolgreich angemeldet" + otp_required: "Dein Konto erfordert einen zweiten Faktor — richte ihn ein, um fortzufahren." + admin_required: "Dafür sind Admin-Rechte erforderlich" + now_headline: "Es ist jetzt der Aufmacher der Seite." + headline_ineligible: "Dieser Asset-Typ kann kein Aufmacher sein." + locked_by_other: "Die Seite ist gerade von jemand anderem gesperrt." + autosave_failed: "Autosave fehlgeschlagen" + sessions: + otp_setup_now: "Dein Konto erfordert einen zweiten Faktor — richte ihn jetzt ein." + logged_out: "Du wurdest abgemeldet." + failed: "Anmeldung fehlgeschlagen" + otp: + too_many_attempts: "Zu viele Versuche — bitte neu anmelden." + code_mismatch: "Der Code hat nicht gepasst." + code_mismatch_rescan: "Der Code hat nicht gepasst. Neu scannen oder auf den nächsten Code warten." + wrong_password: "Falsches Passwort." + wrong_credentials: "Passwort oder Code falsch — zweiter Faktor unverändert." + enabled: "Zweiter Faktor aktiviert. Der eben eingegebene Code ist verbraucht — für die Anmeldung auf den nächsten warten." + disabled: "Zweiter Faktor entfernt." + users: + created: "Benutzer %{login} angelegt" + updated: "Benutzer %{login} aktualisiert" + otp_reset: "Zweiter Faktor von %{login} zurückgesetzt" + assets: + created: "Asset wurde angelegt." + updated: "Asset wurde aktualisiert." + attached: "Asset wurde angelegt und an „%{title}“ angehängt." + already_attached: "Asset gespeichert — es war bereits an „%{title}“ angehängt." + events: + created: "Termin wurde angelegt." + updated: "Termin wurde aktualisiert." + tag_prefilled: "Tag '%{tag}' wurde vorausgefüllt, weil diese Seite mit '%{source}' getaggt ist. Er lässt sich unten entfernen." + occurrences: + created: "Termin-Instanz wurde angelegt." + updated: "Termin-Instanz wurde aktualisiert." + revisions: + unavailable: "Dieser Vergleich ist nicht mehr verfügbar." + restored: "Revision %{rev} wiederhergestellt" + nodes: + created_with_attachment: "Seite mit angehängtem „%{name}“ angelegt." + autosave_banner: "Diese Seite hat ungespeicherte Änderungen aus einer früheren Sitzung, unten angezeigt. Speichern, um sie zu behalten — oder unten \"Autosave verwerfen\" nutzen, um zum letzten gespeicherten Stand zurückzukehren." + locked_ready: "Node gesperrt und bereit zum Bearbeiten" + draft_saved: "Entwurf gespeichert. Veröffentliche deine Änderungen im Status-Abschnitt, sobald du fertig bist." + trashed: "Seite wurde in den Papierkorb verschoben" + already_trashed: "Seite ist bereits im Papierkorb" + restored: "Seite wurde aus dem Papierkorb wiederhergestellt" + restore_target_missing: "Wiederherstellungsziel nicht gefunden" + deleted: "Seite wurde endgültig gelöscht" + published: "Entwurf wurde veröffentlicht" + unlocked: "Node entsperrt" + already_unlocked: "Bereits entsperrt" + preview_created: "Teilbarer Vorschau-Link erzeugt — siehe unten." + preview_needs_draft: "Erst einen Entwurf anlegen oder bearbeiten — teilbare Vorschau-Links gibt es nur für Seiten mit aktivem Entwurf." + preview_revoked: "Teilbarer Vorschau-Link zurückgezogen." + page_translations: + saved: "%{lang}-Übersetzung gespeichert. Den Entwurf veröffentlichen, um sie live zu schalten." + none_to_remove: "Es existiert keine %{lang}-Übersetzung zum Entfernen." + last_translation: "Die einzige verbliebene Übersetzung kann nicht entfernt werden." + removed: "%{lang}-Übersetzung aus dem Entwurf entfernt. Veröffentlichen, um das dauerhaft zu machen." diff --git a/config/locales/en.yml b/config/locales/en.yml index cb75693b..616a1d8f 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -326,3 +326,65 @@ en: other: "Delete \"%{title}\" and the %{count} pages beneath it permanently? This cannot be undone." delete_permanently: "Delete permanently" restore_hint: "To restore a page, open it and pick a new parent in its Trash section." + + flash: + common: + logged_in: "Logged in successfully" + otp_required: "Your account requires a second factor -- set it up to continue." + admin_required: "Sorry, you need to be an admin for this action" + now_headline: "It is now the page's headline." + headline_ineligible: "This asset type cannot be a headline." + locked_by_other: "The page is locked by another editor." + autosave_failed: "Autosave failed" + sessions: + otp_setup_now: "Your account requires a second factor -- set it up now." + logged_out: "You have been logged out." + failed: "login not successful" + otp: + too_many_attempts: "Too many attempts -- log in again." + code_mismatch: "That code did not match." + code_mismatch_rescan: "That code did not match. Rescan or wait for the next code." + wrong_password: "Wrong password." + wrong_credentials: "Password or code wrong -- second factor unchanged." + enabled: "Second factor enabled. The code you just entered is spent -- wait for the next one before logging in with it." + disabled: "Second factor disabled." + users: + created: "User created %{login}" + updated: "Updated user %{login}" + otp_reset: "Second factor reset for %{login}" + assets: + created: "Asset was successfully created." + updated: "Asset was successfully updated." + attached: "Asset was successfully created and attached to “%{title}”." + already_attached: "Asset saved — it was already attached to “%{title}”." + events: + created: "Event was successfully created." + updated: "Event was successfully updated." + tag_prefilled: "Tag '%{tag}' was pre-filled because this page is tagged '%{source}'. You can remove it below." + occurrences: + created: "Occurrence was successfully created." + updated: "Occurrence was successfully updated." + revisions: + unavailable: "That comparison is no longer available." + restored: "Revision %{rev} restored" + nodes: + created_with_attachment: "Page created with “%{name}” attached." + autosave_banner: "This page has unsaved changes from a previous session, shown below. Save to keep them, or use \"Discard Autosave\" below to go back to the last saved version." + locked_ready: "Node locked and ready to edit" + draft_saved: "Draft saved. Publish your changes in the Status section once you're done." + trashed: "Page has been moved to the Trash" + already_trashed: "Page is already in the Trash" + restored: "Page has been restored from the Trash" + restore_target_missing: "Restore target not found" + deleted: "Page has been permanently deleted" + published: "Draft has been published" + unlocked: "Node unlocked" + already_unlocked: "Already unlocked" + preview_created: "Shareable preview link created - see below." + preview_needs_draft: "Create or edit a draft first - shared preview links are only available for pages with an active draft." + preview_revoked: "Shareable preview link revoked." + page_translations: + saved: "%{lang} translation saved. Publish the draft to make it live." + none_to_remove: "No %{lang} translation exists to remove." + last_translation: "Can't remove the only remaining translation." + removed: "%{lang} translation removed from the draft. Publish to make this permanent." diff --git a/test/controllers/assets_controller_test.rb b/test/controllers/assets_controller_test.rb index 4be2e8a1..467e1a68 100644 --- a/test/controllers/assets_controller_test.rb +++ b/test/controllers/assets_controller_test.rb @@ -102,7 +102,7 @@ class AssetsControllerTest < ActionController::TestCase assert_response :redirect asset = Asset.last assert_includes node.draft.assets.reload, asset - assert_match /attached/, flash[:notice] + assert_equal I18n.t("flash.assets.attached", :title => node.title), flash[:notice] end test "create against a foreign-locked node keeps the asset but refuses the attach" do diff --git a/test/controllers/events_controller_test.rb b/test/controllers/events_controller_test.rb index 46f3f4f1..d4fd66d6 100644 --- a/test/controllers/events_controller_test.rb +++ b/test/controllers/events_controller_test.rb @@ -83,7 +83,7 @@ class EventsControllerTest < ActionController::TestCase end assert_redirected_to edit_node_path(node) - assert_equal 'Event was successfully created.', flash[:notice] + assert_equal I18n.t("flash.events.created"), flash[:notice] end test "should not create an event without a title or a node_id" do diff --git a/test/controllers/nodes_controller_test.rb b/test/controllers/nodes_controller_test.rb index 8b59fc37..d7a3abbd 100644 --- a/test/controllers/nodes_controller_test.rb +++ b/test/controllers/nodes_controller_test.rb @@ -91,7 +91,7 @@ class NodesControllerTest < ActionController::TestCase node = Node.last assert_includes node.draft.assets, asset assert_equal asset, node.draft.headline_asset - assert_match /attached/, flash[:notice] + assert_equal I18n.t("flash.nodes.created_with_attachment", :name => "Birth attachment") + " " + I18n.t("flash.common.now_headline"), flash[:notice] end test "the attach notice survives the redirect into the editor" do @@ -104,8 +104,8 @@ class NodesControllerTest < ActionController::TestCase get :edit, params: { :id => Node.last.id } assert_response :success - assert_match /attached/, flash[:notice] - assert_no_match /ready to edit/, flash[:notice] + assert_equal I18n.t("flash.nodes.created_with_attachment", :name => "Flash survivor"), flash[:notice] + assert_not_equal I18n.t("flash.nodes.locked_ready"), flash[:notice] end test "editing a node" do @@ -146,7 +146,7 @@ class NodesControllerTest < ActionController::TestCase get :edit, params: { :id => node.id } assert_response :redirect - assert flash[:error] =~ /Page is locked by another user/ + assert_equal I18n.t("flash.common.locked_by_other"), flash[:error] end def test_update_a_draft @@ -282,7 +282,7 @@ class NodesControllerTest < ActionController::TestCase put :unlock, params: { :id => node.id } assert_response :redirect - assert_equal "Already unlocked", flash[:notice] + assert_equal I18n.t("flash.nodes.already_unlocked"), flash[:notice] end test "updating a node by changing its parent" do diff --git a/test/controllers/page_translations_controller_test.rb b/test/controllers/page_translations_controller_test.rb index feaacd0e..7484a203 100644 --- a/test/controllers/page_translations_controller_test.rb +++ b/test/controllers/page_translations_controller_test.rb @@ -55,7 +55,7 @@ class PageTranslationsControllerTest < ActionController::TestCase delete :destroy, params: { :node_id => node.id, :translation_locale => "en" } - assert_equal "Can't remove the only remaining translation.", flash[:error] + assert_equal I18n.t("flash.page_translations.last_translation"), flash[:error] end test "destroy is a safe no-op, not a false success, when the translation doesn't exist" do @@ -64,7 +64,7 @@ class PageTranslationsControllerTest < ActionController::TestCase delete :destroy, params: { :node_id => node.id, :translation_locale => "en" } - assert_match(/No EN translation exists/, flash[:error]) + assert_equal I18n.t("flash.page_translations.none_to_remove", :lang => "EN"), flash[:error] end test "autosave writes the translation without creating a new revision or touching the draft" do diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb index dcd8f259..67f7c053 100644 --- a/test/controllers/users_controller_test.rb +++ b/test/controllers/users_controller_test.rb @@ -1,7 +1,7 @@ require 'test_helper' class UsersControllerTest < ActionController::TestCase - + test "get index as regular user renders stripped partial" do login_as :quentin get :index @@ -16,20 +16,20 @@ class UsersControllerTest < ActionController::TestCase assert_select "button[type=submit]", I18n.t("admin.common.destroy") assert_select "a", "show" end - + test "get new when logged in as admin" do login_as :aaron get :new assert_response :success end - + test "get new without being logged in as admin redirects back to index" do login_as :quentin get :new assert_response :redirect assert_redirected_to users_path assert_equal( - "Sorry, you need to be an admin for this action", + I18n.t("flash.common.admin_required"), flash[:notice] ) end @@ -84,7 +84,7 @@ class UsersControllerTest < ActionController::TestCase assert_redirected_to users_path assert_equal( - "Sorry, you need to be an admin for this action", + I18n.t("flash.common.admin_required"), flash[:notice] ) end @@ -94,7 +94,7 @@ class UsersControllerTest < ActionController::TestCase get :edit, params: { :id => User.find_by_login("aaron").id } assert_redirected_to users_path assert_equal( - "Sorry, you need to be an admin for this action", + I18n.t("flash.common.admin_required"), flash[:notice] ) end @@ -117,7 +117,7 @@ class UsersControllerTest < ActionController::TestCase put :update, params: { :id => user.id, :user => {:login => "random"} } assert_redirected_to users_path assert_equal( - "Sorry, you need to be an admin for this action", + I18n.t("flash.common.admin_required"), flash[:notice] ) end @@ -137,7 +137,7 @@ class UsersControllerTest < ActionController::TestCase assert_redirected_to user_path(user) assert_equal "random", user.reload.login end - + test "showing a user" do login_as :quentin get :show, params: { :id => User.find_by_login("aaron").id } @@ -151,7 +151,7 @@ class UsersControllerTest < ActionController::TestCase end assert_redirected_to users_path assert_equal( - "Sorry, you need to be an admin for this action", + I18n.t("flash.common.admin_required"), flash[:notice] ) end -- cgit v1.3