Почему вашему 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