WordPress Localization Hooks Reference

Filters and actions for customizing translation behavior.

Translation Filters

gettext

Filters translated text after translation lookup.

apply_filters( 'gettext', string $translation, string $text, string $domain )

Parameters:

  • $translation – Translated text
  • $text – Original text
  • $domain – Text domain

Example – Replace specific translations:

add_filter( 'gettext', function( $translation, $text, $domain ) {
    if ( 'my-plugin' === $domain && 'Submit' === $text ) {
        return 'Send Message';
    }
    return $translation;
}, 10, 3 );

gettext_{$domain}

Domain-specific translation filter. More efficient than checking domain in gettext.

apply_filters( "gettext_{$domain}", string $translation, string $text, string $domain )

Since: WordPress 5.5.0

Example:

add_filter( 'gettext_my-plugin', function( $translation, $text, $domain ) {
    if ( 'Hello' === $text ) {
        return 'Hi there';
    }
    return $translation;
}, 10, 3 );

gettext_with_context

Filters translations that have gettext context.

apply_filters( 'gettext_with_context', string $translation, string $text, string $context, string $domain )

Example:

add_filter( 'gettext_with_context', function( $translation, $text, $context, $domain ) {
    if ( 'verb' === $context && 'Post' === $text ) {
        return 'Publish Now';
    }
    return $translation;
}, 10, 4 );

gettext_with_context_{$domain}

Domain-specific contextual translation filter.

apply_filters( "gettext_with_context_{$domain}", string $translation, string $text, string $context, string $domain )

Since: WordPress 5.5.0


ngettext

Filters plural form translations.

apply_filters( 'ngettext', string $translation, string $single, string $plural, int $number, string $domain )

Example:

add_filter( 'ngettext', function( $translation, $single, $plural, $number, $domain ) {
    if ( 'my-plugin' === $domain && '%d item' === $single ) {
        return 1 === $number ? '%d product' : '%d products';
    }
    return $translation;
}, 10, 5 );

ngettext_{$domain}

Domain-specific plural translation filter.

apply_filters( "ngettext_{$domain}", string $translation, string $single, string $plural, int $number, string $domain )

Since: WordPress 5.5.0


ngettext_with_context

Filters plural translations with gettext context.

apply_filters( 'ngettext_with_context', string $translation, string $single, string $plural, int $number, string $context, string $domain )

ngettext_with_context_{$domain}

Domain-specific contextual plural filter.

apply_filters( "ngettext_with_context_{$domain}", string $translation, string $single, string $plural, int $number, string $context, string $domain )

Since: WordPress 5.5.0


Locale Filters

locale

Filters the locale of the WordPress installation.

apply_filters( 'locale', string $locale )

Example – Force locale based on URL:

add_filter( 'locale', function( $locale ) {
    if ( isset( $_GET['lang'] ) && 'de' === $_GET['lang'] ) {
        return 'de_DE';
    }
    return $locale;
} );

pre_determine_locale

Short-circuits locale determination before default logic.

apply_filters( 'pre_determine_locale', string|null $locale )

Since: WordPress 5.0.0

Example:

add_filter( 'pre_determine_locale', function( $locale ) {
    // Use session-based locale
    if ( isset( $_SESSION['user_locale'] ) ) {
        return $_SESSION['user_locale'];
    }
    return $locale; // null continues normal determination
} );

determine_locale

Filters the determined locale for the current request.

apply_filters( 'determine_locale', string $locale )

Since: WordPress 5.0.0


Text Domain Loading Filters

pre_load_textdomain

Short-circuits translation file loading.

apply_filters( 'pre_load_textdomain', bool|null $loaded, string $domain, string $mofile, string|null $locale )

Since: WordPress 6.3.0

Example – Use custom translation source:

add_filter( 'pre_load_textdomain', function( $loaded, $domain, $mofile, $locale ) {
    if ( 'my-plugin' === $domain ) {
        // Load from API, cache, etc.
        load_custom_translations( $domain, $locale );
        return true; // Skip normal loading
    }
    return $loaded;
}, 10, 4 );

override_load_textdomain

Allows overriding the default MO file loading.

apply_filters( 'override_load_textdomain', bool $override, string $domain, string $mofile, string|null $locale )

Example:

add_filter( 'override_load_textdomain', function( $override, $domain, $mofile, $locale ) {
    if ( 'my-plugin' === $domain ) {
        // Handle loading yourself
        return true;
    }
    return $override;
}, 10, 4 );

load_textdomain_mofile

Filters the MO file path before loading.

apply_filters( 'load_textdomain_mofile', string $mofile, string $domain )

Example – Use custom translation directory:

add_filter( 'load_textdomain_mofile', function( $mofile, $domain ) {
    if ( 'my-plugin' === $domain ) {
        return '/custom/path/my-plugin-' . get_locale() . '.mo';
    }
    return $mofile;
}, 10, 2 );

load_translation_file

Filters the translation file path (MO or PHP).

apply_filters( 'load_translation_file', string $file, string $domain, string $locale )

Since: WordPress 6.5.0


translation_file_format

Filters preferred translation file format.

apply_filters( 'translation_file_format', string $format, string $domain )

Since: WordPress 6.5.0

Parameters:

  • $format – ‘php’ or ‘mo’ (default: ‘php’)
  • $domain – Text domain

Example – Force MO files:

add_filter( 'translation_file_format', function( $format, $domain ) {
    return 'mo'; // Always use MO files instead of PHP
}, 10, 2 );

override_unload_textdomain

Allows overriding text domain unloading.

apply_filters( 'override_unload_textdomain', bool $override, string $domain, bool $reloadable )

Script Translation Filters

pre_load_script_translations

Short-circuits script translation loading.

apply_filters( 'pre_load_script_translations', string|false|null $translations, string|false $file, string $handle, string $domain )

Since: WordPress 5.0.2


load_script_translation_file

Filters the script translation file path.

apply_filters( 'load_script_translation_file', string|false $file, string $handle, string $domain )

load_script_translations

Filters loaded script translations (JSON).

apply_filters( 'load_script_translations', string $translations, string $file, string $handle, string $domain )

load_script_textdomain_relative_path

Filters the relative path used for finding script translations.

apply_filters( 'load_script_textdomain_relative_path', string|false $relative, string $src )

Locale Switching Actions

switch_locale

Fires when the locale is switched.

do_action( 'switch_locale', string $locale, int|false $user_id )

Since: WordPress 4.7.0

Example:

add_action( 'switch_locale', function( $locale, $user_id ) {
    // Clear locale-specific caches
    wp_cache_delete( 'my_locale_cache' );
}, 10, 2 );

restore_previous_locale

Fires when the locale is restored.

do_action( 'restore_previous_locale', string $locale, string $previous_locale )

Since: WordPress 4.7.0


change_locale

Fires when the locale is changed (switch or restore).

do_action( 'change_locale', string $locale )

Since: WordPress 4.7.0

Example:

add_action( 'change_locale', function( $locale ) {
    // Re-initialize locale-dependent features
    global $wp_locale;
    $wp_locale = new WP_Locale();
} );

Text Domain Loading Actions

load_textdomain

Fires before a MO file is loaded.

do_action( 'load_textdomain', string $domain, string $mofile )

Example:

add_action( 'load_textdomain', function( $domain, $mofile ) {
    error_log( "Loading translations for {$domain} from {$mofile}" );
}, 10, 2 );

unload_textdomain

Fires before a text domain is unloaded.

do_action( 'unload_textdomain', string $domain, bool $reloadable )

Since: WordPress 3.0.0 (reloadable param added 6.1.0)


Language List Filters

get_available_languages

Filters the list of available language codes.

apply_filters( 'get_available_languages', string[] $languages, string $dir )

Example:

add_filter( 'get_available_languages', function( $languages, $dir ) {
    // Add a custom language
    $languages[] = 'custom_LANG';
    return $languages;
}, 10, 2 );

Practical Examples

Override All Translations for a Domain

add_filter( 'gettext_my-plugin', function( $translation, $text, $domain ) {
    $overrides = [
        'Submit'  => 'Send',
        'Cancel'  => 'Never mind',
        'Save'    => 'Keep it',
    ];
    
    return $overrides[ $text ] ?? $translation;
}, 10, 3 );

Log Untranslated Strings (Development)

add_filter( 'gettext', function( $translation, $text, $domain ) {
    if ( $translation === $text && 'default' !== $domain ) {
        error_log( "Untranslated [{$domain}]: {$text}" );
    }
    return $translation;
}, 10, 3 );

Dynamic Locale Based on User Meta

add_filter( 'locale', function( $locale ) {
    if ( is_user_logged_in() ) {
        $user_locale = get_user_meta( get_current_user_id(), 'preferred_locale', true );
        if ( $user_locale ) {
            return $user_locale;
        }
    }
    return $locale;
} );

Preload Translations from Cache

add_filter( 'pre_load_textdomain', function( $loaded, $domain, $mofile, $locale ) {
    $cache_key = "translations_{$domain}_{$locale}";
    $cached = wp_cache_get( $cache_key, 'l10n' );
    
    if ( $cached ) {
        // Inject cached translations
        return true;
    }
    
    return $loaded; // Continue normal loading
}, 10, 4 );

Force RTL for Testing

add_filter( 'locale', function( $locale ) {
    if ( isset( $_GET['test_rtl'] ) ) {
        return 'he_IL'; // Hebrew (RTL language)
    }
    return $locale;
} );