PTC

Guía de internacionalización de Java: traduzca archivos .properties con IA

Configure ResourceBundle, estructure los archivos .properties, traduzca a más de 40 idiomas con IA y, a continuación, haga que PTC (Private Translation Cloud) revise la aplicación Java en ejecución mediante capturas de pantalla o una extensión de navegador. Al final tendrá un JAR multilingüe listo para publicar, con cada idioma de destino verificado antes del lanzamiento. Para una visión general del servicio Java independiente, consulte traducir aplicaciones Java con IA.

ResourceBundle carga el archivo .properties correcto en tiempo de ejecución

El sistema de i18n de Java se construye en torno a dos cosas. Los archivos .properties que almacenan sus cadenas traducidas, y la clase ResourceBundle que carga el archivo correcto en tiempo de ejecución según la configuración regional del usuario.

Cuando su aplicación se ejecuta, ResourceBundle comprueba la configuración regional del usuario y carga el archivo correspondiente automáticamente. Si falta una traducción, recurre silenciosamente al archivo predeterminado. Nada se rompe, pero las traducciones que faltan tampoco aparecen como errores. Llamar a una cadena en el código:

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

Ese es todo el mecanismo. El resto del trabajo de localización ocurre en los propios archivos .properties, razón por la cual estructurarlos correctamente es importante.

Configure su resource bundle con messages_{locale}.properties

Un resource bundle es un conjunto de archivos .properties que comparten un nombre base común. El nombre base es la parte del nombre del archivo anterior al sufijo de configuración regional. Es lo que ResourceBundle.getBundle() utiliza para encontrar el archivo correcto en tiempo de ejecución.

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)

Las aplicaciones más grandes a menudo utilizan varios resource bundles para mantener todo organizado:

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

Java espera un patrón de nomenclatura específico. basename_language.properties o basename_language_COUNTRY.properties para variantes regionales:

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

Los códigos de idioma siguen ISO 639-1. Los códigos de país siguen ISO 3166-1. Usar el formato incorrecto significa que ResourceBundle no encontrará el archivo en tiempo de ejecución.

Cargue y use el bundle en el código, con MessageFormat para la sustitución de marcadores de posición:

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

Para cadenas simples sin marcadores de posición, messages.getString("key") es suficiente.

Seis convenciones que hacen que sus archivos .properties estén listos para traducir

Cada línea es un par clave-valor separado por =. La forma en que escribe su archivo de origen afecta directamente a la calidad de sus traducciones. Tanto si traduce manualmente como con una herramienta de IA como PTC.

1. Use claves claras y descriptivas que indiquen dónde aparece la cadena

Las claves deben dejar claro dónde y cómo se utiliza una cadena. Esto es importante cuando gestiona cientos de cadenas en varios archivos.

# Incorrect
btn1 = Submit
msg2 = Error

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

Nunca cambie una clave después de que haya comenzado la traducción. Cambiar una clave deja huérfana la traducción existente.

2. Use marcadores de posición numerados, no concatenación de cadenas en el código

Escriba la oración completa en su archivo .properties y use marcadores de posición numerados para el contenido variable en lugar de concatenar cadenas en el código.

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

Muchos idiomas cambian el orden de las palabras y las reglas de concordancia, por lo que dividir las oraciones en fragmentos hace imposible una traducción correcta.

3. Gestione la pluralización con ChoiceFormat, ICU o claves con sufijo

Para la pluralización en Java estándar, ChoiceFormat funciona directamente dentro de .properties:

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

Java procesa esto en tiempo de ejecución y devuelve la forma correcta según el valor pasado. ChoiceFormat es simple pero se limita a la coincidencia de rangos numéricos. No gestiona de forma nativa reglas de plural complejas.

Para plurales que tienen en cuenta el idioma (el one/few/many/other del polaco, las seis formas del árabe), use el MessageFormat de ICU4J:

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

O codifique los plurales como claves separadas con sufijos convencionales para que PTC pueda generar las categorías de plural correctas por idioma:

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

PTC genera las categorías de plural correctas por idioma de destino. El polaco obtiene one / few / many / other. El japonés obtiene solo other.

4. Escape =, :, # y \ con una barra invertida

Caracteres como =, :, # y \ tienen un significado especial en los archivos .properties:

  • = o : separa las claves de los valores.
  • # o ! inicia un comentario.
  • \ introduce secuencias de escape (como \n para un salto de línea).

Use el escape con una barra invertida cuando sea necesario:

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

5. Guarde los archivos .properties como UTF-8

Guarde siempre los archivos .properties en UTF-8. Sin ello, los caracteres no ASCII se corrompen y las traducciones se vuelven ilegibles. Históricamente, los archivos .properties de Java eran ISO-8859-1 y requerían escapes \uXXXX para los caracteres no ASCII. Java 9+ los lee como UTF-8 de forma predeterminada, así que compruebe la versión de su entorno de ejecución antes de confiar en UTF-8 sin procesar.

6. Mantenga todo el texto visible para el usuario fuera del código

Si una cadena es visible para los usuarios, pertenece a un archivo .properties. Las cadenas codificadas de forma fija no se traducirán. Su aplicación acabará mostrando una mezcla de idiomas.

Formatee fechas, horas, números y moneda con ayudantes que tienen en cuenta la configuración regional

No todo lo que necesita localizarse vive en un archivo .properties. Las fechas, las horas, los números y los valores de moneda se formatean en el código en tiempo de ejecución, y hacerlo bien importa tanto como sus cadenas traducidas.

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

Moneda 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 EUR"

Use siempre formateadores que tengan en cuenta la configuración regional. Nunca codifique de forma fija "$", separadores de miles "," ni patrones "MM/DD/YYYY".

Integre ResourceBundle en Spring Boot con MessageSource

Spring Boot envuelve ResourceBundle en un bean MessageSource que se integra con las funciones de i18n del framework. Mensajes de validación, plantillas Thymeleaf, resolución de la configuración regional de las solicitudes web.

Configure en application.properties:

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

Coloque messages.properties, messages_es.properties, etc. bajo src/main/resources/.

Use en un controlador:

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

Configure el resolver de la configuración regional para que lea desde el encabezado Accept-Language o un parámetro de 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);
    }
}

Ahora GET /greeting?name=World&lang=es devuelve la versión en español.

Traduzca archivos .properties de Java con PTC en 5 pasos

  1. Inicie un proyecto de PTC y elija su configuración regional de origen (inglés / messages.properties).
  2. Cargue su(s) archivo(s) .properties y establezca las rutas de salida. PTC analiza la estructura clave-valor, reconoce los marcadores de posición de MessageFormat ({0}, {1}) y los patrones de ChoiceFormat, y lee cualquier comentario # como contexto para el traductor.
  3. Añada una breve descripción de su aplicación Java y su público. PTC la utiliza para traducir con el tono y la terminología correctos.
  4. Elija los idiomas de destino y confirme. La prueba gratuita cubre 20.000 palabras a 2 idiomas, sin tarjeta de crédito.
  5. Descargue los archivos .properties traducidos desde la pestaña Archivos de recursos. Uno por idioma, con el sufijo correcto (messages_es.properties, messages_fr.properties). Estructuralmente idénticos al origen: mismas claves, mismos marcadores de posición, valores traducidos.

Colóquelos en src/main/resources/, vuelva a compilar, y ResourceBundle.getBundle("messages", locale) adopta los nuevos idiomas automáticamente. Toda la configuración lleva unos 5 minutos.

Automatice la traducción de Java en cada lanzamiento con Git o la API de PTC

Traducir una vez es sencillo. Mantener las traducciones actualizadas a medida que su aplicación evoluciona es más difícil. Cada nueva cadena, cada actualización de texto, cada clave eliminada debe fluir hasta cada idioma. PTC ofrece dos maneras de automatizarlo.

Integración con Git. Conecte su repositorio de GitHub, GitLab o Bitbucket a PTC. PTC supervisa los cambios en su archivo .properties de origen. Cuando se añade o actualiza una cadena, PTC la traduce y entrega los archivos actualizados de vuelta mediante un pull request.

Integración con CI/CD. Si prefiere mantener todo dentro de su proceso de compilación existente, la API de PTC le permite cargar su archivo de origen y recuperar las traducciones como parte de su trabajo de 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: Trigger PTC translation
        run: |
          curl -X POST https://api.ptc.wpml.org/v1/projects/${{ secrets.PTC_PROJECT_ID }}/sync \
            -H "Authorization: Bearer ${{ secrets.PTC_API_KEY }}"

PTC sincroniza las nuevas cadenas de origen, traduce solo lo que ha cambiado y abre un PR con los archivos messages_es.properties, messages_fr.properties actualizados, y así sucesivamente. Para proyectos de Maven y Gradle, funciona el mismo flujo. A PTC no le importa su herramienta de compilación. Ambos enfoques significan que añadir un nuevo idioma más adelante es un cambio de configuración, no un nuevo proceso manual.

Revisión visual de la traducción de su aplicación Java traducida - publique sin QA manual por idioma

Un archivo .properties traducido es necesario pero no suficiente. Ya sea que su aplicación Java sea un servicio web de Spring Boot que sirve HTML, una aplicación Swing de escritorio o una herramienta CLI del lado del servidor, la salida renderizada puede tener problemas que ninguna revisión a nivel de cadena puede detectar:

  • Una etiqueta en alemán que se desborda de un botón Swing.
  • Un mensaje de validación en francés con la forma gramatical incorrecta.
  • Una cadena en inglés codificada de forma fija fuera de messageSource.getMessage() que se muestra sin traducir.

La revisión visual con IA de PTC cubre ambas variantes de aplicación Java:

  • Para Spring Boot o cualquier aplicación Java basada en web: instale la extensión de navegador de PTC y grabe un recorrido por las páginas críticas de su aplicación. PTC lo reproduce en cada idioma de destino después de cada actualización de traducción.
  • Para escritorio (Swing, JavaFX), servidor (CLI) o cualquier aplicación Java no basada en navegador: cargue capturas de pantalla de la aplicación Java en ejecución en cada idioma de destino. La IA de visión de PTC inspecciona cada pantalla.

Los problemas que PTC puede corregir en los archivos .properties (verbo/sustantivo, desbordamiento del diseño, sentido incorrecto) se corrigen automáticamente. Los problemas en su código Java (llamada messageSource.getMessage() ausente, cadena codificada de forma fija, concatenación de oraciones que debería usar MessageFormat) regresan como prompts listos para pegar en Cursor o Claude Code.

El resultado: un JAR multilingüe verificado por lanzamiento. No solo archivos de propiedades traducidos.

Traduzca notas de lanzamiento, READMEs y correos electrónicos a clientes

Sus notas de lanzamiento, los READMEs en su repositorio Maven interno o en GitHub, los correos electrónicos dirigidos a clientes, la documentación de soporte y las páginas wiki internas viven fuera de .properties. La función Pegar para traducir de PTC gestiona ese texto en el mismo proyecto. Pegue el texto de origen en el panel de PTC, elija los idiomas de destino y obtenga traducciones que usan el mismo glosario y la misma voz de marca que sus cadenas dentro de la aplicación.

Traduzca datos empresariales, tickets de soporte y contenido de clientes con la API de PTC

Los datos empresariales, los tickets de soporte, las entradas de la base de conocimientos y el contenido enviado por los clientes necesitan traducción a medida que llegan. La API REST de PTC traduce este contenido bajo demanda con autenticación mediante token Bearer, usando el mismo glosario y la misma voz de marca que sus traducciones de .properties.

Traduzca Y revise su aplicación Java

Comience su prueba gratuita de 30 días - 20.000 palabras a 2 idiomas, sin tarjeta de crédito. Cargue sus archivos .properties, obtenga versiones traducidas en minutos, luego cargue capturas de pantalla (o instale la extensión de navegador para Spring Boot) y deje que PTC verifique la aplicación en ejecución.

Relacionado: