PTC

בינאום WordPress: איך לתרגם תבניות ותוספים

הכינו את התבנית או התוסף של WordPress לתרגום. מדריך זה מכסה טקסט דומיינים (text domains), פונקציות gettext, יצירת קובצי POT ומנגנון הטעינה שמציג את התרגומים למשתמשים. לאחר מכן, PTC (Private Translation Cloud) מתרגם את קובצי המשאבים ומבצע סקירה חזותית של התבנית או התוסף המרונדרים בכל שפה.

מדריך זה מיועד למפתחים הכותבים את הקוד. אם כבר יש לכם קובץ POT או PO ואתם רק צריכים לתרגם אותו, עברו אל דף קובצי ה־PO לתהליך העבודה ב־3 שלבים.

בסיום המדריך הזה, התבנית או התוסף שלכם יהיו:

  • מבונאמים (Internationalized) נכון לפי תקני הקידוד של WordPress.
  • ניתנים לתרגום על ידי PTC ל־40+ שפות.
  • ניתנים להפצה באמצעות חבילות השפה של WordPress.org.
  • ניתנים לאימות בכל גרסה באמצעות סקירת התרגום החזותית של PTC.

מהו בינאום WordPress?

בינאום (i18n) הוא תהליך הכנת הקוד כך שניתן יהיה לתרגם אותו. לוקליזציה (l10n) היא השלב הבא, שבו נוצרות מחרוזות התרגום בפועל עבור שפות ספציפיות.

עבור תבניות ותוספי WordPress, בינאום פירושו שלושה דברים:

  • עטיפת כל מחרוזת הפונה למשתמש בפונקציות gettext כדי ש־WordPress תוכל להחליף אותן בזמן ריצה.
  • הגדרת טקסט דומיין (text domain) המקשר את התרגומים לפרויקט שלכם.
  • יצירת קובץ POT שממנו עובדים המתרגמים (או PTC).

ברגע שהעבודה הזו מסתיימת, יש לכם כל מה שצריך כדי להפיק קובצי PO,‏ MO,‏ JSON ו־.l10n.php מתורגמים לכל שפה.

PTC מתרגם קובצי POT ל־MO,‏ JSON ו־.l10n.php עבור WordPress

חמש סיומות קבצים מופיעות בכל תהליך עבודה של תרגום WordPress. ‏PTC מתרגם מ־.pot (המקור שלכם) ל־.po,‏ .mo,‏ .json ו־.l10n.php עבור כל שפת יעד. לכל פורמט תפקיד ספציפי:

  • POT (Portable Object Template). קובץ המקור שנוצר מהקוד שלכם. הוא מכיל רשימה של כל מחרוזת שניתנת לתרגום ללא תרגומים מצורפים. את הקובץ הזה אתם מוסרים ל־PTC.
  • PO (Portable Object). עותק של ה־POT עם תרגומים שנוספו עבור שפה ספציפית. זהו קובץ טקסט פשוט וקריא לבני אדם. PTC מחזיר קובץ PO אחד לכל שפת יעד.
  • MO (Machine Object). הגרסה הבינארית המקומפלת של קובץ PO. ‏WordPress קוראת קובצי MO בזמן ריצה כי הם נטענים מהר יותר מקובצי טקסט מסוג PO.
  • JSON. המקבילה של MO עבור JavaScript. ‏WordPress אינה יכולה לקרוא MO מתוך JavaScript, ולכן צינור הבנייה מפיק קובצי JSON עבור מחרוזות בצד הדפדפן.
  • .l10n.php. חלופה חדשה יותר ל־MO, שהוצגה ב־WordPress 6.5. הוא נטען מהר יותר וצורך פחות זיכרון. WordPress בוחרת בו אוטומטית כשיש קובץ כזה לצד קובץ ה־MO.

הפעילו את .l10n.php עבור פרויקטים חדשים. הוא עדיף משמעותית על MO בגרסאות הנתמכות של WordPress.

למה תרגום קהילתי אינו מספיק

‏WordPress.org מציעה תרגום קהילתי באמצעות GlotPress. בפועל, הוא מכסה רק חלק קטן ממה שרוב התוספים והתבניות צריכים. ניתוח של יותר מ־60,000 תוספים ותבניות WordPress מצא שתרגום קהילתי מכסה פחות מ־5% מצרכי התרגום ב־40 שפות.

שתי בעיות מבניות מסבירות את הפער הזה:

  • מתנדבים הם מצרך נדיר ברוב המקומות. קומץ תוספים עם בסיס משתמשים עצום מושכים מתרגמים. רובם לא.
  • הופעת תרגומים יכולה לקחת חודשים או שנים, אם הם מופיעים בכלל. אם אתם רוצים שהמשתמשים יראו את התוסף או התבנית שלכם בשפתם מהיום הראשון, אינכם יכולים להסתמך על הקהילה.

מדריך זה מניח שאתם רוצים כיסוי תרגום מלא ועקבי בלוח זמנים שאתם שולטים בו. זה בדיוק מה ש־PTC מספק.

הכנת תבנית או תוסף ה־WordPress שלכם לתרגום

טקסט דומיין לא תואם או מחרוזת לא עטופה פירושם שהטקסט הזה לעולם לא יופיע בתוצאה המתורגמת. הפרטים הקטנים קובעים.

שלב 1: הגדרת טקסט דומיין (text domain) ונתיב הדומיין

כל תבנית או תוסף זקוקים לטקסט דומיין. טקסט דומיין הוא מזהה ייחודי שאומר ל־WordPress אילו קובצי תרגום שייכים לפרויקט שלכם. הוא חייב להתאים בדיוק לסלאג (slug) של התוסף או התבנית.

הצהירו עליו בכותרת הקובץ הראשי של התוסף:

<?php
/**
 * Plugin Name: My Plugin
 * Description: An example plugin.
 * Version: 1.0.0
 * Text Domain: my-plugin
 * Domain Path: /languages
 */

או ב־style.css של התבנית שלכם:

/*
Theme Name: My Theme
Text Domain: my-theme
Domain Path: /languages
*/

נתיב הדומיין (Domain Path) אומר ל־WordPress היכן נמצאים קובצי התרגום ביחס לשורש התוסף או התבנית. /languages הוא הסטנדרט.

שלב 2: עטיפת מחרוזות ה־PHP בפונקציות gettext

כל מחרוזת שתרצו שתהיה ניתנת לתרגום צריכה להיות עטופה באחת מפונקציות ה־gettext של WordPress. בזמן ריצה, פונקציות אלו מחפשות את התרגום הנכון. אם לא נמצא כזה, הן חוזרות למחרוזת המקורית.

מחרוזות בסיסיות. השתמשו ב־__() כשאתם צריכים להחזיר מחרוזת. עבור פלט HTML, השתמשו בגרסאות המנוטרלות (escaped). תקני הקידוד של WordPress ממליצים על echo esc_html__() על פני _e(). הצורה ה־escaped הופכת את הנטרול (escaping) של הפלט למפורש ומונעת XSS בנקודת הפלט:

// Return a translated string
$label = __( 'Settings', 'my-plugin' );

// Echo a translated string, escaped for HTML
echo esc_html__( 'Settings saved.', 'my-plugin' );

מחרוזות עם משתנים. אל תשרשרו משתנים לתוך מחרוזות. מתרגמים רואים רק שברים ולא יכולים לשנות את סדר המילים עבור שפות עם תחביר שונה. השתמשו ב־printf() או sprintf() עם מציין מיקום. הוסיפו הערת מתרגם כדי שהמתרגמים ידעו מה %s מייצג:

printf(
    /* translators: %s: the user's display name */
    esc_html__( 'Welcome back, %s.', 'my-plugin' ),
    esc_html( $display_name )
);

צורות רבים. צורות רבים באנגלית הן פשוטות (one comment, two comments). שפות אחרות לא. השתמשו ב־_n() כדי לטפל בכל כלל רבים ש־WordPress מכירה:

printf(
    esc_html( _n( '%s comment', '%s comments', $count, 'my-plugin' ) ),
    number_format_i18n( $count )
);

מחרוזות הזקוקות להקשר. למילים מסוימות יש משמעויות שונות בהתאם למקום שבו הן מופיעות. השתמשו ב־_x() כדי לתת למתרגמים את ההקשר שהם צריכים:

// "Export" as a noun (the file) vs. a verb (the action)
echo esc_html_x( 'Export', 'button label', 'my-plugin' );

שלב 3: בינאום מחרוזות ה־JavaScript שלכם

‏WordPress מספקת את חבילת wp-i18n כדי שתוכלו להשתמש באותן פונקציות gettext ב־JavaScript כפי שאתם משתמשים ב־PHP. בעת רישום הסקריפט שלכם, הצהירו על wp-i18n כתלות:

wp_register_script(
    'my-plugin-script',
    plugins_url( 'js/app.js', __FILE__ ),
    array( 'wp-i18n' ),
    '1.0.0',
    true
);

לאחר מכן בקובץ ה־JavaScript שלכם:

const { __, _n, sprintf } = wp.i18n;

const message = __( 'Settings saved.', 'my-plugin' );

אם אתם משתמשים ב־bundler כמו Webpack, התקינו את @wordpress/babel-plugin-makepot. הוא מחלץ מחרוזות ניתנות לתרגום מהבאנדל שלכם כחלק מתהליך הבנייה.

שלב 4: יצירת קובץ ה־POT שלכם

ברגע שהמחרוזות שלכם עטופות, צרו קובץ POT. ה־POT הוא קובץ המקור שבו PTC (או כל מתרגם) עובד. הוא מכיל את כל המחרוזות הניתנות לתרגום, אך ללא התרגומים עצמם.

wp i18n make-pot . languages/my-plugin.pot

‏WP-CLI סורק את קובצי ה־PHP, ה־JavaScript וה־block.json שלכם עבור קריאות gettext. הוא מקמפל אותן לקובץ POT יחיד. אם הצוות שלכם משתמש ב־Composer, הוסיפו את הפקודה הזו כסקריפט Composer. זה שומר על שימוש עקבי ב־WP-CLI בתוך הצוות ללא צורך בהתקנה גלובלית.

סט הפקודות המלא של wp i18n מכסה את שאר הצינור:

פקודה מה היא עושה
wp i18n make-pot יצירת קובץ POT מהמקור.
wp i18n update-po סנכרון קובצי PO קיימים כאשר קובץ ה־POT משתנה.
wp i18n make-mo קימפול קובצי PO לקובצי MO בינאריים.
wp i18n make-json חילוץ מחרוזות JS מתוך PO לקובצי JSON.
wp i18n make-php יצירת קובצי .l10n.php (עבור WordPress 6.5+).

אינכם זקוקים ל־Poedit. כל מה שבתהליך העבודה הזה רץ דרך WP-CLI ו־PTC. ‏WP-CLI מטפל ביצירת POT ובקימפול MO/JSON. ‏PTC מטפל בתרגום ומחזיר כל פורמט קובץ ש־WordPress צריכה. Poedit הוא עורך שולחני שימושי לתרגום ידני, אך הוא אינו חלק מתהליך עבודה זה.

תרגום קובצי POT עם PTC

‏PTC נבנה תוך מחשבה על מפתחי WordPress. התחילו עם קובץ POT וקבלו בחזרה קובצי תרגום מוכנים להפצה. תקופת הניסיון של 30 יום בחינם מכסה עד 20,000 מילים בשני צמדי שפות.

הגדרת פרויקט התרגום הראשון שלכם

העלו את קובץ ה־POT שלכם. בחרו אילו פורמטים של פלט אתם צריכים. PTC מחזיר כל שילוב של:

  • קובצי .po עבור כל שפת יעד.
  • קובצי .mo, מקומפלים ומוכנים למשלוח.
  • קובצי .json עבור מחרוזות ה־JavaScript שלכם.
  • קובצי .l10n.php לטעינה מהירה יותר ב־WordPress 6.5+.

אשף ההגדרה יבקש מכם לתאר את התבנית או התוסף שלכם. PTC משתמש בתיאור כדי ליצור תרגומים בטון ובהקשר הנכונים. הוסיפו מונחים ספציפיים למותג למילון המונחים בשלב זה. מילון המונחים שומר על שמות, תוויות תכונות וכל טרמינולוגיה אחרת עקביים בכל השפות.

‏PTC מנתח את מבנה ה־gettext בעת ההעלאה. הוא מזהה מצייני מיקום (%s,‏ %1$s,‏ %d), צורות רבים (ערכים שחולצו על ידי _n() עם כותרת ה־Plural-Forms שלהם), והקשרים (ערכי _x() עם msgctxt). לאחר מכן הוא יוצר את קטגוריות הרבים הנכונות לכל שפה. פולנית מקבלת one / few / many / other. יפנית מקבלת רק other. ערבית מקבלת שש צורות.

מעבר ללוקליזציה רציפה

ברגע שקובציכם הראשונים תורגמו, עברו למודל Pay-As-You-Go. חברו את PTC למאגר ה־GitHub,‏ GitLab או ה־Bitbucket שלכם. מאותו רגע לא תעלו קבצים ידנית:

# .github/workflows/translate.yml
name: Regenerate POT for PTC
on:
  push:
    branches: [main]
    paths:
      - 'languages/my-plugin.pot'
jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Generate POT
        run: |
          wp i18n make-pot . languages/my-plugin.pot --domain=my-plugin
      - name: Translate with PTC
        run: |
          cat > .ptc-config.yml <<'EOF'
          source_locale: en
          files:
            - file: languages/my-plugin.pot
              output: languages/my-plugin-{{lang}}.po
              additional_translation_files:
                - type: mo
                  path: languages/my-plugin-{{lang}}.mo
          EOF
          curl -fsSL https://raw.githubusercontent.com/OnTheGoSystems/ptc-cli/main/ptc-cli.sh -o ptc-cli.sh
          chmod +x ptc-cli.sh
          ./ptc-cli.sh --config-file .ptc-config.yml --api-token="${{ secrets.PTC_API_TOKEN }}"

יש לכם שתי דרכים לאוטומציה. באמצעות אינטגרציית Git,‏ PTC מנטר את המאגר שלכם ופותח pull request עם תרגומים מעודכנים בכל פעם שקובץ המקור משתנה. כדי להריץ תרגום בתוך משימת ה־CI שלכם, השתמשו ב־PTC CLI – הוא מעלה את הקובץ שהשתנה, ממתין לסיום התרגום ומוריד את הקבצים המתורגמים. תבניות תהליכי עבודה מוכנות עבור GitHub Actions,‏ GitLab CI ו־Bitbucket Pipelines נמצאות במדריך הגדרת צינור CI/CD.

כל אחד מהתהליכים מספק pull request או הורדה עם קובצי ה־.po,‏ .mo,‏ .json ו־.l10n.php המעודכנים. עיינו בתיעוד ה־API של PTC עבור ה־webhook וה־REST API המלאים.

ההחלטה אם לבצע commit לקובצי .mo במאגר שלכם תלויה במדיניות הצוות. תוספים רבים יוצרים אותם בזמן ההפצה במקום זאת. אינטגרציית ה־CI של PTC מפיקה אותם בכל הרצת תרגום. בצעו להם check-in רק אם אתם רוצים את הקבצים המתורגמים בהיסטוריית הגרסאות.

טעינת תרגומים ב־WordPress

עם הקבצים המתורגמים ביד, מקמו אותם נכון ואמרו ל־WordPress היכן למצוא אותם. שם הקובץ הוא השלב הראשון. WordPress מחפשת קובצי תרגום לפי תבנית שמות ספציפית. שם קובץ שאינו תואם פירושו שהקובץ לא ייטען.

דיוק בשמות הקבצים

קודי לוקאל עוקבים אחר הפורמט language_COUNTRY. ‏de_DE הוא גרמנית (גרמניה). fr_FR הוא צרפתית (צרפת). pt_BR הוא פורטוגזית (ברזיל). zh_CN הוא סינית מפושטת. פורטל התרגום של WordPress מפרט כל לוקאל נתמך.

שם הקובץ הצפוי תלוי במקום שבו אתם מניחים את הקובץ:

מיקום תבנית דוגמה
תיקיית /languages/ של התוסף {text-domain}-{locale}.mo my-plugin-de_DE.mo
תיקיית /languages/ של התבנית {locale}.mo de_DE.mo
ספריית השפות הגלובלית של WordPress (‏/wp-content/languages/) {text-domain}-{locale}.mo my-plugin-de_DE.mo

תבניות משתמשות במוסכמת שמות קצרה יותר כאשר הקבצים ארוזים בתוך התבנית. בספריית השפות הגלובלית, גם תוספים וגם תבניות משתמשים בתבנית {text-domain}-{locale}.

טעינת תרגומים עבור תוספים (PHP)

רשמו תרגומים ב־WordPress על ה־hook מסוג init. אל תשתמשו ב־plugins_loaded. הוא מפעיל אזהרת deprecation בגרסאות הנוכחיות של WordPress:

add_action( 'init', function () {
    load_plugin_textdomain(
        'my-plugin',
        false,
        dirname( plugin_basename( __FILE__ ) ) . '/languages/'
    );
} );

טעינת תרגומים עבור תבניות (PHP)

השתמשו ב־load_theme_textdomain() המחובר ל־after_setup_theme:

add_action( 'after_setup_theme', function () {
    load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
} );

טעינת תרגומי JavaScript

לאחר רישום הסקריפט שלכם (שלב 3 לעיל), קראו ל־wp_set_script_translations(). לאחר מכן WordPress טוענת את תרגומי ה־JSON עבור אותו script handle:

add_action( 'init', function () {
    wp_set_script_translations(
        'my-plugin-script',
        'my-plugin',
        plugin_dir_path( __FILE__ ) . 'languages'
    );
} );

אימות הטעינה

  1. הגדירו את שפת אתר ה־WordPress שלכם ללוקאל יעד. ההגדרה נמצאת ב־הגדרות > כללי > שפת האתר.
  2. טענו מחדש את ה־front end ואת דפי הניהול שהתוסף או התבנית שלכם מרנדרים.
  3. מחרוזות העטופות ב־__() או esc_html__() צריכות להופיע בשפה החדשה.

אם משהו חסר, עיינו בתרגומי תוסף WordPress לא מופיעים? תיקון תרגומים חסרים עבור הסיבות הנפוצות ביותר.

שפות מימין לשמאל ופריסות דו־כיווניות

תהליך עבודה של תרגום זהה עבור שפות מימין לשמאל (RTL). ערבית, עברית, פרסית ואורדו משתמשות באותו צינור POT/PO/MO.

השלב הנוסף הוא לוודא שהתבנית שלכם תומכת בסגנונות RTL. ‏WordPress טוענת אוטומטית קובץ rtl.css אם הוא קיים בספריית התבנית שלכם. השתמשו בפונקציה is_rtl() כדי להחיל סגנונות או סקריפטים ספציפיים ל־RTL באופן מותנה.

לוקליזציה של תאריכים, מספרים ומטבעות

מחרוזת מתורגמת היא לא כל הסיפור. תאריכים, מספרים ומטבעות חייבים גם הם לעקוב אחר הלוקאל של המשתמש. השתמשו בפונקציות הפירמוט המובנות של WordPress במקום באלו המקוריות של PHP:

  • date_i18n() מפרמטת תאריכים בהתאם ללוקאל הפעיל.
  • number_format_i18n() מפרמטת מספרים עם מפרידי אלפים ונקודה עשרונית שמתחשבים בלוקאל.

פונקציות אלו אינן חלק מתהליך העבודה של קובצי התרגום. הן חשובות עבור חוויית לוקליזציה מלאה.

בינאום בלוקים של עורך הבלוקים (Gutenberg)

בלוקים מוסיפים שני שלבים נוספים לצינור הסטנדרטי:

  • תרגומי JavaScript זקוקים לקובץ .json לכל לוקאל. צרו אותו מה־.po באמצעות wp i18n make-json.
  • סקריפט העורך של הבלוק זקוק ל־wp_set_script_translations() ב־PHP. זה אומר ל־WordPress להגיש את ה־JSON לבלוק.

הפלט המרונדר של הבלוק ב־front end משתמש באותן קריאות __() כמו שאר ה־PHP שלכם. אין שם עבודה נוספת.

תרגום ה־README ודף המוצר ב־WordPress.org

קובץ ה־readme.txt שלכם אינו קובץ משאבים. ‏WP-CLI לא יאסוף אותו בעת יצירת POT. כדי לתרגם אותו, השתמשו בתכונת הדבק לתרגום של PTC. הדביקו את התוכן, בחרו את שפות היעד שלכם והורידו את התוצאה. אימיילים הפונים ללקוחות שנשלחים מהתוסף ותיאור דף התוסף ב־WordPress.org מתורגמים באותה דרך, כולם באותו פרויקט כדי שהטרמינולוגיה תישאר עקבית.

אם התוסף או התבנית שלכם רשומים ב־WordPress.org, התיאור המתורגם מופיע בלשונית ה־Details של התוסף בשפת המשתמש. כדי להעלות את התרגומים לשם, עקבו אחר תהליך הייבוא של WordPress.org.

תרגום תוכן משתמש בתוסף באמצעות ה־API של PTC

תוספים המאחסנים נתונים שנוצרו על ידי משתמשים (תוספי פורומים, תוספי ביקורות, תוספי תגובות) יכולים לתרגם את התוכן הזה כשהוא מגיע. ה־REST API של PTC מתרגם פוסטים, תגובות וביקורות של משתמשים לפי דרישה עם אימות Bearer-token, תוך שימוש באותו מילון מונחים וטון מותג כמו קובצי ה־.po שלכם.

סקירת תרגום חזותית של התבנית או התוסף המרונדרים – הפצה ללא QA ידני לכל שפה

קובץ .po מתורגם הוא הכרחי, אך הוא אינו מספיק. התבנית או התוסף המתורגמים עדיין זקוקים לאימות:

  • תווית מתורגמת עלולה לחרוג מכפתור בדף הגדרות בגרמנית.
  • המילה "Submit" עלולה להיתרגם כשם עצם בצרפתית כאשר פעולת הניהול דרשה פועל.
  • מחרוזת אנגלית המוטמעת בקוד (hardcoded) מחוץ ל־__() תרונדר ללא תרגום ללא קשר למספר השפות שאתם מפיצים.

סקירת התרגום החזותית של PTC מחליפה את שלב ה־QA הידני. תבניות ותוספי WordPress מרונדרים בדפדפן (גם ב־wp-admin וגם ב־front end). הגרסה המתאימה היא תוסף הדפדפן.

התקינו אותו פעם אחת. הקליטו מעבר מוקלט (walkthrough) של התבנית או התוסף שלכם באתר בדיקה. כסו דפי הגדרות, פעולות ניהול ופלט ב־front end. ‏PTC מריץ מחדש את ההקלטה בכל שפת יעד לאחר כל עדכון תרגום. הוא לוכד כל מסך ומדווח בחזרה על שני סוגי תיקונים:

  • תיקונים בקובצי ה־.po כאשר ל־PTC יש שליטה עליהם. PTC מתרגם מחדש משמעות שגויה, בוחר מילה נרדפת קצרה יותר שמתאימה לכפתור, או יוצר מחדש צורת רבים.
  • הנחיות ל־Cursor או ל־Claude Code כאשר הבעיה נמצאת בקוד ה־PHP או ה־JavaScript שלכם. דוגמאות כוללות עטיפת __() חסרה, מחרוזת אנגלית המוטמעת בקוד, או משפט שנבנה על ידי שרשור שצריך להשתמש ב־sprintf( __( ... ) ).

אתם מפיצים תוסף רב־לשוני מאומת בכל גרסה. הצורך ב־QA ידני נעלם.

תמחור: תקופת ניסיון חינם של 30 יום, ולאחר מכן Pay-As-You-Go

תקופת הניסיון בחינם מכסה 20,000 מילים ל־2 שפות ללא כרטיס אשראי. כשתקופת הניסיון מסתיימת, PTC מציע מודל Pay-As-You-Go. ללא מנוי. ללא התחייבות מינימלית. 500 המילים הראשונות בכל חודש הן בחינם. אתם משלמים רק על השאר. בדף התמחור יש מחשבון עלויות. הירשמו עם אימייל חברה לקבלת תקופת ניסיון עסקית מורחבת.

מוכנים להפיץ תוסף או תבנית מאומתים?

‏PTC יוצר את התרגומים וסוקר את התוסף המרונדר. אתם מאשרים את התוצאה ומפיצים. הלופ המלא רץ ללא QA ידני:

  1. צרו את קובץ ה־.pot שלכם באמצעות wp i18n make-pot.
  2. העלו אותו ל־PTC וקבלו בחזרה קובצי .po,‏ .mo,‏ .l10n.php ו־.json תוך דקות.
  3. התקינו את תוסף הדפדפן כדי לאמת את התוסף הפועל בכל שפת יעד.

התחילו את תקופת הניסיון שלכם ל־30 יום בחינם – 20,000 מילים עלינו, ללא צורך בכרטיס אשראי.

קשור: