Skip to content

Commit 8115eac

Browse files
committed
Add runtime language switching without restart.
1 parent 56d1ba7 commit 8115eac

File tree

3 files changed

+71
-15
lines changed

3 files changed

+71
-15
lines changed

src/core/appinterface.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@
2424
#include "sentry_wrapper.h"
2525
#endif
2626

27+
#include <QCoreApplication>
2728
#include <QDirIterator>
2829
#include <QFileInfo>
2930
#include <QImageReader>
31+
#include <QLocale>
3032
#include <QQuickItem>
33+
#include <QSettings>
3134
#include <QTemporaryFile>
35+
#include <QTranslator>
3236
#include <qgsapplication.h>
3337
#include <qgsauthmanager.h>
3438
#include <qgsmessagelog.h>
@@ -227,6 +231,60 @@ QVariantMap AppInterface::availableLanguages() const
227231
return languages;
228232
}
229233

234+
void AppInterface::changeLanguage( const QString &languageCode )
235+
{
236+
QSettings settings;
237+
settings.setValue( QStringLiteral( "/customLanguage" ), languageCode );
238+
239+
static QTranslator qfieldTranslator;
240+
static QTranslator qtTranslator;
241+
static bool translatorsInitialized = false;
242+
243+
if ( translatorsInitialized )
244+
{
245+
QCoreApplication::removeTranslator( &qtTranslator );
246+
QCoreApplication::removeTranslator( &qfieldTranslator );
247+
}
248+
249+
if ( !languageCode.isEmpty() )
250+
{
251+
if ( !qfieldTranslator.load( QStringLiteral( "qfield_%1" ).arg( languageCode ), QStringLiteral( ":/i18n/" ), "_" ) )
252+
{
253+
qWarning() << "Failed to load QField translation for" << languageCode;
254+
}
255+
if ( !qtTranslator.load( QStringLiteral( "qt_%1" ).arg( languageCode ), QStringLiteral( ":/i18n/" ), "_" ) )
256+
{
257+
qWarning() << "Failed to load Qt translation for" << languageCode;
258+
}
259+
260+
QCoreApplication::installTranslator( &qtTranslator );
261+
QCoreApplication::installTranslator( &qfieldTranslator );
262+
translatorsInitialized = true;
263+
}
264+
else
265+
{
266+
translatorsInitialized = false;
267+
}
268+
269+
if ( !languageCode.isEmpty() )
270+
{
271+
QLocale customLocale( languageCode );
272+
QLocale::setDefault( customLocale );
273+
QgsApplication::setTranslation( languageCode );
274+
QgsApplication::setLocale( QLocale() );
275+
}
276+
else
277+
{
278+
QLocale systemLocale = QLocale::system();
279+
QLocale::setDefault( systemLocale );
280+
QgsApplication::setLocale( systemLocale );
281+
}
282+
if ( mApp )
283+
{
284+
mApp->retranslate();
285+
}
286+
}
287+
230288
bool AppInterface::isFileExtensionSupported( const QString &filename ) const
231289
{
232290
const QFileInfo fi( filename );

src/core/appinterface.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ class AppInterface : public QObject
122122
//! Returns a list of available UI translation languages
123123
Q_INVOKABLE QVariantMap availableLanguages() const;
124124

125+
/**
126+
* Changes the application language to the specified \a languageCode.
127+
* This will reload translators and refresh all QML translations without restarting the app.
128+
* \param languageCode the language code (e.g., "en", "de")
129+
*/
130+
Q_INVOKABLE void changeLanguage( const QString &languageCode );
131+
125132
//! Returns TRUE if a given \a filename can be opened as a project or standalone dataset.
126133
Q_INVOKABLE bool isFileExtensionSupported( const QString &filename ) const;
127134

src/qml/QFieldSettings.qml

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -715,18 +715,6 @@ Page {
715715
wrapMode: Text.WordWrap
716716
}
717717

718-
Label {
719-
id: languageTip
720-
visible: false
721-
722-
Layout.fillWidth: true
723-
text: qsTr("To apply the selected user interface language, QField needs to completely shutdown and restart.")
724-
font: Theme.tipFont
725-
color: Theme.warningColor
726-
727-
wrapMode: Text.WordWrap
728-
}
729-
730718
QfComboBox {
731719
id: languageComboBox
732720
enabled: true
@@ -743,8 +731,12 @@ Page {
743731

744732
onCurrentIndexChanged: {
745733
if (currentLanguageCode != undefined) {
746-
settings.setValue("customLanguage", languageCodes[currentIndex]);
747-
languageTip.visible = languageCodes[currentIndex] !== currentLanguageCode;
734+
var newLanguageCode = languageCodes[currentIndex];
735+
if (newLanguageCode !== currentLanguageCode) {
736+
// Change language immediately without restart
737+
iface.changeLanguage(newLanguageCode);
738+
currentLanguageCode = newLanguageCode;
739+
}
748740
}
749741
}
750742

@@ -758,7 +750,6 @@ Page {
758750
languageComboBox.model = items.concat(Object.values(languages));
759751
languageComboBox.currentIndex = languageCodes.indexOf(customLanguageCode);
760752
currentLanguageCode = customLanguageCode || '';
761-
languageTip.visible = false;
762753
}
763754
}
764755

0 commit comments

Comments
 (0)