<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sasa</title>
    <description>The latest articles on DEV Community by Sasa (@sasa_593fa920f64dac14df3c).</description>
    <link>https://dev.to/sasa_593fa920f64dac14df3c</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3940548%2Fc7a82154-d8c8-4045-8df8-beb449a65558.jpg</url>
      <title>DEV Community: Sasa</title>
      <link>https://dev.to/sasa_593fa920f64dac14df3c</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sasa_593fa920f64dac14df3c"/>
    <language>en</language>
    <item>
      <title>How to localize Klaviyo email campaigns without breaking tokens</title>
      <dc:creator>Sasa</dc:creator>
      <pubDate>Tue, 19 May 2026 16:05:13 +0000</pubDate>
      <link>https://dev.to/sasa_593fa920f64dac14df3c/how-to-localize-klaviyo-email-campaigns-without-breaking-tokens-jmb</link>
      <guid>https://dev.to/sasa_593fa920f64dac14df3c/how-to-localize-klaviyo-email-campaigns-without-breaking-tokens-jmb</guid>
      <description>&lt;h2&gt;
  
  
  The Klaviyo localization problem
&lt;/h2&gt;

&lt;p&gt;Klaviyo uses Django-style template syntax for personalization: &lt;code&gt;{{ first_name|default:"there" }}&lt;/code&gt;, &lt;code&gt;{{ order.total|currency }}&lt;/code&gt;. When you send these templates for translation, two things break consistently.&lt;/p&gt;

&lt;p&gt;First, translators modify the variable names. &lt;code&gt;{{ first_name }}&lt;/code&gt; becomes &lt;code&gt;{{ Vorname }}&lt;/code&gt; in German workflows. Second, filter arguments get translated — the &lt;code&gt;"there"&lt;/code&gt; in &lt;code&gt;{{ first_name|default:"there" }}&lt;/code&gt; is legitimate translatable content, but it sits inside a token that should otherwise be untouched.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right approach
&lt;/h2&gt;

&lt;p&gt;Protect the entire token at import. Replace &lt;code&gt;{{ first_name|default:"there" }}&lt;/code&gt; with a stable placeholder before any content reaches a translator. Restore the original on export.&lt;/p&gt;

&lt;p&gt;For Klaviyo specifically, you need to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple variables: &lt;code&gt;{{ first_name }}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Variables with filters: &lt;code&gt;{{ first_name|default:"there" }}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Numeric filters: &lt;code&gt;{{ order.total|currency }}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The regex pattern that covers Klaviyo Django syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="n"&gt;KLAVIYO_PATTERN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\{\{[-\s]*[\w.|:()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\' ]+[-\s]*\}\}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connecting Klaviyo to a localization workflow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://transendly.com" rel="noopener noreferrer"&gt;Transendly&lt;/a&gt; connects directly to Klaviyo via API. Import your template, tokens are auto-detected and locked, translators work on clean copy, approved translations push back to Klaviyo as new templates per locale.&lt;/p&gt;

&lt;p&gt;Free 21-day trial at &lt;a href="https://transendly.com" rel="noopener noreferrer"&gt;transendly.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>email</category>
      <category>klaviyo</category>
      <category>localization</category>
      <category>saas</category>
    </item>
    <item>
      <title>How to detect and protect ESP tokens across 5 different template syntaxes</title>
      <dc:creator>Sasa</dc:creator>
      <pubDate>Tue, 19 May 2026 15:09:28 +0000</pubDate>
      <link>https://dev.to/sasa_593fa920f64dac14df3c/how-to-detect-and-protect-esp-tokens-across-5-different-template-syntaxes-3b0f</link>
      <guid>https://dev.to/sasa_593fa920f64dac14df3c/how-to-detect-and-protect-esp-tokens-across-5-different-template-syntaxes-3b0f</guid>
      <description>&lt;h1&gt;
  
  
  How to detect and protect ESP tokens across 5 different template syntaxes
&lt;/h1&gt;

&lt;p&gt;When you're building a multilingual email workflow, one problem shows up immediately: every major email service provider uses a different syntax for personalization tokens. And every one of them will break silently if a translator touches the wrong characters.&lt;/p&gt;

&lt;p&gt;This is the problem we solved building &lt;a href="https://transendly.com" rel="noopener noreferrer"&gt;Transendly&lt;/a&gt; — a localization workspace for HTML email campaigns. Here's what we learned about token detection across the five most common ESP syntaxes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The five syntaxes you'll encounter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Handlebars — SendGrid, Postmark
&lt;/h3&gt;

&lt;p&gt;SendGrid Dynamic Templates and Postmark both use Handlebars-compatible syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight handlebars"&gt;&lt;code&gt;&lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;first_name&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;{{#if&lt;/span&gt; &lt;span class="nv"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;plan&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
  You're on the &lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;plan&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt; plan.
&lt;span class="k"&gt;{{/if}}&lt;/span&gt;
&lt;span class="k"&gt;{{#&lt;/span&gt;&lt;span class="nn"&gt;each&lt;/span&gt; &lt;span class="nv"&gt;items&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
  &lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt; — &lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;{{/&lt;/span&gt;&lt;span class="nn"&gt;each&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;{{{&lt;/span&gt;&lt;span class="nv"&gt;unescaped_html&lt;/span&gt;&lt;span class="k"&gt;}}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key things to detect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Double-stache &lt;code&gt;{{variable}}&lt;/code&gt; — simple interpolation&lt;/li&gt;
&lt;li&gt;Triple-stache &lt;code&gt;{{{variable}}}&lt;/code&gt; — unescaped HTML output (Postmark uses this for &lt;code&gt;{{{pm:unsubscribe}}}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Block helpers: &lt;code&gt;{{#if}}...{{/if}}&lt;/code&gt;, &lt;code&gt;{{#each}}...{{/each}}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Nested paths: &lt;code&gt;{{customer.first_name}}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The triple-stache is a common failure point. Translators working in raw HTML often "fix" the extra brace because it looks like a typo.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Django template tags — Klaviyo
&lt;/h3&gt;

&lt;p&gt;Klaviyo uses Django-style syntax with a key difference: filter chaining.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;first_name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;first_name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"there"&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;order_total&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;currency&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;description&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;truncatewords&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;20&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="ni"&gt;&amp;amp;#123;&lt;/span&gt;% if person.plan == "vip" %&lt;span class="ni"&gt;&amp;amp;#125;&lt;/span&gt;
  Exclusive content here.
&lt;span class="ni"&gt;&amp;amp;#123;&lt;/span&gt;% endif %&lt;span class="ni"&gt;&amp;amp;#125;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;|filter&lt;/code&gt; syntax is the dangerous part. A translator who sees &lt;code&gt;{{ first_name|default:"there" }}&lt;/code&gt; will sometimes translate &lt;code&gt;"there"&lt;/code&gt; — which is actually correct — but will also sometimes translate the filter name &lt;code&gt;default&lt;/code&gt; or the variable name &lt;code&gt;first_name&lt;/code&gt;. Both break the template.&lt;/p&gt;

&lt;p&gt;Django tags also use spaces inside the braces (&lt;code&gt;{{ variable }}&lt;/code&gt; not &lt;code&gt;{{variable}}&lt;/code&gt;), which means your regex needs to handle both variants.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Liquid — Shopify Email, some ActiveCampaign flows
&lt;/h3&gt;

&lt;p&gt;Liquid is used in Shopify's email templates and some other platforms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;first_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;email&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;upcase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&amp;amp;#123;% if customer.orders_count &amp;gt; 1 %&amp;amp;#125;
  Thanks for being a returning customer.
&amp;amp;#123;% endif %&amp;amp;#125;
&amp;amp;#123;% for item in order.line_items %&amp;amp;#125;
  &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;: &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;money&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&amp;amp;#123;% endfor %&amp;amp;#125;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Liquid looks similar to Django but has important differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter syntax uses &lt;code&gt;|&lt;/code&gt; with a space on both sides: &lt;code&gt;{{ value | filter }}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Block tags use &lt;code&gt;&amp;amp;#123;% %&amp;amp;#125;&lt;/code&gt; with the tag name: &lt;code&gt;&amp;amp;#123;% if %&amp;amp;#125;&lt;/code&gt;, &lt;code&gt;&amp;amp;#123;% for %&amp;amp;#125;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Object access uses dot notation: &lt;code&gt;customer.first_name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;&amp;amp;#123;% %&amp;amp;#125;&lt;/code&gt; blocks are particularly problematic because translators sometimes interpret them as HTML comments or unknown tags and delete them.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Merge tags — Mailchimp, Constant Contact
&lt;/h3&gt;

&lt;p&gt;Mailchimp uses a completely different pattern — asterisk-pipe delimiters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*|FNAME|*
*|LNAME|*
*|EMAIL|*
*|UNSUB|*
*|MC:SUBJECT|*
*|IF:FNAME|* Hello *|FNAME|*, *|ELSE:|* Hello there, *|END:IF|*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This syntax stands out visually, which is good — translators usually recognize it as "code". But the conditional blocks (&lt;code&gt;*|IF:...|*&lt;/code&gt;, &lt;code&gt;*|ELSE:|*&lt;/code&gt;, &lt;code&gt;*|END:IF|*&lt;/code&gt;) are often mishandled because they look more like markup than the simpler variable tags.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Percent-delimited — ActiveCampaign, some legacy ESPs
&lt;/h3&gt;

&lt;p&gt;ActiveCampaign uses percent signs as delimiters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%FIRSTNAME%
%LASTNAME%
%EMAIL%
%UNSUBSCRIBELINK%
%CUSTOM_FIELD_NAME%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the simplest syntax to detect but also the easiest to accidentally break. The uppercase convention helps — translators rarely translate uppercase strings — but &lt;code&gt;%UNSUBSCRIBELINK%&lt;/code&gt; occasionally gets "translated" to &lt;code&gt;%LIENDEDESABONNEMENT%&lt;/code&gt; in French workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detection approach
&lt;/h2&gt;

&lt;p&gt;For each syntax, you need a regex that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matches the full token including delimiters&lt;/li&gt;
&lt;li&gt;Handles nested or block structures&lt;/li&gt;
&lt;li&gt;Avoids false positives on similar-looking content&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a starting point for each:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="n"&gt;PATTERNS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Handlebars: {{variable}}, {{{variable}}}, {{#helper}}...{{/helper}}
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;handlebars&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\{{2,3}[#/^]?\s*[\w.]+(?:\s+[\w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\'=\s,]+)?\s*\}{2,3}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="c1"&gt;# Django: {{ variable }}, {{ variable|filter }}, &amp;amp;#123;% tag %&amp;amp;#125;
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;django&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\&amp;amp;#123;%[-\s]*\w[\w\s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\'=,.|:()]*[-\s]*%\}|\{\{[-\s]*[\w.|:()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\' ]+[-\s]*\}\}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="c1"&gt;# Liquid: {{ variable | filter }}, &amp;amp;#123;% tag %&amp;amp;#125;
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;liquid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\&amp;amp;#123;%-?\s*[\w\s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\'=,.|:()\-]+\s*-?%\}|\{\{-?\s*[\w.|:()&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\'\ ]+\s*-?\}\}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="c1"&gt;# Mailchimp merge tags: *|TAG|*, *|IF:TAG|*...*|END:IF|*
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mailchimp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\*\|[A-Z0-9_:]+\|\*&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="c1"&gt;# Percent-delimited: %VARIABLE%
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;percent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%[A-Z][A-Z0-9_]+%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detect_esp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Detect which ESP syntax is present in an HTML template.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;PATTERNS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Extract all tokens from an HTML template for a given ESP.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;PATTERNS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown ESP: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PATTERNS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The protection strategy
&lt;/h2&gt;

&lt;p&gt;Once you've detected and extracted tokens, the challenge is keeping them intact through translation while allowing surrounding text to be modified.&lt;/p&gt;

&lt;p&gt;The approach we use:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Extract and replace with placeholders&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;protect_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Replace tokens with stable placeholders. Returns protected HTML and token map.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extract_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;placeholder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;⟦T&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;⟧&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Use unusual characters unlikely to appear in translations
&lt;/span&gt;        &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;
        &lt;span class="n"&gt;protected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;protected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;protected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;restore_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;translated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token_map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Restore original tokens after translation.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;restored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;translated&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;token_map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;restored&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;restored&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;restored&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Validate after restoration&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restored&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Check that all tokens from original are present in restored HTML.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;original_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extract_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;restored_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;extract_tokens&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;restored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;esp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_tokens&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;restored_tokens&lt;/span&gt;
    &lt;span class="n"&gt;added&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;restored_tokens&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;original_tokens&lt;/span&gt;

    &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing tokens after translation: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unexpected tokens after translation: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;added&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Edge cases that will burn you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Translated filter arguments in Django/Liquid&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Source:
{{ first_name|default:"there" }}

# After translation (broken):
{{ first_name|default:"là" }}   # French translator translated "there"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default fallback string is technically translatable content — but it's inside a token. You need to decide: protect the entire token including the argument, or extract just the argument for translation. We protect the entire token and handle fallback strings separately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RTL languages and bidirectional tokens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Arabic and Hebrew email templates render right-to-left, but token syntax is always LTR. Browsers handle this with &lt;code&gt;dir&lt;/code&gt; attributes and unicode bidi marks. If you're using a WYSIWYG translation interface, you need to ensure the token placeholders don't inherit RTL direction and render backwards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tokens inside HTML attributes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/account/{{customer_id}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;View account&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{product_image_url}}"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"{{product_name}}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tokens inside &lt;code&gt;href&lt;/code&gt; and &lt;code&gt;src&lt;/code&gt; attributes are at higher risk. Some translation tools will attempt to "fix" URLs they detect, normalizing or encoding the token syntax in the process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conditional blocks that span multiple translated segments&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;&amp;amp;#123;% if customer.plan == "premium" %&amp;amp;#125;
  You have access to all features.
&amp;amp;#123;% else %&amp;amp;#125;
  Upgrade to unlock everything.
&amp;amp;#123;% endif %&amp;amp;#125;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your translation tool splits segments at sentence boundaries, the &lt;code&gt;&amp;amp;#123;% if %&amp;amp;#125;&lt;/code&gt; and &lt;code&gt;&amp;amp;#123;% endif %&amp;amp;#125;&lt;/code&gt; may end up in different segments. The translator working on the first segment has no idea the second segment is conditional on the same block.&lt;/p&gt;




&lt;h2&gt;
  
  
  What we built
&lt;/h2&gt;

&lt;p&gt;This is the core problem &lt;a href="https://transendly.com" rel="noopener noreferrer"&gt;Transendly&lt;/a&gt; solves — a governed workflow where the token detection, extraction, and restoration happens automatically, translators work in a clean interface without seeing raw token syntax, and validation runs before any locale can be exported to the ESP.&lt;/p&gt;

&lt;p&gt;If you're building something similar or have hit edge cases we haven't covered here, I'd be interested to hear about it in the comments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: &lt;code&gt;email&lt;/code&gt; &lt;code&gt;webdev&lt;/code&gt; &lt;code&gt;javascript&lt;/code&gt; &lt;code&gt;python&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>email</category>
      <category>webdev</category>
      <category>python</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
