Wdrożenie Omnibusa w sklepie na WooCommerce (kurs)

Przy okazji ostatniej większej zmiany wyglądu strony pisałem o „szablonach potomnych” w WordPressie. Wtedy też  (zmiana szablonu) wystąpił „mały zgrzyt” z brakiem tłumaczeń niektórych tekstów, a to oznacza dobrą okazję do napisania tekstu na ten temat, bo choć coraz więcej motywów i wtyczek zawiera polskie tłumaczenia w sobie, to nie tylko może się zdarzyć, że dany motyw czy dana wtyczka nie będzie takiego tłumaczenia mieć, ale też może ono być niekompletne lub niepoprawne.

Proste i wygodne tłumaczenie w WordPressie

Sposób tłumaczenia szablonu i/lub wtyczki zależy od tego, czy autor przygotował go/ją pod obsługę plików językowych (gettext). Najprościej to rozpoznać patrząc do dokumentacji, bądź bezpośrednio do kodu szablonu/wtyczki – jeśli znajdziemy tam fragmenty podobne do:

printf( __( 'All posts by %s', 'twentyfourteen' ), get_the_author() );

To znaczy, że szablon i/lub wtyczką obsługują pliki językowe (gettext) i możemy przystąpić do następnych kroków.

Tłumaczymy za pomocą .po/.mo czy functions.php?

Korzystając z „gettext” możemy do tłumaczenia podejść na 2 sposoby:

  • Tworząc/edytując plik .po (edycja) i .mo (zapis)
  • Korzystając z funkcji w pliku functions.php

Druga metoda (functions.php) sprawdzi się najlepiej przy małej ilości tekstów do przetłumaczenia, gdy zabawa w tworzenie i/lub edycję plików .po/.mo może być nieopłacalna, lub gdy inaczej do danego tekstu nie da się dobrać (albo chcemy zmienić oryginalnie przetłumaczony tekst na inny). Przy większej ilości tekstów do tłumaczenia zdecydowanie warto skorzystać z plików .po/.mo (konkretnie z .po, bo .mo są generowane z .po).

Tłumaczymy szablon lub wtyczkę za pomocą plików .po/.mo

Jeśli do szablonu lub wtyczki dołączony jest plik .po lub .pot (szablon) to sprawa jest prosta – kopiujemy go pod nową nazwą, zazwyczaj:

  • pl_PL.po
  • nazwa-pl_PL.po

Edytujemy np. w programie Poedit:

poedit02

Po czym zapisujemy – przy okazji wygeneruje się też plik .mo, i oba te pliki kopiujemy tam, gdzie trzeba – więcej o tym za chwilę. Zamiast programu Poedit można skorzystać z wtyczki Loco Translate, co umożliwia przygotowanie odpowiedniego tłumaczenia bezpośrednio z kokpitu WordPressa.

Gdy nie ma pliku .po(t)

Może się jednak zdarzyć, że w motywie bądź wtyczce nie ma pliku szablonu (.pot), ani pliku z innymi tłumaczeniami (.po), by wykorzystać jako swego rodzaju wzornik. W takim przypadku mamy 3 możliwości:

  • Tworzymy samodzielnie plik .po i dodajemy ręcznie kolejne frazy do przetłumaczenia
  • Pobieramy (automatycznie) frazy z plików wtyczki/szablonu
  • Korzystamy z wtyczki Loco Translate, która w niektórych przypadkach pozwoli wygenerować odpowiednie pliki na bazie kodu motywu/wtyczki

W pierwszym przypadku tworzymy nowy plik tekstowy, znajdujemy na stronie nieprzetłumaczony tekst, i dodajmy go do naszego pliku w formacie:

msgid "Tekst do przetłumaczenia"
msgstr "Tekst przetłumaczony"

Całość zapisujemy jako plik z rozszerzeniem .po, i otwieramy np. w programie PoEdit, który resztę (łącznie z nagłówkami) zrobi za nas.

Metoda prosta i szybka, choć sprawdzi się raczej w przypadku prostych tekstów. W przypadku „zmiennych” mogą się pojawić problemy – dlatego lepiej potraktować ją jako uzupełnienie metody polegającej na wyciągnięciu danych ze źródeł:

Sięgamy do źródeł

Czasem się zdarza, że wprawdzie autor przygotował swój szablon lub wtyczkę pod obsługę plików językowych, ale nie udostępnił plików, od których moglibyśmy zacząć naszą pracę. W takim przypadku musimy sięgnąć do analizy źródeł – w tej pracy warto wspomóc się np. wspomnianym powyżej programem Poedit lub wtyczką Loco Transalte, który sporą część pracy z tym związanej wykona za nas.

Uruchamiamy program Poedit i wybieramy:

  • Plik > Nowe…

A następnie:

 Język tłumaczenia: polski (Polska)

I:

Wyodrębnij ze źródeł
Konfiguruj kod źródłowy wyodrębniania we właściwościach.

poedit01

Pojawi się nowe okno, w którym w zakładce „źródła słuch kluczowych” dodajemy:

__
_e

poedit_tworzenie-ze-zrodel_zrodla-slow-kluczowych01

Następnie klikamy OK i zapisujemy plik, np. jako:

pl_PL.po

Lub:

nazwa-pl_PL.po

Po tej operacji kolejny raz wybieramy:

Wyodrębnij ze źródeł
Konfiguruj kod źródłowy wyodrębniania we właściwościach.

Tym razem przechodzimy do zakładki „Ścieżki źródeł” i wskazujemy ścieżkę do katalogu ze skórką:

poedit_tworzenie-ze-zrodel_sciezki-zrodel01

Po chwili (zależnie od ilości plików i tekstów w nich) pojawi się nam ekran ze znalezionymi tekstami, gotowymi do tłumaczenia:

poedit02

Dalej postępujemy tak samo, jak w przypadku wcześniejszej edycji plików .po/.pot

Gdzie i pod jaką nazwą zapisać pliki?

Tu nie ma jednej odpowiedzi – sporo zależy od tego, jak to sobie wymyślił autor szablonu/wtyczki, ale są pewne standardy, i jest duża szansa, że… ;-)

Głównym katalogiem z plikami językowymi w WordPressie jest katalog:

wp-content/languages

Znajdziemy tu m.in. pliki językowe samego WordPressa.

Innymi popularnymi katalogami – odpowiednio dla szablonów i wtyczek – są:

wp-content/languages/themes
wp-content/languages/plugins

We wszystkich tych katalogach – z racji tego, że są to katalogi wspólne – zazwyczaj pliki językowe są zapisywane w formacie:

[nazwa]-pl_PL.po
[nazwa]-pl_PL.mo

Zdarzają się sytuacje, gdy pliki językowe należy umieszczać bezpośrednio w katalogu szablony lub wtyczki, często w podkatalogu „languages”:

wp-content/themes/[katalog szablonu]/languages
wp-content/plugins/[katalog wtyczki]/languages

Wtedy zazwyczaj zapisuje się je w formie:

pl_PL.po
pl_PL.mo

To rozwiązanie ma jednak taki minus, że wraz z aktualizacją wtyczki lub motywu utracimy nasze tłumaczenia. Dlatego należy traktować to jako ostateczną ostateczność.

Chmura tłumaczeń WordPressa ma pierwszeństwo

Z racji tego, że w pewnym momencie ekipa odpowiedzialna za rozwój WordPressa dość mocno postawiła na rozwój swojej „chmury tłumaczeń”, to tłumaczenia tam znajdujące się, mają pierwszeństwo. I nie byłoby to problemem, gdyby nie to, że często tłumaczenia te są nie tylko niekompletne, ale też średniej jakości.

W takim przypadku można pliki z tłumaczeniami motywu umieścić w motywie potomnym, z odzwierciedleniem oryginalnej ścieżki. Często będzie to coś w stylu:

wp-content/themes/motyw-potomny/languages

Oprócz tego może być wymagane dodanie odrobiny kodu w pliku functions.php (motywu potomnego), np.:

function webinsider_wp_child_theme_languages() {
    load_child_theme_textdomain( 'child', get_stylesheet_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'webinsider_wp_child_theme_languages' );

Jest spora szansa, że w ten sposób nasze tłumaczenie zdoła napisać tłumaczenie oryginalne tłumaczenie. Jako alternatywę – zwłaszcza w przypadku zmian pojedynczych tekstów – można zastosować metodę opisną poniżej (przydaje się też w przypadku bardziej odpornych na tłumaczenia tekstów).

Tłumaczymy szablon lub wtyczkę za pomocą funkcji w pliku functions.php

Na wstępie  dodam, że wprawdzie można modyfikacji dokonywać na oryginalnych plikach szablonu, to zdecydowanie polecam skorzystać z „szablonów potomnych” (child themes), dzięki czemu nie stracimy zmian przy aktualizacji motywu.

Zaczynamy od utworzenia – jeśli jeszcze go nie ma – pliku functions.php w katalogu naszego szablonu, o takiej zawartości:

<?php

Prawda, że nić trudnego? ;-)

Gdy już mamy przygotowany plik, wpisujemy po „<?php” np. taki kod:

function translate_text( $translated ) {
	$translated = str_ireplace( 'Submit a Comment', 'Napisz komentarz', $translated );
	return $translated;
}
add_filter( 'gettext', 'webinsider_wp_translate_text' );

Przy większej ilości tekstów do przetłumaczenia również możemy skorzystać z tej metody, odpowiednio zwielokrotniając jedną z linijek:

function webinsider_wp_translate_text( $translated ) {
	$translated = str_ireplace( 'Submit a Comment', 'Napisz komentarz', $translated );
	$translated = str_ireplace( 'Posted by %1$s in %2$s', 'Opublikował %1$s w kategoriach: %2$s', $translated );
	return $translated;
}
add_filter( 'gettext', 'webinsider_wp_translate_text' );

Ale osobiście w takim przypadku polecam skorzystać z tabeli – będzie znacznie przejrzyściej:

function webinsider_wp_translate_text( $translated ) {
	$text2translate = array(
		'Submit a Comment' => 'Napisz komentarz',
		'Posted by %1$s in %2$s' => 'Opublikował %1$s w kategoriach: %2$s',
	);
	$translated = str_ireplace(  array_keys($text2translate),  $text2translate,  $translated );
	return $translated;
}
add_filter( 'gettext', 'webinsider_wp_translate_text' );

W przypadku większych stron, z większą liczbą (ilością) tekstów, które potencjalnie można tłumaczyć, można rozważyć dodanie na początku funkcji warunku sprawdzającego „texdomain” dla danego tekstu, tak by filtr nie musiał sprawdzać (i modyfikować) wszystkich pasujących tekstów, nie tylko w WordPressie, motywie, ale też i wszystkich aktywnych wtyczkach:

if ( 'texdomain' !== $textdomain ) {
	return $translated;
}

Jeśli nie będzie to pasujący „textdomain” (lub pasujące, bo warunek można rozbudować) operacja przeszukiwania i tłumaczenia tekstów zostanie przerwana.

Trzeba wtedy też na wejściu funkcji dostarczyć zmienną „textdomain”:

function webinsider_wp_translate_text( $translated, $untranslated, $textdomain ) {

Oraz w filtrze podać liczbę parametrów do pobrania:

add_filter( 'gettext', 'webinsider_wp_translate_text', 10, 3 );

Na koniec zapisujemy nasz plik i to wszystko. Ta metoda oprócz tego, że najczęściej jest szybsza do wdrożenia niż generowanie tłumaczenia na bazie pliku .po(t), to często umożliwia przetłumaczenie tekstów, które przetłumaczyć się nie chcą. Pozwala też zmodyfikować tekst już przetłumaczony (w plikach językowych samego WordPressa, motyw lub wtyczki), gdy z jakiegoś powodu potrzebujemy go zmienić.

Tłumaczenie tylko frontendu

Korzystanie z tłumaczenia za pomocą „gettext” ma jeszcze jedną zaletę – możemy dość swobodnie sterować tym, kiedy tłumaczenia mają być wykonywane. Osobiście najczęściej tłumaczę tylko to, co widzi zewnętrzny użytkownik (frontend), a nie tłumaczę opcji w panelu zarządzania (backend), bo nie mam takiej potrzeby.

I tu z pomocą przychodzi jeden z warunków dostępnych w WordPressie, czyli:

if ( !is_admin() ) { ... }

Dzięki któremu filtr z tłumaczeniem można uruchomić tylko, gdy nie będzie to strona panelu zarządzania WordPressem (WP-Admin):

if ( !is_admin() ) add_filter( 'gettext', 'webinsider_wp_translate_text', 10, 3 );

Zawsze to trochę mniej pracy dla (web)serwera, a do tego nie wchodzą nam tłumaczenia do ustawień…

(!) Zgłoś błąd na stronie
Pomogłem? To może postawisz mi wirtualną kawę?
LUTy dla D-Cinelike (DJI Mini 3 Pro, DJI Avata, OSMO Pocket) od MiniFly
Wdrożenie Omnibusa w sklepie na WooCommerce
Jak (legalnie) latać dronem w Kategorii Otwartej
Wdrożenie Omnibusa w sklepie na WooCommerce (kurs)
Patryk
Wdrożenie Omnibusa w sklepie na WooCommerce (kurs)