From 777fbdc4cac0f85fcf7dc6f604a9f473fb6e9f1e Mon Sep 17 00:00:00 2001 From: Julien Orain Date: Tue, 20 Jan 2026 00:11:22 +0100 Subject: [PATCH] feat(settings): add pagination to imports and exports pages (#598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(settings): split imports and exports * feat(security): sanitize pagination params to prevent abuse * fix(settings): fix syntax in settings nav * feat(settings): internationalize family_exports and imports UI strings * fix(settings): fix coderabbit review * fix(settings): fix coderabbit review * fix(settings): fix coderabbit review * Change default per_page value from 20 to 10 Signed-off-by: Juan José Mata * Add `/family_export` to navigation * Consistency with old defaults * Align `safe_per_page` even if not DRY --------- Signed-off-by: Julien Orain Signed-off-by: Juan José Mata Signed-off-by: Juan José Mata Co-authored-by: JulienOrain Co-authored-by: Juan José Mata Co-authored-by: Juan José Mata --- app/controllers/accounts_controller.rb | 2 +- app/controllers/application_controller.rb | 2 +- .../concerns/accountable_resource.rb | 2 +- app/controllers/concerns/safe_pagination.rb | 15 ++++ app/controllers/family_exports_controller.rb | 18 ++-- app/controllers/imports_controller.rb | 9 +- app/controllers/rules_controller.rb | 2 +- app/controllers/transactions_controller.rb | 6 +- app/helpers/settings_helper.rb | 1 + app/views/family_exports/_list.html.erb | 10 +-- app/views/family_exports/index.html.erb | 86 ++++++++++++++++++- app/views/imports/index.html.erb | 31 ++----- app/views/settings/_settings_nav.html.erb | 1 + app/views/shared/_pagination.html.erb | 2 +- config/locales/breadcrumbs/ca.yml | 6 ++ config/locales/breadcrumbs/de.yml | 6 ++ config/locales/breadcrumbs/en.yml | 6 ++ config/locales/breadcrumbs/es.yml | 6 ++ config/locales/breadcrumbs/nb.yml | 6 ++ config/locales/breadcrumbs/pt-BR.yml | 6 ++ config/locales/breadcrumbs/ro.yml | 6 ++ config/locales/breadcrumbs/tr.yml | 6 ++ config/locales/breadcrumbs/zh-CN.yml | 6 ++ config/locales/views/family_exports/ca.yml | 15 ++++ config/locales/views/family_exports/de.yml | 14 +++ config/locales/views/family_exports/en.yml | 14 +++ config/locales/views/family_exports/es.yml | 14 +++ config/locales/views/family_exports/nb.yml | 14 +++ config/locales/views/family_exports/pt-BR.yml | 16 +++- config/locales/views/family_exports/ro.yml | 14 +++ config/locales/views/family_exports/tr.yml | 14 +++ config/locales/views/family_exports/zh-CN.yml | 14 +++ config/locales/views/family_exports/zh-TW.yml | 6 ++ config/locales/views/imports/ca.yml | 4 +- config/locales/views/imports/de.yml | 6 +- config/locales/views/imports/en.yml | 6 +- config/locales/views/imports/es.yml | 6 +- config/locales/views/imports/nb.yml | 6 +- config/locales/views/imports/pt-BR.yml | 6 +- config/locales/views/imports/ro.yml | 6 +- config/locales/views/imports/tr.yml | 6 +- config/locales/views/imports/zh-CN.yml | 6 +- config/locales/views/settings/ca.yml | 3 +- config/locales/views/settings/de.yml | 3 +- config/locales/views/settings/en.yml | 3 +- config/locales/views/settings/es.yml | 3 +- config/locales/views/settings/nb.yml | 1 + config/locales/views/settings/pt-BR.yml | 1 + config/locales/views/settings/ro.yml | 3 +- config/locales/views/settings/zh-CN.yml | 3 +- .../family_exports_controller_test.rb | 10 +-- 51 files changed, 353 insertions(+), 105 deletions(-) create mode 100644 app/controllers/concerns/safe_pagination.rb create mode 100644 config/locales/breadcrumbs/ca.yml create mode 100644 config/locales/breadcrumbs/de.yml create mode 100644 config/locales/breadcrumbs/en.yml create mode 100644 config/locales/breadcrumbs/es.yml create mode 100644 config/locales/breadcrumbs/nb.yml create mode 100644 config/locales/breadcrumbs/pt-BR.yml create mode 100644 config/locales/breadcrumbs/ro.yml create mode 100644 config/locales/breadcrumbs/tr.yml create mode 100644 config/locales/breadcrumbs/zh-CN.yml diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index b71318b62..cfa403124 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -38,7 +38,7 @@ class AccountsController < ApplicationController @q = params.fetch(:q, {}).permit(:search, status: []) entries = @account.entries.where(excluded: false).search(@q).reverse_chronological - @pagy, @entries = pagy(entries, limit: params[:per_page] || "10") + @pagy, @entries = pagy(entries, limit: safe_per_page) @activity_feed_data = Account::ActivityFeedData.new(@account, @entries) end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b171a080d..9f2cc1565 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,7 +1,7 @@ class ApplicationController < ActionController::Base include RestoreLayoutPreferences, Onboardable, Localize, AutoSync, Authentication, Invitable, SelfHostable, StoreLocation, Impersonatable, Breadcrumbable, - FeatureGuardable, Notifiable + FeatureGuardable, Notifiable, SafePagination include Pundit::Authorization include Pagy::Backend diff --git a/app/controllers/concerns/accountable_resource.rb b/app/controllers/concerns/accountable_resource.rb index 2d994d45c..1b8bbf6d2 100644 --- a/app/controllers/concerns/accountable_resource.rb +++ b/app/controllers/concerns/accountable_resource.rb @@ -27,7 +27,7 @@ module AccountableResource @q = params.fetch(:q, {}).permit(:search) entries = @account.entries.search(@q).reverse_chronological - @pagy, @entries = pagy(entries, limit: params[:per_page] || "10") + @pagy, @entries = pagy(entries, limit: safe_per_page(10)) end def edit diff --git a/app/controllers/concerns/safe_pagination.rb b/app/controllers/concerns/safe_pagination.rb new file mode 100644 index 000000000..de0f794bc --- /dev/null +++ b/app/controllers/concerns/safe_pagination.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module SafePagination + extend ActiveSupport::Concern + + private + def safe_per_page(default = 10) + allowed_values = [ 10, 20, 30, 50, 100 ] + per_page = params[:per_page].to_i + + return default if per_page <= 0 + + allowed_values.include?(per_page) ? per_page : allowed_values.min_by { |v| (v - per_page).abs } + end +end diff --git a/app/controllers/family_exports_controller.rb b/app/controllers/family_exports_controller.rb index b8bd27774..d3a9163f5 100644 --- a/app/controllers/family_exports_controller.rb +++ b/app/controllers/family_exports_controller.rb @@ -13,29 +13,33 @@ class FamilyExportsController < ApplicationController FamilyDataExportJob.perform_later(@export) respond_to do |format| - format.html { redirect_to imports_path, notice: "Export started. You'll be able to download it shortly." } + format.html { redirect_to family_exports_path, notice: t("family_exports.create.success") } format.turbo_stream { - stream_redirect_to imports_path, notice: "Export started. You'll be able to download it shortly." + stream_redirect_to family_exports_path, notice: t("family_exports.create.success") } end end def index - @exports = Current.family.family_exports.ordered.limit(10) - render layout: false # For turbo frame + @pagy, @exports = pagy(Current.family.family_exports.ordered, limit: safe_per_page) + @breadcrumbs = [ + [ t("breadcrumbs.home"), root_path ], + [ t("breadcrumbs.exports"), family_exports_path ] + ] + render layout: "settings" end def download if @export.downloadable? redirect_to @export.export_file, allow_other_host: true else - redirect_to imports_path, alert: "Export not ready for download" + redirect_to family_exports_path, alert: t("family_exports.export_not_ready") end end def destroy @export.destroy - redirect_to imports_path, notice: "Export deleted successfully" + redirect_to family_exports_path, notice: t("family_exports.destroy.success") end private @@ -46,7 +50,7 @@ class FamilyExportsController < ApplicationController def require_admin unless Current.user.admin? - redirect_to root_path, alert: "Access denied" + redirect_to root_path, alert: t("family_exports.access_denied") end end end diff --git a/app/controllers/imports_controller.rb b/app/controllers/imports_controller.rb index 50891d323..227e94866 100644 --- a/app/controllers/imports_controller.rb +++ b/app/controllers/imports_controller.rb @@ -12,11 +12,10 @@ class ImportsController < ApplicationController end def index - @imports = Current.family.imports - @exports = Current.user.admin? ? Current.family.family_exports.ordered.limit(10) : nil + @pagy, @imports = pagy(Current.family.imports.where(type: Import::TYPES).ordered, limit: safe_per_page) @breadcrumbs = [ - [ "Home", root_path ], - [ "Import/Export", imports_path ] + [ t("breadcrumbs.home"), root_path ], + [ t("breadcrumbs.imports"), imports_path ] ] render layout: "settings" end @@ -90,7 +89,7 @@ class ImportsController < ApplicationController private def set_import - @import = Current.family.imports.find(params[:id]) + @import = Current.family.imports.includes(:account).find(params[:id]) end def import_params diff --git a/app/controllers/rules_controller.rb b/app/controllers/rules_controller.rb index cd8a6eb6c..23889dc5a 100644 --- a/app/controllers/rules_controller.rb +++ b/app/controllers/rules_controller.rb @@ -20,7 +20,7 @@ class RulesController < ApplicationController .recent .includes(:rule) - @pagy, @recent_runs = pagy(recent_runs_scope, limit: params[:per_page] || 20, page_param: :runs_page) + @pagy, @recent_runs = pagy(recent_runs_scope, limit: safe_per_page, page_param: :runs_page) render layout: "settings" end diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index 3060af3f5..e5efee0b0 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -21,7 +21,7 @@ class TransactionsController < ApplicationController :transfer_as_inflow, :transfer_as_outflow ) - @pagy, @transactions = pagy(base_scope, limit: per_page) + @pagy, @transactions = pagy(base_scope, limit: safe_per_page) # Load projected recurring transactions for next month @projected_recurring = Current.family.recurring_transactions @@ -281,10 +281,6 @@ class TransactionsController < ApplicationController end private - def per_page - params[:per_page].to_i.positive? ? params[:per_page].to_i : 20 - end - def needs_rule_notification?(transaction) return false if Current.user.rule_prompts_disabled diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index a907cd7c8..1bd120e00 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -20,6 +20,7 @@ module SettingsHelper { name: "Self-Hosting", path: :settings_hosting_path, condition: :self_hosted_and_admin? }, { name: "Providers", path: :settings_providers_path, condition: :admin_user? }, { name: "Imports", path: :imports_path, condition: :admin_user? }, + { name: "Exports", path: :family_exports_path, condition: :admin_user? }, # More section { name: "Guides", path: :settings_guides_path }, { name: "What's new", path: :changelog_path }, diff --git a/app/views/family_exports/_list.html.erb b/app/views/family_exports/_list.html.erb index e73889dfb..5d266eda8 100644 --- a/app/views/family_exports/_list.html.erb +++ b/app/views/family_exports/_list.html.erb @@ -9,7 +9,7 @@
-

Export from <%= export.created_at.strftime("%B %d, %Y at %I:%M %p") %>

+

<%= t("family_exports.list.export_from", date: l(export.created_at, format: :long)) %>

<%= export.filename %>

@@ -31,7 +31,7 @@ <% if export.processing? || export.pending? %>
- Exporting... + <%= t("family_exports.exporting") %>
<% elsif export.completed? %>
@@ -39,7 +39,7 @@ method: :delete, class: "flex items-center gap-2 text-destructive hover:text-destructive-hover", data: { - turbo_confirm: "Are you sure you want to delete this export? This action cannot be undone.", + turbo_confirm: t("family_exports.delete_confirmation"), turbo_frame: "_top" } do %> <%= icon "trash-2", class: "w-5 h-5 text-destructive" %> @@ -61,7 +61,7 @@ method: :delete, class: "flex items-center gap-2 text-destructive hover:text-destructive-hover", data: { - turbo_confirm: "Are you sure you want to delete this failed export?", + turbo_confirm: t("family_exports.delete_failed_confirmation"), turbo_frame: "_top" } do %> <%= icon "trash-2", class: "w-5 h-5 text-destructive" %> @@ -71,7 +71,7 @@
<% end %> <% else %> -

No exports yet.

+

<%= t("family_exports.index.no_exports") %>

<% end %>
<% end %> diff --git a/app/views/family_exports/index.html.erb b/app/views/family_exports/index.html.erb index 530b81518..f4bee6bdf 100644 --- a/app/views/family_exports/index.html.erb +++ b/app/views/family_exports/index.html.erb @@ -1 +1,85 @@ -<%= render "list", exports: @exports %> +<%= settings_section title: t(".title") do %> +
+ <% if @exports.empty? %> +

<%= t(".no_exports") %>

+ <% else %> +
+ <% @exports.each do |export| %> +
+
+
+

<%= t("family_exports.list.export_from", date: l(export.created_at, format: :long)) %>

+

<%= export.filename %>

+
+ + <% if export.processing? || export.pending? %> + + <%= t("family_exports.list.in_progress") %> + + <% elsif export.completed? %> + + <%= t("family_exports.list.complete") %> + + <% elsif export.failed? %> + + <%= t("family_exports.list.failed") %> + + <% end %> +
+ + <% if export.processing? || export.pending? %> +
+
+ <%= t("family_exports.exporting") %> +
+ <% elsif export.completed? %> +
+ <%= button_to family_export_path(export), + method: :delete, + class: "flex items-center gap-2 text-destructive hover:text-destructive-hover", + data: { + turbo_confirm: t("family_exports.delete_confirmation") + } do %> + <%= icon "trash-2", class: "w-5 h-5 text-destructive" %> + <% end %> + + <%= link_to download_family_export_path(export), + class: "flex items-center gap-2 text-primary hover:text-primary-hover" do %> + <%= icon "download", class: "w-5 h-5" %> + <% end %> +
+ <% elsif export.failed? %> +
+
+ <%= icon "alert-circle", class: "w-4 h-4" %> +
+ + <%= button_to family_export_path(export), + method: :delete, + class: "flex items-center gap-2 text-destructive hover:text-destructive-hover", + data: { + turbo_confirm: t("family_exports.delete_failed_confirmation") + } do %> + <%= icon "trash-2", class: "w-5 h-5 text-destructive" %> + <% end %> +
+ <% end %> +
+ <% end %> +
+ + <% if @pagy.pages > 1 %> +
+ <%= render "shared/pagination", pagy: @pagy %> +
+ <% end %> + <% end %> + + <%= link_to new_family_export_path, + class: "bg-container-inset flex items-center justify-center gap-2 text-secondary mt-1 hover:bg-container-inset-hover rounded-lg px-4 py-2 w-full text-center", + data: { turbo_frame: :modal } do %> + <%= icon("plus") %> + <%= t(".new") %> + <% end %> +
+<% end %> diff --git a/app/views/imports/index.html.erb b/app/views/imports/index.html.erb index 8e01454bd..272caab60 100644 --- a/app/views/imports/index.html.erb +++ b/app/views/imports/index.html.erb @@ -1,11 +1,17 @@ -<%= settings_section title: t(".imports") do %> +<%= settings_section title: t(".title") do %>
<% if @imports.empty? %> <%= render partial: "imports/empty" %> <% else %>
- <%= render partial: "imports/import", collection: @imports.ordered %> + <%= render partial: "imports/import", collection: @imports %>
+ + <% if @pagy.pages > 1 %> +
+ <%= render "shared/pagination", pagy: @pagy %> +
+ <% end %> <% end %> <%= link_to new_import_path, @@ -16,24 +22,3 @@ <% end %>
<% end %> - -<% if Current.user.admin? %> - <%= settings_section title: t(".exports") do %> -
-
- <%= turbo_frame_tag "family_exports", src: family_exports_path, loading: :lazy do %> -
-
-
- <% end %> -
- - <%= link_to new_family_export_path, - class: "bg-container-inset flex items-center justify-center gap-2 text-secondary mt-1 hover:bg-container-inset-hover rounded-lg px-4 py-2 w-full text-center", - data: { turbo_frame: :modal } do %> - <%= icon("plus") %> - <%= t(".new_export") %> - <% end %> -
- <% end %> -<% end %> diff --git a/app/views/settings/_settings_nav.html.erb b/app/views/settings/_settings_nav.html.erb index 89a1a73c2..54936014b 100644 --- a/app/views/settings/_settings_nav.html.erb +++ b/app/views/settings/_settings_nav.html.erb @@ -31,6 +31,7 @@ nav_sections = [ { label: t(".self_hosting_label"), path: settings_hosting_path, icon: "database", if: self_hosted? }, { label: "Providers", path: settings_providers_path, icon: "plug" }, { label: t(".imports_label"), path: imports_path, icon: "download" }, + { label: t(".exports_label"), path: family_exports_path, icon: "upload" }, { label: "SSO Providers", path: admin_sso_providers_path, icon: "key-round", if: Current.user&.super_admin? }, { label: "Users", path: admin_users_path, icon: "users", if: Current.user&.super_admin? } ] diff --git a/app/views/shared/_pagination.html.erb b/app/views/shared/_pagination.html.erb index c3c9c292a..edcf4c286 100644 --- a/app/views/shared/_pagination.html.erb +++ b/app/views/shared/_pagination.html.erb @@ -50,7 +50,7 @@
<%= select_tag :per_page, - options_for_select(["10", "20", "30", "50"], pagy.limit), + options_for_select(["10", "20", "30", "50", "100"], pagy.limit), data: { controller: "selectable-link" }, class: "py-1.5 pr-8 text-sm text-primary font-medium bg-container-inset border border-secondary rounded-lg focus:border-secondary focus:ring-secondary focus-visible:ring-secondary" %>
diff --git a/config/locales/breadcrumbs/ca.yml b/config/locales/breadcrumbs/ca.yml new file mode 100644 index 000000000..c726a4da7 --- /dev/null +++ b/config/locales/breadcrumbs/ca.yml @@ -0,0 +1,6 @@ +--- +ca: + breadcrumbs: + exports: Exportacions + home: Inici + imports: Importacions diff --git a/config/locales/breadcrumbs/de.yml b/config/locales/breadcrumbs/de.yml new file mode 100644 index 000000000..842ff38a0 --- /dev/null +++ b/config/locales/breadcrumbs/de.yml @@ -0,0 +1,6 @@ +--- +de: + breadcrumbs: + exports: Exporte + home: Startseite + imports: Importe diff --git a/config/locales/breadcrumbs/en.yml b/config/locales/breadcrumbs/en.yml new file mode 100644 index 000000000..9d81ba325 --- /dev/null +++ b/config/locales/breadcrumbs/en.yml @@ -0,0 +1,6 @@ +--- +en: + breadcrumbs: + exports: Exports + home: Home + imports: Imports diff --git a/config/locales/breadcrumbs/es.yml b/config/locales/breadcrumbs/es.yml new file mode 100644 index 000000000..f0a45a491 --- /dev/null +++ b/config/locales/breadcrumbs/es.yml @@ -0,0 +1,6 @@ +--- +es: + breadcrumbs: + exports: Exportaciones + home: Inicio + imports: Importaciones diff --git a/config/locales/breadcrumbs/nb.yml b/config/locales/breadcrumbs/nb.yml new file mode 100644 index 000000000..c216b77ae --- /dev/null +++ b/config/locales/breadcrumbs/nb.yml @@ -0,0 +1,6 @@ +--- +nb: + breadcrumbs: + exports: Eksporter + home: Hjem + imports: Importer diff --git a/config/locales/breadcrumbs/pt-BR.yml b/config/locales/breadcrumbs/pt-BR.yml new file mode 100644 index 000000000..6e390706c --- /dev/null +++ b/config/locales/breadcrumbs/pt-BR.yml @@ -0,0 +1,6 @@ +--- +pt-BR: + breadcrumbs: + exports: Exportações + home: Início + imports: Importações diff --git a/config/locales/breadcrumbs/ro.yml b/config/locales/breadcrumbs/ro.yml new file mode 100644 index 000000000..86dc25114 --- /dev/null +++ b/config/locales/breadcrumbs/ro.yml @@ -0,0 +1,6 @@ +--- +ro: + breadcrumbs: + exports: Exporturi + home: Acasă + imports: Importuri diff --git a/config/locales/breadcrumbs/tr.yml b/config/locales/breadcrumbs/tr.yml new file mode 100644 index 000000000..08dea8ecd --- /dev/null +++ b/config/locales/breadcrumbs/tr.yml @@ -0,0 +1,6 @@ +--- +tr: + breadcrumbs: + exports: Dışa Aktarmalar + home: Ana Sayfa + imports: İçe Aktarmalar diff --git a/config/locales/breadcrumbs/zh-CN.yml b/config/locales/breadcrumbs/zh-CN.yml new file mode 100644 index 000000000..978e8396c --- /dev/null +++ b/config/locales/breadcrumbs/zh-CN.yml @@ -0,0 +1,6 @@ +--- +zh-CN: + breadcrumbs: + exports: 导出 + home: 主页 + imports: 导入 diff --git a/config/locales/views/family_exports/ca.yml b/config/locales/views/family_exports/ca.yml index c35eb1bb6..a06d6edd3 100644 --- a/config/locales/views/family_exports/ca.yml +++ b/config/locales/views/family_exports/ca.yml @@ -1,7 +1,22 @@ --- ca: family_exports: + access_denied: Accés denegat + create: + success: Exportació iniciada. Podràs descarregar-la aviat. + delete_confirmation: Estàs segur que vols eliminar aquesta exportació? Aquesta acció no es pot desfer. + delete_failed_confirmation: Estàs segur que vols eliminar aquesta exportació fallida? + destroy: + success: Exportació eliminada amb èxit + export_not_ready: L'exportació no està llesta per descarregar + exporting: Exportant... + index: + title: Exportacions + new: Nova exportació + no_exports: Encara no hi ha exportacions. list: + export_from: "Exportació del %{date}" + in_progress: En curs complete: Completat failed: Error in_progress: En curs diff --git a/config/locales/views/family_exports/de.yml b/config/locales/views/family_exports/de.yml index 28cfb0bb6..bb7a9353d 100644 --- a/config/locales/views/family_exports/de.yml +++ b/config/locales/views/family_exports/de.yml @@ -1,7 +1,21 @@ --- de: family_exports: + access_denied: Zugriff verweigert + create: + success: Export gestartet. Sie können ihn in Kürze herunterladen. + delete_confirmation: Möchten Sie diesen Export wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden. + delete_failed_confirmation: Möchten Sie diesen fehlgeschlagenen Export wirklich löschen? + destroy: + success: Export erfolgreich gelöscht + export_not_ready: Export noch nicht zum Download bereit + exporting: Wird exportiert... + index: + title: Exporte + new: Neuer Export + no_exports: Noch keine Exporte vorhanden. list: + export_from: "Export vom %{date}" in_progress: Wird ausgeführt complete: Abgeschlossen failed: Fehlgeschlagen diff --git a/config/locales/views/family_exports/en.yml b/config/locales/views/family_exports/en.yml index 79674716b..732cb9c1b 100644 --- a/config/locales/views/family_exports/en.yml +++ b/config/locales/views/family_exports/en.yml @@ -1,7 +1,21 @@ --- en: family_exports: + access_denied: Access denied + create: + success: Export started. You'll be able to download it shortly. + delete_confirmation: Are you sure you want to delete this export? This action cannot be undone. + delete_failed_confirmation: Are you sure you want to delete this failed export? + destroy: + success: Export deleted successfully + export_not_ready: Export not ready for download + exporting: Exporting... + index: + title: Exports + new: New Export + no_exports: No exports yet. list: + export_from: "Export from %{date}" in_progress: In progress complete: Complete failed: Failed diff --git a/config/locales/views/family_exports/es.yml b/config/locales/views/family_exports/es.yml index 685a91cdb..5979c5349 100644 --- a/config/locales/views/family_exports/es.yml +++ b/config/locales/views/family_exports/es.yml @@ -1,7 +1,21 @@ --- es: family_exports: + access_denied: Acceso denegado + create: + success: Exportación iniciada. Podrás descargarla en breve. + delete_confirmation: ¿Estás seguro de que quieres eliminar esta exportación? Esta acción no se puede deshacer. + delete_failed_confirmation: ¿Estás seguro de que quieres eliminar esta exportación fallida? + destroy: + success: Exportación eliminada con éxito + export_not_ready: La exportación no está lista para descargar + exporting: Exportando... + index: + title: Exportaciones + new: Nueva exportación + no_exports: Aún no hay exportaciones. list: + export_from: "Exportación del %{date}" in_progress: En progreso complete: Completo failed: Fallido diff --git a/config/locales/views/family_exports/nb.yml b/config/locales/views/family_exports/nb.yml index be5e5b53e..dc61e3ca0 100644 --- a/config/locales/views/family_exports/nb.yml +++ b/config/locales/views/family_exports/nb.yml @@ -1,7 +1,21 @@ --- nb: family_exports: + access_denied: Tilgang nektet + create: + success: Eksport startet. Du vil kunne laste den ned snart. + delete_confirmation: Er du sikker på at du vil slette denne eksporten? Denne handlingen kan ikke angres. + delete_failed_confirmation: Er du sikker på at du vil slette denne mislykkede eksporten? + destroy: + success: Eksport slettet + export_not_ready: Eksport ikke klar for nedlasting + exporting: Eksporterer... + index: + title: Eksporter + new: Ny Eksport + no_exports: Ingen eksporter ennå. list: + export_from: "Eksport fra %{date}" in_progress: Pågår complete: Fullført failed: Mislykket diff --git a/config/locales/views/family_exports/pt-BR.yml b/config/locales/views/family_exports/pt-BR.yml index 78d35db25..6412e5c25 100644 --- a/config/locales/views/family_exports/pt-BR.yml +++ b/config/locales/views/family_exports/pt-BR.yml @@ -1,7 +1,21 @@ --- pt-BR: family_exports: + access_denied: Acesso negado + create: + success: Exportação iniciada. Você poderá baixá-la em breve. + delete_confirmation: Tem certeza de que deseja excluir esta exportação? Esta ação não pode ser desfeita. + delete_failed_confirmation: Tem certeza de que deseja excluir esta exportação falhada? + destroy: + success: Exportação excluída com sucesso + export_not_ready: Exportação não está pronta para download + exporting: Exportando... + index: + title: Exportações + new: Nova Exportação + no_exports: Nenhuma exportação ainda. list: - in_progress: Em andamento + export_from: "Exportação de %{date}" + in_progress: Em andamento complete: Concluído failed: Falhou diff --git a/config/locales/views/family_exports/ro.yml b/config/locales/views/family_exports/ro.yml index 24acbad98..a698a2043 100644 --- a/config/locales/views/family_exports/ro.yml +++ b/config/locales/views/family_exports/ro.yml @@ -1,7 +1,21 @@ --- ro: family_exports: + access_denied: Acces interzis + create: + success: Export început. Veți putea să-l descărcați în curând. + delete_confirmation: Sigur doriți să ștergeți acest export? Această acțiune nu poate fi anulată. + delete_failed_confirmation: Sigur doriți să ștergeți acest export eșuat? + destroy: + success: Export șters cu succes + export_not_ready: Exportul nu este gata pentru descărcare + exporting: Se exportă... + index: + title: Exporturi + new: Export nou + no_exports: Nu există încă exporturi. list: + export_from: "Export din %{date}" in_progress: În curs de desfășurare complete: Finalizat failed: Eșuat diff --git a/config/locales/views/family_exports/tr.yml b/config/locales/views/family_exports/tr.yml index db1da6c02..f62e43d32 100644 --- a/config/locales/views/family_exports/tr.yml +++ b/config/locales/views/family_exports/tr.yml @@ -1,7 +1,21 @@ --- tr: family_exports: + access_denied: Erişim reddedildi + create: + success: Dışa aktarma başladı. Kısa süre içinde indirebileceksiniz. + delete_confirmation: Bu dışa aktarma işlemini silmek istediğinizden emin misiniz? Bu işlem geri alınamaz. + delete_failed_confirmation: Bu başarısız dışa aktarma işlemini silmek istediğinizden emin misiniz? + destroy: + success: Dışa aktarma başarıyla silindi + export_not_ready: Dışa aktarma henüz indirmeye hazır değil + exporting: Dışa aktarılıyor... + index: + title: Dışa aktarmalar + new: Yeni Dışa Aktarma + no_exports: Henüz hiç dışa aktarma yok. list: + export_from: "%{date} tarihli dışa aktarma" in_progress: Devam ediyor complete: Tamamlandı failed: Başarısız diff --git a/config/locales/views/family_exports/zh-CN.yml b/config/locales/views/family_exports/zh-CN.yml index 4fef9a5f6..5373a5309 100644 --- a/config/locales/views/family_exports/zh-CN.yml +++ b/config/locales/views/family_exports/zh-CN.yml @@ -1,7 +1,21 @@ --- zh-CN: family_exports: + access_denied: 访问被拒绝 + create: + success: 导出已开始。您很快就能下载它。 + delete_confirmation: 确定要删除此导出吗?此操作无法撤销。 + delete_failed_confirmation: 确定要删除此失败的导出吗? + destroy: + success: 导出已成功删除 + export_not_ready: 导出尚未准备好下载 + exporting: 正在导出... + index: + title: 导出 + new: 新建导出 + no_exports: 暂无导出记录 list: + export_from: "导出自 %{date}" complete: 已完成 failed: 已失败 in_progress: 进行中 diff --git a/config/locales/views/family_exports/zh-TW.yml b/config/locales/views/family_exports/zh-TW.yml index 198743f08..88d3e3700 100644 --- a/config/locales/views/family_exports/zh-TW.yml +++ b/config/locales/views/family_exports/zh-TW.yml @@ -1,6 +1,12 @@ --- zh-TW: family_exports: + access_denied: 存取被拒絕 + create: + success: 匯出已開始。您很快就能下載它。 + destroy: + success: 匯出已成功刪除 + export_not_ready: 匯出尚未準備好下載 list: complete: 已完成 failed: 已失敗 diff --git a/config/locales/views/imports/ca.yml b/config/locales/views/imports/ca.yml index a02426e78..6613243aa 100644 --- a/config/locales/views/imports/ca.yml +++ b/config/locales/views/imports/ca.yml @@ -84,12 +84,12 @@ ca: uploading: Processant files view: Veure index: + title: Importacions + new: Nova importació exports: Exportacions imports: Importacions - new: Nova importació new_export: Nova exportació no_exports: Encara no hi ha exportacions. - title: Importa/Exporta new: description: Pots importar manualment diversos tipus de dades via CSV o utilitzar una de les nostres plantilles d'importació com Mint. diff --git a/config/locales/views/imports/de.yml b/config/locales/views/imports/de.yml index 0498c92bb..b2e5d1f97 100644 --- a/config/locales/views/imports/de.yml +++ b/config/locales/views/imports/de.yml @@ -58,12 +58,8 @@ de: uploading: Zeilen werden verarbeitet view: Anzeigen index: - imports: Importe + title: Importe new: Neuer Import - title: Import/Export - exports: Exporte - new_export: Neuer Export - no_exports: Noch keine Exporte vorhanden. new: description: Du kannst verschiedene Datentypen manuell über CSV importieren oder eine unserer Importvorlagen wie Mint verwenden. import_accounts: Konten importieren diff --git a/config/locales/views/imports/en.yml b/config/locales/views/imports/en.yml index be1b07806..d569d7be7 100644 --- a/config/locales/views/imports/en.yml +++ b/config/locales/views/imports/en.yml @@ -83,12 +83,8 @@ en: uploading: Processing rows view: View index: - imports: Imports + title: Imports new: New Import - title: Import/Export - exports: Exports - new_export: New Export - no_exports: No exports yet. new: description: You can manually import various types of data via CSV or use one of our import templates like Mint. diff --git a/config/locales/views/imports/es.yml b/config/locales/views/imports/es.yml index 0068520d4..9872391c4 100644 --- a/config/locales/views/imports/es.yml +++ b/config/locales/views/imports/es.yml @@ -62,12 +62,8 @@ es: uploading: Procesando filas view: Ver index: - imports: Importaciones + title: Importaciones new: Nueva importación - title: Importar/Exportar - exports: Exportaciones - new_export: Nueva exportación - no_exports: Aún no hay exportaciones. new: description: Puedes importar manualmente varios tipos de datos mediante CSV o usar una de nuestras plantillas de importación como Mint. import_accounts: Importar cuentas diff --git a/config/locales/views/imports/nb.yml b/config/locales/views/imports/nb.yml index c796426b0..a59a2d44f 100644 --- a/config/locales/views/imports/nb.yml +++ b/config/locales/views/imports/nb.yml @@ -71,12 +71,8 @@ nb: uploading: Behandler rader view: Vis index: - imports: Importer - new: Ny Import title: Importer - exports: Eksporter - new_export: Ny Eksport - no_exports: Ingen eksporter ennå. + new: Ny Import new: description: Du kan manuelt importere ulike typer data via CSV eller bruke en av våre importmaler som Mint. diff --git a/config/locales/views/imports/pt-BR.yml b/config/locales/views/imports/pt-BR.yml index 33350d79c..1750672e0 100644 --- a/config/locales/views/imports/pt-BR.yml +++ b/config/locales/views/imports/pt-BR.yml @@ -76,12 +76,8 @@ pt-BR: uploading: Processando linhas view: Visualizar index: - imports: Importações + title: Importações new: Nova Importação - title: Importar/Exportar - exports: Exportações - new_export: Nova Exportação - no_exports: Nenhuma exportação ainda. new: description: Você pode importar manualmente vários tipos de dados via CSV ou usar um de nossos modelos de importação, como o do Mint. diff --git a/config/locales/views/imports/ro.yml b/config/locales/views/imports/ro.yml index d257b3ebc..2da6f2436 100644 --- a/config/locales/views/imports/ro.yml +++ b/config/locales/views/imports/ro.yml @@ -58,12 +58,8 @@ ro: uploading: Se procesează rândurile view: Vezi index: - imports: Importuri + title: Importuri new: Import nou - title: Import/Export - exports: Exporturi - new_export: Export nou - no_exports: Nu există încă exporturi. new: description: Poți importa manual diverse tipuri de date prin CSV sau poți folosi unul dintre șabloanele noastre de import, cum ar fi Mint. import_accounts: Importă conturi diff --git a/config/locales/views/imports/tr.yml b/config/locales/views/imports/tr.yml index a9f389a83..c1abca033 100644 --- a/config/locales/views/imports/tr.yml +++ b/config/locales/views/imports/tr.yml @@ -58,12 +58,8 @@ tr: uploading: Satırlar işleniyor view: Görüntüle index: - imports: İçe aktarmalar - new: Yeni İçe Aktarma title: İçe aktarmalar - exports: Dışa aktarmalar - new_export: Yeni Dışa Aktarma - no_exports: Henüz hiç dışa aktarma yok. + new: Yeni İçe Aktarma new: description: Farklı veri türlerini CSV ile manuel olarak içe aktarabilir veya Mint gibi içe aktarma şablonlarımızı kullanabilirsiniz. import_accounts: Hesapları içe aktar diff --git a/config/locales/views/imports/zh-CN.yml b/config/locales/views/imports/zh-CN.yml index 952bff549..55e2cf8e3 100644 --- a/config/locales/views/imports/zh-CN.yml +++ b/config/locales/views/imports/zh-CN.yml @@ -66,12 +66,8 @@ zh-CN: uploading: 处理行数据中 view: 查看 index: - exports: 导出记录 - imports: 导入记录 + title: 导入记录 new: 新建导入 - new_export: 新建导出 - no_exports: 暂无导出记录 - title: 导入/导出管理 new: description: 您可以通过 CSV 手动导入多种类型数据,或使用我们的导入模板(如 Mint 格式)。 import_accounts: 导入账户 diff --git a/config/locales/views/settings/ca.yml b/config/locales/views/settings/ca.yml index 0dc0aba99..1fa11698e 100644 --- a/config/locales/views/settings/ca.yml +++ b/config/locales/views/settings/ca.yml @@ -127,8 +127,9 @@ ca: categories_label: Categories feedback_label: Feedback general_section_title: General + imports_label: Importacions + exports_label: Exportacions guides_label: Guies - imports_label: Importa/Exporta logout: Tanca la sessió merchants_label: Comerços other_section_title: Més diff --git a/config/locales/views/settings/de.yml b/config/locales/views/settings/de.yml index e38d21d0d..becf9ea7b 100644 --- a/config/locales/views/settings/de.yml +++ b/config/locales/views/settings/de.yml @@ -94,7 +94,8 @@ de: categories_label: Kategorien feedback_label: Feedback general_section_title: Allgemein - imports_label: Import/Export + imports_label: Importe + exports_label: Exporte logout: Abmelden merchants_label: Händler guides_label: Anleitungen diff --git a/config/locales/views/settings/en.yml b/config/locales/views/settings/en.yml index e84e9e056..cba0a4e9b 100644 --- a/config/locales/views/settings/en.yml +++ b/config/locales/views/settings/en.yml @@ -115,7 +115,8 @@ en: categories_label: Categories feedback_label: Feedback general_section_title: General - imports_label: Import/Export + imports_label: Imports + exports_label: Exports logout: Logout merchants_label: Merchants guides_label: Guides diff --git a/config/locales/views/settings/es.yml b/config/locales/views/settings/es.yml index 0079aa1d2..38ede64ff 100644 --- a/config/locales/views/settings/es.yml +++ b/config/locales/views/settings/es.yml @@ -95,7 +95,8 @@ es: categories_label: Categorías feedback_label: Comentarios general_section_title: General - imports_label: Importar/Exportar + imports_label: Importaciones + exports_label: Exportaciones logout: Cerrar sesión merchants_label: Comerciantes guides_label: Guías diff --git a/config/locales/views/settings/nb.yml b/config/locales/views/settings/nb.yml index 5c5354a17..098dd9f6a 100644 --- a/config/locales/views/settings/nb.yml +++ b/config/locales/views/settings/nb.yml @@ -81,6 +81,7 @@ nb: feedback_label: Tilbakemelding general_section_title: Generelt imports_label: Importer + exports_label: Eksporter logout: Logg ut merchants_label: Forhandlere other_section_title: Mer diff --git a/config/locales/views/settings/pt-BR.yml b/config/locales/views/settings/pt-BR.yml index f7c681495..06934d4ea 100644 --- a/config/locales/views/settings/pt-BR.yml +++ b/config/locales/views/settings/pt-BR.yml @@ -91,6 +91,7 @@ pt-BR: feedback_label: Feedback general_section_title: Geral imports_label: Importações + exports_label: Exportações logout: Sair merchants_label: Comerciantes other_section_title: Mais diff --git a/config/locales/views/settings/ro.yml b/config/locales/views/settings/ro.yml index ea473a5c5..3c5b7e091 100644 --- a/config/locales/views/settings/ro.yml +++ b/config/locales/views/settings/ro.yml @@ -98,7 +98,8 @@ ro: categories_label: Categorii feedback_label: Feedback general_section_title: General - imports_label: Import/Export + imports_label: Importuri + exports_label: Exporturi logout: Logout merchants_label: Comercianți guides_label: Ghiduri diff --git a/config/locales/views/settings/zh-CN.yml b/config/locales/views/settings/zh-CN.yml index 4b9d7bff3..c1263c352 100644 --- a/config/locales/views/settings/zh-CN.yml +++ b/config/locales/views/settings/zh-CN.yml @@ -101,7 +101,8 @@ zh-CN: feedback_label: 意见反馈 general_section_title: 通用设置 guides_label: 使用指南 - imports_label: 导入/导出 + imports_label: 导入记录 + exports_label: 导出记录 logout: 退出登录 merchants_label: 商户管理 other_section_title: 更多设置 diff --git a/test/controllers/family_exports_controller_test.rb b/test/controllers/family_exports_controller_test.rb index 017509bba..a7a820ae3 100644 --- a/test/controllers/family_exports_controller_test.rb +++ b/test/controllers/family_exports_controller_test.rb @@ -33,7 +33,7 @@ class FamilyExportsControllerTest < ActionDispatch::IntegrationTest post family_exports_path end - assert_redirected_to imports_path + assert_redirected_to family_exports_path assert_equal "Export started. You'll be able to download it shortly.", flash[:notice] export = @family.family_exports.last @@ -67,7 +67,7 @@ class FamilyExportsControllerTest < ActionDispatch::IntegrationTest export = @family.family_exports.create!(status: "processing") get download_family_export_path(export) - assert_redirected_to imports_path + assert_redirected_to family_exports_path assert_equal "Export not ready for download", flash[:alert] end @@ -78,7 +78,7 @@ class FamilyExportsControllerTest < ActionDispatch::IntegrationTest delete family_export_path(export) end - assert_redirected_to imports_path + assert_redirected_to family_exports_path assert_equal "Export deleted successfully", flash[:notice] end @@ -95,7 +95,7 @@ class FamilyExportsControllerTest < ActionDispatch::IntegrationTest delete family_export_path(export) end - assert_redirected_to imports_path + assert_redirected_to family_exports_path assert_equal "Export deleted successfully", flash[:notice] end @@ -112,7 +112,7 @@ class FamilyExportsControllerTest < ActionDispatch::IntegrationTest delete family_export_path(export) end - assert_redirected_to imports_path + assert_redirected_to family_exports_path assert_equal "Export deleted successfully", flash[:notice] end