WPML
WPML support
When WPML is active, Smart Add-Ons passes addon labels through WPML’s string translation API. Dynamic addon strings still need to be registered with String Translation before they actually translate.
What “supports WPML” means here. The lookup filter is real and wired up. String registration is not — without it, WPML returns the original addon labels. Plugin UI strings (wp-admin menus, settings labels) are a separate .pot file and are not covered by this guide.
What the plugin does
When WPML is active (ICL_SITEPRESS_VERSION is defined), WpmlIntegration attaches to saue_translate_string and calls apply_filters( 'wpml_translate_single_string', $value, $context, $name ). You do not add that filter yourself.
StringTranslator runs every addon group’s name and description, and every field’s label, description, placeholder, and option labels, through that filter when a group is formatted for output.
Context and name values
Registration must use the same context and name values the plugin uses to look translations up. If they do not match, WPML will not apply the translation.
| String | Context | Name |
|---|---|---|
| Group name | saue_group | name_{group_id} |
| Group description | saue_group | description_{group_id} |
| Field label | saue_field | label_{field_id} |
| Field description | saue_field | description_{field_id} |
| Field placeholder | saue_field | placeholder_{field_id} |
| Option label | saue_field_option | option_{field_id}_{value} (or option_{field_id} if the value is empty) |
What is missing
Nowhere in the plugin does it call icl_register_string() (or WPML’s newer wpml_register_single_string action) for these dynamic per-group and per-field strings. wpml_translate_single_string only returns a translation for an already-registered string; otherwise it echoes the original back. As shipped, addon labels will likely not be translated by WPML until you register them.
Register strings when a group is saved
Add this to a mu-plugin or the theme functions.php. saue_addon_group_saved receives the group ID only. Save groups while the site is in its default language so WPML registers the original strings, not a translation. After this is in place, save each existing group once so its strings appear in WPML → String Translation.
/**
* Register Smart Add-Ons group/field strings with WPML String Translation.
*
* The plugin looks translations up via wpml_translate_single_string
* (contexts saue_group, saue_field, saue_field_option). It does not
* call icl_register_string(), so WPML will not list these strings
* until you register them. Context and name must match StringTranslator.
*/
add_action( 'saue_addon_group_saved', function ( $group_id ) {
if ( ! function_exists( 'icl_register_string' ) ) {
return;
}
if ( ! class_exists( SmartAddonsUpsellEngineCorePlugin::class ) ) {
return;
}
$group = SmartAddonsUpsellEngineCorePlugin::getInstance()
->getContainer()
->make( SmartAddonsUpsellEngineAddonsAddonRepository::class )
->getGroupById( (int) $group_id );
if ( ! is_array( $group ) ) {
return;
}
saue_wpml_register_group_strings( $group );
} );
function saue_wpml_register_group_strings( array $group ) {
$group_id = (int) ( $group['id'] ?? 0 );
if ( $group_id <= 0 ) {
return;
}
if ( ! empty( $group['name'] ) && is_string( $group['name'] ) ) {
icl_register_string( 'saue_group', 'name_' . $group_id, $group['name'] );
}
if ( ! empty( $group['description'] ) && is_string( $group['description'] ) ) {
icl_register_string( 'saue_group', 'description_' . $group_id, $group['description'] );
}
foreach ( $group['fields'] ?? [] as $field ) {
$field_id = (int) ( $field['id'] ?? 0 );
if ( $field_id <= 0 ) {
continue;
}
foreach ( [ 'label', 'description', 'placeholder' ] as $key ) {
if ( empty( $field[ $key ] ) || ! is_string( $field[ $key ] ) ) {
continue;
}
icl_register_string( 'saue_field', $key . '_' . $field_id, $field[ $key ] );
}
foreach ( $field['options'] ?? [] as $option ) {
if ( empty( $option['label'] ) || ! is_string( $option['label'] ) ) {
continue;
}
$value = (string) ( $option['value'] ?? '' );
$name = $value !== ''
? 'option_' . $field_id . '_' . $value
: 'option_' . $field_id;
icl_register_string( 'saue_field_option', $name, $option['label'] );
}
}
}After registration
- Open WPML → String Translation and filter by domain/context
saue_group,saue_field, orsaue_field_option. - Enter translations for each language. On the storefront, the built-in filter returns those translations when the visitor’s language matches.
- WPML’s newer equivalent of
icl_register_string()isdo_action( 'wpml_register_single_string', $context, $name, $value )— either works; the context and name values must still match the table above. - Plugin chrome (menus, settings, notices) uses the
sauetext domain and the.potfile in/languages/. That is unrelated to these dynamic addon strings.
Hook signatures: Hooks & Filters.