Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions db/knex_migrations/2026-01-06-0000-add-status-page-language.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
exports.up = async function (knex) {
await knex.schema.alterTable("status_page", function (table) {
table.string("language", 20);
});
};

exports.down = function (knex) {
return knex.schema.alterTable("status_page", function (table) {
table.dropColumn("language");
});
};
2 changes: 2 additions & 0 deletions server/model/status_page.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ class StatusPage extends BeanModel {
showCertificateExpiry: !!this.show_certificate_expiry,
showOnlyLastHeartbeat: !!this.show_only_last_heartbeat,
rssTitle: this.rss_title,
language: this.language,
};
}

Expand Down Expand Up @@ -475,6 +476,7 @@ class StatusPage extends BeanModel {
showCertificateExpiry: !!this.show_certificate_expiry,
showOnlyLastHeartbeat: !!this.show_only_last_heartbeat,
rssTitle: this.rss_title,
language: this.language,
};
}

Expand Down
5 changes: 5 additions & 0 deletions server/socket-handlers/status-page-socket-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ module.exports.statusPageSocketHandler = (socket) => {
statusPage.analytics_id = config.analyticsId;
statusPage.analytics_script_url = config.analyticsScriptUrl;
statusPage.analytics_type = config.analyticsType;
if (typeof config.language === "string" && config.language.trim() !== "") {
statusPage.language = config.language.trim();
} else {
statusPage.language = null;
}
Comment on lines +163 to +167
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the equivalent, or?

Suggested change
if (typeof config.language === "string" && config.language.trim() !== "") {
statusPage.language = config.language.trim();
} else {
statusPage.language = null;
}
statusPage.language = config.language?.trim() || null;


await R.store(statusPage);

Expand Down
4 changes: 2 additions & 2 deletions src/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ export function currentLocale() {
return "en";
}

export const localeDirection = () => {
return rtlLangs.includes(currentLocale()) ? "rtl" : "ltr";
export const localeDirection = (locale = currentLocale()) => {
return rtlLangs.includes(locale) ? "rtl" : "ltr";
};

export const i18n = createI18n({
Expand Down
3 changes: 3 additions & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@
"Footer Text": "Footer Text",
"RSS Title": "RSS Title",
"Leave blank to use status page title": "Leave blank to use status page title",
"Status Page Language": "Status Page Language",
"Use browser language": "Use browser language",
"statusPageLanguageDescription": "Set the display language for anonymous visitors to this status page",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can be more explicit here what this does

Suggested change
"statusPageLanguageDescription": "Set the display language for anonymous visitors to this status page",
"statusPageLanguageDescription": "Set the display language for anonymous visitors to this status page. Logged-in users can change the language they see in their own settings.",

"Refresh Interval": "Refresh Interval",
"Refresh Interval Description": "The status page will do a full site refresh every {0} seconds",
"Show Powered By": "Show Powered By",
Expand Down
27 changes: 23 additions & 4 deletions src/mixins/lang.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default {
data() {
return {
language: currentLocale(),
persistLanguage: true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is only ever written, what are you trying to do here?

};
},

Expand All @@ -17,22 +18,40 @@ export default {

watch: {
async language(lang) {
await this.changeLang(lang);
await this.changeLang(lang, {
persist: this.persistLanguage,
});
this.persistLanguage = true;
},
},

methods: {
/**
* Set the application language
* @param {string} lang Language code to switch to
* @param {{ persist?: boolean }} options Options for language change
* @returns {void}
*/
setLanguage(lang, options = {}) {
this.persistLanguage = options.persist !== false;
this.language = lang;
},

/**
* Change the application language
* @param {string} lang Language code to switch to
* @param {{ persist?: boolean }} options Options for language change
* @returns {Promise<void>}
*/
async changeLang(lang) {
async changeLang(lang, options = {}) {
const persist = options.persist !== false;
Comment on lines +46 to +47
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use single-item options as it is harder to reason about them when only used once

Suggested change
async changeLang(lang, options = {}) {
const persist = options.persist !== false;
async changeLang(lang, persist = true) {

let message = (await langModules["../lang/" + lang + ".json"]()).default;
this.$i18n.setLocaleMessage(lang, message);
this.$i18n.locale = lang;
localStorage.locale = lang;
setPageLocale();
if (persist) {
localStorage.locale = lang;
}
setPageLocale(lang);
timeDurationFormatter.updateLocale(lang);
},
},
Expand Down
44 changes: 44 additions & 0 deletions src/pages/StatusPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,25 @@
</div>
</div>

<!-- Status Page Language -->
<div class="my-3">
<label for="status-page-language" class="form-label">{{ $t("Status Page Language") }}</label>
<select
id="status-page-language"
v-model="config.language"
class="form-select"
data-testid="language-select"
>
<option :value="null">{{ $t("Use browser language") }}</option>
<option v-for="lang in $i18n.availableLocales" :key="lang" :value="lang">
{{ $i18n.messages[lang].languageName }}
</option>
</select>
<div class="form-text">
{{ $t("statusPageLanguageDescription") }}
</div>
</div>

<!-- Custom CSS -->
<div class="my-3">
<div class="mb-1">{{ $t("Custom CSS") }}</div>
Expand Down Expand Up @@ -857,6 +876,10 @@ export default {
if (res.ok) {
this.config = res.config;

if (!("language" in this.config)) {
this.config.language = null;
}

Comment on lines +879 to +882
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this happening?

if (!this.config.customCSS) {
this.config.customCSS = "body {\n" + " \n" + "}\n";
}
Expand Down Expand Up @@ -942,6 +965,27 @@ export default {
this.config.domainNameList = [];
}

if (!("language" in this.config)) {
this.config.language = null;
}

if (this.config.icon) {
this.imgDataUrl = this.config.icon;
}

// Apply configured language if the visitor hasn't set their own preference
if (this.config.language && !localStorage.locale) {
this.$root.setLanguage(this.config.language, { persist: false });
}

this.incident = res.data.incident;
this.maintenanceList = res.data.maintenanceList;
this.$root.publicGroupList = res.data.publicGroupList;

if (!this.config.domainNameList) {
this.config.domainNameList = [];
}

Comment on lines +968 to +988
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please explain what you added here and why.
This might have been a merge issue with master..

if (this.config.icon) {
this.imgDataUrl = this.config.icon;
}
Expand Down
7 changes: 4 additions & 3 deletions src/util-frontend.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,13 @@ export function timezoneList() {

/**
* Set the locale of the HTML page
* @param {string} locale The locale to use
* @returns {void}
*/
export function setPageLocale() {
export function setPageLocale(locale = currentLocale()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is resonably hard to read. Please change it like this instead and adjust the callsites.

This feedback also is applicable to localeDirection

Suggested change
export function setPageLocale(locale = currentLocale()) {
export function setPageLocale(locale) {

const html = document.documentElement;
html.setAttribute("lang", currentLocale());
html.setAttribute("dir", localeDirection());
html.setAttribute("lang", locale);
html.setAttribute("dir", localeDirection(locale));
}

/**
Expand Down
Loading