This commit is contained in:
Daniel Derefaka 2026-01-20 06:03:21 +00:00 committed by GitHub
commit 96670211ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 94 additions and 9 deletions

View File

@ -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");
});
};

View File

@ -450,6 +450,7 @@ class StatusPage extends BeanModel {
showCertificateExpiry: !!this.show_certificate_expiry,
showOnlyLastHeartbeat: !!this.show_only_last_heartbeat,
rssTitle: this.rss_title,
language: this.language,
};
}
@ -477,6 +478,7 @@ class StatusPage extends BeanModel {
showCertificateExpiry: !!this.show_certificate_expiry,
showOnlyLastHeartbeat: !!this.show_only_last_heartbeat,
rssTitle: this.rss_title,
language: this.language,
};
}

View File

@ -339,6 +339,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;
}
await R.store(statusPage);

View File

@ -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({

View File

@ -425,6 +425,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",
"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",

View File

@ -6,6 +6,7 @@ export default {
data() {
return {
language: currentLocale(),
persistLanguage: true,
};
},
@ -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;
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);
},
},

View File

@ -201,6 +201,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>
@ -905,6 +924,10 @@ export default {
if (res.ok) {
this.config = res.config;
if (!("language" in this.config)) {
this.config.language = null;
}
if (!this.config.customCSS) {
this.config.customCSS = "body {\n" + " \n" + "}\n";
}
@ -990,6 +1013,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 = [];
}
if (this.config.icon) {
this.imgDataUrl = this.config.icon;
}

View File

@ -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()) {
const html = document.documentElement;
html.setAttribute("lang", currentLocale());
html.setAttribute("dir", localeDirection());
html.setAttribute("lang", locale);
html.setAttribute("dir", localeDirection(locale));
}
/**