*/ private $previous_language = []; /** * Whether WPML is active and at the minimum supported version. * * @since 2.11.0 * @return bool True when WPML 4.5+ is available, false otherwise. */ public function is_active(): bool { if ( null !== $this->is_active_cache ) { return $this->is_active_cache; } $active = defined( 'ICL_SITEPRESS_VERSION' ) && class_exists( '\SitePress' ) && version_compare( (string) constant( 'ICL_SITEPRESS_VERSION' ), self::MIN_WPML_VERSION, '>=' ); $this->is_active_cache = $active; return $this->is_active_cache; } /** * Current visitor language code as reported by WPML. * * @since 2.11.0 * @return string Language code, or empty string when WPML is inactive or the filter returns a non-string. */ public function current_language(): string { if ( ! $this->is_active() ) { return ''; } $language = apply_filters( 'wpml_current_language', null ); return is_string( $language ) ? $language : ''; } /** * Site default language code as reported by WPML. * * @since 2.11.0 * @return string Language code, or empty string when WPML is inactive or the filter returns a non-string. */ public function default_language(): string { if ( ! $this->is_active() ) { return ''; } $language = apply_filters( 'wpml_default_language', null ); return is_string( $language ) ? $language : ''; } /** * Register a string with WPML's String Translation registry. * * @param string $name Unique string identifier within the domain. * @param string $value Original string value to register. * @param string $domain Translation domain. Defaults to the sureforms text domain. * @since 2.11.0 * @return void */ public function register_string( string $name, string $value, string $domain = 'sureforms' ): void { if ( ! $this->is_active() ) { return; } do_action( 'wpml_register_single_string', $domain, $name, $value ); } /** * Translate a registered string via WPML. * * @param string $value Original string value (used as fallback). * @param string $name Unique string identifier within the domain. * @param string $domain Translation domain. Defaults to the sureforms text domain. * @param string|null $language Optional target language code. When null, uses the current language. * @since 2.11.0 * @return string Translated value, or the original $value when WPML is inactive or no translation exists. */ public function translate( string $value, string $name, string $domain = 'sureforms', ?string $language = null ): string { if ( ! $this->is_active() ) { return $value; } if ( null !== $language ) { $translated = apply_filters( 'wpml_translate_single_string', $value, $domain, $name, $language ); } else { $translated = apply_filters( 'wpml_translate_single_string', $value, $domain, $name ); } if ( null === $translated || ! is_string( $translated ) ) { return $value; } return $translated; } /** * Push the current language onto an internal stack and switch WPML to $language. * * @param string $language Target language code to switch to. * @since 2.11.0 * @return void */ public function switch_language( string $language ): void { if ( ! $this->is_active() ) { return; } $this->previous_language[] = $this->current_language(); do_action( 'wpml_switch_language', $language ); } /** * Pop the previous language off the internal stack and restore WPML's context. * * @since 2.11.0 * @return void */ public function restore_language(): void { if ( ! $this->is_active() ) { return; } if ( empty( $this->previous_language ) ) { return; } $previous = array_pop( $this->previous_language ); do_action( 'wpml_switch_language', $previous ); } /** * {@inheritDoc} * * Builds a self-contained list-based switcher from WPML's `wpml_active_languages` * data. Doesn't depend on the site's WPML "switcher slot" being enabled (footer, * post-actions, etc.), so it works on custom templates that don't include the * theme footer — like SureForms' single-form.php instant-form template. * * Returns empty when WPML is inactive or fewer than two languages are configured. * * @since 2.11.0 * @return string Rendered switcher HTML, or empty string. */ public function render_language_switcher(): string { if ( ! $this->is_active() ) { return ''; } $languages = $this->get_active_languages(); if ( count( $languages ) < 2 ) { return ''; } $current = $this->current_language(); $items = ''; foreach ( $languages as $code => $language ) { $url = isset( $language['url'] ) && is_string( $language['url'] ) ? $language['url'] : ''; $native = isset( $language['native_name'] ) && is_string( $language['native_name'] ) ? $language['native_name'] : ''; $lang = isset( $language['language_code'] ) && is_string( $language['language_code'] ) ? $language['language_code'] : (string) $code; if ( '' === $url || '' === $native ) { continue; } // Prefer WPML's own `active` flag from wpml_active_languages (the canonical // current-language signal for the switcher), falling back to comparing against // current_language() when the flag isn't present. $is_current = isset( $language['active'] ) ? ! empty( $language['active'] ) : ( $lang === $current ); $class = $is_current ? 'srfm-lang-item srfm-lang-item-current' : 'srfm-lang-item'; $items .= sprintf( '