@analitikisler/ai-tag-debugger 0.15.0 → 0.17.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.
- package/CHANGELOG.md +29 -0
- package/README.md +122 -21
- package/README.tr.md +121 -22
- package/package.json +8 -1
- package/src/agent.js +11 -4
- package/src/audit.js +112 -36
- package/src/baseline.js +90 -0
- package/src/browser.js +36 -1
- package/src/changes.js +9 -3
- package/src/checks.js +63 -4
- package/src/ci-output.js +104 -0
- package/src/cli.js +84 -3
- package/src/consent.js +4 -2
- package/src/doctor.js +68 -0
- package/src/gtm.js +298 -0
- package/src/help.js +33 -3
- package/src/history.js +302 -0
- package/src/i18n.js +822 -48
- package/src/mcp.js +22 -4
- package/src/metrics.js +476 -0
- package/src/notify.js +21 -7
- package/src/plan.js +6 -1
- package/src/pool.js +34 -0
- package/src/providers.js +90 -12
- package/src/replay.js +28 -1
- package/src/report.js +1426 -649
- package/src/schema.js +190 -0
- package/src/sheet.js +11 -5
- package/src/whitelabel.js +105 -0
package/src/i18n.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
// Report language strings. Add a language by copying the "en" block.
|
|
2
|
+
//
|
|
3
|
+
// Each language has the same shape: severity labels, ui chrome, detail (the symptom sentence each
|
|
4
|
+
// check emits), gtm (why a tag did or did not fire), and the meaning layer: consequence and fix
|
|
5
|
+
// per check name, the check's category (money, legal, hygiene) and the verdict strings.
|
|
6
|
+
// Event, parameter, tag and trigger names are never translated or re-cased; quoted names are
|
|
7
|
+
// rendered as code by the report.
|
|
8
|
+
|
|
9
|
+
import { PROVIDERS } from "./parsers.js";
|
|
2
10
|
|
|
3
11
|
const q = (s) => `"${s}"`;
|
|
12
|
+
/** The platform's label (GA4, Meta) for the key the checks pass (ga4, meta); anything else passes through. */
|
|
13
|
+
const label = (p) => PROVIDERS[p] ?? String(p);
|
|
14
|
+
// Parameters in one fixed order, so the same bug reads the same on every card: value, currency,
|
|
15
|
+
// transaction_id, items, then alphabetical. The plan's order would make two cards look like two problems.
|
|
16
|
+
const PARAM_ORDER = ["value", "currency", "transaction_id", "items"];
|
|
17
|
+
const rank = (p) => (PARAM_ORDER.includes(p) ? PARAM_ORDER.indexOf(p) : PARAM_ORDER.length);
|
|
18
|
+
const sortParams = (params) => [...params].sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
|
|
19
|
+
/** "a, b and c" with the language's "and". */
|
|
20
|
+
const andList = (items, and) => (items.length <= 1 ? items.join("") : `${items.slice(0, -1).join(", ")} ${and} ${items[items.length - 1]}`);
|
|
21
|
+
/** The counts of a verdict: the object verdict() in metrics.js returns, or a bare counts object. */
|
|
22
|
+
const countsOf = (v) => v?.counts ?? v ?? {};
|
|
23
|
+
const journeysOf = (v) => v?.journeys ?? {};
|
|
4
24
|
|
|
5
25
|
const en = {
|
|
6
26
|
name: "English",
|
|
@@ -25,10 +45,19 @@ const en = {
|
|
|
25
45
|
where: "Where",
|
|
26
46
|
causeAndFix: "Cause and fix",
|
|
27
47
|
likelyCause: "Likely cause",
|
|
48
|
+
gtmTags: "In your GTM container",
|
|
49
|
+
gtmNoTag: "No tag in the container export sends this event.",
|
|
50
|
+
gtmFiresOn: "Fires on",
|
|
51
|
+
gtmNoTrigger: "No firing trigger",
|
|
52
|
+
gtmBlockedBy: "Blocked by",
|
|
53
|
+
gtmPaused: "Paused",
|
|
54
|
+
gtmConsent: (types) => `Needs consent: ${types}`,
|
|
55
|
+
gtmWhy: (tag, verdict, why) => `Tag ${q(tag)}: ${verdict} — ${why}`,
|
|
56
|
+
gtmVerdict: { true: "should have fired", false: "did not fire", unknown: "could not be evaluated" },
|
|
28
57
|
fix: "Fix",
|
|
29
58
|
captured: "Captured",
|
|
30
59
|
noProblems: "No problems found.",
|
|
31
|
-
noExplanation: "
|
|
60
|
+
noExplanation: "No model explanation in this run. The consequence, owner and fix below do not need one.",
|
|
32
61
|
matchingPlan: "Matching the plan",
|
|
33
62
|
timeline: "Journeys and event timeline",
|
|
34
63
|
timelineLead: "Every step of every journey. Events are grouped by platform; open one to see its parameters, the dataLayer push behind it and the network request that carried it. Steps with problems are open.",
|
|
@@ -45,11 +74,14 @@ const en = {
|
|
|
45
74
|
method: "Method",
|
|
46
75
|
status: "Status",
|
|
47
76
|
vendor: "Vendor",
|
|
48
|
-
blockedNote: "answered locally,
|
|
77
|
+
blockedNote: "blocked by this audit: answered locally, never reached the vendor",
|
|
78
|
+
blockedNoteVendor: (vendor) => `blocked by this audit: answered locally, never reached ${vendor}`,
|
|
49
79
|
clickedThrough: "clicked through an overlapping element",
|
|
50
80
|
generatedBy: "Generated by AI Tag Debugger",
|
|
51
81
|
nothing: "None",
|
|
52
82
|
counts: (c) => `${c.broken} broken · ${c.risk} risk · ${c.warning} warning · ${c.info} info · ${c.ok} ok`,
|
|
83
|
+
accepted: "Accepted",
|
|
84
|
+
acceptedLine: (n) => (n === 1 ? "1 accepted finding from the baseline is not counted" : `${n} accepted findings from the baseline are not counted`),
|
|
53
85
|
whereStep: (journey, viewport, step) => `${journey} (${viewport})${step ? `, step "${step}"` : ""}`,
|
|
54
86
|
allGood: "All planned events fired correctly on every journey tested.",
|
|
55
87
|
tabEvents: "Events",
|
|
@@ -101,6 +133,7 @@ const en = {
|
|
|
101
133
|
changesLead: (id, mode) => `Compared with run ${id}, by ${mode === "plan" ? "plan coverage" : "health findings"}`,
|
|
102
134
|
changesLine: (ch) => ch.fixed.length || ch.new.length ? [ch.fixed.length ? `${ch.fixed.length} ${ch.mode === "plan" ? (ch.fixed.length === 1 ? "event" : "events") : (ch.fixed.length === 1 ? "problem" : "problems")} fixed` : "", ch.new.length ? `${ch.new.length} new ${ch.new.length === 1 ? "problem" : "problems"}` : ""].filter(Boolean).join(", ") : "No changes since the last run",
|
|
103
135
|
changeFixed: "Fixed",
|
|
136
|
+
changeWas: (what) => `was: ${what}`,
|
|
104
137
|
changeNew: "New",
|
|
105
138
|
noSavedRun: "No saved run for this site yet. Run `aitd run` first; each run is compared with the one before it.",
|
|
106
139
|
routeChanged: (list) => `The AI took a different route through the site than in the last run: ${list}`,
|
|
@@ -110,7 +143,7 @@ const en = {
|
|
|
110
143
|
bucket: { implemented: "Implemented", missing: "Missing", missing_params: "Missing params", wrong_values: "Wrong values", unplanned: "Unplanned", not_checked: "Not checked" },
|
|
111
144
|
bucketCol: "Result",
|
|
112
145
|
summaryLead: "AI summary, most important first",
|
|
113
|
-
noSummary: "
|
|
146
|
+
noSummary: "No model summary in this run. The verdict and the findings below stand on their own.",
|
|
114
147
|
seeAllFindings: "See all findings →",
|
|
115
148
|
journey: "Journey",
|
|
116
149
|
stepsCol: "Steps",
|
|
@@ -129,12 +162,14 @@ const en = {
|
|
|
129
162
|
runViewports: "Viewports",
|
|
130
163
|
runLanguage: "Language",
|
|
131
164
|
runVersion: "Version",
|
|
165
|
+
junitJourney: "journey completed",
|
|
166
|
+
junitSite: "site",
|
|
132
167
|
consentDefault: "Default",
|
|
133
168
|
consentUpdate: "Update",
|
|
134
169
|
consentLead: "Consent Mode commands the site sent, in order.",
|
|
135
170
|
consentNone: "The site sent no Consent Mode commands on this journey.",
|
|
136
171
|
scenarios: "Consent scenarios",
|
|
137
|
-
scenariosLead: (cmp) => `The
|
|
172
|
+
scenariosLead: (cmp) => `The home page was opened once per consent choice, answered through ${cmp === "banner" ? "the banner's buttons" : cmp}. Each cell is how many hits the tag sent after that choice. A red number is data the visitor had refused.`,
|
|
138
173
|
scenarioCols: { before: "No choice yet", accept: "Accept all", reject: "Reject all", analytics: "Analytics only" },
|
|
139
174
|
scenarioNotRun: "Not supported here",
|
|
140
175
|
scenarioTag: "Tag",
|
|
@@ -170,47 +205,414 @@ const en = {
|
|
|
170
205
|
by: "by",
|
|
171
206
|
credit: (atd) => `This report was made with the open source ${atd}.`,
|
|
172
207
|
timelineLeadV2: "Every step has three tabs: the events it sent, its dataLayer pushes and its network requests. Events and requests can be filtered by source. Steps with problems are open.",
|
|
208
|
+
// The run history (src/history.js): the trend lines after a run, in the alert and in `aitd history`.
|
|
209
|
+
history: {
|
|
210
|
+
noRuns: "No saved run for this site yet. Run `aitd run` first; the trend starts with the second run.",
|
|
211
|
+
oneRun: (id) => `One saved run (${id}); the trend starts with the next one.`,
|
|
212
|
+
direction: { improving: "improving", worsening: "worsening", flat: "flat" },
|
|
213
|
+
headline: (runs, first, last, dir, now, was, ago) => `Trend over ${runs} runs (${first} → ${last}): ${dir}. Now ${now}; ${ago} runs ago ${was}.`,
|
|
214
|
+
headlineShort: (runs, first, last, dir, now) => `Trend over ${runs} runs (${first} → ${last}): ${dir}. Now ${now}.`,
|
|
215
|
+
counts: (c) => `${c.broken} broken · ${c.risk} risk · ${c.warning} warning`,
|
|
216
|
+
openLongest: (items) => `Open longest: ${items.join("; ")}.`,
|
|
217
|
+
since: (label, day, runs) => `${label} since ${day} (${runs} ${runs === 1 ? "run" : "runs"})`,
|
|
218
|
+
flapping: (items) => `Flapping (seen, gone, back again): ${items.join("; ")}.`,
|
|
219
|
+
seenIn: (label, seen, runs) => `${label} in ${seen} of ${runs} runs`,
|
|
220
|
+
places: (n) => ` in ${n} places`,
|
|
221
|
+
unstable: (items) => `Journeys that do not finish every time: ${items.join("; ")}.`,
|
|
222
|
+
stillOpen: (runs, items) => `Still open after ${runs} runs: ${items.join("; ")}.`,
|
|
223
|
+
sparkline: (spark, dir, runs, first, last) => `${spark} ${dir} over ${runs} runs (${first} → ${last})`,
|
|
224
|
+
fixedWas: "was",
|
|
225
|
+
},
|
|
226
|
+
// The Markdown report (docs/design/md-report-spec.md): a verdict first, evidence second.
|
|
227
|
+
md: {
|
|
228
|
+
title: (site, headline) => `${site}: ${headline}`,
|
|
229
|
+
meta: (at, journeys, platforms, version) => `Generated ${at} · ${journeys} ${journeys === 1 ? "journey" : "journeys"} · ${platforms} · ai-tag-debugger ${version}`,
|
|
230
|
+
platformsSeen: (n, list) => (n ? `${n} ${n === 1 ? "platform" : "platforms"} seen (${list})` : "no platform seen"),
|
|
231
|
+
htmlReport: "HTML report",
|
|
232
|
+
noParams: "the hit carried no parameters",
|
|
233
|
+
score: (score) => `data quality score ${score}/100`,
|
|
234
|
+
// Fallback headlines per verdict key, used when the `verdict.headline` strings are not there.
|
|
235
|
+
headline: {
|
|
236
|
+
fail_broken: (what, scope) => `${what} is broken${scope}`,
|
|
237
|
+
fail_incomplete: (journey) => `the ${journey} journey did not finish, so its events could not be checked`,
|
|
238
|
+
attention_risk: (what, scope) => `${what} carries a consent or data risk${scope}`,
|
|
239
|
+
attention_warning: (what, scope) => `${what} needs attention${scope}`,
|
|
240
|
+
attention_no_hits: () => "no tracking hits were captured",
|
|
241
|
+
attention_nothing_tested: () => "nothing was tested",
|
|
242
|
+
pass: (events, journeys) => (events ? `all ${events} planned events fired correctly on ${journeys} ${journeys === 1 ? "journey" : "journeys"}` : `all checks passed on ${journeys} ${journeys === 1 ? "journey" : "journeys"}`),
|
|
243
|
+
},
|
|
244
|
+
tracking: (event) => `${event} tracking`,
|
|
245
|
+
setup: (check) => `the ${check} check`,
|
|
246
|
+
onViewport: (viewport) => ` on ${viewport}`,
|
|
247
|
+
onJourney: (journey) => ` on ${journey}`,
|
|
248
|
+
everywhere: " on every journey",
|
|
249
|
+
aiSummary: "AI summary",
|
|
250
|
+
stillOpen: "Still open",
|
|
251
|
+
priorities: "Priorities",
|
|
252
|
+
nothingToDo: (owner) => `${owner}: nothing to do.`,
|
|
253
|
+
allJourneys: (n) => `all ${n} journeys`,
|
|
254
|
+
step: (n) => `step ${n}`,
|
|
255
|
+
more: (n) => `+${n} more`,
|
|
256
|
+
also: "Also",
|
|
257
|
+
owner: "Owner",
|
|
258
|
+
link: "Link",
|
|
259
|
+
alsoFineOn: "Also fine on",
|
|
260
|
+
consent: "Consent",
|
|
261
|
+
consentMode: (present, total, onTime, v2) => `Consent Mode default set on ${present} of ${total} ${total === 1 ? "journey" : "journeys"}${onTime === false ? ", after the first Google hit" : onTime ? ", before the first Google hit" : ""}; v2 signals ${v2 ? "present" : "missing"}.`,
|
|
262
|
+
consentModeNone: "No Consent Mode default command was seen on any journey.",
|
|
263
|
+
consentNotChecked: "Consent was not checked in this run.",
|
|
264
|
+
cell: { ok: "✓", bad: "✗", cookieless: "cookieless", beforeConsent: "before consent", shouldNotSend: "should not send", adDenied: "ad storage denied", notRun: "–" },
|
|
265
|
+
consentLegend: "✓ allowed · ✗ should not have been sent · \"cookieless\" = Consent Mode ping with storage denied · – = that choice was not run",
|
|
266
|
+
whatPassed: "What passed",
|
|
267
|
+
coverage: (implemented, total, percent) => `Plan coverage: ${implemented} of ${total} planned events implemented${percent === null ? "" : ` (${percent}%)`}`,
|
|
268
|
+
purchaseOk: (platform, place, value, currency, id) => `${platform} purchase value and currency: ${place} (${value} ${currency}${id ? `, ${id}` : ""})`,
|
|
269
|
+
parityOk: (platforms, place) => `Purchase cross-platform match: ${platforms} agree on ${place}`,
|
|
270
|
+
noPii: "Personal data: no plain-text email or user data in any hit.",
|
|
271
|
+
viewport: "Viewport",
|
|
272
|
+
hits: "Hits",
|
|
273
|
+
yes: "yes",
|
|
274
|
+
no: "no",
|
|
275
|
+
flaggedSteps: "Flagged steps",
|
|
276
|
+
timelineNote: "Every hit, dataLayer push and request of every step is in timeline.csv.",
|
|
277
|
+
moreIn: (n, file) => `+${n} more in ${file}`,
|
|
278
|
+
notChecked: "Not checked",
|
|
279
|
+
noPlan: "Planned events: no measurement plan given (`plan` in the config).",
|
|
280
|
+
noGtm: "GTM tag names: no container export given (`gtm_container` in the config).",
|
|
281
|
+
noAnalyticsOnly: "Analytics-only consent: the banner has no such choice.",
|
|
282
|
+
noScenarios: "Consent scenarios: not run (no banner the tool can answer, or a replay).",
|
|
283
|
+
platformsSilent: (list, n) => `${list} ${n === 1 ? "was" : "were"} in scope but the site sent nothing ${n === 1 ? "to it" : "to them"}.`,
|
|
284
|
+
trend: "Trend",
|
|
285
|
+
},
|
|
286
|
+
// Lines the CLI prints after a run and in `aitd history`, in the report's language.
|
|
287
|
+
cli: {
|
|
288
|
+
verdict: (status, headline, score) => `Verdict: ${status} · ${headline}${score === null ? "" : ` · score ${score}/100`}`,
|
|
289
|
+
runCol: "Run",
|
|
290
|
+
scoreCol: "Score",
|
|
291
|
+
completeCol: "Complete",
|
|
292
|
+
historyNone: "No saved run for this site yet.",
|
|
293
|
+
},
|
|
173
294
|
},
|
|
174
295
|
detail: {
|
|
175
296
|
journeyIncomplete: (note) => `The journey did not reach its goal${note ? `: ${note}` : "."} Events after that point could not be checked.`,
|
|
176
|
-
missingEvent: (platform, name) =>
|
|
177
|
-
missingEventEarly: (name) => `${q(name)} was not seen, but the journey stopped early, so
|
|
178
|
-
missingParams: (name, params) => `${q(name)} was sent without ${params.map(q)
|
|
179
|
-
duplicate: (name, n) => `${q(name)} was sent ${n} times by one action
|
|
180
|
-
purchaseValueZero: (platform, name, v) => `${platform} ${q(name)} was sent with value ${q(v)}. A purchase worth 0 or less adds no revenue,
|
|
181
|
-
purchaseValueNaN: (platform, name, v) => `${platform} ${q(name)} was sent with value ${q(v)}, which is not a number, so the revenue is lost. Send a plain number such as 49.90, with no currency sign or thousands separator.`,
|
|
182
|
-
purchaseCurrency: (platform, name, c) => `${platform} ${q(name)} was sent with currency ${q(c)}, which is not a 3-letter ISO 4217 code in capitals (such as USD, EUR or TRY). Platforms
|
|
183
|
-
purchaseItemsEmpty: (platform, name) => `${platform} ${q(name)} was sent with no items, so product and item reports get nothing for this order.`,
|
|
184
|
-
purchaseMismatch: (id, diffs) =>
|
|
185
|
-
serverSide: (platform, server, browser, unseen = []) => `${platform}: ${server.map(q).join(", ")} ${server.length === 1 ? "was" : "were"} sent to a server container on the site's own domain (server-side tagging)${browser.length ? `; ${browser.map(q).join(", ")} went directly from the browser` : ""}.${unseen.length ? ` Server-side copies of ${unseen.join(" and ")} events never pass through the browser, so they can't be seen here.` : ""}`,
|
|
186
|
-
|
|
297
|
+
missingEvent: (platform, name) => `${label(platform)} ${q(name)} was not sent on this journey, although the journey reached its goal. ${label(platform)} recorded nothing for it.`,
|
|
298
|
+
missingEventEarly: (name) => `${q(name)} was not seen, but the journey stopped early, so it is unverified rather than missing.`,
|
|
299
|
+
missingParams: (name, params) => `${q(name)} was sent without ${andList(sortParams(params).map(q), "and")}.`,
|
|
300
|
+
duplicate: (name, n) => `${q(name)} was sent ${n} times by one action. Every real one is counted ${n} times.`,
|
|
301
|
+
purchaseValueZero: (platform, name, v) => `${label(platform)} ${q(name)} was sent with value ${q(v)}. A purchase worth 0 or less adds no revenue, so ad platforms cannot optimise bids on it.`,
|
|
302
|
+
purchaseValueNaN: (platform, name, v) => `${label(platform)} ${q(name)} was sent with value ${q(v)}, which is not a number, so the revenue is lost. Send a plain number such as 49.90, with no currency sign or thousands separator.`,
|
|
303
|
+
purchaseCurrency: (platform, name, c) => `${label(platform)} ${q(name)} was sent with currency ${q(c)}, which is not a 3-letter ISO 4217 code in capitals (such as USD, EUR or TRY). Platforms drop the revenue or convert it at the wrong rate.`,
|
|
304
|
+
purchaseItemsEmpty: (platform, name) => `${label(platform)} ${q(name)} was sent with no items, so product and item reports get nothing for this order.`,
|
|
305
|
+
purchaseMismatch: (id, diffs) => `${id ? `Order ${q(id)}` : "The purchase"} was reported differently: ${diffs.map(([f, g, m]) => `${f} ${q(g)} in GA4 and ${q(m)} in Meta`).join("; ")}. One tag reads the wrong number, so Google and Meta bid on different revenue.`,
|
|
306
|
+
serverSide: (platform, server, browser, unseen = []) => `${label(platform)}: ${server.map(q).join(", ")} ${server.length === 1 ? "was" : "were"} sent to a server container on the site's own domain (server-side tagging)${browser.length ? `; ${browser.map(q).join(", ")} went directly from the browser` : ""}.${unseen.length ? ` Server-side copies of ${unseen.join(" and ")} events never pass through the browser, so they can't be seen here.` : ""}`,
|
|
307
|
+
serverEndpoint: (hosts) => `A server container answers on ${hosts.map(q).join(", ")} (server-side GTM or a similar setup). Events it forwards to ad platforms never pass through the browser, so they can't be seen here.`,
|
|
308
|
+
eventIdReused: (platform, id, names, n) => `${label(platform)} event ID ${q(id)} was used for ${n} different events (${names.map(q).join(", ")}). ${label(platform)} keeps the first and drops the rest as duplicates. Give each event its own ID.`,
|
|
309
|
+
eventIdNotForwarded: (name, ga4Name) => `Meta ${q(name)} has an event ID, but the GA4 ${q(ga4Name)} hit sent to the server container has no event_id. If the server container builds the Conversions API event from that hit, Meta can't match it with the pixel event and counts it twice. Send the same ID as an event_id parameter on the GA4 event.`,
|
|
310
|
+
eventIdMismatch: (name, metaId, ga4Name, ga4Id) => `Meta ${q(name)} has event ID ${q(metaId)}, but the GA4 ${q(ga4Name)} hit sent to the server container carries event_id ${q(ga4Id)}. A Conversions API event built from that hit won't match the pixel event, so Meta counts it twice. Use one ID for both.`,
|
|
311
|
+
dedupIdMissing: (platform, name) => `${label(platform)} ${q(name)} was sent from the browser without an event ID, while a server-side setup was seen on this site. If the server also sends this event, ${label(platform)} cannot match the two and counts it twice.`,
|
|
187
312
|
campaignLost: (names, finalUrl) => `The landing address carried ${names.join(", ")}, but the page ended up on ${finalUrl} without ${names.length === 1 ? "it" : "them"}. A redirect dropped ${names.length === 1 ? "the parameter" : "the parameters"}, so ad clicks lose their attribution.`,
|
|
188
|
-
campaignMissingInHits: (platform, name, names) => `${platform} ${q(name)} on the landing page reports a page address without ${names.join(", ")}, though the page still had ${names.length === 1 ? "it" : "them"}. The visit can be credited to direct traffic instead of the campaign.`,
|
|
313
|
+
campaignMissingInHits: (platform, name, names) => `${label(platform)} ${q(name)} on the landing page reports a page address without ${names.join(", ")}, though the page still had ${names.length === 1 ? "it" : "them"}. The visit can be credited to direct traffic instead of the campaign.`,
|
|
189
314
|
campaignOk: (names) => `${names.join(", ")} survived the landing page's redirects and reached the hits.`,
|
|
190
315
|
consentDefaultMissing: () => "No Google Consent Mode default command (gtag('consent', 'default', ...)) was found in the dataLayer.",
|
|
191
316
|
consentDefaultLate: () => "The Consent Mode default was set after the first tracking hit was sent.",
|
|
192
|
-
beforeConsentNever: (platform, name) => `${platform} ${q(name)}
|
|
193
|
-
beforeConsent: (platform, name) => `${platform} ${q(name)}
|
|
317
|
+
beforeConsentNever: (platform, name) => `${label(platform)} ${q(name)} was sent although the visitor never made a consent choice on this journey. ${label(platform)} receives data from visitors who have not agreed.`,
|
|
318
|
+
beforeConsent: (platform, name) => `${label(platform)} ${q(name)} was sent before the visitor made a consent choice. ${label(platform)} receives data from visitors who have not agreed.`,
|
|
194
319
|
consentV2Missing: (keys) => `The Consent Mode default does not set ${keys.map(q).join(" and ")}. Consent Mode v2 needs them for Google ads in the EEA and UK; without them ad personalization and conversion measurement can stop.`,
|
|
195
|
-
consentV2Update: (keys) => `After the visitor accepted, the Consent Mode update did not grant ${keys.map(q).join(" and ")}.
|
|
320
|
+
consentV2Update: (keys) => `After the visitor accepted, the Consent Mode update did not grant ${keys.map(q).join(" and ")}. They stayed denied, so Google Ads conversions and remarketing stay off even for consenting visitors.`,
|
|
196
321
|
rejectIgnored: () => "A Consent Mode update granted consent after the visitor rejected cookies, so the reject button does not stick.",
|
|
197
322
|
rejectButtonFailed: () => "The cookie banner was still showing after the reject button was clicked.",
|
|
198
|
-
afterReject: (platform, name) => `${platform} ${q(name)} was still sent after the visitor rejected cookies.`,
|
|
323
|
+
afterReject: (platform, name) => `${label(platform)} ${q(name)} was still sent after the visitor rejected cookies.`,
|
|
199
324
|
cookiesBeforeConsent: (names) => `Tracking cookies were set before the visitor accepted: ${names.join(", ")}.`,
|
|
200
325
|
cookiesNeverConsent: (names) => `Tracking cookies were set although consent was never given in this journey: ${names.join(", ")}.`,
|
|
201
326
|
cookiesAfterReject: (names) => `Tracking cookies were set after the visitor rejected cookies: ${names.join(", ")}.`,
|
|
202
|
-
pii: (platform, name) => `An email address was sent in plain text with ${q(name)} to ${platform}.`,
|
|
327
|
+
pii: (platform, name) => `An email address was sent in plain text with ${q(name)} to ${label(platform)}.`,
|
|
203
328
|
unplanned: (list) => `Events sent that are not in the measurement plan: ${list.join(", ")}.`,
|
|
204
|
-
piiUnhashed: (platform, name, fields) => `${q(name)} sent user data to ${platform} without hashing it (${fields.join(", ")}). Ad platforms expect these values SHA-256 hashed.`,
|
|
329
|
+
piiUnhashed: (platform, name, fields) => `${q(name)} sent user data to ${label(platform)} without hashing it (${fields.join(", ")}). Ad platforms expect these values SHA-256 hashed.`,
|
|
205
330
|
piiDataLayer: (fields) => `The dataLayer holds user data that isn't hashed (${fields.join(", ")}). This is a valid setup for Google enhanced conversions, but every other tag and script on the page can read it too. Check that only the tags that should use it do.`,
|
|
206
|
-
plannedOutOfScope: (list) => `${list.length} planned ${list.length === 1 ? "event was" : "events were"} not checked because
|
|
331
|
+
plannedOutOfScope: (list) => `${list.length} planned ${list.length === 1 ? "event was" : "events were"} not checked because ${list.length === 1 ? "its platform was" : "their platforms were"} not selected for this run: ${list.join(", ")}.`,
|
|
207
332
|
matches: (list) => `${list.length} planned events matched the plan: ${list.join(", ")}.`,
|
|
208
333
|
},
|
|
334
|
+
// Why a GTM tag did or did not fire, judged from the captured dataLayer.
|
|
335
|
+
gtm: {
|
|
336
|
+
paused: "the tag is paused",
|
|
337
|
+
noTrigger: "the tag has no firing trigger",
|
|
338
|
+
missingTrigger: (trigger) => `trigger ${trigger} is not in the container export`,
|
|
339
|
+
noPush: (event) => `no dataLayer push with event ${q(event)} in this journey`,
|
|
340
|
+
noPageEvent: (trigger, event) => `trigger ${q(trigger)} waits for GTM's ${event} event, which never reached the dataLayer; the container may not have loaded`,
|
|
341
|
+
pageTrigger: (trigger, kind) => `${kind} triggers such as ${q(trigger)} are evaluated by GTM in the page, not from the dataLayer`,
|
|
342
|
+
unknownType: (trigger, type) => `trigger ${q(trigger)} is of type ${type}, which can't be evaluated from the dataLayer`,
|
|
343
|
+
condition: (trigger, field, op, want, had, negate) => `trigger ${q(trigger)} needs ${field} ${negate ? "not " : ""}${op} ${want}, the push had ${had}`,
|
|
344
|
+
conditionUnknown: (trigger, variable) => `trigger ${q(trigger)} checks ${q(variable)}, which can't be read from the dataLayer`,
|
|
345
|
+
conditionType: (trigger, type) => `trigger ${q(trigger)} has a ${type} condition, which can't be evaluated from the dataLayer`,
|
|
346
|
+
ops: { EQUALS: "equal to", CONTAINS: "containing", STARTS_WITH: "starting with", ENDS_WITH: "ending with", MATCH_REGEX: "matching", LESS: "less than", LESS_OR_EQUALS: "at most", GREATER: "greater than", GREATER_OR_EQUALS: "at least" },
|
|
347
|
+
nothing: "no value",
|
|
348
|
+
triggerFired: (trigger, event) => `trigger ${q(trigger)} fired on the ${q(event)} push`,
|
|
349
|
+
blocked: (trigger) => `blocked by exception trigger ${q(trigger)}`,
|
|
350
|
+
consentDenied: (type) => `needs ${type}, which was denied when the event fired`,
|
|
351
|
+
fired: "the trigger fired and consent was granted; the tag itself or its configuration (measurement id, event name) may be wrong",
|
|
352
|
+
},
|
|
353
|
+
// One sentence per check on what the finding costs, for the reader who owns the budget rather than the
|
|
354
|
+
// tag. No placeholders: the finding's detail names the event, parameter and place.
|
|
355
|
+
consequence: {
|
|
356
|
+
missing_event: "The platform never received this event, so this step of the funnel is invisible and a conversion here cannot be counted or bid on.",
|
|
357
|
+
missing_params: "The event is counted but its required details are missing, so revenue, currency or items never reach the reports.",
|
|
358
|
+
duplicate: "One action is counted several times, so counts and conversion totals are inflated and ad platforms bid on sales that did not happen.",
|
|
359
|
+
purchase_value_invalid: "The purchase value is not a usable number, so revenue is recorded as nothing and return-on-ad-spend reports and value bidding are wrong.",
|
|
360
|
+
purchase_currency_invalid: "The currency is not a code platforms recognise, so the revenue is dropped or converted at the wrong rate.",
|
|
361
|
+
purchase_items_empty: "The purchase has no products, so product reports, catalogue feeds and dynamic remarketing see no sales.",
|
|
362
|
+
purchase_mismatch: "Google and Meta received different revenue for the same order, so one of them reports and bids on the wrong number.",
|
|
363
|
+
campaign_lost_redirect: "A redirect strips the campaign parameters from the landing address, so paid clicks arrive as direct traffic and campaigns get no credit.",
|
|
364
|
+
campaign_missing_in_hits: "The landing page kept the campaign parameters but the hit did not report them, so the visit is credited to direct traffic.",
|
|
365
|
+
campaign_params: "Campaign parameters survived the landing redirect and reached the hits, so paid clicks are credited to their campaigns.",
|
|
366
|
+
event_id_reused: "Two different events share one event ID, so the platform keeps the first and silently drops the other: a real event is lost.",
|
|
367
|
+
event_id_mismatch: "The browser and server copies of this event carry different IDs, so Meta cannot pair them and counts the conversion twice.",
|
|
368
|
+
event_id_not_forwarded: "The GA4 hit that feeds the server container has no event ID, so a server copy cannot be paired with the pixel and is counted twice.",
|
|
369
|
+
dedup_id_missing: "The event left the browser with no event ID while the site uses a server container; if the server also sends it, it is counted twice.",
|
|
370
|
+
server_side: "Some events go through the site's own server; this report sees what the browser sent, not what the server forwarded.",
|
|
371
|
+
server_endpoint: "A server container answers on the site's domain; the events it forwards to ad platforms are not visible here.",
|
|
372
|
+
consent_default_missing: "Google tags run with no consent default, so they behave as if every visitor had consented before being asked.",
|
|
373
|
+
consent_default_late: "The first Google hit went out before the consent default was set, so that hit ignored the visitor's choice.",
|
|
374
|
+
consent_v2_missing: "The consent default lacks the v2 signals, so for EEA and UK traffic Google can stop ad personalisation and conversion measurement.",
|
|
375
|
+
consent_v2_update: "After the visitor accepted, the v2 signals stayed denied, so Google Ads conversions and remarketing stay off even for consenting visitors.",
|
|
376
|
+
before_consent: "The event was sent before the visitor made a choice, so the platform receives data from visitors who have not agreed.",
|
|
377
|
+
after_reject: "The event was still sent after the visitor clicked Reject, so tracking continues against an explicit refusal.",
|
|
378
|
+
reject_ignored: "After Reject, a consent update granted everything anyway, so the reject button is cosmetic.",
|
|
379
|
+
reject_button_failed: "The reject button did nothing and the banner stayed open, so the visitor cannot refuse tracking.",
|
|
380
|
+
cookies_before_consent: "Tracking cookies were written before the visitor chose, so cookies are set without consent.",
|
|
381
|
+
cookies_after_reject: "Tracking cookies were written after the visitor refused them, so the refusal is not honoured.",
|
|
382
|
+
pii: "Personal data left the site unprotected: an email address or ad-matching data in plain text is now in the platform's logs.",
|
|
383
|
+
pii_datalayer: "The dataLayer holds unhashed personal data, so every script on the page can read it, not only the tag that needs it.",
|
|
384
|
+
journey_incomplete: "The browser could not finish this journey, so every event after that point, including any conversion, is unverified.",
|
|
385
|
+
unplanned_events: "Events fire that are not in the plan: either the plan is out of date or tags send things nobody asked for.",
|
|
386
|
+
planned_out_of_scope: "Some planned events are on platforms this run did not check, so their status is unknown.",
|
|
387
|
+
matches_plan: "These planned events fired with everything the plan requires.",
|
|
388
|
+
},
|
|
389
|
+
// The generic direction of the fix for each check. The finding's detail and GTM section carry the exact
|
|
390
|
+
// event, parameter, tag and trigger; the AI's fix steps replace this text when a model ran.
|
|
391
|
+
fix: {
|
|
392
|
+
missing_event: "Check that the tag for this event exists, fires on the right trigger and is not blocked by consent or an exception; the GTM section names the tag when a container export was given. Then re-run this journey.",
|
|
393
|
+
missing_params: "Add the missing parameters to the dataLayer push behind this event, on this page and viewport, and make sure the tag reads them. Re-run the journey to confirm.",
|
|
394
|
+
duplicate: "Find the second sender: two pushes, two tags or a trigger that fires twice. Remove one, or add a once-per-event guard on the tag.",
|
|
395
|
+
purchase_value_invalid: "Send the value as a plain number such as 49.90, with no currency sign or thousands separator, and never 0 for a paid order.",
|
|
396
|
+
purchase_currency_invalid: "Send the currency from the order data as a 3-letter ISO 4217 code in capitals, such as USD, EUR or TRY.",
|
|
397
|
+
purchase_items_empty: "Fill the items list in the purchase push from the order's line items (id, name, price, quantity) and map it in the tag.",
|
|
398
|
+
purchase_mismatch: "Make both tags read the same order fields; usually one reads a subtotal or a different currency. Then compare one order in both platforms.",
|
|
399
|
+
campaign_lost_redirect: "Make the redirect keep the query string, or land paid traffic on the final address directly.",
|
|
400
|
+
campaign_missing_in_hits: "Make the tag report the full landing address, parameters included; look for a page URL override or a page_location variable that fills in late.",
|
|
401
|
+
campaign_params: "Nothing to fix. Check the redirects again when the landing pages change.",
|
|
402
|
+
event_id_reused: "Generate a new event ID for every event, not once per page load.",
|
|
403
|
+
event_id_mismatch: "Use one event ID for the pixel event and the server copy: pass the same value to both tags.",
|
|
404
|
+
event_id_not_forwarded: "Add an event_id parameter, carrying the pixel's ID, to the GA4 event the server container turns into the Conversions API event.",
|
|
405
|
+
dedup_id_missing: "Add an event ID to the browser event and send the same ID from the server, so the platform can pair the two.",
|
|
406
|
+
server_side: "Nothing to fix in the browser. Verify the events the server forwards in the platform's own test tools.",
|
|
407
|
+
server_endpoint: "Nothing to fix in the browser. Check what the server container forwards in its own preview mode.",
|
|
408
|
+
consent_default_missing: "Set a Consent Mode default (all denied where the law requires it) before any Google tag loads, usually in the consent banner's script or a GTM template.",
|
|
409
|
+
consent_default_late: "Move the consent default ahead of the Google tag: it must run before gtm.js or gtag.js loads.",
|
|
410
|
+
consent_v2_missing: "Add ad_user_data and ad_personalization to the consent default, next to ad_storage and analytics_storage.",
|
|
411
|
+
consent_v2_update: "Grant ad_user_data and ad_personalization in the consent update the banner sends after the visitor accepts.",
|
|
412
|
+
before_consent: "Give the tag a consent check (its consent settings or an additional consent trigger), or fire it only after the banner's choice.",
|
|
413
|
+
after_reject: "Make the tag respect the refusal: a consent check on the tag, or a blocking trigger when consent is denied.",
|
|
414
|
+
reject_ignored: "Fix the banner's reject handler so it sends an update with every signal denied and never grants afterwards.",
|
|
415
|
+
reject_button_failed: "Fix the banner's reject button so it closes the banner and stores the refusal; look for a script error on the click.",
|
|
416
|
+
cookies_before_consent: "Load the tags that set these cookies only after consent, or run them in cookieless mode until the visitor chooses.",
|
|
417
|
+
cookies_after_reject: "Block the tags that set these cookies when consent is denied, and delete cookies already set when the visitor refuses.",
|
|
418
|
+
pii: "Take the email or user data out of the hit, or hash it with SHA-256 before the tag sends it; check the URLs and form fields the tag reads.",
|
|
419
|
+
pii_datalayer: "Push user data to the dataLayer already hashed, or restrict it to the tag that needs it and clear it afterwards.",
|
|
420
|
+
journey_incomplete: "Read the note for why the browser stopped (a blocked click, a missing element, an error), fix the page or the step, and re-run the journey.",
|
|
421
|
+
unplanned_events: "Add the events to the measurement plan if they are wanted, or remove the tags that send them.",
|
|
422
|
+
planned_out_of_scope: "Include their platforms in the next run's providers so they are checked.",
|
|
423
|
+
matches_plan: "Nothing to fix.",
|
|
424
|
+
},
|
|
425
|
+
// What kind of damage a check reports: money (revenue, ad spend, attribution), legal (consent, personal
|
|
426
|
+
// data) or hygiene (scope and coverage). Identical in every language; the label block translates it.
|
|
427
|
+
category: {
|
|
428
|
+
missing_event: "money",
|
|
429
|
+
missing_params: "money",
|
|
430
|
+
duplicate: "money",
|
|
431
|
+
purchase_value_invalid: "money",
|
|
432
|
+
purchase_currency_invalid: "money",
|
|
433
|
+
purchase_items_empty: "money",
|
|
434
|
+
purchase_mismatch: "money",
|
|
435
|
+
campaign_lost_redirect: "money",
|
|
436
|
+
campaign_missing_in_hits: "money",
|
|
437
|
+
campaign_params: "money",
|
|
438
|
+
event_id_reused: "money",
|
|
439
|
+
event_id_mismatch: "money",
|
|
440
|
+
event_id_not_forwarded: "money",
|
|
441
|
+
dedup_id_missing: "money",
|
|
442
|
+
server_side: "hygiene",
|
|
443
|
+
server_endpoint: "hygiene",
|
|
444
|
+
consent_default_missing: "legal",
|
|
445
|
+
consent_default_late: "legal",
|
|
446
|
+
consent_v2_missing: "legal",
|
|
447
|
+
consent_v2_update: "money",
|
|
448
|
+
before_consent: "legal",
|
|
449
|
+
after_reject: "legal",
|
|
450
|
+
reject_ignored: "legal",
|
|
451
|
+
reject_button_failed: "legal",
|
|
452
|
+
cookies_before_consent: "legal",
|
|
453
|
+
cookies_after_reject: "legal",
|
|
454
|
+
pii: "legal",
|
|
455
|
+
pii_datalayer: "legal",
|
|
456
|
+
journey_incomplete: "hygiene",
|
|
457
|
+
unplanned_events: "hygiene",
|
|
458
|
+
planned_out_of_scope: "hygiene",
|
|
459
|
+
matches_plan: "hygiene",
|
|
460
|
+
},
|
|
461
|
+
categoryLabel: { money: "Money", legal: "Legal", hygiene: "Hygiene" },
|
|
462
|
+
// The deterministic verdict. Each headline takes the object verdict() in metrics.js returns
|
|
463
|
+
// ({ status, headline, counts, journeys, problems }); a bare counts object also works.
|
|
464
|
+
verdict: {
|
|
465
|
+
status: { pass: "Pass", fail: "Fail", attention: "Needs attention" },
|
|
466
|
+
headline: {
|
|
467
|
+
fail_broken: (v) => {
|
|
468
|
+
const c = countsOf(v);
|
|
469
|
+
const risks = c.risk ? `; ${c.risk} consent or personal-data ${c.risk === 1 ? "risk sits" : "risks sit"} with Tag Manager` : "";
|
|
470
|
+
return `${c.broken} broken ${c.broken === 1 ? "finding needs" : "findings need"} a fix before the numbers can be trusted${risks}.`;
|
|
471
|
+
},
|
|
472
|
+
fail_incomplete: (v) => {
|
|
473
|
+
const j = journeysOf(v);
|
|
474
|
+
const where = j.total ? `${j.incomplete} of ${j.total} journeys did not finish` : "A journey did not finish";
|
|
475
|
+
return `${where}, so every event after the stop, including any conversion, is unverified.`;
|
|
476
|
+
},
|
|
477
|
+
attention_risk: (v) => {
|
|
478
|
+
const c = countsOf(v);
|
|
479
|
+
const warnings = c.warning ? `, and ${c.warning} ${c.warning === 1 ? "warning distorts" : "warnings distort"} the counts` : "";
|
|
480
|
+
return `Nothing is broken, but ${c.risk} consent or personal-data ${c.risk === 1 ? "risk needs" : "risks need"} fixing in Tag Manager${warnings}.`;
|
|
481
|
+
},
|
|
482
|
+
attention_warning: (v) => {
|
|
483
|
+
const c = countsOf(v);
|
|
484
|
+
return `Nothing is broken, but ${c.warning} ${c.warning === 1 ? "warning distorts" : "warnings distort"} counts or coverage and ${c.warning === 1 ? "needs" : "need"} tidying.`;
|
|
485
|
+
},
|
|
486
|
+
attention_no_hits: (v) => {
|
|
487
|
+
const j = journeysOf(v);
|
|
488
|
+
return `${j.total ? `${j.total} ${j.total === 1 ? "journey" : "journeys"} ran` : "The journeys ran"}, but no tracking request was captured, so nothing could be checked.`;
|
|
489
|
+
},
|
|
490
|
+
attention_nothing_tested: () => "No journey ran and nothing was captured, so there is nothing to judge yet.",
|
|
491
|
+
pass: (v) => {
|
|
492
|
+
const j = journeysOf(v);
|
|
493
|
+
return `Every planned event fired correctly on ${j.total ? `all ${j.total} ${j.total === 1 ? "journey" : "journeys"}` : "every journey tested"}; nothing to fix.`;
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
html: {
|
|
498
|
+
skip: "Skip to the report",
|
|
499
|
+
eyebrow: "Tracking audit",
|
|
500
|
+
countsLabel: "Findings by severity",
|
|
501
|
+
themeAuto: "Theme: follows your system",
|
|
502
|
+
themeLight: "Theme: light",
|
|
503
|
+
themeDark: "Theme: dark",
|
|
504
|
+
newTab: "opens in a new tab",
|
|
505
|
+
ownerSplit: (parts) => `${parts.join(", ")}.`,
|
|
506
|
+
forOwner: { developer: (n) => `${n} for the developer`, gtm: (n) => `${n} for Tag Manager`, marketing: (n) => `${n} for marketing` },
|
|
507
|
+
aiSummary: "AI summary",
|
|
508
|
+
platformsChecked: "Platforms checked",
|
|
509
|
+
campaignCheck: "Campaign check",
|
|
510
|
+
campaignChecked: "UTM, gclid and fbclid on the landing page",
|
|
511
|
+
consentModeOn: "consent mode on",
|
|
512
|
+
consentModeSeen: "Consent Mode commands seen",
|
|
513
|
+
cmpBanner: "banner",
|
|
514
|
+
scenariosRun: (n) => `${n} ${n === 1 ? "scenario" : "scenarios"}`,
|
|
515
|
+
runsAllCompleted: (n) => `${n} ${n === 1 ? "run" : "runs"}, all completed`,
|
|
516
|
+
runsCompleted: (done, n) => `${done} of ${n} runs completed`,
|
|
517
|
+
fixFirst: "What to fix first",
|
|
518
|
+
fixFirstLead: "Grouped by who fixes it, most points first. Each line opens its finding.",
|
|
519
|
+
pointsToRecover: (n) => `+${n} points when fixed`,
|
|
520
|
+
nothingFor: (owner) => `Nothing for ${owner} in this run.`,
|
|
521
|
+
moreInFindings: (n) => `${n} more in Findings →`,
|
|
522
|
+
working: "What is working",
|
|
523
|
+
whatWasChecked: "What was checked",
|
|
524
|
+
nothingVerified: "Nothing was verified in this run.",
|
|
525
|
+
coverageVerified: (done, total, pct) => `${done} of ${total} planned events verified${pct === null ? "" : ` (${pct}%)`}.`,
|
|
526
|
+
allRuns: (n) => `all ${n} runs`,
|
|
527
|
+
onlyOn: (places) => `${places.join(", ")} only`,
|
|
528
|
+
journeysLead: "Steps walked, hits captured and the problem cards that point at each run.",
|
|
529
|
+
viewport: "Viewport",
|
|
530
|
+
hitsCol: "Hits",
|
|
531
|
+
trend: "Trend",
|
|
532
|
+
trendLead: "Problem counts over the saved runs, oldest left. A hollow point is a run where a journey did not finish.",
|
|
533
|
+
trendDirection: { improving: "Improving", worsening: "Getting worse", flat: "No change" },
|
|
534
|
+
trendSpan: (n, first, last) => `over ${n} runs, ${first} to ${last}`,
|
|
535
|
+
runIncomplete: "a journey did not finish",
|
|
536
|
+
flapping: "Seen, gone, back again",
|
|
537
|
+
seenIn: (n, total) => `seen in ${n} of ${total} runs`,
|
|
538
|
+
openLongest: "Open longest",
|
|
539
|
+
openSince: (date, runs, places) => `open since ${date} · ${runs} ${runs === 1 ? "run" : "runs"} · ${places} ${places === 1 ? "place" : "places"}`,
|
|
540
|
+
score: "Data quality score",
|
|
541
|
+
scoreLead: "100 minus 15 per broken problem, 10 per risk and 5 per warning, doubled on a conversion event.",
|
|
542
|
+
scoreLost: (n) => `${n} points lost`,
|
|
543
|
+
findingsLead: "Open a finding for its evidence, where it happened and how to verify the fix.",
|
|
544
|
+
okInOverview: (n) => `${n} OK ${n === 1 ? "result is" : "results are"} listed in the overview.`,
|
|
545
|
+
noModel: "No model explanation in this run. The evidence, owner and verify links below do not need one.",
|
|
546
|
+
accepted: "Accepted",
|
|
547
|
+
acceptedNote: "This finding is in the baseline: it is known and does not count against the run.",
|
|
548
|
+
pageUnknown: "page: unknown",
|
|
549
|
+
alsoFineOn: "Also fine on",
|
|
550
|
+
findingLink: "Finding →",
|
|
551
|
+
consentMode: "Consent Mode",
|
|
552
|
+
consentTiming: (ms, before, v2, missing) => `Default set ${ms === null ? "on the first page" : `${Math.round(ms)} ms into the first page`}${before === null ? "" : before ? ", before the first Google hit" : ", after the first Google hit"} · v2 signals ${v2 ? "present" : `missing: ${missing.join(", ")}`}.`,
|
|
553
|
+
consentNoDefault: "No Consent Mode default was pushed on this journey.",
|
|
554
|
+
consentResent: (n) => `The default and the update are re-sent on ${n} more ${n === 1 ? "page load" : "page loads"}, so the stored choice is restored each time.`,
|
|
555
|
+
consentOnHit: "Consent on this hit:",
|
|
556
|
+
scenariosLead: (cmp) => `The home page was opened once per consent choice, answered through ${cmp === "banner" ? "the banner's buttons" : cmp}. Each cell is how many hits the tag sent after that choice.`,
|
|
557
|
+
scenariosLegend: "A marked number is data the visitor had refused. \"cookieless\" is a Consent Mode ping with storage denied, which is allowed.",
|
|
558
|
+
cellCookieless: "cookieless",
|
|
559
|
+
cellAdDenied: "ad storage denied",
|
|
560
|
+
cellWithCookies: "with cookies",
|
|
561
|
+
cellProblem: "problem:",
|
|
562
|
+
cellShouldNot: "should not have been sent",
|
|
563
|
+
stepsTitle: "Steps and the hits each one sent",
|
|
564
|
+
stepsLead: "Open a row for the parameters, the dataLayer pushes and the requests. Rows with a finding are open.",
|
|
565
|
+
stepCol: "Step",
|
|
566
|
+
timeCol: "Time",
|
|
567
|
+
hasFinding: (sev) => `has a ${sev.toLowerCase()} finding`,
|
|
568
|
+
stepDetails: (hits, pushes) => `Details · ${hits} ${hits === 1 ? "hit" : "hits"} · ${pushes} dataLayer`,
|
|
569
|
+
hitsInStep: "Hits in this step",
|
|
570
|
+
blockedBy: (platform) => `blocked by the audit: answered locally, never reached ${platform}`,
|
|
571
|
+
problems: (n) => `${n} ${n === 1 ? "problem" : "problems"}`,
|
|
572
|
+
funnel: "Expected vs observed",
|
|
573
|
+
funnelLead: (observed, expected, ok) => `${observed} of ${expected} expected events fired, ${ok} with every required parameter.`,
|
|
574
|
+
funnelBreaks: (event) => `The funnel breaks at ${event}.`,
|
|
575
|
+
conversion: "conversion",
|
|
576
|
+
sent: "sent",
|
|
577
|
+
notSent: "not sent",
|
|
578
|
+
firstAt: "First at",
|
|
579
|
+
page: "Page",
|
|
580
|
+
params: (list) => `without ${list.join(", ")}`,
|
|
581
|
+
paramsShort: "params",
|
|
582
|
+
parity: "Platform parity",
|
|
583
|
+
parityLead: "The same event on two platforms, and what differs between them.",
|
|
584
|
+
perPlatform: "Per platform",
|
|
585
|
+
difference: "Difference",
|
|
586
|
+
agree: "agree",
|
|
587
|
+
mismatch: { count: "count differs", value: "value differs", currency: "currency differs", value_missing: "value on one side only" },
|
|
588
|
+
onlyOnPlatform: "Only on one platform:",
|
|
589
|
+
detailsCol: "Details",
|
|
590
|
+
coverageLegend: "✓ sent with its parameters · params: sent without required parameters · ✗ not sent · – not expected on this journey",
|
|
591
|
+
needs: (list) => `needs ${list.join(", ")}`,
|
|
592
|
+
notExpected: "not expected",
|
|
593
|
+
conversions: "Conversion integrity",
|
|
594
|
+
conversionsLead: (passed, total) => `${passed} of ${total} purchases pass every check.`,
|
|
595
|
+
conversionChecks: { value: "Value", currency: "Currency", transactionId: "Order ID", items: "Items", duplicate: "Not duplicated", parity: "Parity", eventId: "Event ID" },
|
|
596
|
+
orderId: "Order",
|
|
597
|
+
value: "Value",
|
|
598
|
+
pass: "pass",
|
|
599
|
+
fail: "fail",
|
|
600
|
+
notApplicable: "not applicable",
|
|
601
|
+
seenOn: "Seen on",
|
|
602
|
+
checkedNotSeen: "Checked, not seen",
|
|
603
|
+
neverSeen: (list) => `Checked but never seen: ${list}. No request reached them on any page.`,
|
|
604
|
+
timing: "Timing",
|
|
605
|
+
timingLead: "How long each run took and how far behind each step its first hit came. Includes the audit's own waiting time.",
|
|
606
|
+
duration: "Duration",
|
|
607
|
+
medianFirstHit: "Median first hit",
|
|
608
|
+
slowestHit: "Slowest hit",
|
|
609
|
+
planChanges: "Plan changes",
|
|
610
|
+
},
|
|
209
611
|
};
|
|
210
612
|
|
|
211
613
|
const tr = {
|
|
212
614
|
name: "Turkish",
|
|
213
|
-
severity: { broken: "Bozuk", risk: "Risk", warning: "Uyarı", info: "Bilgi", ok: "
|
|
615
|
+
severity: { broken: "Bozuk", risk: "Risk", warning: "Uyarı", info: "Bilgi", ok: "Sorunsuz" },
|
|
214
616
|
ui: {
|
|
215
617
|
title: (host) => `AI Tag Debugger raporu: ${host}`,
|
|
216
618
|
generated: (at) => `${at} tarihinde ai-tag-debugger ile oluşturuldu · Analitik İşler`,
|
|
@@ -231,10 +633,19 @@ const tr = {
|
|
|
231
633
|
where: "Nerede",
|
|
232
634
|
causeAndFix: "Neden ve çözüm",
|
|
233
635
|
likelyCause: "Olası neden",
|
|
636
|
+
gtmTags: "GTM container'ınızda",
|
|
637
|
+
gtmNoTag: "Container dışa aktarımındaki hiçbir etiket bu olayı göndermiyor.",
|
|
638
|
+
gtmFiresOn: "Tetikleyici:",
|
|
639
|
+
gtmNoTrigger: "Tetikleyici yok",
|
|
640
|
+
gtmBlockedBy: "Engelleyen:",
|
|
641
|
+
gtmPaused: "Duraklatıldı",
|
|
642
|
+
gtmConsent: (types) => `İzin gerekiyor: ${types}`,
|
|
643
|
+
gtmWhy: (tag, verdict, why) => `${q(tag)} etiketi: ${verdict} — ${why}`,
|
|
644
|
+
gtmVerdict: { true: "tetiklenmiş olmalıydı", false: "tetiklenmedi", unknown: "değerlendirilemedi" },
|
|
234
645
|
fix: "Çözüm",
|
|
235
646
|
captured: "Yakalanan",
|
|
236
647
|
noProblems: "Sorun bulunamadı.",
|
|
237
|
-
noExplanation: "
|
|
648
|
+
noExplanation: "Bu çalıştırmada model açıklaması yok. Aşağıdaki etki, sorumlu ve çözüm bilgileri için gerekmiyor.",
|
|
238
649
|
matchingPlan: "Plana uygun olanlar",
|
|
239
650
|
timeline: "Yolculuklar ve olay zaman çizelgesi",
|
|
240
651
|
timelineLead: "Her yolculuğun her adımı. Olaylar platforma göre gruplanır; bir olayı açınca parametrelerini, arkasındaki dataLayer gönderimini ve onu taşıyan ağ isteğini görürsünüz. Sorunlu adımlar açık gösterilir.",
|
|
@@ -251,11 +662,14 @@ const tr = {
|
|
|
251
662
|
method: "Metot",
|
|
252
663
|
status: "Durum",
|
|
253
664
|
vendor: "Sağlayıcı",
|
|
254
|
-
blockedNote: "yerel olarak yanıtlandı,
|
|
665
|
+
blockedNote: "bu denetim engelledi: yerel olarak yanıtlandı, sağlayıcıya hiç ulaşmadı",
|
|
666
|
+
blockedNoteVendor: (vendor) => `bu denetim engelledi: yerel olarak yanıtlandı, ${vendor} platformuna hiç ulaşmadı`,
|
|
255
667
|
clickedThrough: "üstündeki bir öğeye rağmen tıklandı",
|
|
256
668
|
generatedBy: "AI Tag Debugger ile oluşturuldu",
|
|
257
669
|
nothing: "Yok",
|
|
258
|
-
counts: (c) => `${c.broken} bozuk · ${c.risk} risk · ${c.warning} uyarı · ${c.info} bilgi · ${c.ok}
|
|
670
|
+
counts: (c) => `${c.broken} bozuk · ${c.risk} risk · ${c.warning} uyarı · ${c.info} bilgi · ${c.ok} sorunsuz`,
|
|
671
|
+
accepted: "Kabul edildi",
|
|
672
|
+
acceptedLine: (n) => `Temel dosyada kabul edilen ${n} bulgu sayılmadı`,
|
|
259
673
|
whereStep: (journey, viewport, step) => `${journey} (${viewport})${step ? `, "${step}" adımı` : ""}`,
|
|
260
674
|
allGood: "Test edilen tüm yolculuklarda plandaki tüm olaylar doğru çalıştı.",
|
|
261
675
|
tabEvents: "Olaylar",
|
|
@@ -307,6 +721,7 @@ const tr = {
|
|
|
307
721
|
changesLead: (id, mode) => `${id} çalıştırmasıyla ${mode === "plan" ? "plan kapsamına" : "sağlık bulgularına"} göre karşılaştırıldı`,
|
|
308
722
|
changesLine: (ch) => ch.fixed.length || ch.new.length ? [ch.fixed.length ? `${ch.fixed.length} ${ch.mode === "plan" ? "olay" : "sorun"} düzeldi` : "", ch.new.length ? `${ch.new.length} yeni sorun` : ""].filter(Boolean).join(", ") : "Son çalıştırmadan bu yana değişiklik yok",
|
|
309
723
|
changeFixed: "Düzeldi",
|
|
724
|
+
changeWas: (what) => `önceki durum: ${what}`,
|
|
310
725
|
changeNew: "Yeni",
|
|
311
726
|
noSavedRun: "Bu site için henüz kayıtlı çalıştırma yok. Önce `aitd run` çalıştırın; her çalıştırma bir öncekiyle karşılaştırılır.",
|
|
312
727
|
routeChanged: (list) => `Yapay zeka siteyi son çalıştırmadan farklı bir yoldan gezdi: ${list}`,
|
|
@@ -316,7 +731,7 @@ const tr = {
|
|
|
316
731
|
bucket: { implemented: "Uygulanmış", missing: "Eksik", missing_params: "Eksik parametre", wrong_values: "Hatalı değer", unplanned: "Planda yok", not_checked: "Kontrol edilmedi" },
|
|
317
732
|
bucketCol: "Sonuç",
|
|
318
733
|
summaryLead: "Yapay zekâ özeti, öncelik sırasıyla",
|
|
319
|
-
noSummary: "
|
|
734
|
+
noSummary: "Bu çalıştırmada model özeti yok. Karar ve aşağıdaki bulgular tek başına yeterli.",
|
|
320
735
|
seeAllFindings: "Tüm bulguları gör →",
|
|
321
736
|
journey: "Yolculuk",
|
|
322
737
|
stepsCol: "Adım",
|
|
@@ -335,12 +750,14 @@ const tr = {
|
|
|
335
750
|
runViewports: "Ekranlar",
|
|
336
751
|
runLanguage: "Dil",
|
|
337
752
|
runVersion: "Sürüm",
|
|
753
|
+
junitJourney: "yolculuk tamamlandı",
|
|
754
|
+
junitSite: "site",
|
|
338
755
|
consentDefault: "Varsayılan",
|
|
339
756
|
consentUpdate: "Güncelleme",
|
|
340
757
|
consentLead: "Sitenin gönderdiği Consent Mode komutları, sırasıyla.",
|
|
341
758
|
consentNone: "Site bu yolculukta Consent Mode komutu göndermedi.",
|
|
342
759
|
scenarios: "Onay senaryoları",
|
|
343
|
-
scenariosLead: (cmp) => `
|
|
760
|
+
scenariosLead: (cmp) => `Ana sayfa her onay seçimi için bir kez açıldı; seçim ${cmp === "banner" ? "banner düğmeleriyle" : `${cmp} üzerinden`} yapıldı. Her hücre, etiketin o seçimden sonra gönderdiği istek sayısıdır. Kırmızı sayı, ziyaretçinin reddettiği veridir.`,
|
|
344
761
|
scenarioCols: { before: "Henüz seçim yok", accept: "Tümünü kabul", reject: "Tümünü reddet", analytics: "Yalnızca analitik" },
|
|
345
762
|
scenarioNotRun: "Burada desteklenmiyor",
|
|
346
763
|
scenarioTag: "Etiket",
|
|
@@ -376,42 +793,399 @@ const tr = {
|
|
|
376
793
|
by: "by",
|
|
377
794
|
credit: (atd) => `Bu rapor açık kaynak ${atd} ile oluşturuldu.`,
|
|
378
795
|
timelineLeadV2: "Her adımda üç sekme var: o adımda gönderilen olaylar, dataLayer gönderimleri ve ağ istekleri. Olayları ve istekleri kaynağa göre filtreleyebilirsiniz. Sorunlu adımlar açık gösterilir.",
|
|
796
|
+
history: {
|
|
797
|
+
noRuns: "Bu site için henüz kayıtlı çalıştırma yok. Önce `aitd run` çalıştırın; eğilim ikinci çalıştırmayla başlar.",
|
|
798
|
+
oneRun: (id) => `Tek kayıtlı çalıştırma var (${id}); eğilim bir sonrakiyle başlar.`,
|
|
799
|
+
direction: { improving: "iyileşiyor", worsening: "kötüleşiyor", flat: "değişmiyor" },
|
|
800
|
+
headline: (runs, first, last, dir, now, was, ago) => `${runs} çalıştırmada eğilim (${first} → ${last}): ${dir}. Şimdi ${now}; ${ago} çalıştırma önce ${was}.`,
|
|
801
|
+
headlineShort: (runs, first, last, dir, now) => `${runs} çalıştırmada eğilim (${first} → ${last}): ${dir}. Şimdi ${now}.`,
|
|
802
|
+
counts: (c) => `${c.broken} bozuk · ${c.risk} risk · ${c.warning} uyarı`,
|
|
803
|
+
openLongest: (items) => `En uzun süredir açık: ${items.join("; ")}.`,
|
|
804
|
+
since: (label, day, runs) => `${label} ${day} tarihinden beri (${runs} çalıştırma)`,
|
|
805
|
+
flapping: (items) => `Gelip giden (görüldü, kayboldu, yine görüldü): ${items.join("; ")}.`,
|
|
806
|
+
seenIn: (label, seen, runs) => `${label} ${runs} çalıştırmanın ${seen} tanesinde`,
|
|
807
|
+
places: (n) => ` ${n} yerde`,
|
|
808
|
+
unstable: (items) => `Her seferinde tamamlanmayan yolculuklar: ${items.join("; ")}.`,
|
|
809
|
+
stillOpen: (runs, items) => `${runs} çalıştırmadır hâlâ açık: ${items.join("; ")}.`,
|
|
810
|
+
sparkline: (spark, dir, runs, first, last) => `${spark} ${runs} çalıştırmada ${dir} (${first} → ${last})`,
|
|
811
|
+
fixedWas: "önceki durum",
|
|
812
|
+
},
|
|
813
|
+
md: {
|
|
814
|
+
title: (site, headline) => `${site}: ${headline}`,
|
|
815
|
+
meta: (at, journeys, platforms, version) => `${at} tarihinde oluşturuldu · ${journeys} yolculuk · ${platforms} · ai-tag-debugger ${version}`,
|
|
816
|
+
platformsSeen: (n, list) => (n ? `${n} platform görüldü (${list})` : "hiçbir platform görülmedi"),
|
|
817
|
+
htmlReport: "HTML rapor",
|
|
818
|
+
noParams: "istek hiç parametre taşımıyordu",
|
|
819
|
+
score: (score) => `veri kalitesi puanı ${score}/100`,
|
|
820
|
+
headline: {
|
|
821
|
+
fail_broken: (what, scope) => `${what} bozuk${scope}`,
|
|
822
|
+
fail_incomplete: (journey) => `${journey} yolculuğu tamamlanmadı, bu yüzden olayları kontrol edilemedi`,
|
|
823
|
+
attention_risk: (what, scope) => `${what} bir onay veya veri riski taşıyor${scope}`,
|
|
824
|
+
attention_warning: (what, scope) => `${what} dikkat gerektiriyor${scope}`,
|
|
825
|
+
attention_no_hits: () => "hiç izleme isteği yakalanmadı",
|
|
826
|
+
attention_nothing_tested: () => "hiçbir şey test edilmedi",
|
|
827
|
+
pass: (events, journeys) => (events ? `plandaki ${events} olayın tümü ${journeys} yolculukta doğru çalıştı` : `${journeys} yolculukta tüm kontroller geçti`),
|
|
828
|
+
},
|
|
829
|
+
tracking: (event) => `${event} izlemesi`,
|
|
830
|
+
setup: (check) => `${check} kontrolü`,
|
|
831
|
+
onViewport: (viewport) => ` (${viewport})`,
|
|
832
|
+
onJourney: (journey) => ` (${journey})`,
|
|
833
|
+
everywhere: " (her yolculukta)",
|
|
834
|
+
aiSummary: "Yapay zekâ özeti",
|
|
835
|
+
stillOpen: "Hâlâ açık",
|
|
836
|
+
priorities: "Öncelikler",
|
|
837
|
+
nothingToDo: (owner) => `${owner}: yapılacak bir şey yok.`,
|
|
838
|
+
allJourneys: (n) => `${n} yolculuğun tümü`,
|
|
839
|
+
step: (n) => `adım ${n}`,
|
|
840
|
+
more: (n) => `+${n} daha`,
|
|
841
|
+
also: "Ayrıca",
|
|
842
|
+
owner: "Sorumlu",
|
|
843
|
+
link: "Bağlantı",
|
|
844
|
+
alsoFineOn: "Şurada sorunsuz",
|
|
845
|
+
consent: "Onay",
|
|
846
|
+
consentMode: (present, total, onTime, v2) => `Consent Mode varsayılanı ${total} yolculuğun ${present} tanesinde ayarlandı${onTime === false ? ", ilk Google isteğinden sonra" : onTime ? ", ilk Google isteğinden önce" : ""}; v2 sinyalleri ${v2 ? "var" : "eksik"}.`,
|
|
847
|
+
consentModeNone: "Hiçbir yolculukta Consent Mode varsayılan komutu görülmedi.",
|
|
848
|
+
consentNotChecked: "Bu çalıştırmada onay kontrol edilmedi.",
|
|
849
|
+
cell: { ok: "✓", bad: "✗", cookieless: "çerezsiz", beforeConsent: "onaydan önce", shouldNotSend: "gönderilmemeliydi", adDenied: "reklam depolaması reddedilmiş", notRun: "–" },
|
|
850
|
+
consentLegend: "✓ izinli · ✗ gönderilmemeliydi · \"çerezsiz\" = depolama reddedilmişken Consent Mode pingi · – = bu seçim çalıştırılmadı",
|
|
851
|
+
whatPassed: "Sorunsuz olanlar",
|
|
852
|
+
coverage: (implemented, total, percent) => `Plan kapsamı: plandaki ${total} olaydan ${implemented} tanesi uygulanmış${percent === null ? "" : ` (%${percent})`}`,
|
|
853
|
+
purchaseOk: (platform, place, value, currency, id) => `${platform} satın alma değeri ve para birimi: ${place} (${value} ${currency}${id ? `, ${id}` : ""})`,
|
|
854
|
+
parityOk: (platforms, place) => `Satın alma platformlar arasında tutarlı: ${platforms} ${place} için aynı değeri bildirdi`,
|
|
855
|
+
noPii: "Kişisel veri: hiçbir istekte düz metin e-posta veya kullanıcı verisi yok.",
|
|
856
|
+
viewport: "Görünüm",
|
|
857
|
+
hits: "İstek",
|
|
858
|
+
yes: "evet",
|
|
859
|
+
no: "hayır",
|
|
860
|
+
flaggedSteps: "Sorunlu adımlar",
|
|
861
|
+
timelineNote: "Her adımın tüm istekleri, dataLayer gönderimleri ve ağ çağrıları timeline.csv dosyasında.",
|
|
862
|
+
moreIn: (n, file) => `+${n} daha ${file} dosyasında`,
|
|
863
|
+
notChecked: "Kontrol edilmeyenler",
|
|
864
|
+
noPlan: "Plandaki olaylar: ölçüm planı verilmedi (yapılandırmada `plan`).",
|
|
865
|
+
noGtm: "GTM etiket adları: container dışa aktarımı verilmedi (yapılandırmada `gtm_container`).",
|
|
866
|
+
noAnalyticsOnly: "Yalnızca analitik onayı: banner'da böyle bir seçenek yok.",
|
|
867
|
+
noScenarios: "Onay senaryoları: çalıştırılmadı (yanıtlanabilir banner yok ya da tekrar oynatma).",
|
|
868
|
+
platformsSilent: (list, n) => `${list} kapsamdaydı ama site ${n === 1 ? "ona" : "onlara"} hiçbir şey göndermedi.`,
|
|
869
|
+
trend: "Eğilim",
|
|
870
|
+
},
|
|
871
|
+
cli: {
|
|
872
|
+
verdict: (status, headline, score) => `Sonuç: ${status} · ${headline}${score === null ? "" : ` · puan ${score}/100`}`,
|
|
873
|
+
runCol: "Çalıştırma",
|
|
874
|
+
scoreCol: "Puan",
|
|
875
|
+
completeCol: "Tamamlandı",
|
|
876
|
+
historyNone: "Bu site için henüz kayıtlı çalıştırma yok.",
|
|
877
|
+
},
|
|
379
878
|
},
|
|
380
879
|
detail: {
|
|
381
880
|
journeyIncomplete: (note) => `Yolculuk hedefine ulaşmadı${note ? `: ${note}` : "."} Bu noktadan sonraki olaylar kontrol edilemedi.`,
|
|
382
|
-
missingEvent: (platform, name) =>
|
|
383
|
-
missingEventEarly: (name) => `${q(name)} görülmedi
|
|
384
|
-
missingParams: (name, params) => `${q(name)} olayı ${params.map(q)
|
|
385
|
-
duplicate: (name, n) => `${q(name)} tek bir işlemde ${n} kez gönderildi
|
|
386
|
-
purchaseValueZero: (platform, name, v) => `${platform} ${q(name)} ${q(v)} değeriyle gönderildi. 0 veya daha düşük değerli bir satın alma gelire eklenmez
|
|
387
|
-
purchaseValueNaN: (platform, name, v) => `${platform} ${q(name)} sayı olmayan ${q(v)} değeriyle gönderildi, bu yüzden gelir kayboluyor. Para birimi işareti veya binlik ayırıcı olmadan 49.90 gibi düz bir sayı gönderin.`,
|
|
388
|
-
purchaseCurrency: (platform, name, c) => `${platform} ${q(name)} ${q(c)} para birimiyle gönderildi; bu, büyük harfli 3 harfli bir ISO 4217 kodu değil (USD, EUR veya TRY gibi). Platformlar geliri
|
|
389
|
-
purchaseItemsEmpty: (platform, name) => `${platform} ${q(name)} ürün listesi boş gönderildi, bu yüzden ürün raporları bu siparişten veri alamaz.`,
|
|
390
|
-
purchaseMismatch: (id, diffs) => `GA4 ve Meta ${id ? `${q(id)} siparişini` : "satın almayı"} farklı bildirdi: ${diffs.map(([f, g, m]) => `${f === "value" ? "değer" : "para birimi"} GA4'te ${q(g)}, Meta'da ${q(m)}`).join("; ")}. Etiketlerden biri yanlış
|
|
391
|
-
serverSide: (platform, server, browser, unseen = []) => `${platform}: ${server.map(q).join(", ")} sitenin kendi alan adındaki bir sunucu
|
|
392
|
-
|
|
881
|
+
missingEvent: (platform, name) => `${label(platform)} ${q(name)} bu yolculukta gönderilmedi; oysa yolculuk hedefine ulaştı. ${label(platform)} bu olay için hiçbir veri almadı.`,
|
|
882
|
+
missingEventEarly: (name) => `${q(name)} görülmedi; ancak yolculuk erken durduğu için bu olay eksik değil, doğrulanmamış sayılır.`,
|
|
883
|
+
missingParams: (name, params) => `${q(name)} olayı ${andList(sortParams(params).map(q), "ve")} ${params.length > 1 ? "parametreleri" : "parametresi"} olmadan gönderildi.`,
|
|
884
|
+
duplicate: (name, n) => `${q(name)} tek bir işlemde ${n} kez gönderildi. Her gerçek olay ${n} kez sayılıyor.`,
|
|
885
|
+
purchaseValueZero: (platform, name, v) => `${label(platform)} ${q(name)} ${q(v)} değeriyle gönderildi. 0 veya daha düşük değerli bir satın alma gelire eklenmez; reklam platformları teklifleri buna göre optimize edemez.`,
|
|
886
|
+
purchaseValueNaN: (platform, name, v) => `${label(platform)} ${q(name)} sayı olmayan ${q(v)} değeriyle gönderildi, bu yüzden gelir kayboluyor. Para birimi işareti veya binlik ayırıcı olmadan 49.90 gibi düz bir sayı gönderin.`,
|
|
887
|
+
purchaseCurrency: (platform, name, c) => `${label(platform)} ${q(name)} ${q(c)} para birimiyle gönderildi; bu, büyük harfli 3 harfli bir ISO 4217 kodu değil (USD, EUR veya TRY gibi). Platformlar geliri düşürür ya da yanlış kurdan çevirir.`,
|
|
888
|
+
purchaseItemsEmpty: (platform, name) => `${label(platform)} ${q(name)} ürün listesi boş gönderildi, bu yüzden ürün raporları bu siparişten veri alamaz.`,
|
|
889
|
+
purchaseMismatch: (id, diffs) => `GA4 ve Meta ${id ? `${q(id)} siparişini` : "satın almayı"} farklı bildirdi: ${diffs.map(([f, g, m]) => `${f === "value" ? "değer" : "para birimi"} GA4'te ${q(g)}, Meta'da ${q(m)}`).join("; ")}. Etiketlerden biri yanlış sayıyı okuyor; Google ve Meta farklı gelir üzerinden teklif veriyor.`,
|
|
890
|
+
serverSide: (platform, server, browser, unseen = []) => `${label(platform)}: ${server.map(q).join(", ")} sitenin kendi alan adındaki bir sunucu container'ına gönderildi (sunucu tarafı etiketleme)${browser.length ? `; ${browser.map(q).join(", ")} doğrudan tarayıcıdan gitti` : ""}.${unseen.length ? ` ${unseen.join(" ve ")} olaylarının sunucu tarafı kopyaları tarayıcıdan geçmez, bu yüzden burada görünmez.` : ""}`,
|
|
891
|
+
serverEndpoint: (hosts) => `${hosts.map(q).join(", ")} adresinde bir sunucu container'ı yanıt veriyor (sunucu tarafı GTM veya benzeri bir kurulum). Reklam platformlarına ilettiği olaylar tarayıcıdan geçmez, bu yüzden burada görünmez.`,
|
|
892
|
+
eventIdReused: (platform, id, names, n) => `${label(platform)} olay kimliği ${q(id)} ${n} farklı olay için kullanıldı (${names.map(q).join(", ")}). ${label(platform)} ilkini tutar, diğerlerini kopya sayıp atar. Her olaya kendi kimliğini verin.`,
|
|
893
|
+
eventIdNotForwarded: (name, ga4Name) => `Meta ${q(name)} olay kimliği taşıyor, ancak sunucu container'ına giden GA4 ${q(ga4Name)} isteğinde event_id yok. Sunucu container'ı Conversions API olayını bu istekten üretiyorsa Meta onu piksel olayıyla eşleştiremez ve iki kez sayar. Aynı kimliği GA4 olayına event_id parametresi olarak ekleyin.`,
|
|
894
|
+
eventIdMismatch: (name, metaId, ga4Name, ga4Id) => `Meta ${q(name)} olay kimliği ${q(metaId)}, ancak sunucu container'ına giden GA4 ${q(ga4Name)} isteği event_id ${q(ga4Id)} taşıyor. Bu istekten üretilen Conversions API olayı piksel olayıyla eşleşmez, Meta onu iki kez sayar. İkisi için tek bir kimlik kullanın.`,
|
|
895
|
+
dedupIdMissing: (platform, name) => `${label(platform)} ${q(name)} tarayıcıdan olay kimliği olmadan gönderildi; sitede sunucu tarafı bir kurulum görüldü. Sunucu da bu olayı gönderiyorsa ${label(platform)} ikisini eşleştiremez ve iki kez sayar.`,
|
|
393
896
|
campaignLost: (names, finalUrl) => `Açılış adresi ${names.join(", ")} taşıyordu, ancak sayfa ${finalUrl} adresinde ${names.length === 1 ? "onsuz" : "onlarsız"} sonlandı. Bir yönlendirme ${names.length === 1 ? "parametreyi" : "parametreleri"} düşürdü, bu yüzden reklam tıklamalarının atfı kaybolur.`,
|
|
394
|
-
campaignMissingInHits: (platform, name, names) => `Açılış sayfasındaki ${platform} ${q(name)} isteği ${names.join(", ")} olmadan bir sayfa adresi bildiriyor, oysa sayfada ${names.length === 1 ? "o" : "onlar"} hâlâ vardı. Ziyaret kampanyaya değil doğrudan trafiğe yazılabilir.`,
|
|
897
|
+
campaignMissingInHits: (platform, name, names) => `Açılış sayfasındaki ${label(platform)} ${q(name)} isteği ${names.join(", ")} olmadan bir sayfa adresi bildiriyor, oysa sayfada ${names.length === 1 ? "o" : "onlar"} hâlâ vardı. Ziyaret kampanyaya değil doğrudan trafiğe yazılabilir.`,
|
|
395
898
|
campaignOk: (names) => `${names.join(", ")} açılış sayfasının yönlendirmelerinden geçti ve isteklere ulaştı.`,
|
|
396
899
|
consentDefaultMissing: () => "dataLayer'da Google Consent Mode varsayılan komutu (gtag('consent', 'default', ...)) bulunamadı.",
|
|
397
900
|
consentDefaultLate: () => "Consent Mode varsayılanı, ilk izleme isteği gönderildikten sonra ayarlandı.",
|
|
398
|
-
beforeConsentNever: (platform, name) => `${platform} ${q(name)}, bu yolculukta hiç onay
|
|
399
|
-
beforeConsent: (platform, name) => `${platform} ${q(name)}, ziyaretçi
|
|
901
|
+
beforeConsentNever: (platform, name) => `${label(platform)} ${q(name)}, ziyaretçi bu yolculukta hiç onay seçimi yapmadığı hâlde gönderildi. ${label(platform)}, onay vermemiş ziyaretçilerden veri alıyor.`,
|
|
902
|
+
beforeConsent: (platform, name) => `${label(platform)} ${q(name)}, ziyaretçi onay seçimini yapmadan önce gönderildi. ${label(platform)}, onay vermemiş ziyaretçilerden veri alıyor.`,
|
|
400
903
|
consentV2Missing: (keys) => `Consent Mode varsayılanı ${keys.map(q).join(" ve ")} değerlerini ayarlamıyor. Consent Mode v2, AEA ve Birleşik Krallık'taki Google reklamları için bunları ister; yoksa reklam kişiselleştirme ve dönüşüm ölçümü durabilir.`,
|
|
401
|
-
consentV2Update: (keys) => `Ziyaretçi kabul ettikten sonra Consent Mode güncellemesi ${keys.map(q).join(" ve ")} iznini vermedi.
|
|
904
|
+
consentV2Update: (keys) => `Ziyaretçi kabul ettikten sonra Consent Mode güncellemesi ${keys.map(q).join(" ve ")} iznini vermedi. Bu sinyaller reddedilmiş kaldı; onay veren ziyaretçiler için bile Google Ads dönüşümleri ve yeniden pazarlama kapalı kalıyor.`,
|
|
402
905
|
rejectIgnored: () => "Ziyaretçi çerezleri reddettikten sonra bir Consent Mode güncellemesi izin verdi; reddet düğmesi işe yaramıyor.",
|
|
403
906
|
rejectButtonFailed: () => "Reddet düğmesine tıklandıktan sonra çerez bandı hâlâ görünüyordu.",
|
|
404
|
-
afterReject: (platform, name) => `${platform} ${q(name)}, ziyaretçi çerezleri reddettikten sonra da gönderildi.`,
|
|
907
|
+
afterReject: (platform, name) => `${label(platform)} ${q(name)}, ziyaretçi çerezleri reddettikten sonra da gönderildi.`,
|
|
405
908
|
cookiesBeforeConsent: (names) => `Ziyaretçi kabul etmeden önce izleme çerezleri yazıldı: ${names.join(", ")}.`,
|
|
406
909
|
cookiesNeverConsent: (names) => `Bu yolculukta hiç onay verilmemesine rağmen izleme çerezleri yazıldı: ${names.join(", ")}.`,
|
|
407
910
|
cookiesAfterReject: (names) => `Ziyaretçi çerezleri reddettikten sonra izleme çerezleri yazıldı: ${names.join(", ")}.`,
|
|
408
|
-
pii: (platform, name) => `${q(name)} ile birlikte ${platform} platformuna düz metin olarak bir e-posta adresi gönderildi.`,
|
|
911
|
+
pii: (platform, name) => `${q(name)} ile birlikte ${label(platform)} platformuna düz metin olarak bir e-posta adresi gönderildi.`,
|
|
409
912
|
unplanned: (list) => `Ölçüm planında olmayan olaylar gönderildi: ${list.join(", ")}.`,
|
|
410
|
-
piiUnhashed: (platform, name, fields) => `${q(name)}, ${platform} platformuna kullanıcı verisini karma (hash) yapmadan gönderdi (${fields.join(", ")}). Reklam platformları bu değerleri SHA-256 ile karma yapılmış bekler.`,
|
|
913
|
+
piiUnhashed: (platform, name, fields) => `${q(name)}, ${label(platform)} platformuna kullanıcı verisini karma (hash) yapmadan gönderdi (${fields.join(", ")}). Reklam platformları bu değerleri SHA-256 ile karma yapılmış bekler.`,
|
|
411
914
|
piiDataLayer: (fields) => `dataLayer karma (hash) yapılmamış kullanıcı verisi içeriyor (${fields.join(", ")}). Bu, Google gelişmiş dönüşümleri için geçerli bir kurulum, ancak sayfadaki diğer tüm etiketler ve betikler de bu veriyi okuyabilir. Yalnızca kullanması gereken etiketlerin kullandığını kontrol edin.`,
|
|
412
|
-
plannedOutOfScope: (list) => `Plandaki ${list.length} olay,
|
|
915
|
+
plannedOutOfScope: (list) => `Plandaki ${list.length} olay, platformu bu çalıştırmada seçilmediği için kontrol edilmedi: ${list.join(", ")}.`,
|
|
413
916
|
matches: (list) => `Plandaki ${list.length} olay plana uygun çalıştı: ${list.join(", ")}.`,
|
|
414
917
|
},
|
|
918
|
+
// Bir GTM etiketinin neden çalışıp çalışmadığı, yakalanan dataLayer'dan okunur. Cümleler
|
|
919
|
+
// "X etiketi: tetiklenmedi — ..." kalıbının devamı olarak küçük harfle başlar.
|
|
920
|
+
gtm: {
|
|
921
|
+
paused: "etiket duraklatılmış",
|
|
922
|
+
noTrigger: "etiketin hiçbir tetikleyicisi yok",
|
|
923
|
+
missingTrigger: (trigger) => `${trigger} tetikleyicisi container dışa aktarımında bulunmuyor`,
|
|
924
|
+
noPush: (event) => `bu yolculukta ${q(event)} olayını taşıyan bir dataLayer gönderimi yok`,
|
|
925
|
+
noPageEvent: (trigger, event) => `${q(trigger)} tetikleyicisi GTM'nin ${event} olayını bekliyor, ancak bu olay dataLayer'a hiç gelmedi; container yüklenmemiş olabilir`,
|
|
926
|
+
pageTrigger: (trigger, kind) => `${q(trigger)} gibi ${kind} türü tetikleyicileri GTM dataLayer'dan değil, sayfanın içinde değerlendirir`,
|
|
927
|
+
unknownType: (trigger, type) => `${q(trigger)} tetikleyicisi ${type} türünde; bu tür dataLayer'dan değerlendirilemez`,
|
|
928
|
+
condition: (trigger, field, op, want, had, negate) => `${q(trigger)} tetikleyicisi ${field} için ${want} ${op}${negate ? " olmayan" : ""} bir değer bekliyor; gönderimde ise ${had} vardı`,
|
|
929
|
+
conditionUnknown: (trigger, variable) => `${q(trigger)} tetikleyicisi ${q(variable)} değişkenine bakıyor; bu değişken dataLayer'dan okunamaz`,
|
|
930
|
+
conditionType: (trigger, type) => `${q(trigger)} tetikleyicisinde ${type} türünde bir koşul var; bu koşul dataLayer'dan değerlendirilemez`,
|
|
931
|
+
ops: { EQUALS: "değerine eşit", CONTAINS: "içeren", STARTS_WITH: "ile başlayan", ENDS_WITH: "ile biten", MATCH_REGEX: "ile eşleşen", LESS: "değerinden küçük", LESS_OR_EQUALS: "veya daha küçük", GREATER: "değerinden büyük", GREATER_OR_EQUALS: "veya daha büyük" },
|
|
932
|
+
nothing: "değer yok",
|
|
933
|
+
triggerFired: (trigger, event) => `${q(trigger)} tetikleyicisi ${q(event)} gönderiminde çalıştı`,
|
|
934
|
+
blocked: (trigger) => `${q(trigger)} istisna tetikleyicisi tarafından engellendi`,
|
|
935
|
+
consentDenied: (type) => `${type} izni gerekiyor; olay tetiklendiğinde bu izin reddedilmiş durumdaydı`,
|
|
936
|
+
fired: "tetikleyici çalıştı ve izin verilmişti; etiketin kendisi veya yapılandırması (ölçüm kimliği, olay adı) hatalı olabilir",
|
|
937
|
+
},
|
|
938
|
+
consequence: {
|
|
939
|
+
missing_event: "Platform bu olayı hiç almadı; hunideki bu adım görünmez ve bir dönüşümse reklam platformu onu sayamaz, teklif de veremez.",
|
|
940
|
+
missing_params: "Olay sayılıyor ama zorunlu ayrıntıları eksik; gelir, para birimi veya ürünler raporlara hiç ulaşmıyor.",
|
|
941
|
+
duplicate: "Tek bir işlem birkaç kez sayılıyor; sayılar ve dönüşüm toplamları şişiyor, reklam platformları olmayan satışlara teklif veriyor.",
|
|
942
|
+
purchase_value_invalid: "Satın alma değeri kullanılabilir bir sayı değil; gelir sıfır yazılıyor, ROAS raporları ve değere dayalı teklifler yanlış.",
|
|
943
|
+
purchase_currency_invalid: "Para birimi platformların tanıdığı bir kod değil; gelir ya düşüyor ya da yanlış kurdan çevriliyor.",
|
|
944
|
+
purchase_items_empty: "Satın almada ürün yok; ürün raporları, katalog akışları ve dinamik yeniden pazarlama hiç satış görmüyor.",
|
|
945
|
+
purchase_mismatch: "Google ve Meta aynı sipariş için farklı gelir aldı; biri yanlış sayıyı raporluyor ve ona göre teklif veriyor.",
|
|
946
|
+
campaign_lost_redirect: "Bir yönlendirme kampanya parametrelerini siliyor; ücretli tıklamalar doğrudan trafik sayılıyor, kampanyalar sattıklarının karşılığını alamıyor.",
|
|
947
|
+
campaign_missing_in_hits: "Açılış sayfası kampanya parametrelerini korudu ama istek onları bildirmedi; ziyaret doğrudan trafiğe yazılıyor.",
|
|
948
|
+
campaign_params: "Kampanya parametreleri açılış yönlendirmesinden geçip isteklere ulaştı; ücretli tıklamalar kendi kampanyalarına yazılıyor.",
|
|
949
|
+
event_id_reused: "İki farklı olay tek bir olay kimliğini paylaşıyor; platform ilkini tutup diğerini sessizce atıyor, gerçek bir olay kayboluyor.",
|
|
950
|
+
event_id_mismatch: "Bu olayın tarayıcı ve sunucu kopyaları farklı kimlik taşıyor; Meta ikisini eşleştiremiyor ve dönüşümü iki kez sayıyor.",
|
|
951
|
+
event_id_not_forwarded: "Sunucu container'ını besleyen GA4 isteğinde olay kimliği yok; sunucu kopyası pikselle eşleşemiyor ve iki kez sayılıyor.",
|
|
952
|
+
dedup_id_missing: "Olay tarayıcıdan olay kimliği olmadan çıktı ve site bir sunucu container'ı kullanıyor; sunucu da gönderirse iki kez sayılır.",
|
|
953
|
+
server_side: "Bazı olaylar sitenin kendi sunucusundan geçiyor; bu rapor tarayıcının gönderdiğini görür, sunucunun ilettiğini değil.",
|
|
954
|
+
server_endpoint: "Sitenin alan adında bir sunucu container'ı yanıt veriyor; reklam platformlarına ilettiği olaylar burada görünmez.",
|
|
955
|
+
consent_default_missing: "Google etiketleri onay varsayılanı olmadan çalışıyor; her ziyaretçi sorulmadan onay vermiş gibi davranıyorlar.",
|
|
956
|
+
consent_default_late: "İlk Google isteği onay varsayılanı ayarlanmadan çıktı; o istek ziyaretçinin seçimini yok saydı.",
|
|
957
|
+
consent_v2_missing: "Onay varsayılanında v2 sinyalleri yok; AEA ve Birleşik Krallık trafiğinde Google reklam kişiselleştirmeyi ve dönüşüm ölçümünü durdurabilir.",
|
|
958
|
+
consent_v2_update: "Ziyaretçi kabul ettikten sonra v2 sinyalleri reddedilmiş kaldı; onay verenler için bile Google Ads dönüşümleri ve yeniden pazarlama kapalı.",
|
|
959
|
+
before_consent: "Olay ziyaretçi seçim yapmadan gönderildi; platform, onay vermemiş ziyaretçilerden veri alıyor.",
|
|
960
|
+
after_reject: "Olay ziyaretçi Reddet'e tıkladıktan sonra da gönderildi; izleme açık bir redde rağmen sürüyor.",
|
|
961
|
+
reject_ignored: "Reddetmenin ardından bir onay güncellemesi her şeye yine izin verdi; reddet düğmesi göstermelik.",
|
|
962
|
+
reject_button_failed: "Reddet düğmesi hiçbir şey yapmadı ve banner açık kaldı; ziyaretçi izlemeyi reddedemiyor.",
|
|
963
|
+
cookies_before_consent: "İzleme çerezleri ziyaretçi seçim yapmadan yazıldı; çerezler onay alınmadan kuruluyor.",
|
|
964
|
+
cookies_after_reject: "İzleme çerezleri ziyaretçi reddettikten sonra yazıldı; red kararına uyulmuyor.",
|
|
965
|
+
pii: "Kişisel veri siteden korunmasız çıktı: düz metin bir e-posta adresi veya reklam eşleştirme verisi artık platformun kayıtlarında.",
|
|
966
|
+
pii_datalayer: "dataLayer karma yapılmamış kişisel veri tutuyor; sayfadaki her betik bunu okuyabilir, yalnızca ihtiyaç duyan etiket değil.",
|
|
967
|
+
journey_incomplete: "Tarayıcı bu yolculuğu bitiremedi; o noktadan sonraki her olay, dönüşüm dâhil, doğrulanmamış durumda.",
|
|
968
|
+
unplanned_events: "Planda olmayan olaylar gönderiliyor: ya plan güncel değil ya da etiketler kimsenin istemediği şeyler gönderiyor.",
|
|
969
|
+
planned_out_of_scope: "Plandaki bazı olaylar bu çalıştırmanın kontrol etmediği platformlarda; durumları bilinmiyor.",
|
|
970
|
+
matches_plan: "Plandaki bu olaylar, planın istediği her şeyle birlikte gönderildi.",
|
|
971
|
+
},
|
|
972
|
+
fix: {
|
|
973
|
+
missing_event: "Bu olayın etiketinin var olduğunu, doğru tetikleyiciyle çalıştığını ve onay ya da bir istisna tarafından engellenmediğini kontrol edin; container dışa aktarımı verildiyse GTM bölümü etiketi adıyla gösterir. Sonra bu yolculuğu yeniden çalıştırın.",
|
|
974
|
+
missing_params: "Eksik parametreleri bu sayfa ve ekranda olayın arkasındaki dataLayer gönderimine ekleyin ve etiketin onları okuduğundan emin olun. Doğrulamak için yolculuğu yeniden çalıştırın.",
|
|
975
|
+
duplicate: "İkinci göndereni bulun: iki gönderim, iki etiket ya da iki kez çalışan bir tetikleyici. Birini kaldırın veya etikete olay başına bir kez çalışma koruması ekleyin.",
|
|
976
|
+
purchase_value_invalid: "Değeri 49.90 gibi düz bir sayı olarak gönderin; para birimi işareti ve binlik ayırıcı olmasın, ücretli bir sipariş için asla 0 olmasın.",
|
|
977
|
+
purchase_currency_invalid: "Para birimini sipariş verisinden, USD, EUR veya TRY gibi büyük harfli 3 harfli bir ISO 4217 kodu olarak gönderin.",
|
|
978
|
+
purchase_items_empty: "Satın alma gönderimindeki ürün listesini siparişin kalemlerinden (id, ad, fiyat, adet) doldurun ve etikette eşleyin.",
|
|
979
|
+
purchase_mismatch: "İki etiketin de aynı sipariş alanlarını okumasını sağlayın; genellikle biri ara toplamı ya da farklı bir para birimini okur. Sonra bir siparişi iki platformda da karşılaştırın.",
|
|
980
|
+
campaign_lost_redirect: "Yönlendirmenin sorgu dizesini korumasını sağlayın ya da ücretli trafiği doğrudan son adrese indirin.",
|
|
981
|
+
campaign_missing_in_hits: "Etiketin açılış adresini parametreleriyle birlikte eksiksiz bildirmesini sağlayın; bir sayfa URL'si geçersiz kılması ya da geç dolan bir page_location değişkeni olup olmadığına bakın.",
|
|
982
|
+
campaign_params: "Düzeltilecek bir şey yok. Açılış sayfaları değiştiğinde yönlendirmeleri yeniden kontrol edin.",
|
|
983
|
+
event_id_reused: "Her olay için yeni bir olay kimliği üretin; sayfa yüklemesi başına bir kez değil.",
|
|
984
|
+
event_id_mismatch: "Piksel olayı ve sunucu kopyası için tek bir olay kimliği kullanın: aynı değeri iki etikete de verin.",
|
|
985
|
+
event_id_not_forwarded: "Sunucu container'ının Conversions API olayına dönüştürdüğü GA4 olayına, pikselin kimliğini taşıyan bir event_id parametresi ekleyin.",
|
|
986
|
+
dedup_id_missing: "Tarayıcı olayına bir olay kimliği ekleyin ve aynı kimliği sunucudan da gönderin; platform ikisini böyle eşleştirir.",
|
|
987
|
+
server_side: "Tarayıcı tarafında düzeltilecek bir şey yok. Sunucunun ilettiği olayları platformun kendi test araçlarında doğrulayın.",
|
|
988
|
+
server_endpoint: "Tarayıcı tarafında düzeltilecek bir şey yok. Sunucu container'ının neyi ilettiğini kendi önizleme modunda kontrol edin.",
|
|
989
|
+
consent_default_missing: "Herhangi bir Google etiketi yüklenmeden önce, genellikle onay banner'ının betiğinde veya bir GTM şablonunda, bir Consent Mode varsayılanı ayarlayın (yasanın gerektirdiği yerde hepsi reddedilmiş).",
|
|
990
|
+
consent_default_late: "Onay varsayılanını Google etiketinin önüne alın: gtm.js veya gtag.js yüklenmeden önce çalışmalı.",
|
|
991
|
+
consent_v2_missing: "Onay varsayılanına ad_storage ve analytics_storage'ın yanına ad_user_data ve ad_personalization sinyallerini ekleyin.",
|
|
992
|
+
consent_v2_update: "Banner'ın ziyaretçi kabul ettikten sonra gönderdiği onay güncellemesinde ad_user_data ve ad_personalization iznini verin.",
|
|
993
|
+
before_consent: "Etikete bir onay kontrolü ekleyin (etiketin onay ayarları ya da ek bir onay tetikleyicisi) veya onu yalnızca banner seçiminden sonra çalıştırın.",
|
|
994
|
+
after_reject: "Etiketin reddi dikkate almasını sağlayın: etikette bir onay kontrolü ya da onay reddedildiğinde devreye giren bir engelleme tetikleyicisi.",
|
|
995
|
+
reject_ignored: "Banner'ın reddet işleyicisini düzeltin: her sinyali reddedilmiş olarak güncellesin ve sonrasında asla izin vermesin.",
|
|
996
|
+
reject_button_failed: "Banner'ın reddet düğmesini düzeltin: banner'ı kapatmalı ve reddi saklamalı; tıklamada bir betik hatası olup olmadığına bakın.",
|
|
997
|
+
cookies_before_consent: "Bu çerezleri yazan etiketleri yalnızca onaydan sonra yükleyin ya da ziyaretçi seçim yapana kadar çerezsiz modda çalıştırın.",
|
|
998
|
+
cookies_after_reject: "Onay reddedildiğinde bu çerezleri yazan etiketleri engelleyin ve ziyaretçi reddettiğinde önceden yazılmış çerezleri silin.",
|
|
999
|
+
pii: "E-postayı veya kullanıcı verisini istekten çıkarın ya da etiket göndermeden önce SHA-256 ile karma yapın; etiketin okuduğu URL'leri ve form alanlarını kontrol edin.",
|
|
1000
|
+
pii_datalayer: "Kullanıcı verisini dataLayer'a karma yapılmış olarak gönderin ya da yalnızca ihtiyaç duyan etiketle sınırlayıp ardından temizleyin.",
|
|
1001
|
+
journey_incomplete: "Tarayıcının neden durduğunu nottan okuyun (engellenen bir tıklama, bulunamayan bir öğe, bir hata), sayfayı ya da adımı düzeltin ve yolculuğu yeniden çalıştırın.",
|
|
1002
|
+
unplanned_events: "İstenen olayları ölçüm planına ekleyin ya da onları gönderen etiketleri kaldırın.",
|
|
1003
|
+
planned_out_of_scope: "Kontrol edilmeleri için platformlarını bir sonraki çalıştırmanın sağlayıcılarına ekleyin.",
|
|
1004
|
+
matches_plan: "Düzeltilecek bir şey yok.",
|
|
1005
|
+
},
|
|
1006
|
+
// Dil fark etmeksizin aynı: kategori bir etiket, çevirisi categoryLabel'da.
|
|
1007
|
+
category: {
|
|
1008
|
+
missing_event: "money",
|
|
1009
|
+
missing_params: "money",
|
|
1010
|
+
duplicate: "money",
|
|
1011
|
+
purchase_value_invalid: "money",
|
|
1012
|
+
purchase_currency_invalid: "money",
|
|
1013
|
+
purchase_items_empty: "money",
|
|
1014
|
+
purchase_mismatch: "money",
|
|
1015
|
+
campaign_lost_redirect: "money",
|
|
1016
|
+
campaign_missing_in_hits: "money",
|
|
1017
|
+
campaign_params: "money",
|
|
1018
|
+
event_id_reused: "money",
|
|
1019
|
+
event_id_mismatch: "money",
|
|
1020
|
+
event_id_not_forwarded: "money",
|
|
1021
|
+
dedup_id_missing: "money",
|
|
1022
|
+
server_side: "hygiene",
|
|
1023
|
+
server_endpoint: "hygiene",
|
|
1024
|
+
consent_default_missing: "legal",
|
|
1025
|
+
consent_default_late: "legal",
|
|
1026
|
+
consent_v2_missing: "legal",
|
|
1027
|
+
consent_v2_update: "money",
|
|
1028
|
+
before_consent: "legal",
|
|
1029
|
+
after_reject: "legal",
|
|
1030
|
+
reject_ignored: "legal",
|
|
1031
|
+
reject_button_failed: "legal",
|
|
1032
|
+
cookies_before_consent: "legal",
|
|
1033
|
+
cookies_after_reject: "legal",
|
|
1034
|
+
pii: "legal",
|
|
1035
|
+
pii_datalayer: "legal",
|
|
1036
|
+
journey_incomplete: "hygiene",
|
|
1037
|
+
unplanned_events: "hygiene",
|
|
1038
|
+
planned_out_of_scope: "hygiene",
|
|
1039
|
+
matches_plan: "hygiene",
|
|
1040
|
+
},
|
|
1041
|
+
categoryLabel: { money: "Para", legal: "Hukuki", hygiene: "Veri kalitesi" },
|
|
1042
|
+
verdict: {
|
|
1043
|
+
status: { pass: "Geçti", fail: "Kaldı", attention: "Dikkat gerekiyor" },
|
|
1044
|
+
headline: {
|
|
1045
|
+
fail_broken: (v) => {
|
|
1046
|
+
const c = countsOf(v);
|
|
1047
|
+
const risks = c.risk ? `; ${c.risk} onay veya kişisel veri riski Tag Manager'ın sorumluluğunda` : "";
|
|
1048
|
+
return `${c.broken} bozuk bulgu düzeltilmeden sayılara güvenilemez${risks}.`;
|
|
1049
|
+
},
|
|
1050
|
+
fail_incomplete: (v) => {
|
|
1051
|
+
const j = journeysOf(v);
|
|
1052
|
+
const where = j.total ? `${j.total} yolculuktan ${j.incomplete} tanesi tamamlanmadı` : "Bir yolculuk tamamlanmadı";
|
|
1053
|
+
return `${where}; durduğu noktadan sonraki olaylar, dönüşüm dâhil, doğrulanmadı.`;
|
|
1054
|
+
},
|
|
1055
|
+
attention_risk: (v) => {
|
|
1056
|
+
const c = countsOf(v);
|
|
1057
|
+
const warnings = c.warning ? `; ${c.warning} uyarı da sayıları bozuyor` : "";
|
|
1058
|
+
return `Bozuk bir şey yok, ancak ${c.risk} onay veya kişisel veri riskinin Tag Manager'da düzeltilmesi gerekiyor${warnings}.`;
|
|
1059
|
+
},
|
|
1060
|
+
attention_warning: (v) => {
|
|
1061
|
+
const c = countsOf(v);
|
|
1062
|
+
return `Bozuk bir şey yok, ancak ${c.warning} uyarı sayıları veya kapsamı bozuyor; düzeltilmesi gerekiyor.`;
|
|
1063
|
+
},
|
|
1064
|
+
attention_no_hits: (v) => {
|
|
1065
|
+
const j = journeysOf(v);
|
|
1066
|
+
return `${j.total ? `${j.total} yolculuk çalıştı` : "Yolculuklar çalıştı"}, ancak hiç izleme isteği yakalanmadı; bu yüzden hiçbir şey kontrol edilemedi.`;
|
|
1067
|
+
},
|
|
1068
|
+
attention_nothing_tested: () => "Hiç yolculuk çalışmadı ve hiçbir şey yakalanmadı; henüz değerlendirilecek bir şey yok.",
|
|
1069
|
+
pass: (v) => {
|
|
1070
|
+
const j = journeysOf(v);
|
|
1071
|
+
return `Plandaki tüm olaylar ${j.total ? `${j.total} yolculuğun tamamında` : "test edilen her yolculukta"} doğru çalıştı; düzeltilecek bir şey yok.`;
|
|
1072
|
+
},
|
|
1073
|
+
},
|
|
1074
|
+
},
|
|
1075
|
+
html: {
|
|
1076
|
+
skip: "Rapora atla",
|
|
1077
|
+
eyebrow: "İzleme denetimi",
|
|
1078
|
+
countsLabel: "Önem derecesine göre bulgular",
|
|
1079
|
+
themeAuto: "Tema: sistemi izler",
|
|
1080
|
+
themeLight: "Tema: açık",
|
|
1081
|
+
themeDark: "Tema: koyu",
|
|
1082
|
+
newTab: "yeni sekmede açılır",
|
|
1083
|
+
ownerSplit: (parts) => `${parts.join(", ")}.`,
|
|
1084
|
+
forOwner: { developer: (n) => `geliştirici için ${n}`, gtm: (n) => `Tag Manager için ${n}`, marketing: (n) => `pazarlama için ${n}` },
|
|
1085
|
+
aiSummary: "Yapay zekâ özeti",
|
|
1086
|
+
platformsChecked: "Kontrol edilen platformlar",
|
|
1087
|
+
campaignCheck: "Kampanya kontrolü",
|
|
1088
|
+
campaignChecked: "Açılış sayfasında UTM, gclid ve fbclid",
|
|
1089
|
+
consentModeOn: "consent mode açık",
|
|
1090
|
+
consentModeSeen: "Consent Mode komutları görüldü",
|
|
1091
|
+
cmpBanner: "banner",
|
|
1092
|
+
scenariosRun: (n) => `${n} senaryo`,
|
|
1093
|
+
runsAllCompleted: (n) => `${n} çalıştırma, hepsi tamamlandı`,
|
|
1094
|
+
runsCompleted: (done, n) => `${n} çalıştırmadan ${done} tanesi tamamlandı`,
|
|
1095
|
+
fixFirst: "Önce ne düzeltilmeli",
|
|
1096
|
+
fixFirstLead: "Düzeltecek kişiye göre gruplandı, en çok puan kazandıran önce. Her satır bulgusunu açar.",
|
|
1097
|
+
pointsToRecover: (n) => `düzeltilince +${n} puan`,
|
|
1098
|
+
nothingFor: (owner) => `Bu çalıştırmada ${owner} için bir şey yok.`,
|
|
1099
|
+
moreInFindings: (n) => `Bulgular'da ${n} tane daha →`,
|
|
1100
|
+
working: "Çalışanlar",
|
|
1101
|
+
whatWasChecked: "Neler kontrol edildi",
|
|
1102
|
+
nothingVerified: "Bu çalıştırmada hiçbir şey doğrulanmadı.",
|
|
1103
|
+
coverageVerified: (done, total, pct) => `Planlanan ${total} olaydan ${done} tanesi doğrulandı${pct === null ? "" : ` (%${pct})`}.`,
|
|
1104
|
+
allRuns: (n) => `${n} çalıştırmanın hepsi`,
|
|
1105
|
+
onlyOn: (places) => `yalnızca ${places.join(", ")}`,
|
|
1106
|
+
journeysLead: "Yürünen adımlar, yakalanan istekler ve her çalıştırmayı gösteren sorun kartları.",
|
|
1107
|
+
viewport: "Görünüm",
|
|
1108
|
+
hitsCol: "İstekler",
|
|
1109
|
+
trend: "Eğilim",
|
|
1110
|
+
trendLead: "Kayıtlı çalıştırmalardaki sorun sayıları, en eski solda. İçi boş nokta, bir yolculuğun tamamlanmadığı çalıştırmadır.",
|
|
1111
|
+
trendDirection: { improving: "İyileşiyor", worsening: "Kötüleşiyor", flat: "Değişmedi" },
|
|
1112
|
+
trendSpan: (n, first, last) => `${n} çalıştırmada, ${first} – ${last}`,
|
|
1113
|
+
runIncomplete: "bir yolculuk tamamlanmadı",
|
|
1114
|
+
flapping: "Görüldü, gitti, geri geldi",
|
|
1115
|
+
seenIn: (n, total) => `${total} çalıştırmanın ${n} tanesinde görüldü`,
|
|
1116
|
+
openLongest: "En uzun süredir açık",
|
|
1117
|
+
openSince: (date, runs, places) => `${date} tarihinden beri açık · ${runs} çalıştırma · ${places} yer`,
|
|
1118
|
+
score: "Veri kalitesi puanı",
|
|
1119
|
+
scoreLead: "100 eksi her bozuk sorun için 15, her risk için 10 ve her uyarı için 5; dönüşüm olaylarında iki katı.",
|
|
1120
|
+
scoreLost: (n) => `${n} puan kaybedildi`,
|
|
1121
|
+
findingsLead: "Kanıtı, nerede olduğunu ve düzeltmenin nasıl doğrulanacağını görmek için bir bulguyu açın.",
|
|
1122
|
+
okInOverview: (n) => `${n} sorunsuz sonuç genel bakışta listeleniyor.`,
|
|
1123
|
+
noModel: "Bu çalıştırmada model açıklaması yok. Aşağıdaki kanıt, sorumlu ve doğrulama bağlantıları için gerekmiyor.",
|
|
1124
|
+
accepted: "Kabul edildi",
|
|
1125
|
+
acceptedNote: "Bu bulgu temel çizgide: biliniyor ve çalıştırmanın aleyhine sayılmıyor.",
|
|
1126
|
+
pageUnknown: "sayfa: bilinmiyor",
|
|
1127
|
+
alsoFineOn: "Şurada sorunsuz:",
|
|
1128
|
+
findingLink: "Bulgu →",
|
|
1129
|
+
consentMode: "Consent Mode",
|
|
1130
|
+
consentTiming: (ms, before, v2, missing) => `Varsayılan ${ms === null ? "ilk sayfada" : `ilk sayfanın ${Math.round(ms)}. milisaniyesinde`} ayarlandı${before === null ? "" : before ? ", ilk Google isteğinden önce" : ", ilk Google isteğinden sonra"} · v2 sinyalleri ${v2 ? "mevcut" : `eksik: ${missing.join(", ")}`}.`,
|
|
1131
|
+
consentNoDefault: "Bu yolculukta Consent Mode varsayılanı gönderilmedi.",
|
|
1132
|
+
consentResent: (n) => `Varsayılan ve güncelleme ${n} sayfa yüklemesinde daha yeniden gönderildi; kayıtlı tercih her seferinde geri yükleniyor.`,
|
|
1133
|
+
consentOnHit: "Bu istekteki onay:",
|
|
1134
|
+
scenariosLead: (cmp) => `Ana sayfa her onay seçeneği için bir kez açıldı; yanıt ${cmp === "banner" ? "bandın düğmeleriyle" : cmp} verildi. Her hücre, etiketin o seçimden sonra gönderdiği istek sayısıdır.`,
|
|
1135
|
+
scenariosLegend: "İşaretli sayı, ziyaretçinin reddettiği veridir. \"cookieless\", depolama reddedilmişken atılan Consent Mode ping'idir ve izinlidir.",
|
|
1136
|
+
cellCookieless: "cookieless",
|
|
1137
|
+
cellAdDenied: "ad storage reddedilmiş",
|
|
1138
|
+
cellWithCookies: "çerezlerle",
|
|
1139
|
+
cellProblem: "sorun:",
|
|
1140
|
+
cellShouldNot: "gönderilmemeliydi",
|
|
1141
|
+
stepsTitle: "Adımlar ve her birinin gönderdiği istekler",
|
|
1142
|
+
stepsLead: "Parametreler, dataLayer gönderimleri ve istekler için bir satırı açın. Bulgusu olan satırlar açık.",
|
|
1143
|
+
stepCol: "Adım",
|
|
1144
|
+
timeCol: "Zaman",
|
|
1145
|
+
hasFinding: (sev) => `${sev.toLowerCase()} bulgusu var`,
|
|
1146
|
+
stepDetails: (hits, pushes) => `Ayrıntılar · ${hits} istek · ${pushes} dataLayer`,
|
|
1147
|
+
hitsInStep: "Bu adımdaki istekler",
|
|
1148
|
+
blockedBy: (platform) => `denetim engelledi: yerel olarak yanıtlandı, ${platform} platformuna hiç ulaşmadı`,
|
|
1149
|
+
problems: (n) => `${n} sorun`,
|
|
1150
|
+
funnel: "Beklenen ve gözlenen",
|
|
1151
|
+
funnelLead: (observed, expected, ok) => `Beklenen ${expected} olaydan ${observed} tanesi tetiklendi, ${ok} tanesi tüm zorunlu parametrelerle.`,
|
|
1152
|
+
funnelBreaks: (event) => `Huni ${event} olayında kopuyor.`,
|
|
1153
|
+
conversion: "dönüşüm",
|
|
1154
|
+
sent: "gönderildi",
|
|
1155
|
+
notSent: "gönderilmedi",
|
|
1156
|
+
firstAt: "İlk görüldüğü yer",
|
|
1157
|
+
page: "Sayfa",
|
|
1158
|
+
params: (list) => `${list.join(", ")} olmadan`,
|
|
1159
|
+
paramsShort: "param.",
|
|
1160
|
+
parity: "Platform tutarlılığı",
|
|
1161
|
+
parityLead: "Aynı olayın iki platformdaki hâli ve aralarındaki farklar.",
|
|
1162
|
+
perPlatform: "Platforma göre",
|
|
1163
|
+
difference: "Fark",
|
|
1164
|
+
agree: "uyumlu",
|
|
1165
|
+
mismatch: { count: "sayı farklı", value: "değer farklı", currency: "para birimi farklı", value_missing: "değer yalnızca bir tarafta" },
|
|
1166
|
+
onlyOnPlatform: "Yalnızca tek platformda:",
|
|
1167
|
+
detailsCol: "Ayrıntılar",
|
|
1168
|
+
coverageLegend: "✓ parametreleriyle gönderildi · param.: zorunlu parametreler olmadan gönderildi · ✗ gönderilmedi · – bu yolculukta beklenmiyor",
|
|
1169
|
+
needs: (list) => `gerekli: ${list.join(", ")}`,
|
|
1170
|
+
notExpected: "beklenmiyor",
|
|
1171
|
+
conversions: "Dönüşüm bütünlüğü",
|
|
1172
|
+
conversionsLead: (passed, total) => `${total} satın almadan ${passed} tanesi tüm kontrolleri geçiyor.`,
|
|
1173
|
+
conversionChecks: { value: "Değer", currency: "Para birimi", transactionId: "Sipariş no", items: "Ürünler", duplicate: "Tekrarsız", parity: "Tutarlılık", eventId: "Olay kimliği" },
|
|
1174
|
+
orderId: "Sipariş",
|
|
1175
|
+
value: "Değer",
|
|
1176
|
+
pass: "geçti",
|
|
1177
|
+
fail: "başarısız",
|
|
1178
|
+
notApplicable: "uygulanamaz",
|
|
1179
|
+
seenOn: "Görüldüğü sayfalar",
|
|
1180
|
+
checkedNotSeen: "Kontrol edildi, görülmedi",
|
|
1181
|
+
neverSeen: (list) => `Kontrol edildi ama hiç görülmedi: ${list}. Hiçbir sayfada onlara istek gitmedi.`,
|
|
1182
|
+
timing: "Zamanlama",
|
|
1183
|
+
timingLead: "Her çalıştırmanın süresi ve her adımın ilk isteğinin ne kadar geç geldiği. Denetimin kendi bekleme süresi dahildir.",
|
|
1184
|
+
duration: "Süre",
|
|
1185
|
+
medianFirstHit: "Ortanca ilk istek",
|
|
1186
|
+
slowestHit: "En yavaş istek",
|
|
1187
|
+
planChanges: "Plan değişiklikleri",
|
|
1188
|
+
},
|
|
415
1189
|
};
|
|
416
1190
|
|
|
417
1191
|
export const LANGUAGES = { en, tr };
|