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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/spotlight/admin/crop.es6 +6 -0
- data/app/assets/javascripts/spotlight/admin/sir-trevor/block_controls.js +21 -12
- data/app/assets/stylesheets/spotlight/_featured_browse_categories_block.scss +4 -4
- data/app/assets/stylesheets/spotlight/_item_text_block.scss +6 -0
- data/app/assets/stylesheets/spotlight/_report_a_problem.scss +5 -2
- data/app/controllers/spotlight/resources/csv_upload_controller.rb +1 -1
- data/app/jobs/spotlight/add_uploads_from_csv.rb +30 -5
- data/app/mailers/spotlight/indexing_complete_mailer.rb +3 -2
- data/app/models/spotlight/contact.rb +1 -1
- data/app/models/spotlight/custom_field.rb +3 -3
- data/app/models/spotlight/featured_image.rb +1 -1
- data/app/models/spotlight/page_configurations.rb +1 -0
- data/app/models/spotlight/page_content.rb +2 -0
- data/app/models/spotlight/resources/csv_upload.rb +2 -1
- data/app/models/spotlight/resources/iiif_manifest.rb +2 -0
- data/app/services/spotlight/solr_document_builder.rb +1 -0
- data/app/values/custom_field_name.rb +1 -0
- data/app/views/spotlight/indexing_complete_mailer/documents_indexed.html.erb +9 -0
- data/app/views/spotlight/pages/_form.html.erb +1 -1
- data/app/views/spotlight/shared/_honeypot_field.html.erb +4 -0
- data/app/views/spotlight/shared/_report_a_problem.html.erb +7 -10
- data/config/i18n-tasks.yml +2 -0
- data/config/locales/spotlight.ar.yml +22 -18
- data/config/locales/spotlight.en.yml +13 -6
- data/lib/generators/spotlight/install_generator.rb +22 -1
- data/lib/generators/spotlight/templates/config/initializers/sir_trevor_rails.rb +10 -0
- data/lib/generators/spotlight/templates/config/initializers/spotlight_initializer.rb +2 -0
- data/lib/spotlight/engine.rb +3 -0
- data/lib/spotlight/upload_field_config.rb +1 -0
- data/lib/spotlight/version.rb +1 -1
- data/spec/controllers/spotlight/browse_controller_spec.rb +1 -1
- data/spec/controllers/spotlight/resources/csv_upload_controller_spec.rb +4 -4
- data/spec/examples.txt +1410 -125
- data/spec/features/add_contacts_spec.rb +1 -1
- data/spec/features/browse_category_admin_spec.rb +2 -2
- data/spec/features/create_exhibit_spec.rb +5 -4
- data/spec/features/dashboard_spec.rb +5 -5
- data/spec/features/exhibits/administration_spec.rb +3 -3
- data/spec/features/exhibits/language_create_edit_spec.rb +3 -3
- data/spec/features/javascript/block_controls_spec.rb +2 -0
- data/spec/features/report_a_problem_spec.rb +5 -4
- data/spec/helpers/spotlight/pages_helper_spec.rb +2 -2
- data/spec/jobs/spotlight/add_uploads_from_csv_spec.rb +13 -1
- data/spec/mailers/spotlight/indexing_complete_mailer_spec.rb +11 -1
- data/spec/models/solr_document_spec.rb +2 -3
- data/spec/models/spotlight/access_controls_enforcement_search_builder_spec.rb +1 -0
- data/spec/models/spotlight/featured_image_spec.rb +0 -1
- data/spec/models/spotlight/role_spec.rb +2 -2
- data/spec/services/spotlight/exhibit_import_export_service_spec.rb +14 -2
- data/spec/services/spotlight/iiif_resource_resolver_spec.rb +1 -1
- data/spec/test_app_templates/Gemfile.extra +0 -3
- data/spec/views/spotlight/metadata_configurations/_metadata_field.html.erb_spec.rb +3 -3
- data/spec/views/spotlight/search_configurations/_sort.html.erb_spec.rb +7 -8
- data/vendor/assets/javascripts/leaflet-iiif.js +46 -21
- metadata +54 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a3577af6f5ec30554f2e91955c7613e6501ef8e95f2822f6a92022626c03230
|
4
|
+
data.tar.gz: e45881b0867cba47bb74a93a7a008a843154383939c8db3abbb0c244e0a6ff57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
44
|
-
var group = groups[
|
45
|
-
var groupEl = $("<div class='st-controls-group'><div class='st-group-col-form-label'>" +
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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("
|
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("
|
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("
|
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("
|
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
|
}
|
@@ -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::
|
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
|
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(
|
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
|
-
|
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
|
@@ -18,10 +18,10 @@ module Spotlight
|
|
18
18
|
self.field_type ||= 'text'
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
before_update :update_field_name, if: -> { field_type_changed? || readonly_field_changed? }
|
22
22
|
|
23
|
-
|
24
|
-
|
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
|
@@ -3,9 +3,10 @@
|
|
3
3
|
module Spotlight
|
4
4
|
module Resources
|
5
5
|
##
|
6
|
-
# Shim object for CSV Uploads. see {Spotlight::
|
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
|
@@ -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':
|
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
|
|
@@ -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
|
-
|
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="
|
17
|
-
|
18
|
-
|
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 %>
|
data/config/i18n-tasks.yml
CHANGED
@@ -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
|
-
|
19
|
+
zero: "%{count} عنصر"
|
20
|
+
one: "%{count} عنصر"
|
21
|
+
two: "%{count} عنصرين"
|
20
22
|
few: "%{count} عناصر"
|
21
|
-
many: "%{count}
|
22
|
-
other: "%{count}
|
23
|
-
|
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
|
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
|
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
|
-
|
49
|
+
zero: "%{count} عنصر"
|
50
|
+
one: "%{count} عنصر"
|
51
|
+
two: "%{count} عنصرين"
|
47
52
|
few: "%{count} عناصر"
|
48
|
-
many: "%{count}
|
49
|
-
other: "%{count}
|
50
|
-
|
51
|
-
zero: لا يوجد
|
53
|
+
many: "%{count} عنصراً"
|
54
|
+
other: "%{count} عنصراً"
|
55
|
+
|
52
56
|
link_to_search_block:
|
53
57
|
items:
|
54
|
-
|
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} عنصراً"
|