LokalizacjaInternacjonalizacjaTłumaczenie AI

Lokalizacja e-maili: jak tłumaczyć kampanie w najpopularniejszych systemach ESP

Każda platforma e-mail marketingowa obsługuje języki w inny sposób. Niektóre tłumaczą treści za Ciebie, inne oferują puste sloty na wersje lokalne, a jeszcze inne wymagają ręcznego pisania instrukcji warunkowych. Oto jak w rzeczywistości działają Braze, Customer.io, Klaviyo, Mailchimp, Iterable oraz Brevo i jak tłumaczyć teksty, by nie uszkodzić kodu Liquid.

Mariia Ivakhnenko
Mariia Ivakhnenko24 min czytania
Na tej stronie

Zajmuję się marketingiem cyklu życia, więc w edytorach kampanii spędziłem szmat czasu, a lokalizacja e-maili była czymś, co wciąż zdarzało mi się bagatelizować. Tłumaczenie strony docelowej to zadanie o stałej formie. Tłumaczenie kampanii e-mailowej wygląda jednak zupełnie inaczej w każdym narzędziu, z którym masz do czynienia, ponieważ każda platforma na własną rękę definiuje, czym w ogóle jest „język”.

Niektóre platformy tłumaczą treści za Ciebie. Inne dają Ci puste sloty na wersje lokalne i oczekują ich uzupełnienia. Jeszcze inna wymaga tworzenia logiki warunkowej bezpośrednio w treści wiadomości. A pod tym wszystkim kryje się to samo zagrożenie: Twoje treści są pełne składni szablonów, która musi wrócić z tłumaczenia w nienaruszonym stanie, co do znaku – inaczej wysyłka się posypie.

Ten przewodnik opisuje, jak faktycznie działają najpopularniejsze platformy, jak wyeksportować i ponownie zaimportować tekst oraz które etapy pracy wyglądają wszędzie tak samo.

Trzy sposoby, na jakie platformy e-mailowe obsługują języki

Zanim przejdziemy do szczegółowego omówienia poszczególnych platform, warto zrozumieć, z którą z trzech architektur masz do czynienia. To od niej zależy cały Twój proces pracy, a zazwyczaj nie da się jej zmienić.

ArchitekturaCo zapewnia platformaCo dostarczasz TyPlatformy
Tłumaczy za CiebieTłumaczenie maszynowe w edytorze, warianty językowe generowane na podstawie wersji domyślnejWeryfikacja, poprawki, lista fraz wykluczonych z tłumaczeniaKlaviyo, Customer.io, Brevo
Zapewnia sloty na wersje lokalneTreści z tagami, strukturę wariantów, eksport i import przez CSV lub APISame tłumaczeniaBraze, Iterable
Nie zapewnia niczegoTagi personalizacji i instrukcje warunkoweWszystko, zapisane w formie logiki warunkowej w treści wiadomościMailchimp

Środkowy wiersz to miejsce, w którym funkcjonuje większość poważnych programów wielojęzycznych, i to właśnie jemu poświęcam w tym przewodniku najwięcej miejsca. Dzieje się tak dlatego, że gdy „platforma zapewnia puste sloty na wersje lokalne”, proces tłumaczenia staje się po prostu niezbędny.

Lokalizacja wiadomości e-mail w Braze

Braze opiera się na modelu „otaguj i wypełnij” i ma najbardziej charakterystyczną składnię z całego zestawienia. Każdy fragment e-maila przeznaczony do tłumaczenia zamykasz w tagu Liquid z identyfikatorem:

{% translation greeting %}Hello!{% endtranslation %}

Ogólny format to {% translation twoje_id_tutaj %}tekst domyślny{% endtranslation %}, a identyfikatory muszą być unikalne w obrębie danej wiadomości. W edytorze dostępny jest skrót klawiszowy do ujęcia zaznaczenia w tagi (Cmd+Alt+L na macOS, Ctrl+Alt+L w systemie Windows). Braze nie tłumaczy niczego samodzielnie: musisz dostarczyć tłumaczenia, wgrywając plik CSV lub korzystając z API tłumaczeń, które w momencie pisania tego tekstu znajduje się w fazie wczesnego dostępu.

Udokumentowane limity zaczynają mieć znaczenie, gdy kampania nabiera realnych kształtów:

LimitWartość
Tagi tłumaczeń na wiadomość200
Liczba znaków w tekście domyślnym2 000
Tłumaczenia na wersję lokalną409 600 bajtów (około 409,6 KB)
Wersje lokalne na przestrzeń roboczą200

Zagnieżdżone tagi tłumaczeń nie są obsługiwane. Wersja lokalna (locale) pochodzi z profilu użytkownika i jest konfigurowana w sekcji Settings → Localization Settings na podstawie domyślnych atrybutów language i country lub atrybutu niestandardowego. W przypadku gdy oba są obecne, priorytet ma atrybut niestandardowy.

Przed rozpoczęciem warto poznać dwie kwestie specyficzne dla Braze:

Ujęcie adresu URL w tagi przerywa śledzenie kliknięć, chyba że fragment objęty tagiem kończy się znakiem ? lub &. Braze opisuje sposób na obejście tego problemu bezpośrednio w dokumentacji:

<a href="https://{% translation id_1 %}example.com{% endtranslation %}?">Shop Now</a>

Nie otwieraj pliku CSV z tłumaczeniami w Excelu. Sama dokumentacja Braze odradza to ze względu na problemy z wyświetlaniem znaków spoza alfabetu angielskiego. To najczęstsza przyczyna niepostrzeżonego uszkodzenia procesu lokalizacji w Braze, a winę ponosi Excel, nie platforma: program próbuje odgadnąć kodowanie pliku CSV i robi to błędnie.

Bloki treści (Content Blocks) platformy Braze mogą zawierać własne tłumaczenia, co pozwala zlokalizować wspólną stopkę raz, zamiast w każdej kampanii z osobna. Odwołuj się do nich za pomocą {{content_blocks.${your_block}}}; bloki wstawione przez Liquid pozostają połączone i aktualizują się automatycznie, natomiast te dodane z listy rozwijanej edytora – nie. Jeśli blok nie ma tłumaczenia dla danej wersji lokalnej, zostanie wyświetlony w języku oryginalnym, zamiast powodować błąd.

Jeśli zamiast tagowania wolisz stosować rozgałęzienia, Braze wspiera również metodę „zrób to sam”:

{% if ${language} == 'en' %}
English content
{% elsif ${language} == 'es' %}
Spanish content
{% else %}
Fallback content
{% endif %}

Zauważ, że wewnątrz tagu Liquid atrybut występuje samodzielnie jako ${language}, natomiast w treści wiadomości jest ujęty w klamry: {{${language}}}. Braze zaleca, aby zawsze uwzględniać wariant {% else %}, ponieważ niektórzy użytkownicy nie mają ustawionego języka, używają języka nieobsługiwanego lub korzystają z urządzenia, na którym nie można go wykryć.

Dokumentacja: Lokalizacja w Braze

Lokalizacja wiadomości e-mail w Customer.io

Customer.io przyjęło odwrotne podejście: lokalizacja jest funkcją natywną, wbudowaną w edytor wiadomości, a dodatkowo dostępny jest przycisk automatycznego tłumaczenia AI. Tworzysz wiadomość w języku domyślnym i dodajesz warianty językowe bez konieczności rozgałęziania kampanii. Rozwiązanie to działa w przypadku e-maili, SMS-ów, WhatsAppa, powiadomień push oraz wiadomości w aplikacji.

Nazwa atrybutu języka zależy wyłącznie od Ciebie. W sekcji Workspace Settings → Language settings wskazujesz Customer.io, który atrybut profilu zawiera informację o języku – może to być language, locale lub dowolna nazwa używana już w Twoim CRM-ie. Wartości muszą być dwuliterowym kodem (en) lub parą język-region rozdzieloną myślnikiem (en-US). Wielkość liter nie ma znaczenia, więc es-MX i es-mx zadziałają tak samo, ale myślnik jest wymagany.

Automatyczne tłumaczenie obejmuje treść, temat i preheader. Nie obejmuje jednak poniższych elementów – tę listę warto sobie powiesić nad biurkiem:

  • Obrazów, choć tłumaczy tekst alternatywny (alt text)
  • Układów wiadomości w edytorach rich-text i kodu
  • Statycznego tekstu Liquid, wartości atrybutów i wartości filtrów
  • Snippetów
  • Tekstu komponentów niestandardowych, chyba że najpierw je odłączysz

Ten trzeci punkt zasługuje na przykład, bo to właśnie on jest najbardziej podstępny. W samej dokumentacji lokalizacji Customer.io znajdziemy takie zdanie:

Bonjour {{ customer.first_name | default:"ami" }}

Słowo ami to tekst zastępczy wyświetlany każdemu, kto nie ma w bazie zapisanego imienia. To realna treść, którą widzi odbiorca, a ponieważ znajduje się wewnątrz filtra Liquid, funkcja automatycznego tłumaczenia jej nie tknie. Wyślij taką wiadomość do niemieckich odbiorców, a spora część z nich zostanie powitana jako ami. Każdy tekst zastępczy w każdym filtrze default: musi zostać przetłumaczony ręcznie dla każdego wariantu, a interfejs w żaden sposób Ci o tym nie przypomni.

Dwa kolejne ograniczenia, które należy uwzględnić w planach: tłumaczenia nie są aktualizowane automatycznie po zmianie domyślnego szablonu, a testy A/B z tłumaczeniami działają w przypadku wysyłek jednorazowych, ale nie w przypadku automatyzacji czy broadcastów wyzwalanych przez API.

Snippetom należy się osobna wzmianka. To mechanizm treści wielokrotnego użytku ({{snippets.your_snippet}}, domyślnie o rozmiarze do 16 KB każdy), którego automatyczne tłumaczenie nie obejmuje. Customer.io zaleca umieszczanie instrukcji warunkowych bezpośrednio w samym snippecie:

{% if customer.language == 'fr' %}
  Se désabonner
{% elsif customer.language == 'de' %}
  Abmelden
{% else %}
  Unsubscribe
{% endif %}

W rezultacie praca w Customer.io sprowadza się zazwyczaj do tworzenia natywnych wariantów treści wiadomości oraz ręcznego dopisywania instrukcji warunkowych w każdym współdzielonym snippecie. Warto o tym pamiętać, zanim założysz, że przycisk AI załatwi wszystko za Ciebie.

Dokumentacja: Lokalizacja w Customer.io

Lokalizacja wiadomości e-mail w Klaviyo

Funkcja Klaviyo o nazwie Smart Translations pozwala na maszynowe tłumaczenie treści wiadomości na ponad 60 języków bezpośrednio w edytorze kampanii lub flow. Włącza się ją w sekcji Settings → Account → Translation za pomocą przełącznika „Translate messages”. Wymaga ona płatnego konta i nie jest dostępna w wersji próbnej.

Lista elementów, które według dokumentacji Klaviyo są tłumaczone automatycznie, jest ściśle określona: bloki tekstowe, etykiety oraz teksty alternatywne. Tematy wiadomości nie znajdują się na tej liście, więc zanim założysz, że kampania jest w pełni obsłużona, zweryfikuj to na swoim koncie.

Rozpoznawanie języka domyślnie opiera się na polu Locale w profilu, a w razie jego braku – na polach Country lub Language. Klaviyo obsługuje kody BCP-47 (en-GB, es-ES), a także nazwy zapisane tekstem, takie jak English czy French.

Dwie rzeczy sprawiają, że praca z Klaviyo jest wyjątkowo wygodna. Pierwszą jest lista „Do Not Translate”: nazwy marek, produktów i wszelkie terminy, których model ma nie dotykać, definiowane raz na poziomie konta. Większość platform nie ma odpowiednika tej funkcji, a to właśnie ona decyduje o tym, czy nazwa Twojego produktu zachowa spójność w dziesięciu wersjach językowych, czy też zmieni się w dziesięć różnych słów.

Drugą jest menu nadpisywania poszczególnych elementów. Przy każdym przetłumaczonym fragmencie dostępne są opcje Re-translate, Match source, Edit oraz Ignore, a między językami można przełączać się za pomocą strzałek u góry edytora. Dzięki temu weryfikacja sprowadza się do przejrzenia oznaczonych elementów zamiast ponownego czytania całości.

Klaviyo obsługuje również proces eksportu i importu plików CSV (tzv. round-trip), co jest najlepszym rozwiązaniem, jeśli współpracujesz z tłumaczami lub korzystasz z zewnętrznych narzędzi. W sekcji Translate → menu akcji znajdziesz opcję Export CSV w formacie Smartling lub Simple. Plik zawiera kolumny block_id (unikalny identyfikator każdego ciągu tekstowego), source (tekst źródłowy) oraz po jednej kolumnie na każdy język, nazwanej odpowiednim kodem. Zasady są rygorystyczne i logiczne: nie wolno edytować ani usuwać wartości block_id, dodawać nowych wierszy ani zmieniać treści w kolumnie source.

Osoby przechodzące z Braze lub Customer.io często zaskakuje jeden fakt: Klaviyo to nie Liquid. Platforma ta korzysta ze składni szablonów Django.

{% if person|lookup:'Loyalty Points' > 150 %}
Hey VIP! You've always got free shipping & free returns
{% elif person|lookup:'Loyalty Points' > 0 %}
You have {{ person|lookup:'Loyalty Points' }} points, and you just need 150 to become a VIP!
{% else %}
Have you heard about our VIP program? Join today on our website to start earning rewards.
{% endif %}

Tagi wyglądają na tyle podobnie do Liquida, że łatwo dać się nabrać, a potem różnica między elif a elsif potrafi zepsuć całe popołudnie. Personalizacja z tekstem zastępczym wygląda następująco: {{ first_name|default:'friend' }}.

Dokumentacja: Klaviyo Smart Translations · Składnia Django

Lokalizacja wiadomości e-mail w Mailchimp

Mailchimp nie oferuje natywnej funkcji kampanii wielojęzycznych. Ma jednak warunkowe tagi scalające, a oficjalnie zalecana metoda polega na umieszczeniu wszystkich wersji językowych w jednej wiadomości i zdaniu się na instrukcje warunkowe, które wybiorą tę właściwą.

*|IF:MC_LANGUAGE=es|*
Spanish content here.
*|ELSEIF:MC_LANGUAGE=de|*
German content here.
*|ELSE:|*
Display English content for everyone else.
*|END:IF|*

*|MC_LANGUAGE|* zawiera kod języka kontaktu, a *|MC_LANGUAGE_LABEL|* jego czytelną nazwę. Mailchimp próbuje wykryć język z przeglądarki subskrybenta; można go również ustawić dla każdego kontaktu w sekcji profile → Settings → Language lub masowo podczas importu. Należy pamiętać, że *|END:IF|* zamyka zarówno bloki IF, jak i IFNOT.

To jedno ograniczenie zazwyczaj przesądza o sprawie. Zlokalizowany e-mail z tematem w niewłaściwym języku traci szansę na otwarcie, zanim treść w ogóle zacznie mieć znaczenie. W efekcie większość zespołów obsługujących w Mailchimp więcej niż dwa języki i tak tworzy osobne kampanie dla każdego z nich – a wtedy podejście oparte na warunkowych tagach scalających staje się bezużyteczne. Warto o tym wiedzieć na etapie planowania, a nie dopiero po przygotowaniu szablonu.

Dokumentacja: Tłumaczenie treści w Mailchimp

Lokalizacja wiadomości e-mail w Iterable

Iterable posiada funkcję obsługi wersji językowych (locales) z prawdziwego zdarzenia, a jej dokumentacja w odświeżająco bezpośredni sposób wyjaśnia, co to oznacza, a czego nie:

Funkcja locales nie tłumaczy treści.

Otrzymujesz szkielet dla wariantów, ale tłumaczenia musisz dostarczyć sam. W zamian wszystkie wersje współdzielą jeden templateId, dzięki czemu Twoje statystyki pozostają spójne, zamiast rozdrabniać się na dziesięć osobnych szablonów. Każdy, kto próbował raportować wyniki kampanii rozbitej na kopie językowe, wie, że dla samej tej korzyści warto poświęcić czas na konfigurację.

Pole musi nazywać się dokładnie locale. Iterable stawia sprawę jasno: jeśli nadasz mu nazwę languagePreference lub jakąkolwiek inną, system nie będzie w stanie dopasować użytkowników do wariantów. Nazwy lokalizacji są zgodne ze standardami ISO-639 i ISO-3166 (fr-CA, fr-FR), a obsługiwane są również kody trzyliterowe. Pamiętaj, że raz utworzonej lokalizacji nie można już zmienić, więc ustal konwencję nazewnictwa, zanim stworzysz ich dwadzieścia. Puste pole lokalizacji skutkuje wysyłką wersji domyślnej; w przypadku braku dopasowania o wszystkim decyduje ustawienie na poziomie projektu, które pozwala wybrać między pominięciem wysyłki a wysłaniem wariantu domyślnego.

Iterable wyraźnie odradza też stosowanie rozwiązań typu „zrób to sam”:

Choć Iterable jest elastyczną platformą i pozwala na tworzenie treści w wielu językach przy użyciu języka Handlebars lub funkcji Catalog, nie są to najlepsze praktyki w zakresie lokalizacji.

Systemem szablonów jest Handlebars, a nazwy pól rozróżniają wielkość liter. W edytorze WYSIWYG można jednak natknąć się na pewien haczyk: instrukcje warunkowe muszą być ujęte w komentarze HTML, inaczej edytor je uszkodzi.

<!--{{#if activeUser}}-->
    <div>Hi active user!</div>
<!--{{else}}-->
    <div>Hi inactive user</div>
<!--{{/if}}-->

W przypadku procesu round-trip, endpoint GET /api/templates/email/get pozwala pobrać treść szablonu dla tłumaczy.

Dokumentacja: Obsługa wielu języków w Iterable

Lokalizacja wiadomości e-mail w Brevo

Brevo należy do grona platform oferujących wbudowane tłumaczenia i w tej konkretnej kwestii jest najbardziej bezpośrednim konkurentem Mailchimpa. Tworzysz jedną kampanię, która dostosowuje się do języka lub kodu kraju przypisanego do kontaktu, klikasz Add languages, a Brevo powiela ją dla każdego z języków. Treść możesz przetłumaczyć samodzielnie lub z pomocą Aury – asystenta AI platformy.

Zakres elementów, które można zmieniać w zależności od języka, jest tu szerszy niż w większości narzędzi: od nazwy nadawcy, tematu wiadomości i tekstu podglądu, po sam projekt e-maila, adres reply-to, śledzenie w Google Analytics i niestandardową stronę rezygnacji z subskrypcji. Temat wiadomości zasługuje na szczególną uwagę, bo to właśnie tego nie potrafi Mailchimp.

Udokumentowane ograniczenia: brak obsługi tłumaczeń opartych na plikach (brak procesu round-trip dla plików CSV wyklucza Brevo, jeśli współpracujesz z zewnętrznym biurem tłumaczeń), brak wsparcia dla kampanii z testami A/B oraz konieczność tworzenia osobnej wersji zapisanych sekcji dla każdego języka. Kontakty, których atrybut języka nie pasuje do żadnej ze skonfigurowanych wersji, otrzymają wariant domyślny.

Dokumentacja: Kampanie wielojęzyczne w Brevo

Liquid, Handlebars i tagi scalające: elementy, które muszą pozostać nienaruszone

Niezależnie od używanej platformy, sam etap tłumaczenia wiąże się z jednym twardym wymogiem. Treść zawiera składnię szablonów, a każdy jej znak musi wrócić w dokładnie takiej samej formie, w jakiej trafił do tłumaczenia. Przetłumaczone {% endif %} oznacza błąd wysyłki.

Oto jak wygląda składnia na platformach opisanych w tym przewodniku:

PlatformaJęzykPersonalizacjaInstrukcja warunkowa
BrazeLiquid{{${first_name}}}{% if %} / {% elsif %} / {% else %} / {% endif %}
Customer.ioLiquid{{customer.first_name}}{% if %} / {% elsif %} / {% else %} / {% endif %}
KlaviyoDjango{{ first_name }}{% if %} / {% elif %} / {% else %} / {% endif %}
MailchimpTagi scalające*|FNAME|**|IF:X|* / *|ELSEIF:X|* / *|ELSE:|* / *|END:IF|*
IterableHandlebars{{firstName}}{{#if}} / {{else}} / {{/if}}
BrevoJęzyk szablonów Brevo{{ contact.FIRSTNAME }}{% if %} / {% else %} / {% endif %}

Za niemal wszystkie problemy w tym obszarze odpowiadają trzy rodzaje błędów.

Model tłumaczy token. W rezultacie otrzymujesz {{ prénom }} lub {% si %}, co powoduje błąd wysyłki lub wyświetlenie surowego tekstu. Porządne narzędzia maskują tokeny, zanim tekst trafi do modelu, i przywracają je później, dzięki czemu model w ogóle nie widzi w nich słów do przetłumaczenia.

Model przesuwa token. Szyk wyrazów w różnych językach naturalnie się różni, więc token powinien zmienić swoje miejsce. Problem pojawia się, gdy trafi do niewłaściwej części zdania lub gdy {% if %} i {% endif %} zmienią kolejność. Pozycja ma znaczenie; rozwiązaniem jest sprawdzenie, czy zestaw tokenów wyjściowych zgadza się z wejściowym, i ponowne przetworzenie bloku, jeśli wystąpią rozbieżności.

Zmienia się liczba tokenów. Najgroźniejszy jest pominięty token, ponieważ e-mail wciąż się renderuje, tyle że z brakującym imieniem lub brakującym warunkiem. Właśnie dlatego liczenie jest ważniejsze niż sprawdzanie „na oko”.

I zasada, która łączy wszystkie te trzy kwestie: gałęzie warunkowe to oddzielne ciągi znaków. W tym wierszu mamy dwa niezależne fragmenty tekstu. Tłumacz lub model, któremu poda się całość w jednym bloku, poradzi sobie z nimi gorzej niż ten, który otrzyma każdy z nich z osobna wraz z kontekstem:

{% if ${loyalty_tier} == 'gold' %}Gold members get an extra 10%.{% else %}Join Gold for an extra 10%.{% endif %}

E-maile HTML i tabele ciągów znaków to dwa różne zadania

Na tej drodze trafiamy na rozstaje, które decydują o całej konfiguracji – a większość osób uświadamia to sobie dopiero w połowie drogi.

Niektóre treści e-mailowe to dokumenty: szablony HTML czy wyrenderowane wiadomości – coś o określonej strukturze i układzie, co czyta się od góry do dołu. Należy je tłumaczyć jako spójny tekst, ponieważ nagłówek i znajdująca się pod nim treść stanowią całość. Tłumacz widzący oba te elementy podejmie lepsze decyzje niż ten, któremu pokazuje się je z osobna.

Inne treści e-mailowe to tabele ciągów znaków: lista z kluczami, w której każdy wiersz stanowi odrębną całość. cta_button, subject_line, footer_unsub. Towarzyszą im metadane, które są ważniejsze niż sama warstwa tekstowa: klucz, który nigdy nie może się zmienić, notatka z kontekstem, a często także limit znaków – ponieważ zbyt długi temat wiadomości zostanie ucięty w skrzynce odbiorczej.

Pliki CSV z Braze i Klaviyo oraz wszelkie formaty plików lokalizacyjnych ze świata oprogramowania (gettext PO, XLIFF) to tabele ciągów znaków. Szablony HTML to dokumenty. Potraktuj tabelę ciągów znaków jak dokument, a stracisz klucze; potraktuj dokument jak tabelę, a poszatkujesz tekst na oderwane od siebie fragmenty.

Właśnie dlatego w Transept obsługę plików z ciągami zaprojektowaliśmy jako odrębną ścieżkę, zamiast włączać ją do mechanizmu importu dokumentów. Plik CSV z treściami e-maili trafia do systemu w formie przejrzystej tabeli z polami: klucz, źródło i tłumaczenie. Limit znaków wyświetla się jako licznik działający w czasie rzeczywistym, a do każdego wiersza przypisana jest notatka z kontekstem.

Siatka ciągów znaków w Transept przedstawiająca zaimportowany plik CSV z kampanią e-mailową. Widoczne są wiersze dla pól subject_line, preheader, hero_headline, hero_body, cta_button, loyalty_line, shipping_note i footer_unsub. W kolumnie źródłowej zachowano tag personalizacji Braze i warunek Liquid, po prawej stronie widać niemieckie tłumaczenia, a pod każdym z nich znajdują się liczniki znaków, takie jak 46/90 i 8/18.

Kluczowe jest to, że plik wyjściowy zachowuje formę, w jakiej do nas trafił. Eksportujesz przetłumaczony oryginał, z kluczami i kolumnami dokładnie tam, gdzie spodziewa się ich platforma, zamiast eksportować coś, co musiałbyś potem ręcznie poprawiać.

Czego dowiedzieliśmy się, budując obsługę e-maili w Transept

Udostępniliśmy funkcję importu plików z ciągami znaków właśnie z myślą o tym modelu pracy, a w trakcie prac natknęliśmy się na kwestie, o których nie widziałem wcześniej żadnych wzmianek. To nasze własne wnioski, oparte na naszym kodzie i przeprowadzonych testach.

„50% off” to, technicznie rzecz biorąc, konwersja printf

Ciągi znaków w oprogramowaniu często wykorzystują symbole zastępcze printf: %s, %d, %1$s. Jeśli maskujesz je przed tłumaczeniem, oczywiste wyrażenie regularne akceptuje pełny zestaw flag printf, w tym flagę spacji (% d wstawia spację przed liczbami dodatnimi). To poprawna składnia printf i jej akceptowanie jest uzasadnione.

To również przepis na katastrofę w tekstach marketingowych. Przy aktywnej fladze spacji 50% off zawiera dopasowanie: % o zostaje zinterpretowane jako konwersja ósemkowa z flagą spacji. To samo dotyczy 100% organic oraz Up to 70% off – czyli najczęstszej konstrukcji w e-mailach promocyjnych.

Sprawdziliśmy oba warianty:

WejścieŚcisły wzorzecZ flagą spacji
50% obniżki na pierwsze zamówieniebrak dopasowania% o
100% bawełna organicznabrak dopasowania% o
Cześć %s, zaoszczędziłeś %d%%%s, %d, %%%s, %d, %%

Maskowanie % o zamienia informację o zniżce w symbol zastępczy, przez co model otrzymuje okaleczone zdanie. Świadomie odrzucamy flagę spacji i nic na tym nie tracimy – w rzeczywistych tabelach ciągów znaków nikt z niej nie korzysta.

Tag personalizacji w Braze ma trzy klamry zamykające

Na ten błąd natknęliśmy się podczas pisania tego przewodnika, co jest świetnym argumentem za tym, by w ogóle je tworzyć.

Składnia w Braze to {{${first_name}}}. Policzmy klamry zamykające: najpierw ta od samego atrybutu (}), a potem dwie zamykające znacznik wyjściowy Liquid. Trzy pod rząd.

Prawie każdy tokenizer Liquid skanuje tekst niezachłannie do pierwszego wystąpienia }}. W przypadku {{${first_name}}} zamyka on znacznik o jedną klamrę za wcześnie: przechwytuje {{${first_name}} i zostawia samotną klamrę } w tekście do przetłumaczenia. Token wydaje się obsłużony, ale zbłąkana klamra trafia do modelu jako zwykły tekst i wraca przesunięta, powielona lub całkowicie znika.

{{${first_name}}}, your spring sale starts now

  non-greedy scan  →  token: {{${first_name}}     leftover: "}, your spring sale starts now"
  brace-aware scan →  token: {{${first_name}}}    leftover: ", your spring sale starts now"

Nasz tokenizer zachował się właśnie w ten pierwszy sposób. Znaleźliśmy błąd, naprawiliśmy go tak, aby dopuszczał jeden poziom zagnieżdżenia wewnątrz tokena, i dodaliśmy konkretną składnię Braze do naszego zestawu testów. Jeśli rozwijasz własne narzędzia do e-maili, przetestuj je pod kątem {{${attribute}}}, ponieważ standardowa forma {{ attribute }} działa poprawnie i całkowicie maskuje ten błąd.

Cudzysłowy wewnątrz symboli zastępczych psują odpowiedzi JSON

Gdy wysyłasz do modelu partię ciągów znaków i wymuszasz format JSON, cudzysłów " niepoprzedzony znakiem ucieczki przedwcześnie zamyka ciąg, co powoduje odrzucenie reszty partii. Natknęliśmy się na ten problem w przypadku symboli zastępczych zawierających atrybuty w cudzysłowie – udało nam się go odtworzyć w około 58% prób na jednym z modeli.

Rozwiązaniem nie jest dopracowanie instrukcji dotyczących znaków ucieczki w prompcie. Należy sprawić, by format przesyłu danych był pozbawiony cudzysłowów, co całkowicie eliminuje ryzyko błędu: model widzi wyłącznie symbole zastępcze bez cudzysłowów, a ich kanoniczna forma z cudzysłowami jest przywracana na późniejszym etapie. Poleganie na tym, że model „zazwyczaj” nie psuje struktury JSON, to najgorszy możliwy profil niezawodności, ponieważ błędy pozostają niezauważone.

Wpisy typu fuzzy to sygnał, a nie gotowe tłumaczenie

Jeśli Twoje teksty pochodzą z plików PO gettext, wpisy posiadają flagę fuzzy, co oznacza: „zostało to dopasowane automatycznie, człowiek tego nie potwierdził”. Traktowanie wpisów fuzzy jak gotowych tłumaczeń to włączanie do projektu sterty domysłów jako zatwierdzonej pracy.

Wykluczamy je z procesu wstępnego zasilania, tłumaczymy od zera i usuwamy flagę fuzzy przy eksporcie – do tego czasu wpis jest już zweryfikowany, więc flaga traci rację bytu.

Dobre praktyki lokalizacji kampanii e-mailowych

Nawyki, które odróżniają sprawnie prowadzony program od drogi przez mękę – uszeregowane mniej więcej według tego, jak wielu kłopotów pozwalają uniknąć.

Ustal kody lokalizacji raz, na poziomie profilu. Powinny być dwuliterowe lub z oznaczeniem regionu i spójne w całym systemie. Większość przypadków, gdy „tłumaczenie się nie wyświetliło”, to sytuacje, w których profil nl-BE trafia na wiadomość nl.

Dodawaj kontekst do każdego ciągu znaków, zanim trafi on do tłumaczenia. Tłumacz widzący w arkuszu frazę Shop the sale nie ma pojęcia, czy to przycisk, nagłówek czy link, ani że tekst musi się zmieścić w osiemnastu znakach. Każda platforma oferująca pole na kontekst lub opis prosi Cię o to, co w największym stopniu podnosi jakość efektu końcowego – a mimo to niemal nikt go nie uzupełnia.

Traktuj limity znaków jako kluczowe ograniczenie. Niemieckie teksty są zazwyczaj od 1,5 do 2 razy dłuższe niż angielskie. CTA, które mieści się po angielsku, może wyjść poza ramy, a temat wiadomości zostać ucięty w połowie słowa w skrzynce odbiorczej. Przekazuj informację o limicie wraz z ciągiem znaków, aby osoba tłumacząca widziała licznik.

Prowadź listę fraz niepodlegających tłumaczeniu. Nazwy produktów, terminy markowe, nazwy funkcji. Klaviyo ma tę funkcję wbudowaną; na innych platformach taką rolę pełni glosariusz. Tak czy inaczej, przygotuj ją przed pierwszą wysyłką, a nie dopiero wtedy, gdy znajdziesz nazwę swojego produktu w sześciu różnych wariantach.

Tłumacz warianty zapasowe. Każdy filtr default:, każdą gałąź {% else %} i każde „Cześć”, które wyświetla się, gdy brakuje imienia. To teksty, które nigdy nie pojawiają się w podglądzie, przez co umykają weryfikacji – a przecież trafiają do odbiorców, o których wiesz najmniej.

Wykorzystuj raz podjęte decyzje w kolejnych wysyłkach. Treści kampanii stale się powtarzają: ta sama stopka, ta sama formułka rezygnacji z subskrypcji, ta sama oprawa sezonowa co roku. Pamięć tłumaczeniowa sprawia, że raz ustalasz brzmienie frazy „Kupuj na wyprzedaży” i pozostaje ono spójne w każdej kolejnej kampanii, zamiast rozmywać się na trzy warianty tylko dlatego, że przy trzech różnych wysyłkach podjęto inne decyzje.

Zrób wysyłkę testową w każdym języku przed tą właściwą. Wyrenderuj właściwy szablon z użyciem prawdziwego profilu dla każdej lokalizacji. Instrukcje warunkowe, które w edytorze wyglądają poprawnie, mogą zawieść w sposób, który ujawnia dopiero renderowanie. To właśnie ten krok pozwala wyłapać nietłumaczony wariant zapasowy lub uszkodzoną gałąź kodu, póki jeszcze nic Cię to nie kosztuje.

Najczęściej zadawane pytania

Czym jest lokalizacja e-maili?

Lokalizacja e-maili to proces dostosowywania kampanii do innego języka i rynku: treści, tematu wiadomości i preheadera, wariantów zapasowych personalizacji oraz konwencji formatowania właściwych dla danej lokalizacji. Różni się ona od zwykłego tłumaczenia tym, że e-mail zawiera składnię szablonu (tagi scalające, instrukcje warunkowe Liquid lub Handlebars), która musi pozostać nienaruszona, a także ograniczenia – takie jak dopuszczalna długość tematu – których w przekładzie należy bezwzględnie przestrzegać.

Które platformy e-mailowe automatycznie tłumaczą kampanie?

Klaviyo (Smart Translations, ponad 60 języków), Customer.io (automatyczne tłumaczenie AI w e-mailach, SMS-ach, WhatsAppie, powiadomieniach push i wewnątrz aplikacji) oraz Brevo (za pośrednictwem asystenta Aura) generują tłumaczenia bezpośrednio w edytorze. Braze i Iterable zapewniają strukturę dla różnych wersji językowych, ale wymagają samodzielnego dostarczenia tłumaczeń. Mailchimp nie oferuje natywnej obsługi kampanii wielojęzycznych i opiera się na warunkowych tagach scalających.

Czy mogę przetłumaczyć temat wiadomości w Mailchimp?

Nie. Z dokumentacji Mailchimp wynika, że przetłumaczenie tematu wiadomości nie jest możliwe, ponieważ warunkowe tagi scalające nie działają w polu tematu. Aby wysyłać zlokalizowane tematy wiadomości przez Mailchimp, musisz stworzyć osobną kampanię dla każdego języka, segmentowaną według pola języka kontaktu.

Jak zapobiec uszkodzeniu tagów Liquid przez tłumaczenie?

Zamaskuj tokeny, zanim tekst trafi do modelu tłumaczeniowego, aby nie brał ich za zwykłe słowa. Następnie przywróć je i przed zaakceptowaniem wyniku upewnij się, że zestaw tokenów w tekście wyjściowym zgadza się z wejściowym. Jakość podnosi również tłumaczenie każdej gałęzi warunkowej jako osobnego ciągu znaków. Dzięki temu, zamiast przekazywać całą linię {% if %}...{% endif %} w jednym bloku, każda gałąź jest tłumaczona jako samodzielne zdanie – bo w rzeczywistości nim jest.

Jaka jest różnica między e-mailem HTML a tabelą ciągów znaków?

E-mail HTML to dokument: tekst ciągły o określonej strukturze, który najlepiej tłumaczyć w całości, aby zachować kontekst między nagłówkiem a treścią wiadomości. Tabela ciągów znaków to lista z kluczami, w której każdy wiersz jest samodzielnym elementem z przypisanym na stałe kluczem, zazwyczaj notatką kontekstową i często limitem znaków. Eksporty CSV z Braze i Klaviyo, pliki gettext PO oraz XLIFF to właśnie tabele ciągów. Oba te formaty wymagają innego podejścia: traktowanie tabeli ciągów jak dokumentu prowadzi do utraty kluczy, a dokumentu jak tabeli – do fragmentacji tekstu.

Czy do tłumaczeń lepiej używać eksportu CSV, czy API platformy?

CSV to praktyczny wybór, gdy tłumaczeniem zajmuje się człowiek lub zewnętrzny dostawca – to rozwiązanie opisano w dokumentacji Braze i Klaviyo. Automatyzacja przez API sprawdza się lepiej, gdy proces powtarza się regularnie lub gdy liczba tłumaczeń jest tak duża, że ręczna obsługa plików staje się wąskim gardłem. Braze oferuje API do tłumaczeń (w fazie wczesnego dostępu w momencie pisania tego tekstu), a Iterable udostępnia treść szablonów przez GET /api/templates/email/get. Brevo nie obsługuje żadnej z tych opcji: nie oferuje tłumaczeń opartych na plikach, więc kampanie trzeba tłumaczyć bezpośrednio w interfejsie.

Ile języków może obsługiwać pojedyncza kampania e-mailowa?

To zależy od platformy. Braze pozwala na maksymalnie 200 lokalizacji w ramach obszaru roboczego i 200 tagów tłumaczeniowych w jednej wiadomości. Klaviyo obsługuje ponad 60 języków dzięki funkcji Smart Translations. Customer.io akceptuje kilkaset kodów języków i wariantów regionalnych. W praktyce rzadko ograniczają nas limity platformy; prawdziwym wyzwaniem jest liczba języków, które jesteś w stanie na bieżąco weryfikować i aktualizować wraz ze zmianami w treści źródłowej.

Autor

Mariia Ivakhnenko
Mariia IvakhnenkoWspółzałożycielka

Współzałożycielka Transept. Posiada trzy dyplomy z filologii angielskiej – studiowała w Kijowie, Ostrawie i spędziła rok w Salzburgu. Z pochodzenia Ukrainka, która większość swojego pisarskiego życia spędza w języku angielskim. Do świata AI weszła jako inżynierka promptów, a następnie zajęła się marketingiem produktu i cyklu życia. Pisze na wpół fikcyjne historie o prawdziwych ludziach i wciąż krąży wokół pytania o to, co gubi się w tłumaczeniu między językami.