iobroker.kanban 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +224 -0
- package/admin/i18n/de.json +100 -0
- package/admin/i18n/en.json +100 -0
- package/admin/i18n/es.json +100 -0
- package/admin/i18n/fr.json +100 -0
- package/admin/i18n/it.json +100 -0
- package/admin/i18n/nl.json +100 -0
- package/admin/i18n/pl.json +100 -0
- package/admin/i18n/pt.json +100 -0
- package/admin/i18n/ru.json +100 -0
- package/admin/i18n/uk.json +100 -0
- package/admin/i18n/zh-cn.json +100 -0
- package/admin/jsonConfig.json +668 -0
- package/admin/kanban.png +0 -0
- package/io-package.json +299 -0
- package/lib/cron.js +203 -0
- package/lib/dueat.js +77 -0
- package/lib/events.js +24 -0
- package/lib/holidays.js +167 -0
- package/lib/i18n-server.js +301 -0
- package/lib/notify.js +627 -0
- package/lib/scheduler.js +198 -0
- package/lib/server.js +799 -0
- package/lib/store.js +1500 -0
- package/main.js +382 -0
- package/package.json +58 -0
- package/www/css/app.css +1022 -0
- package/www/i18n/de.json +238 -0
- package/www/i18n/en.json +238 -0
- package/www/i18n/es.json +238 -0
- package/www/i18n/fr.json +238 -0
- package/www/i18n/it.json +238 -0
- package/www/i18n/nl.json +238 -0
- package/www/i18n/pl.json +238 -0
- package/www/i18n/pt.json +238 -0
- package/www/i18n/ru.json +238 -0
- package/www/i18n/uk.json +238 -0
- package/www/i18n/zh-cn.json +238 -0
- package/www/index.html +171 -0
- package/www/js/api.js +98 -0
- package/www/js/app.js +411 -0
- package/www/js/board.js +983 -0
- package/www/js/colorpicker.js +165 -0
- package/www/js/dialogs.js +1419 -0
- package/www/js/i18n.js +43 -0
- package/www/vendor/marked.min.js +69 -0
- package/www/vendor/purify.min.js +3 -0
- package/www/vendor/sortable.min.js +2 -0
package/lib/holidays.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// Feiertags-Berechnung für die Arbeitstag-Logik der Wiederholungen.
|
|
2
|
+
//
|
|
3
|
+
// Der ioBroker-`feiertage`-Adapter exponiert nur today/tomorrow/next – keine
|
|
4
|
+
// abfragbare Jahresliste. Für die Vorausberechnung von Fälligkeiten (bis 800
|
|
5
|
+
// Tage voraus) berechnen wir die Feiertage daher selbst und nutzen aus der
|
|
6
|
+
// feiertage-Adapter-Config nur die Info, WELCHE Feiertage gelten (Bundesland).
|
|
7
|
+
//
|
|
8
|
+
// Wichtig: Für „Arbeitstag" zählen ausschließlich gesetzlich arbeitsfreie Tage.
|
|
9
|
+
// Deko-Tage wie Valentinstag (im Adapter aktivierbar) sind normale Arbeitstage
|
|
10
|
+
// und stehen daher gar nicht erst in RULES.
|
|
11
|
+
|
|
12
|
+
function fmt(d) {
|
|
13
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Ostersonntag (Anonymous-Gregorian-/Meeus-Algorithmus)
|
|
17
|
+
function easterSunday(year) {
|
|
18
|
+
const a = year % 19,
|
|
19
|
+
b = Math.floor(year / 100),
|
|
20
|
+
c = year % 100;
|
|
21
|
+
const d = Math.floor(b / 4),
|
|
22
|
+
e = b % 4,
|
|
23
|
+
f = Math.floor((b + 8) / 25),
|
|
24
|
+
g = Math.floor((b - f + 1) / 3);
|
|
25
|
+
const h = (19 * a + b - d - g + 15) % 30,
|
|
26
|
+
i = Math.floor(c / 4),
|
|
27
|
+
k = c % 4;
|
|
28
|
+
const l = (32 + 2 * e + 2 * i - h - k) % 7,
|
|
29
|
+
m = Math.floor((a + 11 * h + 22 * l) / 451);
|
|
30
|
+
const month = Math.floor((h + l - 7 * m + 114) / 31),
|
|
31
|
+
day = ((h + l - 7 * m + 114) % 31) + 1;
|
|
32
|
+
return new Date(year, month - 1, day, 12, 0, 0, 0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function easterOffset(year, off) {
|
|
36
|
+
const e = easterSunday(year);
|
|
37
|
+
e.setDate(e.getDate() + off);
|
|
38
|
+
return e;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Nur gesetzlich arbeitsfrei-fähige Feiertage (bundesweit + länderspezifisch).
|
|
42
|
+
// Key = feiertage-Adapter enable_<key>. fixed:[monat,tag] | easter:offset | fn.
|
|
43
|
+
const RULES = {
|
|
44
|
+
neujahr: { fixed: [1, 1] },
|
|
45
|
+
dreikoenige: { fixed: [1, 6] }, // BW, BY, ST
|
|
46
|
+
weltfrauentag: { fixed: [3, 8] }, // BE, MV
|
|
47
|
+
karfreitag: { easter: -2 },
|
|
48
|
+
ostersonntag: { easter: 0 }, // BB (sonst Sonntag)
|
|
49
|
+
ostermontag: { easter: 1 },
|
|
50
|
+
maifeiertag: { fixed: [5, 1] },
|
|
51
|
+
chimmelfahrt: { easter: 39 }, // Christi Himmelfahrt
|
|
52
|
+
pfingstsonntag: { easter: 49 }, // BB (sonst Sonntag)
|
|
53
|
+
pfingstmontag: { easter: 50 },
|
|
54
|
+
fronleichnam: { easter: 60 }, // BW, BY, HE, NW, RP, SL + teilw.
|
|
55
|
+
friedensfest: { fixed: [8, 8] }, // Augsburg
|
|
56
|
+
mhimmelfahrt: { fixed: [8, 15] }, // SL, teilw. BY
|
|
57
|
+
wkinder: { fixed: [9, 20] }, // Weltkindertag, TH
|
|
58
|
+
einheitstag: { fixed: [10, 3] },
|
|
59
|
+
reformationstag: { fixed: [10, 31] }, // norddt. Länder + Ost
|
|
60
|
+
allerheiligen: { fixed: [11, 1] }, // BW, BY, NW, RP, SL
|
|
61
|
+
bussbettag: { fn: bussUndBettag }, // SN – Mittwoch vor dem 23.11.
|
|
62
|
+
weihnachtstag1: { fixed: [12, 25] },
|
|
63
|
+
weihnachtstag2: { fixed: [12, 26] },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Buß- und Bettag: Mittwoch vor dem 23. November
|
|
67
|
+
function bussUndBettag(year) {
|
|
68
|
+
const d = new Date(year, 10, 23, 12, 0, 0, 0); // 23.11.
|
|
69
|
+
// zurück bis zum Mittwoch (3) davor
|
|
70
|
+
do {
|
|
71
|
+
d.setDate(d.getDate() - 1);
|
|
72
|
+
} while (d.getDay() !== 3);
|
|
73
|
+
return d;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Default-Satz, wenn kein feiertage-Adapter vorhanden ist:
|
|
77
|
+
// bundesweit einheitliche gesetzliche Feiertage.
|
|
78
|
+
const DEFAULT_KEYS = [
|
|
79
|
+
'neujahr',
|
|
80
|
+
'karfreitag',
|
|
81
|
+
'ostermontag',
|
|
82
|
+
'maifeiertag',
|
|
83
|
+
'chimmelfahrt',
|
|
84
|
+
'pfingstmontag',
|
|
85
|
+
'einheitstag',
|
|
86
|
+
'weihnachtstag1',
|
|
87
|
+
'weihnachtstag2',
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
class Holidays {
|
|
91
|
+
constructor() {
|
|
92
|
+
this.activeKeys = new Set(DEFAULT_KEYS);
|
|
93
|
+
this.source = 'default';
|
|
94
|
+
this._cache = new Map(); // year -> Set('YYYY-MM-DD')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* native-Config des feiertage-Adapters (oder null) übernehmen.
|
|
99
|
+
*
|
|
100
|
+
* @param native
|
|
101
|
+
*/
|
|
102
|
+
configure(native) {
|
|
103
|
+
this._cache.clear();
|
|
104
|
+
if (native && typeof native === 'object') {
|
|
105
|
+
const keys = Object.keys(RULES).filter(k => native[`enable_${k}`] === true);
|
|
106
|
+
this.activeKeys = new Set(keys);
|
|
107
|
+
this.source = 'feiertage-adapter';
|
|
108
|
+
} else {
|
|
109
|
+
this.activeKeys = new Set(DEFAULT_KEYS);
|
|
110
|
+
this.source = 'default';
|
|
111
|
+
}
|
|
112
|
+
return { source: this.source, count: this.activeKeys.size };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_yearSet(year) {
|
|
116
|
+
let set = this._cache.get(year);
|
|
117
|
+
if (set) {
|
|
118
|
+
return set;
|
|
119
|
+
}
|
|
120
|
+
set = new Set();
|
|
121
|
+
for (const key of this.activeKeys) {
|
|
122
|
+
const rule = RULES[key];
|
|
123
|
+
if (!rule) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
let d;
|
|
127
|
+
if (rule.fixed) {
|
|
128
|
+
d = new Date(year, rule.fixed[0] - 1, rule.fixed[1], 12, 0, 0, 0);
|
|
129
|
+
} else if (typeof rule.easter === 'number') {
|
|
130
|
+
d = easterOffset(year, rule.easter);
|
|
131
|
+
} else if (rule.fn) {
|
|
132
|
+
d = rule.fn(year);
|
|
133
|
+
}
|
|
134
|
+
if (d) {
|
|
135
|
+
set.add(fmt(d));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
this._cache.set(year, set);
|
|
139
|
+
return set;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Ist das Datum ein (aktiver) gesetzlicher Feiertag?
|
|
144
|
+
*
|
|
145
|
+
* @param d
|
|
146
|
+
*/
|
|
147
|
+
isHoliday(d) {
|
|
148
|
+
return this._yearSet(d.getFullYear()).has(fmt(d));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Arbeitstag = kein Wochenende und kein gesetzlicher Feiertag.
|
|
153
|
+
*
|
|
154
|
+
* @param d
|
|
155
|
+
*/
|
|
156
|
+
isWorkday(d) {
|
|
157
|
+
const wd = d.getDay();
|
|
158
|
+
if (wd === 0 || wd === 6) {
|
|
159
|
+
return false;
|
|
160
|
+
} // So/Sa
|
|
161
|
+
return !this.isHoliday(d);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = new Holidays(); // Singleton
|
|
166
|
+
module.exports.Holidays = Holidays;
|
|
167
|
+
module.exports.easterSunday = easterSunday;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Serverseitige Übersetzungen: Default-Spaltennamen (bei Board-Erstellung) und
|
|
4
|
+
// E-Mail-Texte. Klein gehalten; Englisch ist Fallback für fehlende Sprachen.
|
|
5
|
+
|
|
6
|
+
const STRINGS = {
|
|
7
|
+
en: {
|
|
8
|
+
'col.todo': 'To do',
|
|
9
|
+
'col.doing': 'In progress',
|
|
10
|
+
'col.done': 'Done',
|
|
11
|
+
'ev.cardCreated': 'New card',
|
|
12
|
+
'ev.cardUpdated': 'Card changed',
|
|
13
|
+
'ev.cardMoved': 'Card moved',
|
|
14
|
+
'ev.cardAssigned': 'Card assigned',
|
|
15
|
+
'ev.cardDone': 'Card done',
|
|
16
|
+
'ev.cardDeleted': 'Card deleted',
|
|
17
|
+
'ev.cardDue': 'Card due',
|
|
18
|
+
'ev.cardRestored': 'Card restored',
|
|
19
|
+
'ev.cardPurged': 'Card permanently deleted',
|
|
20
|
+
'col.trash': 'Trash',
|
|
21
|
+
'mail.board': 'Board',
|
|
22
|
+
'mail.moved': 'Moved',
|
|
23
|
+
'mail.due': 'Due',
|
|
24
|
+
'mail.assignees': 'Assignees',
|
|
25
|
+
'mail.by': 'By',
|
|
26
|
+
'mail.description': 'Description',
|
|
27
|
+
'mail.openCard': 'Open card in board',
|
|
28
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
29
|
+
'mail.cleanupSubject': 'Cards moved to trash',
|
|
30
|
+
'mail.cleanupIntro': 'The following cards were moved to the trash:',
|
|
31
|
+
'mail.purgedIntro': 'The following cards were permanently deleted:',
|
|
32
|
+
},
|
|
33
|
+
de: {
|
|
34
|
+
'col.todo': 'Zu erledigen',
|
|
35
|
+
'col.doing': 'In Arbeit',
|
|
36
|
+
'col.done': 'Erledigt',
|
|
37
|
+
'ev.cardCreated': 'Neue Karte',
|
|
38
|
+
'ev.cardUpdated': 'Karte geändert',
|
|
39
|
+
'ev.cardMoved': 'Karte verschoben',
|
|
40
|
+
'ev.cardAssigned': 'Karte zugewiesen',
|
|
41
|
+
'ev.cardDone': 'Karte erledigt',
|
|
42
|
+
'ev.cardDeleted': 'Karte gelöscht',
|
|
43
|
+
'ev.cardDue': 'Karte fällig',
|
|
44
|
+
'ev.cardRestored': 'Karte wiederhergestellt',
|
|
45
|
+
'ev.cardPurged': 'Karte endgültig gelöscht',
|
|
46
|
+
'col.trash': 'Papierkorb',
|
|
47
|
+
'mail.board': 'Board',
|
|
48
|
+
'mail.moved': 'Verschoben',
|
|
49
|
+
'mail.due': 'Fällig',
|
|
50
|
+
'mail.assignees': 'Zuständig',
|
|
51
|
+
'mail.by': 'Durch',
|
|
52
|
+
'mail.description': 'Beschreibung',
|
|
53
|
+
'mail.openCard': 'Karte im Board öffnen',
|
|
54
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
55
|
+
'mail.cleanupSubject': 'Karten in den Papierkorb verschoben',
|
|
56
|
+
'mail.cleanupIntro': 'Folgende Karten wurden in den Papierkorb verschoben:',
|
|
57
|
+
'mail.purgedIntro': 'Folgende Karten wurden endgültig gelöscht:',
|
|
58
|
+
},
|
|
59
|
+
fr: {
|
|
60
|
+
'col.todo': 'À faire',
|
|
61
|
+
'col.doing': 'En cours',
|
|
62
|
+
'col.done': 'Terminé',
|
|
63
|
+
'ev.cardCreated': 'Nouvelle carte',
|
|
64
|
+
'ev.cardUpdated': 'Carte modifiée',
|
|
65
|
+
'ev.cardMoved': 'Carte déplacée',
|
|
66
|
+
'ev.cardAssigned': 'Carte assignée',
|
|
67
|
+
'ev.cardDone': 'Carte terminée',
|
|
68
|
+
'ev.cardDeleted': 'Carte supprimée',
|
|
69
|
+
'ev.cardDue': 'Carte à échéance',
|
|
70
|
+
'ev.cardRestored': 'Carte restaurée',
|
|
71
|
+
'ev.cardPurged': 'Carte supprimée définitivement',
|
|
72
|
+
'col.trash': 'Corbeille',
|
|
73
|
+
'mail.board': 'Tableau',
|
|
74
|
+
'mail.moved': 'Déplacée',
|
|
75
|
+
'mail.due': 'Échéance',
|
|
76
|
+
'mail.assignees': 'Assignés',
|
|
77
|
+
'mail.by': 'Par',
|
|
78
|
+
'mail.description': 'Description',
|
|
79
|
+
'mail.openCard': 'Ouvrir la carte dans le tableau',
|
|
80
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
81
|
+
'mail.cleanupSubject': 'Cartes déplacées vers la corbeille',
|
|
82
|
+
'mail.cleanupIntro': 'Les cartes suivantes ont été déplacées vers la corbeille :',
|
|
83
|
+
'mail.purgedIntro': 'Les cartes suivantes ont été supprimées définitivement :',
|
|
84
|
+
},
|
|
85
|
+
nl: {
|
|
86
|
+
'col.todo': 'Te doen',
|
|
87
|
+
'col.doing': 'Bezig',
|
|
88
|
+
'col.done': 'Voltooid',
|
|
89
|
+
'ev.cardCreated': 'Nieuwe kaart',
|
|
90
|
+
'ev.cardUpdated': 'Kaart gewijzigd',
|
|
91
|
+
'ev.cardMoved': 'Kaart verplaatst',
|
|
92
|
+
'ev.cardAssigned': 'Kaart toegewezen',
|
|
93
|
+
'ev.cardDone': 'Kaart voltooid',
|
|
94
|
+
'ev.cardDeleted': 'Kaart verwijderd',
|
|
95
|
+
'ev.cardDue': 'Kaart vervalt',
|
|
96
|
+
'ev.cardRestored': 'Kaart hersteld',
|
|
97
|
+
'ev.cardPurged': 'Kaart definitief verwijderd',
|
|
98
|
+
'col.trash': 'Prullenbak',
|
|
99
|
+
'mail.board': 'Bord',
|
|
100
|
+
'mail.moved': 'Verplaatst',
|
|
101
|
+
'mail.due': 'Vervaldatum',
|
|
102
|
+
'mail.assignees': 'Toegewezen aan',
|
|
103
|
+
'mail.by': 'Door',
|
|
104
|
+
'mail.description': 'Beschrijving',
|
|
105
|
+
'mail.openCard': 'Kaart in bord openen',
|
|
106
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
107
|
+
'mail.cleanupSubject': 'Kaarten naar prullenbak verplaatst',
|
|
108
|
+
'mail.cleanupIntro': 'De volgende kaarten zijn naar de prullenbak verplaatst:',
|
|
109
|
+
'mail.purgedIntro': 'De volgende kaarten zijn definitief verwijderd:',
|
|
110
|
+
},
|
|
111
|
+
it: {
|
|
112
|
+
'col.todo': 'Da fare',
|
|
113
|
+
'col.doing': 'In corso',
|
|
114
|
+
'col.done': 'Completato',
|
|
115
|
+
'ev.cardCreated': 'Nuova scheda',
|
|
116
|
+
'ev.cardUpdated': 'Scheda modificata',
|
|
117
|
+
'ev.cardMoved': 'Scheda spostata',
|
|
118
|
+
'ev.cardAssigned': 'Scheda assegnata',
|
|
119
|
+
'ev.cardDone': 'Scheda completata',
|
|
120
|
+
'ev.cardDeleted': 'Scheda eliminata',
|
|
121
|
+
'ev.cardDue': 'Scheda in scadenza',
|
|
122
|
+
'ev.cardRestored': 'Scheda ripristinata',
|
|
123
|
+
'ev.cardPurged': 'Scheda eliminata definitivamente',
|
|
124
|
+
'col.trash': 'Cestino',
|
|
125
|
+
'mail.board': 'Bacheca',
|
|
126
|
+
'mail.moved': 'Spostata',
|
|
127
|
+
'mail.due': 'Scadenza',
|
|
128
|
+
'mail.assignees': 'Assegnatari',
|
|
129
|
+
'mail.by': 'Da',
|
|
130
|
+
'mail.description': 'Descrizione',
|
|
131
|
+
'mail.openCard': 'Apri la scheda nella bacheca',
|
|
132
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
133
|
+
'mail.cleanupSubject': 'Schede spostate nel cestino',
|
|
134
|
+
'mail.cleanupIntro': 'Le seguenti schede sono state spostate nel cestino:',
|
|
135
|
+
'mail.purgedIntro': 'Le seguenti schede sono state eliminate definitivamente:',
|
|
136
|
+
},
|
|
137
|
+
es: {
|
|
138
|
+
'col.todo': 'Por hacer',
|
|
139
|
+
'col.doing': 'En curso',
|
|
140
|
+
'col.done': 'Hecho',
|
|
141
|
+
'ev.cardCreated': 'Tarjeta nueva',
|
|
142
|
+
'ev.cardUpdated': 'Tarjeta modificada',
|
|
143
|
+
'ev.cardMoved': 'Tarjeta movida',
|
|
144
|
+
'ev.cardAssigned': 'Tarjeta asignada',
|
|
145
|
+
'ev.cardDone': 'Tarjeta hecha',
|
|
146
|
+
'ev.cardDeleted': 'Tarjeta eliminada',
|
|
147
|
+
'ev.cardDue': 'Tarjeta vencida',
|
|
148
|
+
'ev.cardRestored': 'Tarjeta restaurada',
|
|
149
|
+
'ev.cardPurged': 'Tarjeta eliminada definitivamente',
|
|
150
|
+
'col.trash': 'Papelera',
|
|
151
|
+
'mail.board': 'Tablero',
|
|
152
|
+
'mail.moved': 'Movida',
|
|
153
|
+
'mail.due': 'Vencimiento',
|
|
154
|
+
'mail.assignees': 'Responsables',
|
|
155
|
+
'mail.by': 'Por',
|
|
156
|
+
'mail.description': 'Descripción',
|
|
157
|
+
'mail.openCard': 'Abrir la tarjeta en el tablero',
|
|
158
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
159
|
+
'mail.cleanupSubject': 'Tarjetas movidas a la papelera',
|
|
160
|
+
'mail.cleanupIntro': 'Las siguientes tarjetas se han movido a la papelera:',
|
|
161
|
+
'mail.purgedIntro': 'Las siguientes tarjetas se han eliminado definitivamente:',
|
|
162
|
+
},
|
|
163
|
+
pl: {
|
|
164
|
+
'col.todo': 'Do zrobienia',
|
|
165
|
+
'col.doing': 'W trakcie',
|
|
166
|
+
'col.done': 'Gotowe',
|
|
167
|
+
'ev.cardCreated': 'Nowa karta',
|
|
168
|
+
'ev.cardUpdated': 'Karta zmieniona',
|
|
169
|
+
'ev.cardMoved': 'Karta przeniesiona',
|
|
170
|
+
'ev.cardAssigned': 'Karta przypisana',
|
|
171
|
+
'ev.cardDone': 'Karta gotowa',
|
|
172
|
+
'ev.cardDeleted': 'Karta usunięta',
|
|
173
|
+
'ev.cardDue': 'Termin karty',
|
|
174
|
+
'ev.cardRestored': 'Karta przywrócona',
|
|
175
|
+
'ev.cardPurged': 'Karta usunięta trwale',
|
|
176
|
+
'col.trash': 'Kosz',
|
|
177
|
+
'mail.board': 'Tablica',
|
|
178
|
+
'mail.moved': 'Przeniesiona',
|
|
179
|
+
'mail.due': 'Termin',
|
|
180
|
+
'mail.assignees': 'Odpowiedzialni',
|
|
181
|
+
'mail.by': 'Przez',
|
|
182
|
+
'mail.description': 'Opis',
|
|
183
|
+
'mail.openCard': 'Otwórz kartę w tablicy',
|
|
184
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
185
|
+
'mail.cleanupSubject': 'Karty przeniesione do kosza',
|
|
186
|
+
'mail.cleanupIntro': 'Następujące karty zostały przeniesione do kosza:',
|
|
187
|
+
'mail.purgedIntro': 'Następujące karty zostały trwale usunięte:',
|
|
188
|
+
},
|
|
189
|
+
pt: {
|
|
190
|
+
'col.todo': 'A fazer',
|
|
191
|
+
'col.doing': 'Em curso',
|
|
192
|
+
'col.done': 'Concluído',
|
|
193
|
+
'ev.cardCreated': 'Novo cartão',
|
|
194
|
+
'ev.cardUpdated': 'Cartão alterado',
|
|
195
|
+
'ev.cardMoved': 'Cartão movido',
|
|
196
|
+
'ev.cardAssigned': 'Cartão atribuído',
|
|
197
|
+
'ev.cardDone': 'Cartão concluído',
|
|
198
|
+
'ev.cardDeleted': 'Cartão eliminado',
|
|
199
|
+
'ev.cardDue': 'Cartão a vencer',
|
|
200
|
+
'ev.cardRestored': 'Cartão restaurado',
|
|
201
|
+
'ev.cardPurged': 'Cartão eliminado definitivamente',
|
|
202
|
+
'col.trash': 'Lixeira',
|
|
203
|
+
'mail.board': 'Quadro',
|
|
204
|
+
'mail.moved': 'Movido',
|
|
205
|
+
'mail.due': 'Vencimento',
|
|
206
|
+
'mail.assignees': 'Responsáveis',
|
|
207
|
+
'mail.by': 'Por',
|
|
208
|
+
'mail.description': 'Descrição',
|
|
209
|
+
'mail.openCard': 'Abrir o cartão no quadro',
|
|
210
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
211
|
+
'mail.cleanupSubject': 'Cartões movidos para a lixeira',
|
|
212
|
+
'mail.cleanupIntro': 'Os seguintes cartões foram movidos para a lixeira:',
|
|
213
|
+
'mail.purgedIntro': 'Os seguintes cartões foram eliminados definitivamente:',
|
|
214
|
+
},
|
|
215
|
+
ru: {
|
|
216
|
+
'col.todo': 'К выполнению',
|
|
217
|
+
'col.doing': 'В работе',
|
|
218
|
+
'col.done': 'Готово',
|
|
219
|
+
'ev.cardCreated': 'Новая карточка',
|
|
220
|
+
'ev.cardUpdated': 'Карточка изменена',
|
|
221
|
+
'ev.cardMoved': 'Карточка перемещена',
|
|
222
|
+
'ev.cardAssigned': 'Карточка назначена',
|
|
223
|
+
'ev.cardDone': 'Карточка выполнена',
|
|
224
|
+
'ev.cardDeleted': 'Карточка удалена',
|
|
225
|
+
'ev.cardDue': 'Срок карточки',
|
|
226
|
+
'ev.cardRestored': 'Карточка восстановлена',
|
|
227
|
+
'ev.cardPurged': 'Карточка удалена окончательно',
|
|
228
|
+
'col.trash': 'Корзина',
|
|
229
|
+
'mail.board': 'Доска',
|
|
230
|
+
'mail.moved': 'Перемещена',
|
|
231
|
+
'mail.due': 'Срок',
|
|
232
|
+
'mail.assignees': 'Ответственные',
|
|
233
|
+
'mail.by': 'Кем',
|
|
234
|
+
'mail.description': 'Описание',
|
|
235
|
+
'mail.openCard': 'Открыть карточку на доске',
|
|
236
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
237
|
+
'mail.cleanupSubject': 'Карточки перемещены в корзину',
|
|
238
|
+
'mail.cleanupIntro': 'Следующие карточки перемещены в корзину:',
|
|
239
|
+
'mail.purgedIntro': 'Следующие карточки удалены окончательно:',
|
|
240
|
+
},
|
|
241
|
+
uk: {
|
|
242
|
+
'col.todo': 'До виконання',
|
|
243
|
+
'col.doing': 'У роботі',
|
|
244
|
+
'col.done': 'Готово',
|
|
245
|
+
'ev.cardCreated': 'Нова картка',
|
|
246
|
+
'ev.cardUpdated': 'Картку змінено',
|
|
247
|
+
'ev.cardMoved': 'Картку переміщено',
|
|
248
|
+
'ev.cardAssigned': 'Картку призначено',
|
|
249
|
+
'ev.cardDone': 'Картку виконано',
|
|
250
|
+
'ev.cardDeleted': 'Картку видалено',
|
|
251
|
+
'ev.cardDue': 'Термін картки',
|
|
252
|
+
'ev.cardRestored': 'Картку відновлено',
|
|
253
|
+
'ev.cardPurged': 'Картку видалено остаточно',
|
|
254
|
+
'col.trash': 'Кошик',
|
|
255
|
+
'mail.board': 'Дошка',
|
|
256
|
+
'mail.moved': 'Переміщено',
|
|
257
|
+
'mail.due': 'Термін',
|
|
258
|
+
'mail.assignees': 'Відповідальні',
|
|
259
|
+
'mail.by': 'Ким',
|
|
260
|
+
'mail.description': 'Опис',
|
|
261
|
+
'mail.openCard': 'Відкрити картку на дошці',
|
|
262
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
263
|
+
'mail.cleanupSubject': 'Картки переміщено в кошик',
|
|
264
|
+
'mail.cleanupIntro': 'Наведені картки переміщено в кошик:',
|
|
265
|
+
'mail.purgedIntro': 'Наведені картки видалено остаточно:',
|
|
266
|
+
},
|
|
267
|
+
'zh-cn': {
|
|
268
|
+
'col.todo': '待办',
|
|
269
|
+
'col.doing': '进行中',
|
|
270
|
+
'col.done': '已完成',
|
|
271
|
+
'ev.cardCreated': '新卡片',
|
|
272
|
+
'ev.cardUpdated': '卡片已修改',
|
|
273
|
+
'ev.cardMoved': '卡片已移动',
|
|
274
|
+
'ev.cardAssigned': '卡片已指派',
|
|
275
|
+
'ev.cardDone': '卡片已完成',
|
|
276
|
+
'ev.cardDeleted': '卡片已删除',
|
|
277
|
+
'ev.cardDue': '卡片到期',
|
|
278
|
+
'ev.cardRestored': '卡片已恢复',
|
|
279
|
+
'ev.cardPurged': '卡片已永久删除',
|
|
280
|
+
'col.trash': '回收站',
|
|
281
|
+
'mail.board': '看板',
|
|
282
|
+
'mail.moved': '已移动',
|
|
283
|
+
'mail.due': '到期',
|
|
284
|
+
'mail.assignees': '负责人',
|
|
285
|
+
'mail.by': '操作人',
|
|
286
|
+
'mail.description': '描述',
|
|
287
|
+
'mail.openCard': '在看板中打开卡片',
|
|
288
|
+
'mail.subjectPrefix': '[Kanban]',
|
|
289
|
+
'mail.cleanupSubject': '卡片已移入回收站',
|
|
290
|
+
'mail.cleanupIntro': '以下卡片已被移入回收站:',
|
|
291
|
+
'mail.purgedIntro': '以下卡片已被永久删除:',
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
function serverT(lang, key) {
|
|
296
|
+
const l = String(lang || 'en').toLowerCase();
|
|
297
|
+
const dict = STRINGS[l] || STRINGS.en;
|
|
298
|
+
return dict[key] != null ? dict[key] : STRINGS.en[key] != null ? STRINGS.en[key] : key;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
module.exports = { serverT, SERVER_LANGS: Object.keys(STRINGS) };
|