Урок 14

Интернационализация


1. Что такое интернационализация и локализация приложений

Интернационализация (i18n) - это процесс разработки приложения такой структуры, при которой дополнение нового языка не требует перестройки и перекомпиляции (сборки) всего приложения. Достигается это за счет отдельного хранения данных интернационализации в виде файлов свойств, загружаемых приложением динамически в процессе работы.

Локализация (l10n) – это адаптация приложения к конкретному языку и региону путем перевода выводимых пользователю текстовых элементов и документации, а также определения данных времени, валют и др., согласно специфике данного региона.

2. Класс Locale

Класс java.util.Locale позволяет учесть особенности региональных представлений алфавита, символов, чисел, дат и проч. Автоматически виртуальная машина использует текущие региональные установки операционной системы, но при необходимости их можно изменять.

Для некоторых стран региональные параметры устанавливаются с помощью констант, например: Locale.US, Locale.FRANCE.

Для всех остальных объект Locale нужно создавать с помощью конструктора, например: Locale rus = new Locale("ru", "RU");

Определить текущий вариант региональных параметров можно следующим образом: Locale current = Locale.getDefault();

А можно и изменить для текущего экземпляра (instance) JVM: Locale.setDefault(Locale.CANADA)

Пример 1. Использования класса Locale

import java.util.Locale;

public class LocaleDemo1 {
    public static void main(String[] args) {
        Locale fr = Locale.FRANCE;
        Locale us = Locale.US;
        Locale rus = new Locale("ru", "RU");

        Locale current = Locale.getDefault();
        getLocaleInfo(current);

        Locale.setDefault(Locale.CANADA);
        current = Locale.getDefault();
        getLocaleInfo(current);

        Locale.setDefault(new Locale("uk", "UA"));
        current = Locale.getDefault();
        getLocaleInfo(current);
    }

    public static void getLocaleInfo(Locale current) {
        System.out.println("Код региона: " + current.getCountry());
        System.out.println("Название региона: " + current.getDisplayCountry());
        System.out.println("Код языка региона: " + current.getLanguage());
        System.out.println("Название языка региона: " + current.getDisplayLanguage());
        System.out.println();
    }
}

3. Класс ResourceBundle

В файлах свойств информация должна быть организована по принципу:

#Комментарий
group1.key1 = value1
group1.key2 = value2
group2.key1 = value3…

Например:

label.button = submit
label.field = login
message.welcome = Welcome!

или

label.button = принять
label.field = логин
message.welcome = Добро пожаловать!

Класс ResourceBundle предназначен для взаимодействия с текстовыми файлами свойств (расширение - properties). Каждый объект ResourceBundle представляет собой набор соответствующих подтипов, которые разделяют одно и то же базовое имя.

Следующий список показывает возможный набор соответствующих ресурсов с базовым именем:
text.properties
text_ru_RU.properties
text_it_CH.properties
text_fr_CA.properties

Чтобы выбрать определенный объект ResourceBundle, следует вызвать один из статических перегруженных методов getBundle(параметры).

Следующий фрагмент выбирает text объекта ResourceBundle для объекта Locale, который соответствует французскому языку и стране Канада:

Locale locale = new Locale("fr", "CA");
ResourceBundle rb = ResourceBundle.getBundle("text", locale);

Если объект ResourceBundle для заданного объекта Locale не существует, то метод getBundle() извлечет наиболее общий.

Если общее определение файла ресурсов не задано, то метод getBundle() генерирует исключительную ситуацию MissingResourceException. Чтобы это не произошло, необходимо обеспечить наличие базового файла ресурсов без суффиксов, а именно: text.properties в дополнение к частным случаям вида: 
text_en_US.properties
text_ru_RU.properties.

Пусть базовое имя ресурса baseName, и ресурс нам нужен для language1, country1. Locale по умолчанию определена через language2, country2. Мы вызываем ResourceBundle.getBundle(baseName, locale1). В каком порядке будет организован поиск в properties файлах?Формируется следующий список строк (т.н. кандидаты в имена пакетов):

  1. baseName + "_"+ language1 + "_" + country1
  2. baseName + "_"+ language1
  3. baseName + "_"+ language2 + "_" + country2
  4. baseName + "_"+ language2
  5. baseName

Пример 2. Использования класса ResourceBundle

import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;

public class ResourceBundleDemo1 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        printInfo("", "");
        printInfo("en", "US");
        printInfo("uk", "UA");
    }

    private static void printInfo(String language, String country) throws UnsupportedEncodingException {
        Locale current = new Locale(language, country);
        ResourceBundle rb = ResourceBundle.getBundle("text", current);
        String s1 = rb.getString("str1");
        s1 = new String(s1.getBytes("ISO-8859-1"), "UTF-8");

        System.out.println(s1);
        String s2 = rb.getString("str2");
        s2 = new String(s2.getBytes("ISO-8859-1"), "UTF-8");
        System.out.println(s2);
        System.out.println();
    }
}

В классе ResourceBundle определен ряд полезных методов:

  1. getKeys() - возвращает объект Enumeration, который применяется для последовательного обращения к элементам.
  2. keySet() – возвращает множество Set всех ключей.
  3. getString(String key) - извлекается конкретное значение по конкретному ключу.
  4. boolean containsKey(String key) - проверить наличие ключа в файле.

Пример 3. Использования класса ResourceBundle

import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;

public class ResourceBundleDemo2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        printInfo("", "");

        printInfo("en", "US");
        printInfo("uk", "UA");
    }

    private static void printInfo(String language, String country) throws UnsupportedEncodingException {
        Locale current = new Locale(language, country);
        ResourceBundle rb = ResourceBundle.getBundle("text", current);
        for (String key : rb.keySet()) {
            String value = rb.getString(key);
            value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
            System.out.println(value);
        }
        System.out.println();
    }
}


0 comments
Leave your comment: