PTC

מדריך לבינאום ב־Java: תרגום קובצי .properties מבוסס בינה מלאכותית

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

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

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

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

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

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

הגדרת חבילת המשאבים שלכם עם messages_{locale}.properties

חבילת משאבים היא אוסף של קובצי .properties שחולקים שם בסיס משותף. שם הבסיס הוא החלק בשם הקובץ שלפני סיומת ה־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)

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

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. טפלו בצורות רבים בעזרת 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:

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

בצעו escape בעזרת לוכסן אחורי היכן שצריך:

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

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

שמרו תמיד קובצי .properties ב־UTF-8. בלעדיו, תווים שאינם ASCII משתבשים והתרגומים הופכים לבלתי קריאים. היסטורית, קובצי .properties ב־Java היו בקידוד ISO-8859-1, מה שדרש שימוש ב־escape מסוג \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. לעולם אל תטמיעו בקוד (hardcode) את "$", מפרידי אלפים כמו ",", או תבניות "MM/DD/YYYY".

חיבור ResourceBundle ל־Spring Boot בעזרת MessageSource

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

הגדירו ב־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 לקרוא מה־header 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 מתורגמים מהלשונית Files. קובץ אחד לכל שפה, עם הסיומת הנכונה (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. מערכת PTC עוקבת אחר קובץ ה־.properties של המקור שלכם לאיתור שינויים. כאשר מחרוזת מתווספת או מתעדכנת, PTC מתרגמת אותה ומחזירה את הקבצים המעודכנים באמצעות merge 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.
  • הודעת אימות בצרפתית עם צורה דקדוקית שגויה.
  • מחרוזת אנגלית מוטמעת בקוד (hardcoded) מחוץ ל־messageSource.getMessage() שמוצגת ללא תרגום.

ה־AI Visual QA של PTC מכסה את שתי הווריאציות של אפליקציות Java:

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

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

התוצאה: JAR רב־לשוני ומאומת בכל שחרור גרסה. לא רק קובצי property מתורגמים.

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

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

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

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

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

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

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