decidim-core 0.30.5 → 0.30.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/announcement_cell.rb +10 -2
  3. data/app/cells/decidim/attachments_file_tab/show.erb +1 -1
  4. data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +5 -1
  5. data/app/cells/decidim/content_blocks/participatory_space_metadata/content.erb +2 -2
  6. data/app/cells/decidim/nav_links/show.erb +2 -2
  7. data/app/cells/decidim/report_button/already_reported_modal.erb +1 -1
  8. data/app/cells/decidim/report_button/flag_modal.erb +1 -1
  9. data/app/cells/decidim/report_user_button/already_reported_modal.erb +1 -1
  10. data/app/cells/decidim/report_user_button/flag_modal.erb +1 -1
  11. data/app/cells/decidim/statistic/show.erb +4 -4
  12. data/app/cells/decidim/upload_modal/files.erb +16 -8
  13. data/app/cells/decidim/upload_modal_cell.rb +21 -5
  14. data/app/commands/decidim/multiple_attachments_methods.rb +20 -3
  15. data/app/controllers/concerns/decidim/direct_upload.rb +2 -12
  16. data/app/controllers/decidim/devise/sessions_controller.rb +7 -0
  17. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +2 -2
  18. data/app/jobs/decidim/export_participatory_space_job.rb +1 -1
  19. data/app/jobs/decidim/find_and_update_descendants_job.rb +8 -2
  20. data/app/jobs/decidim/update_search_indexes_job.rb +2 -2
  21. data/app/models/decidim/attachment.rb +22 -1
  22. data/app/packs/src/decidim/a11y.js +29 -0
  23. data/app/packs/src/decidim/a11y.test.js +81 -0
  24. data/app/packs/src/decidim/confirm.js +8 -1
  25. data/app/packs/src/decidim/confirm.test.js +225 -0
  26. data/app/packs/src/decidim/direct_uploads/upload_field.js +1 -1
  27. data/app/packs/src/decidim/focus_guard.js +4 -4
  28. data/app/packs/stylesheets/decidim/_cards.scss +12 -4
  29. data/app/packs/stylesheets/decidim/_modal_update.scss +1 -1
  30. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +1 -1
  31. data/app/services/decidim/open_data_exporter.rb +1 -1
  32. data/app/views/decidim/devise/invitations/edit.html.erb +3 -3
  33. data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +1 -1
  34. data/config/initializers/devise.rb +6 -0
  35. data/config/locales/ar.yml +3 -3
  36. data/config/locales/bg.yml +0 -4
  37. data/config/locales/ca-IT.yml +12 -6
  38. data/config/locales/ca.yml +12 -6
  39. data/config/locales/cs.yml +23 -8
  40. data/config/locales/de.yml +4 -8
  41. data/config/locales/el.yml +1 -2
  42. data/config/locales/en.yml +10 -4
  43. data/config/locales/es-MX.yml +13 -7
  44. data/config/locales/es-PY.yml +13 -7
  45. data/config/locales/es.yml +15 -9
  46. data/config/locales/eu.yml +13 -10
  47. data/config/locales/fi-plain.yml +5 -4
  48. data/config/locales/fi.yml +6 -5
  49. data/config/locales/fr-CA.yml +11 -5
  50. data/config/locales/fr.yml +13 -7
  51. data/config/locales/gl.yml +0 -2
  52. data/config/locales/hu.yml +5 -9
  53. data/config/locales/id-ID.yml +0 -2
  54. data/config/locales/it.yml +1 -3
  55. data/config/locales/ja.yml +11 -8
  56. data/config/locales/lb.yml +0 -2
  57. data/config/locales/lt.yml +1 -3
  58. data/config/locales/lv.yml +0 -2
  59. data/config/locales/nl.yml +0 -2
  60. data/config/locales/no.yml +0 -2
  61. data/config/locales/pl.yml +0 -4
  62. data/config/locales/pt-BR.yml +29 -5
  63. data/config/locales/pt.yml +0 -2
  64. data/config/locales/ro-RO.yml +5 -6
  65. data/config/locales/ru.yml +0 -2
  66. data/config/locales/sk.yml +0 -4
  67. data/config/locales/sv.yml +254 -31
  68. data/config/locales/tr-TR.yml +17 -5
  69. data/config/locales/zh-CN.yml +0 -2
  70. data/config/locales/zh-TW.yml +1 -3
  71. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +1 -1
  72. data/lib/decidim/core/version.rb +1 -1
  73. data/lib/decidim/form_builder.rb +40 -6
  74. data/lib/decidim/maintenance/taxonomy_importer.rb +1 -1
  75. data/lib/decidim/searchable.rb +4 -4
  76. metadata +8 -6
@@ -0,0 +1,225 @@
1
+ /* global jest */
2
+
3
+ jest.mock("src/decidim/icon", () => () => "<svg></svg>");
4
+
5
+ describe("Confirm dialog for button[type='button']", () => {
6
+ let mockRails = null;
7
+ let mockDecidim = null;
8
+
9
+ beforeEach(() => {
10
+ jest.clearAllMocks();
11
+ document.body.innerHTML = `
12
+ <div id="confirm-modal" style="display: none;">
13
+ <div data-dialog-title></div>
14
+ <div class="confirm-modal-icon"></div>
15
+ <div data-confirm-modal-content></div>
16
+ <button data-confirm-ok>Confirm</button>
17
+ <button data-confirm-cancel>Cancel</button>
18
+ </div>
19
+ `;
20
+
21
+ mockRails = {
22
+ linkClickSelector: "a[data-confirm]",
23
+ buttonClickSelector: "button[data-confirm]:not([form])",
24
+ formInputClickSelector: 'form button[type="submit"], form button:not([type])',
25
+ inputChangeSelector: "input[data-confirm], select[data-confirm]",
26
+ formSubmitSelector: "form[data-confirm]",
27
+ stopEverything: jest.fn(),
28
+ fire: jest.fn((el, event) => {
29
+ const evt = new CustomEvent(event);
30
+ el.dispatchEvent(evt);
31
+ return true;
32
+ }),
33
+ matches: function(element, selector) {
34
+ if (element instanceof Element) {
35
+ return element.matches(selector);
36
+ }
37
+ return false;
38
+ }
39
+ };
40
+
41
+ mockDecidim = {
42
+ currentDialogs: {
43
+ "confirm-modal": {
44
+ open: jest.fn(),
45
+ close: jest.fn()
46
+ }
47
+ }
48
+ };
49
+
50
+ window.Rails = mockRails;
51
+ window.Decidim = mockDecidim;
52
+ });
53
+
54
+ afterEach(() => {
55
+ document.body.innerHTML = "";
56
+ });
57
+
58
+ describe("selector matching for button[type='button'] with data-confirm", () => {
59
+ it("matches button[data-confirm][type='button'] selector", () => {
60
+ const button = document.createElement("button");
61
+ button.type = "button";
62
+ button.setAttribute("data-confirm", "Are you sure?");
63
+
64
+ expect(button.matches('button[data-confirm][type="button"]')).toBe(true);
65
+ });
66
+
67
+ it("matches form button[data-confirm] selector", () => {
68
+ const form = document.createElement("form");
69
+ const button = document.createElement("button");
70
+ button.setAttribute("data-confirm", "Are you sure?");
71
+ form.appendChild(button);
72
+
73
+ expect(button.matches("form button[data-confirm]")).toBe(true);
74
+ });
75
+
76
+ it("does not match regular button without data-confirm", () => {
77
+ const button = document.createElement("button");
78
+ button.type = "button";
79
+
80
+ expect(button.matches('button[data-confirm][type="button"]')).toBe(false);
81
+ });
82
+
83
+ it("does not match button[type='submit'] with the type='button' selector", () => {
84
+ const button = document.createElement("button");
85
+ button.type = "submit";
86
+ button.setAttribute("data-confirm", "Are you sure?");
87
+
88
+ expect(button.matches('button[data-confirm][type="button"]')).toBe(false);
89
+ });
90
+
91
+ it("matches button[type='button'] inside form", () => {
92
+ document.body.innerHTML = `
93
+ <form>
94
+ <button type="button" data-confirm="Test message">Click me</button>
95
+ </form>
96
+ `;
97
+
98
+ const button = document.querySelector('button[type="button"]');
99
+ expect(button.matches('button[data-confirm][type="button"]')).toBe(true);
100
+ expect(button.matches("form button[data-confirm]")).toBe(true);
101
+ });
102
+
103
+ it("does not match button[type='button'] without data-confirm inside form", () => {
104
+ document.body.innerHTML = `
105
+ <form>
106
+ <button type="button">Click me</button>
107
+ </form>
108
+ `;
109
+
110
+ const button = document.querySelector('button[type="button"]');
111
+ expect(button.matches('button[data-confirm][type="button"]')).toBe(false);
112
+ expect(button.matches("form button[data-confirm]")).toBe(false);
113
+ });
114
+ });
115
+
116
+ describe("initializeConfirm - selectors registration", () => {
117
+ it("adds click event listener with proper selectors including button[type='button'] support", async () => {
118
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
119
+
120
+ const addEventListenerSpy = jest.spyOn(document, "addEventListener");
121
+
122
+ initializeConfirm();
123
+
124
+ expect(addEventListenerSpy).toHaveBeenCalledWith("click", expect.any(Function));
125
+ });
126
+
127
+ it("adds change event listener for input change selector", async () => {
128
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
129
+
130
+ const addEventListenerSpy = jest.spyOn(document, "addEventListener");
131
+
132
+ initializeConfirm();
133
+
134
+ const changeHandlerCalls = addEventListenerSpy.mock.calls.filter(
135
+ (call) => call[0] === "change"
136
+ );
137
+ expect(changeHandlerCalls.length).toBeGreaterThan(0);
138
+ });
139
+
140
+ it("adds submit event listener for form submit selector", async () => {
141
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
142
+
143
+ const addEventListenerSpy = jest.spyOn(document, "addEventListener");
144
+
145
+ initializeConfirm();
146
+
147
+ const submitHandlerCalls = addEventListenerSpy.mock.calls.filter(
148
+ (call) => call[0] === "submit"
149
+ );
150
+ expect(submitHandlerCalls.length).toBeGreaterThan(0);
151
+ });
152
+
153
+ it("adds DOMContentLoaded event listener for Foundation Abide compatibility", async () => {
154
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
155
+
156
+ const addEventListenerSpy = jest.spyOn(document, "addEventListener");
157
+
158
+ initializeConfirm();
159
+
160
+ const turboLoadCalls = addEventListenerSpy.mock.calls.filter(
161
+ (call) => call[0] === "DOMContentLoaded"
162
+ );
163
+ expect(turboLoadCalls.length).toBeGreaterThan(0);
164
+ });
165
+ });
166
+
167
+ describe("handleDocumentEvent with button[type='button'] support", () => {
168
+ it("handles click on button[type='button'] with data-confirm and form attribute", async () => {
169
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
170
+
171
+ document.body.innerHTML = `
172
+ <form id="my-form">
173
+ <button type="button" form="my-form" data-confirm="Are you sure?">Click me</button>
174
+ </form>
175
+ `;
176
+
177
+ const button = document.querySelector('button[type="button"]');
178
+ const openSpy = jest.spyOn(mockDecidim.currentDialogs["confirm-modal"], "open");
179
+
180
+ initializeConfirm();
181
+
182
+ button.click();
183
+
184
+ expect(openSpy).toHaveBeenCalled();
185
+ });
186
+
187
+ it("handles click on button[type='button'] with data-confirm outside form", async () => {
188
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
189
+
190
+ document.body.innerHTML = `
191
+ <button type="button" data-confirm="Are you sure?">Click me</button>
192
+ `;
193
+
194
+ const button = document.querySelector('button[type="button"]');
195
+ const openSpy = jest.spyOn(mockDecidim.currentDialogs["confirm-modal"], "open");
196
+
197
+ initializeConfirm();
198
+
199
+ button.click();
200
+
201
+ expect(openSpy).toHaveBeenCalled();
202
+ });
203
+
204
+ it("does not trigger confirm for button without data-confirm attribute", async () => {
205
+ const { initializeConfirm } = await import("src/decidim/confirm.js");
206
+
207
+ document.body.innerHTML = `
208
+ <form>
209
+ <button type="button">Click me</button>
210
+ </form>
211
+ `;
212
+
213
+ const button = document.querySelector('button[type="button"]');
214
+ const openSpy = jest.spyOn(mockDecidim.currentDialogs["confirm-modal"], "open");
215
+
216
+ initializeConfirm();
217
+
218
+ button.click();
219
+
220
+ expect(openSpy).not.toHaveBeenCalled();
221
+ });
222
+ });
223
+ });
224
+
225
+ /* dummy end */
@@ -79,7 +79,7 @@ const updateActiveUploads = (modal) => {
79
79
  const template = `
80
80
  <div ${attachmentIdOrHiddenField} data-filename="${escapeQuotes(file.name)}" data-title="${escapeQuotes(title)}">
81
81
  ${(/image/).test(file.type) && "<div><img src=\"data:,\" role=\"presentation\" /></div>" || ""}
82
- <span>${escapeHtml(title)}</span>
82
+ <p>${escapeHtml(title)}</p>
83
83
  ${hidden}
84
84
  </div>
85
85
  `
@@ -78,16 +78,16 @@ export default class FocusGuard {
78
78
 
79
79
  let target = null;
80
80
  if (guard.dataset.position === "start") {
81
- // Focus at the start guard, so focus the first focusable element after that
82
- for (let ind = 0; ind < visibleNodes.length; ind += 1) {
81
+ // Focus at the start guard, so focus the last focusable element (cycle forward to end)
82
+ for (let ind = visibleNodes.length - 1; ind >= 0; ind -= 1) {
83
83
  if (!this.isFocusGuard(visibleNodes[ind]) && this.isFocusable(visibleNodes[ind])) {
84
84
  target = visibleNodes[ind];
85
85
  break;
86
86
  }
87
87
  }
88
88
  } else {
89
- // Focus at the end guard, so focus the first focusable element after that
90
- for (let ind = visibleNodes.length - 1; ind >= 0; ind -= 1) {
89
+ // Focus at the end guard, so focus the first focusable element (cycle back to start)
90
+ for (let ind = 0; ind < visibleNodes.length; ind += 1) {
91
91
  if (!this.isFocusGuard(visibleNodes[ind]) && this.isFocusable(visibleNodes[ind])) {
92
92
  target = visibleNodes[ind];
93
93
  break;
@@ -116,7 +116,7 @@
116
116
  }
117
117
 
118
118
  &__calendar {
119
- @apply w-14 flex flex-col justify-start rounded overflow-hidden bg-background text-center;
119
+ @apply w-20 flex flex-col justify-start rounded overflow-hidden bg-background text-center;
120
120
 
121
121
  /* overwrite defaults */
122
122
  &-list__reset {
@@ -128,17 +128,25 @@
128
128
  }
129
129
 
130
130
  &-day {
131
- @apply text-black text-2xl font-bold;
131
+ @apply text-black text-xl font-semibold;
132
132
  }
133
133
 
134
134
  &-year {
135
- @apply text-black text-xs;
135
+ @apply text-black text-xs mb-0.5;
136
136
  }
137
137
 
138
138
  &-month,
139
139
  &-day,
140
140
  &-year {
141
- @apply inline-flex items-center justify-evenly empty:[&>div]:hidden;
141
+ @apply inline-flex items-center justify-center empty:[&>div]:hidden;
142
+ }
143
+
144
+ &-separator {
145
+ @apply mx-2 font-normal text-sm;
146
+ }
147
+
148
+ .card__list-content {
149
+ @apply mt-0.5;
142
150
  }
143
151
  }
144
152
 
@@ -131,7 +131,7 @@
131
131
  @apply w-full rounded bg-background flex items-center justify-center py-4 [&_img]:object-cover [&_img]:h-[200px];
132
132
  }
133
133
 
134
- span {
134
+ p {
135
135
  @apply text-sm text-gray-2 mx-auto w-full break-all mb-2;
136
136
  }
137
137
  }
@@ -99,7 +99,7 @@
99
99
  @apply divide-y divide-white [&>li]:py-3.5 first:[&>li]:pt-0 last:[&>li]:pb-0;
100
100
 
101
101
  &-container {
102
- @apply ml-0 md:ml-6 bg-primary p-3 md:p-6 rounded w-full md:w-auto self-start;
102
+ @apply mb-8 ml-0 md:ml-6 bg-primary p-3 md:p-6 rounded w-full md:w-auto self-start;
103
103
 
104
104
  [id*="dropdown-menu"] {
105
105
  @apply mx-0;
@@ -117,7 +117,7 @@ module Decidim
117
117
 
118
118
  def data_for_participatory_space(export_manifest)
119
119
  collection = participatory_spaces.filter { |space| space.manifest.name == export_manifest.manifest.name }.flat_map do |participatory_space|
120
- export_manifest.collection.call(participatory_space)
120
+ export_manifest.collection.call(participatory_space, nil)
121
121
  end
122
122
 
123
123
  serializer = export_manifest.open_data_serializer.nil? ? export_manifest.serializer : export_manifest.open_data_serializer
@@ -4,7 +4,7 @@
4
4
  <h1 class="title-decorator inline-block text-left mb-12"><%= t "devise.invitations.edit.header" %></h1>
5
5
 
6
6
  <p class="text-lg text-gray-2">
7
- <%= t("devise.invitations.edit.subtitle").html_safe %>
7
+ <%= current_organization.users_registration_mode_disabled? ? t("devise.invitations.edit.subtitle_no_password").html_safe : t("devise.invitations.edit.subtitle").html_safe %>
8
8
  </p>
9
9
  </div>
10
10
 
@@ -16,8 +16,8 @@
16
16
 
17
17
  <%= f.text_field :nickname, help_text: t("devise.invitations.edit.nickname_help", organization: current_organization_name), required: "required", autocomplete: "nickname" %>
18
18
 
19
- <% if f.object.class.require_password_on_accepting %>
20
- <%= render partial: "decidim/account/password_fields", locals: { form: f, user: :user } %>
19
+ <% unless current_organization.users_registration_mode_disabled? %>
20
+ <%= render partial: "decidim/account/password_fields", locals: { form: f, user: resource.admin? ? :admin : :user } %>
21
21
  <% end %>
22
22
  </div>
23
23
 
@@ -31,7 +31,7 @@
31
31
  </div>
32
32
  <% end %>
33
33
 
34
- <p class="h3 mt-2"><%= t("decidim.block_user_mailer.notify.hello") %>&nbsp;<%= current_user.name %></p>
34
+ <p class="h3 mt-2"><%= t("layouts.decidim.header.mobile_account_greeting", user_name: current_user.name) %></p>
35
35
 
36
36
  <ul>
37
37
  <%= render partial: "layouts/decidim/header/main_links_dropdown" %>
@@ -175,6 +175,12 @@ Devise.setup do |config|
175
175
  # Default: true
176
176
  config.allow_insecure_sign_in_after_accept = true
177
177
 
178
+ # Require password when user accepts the invitation.
179
+ # Disable if you do not want to ask for or enforce setting a password while accepting,
180
+ # because it is set when the user is invited or will be set later.
181
+ # Default: true
182
+ config.require_password_on_accepting = false
183
+
178
184
  # A period that the user is allowed to confirm their account before their
179
185
  # token becomes invalid. For example, if set to 3.days, the user can confirm
180
186
  # their account within 3 days after the mail was sent, but on the fourth day
@@ -1330,8 +1330,6 @@ ar:
1330
1330
  submit_button: ارسل دعوة
1331
1331
  no_invitations_remaining: لا توجد دعوات متبقية
1332
1332
  send_instructions: تم إرسال دعوة بريد إلكتروني إلى %{email}.
1333
- updated: تم ضبط كلمة مرورك بنجاح. انت الآن مسجل دخولك.
1334
- updated_not_active: تم ضبط كلمة مرورك بنجاح.
1335
1333
  mailer:
1336
1334
  confirmation_instructions:
1337
1335
  action: تأكيد حسابي
@@ -1393,6 +1391,7 @@ ar:
1393
1391
  links:
1394
1392
  back: الى الخلف
1395
1393
  forgot_your_password: نسيت رقمك السري؟
1394
+ log_in: تسجيل الدخول
1396
1395
  log_in_with_provider: تسجيل الدخول باستخدام %{provider}
1397
1396
  minimum_password_length:
1398
1397
  zero: "(%{count} حرف كحد أدنى)"
@@ -1481,7 +1480,7 @@ ar:
1481
1480
  description: وصف
1482
1481
  name: اسم
1483
1482
  service: الخدمة
1484
- type: نوع
1483
+ type: النوع
1485
1484
  items:
1486
1485
  _session_id:
1487
1486
  description: يسمح للمواقع بتذكر المستخدم داخل الموقع عندما ينتقل بين صفحات الويب.
@@ -1531,6 +1530,7 @@ ar:
1531
1530
  data_consent_settings: إعدادات ملفات تعريف الارتباط
1532
1531
  decidim_logo: شعار Decidim
1533
1532
  decidim_title: Decidim
1533
+ log_in: تسجيل الدخول
1534
1534
  made_with_open_source: موقع تم إنشاؤه <a target="_blank" href="https://github.com/decidim/decidim">بالبرمجيات الحرة</a>.
1535
1535
  resources: الموارد
1536
1536
  header:
@@ -1550,8 +1550,6 @@ bg:
1550
1550
  submit_button: Изпрати покана
1551
1551
  no_invitations_remaining: Няма останали покани
1552
1552
  send_instructions: Писмо с покана беше изпратено до %{email}.
1553
- updated: Вашата парола беше зададена успешно. Вече сте влезли.
1554
- updated_not_active: Вашата парола беше зададена успешно.
1555
1553
  mailer:
1556
1554
  confirmation_instructions:
1557
1555
  action: Потвърди профила ми
@@ -1608,8 +1606,6 @@ bg:
1608
1606
  confirm_new_password: Потвърди нова парола
1609
1607
  new_password: Нова парола
1610
1608
  old_password_help: За да потвърдите промените във вашия акаунт, моля, въведете текущата си парола.
1611
- password_help: "Минимум %{minimum_characters} символа, не трябва да са разпространени (например, 123456) и трябва да са различни от вашите име и ел. поща."
1612
- password_help_admin: "Минимум %{minimum_characters} символа, не трябва да са разпространени (например, 123456) и трябва да са различни от вашите име и ел. поща."
1613
1609
  title: Промяна на паролата
1614
1610
  new:
1615
1611
  forgot_your_password: Забравили сте паролата си?
@@ -1120,6 +1120,9 @@ ca-IT:
1120
1120
  explanation: 'Instruccions per a la imatge:'
1121
1121
  message_1: Preferiblement una imatge apaïsada que no tingui cap text.
1122
1122
  message_2: El servei retalla la imatge.
1123
+ import_file:
1124
+ explanation: 'Instruccions per al fitxer d''importació:'
1125
+ message_1: Ha de ser un document JSON descarregat mitjançant la funció d'exportació.
1123
1126
  file_validation:
1124
1127
  allowed_file_extensions: 'Tipus de fitxers admesos: %{extensions}'
1125
1128
  max_file_dimension: 'Mides máximes de l''arxiu: %{resolution} pixels'
@@ -1618,7 +1621,7 @@ ca-IT:
1618
1621
  download:
1619
1622
  components: Components
1620
1623
  core: Nucli
1621
- spaces: Espai participatiu
1624
+ spaces: Espais de participació
1622
1625
  title: Descarregar recursos
1623
1626
  download_open_data: Descarrega tots els fitxers de dades obertes
1624
1627
  download_resource: Descarregar "%{resource_name}" en format CSV
@@ -1736,7 +1739,7 @@ ca-IT:
1736
1739
  actions:
1737
1740
  create_user_group: Crea un grup
1738
1741
  disabled_message: Missatge
1739
- edit_profile: Edita el perfil
1742
+ edit_profile: Editar el perfil
1740
1743
  edit_user_group: Edita el perfil del grup
1741
1744
  invite_user: Convida la participant
1742
1745
  join_user_group: Sol·licita unir-se al grup
@@ -1971,6 +1974,7 @@ ca-IT:
1971
1974
  send_paranoid_instructions: Si la teva adreça de correu electrònic existeix a la nostra base de dades, rebràs un correu electrònic amb instruccions per confirmar la teva adreça en pocs minuts.
1972
1975
  failure:
1973
1976
  already_authenticated: Ja has iniciat la sessió.
1977
+ csrf_token: No es pot verificar la teva sol·licitud. Si us plau, torna a provar-ho.
1974
1978
  inactive: El teu compte encara no està activat.
1975
1979
  invalid: El %{authentication_keys} o la contrasenya no són vàlids.
1976
1980
  invited: Tens una invitació pendent, accepta-la per acabar de crear el teu compte.
@@ -1985,6 +1989,7 @@ ca-IT:
1985
1989
  nickname_help: El teu àlies a %{organization}. Només pot contenir lletres, números, '-' i '_'.
1986
1990
  submit_button: Desa
1987
1991
  subtitle: Si acceptes la invitació, si us plau, estableix el teu àlies i contrasenya.
1992
+ subtitle_no_password: Si acceptes la invitació, si us plau, estableix el teu àlies o sobrenom.
1988
1993
  invitation_removed: S'ha eliminat la teva invitació.
1989
1994
  invitation_token_invalid: El token de invitació proporcionat no és vàlid!
1990
1995
  new:
@@ -1992,8 +1997,8 @@ ca-IT:
1992
1997
  submit_button: Enviar una invitació
1993
1998
  no_invitations_remaining: No queden invitacions
1994
1999
  send_instructions: S'ha enviat una invitació via correu electrònic a %{email}.
1995
- updated: La teva contrasenya s'ha establert correctament. Ja has iniciat sessió.
1996
- updated_not_active: La teva contrasenya s'ha establert correctament.
2000
+ updated: La invitació s'ha acceptat correctament. S'ha iniciat la teva sessió.
2001
+ updated_not_active: La invitació s'ha acceptat correctament.
1997
2002
  mailer:
1998
2003
  confirmation_instructions:
1999
2004
  action: Confirma el meu compte
@@ -2052,8 +2057,8 @@ ca-IT:
2052
2057
  confirm_new_password: Confirmar la nova contrasenya
2053
2058
  new_password: Nova contrasenya
2054
2059
  old_password_help: Per tal de confirmar els canvis al teu compte, si us plau, proporciona'ns la teva contrasenya actual.
2055
- password_help: "%{minimum_characters} caràcters mínim, no ha de ser massa comú (per exemple 123456) i ha de ser diferent del teu àlies i la teva adreça de correu electrònic."
2056
- password_help_admin: "%{minimum_characters} caràcters mínim, no ha de ser massa comú (per exemple 123456) i ha de ser diferent del teu àlies, del teu correu electrònic i de les teves antigues contrasenyes."
2060
+ password_help: "La contrasenya ha de tenir com a mínim %{minimum_characters} caràcters, d'aquests, almenys 5 caràcters han de ser diferents, no han de ser massa comuns (p. ex. 123456) i ha de ser diferent del número, sobrenom, correu electrònic i del domini de la plataforma."
2061
+ password_help_admin: "La contrasenya ha de tenir com a mínim %{minimum_characters} caràcters, d'aquests, almenys 5 caràcters han de ser diferents, no han de ser massa comuns (p. ex. 123456) i ha de ser diferent del número, sobrenom, correu electrònic, domini de la plataforma o contrasenyes antigues."
2057
2062
  title: Canvi de contrasenya
2058
2063
  new:
2059
2064
  forgot_your_password: Has oblidat la teva contrasenya?
@@ -2296,6 +2301,7 @@ ca-IT:
2296
2301
  confirm_close_ephemeral_session: Si navegues fora d'aquesta pàgina, la teva sessió es tancarà. Segur que vols sortir d'aquesta pàgina?
2297
2302
  log_in: Entra
2298
2303
  main_menu: Menú principal
2304
+ mobile_account_greeting: Hola %{user_name},
2299
2305
  user_menu: Menú d'usuari
2300
2306
  impersonation_warning:
2301
2307
  close_session: Tanca la sessió
@@ -1120,6 +1120,9 @@ ca:
1120
1120
  explanation: 'Instruccions per a la imatge:'
1121
1121
  message_1: Preferiblement una imatge apaïsada que no tingui cap text.
1122
1122
  message_2: El servei retalla la imatge.
1123
+ import_file:
1124
+ explanation: 'Instruccions per al fitxer d''importació:'
1125
+ message_1: Ha de ser un document JSON descarregat mitjançant la funció d'exportació.
1123
1126
  file_validation:
1124
1127
  allowed_file_extensions: 'Tipus de fitxers admesos: %{extensions}'
1125
1128
  max_file_dimension: 'Mides máximes de l''arxiu: %{resolution} pixels'
@@ -1618,7 +1621,7 @@ ca:
1618
1621
  download:
1619
1622
  components: Components
1620
1623
  core: Nucli
1621
- spaces: Espai participatiu
1624
+ spaces: Espais de participació
1622
1625
  title: Descarregar recursos
1623
1626
  download_open_data: Descarrega tots els fitxers de dades obertes
1624
1627
  download_resource: Descarregar "%{resource_name}" en format CSV
@@ -1736,7 +1739,7 @@ ca:
1736
1739
  actions:
1737
1740
  create_user_group: Crea un grup
1738
1741
  disabled_message: Missatge
1739
- edit_profile: Edita el perfil
1742
+ edit_profile: Editar el perfil
1740
1743
  edit_user_group: Edita el perfil del grup
1741
1744
  invite_user: Convida la participant
1742
1745
  join_user_group: Sol·licita unir-se al grup
@@ -1971,6 +1974,7 @@ ca:
1971
1974
  send_paranoid_instructions: Si la teva adreça de correu electrònic existeix a la nostra base de dades, rebràs un correu electrònic amb instruccions per confirmar la teva adreça en pocs minuts.
1972
1975
  failure:
1973
1976
  already_authenticated: Ja has iniciat la sessió.
1977
+ csrf_token: No es pot verificar la teva sol·licitud. Si us plau, torna a provar-ho.
1974
1978
  inactive: El teu compte encara no està activat.
1975
1979
  invalid: El %{authentication_keys} o la contrasenya no són vàlids.
1976
1980
  invited: Tens una invitació pendent, accepta-la per acabar de crear el teu compte.
@@ -1985,6 +1989,7 @@ ca:
1985
1989
  nickname_help: El teu àlies a %{organization}. Només pot contenir lletres, números, '-' i '_'.
1986
1990
  submit_button: Desa
1987
1991
  subtitle: Si acceptes la invitació, si us plau, estableix el teu àlies i contrasenya.
1992
+ subtitle_no_password: Si acceptes la invitació, si us plau, estableix el teu àlies o sobrenom.
1988
1993
  invitation_removed: S'ha eliminat la teva invitació.
1989
1994
  invitation_token_invalid: El token de invitació proporcionat no és vàlid!
1990
1995
  new:
@@ -1992,8 +1997,8 @@ ca:
1992
1997
  submit_button: Enviar una invitació
1993
1998
  no_invitations_remaining: No queden invitacions
1994
1999
  send_instructions: S'ha enviat una invitació via correu electrònic a %{email}.
1995
- updated: La teva contrasenya s'ha establert correctament. Ja has iniciat sessió.
1996
- updated_not_active: La teva contrasenya s'ha establert correctament.
2000
+ updated: La invitació s'ha acceptat correctament. S'ha iniciat la teva sessió.
2001
+ updated_not_active: La invitació s'ha acceptat correctament.
1997
2002
  mailer:
1998
2003
  confirmation_instructions:
1999
2004
  action: Confirma el meu compte
@@ -2052,8 +2057,8 @@ ca:
2052
2057
  confirm_new_password: Confirmar la nova contrasenya
2053
2058
  new_password: Nova contrasenya
2054
2059
  old_password_help: Per tal de confirmar els canvis al teu compte, si us plau, proporciona'ns la teva contrasenya actual.
2055
- password_help: "%{minimum_characters} caràcters mínim, no ha de ser massa comú (per exemple 123456) i ha de ser diferent del teu àlies i la teva adreça de correu electrònic."
2056
- password_help_admin: "%{minimum_characters} caràcters mínim, no ha de ser massa comú (per exemple 123456) i ha de ser diferent del teu àlies, del teu correu electrònic i de les teves antigues contrasenyes."
2060
+ password_help: "La contrasenya ha de tenir com a mínim %{minimum_characters} caràcters, d'aquests, almenys 5 caràcters han de ser diferents, no han de ser massa comuns (p. ex. 123456) i ha de ser diferent del número, sobrenom, correu electrònic i del domini de la plataforma."
2061
+ password_help_admin: "La contrasenya ha de tenir com a mínim %{minimum_characters} caràcters, d'aquests, almenys 5 caràcters han de ser diferents, no han de ser massa comuns (p. ex. 123456) i ha de ser diferent del número, sobrenom, correu electrònic, domini de la plataforma o contrasenyes antigues."
2057
2062
  title: Canvi de contrasenya
2058
2063
  new:
2059
2064
  forgot_your_password: Has oblidat la teva contrasenya?
@@ -2296,6 +2301,7 @@ ca:
2296
2301
  confirm_close_ephemeral_session: Si navegues fora d'aquesta pàgina, la teva sessió es tancarà. Segur que vols sortir d'aquesta pàgina?
2297
2302
  log_in: Entra
2298
2303
  main_menu: Menú principal
2304
+ mobile_account_greeting: Hola %{user_name},
2299
2305
  user_menu: Menú d'usuari
2300
2306
  impersonation_warning:
2301
2307
  close_session: Tanca la sessió