feat: implement internationalization for duty calendar
All checks were successful
CI / lint-and-test (push) Successful in 14s
All checks were successful
CI / lint-and-test (push) Successful in 14s
- Introduced a new `i18n.js` module for handling translations and language detection, supporting both Russian and English. - Updated various components to utilize the new translation functions, enhancing user experience by providing localized messages for errors, hints, and UI elements. - Refactored existing code in `api.js`, `calendar.js`, `dutyList.js`, `hints.js`, and `ui.js` to replace hardcoded strings with translated messages, improving maintainability and accessibility. - Enhanced the initialization process in `main.js` to set the document language and update UI elements based on the user's language preference.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
import { dutyListEl, state } from "./dom.js";
|
||||
import { EVENT_TYPE_LABELS } from "./constants.js";
|
||||
import { t } from "./i18n.js";
|
||||
import { escapeHtml } from "./utils.js";
|
||||
import {
|
||||
localDateString,
|
||||
@@ -33,9 +33,10 @@ export function dutyTimelineCardHtml(d, isCurrent) {
|
||||
} else {
|
||||
timeStr = startDDMM + " " + startTime + " – " + endDDMM + " " + endTime;
|
||||
}
|
||||
const lang = state.lang;
|
||||
const typeLabel = isCurrent
|
||||
? "Сейчас дежурит"
|
||||
: (EVENT_TYPE_LABELS[d.event_type] || "Дежурство");
|
||||
? t(lang, "duty.now_on_duty")
|
||||
: (t(lang, "event_type." + (d.event_type || "duty")));
|
||||
const extraClass = isCurrent ? " duty-item--current" : "";
|
||||
return (
|
||||
'<div class="duty-item duty-item--duty duty-timeline-card' +
|
||||
@@ -59,15 +60,16 @@ export function dutyTimelineCardHtml(d, isCurrent) {
|
||||
* @returns {string}
|
||||
*/
|
||||
export function dutyItemHtml(d, typeLabelOverride, showUntilEnd, extraClass) {
|
||||
const lang = state.lang;
|
||||
const typeLabel =
|
||||
typeLabelOverride != null
|
||||
? typeLabelOverride
|
||||
: (EVENT_TYPE_LABELS[d.event_type] || d.event_type);
|
||||
: (t(lang, "event_type." + (d.event_type || "duty")));
|
||||
let itemClass = "duty-item duty-item--" + (d.event_type || "duty");
|
||||
if (extraClass) itemClass += " " + extraClass;
|
||||
let timeOrRange = "";
|
||||
if (showUntilEnd && d.event_type === "duty") {
|
||||
timeOrRange = "до " + formatTimeLocal(d.end_at);
|
||||
timeOrRange = t(lang, "duty.until", { time: formatTimeLocal(d.end_at) });
|
||||
} else if (d.event_type === "vacation" || d.event_type === "unavailable") {
|
||||
const startStr = formatDateKey(d.start_at);
|
||||
const endStr = formatDateKey(d.end_at);
|
||||
@@ -98,7 +100,7 @@ export function renderDutyList(duties) {
|
||||
const filtered = duties.filter((d) => d.event_type === "duty");
|
||||
if (filtered.length === 0) {
|
||||
dutyListEl.classList.remove("duty-timeline");
|
||||
dutyListEl.innerHTML = '<p class="muted">В этом месяце дежурств нет.</p>';
|
||||
dutyListEl.innerHTML = '<p class="muted">' + t(state.lang, "duty.none_this_month") + "</p>";
|
||||
return;
|
||||
}
|
||||
dutyListEl.classList.add("duty-timeline");
|
||||
@@ -121,7 +123,9 @@ export function renderDutyList(duties) {
|
||||
"duty-timeline-day" + (isToday ? " duty-timeline-day--today" : "");
|
||||
const dateLabel = dateKeyToDDMM(date);
|
||||
const dateCellHtml = isToday
|
||||
? '<span class="duty-timeline-date"><span class="duty-timeline-date-label">Сегодня</span><span class="duty-timeline-date-day">' +
|
||||
? '<span class="duty-timeline-date"><span class="duty-timeline-date-label">' +
|
||||
escapeHtml(t(state.lang, "duty.today")) +
|
||||
'</span><span class="duty-timeline-date-day">' +
|
||||
escapeHtml(dateLabel) +
|
||||
'</span><span class="duty-timeline-date-dot" aria-hidden="true"></span></span>'
|
||||
: '<span class="duty-timeline-date">' + escapeHtml(dateLabel) + "</span>";
|
||||
|
||||
Reference in New Issue
Block a user