dugway 1.0.14 → 1.2.0
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.
- checksums.yaml +4 -4
- data/.bundle/config +2 -0
- data/.github/workflows/main.yml +1 -1
- data/.gitignore +1 -0
- data/README.md +9 -0
- data/lib/dugway/application.rb +5 -3
- data/lib/dugway/assets/big_cartel_logo.svg +4 -0
- data/lib/dugway/cli/build.rb +18 -1
- data/lib/dugway/cli/server.rb +2 -2
- data/lib/dugway/cli/templates/source/settings.json +8 -0
- data/lib/dugway/cli/validate.rb +20 -2
- data/lib/dugway/controller.rb +5 -1
- data/lib/dugway/liquid/drops/account_drop.rb +4 -0
- data/lib/dugway/liquid/drops/features_drop.rb +144 -0
- data/lib/dugway/liquid/drops/product_drop.rb +8 -0
- data/lib/dugway/liquid/drops/products_drop.rb +1 -1
- data/lib/dugway/liquid/drops/related_products_drop.rb +88 -0
- data/lib/dugway/liquid/drops/theme_drop.rb +23 -0
- data/lib/dugway/liquid/drops/translations_drop.rb +122 -0
- data/lib/dugway/liquifier.rb +44 -8
- data/lib/dugway/store.rb +7 -2
- data/lib/dugway/theme.rb +169 -3
- data/lib/dugway/version.rb +1 -1
- data/lib/dugway.rb +31 -1
- data/locales/storefront.de.yml +79 -0
- data/locales/storefront.en-CA.yml +79 -0
- data/locales/storefront.en-GB.yml +79 -0
- data/locales/storefront.en-US.yml +79 -0
- data/locales/storefront.es-ES.yml +79 -0
- data/locales/storefront.es-MX.yml +79 -0
- data/locales/storefront.fr-CA.yml +79 -0
- data/locales/storefront.fr-FR.yml +79 -0
- data/locales/storefront.id.yml +79 -0
- data/locales/storefront.it.yml +79 -0
- data/locales/storefront.ja.yml +79 -0
- data/locales/storefront.ko.yml +79 -0
- data/locales/storefront.nl.yml +79 -0
- data/locales/storefront.pl.yml +79 -0
- data/locales/storefront.pt-BR.yml +79 -0
- data/locales/storefront.pt-PT.yml +79 -0
- data/locales/storefront.ro.yml +79 -0
- data/locales/storefront.sv.yml +79 -0
- data/locales/storefront.tr.yml +79 -0
- data/locales/storefront.zh-CN.yml +79 -0
- data/locales/storefront.zh-TW.yml +79 -0
- data/log/dugway.log +1 -0
- data/spec/features/page_rendering_spec.rb +4 -4
- data/spec/fixtures/theme/layout.html +2 -0
- data/spec/fixtures/theme/settings.json +6 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/units/dugway/liquid/drops/features_drop_spec.rb +182 -0
- data/spec/units/dugway/liquid/drops/product_drop_spec.rb +36 -0
- data/spec/units/dugway/liquid/drops/related_products_drop_spec.rb +80 -0
- data/spec/units/dugway/liquid/drops/theme_drop_spec.rb +45 -0
- data/spec/units/dugway/liquid/drops/translations_drop_spec.rb +292 -0
- data/spec/units/dugway/store_spec.rb +37 -0
- data/spec/units/dugway/theme_spec.rb +456 -0
- metadata +35 -2
data/lib/dugway/theme.rb
CHANGED
@@ -13,10 +13,12 @@ module Dugway
|
|
13
13
|
File.join(__dir__, 'config', 'theme_color_attribute_mappings.yml')
|
14
14
|
).freeze
|
15
15
|
|
16
|
-
attr_reader :errors
|
16
|
+
attr_reader :errors, :warnings
|
17
17
|
|
18
18
|
def initialize(overridden_customization={})
|
19
19
|
@overridden_customization = overridden_customization.stringify_keys
|
20
|
+
@errors = []
|
21
|
+
@warnings = []
|
20
22
|
end
|
21
23
|
|
22
24
|
def layout
|
@@ -39,9 +41,13 @@ module Dugway
|
|
39
41
|
customization_for_type('image_sets')
|
40
42
|
end
|
41
43
|
|
44
|
+
def features
|
45
|
+
customization_for_type('features')
|
46
|
+
end
|
47
|
+
|
42
48
|
def customization
|
43
49
|
Hash.new.tap do |customization|
|
44
|
-
%w( fonts colors options images image_sets ).each do |type|
|
50
|
+
%w( fonts colors options images image_sets features).each do |type|
|
45
51
|
customization.update(customization_for_type(type))
|
46
52
|
end
|
47
53
|
|
@@ -93,8 +99,9 @@ module Dugway
|
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
96
|
-
def valid?(validate_colors: true, validate_layout_attributes: true)
|
102
|
+
def valid?(validate_colors: true, validate_layout_attributes: true, validate_options: true)
|
97
103
|
@errors = []
|
104
|
+
@warnings = []
|
98
105
|
|
99
106
|
REQUIRED_FILES.each do |file|
|
100
107
|
@errors << "Missing source/#{ file }" if read_source_file(file).nil?
|
@@ -118,11 +125,28 @@ module Dugway
|
|
118
125
|
validate_required_color_settings if validate_colors
|
119
126
|
validate_required_layout_attributes if validate_layout_attributes
|
120
127
|
|
128
|
+
if validate_options
|
129
|
+
validate_options_settings # Validate descriptions, requires, defaults
|
130
|
+
# Validate sections for options, images, and image_sets
|
131
|
+
validate_setting_sections(settings['options'], 'options') if settings['options']
|
132
|
+
validate_setting_sections(settings['images'], 'images') if settings['images']
|
133
|
+
validate_setting_sections(settings['image_sets'], 'image_sets') if settings['image_sets']
|
134
|
+
end
|
135
|
+
|
121
136
|
@errors.empty?
|
122
137
|
end
|
123
138
|
|
124
139
|
def validate_required_color_settings
|
140
|
+
if !settings['colors']
|
141
|
+
@errors << "Missing colors section in theme settings"
|
142
|
+
return
|
143
|
+
end
|
144
|
+
|
125
145
|
required_colors_attribute_names = THEME_COLOR_ATTRIBUTE_MAPPINGS['required_color_attributes']
|
146
|
+
if !required_colors_attribute_names
|
147
|
+
@errors << "Missing required color attributes configuration"
|
148
|
+
return
|
149
|
+
end
|
126
150
|
|
127
151
|
theme_colors = settings['colors'].map { |c| c['variable'] }
|
128
152
|
mappings = THEME_COLOR_ATTRIBUTE_MAPPINGS[name] || {}
|
@@ -154,8 +178,41 @@ module Dugway
|
|
154
178
|
@errors << "layout.html must have exactly one `data-bc-hook=\"footer\"`" if footer_hooks != 1
|
155
179
|
end
|
156
180
|
|
181
|
+
VALID_SECTIONS = %w(global_navigation homepage product_page general messaging social translations).freeze
|
182
|
+
|
183
|
+
def validate_options_settings
|
184
|
+
return unless settings['options']
|
185
|
+
|
186
|
+
validate_options_descriptions
|
187
|
+
validate_options_requires
|
188
|
+
validate_option_defaults
|
189
|
+
end
|
190
|
+
|
157
191
|
private
|
158
192
|
|
193
|
+
# Generic method to validate the 'section' property for any array of settings
|
194
|
+
def validate_setting_sections(settings_array, setting_type_name)
|
195
|
+
return unless settings_array.is_a?(Array)
|
196
|
+
|
197
|
+
settings_array.each do |setting|
|
198
|
+
variable = setting['variable'] || 'unknown'
|
199
|
+
|
200
|
+
unless setting.key?('section')
|
201
|
+
warning_msg = "Warning: Theme setting '#{variable}' is missing the 'section' property."
|
202
|
+
@warnings << warning_msg
|
203
|
+
Kernel.warn(warning_msg)
|
204
|
+
next # Skip further checks if section is missing
|
205
|
+
end
|
206
|
+
|
207
|
+
section_value = setting['section']
|
208
|
+
unless VALID_SECTIONS.include?(section_value)
|
209
|
+
warning_msg = "Warning: Theme setting '#{variable}' has an invalid 'section' value: '#{section_value}'. Allowed values are: #{VALID_SECTIONS.join(', ')}."
|
210
|
+
@warnings << warning_msg
|
211
|
+
Kernel.warn(warning_msg)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
159
216
|
def validate_preview
|
160
217
|
preview = settings['preset_styles']['preview']
|
161
218
|
if preview
|
@@ -225,6 +282,115 @@ module Dugway
|
|
225
282
|
@errors << "Duplicate style names found: #{duplicates.join(', ')}" if duplicates.any?
|
226
283
|
end
|
227
284
|
|
285
|
+
def validate_options_descriptions
|
286
|
+
missing_descriptions = settings['options'].select { |option|
|
287
|
+
option['description'].nil? || option['description'].strip.empty?
|
288
|
+
}.map { |option| option['variable'] }
|
289
|
+
|
290
|
+
@errors << "Missing descriptions for settings: #{missing_descriptions.join(', ')}" unless missing_descriptions.empty?
|
291
|
+
end
|
292
|
+
|
293
|
+
# Validate that any dependent settings are present in the theme settings
|
294
|
+
def validate_options_requires
|
295
|
+
return unless settings['options']
|
296
|
+
all_variables = settings['options'].map { |o| o['variable'] }
|
297
|
+
valid_operators = %w(eq neq gt lt gte lte present)
|
298
|
+
|
299
|
+
settings['options'].each do |option|
|
300
|
+
next unless option['requires']
|
301
|
+
|
302
|
+
# Handle case where requires is a string
|
303
|
+
if option['requires'].is_a?(String)
|
304
|
+
next if option['requires'] == 'inventory'
|
305
|
+
unless all_variables.include?(option['requires'])
|
306
|
+
@errors << "Option '#{option['variable']}' requires unknown setting '#{option['requires']}'"
|
307
|
+
end
|
308
|
+
next
|
309
|
+
end
|
310
|
+
|
311
|
+
# Validate requires is either a string or array
|
312
|
+
unless option['requires'].is_a?(Array)
|
313
|
+
@errors << "Option '#{option['variable']}' requires must be string 'inventory' or array of rules"
|
314
|
+
next
|
315
|
+
end
|
316
|
+
|
317
|
+
# Process each rule in the array
|
318
|
+
option['requires'].each do |rule|
|
319
|
+
next if rule == 'inventory'
|
320
|
+
|
321
|
+
# Extract setting name and optional operator/value
|
322
|
+
parts = rule.split(/\s+/)
|
323
|
+
setting_name = parts[0]
|
324
|
+
operator = parts[1]
|
325
|
+
value = parts[2]
|
326
|
+
|
327
|
+
if setting_name.start_with?('feature:')
|
328
|
+
# Validate feature flag format
|
329
|
+
unless setting_name =~ /^feature:[a-z_]+$/
|
330
|
+
@errors << "Option '#{option['variable']}' has invalid feature flag format"
|
331
|
+
next
|
332
|
+
end
|
333
|
+
|
334
|
+
# Only validate operator/value if they exist
|
335
|
+
if operator
|
336
|
+
is_valid_operator = ['eq', 'neq'].include?(operator)
|
337
|
+
|
338
|
+
@errors << "Option '#{option['variable']}' has invalid operator '#{operator}'. Feature flags can only use `eq` or `neq`." unless is_valid_operator
|
339
|
+
|
340
|
+
is_valid_value = ['visible'].include?(value)
|
341
|
+
|
342
|
+
@errors << "Option '#{option['variable']}' has invalid comparison value '#{value}'. Feature flags can only check for `visible`." unless is_valid_value
|
343
|
+
end
|
344
|
+
next
|
345
|
+
end
|
346
|
+
|
347
|
+
# --- Non-feature rule validation ---
|
348
|
+
unless all_variables.include?(setting_name)
|
349
|
+
@errors << "Option '#{option['variable']}' requires unknown setting '#{setting_name}'"
|
350
|
+
next # Skip further checks for this rule if setting is unknown
|
351
|
+
end
|
352
|
+
|
353
|
+
# Validate operator if present
|
354
|
+
if operator && !valid_operators.include?(operator)
|
355
|
+
@errors << "Option '#{option['variable']}' has invalid operator '#{operator}'. Allowed operators are: #{valid_operators.join(', ')}."
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def validate_option_value(option, value_type)
|
362
|
+
value = option[value_type]
|
363
|
+
return unless value
|
364
|
+
|
365
|
+
case option['type']
|
366
|
+
when 'select'
|
367
|
+
validate_select_option(option, value, value_type)
|
368
|
+
when 'boolean'
|
369
|
+
@errors << "#{value_type.capitalize} '#{value}' is not a boolean for #{option['variable']}" unless [true, false].include?(value)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def validate_option_defaults
|
374
|
+
return unless settings['options']
|
375
|
+
settings['options'].each do |option|
|
376
|
+
validate_option_value(option, 'default')
|
377
|
+
validate_option_value(option, 'upgrade_default')
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
def validate_select_option(option, value, value_type)
|
382
|
+
if option['options'] == "product_orders"
|
383
|
+
valid_values = %w[position top-selling newest views updated_new_to_old]
|
384
|
+
@errors << "#{value_type.capitalize} '#{value}' is not a valid option for #{option['variable']}" unless valid_values.include?(value)
|
385
|
+
elsif option['options'].is_a?(String) && option['options'] =~ /^\d+\.\.\d+$/
|
386
|
+
range = eval(option['options'])
|
387
|
+
@errors << "#{value_type.capitalize} '#{value}' is out of range for #{option['variable']}" unless range.include?(value.to_i)
|
388
|
+
elsif option['options'].is_a?(Array)
|
389
|
+
valid_values = option['options'].map { |o| o.is_a?(Array) ? o[1] : o }
|
390
|
+
@errors << "#{value_type.capitalize} '#{value}' is not a valid option for #{option['variable']}" unless valid_values.include?(value)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
228
394
|
def source_dir
|
229
395
|
Dugway.source_dir
|
230
396
|
end
|
data/lib/dugway/version.rb
CHANGED
data/lib/dugway.rb
CHANGED
@@ -14,6 +14,33 @@ require 'i18n'
|
|
14
14
|
require 'bigcartel-currency-locales'
|
15
15
|
require 'bigcartel/theme/fonts'
|
16
16
|
|
17
|
+
# Configure I18n to load locale files from the gem's locales directory.
|
18
|
+
# This allows for easy addition and management of translations.
|
19
|
+
gem_locales_pattern = File.expand_path('../locales/storefront.*.yml', File.dirname(__FILE__))
|
20
|
+
gem_locale_files = Dir.glob(gem_locales_pattern)
|
21
|
+
|
22
|
+
# Add these locale files to the I18n load path, ensuring no duplicates and preserving existing paths.
|
23
|
+
I18n.load_path = (I18n.load_path + gem_locale_files).uniq
|
24
|
+
|
25
|
+
# Determine available locales from the filenames (e.g., 'storefront.en-US.yml' -> :'en-US').
|
26
|
+
available_locales = gem_locale_files.map do |file|
|
27
|
+
# Extracts 'en-US' from 'storefront.en-US.yml' or 'de' from 'storefront.de.yml'
|
28
|
+
locale_string = File.basename(file, '.yml').split('storefront.').last
|
29
|
+
locale_string.to_sym if locale_string
|
30
|
+
end.compact.uniq
|
31
|
+
|
32
|
+
# Ensure :en is an available locale if any 'en-XX' variant exists (e.g., :en-US, :en-GB),
|
33
|
+
# as I18n can use :en as a fallback.
|
34
|
+
if available_locales.any? { |loc| loc.to_s.start_with?('en-') } && !available_locales.include?(:en)
|
35
|
+
available_locales << :en
|
36
|
+
end
|
37
|
+
|
38
|
+
# Set available locales. Provide a default if no locale files are found (e.g., during initial setup or in case of an error).
|
39
|
+
I18n.config.available_locales = available_locales.empty? ? [:'en-US', :en] : available_locales
|
40
|
+
|
41
|
+
# Reload I18n to apply changes and load the translations from the files.
|
42
|
+
I18n.backend.reload!
|
43
|
+
|
17
44
|
require 'rack/builder'
|
18
45
|
require 'rack/commonlogger'
|
19
46
|
require 'better_errors'
|
@@ -52,7 +79,9 @@ module Dugway
|
|
52
79
|
end
|
53
80
|
|
54
81
|
def store
|
55
|
-
|
82
|
+
store_options = options && options[:store] ? options[:store] : {}
|
83
|
+
subdomain = store_options[:subdomain] || 'dugway'
|
84
|
+
@store ||= Store.new(subdomain, store_options)
|
56
85
|
end
|
57
86
|
|
58
87
|
def theme
|
@@ -74,5 +103,6 @@ module Dugway
|
|
74
103
|
def options
|
75
104
|
@options
|
76
105
|
end
|
106
|
+
|
77
107
|
end
|
78
108
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
de:
|
2
|
+
storefront:
|
3
|
+
navigation:
|
4
|
+
all: "Alle"
|
5
|
+
all_products: "Alle Produkte"
|
6
|
+
back_to_site: "Zurück zur Seite"
|
7
|
+
cart: "Warenkorb"
|
8
|
+
categories: "Kategorien"
|
9
|
+
contact: "Kontakt"
|
10
|
+
home: "Startseite"
|
11
|
+
item: "Artikel" # capitalized as it is proper grammar in German
|
12
|
+
items: "Artikel" # capitalized as it is proper grammar in German
|
13
|
+
more: "Mehr"
|
14
|
+
next: "Weiter"
|
15
|
+
newest: "Neueste"
|
16
|
+
pages: "Seiten"
|
17
|
+
previous: "Zurück"
|
18
|
+
products: "Produkte"
|
19
|
+
quick_view: "Schnellansicht"
|
20
|
+
search: "Suche"
|
21
|
+
shop: "Shop"
|
22
|
+
social: "Folge uns"
|
23
|
+
subscribe: "Abonnieren"
|
24
|
+
top_selling: "Meistverkauft"
|
25
|
+
view: "Ansehen"
|
26
|
+
view_all: "Alle anzeigen"
|
27
|
+
# "Sort By" translations are used in very few themes, and are not exposed in theme settings for sellers to configure
|
28
|
+
sort_by: Sortieren nach
|
29
|
+
sort_by_featured: Empfohlen
|
30
|
+
sort_by_on_sale: Im Angebot
|
31
|
+
sort_by_top_selling: Bestseller
|
32
|
+
sort_by_alphabetically_a_to_z: Alphabetisch (A bis Z)
|
33
|
+
sort_by_alphabetically_z_to_a: Alphabetisch (Z bis A)
|
34
|
+
sort_by_date_new_to_old: Datum (neu zu alt)
|
35
|
+
sort_by_date_old_to_new: Datum (alt zu neu)
|
36
|
+
sort_by_price_low_to_high: Preis (niedrig zu hoch)
|
37
|
+
sort_by_price_high_to_low: Preis (hoch zu niedrig)
|
38
|
+
home:
|
39
|
+
all_products: "Alle Produkte"
|
40
|
+
featured: "Empfohlen"
|
41
|
+
featured_categories: "Empfohlene Kategorien"
|
42
|
+
featured_products: "Empfohlene Produkte"
|
43
|
+
featured_video: ""
|
44
|
+
products:
|
45
|
+
add_to_cart: "Hinzufügen"
|
46
|
+
added: "Hinzugefügt!" # Used in few themes, intentionally not exposed in theme settings
|
47
|
+
adding: "Hinzufügen..." # Used in few themes, intentionally not exposed in theme settings
|
48
|
+
almost_sold_out: "Nur noch wenige!"
|
49
|
+
coming_soon: "Demnächst verfügbar"
|
50
|
+
in_stock: "auf Lager"
|
51
|
+
description: "Beschreibung"
|
52
|
+
inventory: "Lagerbestand"
|
53
|
+
low_inventory: "Begrenzte Menge"
|
54
|
+
no_products: "Keine Produkte gefunden"
|
55
|
+
on_sale: "Im Angebot"
|
56
|
+
related_products: "Das gefällt dir vielleicht"
|
57
|
+
reset: "Zurücksetzen"
|
58
|
+
search_results: "Suchergebnisse"
|
59
|
+
select: "Wählen"
|
60
|
+
select_variant: "Option wählen"
|
61
|
+
sold_out: "Ausverkauft"
|
62
|
+
cart:
|
63
|
+
checkout: "Zur Kasse"
|
64
|
+
continue_shopping: "Weiter einkaufen"
|
65
|
+
empty_cart: "Dein Warenkorb ist leer"
|
66
|
+
quantity_abbreviated: "Anz."
|
67
|
+
quantity: "Anzahl"
|
68
|
+
remove: "Entfernen"
|
69
|
+
share_this_cart: "Diesen Warenkorb teilen"
|
70
|
+
share_this_cart_link_copy_success: "Link kopiert!"
|
71
|
+
subtotal: "Zwischensumme"
|
72
|
+
view_cart: "Warenkorb ansehen"
|
73
|
+
contact:
|
74
|
+
email: "E-Mail"
|
75
|
+
form_success: "Danke! Deine Nachricht wurde gesendet und wir werden uns bald bei dir melden."
|
76
|
+
message: "Nachricht"
|
77
|
+
name: "Name"
|
78
|
+
send_button: "Nachricht senden"
|
79
|
+
subject: "Betreff"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
en-CA:
|
2
|
+
storefront:
|
3
|
+
navigation:
|
4
|
+
all: "All"
|
5
|
+
all_products: "All products"
|
6
|
+
back_to_site: "Back to site"
|
7
|
+
cart: "Cart"
|
8
|
+
categories: "Categories"
|
9
|
+
contact: "Contact"
|
10
|
+
home: "Home"
|
11
|
+
item: "item"
|
12
|
+
items: "items"
|
13
|
+
more: "More"
|
14
|
+
next: "Next"
|
15
|
+
newest: "Newest"
|
16
|
+
pages: "Pages"
|
17
|
+
previous: "Previous"
|
18
|
+
products: "Products"
|
19
|
+
quick_view: "Quick view"
|
20
|
+
search: "Search"
|
21
|
+
shop: "Shop"
|
22
|
+
social: "Follow us"
|
23
|
+
subscribe: "Subscribe"
|
24
|
+
top_selling: "Best-selling"
|
25
|
+
view: "View"
|
26
|
+
view_all: "View all"
|
27
|
+
# "Sort By" translations are used in very few themes, and are not exposed in theme settings for sellers to configure
|
28
|
+
sort_by: Sort by
|
29
|
+
sort_by_featured: Featured
|
30
|
+
sort_by_on_sale: On Sale
|
31
|
+
sort_by_top_selling: Top Selling
|
32
|
+
sort_by_alphabetically_a_to_z: Alphabetically (A to Z)
|
33
|
+
sort_by_alphabetically_z_to_a: Alphabetically (Z to A)
|
34
|
+
sort_by_date_new_to_old: Date (New to Old)
|
35
|
+
sort_by_date_old_to_new: Date (Old to New)
|
36
|
+
sort_by_price_low_to_high: Price (Low to High)
|
37
|
+
sort_by_price_high_to_low: Price (High to Low)
|
38
|
+
home:
|
39
|
+
all_products: "All products"
|
40
|
+
featured: "Featured"
|
41
|
+
featured_categories: "Featured categories"
|
42
|
+
featured_products: "Featured products"
|
43
|
+
featured_video: ""
|
44
|
+
products:
|
45
|
+
add_to_cart: "Add to cart"
|
46
|
+
adding: "Adding..." # Used in few themes, intentionally not exposed in theme settings
|
47
|
+
added: "Added!" # Used in few themes, intentionally not exposed in theme settings
|
48
|
+
almost_sold_out: "Only a few left!"
|
49
|
+
coming_soon: "Coming soon"
|
50
|
+
description: "Description"
|
51
|
+
in_stock: "in stock"
|
52
|
+
inventory: "Inventory"
|
53
|
+
low_inventory: "Limited quantities available"
|
54
|
+
no_products: "No products found"
|
55
|
+
on_sale: "On sale"
|
56
|
+
related_products: "You might also like"
|
57
|
+
reset: "Reset"
|
58
|
+
search_results: "Search results"
|
59
|
+
select: "Select"
|
60
|
+
select_variant: "Select option"
|
61
|
+
sold_out: "Sold out"
|
62
|
+
cart:
|
63
|
+
checkout: "Checkout"
|
64
|
+
continue_shopping: "Continue shopping"
|
65
|
+
empty_cart: "Your cart is empty"
|
66
|
+
quantity_abbreviated: "Qty"
|
67
|
+
quantity: "Quantity"
|
68
|
+
remove: "Remove"
|
69
|
+
share_this_cart: "Share this cart"
|
70
|
+
share_this_cart_link_copy_success: "Link copied!"
|
71
|
+
subtotal: "Subtotal"
|
72
|
+
view_cart: "View cart"
|
73
|
+
contact:
|
74
|
+
email: "Email"
|
75
|
+
form_success: "Thanks! Your message has been sent and we'll get back to you soon."
|
76
|
+
message: "Message"
|
77
|
+
name: "Name"
|
78
|
+
send_button: "Send message"
|
79
|
+
subject: "Subject"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
en-GB:
|
2
|
+
storefront:
|
3
|
+
navigation:
|
4
|
+
all: "All"
|
5
|
+
all_products: "All products"
|
6
|
+
back_to_site: "Back to site"
|
7
|
+
cart: "Basket"
|
8
|
+
categories: "Categories"
|
9
|
+
contact: "Contact"
|
10
|
+
home: "Home"
|
11
|
+
item: "item"
|
12
|
+
items: "items"
|
13
|
+
more: "More"
|
14
|
+
next: "Next"
|
15
|
+
newest: "Newest"
|
16
|
+
pages: "Pages"
|
17
|
+
previous: "Previous"
|
18
|
+
products: "Products"
|
19
|
+
quick_view: "Quick view"
|
20
|
+
search: "Search"
|
21
|
+
shop: "Shop"
|
22
|
+
social: "Follow us"
|
23
|
+
subscribe: "Subscribe"
|
24
|
+
top_selling: "Top-selling"
|
25
|
+
view: "View"
|
26
|
+
view_all: "View all"
|
27
|
+
# "Sort By" translations are used in very few themes, and are not exposed in theme settings for sellers to configure
|
28
|
+
sort_by: Sort by
|
29
|
+
sort_by_featured: Featured
|
30
|
+
sort_by_on_sale: On Sale
|
31
|
+
sort_by_top_selling: Top Selling
|
32
|
+
sort_by_alphabetically_a_to_z: Alphabetically (A to Z)
|
33
|
+
sort_by_alphabetically_z_to_a: Alphabetically (Z to A)
|
34
|
+
sort_by_date_new_to_old: Date (New to Old)
|
35
|
+
sort_by_date_old_to_new: Date (Old to New)
|
36
|
+
sort_by_price_low_to_high: Price (Low to High)
|
37
|
+
sort_by_price_high_to_low: Price (High to Low)
|
38
|
+
home:
|
39
|
+
all_products: "All products"
|
40
|
+
featured: "Featured"
|
41
|
+
featured_categories: "Featured categories"
|
42
|
+
featured_products: "Featured products"
|
43
|
+
featured_video: ""
|
44
|
+
products:
|
45
|
+
add_to_cart: "Add to basket"
|
46
|
+
adding: "Adding..." # Used in few themes, intentionally not exposed in theme settings
|
47
|
+
added: "Added!" # Used in few themes, intentionally not exposed in theme settings
|
48
|
+
almost_sold_out: "Only a few left!"
|
49
|
+
coming_soon: "Coming soon"
|
50
|
+
description: "Description"
|
51
|
+
in_stock: "in stock"
|
52
|
+
inventory: "Stock"
|
53
|
+
low_inventory: "Limited quantities available"
|
54
|
+
no_products: "No products found"
|
55
|
+
on_sale: "On offer"
|
56
|
+
related_products: "You might also like"
|
57
|
+
reset: "Reset"
|
58
|
+
search_results: "Search results"
|
59
|
+
select: "Select"
|
60
|
+
select_variant: "Select option"
|
61
|
+
sold_out: "Sold out"
|
62
|
+
cart:
|
63
|
+
checkout: "Checkout"
|
64
|
+
continue_shopping: "Continue shopping"
|
65
|
+
empty_cart: "Your basket is empty"
|
66
|
+
quantity_abbreviated: "Qty"
|
67
|
+
quantity: "Quantity"
|
68
|
+
remove: "Remove"
|
69
|
+
share_this_cart: "Share this basket"
|
70
|
+
share_this_cart_link_copy_success: "Link copied!"
|
71
|
+
subtotal: "Subtotal"
|
72
|
+
view_cart: "View basket"
|
73
|
+
contact:
|
74
|
+
email: "Email"
|
75
|
+
form_success: "Thanks! Your message has been sent and we'll get back to you soon."
|
76
|
+
message: "Message"
|
77
|
+
name: "Name"
|
78
|
+
send_button: "Send message"
|
79
|
+
subject: "Subject"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
en-US:
|
2
|
+
storefront:
|
3
|
+
navigation:
|
4
|
+
all: "All"
|
5
|
+
all_products: "All products"
|
6
|
+
back_to_site: "Back to site"
|
7
|
+
cart: "Cart"
|
8
|
+
categories: "Categories"
|
9
|
+
contact: "Contact"
|
10
|
+
home: "Home"
|
11
|
+
item: "item"
|
12
|
+
items: "items"
|
13
|
+
more: "More"
|
14
|
+
next: "Next"
|
15
|
+
newest: "Newest"
|
16
|
+
pages: "Pages"
|
17
|
+
previous: "Previous"
|
18
|
+
products: "Products"
|
19
|
+
quick_view: "Quick view"
|
20
|
+
search: "Search"
|
21
|
+
shop: "Shop"
|
22
|
+
social: "Follow us"
|
23
|
+
subscribe: "Subscribe"
|
24
|
+
top_selling: "Top-selling"
|
25
|
+
view: "View"
|
26
|
+
view_all: "View all"
|
27
|
+
# "Sort By" translations are used in very few themes, and are not exposed in theme settings for sellers to configure
|
28
|
+
sort_by: Sort by
|
29
|
+
sort_by_featured: Featured
|
30
|
+
sort_by_on_sale: On Sale
|
31
|
+
sort_by_top_selling: Top Selling
|
32
|
+
sort_by_alphabetically_a_to_z: Alphabetically (A to Z)
|
33
|
+
sort_by_alphabetically_z_to_a: Alphabetically (Z to A)
|
34
|
+
sort_by_date_new_to_old: Date (New to Old)
|
35
|
+
sort_by_date_old_to_new: Date (Old to New)
|
36
|
+
sort_by_price_low_to_high: Price (Low to High)
|
37
|
+
sort_by_price_high_to_low: Price (High to Low)
|
38
|
+
home:
|
39
|
+
all_products: "All products"
|
40
|
+
featured: "Featured"
|
41
|
+
featured_categories: "Featured categories"
|
42
|
+
featured_products: "Featured products"
|
43
|
+
featured_video: ""
|
44
|
+
products:
|
45
|
+
add_to_cart: "Add to cart"
|
46
|
+
adding: "Adding..." # Used in few themes, intentionally not exposed in theme settings
|
47
|
+
added: "Added!" # Used in few themes, intentionally not exposed in theme settings
|
48
|
+
almost_sold_out: "Only a few left!"
|
49
|
+
coming_soon: "Coming soon"
|
50
|
+
description: "Description"
|
51
|
+
in_stock: "in stock"
|
52
|
+
inventory: "Inventory"
|
53
|
+
low_inventory: "Limited quantities available"
|
54
|
+
no_products: "No products found"
|
55
|
+
on_sale: "On sale"
|
56
|
+
related_products: "You might also like"
|
57
|
+
reset: "Reset"
|
58
|
+
search_results: "Search results"
|
59
|
+
select: "Select"
|
60
|
+
select_variant: "Select option"
|
61
|
+
sold_out: "Sold out"
|
62
|
+
cart:
|
63
|
+
checkout: "Checkout"
|
64
|
+
continue_shopping: "Continue shopping"
|
65
|
+
empty_cart: "Your cart is empty"
|
66
|
+
quantity_abbreviated: "Qty"
|
67
|
+
quantity: "Quantity"
|
68
|
+
remove: "Remove"
|
69
|
+
share_this_cart: "Share this cart"
|
70
|
+
share_this_cart_link_copy_success: "Link copied!"
|
71
|
+
subtotal: "Subtotal"
|
72
|
+
view_cart: "View cart"
|
73
|
+
contact:
|
74
|
+
email: "Email"
|
75
|
+
form_success: "Thanks! Your message has been sent and we'll get back to you soon."
|
76
|
+
message: "Message"
|
77
|
+
name: "Name"
|
78
|
+
send_button: "Send message"
|
79
|
+
subject: "Subject"
|
@@ -0,0 +1,79 @@
|
|
1
|
+
es-ES:
|
2
|
+
storefront:
|
3
|
+
navigation:
|
4
|
+
all: "Todo"
|
5
|
+
all_products: "Todos los productos"
|
6
|
+
back_to_site: "Volver al sitio"
|
7
|
+
cart: "Carrito"
|
8
|
+
categories: "Categorías"
|
9
|
+
contact: "Contáctanos"
|
10
|
+
home: "Inicio"
|
11
|
+
item: "artículo"
|
12
|
+
items: "artículos"
|
13
|
+
more: "Más"
|
14
|
+
next: "Siguiente"
|
15
|
+
newest: "Novedades"
|
16
|
+
pages: "Páginas"
|
17
|
+
previous: "Anterior"
|
18
|
+
products: "Productos"
|
19
|
+
quick_view: "Vista rápida"
|
20
|
+
search: "Buscar"
|
21
|
+
shop: "Tienda"
|
22
|
+
social: "Síguenos"
|
23
|
+
subscribe: "Suscribirse"
|
24
|
+
top_selling: "Más vendidos"
|
25
|
+
view: "Ver"
|
26
|
+
view_all: "Ver todo"
|
27
|
+
# "Sort By" translations are used in very few themes, and are not exposed in theme settings for sellers to configure
|
28
|
+
sort_by: Ordenar por
|
29
|
+
sort_by_featured: Destacados
|
30
|
+
sort_by_on_sale: En oferta
|
31
|
+
sort_by_top_selling: Más vendidos
|
32
|
+
sort_by_alphabetically_a_to_z: Alfabético (A a Z)
|
33
|
+
sort_by_alphabetically_z_to_a: Alfabético (Z a A)
|
34
|
+
sort_by_date_new_to_old: Fecha (más reciente)
|
35
|
+
sort_by_date_old_to_new: Fecha (más antiguo)
|
36
|
+
sort_by_price_low_to_high: Precio (menor a mayor)
|
37
|
+
sort_by_price_high_to_low: Precio (mayor a menor)
|
38
|
+
home:
|
39
|
+
all_products: "Todos los productos"
|
40
|
+
featured: "Destacado"
|
41
|
+
featured_categories: "Categorías destacadas"
|
42
|
+
featured_products: "Productos destacados"
|
43
|
+
featured_video: ""
|
44
|
+
products:
|
45
|
+
add_to_cart: "Añadir"
|
46
|
+
added: "¡Añadido!" # Used in few themes, intentionally not exposed in theme settings
|
47
|
+
adding: "Añadiendo..." # Used in few themes, intentionally not exposed in theme settings
|
48
|
+
almost_sold_out: "¡Quedan pocos!"
|
49
|
+
coming_soon: "Próximamente"
|
50
|
+
in_stock: "en stock"
|
51
|
+
description: "Descripción"
|
52
|
+
inventory: "Existencias"
|
53
|
+
low_inventory: "Cantidades limitadas"
|
54
|
+
no_products: "No se encuentran productos"
|
55
|
+
on_sale: "En oferta"
|
56
|
+
related_products: "Te podría gustar"
|
57
|
+
reset: "Restablecer"
|
58
|
+
search_results: "Resultados de búsqueda"
|
59
|
+
select: "Selecciona"
|
60
|
+
select_variant: "Seleccionar opción"
|
61
|
+
sold_out: "Agotado"
|
62
|
+
cart:
|
63
|
+
checkout: "Comprar"
|
64
|
+
continue_shopping: "Continuar comprando"
|
65
|
+
empty_cart: "Tu carrito está vacío"
|
66
|
+
quantity_abbreviated: "Cant."
|
67
|
+
quantity: "Cantidad"
|
68
|
+
remove: "Eliminar"
|
69
|
+
share_this_cart: "Compartir este carrito"
|
70
|
+
share_this_cart_link_copy_success: "¡Enlace copiado!"
|
71
|
+
subtotal: "Subtotal"
|
72
|
+
view_cart: "Ver carrito"
|
73
|
+
contact:
|
74
|
+
email: "Correo electrónico"
|
75
|
+
form_success: "¡Gracias! Tu mensaje ha sido enviado y te responderemos pronto."
|
76
|
+
message: "Mensaje"
|
77
|
+
name: "Nombre"
|
78
|
+
send_button: "Enviar mensaje"
|
79
|
+
subject: "Asunto"
|