blacklight-spotlight 3.0.0.alpha.10 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/spotlight/admin/crop.es6 +6 -0
  3. data/app/assets/javascripts/spotlight/admin/sir-trevor/block_controls.js +21 -12
  4. data/app/assets/stylesheets/spotlight/_featured_browse_categories_block.scss +4 -4
  5. data/app/assets/stylesheets/spotlight/_item_text_block.scss +6 -0
  6. data/app/assets/stylesheets/spotlight/_report_a_problem.scss +5 -2
  7. data/app/controllers/spotlight/resources/csv_upload_controller.rb +1 -1
  8. data/app/jobs/spotlight/add_uploads_from_csv.rb +30 -5
  9. data/app/mailers/spotlight/indexing_complete_mailer.rb +3 -2
  10. data/app/models/spotlight/contact.rb +1 -1
  11. data/app/models/spotlight/custom_field.rb +3 -3
  12. data/app/models/spotlight/featured_image.rb +1 -1
  13. data/app/models/spotlight/page_configurations.rb +1 -0
  14. data/app/models/spotlight/page_content.rb +2 -0
  15. data/app/models/spotlight/resources/csv_upload.rb +2 -1
  16. data/app/models/spotlight/resources/iiif_manifest.rb +2 -0
  17. data/app/services/spotlight/solr_document_builder.rb +1 -0
  18. data/app/values/custom_field_name.rb +1 -0
  19. data/app/views/spotlight/indexing_complete_mailer/documents_indexed.html.erb +9 -0
  20. data/app/views/spotlight/pages/_form.html.erb +1 -1
  21. data/app/views/spotlight/shared/_honeypot_field.html.erb +4 -0
  22. data/app/views/spotlight/shared/_report_a_problem.html.erb +7 -10
  23. data/config/i18n-tasks.yml +2 -0
  24. data/config/locales/spotlight.ar.yml +22 -18
  25. data/config/locales/spotlight.en.yml +13 -6
  26. data/lib/generators/spotlight/install_generator.rb +22 -1
  27. data/lib/generators/spotlight/templates/config/initializers/sir_trevor_rails.rb +10 -0
  28. data/lib/generators/spotlight/templates/config/initializers/spotlight_initializer.rb +2 -0
  29. data/lib/spotlight/engine.rb +3 -0
  30. data/lib/spotlight/upload_field_config.rb +1 -0
  31. data/lib/spotlight/version.rb +1 -1
  32. data/spec/controllers/spotlight/browse_controller_spec.rb +1 -1
  33. data/spec/controllers/spotlight/resources/csv_upload_controller_spec.rb +4 -4
  34. data/spec/examples.txt +1410 -125
  35. data/spec/features/add_contacts_spec.rb +1 -1
  36. data/spec/features/browse_category_admin_spec.rb +2 -2
  37. data/spec/features/create_exhibit_spec.rb +5 -4
  38. data/spec/features/dashboard_spec.rb +5 -5
  39. data/spec/features/exhibits/administration_spec.rb +3 -3
  40. data/spec/features/exhibits/language_create_edit_spec.rb +3 -3
  41. data/spec/features/javascript/block_controls_spec.rb +2 -0
  42. data/spec/features/report_a_problem_spec.rb +5 -4
  43. data/spec/helpers/spotlight/pages_helper_spec.rb +2 -2
  44. data/spec/jobs/spotlight/add_uploads_from_csv_spec.rb +13 -1
  45. data/spec/mailers/spotlight/indexing_complete_mailer_spec.rb +11 -1
  46. data/spec/models/solr_document_spec.rb +2 -3
  47. data/spec/models/spotlight/access_controls_enforcement_search_builder_spec.rb +1 -0
  48. data/spec/models/spotlight/featured_image_spec.rb +0 -1
  49. data/spec/models/spotlight/role_spec.rb +2 -2
  50. data/spec/services/spotlight/exhibit_import_export_service_spec.rb +14 -2
  51. data/spec/services/spotlight/iiif_resource_resolver_spec.rb +1 -1
  52. data/spec/test_app_templates/Gemfile.extra +0 -3
  53. data/spec/views/spotlight/metadata_configurations/_metadata_field.html.erb_spec.rb +3 -3
  54. data/spec/views/spotlight/search_configurations/_sort.html.erb_spec.rb +7 -8
  55. data/vendor/assets/javascripts/leaflet-iiif.js +46 -21
  56. metadata +54 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27efff1c809c87463bcd240ccc65b6edca2182b73238f1027bc178a2f009ab5e
4
- data.tar.gz: 9df0f469fa0bc43f39a718d2cdb3bc7909e25da15a2e1d189ccc054b006eb579
3
+ metadata.gz: 8a3577af6f5ec30554f2e91955c7613e6501ef8e95f2822f6a92022626c03230
4
+ data.tar.gz: e45881b0867cba47bb74a93a7a008a843154383939c8db3abbb0c244e0a6ff57
5
5
  SHA512:
6
- metadata.gz: fc49fe51f1c599c5c3569d4387f7b2c1e124e9d8369a2b554ec26e441d8197f4f7e154cec7ab0b9c8fd3bdb8597315675da6d54b129df4774cdafbecfa339c9f
7
- data.tar.gz: c06bc5cd170cf772c13bf220bb8e0ebb136b81fb7a575b6cbfe16704fe77c4cf42c759131f9fda803361b909537ba97e9e366e58f4ab99b68d4275408b3c7853
6
+ metadata.gz: 7164e6ebcca3edd4db9d2b95ed7fafb2ec55188de3e16bdf92963b893e6b717dae262a7a2ab5f3fbfbe2e2f8de7a602083e2586b338fdbf5f1f2f96c4f5cb402
7
+ data.tar.gz: aaf1d73d51efd42699f32e1c9315ee43c4ab5e9bdb85e737eddbd94b4d9cf565e93deb58751074fecc5aaf8461cd82eb68db52fa5189db88df38035125e7ee60
@@ -40,6 +40,12 @@ export default class Crop {
40
40
  this.renderCropperMap();
41
41
 
42
42
  if (this.imageLayer) {
43
+ // Force a broken layer's container to be an element before removing.
44
+ // Code in leaflet-iiif land calls delete on the image layer's container when removing,
45
+ // which errors if there is an issue fetching the info.json and stops further necessary steps to execute.
46
+ if(!this.imageLayer._container) {
47
+ this.imageLayer._container = $('<div></div>');
48
+ }
43
49
  this.cropperMap.removeLayer(this.imageLayer);
44
50
  }
45
51
 
@@ -40,19 +40,28 @@
40
40
  }
41
41
  }
42
42
 
43
- return Object.keys(groups).reduce(function(memo, groupKey) {
44
- var group = groups[groupKey];
45
- var groupEl = $("<div class='st-controls-group'><div class='st-group-col-form-label'>" + groupKey + "</div></div>");
43
+ function generateBlock(groups, key) {
44
+ var group = groups[key];
45
+ var groupEl = $("<div class='st-controls-group'><div class='st-group-col-form-label'>" + key + "</div></div>");
46
46
  var buttons = group.reduce(function(memo, btn) {
47
47
  return memo += btn;
48
48
  }, "");
49
49
  groupEl.append(buttons);
50
- if (memo.length === 0) {
51
- return memo += groupEl[0].outerHTML;
52
- } else {
53
- return memo += "<hr />" + groupEl[0].outerHTML;
50
+ return groupEl[0].outerHTML;
51
+ }
52
+
53
+ var standardWidgets = generateBlock(groups, i18n.t("blocks:group:undefined"));
54
+
55
+ var exhibitWidgets = Object.keys(groups).map(function(key) {
56
+ if (key !== i18n.t("blocks:group:undefined")) {
57
+ return generateBlock(groups, key);
54
58
  }
55
- }, "");
59
+ }).filter(function (element) {
60
+ return element != null;
61
+ });
62
+
63
+ var blocks = [standardWidgets].concat(exhibitWidgets).join("<hr />");
64
+ return blocks;
56
65
  }
57
66
 
58
67
  function render(Blocks, availableTypes) {
@@ -65,7 +74,7 @@
65
74
  elButtons.appendChild(el);
66
75
  return elButtons;
67
76
  }
68
-
77
+
69
78
  global.Spotlight.BlockControls = function() { };
70
79
  global.Spotlight.BlockControls.create = function(editor) {
71
80
  // REFACTOR - should probably not know about blockManager
@@ -83,10 +92,10 @@
83
92
  SirTrevor = null;
84
93
  el = null;
85
94
  }
86
-
95
+
87
96
  function insert(e) {
88
97
  e.stopPropagation();
89
-
98
+
90
99
  var parent = this.parentNode;
91
100
  if (!parent || hide() === parent) { return; }
92
101
  $('.st-block__inner', parent).after(el);
@@ -101,7 +110,7 @@
101
110
 
102
111
  $(editor.wrapper).delegate(".st-block-replacer", "click", insert);
103
112
  $(editor.wrapper).delegate(".st-block-controls__button", "click", insert);
104
-
113
+
105
114
  return {
106
115
  el: el,
107
116
  hide: hide,
@@ -77,7 +77,7 @@ $aspect-ratio-factor-medium-image: 1; // 1:1 width: height
77
77
  width: $no-sidebar-desktop-large-image-width;
78
78
  height: $no-sidebar-desktop-large-image-width * $aspect-ratio-factor-large-image;
79
79
  }
80
- @media (min-width: breakpoint-min("xl")) {
80
+ @media (min-width: breakpoint-min("lg")) {
81
81
  width: $no-sidebar-large-desktop-large-image-width;
82
82
  height: $no-sidebar-large-desktop-large-image-width * $aspect-ratio-factor-large-image;
83
83
  }
@@ -111,11 +111,11 @@ $aspect-ratio-factor-medium-image: 1; // 1:1 width: height
111
111
  width: $with-sidebar-tablet-large-image-width;
112
112
  height: $with-sidebar-tablet-large-image-width * $aspect-ratio-factor-large-image;
113
113
  }
114
- @media (min-width: breakpoint-min("md")) and (max-width: breakpoint-max("xl")) {
114
+ @media (min-width: breakpoint-min("md")) and (max-width: breakpoint-max("lg")) {
115
115
  width: $with-sidebar-desktop-large-image-width;
116
116
  height: $with-sidebar-desktop-large-image-width * $aspect-ratio-factor-large-image;
117
117
  }
118
- @media (min-width: breakpoint-min("xl")) {
118
+ @media (min-width: breakpoint-min("lg")) {
119
119
  width: $with-sidebar-large-desktop-large-image-width;
120
120
  height: $with-sidebar-large-desktop-large-image-width * $aspect-ratio-factor-large-image;
121
121
  }
@@ -129,7 +129,7 @@ $aspect-ratio-factor-medium-image: 1; // 1:1 width: height
129
129
  width: $with-sidebar-xs-image-width;
130
130
  height: $with-sidebar-xs-image-width * $aspect-ratio-factor-medium-image;
131
131
  }
132
- @media (min-width: breakpoint-min("xl")) {
132
+ @media (min-width: breakpoint-min("lg")) {
133
133
  width: $with-sidebar-large-desktop-medium-image-width;
134
134
  height: $with-sidebar-large-desktop-medium-image-width * $aspect-ratio-factor-medium-image;
135
135
  }
@@ -21,6 +21,12 @@
21
21
  }
22
22
  }
23
23
 
24
+ .item-text {
25
+ .item-col {
26
+ z-index: 1;
27
+ }
28
+ }
29
+
24
30
  .item-text-admin {
25
31
  .text-align {
26
32
  margin-top: 15px;
@@ -1,7 +1,10 @@
1
1
  #report-problem-form {
2
2
  display: none;
3
- background-color: #e7e7e7;
4
- border-bottom: 1px dotted $gray-600;
3
+ border-bottom: 1px solid $gray-600;
4
+
5
+ h2 {
6
+ @extend .sr-only;
7
+ }
5
8
  }
6
9
 
7
10
  @include media-breakpoint-up(sm) {
@@ -16,7 +16,7 @@ module Spotlight
16
16
 
17
17
  def create
18
18
  csv = CSV.parse(csv_io_param, headers: true, return_headers: false).map(&:to_hash)
19
- Spotlight::AddUploadsFromCSV.perform_later(csv, current_exhibit, current_user)
19
+ Spotlight::AddUploadsFromCsv.perform_later(csv, current_exhibit, current_user)
20
20
  flash[:notice] = t('spotlight.resources.upload.csv.success', file_name: csv_io_name)
21
21
  redirect_to spotlight.admin_exhibit_catalog_path(current_exhibit)
22
22
  end
@@ -3,15 +3,41 @@
3
3
  module Spotlight
4
4
  ##
5
5
  # Process a CSV upload into new Spotlight::Resource::Upload objects
6
- class AddUploadsFromCSV < ActiveJob::Base
6
+ class AddUploadsFromCsv < ActiveJob::Base
7
+ attr_reader :count
8
+ attr_reader :errors
9
+
7
10
  queue_as :default
8
11
 
9
12
  after_perform do |job|
10
13
  csv_data, exhibit, user = job.arguments
11
- Spotlight::IndexingCompleteMailer.documents_indexed(csv_data, exhibit, user).deliver_now
14
+ Spotlight::IndexingCompleteMailer.documents_indexed(
15
+ csv_data,
16
+ exhibit,
17
+ user,
18
+ indexed_count: job.count,
19
+ errors: job.errors
20
+ ).deliver_now
12
21
  end
13
22
 
14
23
  def perform(csv_data, exhibit, _user)
24
+ @count = 0
25
+ @errors = {}
26
+
27
+ resources(csv_data, exhibit).each_with_index do |resource, index|
28
+ if resource.save_and_index
29
+ @count += 1
30
+ else
31
+ @errors[index + 1] = resource.errors.full_messages + resource.upload&.errors&.full_messages
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def resources(csv_data, exhibit)
39
+ return to_enum(:resources, csv_data, exhibit) unless block_given?
40
+
15
41
  encoded_csv(csv_data).each do |row|
16
42
  url = row.delete('url')
17
43
  next unless url.present?
@@ -21,12 +47,11 @@ module Spotlight
21
47
  exhibit: exhibit
22
48
  )
23
49
  resource.build_upload(remote_image_url: url) unless url == '~'
24
- resource.save_and_index
50
+
51
+ yield resource
25
52
  end
26
53
  end
27
54
 
28
- private
29
-
30
55
  def encoded_csv(csv)
31
56
  csv.map do |row|
32
57
  row.map do |label, column|
@@ -5,9 +5,10 @@ module Spotlight
5
5
  # Notify the curator that we're finished processing a
6
6
  # batch upload
7
7
  class IndexingCompleteMailer < ActionMailer::Base
8
- def documents_indexed(csv_data, exhibit, user)
9
- @number = csv_data.length
8
+ def documents_indexed(csv_data, exhibit, user, indexed_count: nil, errors: [])
9
+ @number = indexed_count || csv_data.length
10
10
  @exhibit = exhibit
11
+ @errors = errors
11
12
  mail(to: user.email, subject: 'Document indexing complete')
12
13
  end
13
14
  end
@@ -19,7 +19,7 @@ module Spotlight
19
19
  self.contact_info = contact_info.symbolize_keys
20
20
  end
21
21
 
22
- before_save on: :create do
22
+ before_create do
23
23
  self.show_in_sidebar = true if show_in_sidebar.nil?
24
24
  end
25
25
 
@@ -18,10 +18,10 @@ module Spotlight
18
18
  self.field_type ||= 'text'
19
19
  end
20
20
 
21
- before_save :update_field_name, on: :update, if: -> { field_type_changed? || readonly_field_changed? }
21
+ before_update :update_field_name, if: -> { field_type_changed? || readonly_field_changed? }
22
22
 
23
- after_commit :update_blacklight_configuration_after_field_name_change, on: :update, if: -> { saved_change_to_field? || saved_change_to_slug? }
24
- after_commit :update_sidecar_data_after_field_name_change, on: :update, if: -> { saved_change_to_field? || saved_change_to_slug? }
23
+ after_update_commit :update_blacklight_configuration_after_field_name_change, if: -> { saved_change_to_field? || saved_change_to_slug? }
24
+ after_update_commit :update_sidecar_data_after_field_name_change, if: -> { saved_change_to_field? || saved_change_to_slug? }
25
25
 
26
26
  def label=(label)
27
27
  configuration['label'] = label
@@ -66,7 +66,7 @@ module Spotlight
66
66
  def iiif_tilesource
67
67
  if self[:iiif_tilesource]
68
68
  self[:iiif_tilesource]
69
- elsif source == 'remote' && file_present?
69
+ elsif file_present?
70
70
  riiif = Riiif::Engine.routes.url_helpers
71
71
  riiif.info_path(id)
72
72
  end
@@ -27,6 +27,7 @@ module Spotlight
27
27
  to: :context
28
28
 
29
29
  attr_reader :context, :page
30
+
30
31
  def initialize(context:, page:)
31
32
  @context = context
32
33
  @page = page
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'spotlight/page_content/sir_trevor'
4
+
3
5
  module Spotlight
4
6
  # Factory for picking the right page content renderer
5
7
  module PageContent
@@ -3,9 +3,10 @@
3
3
  module Spotlight
4
4
  module Resources
5
5
  ##
6
- # Shim object for CSV Uploads. see {Spotlight::AddUploadsFromCSV}
6
+ # Shim object for CSV Uploads. see {Spotlight::AddUploadsFromCsv}
7
7
  class CsvUpload
8
8
  attr_reader :url
9
+
9
10
  include ActiveModel::Model
10
11
  extend ActiveModel::Translation
11
12
  end
@@ -6,6 +6,7 @@ module Spotlight
6
6
  # A PORO to construct a solr hash for a given IiifManifest
7
7
  class IiifManifest
8
8
  attr_reader :collection
9
+
9
10
  def initialize(attrs = {})
10
11
  @url = attrs[:url]
11
12
  @manifest = attrs[:manifest]
@@ -36,6 +37,7 @@ module Spotlight
36
37
  private
37
38
 
38
39
  attr_reader :url, :manifest, :exhibit, :solr_hash
40
+
39
41
  delegate :blacklight_config, to: :exhibit
40
42
 
41
43
  def add_document_id
@@ -8,6 +8,7 @@ module Spotlight
8
8
  end
9
9
 
10
10
  attr_reader :resource
11
+
11
12
  delegate :exhibit, :document_model, to: :resource
12
13
 
13
14
  ##
@@ -5,6 +5,7 @@
5
5
  class CustomFieldName
6
6
  delegate :readonly_field?, :configuration, :field_type, to: :custom_field
7
7
  attr_reader :custom_field
8
+
8
9
  def initialize(custom_field)
9
10
  @custom_field = custom_field
10
11
  end
@@ -1,3 +1,12 @@
1
1
  <p><%= t :".title" %></p>
2
2
 
3
3
  <p><%= t :".body", count: @number, title: @exhibit.title %></p>
4
+
5
+ <% if @errors.length > 0 %>
6
+ <p><%= t :".errors", default: :'spotlight.catalog.reindex_progress_panel.error' %></p>
7
+ <ul>
8
+ <% @errors.each do |index, message| %>
9
+ <li><%= t :'.error', index: index, message: message.to_sentence %>
10
+ <% end %>
11
+ </ul>
12
+ <% end %>
@@ -40,7 +40,7 @@
40
40
  </div>
41
41
  <div class="form-group">
42
42
  <%= f.label :content, class: 'sr-only' %>
43
- <%= f.text_area_without_bootstrap :content, value: { data: f.object.content.as_json }.to_json, class: content_editor_class(f.object), data: { 'block-types': Spotlight::Engine.config.sir_trevor_widgets } %>
43
+ <%= f.text_area_without_bootstrap :content, value: { data: f.object.content.as_json }.to_json, class: content_editor_class(f.object), data: { 'block-types': SirTrevorRails::Block.custom_block_types } %>
44
44
  </div>
45
45
  </div>
46
46
 
@@ -0,0 +1,4 @@
1
+ <span style="display:none;visibility:hidden;">
2
+ <% honeypot_field_name = Spotlight::Engine.config.spambot_honeypot_email_field %>
3
+ <%= f.email_field honeypot_field_name, label: t(:'spotlight.shared.report_a_problem.honeypot_field_explanation') %>
4
+ </span>
@@ -2,20 +2,17 @@
2
2
  <div class="row justify-content-center">
3
3
  <% contact_form ||= Spotlight::ContactForm.new current_url: request.original_url %>
4
4
  <%= bootstrap_form_for contact_form, url: spotlight.exhibit_contact_form_path(current_exhibit, contact_form), layout: :horizontal, label_col: 'col-sm-3', control_col: 'col-sm-9', html: { class: 'col-md-offset-2 col-md-8 my-3 '} do |f| %>
5
-
6
5
  <h2><%= t(:'.title') %></h2>
6
+ <div class="alert alert-primary"><%= t('.reporting_from', url: contact_form.current_url) %></div>
7
+ <%= f.text_area :message, rows: 4 %>
7
8
  <%= f.text_field :name %>
8
- <span style="display:none;visibility:hidden;">
9
- <% honeypot_field_name = Spotlight::Engine.config.spambot_honeypot_email_field %>
10
- <%= f.email_field honeypot_field_name, label: t(:'.honeypot_field_explanation') %>
11
- </span>
9
+ <%= render '/spotlight/shared/honeypot_field', f: f %>
12
10
  <%= f.email_field :email %>
13
- <%= f.text_area :message, rows: 7 %>
14
11
  <%= f.hidden_field :current_url %>
15
- <div class="form-actions">
16
- <div class="primary-actions">
17
- <%= link_to t(:'helpers.action.cancel'), '#', class: 'btn-sizing', data: { 'behavior' => 'cancel-link' } %>
18
- <%= f.submit nil, class: 'btn btn-primary' %>
12
+ <div class="form-actions row">
13
+ <div class="col offset-sm-3">
14
+ <%= f.submit nil, class: 'btn btn-primary' %>
15
+ <%= link_to t(:'helpers.action.cancel'), '#', class: 'btn-sizing', data: { 'behavior' => 'cancel-link' } %>
19
16
  </div>
20
17
  </div>
21
18
  <% end %>
@@ -34,6 +34,7 @@ ignore_unused:
34
34
  - activerecord.attributes.spotlight/page.{display_sidebar\?,display_title} # app/views/spotlight/home_pages/_page_options.html.erb
35
35
  - activerecord.attributes.spotlight/language.locale # app/views/spotlight/exhibits/_languages.html.erb
36
36
  - activerecord.attributes.spotlight/contact.avatar # app/views/spotlight/contacts/_form.html.erb
37
+ - activerecord.attributes.spotlight/exhibit.contact_emails # app/views/spotlight/exhibits/_form.html.erb
37
38
  - activerecord.attributes.spotlight/exhibit.published # app/views/spotlight/sites/_exhibit.html.erb
38
39
  - activerecord.attributes.spotlight/masthead.display # app/views/spotlight/appearances/edit.html.erb
39
40
  - activerecord.attributes.spotlight/custom_field.is_multiple # app/views/spotlight/custom_fields/_form.html.erb
@@ -66,6 +67,7 @@ ignore_unused:
66
67
  - helpers.submit.{submit,update} # Generically used set defaults
67
68
  - helpers.submit.contact.create # app/views/spotlight/contacts/_form.html.erb
68
69
  - helpers.action.exhibit.contact.submit # helpers.action.exhibit.contact.submit
70
+ - helpers.label.contact_form.{email,name} # app/views/spotlight/shared/_report_a_problem.html.erb
69
71
 
70
72
  # TODO Look into these as its unclear
71
73
  - activerecord.models.spotlight.page
@@ -16,25 +16,28 @@ ar:
16
16
  browse:
17
17
  search:
18
18
  item_count:
19
- one: 1 عنصر
19
+ zero: "%{count} عنصر"
20
+ one: "%{count} عنصر"
21
+ two: "%{count} عنصرين"
20
22
  few: "%{count} عناصر"
21
- many: "%{count} عناصر"
22
- other: "%{count} عناصر"
23
- two: عنصرين
24
- zero: لا يوجد
23
+ many: "%{count} عنصراً"
24
+ other: "%{count} عنصراً"
25
+
25
26
  search_box:
26
27
  label: ابحث في فئة التصفح الحالية
27
28
  placeholder: بحث...
28
29
  reset: مسح استعلام البحث
29
30
  submit: ابحث في فئة التصفح
30
31
  success:
31
- expand_html: يمكنك ايضاً <a href="%{expand_search_url}">البحث في كل مواد المعرض عن "%{browse_query}"</a>.
32
- result_number_html: طابق استعلام البحث <strong> %{search_size} من %{parent_search_count} عنصر</strong> في هذه الفئة.
32
+ expand_html: "يمكنك ايضاً <a href=\"%{expand_search_url}\">البحث في كل مواد المعرض عن \"%{browse_query}\"</a>."
33
+ result_number_html: "طابق استعلام البحث <strong> %{search_size} من %{parent_search_count} عنصر</strong> في هذه الفئة."
33
34
  zero_results:
34
- expand_html: تستطيع أن <a href="%{clear_search_url}"> تمسح استعلام البحث </a> أو محاولة <a href="%{expand_search_url}"> البحث في كل المواد المعروضة لاستعلام البحث ل"%{browse_query}"</a>
35
+ expand_html: "تستطيع أن <a href=\"%{clear_search_url}\"> تمسح استعلام البحث </a> أو محاولة <a href=\"%{expand_search_url}\"> البحث في كل المواد المعروضة لاستعلام البحث ل\"%{browse_query}\"</a>"
35
36
  result_number: لم يتطابق بحثك مع أي عنصر في هذه الفئة.
36
37
  header_links:
37
38
  contact: ملاحظات واقتراحات
39
+ login: تسجيل الدخول
40
+ logout: تسجيل الخروج
38
41
  shared:
39
42
  report_a_problem:
40
43
  honeypot_field_explanation: تجاهل هذا المربع النصي، فهو يُستخدم فقط لكشف المحتالين. إذا كتبت أي شيء في هذا المربع النصي، فلن يتم إرسال رسالتك.
@@ -43,17 +46,18 @@ ar:
43
46
  blocks:
44
47
  browse_block:
45
48
  items:
46
- one: 1 عنصر
49
+ zero: "%{count} عنصر"
50
+ one: "%{count} عنصر"
51
+ two: "%{count} عنصرين"
47
52
  few: "%{count} عناصر"
48
- many: "%{count} عناصر"
49
- other: "%{count} عناصر"
50
- two: عنصرين
51
- zero: لا يوجد
53
+ many: "%{count} عنصراً"
54
+ other: "%{count} عنصراً"
55
+
52
56
  link_to_search_block:
53
57
  items:
54
- one: 1 عنصر
58
+ zero: "%{count} عنصر"
59
+ one: "%{count} عنصر"
60
+ two: "%{count} عنصرين"
55
61
  few: "%{count} عناصر"
56
- many: "%{count} عناصر"
57
- other: "%{count} عناصر"
58
- two: عنصرين
59
- zero: لا يوجد
62
+ many: "%{count} عنصراً"
63
+ other: "%{count} عنصراً"