shopify_app 9.0.0 → 12.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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."
|