{"id":20865,"date":"2026-10-18T17:58:00","date_gmt":"2026-10-18T15:58:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=20865"},"modified":"2026-10-09T22:29:15","modified_gmt":"2026-10-09T20:29:15","slug":"tlumaczenie-wtyczek-wordpress","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/","title":{"rendered":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript"},"content":{"rendered":"<p>Wtyczka napisana wy\u0142\u0105cznie po angielsku wy\u015bwietla angielskie przyciski tak\u017ce na niemieckiej czy polskiej stronie, cho\u0107 sam WordPress od dawna m\u00f3wi j\u0119zykiem odwiedzaj\u0105cych. Ten blog ukazuje si\u0119 po angielsku, niemiecku i polsku, wi\u0119c ka\u017cdy tekst u\u017cywanej tu wtyczki musi istnie\u0107 w trzech wersjach, \u0142\u0105cznie z komunikatami, kt\u00f3re JavaScript dopisuje do strony dopiero po jej za\u0142adowaniu. WordPress rozwi\u0105zuje to na trzech poziomach: wywo\u0142ania gettext w PHP, osobne pliki JSON dla skrypt\u00f3w oraz paczki j\u0119zykowe budowane i rozsy\u0142ane przez translate.wordpress.org. Wiele starszych poradnik\u00f3w wci\u0105\u017c wywo\u0142uje <code>load_plugin_textdomain()<\/code> wcze\u015bnie, w <code>plugins_loaded<\/code>, cho\u0107 od WordPressa 6.7 to wywo\u0142anie tylko rejestruje \u015bcie\u017ck\u0119; komunikat wprowadzony w 6.7 pochodzi z wywo\u0142a\u0144 t\u0142umacze\u0144 przed <code>after_setup_theme<\/code>.<\/p>\n<p>W tym artykule zbudujemy ma\u0142\u0105 wtyczk\u0119 \u201eLW Reading Time\u201d z jednym plikiem PHP i skryptem importuj\u0105cym <code>@wordpress\/i18n<\/code>. Przyjrzymy si\u0119 funkcjom t\u0142umacze\u0144 i regu\u0142om liczby mnogiej dla niemieckiego i polskiego. Poka\u017cemy te\u017c, co WordPress 7.1.2 (aktualne wydanie na dzie\u0144 29.09.2026) \u0142aduje samodzielnie, jak tekst trafia przez GlotPress do paczki j\u0119zykowej i jak lokalnie budowa\u0107 pliki t\u0142umacze\u0144 za pomoc\u0105 WP-CLI. <a href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/plugin-check-lokalnie-i-w-ci\/\">Plugin Check<\/a> i <a href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/readme-naglowek-wtyczki-svn\/\">pola pliku <code>readme.txt<\/code><\/a> maj\u0105 w tej serii osobne artyku\u0142y; tutaj omawiamy je tylko w zwi\u0105zku z t\u0142umaczeniami.<\/p>\n<h2>Text domain: jeden identyfikator, zgodny ze slugiem<\/h2>\n<p>Ka\u017cde wywo\u0142anie gettext przyjmuje jako ostatni argument text domain, czyli identyfikator wskazuj\u0105cy, do kt\u00f3rego pliku t\u0142umacze\u0144 nale\u017cy dany tekst. Dla wtyczek z katalogu WordPress.org regu\u0142a jest \u015bcis\u0142a: text domain musi by\u0107 identyczny ze slugiem. Wtyczka o slugu <code>akismet<\/code> u\u017cywa wi\u0119c text domain <code>akismet<\/code> i nie powinna mie\u0107 drugiego. Wed\u0142ug podr\u0119cznika Meta wtyczka \u0142ami\u0105ca t\u0119 zasad\u0119 nie zostanie poprawnie zaimportowana do translate.wordpress.org i nie dostanie paczek j\u0119zykowych. Dozwolone s\u0105 ma\u0142e litery i my\u015blniki, bez podkre\u015ble\u0144 i spacji.<\/p>\n<p>Text domain musi te\u017c by\u0107 dos\u0142ownym ci\u0105giem znak\u00f3w. <code>wp i18n make-pot<\/code> i importer na WordPress.org czytaj\u0105 kod \u017ar\u00f3d\u0142owy bez jego wykonywania, dlatego sta\u0142a lub zmienna w miejscu <code>'lw-reading-time'<\/code> pozostaje dla nich niewidoczna; podr\u0119cznik wtyczek wprost odradza taki skr\u00f3t. Nawet teksty, kt\u00f3re rdze\u0144 ju\u017c t\u0142umaczy, na przyk\u0142ad \u201eSettings\u201d, dostaj\u0105 w\u0142asny text domain wtyczki. W przeciwnym razie trac\u0105 t\u0142umaczenie, gdy tylko rdze\u0144 zmieni brzmienie.<\/p>\n<p>Nag\u0142\u00f3wek <code>Text Domain<\/code> jest wed\u0142ug podr\u0119cznika opcjonalny od WordPressa 4.6, a <code>Domain Path<\/code> wtyczki z katalogu mog\u0105 pomin\u0105\u0107. Mimo to warto ustawia\u0107 oba: <code>make-pot<\/code> domy\u015blnie odczytuje text domain z nag\u0142\u00f3wka, a od WordPressa 6.8 w\u0142a\u015bnie ta para pozwala wtyczkom spoza katalogu automatycznie \u0142adowa\u0107 t\u0142umaczenia. Plugin Check 2.1.0 (wydany 16.08.2026) zg\u0142asza nieprawid\u0142owy format text domain jako b\u0142\u0105d, a nag\u0142\u00f3wek niezgodny ze slugiem jako ostrze\u017cenie. Ostrze\u017cenie pojawia si\u0119 te\u017c wtedy, gdy <code>Domain Path<\/code> nie zaczyna si\u0119 od uko\u015bnika albo wskazuje nieistniej\u0105cy katalog. Dlatego przyk\u0142adowa wtyczka zawiera katalog <code>languages\/<\/code> z plikiem POT.<\/p>\n<h2>Funkcje gettext w PHP<\/h2>\n<p>G\u0142\u00f3wny plik przyk\u0142adowej wtyczki pokazuje nad pojedynczymi wpisami szacowany czas czytania i dodaje przycisk, kt\u00f3rego etykiet\u0119 p\u00f3\u017aniej zmienia skrypt. Ka\u017cdy widoczny tekst przechodzi przez funkcj\u0119 t\u0142umacz\u0105c\u0105:<\/p>\n\n\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"php\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">PHP<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-php\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-meta\">&lt;?php<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/**<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Plugin Name:       LW Reading Time<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Description:       Shows the estimated reading time above single posts.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Version:           1.0.0<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Requires at least: 6.8<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Requires PHP:      7.4<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Author:            Lukas Wojcik<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * License:           GPL-2.0-or-later<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * License URI:       https:\/\/www.gnu.org\/licenses\/gpl-2.0.html<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Text Domain:       lw-reading-time<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Domain Path:       \/languages<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * @package LW_Reading_Time<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *\/<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">defined<\/span>( <span class=\"cbb-string\">'ABSPATH'<\/span> ) || exit;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">const<\/span> <span class=\"cbb-constant\">LW_READING_TIME_WORDS_PER_MINUTE<\/span> = <span class=\"cbb-number\">200<\/span>;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/**<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Returns the estimated reading time of a post in whole minutes.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * @param WP_Post $post Post object.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * @return int Minutes, at least 1.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *\/<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">lw_reading_time_minutes<\/span>( WP_Post <span class=\"cbb-variable\">$post<\/span> ) {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$text<\/span>  = <span class=\"cbb-function\">wp_strip_all_tags<\/span>( <span class=\"cbb-function\">strip_shortcodes<\/span>( <span class=\"cbb-variable\">$post<\/span><span class=\"cbb-operator\">-&gt;<\/span>post_content ) );\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$words<\/span> = <span class=\"cbb-function\">preg_split<\/span>( <span class=\"cbb-string\">'\/\\s+\/u'<\/span>, <span class=\"cbb-function\">trim<\/span>( <span class=\"cbb-variable\">$text<\/span> ), <span class=\"cbb-number\">-1<\/span>, <span class=\"cbb-constant\">PREG_SPLIT_NO_EMPTY<\/span> );\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-function\">max<\/span>( <span class=\"cbb-number\">1<\/span>, <span class=\"cbb-type\">(int)<\/span> <span class=\"cbb-function\">ceil<\/span>( <span class=\"cbb-function\">count<\/span>( <span class=\"cbb-variable\">$words<\/span> ) \/ <span class=\"cbb-constant\">LW_READING_TIME_WORDS_PER_MINUTE<\/span> ) );\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/**<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Prepends the reading time and a \"mark as read\" button to single posts.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * @param string $content Post content.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * @return string<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *\/<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">lw_reading_time_prepend<\/span>( <span class=\"cbb-variable\">$content<\/span> ) {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">if<\/span> ( ! <span class=\"cbb-function\">is_singular<\/span>( <span class=\"cbb-string\">'post'<\/span> ) || ! <span class=\"cbb-function\">in_the_loop<\/span>() || ! <span class=\"cbb-function\">is_main_query<\/span>() ) {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-variable\">$content<\/span>;\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$post<\/span>    = <span class=\"cbb-function\">get_post<\/span>();\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$minutes<\/span> = <span class=\"cbb-function\">lw_reading_time_minutes<\/span>( <span class=\"cbb-variable\">$post<\/span> );\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$label<\/span> = <span class=\"cbb-function\">sprintf<\/span>(\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-comment\">\/* translators: %s: estimated reading time in minutes. *\/<\/span>\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-function\">_n<\/span>( <span class=\"cbb-string\">'Reading time: %s minute'<\/span>, <span class=\"cbb-string\">'Reading time: %s minutes'<\/span>, <span class=\"cbb-variable\">$minutes<\/span>, <span class=\"cbb-string\">'lw-reading-time'<\/span> ),\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-function\">number_format_i18n<\/span>( <span class=\"cbb-variable\">$minutes<\/span> )\n<\/span><span class=\"cbb-line\">\t);\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$button<\/span> = <span class=\"cbb-function\">sprintf<\/span>(\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-string\">'&lt;button type=\"button\" class=\"lw-reading-time__mark\" data-post=\"%1$d\"&gt;%2$s&lt;\/button&gt;'<\/span>,\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-type\">(int)<\/span> <span class=\"cbb-variable\">$post<\/span><span class=\"cbb-operator\">-&gt;<\/span>ID,\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-function\">esc_html__<\/span>( <span class=\"cbb-string\">'Mark as read'<\/span>, <span class=\"cbb-string\">'lw-reading-time'<\/span> )\n<\/span><span class=\"cbb-line\">\t);\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-string\">'&lt;p class=\"lw-reading-time\"&gt;'<\/span> . <span class=\"cbb-function\">esc_html<\/span>( <span class=\"cbb-variable\">$label<\/span> ) . <span class=\"cbb-string\">' '<\/span> . <span class=\"cbb-variable\">$button<\/span> . <span class=\"cbb-string\">'&lt;\/p&gt;'<\/span> . <span class=\"cbb-variable\">$content<\/span>;\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">add_filter<\/span>( <span class=\"cbb-string\">'the_content'<\/span>, <span class=\"cbb-string\">'lw_reading_time_prepend'<\/span> );\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/**<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> * Enqueues the front-end script and connects it to its translation files.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"> *\/<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">lw_reading_time_enqueue_script<\/span>() {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">if<\/span> ( ! <span class=\"cbb-function\">is_singular<\/span>( <span class=\"cbb-string\">'post'<\/span> ) ) {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">return<\/span>;\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$asset_file<\/span> = <span class=\"cbb-function\">plugin_dir_path<\/span>( __FILE__ ) . <span class=\"cbb-string\">'build\/index.asset.php'<\/span>;\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">if<\/span> ( ! <span class=\"cbb-function\">file_exists<\/span>( <span class=\"cbb-variable\">$asset_file<\/span> ) ) {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">return<\/span>;\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$asset<\/span> = <span class=\"cbb-keyword\">require<\/span> <span class=\"cbb-variable\">$asset_file<\/span>;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-function\">wp_enqueue_script<\/span>(\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-string\">'lw-reading-time'<\/span>,\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-function\">plugins_url<\/span>( <span class=\"cbb-string\">'build\/index.js'<\/span>, __FILE__ ),\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-variable\">$asset<\/span>&#91;<span class=\"cbb-string\">'dependencies'<\/span>&#93;,\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-variable\">$asset<\/span>&#91;<span class=\"cbb-string\">'version'<\/span>&#93;,\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">array<\/span>( <span class=\"cbb-string\">'in_footer'<\/span> <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-constant\">true<\/span> )\n<\/span><span class=\"cbb-line\">\t);\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-comment\">\/\/ Looks for lw-reading-time-{locale}-{md5 of \"build\/index.js\"}.json in wp-content\/languages\/plugins, without a language pack there in languages\/ (Domain Path).<\/span>\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-function\">wp_set_script_translations<\/span>( <span class=\"cbb-string\">'lw-reading-time'<\/span>, <span class=\"cbb-string\">'lw-reading-time'<\/span> );\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">add_action<\/span>( <span class=\"cbb-string\">'wp_enqueue_scripts'<\/span>, <span class=\"cbb-string\">'lw_reading_time_enqueue_script'<\/span> );<\/span><\/code><\/pre><\/figure>\n\n\n<p><code>__()<\/code> zwraca t\u0142umaczenie, <code>_e()<\/code> od razu je wypisuje. W\u0142a\u015bnie takie wypisywanie bez escapowania wytykaj\u0105 WordPress Coding Standards: sniff <code>EscapeOutput<\/code> traktuje <code>_e()<\/code> i <code>_ex()<\/code> jako niebezpieczne funkcje wyj\u015bcia i proponuje w zamian <code>esc_html_e()<\/code> lub <code>esc_attr_e()<\/code>. Funkcje \u0142\u0105czone <code>esc_html__()<\/code>, <code>esc_html_e()<\/code>, <code>esc_attr__()<\/code>, <code>esc_attr_e()<\/code>, <code>esc_html_x()<\/code> i <code>esc_attr_x()<\/code> t\u0142umacz\u0105 i escapuj\u0105 w jednym kroku. T\u0142umaczenie to wci\u0105\u017c tekst spoza kodu, wi\u0119c traktuje si\u0119 je jak ka\u017cde inne wyj\u015bcie. W przyk\u0142adzie <code>esc_html()<\/code> obejmuje wynik <code>sprintf()<\/code>; escapowanie samego wzorca pozostawi\u0142oby wstawion\u0105 warto\u015b\u0107 bez kontroli.<\/p>\n<h3>Symbole zast\u0119pcze i komentarze dla t\u0142umaczy<\/h3>\n<p>Zmienne nigdy nie trafiaj\u0105 do t\u0142umaczonego tekstu. Wywo\u0142anie <code>_e( \"Your city is $city.\" )<\/code> nie zadzia\u0142a, bo ekstraktor znajdzie tekst z dos\u0142ownym <code>$city<\/code>, a WordPress w czasie dzia\u0142ania b\u0119dzie szuka\u0142 tekstu z faktyczn\u0105 nazw\u0105 miasta, kt\u00f3rej nie ma w \u017cadnym pliku t\u0142umacze\u0144. Poprawna forma to symbol zast\u0119pczy z <code>printf()<\/code> lub <code>sprintf()<\/code>. Przy kilku symbolach podr\u0119cznik zaleca numerowane argumenty, takie jak <code>%1$s<\/code> i <code>%2$s<\/code>, w pojedynczych cudzys\u0142owach, aby t\u0142umaczenie mog\u0142o zmieni\u0107 ich kolejno\u015b\u0107.<\/p>\n<p>Komentarz zaczynaj\u0105cy si\u0119 od <code>translators:<\/code> wyja\u015bnia t\u0142umaczom, co oznacza symbol zast\u0119pczy. Musi by\u0107 ostatnim komentarzem PHP przed wywo\u0142aniem gettext; <code>make-pot<\/code> przenosi go do pliku POT jako wiersz <code>#.<\/code>, a GlotPress wy\u015bwietla go obok tekstu. Sam\u0105 liczb\u0119 przepuszcza si\u0119 przez <code>number_format_i18n()<\/code>, bo niemiecki i polski stosuj\u0105 inne separatory tysi\u0119cy ni\u017c angielski.<\/p>\n<p><code>_x()<\/code> dodaje kontekst dla s\u0142\u00f3w o wielu znaczeniach; GlotPress traktuje par\u0119 kontekst plus tekst jako osobny wpis. Skrypt poni\u017cej u\u017cywa <code>_x( 'Read', \u2026 )<\/code> dla stanu po klikni\u0119ciu. Bez kontekstu \u201eRead\u201d mog\u0142oby zosta\u0107 przet\u0142umaczone jako czasownik \u201eCzytaj\u201d albo \u201eLesen\u201d, a przycisk potrzebuje formy \u201ePrzeczytany\u201d lub \u201eGelesen\u201d.<\/p>\n<h3>Formy liczby mnogiej: dwie po angielsku i niemiecku, trzy po polsku<\/h3>\n<p><code>_n()<\/code> przyjmuje liczb\u0119 pojedyncz\u0105, mnog\u0105, liczb\u0119 element\u00f3w i text domain. Angielskiemu i niemieckiemu wystarczaj\u0105 dwie formy, polski potrzebuje trzech. Regu\u0142\u0119 zapisuje nag\u0142\u00f3wek <code>Plural-Forms<\/code> danego j\u0119zyka. GlotPress, oprogramowanie stoj\u0105ce za translate.wordpress.org, definiuje polski jako <code>nplurals=3<\/code> z wyra\u017ceniem <code>(n == 1) ? 0 : ((n % 10 &gt;= 2 &amp;&amp; n % 10 &lt;= 4 &amp;&amp; (n % 100 &lt; 12 || n % 100 &gt; 14)) ? 1 : 2)<\/code>; polski eksport z translate.wordpress.org ma identyczny nag\u0142\u00f3wek. Dla czasu czytania daje to:<\/p>\n<table>\n<thead>\n<tr><th>Minuty<\/th><th>Angielski<\/th><th>Niemiecki<\/th><th>Polski (forma)<\/th><\/tr>\n<\/thead>\n<tbody>\n<tr><td>1<\/td><td>Reading time: 1 minute<\/td><td>Lesezeit: 1 Minute<\/td><td>Czas czytania: 1 minuta (0)<\/td><\/tr>\n<tr><td>2<\/td><td>Reading time: 2 minutes<\/td><td>Lesezeit: 2 Minuten<\/td><td>Czas czytania: 2 minuty (1)<\/td><\/tr>\n<tr><td>5<\/td><td>Reading time: 5 minutes<\/td><td>Lesezeit: 5 Minuten<\/td><td>Czas czytania: 5 minut (2)<\/td><\/tr>\n<tr><td>12<\/td><td>Reading time: 12 minutes<\/td><td>Lesezeit: 12 Minuten<\/td><td>Czas czytania: 12 minut (2)<\/td><\/tr>\n<tr><td>21<\/td><td>Reading time: 21 minutes<\/td><td>Lesezeit: 21 Minuten<\/td><td>Czas czytania: 21 minut (2)<\/td><\/tr>\n<tr><td>22<\/td><td>Reading time: 22 minutes<\/td><td>Lesezeit: 22 Minuten<\/td><td>Czas czytania: 22 minuty (1)<\/td><\/tr>\n<\/tbody>\n<\/table>\n<p>St\u0105d bierze si\u0119 zasada z podr\u0119cznika: r\u00f3wnie\u017c liczba pojedyncza zawiera symbol zast\u0119pczy, czyli <code>'%s minute'<\/code>, a nie <code>'One minute'<\/code>, poniewa\u017c w niekt\u00f3rych j\u0119zykach \u201epojedyncza\u201d forma obejmuje tak\u017ce inne liczby ni\u017c jeden. Kod przekazuje tylko liczb\u0119, a o tym, kt\u00f3re z trzech polskich zda\u0144 si\u0119 pojawi, decyduje plik t\u0142umacze\u0144. Dla tekst\u00f3w w liczbie mnogiej, kt\u00f3rych liczba nie jest jeszcze znana w chwili definicji, istniej\u0105 <code>_n_noop()<\/code> i <code>translate_nooped_plural()<\/code>.<\/p>\n<h2>Kto \u0142aduje t\u0142umaczenia: just-in-time zamiast load_plugin_textdomain<\/h2>\n<p>WordPress 4.6 zmieni\u0142 spos\u00f3b \u0142adowania od podstaw. Notatka dla deweloper\u00f3w z lipca 2016 roku wprowadzi\u0142a \u0142adowanie just-in-time: gdy WordPress po raz pierwszy natrafi na dany text domain, <code>_load_textdomain_just_in_time()<\/code> szuka pasuj\u0105cego pliku w <code>wp-content\/languages<\/code> i go wczytuje. Od tego czasu wtyczki z katalogu nie potrzebuj\u0105 <code>load_plugin_textdomain()<\/code>. W tej samej wersji odwr\u00f3cono kolejno\u015b\u0107 wyszukiwania: paczki j\u0119zykowe w <code>wp-content\/languages<\/code> maj\u0105 pierwsze\u0144stwo przed plikami w katalogu wtyczki.<\/p>\n<p>WordPress 6.5 zmieni\u0142 mechanizm t\u0142umacze\u0144. Paczki j\u0119zykowe zawieraj\u0105 odt\u0105d obok <code>.po<\/code> i <code>.mo<\/code> tak\u017ce plik <code>.l10n.php<\/code>. Je\u015bli ten plik istnieje, WordPress wczytuje go zamiast <code>.mo<\/code>. Dzi\u0119ki temu \u0142adowanie jest szybsze, zu\u017cywa mniej pami\u0119ci i korzysta z OPcache. Filtr <code>translation_file_format<\/code> pozwala wr\u00f3ci\u0107 do formatu <code>mo<\/code>.<\/p>\n<p>WordPress 6.7 zamieni\u0142 <code>load_plugin_textdomain()<\/code> w sam\u0105 rejestracj\u0119: funkcja zapami\u0119tuje tylko \u015bcie\u017ck\u0119, a w\u0142a\u015bciwe \u0142adowanie zostawia mechanizmowi just-in-time. Jednocze\u015bnie pojawi\u0142 si\u0119 komunikat <code>_doing_it_wrong()<\/code>. Gdy t\u0142umaczenia danej domeny zostan\u0105 za\u017c\u0105dane przed <code>after_setup_theme<\/code>, WordPress informuje, \u017ce \u0142adowanie uruchomiono \u201etoo early\u201d, i wskazuje <code>init<\/code> jako najwcze\u015bniejszy w\u0142a\u015bciwy moment. Wed\u0142ug notatki tak wczesne \u0142adowanie zmusza WordPressa do przedwczesnego ustalenia bie\u017c\u0105cego u\u017cytkownika i odbiera innym wtyczkom mo\u017cliwo\u015b\u0107 filtrowania j\u0119zyka lub \u015bcie\u017cki pliku. Dla test\u00f3w istotny jest szczeg\u00f3\u0142 z pliku <code>l10n.php<\/code> w rdzeniu: komunikat pojawia si\u0119, gdy rdze\u0144 zna katalog j\u0119zykowy dla danej domeny, a nie dopiero wtedy, gdy istnieje plik t\u0142umacze\u0144. Od wersji 6.8 rdze\u0144 rejestruje dla ka\u017cdej aktywnej wtyczki katalog z nag\u0142\u00f3wka <code>Domain Path<\/code> (bez nag\u0142\u00f3wka katalog wtyczki), dlatego w WordPressie 7.1.2 poni\u017cszy przyk\u0142ad wywo\u0142uje komunikat tak\u017ce na stronie po angielsku bez \u017cadnego pliku t\u0142umacze\u0144.<\/p>\n\n\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"php\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">PHP<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-php\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-meta\">&lt;?php<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ Too early: runs while WordPress loads the plugin file, before after_setup_theme and init.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ WordPress 6.7+ reports (since 6.8 also without a translation file, even on en_US)<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ _load_textdomain_just_in_time() via _doing_it_wrong().<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">define<\/span>( <span class=\"cbb-string\">'LW_READING_TIME_TITLE'<\/span>, <span class=\"cbb-function\">__<\/span>( <span class=\"cbb-string\">'Reading time'<\/span>, <span class=\"cbb-string\">'lw-reading-time'<\/span> ) );\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ Better: translate at the moment the text is needed (init or later).<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">lw_reading_time_title<\/span>() {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-function\">__<\/span>( <span class=\"cbb-string\">'Reading time'<\/span>, <span class=\"cbb-string\">'lw-reading-time'<\/span> );\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ Plugin metadata without translating it: third parameter $translate = false.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">lw_reading_time_version<\/span>() {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">if<\/span> ( ! <span class=\"cbb-function\">function_exists<\/span>( <span class=\"cbb-string\">'get_plugin_data'<\/span> ) ) {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">require_once<\/span> <span class=\"cbb-constant\">ABSPATH<\/span> . <span class=\"cbb-string\">'wp-admin\/includes\/plugin.php'<\/span>;\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-variable\">$data<\/span> = <span class=\"cbb-function\">get_plugin_data<\/span>( __FILE__, <span class=\"cbb-constant\">false<\/span>, <span class=\"cbb-constant\">false<\/span> );\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-variable\">$data<\/span>&#91;<span class=\"cbb-string\">'Version'<\/span>&#93;;\n<\/span><span class=\"cbb-line\">}<\/span><\/code><\/pre><\/figure>\n\n\n<p>Notatka wymienia dwie typowe przyczyny: <code>get_plugin_data()<\/code> bez <code>$translate = false<\/code> oraz klasy tworzone bezpo\u015brednio w pliku g\u0142\u00f3wnym, kt\u00f3rych konstruktor wywo\u0142uje <code>__()<\/code>. Do namierzenia \u017ar\u00f3d\u0142a proponuje callback na akcji <code>doing_it_wrong_run<\/code>, kt\u00f3ry dla <code>_load_textdomain_just_in_time<\/code> wypisuje backtrace, albo wtyczk\u0119 Query Monitor.<\/p>\n<p>WordPress 6.8 rozszerzy\u0142 \u0142adowanie just-in-time na wtyczki spoza katalogu i korzysta przy tym z nag\u0142\u00f3wk\u00f3w <code>Text Domain<\/code> i <code>Domain Path<\/code>. Notatka streszcza to w dw\u00f3ch przypadkach:<\/p>\n<ul>\n<li>Wtyczka hostowana na WordPress.org, wymagaj\u0105ca co najmniej WordPressa 4.6: wywo\u0142anie <code>load_plugin_textdomain()<\/code> nie jest potrzebne.<\/li>\n<li>Wtyczka z nag\u0142\u00f3wkami <code>Text Domain<\/code> i <code>Domain Path<\/code>, wymagaj\u0105ca co najmniej WordPressa 6.8: wywo\u0142anie r\u00f3wnie\u017c nie jest potrzebne.<\/li>\n<\/ul>\n<p>W pozosta\u0142ych przypadkach, na przyk\u0142ad przy wtyczce rozpowszechnianej poza katalogiem i wspieraj\u0105cej starsze wersje, wywo\u0142anie zostaje, ale nale\u017cy je przenie\u015b\u0107 do <code>init<\/code>. Plugin Check egzekwuje to dla katalogu: sniff <code>PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound<\/code> zg\u0142asza ostrze\u017cenie, gdy minimalna wersja z <code>Requires at least<\/code> (nag\u0142\u00f3wek lub readme) jest wy\u017csza ni\u017c 4.6. Komunikat dodaje, \u017ce WordPress sam \u0142aduje t\u0142umaczenia pod slugiem wtyczki.<\/p>\n<h2>JavaScript: @wordpress\/i18n, budowanie i wp_set_script_translations<\/h2>\n<p>Od WordPressa 5.0 uchwyt skryptu <code>wp-i18n<\/code> udost\u0119pnia w przegl\u0105darce te same funkcje: <code>__()<\/code>, <code>_x()<\/code>, <code>_n()<\/code>, <code>_nx()<\/code> i <code>sprintf()<\/code>. Przyk\u0142ad importuje je z pakietu npm <code>@wordpress\/i18n<\/code> i buduje plik za pomoc\u0105 <code>@wordpress\/scripts<\/code>:<\/p>\n\n\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"json\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">JSON<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-json\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\">{\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-attr\">\"name\"<\/span>: <span class=\"cbb-string\">\"lw-reading-time\"<\/span>,\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-attr\">\"version\"<\/span>: <span class=\"cbb-string\">\"1.0.0\"<\/span>,\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-attr\">\"private\"<\/span>: <span class=\"cbb-constant\">true<\/span>,\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-attr\">\"license\"<\/span>: <span class=\"cbb-string\">\"GPL-2.0-or-later\"<\/span>,\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-attr\">\"scripts\"<\/span>: {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-attr\">\"build\"<\/span>: <span class=\"cbb-string\">\"wp-scripts build\"<\/span>,\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-attr\">\"start\"<\/span>: <span class=\"cbb-string\">\"wp-scripts start\"<\/span>\n<\/span><span class=\"cbb-line\">\t},\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-attr\">\"devDependencies\"<\/span>: {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-attr\">\"@wordpress\/scripts\"<\/span>: <span class=\"cbb-string\">\"^36.0.0\"<\/span>\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">}<\/span><\/code><\/pre><\/figure>\n\n\n\n\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"javascript\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">JavaScript<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-javascript\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ src\/index.js<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">import<\/span> { _n, _x, sprintf } <span class=\"cbb-keyword\">from<\/span> <span class=\"cbb-string\">'@wordpress\/i18n'<\/span>;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">const<\/span> STORAGE_KEY = <span class=\"cbb-string\">'lwReadingTimeRead'<\/span>;\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">getReadPosts<\/span>() {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">try<\/span> {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">const<\/span> stored = JSON.<span class=\"cbb-function\">parse<\/span>( window.localStorage.<span class=\"cbb-function\">getItem<\/span>( STORAGE_KEY ) );\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-type\">Array<\/span>.<span class=\"cbb-function\">isArray<\/span>( stored ) ? stored : &#91;&#93;;\n<\/span><span class=\"cbb-line\">\t} <span class=\"cbb-keyword\">catch<\/span> ( error ) {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">return<\/span> &#91;&#93;;\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">function<\/span> <span class=\"cbb-function\">saveReadPosts<\/span>( ids ) {\n<\/span><span class=\"cbb-line\">\t<span class=\"cbb-keyword\">try<\/span> {\n<\/span><span class=\"cbb-line\">\t\twindow.localStorage.<span class=\"cbb-function\">setItem<\/span>( STORAGE_KEY, JSON.<span class=\"cbb-function\">stringify<\/span>( ids ) );\n<\/span><span class=\"cbb-line\">\t} <span class=\"cbb-keyword\">catch<\/span> ( error ) {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-comment\">\/\/ Storage may be unavailable (e.g. private windows); the button still updates.<\/span>\n<\/span><span class=\"cbb-line\">\t}\n<\/span><span class=\"cbb-line\">}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">document.<span class=\"cbb-function\">querySelectorAll<\/span>( <span class=\"cbb-string\">'.lw-reading-time__mark'<\/span> ).<span class=\"cbb-function\">forEach<\/span>( ( button ) <span class=\"cbb-operator\">=&gt;<\/span> {\n<\/span><span class=\"cbb-line\">\tbutton.<span class=\"cbb-function\">addEventListener<\/span>( <span class=\"cbb-string\">'click'<\/span>, () <span class=\"cbb-operator\">=&gt;<\/span> {\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">const<\/span> postId = <span class=\"cbb-function\">Number<\/span>( button.dataset.post );\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">const<\/span> readPosts = <span class=\"cbb-function\">getReadPosts<\/span>();\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t\t<span class=\"cbb-keyword\">if<\/span> ( ! readPosts.<span class=\"cbb-function\">includes<\/span>( postId ) ) {\n<\/span><span class=\"cbb-line\">\t\t\treadPosts.<span class=\"cbb-function\">push<\/span>( postId );\n<\/span><span class=\"cbb-line\">\t\t\t<span class=\"cbb-function\">saveReadPosts<\/span>( readPosts );\n<\/span><span class=\"cbb-line\">\t\t}\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">\t\tbutton.disabled = <span class=\"cbb-constant\">true<\/span>;\n<\/span><span class=\"cbb-line\">\t\tbutton.textContent = <span class=\"cbb-function\">_x<\/span>(\n<\/span><span class=\"cbb-line\">\t\t\t<span class=\"cbb-string\">'Read'<\/span>,\n<\/span><span class=\"cbb-line\">\t\t\t<span class=\"cbb-string\">'status of a post after it was marked as read'<\/span>,\n<\/span><span class=\"cbb-line\">\t\t\t<span class=\"cbb-string\">'lw-reading-time'<\/span>\n<\/span><span class=\"cbb-line\">\t\t);\n<\/span><span class=\"cbb-line\">\t\tbutton.title = <span class=\"cbb-function\">sprintf<\/span>(\n<\/span><span class=\"cbb-line\">\t\t\t<span class=\"cbb-comment\">\/* translators: %d: number of posts marked as read in this browser. *\/<\/span>\n<\/span><span class=\"cbb-line\">\t\t\t<span class=\"cbb-function\">_n<\/span>(\n<\/span><span class=\"cbb-line\">\t\t\t\t<span class=\"cbb-string\">'%d post marked as read in this browser'<\/span>,\n<\/span><span class=\"cbb-line\">\t\t\t\t<span class=\"cbb-string\">'%d posts marked as read in this browser'<\/span>,\n<\/span><span class=\"cbb-line\">\t\t\t\treadPosts.length,\n<\/span><span class=\"cbb-line\">\t\t\t\t<span class=\"cbb-string\">'lw-reading-time'<\/span>\n<\/span><span class=\"cbb-line\">\t\t\t),\n<\/span><span class=\"cbb-line\">\t\t\treadPosts.length\n<\/span><span class=\"cbb-line\">\t\t);\n<\/span><span class=\"cbb-line\">\t} );\n<\/span><span class=\"cbb-line\">} );<\/span><\/code><\/pre><\/figure>\n\n\n<p>Bez pliku <code>block.json<\/code> polecenie <code>wp-scripts build<\/code> przyjmuje <code>src\/index.js<\/code> jako punkt wej\u015bcia i zapisuje <code>build\/index.js<\/code>. Wtyczka webpacka Dependency Extraction zast\u0119puje import globalnym obiektem <code>wp.i18n<\/code> i tworzy <code>build\/index.asset.php<\/code> z zale\u017cno\u015bci\u0105 <code>wp-i18n<\/code> oraz hashem wersji; plik PHP przekazuje oba do <code>wp_enqueue_script()<\/code>. Konfiguracja webpacka zachowuje w zminifikowanym wyniku komentarze z <code>translators:<\/code>, a <code>make-pot<\/code> rozpoznaje formy wywo\u0142a\u0144 generowane przez webpack.<\/p>\n<p>Po\u0142\u0105czenie skryptu z t\u0142umaczeniem tworzy funkcja <code>wp_set_script_translations()<\/code>, dost\u0119pna od WordPressa 5.0, z opcjonalnym text domain od wersji 5.1. Dzia\u0142a tylko dla skryptu ju\u017c zarejestrowanego, rozpoznawanego po uchwycie \u2013 tym samym identyfikatorze, na kt\u00f3rym opiera si\u0119 <a href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/optymalizacja-wydajnosci-przez-functions-php-selektywne-wyrejestrowywanie\/\">artyku\u0142 o selektywnym wy\u0142\u0105czaniu skrypt\u00f3w wtyczek<\/a>. WordPress szuka wtedy pliku JSON w formacie Jed i umieszcza jego zawarto\u015b\u0107 w <code>wp.i18n<\/code>, zanim skrypt si\u0119 uruchomi. Nazwa pliku ma posta\u0107 <code>{domain}-{locale}-{md5}.json<\/code>; hash liczony jest ze \u015bcie\u017cki skryptu wzgl\u0119dem katalogu wtyczki i dla <code>build\/index.js<\/code> wynosi <code>dfbff627e6c248bcb3b61d7d06da9ca9<\/code>. Rdze\u0144 przed haszowaniem zamienia <code>.min.js<\/code> na <code>.js<\/code>, a <code>make-pot<\/code> domy\u015blnie pomija pliki <code>*.min.js<\/code>. Opcjonalny trzeci parametr wskazuje katalog, kt\u00f3ry WordPress sprawdza jako pierwszy, zar\u00f3wno pod k\u0105tem <code>{domain}-{locale}-{handle}.json<\/code>, jak i nazwy z hashem, zanim si\u0119gnie do <code>wp-content\/languages\/plugins<\/code>.<\/p>\n<p>Dla modu\u0142\u00f3w skrypt\u00f3w rejestrowanych przez <code>wp_register_script_module()<\/code> WordPress 7.0 doda\u0142 odpowiednik <code>wp_set_script_module_translations()<\/code>. Przyk\u0142ad korzysta z klasycznego skryptu, wi\u0119c funkcja pojawia si\u0119 tu tylko jako wzmianka.<\/p>\n<h2>Od kodu \u017ar\u00f3d\u0142owego do paczki j\u0119zykowej<\/h2>\n<p>Dla wtyczek z katalogu serwis WordPress.org po kolejnym commicie SVN analizuje wszystkie pliki PHP i JavaScript, a teksty importuje do translate.wordpress.org. Ka\u017cda wtyczka ma tam cztery podprojekty: Development, Development Readme, Stable (latest release) i Stable Readme (latest release). Istniej\u0105ce pliki <code>.mo<\/code> z wtyczki zostaj\u0105 przej\u0119te jednorazowo; dalsza praca nad t\u0142umaczeniem odbywa si\u0119 ju\u017c na platformie.<\/p>\n<p>T\u0142umaczenia mo\u017ce zg\u0142asza\u0107 ka\u017cda osoba z kontem WordPress.org. Propozycje maj\u0105 najpierw status \u201eWaiting\u201d i licz\u0105 si\u0119 dopiero wtedy, gdy General Translation Editor danego j\u0119zyka albo Project Translation Editor wyznaczony dla wtyczki nada im status \u201eCurrent\u201d. Niezweryfikowane t\u0142umaczenia maszynowe nie s\u0105 przyjmowane. Pierwsza paczka j\u0119zykowa dla danego j\u0119zyka powstaje, gdy zatwierdzonych jest co najmniej 90 procent tekst\u00f3w podprojektu Stable; teksty z readme si\u0119 do tego progu nie wliczaj\u0105. P\u00f3\u017aniej ka\u017cda zmiana tekst\u00f3w lub t\u0142umacze\u0144 generuje now\u0105 paczk\u0119, nawet je\u015bli pokrycie zn\u00f3w spadnie poni\u017cej 90 procent.<\/p>\n<p>Paczka j\u0119zykowa zawiera pliki <code>.po<\/code> i <code>.mo<\/code>, od WordPressa 6.5 plik <code>.l10n.php<\/code> oraz po jednym pliku JSON na ka\u017cdy skrypt z tekstami do t\u0142umaczenia. WordPress instaluje j\u0105 w ramach zwyk\u0142ych aktualizacji t\u0142umacze\u0144 w katalogu <code>wp-content\/languages\/plugins\/<\/code>. Tam \u0142adowanie just-in-time i <code>wp_set_script_translations()<\/code> odnajduj\u0105 pliki bez dodatkowego kodu we wtyczce.<\/p>\n<figure class=\"lw-diagram\">\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/wp-plugin-i18n-pl.png?v=20260930\" width=\"1120\" height=\"580\" alt=\"Jeden tekst od kodu \u017ar\u00f3d\u0142owego do wy\u015bwietlenia: __() i _n() w PHP oraz @wordpress\/i18n w skrypcie s\u0105 importowane po commicie SVN, proponowane i zatwierdzane w GlotPress, przy 90% zatwierdzenia trafiaj\u0105 do paczki j\u0119zykowej i \u0142aduj\u0105 si\u0119 just in time dla PHP i JavaScript; lokalnie pliki buduje WP-CLI bez GlotPress\">\n<figcaption>Jak translate.wordpress.org zamienia wywo\u0142anie gettext w paczk\u0119 j\u0119zykow\u0105 \u0142adowan\u0105 przez WordPress dla PHP i JavaScript<\/figcaption>\n<\/figure>\n<h2>W\u0142asne pliki t\u0142umacze\u0144 z WP-CLI<\/h2>\n<p>Lokalne pliki s\u0105 potrzebne dla wtyczek spoza katalogu, na czas przed pojawieniem si\u0119 pierwszej paczki j\u0119zykowej i w projektach dla klient\u00f3w z w\u0142asnym s\u0142ownictwem. Polecenia <code>wp i18n<\/code> obejmuj\u0105 ca\u0142y \u0142a\u0144cuch:<\/p>\n\n\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"bash\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Shell<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-bash\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\"># Run inside wp-content\/plugins\/lw-reading-time\/<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># 1. Build the script: creates build\/index.js and build\/index.asset.php (dependency \"wp-i18n\").<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">npm<\/span> install\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">npm<\/span> run build\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># 2. Extract all strings from PHP and from the built JavaScript into a template.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">wp<\/span> i18n make-pot . languages\/lw-reading-time.pot <span class=\"cbb-attr\">--exclude<\/span>=src\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># 3. Copy the template to languages\/lw-reading-time-pl_PL.po (and -de_DE.po),<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\">#    translate it in Poedit or a text editor, then compile the runtime files.<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">wp<\/span> i18n make-mo languages\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">wp<\/span> i18n make-php languages\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">wp<\/span> i18n make-json languages <span class=\"cbb-attr\">--no-purge<\/span>\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># Result for Polish:<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># languages\/lw-reading-time-pl_PL.po<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># languages\/lw-reading-time-pl_PL.mo<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># languages\/lw-reading-time-pl_PL.l10n.php<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-comment\"># languages\/lw-reading-time-pl_PL-dfbff627e6c248bcb3b61d7d06da9ca9.json   (md5 of \"build\/index.js\")<\/span><\/span><\/code><\/pre><\/figure>\n\n\n<p><code>make-pot<\/code> przeszukuje pliki PHP, Blade i JavaScript oraz nag\u0142\u00f3wek wtyczki, zawsze pomijaj\u0105c <code>node_modules<\/code>, <code>vendor<\/code>, katalogi system\u00f3w kontroli wersji i <code>*.min.js<\/code>. W przyk\u0142adzie <code>--exclude=src<\/code> sprawia, \u017ce jako \u017ar\u00f3d\u0142o tekst\u00f3w JavaScript wyst\u0119puje wy\u0142\u0105cznie zbudowany plik. <code>make-mo<\/code> kompiluje pliki binarne, polecenie <code>make-php<\/code> tworzy pliki <code>.l10n.php<\/code> i jest dost\u0119pne od WP-CLI 2.10.0 (i18n-command 2.6.0). <code>make-json<\/code> zapisuje po jednym pliku JSON w formacie Jed na ka\u017cdy plik \u017ar\u00f3d\u0142owy JavaScript i domy\u015blnie usuwa potem teksty JavaScript z pliku PO; z opcj\u0105 <code>--no-purge<\/code> plik PO pozostaje nietkni\u0119ty. Polski plik PO zawiera wtedy wszystkie trzy formy liczby mnogiej:<\/p>\n\n\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"plain\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Text<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-plain\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"># languages\/lw-reading-time-pl_PL.po (excerpt)\n<\/span><span class=\"cbb-line\">msgid \"\"\n<\/span><span class=\"cbb-line\">msgstr \"\"\n<\/span><span class=\"cbb-line\">\"Language: pl_PL\\n\"\n<\/span><span class=\"cbb-line\">\"Content-Type: text\/plain; charset=UTF-8\\n\"\n<\/span><span class=\"cbb-line\">\"Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n % 10 &gt;= 2 &amp;&amp; n % 10 &lt;= 4 &amp;&amp; (n % 100 &lt; 12 || n % 100 &gt; 14)) ? 1 : 2);\\n\"\n<\/span><span class=\"cbb-line\">\"X-Domain: lw-reading-time\\n\"\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">#. translators: %s: estimated reading time in minutes.\n<\/span><span class=\"cbb-line\">#: lw-reading-time.php:50\n<\/span><span class=\"cbb-line\">msgid \"Reading time: %s minute\"\n<\/span><span class=\"cbb-line\">msgid_plural \"Reading time: %s minutes\"\n<\/span><span class=\"cbb-line\">msgstr&#91;0&#93; \"Czas czytania: %s minuta\"\n<\/span><span class=\"cbb-line\">msgstr&#91;1&#93; \"Czas czytania: %s minuty\"\n<\/span><span class=\"cbb-line\">msgstr&#91;2&#93; \"Czas czytania: %s minut\"\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">#: lw-reading-time.php:57\n<\/span><span class=\"cbb-line\">msgid \"Mark as read\"\n<\/span><span class=\"cbb-line\">msgstr \"Oznacz jako przeczytany\"\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">#: build\/index.js:1\n<\/span><span class=\"cbb-line\">msgctxt \"status of a post after it was marked as read\"\n<\/span><span class=\"cbb-line\">msgid \"Read\"\n<\/span><span class=\"cbb-line\">msgstr \"Przeczytany\"\n<\/span><span class=\"cbb-line\">\n<\/span><span class=\"cbb-line\">#. translators: %d: number of posts marked as read in this browser.\n<\/span><span class=\"cbb-line\">#: build\/index.js:2\n<\/span><span class=\"cbb-line\">msgid \"%d post marked as read in this browser\"\n<\/span><span class=\"cbb-line\">msgid_plural \"%d posts marked as read in this browser\"\n<\/span><span class=\"cbb-line\">msgstr&#91;0&#93; \"%d wpis oznaczony jako przeczytany w tej przegl\u0105darce\"\n<\/span><span class=\"cbb-line\">msgstr&#91;1&#93; \"%d wpisy oznaczone jako przeczytane w tej przegl\u0105darce\"\n<\/span><span class=\"cbb-line\">msgstr&#91;2&#93; \"%d wpis\u00f3w oznaczonych jako przeczytane w tej przegl\u0105darce\"<\/span><\/code><\/pre><\/figure>\n\n\n<p>Od wersji 4.6 paczki j\u0119zykowe w <code>wp-content\/languages<\/code> maj\u0105 pierwsze\u0144stwo przed plikami we wtyczce. Je\u015bli wtyczka mimo to ma \u0142adowa\u0107 w\u0142asne t\u0142umaczenia, podr\u0119cznik wskazuje filtr <code>load_textdomain_mofile<\/code>; od wersji 6.5 rdze\u0144 oferuje dodatkowo <code>load_translation_file<\/code>, kt\u00f3ry otrzymuje \u015bcie\u017ck\u0119 zar\u00f3wno do pliku <code>.mo<\/code>, jak i <code>.l10n.php<\/code>. Dla skrypt\u00f3w trzeci parametr <code>wp_set_script_translations()<\/code> okre\u015bla katalog sprawdzany jako pierwszy.<\/p>\n<h2>Ograniczenia i otwarte kwestie<\/h2>\n<ul>\n<li>Przyk\u0142adow\u0105 wtyczk\u0119 uruchomiono w WordPressie 7.1.2 z WP-CLI 2.12.0 i <code>@wordpress\/scripts<\/code> 36.0.0; pakiet wymaga Node 22.22.2 lub nowszego, pod Node 20 npm zg\u0142asza\u0142 jedynie ostrze\u017cenie. Numery wierszy w wycinku pliku PO pochodz\u0105 z tej kompilacji i przesuwaj\u0105 si\u0119 przy ka\u017cdej zmianie kodu.<\/li>\n<li>Wykorzystane \u017ar\u00f3d\u0142a nie dokumentuj\u0105, czy importer na WordPress.org pomija katalogi takie jak <code>src\/<\/code> albo pliki zminifikowane tak samo jak <code>make-pot<\/code>. Dla paczki j\u0119zykowej liczy si\u0119 to, \u017ce zbudowany plik trafia do SVN.<\/li>\n<li>Bez trzeciego parametru <code>wp_set_script_translations()<\/code> w WordPressie 7.1.2 znajduje pliki JSON tak\u017ce w katalogu z nag\u0142\u00f3wka <code>Domain Path<\/code>, bo rdze\u0144 korzysta z katalogu zarejestrowanego dla domeny. Gdy w <code>wp-content\/languages\/plugins<\/code> le\u017cy plik t\u0142umacze\u0144 dla tego samego j\u0119zyka, pliki JSON wtyczki zostaj\u0105 pomini\u0119te.<\/li>\n<li><code>_n()<\/code> oczekuje liczby ca\u0142kowitej; warto\u015bci u\u0142amkowe, jak 1,5 minuty, podlegaj\u0105 w polszczy\u017anie innym regu\u0142om gramatycznym. Przyk\u0142ad zaokr\u0105gla w g\u00f3r\u0119 do pe\u0142nych minut.<\/li>\n<\/ul>\n\n<div class=\"lw-faq\">\n<h2>Pytania i odpowiedzi<\/h2>\n\n<h3>Czy wtyczka z katalogu musi do\u0142\u0105cza\u0107 w\u0142asne pliki .mo?<\/h3>\n<p>Nie. Po imporcie do translate.wordpress.org powstaj\u0105 paczki j\u0119zykowe, kt\u00f3re WordPress sam pobiera do <code>wp-content\/languages\/plugins\/<\/code>. Istniej\u0105ce pliki <code>.mo<\/code> zostaj\u0105 przej\u0119te jednorazowo przy pierwszym imporcie; wed\u0142ug podr\u0119cznika Meta da si\u0119 je potem usun\u0105\u0107 z paczki i z SVN.<\/p>\n\n<h3>Czy komunikat o zbyt wczesnym \u0142adowaniu pojawia si\u0119 tylko na stronie z plikiem t\u0142umacze\u0144?<\/h3>\n<p>Nie, w WordPressie 7.1.2 nie. Kontrola w <code>_load_textdomain_just_in_time()<\/code> dzia\u0142a, gdy rdze\u0144 zna katalog j\u0119zykowy dla domeny, a od wersji 6.8 rdze\u0144 rejestruje dla ka\u017cdej aktywnej wtyczki jej katalog lub katalog z <code>Domain Path<\/code>. Test na stronie z <code>en_US<\/code> bez \u017cadnego pliku t\u0142umacze\u0144 r\u00f3wnie\u017c pokazuje wi\u0119c ten komunikat. Paczki j\u0119zykowe pozostaj\u0105 potrzebne do sprawdzenia samego przet\u0142umaczonego wyniku.<\/p>\n\n<h3>Teksty PHP s\u0105 przet\u0142umaczone, a teksty skryptu zostaj\u0105 po angielsku. Jaka jest zwykle przyczyna?<\/h3>\n<ul>\n<li><code>wp_set_script_translations()<\/code> dzia\u0142a przed rejestracj\u0105 skryptu albo z innym uchwytem.<\/li>\n<li>Hash w nazwie pliku JSON nie pasuje do wzgl\u0119dnej \u015bcie\u017cki dostarczanego pliku, na przyk\u0142ad dlatego, \u017ce plik POT powsta\u0142 z <code>src\/<\/code> zamiast z <code>build\/<\/code>.<\/li>\n<li>W SVN brakuje zbudowanego pliku, wi\u0119c WordPress.org nie znajduje tekst\u00f3w JavaScript.<\/li>\n<\/ul>\n<\/div>\n\n<div class=\"lw-quellen\">\n<h2>\u0179r\u00f3d\u0142a<\/h2>\n<ul>\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/internationalization\/how-to-internationalize-your-plugin\/\" target=\"_blank\" rel=\"noopener noreferrer\">Plugin Handbook: How to Internationalize Your Plugin<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/plugins\/internationalization\/localization\/\" target=\"_blank\" rel=\"noopener noreferrer\">Plugin Handbook: Localization<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/block-editor\/how-to-guides\/internationalization\/\" target=\"_blank\" rel=\"noopener noreferrer\">Block Editor Handbook: Internationalization<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/__\/\" target=\"_blank\" rel=\"noopener noreferrer\">Code Reference: __()<\/a>, <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/_e\/\" target=\"_blank\" rel=\"noopener noreferrer\">_e()<\/a>, <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/_x\/\" target=\"_blank\" rel=\"noopener noreferrer\">_x()<\/a>, <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/_n\/\" target=\"_blank\" rel=\"noopener noreferrer\">_n()<\/a>, <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/esc_html__\/\" target=\"_blank\" rel=\"noopener noreferrer\">esc_html__()<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/load_plugin_textdomain\/\" target=\"_blank\" rel=\"noopener noreferrer\">Code Reference: load_plugin_textdomain()<\/a> i <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_set_script_translations\/\" target=\"_blank\" rel=\"noopener noreferrer\">wp_set_script_translations()<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/core\/2016\/07\/06\/i18n-improvements-in-4-6\/\" target=\"_blank\" rel=\"noopener noreferrer\">Make WordPress Core: I18N Improvements in 4.6<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/core\/2018\/11\/09\/new-javascript-i18n-support-in-wordpress\/\" target=\"_blank\" rel=\"noopener noreferrer\">Make WordPress Core: JavaScript i18n support in WordPress 5.0<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/core\/2024\/02\/27\/i18n-improvements-6-5-performant-translations\/\" target=\"_blank\" rel=\"noopener noreferrer\">Make WordPress Core: I18N Improvements in 6.5 (Performant Translations)<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/core\/2024\/10\/21\/i18n-improvements-6-7\/\" target=\"_blank\" rel=\"noopener noreferrer\">Make WordPress Core: Internationalization improvements in 6.7<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/core\/2025\/03\/12\/i18n-improvements-6-8\/\" target=\"_blank\" rel=\"noopener noreferrer\">Make WordPress Core: Internationalization improvements in 6.8<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/meta\/handbook\/tutorials-guides\/translations\/\" target=\"_blank\" rel=\"noopener noreferrer\">Meta Handbook: Translations<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/make.wordpress.org\/polyglots\/handbook\/plugin-theme-authors-guide\/\" target=\"_blank\" rel=\"noopener noreferrer\">Polyglots Handbook: Plugin\/Theme Authors Guide<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/i18n\/make-pot\/\" target=\"_blank\" rel=\"noopener noreferrer\">WP-CLI: wp i18n make-pot<\/a>, <a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/i18n\/make-json\/\" target=\"_blank\" rel=\"noopener noreferrer\">make-json<\/a>, <a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/i18n\/make-php\/\" target=\"_blank\" rel=\"noopener noreferrer\">make-php<\/a>, <a href=\"https:\/\/developer.wordpress.org\/cli\/commands\/i18n\/make-mo\/\" target=\"_blank\" rel=\"noopener noreferrer\">make-mo<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1\/src\/wp-includes\/l10n.php\" target=\"_blank\" rel=\"noopener noreferrer\">wordpress-develop, ga\u0142\u0105\u017a 7.1: wp-includes\/l10n.php<\/a> i <a href=\"https:\/\/github.com\/WordPress\/wordpress-develop\/blob\/7.1\/src\/wp-includes\/script-modules.php\" target=\"_blank\" rel=\"noopener noreferrer\">script-modules.php<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/github.com\/GlotPress\/GlotPress\/blob\/develop\/locales\/locales.php\" target=\"_blank\" rel=\"noopener noreferrer\">GlotPress: locales.php (regu\u0142y liczby mnogiej)<\/a> i <a href=\"https:\/\/translate.wordpress.org\/projects\/wp-plugins\/akismet\/\" target=\"_blank\" rel=\"noopener noreferrer\">translate.wordpress.org: projekt Akismet, eksport polski<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/plugin-check\/releases\/tag\/2.1.0\" target=\"_blank\" rel=\"noopener noreferrer\">Plugin Check 2.1.0<\/a>: DiscouragedFunctionsSniff i Plugin_Header_Fields_Check (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/gutenberg\/tree\/trunk\/packages\/scripts\" target=\"_blank\" rel=\"noopener noreferrer\">@wordpress\/scripts<\/a> (README i konfiguracja webpacka) oraz <a href=\"https:\/\/github.com\/WordPress\/gutenberg\/tree\/trunk\/packages\/i18n\" target=\"_blank\" rel=\"noopener noreferrer\">@wordpress\/i18n<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/github.com\/WordPress\/WordPress-Coding-Standards\/blob\/develop\/WordPress\/Sniffs\/Security\/EscapeOutputSniff.php\" target=\"_blank\" rel=\"noopener noreferrer\">WordPress Coding Standards: EscapeOutputSniff<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<li><a href=\"https:\/\/wordpress.org\/download\/releases\/\" target=\"_blank\" rel=\"noopener noreferrer\">WordPress Releases<\/a> (dost\u0119p: 29.09.2026)<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Ma\u0142a wtyczka w PHP i JavaScript pokazuje, jak teksty staj\u0105 si\u0119 przet\u0142umaczalne, jak dzia\u0142aj\u0105 polskie formy liczby mnogiej i jakie pliki dostarcza translate.wordpress.org.<\/p>\n","protected":false},"author":1,"featured_media":20909,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[92646],"tags":[92271,92280,92238,92286],"class_list":["post-20865","post","type-post","status-publish","format-standard","hentry","category-tutorials-pl-wordpress-plugins-tricks-pl","tag-javascript-pl","tag-php-pl","tag-tutorial-pl","tag-wordpress-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Text domain, __(), _n() i @wordpress\/i18n: jak t\u0142umaczy si\u0119 wtyczki WordPress, kiedy load_plugin_textdomain jest zb\u0119dne i co buduje WP-CLI.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Text domain, __(), _n() i @wordpress\/i18n: jak t\u0142umaczy si\u0119 wtyczki WordPress, kiedy load_plugin_textdomain jest zb\u0119dne i co buduje WP-CLI.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-18T15:58:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20865-tlumaczenie-wtyczek-wordpress.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"19 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript\",\"datePublished\":\"2026-10-18T15:58:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/\"},\"wordCount\":2548,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20865-tlumaczenie-wtyczek-wordpress.png\",\"keywords\":[\"JavaScript\",\"PHP\",\"Tutorial\",\"WordPress\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/\",\"name\":\"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20865-tlumaczenie-wtyczek-wordpress.png\",\"datePublished\":\"2026-10-18T15:58:00+00:00\",\"description\":\"Text domain, __(), _n() i @wordpress\\\/i18n: jak t\u0142umaczy si\u0119 wtyczki WordPress, kiedy load_plugin_textdomain jest zb\u0119dne i co buduje WP-CLI.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20865-tlumaczenie-wtyczek-wordpress.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/fi-20865-tlumaczenie-wtyczek-wordpress.png\",\"width\":1200,\"height\":630,\"caption\":\"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/wordpress-plugins-tricks-pl\\\/tutorials-pl-wordpress-plugins-tricks-pl\\\/tlumaczenie-wtyczek-wordpress\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript | Lukas Wojcik","description":"Text domain, __(), _n() i @wordpress\/i18n: jak t\u0142umaczy si\u0119 wtyczki WordPress, kiedy load_plugin_textdomain jest zb\u0119dne i co buduje WP-CLI.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/","og_locale":"en_US","og_type":"article","og_title":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript | Lukas Wojcik","og_description":"Text domain, __(), _n() i @wordpress\/i18n: jak t\u0142umaczy si\u0119 wtyczki WordPress, kiedy load_plugin_textdomain jest zb\u0119dne i co buduje WP-CLI.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-10-18T15:58:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20865-tlumaczenie-wtyczek-wordpress.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"19 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript","datePublished":"2026-10-18T15:58:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/"},"wordCount":2548,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20865-tlumaczenie-wtyczek-wordpress.png","keywords":["JavaScript","PHP","Tutorial","WordPress"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/","name":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20865-tlumaczenie-wtyczek-wordpress.png","datePublished":"2026-10-18T15:58:00+00:00","description":"Text domain, __(), _n() i @wordpress\/i18n: jak t\u0142umaczy si\u0119 wtyczki WordPress, kiedy load_plugin_textdomain jest zb\u0119dne i co buduje WP-CLI.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20865-tlumaczenie-wtyczek-wordpress.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/fi-20865-tlumaczenie-wtyczek-wordpress.png","width":1200,"height":630,"caption":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/wordpress-plugins-tricks-pl\/tutorials-pl-wordpress-plugins-tricks-pl\/tlumaczenie-wtyczek-wordpress\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"T\u0142umaczenie wtyczek: text domain, paczki j\u0119zykowe i JavaScript"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/20865","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=20865"}],"version-history":[{"count":2,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/20865\/revisions"}],"predecessor-version":[{"id":22725,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/20865\/revisions\/22725"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/20909"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=20865"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=20865"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=20865"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}