Support Log in

58. Translation / String Hooks

Developer Guide
Prefer video? Watch the Fillin Forge tutorials 9 short guides covering every feature Watch

Fillin Forge exposes a small set of hooks so a multilingual stack (Lang Forge first-party, anything compatible by contract) can localize labels, placeholders, options, and form-level text. The hooks are passive — without a listener the original strings are emitted unchanged, so sites without a translation plugin keep working exactly the way they did before.

Filter: formforge_translate_string

Fires for every translatable string Fillin Forge renders (labels, placeholders, descriptions, option labels, submit button, success message, schedule message). A translation plugin attaches to this filter and returns the translated string for the current language.

php
add_filter('formforge_translate_string', function ($string, $key, $field_id, $form_id) {
    // $string   - the source-language string (e.g. "Name")
    // $key      - which slot the string fills:
    //               'label', 'placeholder', 'description',
    //               'option_label:<value>',
    //               'submit_text', 'success_message', 'schedule_message'
    // $field_id - the field's `id` from wp_formforge_forms.fields. Empty
    //             string for form-level keys.
    // $form_id  - integer form id.
    if ($key === 'label' && $field_id === 'name') {
        // Look up your translation here.
        return my_plugin_translate($string, "form-{$form_id}-name");
    }
    return $string;
}, 10, 4);

Returning the original $string is the correct fallback when no translation is available — the renderer escapes the result, so the user never sees a missing-translation marker.

Action: formforge/strings_registered

Fires after a form is created or updated, with every translatable string in a single call. Listeners use this to register strings in their translation tables in batches.

php
add_action('formforge/strings_registered', function ($form_id, $strings) {
    // $strings is an array of:
    //   ['key' => '<key>', 'field_id' => '<field_id>', 'value' => '<source string>']
    foreach ($strings as $entry) {
        my_plugin_register_string($form_id, $entry['key'], $entry['field_id'], $entry['value']);
    }
}, 10, 2);

Re-fires on every save, so renamed labels and added options end up in your translation table without an explicit re-import. Listeners should treat registration as idempotent (INSERT IGNORE / upsert by (form_id, key, field_id)).

Action: formforge/strings_unregistered

Fires when a form is deleted, after its row in wp_formforge_forms and its submissions and analytics rows have been removed. Use this to clean up translations attached to the form.

php
add_action('formforge/strings_unregistered', function ($form_id) {
    my_plugin_delete_form_strings($form_id);
}, 10, 1);

Filter: formforge_current_language

Returns the visitor’s current language at form-render time. The result is emitted into the rendered form as a hidden formforge_lang input so a translation plugin can read the language from the submit request (Fillin Forge itself does not read this field; admin-ajax requests don’t carry the URL-prefix or ?lang= signal a multilingual plugin would normally use to detect the visitor’s language).

php
add_filter('formforge_current_language', function ($default, $form_id) {
    return my_plugin_get_current_language() ?: $default;
}, 10, 2);

Return '' (the default) to skip the hidden field entirely.

The language during the AJAX submit

Fillin Forge puts the visitor’s language into the hidden formforge_lang field of the form (see formforge_current_language above). The field comes back in the submit request, and Fillin Forge builds the success message through formforge_translate_string, which receives only $string, $key, $field_id and $form_id. Fillin Forge does not read formforge_lang itself and has no filter to override the language at that point. A translation plugin that wants the language has to read $_POST['formforge_lang'] itself, inside its formforge_translate_string listener. Lang Forge does this in a filter of its own, langforge_formforge_translate_lang_override, which belongs to Lang Forge and not to Fillin Forge.

Per-form string domain

The Lang Forge listener uses formforge: as the per-form string_domain in wp_langforge_strings. This keeps every form’s strings grouped together and makes per-form cleanup a single DELETE WHERE string_domain = ? call. If you are writing a non-LangForge listener, follow the same convention so admin tools that aggregate across translation backends can match strings to forms reliably.

Stable string names

To keep translations stable across re-saves, Fillin Forge does not include the source-language text in its generated string names. The names are:

  • Field-level: field__ — e.g. field_name_label, field_email_placeholder, field_category_option_label:business
  • Form-level: — e.g. submit_text, success_message, schedule_message

Renaming a field’s id will reset its translation key (intentional, because the identity of the field changed). Renaming a label’s text without changing the id keeps the existing translation row in place, so the translator’s previous work is preserved (you may want to mark it for review — that’s a translation-plugin concern, not a Fillin Forge one).

—

Forge AI Assistant Online

Hi! I'm the Fillin Forge AI assistant. Ask me anything about the plugin — setup, features, troubleshooting, or development.

Just now
Powered by Forge AI · Browse docs