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

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

03.12.2012, 11:59. Показов 7104. Ответов 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
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru