The DÁP Design System includes a built-in internationalization system powered by i18next and lit-i18n, allowing you to customize translations for your application or add support for additional languages.
The design system comes with built-in support for:
- Hungarian (hu) - Default language
- English (en)
- German (de)
The language is automatically detected from:
- The
langattribute on the<html>element - Browser language settings
- Falls back to Hungarian if neither is available
<!-- Set language on the HTML element -->
<html lang="en">
You can inject custom translations for additional languages or override existing translations by using the exported i18next instance.
import { i18next } from 'dap-design-system'
// Add German translations
i18next.addResourceBundle('de', 'translation', {
pager: {
pageSize: '{{count}} Einträge / Seite',
first: 'Erste',
previous: 'Zurück',
next: 'Weiter',
last: 'Letzte',
pageInfo: '{{rangeStart}}-{{rangeEnd}} von {{totalRows}}'
},
close: 'Schließen',
cancel: 'Abbrechen',
confirm: 'Bestätigen'
}, true, true)
// Switch to German
i18next.changeLanguage('de')
document.documentElement.lang = 'de'
The i18next instance is available from both main and tree-shakeable entry points:
// From components entry
import { i18next, DapDSPager } from 'dap-design-system/components'
// From main entry
import { i18next } from 'dap-design-system'
<!doctype html>
<html lang="fr">
<head>
<script type="module">
import { i18next } from 'dap-design-system'
// Add French translations
i18next.addResourceBundle('fr', 'translation', {
pager: {
pageSize: '{{count}} Elemente / page',
first: 'Première',
previous: 'Précédent',
next: 'Suivant',
last: 'Dernière',
pageInfo: '{{rangeStart}}-{{rangeEnd}} sur {{totalRows}}'
}
}, true, true)
// Set language
i18next.changeLanguage('fr')
</script>
</head>
<body>
<dap-ds-pager total-rows="100"></dap-ds-pager>
</body>
</html>
Components that display dates, months, and day names (Calendar, Datepicker, Timepicker) use Day.js for date formatting. While i18next handles text translations, Day.js requires separate locale files for date formatting.
The following languages have Day.js locales pre-loaded and work automatically:
- Hungarian (hu)
- English (en)
- German (de)
For these languages, date/month/day names will be localized automatically without any additional setup.
For custom languages (e.g., French, Italian, Spanish), you must manually import and register the Day.js locale to ensure date formatting works correctly.
To add support for a custom language, manually import and register the Day.js locale:
import 'dayjs/locale/fr' // Import the Day.js locale
import { i18next, registerDayjsLocale } from 'dap-design-system'
// Register the locale with Day.js
registerDayjsLocale('fr')
// Add your i18next translations
i18next.addResourceBundle('fr', 'translation', {
calendar: {
today: "aujourd'hui",
now: 'maintenant',
nextMonth: 'mois prochain',
prevMonth: 'mois précédent',
year: 'année',
month: 'mois'
}
}, true, true)
// Switch to French
i18next.changeLanguage('fr')
document.documentElement.lang = 'fr'
<!doctype html>
<html lang="fr">
<head>
<script type="module">
// Step 1: Import the Day.js locale
import 'dayjs/locale/fr'
// Step 2: Import the design system functions
import { i18next, registerDayjsLocale } from 'dap-design-system'
// Step 3: Register the Day.js locale
registerDayjsLocale('fr')
// Step 4: Add i18next translations
i18next.addResourceBundle('fr', 'translation', {
pager: {
pageSize: '{{count}} éléments / page',
first: 'Première',
previous: 'Précédent',
next: 'Suivant',
last: 'Dernière',
pageInfo: '{{rangeStart}}-{{rangeEnd}} sur {{totalRows}}'
},
calendar: {
today: "aujourd'hui",
now: 'maintenant',
nextMonth: 'mois prochain',
prevMonth: 'mois précédent',
year: 'année',
month: 'mois'
},
close: 'Fermer',
cancel: 'Annuler',
confirm: 'Confirmer'
}, true, true)
// Step 5: Set the language
i18next.changeLanguage('fr')
document.documentElement.lang = 'fr'
</script>
</head>
<body>
<dap-ds-datepicker label="Sélectionner une date"></dap-ds-datepicker>
<dap-ds-pager total-rows="100"></dap-ds-pager>
</body>
</html>
Day.js supports many locales. You can import any available locale:
import 'dayjs/locale/fr' // French
import 'dayjs/locale/it' // Italian
import 'dayjs/locale/es' // Spanish
import 'dayjs/locale/ja' // Japanese
import 'dayjs/locale/zh-cn' // Chinese (Simplified)
// ... and many more
If date/month/day names are not localized correctly:
- Check if locale is imported: Ensure you've imported the Day.js locale file
- Check if locale is registered: Call
registerDayjsLocale()after importing - Check console warnings: The system logs warnings if a locale is not registered
- Verify locale code: Use the correct 2-letter language code (e.g.,
'fr'not'fr-FR')
// ❌ Wrong - locale code should be 2 letters
registerDayjsLocale('fr-FR')
// ✅ Correct
registerDayjsLocale('fr')
registerDayjsLocale(localeCode: string): voidManually register a Day.js locale that has been imported.
Parameters:
localeCode- The 2-letter language code (e.g.,'fr','it','es')
Example:
import 'dayjs/locale/fr'
import { registerDayjsLocale } from 'dap-design-system'
registerDayjsLocale('fr')
Below is the complete list of all translation keys available in the design system. You can override any of these keys when adding custom language support.
{
"bannerType": {
"neutral": "Information",
"informative": "Information",
"positive": "Success",
"warning": "Warning",
"negative": "Error"
},
"close": "Close",
"delete": "delete",
"cancel": "Cancel",
"clear": "Clear selection",
"copy": "Copy",
"confirm": "Confirm",
"ok": "Ok",
"search": "Search",
"tag": "tag",
"opensInNewTab": "(opens in new tab)",
"label": {
"optional": "(Optional)",
"tooltip": "Information"
},
"errors": {
"maxLength": "Exceeded the maximum length by {{count}} character"
},
"feedback": {
"info": "Info",
"success": "Success",
"error": "Error"
},
"listItems": {
"selected": "kiválasztva",
"disabled": "nem elérhető"
},
"dap-badge": "Prepared within the framework of the Digital Citizenship Program.",
"dap-badge-large": "The service has been updated within the framework of the Digital Citizenship Program.",
"loading": "loading",
"spinner": "Loading...",
"show": "show",
"hide": "hide",
"decrease": "decrease",
"increase": "increase",
"tocTitle": "Table of contents",
"date": "{{val, datetime}}",
"selected": "selected",
"calendar": {
"today": "today",
"now": "now",
"nextMonth": "next month",
"prevMonth": "previous month",
"year": "year",
"month": "month"
},
"form": {
"validationMessage": {
"select": "Please select an option",
"datepicker": "Please select a date"
}
},
"fileInput": {
"dragDropArea": "Drag and drop files here or click to upload",
"dragDropInstructions": "You can also upload files by dragging and dropping them into the area.",
"files": "Files",
"uploadButtonLabel": "Upload",
"browseButtonLabel": "Browse",
"browse": "Browse files",
"fileList": "File list",
"fileSize": "{{size}} MB",
"upload": "Upload",
"uploading": "Uploading",
"dropzone": {
"label": "Upload files",
"text": "Drag and drop files here or click to upload",
"acceptedTypes": "Accepted file types"
},
"link": "Link",
"cancel": "Cancel",
"delete": "Delete",
"view": "View",
"error": {
"fileSize": "The file size exceeds the maximum limit of {size} MB",
"fileType": "The file type is not allowed",
"fileAmount": "The number of files exceeds the maximum limit of {count}",
"perFileSize": "The file size exceeds the maximum limit of {size} MB"
},
"removeDialog": {
"title": "Remove file",
"message": "Are you sure you want to remove {{fileName}}?",
"confirm": "Delete",
"cancel": "Cancel"
}
},
"pager": {
"pageSize": "{{count}} items / page",
"first": "First",
"previous": "Previous",
"next": "Next",
"last": "Last",
"pageInfo": "{{rangeStart}}-{{rangeEnd}} of {{totalRows}}"
},
"datatable": {
"sortAscending": "Sort ascending",
"sortDescending": "Sort descending",
"clearSort": "Clear sort",
"tableDescription": "Data table with sortable columns",
"defaultCaption": "Data table",
"rowSelected": "Row selected",
"rowDeselected": "Row deselected",
"sortedBy": "Sorted by {{column}} {{direction}}",
"pageChanged": "Page {{page}} of {{total}}",
"noData": "No data available"
},
"accordion": {
"expand": "Expand section",
"collapse": "Collapse section"
},
"official-website-banner": {
"heading": "An official website of the Government of Hungary.",
"heading-2": "Secure website",
"content": "The lock icon or https:// indicates that you have securely connected to the website. Only share personal information on official, secure websites. The certificates for the official websites of the Hungarian Government are issued by Microsec."
},
"avatar-group": {
"overflow-label": "{{count}} more avatar{{count > 1 ? 's' : ''}}"
},
"timepicker": {
"hour": "Hour",
"minute": "Minute",
"second": "Second"
},
"chip": {
"remove": "Remove"
},
"snackbar": {
"notifications": "Notifications"
},
"combobox": {
"multiselect": {
"selected": "{{count}} item{{count > 1 ? 's' : ''}} selected"
}
},
"progress": {
"loading": "Loading",
"progress": "Progress: {{percentage}}%"
}
}
You can switch languages at runtime, and all reactive components will update automatically:
import { i18next } from 'dap-design-system'
// Function to switch language
function switchLanguage(lang) {
i18next.changeLanguage(lang)
document.documentElement.lang = lang
}
// Example usage
switchLanguage('de') // Switch to German
switchLanguage('en') // Switch to English
switchLanguage('hu') // Switch to Hungarian
The following components use reactive translations and will automatically update when the language changes:
- Calendar
- Datepicker
- Timepicker
- Pager
- Select (including dropdowns)
- Modal
- Callout
- Official Website Banner
- Password Input
- Number Input
- DAP Badge
- Copybox Input
- Banner
- Spinner
Other components may require a manual re-render or page reload after language changes.
You don't need to translate everything - you can override only specific components or keys:
import { i18next } from 'dap-design-system'
// Only override specific pager translations
i18next.addResourceBundle('de', 'translation', {
pager: {
next: 'Weiter',
previous: 'Zurück'
}
}, true, true)
// Other translations will use the library defaults
You can register multiple languages at once:
import { i18next } from 'dap-design-system'
const languages = {
de: {
pager: {
pageSize: '{{count}} Einträge / Seite',
first: 'Erste',
previous: 'Zurück',
next: 'Weiter',
last: 'Letzte'
}
},
fr: {
pager: {
pageSize: '{{count}} Elemente / page',
first: 'Première',
previous: 'Précédent',
next: 'Suivant',
last: 'Dernière'
}
}
}
// Register all languages
Object.entries(languages).forEach(([lang, translations]) => {
i18next.addResourceBundle(lang, 'translation', translations, true, true)
})
The exported i18next instance supports all standard i18next methods and features:
i18next.addResourceBundle('en', 'translation', {
items_one: "{{count}} item",
items_other: "{{count}} items"
}, true, true)
i18next.addResourceBundle('en', 'translation', {
button: {
save: "Save",
cancel: "Cancel"
},
form: {
submit: "$t(button.save) Form"
}
}, true, true)
i18next.addResourceBundle('en', 'translation', {
date: "{{val, datetime}}"
}, true, true)
addResourceBundle(lng, ns, resources, deep, overwrite)- Add translations for a languagechangeLanguage(lng)- Switch active languaget(key, options)- Translate a key (used internally by components)language- Get current language (property)languages- Get supported languages (property)
See the i18next documentation for the complete API.
registerDayjsLocale(localeCode)- Manually register a Day.js locale that has been imported- Parameters:
localeCode(string) - The 2-letter language code (e.g.,'fr','it','es') - Example:
registerDayjsLocale('fr')
- Parameters:
- Set the HTML lang attribute: Always update
document.documentElement.langwhen changing languages for accessibility - Load translations early: Add custom translations before your components are rendered
- Load Day.js locales for custom languages: If using Calendar, Datepicker, or Timepicker with custom languages, import and register the Day.js locale
- Use interpolation: Take advantage of i18next's interpolation for dynamic values
- Keep translations centralized: Store all your translations in a single location
- Test with RTL languages: If supporting RTL languages, test with the
dirattribute
// Import Day.js locales for custom languages
import 'dayjs/locale/fr'
import 'dayjs/locale/it'
import { i18next, registerDayjsLocale } from 'dap-design-system'
// Register Day.js locales for custom languages
registerDayjsLocale('fr')
registerDayjsLocale('it')
// Define all your translations
const translations = {
de: {
pager: { /* German translations */ },
calendar: { /* German translations */ },
// ... more translations
},
fr: {
pager: { /* French translations */ },
calendar: { /* French translations */ },
// ... more translations
},
it: {
pager: { /* Italian translations */ },
calendar: { /* Italian translations */ },
// ... more translations
}
}
// Initialize all languages
Object.entries(translations).forEach(([lang, trans]) => {
i18next.addResourceBundle(lang, 'translation', trans, true, true)
})
// Set initial language
const userLang = navigator.language.slice(0, 2)
i18next.changeLanguage(userLang)
document.documentElement.lang = userLang
<dap-ds-select id="language-selector">
<dap-ds-option-item value="en">English</dap-ds-option-item>
<dap-ds-option-item value="hu">Magyar</dap-ds-option-item>
<dap-ds-option-item value="de">Deutsch</dap-ds-option-item>
</dap-ds-select>
<script type="module">
import { i18next } from 'dap-design-system'
const selector = document.querySelector('#language-selector')
selector.value = i18next.language
selector.addEventListener('dds-change', (e) => {
const newLang = e.detail.value
i18next.changeLanguage(newLang)
document.documentElement.lang = newLang
})
</script>
If translations don't update after calling changeLanguage():
- Check component support: Ensure the component uses reactive translations (see list above)
- Verify language was added: Make sure you called
addResourceBundle()before switching - Check the HTML lang attribute: Update
document.documentElement.langalong withchangeLanguage()
If some text isn't translated:
- Check translation keys: Ensure you're using the correct key structure
- Add missing keys: Some components may use keys not listed in the common section
- Check console: i18next logs missing translation keys in development mode
If date/month/day names in Calendar, Datepicker, or Timepicker components are not localized:
- Check if Day.js locale is imported: Ensure you've imported the locale file (e.g.,
import 'dayjs/locale/fr') - Check if Day.js locale is registered: Call
registerDayjsLocale()after importing - Check console warnings: The system logs warnings if a locale is not registered
- Verify locale code: Use the correct 2-letter language code matching your i18next language