PTC

Java-Internationalisierungs-Guide: .properties-Dateien mit KI übersetzen

Richten Sie ResourceBundle ein, strukturieren Sie .properties-Dateien, übersetzen Sie mit KI in über 40 Sprachen und lassen Sie PTC (Private Translation Cloud) die laufende Java-App per Screenshot oder Browser-Erweiterung prüfen. Am Ende verfügen Sie über ein mehrsprachiges JAR, das bereit für den Release ist, wobei jede Zielsprache vor der Veröffentlichung verifiziert wurde. Eine Übersicht über den eigenständigen Java-Service finden Sie unter Java-Apps mit KI übersetzen.

ResourceBundle lädt zur Laufzeit die richtige .properties-Datei

Das i18n-System von Java baut auf zwei Dingen auf: .properties-Dateien, die Ihre übersetzten Strings speichern, und die ResourceBundle-Klasse, die zur Laufzeit basierend auf dem Locale des Benutzers die richtige Datei lädt.

Wenn Ihre App ausgeführt wird, prüft ResourceBundle das Locale des Benutzers und lädt automatisch die passende Datei. Wenn eine Übersetzung fehlt, führt es unbemerkt einen Fallback auf die Standarddatei durch. Nichts geht kaputt, aber fehlende Übersetzungen werden auch nicht als Fehler angezeigt. Einen String im Code aufrufen:

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

Das ist der gesamte Mechanismus. Der Rest der Lokalisierungsarbeit findet in den .properties-Dateien selbst statt, weshalb ihre korrekte Strukturierung wichtig ist.

Richten Sie Ihr Ressourcenbündel mit messages_{locale}.properties ein

Ein Ressourcenbündel ist eine Gruppe von .properties-Dateien, die sich einen gemeinsamen Basisnamen teilen. Der Basisname ist der Teil des Dateinamens vor dem Locale-Suffix. Das ist es, was ResourceBundle.getBundle() verwendet, um zur Laufzeit die richtige Datei zu finden.

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)

Größere Anwendungen verwenden oft mehrere Ressourcenbündel, um für Übersichtlichkeit zu sorgen:

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

Java erwartet ein bestimmtes Benennungsmuster: basename_language.properties oder basename_language_COUNTRY.properties für regionale Varianten:

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

Sprachcodes folgen ISO 639-1. Ländercodes folgen ISO 3166-1. Die Verwendung des falschen Formats führt dazu, dass ResourceBundle die Datei zur Laufzeit nicht findet.

Laden und verwenden Sie das Bündel im Code, mit MessageFormat für die Ersetzung von Platzhaltern:

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"
    }
}

Für einfache Strings ohne Platzhalter reicht messages.getString("key") aus.

Sechs Konventionen, die Ihre .properties-Dateien übersetzungsbereit machen

Jede Zeile ist ein Schlüssel-Wert-Paar, getrennt durch =. Wie Sie Ihre Quelldatei schreiben, wirkt sich direkt auf die Qualität Ihrer Übersetzungen aus. Das gilt unabhängig davon, ob Sie manuell oder mit einem KI-Tool wie PTC übersetzen.

1. Verwenden Sie klare, aussagekräftige Schlüssel, die benennen, wo der String erscheint

Schlüssel sollten offensichtlich machen, wo und wie ein String verwendet wird. Das ist wichtig, wenn Sie Hunderte von Strings in mehreren Dateien verwalten.

# Incorrect
btn1 = Submit
msg2 = Error

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

Ändern Sie niemals einen Schlüssel, nachdem die Übersetzung begonnen hat. Die Änderung eines Schlüssels führt dazu, dass die bereits vorhandene Übersetzung verwaist.

2. Verwenden Sie nummerierte Platzhalter, keine String-Verkettung im Code

Schreiben Sie den vollständigen Satz in Ihre .properties-Datei und verwenden Sie nummerierte Platzhalter für variable Inhalte, anstatt Strings im Code zu verketten.

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

In vielen Sprachen ändern sich die Wortstellung und die Regeln für die grammatikalische Übereinstimmung, sodass das Aufteilen von Sätzen in Fragmente eine korrekte Übersetzung unmöglich macht.

3. Handhaben Sie die Pluralisierung mit ChoiceFormat, ICU oder Suffix-Schlüsseln

Für die Pluralisierung in Standard-Java funktioniert ChoiceFormat direkt innerhalb von .properties:

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

Java verarbeitet dies zur Laufzeit und gibt basierend auf dem übergebenen Wert die richtige Form zurück. ChoiceFormat ist einfach, aber auf den Abgleich von Zahlenbereichen beschränkt. Komplexe Pluralregeln werden von Haus aus nicht unterstützt.

Für sprachspezifische Plurale (die polnischen Formen one/few/many/other, die sechs Formen des Arabischen) verwenden Sie MessageFormat der ICU4J-Bibliothek:

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

Oder codieren Sie Plurale als separate Schlüssel mit herkömmlichen Suffixen, damit PTC die richtigen Pluralkategorien pro Sprache generieren kann:

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

PTC generiert die richtigen Pluralkategorien pro Zielsprache. Polnisch erhält one / few / many / other. Japanisch erhält nur other.

4. Escapen Sie =, :, # und \ mit einem Backslash

Zeichen wie =, :, # und \ haben in .properties-Dateien eine besondere Bedeutung:

  • = oder : trennt Schlüssel von Werten.
  • # oder ! startet einen Kommentar.
  • \ leitet Escape-Sequenzen ein (wie \n für einen Zeilenumbruch).

Escapen Sie bei Bedarf mit einem Backslash:

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

5. Speichern Sie .properties-Dateien als UTF-8

Speichern Sie .properties-Dateien immer in UTF-8. Ohne dies werden Nicht-ASCII-Zeichen beschädigt und Übersetzungen unleserlich. Historisch gesehen waren Java-.properties-Dateien in ISO-8859-1 codiert, was \uXXXX-Escapes für Nicht-ASCII-Zeichen erforderte. Java 9+ liest sie standardmäßig als UTF-8. Überprüfen Sie daher Ihre Runtime-Version, bevor Sie sich auf reines UTF-8 verlassen.

6. Halten Sie jeglichen benutzerseitigen Text aus dem Code heraus

Wenn ein String für Benutzer sichtbar ist, gehört er in eine .properties-Datei. Hardcodierte Strings werden nicht übersetzt. Ihre App wird am Ende eine Mischung aus Sprachen anzeigen.

Formatieren Sie Datumsangaben, Uhrzeiten, Zahlen und Währungen mit Locale-fähigen Hilfsfunktionen

Nicht alles, was lokalisiert werden muss, befindet sich in einer .properties-Datei. Datumsangaben, Uhrzeiten, Zahlen und Währungswerte werden zur Laufzeit im Code formatiert, und sie richtig hinzubekommen ist genauso wichtig wie Ihre übersetzten Strings.

Datumsangaben mit 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"

Währungen mit 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 €"

Verwenden Sie immer Locale-fähige Formatierer. Hardcodieren Sie niemals "$", ","-Tausendertrennzeichen oder "MM/DD/YYYY"-Muster.

ResourceBundle über MessageSource in Spring Boot einbinden

Spring Boot verpackt ResourceBundle in einen MessageSource-Bean, das sich in die i18n-Funktionen des Frameworks integriert. Es deckt auch Validierungsnachrichten, Thymeleaf-Templates und die Locale-Auflösung von Web-Requests ab.

In application.properties konfigurieren:

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

Platzieren Sie messages.properties, messages_es.properties usw. unter src/main/resources/.

In einem Controller verwenden:

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()
        );
    }
}

Konfigurieren Sie den Locale-Resolver so, dass er aus dem Accept-Language-Header oder einem URL-Parameter liest:

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);
    }
}

Nun gibt GET /greeting?name=World&lang=es die spanische Version zurück.

Java-.properties-Dateien mit PTC in 5 Schritten übersetzen

  1. Starten Sie ein PTC-Projekt und wählen Sie Ihr Ausgangs-Locale (Englisch / messages.properties).
  2. Laden Sie Ihre .properties-Datei(en) hoch und legen Sie Ausgabepfade fest. PTC parst die Schlüssel-Wert-Struktur, erkennt MessageFormat-Platzhalter ({0}, {1}) sowie ChoiceFormat-Muster und liest eventuelle #-Kommentare als Übersetzerkontext aus.
  3. Fügen Sie eine kurze Beschreibung Ihrer Java-Anwendung und Zielgruppe hinzu. PTC nutzt dies, um mit der richtigen Tonalität und Terminologie zu übersetzen.
  4. Wählen Sie die Zielsprachen aus und bestätigen Sie. Die Testphase deckt 20.000 Wörter in 2 Sprachen ab, keine Kreditkarte erforderlich.
  5. Laden Sie übersetzte .properties-Dateien aus dem Tab Files herunter. Eine pro Sprache, mit dem richtigen Suffix (messages_es.properties, messages_fr.properties). Strukturell identisch mit der Quelle: gleiche Schlüssel, gleiche Platzhalter, übersetzte Werte.

Legen Sie sie in src/main/resources/ ab, führen Sie einen neuen Build durch, und ResourceBundle.getBundle("messages", locale) erkennt die neuen Sprachen automatisch. Die gesamte Einrichtung dauert etwa 5 Minuten.

Automatisieren Sie die Java-Übersetzung bei jedem Release mit Git oder der PTC-API

Einmaliges Übersetzen ist unkompliziert. Übersetzungen aktuell zu halten, während sich Ihre Anwendung weiterentwickelt, ist schwieriger. Jeder neue String, jede Textaktualisierung, jeder entfernte Schlüssel muss in jede Sprache einfließen. PTC bietet zwei Möglichkeiten zur Automatisierung.

Git-Integration. Verbinden Sie Ihr GitHub-, GitLab- oder Bitbucket-Repository mit PTC. PTC überwacht Ihre .properties-Quelldatei auf Änderungen. Wenn ein String hinzugefügt oder aktualisiert wird, übersetzt PTC ihn und liefert die aktualisierten Dateien über einen Merge Request zurück.

CI/CD-Integration. Wenn Sie lieber alles innerhalb Ihres bestehenden Build-Prozesses belassen möchten, können Sie mit der API von PTC Ihre Quelldatei hochladen und Übersetzungen als Teil Ihres CI-Jobs abrufen:

# .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 synchronisiert die neuen Quellstrings, übersetzt nur das, was sich geändert hat, und öffnet einen PR mit den aktualisierten Dateien messages_es.properties, messages_fr.properties und so weiter. Für Maven- und Gradle-Projekte funktioniert derselbe Workflow. PTC ist Ihr Build-Tool egal. Beide Ansätze bedeuten, dass das spätere Hinzufügen einer neuen Sprache eine Konfigurationsänderung ist und kein neuer manueller Prozess.

Visuelle Übersetzungsprüfung Ihrer übersetzten Java-App – veröffentlichen ohne manuelle QA pro Sprache

Eine übersetzte .properties-Datei ist notwendig, aber nicht ausreichend. Unabhängig davon, ob Ihre Java-App ein Spring Boot-Webdienst ist, der HTML ausliefert, eine Desktop-Swing-App oder ein serverseitiges CLI-Tool, kann die gerenderte Ausgabe Fehler aufweisen, die bei einer Prüfung auf String-Ebene nicht erkannt werden können:

  • Ein deutsches Label, das einen Swing-Button überlaufen lässt.
  • Eine französische Validierungsnachricht mit der falschen grammatikalischen Form.
  • Ein hardcodierter englischer String außerhalb von messageSource.getMessage(), der unübersetzt angezeigt wird.

Die AI Visual QA von PTC deckt beide Varianten von Java-Apps ab:

  • Für Spring Boot oder jede webbasierte Java-App: Installieren Sie die PTC-Browser-Erweiterung und zeichnen Sie einen Rundgang durch die kritischen Seiten Ihrer App auf. PTC spielt diesen nach jedem Übersetzungsupdate in jeder Zielsprache ab.
  • Für Desktop- (Swing, JavaFX), Server- (CLI) oder jede nicht-browserbasierte Java-App: Laden Sie Screenshots der laufenden Java-App in jeder Zielsprache hoch. Die Vision-KI von PTC prüft jeden Bildschirm.

Fehler, die PTC in den .properties-Dateien beheben kann (Verb/Substantiv, Layout-Überlauf, falsche Bedeutung), werden automatisch behoben. Fehler in Ihrem Java-Code (fehlender messageSource.getMessage()-Aufruf, hardcodierter String, Satzverkettung, die MessageFormat verwenden sollte) kommen als einsatzbereite Prompts für Cursor oder Claude Code zurück.

Das Ergebnis: ein verifiziertes, mehrsprachiges JAR pro Release. Nicht nur übersetzte Property-Dateien.

Release Notes, READMEs und Kunden-E-Mails übersetzen

Ihre Release Notes, READMEs in Ihrem internen Maven-Repository oder auf GitHub, kundenorientierten E-Mails, Support-Dokumentationen und internen Wiki-Seiten befinden sich außerhalb von .properties. Paste to Translate von PTC verarbeitet diese Texte im selben Projekt. Fügen Sie den Ausgangstext im PTC-Dashboard ein, wählen Sie die Zielsprachen aus und Sie erhalten Übersetzungen zurück, die dasselbe Glossar und dieselbe Markenstimme verwenden wie Ihre In-App-Strings.

Unternehmensdaten, Support-Tickets und Kundeninhalte mit der PTC-API übersetzen

Unternehmensdaten, Support-Tickets, Knowledge-Base-Einträge und von Kunden eingereichte Inhalte müssen übersetzt werden, sobald sie eintreffen. Die PTC-REST-API übersetzt diese Inhalte bei Bedarf mit Bearer-Token-Authentifizierung und verwendet dabei dasselbe Glossar und dieselbe Markenstimme wie Ihre .properties-Übersetzungen.

PTC übersetzt Ihre Java-App UND prüft das laufende Ergebnis

Starten Sie Ihre 30-Tage-Testphase – 20.000 Wörter in 2 Sprachen, keine Kreditkarte erforderlich. Laden Sie Ihre .properties-Dateien hoch, erhalten Sie in wenigen Minuten übersetzte Versionen, laden Sie dann Screenshots hoch (oder installieren Sie die Browser-Erweiterung für Spring Boot) und lassen Sie PTC die laufende App verifizieren.

Verwandte Themen: