Говорим на всех языках: интернационализация Java-приложений

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему вашему Java-приложению пора заговорить по-человечески?

Вы когда-нибудь задумывались, почему приложения, которыми мы пользуемся каждый день — от Spotify до Notion — сразу «понимают», на каком языке с вами говорить? Они не читают мысли, не угадывают по IP-адресу. Они используют интернационализацию (i18n).

Для Java-разработчика умение делать приложения многоязычными — это не просто «фишка», а обязательный навык, если вы целитесь в глобальный рынок. Представьте: вы написали крутой сервис для управления задачами. В России он взлетел. Но как только вы захотите продать его в Германию или Японию — пользователи увидят кнопку «Создать задачу» на русском. И закроют вкладку. Грустно, правда?

В этой статье мы не просто поговорим о теории. Мы возьмём Java-приложение (самое обычное, консольное или веб) и шаг за шагом добавим в него поддержку русского, английского и немецкого языков. Вы увидите, что интернационализация Java — это не страшно, а очень даже элегантно. Поехали!

Что такое интернационализация и локализация? Не путайте!

Часто эти понятия смешивают. Давайте расставим точки над i.

  • Интернационализация (i18n) — это процесс проектирования приложения так, чтобы его можно было адаптировать под разные языки и регионы без изменения кода. Вы закладываете «крючки» для перевода.
  • Локализация (l10n) — это уже наполнение этих «крючков» конкретными переводами, форматами дат, валютами и правилами сортировки для конкретной страны.

В Java за интернационализацию отвечают классы из пакета java.util: Locale и ResourceBundle. Запомните их — это ваши лучшие друзья.

Шаг 1. Знакомство с Locale — сердцем интернационализации

Класс Locale представляет конкретный регион (язык + страна). Например:

  • Locale.US — английский (США)
  • Locale.GERMANY — немецкий (Германия)
  • new Locale("ru", "RU") — русский (Россия)

Locale используется для выбора правильного перевода строк, форматирования чисел, дат, валют. Без него интернационализация невозможна.

Как получить текущую локаль?

import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        // Локаль по умолчанию (обычно совпадает с системной)
        Locale defaultLocale = Locale.getDefault();
        System.out.println("Текущая локаль: " + defaultLocale);

        // Доступные локали в JVM
        Locale[] available = Locale.getAvailableLocales();
        System.out.println("Всего доступно: " + available.length);
    }
}

Вывод может быть, например: Текущая локаль: ru_RU. Но мы не будем полагаться на системную локаль — в веб-приложении её обычно передаёт браузер пользователя.

Шаг 2. ResourceBundle — ваш переводчик

Теперь самое интересное: как хранить переводы? В Java для этого используются файлы свойств (.properties). Каждый файл — это набор пар ключ=значение.

Создаём файлы переводов

Создайте в директории src/main/resources (или просто в папке с исходниками) три файла:

1. Messages.properties (язык по умолчанию — английский)

greeting=Hello, {0}!
farewell=Goodbye!
app.title=Task Manager

2. Messages_ru_RU.properties (русский)

greeting=Привет, {0}!
farewell=До свидания!
app.title=Менеджер задач

3. Messages_de_DE.properties (немецкий)

greeting=Hallo, {0}!
farewell=Auf Wiedersehen!
app.title=Aufgabenverwaltung

Обратите внимание на суффиксы: _ru_RU, _de_DE. Java ищет файл по шаблону: БазовоеИмя_язык_СТРАНА.properties. Если точного совпадения нет — берётся файл без суффикса (базовый).

Загружаем перевод в коде

import java.util.Locale;
import java.util.ResourceBundle;

public class I18nExample {
    public static void main(String[] args) {
        // Допустим, пользователь из Германии
        Locale germanLocale = Locale.GERMANY;
        ResourceBundle bundle = ResourceBundle.getBundle("Messages", germanLocale);

        // Извлекаем строки
        String greeting = bundle.getString("greeting");
        String formattedGreeting = java.text.MessageFormat.format(greeting, "Max");
        System.out.println(formattedGreeting); // "Hallo, Max!"

        System.out.println(bundle.getString("app.title")); // "Aufgabenverwaltung"
    }
}

Вуаля! Приложение «заговорило» по-немецки без единой правки кода. Только поменяли файл свойств.

Шаг 3. Форматирование: даты, числа и валюты

Перевести слова — полдела. Но что делать с датами? В США пишут 12/31/2023, в Германии — 31.12.2023, а в России — 31.12.2023 (но с другим названием месяца). Java решает это элегантно через классы форматтеры.

Форматирование дат

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class DateFormatExample {
    public static void main(String[] args) {
        Date now = new Date();

        // Для США
        DateFormat usFormat = DateFormat.getDateInstance(DateFormat.LONG, Locale.US);
        System.out.println("US: " + usFormat.format(now)); // "December 31, 2023"

        // Для Германии
        DateFormat deFormat = DateFormat.getDateInstance(DateFormat.LONG, Locale.GERMANY);
        System.out.println("DE: " + deFormat.format(now)); // "31. Dezember 2023"

        // Для России
        DateFormat ruFormat = DateFormat.getDateInstance(DateFormat.LONG, new Locale("ru", "RU"));
        System.out.println("RU: " + ruFormat.format(now)); // "31 декабря 2023 г."
    }
}

Обратите внимание: названия месяцев и дней недели автоматически берутся из локали JVM. Если у вас Java 8+, рекомендую использовать java.time.format.DateTimeFormatter — он ещё гибче.

Форматирование чисел и валют

import java.text.NumberFormat;
import java.util.Locale;

public class NumberFormatExample {
    public static void main(String[] args) {
        double price = 12345.67;

        NumberFormat usFormat = NumberFormat.getCurrencyInstance(Locale.US);
        System.out.println("US: " + usFormat.format(price)); // "$12,345.67                

Блоги

Рекомендаций по книгам