מדריך בינאום (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 שלבים
- התחילו פרויקט PTC ובחרו את ה־locale של המקור (אנגלית /
messages.properties). - העלו את קובצי ה־
.propertiesשלכם והגדירו נתיבי פלט. PTC מנתח את מבנה המפתח-ערך, מזהה מצייני מיקום שלMessageFormat(כמו{0},{1}) ותבניותChoiceFormat, וקורא כל הערת#כהקשר למתרגם. - הוסיפו תיאור קצר של אפליקציית ה־Java וקהל היעד שלכם. PTC משתמש במידע זה כדי לתרגם בטון ובטרמינולוגיה הנכונים.
- בחרו שפות יעד ואשרו. תקופת הניסיון בחינם מכסה 20,000 מילים ל־2 שפות, ללא צורך בכרטיס אשראי.
- הורידו קובצי
.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 לאמת את האפליקציה הפעילה.
נושאים קשורים:
- תרגום אפליקציות Java באמצעות בינה מלאכותית – סקירת שירות לצוותי Java.
- תיעוד ה־API של PTC – נקודות קצה REST לאינטגרציית CI.
- לוקליזציית תוכנה מבוססת בינה מלאכותית המיועדת לצינורות CI/CD – סקירת שירות לצוותי הנדסה.