LearnDash custom labels translate per language only when something replaces the stored value: filter learndash_get_label and return a different word for each locale, then add a learndash_label_to_lower filter for languages where the lowercase form is wrong. LearnDash stores one value per label in the learndash_settings_custom_labels option, so a saved label such as "Programme" shows in every language until code or your multilingual plugin replaces it. If you only need the standard translation of "Course" or "Lesson", the simpler fix is to leave the label field empty.
This snippet article goes further than our custom labels guide: a complete per-locale plugin, lowercase handling, what learndash_label_to_slug does and does not change, and the timing issue behind post type names that refuse to switch language.
Checked against LearnDash 4.18.0.1 (includes/class-ld-custom-label.php and includes/class-ld-lms.php). LearnDash 5.x is current; confirm the filter names against the version you run.
How LearnDash resolves a label
LearnDash_Custom_Label::get_label( $key ), which learndash_get_custom_label() wraps, works in three steps:
- It lowercases the key and reads
learndash_settings_custom_labels. A non-empty stored value wins. - Otherwise it returns the default through
esc_html__()in thelearndashtext domain, for example "Course" or "Mark Complete". That default is translated by the active language file. - Either result passes through
apply_filters( 'learndash_get_label', $label, $key ).
label_to_lower() runs mb_strtolower() on the result of get_label() and then applies learndash_label_to_lower. label_to_slug() runs sanitize_title() on it and applies learndash_label_to_slug. Because both start from get_label(), one filter on learndash_get_label feeds all three.
Option 1: leave the field empty and use translations
An empty label field means LearnDash returns the translated default. On a site in English, German and French with the standard terms, install the language files as described in our LearnDash translation guide and you are done, with no code.
If you want a different term in one language only, you can edit that language's translation of the msgid "Course" in the learndash text domain. Be aware that this changes every string with exactly that msgid, which is usually what you want for a terminology change, and that edited files must live where plugin updates do not overwrite them.
Option 2: a per-locale filter plugin
When you need your own terms in several languages, or labels that are not in WPML's admin texts list, use a small plugin. Put it in wp-content/mu-plugins/ so it cannot be deactivated by accident. Not run on a live site; test on staging first.
<?php
/**
* Plugin Name: AIOLMS LearnDash labels per language
* Description: Returns LearnDash custom labels per locale.
*/
defined( 'ABSPATH' ) || exit;
function aiolms_ld_label_map() {
return array(
'de_DE' => array(
'course' => 'Kurs',
'courses' => 'Kurse',
'lesson' => 'Lektion',
'lessons' => 'Lektionen',
'button_take_this_course' => 'Kurs starten',
),
'fr_FR' => array(
'course' => 'Formation',
'courses' => 'Formations',
'lesson' => 'Module',
'lessons' => 'Modules',
),
);
}
add_filter( 'learndash_get_label', 'aiolms_ld_label_per_locale', 10, 2 );
function aiolms_ld_label_per_locale( $label, $key ) {
$map = aiolms_ld_label_map();
$locale = determine_locale();
if ( isset( $map[ $locale ][ $key ] ) ) {
return $map[ $locale ][ $key ];
}
return $label;
}
add_filter( 'learndash_label_to_lower', 'aiolms_ld_label_lower_per_locale', 10, 2 );
function aiolms_ld_label_lower_per_locale( $label, $key ) {
// German capitalises nouns, so keep the label as written.
if ( 0 === strpos( determine_locale(), 'de_' ) ) {
return learndash_get_custom_label( $key );
}
return $label;
}
Notes on the code:
determine_locale()returns the locale WordPress loads translations for, including a user's profile language in wp-admin, so a German-speaking admin sees German labels on an English site.- Keys arrive lowercased. Valid keys include
course,lesson,topic,quiz,question,group,group_leader,exam,certificate,assignment,essay, the plurals, and the buttonsbutton_take_this_course,button_take_this_group,button_mark_completeandbutton_click_here_to_continue. - A locale missing from the map falls through to the stored label, so list every locale you serve.
- Return plain text, and escape labels when you print them in your own templates.
Why German needs the lowercase filter
LearnDash builds sentences with learndash_get_custom_label_lower(), for example "this course". For English and French that is correct. German capitalises every noun, so mb_strtolower() turns "Kurs" into "kurs" inside a sentence, which reads as a mistake to native speakers. The second filter above returns the label unchanged for any de_ locale. Apply the same idea to any language with similar rules.
What learndash_label_to_slug does and does not change
In 4.18.0.1, learndash_get_custom_label_slug() is used in two places: to seed the default permalink slugs when the Permalinks settings have never been saved, and to pass label slugs to the block editor scripts. It does not rewrite saved permalinks, which are stored in their own settings. Filtering learndash_label_to_slug per language therefore does not give you /kurse/ in German and /formations/ in French. Language-specific URL slugs are a job for your multilingual plugin's slug translation, as covered in our guide to translating WordPress LMS plugins.
When post type names stay in one language
LearnDash registers its post types on init at priority 2, and builds their names from the labels at that moment. Admin menus, post type archive titles and other places that read the registered post type names use whatever locale was active then. If your filter switches button text correctly but the admin menu or archive title stays in the default language, the language was decided after registration. With determine_locale() this works for user profile languages in wp-admin. With a multilingual plugin, check how early it sets the current language on the front end, and test each language's archive page.
Testing checklist
- Switch your admin profile language and confirm the LearnDash menu, settings and course builder show the mapped terms.
- Visit a course, lesson and quiz in each front-end language and check headings, buttons and progress text.
- Check sentences that use the lowercase form, especially in German.
- Send a test notification email and confirm which language its labels use.
- Confirm that WPML or Polylang string translations, if you also use them, do not fight the filter. The filter runs last, so it wins.
How we can help
We build multilingual LearnDash sites and the small plugins that keep terminology consistent across languages. If labels, slugs or emails are mixing languages on your site, our LMS plugin development team can sort it out. For the wider platform, see the LearnDash guide.
Frequently asked questions
Why does my LearnDash custom label not change when I switch language?
A saved custom label is stored once in the learndash_settings_custom_labels option and returned for every language. Leave the field empty to use translated defaults, translate it with WPML string translation, or return a value per locale from the learndash_get_label filter.
Does the learndash_get_label filter also change lowercase labels?
Yes. label_to_lower() and label_to_slug() both call get_label() first, so your filtered value flows into them. Use learndash_label_to_lower to change the lowercase form separately, for example for German nouns.
Can I translate LearnDash URL slugs with learndash_label_to_slug?
No. In 4.18.0.1 that helper only seeds default permalink slugs before the Permalinks settings are saved and passes data to the block editor. Saved permalinks are separate settings, so translate slugs with your multilingual plugin.
Free 30-minute consultation
Not sure where to start? Talk to an LMS engineer.
Tell us what platform you run and what you need. You’ll get honest, practical advice - even if the answer is that you don’t need us.
Sources & references
- LearnDash custom labels - LearnDash
- LearnDash developer documentation - LearnDash
- determine_locale() function reference - WordPress.org
Learn more about this topic with AI
Gemini opens with the prompt copied - paste it into the chat to start.