dugway 1.1.0 → 1.3.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 +32 -7
- data/dugway.gemspec +11 -9
- data/lib/dugway/application.rb +5 -3
- data/lib/dugway/assets/big_cartel_logo.svg +4 -0
- data/lib/dugway/cli/build.rb +7 -1
- data/lib/dugway/cli/server.rb +69 -9
- data/lib/dugway/cli/templates/source/settings.json +8 -0
- data/lib/dugway/cli/validate.rb +9 -2
- data/lib/dugway/controller.rb +5 -1
- data/lib/dugway/liquid/drops/account_drop.rb +4 -0
- data/lib/dugway/liquid/drops/artists_drop.rb +12 -0
- data/lib/dugway/liquid/drops/base_drop.rb +27 -2
- data/lib/dugway/liquid/drops/categories_drop.rb +12 -0
- data/lib/dugway/liquid/drops/features_drop.rb +144 -0
- data/lib/dugway/liquid/drops/pages_drop.rb +30 -2
- data/lib/dugway/liquid/drops/product_drop.rb +11 -0
- data/lib/dugway/liquid/drops/products_drop.rb +39 -0
- data/lib/dugway/liquid/drops/theme_drop.rb +52 -6
- data/lib/dugway/liquid/drops/translations_drop.rb +122 -0
- data/lib/dugway/liquid/filters/core_filters.rb +169 -7
- data/lib/dugway/liquid/filters/font_filters.rb +1 -0
- data/lib/dugway/liquid/filters/util_filters.rb +1 -10
- data/lib/dugway/liquid/tags/get.rb +6 -6
- data/lib/dugway/liquid/tags/paginate.rb +61 -11
- data/lib/dugway/liquifier.rb +44 -8
- data/lib/dugway/store.rb +46 -3
- data/lib/dugway/theme.rb +151 -15
- data/lib/dugway/version.rb +1 -1
- data/lib/dugway.rb +55 -2
- data/locales/storefront.de.yml +81 -0
- data/locales/storefront.en-CA.yml +81 -0
- data/locales/storefront.en-GB.yml +81 -0
- data/locales/storefront.en-US.yml +81 -0
- data/locales/storefront.es-ES.yml +81 -0
- data/locales/storefront.es-MX.yml +81 -0
- data/locales/storefront.fr-CA.yml +81 -0
- data/locales/storefront.fr-FR.yml +81 -0
- data/locales/storefront.id.yml +81 -0
- data/locales/storefront.it.yml +81 -0
- data/locales/storefront.ja.yml +81 -0
- data/locales/storefront.ko.yml +81 -0
- data/locales/storefront.nl.yml +81 -0
- data/locales/storefront.pl.yml +81 -0
- data/locales/storefront.pt-BR.yml +81 -0
- data/locales/storefront.pt-PT.yml +81 -0
- data/locales/storefront.ro.yml +81 -0
- data/locales/storefront.sv.yml +81 -0
- data/locales/storefront.tr.yml +81 -0
- data/locales/storefront.zh-CN.yml +81 -0
- data/locales/storefront.zh-TW.yml +81 -0
- data/log/dugway.log +1 -0
- data/mise.toml +2 -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 +7 -0
- data/spec/units/dugway/liquid/drops/features_drop_spec.rb +182 -0
- data/spec/units/dugway/liquid/drops/pages_drop_spec.rb +186 -7
- data/spec/units/dugway/liquid/drops/product_drop_spec.rb +17 -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/liquid/filters/core_filters_spec.rb +301 -3
- data/spec/units/dugway/store_spec.rb +55 -0
- data/spec/units/dugway/theme_spec.rb +543 -1
- metadata +84 -25
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
|
|
@@ -95,6 +101,7 @@ module Dugway
|
|
95
101
|
|
96
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?
|
@@ -117,7 +124,14 @@ module Dugway
|
|
117
124
|
|
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
|
121
135
|
|
122
136
|
@errors.empty?
|
123
137
|
end
|
@@ -164,15 +178,41 @@ module Dugway
|
|
164
178
|
@errors << "layout.html must have exactly one `data-bc-hook=\"footer\"`" if footer_hooks != 1
|
165
179
|
end
|
166
180
|
|
181
|
+
VALID_SECTIONS = %w(global_navigation homepage product_page general messaging social translations).freeze
|
182
|
+
|
167
183
|
def validate_options_settings
|
168
184
|
return unless settings['options']
|
169
185
|
|
170
186
|
validate_options_descriptions
|
171
187
|
validate_options_requires
|
188
|
+
validate_option_defaults
|
172
189
|
end
|
173
190
|
|
174
191
|
private
|
175
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
|
+
|
176
216
|
def validate_preview
|
177
217
|
preview = settings['preset_styles']['preview']
|
178
218
|
if preview
|
@@ -254,6 +294,10 @@ module Dugway
|
|
254
294
|
def validate_options_requires
|
255
295
|
return unless settings['options']
|
256
296
|
all_variables = settings['options'].map { |o| o['variable'] }
|
297
|
+
|
298
|
+
# Include variables from images and image_sets settings
|
299
|
+
all_variables.concat(settings['images'].map { |i| i['variable'] }) if settings['images']
|
300
|
+
all_variables.concat(settings['image_sets'].map { |i| i['variable'] }) if settings['image_sets']
|
257
301
|
|
258
302
|
settings['options'].each do |option|
|
259
303
|
next unless option['requires']
|
@@ -275,24 +319,116 @@ module Dugway
|
|
275
319
|
|
276
320
|
# Process each rule in the array
|
277
321
|
option['requires'].each do |rule|
|
278
|
-
|
322
|
+
validate_requires_rule(rule, option['variable'], all_variables)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
279
326
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
327
|
+
# Validates individual requires rule - handles both string rules and object rules (like 'any')
|
328
|
+
def validate_requires_rule(rule, option_variable, all_variables)
|
329
|
+
# Handle object-based rules (like {"any": [...]})
|
330
|
+
if rule.is_a?(Hash)
|
331
|
+
if rule.has_key?('any')
|
332
|
+
validate_any_condition(rule['any'], option_variable, all_variables)
|
333
|
+
else
|
334
|
+
@errors << "Option '#{option_variable}' has unsupported requires object. Only 'any' is currently supported."
|
335
|
+
end
|
336
|
+
return
|
337
|
+
end
|
287
338
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
339
|
+
# Handle string-based rules (existing logic)
|
340
|
+
return if rule == 'inventory'
|
341
|
+
|
342
|
+
valid_operators = %w(eq neq gt lt gte lte present)
|
343
|
+
|
344
|
+
# Extract setting name and optional operator/value
|
345
|
+
parts = rule.split(/\s+/)
|
346
|
+
setting_name = parts[0]
|
347
|
+
operator = parts[1]
|
348
|
+
value = parts[2]
|
349
|
+
|
350
|
+
if setting_name.start_with?('feature:')
|
351
|
+
# Validate feature flag format
|
352
|
+
unless setting_name =~ /^feature:[a-z_]+$/
|
353
|
+
@errors << "Option '#{option_variable}' has invalid feature flag format"
|
354
|
+
return
|
292
355
|
end
|
356
|
+
|
357
|
+
# Only validate operator/value if they exist
|
358
|
+
if operator
|
359
|
+
is_valid_operator = ['eq', 'neq'].include?(operator)
|
360
|
+
|
361
|
+
@errors << "Option '#{option_variable}' has invalid operator '#{operator}'. Feature flags can only use `eq` or `neq`." unless is_valid_operator
|
362
|
+
|
363
|
+
is_valid_value = ['visible'].include?(value)
|
364
|
+
|
365
|
+
@errors << "Option '#{option_variable}' has invalid comparison value '#{value}'. Feature flags can only check for `visible`." unless is_valid_value
|
366
|
+
end
|
367
|
+
return
|
368
|
+
end
|
369
|
+
|
370
|
+
# --- Non-feature rule validation ---
|
371
|
+
unless all_variables.include?(setting_name)
|
372
|
+
@errors << "Option '#{option_variable}' requires unknown setting '#{setting_name}'"
|
373
|
+
return # Skip further checks for this rule if setting is unknown
|
374
|
+
end
|
375
|
+
|
376
|
+
# Validate operator if present
|
377
|
+
if operator && !valid_operators.include?(operator)
|
378
|
+
@errors << "Option '#{option_variable}' has invalid operator '#{operator}'. Allowed operators are: #{valid_operators.join(', ')}."
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
# Validates 'any' condition - ensures it's an array and validates each nested rule
|
383
|
+
def validate_any_condition(any_rules, option_variable, all_variables)
|
384
|
+
unless any_rules.is_a?(Array)
|
385
|
+
@errors << "Option '#{option_variable}' has invalid 'any' condition - must be an array of rules"
|
386
|
+
return
|
387
|
+
end
|
388
|
+
|
389
|
+
if any_rules.empty?
|
390
|
+
@errors << "Option '#{option_variable}' has empty 'any' condition - must contain at least one rule"
|
391
|
+
return
|
392
|
+
end
|
393
|
+
|
394
|
+
# Validate each rule within the 'any' condition
|
395
|
+
any_rules.each do |nested_rule|
|
396
|
+
validate_requires_rule(nested_rule, option_variable, all_variables)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def validate_option_value(option, value_type)
|
401
|
+
value = option[value_type]
|
402
|
+
return unless value
|
403
|
+
|
404
|
+
case option['type']
|
405
|
+
when 'select'
|
406
|
+
validate_select_option(option, value, value_type)
|
407
|
+
when 'boolean'
|
408
|
+
@errors << "#{value_type.capitalize} '#{value}' is not a boolean for #{option['variable']}" unless [true, false].include?(value)
|
293
409
|
end
|
294
410
|
end
|
295
411
|
|
412
|
+
def validate_option_defaults
|
413
|
+
return unless settings['options']
|
414
|
+
settings['options'].each do |option|
|
415
|
+
validate_option_value(option, 'default')
|
416
|
+
validate_option_value(option, 'upgrade_default')
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
def validate_select_option(option, value, value_type)
|
421
|
+
if option['options'] == "product_orders"
|
422
|
+
valid_values = %w[position top-selling newest views updated_new_to_old]
|
423
|
+
@errors << "#{value_type.capitalize} '#{value}' is not a valid option for #{option['variable']}" unless valid_values.include?(value)
|
424
|
+
elsif option['options'].is_a?(String) && option['options'] =~ /^\d+\.\.\d+$/
|
425
|
+
range = eval(option['options'])
|
426
|
+
@errors << "#{value_type.capitalize} '#{value}' is out of range for #{option['variable']}" unless range.include?(value.to_i)
|
427
|
+
elsif option['options'].is_a?(Array)
|
428
|
+
valid_values = option['options'].map { |o| o.is_a?(Array) ? o[1] : o }
|
429
|
+
@errors << "#{value_type.capitalize} '#{value}' is not a valid option for #{option['variable']}" unless valid_values.include?(value)
|
430
|
+
end
|
431
|
+
end
|
296
432
|
|
297
433
|
def source_dir
|
298
434
|
Dugway.source_dir
|
data/lib/dugway/version.rb
CHANGED
data/lib/dugway.rb
CHANGED
@@ -11,9 +11,45 @@ end
|
|
11
11
|
|
12
12
|
require 'active_support/all'
|
13
13
|
require 'i18n'
|
14
|
+
require 'i18n/backend/fallbacks'
|
14
15
|
require 'bigcartel-currency-locales'
|
15
16
|
require 'bigcartel/theme/fonts'
|
16
17
|
|
18
|
+
# Configure I18n to load locale files from the gem's locales directory.
|
19
|
+
# This allows for easy addition and management of translations.
|
20
|
+
gem_locales_pattern = File.expand_path('../locales/storefront.*.yml', File.dirname(__FILE__))
|
21
|
+
gem_locale_files = Dir.glob(gem_locales_pattern)
|
22
|
+
|
23
|
+
# Add these locale files to the I18n load path, ensuring no duplicates and preserving existing paths.
|
24
|
+
I18n.load_path = (I18n.load_path + gem_locale_files).uniq
|
25
|
+
|
26
|
+
# Determine available locales from the filenames (e.g., 'storefront.en-US.yml' -> :'en-US').
|
27
|
+
available_locales = gem_locale_files.map do |file|
|
28
|
+
# Extracts 'en-US' from 'storefront.en-US.yml' or 'de' from 'storefront.de.yml'
|
29
|
+
locale_string = File.basename(file, '.yml').split('storefront.').last
|
30
|
+
locale_string.to_sym if locale_string
|
31
|
+
end.compact.uniq
|
32
|
+
|
33
|
+
# Ensure :en is an available locale if any 'en-XX' variant exists (e.g., :en-US, :en-GB),
|
34
|
+
# as I18n can use :en as a fallback.
|
35
|
+
if available_locales.any? { |loc| loc.to_s.start_with?('en-') } && !available_locales.include?(:en)
|
36
|
+
available_locales << :en
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set available locales. Provide a default if no locale files are found (e.g., during initial setup or in case of an error).
|
40
|
+
I18n.config.available_locales = available_locales.empty? ? [:'en-US', :en] : available_locales
|
41
|
+
|
42
|
+
# Enable fallbacks for I18n
|
43
|
+
# This allows sv-SE to fallback to sv, en-GB to en, etc.
|
44
|
+
I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
|
45
|
+
|
46
|
+
# Disable enforce_available_locales to allow invalid locales like 'eu'
|
47
|
+
# We'll handle them gracefully with fallbacks
|
48
|
+
I18n.enforce_available_locales = false
|
49
|
+
|
50
|
+
# Reload I18n to apply changes and load the translations from the files.
|
51
|
+
I18n.backend.reload!
|
52
|
+
|
17
53
|
require 'rack/builder'
|
18
54
|
require 'rack/commonlogger'
|
19
55
|
require 'better_errors'
|
@@ -36,7 +72,21 @@ module Dugway
|
|
36
72
|
|
37
73
|
BigCartel::CurrencyLocales.insert
|
38
74
|
I18n.default_locale = 'en-US'
|
39
|
-
|
75
|
+
|
76
|
+
# Set locale with fallback handling for invalid or missing locales
|
77
|
+
begin
|
78
|
+
requested_locale = Dugway.store.locale
|
79
|
+
if requested_locale
|
80
|
+
# Try to set the locale - if it's completely invalid (like 'eu'),
|
81
|
+
# this will fall back to default_locale due to enforce_available_locales = false
|
82
|
+
I18n.locale = requested_locale
|
83
|
+
else
|
84
|
+
I18n.locale = I18n.default_locale
|
85
|
+
end
|
86
|
+
rescue I18n::InvalidLocale
|
87
|
+
# If somehow we still get an invalid locale error, fall back to default
|
88
|
+
I18n.locale = I18n.default_locale
|
89
|
+
end
|
40
90
|
|
41
91
|
Rack::Builder.app do
|
42
92
|
use Rack::Session::Cookie, :secret => 'stopwarningmeaboutnothavingasecret'
|
@@ -52,7 +102,9 @@ module Dugway
|
|
52
102
|
end
|
53
103
|
|
54
104
|
def store
|
55
|
-
|
105
|
+
store_options = options && options[:store] ? options[:store] : {}
|
106
|
+
subdomain = store_options[:subdomain] || 'dugway'
|
107
|
+
@store ||= Store.new(subdomain, store_options)
|
56
108
|
end
|
57
109
|
|
58
110
|
def theme
|
@@ -74,5 +126,6 @@ module Dugway
|
|
74
126
|
def options
|
75
127
|
@options
|
76
128
|
end
|
129
|
+
|
77
130
|
end
|
78
131
|
end
|
@@ -0,0 +1,81 @@
|
|
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
|
+
variant: "Option"
|
63
|
+
variants: "Optionen"
|
64
|
+
cart:
|
65
|
+
checkout: "Zur Kasse"
|
66
|
+
continue_shopping: "Weiter einkaufen"
|
67
|
+
empty_cart: "Dein Warenkorb ist leer"
|
68
|
+
quantity_abbreviated: "Anz."
|
69
|
+
quantity: "Anzahl"
|
70
|
+
remove: "Entfernen"
|
71
|
+
share_this_cart: "Diesen Warenkorb teilen"
|
72
|
+
share_this_cart_link_copy_success: "Link kopiert!"
|
73
|
+
subtotal: "Zwischensumme"
|
74
|
+
view_cart: "Warenkorb ansehen"
|
75
|
+
contact:
|
76
|
+
email: "E-Mail"
|
77
|
+
form_success: "Danke! Deine Nachricht wurde gesendet und wir werden uns bald bei dir melden."
|
78
|
+
message: "Nachricht"
|
79
|
+
name: "Name"
|
80
|
+
send_button: "Nachricht senden"
|
81
|
+
subject: "Betreff"
|
@@ -0,0 +1,81 @@
|
|
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
|
+
variant: "Option"
|
63
|
+
variants: "Options"
|
64
|
+
cart:
|
65
|
+
checkout: "Checkout"
|
66
|
+
continue_shopping: "Continue shopping"
|
67
|
+
empty_cart: "Your cart is empty"
|
68
|
+
quantity_abbreviated: "Qty"
|
69
|
+
quantity: "Quantity"
|
70
|
+
remove: "Remove"
|
71
|
+
share_this_cart: "Share this cart"
|
72
|
+
share_this_cart_link_copy_success: "Link copied!"
|
73
|
+
subtotal: "Subtotal"
|
74
|
+
view_cart: "View cart"
|
75
|
+
contact:
|
76
|
+
email: "Email"
|
77
|
+
form_success: "Thanks! Your message has been sent and we'll get back to you soon."
|
78
|
+
message: "Message"
|
79
|
+
name: "Name"
|
80
|
+
send_button: "Send message"
|
81
|
+
subject: "Subject"
|
@@ -0,0 +1,81 @@
|
|
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
|
+
variant: "Option"
|
63
|
+
variants: "Options"
|
64
|
+
cart:
|
65
|
+
checkout: "Checkout"
|
66
|
+
continue_shopping: "Continue shopping"
|
67
|
+
empty_cart: "Your basket is empty"
|
68
|
+
quantity_abbreviated: "Qty"
|
69
|
+
quantity: "Quantity"
|
70
|
+
remove: "Remove"
|
71
|
+
share_this_cart: "Share this basket"
|
72
|
+
share_this_cart_link_copy_success: "Link copied!"
|
73
|
+
subtotal: "Subtotal"
|
74
|
+
view_cart: "View basket"
|
75
|
+
contact:
|
76
|
+
email: "Email"
|
77
|
+
form_success: "Thanks! Your message has been sent and we'll get back to you soon."
|
78
|
+
message: "Message"
|
79
|
+
name: "Name"
|
80
|
+
send_button: "Send message"
|
81
|
+
subject: "Subject"
|
@@ -0,0 +1,81 @@
|
|
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
|
+
variant: "Option"
|
63
|
+
variants: "Options"
|
64
|
+
cart:
|
65
|
+
checkout: "Checkout"
|
66
|
+
continue_shopping: "Continue shopping"
|
67
|
+
empty_cart: "Your cart is empty"
|
68
|
+
quantity_abbreviated: "Qty"
|
69
|
+
quantity: "Quantity"
|
70
|
+
remove: "Remove"
|
71
|
+
share_this_cart: "Share this cart"
|
72
|
+
share_this_cart_link_copy_success: "Link copied!"
|
73
|
+
subtotal: "Subtotal"
|
74
|
+
view_cart: "View cart"
|
75
|
+
contact:
|
76
|
+
email: "Email"
|
77
|
+
form_success: "Thanks! Your message has been sent and we'll get back to you soon."
|
78
|
+
message: "Message"
|
79
|
+
name: "Name"
|
80
|
+
send_button: "Send message"
|
81
|
+
subject: "Subject"
|