Followup on previous topic - Part #2

Hi,

I do have un update on Followup on previous topic!

WPML support was very persisting this time, and ended up with providing custom code that makes it possible to translate content on a Single Layout. The codes is not (yet) perfect, as it doesn’t recognise content that’s nested inside an elements, such as text strings in a counter-element. Is that something you guys could chip in? It would be great to see the compatibility between ThemeCo and WPML increase again, and I hope sharing this, helps a bit. But it would be great if your developers would add their bit as well!

/**
 * WPML Workaround for compsupp-8255 
 */
 
// 1. Register strings when saving Layout posts.
  
add_action( 'save_post', function( $post_id, $post, $update ) {
 
    if ( wp_is_post_revision( $post_id ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ) {
        return;
    }
 
    $pt = get_post_type( $post_id );
    $layout_types = [ 'cs_layout_single', 'cs_layout_archive', 'cs_layout_single_wc', 'cs_layout_archive_wc' ];
 
    // If the site uses other cs_layout_* types, widen this check:
    // if ( strpos( $pt, 'cs_layout_' ) !== 0 ) return;
    if ( ! in_array( $pt, $layout_types, true ) ) {
        return;
    }
 
    // Only if WPML String Translation is present.
    if ( ! has_action( 'wpml_register_single_string' ) ) {
        return;
    }
 
    $data = json_decode( (string) $post->post_content, true );
    if ( ! is_array( $data ) ) {
        return;
    }
 
    $items   = cs_wpml_cs_collect_text_content( $data ); // [ path => original_text ]
    $context = 'cornerstone-layout';
 
    foreach ( $items as $path => $original ) {
        // Includes a short hash to avoid collisions and keep it semi-readable in ST.
        $hash = substr( md5( $path . '|' . $original ), 0, 10 );
        $name = $path . ' #' . $hash;
 
        do_action( 'wpml_register_single_string', $context, $name, $original );
    }
 
}, 10, 3 );
 
 
// 2. Replace strings on load for Layout documents.
 
add_filter( 'cs_layout_load_content', function( $post_content ) {
 
    if ( ! has_filter( 'wpml_translate_single_string' ) ) {
        return $post_content;
    }
 
    $data = json_decode( (string) $post_content, true );
    if ( ! is_array( $data ) ) {
        return $post_content;
    }
 
    $context = 'cornerstone-layout';
 
    $data = cs_wpml_cs_translate_text_content( $data, $context );
 
    return wp_json_encode( $data );
 
}, 10, 1 );
 
 
// Collect ONLY 'text_content' strings
 
function cs_wpml_cs_collect_text_content( array $data ) : array {
    $out = [];
 
    $walk = function( $node, $path ) use ( &$walk, &$out ) {
 
        if ( is_array( $node ) ) {
            foreach ( $node as $k => $v ) {
 
                $new_path = ( $path === '' ) ? (string) $k : $path . '.' . $k;
 
                if ( $k === 'text_content' && is_string( $v ) ) {
                    // Skip Dynamic Content tokens like {{dc:...}} or {{ acf... }}
                    if ( strpos( $v, '{{' ) === false ) {
                        $out[ $new_path ] = $v;
                    }
                    continue;
                }
 
                if ( is_array( $v ) ) {
                    $walk( $v, $new_path );
                }
            }
        }
    };
 
    $walk( $data, '' );
    return $out;
}
 
 
/**
 * Translate ONLY 'text_content' strings.
 */
function cs_wpml_cs_translate_text_content( array $data, string $context ) : array {
 
    $walk = function( $node, $path ) use ( &$walk, $context ) {
 
        if ( is_array( $node ) ) {
            foreach ( $node as $k => $v ) {
 
                $new_path = ( $path === '' ) ? (string) $k : $path . '.' . $k;
 
                if ( $k === 'text_content' && is_string( $v ) ) {
 
                    // Skip Dynamic Content tokens like {{...}}
                    if ( strpos( $v, '{{' ) === false ) {
 
                        $hash = substr( md5( $new_path . '|' . $v ), 0, 10 );
                        $name = $new_path . ' #' . $hash;
 
                        $node[ $k ] = apply_filters( 'wpml_translate_single_string', $v, $context, $name );
                    }
 
                    continue;
                }
 
                if ( is_array( $v ) ) {
                    $node[ $k ] = $walk( $v, $new_path );
                }
            }
        }
 
        return $node;
    };
 
    return $walk( $data, '' );
}

-Resave your single layout in the Cornerstone editor

-Go to WPML > String Translation and look for the domain “cornerstone-layout”

-If needed, select the strings and change their language to Dutch

-Translate them

-Go to “Cornerstone > Settings” and clear cache.

1 Like

Hey @dhunink,

Thanks for sharing this.
I will bookmark this because I believe it will be invaluable to other users as well.

Cheers.

Hi @ruenel,

You’re welcome, I’m happy to hear that you value this! If I have updated code that will work with more elements, I will post that code.

Could you please take a moment to discuss my remarks with the developers as well? As I stated in my previous message:

Is that something you guys could chip in? It would be great to see the compatibility between ThemeCo and WPML increase again, and I hope sharing this, helps a bit. But it would be great if your developers would add their bit as well!

I’ve reached out to them about improving this. Thanks for the info and code you sent us.

Hi @ruenel and @charlie,

The 2nd tier support of WPML has updated their code and published it at https://wpml.org/errata/pro-theme-layout-texts-not-translatable-via-wpml-translation-editor/. In another conversation I had with them they hinted that this may also make translating Footer-elements possible. Sounds very interesting. But at the same time I do realise that their remark at the end is something that will require manual action each time that elements are added or renamed on your end.

**Note:**
Depending on the widgets used in your layout, you might need to expand the list of keys in both functions  `'cs_wpml_cs_collect_text_content'`  and  `'cs_wpml_cs_translate_text_content'`  (to add keys such as ‘ *toggle_anchor_text_primary_content* ‘, ‘ *card_front_text_content* ‘, ‘ *card_back_text_content* ‘, etc.).

That might be worth something to discuss between @Charlie and WPML-dev?
I’m looking forward to learn how discussion is going. If I can help by testing something out, I’d be more than okay to do so!

Hey @dhunink,

Thank you for the update. Reviewing the code, it indeed has the potential to translate the Cornerstone Footer and this would require adding all the translatable fields whether manually or programatically. It would be best for @charlie to see this so I’m forwarding this to him.

Please stay tuned.

Hi @christian,

I understand why you’re forwarding this to @Charlie. I do get the feeling that we’re getting pretty close to finally improve the compatibility between WPML and Pro tough, with the custom code WPML support shared.
The big issue in their code is the need to add every translatable element by hand, which is simply not a okay option, from a programmers perspective. But I’m sure @charlie will have a thought on this.

In the meantime I’m going to add a few elements to that custom code, so my own website is working as expected.
Where can I find the correct names for all translatable strings for the Card-element?

It’s two fold since we need to get a way for them to translate similar to how they do pages. And since we have many new elements coming out, we’re going to create a system for them to get all element keys to translate. We’re going to try some things for Pro 6.8.

If you enable the Cornerstone dev tools. You can get a list of all values. Look for “content” most of the Card element values that should be translated are named similar to that.

Let us know if that helps.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.