Форум программистов, компьютерный форум, киберфорум
Java: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/34: Рейтинг темы: голосов - 34, средняя оценка - 4.82
 Аватар для KillJoy
58 / 58 / 29
Регистрация: 21.09.2009
Сообщений: 313
Записей в блоге: 1

Локализация приложения

03.12.2012, 11:59. Показов 7140. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день. Помогите разобраться со следующими вопросами:
Вот есть некое Swing приложение, поддерживающее два языка. Есть кнопка переключения между языками. Вопрос- как при нажатии кнопки изменить язык интерфейса (надписи на кнопках, метках и т.д). Вопрос не в том, как локализовать приложение, а в том, как переключиться между языками в работающем приложении.

И вот еще- есть, например, JSpinner и JComboBox<Double>. Как "заставить" их отображать числа согласно текущей локали?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
03.12.2012, 11:59
Ответы с готовыми решениями:

Локализация приложения
Здравствуйте, помогите учащимся!) хочу реализовать адекватное переключение языков в приложении. покачто сделал так: public ...

Локализация приложения
Помогите с локализацией. Приложение из нескольких фреймов. Хотела сделать меню чтобы можно было выбирать языки. Сделала для первого...

Zh_CN локализация
имется проблемка с локализацией для китайского. ситуация следующая во втором случае отображается корректно при создании простого...

3
 Аватар для Skipy
2000 / 1427 / 92
Регистрация: 25.11.2010
Сообщений: 3,611
03.12.2012, 16:29
Цитата Сообщение от KillJoy Посмотреть сообщение
Вот есть некое Swing приложение, поддерживающее два языка. Есть кнопка переключения между языками. Вопрос- как при нажатии кнопки изменить язык интерфейса (надписи на кнопках, метках и т.д). Вопрос не в том, как локализовать приложение, а в том, как переключиться между языками в работающем приложении.
Ну... Вариантов два. Или полностью пересоздавать интерфейс на нужном языке, или написать фреймворк (унаследоваться от нужных компонент, написать процедуру перебора или что-нибудь еще в этом роде), который умеет работать с локализацией, тогда каждую компоненту, требующую перерисовки, уведомлять, что произошла смена локали.

Добавлено через 3 часа 29 минут
Навскидку можно так сделать:

langs.properties (лежит рядом с MainFrame)
Code
1
2
langs=en,ru
lang.default=en
Локализация (все файлы лежат тоже рядом с MainFrame):

main.properties
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
menu.file=File
menu.language=Language
menu.help=Help
 
menu.file.exit=Exit
menu.help.about=About
 
lbl.firstName=First name
lbl.lastName=Last name
btn.ok=OK
btn.cancel=Cancel
 
menu.en.desc=English
menu.ru.desc=Russian
 
title=Localization change test
main_en.properties существует, но пустой

main_ru.properties
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
menu.file=Файл
menu.language=Язык
menu.help=Помощь
 
menu.file.exit=Выход
menu.help.about=О программе
 
lbl.firstName=Имя
lbl.lastName=Фамилия
btn.ok=Ок
btn.cancel=Отмена
 
menu.en.desc=Английский
menu.ru.desc=Русский
 
title=Тестирование изменения локализации
Машина локализации:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package ru.skipy.tests.uiloc;
 
import javax.swing.*;
import java.awt.*;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
 
/**
 * L10nEngine
 *
 * @author Eugene Matyushkin aka Skipy
 * @since 03.12.12
 */
public class L10nEngine {
 
    public static final String LOCALIZATION_KEY = "l10nKey";
 
    private String resourceBundleName;
    private ResourceBundle bundle;
 
    static Map<Class, ComponentHandler> handlers = new HashMap<>();
 
    static {
        new ComponentHandler(JLabel.class) {
            @Override
            public void apply(JComponent c, String value) {
                ((JLabel) c).setText(value);
            }
        };
        new ComponentHandler(JButton.class) {
            @Override
            public void apply(JComponent c, String value) {
                ((JButton) c).setText(value);
            }
        };
        new ComponentHandler(JMenu.class) {
            @Override
            public void apply(JComponent c, String value) {
                ((JMenu) c).setText(value);
            }
        };
        new ComponentHandler(JMenuItem.class) {
            @Override
            public void apply(JComponent c, String value) {
                ((JMenuItem) c).setText(value);
            }
        };
        new ComponentHandler(JRadioButtonMenuItem.class) {
            @Override
            public void apply(JComponent c, String value) {
                ((JRadioButtonMenuItem) c).setText(value);
            }
        };
    }
 
    public L10nEngine(String resourceBundleName) {
        this.resourceBundleName = resourceBundleName;
    }
 
    public void setLocale(String newLocale) {
        bundle = ResourceBundle.getBundle(resourceBundleName, new Locale(newLocale));
    }
 
    public void changeLocale(Container topLevelContainer) {
        processContainer(topLevelContainer);
    }
 
    public void changeLocale(JMenuBar menuBar) {
        for (Component c : menuBar.getComponents()) {
            if (c instanceof JMenu) {
                processMenuItem((JMenu) c);
            } else if (c instanceof JComponent) {
                processJComponent((JComponent) c);
            }
        }
    }
 
    private void processMenuItem(JMenuItem mi) {
        Object cp = mi.getClientProperty(LOCALIZATION_KEY);
        if (cp != null) {
            applyLocale(mi, (String) cp);
        }
        if (mi instanceof JMenu) {
            JMenu m = (JMenu) mi;
            for (int i = 0; i < m.getItemCount(); i++) {
                processMenuItem(m.getItem(i));
            }
        }
    }
 
    private void processContainer(Container container) {
        for (Component c : container.getComponents()) {
            if (c instanceof Container) {
                processContainer((Container) c);
                if (c instanceof JComponent) {
                    processJComponent((JComponent) c);
                }
            }
        }
    }
 
    private void processJComponent(JComponent jc) {
        Object cp = jc.getClientProperty(LOCALIZATION_KEY);
        if (cp != null) {
            applyLocale(jc, (String) cp);
        }
    }
 
    private void applyLocale(JComponent c, String key) {
        ComponentHandler ch = handlers.get(c.getClass());
        if (ch == null) {
            return;
        }
        ch.apply(c, bundle.getString(key));
    }
 
    public String getStringResource(String key) {
        return bundle.getString(key);
    }
 
 
    abstract static class ComponentHandler {
 
        private ComponentHandler(Class cls) {
            handlers.put(cls, this);
        }
 
        public abstract void apply(JComponent c, String value);
    }
}
Ну и использование:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package ru.skipy.tests.uiloc;
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.*;
 
/**
 * MainFrame
 *
 * @author Eugene Matyushkin aka Skipy
 * @since 03.12.12
 */
public class MainFrame extends JFrame {
 
    private static final String RB_NAME = "ru.skipy.tests.uiloc.main";
    private static final String TITLE_KEY = "title";
 
    private static final String PROP_LANGS = "langs";
    private static final String PROP_LANGS_DEFAULT = "lang.default";
 
    L10nEngine l10nEngine = new L10nEngine(RB_NAME);
 
    public MainFrame() {
        super();
        Properties props = new Properties();
        try {
            props.load(getClass().getResourceAsStream("langs.properties"));
        } catch (IOException ex) {
            System.err.println("Error while loading language properties: " + ex.getMessage());
        }
        String langsProp = props.getProperty(PROP_LANGS);
        String defaultLang = props.getProperty(PROP_LANGS_DEFAULT);
        Set<String> langSet = new TreeSet<>(Arrays.asList(langsProp.split(",")));
 
        createMenuBar(langSet, defaultLang);
 
        JPanel cp = new JPanel(new GridBagLayout());
        JLabel lblFirstName = new JLabel();
        lblFirstName.putClientProperty(L10nEngine.LOCALIZATION_KEY, "lbl.firstName");
        JLabel lblLastName = new JLabel();
        lblLastName.putClientProperty(L10nEngine.LOCALIZATION_KEY, "lbl.lastName");
 
        JButton btnOk = new JButton();
        btnOk.putClientProperty(L10nEngine.LOCALIZATION_KEY, "btn.ok");
        JButton btnCancel = new JButton();
        btnCancel.putClientProperty(L10nEngine.LOCALIZATION_KEY, "btn.cancel");
 
        cp.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        cp.add(lblFirstName, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.LINE_START,
                GridBagConstraints.BOTH, new Insets(0, 0, 5, 5), 0, 0));
 
        cp.add(new JTextField(30), new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.LINE_START,
                GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
 
        cp.add(lblLastName, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.LINE_START,
                GridBagConstraints.BOTH, new Insets(0, 0, 5, 5), 0, 0));
 
        cp.add(new JTextField(30), new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.LINE_START,
                GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
 
        JPanel btnPanel = new JPanel(new GridBagLayout());
        btnPanel.add(btnOk, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.LINE_END,
                GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
        btnPanel.add(btnCancel, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.LINE_END,
                GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
 
        cp.add(btnPanel, new GridBagConstraints(0, 2, 2, 1, 1, 0, GridBagConstraints.CENTER,
                GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
 
        setContentPane(cp);
 
        applyLocale(defaultLang);
 
        pack();
        setSize(500, getHeight());
        setLocationRelativeTo(null);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
 
    private void applyLocale(String locale){
        l10nEngine.setLocale(locale);
        l10nEngine.changeLocale(getContentPane());
        l10nEngine.changeLocale(getJMenuBar());
        setTitle(l10nEngine.getStringResource(TITLE_KEY));
    }
 
    private void createMenuBar(Set<String> languages, String defaultLanguage) {
        JMenuBar mb = new JMenuBar();
        setJMenuBar(mb);
 
        JMenu mFile = new JMenu();
        mFile.putClientProperty(L10nEngine.LOCALIZATION_KEY, "menu.file");
        JMenu mLang = new JMenu();
        mLang.putClientProperty(L10nEngine.LOCALIZATION_KEY, "menu.language");
        JMenu mHelp = new JMenu();
        mHelp.putClientProperty(L10nEngine.LOCALIZATION_KEY, "menu.help");
        mb.add(mFile);
        mb.add(mLang);
        mb.add(mHelp);
 
        JMenuItem miExit = new JMenuItem();
        miExit.putClientProperty(L10nEngine.LOCALIZATION_KEY, "menu.file.exit");
        mFile.add(miExit);
        miExit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
 
        JMenuItem miAbout = new JMenuItem();
        miAbout.putClientProperty(L10nEngine.LOCALIZATION_KEY, "menu.help.about");
        mHelp.add(miAbout);
 
        ButtonGroup bg = new ButtonGroup();
        for (final String lang : languages) {
            JRadioButtonMenuItem miLang = new JRadioButtonMenuItem("", false);
            miLang.putClientProperty(L10nEngine.LOCALIZATION_KEY, "menu." + lang + ".desc");
            bg.add(miLang);
            mLang.add(miLang);
            if (lang.equals(defaultLanguage)) {
                miLang.setSelected(true);
            }
            miLang.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    applyLocale(lang);
                }
            });
        }
    }
 
    public static void main(String[] args) {
        new MainFrame().setVisible(true);
    }
}
Из langs.properties читаются языки, по ним создаются меню, в которых прописывается смена языка. Дальше перебираются компонентыв контейнерах и меняется им текст, в зависимости от типа.
1
 Аватар для KillJoy
58 / 58 / 29
Регистрация: 21.09.2009
Сообщений: 313
Записей в блоге: 1
03.12.2012, 20:27  [ТС]
Не могу запустить ваш код - java.lang.NullPointerException atjava.util.Properties$LineReader.readLi ne(Unknown Source). Не может найти файл langs.properties

Добавлено через 4 минуты
Проблема решена

Добавлено через 2 часа 35 минут
А как быть с локализацией TitledBorder?
0
 Аватар для Skipy
2000 / 1427 / 92
Регистрация: 25.11.2010
Сообщений: 3,611
04.12.2012, 15:11
Добавлять обработчик под этот тип компоненты и выставлять заголовок. Вернее, проверять наличие рамки с заголовком. Где хранить ключ заголовка для рамки - вопрос. Можно для компоненты еще один задать - что-нибудь типа BORDER_LOCALIZATION_KEY. Но если рамок будет несколько - это не сработает.

В общем, тут уже думать надо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
04.12.2012, 15:11
Помогаю со студенческими работами здесь

Локализация в Java и другие вопросы..
Proshy obratit Vashe vnimanie na moyu procby... Lamer v Java. No neplox v .NETe Vot vo3niklo pary voprosov, nado proekt nebolshoy...

JavaFX локализация
Создал файлы с языками, подключил, но как при нажатии кнопки изменения языка изменить язык? Если просто поменять переменную Locale ничего...

Локализация приложения
Всем привет, реализовал смену языка в приложении таким способом: private void englishToolStripMenuItem1_Click(object sender, EventArgs...

Локализация приложения
Всем привет. Нужно реализовать локализацию. Сделал 2 файла ресурса. Но не один из них при запуске не подключается. В чем проблема. Заранее...

Локализация приложения
Сделать локализацию приложения на двух языках: русский и английский с возможностью переключения языка из приложения (без привязки к языку...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Программный контроль заполнения реквизита табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать контроль заполнения реквизита табличной части. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
Программная установка даты и запрет ее изменения
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: при создании документов установить период списания автоматически. . .
Вывод данных в справочнике через динамический список
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Функция заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru