PTC

Guida all'internazionalizzazione in Java: tradurre i file .properties con l'IA

Configura ResourceBundle, struttura i file .properties, traduci in oltre 40 lingue con l'IA, quindi lascia che PTC (Private Translation Cloud) revisioni l'app Java in esecuzione tramite schermate o estensione del browser. Alla fine avrai un JAR multilingue pronto per il rilascio, con ogni lingua di destinazione verificata prima della release. Per una panoramica sul servizio Java indipendente, vedi tradurre le app Java con l'IA.

ResourceBundle carica il file .properties corretto a runtime

Il sistema di i18n di Java si basa su due elementi. I file .properties che memorizzano le tue stringhe tradotte e la classe ResourceBundle che carica il file corretto a runtime in base al locale dell'utente.

Quando la tua app è in esecuzione, ResourceBundle controlla il locale dell'utente e carica automaticamente il file corrispondente. Se manca una traduzione, esegue il fallback al file predefinito in modo invisibile. Non si rompe nulla, ma le traduzioni mancanti non vengono nemmeno segnalate come errori. Per richiamare una stringa nel codice:

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

Questo è l'intero meccanismo. Il resto del lavoro di localizzazione avviene nei file .properties stessi, motivo per cui strutturarli correttamente è importante.

Configura il tuo bundle di risorse con messages_{locale}.properties

Un bundle di risorse è un insieme di file .properties che condividono un base name comune. Il base name è la parte del nome file che precede il suffisso del locale. È ciò che ResourceBundle.getBundle() usa per trovare il file corretto a runtime.

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)

Le applicazioni più grandi usano spesso più bundle di risorse per mantenere tutto organizzato:

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

Java si aspetta uno schema di denominazione specifico: basename_language.properties, oppure basename_language_COUNTRY.properties per le varianti regionali:

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

I codici della lingua seguono lo standard ISO 639-1. I codici del paese seguono lo standard ISO 3166-1. Usare il formato sbagliato significa che ResourceBundle non troverà il file a runtime.

Carica e usa il bundle nel codice, con MessageFormat per la sostituzione dei segnaposto:

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

Per le stringhe semplici senza segnaposto, messages.getString("key") è sufficiente.

Sei convenzioni che rendono i tuoi file .properties pronti per la traduzione

Ogni riga è una coppia chiave-valore separata da =. Come scrivi il tuo file di origine influisce direttamente sulla qualità delle tue traduzioni. Questo vale sia che tu traduca manualmente o con uno strumento di IA come PTC.

1. Usa chiavi chiare e descrittive che indichino dove appare la stringa

Le chiavi dovrebbero rendere ovvio dove e come viene usata una stringa. Questo è importante quando gestisci centinaia di stringhe su più file.

# Incorrect
btn1 = Submit
msg2 = Error

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

Non cambiare mai una chiave dopo che la traduzione è iniziata. Cambiare una chiave rende orfana la traduzione esistente.

2. Usa segnaposto numerati, non la concatenazione di stringhe nel codice

Scrivi la frase completa nel tuo file .properties e usa segnaposto numerati per i contenuti variabili invece di concatenare le stringhe nel codice.

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

Molte lingue cambiano l'ordine delle parole e le regole di concordanza, quindi dividere le frasi in frammenti rende impossibile una traduzione corretta.

3. Gestisci la pluralizzazione con ChoiceFormat, ICU o chiavi con suffisso

Per la pluralizzazione in Java standard, ChoiceFormat funziona direttamente all'interno di .properties:

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

Java elabora questo dato a runtime e restituisce la forma corretta in base al valore passato. ChoiceFormat è semplice ma limitato alla corrispondenza di intervalli numerici. Non gestisce in modo nativo regole di plurale complesse.

Per i plurali specifici della lingua (one/few/many/other del polacco, le sei forme dell'arabo), usa MessageFormat della libreria ICU4J:

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

Oppure codifica i plurali come chiavi separate con suffissi convenzionali in modo che PTC possa generare le categorie di plurale corrette per lingua:

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

PTC genera le categorie di plurale corrette per ogni lingua di destinazione. Il polacco ottiene one / few / many / other. Il giapponese ottiene solo other.

4. Esegui l'escape di =, :, # e \ con un backslash

Caratteri come =, :, # e \ hanno un significato speciale nei file .properties:

  • = o : separa le chiavi dai valori.
  • # o ! inizia un commento.
  • \ introduce le sequenze di escape (come \n per il ritorno a capo).

Esegui l'escape con un backslash dove necessario:

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

5. Salva i file .properties in UTF-8

Salva sempre i file .properties in UTF-8. Senza di esso, i caratteri non ASCII si corrompono e le traduzioni diventano illeggibili. Storicamente i file .properties di Java erano in ISO-8859-1 e richiedevano escape \uXXXX per i caratteri non ASCII. Java 9+ li legge come UTF-8 per impostazione predefinita, quindi controlla la tua versione di runtime prima di fare affidamento sul formato UTF-8 puro.

6. Tieni fuori dal codice tutto il testo visibile all'utente

Se una stringa è visibile agli utenti, deve trovarsi in un file .properties. Le stringhe hardcoded non verranno tradotte. La tua app finirà per mostrare un mix di lingue.

Formatta date, orari, numeri e valute con helper basati sul locale

Non tutto ciò che deve essere localizzato risiede in un file .properties. Date, orari, numeri e valori valutari vengono formattati nel codice a runtime e gestirli correttamente è importante tanto quanto le tue stringhe tradotte.

Date con 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"

Valute con 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 €"

Usa sempre formattatori basati sul locale. Non inserire mai come hardcoded "$", separatori delle migliaia "," o pattern "MM/DD/YYYY".

Integra ResourceBundle in Spring Boot con MessageSource

Spring Boot racchiude ResourceBundle in un bean MessageSource che si integra con le funzionalità di i18n del framework. Copre anche i messaggi di convalida, i template Thymeleaf e la risoluzione del locale delle richieste web.

Configura in application.properties:

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

Posiziona messages.properties, messages_es.properties, ecc. sotto src/main/resources/.

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

Configura il risolutore del locale per leggere dall'header Accept-Language o da un parametro 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);
    }
}

Ora GET /greeting?name=World&lang=es restituisce la versione spagnola.

Traduci i file .properties di Java con PTC in 5 passaggi

  1. Inizia un progetto PTC e scegli il tuo locale di origine (Inglese / messages.properties).
  2. Carica i tuoi file .properties e imposta i percorsi di output. PTC analizza la struttura chiave-valore, riconosce i segnaposto MessageFormat ({0}, {1}) e i pattern ChoiceFormat, e legge eventuali commenti # come contesto per il traduttore.
  3. Aggiungi una breve descrizione della tua applicazione Java e del pubblico. PTC la usa per tradurre con il tono e la terminologia corretti.
  4. Scegli le lingue di destinazione e conferma. La prova copre 20.000 parole in 2 lingue, nessuna carta di credito.
  5. Scarica i file .properties tradotti dalla scheda Files. Uno per lingua, con il suffisso corretto (messages_es.properties, messages_fr.properties). Strutturalmente identici all'origine: stesse chiavi, stessi segnaposto, valori tradotti.

Inseriscili in src/main/resources/, ricompila la build e ResourceBundle.getBundle("messages", locale) rileva automaticamente le nuove lingue. L'intera configurazione richiede circa 5 minuti.

Automatizza la traduzione di Java a ogni rilascio con Git o l'API di PTC

Tradurre una volta è semplice. Mantenere le traduzioni aggiornate man mano che la tua applicazione si evolve è più difficile. Ogni nuova stringa, ogni aggiornamento dei testi, ogni chiave rimossa deve propagarsi in ogni lingua. PTC offre due modi per automatizzare questo processo.

Integrazione Git. Collega il tuo repository GitHub, GitLab o Bitbucket a PTC. PTC monitora il tuo file .properties di origine per rilevare le modifiche. Quando una stringa viene aggiunta o aggiornata, PTC la traduce e restituisce i file aggiornati tramite un merge request.

Integrazione CI/CD. Se preferisci mantenere tutto all'interno del tuo processo di build esistente, l'API di PTC ti permette di caricare il tuo file di origine e recuperare le traduzioni come parte del tuo job CI.

Fai il commit di un .ptc-config.yml che indichi il tuo file di origine e dove devono essere posizionate le traduzioni:

# .ptc-config.yml
source_locale: en
files:
  - file: src/main/resources/messages.properties
    output: src/main/resources/messages_{{lang}}.properties

Quindi aggiungi l'azione PTC Translate al tuo workflow. Include al suo interno una versione fissata della CLI di PTC, in modo che la tua build non scarichi nulla in fase di esecuzione:

# .github/workflows/translate.yml
name: Translate
on:
  push:
    branches: [main]
    paths:
      - 'src/main/resources/messages.properties'
  workflow_dispatch: {}

jobs:
  translate:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
      - uses: OnTheGoSystems/ptc-action@v1
        with:
          api-token: ${{ secrets.PTC_API_TOKEN }}
          create-pr: true

PTC sincronizza le nuove stringhe di origine, traduce solo ciò che è cambiato e apre una PR con i file messages_es.properties, messages_fr.properties aggiornati, e così via. Per i progetti Maven e Gradle, funziona lo stesso flusso. A PTC non importa quale strumento di build utilizzi. Entrambi gli approcci fanno sì che l'aggiunta successiva di una nuova lingua sia una modifica di configurazione, non un nuovo processo manuale.

Revisione visiva della traduzione della tua app Java tradotta: rilascia senza QA manuale per lingua

Un file .properties tradotto è necessario ma non sufficiente. Che la tua app Java sia un servizio web Spring Boot che serve HTML, un'app desktop Swing o uno strumento CLI lato server, il risultato renderizzato potrebbe presentare problemi che nessuna revisione a livello di stringa può intercettare:

  • Un'etichetta in tedesco che va in overflow su un pulsante Swing.
  • Un messaggio di convalida in francese con la forma grammaticale errata.
  • Una stringa hardcoded in inglese al di fuori di messageSource.getMessage() che viene visualizzata non tradotta.

L'AI Visual QA di PTC copre entrambe le varianti di app Java:

  • Per Spring Boot o qualsiasi app Java basata sul web: installa l'estensione del browser di PTC e registra un percorso guidato delle pagine critiche della tua app. PTC lo riproduce in ogni lingua di destinazione dopo ogni aggiornamento della traduzione.
  • Per app desktop (Swing, JavaFX), server (CLI) o qualsiasi app Java non per browser: carica le schermate dell'app Java in esecuzione in ciascuna lingua di destinazione. L'IA visiva di PTC ispeziona ogni schermata.

I problemi che PTC può risolvere nei file .properties (verbo/sostantivo, overflow del layout, accezione errata) vengono corretti automaticamente. I problemi nel tuo codice Java (chiamata messageSource.getMessage() mancante, stringa hardcoded, concatenazione di frasi che dovrebbe usare MessageFormat) vengono restituiti come prompt pronti da incollare per Cursor o Claude Code.

Il risultato: un JAR multilingue verificato per ogni rilascio. Non solo file di proprietà tradotti.

Traduci note di rilascio, README ed email per i clienti

Le tue note di rilascio, i README sul tuo repository Maven interno o su GitHub, le email rivolte ai clienti, la documentazione di supporto e le pagine wiki interne risiedono al di fuori di .properties. Paste to Translate di PTC gestisce questi testi nello stesso progetto. Incolla il testo di origine nel pannello di controllo di PTC, scegli le lingue di destinazione e ottieni traduzioni che utilizzano lo stesso glossario e la stessa voce del brand delle tue stringhe in-app.

Traduci dati aziendali, ticket di supporto e contenuti del cliente con l'API di PTC

I dati aziendali, i ticket di supporto, le voci della knowledge base e i contenuti inviati dai clienti necessitano di traduzione non appena arrivano. L'API REST di PTC traduce questi contenuti su richiesta con autenticazione tramite token Bearer, utilizzando lo stesso glossario e la stessa voce del brand delle tue traduzioni in .properties.

PTC traduce la tua app Java E ne revisiona il risultato in esecuzione

Inizia la tua prova di 30 giorni: 20.000 parole in 2 lingue, nessuna carta di credito. Carica i tuoi file .properties, ottieni le versioni tradotte in pochi minuti, quindi carica le schermate (o installa l'estensione del browser per Spring Boot) e lascia che PTC verifichi l'app in esecuzione.

Correlati: