shopify_app 9.0.0 → 12.0.5
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/.travis.yml +0 -2
- data/CHANGELOG.md +145 -0
- data/README.md +180 -126
- data/app/assets/javascripts/shopify_app/itp_helper.js +6 -6
- data/app/assets/javascripts/shopify_app/storage_access.js +36 -7
- data/app/controllers/concerns/shopify_app/authenticated.rb +1 -1
- data/app/controllers/shopify_app/callback_controller.rb +14 -5
- data/app/controllers/shopify_app/extension_verification_controller.rb +20 -0
- data/app/controllers/shopify_app/sessions_controller.rb +44 -18
- data/app/views/shopify_app/sessions/enable_cookies.html.erb +3 -1
- data/app/views/shopify_app/sessions/request_storage_access.html.erb +2 -1
- data/app/views/shopify_app/sessions/top_level_interaction.html.erb +1 -0
- data/app/views/shopify_app/shared/redirect.html.erb +1 -0
- data/config/locales/cs.yml +23 -0
- data/config/locales/da.yml +20 -0
- data/config/locales/de.yml +5 -5
- data/config/locales/en.yml +1 -1
- data/config/locales/es.yml +3 -3
- data/config/locales/fi.yml +20 -0
- data/config/locales/fr.yml +3 -3
- data/config/locales/hi.yml +23 -0
- data/config/locales/it.yml +2 -3
- data/config/locales/ja.yml +1 -1
- data/config/locales/ko.yml +19 -0
- data/config/locales/ms.yml +22 -0
- data/config/locales/nb.yml +21 -0
- data/config/locales/nl.yml +3 -3
- data/config/locales/pl.yml +21 -0
- data/config/locales/pt-BR.yml +9 -10
- data/config/locales/pt-PT.yml +22 -0
- data/config/locales/sv.yml +21 -0
- data/config/locales/th.yml +20 -0
- data/config/locales/tr.yml +22 -0
- data/config/locales/zh-CN.yml +3 -3
- data/config/locales/zh-TW.yml +1 -2
- data/docs/Quickstart.md +44 -16
- data/docs/Releasing.md +0 -1
- data/docs/install-on-dev-shop.png +0 -0
- data/docs/test-your-app.png +0 -0
- data/karma.conf.js +1 -0
- data/lib/generators/shopify_app/add_after_authenticate_job/add_after_authenticate_job_generator.rb +2 -2
- data/lib/generators/shopify_app/add_marketing_activity_extension/add_marketing_activity_extension_generator.rb +39 -0
- data/lib/generators/shopify_app/add_marketing_activity_extension/templates/marketing_activities_controller.rb +62 -0
- data/lib/generators/shopify_app/home_controller/home_controller_generator.rb +0 -6
- data/lib/generators/shopify_app/install/install_generator.rb +27 -11
- data/lib/generators/shopify_app/install/templates/_flash_messages.html.erb +1 -17
- data/lib/generators/shopify_app/install/templates/embedded_app.html.erb +11 -10
- data/lib/generators/shopify_app/install/templates/flash_messages.js +26 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.js +15 -0
- data/lib/generators/shopify_app/install/templates/shopify_app.rb +6 -3
- data/lib/generators/shopify_app/install/templates/shopify_app_index.js +2 -0
- data/lib/generators/shopify_app/install/templates/shopify_provider.rb +1 -0
- data/lib/generators/shopify_app/install/templates/user_agent.rb +5 -0
- data/lib/generators/shopify_app/user_model/templates/db/migrate/create_users.erb +16 -0
- data/lib/generators/shopify_app/user_model/templates/user.rb +7 -0
- data/lib/generators/shopify_app/user_model/templates/users.yml +4 -0
- data/lib/generators/shopify_app/user_model/user_model_generator.rb +38 -0
- data/lib/shopify_app.rb +46 -29
- data/lib/shopify_app/configuration.rb +24 -9
- data/lib/shopify_app/controller_concerns/login_protection.rb +53 -7
- data/lib/shopify_app/engine.rb +4 -0
- data/lib/shopify_app/managers/webhooks_manager.rb +1 -1
- data/lib/shopify_app/middleware/same_site_cookie_middleware.rb +33 -0
- data/lib/shopify_app/session/in_memory_session_store.rb +1 -1
- data/lib/shopify_app/session/session_repository.rb +2 -2
- data/lib/shopify_app/session/session_storage.rb +10 -22
- data/lib/shopify_app/session/storage_strategies/shop_storage_strategy.rb +23 -0
- data/lib/shopify_app/session/storage_strategies/user_storage_strategy.rb +24 -0
- data/lib/shopify_app/utils.rb +7 -0
- data/lib/shopify_app/version.rb +1 -1
- data/package-lock.json +7212 -11
- data/package.json +9 -9
- data/service.yml +1 -1
- data/shopify_app.gemspec +10 -5
- data/translation.yml +1 -1
- data/yarn.lock +2555 -1886
- metadata +115 -19
- data/lib/generators/shopify_app/home_controller/templates/shopify_app_ready_script.html.erb +0 -7
@@ -4,31 +4,31 @@
|
|
4
4
|
this.itpAction = document.getElementById('TopLevelInteractionButton');
|
5
5
|
this.redirectUrl = opts.redirectUrl;
|
6
6
|
}
|
7
|
-
|
7
|
+
|
8
8
|
ITPHelper.prototype.redirect = function() {
|
9
9
|
sessionStorage.setItem('shopify.top_level_interaction', true);
|
10
10
|
window.location.href = this.redirectUrl;
|
11
11
|
}
|
12
|
-
|
12
|
+
|
13
13
|
ITPHelper.prototype.userAgentIsAffected = function() {
|
14
14
|
return Boolean(document.hasStorageAccess);
|
15
15
|
}
|
16
|
-
|
16
|
+
|
17
17
|
ITPHelper.prototype.canPartitionCookies = function() {
|
18
18
|
var versionRegEx = /Version\/12\.0\.?\d? Safari/;
|
19
19
|
return versionRegEx.test(navigator.userAgent);
|
20
20
|
}
|
21
|
-
|
21
|
+
|
22
22
|
ITPHelper.prototype.setUpContent = function(onClick) {
|
23
23
|
this.itpContent.style.display = 'block';
|
24
24
|
this.itpAction.addEventListener('click', this.redirect.bind(this));
|
25
25
|
}
|
26
|
-
|
26
|
+
|
27
27
|
ITPHelper.prototype.execute = function() {
|
28
28
|
if (!this.itpContent) {
|
29
29
|
return;
|
30
30
|
}
|
31
|
-
|
31
|
+
|
32
32
|
if (this.userAgentIsAffected()) {
|
33
33
|
this.setUpContent();
|
34
34
|
} else {
|
@@ -28,18 +28,47 @@
|
|
28
28
|
window.parent.location.href = this.redirectData.myshopifyUrl + '/admin/apps';
|
29
29
|
}
|
30
30
|
|
31
|
-
StorageAccessHelper.prototype.
|
32
|
-
window.location.href = this.redirectData.
|
31
|
+
StorageAccessHelper.prototype.redirectToAppTargetUrl = function() {
|
32
|
+
window.location.href = this.redirectData.appTargetUrl;
|
33
|
+
}
|
34
|
+
|
35
|
+
StorageAccessHelper.prototype.sameSiteNoneIncompatible = function(ua) {
|
36
|
+
return ua.includes("iPhone OS 12_") || ua.includes("iPad; CPU OS 12_") || //iOS 12
|
37
|
+
(ua.includes("UCBrowser/")
|
38
|
+
? this.isOlderUcBrowser(ua) //UC Browser < 12.13.2
|
39
|
+
: (ua.includes("Chrome/5") || ua.includes("Chrome/6"))) ||
|
40
|
+
ua.includes("Chromium/5") || ua.includes("Chromium/6") ||
|
41
|
+
(ua.includes(" OS X 10_14_") &&
|
42
|
+
((ua.includes("Version/") && ua.includes("Safari")) || //Safari on MacOS 10.14
|
43
|
+
ua.endsWith("(KHTML, like Gecko)"))); //Web view on MacOS 10.14
|
44
|
+
}
|
45
|
+
|
46
|
+
StorageAccessHelper.prototype.isOlderUcBrowser = function(ua) {
|
47
|
+
var match = ua.match(/UCBrowser\/(\d+)\.(\d+)\.(\d+)\./);
|
48
|
+
if (!match) return false;
|
49
|
+
var major = parseInt(match[1]);
|
50
|
+
var minor = parseInt(match[2]);
|
51
|
+
var build = parseInt(match[3]);
|
52
|
+
if (major != 12) return major < 12;
|
53
|
+
if (minor != 13) return minor < 13;
|
54
|
+
return build < 2;
|
55
|
+
}
|
56
|
+
|
57
|
+
StorageAccessHelper.prototype.setCookie = function(value) {
|
58
|
+
if(!this.sameSiteNoneIncompatible(navigator.userAgent)) {
|
59
|
+
value += '; secure; SameSite=None'
|
60
|
+
}
|
61
|
+
document.cookie = value;
|
33
62
|
}
|
34
63
|
|
35
64
|
StorageAccessHelper.prototype.grantedStorageAccess = function() {
|
36
65
|
try {
|
37
66
|
sessionStorage.setItem('shopify.granted_storage_access', true);
|
38
|
-
|
67
|
+
this.setCookie('shopify.granted_storage_access=true');
|
39
68
|
if (!document.cookie) {
|
40
69
|
throw 'Cannot set third-party cookie.'
|
41
70
|
}
|
42
|
-
this.
|
71
|
+
this.redirectToAppTargetUrl();
|
43
72
|
} catch (error) {
|
44
73
|
console.warn('Third party cookies may be blocked.', error);
|
45
74
|
this.redirectToAppTLD(ACCESS_DENIED_STATUS);
|
@@ -61,7 +90,7 @@
|
|
61
90
|
StorageAccessHelper.prototype.handleHasStorageAccess = function() {
|
62
91
|
if (sessionStorage.getItem('shopify.granted_storage_access')) {
|
63
92
|
// If app was classified by ITP and used Storage Access API to acquire access
|
64
|
-
this.
|
93
|
+
this.redirectToAppTargetUrl();
|
65
94
|
} else {
|
66
95
|
// If app has not been classified by ITP and still has storage access
|
67
96
|
this.redirectToAppTLD(ACCESS_GRANTED_STATUS);
|
@@ -103,11 +132,11 @@
|
|
103
132
|
|
104
133
|
/* ITP 2.0 solution: handles cookie partitioning */
|
105
134
|
StorageAccessHelper.prototype.setUpHelper = function() {
|
106
|
-
return new ITPHelper({redirectUrl: window.shopOrigin + "/admin/apps/" + window.apiKey});
|
135
|
+
return new ITPHelper({redirectUrl: window.shopOrigin + "/admin/apps/" + window.apiKey + window.returnTo});
|
107
136
|
}
|
108
137
|
|
109
138
|
StorageAccessHelper.prototype.setCookieAndRedirect = function() {
|
110
|
-
|
139
|
+
this.setCookie('shopify.cookies_persist=true');
|
111
140
|
var helper = this.setUpHelper();
|
112
141
|
helper.redirect();
|
113
142
|
}
|
@@ -8,7 +8,7 @@ module ShopifyApp
|
|
8
8
|
include ShopifyApp::Localization
|
9
9
|
include ShopifyApp::LoginProtection
|
10
10
|
include ShopifyApp::EmbeddedApp
|
11
|
-
before_action :
|
11
|
+
before_action :login_again_if_different_user_or_shop
|
12
12
|
around_action :shopify_session
|
13
13
|
end
|
14
14
|
end
|
@@ -15,7 +15,7 @@ module ShopifyApp
|
|
15
15
|
redirect_to return_address
|
16
16
|
else
|
17
17
|
flash[:error] = I18n.t('could_not_log_in')
|
18
|
-
redirect_to
|
18
|
+
redirect_to(login_url_with_optional_shop)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -55,10 +55,16 @@ module ShopifyApp
|
|
55
55
|
token: token,
|
56
56
|
api_version: ShopifyApp.configuration.api_version
|
57
57
|
)
|
58
|
-
|
59
|
-
session[:shopify] = ShopifyApp::SessionRepository.store(session_store)
|
58
|
+
session[:shopify] = ShopifyApp::SessionRepository.store(session_store, user: associated_user)
|
60
59
|
session[:shopify_domain] = shop_name
|
61
60
|
session[:shopify_user] = associated_user
|
61
|
+
|
62
|
+
if ShopifyApp.configuration.per_user_tokens?
|
63
|
+
# Adds the user_session to the session to determine if the logged in user has changed
|
64
|
+
user_session = auth_hash&.extra&.session
|
65
|
+
raise IndexError, "Missing user session signature" if user_session.nil?
|
66
|
+
session[:user_session] = user_session
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
def install_webhooks
|
@@ -86,10 +92,13 @@ module ShopifyApp
|
|
86
92
|
|
87
93
|
return unless config && config[:job].present?
|
88
94
|
|
95
|
+
job = config[:job]
|
96
|
+
job = job.constantize if job.is_a?(String)
|
97
|
+
|
89
98
|
if config[:inline] == true
|
90
|
-
|
99
|
+
job.perform_now(shop_domain: session[:shopify_domain])
|
91
100
|
else
|
92
|
-
|
101
|
+
job.perform_later(shop_domain: session[:shopify_domain])
|
93
102
|
end
|
94
103
|
end
|
95
104
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ShopifyApp
|
4
|
+
class ExtensionVerificationController < ActionController::Base
|
5
|
+
protect_from_forgery with: :null_session
|
6
|
+
before_action :verify_request
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def verify_request
|
11
|
+
hmac_header = request.headers['HTTP_X_SHOPIFY_HMAC_SHA256']
|
12
|
+
request_body = request.body.read
|
13
|
+
secret = ShopifyApp.configuration.secret
|
14
|
+
digest = OpenSSL::Digest.new('sha256')
|
15
|
+
|
16
|
+
expected_hmac = Base64.strict_encode64(OpenSSL::HMAC.digest(digest, secret, request_body))
|
17
|
+
head(:unauthorized) unless ActiveSupport::SecurityUtils.secure_compare(expected_hmac, hmac_header)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -20,16 +20,20 @@ module ShopifyApp
|
|
20
20
|
|
21
21
|
render(:enable_cookies, layout: false, locals: {
|
22
22
|
does_not_have_storage_access_url: top_level_interaction_path(
|
23
|
-
shop: sanitized_shop_name
|
23
|
+
shop: sanitized_shop_name,
|
24
|
+
return_to: params[:return_to]
|
24
25
|
),
|
25
|
-
has_storage_access_url:
|
26
|
-
|
27
|
-
|
26
|
+
has_storage_access_url: login_url_with_optional_shop(top_level: true),
|
27
|
+
app_target_url: granted_storage_access_path(
|
28
|
+
shop: sanitized_shop_name,
|
29
|
+
return_to: params[:return_to]
|
30
|
+
),
|
31
|
+
current_shopify_domain: current_shopify_domain
|
28
32
|
})
|
29
33
|
end
|
30
34
|
|
31
35
|
def top_level_interaction
|
32
|
-
@url =
|
36
|
+
@url = login_url_with_optional_shop(top_level: true)
|
33
37
|
validate_shop
|
34
38
|
end
|
35
39
|
|
@@ -38,14 +42,15 @@ module ShopifyApp
|
|
38
42
|
|
39
43
|
session['shopify.granted_storage_access'] = true
|
40
44
|
|
41
|
-
|
42
|
-
|
45
|
+
copy_return_to_param_to_session
|
46
|
+
|
47
|
+
redirect_to(return_address_with_params({ shop: @shop }))
|
43
48
|
end
|
44
49
|
|
45
50
|
def destroy
|
46
51
|
reset_session
|
47
52
|
flash[:notice] = I18n.t('.logged_out')
|
48
|
-
redirect_to
|
53
|
+
redirect_to(login_url_with_optional_shop)
|
49
54
|
end
|
50
55
|
|
51
56
|
private
|
@@ -54,6 +59,8 @@ module ShopifyApp
|
|
54
59
|
return render_invalid_shop_error unless sanitized_shop_name.present?
|
55
60
|
session['shopify.omniauth_params'] = { shop: sanitized_shop_name }
|
56
61
|
|
62
|
+
copy_return_to_param_to_session
|
63
|
+
|
57
64
|
if user_agent_can_partition_cookies
|
58
65
|
authenticate_with_partitioning
|
59
66
|
else
|
@@ -77,7 +84,7 @@ module ShopifyApp
|
|
77
84
|
authenticate_in_context
|
78
85
|
else
|
79
86
|
set_top_level_oauth_cookie
|
80
|
-
|
87
|
+
enable_cookie_access
|
81
88
|
end
|
82
89
|
end
|
83
90
|
|
@@ -91,17 +98,28 @@ module ShopifyApp
|
|
91
98
|
true
|
92
99
|
end
|
93
100
|
|
101
|
+
def copy_return_to_param_to_session
|
102
|
+
session[:return_to] = params[:return_to] if params[:return_to]
|
103
|
+
end
|
104
|
+
|
94
105
|
def render_invalid_shop_error
|
95
106
|
flash[:error] = I18n.t('invalid_shop_url')
|
96
107
|
redirect_to return_address
|
97
108
|
end
|
98
109
|
|
110
|
+
def enable_cookie_access
|
111
|
+
fullpage_redirect_to(enable_cookies_path(
|
112
|
+
shop: sanitized_shop_name,
|
113
|
+
return_to: session[:return_to]
|
114
|
+
))
|
115
|
+
end
|
116
|
+
|
99
117
|
def authenticate_in_context
|
100
118
|
redirect_to "#{main_app.root_path}auth/shopify"
|
101
119
|
end
|
102
120
|
|
103
121
|
def authenticate_at_top_level
|
104
|
-
fullpage_redirect_to
|
122
|
+
fullpage_redirect_to(login_url_with_optional_shop(top_level: true))
|
105
123
|
end
|
106
124
|
|
107
125
|
def authenticate_in_context?
|
@@ -119,14 +137,22 @@ module ShopifyApp
|
|
119
137
|
end
|
120
138
|
|
121
139
|
def redirect_to_request_storage_access
|
122
|
-
render
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
140
|
+
render(
|
141
|
+
:request_storage_access,
|
142
|
+
layout: false,
|
143
|
+
locals: {
|
144
|
+
does_not_have_storage_access_url: top_level_interaction_path(
|
145
|
+
shop: sanitized_shop_name,
|
146
|
+
return_to: session[:return_to]
|
147
|
+
),
|
148
|
+
has_storage_access_url: login_url_with_optional_shop(top_level: true),
|
149
|
+
app_target_url: granted_storage_access_path(
|
150
|
+
shop: sanitized_shop_name,
|
151
|
+
return_to: session[:return_to]
|
152
|
+
),
|
153
|
+
current_shopify_domain: current_shopify_domain
|
154
|
+
}
|
155
|
+
)
|
130
156
|
end
|
131
157
|
end
|
132
158
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
<html lang="<%= I18n.locale %>">
|
3
3
|
<head>
|
4
4
|
<meta charset="utf-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
5
6
|
<base target="_top">
|
6
7
|
<title>Redirecting…</title>
|
7
8
|
<%= render 'shopify_app/partials/layout_styles' %>
|
@@ -16,6 +17,7 @@
|
|
16
17
|
<script>
|
17
18
|
window.apiKey = "<%= ShopifyApp.configuration.api_key %>";
|
18
19
|
window.shopOrigin = "https://<%= @shop %>";
|
20
|
+
window.returnTo = "<%= params[:return_to] %>"
|
19
21
|
</script>
|
20
22
|
|
21
23
|
<%= javascript_include_tag('shopify_app/enable_cookies', crossorigin: 'anonymous', integrity: true) %>
|
@@ -30,7 +32,7 @@
|
|
30
32
|
myshopifyUrl: "https://#{current_shopify_domain}",
|
31
33
|
hasStorageAccessUrl: "#{has_storage_access_url}",
|
32
34
|
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
33
|
-
|
35
|
+
appTargetUrl: "#{app_target_url}"
|
34
36
|
},
|
35
37
|
},
|
36
38
|
)
|
@@ -2,6 +2,7 @@
|
|
2
2
|
<html lang="<%= I18n.locale %>">
|
3
3
|
<head>
|
4
4
|
<meta charset="utf-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
5
6
|
<base target="_top">
|
6
7
|
<title>Redirecting…</title>
|
7
8
|
<%= render 'shopify_app/partials/layout_styles' %>
|
@@ -23,7 +24,7 @@
|
|
23
24
|
myshopifyUrl: "https://#{current_shopify_domain}",
|
24
25
|
hasStorageAccessUrl: "#{has_storage_access_url}",
|
25
26
|
doesNotHaveStorageAccessUrl: "#{does_not_have_storage_access_url}",
|
26
|
-
|
27
|
+
appTargetUrl: "#{app_target_url}"
|
27
28
|
},
|
28
29
|
},
|
29
30
|
)
|
@@ -2,6 +2,7 @@
|
|
2
2
|
<html lang="en">
|
3
3
|
<head>
|
4
4
|
<meta charset="utf-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
5
6
|
<base target="_top">
|
6
7
|
<title>Redirecting…</title>
|
7
8
|
<%= javascript_include_tag('shopify_app/redirect', crossorigin: 'anonymous', integrity: true) %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
cs:
|
3
|
+
logged_out: Odhlášení proběhlo úspěšně
|
4
|
+
could_not_log_in: Nelze se přihlásit do obchodu Shopify
|
5
|
+
invalid_shop_url: Neplatná doména obchodu
|
6
|
+
enable_cookies_heading: Zapnout soubory cookie z aplikace %{app}
|
7
|
+
enable_cookies_body: Pokud chcete v Shopify používat aplikaci %{app}, musíte soubory
|
8
|
+
cookie v tomto prohlížeči povolit ručně.
|
9
|
+
enable_cookies_footer: Soubory cookie umožňují, aby vás aplikace ověřila pomocí
|
10
|
+
dočasného uchování preferencí a osobních údajů. Jejich platnost vyprší po 30 dnech.
|
11
|
+
enable_cookies_action: Povolit soubory cookie
|
12
|
+
top_level_interaction_heading: Váš prohlížeč potřebuje ověřit aplikaci %{app}
|
13
|
+
top_level_interaction_body: Váš prohlížeč vyžaduje, aby si od vás aplikace, jako
|
14
|
+
je %{app}, nejdřív vyžádaly přístup k souborům cookie, než je pro vás Shopify
|
15
|
+
otevře.
|
16
|
+
top_level_interaction_action: Pokračovat
|
17
|
+
request_storage_access_heading: Aplikace %{app} potřebuje získat přístup k souborům
|
18
|
+
cookie
|
19
|
+
request_storage_access_body: Tato aplikace vám umožní ověření prostřednictvím dočasného
|
20
|
+
uchování vašich osobních údajů. Pokud chcete používat tuto aplikaci, klikněte
|
21
|
+
na tlačítko Pokračovat a povolte soubory cookie.
|
22
|
+
request_storage_access_footer: Platnost souborů cookie vyprší po 30 dnech.
|
23
|
+
request_storage_access_action: Pokračovat
|
@@ -0,0 +1,20 @@
|
|
1
|
+
---
|
2
|
+
da:
|
3
|
+
logged_out: Logget ud
|
4
|
+
could_not_log_in: Kunne ikke logge ind på Shopify-butik
|
5
|
+
invalid_shop_url: Ugyldig butiksdomæne
|
6
|
+
enable_cookies_heading: Aktivér cookies fra %{app}
|
7
|
+
enable_cookies_body: Du skal manuelt aktivere cookies i denne browser for at kunne
|
8
|
+
bruge %{app} i Shopify.
|
9
|
+
enable_cookies_footer: Cookies lader appen godkende dig ved at gemme dine præferencer
|
10
|
+
og personlige oplysninger midlertidigt. De udløber efter 30 dage.
|
11
|
+
enable_cookies_action: Aktivér cookies
|
12
|
+
top_level_interaction_heading: Din browser skal godkende %{app}
|
13
|
+
top_level_interaction_body: Din browser kræver, at apps som f.eks. %{app} spørger
|
14
|
+
dig om adgang til cookies, inden Shopify kan åbne den for dig.
|
15
|
+
top_level_interaction_action: Fortsæt
|
16
|
+
request_storage_access_heading: "%{app} skal have adgang til cookies"
|
17
|
+
request_storage_access_body: Det lader appen godkende dig ved at gemme dine personlige
|
18
|
+
oplysninger midlertidigt. Klik på forsæt, og tillad cookies for at bruge appen.
|
19
|
+
request_storage_access_footer: Cookies udløber efter 30 dage.
|
20
|
+
request_storage_access_action: Fortsæt
|
data/config/locales/de.yml
CHANGED
@@ -7,16 +7,16 @@ de:
|
|
7
7
|
enable_cookies_body: Sie müssen Cookies in diesem Browser manuell aktivieren, um
|
8
8
|
%{app} in Shopify verwenden zu können.
|
9
9
|
enable_cookies_footer: Mithilfe von Cookies kann die App Sie authentifizieren, indem
|
10
|
-
Ihre Einstellungen und
|
10
|
+
Ihre Einstellungen und personenbezogenen Daten vorübergehend gespeichert werden.
|
11
11
|
Sie laufen nach 30 Tagen ab.
|
12
12
|
enable_cookies_action: Cookies aktivieren
|
13
13
|
top_level_interaction_heading: Ihr Browser muss %{app} authentifizieren
|
14
|
-
top_level_interaction_body: Ihr Browser verlangt, dass Apps
|
15
|
-
|
14
|
+
top_level_interaction_body: Ihr Browser verlangt, dass Apps wie %{app} Sie um Zugriff
|
15
|
+
auf Cookies bitten, bevor Shopify sie für Sie öffnen kann.
|
16
16
|
top_level_interaction_action: Weiter
|
17
17
|
request_storage_access_heading: "%{app} braucht Zugriff auf Cookies"
|
18
18
|
request_storage_access_body: Damit kann die App Sie authentifizieren, indem Ihre
|
19
|
-
Einstellungen und
|
20
|
-
|
19
|
+
Einstellungen und personenbezogenen Daten vorübergehend gespeichert werden. Klicken
|
20
|
+
Sie auf "Weiter" und erlauben Sie den Cookies, die App zu verwenden.
|
21
21
|
request_storage_access_footer: Cookies laufen nach 30 Tagen ab.
|
22
22
|
request_storage_access_action: Weiter
|
data/config/locales/en.yml
CHANGED
@@ -7,7 +7,7 @@ en:
|
|
7
7
|
enable_cookies_footer: 'Cookies let the app authenticate you by temporarily storing your preferences and personal information. They expire after 30 days.'
|
8
8
|
enable_cookies_action: 'Enable cookies'
|
9
9
|
top_level_interaction_heading: "Your browser needs to authenticate %{app}"
|
10
|
-
top_level_interaction_body: "Your browser requires
|
10
|
+
top_level_interaction_body: "Your browser requires apps like %{app} to ask you for access to cookies before Shopify can open it for you."
|
11
11
|
top_level_interaction_action: 'Continue'
|
12
12
|
request_storage_access_heading: "%{app} needs access to cookies"
|
13
13
|
request_storage_access_body: "This lets the app authenticate you by temporarily storing your personal information. Click continue and allow cookies to use the app."
|