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\nper 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
- Inizia un progetto PTC e scegli il tuo locale di origine (Inglese /
messages.properties). - Carica i tuoi file
.propertiese imposta i percorsi di output. PTC analizza la struttura chiave-valore, riconosce i segnapostoMessageFormat({0},{1}) e i patternChoiceFormat, e legge eventuali commenti#come contesto per il traduttore. - Aggiungi una breve descrizione della tua applicazione Java e del pubblico. PTC la usa per tradurre con il tono e la terminologia corretti.
- Scegli le lingue di destinazione e conferma. La prova copre 20.000 parole in 2 lingue, nessuna carta di credito.
- Scarica i file
.propertiestradotti 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:
- Tradurre app Java con l'IA: panoramica del servizio per i team Java.
- Riferimento API di PTC: endpoint REST per l'integrazione CI.
- Localizzazione software con IA creata per le pipeline CI/CD: panoramica del servizio per i team di ingegneria.