PTC

מדריך בינאום (i18n) ל־Java: תרגום קובצי properties באמצעות בינה מלאכותית

הגדירו ResourceBundle, ארגנו את קובצי ה־.properties, תרגמו ל-40+ שפות באמצעות בינה מלאכותית, ולאחר מכן תנו ל־PTC (‏Private Translation Cloud) לסקור את אפליקציית ה־Java הפעילה באמצעות צילומי מסך או תוסף דפדפן. בסיום התהליך יהיה בידיכם קובץ JAR רב-לשוני מוכן להפצה, כשכל שפת יעד מאומתת לפני השחרור. לסקירה כללית של שירות ה־Java העצמאי, ראו תרגום אפליקציות Java באמצעות בינה מלאכותית.

ResourceBundle טוען את קובץ ה־.properties הנכון בזמן ריצה

מערכת ה־i18n של Java בנויה סביב שני מרכיבים: קובצי .properties המאחסנים את המחרוזות המתורגמות שלכם, ומחלקת ResourceBundle שטוענת את הקובץ המתאים בזמן ריצה בהתאם להגדרות ה-locale של המשתמש.

כשהאפליקציה פועלת, ResourceBundle בודק את ה-locale של המשתמש וטוען את הקובץ התואם באופן אוטומטי. אם תרגום מסוים חסר, המערכת עוברת בשקט לקובץ ברירת המחדל. שום דבר לא נשבר, אך תרגומים חסרים גם לא מופיעים כשגיאות. כך נראית קריאה למחרוזת בקוד:

ResourceBundle bundle = ResourceBundle.getBundle("messages", Locale.FRENCH);
String greeting = bundle.getString("welcome.message");

זהו המנגנון כולו. שאר עבודת הלוקליזציה מתבצעת בקובצי ה־.properties עצמם, ולכן חשוב לבנות אותם נכון.

הגדרת resource bundle עם messages_{locale}.properties

‏resource bundle הוא קבוצה של קובצי .properties החולקים שם בסיס (base name) משותף. שם הבסיס הוא חלק משם הקובץ המופיע לפני סיומת ה־locale. זהו השם שבו משתמשת הפקודה ResourceBundle.getBundle() כדי למצוא את הקובץ הנכון בזמן ריצה.

src/main/resources/
  messages.properties        # default (usually English)
  messages_fr.properties     # French
  messages_de.properties     # German
  messages_es.properties     # Spanish
  messages_ja.properties     # Japanese
  messages_zh_CN.properties  # Simplified Chinese (note underscore, not hyphen)

אפליקציות גדולות משתמשות לעיתים קרובות במספר resource bundles כדי לשמור על הסדר:

src/main/resources/
  messages.properties
  errors.properties
  emails.properties

‏Java מצפה לתבנית שמות ספציפית: basename_language.properties, או basename_language_COUNTRY.properties עבור וריאציות אזוריות:

messages_fr.properties      # French
messages_fr_CA.properties   # French (Canada)
messages_pt_BR.properties   # Portuguese (Brazil)

קודי שפה עוקבים אחר תקן ISO 639-1. קודי מדינה עוקבים אחר תקן ISO 3166-1. שימוש בפורמט שגוי יגרום לכך ש־ResourceBundle לא ימצא את הקובץ בזמן ריצה.

טענו והשתמשו ב־bundle בקוד, בשילוב עם MessageFormat עבור החלפת מצייני מיקום:

import java.util.Locale;
import java.util.ResourceBundle;
import java.text.MessageFormat;

public class App {
    public static void main(String[] args) {
        Locale locale = Locale.of("es");
        ResourceBundle messages = ResourceBundle.getBundle("messages", locale);

        String welcome = MessageFormat.format(
            messages.getString("app.welcome"),
            "My App"
        );
        System.out.println(welcome);
        // -> "Bienvenido a My App"
    }
}

עבור מחרוזות פשוטות ללא מצייני מיקום, הפקודה messages.getString("key") מספיקה.

שש מוסכמות שיהפכו את קובצי ה־.properties שלכם למוכנים לתרגום

כל שורה היא זוג של מפתח-ערך המופרדים בסימן =. האופן שבו תכתבו את קובץ המקור משפיע ישירות על איכות התרגומים שלכם. זה נכון בין אם אתם מתרגמים ידנית ובין אם אתם משתמשים בכלי בינה מלאכותית כמו PTC.

1. השתמשו במפתחות ברורים ותיאוריים המציינים היכן המחרוזת מופיעה

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

# Incorrect
btn1 = Submit
msg2 = Error

# Correct
form.submit.button = Submit
error.login.invalid_credentials = Invalid username or password

לעולם אל תשנו מפתח לאחר שהתרגום החל. שינוי מפתח מנתק את התרגום הקיים והופך אותו ליתום.

2. השתמשו במצייני מיקום ממוספרים, לא בשרשור מחרוזות בקוד

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

// Incorrect (in code)
"Hello, " + username + "! You have " + count + " new messages."
# Correct (in .properties)
dashboard.greeting = Hello, {0}! You have {1} new messages.

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

3. טפלו בריבוי (pluralization) באמצעות ChoiceFormat, ICU או סיומות מפתחות

עבור טיפול בריבוי ב־Java סטנדרטית, ChoiceFormat עובד ישירות בתוך קובצי .properties:

messages.count = {0,choice,0#no messages|1#one message|1<{0} messages}

‏Java מעבדת זאת בזמן ריצה ומחזירה את הצורה הנכונה בהתאם לערך שהועבר. ChoiceFormat הוא פשוט אך מוגבל להתאמה לפי טווחי מספרים. הוא אינו תומך באופן טבעי בכללי ריבוי מורכבים.

עבור ריבוי שמתחשב בשפה (כמו צורות one/few/many/other בפולנית, או שש הצורות בערבית), השתמשו ב־MessageFormat של ICU4J:

String pattern = "{0, plural, one {# note} other {# notes}}";
String result = new com.ibm.icu.text.MessageFormat(pattern, locale).format(new Object[]{count});

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

notes.count.zero=No notes yet
notes.count.one={0} note
notes.count.other={0} notes

‏PTC מפיק את קטגוריות הריבוי הנכונות לכל שפת יעד. פולנית תקבל one / few / many / other. יפנית תקבל רק other.

4. בצעו Escape לסימנים =, :, #, ו־\ באמצעות לוכסן אחורי

לתווים כמו =, :, #, ו־\ יש משמעות מיוחדת בקובצי .properties:

  • = או : מפרידים בין מפתחות לערכים.
  • # או ! מתחילים הערה.
  • \ משמש לרצפי מילוט (כמו \n לשורה חדשה).

השתמשו בלוכסן אחורי (backslash) לביצוע escape במידת הצורך:

support.link = Visit us at https\://support.example.com

5. שמרו קובצי .properties בקידוד UTF-8

שמרו תמיד קובצי .properties בקידוד UTF-8. ללא קידוד זה, תווים שאינם ASCII ישתבשו והתרגומים יהפכו לבלתי קריאים. היסטורית, קובצי .properties ב־Java היו בקידוד ISO-8859-1, מה שדרש מילוט \uXXXX עבור תווים שאינם ASCII. החל מגרסה 9, Java קוראת אותם כ־UTF-8 כברירת מחדל, לכן בדקו את גרסת זמן הריצה שלכם לפני שתסתמכו על UTF-8 גולמי.

6. הוציאו את כל הטקסט הפונה למשתמש מהקוד

אם מחרוזת גלויה למשתמשים, מקומה בקובץ .properties. מחרוזות המוטמעות ישירות בקוד (hardcoded) לא יתורגמו, והאפליקציה שלכם תציג בסופו של דבר תערובת של שפות.

עיצוב תאריכים, זמנים, מספרים ומטבעות באמצעות עזרי עיצוב מותאמי locale

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

תאריכים עם DateTimeFormatter:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

LocalDate today = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter
    .ofLocalizedDate(FormatStyle.LONG)
    .withLocale(Locale.of("fr"));
System.out.println(today.format(formatter));
// -> "27 mai 2026"

מטבע עם NumberFormat:

import java.text.NumberFormat;
import java.util.Currency;

NumberFormat formatter = NumberFormat.getCurrencyInstance(Locale.of("de", "DE"));
formatter.setCurrency(Currency.getInstance("EUR"));
System.out.println(formatter.format(1999.99));
// -> "1.999,99 €"

השתמשו תמיד במעצבים (formatters) מותאמי locale. לעולם אל תטמיעו בקוד סימני "$", פסיקים כמפרידי אלפים או תבניות כמו "MM/DD/YYYY".

חיבור ResourceBundle ל־Spring Boot באמצעות MessageSource

‏Spring Boot עוטף את ResourceBundle ב־bean מסוג MessageSource המשתלב בתכונות ה־i18n של הפריימוורק. הוא מכסה גם הודעות אימות (validation), תבניות Thymeleaf וזיהוי locale של בקשות רשת.

הגדירו ב־application.properties:

spring.messages.basename=messages
spring.messages.encoding=UTF-8
spring.messages.fallback-to-system-locale=false

מקמו את messages.properties, ‏messages_es.properties וכו' תחת src/main/resources/.

שימוש ב־controller:

import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;

@RestController
public class GreetingController {
    private final MessageSource messageSource;

    public GreetingController(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @GetMapping("/greeting")
    public String greeting(@RequestParam String name) {
        return messageSource.getMessage(
            "app.greeting",
            new Object[]{name},
            LocaleContextHolder.getLocale()
        );
    }
}

הגדירו את ה־locale resolver לקריאה מכותרת Accept-Language או מפרמטר ב־URL:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;

@Configuration
public class I18nConfig implements WebMvcConfigurer {
    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
        resolver.setDefaultLocale(Locale.ENGLISH);
        return resolver;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName("lang");
        registry.addInterceptor(interceptor);
    }
}

כעת הקריאה GET /greeting?name=World&lang=es תחזיר את הגרסה הספרדית.

תרגום קובצי .properties של Java עם PTC ב־5 שלבים

  1. התחילו פרויקט PTC ובחרו את ה־locale של המקור (אנגלית / messages.properties).
  2. העלו את קובצי ה־.properties שלכם והגדירו נתיבי פלט. ‏PTC מנתח את מבנה המפתח-ערך, מזהה מצייני מיקום של MessageFormat (כמו {0}, {1}) ותבניות ChoiceFormat, וקורא כל הערת # כהקשר למתרגם.
  3. הוסיפו תיאור קצר של אפליקציית ה־Java וקהל היעד שלכם. ‏PTC משתמש במידע זה כדי לתרגם בטון ובטרמינולוגיה הנכונים.
  4. בחרו שפות יעד ואשרו. תקופת הניסיון בחינם מכסה 20,000 מילים ל־2 שפות, ללא צורך בכרטיס אשראי.
  5. הורידו קובצי .properties מתורגמים מלשונית קובצי משאבים. קובץ אחד לכל שפה, עם הסיומת הנכונה (messages_es.properties, messages_fr.properties). הקבצים זהים מבנית למקור: אותם מפתחות, אותם מצייני מיקום, וערכים מתורגמים.

הכניסו אותם ל־src/main/resources/, בצעו build מחדש, ו־ResourceBundle.getBundle("messages", locale) יזהה את השפות החדשות באופן אוטומטי. ההגדרה כולה אורכת כ־5 דקות.

אוטומציה של תרגום Java בכל גרסה באמצעות Git או ה־API של PTC

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

אינטגרציית Git. חברו את מאגר ה־GitHub, ‏GitLab או ה־Bitbucket שלכם ל־PTC. המערכת תנטר את קובץ ה־.properties המקורי לשינויים. כשמחרוזת מתווספת או מתעדכנת, PTC מתרגם אותה ומספק את הקבצים המעודכנים באמצעות pull request.

אינטגרציית CI/CD. אם אתם מעדיפים לשמור הכל בתוך תהליך ה־build הקיים שלכם, ה־API של PTC מאפשר לכם להעלות את קובץ המקור ולקבל תרגומים כחלק ממשימת ה־CI:

# .github/workflows/translate.yml
name: PTC translate
on:
  push:
    branches: [main]
    paths:
      - 'src/main/resources/messages.properties'
jobs:
  translate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Translate with PTC
        run: |
          cat > .ptc-config.yml <<'EOF'
          source_locale: en
          files:
            - file: src/main/resources/messages.properties
              output: src/main/resources/messages_{{lang}}.properties
          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 }}"

‏PTC מסנכרן את מחרוזות המקור החדשות, מתרגם רק את מה שהשתנה, ופותח PR עם הקבצים המעודכנים (messages_es.properties, messages_fr.properties וכו'). התהליך זהה עבור פרויקטים ב־Maven וב־Gradle. ל־PTC לא משנה באיזה כלי build אתם משתמשים. שתי הגישות הופכות הוספת שפה חדשה בעתיד לשינוי הגדרה פשוט, ולא לתהליך ידני חדש.

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

קובץ .properties מתורגם הוא הכרחי אך לא מספיק. בין אם אפליקציית ה־Java שלכם היא שירות רשת ב־Spring Boot המגיש HTML, אפליקציית Swing לשולחן העבודה או כלי CLI בצד השרת, התוצאה המרונדרת עלולה לסבול מבעיות ששום סקירה ברמת המחרוזת לא תזהה:

  • תווית בגרמנית שחורגת מגבולות כפתור ב־Swing.
  • הודעת אימות בצרפתית עם הטיה דקדוקית שגויה.
  • מחרוזת באנגלית שהוטמעה ישירות מחוץ ל־messageSource.getMessage() ומופיעה ללא תרגום.

‏AI Visual QA של PTC מכסה את שני סוגי אפליקציות ה-Java:

  • עבור Spring Boot או כל אפליקציית Java מבוססת רשת: התקינו את תוסף הדפדפן של PTC והקליטו מעבר מוקלט (walkthrough) בדפי המפתח של האפליקציה. PTC יריץ אותו מחדש בכל שפת יעד לאחר כל עדכון תרגום.
  • עבור אפליקציות שולחן עבודה (Swing, JavaFX), שרת (CLI) או כל אפליקציית Java שאינה בדפדפן: העלו צילומי מסך של אפליקציית ה־Java הפועלת בכל שפת יעד. הבינה המלאכותית החזותית של PTC תסרוק כל מסך.

בעיות ש־PTC יכול לתקן בקובצי ה־.properties (פועל/שם עצם, חריגה מהפריסה, משמעות שגויה) מתוקנות אוטומטית. בעיות בקוד ה־Java (קריאה חסרה ל־messageSource.getMessage(), מחרוזת hardcoded, שרשור משפטים שצריך להשתמש ב־MessageFormat) חוזרות כהנחיות (prompts) מוכנות להדבקה עבור Cursor או Claude Code.

התוצאה: קובץ JAR מאומת ורב-לשוני בכל גרסה. לא רק קובצי properties מתורגמים.

תרגום הערות גרסה, קובצי README ומיילים ללקוחות

הערות הגרסה שלכם, קובצי README במאגר ה־Maven הפנימי או ב־GitHub, מיילים ללקוחות, תיעוד תמיכה ודפי ויקי פנימיים נמצאים מחוץ לקובצי ה־.properties. תכונת הדבקה לתרגום של PTC מטפלת בטקסטים אלו באותו פרויקט. הדביקו את טקסט המקור בלוח הבקרה של PTC, בחרו שפות יעד, וקבלו תרגומים המשתמשים באותו מילון מונחים ובאותו טון מותג כמו המחרוזות בתוך האפליקציה.

תרגום נתונים ארגוניים, כרטיסי תמיכה ותוכן לקוחות באמצעות ה־API של PTC

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

PTC מתרגם את אפליקציית ה־Java שלכם וגם סוקר את התוצאה הפעילה

התחילו תקופת ניסיון של 30 יום בחינם – 20,000 מילים ל־2 שפות, ללא צורך בכרטיס אשראי. העלו את קובצי ה־.properties שלכם, קבלו גרסאות מתורגמות תוך דקות, ולאחר מכן העלו צילומי מסך (או התקינו את תוסף הדפדפן עבור Spring Boot) ותנו ל־PTC לאמת את האפליקציה הפעילה.

נושאים קשורים: