agentsclimarketplace

Wpml string translation

Skill Lonsdale201/wp-agent-skills/wpml/wpml-string-translation

A community-maintained collection of agent skills for WordPress plugin and theme development.

Install
npx -y skills add Lonsdale201/wp-agent-skills --skill wpml-string-translation

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 21 stars21 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Register and translate a WordPress plugin's dynamic strings with WPML — option values, admin-entered labels, and other free-form text that is NOT a static gettext string. Register via do_action('wpml_register_single_string', $domain, $name, $value) and read back via apply_filters('wpml_translate_single_string', $value, $domain, $name[, $lang]); legacy equivalents are icl_register_string( $context, $name, $value) and icl_t(). CRITICAL — these handlers live in the WPML String Translation add-on, NOT the base plugin — the base only FIRES the hooks, so without ST the translate filter returns the original (safe) and register is a silent no-op, while raw unguarded icl_register_string / icl_t calls FATAL. Covers detecting ST (defined('WPML_ST_VERSION'), class_exists('WPML_String_Translation'), function_exists('icl_register_string')), the function_exists fallback wrapper pattern, and when to use wpml-config admin-texts instead. Use for translatable settings, dynamic labels, or any registered string.

SKILL.md

9.9 KB, as published. Nobody here has run it

WPML: string registration & translation

For free-form / dynamic strings your plugin emits that WPML can't reach otherwise — option values entered in your settings, admin-defined labels, messages built at runtime. Static UI text stays on normal WordPress i18n (__(), _e() + .po/.mo); this skill is only for strings that live in the database or are generated dynamically.

Read this first — it needs the String Translation add-on

The base plugin only FIRES the string hooks; the handlers that actually store and translate strings ship with the separate WPML String Translation add-on. Verified: there is no add_action('wpml_register_single_string', …) or add_filter('wpml_translate_single_string', …) anywhere in sitepress-multilingual-cms, and icl_register_string / icl_t / icl_gettext are not defined in the base plugin.

Standard WordPress hook semantics then give you a safe default only for the hook form:

  • apply_filters('wpml_translate_single_string', $value, …) with no handler → returns $value unchanged (original text; safe fallback).
  • do_action('wpml_register_single_string', …) with no handler → silent no-op.
  • icl_register_string() / icl_t() called directly with ST inactive → fatal undefined function unless guarded.

So: prefer the hook form (degrades safely), and if you use the legacy icl_* functions, guard every call with function_exists().

Detecting String Translation

// Preferred:
if ( defined( 'WPML_ST_VERSION' ) ) { /* ST active */ }

// Base ships a helper that does exactly this:
if ( function_exists( 'wpml_is_st_loaded' ) && wpml_is_st_loaded() ) { /* ST active */ }

// Also used internally:
class_exists( 'WPML_String_Translation' );

// Feature-detect the legacy API before calling it:
function_exists( 'icl_register_string' );

wpml_is_st_loaded() returns defined('WPML_ST_VERSION') (inc/functions.php:922-924); class_exists('WPML_String_Translation') is used at inc/translation-management/translation-management.class.php:1742.

Register and translate — the hook form (recommended)

Register the string once (typically when you save the option that holds it), then translate it on output:

$domain = 'my-plugin';               // WPML "context" that groups your strings
$name   = 'welcome_heading';         // stable, unique per string within the domain
$value  = get_option( 'my_plugin_welcome' );

// 1) Register (no-op if ST inactive):
do_action( 'wpml_register_single_string', $domain, $name, $value );

// 2) Translate on output (returns $value unchanged if ST inactive or untranslated):
echo esc_html( apply_filters( 'wpml_translate_single_string', $value, $domain, $name ) );

Verified signatures in the base plugin's own call sites:

(There is also a heavier package form do_action('wpml_register_string', $value, $name, $package, $title, $type) used by page-builder integrations — for ordinary plugin strings use the _single_string form above.)

Legacy icl_* form — guard it

icl_register_string( $context, $name, $value ) and icl_t( $context, $name, $value ) are the older API (provided by ST). They fatal if ST is inactive, so wrap them — this is exactly the pattern WPML ships in its theme-integration example (docs/theme-integration/wpml-integration.php:130-142):

function my_plugin_register_string( $context, $name, $value ) {
    if ( function_exists( 'icl_register_string' ) && trim( $value ) ) {
        icl_register_string( $context, $name, $value );
    }
}

function my_plugin_t( $context, $name, $original_value ) {
    return function_exists( 'icl_t' )
        ? icl_t( $context, $name, $original_value )
        : $original_value;   // graceful fallback
}

The hook form above needs no such guard (the hooks simply don't fire without ST), which is why it's preferred for new code.

When to use <admin-texts> in wpml-config.xml instead

For option values stored in wp_options, the cleaner path is often the declarative <admin-texts> section in wpml-config.xml — WPML String Translation reads it and exposes those options for translation automatically, no do_action('wpml_register_single_string', …) needed:

<admin-texts>
    <key name="my_plugin_options">
        <key name="welcome_heading" />
    </key>
</admin-texts>

Both paths require String Translation. Use <admin-texts> for settings that live in an option; use runtime registration for strings built dynamically (loops, per-item labels) that don't map to a fixed option key. See wpml-config for the <admin-texts> shape.

Critical rules

  • String registration/translation requires WPML String Translation. Detect with defined('WPML_ST_VERSION') and design so your plugin still works (untranslated) without it.
  • Prefer the hook form (wpml_register_single_string / wpml_translate_single_string) — it degrades to a no-op / passthrough with ST absent. Raw icl_register_string / icl_t fatal unguarded.
  • Guard every legacy icl_* call with function_exists().
  • $domain + $name must be stable. Changing them orphans existing translations (WPML keys strings by context + name). Namespace the domain to your plugin.
  • Register before you translate. A string that's never registered has no translation to return — the filter returns the original.
  • Don't register a static gettext string here. Use __()/_e() + a .pot for fixed UI text; reserve this for DB/dynamic values.
  • Escape on output as usual (esc_html, etc.) — the translated string is untrusted output like any other.

Common mistakes

// WRONG — direct legacy call; fatal if String Translation isn't active
echo icl_t( 'my-plugin', 'welcome', $value );

// RIGHT — hook form, safe without ST
do_action( 'wpml_register_single_string', 'my-plugin', 'welcome', $value );
echo esc_html( apply_filters( 'wpml_translate_single_string', $value, 'my-plugin', 'welcome' ) );

// WRONG — assuming translation "works" on base WPML with no ST add-on
// (the filter returns the ORIGINAL string, silently — verify WPML_ST_VERSION if you depend on it)

// WRONG — unstable name breaks saved translations on every save
do_action( 'wpml_register_single_string', 'my-plugin', 'welcome_' . time(), $value );
// RIGHT — stable name
do_action( 'wpml_register_single_string', 'my-plugin', 'welcome_heading', $value );

Cross-references

  • wpml-config<admin-texts> for translating options declaratively (also needs ST).
  • wpml-overview — the base-vs-add-on split and when strings are even the right tool.
  • wpml-language-api — resolving translated object IDs (a different concern from translating strings).

What this skill does NOT cover

  • The String Translation admin UI / scanning — end-user workflow, not developer API.
  • .po/.mo gettext translation of static strings — that's core WordPress i18n; wpml-config.xml has no <gettext-domains> section (see wpml-config reference).
  • The page-builder package form (wpml_register_string with a $package) beyond a mention — that's for builder integrations.
  • WPML's own internal string storage schema — interact via the hooks.

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.