How to Internationalize and Localize Java Applications

Learn how to set up Java internationalization, translate .properties files, and automate your Java localization workflow.

How Java Internationalization Works

Java’s i18n system is built around two things: 

  • .properties files that store your translated strings
  • The ResourceBundle class that loads the right file at runtime based on the user’s locale

When your app runs, ResourceBundle checks the user’s locale and loads the matching file automatically. If a translation is missing, it falls back to the default file so nothing breaks.

Calling a string in code is straightforward:

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

That’s the whole mechanism. The rest of localization work happens in the .properties files themselves, which is why structuring them correctly matters.

Setting Up Your Resource Bundle

A resource bundle is a set of .properties files that share a common base name. The base name is the part of the filename before the locale suffix, and it’s what ResourceBundle.getBundle() uses to find the right file at runtime.

messages.properties         # default (usually English)
messages_fr.properties      # French
messages_de.properties      # German
messages_es.properties      # Spanish

Here, messages is the base name. You can name it anything, but it should reflect what the file contains. Larger applications often use multiple resource bundles to keep things organized:

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

Java expects a specific naming pattern: basename_language.properties or basename_language_COUNTRY.properties for regional variants.

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

Language codes follow ISO 639-1 and country codes follow ISO 3166-1. Using the wrong format means ResourceBundle won’t find the file at runtime.

Structuring Java .properties Files

Each line in a .properties file is a key-value pair separated by =.

welcome.message = Welcome to our application
error.login.invalid_credentials = Invalid username or password
form.submit.button = Submit

Besides using key-value pairs, it’s important to know that how you write your source file directly affects the quality of your translations. Certain best practices always apply, no matter if you’re translating manually or using an AI translation tool like PTC.

1

Use Clear, Descriptive Keys

Keys should make it obvious where and how a string is used. This matters when you’re managing hundreds of strings across multiple files.

Incorrect usage of keys:

btn1 = Submit 
msg2 = Error

Correct usage of keys:

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

2

Use Placeholders for Dynamic Content

Write the full sentence in your .properties file and use numbered placeholders for variable content instead of concatenating strings in code.

Incorrect (in code):

"Hello, " + username + "! You have " + count + " new messages." 

Correct  (in .properties file):

dashboard.greeting = Hello, {0}! You have {1} new messages.

Many languages change word order and agreement rules, so splitting sentences into fragments makes correct translation impossible.

3

Handle Pluralization with ChoiceFormat

Some strings change depending on a numeric value. Instead of writing separate keys for singular and plural, use a ChoiceFormat pattern directly in your .properties file:

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

Java processes this pattern at runtime and returns the right form based on the value passed in.

4

Escape Special Characters

Characters like =, :, #, and \ have special meaning in .properties files:

  • = or :separates keys from values
  • # or ! starts a comment
  • \ introduces escape sequences (like \n for newline)

If you need to use these characters in a string, escape them with a backslash.

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

5

Save Files in UTF-8

Always save .properties files in UTF-8. Without it, non-ASCII characters become corrupted and translations become unreadable.

6

Keep All User-facing Text Out of Your Code

If a string is visible to users, it belongs in a .properties file. Hardcoded strings won’t get translated, and your app will end up showing a mix of languages.

Other Java Localization Considerations

Not everything that needs localizing lives in a .properties file. Dates, times, numbers, and currency values are formatted in code at runtime, and getting them right matters just as much as your translated strings.

Java provides built-in classes for this:

  • DateTimeFormatter for locale-aware date and time formatting
  • NumberFormat for numbers, percentages, and currency values

Since this guide focuses on .properties files and their translation, we won’t cover these in depth here. The official Java documentation for DateTimeFormatter and NumberFormat is a good place to start.

Translating Java .properties Files

Once your source file is ready, you have a few options for getting it translated. The right choice depends on your budget, timeline, and how much automation you need.

OptionTurnaroundCostMaintenance Needs
Professional translatorsDays to weeksHighManual export, send, receive, and re-integrate every update
Translation scriptsMinutesLowRequires review – placeholders can break, context for translations may be wrong
AI translation (like PTC)MinutesLowContext-aware translations sync automatically via Git or CI/CD

With PTC, human-quality translations are ready in minutes, and there’s no subscription — you only pay for what you translate. To get started, you get 20,000 words translated into two languages for free, no credit card required.

After signing up, a setup wizard walks you through the basics: a brief description of your application, your target languages, and your .properties file. The whole process takes about 5 minutes. For a full walkthrough, check out our getting started guide.

After PTC finishes translating, go to the Resource Files tab and download a ZIP file with the translated .properties files. 

Add these files back into your project’s src/main/resources folder, alongside your original source file. At runtime, ResourceBundle automatically picks the correct file based on the user’s locale. You don’t need to change your code.

Keeping Java .properties Translations in Sync

Translating your .properties file once is straightforward. What about keeping translations up to date as your application evolves? Every time you add a new string, update existing copy, or remove a key, your translated files need to reflect that change.

Doing this manually means exporting files, sending them out for translation, waiting, and re-integrating them every time, which is why most teams eventually automate it.

PTC offers two ways to automate the translation process:

Git Integration

Connect your GitHub, GitLab, or Bitbucket repository to PTC and it will monitor your source .properties file for changes. When a string is added or updated, PTC automatically translates it and delivers the updated translation files back via a pull request. Your translations stay in sync without any manual steps.

CI/CD Integration

If you prefer to keep everything inside your existing build process, PTC’s API lets you upload your source file and retrieve translations as part of your CI job. Every build produces up-to-date translations automatically.

Both approaches mean that adding a new language later is just a configuration change, not a new manual process.

Ready to Localize Your Java App?

Your .properties files are the foundation of your Java localization workflow. Get the structure right, keep your translations in sync, and your app can support new languages without slowing down your release cycle.

If you haven’t tried PTC yet, the free trial is a good place to start. 20,000 words, two languages, no credit card required.

Scroll to Top