Skip to content

Commit

Permalink
On wasm, use English locale if current language cannot be rendered
Browse files Browse the repository at this point in the history
Chinese and Thai language characters cannot be rendered by the
default Museo font, and this is the only font bundled in the wasm
build at the moment.

For these two languages, indicate in the language list that they
are not supported in the browser, and if one of these languages are
selected as the current language, then fall back to the previously-
used application language on startup.
  • Loading branch information
blammit committed Feb 8, 2024
1 parent 08dbd1d commit 9f2e370
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 14 deletions.
8 changes: 7 additions & 1 deletion pages/settings/PageSettingsDisplay.qml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ Page {

LanguageModel {
id: languageModel
currentLanguage: Language.current
//% "(no browser support)"
unsupportedLanguageMessage: qsTrId("settings_language_no_browser_support")
}

Instantiator {
Expand All @@ -133,6 +134,11 @@ Page {
VeQuickItem {
id: languageDataItem
uid: Global.systemSettings.serviceUid + "/Settings/Gui/Language"
onValueChanged: {
if (value !== undefined) {
languageModel.currentLanguage = Language.fromCode(value)
}
}
}

Component {
Expand Down
93 changes: 82 additions & 11 deletions src/language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,44 @@ QUrl fontUrlForLanguage(QLocale::Language language)
{ QLocale::Thai, QStringLiteral("NotoSansThai.ttf") },
};

static const QUrl defaultFontUrl = QUrl("qrc:/fonts/MuseoSans-500.otf");

#if defined(VENUS_WEBASSEMBLY_BUILD)
// On wasm, the server contains symlinks to the required font files in the root dir.
QString fileName = fontFileNames.value(language);
if (!fileName.isEmpty()) {
return QUrl(fileName);
}
Q_UNUSED(language);
// On wasm, the custom font files are not available. Just use the default font.
return defaultFontUrl;

#elif not defined(VENUS_DESKTOP_BUILD)
// On device, look for the system-installed font files.
QString fileName = fontFileNames.value(language);
if (!fileName.isEmpty()) {
return QUrl::fromLocalFile("/usr/lib/fonts/" + fileName);
}
#else
Q_UNUSED(language);
#endif

// Use the default font on other platforms, or if the default font supports this language.
static const QUrl defaultFontUrl = QUrl("qrc:/fonts/MuseoSans-500.otf");
// Use the default font on other platforms.
return defaultFontUrl;
}

bool isLanguageRenderingSupported(QLocale::Language language)
{
#if defined(VENUS_WEBASSEMBLY_BUILD)
// On wasm, the scripts for these languages cannot be rendered by the default Museo font.
switch (language) {
case QLocale::Chinese:
case QLocale::Thai:
return false;
default:
break;
}
#else
Q_UNUSED(language);
#endif
return true;
}

}


Expand Down Expand Up @@ -109,7 +128,32 @@ QString LanguageModel::currentDisplayText() const
if (m_currentIndex < 0 || m_currentIndex >= m_languages.count()) {
return QString();
}
return m_languages.at(m_currentIndex).name;
const LanguageData &data = m_languages.at(m_currentIndex);
return languageDisplayName(data.language, data.name);
}

QString LanguageModel::unsupportedLanguageMessage() const
{
return m_unsupportedLanguageMessage;
}

void LanguageModel::setUnsupportedLanguageMessage(const QString &msg)
{
if (m_unsupportedLanguageMessage != msg) {
m_unsupportedLanguageMessage = msg;
emit unsupportedLanguageMessageChanged();

if (!isLanguageRenderingSupported(m_currentLanguage)) {
emit currentDisplayTextChanged();
}

for (int i = 0; i < m_languages.count(); ++i) {
if (!isLanguageRenderingSupported(m_languages.at(i).language)) {
static const QList<int> roles = { Qt::DisplayRole };
emit dataChanged(createIndex(i, 0), createIndex(i, 0), roles);
}
}
}
}

int LanguageModel::languageAt(int index) const
Expand Down Expand Up @@ -147,7 +191,7 @@ QVariant LanguageModel::data(const QModelIndex &index, int role) const

switch (role) {
case Qt::DisplayRole:
return data.name;
return languageDisplayName(data.language, data.name);
case FontFileUrlRole:
return data.fontFileUrl;
case FontFamilyRole:
Expand All @@ -157,11 +201,30 @@ QVariant LanguageModel::data(const QModelIndex &index, int role) const
}
}

void LanguageModel::addLanguage(const QString &name, const QString &code, const QLocale::Language &language)
void LanguageModel::addLanguage(const QString &name, const QString &code, QLocale::Language language)
{
m_languages.append({name, code, fontUrlForLanguage(language), QString(), language });
}

QString LanguageModel::languageDisplayName(QLocale::Language language, const QString &name) const
{
#if defined(VENUS_WEBASSEMBLY_BUILD)
// For languages that cannot be rendered by the default font in wasm, show the language name
// in English, so that the name can be rendered.
switch (language) {
case QLocale::Chinese:
return QStringLiteral("Chinese %1").arg(m_unsupportedLanguageMessage);
case QLocale::Thai:
return QStringLiteral("Thai %1").arg(m_unsupportedLanguageMessage);
default:
break;
}
#else
Q_UNUSED(language);
#endif
return name;
}

QHash<int, QByteArray> LanguageModel::roleNames() const
{
return m_roleNames;
Expand All @@ -174,7 +237,7 @@ Language* Language::create(QQmlEngine *, QJSEngine *)
return language;
}

Language::Language(QQmlEngine* engine) : QObject(nullptr)
Language::Language(QQmlEngine*) : QObject(nullptr)
{
/* Load appropriate translations for current locale, e.g. :/i18n/venus-gui-v2_fr.qm */
if (!installTranslatorForLanguage(QLocale().language())) {
Expand Down Expand Up @@ -228,6 +291,14 @@ void Language::setCurrentLanguageCode(const QString &code)

bool Language::installTranslatorForLanguage(QLocale::Language language)
{
#if defined(VENUS_WEBASSEMBLY_BUILD)
if (!isLanguageRenderingSupported(language)) {
qCWarning(venusGui) << "Cannot render language" << QLocale(language).name()
<< "with the default font on WASM";
return false;
}
#endif

const bool alreadyLoaded = m_loadedTranslators.contains(language);
QTranslator *currTranslator = m_loadedTranslators.value(m_currentLanguage);
QTranslator *translator = alreadyLoaded ? m_loadedTranslators.value(language) : new QTranslator(this);
Expand Down
10 changes: 9 additions & 1 deletion src/language.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class LanguageModel : public QAbstractListModel
Q_PROPERTY(int currentIndex READ currentIndex NOTIFY currentIndexChanged)
Q_PROPERTY(QString currentDisplayText READ currentDisplayText NOTIFY currentDisplayTextChanged)
Q_PROPERTY(int count READ rowCount CONSTANT)
Q_PROPERTY(QString unsupportedLanguageMessage READ unsupportedLanguageMessage WRITE setUnsupportedLanguageMessage NOTIFY unsupportedLanguageMessageChanged)

public:
enum Role {
Expand All @@ -42,9 +43,13 @@ class LanguageModel : public QAbstractListModel

int currentLanguage() const;
void setCurrentLanguage(int language);

int currentIndex() const;
QString currentDisplayText() const;

QString unsupportedLanguageMessage() const;
void setUnsupportedLanguageMessage(const QString &msg);

Q_INVOKABLE int languageAt(int index) const;
Q_INVOKABLE void setFontFamily(const QUrl &fontUrl, const QString &fontFamily);

Expand All @@ -55,6 +60,7 @@ class LanguageModel : public QAbstractListModel
void currentLanguageChanged();
void currentIndexChanged();
void currentDisplayTextChanged();
void unsupportedLanguageMessageChanged();

protected:
QHash<int, QByteArray> roleNames() const override;
Expand All @@ -68,10 +74,12 @@ class LanguageModel : public QAbstractListModel
QLocale::Language language;
};

void addLanguage(const QString &name, const QString &code, const QLocale::Language &language);
void addLanguage(const QString &name, const QString &code, QLocale::Language language);
QString languageDisplayName(QLocale::Language language, const QString &name) const;

QHash<int, QByteArray> m_roleNames;
QList<LanguageData> m_languages;
QString m_unsupportedLanguageMessage;
int m_currentIndex = -1;
QLocale::Language m_currentLanguage = QLocale::AnyLanguage;
};
Expand Down

0 comments on commit 9f2e370

Please sign in to comment.