Skip to main content

SvelteKit Customization

Translations

Where the copy comes from

The banner, dialog, widget, gate placeholder and IAB surfaces read their text from one set of translations for the visitor's language. Which set depends on the provider's mode:

ModeCopy comes fromLanguages
hosted()The backend's /init response, in the language the browser or server asked for, with the provider's i18n messages for that language on topEvery language the backend bundles: bg, cs, cy, da, de, el, en, es, et, fi, fr, ga, gu, he, hi, hr, hu, id, is, it, lb, lt, lv, mt, nb, nl, nn, pl, pt, rm, ro, sk, sl, sv and zh
manifest()The manifest's translations over the base copy for the visitor's language, with the provider's i18n messages on top. Resolved on the server in SvelteKit, in the browser in Svelte.English base copy is bundled; another language's base copy loads the first time a visitor needs it
offline()The provider's i18n prop, merged over bundled EnglishEnglish, plus any language you supply in full

The browser bundle carries English only. Other languages arrive from the backend, or from messages you pass.

Change the copy for one banner

ConsentBanner takes title, description, acceptButtonText, rejectButtonText, customizeButtonText and dismissButtonText. These props win in every mode:

<ConsentBanner
	title="Cookies on this site"
	rejectButtonText="Reject optional"
/>

The props replace the text in every language, so pass values in the page's language, or compute them from your own i18n library.

Change the copy site-wide

Pass i18n to the provider. messages holds partial translations per language; the keys you leave out keep c15t's copy:

src/lib/consent-i18n.ts
import type { I18nConfig } from '@c15t/svelte';

// Pass as `i18n={i18n}` on ConsentProvider. Messages merge over the
// bundled English copy, so list only the keys you change.
export const i18n: Partial<I18nConfig> = {
	locale: 'en',
	messages: {
		en: {
			common: { customize: 'Choose cookies', rejectAll: 'Reject optional' },
			cookieBanner: { title: 'Your privacy on this site' },
		},
	},
};

locale selects the language the provider starts in, en by default.

In hosted() mode, the backend's copy for the visitor's language is the base, and your i18n messages for that language replace it key by key. Keys you do not list keep the backend's copy, including copy edited in your Inth project. The same applies to the copy SvelteKit's loadConsent resolves on the server. c15t picks the messages for the exact language first, then for its primary language, so a visitor resolved to de-AT gets your de messages when there is no de-AT entry. Messages for other languages are not applied.

A key only overrides the backend when your text differs from c15t's built-in wording for that language. So passing the stock bundles from @c15t/translations/all to enable languages keeps backend edits visible, while a key you actually reworded stays pinned in code. Core bundles only English; for other languages, import @c15t/translations/all so c15t can recognize its stock wording. A self-hosted backend takes customTranslations and i18n in its configuration.

In offline() mode, i18n is the only source of copy, and it applies from the first render.

Common message keys

KeyWhere it shows
cookieBanner.title, cookieBanner.descriptionChoice banner heading and body.
cookieBanner.noticeTitle, cookieBanner.noticeDescriptionNotice banner heading and body.
common.acceptAll, common.rejectAll, common.customize, common.saveBanner and dialog buttons.
common.acknowledgeThe notice's dismiss button.
common.securedByThe "Secured by" tag.
consentManagerDialog.title, consentManagerDialog.descriptionPreference dialog heading and body.
consentTypes.<category>.title, consentTypes.<category>.descriptionA category's name and description, such as consentTypes.measurement.title.
consentGate.title, consentGate.actionButtonThe ConsentGate placeholder. {category} is replaced by the category title.

Copy and translations covers wording for each action and testing long labels.

Switch the language

getConsentManager().setLanguage(code) switches the language and resolves the policy again, so a hosted backend returns copy in the new language and your i18n messages for that language apply on top. Call it from your language switcher's event handler. The visitor's language otherwise comes from the Accept-Language header, or from overrides.language on the provider.

The root of the banner, dialog and widget sets dir from the active language, so right-to-left languages such as Hebrew lay out correctly.

Verify the copy

Open the page with the browser language set to each language you support. The banner, the dialog's category names and the gate placeholder all use that language. Then choose a narrow window and zoom to 200%: long labels wrap without cutting off.

Language on the server

loadConsent resolves the language from the request's Accept-Language header and returns the copy for it in consent, so the server HTML is already in the visitor's language. Pass language to loadConsent or c15tHandle to force one, for example from a /de/ route prefix. The provider applies its i18n messages for that language over the server-resolved copy, so the server HTML already shows your overrides.