@mundogamernetwork/shared-ui 1.8.16 → 1.8.18
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.
- package/components/MediaKit/MgRateCardBundleEditor.vue +2 -2
- package/components/MediaKit/MgRateCardEditor.vue +12 -12
- package/components/PressKit/AssetGallery.vue +2 -2
- package/components/PressKit/Awards.vue +1 -1
- package/components/PressKit/Hero.vue +1 -1
- package/components/PressKit/VideoPlayer.vue +1 -1
- package/components/keys/KeyCampaignDashboardCard.vue +8 -8
- package/components/playtest/PlaytestBrief.vue +1 -1
- package/components/playtest/PlaytestPendingConfirmation.vue +2 -2
- package/components/playtest/concept-poll/RankedChoiceVote.vue +2 -2
- package/components/playtest/moderated/JoinCallPanel.vue +1 -1
- package/components/ui/MgHeaderUIUser.vue +1 -1
- package/components/ui/MgWalletPlanBadge.vue +1 -1
- package/locales/de.json +16 -6
- package/locales/en.json +11 -1
- package/locales/es.json +381 -0
- package/locales/pt-BR.json +16 -6
- package/locales/ro.json +16 -6
- package/package.json +1 -1
- package/pages/icons.vue +41 -6
- package/pages/key-campaigns/[slug].vue +51 -2
- package/pages/key-campaigns/index.vue +48 -11
- package/pages/key-campaigns/key-materials.vue +27 -3
- package/pages/key-campaigns/redeem-key-approved.vue +117 -11
- package/pages/key-campaigns/redeem-key.vue +105 -6
- package/plugins/seo-tag-priority.ts +67 -0
- package/services/campaignService.ts +76 -0
- package/utils/clearSession.ts +22 -0
- package/utils/embargo.ts +125 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<!-- Bundle Form -->
|
|
13
13
|
<div v-if="showForm" class="bundle-form">
|
|
14
14
|
<div class="visibility-note">
|
|
15
|
-
<MGIcon icon="
|
|
15
|
+
<MGIcon icon="about" />
|
|
16
16
|
<span>{{ $t("media_kit.bundles.visibility_note") }}</span>
|
|
17
17
|
</div>
|
|
18
18
|
<div class="form-group">
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
<span class="card-price">{{ formatPrice(card.price_min, card.currency) }}</span>
|
|
48
48
|
</div>
|
|
49
49
|
<div class="check-indicator">
|
|
50
|
-
<MGIcon icon="
|
|
50
|
+
<MGIcon icon="verified" v-if="form.rate_card_ids.includes(card.id)" />
|
|
51
51
|
</div>
|
|
52
52
|
<div v-if="form.rate_card_ids.includes(card.id)" class="card-qty" @click.stop.prevent>
|
|
53
53
|
<span>×</span>
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
</select>
|
|
25
25
|
</div>
|
|
26
26
|
<div class="form-group">
|
|
27
|
-
<label>{{ $t("media_kit.editor.
|
|
28
|
-
<select v-model="form.
|
|
27
|
+
<label>{{ $t("media_kit.editor.ad_channel") }}</label>
|
|
28
|
+
<select v-model="form.ad_channel_id" :class="{ 'input-error': rateCardErrors.ad_channel_id }" @change="delete rateCardErrors.ad_channel_id" required>
|
|
29
29
|
<option value="">{{ $t("media_kit.editor.select") }}</option>
|
|
30
|
-
<option v-for="
|
|
31
|
-
{{
|
|
30
|
+
<option v-for="channel in adChannels" :key="channel.id" :value="channel.id">
|
|
31
|
+
{{ channel.name }}
|
|
32
32
|
</option>
|
|
33
33
|
</select>
|
|
34
34
|
</div>
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
<div v-for="card in rateCards" :key="card.id" class="rate-card-item">
|
|
111
111
|
<div class="card-info">
|
|
112
112
|
<span class="format">{{ card.content_format?.name || card.label }}</span>
|
|
113
|
-
<span class="channel">{{ card.
|
|
113
|
+
<span class="channel">{{ card.ad_channel?.name }}</span>
|
|
114
114
|
<span class="price">{{ formatPrice(card.price_min, card.price_max, card.currency) }}</span>
|
|
115
115
|
</div>
|
|
116
116
|
<div class="card-actions">
|
|
@@ -134,7 +134,7 @@ const { t } = useI18n();
|
|
|
134
134
|
interface RateCard {
|
|
135
135
|
id: number;
|
|
136
136
|
content_format_id: number;
|
|
137
|
-
|
|
137
|
+
ad_channel_id: number;
|
|
138
138
|
label?: string;
|
|
139
139
|
price_min: string;
|
|
140
140
|
price_max?: string;
|
|
@@ -143,7 +143,7 @@ interface RateCard {
|
|
|
143
143
|
description?: string;
|
|
144
144
|
is_active: boolean;
|
|
145
145
|
content_format?: { id: number; name: string };
|
|
146
|
-
|
|
146
|
+
ad_channel?: { id: number; name: string };
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
interface LookupItem {
|
|
@@ -156,7 +156,7 @@ const props = withDefaults(
|
|
|
156
156
|
rateCards: RateCard[];
|
|
157
157
|
influencerProInfoId: number;
|
|
158
158
|
contentFormats: LookupItem[];
|
|
159
|
-
|
|
159
|
+
adChannels: LookupItem[];
|
|
160
160
|
isEnabled?: boolean;
|
|
161
161
|
/** MGN commission % for the current plan (host app resolves this, e.g. from feature_limits). */
|
|
162
162
|
commissionPercent?: number;
|
|
@@ -196,7 +196,7 @@ const saving = ref(false);
|
|
|
196
196
|
|
|
197
197
|
const defaultForm = {
|
|
198
198
|
content_format_id: '',
|
|
199
|
-
|
|
199
|
+
ad_channel_id: '',
|
|
200
200
|
price_min: '',
|
|
201
201
|
price_max: '',
|
|
202
202
|
currency: 'USD',
|
|
@@ -265,7 +265,7 @@ const editCard = (card: RateCard) => {
|
|
|
265
265
|
editing.value = card.id;
|
|
266
266
|
form.value = {
|
|
267
267
|
content_format_id: String(card.content_format_id),
|
|
268
|
-
|
|
268
|
+
ad_channel_id: String(card.ad_channel_id),
|
|
269
269
|
price_min: card.price_min,
|
|
270
270
|
price_max: card.price_max || '',
|
|
271
271
|
currency: card.currency,
|
|
@@ -283,7 +283,7 @@ const saveRateCard = async () => {
|
|
|
283
283
|
// Client-side required field check (HTML required bypassed by @click)
|
|
284
284
|
Object.keys(rateCardErrors).forEach(k => delete rateCardErrors[k]);
|
|
285
285
|
if (!form.value.content_format_id) rateCardErrors.content_format_id = 'required';
|
|
286
|
-
if (!form.value.
|
|
286
|
+
if (!form.value.ad_channel_id) rateCardErrors.ad_channel_id = 'required';
|
|
287
287
|
if (!form.value.price_min && form.value.price_min !== 0) rateCardErrors.price_min = 'required';
|
|
288
288
|
if (Object.keys(rateCardErrors).length) return;
|
|
289
289
|
|
|
@@ -293,7 +293,7 @@ const saveRateCard = async () => {
|
|
|
293
293
|
...form.value,
|
|
294
294
|
influencer_professional_info_id: props.influencerProInfoId,
|
|
295
295
|
content_format_id: Number(form.value.content_format_id),
|
|
296
|
-
|
|
296
|
+
ad_channel_id: Number(form.value.ad_channel_id),
|
|
297
297
|
price_min: Number(form.value.price_min),
|
|
298
298
|
price_max: form.value.price_max ? Number(form.value.price_max) : null,
|
|
299
299
|
delivery_time_days: form.value.delivery_time_days ? Number(form.value.delivery_time_days) : null,
|
|
@@ -80,7 +80,7 @@ function downloadAll() {
|
|
|
80
80
|
<div class="gallery-header">
|
|
81
81
|
<h3 class="section-title">{{ $t('press_kit.assets') }}</h3>
|
|
82
82
|
<button v-if="allowDownload && assets.length" class="btn-download-all" @click="downloadAll">
|
|
83
|
-
<MGIcon icon="
|
|
83
|
+
<MGIcon icon="save" /> {{ $t('press_kit.download_all') }}
|
|
84
84
|
</button>
|
|
85
85
|
</div>
|
|
86
86
|
|
|
@@ -134,7 +134,7 @@ function downloadAll() {
|
|
|
134
134
|
<div class="lb-info">
|
|
135
135
|
<span>{{ imageAssets[lightboxIndex]?.title || imageAssets[lightboxIndex]?.type }}</span>
|
|
136
136
|
<button v-if="allowDownload" class="lb-download" @click="downloadAsset(imageAssets[lightboxIndex])">
|
|
137
|
-
<MGIcon icon="
|
|
137
|
+
<MGIcon icon="save" /> {{ $t('press_kit.download') }}
|
|
138
138
|
</button>
|
|
139
139
|
</div>
|
|
140
140
|
</div>
|
|
@@ -27,7 +27,7 @@ defineProps<Props>();
|
|
|
27
27
|
rel="noopener"
|
|
28
28
|
:class="['award-card', { 'no-link': !award.url }]"
|
|
29
29
|
>
|
|
30
|
-
<MGIcon icon="
|
|
30
|
+
<MGIcon icon="achievements" class="award-icon" />
|
|
31
31
|
<div class="award-info">
|
|
32
32
|
<span class="award-title">{{ award.title }}</span>
|
|
33
33
|
<span v-if="award.event || award.year" class="award-event">
|
|
@@ -27,7 +27,7 @@ const youtubeEmbedUrl = computed(() => {
|
|
|
27
27
|
<h1 v-else class="hero-title">{{ name }}</h1>
|
|
28
28
|
<p v-if="tagline" class="hero-tagline">{{ tagline }}</p>
|
|
29
29
|
<button v-if="trailerUrl" class="btn-trailer" @click="showTrailer = true">
|
|
30
|
-
<MGIcon icon="
|
|
30
|
+
<MGIcon icon="videos" /> {{ $t('press_kit.watch_trailer') }}
|
|
31
31
|
</button>
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
@@ -55,7 +55,7 @@ function formatType(type?: string) {
|
|
|
55
55
|
:class="['video-item', { active: activeVideo?.id === video.id }]"
|
|
56
56
|
@click="activeVideo = video"
|
|
57
57
|
>
|
|
58
|
-
<MGIcon icon="
|
|
58
|
+
<MGIcon icon="videos" />
|
|
59
59
|
<div class="video-meta">
|
|
60
60
|
<span class="video-title">{{ video.title }}</span>
|
|
61
61
|
<span v-if="video.type" class="video-type">{{ formatType(video.type) }}</span>
|
|
@@ -130,38 +130,38 @@ const detailRoute = computed(() =>
|
|
|
130
130
|
|
|
131
131
|
<!-- Exclusive badge -->
|
|
132
132
|
<div v-if="card.is_exclusive && !userCanAccess" class="kc-card__exclusive-badge kc-card__exclusive-lock">
|
|
133
|
-
<
|
|
133
|
+
<MGIcon size="1x" icon="reward" /> {{ $t("keys.card.exclusive_upgrade") }}
|
|
134
134
|
</div>
|
|
135
135
|
<div v-else-if="card.is_exclusive" class="kc-card__exclusive-badge">
|
|
136
|
-
<
|
|
136
|
+
<MGIcon size="1x" icon="reward" /> {{ $t("keys.card.exclusive") }}
|
|
137
137
|
</div>
|
|
138
138
|
|
|
139
139
|
<!-- Tier-locked badge -->
|
|
140
140
|
<div v-else-if="card.is_tier_locked && card.access_tier !== 'free' && !userCanAccess" class="kc-card__exclusive-badge">
|
|
141
|
-
<
|
|
141
|
+
<MGIcon size="1x" icon="reward" /> {{ cardTierLabel(card.access_tier) }}
|
|
142
142
|
</div>
|
|
143
143
|
|
|
144
144
|
<!-- Early access badge -->
|
|
145
145
|
<div v-else-if="(card.early_access_hours ?? 0) > 0 && userCanAccess" class="kc-card__early-access-badge">
|
|
146
|
-
<
|
|
146
|
+
<MGIcon size="1x" icon="clock" /> {{ $t("keys.card.early_access") }}
|
|
147
147
|
</div>
|
|
148
148
|
|
|
149
149
|
<!-- Streamer level badge -->
|
|
150
150
|
<div v-if="card.streamer_type === 2 || card.streamer_type === 3" class="kc-card__exclusive-badge kc-card__level-badge">
|
|
151
|
-
<
|
|
151
|
+
<MGIcon size="1x" icon="verified" />
|
|
152
152
|
{{ card.streamer_type === 2 ? $t("keys.card.level_official") : $t("keys.card.level_affiliate") }}
|
|
153
153
|
</div>
|
|
154
154
|
|
|
155
155
|
<!-- Early-access lock overlay -->
|
|
156
156
|
<div v-if="!userCanAccess && card.available_at_for_user" class="kc-card__lock-overlay">
|
|
157
|
-
<
|
|
157
|
+
<MGIcon size="1x" icon="lock" />
|
|
158
158
|
<span class="lock-label">{{ $t("keys.card.early_access_lock_title") }}</span>
|
|
159
159
|
<span class="lock-countdown">{{ $t("keys.card.early_access_opens_in") }} {{ formatCountdown(card.available_at_for_user) }}</span>
|
|
160
160
|
</div>
|
|
161
161
|
|
|
162
162
|
<!-- Exclusive lock overlay -->
|
|
163
163
|
<div v-else-if="!userCanAccess && card.is_exclusive" class="kc-card__lock-overlay kc-card__lock-overlay--exclusive">
|
|
164
|
-
<
|
|
164
|
+
<MGIcon size="1x" icon="reward" />
|
|
165
165
|
<span class="lock-label">{{ $t("keys.card.exclusive_lock_title") }}</span>
|
|
166
166
|
<span class="lock-cta">{{ $t("keys.card.exclusive_upgrade_cta") }}</span>
|
|
167
167
|
</div>
|
|
@@ -198,7 +198,7 @@ const detailRoute = computed(() =>
|
|
|
198
198
|
</NuxtLink>
|
|
199
199
|
<NuxtLink v-if="!publicMode" :to="`/${locale}/dashboard/pricing`">
|
|
200
200
|
<button class="btn secondary upgrade-btn">
|
|
201
|
-
<
|
|
201
|
+
<MGIcon size="1x" icon="chevron-up" /> {{ $t("keys.card.upgrade_plan") }}
|
|
202
202
|
</button>
|
|
203
203
|
</NuxtLink>
|
|
204
204
|
</template>
|
|
@@ -54,7 +54,7 @@ const categoryLabel = computed(() => {
|
|
|
54
54
|
</div>
|
|
55
55
|
|
|
56
56
|
<div v-if="campaign.eligible === false" class="pt-brief__ineligible">
|
|
57
|
-
<
|
|
57
|
+
<MGIcon size="1x" icon="lock" />
|
|
58
58
|
<span>{{ campaign.ineligibility_reason || $t("playtest.brief.ineligible_generic", "You don't currently qualify for this playtest.") }}</span>
|
|
59
59
|
</div>
|
|
60
60
|
|
|
@@ -23,8 +23,8 @@ const emit = defineEmits<{
|
|
|
23
23
|
<template>
|
|
24
24
|
<div class="pt-pending" :class="{ 'pt-pending--ineligible': ineligible }">
|
|
25
25
|
<div class="pt-pending__icon">
|
|
26
|
-
<
|
|
27
|
-
<
|
|
26
|
+
<MGIcon v-if="ineligible" size="1x" icon="exclamation" />
|
|
27
|
+
<MGIcon v-else size="1x" icon="verified-filled" />
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<h3 class="pt-pending__title">
|
|
@@ -65,7 +65,7 @@ function submit() {
|
|
|
65
65
|
:aria-label="$t('playtest.concept_poll.move_up', 'Move up')"
|
|
66
66
|
@click="moveUp(index)"
|
|
67
67
|
>
|
|
68
|
-
<
|
|
68
|
+
<MGIcon size="1x" icon="chevron-up" />
|
|
69
69
|
</button>
|
|
70
70
|
<button
|
|
71
71
|
type="button"
|
|
@@ -74,7 +74,7 @@ function submit() {
|
|
|
74
74
|
:aria-label="$t('playtest.concept_poll.move_down', 'Move down')"
|
|
75
75
|
@click="moveDown(index)"
|
|
76
76
|
>
|
|
77
|
-
<
|
|
77
|
+
<MGIcon size="1x" icon="chevron-down" />
|
|
78
78
|
</button>
|
|
79
79
|
</span>
|
|
80
80
|
</li>
|
|
@@ -35,7 +35,7 @@ const scheduledAt = computed(() => (props.session?.scheduled_at ? new Date(props
|
|
|
35
35
|
<p class="join-call-panel__time">{{ scheduledAt?.toLocaleString() }}</p>
|
|
36
36
|
|
|
37
37
|
<div v-if="session.tester_confirmed_at" class="join-call-panel__confirmed-badge">
|
|
38
|
-
<
|
|
38
|
+
<MGIcon size="1x" icon="verified-filled" />
|
|
39
39
|
{{ $t("playtest.moderated.you_confirmed", "You've confirmed attendance") }}
|
|
40
40
|
</div>
|
|
41
41
|
|
|
@@ -106,7 +106,7 @@ const handleLogout = async () => {
|
|
|
106
106
|
|
|
107
107
|
<div v-if="features.wallet && user?.coins !== null" class="row info-row">
|
|
108
108
|
<span class="coins">
|
|
109
|
-
<MGIcon icon="coin" />
|
|
109
|
+
<MGIcon icon="coin-v2" />
|
|
110
110
|
{{ Math.floor(user?.coins ?? 0).toLocaleString() }}
|
|
111
111
|
</span>
|
|
112
112
|
</div>
|
|
@@ -43,7 +43,7 @@ const isSubscriber = computed(() => !!(user.value as any)?.subscription?.is_subs
|
|
|
43
43
|
<template>
|
|
44
44
|
<div class="mg-wallet-plan">
|
|
45
45
|
<span v-if="showWallet" class="mg-wallet-plan__coins">
|
|
46
|
-
<MGIcon icon="coin" />
|
|
46
|
+
<MGIcon icon="coin-v2" />
|
|
47
47
|
{{ Math.floor(walletBalance).toLocaleString() }}
|
|
48
48
|
<span class="mg-wallet-plan__currency">MGC</span>
|
|
49
49
|
</span>
|
package/locales/de.json
CHANGED
|
@@ -54,14 +54,15 @@
|
|
|
54
54
|
"exclusive_official": "Official streamers only",
|
|
55
55
|
"level_official": "Official",
|
|
56
56
|
"level_affiliate": "Affiliate",
|
|
57
|
-
"tier_locked": "Exklusiv für den Plan {tier} oder höher"
|
|
57
|
+
"tier_locked": "Exklusiv für den Plan {tier} oder höher",
|
|
58
|
+
"early_access": "Vorabzugang für {tier}-Plan oder höher"
|
|
58
59
|
},
|
|
59
60
|
"status_key": {
|
|
60
61
|
"see_key": "View key",
|
|
61
62
|
"of": "of",
|
|
62
|
-
"title_not_open": "
|
|
63
|
-
"title_span_not_open": "
|
|
64
|
-
"obs_not_open": "
|
|
63
|
+
"title_not_open": "Diese Kampagne",
|
|
64
|
+
"title_span_not_open": "ist noch nicht gestartet",
|
|
65
|
+
"obs_not_open": "Anfragen werden erst ab dem Startdatum der Kampagne angenommen. Schau dann wieder vorbei.",
|
|
65
66
|
"title_0": "Campaign",
|
|
66
67
|
"title_span_0": "ended",
|
|
67
68
|
"obs_0": "The redemption period for the key has expired.",
|
|
@@ -118,8 +119,8 @@
|
|
|
118
119
|
"launch": "Launch",
|
|
119
120
|
"status": "Status",
|
|
120
121
|
"status_active": "Active",
|
|
121
|
-
"status_upcoming": "
|
|
122
|
-
"opens_in": "
|
|
122
|
+
"status_upcoming": "Demnächst",
|
|
123
|
+
"opens_in": "Öffnet in",
|
|
123
124
|
"follow_campaign": "Benachrichtige mich bei Eröffnung",
|
|
124
125
|
"following": "Du wirst benachrichtigt",
|
|
125
126
|
"status_closed": "Closed",
|
|
@@ -187,10 +188,15 @@
|
|
|
187
188
|
"error_user_blocked": "Ihr Zugang zu Key-Anfragen wurde vorübergehend gesperrt, da Material-Einreichungen überfällig sind. Bitte reichen Sie Ihre ausstehenden Materialien ein.",
|
|
188
189
|
"error_not_eligible": "Diese Kampagne ist für Ihren aktuellen Plan nicht verfügbar.",
|
|
189
190
|
"error_pending_limit": "Sie haben das gleichzeitige Anfragenlimit Ihres Plans erreicht. Bitte erfüllen Sie Ihre ausstehenden Verpflichtungen, bevor Sie einen neuen Key anfordern.",
|
|
191
|
+
"error_session_expired": "Deine Sitzung ist abgelaufen.",
|
|
192
|
+
"error_session_expired_help": "Melde dich erneut an, um diese Anfrage abzuschließen. Deine Eingaben wurden noch nicht gesendet.",
|
|
193
|
+
"login_again": "Erneut anmelden",
|
|
190
194
|
"select_option": "Option auswählen",
|
|
191
195
|
"required_data": "Erforderliche Angaben",
|
|
192
196
|
"already_requested": "Sie haben bereits eine Anfrage für diese Kampagne gestellt.",
|
|
193
197
|
"sold_out": "Alle Keys für diese Kampagne wurden bereits eingelöst.",
|
|
198
|
+
"keys_left": "{n} Key übrig | {n} Keys übrig",
|
|
199
|
+
"keys_low_stock": "Letzter Key | Letzte {n}",
|
|
194
200
|
"back_to_campaign": "Zur Kampagne zurückkehren",
|
|
195
201
|
"status_pending": "Anfrage ausstehend — bitte warten Sie auf die Genehmigung",
|
|
196
202
|
"status_approved": "Anfrage genehmigt — Sie können jetzt Ihren Schlüssel abrufen",
|
|
@@ -219,8 +225,12 @@
|
|
|
219
225
|
"embargo_warning_desc": "Du darfst vor dem {date} keine Inhalte über dieses Spiel veröffentlichen oder teilen.",
|
|
220
226
|
"embargo_ack_label": "Ich verstehe, dass dieser Key bis {date} gesperrt ist, und werde vorher nichts veröffentlichen.",
|
|
221
227
|
"embargo_ack_confirm": "Bestätigen & Key anzeigen",
|
|
228
|
+
"embargo_ack_required": "Bestätige, dass du Datum und Uhrzeit der Sperrfrist kennst, bevor du den Key anforderst.",
|
|
222
229
|
"no_embargo_title": "Keine Sperrfrist",
|
|
223
230
|
"no_embargo_desc": "Du kannst sofort Inhalte über dieses Spiel veröffentlichen oder teilen.",
|
|
231
|
+
"embargo_lifted_title": "Sperrfrist aufgehoben",
|
|
232
|
+
"embargo_countdown": "Wird {relative} aufgehoben.",
|
|
233
|
+
"embargo_reminder_short": "Veröffentliche nichts über dieses Spiel vor dem {date}.",
|
|
224
234
|
"pr_contact_label": "PR-Kontakt"
|
|
225
235
|
},
|
|
226
236
|
"materials": {
|
package/locales/en.json
CHANGED
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
"exclusive_official": "Official streamers only",
|
|
55
55
|
"level_official": "Official",
|
|
56
56
|
"level_affiliate": "Affiliate",
|
|
57
|
-
"tier_locked": "Exclusive to {tier} plan or higher"
|
|
57
|
+
"tier_locked": "Exclusive to {tier} plan or higher",
|
|
58
|
+
"early_access": "Early access for {tier} plan or higher"
|
|
58
59
|
},
|
|
59
60
|
"status_key": {
|
|
60
61
|
"see_key": "View key",
|
|
@@ -187,10 +188,15 @@
|
|
|
187
188
|
"error_user_blocked": "Your key request access has been temporarily blocked due to overdue material submissions. Please submit your pending materials to restore access.",
|
|
188
189
|
"error_not_eligible": "This campaign is not available for your current plan.",
|
|
189
190
|
"error_pending_limit": "You have reached the simultaneous request limit for your plan. Please fulfill your pending obligations before requesting a new key.",
|
|
191
|
+
"error_session_expired": "Your session has expired.",
|
|
192
|
+
"error_session_expired_help": "Sign in again to finish this request. Nothing you typed was sent yet.",
|
|
193
|
+
"login_again": "Sign in again",
|
|
190
194
|
"select_option": "Select an option",
|
|
191
195
|
"required_data": "Required data",
|
|
192
196
|
"already_requested": "You have already submitted a request for this campaign.",
|
|
193
197
|
"sold_out": "All keys for this campaign have already been claimed.",
|
|
198
|
+
"keys_left": "{n} key left | {n} keys left",
|
|
199
|
+
"keys_low_stock": "Last key | Last {n}",
|
|
194
200
|
"back_to_campaign": "Back to campaign",
|
|
195
201
|
"status_pending": "Request pending — waiting for approval",
|
|
196
202
|
"status_approved": "Request approved — you can now retrieve your key",
|
|
@@ -219,8 +225,12 @@
|
|
|
219
225
|
"embargo_warning_desc": "You must not publish or share any content about this game before {date}.",
|
|
220
226
|
"embargo_ack_label": "I understand this key is embargoed until {date} and will not publish before then.",
|
|
221
227
|
"embargo_ack_confirm": "Confirm & reveal key",
|
|
228
|
+
"embargo_ack_required": "Confirm you are aware of the embargo date and time before requesting the key.",
|
|
222
229
|
"no_embargo_title": "No embargo",
|
|
223
230
|
"no_embargo_desc": "You're free to publish or share content about this game right away.",
|
|
231
|
+
"embargo_lifted_title": "Embargo lifted",
|
|
232
|
+
"embargo_countdown": "Lifts {relative}.",
|
|
233
|
+
"embargo_reminder_short": "Do not publish anything about this game before {date}.",
|
|
224
234
|
"pr_contact_label": "PR contact"
|
|
225
235
|
},
|
|
226
236
|
"materials": {
|