@cavuno/board 3.2.0 → 4.1.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 +433 -0
- package/README.md +6 -2
- package/dist/{_spec-nkWAraS0.d.mts → _spec-BZDv2dc5.d.mts} +100 -68
- package/dist/{_spec-nkWAraS0.d.ts → _spec-BZDv2dc5.d.ts} +100 -68
- package/dist/bin.mjs +7 -2
- package/dist/{blog-iV9XEIGf.d.ts → blog-BHx6iH3Z.d.ts} +1 -1
- package/dist/{blog-DGBHmExV.d.mts → blog-DyDvyQrI.d.mts} +1 -1
- package/dist/{board-JhdUWIoq.d.ts → board-BF3Qao6J.d.mts} +7 -6
- package/dist/{board-BJbXd_9_.d.mts → board-BTEZ0uiI.d.ts} +7 -6
- package/dist/breadcrumbs-SGaWth6C.d.ts +372 -0
- package/dist/breadcrumbs-icxRVydh.d.mts +372 -0
- package/dist/chunk-BGKNXG4H.mjs +146 -0
- package/dist/{chunk-NXY3OWGF.mjs → chunk-T2KC6XGV.mjs} +1 -1
- package/dist/{chunk-STE77MAT.mjs → chunk-YEAQ3JEI.mjs} +143 -134
- package/dist/doctor.js +1 -1
- package/dist/doctor.mjs +1 -1
- package/dist/filters.d.mts +25 -20
- package/dist/filters.d.ts +25 -20
- package/dist/filters.js +3 -692
- package/dist/filters.mjs +3 -29
- package/dist/format.d.mts +57 -231
- package/dist/format.d.ts +57 -231
- package/dist/format.js +327 -968
- package/dist/format.mjs +207 -264
- package/dist/go.js +11 -1
- package/dist/go.mjs +1 -1
- package/dist/index.d.mts +67 -76
- package/dist/index.d.ts +67 -76
- package/dist/index.js +45 -36
- package/dist/index.mjs +45 -36
- package/dist/{jobs-BiEvL9d7.d.ts → jobs-BX6d_sdd.d.mts} +4 -4
- package/dist/{jobs-lVvKCBCU.d.mts → jobs-BbLJfz1z.d.ts} +4 -4
- package/dist/paths.d.mts +89 -1
- package/dist/paths.d.ts +89 -1
- package/dist/paths.js +62 -14
- package/dist/paths.mjs +11 -3
- package/dist/route-contract.js +23 -13
- package/dist/route-contract.mjs +2 -2
- package/dist/{search-CCyFWPi3.d.mts → search-7B-mVRNA.d.ts} +14 -3
- package/dist/{search-CyRvVMUp.d.ts → search-OKrdAHv8.d.mts} +14 -3
- package/dist/seo.d.mts +30 -29
- package/dist/seo.d.ts +30 -29
- package/dist/seo.js +197 -718
- package/dist/seo.mjs +26 -24
- package/dist/server.d.mts +5 -5
- package/dist/server.d.ts +5 -5
- package/dist/sitemap.d.mts +5 -5
- package/dist/sitemap.d.ts +5 -5
- package/dist/sitemap.js +25 -14
- package/dist/sitemap.mjs +3 -2
- package/dist/skills.js +1 -1
- package/dist/skills.mjs +1 -1
- package/dist/suggest.d.mts +2 -2
- package/dist/suggest.d.ts +2 -2
- package/dist/suggest.js +17 -3
- package/dist/suggest.mjs +17 -3
- package/dist/well-known.js +23 -13
- package/dist/well-known.mjs +2 -2
- package/package.json +2 -4
- package/skills/cavuno-board-api-client/SKILL.md +42 -0
- package/skills/cavuno-board-applications/SKILL.md +4 -1
- package/skills/cavuno-board-filters/SKILL.md +11 -12
- package/skills/cavuno-board-format/SKILL.md +68 -56
- package/skills/cavuno-board-i18n/SKILL.md +102 -21
- package/skills/cavuno-board-search-suggestions/SKILL.md +8 -3
- package/skills/cavuno-board-seo/BLOG.md +4 -1
- package/skills/cavuno-board-seo/JOB_AND_BREADCRUMBS.md +5 -2
- package/skills/cavuno-board-seo/LISTING.md +35 -12
- package/skills/cavuno-board-seo/SALARY.md +83 -18
- package/skills/cavuno-board-seo/SKILL.md +3 -2
- package/skills/manifest.json +3 -3
- package/dist/breadcrumbs-1hMjcsqA.d.mts +0 -171
- package/dist/breadcrumbs-DexU07TT.d.ts +0 -171
- package/dist/chunk-IJCJ26SQ.mjs +0 -596
- package/dist/chunk-L7ZOYWHW.mjs +0 -98
- package/dist/chunk-LUGJWOT7.mjs +0 -96
- package/dist/ui-copy-CCkz6CVF.d.mts +0 -230
- package/dist/ui-copy-CCkz6CVF.d.ts +0 -230
package/dist/seo.js
CHANGED
|
@@ -32,9 +32,8 @@ __export(seo_exports, {
|
|
|
32
32
|
createJobPostingJsonLd: () => createJobPostingJsonLd,
|
|
33
33
|
crossAxisSalaryJsonLd: () => crossAxisSalaryJsonLd,
|
|
34
34
|
faqJsonLd: () => faqJsonLd,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
formatUsd: () => formatUsd,
|
|
35
|
+
formatSalaryStat: () => formatSalaryStat,
|
|
36
|
+
formatSalaryStatRange: () => formatSalaryStatRange,
|
|
38
37
|
itemListJsonLd: () => itemListJsonLd,
|
|
39
38
|
listingHead: () => listingHead,
|
|
40
39
|
listingJsonLd: () => listingJsonLd,
|
|
@@ -161,490 +160,56 @@ function buildAbsoluteUrl(origin, path) {
|
|
|
161
160
|
}
|
|
162
161
|
}
|
|
163
162
|
|
|
164
|
-
// src/
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
headingJobs: "Jobs",
|
|
174
|
-
keywordLabel: "Keyword",
|
|
175
|
-
keywordPlaceholder: "Search jobs\u2026",
|
|
176
|
-
locationLabel: "Location",
|
|
177
|
-
locationPlaceholder: "City or region",
|
|
178
|
-
workplacePlaceholder: "Workplace",
|
|
179
|
-
anyWorkplaceLabel: "Any workplace",
|
|
180
|
-
typePlaceholder: "Type",
|
|
181
|
-
anyTypeLabel: "Any type",
|
|
182
|
-
sortPlaceholder: "Sort",
|
|
183
|
-
loadMoreLabel: "Load more",
|
|
184
|
-
noJobsMatchText: "No jobs match \u2014 try clearing a filter."
|
|
185
|
-
},
|
|
186
|
-
jobDetail: {
|
|
187
|
-
categoriesHeading: "Categories",
|
|
188
|
-
skillsHeading: "Skills",
|
|
189
|
-
additionalDetailsHeading: "Additional details",
|
|
190
|
-
customFieldYesLabel: "Yes",
|
|
191
|
-
customFieldNoLabel: "No",
|
|
192
|
-
locationsLabel: "Locations",
|
|
193
|
-
workPermitsLabel: "Work permits",
|
|
194
|
-
timezonesLabel: "Timezones",
|
|
195
|
-
educationLabel: "Education",
|
|
196
|
-
experienceLabel: "Experience",
|
|
197
|
-
worldwideLabel: "Worldwide",
|
|
198
|
-
noExperienceRequiredLabel: "No experience required",
|
|
199
|
-
experienceYears: (years) => `${years}+ years`,
|
|
200
|
-
posted: (published) => `Posted ${published}`,
|
|
201
|
-
noDescriptionText: "No description provided.",
|
|
202
|
-
viewCompanyProfileLabel: "View company profile",
|
|
203
|
-
similarJobsHeading: "Similar jobs",
|
|
204
|
-
breadcrumbAriaLabel: "Breadcrumb"
|
|
205
|
-
},
|
|
206
|
-
apply: {
|
|
207
|
-
applyButtonText: "Apply for this job",
|
|
208
|
-
applyingLabel: "Applying\u2026",
|
|
209
|
-
applyOnEmployerSiteLabel: "Apply on employer site",
|
|
210
|
-
signInToApplyLabel: "Sign in to apply",
|
|
211
|
-
verifyEmailToApplyLabel: "Verify email to apply",
|
|
212
|
-
appliedViewApplicationsLabel: "Applied \u2014 view applications",
|
|
213
|
-
applicationSubmitError: "Something went wrong. Please try again."
|
|
214
|
-
},
|
|
215
|
-
alerts: {
|
|
216
|
-
jobAlertTitle: "Get job alerts",
|
|
217
|
-
jobAlertEmailPlaceholder: "you@example.com",
|
|
218
|
-
jobAlertButtonText: "Get alerts",
|
|
219
|
-
subscribingLabel: "Subscribing\u2026",
|
|
220
|
-
jobAlertSuccessToast: "If this email isn't already subscribed, we've sent a confirmation link \u2014 check your inbox.",
|
|
221
|
-
jobAlertErrorToast: "Something went wrong. Please try again.",
|
|
222
|
-
sectionAriaLabel: "Job alerts",
|
|
223
|
-
emailAriaLabel: "email",
|
|
224
|
-
submitAriaLabel: "get job alerts"
|
|
225
|
-
},
|
|
226
|
-
copyLink: {
|
|
227
|
-
copyLinkLabel: "Copy link",
|
|
228
|
-
copiedLabel: "Copied",
|
|
229
|
-
ariaLabel: "copy link"
|
|
230
|
-
},
|
|
231
|
-
salary: {
|
|
232
|
-
comparisonHeadlineAverage: "Average salary",
|
|
233
|
-
perYearSuffix: "/ year",
|
|
234
|
-
comparisonPercentile25Label: "25th percentile",
|
|
235
|
-
medianLabel: "Median",
|
|
236
|
-
comparisonPercentile75Label: "75th percentile",
|
|
237
|
-
basedOnLabel: "Based on",
|
|
238
|
-
seniorityTableHeaderLevel: "Level",
|
|
239
|
-
seniorityTableHeaderAvg: "Average",
|
|
240
|
-
boardBaselineLabel: "Board baseline",
|
|
241
|
-
seniorityTableHeaderDiff: "vs. board",
|
|
242
|
-
faqHeading: "Frequently asked questions"
|
|
243
|
-
},
|
|
244
|
-
nav: {
|
|
245
|
-
home: "Jobs",
|
|
246
|
-
companies: "Companies",
|
|
247
|
-
pricing: "Pricing",
|
|
248
|
-
talent: "Talent",
|
|
249
|
-
post: "Post a job",
|
|
250
|
-
blog: "Blog"
|
|
251
|
-
},
|
|
252
|
-
footer: {
|
|
253
|
-
forCandidatesHeading: "For Candidates",
|
|
254
|
-
forCompaniesHeading: "For Companies",
|
|
255
|
-
resourcesHeading: "Resources",
|
|
256
|
-
aboutHeading: "About",
|
|
257
|
-
websiteLabel: "Website",
|
|
258
|
-
aboutLabel: "About",
|
|
259
|
-
contactLabel: "Contact us",
|
|
260
|
-
locationsLabel: "Locations",
|
|
261
|
-
salariesLabel: "Salaries",
|
|
262
|
-
sitemapLabel: "Sitemap",
|
|
263
|
-
termsOfServiceLabel: "Terms of Service",
|
|
264
|
-
privacyPolicyLabel: "Privacy Policy",
|
|
265
|
-
cookiePolicyLabel: "Cookie Policy",
|
|
266
|
-
impressumLabel: "Impressum",
|
|
267
|
-
allRightsReservedText: "All rights reserved.",
|
|
268
|
-
copyrightPrefix: "\xA9 {{year}} {{board_name}}.",
|
|
269
|
-
poweredByText: "Powered by",
|
|
270
|
-
defaultDescription: "Discover the latest roles from {{board_name}}."
|
|
271
|
-
},
|
|
272
|
-
breadcrumbs: {
|
|
273
|
-
home: "Home",
|
|
274
|
-
jobs: "Jobs",
|
|
275
|
-
locations: "Locations",
|
|
276
|
-
salaries: "Salaries",
|
|
277
|
-
companies: "Companies",
|
|
278
|
-
skills: "Skills",
|
|
279
|
-
titles: "Titles",
|
|
280
|
-
blog: "Blog",
|
|
281
|
-
post: "Post a Job",
|
|
282
|
-
pricing: "Pricing",
|
|
283
|
-
about: "About",
|
|
284
|
-
impressum: "Impressum",
|
|
285
|
-
termsOfService: "Terms of Service",
|
|
286
|
-
privacyPolicy: "Privacy Policy",
|
|
287
|
-
cookiePolicy: "Cookie Policy",
|
|
288
|
-
talent: "Talent"
|
|
289
|
-
},
|
|
290
|
-
pagination: {
|
|
291
|
-
ariaLabel: "Pagination",
|
|
292
|
-
previousLabel: "Previous",
|
|
293
|
-
nextLabel: "Next"
|
|
294
|
-
},
|
|
295
|
-
blog: {
|
|
296
|
-
bylineLabel: "By",
|
|
297
|
-
readingTimeLabel: "min read",
|
|
298
|
-
searchLabel: "Search",
|
|
299
|
-
searchPlaceholder: "Search posts...",
|
|
300
|
-
clearButtonLabel: "Clear search",
|
|
301
|
-
tagFilterLabel: "Topics",
|
|
302
|
-
tagFilterAllLabel: "All",
|
|
303
|
-
emptyTitle: "No matching posts",
|
|
304
|
-
emptyDescription: "Try adjusting your search or clearing your filters.",
|
|
305
|
-
emptyResetLabel: "Clear filters"
|
|
306
|
-
},
|
|
307
|
-
entity: {
|
|
308
|
-
jobSingular: "job",
|
|
309
|
-
jobPlural: "jobs",
|
|
310
|
-
companySingular: "company",
|
|
311
|
-
companyPlural: "companies"
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
var DE = {
|
|
315
|
-
jobCard: {
|
|
316
|
-
featuredLabel: "Hervorgehoben",
|
|
317
|
-
aiRankedLabel: "KI-sortiert",
|
|
318
|
-
sortNewestLabel: "Neueste zuerst",
|
|
319
|
-
sortSalaryHighLabel: "Gehalt: absteigend"
|
|
320
|
-
},
|
|
321
|
-
jobSearch: {
|
|
322
|
-
headingJobs: "Jobs",
|
|
323
|
-
keywordLabel: "Stichwort",
|
|
324
|
-
keywordPlaceholder: "Jobtitel oder -beschreibungen suchen",
|
|
325
|
-
locationLabel: "Standort",
|
|
326
|
-
locationPlaceholder: "Stadt, Land oder Region",
|
|
327
|
-
workplacePlaceholder: "Arbeitsmodell",
|
|
328
|
-
anyWorkplaceLabel: "Alle Arbeitsmodelle",
|
|
329
|
-
typePlaceholder: "Anstellungsart",
|
|
330
|
-
anyTypeLabel: "Alle Anstellungsarten",
|
|
331
|
-
sortPlaceholder: "Sortieren",
|
|
332
|
-
loadMoreLabel: "Mehr laden",
|
|
333
|
-
noJobsMatchText: "Keine passenden Jobs \u2014 setze einen Filter zur\xFCck."
|
|
334
|
-
},
|
|
335
|
-
jobDetail: {
|
|
336
|
-
categoriesHeading: "Kategorien",
|
|
337
|
-
skillsHeading: "F\xE4higkeiten",
|
|
338
|
-
additionalDetailsHeading: "Weitere Details",
|
|
339
|
-
customFieldYesLabel: "Ja",
|
|
340
|
-
customFieldNoLabel: "Nein",
|
|
341
|
-
locationsLabel: "Standorte",
|
|
342
|
-
workPermitsLabel: "Arbeitserlaubnis",
|
|
343
|
-
timezonesLabel: "Zeitzonen",
|
|
344
|
-
educationLabel: "Ausbildung",
|
|
345
|
-
experienceLabel: "Berufserfahrung",
|
|
346
|
-
worldwideLabel: "Weltweit",
|
|
347
|
-
noExperienceRequiredLabel: "Keine Berufserfahrung erforderlich",
|
|
348
|
-
experienceYears: (years) => `${years}+ Jahre`,
|
|
349
|
-
posted: (published) => `Ver\xF6ffentlicht ${published}`,
|
|
350
|
-
noDescriptionText: "Keine Beschreibung vorhanden.",
|
|
351
|
-
viewCompanyProfileLabel: "Unternehmensprofil ansehen",
|
|
352
|
-
similarJobsHeading: "\xC4hnliche Jobs",
|
|
353
|
-
breadcrumbAriaLabel: "Seitenpfad"
|
|
354
|
-
},
|
|
355
|
-
apply: {
|
|
356
|
-
applyButtonText: "Jetzt bewerben",
|
|
357
|
-
applyingLabel: "Wird gesendet \u2026",
|
|
358
|
-
applyOnEmployerSiteLabel: "Beim Unternehmen bewerben",
|
|
359
|
-
signInToApplyLabel: "Zum Bewerben anmelden",
|
|
360
|
-
verifyEmailToApplyLabel: "E-Mail best\xE4tigen, um dich zu bewerben",
|
|
361
|
-
appliedViewApplicationsLabel: "Beworben \u2014 Bewerbungen ansehen",
|
|
362
|
-
applicationSubmitError: "Etwas ist schiefgelaufen. Bitte versuche es erneut."
|
|
363
|
-
},
|
|
364
|
-
alerts: {
|
|
365
|
-
jobAlertTitle: "Job-Benachrichtigungen erhalten",
|
|
366
|
-
jobAlertEmailPlaceholder: "name@beispiel.de",
|
|
367
|
-
jobAlertButtonText: "Abonnieren",
|
|
368
|
-
subscribingLabel: "Wird abonniert \u2026",
|
|
369
|
-
jobAlertSuccessToast: "Falls diese E-Mail noch nicht abonniert ist, haben wir einen Best\xE4tigungslink gesendet \u2014 pr\xFCfe deinen Posteingang.",
|
|
370
|
-
jobAlertErrorToast: "Etwas ist schiefgelaufen. Bitte versuche es erneut.",
|
|
371
|
-
sectionAriaLabel: "Job-Benachrichtigungen",
|
|
372
|
-
emailAriaLabel: "E-Mail",
|
|
373
|
-
submitAriaLabel: "Job-Benachrichtigungen erhalten"
|
|
374
|
-
},
|
|
375
|
-
copyLink: {
|
|
376
|
-
copyLinkLabel: "Link kopieren",
|
|
377
|
-
copiedLabel: "Kopiert",
|
|
378
|
-
ariaLabel: "Link kopieren"
|
|
379
|
-
},
|
|
380
|
-
salary: {
|
|
381
|
-
comparisonHeadlineAverage: "Durchschnittsgehalt",
|
|
382
|
-
perYearSuffix: "/ Jahr",
|
|
383
|
-
comparisonPercentile25Label: "25. Perzentil",
|
|
384
|
-
medianLabel: "Median",
|
|
385
|
-
comparisonPercentile75Label: "75. Perzentil",
|
|
386
|
-
basedOnLabel: "Basierend auf",
|
|
387
|
-
seniorityTableHeaderLevel: "Erfahrungslevel",
|
|
388
|
-
seniorityTableHeaderAvg: "Durchschnitt",
|
|
389
|
-
boardBaselineLabel: "Board-Durchschnitt",
|
|
390
|
-
seniorityTableHeaderDiff: "vs. Board",
|
|
391
|
-
faqHeading: "H\xE4ufig gestellte Fragen"
|
|
392
|
-
},
|
|
393
|
-
nav: {
|
|
394
|
-
home: "Jobs",
|
|
395
|
-
companies: "Unternehmen",
|
|
396
|
-
pricing: "Preise",
|
|
397
|
-
talent: "Talente",
|
|
398
|
-
post: "Job ver\xF6ffentlichen",
|
|
399
|
-
blog: "Blog"
|
|
400
|
-
},
|
|
401
|
-
footer: {
|
|
402
|
-
forCandidatesHeading: "F\xFCr Kandidaten",
|
|
403
|
-
forCompaniesHeading: "F\xFCr Unternehmen",
|
|
404
|
-
resourcesHeading: "Ressourcen",
|
|
405
|
-
aboutHeading: "\xDCber uns",
|
|
406
|
-
websiteLabel: "Website",
|
|
407
|
-
aboutLabel: "\xDCber uns",
|
|
408
|
-
contactLabel: "Kontakt",
|
|
409
|
-
locationsLabel: "Standorte",
|
|
410
|
-
salariesLabel: "Geh\xE4lter",
|
|
411
|
-
sitemapLabel: "Sitemap",
|
|
412
|
-
termsOfServiceLabel: "Nutzungsbedingungen",
|
|
413
|
-
privacyPolicyLabel: "Datenschutzerkl\xE4rung",
|
|
414
|
-
cookiePolicyLabel: "Cookie-Richtlinie",
|
|
415
|
-
impressumLabel: "Impressum",
|
|
416
|
-
allRightsReservedText: "Alle Rechte vorbehalten.",
|
|
417
|
-
copyrightPrefix: "\xA9 {{year}} {{board_name}}.",
|
|
418
|
-
poweredByText: "Bereitgestellt von",
|
|
419
|
-
defaultDescription: "Entdecke die neuesten Stellen von {{board_name}}."
|
|
420
|
-
},
|
|
421
|
-
breadcrumbs: {
|
|
422
|
-
home: "Startseite",
|
|
423
|
-
jobs: "Jobs",
|
|
424
|
-
locations: "Standorte",
|
|
425
|
-
salaries: "Geh\xE4lter",
|
|
426
|
-
companies: "Unternehmen",
|
|
427
|
-
skills: "F\xE4higkeiten",
|
|
428
|
-
titles: "Berufsbezeichnungen",
|
|
429
|
-
blog: "Blog",
|
|
430
|
-
post: "Job ver\xF6ffentlichen",
|
|
431
|
-
pricing: "Preise",
|
|
432
|
-
about: "\xDCber uns",
|
|
433
|
-
impressum: "Impressum",
|
|
434
|
-
termsOfService: "Nutzungsbedingungen",
|
|
435
|
-
privacyPolicy: "Datenschutzerkl\xE4rung",
|
|
436
|
-
cookiePolicy: "Cookie-Richtlinie",
|
|
437
|
-
talent: "Talente"
|
|
438
|
-
},
|
|
439
|
-
pagination: {
|
|
440
|
-
ariaLabel: "Seitennummerierung",
|
|
441
|
-
previousLabel: "Zur\xFCck",
|
|
442
|
-
nextLabel: "Weiter"
|
|
443
|
-
},
|
|
444
|
-
blog: {
|
|
445
|
-
bylineLabel: "Von",
|
|
446
|
-
readingTimeLabel: "Minuten Lesezeit",
|
|
447
|
-
searchLabel: "Suche",
|
|
448
|
-
searchPlaceholder: "Artikel suchen...",
|
|
449
|
-
clearButtonLabel: "Suche leeren",
|
|
450
|
-
tagFilterLabel: "Themen",
|
|
451
|
-
tagFilterAllLabel: "Alle",
|
|
452
|
-
emptyTitle: "Keine passenden Artikel gefunden",
|
|
453
|
-
emptyDescription: "Versuche, deine Suche anzupassen oder die Filter zur\xFCckzusetzen.",
|
|
454
|
-
emptyResetLabel: "Filter zur\xFCcksetzen"
|
|
455
|
-
},
|
|
456
|
-
entity: {
|
|
457
|
-
jobSingular: "Job",
|
|
458
|
-
jobPlural: "Jobs",
|
|
459
|
-
companySingular: "Unternehmen",
|
|
460
|
-
companyPlural: "Unternehmen"
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
var FR = {
|
|
464
|
-
jobCard: {
|
|
465
|
-
featuredLabel: "\xC0 la une",
|
|
466
|
-
aiRankedLabel: "Classement IA",
|
|
467
|
-
sortNewestLabel: "Plus r\xE9centes",
|
|
468
|
-
sortSalaryHighLabel: "Salaire : d\xE9croissant"
|
|
469
|
-
},
|
|
470
|
-
jobSearch: {
|
|
471
|
-
headingJobs: "Offres d'emploi",
|
|
472
|
-
keywordLabel: "Mot-cl\xE9",
|
|
473
|
-
keywordPlaceholder: "Rechercher une offre\u2026",
|
|
474
|
-
locationLabel: "Lieu",
|
|
475
|
-
locationPlaceholder: "Ville ou r\xE9gion",
|
|
476
|
-
workplacePlaceholder: "Mode de travail",
|
|
477
|
-
anyWorkplaceLabel: "Tous les modes de travail",
|
|
478
|
-
typePlaceholder: "Type de contrat",
|
|
479
|
-
anyTypeLabel: "Tous les types",
|
|
480
|
-
sortPlaceholder: "Trier",
|
|
481
|
-
loadMoreLabel: "Voir plus",
|
|
482
|
-
noJobsMatchText: "Aucune offre ne correspond \u2014 essayez de retirer un filtre."
|
|
483
|
-
},
|
|
484
|
-
jobDetail: {
|
|
485
|
-
categoriesHeading: "Cat\xE9gories",
|
|
486
|
-
skillsHeading: "Comp\xE9tences",
|
|
487
|
-
additionalDetailsHeading: "Informations compl\xE9mentaires",
|
|
488
|
-
customFieldYesLabel: "Oui",
|
|
489
|
-
customFieldNoLabel: "Non",
|
|
490
|
-
locationsLabel: "Lieux",
|
|
491
|
-
workPermitsLabel: "Permis de travail",
|
|
492
|
-
timezonesLabel: "Fuseaux horaires",
|
|
493
|
-
educationLabel: "Formation",
|
|
494
|
-
experienceLabel: "Exp\xE9rience",
|
|
495
|
-
worldwideLabel: "Monde entier",
|
|
496
|
-
noExperienceRequiredLabel: "Aucune exp\xE9rience requise",
|
|
497
|
-
experienceYears: (years) => `${years}+ ans`,
|
|
498
|
-
posted: (published) => `Publi\xE9e ${published}`,
|
|
499
|
-
noDescriptionText: "Aucune description fournie.",
|
|
500
|
-
viewCompanyProfileLabel: "Voir le profil de l'entreprise",
|
|
501
|
-
similarJobsHeading: "Offres similaires",
|
|
502
|
-
breadcrumbAriaLabel: "Fil d'Ariane"
|
|
503
|
-
},
|
|
504
|
-
apply: {
|
|
505
|
-
applyButtonText: "Postuler \xE0 cette offre",
|
|
506
|
-
applyingLabel: "Envoi en cours\u2026",
|
|
507
|
-
applyOnEmployerSiteLabel: "Postuler sur le site de l'employeur",
|
|
508
|
-
signInToApplyLabel: "Connectez-vous pour postuler",
|
|
509
|
-
verifyEmailToApplyLabel: "V\xE9rifiez votre e-mail pour postuler",
|
|
510
|
-
appliedViewApplicationsLabel: "Candidature envoy\xE9e \u2014 voir mes candidatures",
|
|
511
|
-
applicationSubmitError: "Une erreur est survenue. Veuillez r\xE9essayer."
|
|
512
|
-
},
|
|
513
|
-
alerts: {
|
|
514
|
-
jobAlertTitle: "Recevoir des alertes emploi",
|
|
515
|
-
jobAlertEmailPlaceholder: "vous@exemple.fr",
|
|
516
|
-
jobAlertButtonText: "Activer les alertes",
|
|
517
|
-
subscribingLabel: "Abonnement en cours\u2026",
|
|
518
|
-
jobAlertSuccessToast: "Si cet e-mail n'est pas d\xE9j\xE0 abonn\xE9, nous avons envoy\xE9 un lien de confirmation \u2014 v\xE9rifiez votre bo\xEEte de r\xE9ception.",
|
|
519
|
-
jobAlertErrorToast: "Une erreur est survenue. Veuillez r\xE9essayer.",
|
|
520
|
-
sectionAriaLabel: "Alertes emploi",
|
|
521
|
-
emailAriaLabel: "e-mail",
|
|
522
|
-
submitAriaLabel: "recevoir des alertes emploi"
|
|
523
|
-
},
|
|
524
|
-
copyLink: {
|
|
525
|
-
copyLinkLabel: "Copier le lien",
|
|
526
|
-
copiedLabel: "Copi\xE9",
|
|
527
|
-
ariaLabel: "copier le lien"
|
|
528
|
-
},
|
|
529
|
-
salary: {
|
|
530
|
-
comparisonHeadlineAverage: "Salaire moyen",
|
|
531
|
-
perYearSuffix: "/ an",
|
|
532
|
-
comparisonPercentile25Label: "25e percentile",
|
|
533
|
-
medianLabel: "M\xE9diane",
|
|
534
|
-
comparisonPercentile75Label: "75e percentile",
|
|
535
|
-
basedOnLabel: "Bas\xE9 sur",
|
|
536
|
-
seniorityTableHeaderLevel: "Niveau",
|
|
537
|
-
seniorityTableHeaderAvg: "Moyenne",
|
|
538
|
-
boardBaselineLabel: "R\xE9f\xE9rence du site",
|
|
539
|
-
seniorityTableHeaderDiff: "vs site",
|
|
540
|
-
faqHeading: "Questions fr\xE9quentes"
|
|
541
|
-
},
|
|
542
|
-
nav: {
|
|
543
|
-
home: "Offres",
|
|
544
|
-
companies: "Entreprises",
|
|
545
|
-
pricing: "Tarifs",
|
|
546
|
-
talent: "Talents",
|
|
547
|
-
post: "Publier une offre",
|
|
548
|
-
blog: "Blog"
|
|
549
|
-
},
|
|
550
|
-
footer: {
|
|
551
|
-
forCandidatesHeading: "Pour les candidats",
|
|
552
|
-
forCompaniesHeading: "Pour les entreprises",
|
|
553
|
-
resourcesHeading: "Ressources",
|
|
554
|
-
aboutHeading: "\xC0 propos",
|
|
555
|
-
websiteLabel: "Site web",
|
|
556
|
-
aboutLabel: "\xC0 propos",
|
|
557
|
-
contactLabel: "Nous contacter",
|
|
558
|
-
locationsLabel: "Lieux",
|
|
559
|
-
salariesLabel: "Salaires",
|
|
560
|
-
sitemapLabel: "Plan du site",
|
|
561
|
-
termsOfServiceLabel: "Conditions d'utilisation",
|
|
562
|
-
privacyPolicyLabel: "Politique de confidentialit\xE9",
|
|
563
|
-
cookiePolicyLabel: "Politique de cookies",
|
|
564
|
-
impressumLabel: "Mentions l\xE9gales",
|
|
565
|
-
allRightsReservedText: "Tous droits r\xE9serv\xE9s.",
|
|
566
|
-
copyrightPrefix: "\xA9 {{year}} {{board_name}}.",
|
|
567
|
-
poweredByText: "Propuls\xE9 par",
|
|
568
|
-
defaultDescription: "D\xE9couvrez les derni\xE8res offres de {{board_name}}."
|
|
569
|
-
},
|
|
570
|
-
breadcrumbs: {
|
|
571
|
-
home: "Accueil",
|
|
572
|
-
jobs: "Offres",
|
|
573
|
-
locations: "Lieux",
|
|
574
|
-
salaries: "Salaires",
|
|
575
|
-
companies: "Entreprises",
|
|
576
|
-
skills: "Comp\xE9tences",
|
|
577
|
-
titles: "Intitul\xE9s de poste",
|
|
578
|
-
blog: "Blog",
|
|
579
|
-
post: "Publier une offre",
|
|
580
|
-
pricing: "Tarifs",
|
|
581
|
-
about: "\xC0 propos",
|
|
582
|
-
impressum: "Mentions l\xE9gales",
|
|
583
|
-
termsOfService: "Conditions d'utilisation",
|
|
584
|
-
privacyPolicy: "Politique de confidentialit\xE9",
|
|
585
|
-
cookiePolicy: "Politique de cookies",
|
|
586
|
-
talent: "Talents"
|
|
587
|
-
},
|
|
588
|
-
pagination: {
|
|
589
|
-
ariaLabel: "Pagination",
|
|
590
|
-
previousLabel: "Pr\xE9c\xE9dent",
|
|
591
|
-
nextLabel: "Suivant"
|
|
592
|
-
},
|
|
593
|
-
blog: {
|
|
594
|
-
bylineLabel: "Par",
|
|
595
|
-
readingTimeLabel: "min de lecture",
|
|
596
|
-
searchLabel: "Recherche",
|
|
597
|
-
searchPlaceholder: "Rechercher un article...",
|
|
598
|
-
clearButtonLabel: "Effacer la recherche",
|
|
599
|
-
tagFilterLabel: "Th\xE8mes",
|
|
600
|
-
tagFilterAllLabel: "Tous",
|
|
601
|
-
emptyTitle: "Aucun article correspondant",
|
|
602
|
-
emptyDescription: "Essayez de modifier votre recherche ou de r\xE9initialiser les filtres.",
|
|
603
|
-
emptyResetLabel: "R\xE9initialiser les filtres"
|
|
604
|
-
},
|
|
605
|
-
entity: {
|
|
606
|
-
jobSingular: "offre",
|
|
607
|
-
jobPlural: "offres",
|
|
608
|
-
companySingular: "entreprise",
|
|
609
|
-
companyPlural: "entreprises"
|
|
610
|
-
}
|
|
611
|
-
};
|
|
612
|
-
var CATALOGS = { en: EN, de: DE, fr: FR };
|
|
613
|
-
function mergeGroup(group, overrides) {
|
|
614
|
-
if (!overrides) return group;
|
|
615
|
-
const out = { ...group };
|
|
616
|
-
for (const [key, value] of Object.entries(group)) {
|
|
617
|
-
if (typeof value !== "string") continue;
|
|
618
|
-
const override = overrides[key];
|
|
619
|
-
if (typeof override === "string" && override.trim() !== "") {
|
|
620
|
-
out[key] = override;
|
|
621
|
-
}
|
|
163
|
+
// src/paths/index.ts
|
|
164
|
+
function encodePathSegment(segment) {
|
|
165
|
+
try {
|
|
166
|
+
return encodeURIComponent(decodeURIComponent(segment)).replace(
|
|
167
|
+
/%3A/gi,
|
|
168
|
+
":"
|
|
169
|
+
);
|
|
170
|
+
} catch {
|
|
171
|
+
return encodeURIComponent(segment).replace(/%3A/gi, ":");
|
|
622
172
|
}
|
|
623
|
-
return out;
|
|
624
173
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
174
|
+
function jobDetailPath(companySlug, jobSlug) {
|
|
175
|
+
return `/companies/${encodePathSegment(companySlug)}/jobs/${encodePathSegment(jobSlug)}`;
|
|
176
|
+
}
|
|
177
|
+
function jobsCategoryPath(categorySlug) {
|
|
178
|
+
return `/jobs/${encodePathSegment(categorySlug)}`;
|
|
179
|
+
}
|
|
180
|
+
function jobsLocationPath(placeSlug) {
|
|
181
|
+
return `/jobs/locations/${encodePathSegment(placeSlug)}`;
|
|
182
|
+
}
|
|
183
|
+
function jobsLocationCategoryPath(placeSlug, categorySlug) {
|
|
184
|
+
return `${jobsLocationPath(placeSlug)}/${encodePathSegment(categorySlug)}`;
|
|
185
|
+
}
|
|
186
|
+
var BOARD_PATHS = {
|
|
187
|
+
home: "/",
|
|
188
|
+
jobs: "/jobs",
|
|
189
|
+
companies: "/companies",
|
|
190
|
+
salaries: "/salaries",
|
|
191
|
+
salaryCompanies: "/salaries/companies",
|
|
192
|
+
salaryTitles: "/salaries/titles",
|
|
193
|
+
salarySkills: "/salaries/skills",
|
|
194
|
+
salaryLocations: "/salaries/locations",
|
|
195
|
+
blog: "/blog",
|
|
196
|
+
about: "/about",
|
|
197
|
+
privacyPolicy: "/privacy-policy",
|
|
198
|
+
termsOfService: "/terms-of-service",
|
|
199
|
+
cookiePolicy: "/cookie-policy",
|
|
200
|
+
impressum: "/impressum",
|
|
201
|
+
talent: "/talent",
|
|
202
|
+
employers: "/employers",
|
|
203
|
+
/**
|
|
204
|
+
* Alert-email surfaces. Promoted out of raw literals in
|
|
205
|
+
* the job-alerts composer so /go indirection and email composition share
|
|
206
|
+
* one definition.
|
|
207
|
+
*/
|
|
208
|
+
alertsManage: "/alerts/manage",
|
|
209
|
+
alertsConfirm: "/alerts/confirm"
|
|
639
210
|
};
|
|
640
|
-
function
|
|
641
|
-
|
|
642
|
-
if (!labels) return catalog;
|
|
643
|
-
const resolved = {};
|
|
644
|
-
for (const [group, source] of Object.entries(GROUP_OVERRIDE_SOURCE)) {
|
|
645
|
-
resolved[group] = mergeGroup(catalog[group], labels[source]);
|
|
646
|
-
}
|
|
647
|
-
return resolved;
|
|
211
|
+
function boardUrl(origin, path) {
|
|
212
|
+
return `${origin.replace(/\/+$/, "")}${path}`;
|
|
648
213
|
}
|
|
649
214
|
|
|
650
215
|
// src/seo/breadcrumbs.ts
|
|
@@ -690,25 +255,29 @@ function resolveBreadcrumbHref(href, origin) {
|
|
|
690
255
|
function isAbsoluteUrl(href) {
|
|
691
256
|
return /^https?:\/\//i.test(href);
|
|
692
257
|
}
|
|
693
|
-
function buildJobBreadcrumbs(job
|
|
694
|
-
const copy = uiCopy(language, labels).breadcrumbs;
|
|
258
|
+
function buildJobBreadcrumbs(job) {
|
|
695
259
|
const crumbs = [
|
|
696
|
-
{
|
|
697
|
-
{
|
|
260
|
+
{ kind: "home", path: BOARD_PATHS.home },
|
|
261
|
+
{ kind: "jobs", path: BOARD_PATHS.jobs }
|
|
698
262
|
];
|
|
699
263
|
let lastPlaceSlug = null;
|
|
700
264
|
for (const place of job.placeHierarchy) {
|
|
701
265
|
lastPlaceSlug = place.slug;
|
|
702
|
-
crumbs.push({
|
|
266
|
+
crumbs.push({
|
|
267
|
+
kind: "place",
|
|
268
|
+
name: place.name,
|
|
269
|
+
path: jobsLocationPath(place.slug)
|
|
270
|
+
});
|
|
703
271
|
}
|
|
704
272
|
const primaryCategory = job.categories[0];
|
|
705
273
|
if (primaryCategory) {
|
|
706
274
|
crumbs.push({
|
|
275
|
+
kind: "category",
|
|
707
276
|
name: primaryCategory.name,
|
|
708
|
-
path: lastPlaceSlug ?
|
|
277
|
+
path: lastPlaceSlug ? jobsLocationCategoryPath(lastPlaceSlug, primaryCategory.slug) : jobsCategoryPath(primaryCategory.slug)
|
|
709
278
|
});
|
|
710
279
|
}
|
|
711
|
-
crumbs.push({ name: job.title });
|
|
280
|
+
crumbs.push({ kind: "job", name: job.title });
|
|
712
281
|
return crumbs;
|
|
713
282
|
}
|
|
714
283
|
|
|
@@ -1165,9 +734,8 @@ function pruneJsonLd(value) {
|
|
|
1165
734
|
|
|
1166
735
|
// src/seo/listing.ts
|
|
1167
736
|
function listingHead(options) {
|
|
1168
|
-
const
|
|
1169
|
-
const
|
|
1170
|
-
const description = `Browse ${countPrefix}${options.heading.toLowerCase()} on ${options.boardName}.`;
|
|
737
|
+
const title = options.title;
|
|
738
|
+
const description = options.description;
|
|
1171
739
|
const url = `${options.origin}${options.path}`;
|
|
1172
740
|
return {
|
|
1173
741
|
meta: [
|
|
@@ -1182,174 +750,112 @@ function listingHead(options) {
|
|
|
1182
750
|
};
|
|
1183
751
|
}
|
|
1184
752
|
function listingJsonLd(options) {
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
{
|
|
753
|
+
const objects = [];
|
|
754
|
+
if (options.breadcrumbs.length >= 2) {
|
|
755
|
+
objects.push({
|
|
1188
756
|
"@context": "https://schema.org",
|
|
1189
|
-
// Deliberately NOT createBreadcrumbJsonLd (breadcrumbs.ts): listing trails
|
|
1190
|
-
// are code-constructed (never user copy), so the hosted listing page skips
|
|
1191
|
-
// the trim/drop-blank/min-2 gate that module transcribes. Same schema.org
|
|
1192
|
-
// fragment, different (intentional) semantics — do not unify blindly.
|
|
1193
757
|
"@type": "BreadcrumbList",
|
|
1194
758
|
itemListElement: options.breadcrumbs.map((crumb, index) => ({
|
|
1195
759
|
"@type": "ListItem",
|
|
1196
760
|
position: index + 1,
|
|
1197
761
|
name: crumb.name,
|
|
1198
|
-
...crumb.path ? { item:
|
|
762
|
+
...crumb.path ? { item: boardUrl(options.origin, crumb.path) } : {}
|
|
1199
763
|
}))
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
const detailJobs = (options.jobs ?? []).filter(
|
|
767
|
+
(job) => job.company != null && Boolean(job.company.slug)
|
|
768
|
+
);
|
|
769
|
+
if (detailJobs.length > 0) {
|
|
1203
770
|
objects.push({
|
|
1204
771
|
"@context": "https://schema.org",
|
|
1205
772
|
"@type": "ItemList",
|
|
1206
|
-
itemListElement:
|
|
773
|
+
itemListElement: detailJobs.map((job, index) => ({
|
|
1207
774
|
"@type": "ListItem",
|
|
1208
775
|
position: index + 1,
|
|
1209
|
-
url:
|
|
776
|
+
url: boardUrl(
|
|
777
|
+
options.origin,
|
|
778
|
+
jobDetailPath(job.company.slug, job.slug)
|
|
779
|
+
)
|
|
1210
780
|
}))
|
|
1211
781
|
});
|
|
1212
782
|
}
|
|
1213
783
|
return objects;
|
|
1214
784
|
}
|
|
1215
785
|
|
|
1216
|
-
// src/format/
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
associate: "Associate",
|
|
1229
|
-
mid_level: "Mid-level",
|
|
1230
|
-
senior: "Senior",
|
|
1231
|
-
lead: "Lead",
|
|
1232
|
-
principal: "Principal",
|
|
1233
|
-
director: "Director",
|
|
1234
|
-
executive: "Executive"
|
|
1235
|
-
},
|
|
1236
|
-
frames: {
|
|
1237
|
-
entitySalariesTitle: ({ entity, range }) => `${entity} Salaries (${range}/yr)`,
|
|
1238
|
-
salariesInPlaceTitle: ({ place, range }) => `Salaries in ${place} (${range}/yr)`,
|
|
1239
|
-
salariesInPlaceTitleNoRange: ({ place }) => `Salaries in ${place}`,
|
|
1240
|
-
entitySalariesInPlaceTitle: ({ entity, place, range }) => `${entity} Salaries in ${place} (${range}/yr)`,
|
|
1241
|
-
companySalariesTitle: ({ company, range }) => `${company} Salaries${range ? ` (${range}/yr)` : ""}`,
|
|
1242
|
-
companyCategorySalariesTitle: ({ company, category, range }) => `${company} ${category} Salaries${range ? ` (${range}/yr)` : ""}`,
|
|
1243
|
-
professionalsEarn: ({ entity, range, count }) => `${entity} professionals earn ${range}/yr on average across ${count} job postings.`,
|
|
1244
|
-
rolesPay: ({ entity, range, count }) => `${entity} roles pay ${range}/yr on average across ${count} job postings.`,
|
|
1245
|
-
professionalsInLocationEarn: ({ entity, place, range, count }) => `${entity} professionals in ${place} earn ${range}/yr on average across ${count} job postings.`,
|
|
1246
|
-
seniorityRange: ({ lowLabel, lowAmount, highLabel, highAmount }) => `${lowLabel} roles start at ${lowAmount}, ${highLabel} roles reach ${highAmount}.`,
|
|
1247
|
-
seniorityRangeWhile: ({ lowLabel, lowAmount, highLabel, highAmount }) => `${lowLabel} salaries start at ${lowAmount}, while ${highLabel} roles reach ${highAmount}.`,
|
|
1248
|
-
compareAcrossTopPaying: ({ count }) => `Compare across ${count} top-paying ${count === 1 ? "company" : "companies"}.`,
|
|
1249
|
-
compareAcrossTop: ({ count }) => `Compare across ${count} top ${count === 1 ? "company" : "companies"}.`,
|
|
1250
|
-
boardWideAverage: ({ entity, range }) => `Board-wide ${entity} average: ${range}/yr.`,
|
|
1251
|
-
averageSalaryInCity: ({ place, range, count }) => `Average salary in ${place} is ${range}/yr across ${count} jobs. Browse salary data by title and skill.`,
|
|
1252
|
-
browseLocationsInRegion: ({ count, place }) => `Browse salary data across ${count} locations in ${place}. Compare salaries by title, skill, and company.`,
|
|
1253
|
-
companyPays: ({ company, range, count }) => `${company} pays ${range}/yr on average across ${count} job postings.`,
|
|
1254
|
-
breakdownAcrossCategories: ({ count }) => `Breakdown across ${count} job ${count === 1 ? "category" : "categories"}.`,
|
|
1255
|
-
compareWithSimilar: ({ count }) => `Compare with ${count} similar ${count === 1 ? "company" : "companies"}.`,
|
|
1256
|
-
salaryInfoFor: ({ company, board }) => `Salary information for ${company} on ${board}.`,
|
|
1257
|
-
categoryRolesAtCompanyPay: ({ category, company, range, count }) => `${category} roles at ${company} pay ${range}/yr based on ${count} job postings.`,
|
|
1258
|
-
categorySalaryDataFor: ({ category, company, board }) => `${category} salary data for ${company} on ${board}.`
|
|
1259
|
-
}
|
|
1260
|
-
};
|
|
1261
|
-
var DE2 = {
|
|
1262
|
-
timeframe: {
|
|
1263
|
-
per_year: "pro Jahr",
|
|
1264
|
-
per_month: "pro Monat",
|
|
1265
|
-
per_week: "pro Woche",
|
|
1266
|
-
per_day: "pro Tag",
|
|
1267
|
-
per_hour: "pro Stunde"
|
|
1268
|
-
},
|
|
1269
|
-
rangePrefix: { from: "ab", upTo: "bis zu" },
|
|
1270
|
-
seniority: {
|
|
1271
|
-
entry_level: "Entry-Level",
|
|
1272
|
-
associate: "Associate",
|
|
1273
|
-
mid_level: "Mid-Level",
|
|
1274
|
-
senior: "Senior",
|
|
1275
|
-
lead: "Lead",
|
|
1276
|
-
principal: "Principal",
|
|
1277
|
-
director: "Director",
|
|
1278
|
-
executive: "F\xFChrungskraft"
|
|
1279
|
-
},
|
|
1280
|
-
frames: {
|
|
1281
|
-
entitySalariesTitle: ({ entity, range }) => `${entity} Geh\xE4lter (${range}/Jahr)`,
|
|
1282
|
-
salariesInPlaceTitle: ({ place, range }) => `Geh\xE4lter in ${place} (${range}/Jahr)`,
|
|
1283
|
-
salariesInPlaceTitleNoRange: ({ place }) => `Geh\xE4lter in ${place}`,
|
|
1284
|
-
entitySalariesInPlaceTitle: ({ entity, place, range }) => `${entity} Geh\xE4lter in ${place} (${range}/Jahr)`,
|
|
1285
|
-
companySalariesTitle: ({ company, range }) => `${company} Geh\xE4lter${range ? ` (${range}/Jahr)` : ""}`,
|
|
1286
|
-
companyCategorySalariesTitle: ({ company, category, range }) => `${company} ${category} Geh\xE4lter${range ? ` (${range}/Jahr)` : ""}`,
|
|
1287
|
-
professionalsEarn: ({ entity, range, count }) => `${entity}-Fachkr\xE4fte verdienen durchschnittlich ${range}/Jahr, basierend auf ${count} Stellenanzeigen.`,
|
|
1288
|
-
rolesPay: ({ entity, range, count }) => `${entity}-Positionen werden mit durchschnittlich ${range}/Jahr verg\xFCtet, basierend auf ${count} Stellenanzeigen.`,
|
|
1289
|
-
professionalsInLocationEarn: ({ entity, place, range, count }) => `${entity}-Fachkr\xE4fte in ${place} verdienen durchschnittlich ${range}/Jahr, basierend auf ${count} Stellenanzeigen.`,
|
|
1290
|
-
seniorityRange: ({ lowLabel, lowAmount, highLabel, highAmount }) => `${lowLabel}-Positionen beginnen bei ${lowAmount}, ${highLabel}-Positionen erreichen ${highAmount}.`,
|
|
1291
|
-
seniorityRangeWhile: ({ lowLabel, lowAmount, highLabel, highAmount }) => `${lowLabel}-Geh\xE4lter beginnen bei ${lowAmount}, w\xE4hrend ${highLabel}-Positionen ${highAmount} erreichen.`,
|
|
1292
|
-
compareAcrossTopPaying: ({ count }) => `Vergleichen Sie ${count} ${count === 1 ? "bestzahlendes" : "bestzahlende"} Unternehmen.`,
|
|
1293
|
-
compareAcrossTop: ({ count }) => `Vergleichen Sie ${count} Top-Unternehmen.`,
|
|
1294
|
-
boardWideAverage: ({ entity, range }) => `Gesamtdurchschnitt ${entity}: ${range}/Jahr.`,
|
|
1295
|
-
averageSalaryInCity: ({ place, range, count }) => `Das Durchschnittsgehalt in ${place} betr\xE4gt ${range}/Jahr, basierend auf ${count} Stellen. Gehaltsdaten nach Titel und F\xE4higkeiten durchsuchen.`,
|
|
1296
|
-
browseLocationsInRegion: ({ count, place }) => `Gehaltsdaten f\xFCr ${count} Standorte in ${place} durchsuchen. Geh\xE4lter nach Titel, F\xE4higkeiten und Unternehmen vergleichen.`,
|
|
1297
|
-
companyPays: ({ company, range, count }) => `${company} zahlt durchschnittlich ${range}/Jahr, basierend auf ${count} Stellenanzeigen.`,
|
|
1298
|
-
breakdownAcrossCategories: ({ count }) => `Aufschl\xFCsselung \xFCber ${count} Job-${count === 1 ? "Kategorie" : "Kategorien"}.`,
|
|
1299
|
-
compareWithSimilar: ({ count }) => `Vergleichen Sie mit ${count} \xE4hnlichen Unternehmen.`,
|
|
1300
|
-
salaryInfoFor: ({ company, board }) => `Gehaltsinformationen f\xFCr ${company} auf ${board}.`,
|
|
1301
|
-
categoryRolesAtCompanyPay: ({ category, company, range, count }) => `${category}-Positionen bei ${company} werden mit ${range}/Jahr verg\xFCtet, basierend auf ${count} Stellenanzeigen.`,
|
|
1302
|
-
categorySalaryDataFor: ({ category, company, board }) => `${category}-Gehaltsdaten f\xFCr ${company} auf ${board}.`
|
|
786
|
+
// src/format/locale.ts
|
|
787
|
+
function normalizeLocale(language) {
|
|
788
|
+
const trimmed = language.trim();
|
|
789
|
+
if (!trimmed) return null;
|
|
790
|
+
try {
|
|
791
|
+
const candidate = trimmed.replace(/_/g, "-");
|
|
792
|
+
const [canonical] = Intl.getCanonicalLocales(candidate);
|
|
793
|
+
if (!canonical) return null;
|
|
794
|
+
const [supported] = Intl.NumberFormat.supportedLocalesOf([canonical]);
|
|
795
|
+
return supported ?? null;
|
|
796
|
+
} catch {
|
|
797
|
+
return null;
|
|
1303
798
|
}
|
|
1304
|
-
};
|
|
1305
|
-
var LEXICONS = { en: EN2, de: DE2 };
|
|
1306
|
-
function getSalaryLexicon(locale) {
|
|
1307
|
-
return locale && LEXICONS[locale] || EN2;
|
|
1308
799
|
}
|
|
1309
800
|
|
|
1310
801
|
// src/seo/salary.ts
|
|
1311
|
-
var
|
|
1312
|
-
function
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
minimumFractionDigits: 0,
|
|
1321
|
-
maximumFractionDigits: 1
|
|
1322
|
-
});
|
|
1323
|
-
compactCurrencyCache.set(language, formatter);
|
|
1324
|
-
return formatter;
|
|
802
|
+
var currencyFormatterCache = /* @__PURE__ */ new Map();
|
|
803
|
+
function notationForMagnitude(...values) {
|
|
804
|
+
let anyFinite = false;
|
|
805
|
+
for (const v of values) {
|
|
806
|
+
if (v == null || !Number.isFinite(v)) continue;
|
|
807
|
+
anyFinite = true;
|
|
808
|
+
if (Math.abs(v) >= 1e3) return "compact";
|
|
809
|
+
}
|
|
810
|
+
return anyFinite ? "standard" : "compact";
|
|
1325
811
|
}
|
|
1326
|
-
function
|
|
812
|
+
function getCurrencyFormatter(language, currencyCode, notation) {
|
|
813
|
+
const key = `${language}:${currencyCode}:${notation}`;
|
|
814
|
+
const cached = currencyFormatterCache.get(key);
|
|
815
|
+
if (cached !== void 0) return cached;
|
|
816
|
+
let formatter;
|
|
1327
817
|
try {
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
818
|
+
const options = {
|
|
819
|
+
style: "currency",
|
|
820
|
+
currency: currencyCode,
|
|
821
|
+
notation
|
|
822
|
+
};
|
|
823
|
+
if (notation === "compact") {
|
|
824
|
+
options.compactDisplay = "short";
|
|
825
|
+
options.minimumFractionDigits = 0;
|
|
826
|
+
options.maximumFractionDigits = 1;
|
|
1337
827
|
}
|
|
1338
|
-
|
|
828
|
+
formatter = new Intl.NumberFormat(language, options);
|
|
829
|
+
} catch {
|
|
830
|
+
formatter = null;
|
|
1339
831
|
}
|
|
832
|
+
currencyFormatterCache.set(key, formatter);
|
|
833
|
+
return formatter;
|
|
1340
834
|
}
|
|
1341
|
-
function
|
|
1342
|
-
|
|
835
|
+
function formatSalaryStat(locale, value, currency, notation) {
|
|
836
|
+
if (!Number.isFinite(value)) return null;
|
|
837
|
+
const currencyCode = currency?.trim().toUpperCase() || null;
|
|
838
|
+
if (!currencyCode) return null;
|
|
839
|
+
const normalized = normalizeLocale(locale);
|
|
840
|
+
if (!normalized) return null;
|
|
841
|
+
const resolved = notation ?? notationForMagnitude(value);
|
|
842
|
+
const formatter = getCurrencyFormatter(normalized, currencyCode, resolved);
|
|
843
|
+
if (!formatter) return null;
|
|
844
|
+
return formatter.format(value);
|
|
1343
845
|
}
|
|
1344
|
-
function
|
|
1345
|
-
if (
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
const
|
|
1349
|
-
if (
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
846
|
+
function formatSalaryStatRange(locale, min, max, currency, notation) {
|
|
847
|
+
if (!Number.isFinite(min) || !Number.isFinite(max)) return null;
|
|
848
|
+
const currencyCode = currency?.trim().toUpperCase() || null;
|
|
849
|
+
if (!currencyCode) return null;
|
|
850
|
+
const normalized = normalizeLocale(locale);
|
|
851
|
+
if (!normalized) return null;
|
|
852
|
+
const resolved = notation ?? notationForMagnitude(min, max);
|
|
853
|
+
const formatter = getCurrencyFormatter(normalized, currencyCode, resolved);
|
|
854
|
+
if (!formatter) return null;
|
|
855
|
+
const low = Math.min(min, max);
|
|
856
|
+
const high = Math.max(min, max);
|
|
857
|
+
if (low === high) return formatter.format(low);
|
|
858
|
+
return formatter.formatRange(low, high);
|
|
1353
859
|
}
|
|
1354
860
|
var SENIORITY_ORDER = [
|
|
1355
861
|
"entry_level",
|
|
@@ -1379,7 +885,7 @@ var yearly = {
|
|
|
1379
885
|
function distribution(name, currency, minValue, maxValue, stats = {}) {
|
|
1380
886
|
return {
|
|
1381
887
|
"@type": "MonetaryAmountDistribution",
|
|
1382
|
-
name,
|
|
888
|
+
...name !== void 0 ? { name } : {},
|
|
1383
889
|
currency,
|
|
1384
890
|
minValue,
|
|
1385
891
|
maxValue,
|
|
@@ -1387,15 +893,19 @@ function distribution(name, currency, minValue, maxValue, stats = {}) {
|
|
|
1387
893
|
...yearly
|
|
1388
894
|
};
|
|
1389
895
|
}
|
|
1390
|
-
function seniorityDistributions(
|
|
1391
|
-
return rows.map(
|
|
1392
|
-
|
|
1393
|
-
|
|
896
|
+
function seniorityDistributions(rows, currency, entity, options) {
|
|
897
|
+
return rows.map((row) => {
|
|
898
|
+
const name = options?.seniorityName?.({
|
|
899
|
+
seniority: row.seniority,
|
|
900
|
+
entity
|
|
901
|
+
});
|
|
902
|
+
return distribution(
|
|
903
|
+
name,
|
|
1394
904
|
currency,
|
|
1395
905
|
row.avgSalaryMin,
|
|
1396
906
|
row.avgSalaryMax
|
|
1397
|
-
)
|
|
1398
|
-
);
|
|
907
|
+
);
|
|
908
|
+
});
|
|
1399
909
|
}
|
|
1400
910
|
function salaryEnvelope(type, name, extra, estimatedSalary) {
|
|
1401
911
|
return {
|
|
@@ -1406,17 +916,27 @@ function salaryEnvelope(type, name, extra, estimatedSalary) {
|
|
|
1406
916
|
estimatedSalary
|
|
1407
917
|
};
|
|
1408
918
|
}
|
|
1409
|
-
function buildSalaryFaq(locale, label, overall) {
|
|
919
|
+
function buildSalaryFaq(locale, label, overall, currency) {
|
|
1410
920
|
if (!overall) return [];
|
|
1411
|
-
const range =
|
|
921
|
+
const range = formatSalaryStatRange(
|
|
922
|
+
locale,
|
|
923
|
+
overall.avgMin,
|
|
924
|
+
overall.avgMax,
|
|
925
|
+
currency
|
|
926
|
+
);
|
|
1412
927
|
return [
|
|
1413
928
|
{
|
|
1414
|
-
|
|
1415
|
-
|
|
929
|
+
kind: "average",
|
|
930
|
+
label,
|
|
931
|
+
range,
|
|
932
|
+
avgMin: overall.avgMin,
|
|
933
|
+
avgMax: overall.avgMax,
|
|
934
|
+
currency,
|
|
935
|
+
jobCount: overall.jobCount
|
|
1416
936
|
},
|
|
1417
937
|
{
|
|
1418
|
-
|
|
1419
|
-
|
|
938
|
+
kind: "methodology",
|
|
939
|
+
label
|
|
1420
940
|
}
|
|
1421
941
|
];
|
|
1422
942
|
}
|
|
@@ -1446,11 +966,11 @@ function faqJsonLd(faqs) {
|
|
|
1446
966
|
}))
|
|
1447
967
|
};
|
|
1448
968
|
}
|
|
1449
|
-
function titleSalaryJsonLd(
|
|
969
|
+
function titleSalaryJsonLd(d, options) {
|
|
1450
970
|
if (!d.overallSalary) return null;
|
|
1451
971
|
return salaryEnvelope("Occupation", d.categoryName, {}, [
|
|
1452
972
|
distribution(
|
|
1453
|
-
|
|
973
|
+
d.categoryName,
|
|
1454
974
|
d.currency,
|
|
1455
975
|
d.overallSalary.avgMin,
|
|
1456
976
|
d.overallSalary.avgMax,
|
|
@@ -1460,10 +980,10 @@ function titleSalaryJsonLd(locale, d) {
|
|
|
1460
980
|
}
|
|
1461
981
|
),
|
|
1462
982
|
...seniorityDistributions(
|
|
1463
|
-
locale,
|
|
1464
983
|
d.bySeniority,
|
|
1465
984
|
d.currency,
|
|
1466
|
-
|
|
985
|
+
d.categoryName,
|
|
986
|
+
options
|
|
1467
987
|
)
|
|
1468
988
|
]);
|
|
1469
989
|
}
|
|
@@ -1471,7 +991,7 @@ function skillSalaryJsonLd(d) {
|
|
|
1471
991
|
if (!d.overallSalary) return null;
|
|
1472
992
|
return salaryEnvelope("Occupation", d.skillName, {}, [
|
|
1473
993
|
distribution(
|
|
1474
|
-
|
|
994
|
+
d.skillName,
|
|
1475
995
|
d.currency,
|
|
1476
996
|
d.overallSalary.avgMin,
|
|
1477
997
|
d.overallSalary.avgMax,
|
|
@@ -1483,42 +1003,22 @@ function skillSalaryJsonLd(d) {
|
|
|
1483
1003
|
)
|
|
1484
1004
|
]);
|
|
1485
1005
|
}
|
|
1486
|
-
function locationSalaryJsonLd(d) {
|
|
1006
|
+
function locationSalaryJsonLd(d, options) {
|
|
1007
|
+
if (!options?.occupationUrl) return null;
|
|
1487
1008
|
const isCity = d.adminLevel === "city" || d.adminLevel === "locality";
|
|
1488
|
-
if (!isCity
|
|
1489
|
-
return
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
"@type": "City",
|
|
1495
|
-
name: d.placeName,
|
|
1496
|
-
address: { "@type": "PostalAddress", addressCountry: d.countryCode }
|
|
1497
|
-
}
|
|
1498
|
-
},
|
|
1499
|
-
[
|
|
1500
|
-
distribution(
|
|
1501
|
-
`Average salary in ${d.placeName}`,
|
|
1502
|
-
d.currency,
|
|
1503
|
-
d.overallSalary.avgMin,
|
|
1504
|
-
d.overallSalary.avgMax,
|
|
1505
|
-
{
|
|
1506
|
-
median: Math.round(
|
|
1507
|
-
(d.overallSalary.medianMin + d.overallSalary.medianMax) / 2
|
|
1508
|
-
),
|
|
1509
|
-
// Hosted includes these unconditionally, nulls and all.
|
|
1510
|
-
percentile25: d.overallSalary.p25Min,
|
|
1511
|
-
percentile75: d.overallSalary.p75Max
|
|
1512
|
-
}
|
|
1513
|
-
)
|
|
1514
|
-
]
|
|
1009
|
+
if (!isCity) return null;
|
|
1010
|
+
return itemListJsonLd(
|
|
1011
|
+
d.topCategories.map((c) => ({
|
|
1012
|
+
name: c.categoryName,
|
|
1013
|
+
url: options.occupationUrl(c)
|
|
1014
|
+
}))
|
|
1515
1015
|
);
|
|
1516
1016
|
}
|
|
1517
|
-
function crossAxisSalaryJsonLd(
|
|
1017
|
+
function crossAxisSalaryJsonLd(args, options) {
|
|
1518
1018
|
if (!args.overall) return null;
|
|
1519
1019
|
return salaryEnvelope(
|
|
1520
1020
|
"Occupation",
|
|
1521
|
-
|
|
1021
|
+
args.name,
|
|
1522
1022
|
{
|
|
1523
1023
|
occupationLocation: {
|
|
1524
1024
|
"@type": "AdministrativeArea",
|
|
@@ -1531,7 +1031,7 @@ function crossAxisSalaryJsonLd(locale, args) {
|
|
|
1531
1031
|
},
|
|
1532
1032
|
[
|
|
1533
1033
|
distribution(
|
|
1534
|
-
|
|
1034
|
+
args.name,
|
|
1535
1035
|
args.currency,
|
|
1536
1036
|
args.overall.avgMin,
|
|
1537
1037
|
args.overall.avgMax,
|
|
@@ -1541,56 +1041,35 @@ function crossAxisSalaryJsonLd(locale, args) {
|
|
|
1541
1041
|
}
|
|
1542
1042
|
),
|
|
1543
1043
|
...seniorityDistributions(
|
|
1544
|
-
locale,
|
|
1545
1044
|
args.bySeniority,
|
|
1546
1045
|
args.currency,
|
|
1547
|
-
|
|
1046
|
+
args.name,
|
|
1047
|
+
options
|
|
1548
1048
|
)
|
|
1549
1049
|
]
|
|
1550
1050
|
);
|
|
1551
1051
|
}
|
|
1552
|
-
function companySalaryJsonLd(
|
|
1553
|
-
if (!
|
|
1554
|
-
return
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
hiringOrganization: { "@type": "Organization", name: d.companyName }
|
|
1560
|
-
},
|
|
1561
|
-
[
|
|
1562
|
-
distribution(
|
|
1563
|
-
"base",
|
|
1564
|
-
d.currency,
|
|
1565
|
-
d.overallSalary.avgMin,
|
|
1566
|
-
d.overallSalary.avgMax,
|
|
1567
|
-
{
|
|
1568
|
-
...d.boardMedianMin && d.boardMedianMax ? { median: Math.round((d.boardMedianMin + d.boardMedianMax) / 2) } : {},
|
|
1569
|
-
...d.boardP25Min ? { percentile25: d.boardP25Min } : {},
|
|
1570
|
-
...d.boardP75Max ? { percentile75: d.boardP75Max } : {}
|
|
1571
|
-
}
|
|
1572
|
-
),
|
|
1573
|
-
...seniorityDistributions(
|
|
1574
|
-
locale,
|
|
1575
|
-
d.bySeniority,
|
|
1576
|
-
d.currency,
|
|
1577
|
-
(label) => `${label} salary`
|
|
1578
|
-
)
|
|
1579
|
-
]
|
|
1052
|
+
function companySalaryJsonLd(d, options) {
|
|
1053
|
+
if (!options?.occupationUrl) return null;
|
|
1054
|
+
return itemListJsonLd(
|
|
1055
|
+
d.byCategory.map((c) => ({
|
|
1056
|
+
name: c.categoryName,
|
|
1057
|
+
url: options.occupationUrl(c)
|
|
1058
|
+
}))
|
|
1580
1059
|
);
|
|
1581
1060
|
}
|
|
1582
|
-
function companyCategorySalaryJsonLd(
|
|
1061
|
+
function companyCategorySalaryJsonLd(d, options) {
|
|
1583
1062
|
if (!d.overallSalary) return null;
|
|
1584
1063
|
return salaryEnvelope(
|
|
1585
1064
|
"Occupation",
|
|
1586
|
-
|
|
1065
|
+
d.categoryName,
|
|
1587
1066
|
{
|
|
1588
1067
|
occupationalCategory: d.categoryName,
|
|
1589
1068
|
hiringOrganization: { "@type": "Organization", name: d.companyName }
|
|
1590
1069
|
},
|
|
1591
1070
|
[
|
|
1592
1071
|
distribution(
|
|
1593
|
-
|
|
1072
|
+
d.categoryName,
|
|
1594
1073
|
d.currency,
|
|
1595
1074
|
d.overallSalary.avgMin,
|
|
1596
1075
|
d.overallSalary.avgMax,
|
|
@@ -1600,10 +1079,10 @@ function companyCategorySalaryJsonLd(locale, d) {
|
|
|
1600
1079
|
}
|
|
1601
1080
|
),
|
|
1602
1081
|
...seniorityDistributions(
|
|
1603
|
-
locale,
|
|
1604
1082
|
d.bySeniority,
|
|
1605
1083
|
d.currency,
|
|
1606
|
-
|
|
1084
|
+
d.categoryName,
|
|
1085
|
+
options
|
|
1607
1086
|
)
|
|
1608
1087
|
]
|
|
1609
1088
|
);
|