mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-06-28 12:12:20 +00:00
commit
cccaa1f33d
@ -11,12 +11,13 @@ _This release is scheduled to be released on 2021-04-01._
|
||||
|
||||
### Added
|
||||
|
||||
- Added Galician language.
|
||||
- Added GitHub workflows for automated testing and changelog enforcement.
|
||||
- Added CodeCov badge to Readme.
|
||||
- Added CURRENTWEATHER_TYPE notification to currentweather and weather module, use it in compliments module.
|
||||
- Added `start:dev` command to the npm scripts for starting electron with devTools open.
|
||||
- Added logging when using deprecated modules weatherforecast or currentweather.
|
||||
- Portuguese translations for "MODULE_CONFIG_CHANGED" and PRECIP.
|
||||
- Added Portuguese translations for "MODULE_CONFIG_CHANGED" and "PRECIP".
|
||||
- Respect parameter ColoredSymbolOnly also for custom events
|
||||
- Added a new parameter to hide time portion on relative times
|
||||
- `module.show` has now the option for a callback on error.
|
||||
@ -39,6 +40,7 @@ _This release is scheduled to be released on 2021-04-01._
|
||||
- Exposed logger as node module for easier access for 3rd party modules
|
||||
- Replaced deprecated `request` package with `node-fetch` and `digest-fetch`
|
||||
- Refactored calendar fetcher
|
||||
- Cleaned up newsfeed module
|
||||
|
||||
### Removed
|
||||
|
||||
@ -59,6 +61,8 @@ _This release is scheduled to be released on 2021-04-01._
|
||||
- Fix e2e tests after spectron update
|
||||
- Fix updatenotification creating zombie processes by setting a timeout for the git process
|
||||
- Fix weather module openweathermap not loading if lat and lon set without onecall.
|
||||
- Fix calendar daylight savings offset calculation if recurring start date before 2007
|
||||
- Fix calendar time/date adjustment when time with GMT offset is different day (#2488)
|
||||
|
||||
## [2.14.0] - 2021-01-01
|
||||
|
||||
|
@ -482,7 +482,6 @@ Module.register("calendar", {
|
||||
|
||||
for (const calendarUrl in this.calendarData) {
|
||||
const calendar = this.calendarData[calendarUrl];
|
||||
console.log(calendar);
|
||||
for (const e in calendar) {
|
||||
const event = JSON.parse(JSON.stringify(calendar[e])); // clone object
|
||||
|
||||
|
@ -71,8 +71,13 @@ const CalendarUtils = {
|
||||
Log.debug("adjusted date=" + event.start);
|
||||
} else {
|
||||
// get the start time in that timezone
|
||||
Log.debug("start date/time=" + moment(event.start).toDate());
|
||||
start_offset = moment.tz(moment(event.start), event.start.tz).utcOffset();
|
||||
let es = moment(event.start);
|
||||
// check for start date prior to start of daylight changing date
|
||||
if (es.format("YYYY") < 2007) {
|
||||
es.set("year", 2013); // if so, use a closer date
|
||||
}
|
||||
Log.debug("start date/time=" + es.toDate());
|
||||
start_offset = moment.tz(es, event.start.tz).utcOffset();
|
||||
Log.debug("start offset=" + start_offset);
|
||||
|
||||
Log.debug("start date/time w tz =" + moment.tz(moment(event.start), event.start.tz).toDate());
|
||||
@ -291,14 +296,14 @@ const CalendarUtils = {
|
||||
let curEvent = event;
|
||||
let showRecurrence = true;
|
||||
|
||||
// get the offset of today where we are processing
|
||||
// this will be the correction we need to apply
|
||||
let nowOffset = new Date().getTimezoneOffset();
|
||||
// for full day events, the time might be off from RRULE/Luxon problem
|
||||
if (CalendarUtils.isFullDayEvent(event)) {
|
||||
Log.debug("fullday");
|
||||
// if the offset is negative, east of GMT where the problem is
|
||||
if (date.getTimezoneOffset() < 0) {
|
||||
// get the offset of today where we are processing
|
||||
// this will be the correction we need to apply
|
||||
let nowOffset = new Date().getTimezoneOffset();
|
||||
Log.debug("now offset is " + nowOffset);
|
||||
// reduce the time by the offset
|
||||
Log.debug(" recurring date is " + date + " offset is " + date.getTimezoneOffset());
|
||||
@ -309,6 +314,39 @@ const CalendarUtils = {
|
||||
duration = 24 * 60 * 60 * 1000;
|
||||
Log.debug("new recurring date is " + date);
|
||||
}
|
||||
} else {
|
||||
// not full day, but luxon can still screw up the date on the rule processing
|
||||
// get time zone offset of the rule calculated event
|
||||
let dateoffset = date.getTimezoneOffset();
|
||||
// reduce the time by the offset
|
||||
Log.debug(" recurring date is " + date + " offset is " + dateoffset);
|
||||
let dh = moment(date).format("HH");
|
||||
Log.debug(" recurring date is " + date + " offset is " + dateoffset / 60 + " Hour is " + dh);
|
||||
|
||||
// we need to correct the date to get back to the right event for
|
||||
if (dateoffset < 0) {
|
||||
// if the date hour is less than the offset
|
||||
if (dh < Math.abs(dateoffset / 60)) {
|
||||
// reduce the time by the offset
|
||||
Log.debug(" recurring date is " + date + " offset is " + dateoffset);
|
||||
// apply the correction to the date/time to get it UTC relative
|
||||
date = new Date(date.getTime() - Math.abs(nowOffset) * 60000);
|
||||
// the duration was calculated way back at the top before we could correct the start time..
|
||||
// fix it for this event entry
|
||||
//duration = 24 * 60 * 60 * 1000;
|
||||
Log.debug("new recurring date1 is " + date);
|
||||
}
|
||||
} else {
|
||||
// if the date hour is less than the offset
|
||||
if (24 - dh < Math.abs(dateoffset / 60)) {
|
||||
// apply the correction to the date/time back to right day
|
||||
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
|
||||
// the duration was calculated way back at the top before we could correct the start time..
|
||||
// fix it for this event entry
|
||||
//duration = 24 * 60 * 60 * 1000;
|
||||
Log.debug("new recurring date2 is " + date);
|
||||
}
|
||||
}
|
||||
}
|
||||
startDate = moment(date);
|
||||
|
||||
|
@ -66,6 +66,7 @@ Module.register("newsfeed", {
|
||||
|
||||
this.newsItems = [];
|
||||
this.loaded = false;
|
||||
this.error = null;
|
||||
this.activeItem = 0;
|
||||
this.scrollPosition = 0;
|
||||
|
||||
@ -87,8 +88,10 @@ Module.register("newsfeed", {
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
this.error = null;
|
||||
} else if (notification === "INCORRECT_URL") {
|
||||
Log.error("Newsfeed Error. Incorrect url: " + payload.url);
|
||||
this.error = `Incorrect url: ${payload.url}`;
|
||||
this.scheduleUpdateInterval();
|
||||
}
|
||||
},
|
||||
|
||||
@ -110,15 +113,20 @@ Module.register("newsfeed", {
|
||||
url: this.getActiveItemURL()
|
||||
};
|
||||
}
|
||||
if (this.error) {
|
||||
return {
|
||||
error: this.error
|
||||
};
|
||||
}
|
||||
if (this.newsItems.length === 0) {
|
||||
return {
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
if (this.activeItem >= this.newsItems.length) {
|
||||
this.activeItem = 0;
|
||||
}
|
||||
|
||||
const item = this.newsItems[this.activeItem];
|
||||
|
||||
return {
|
||||
@ -139,8 +147,7 @@ Module.register("newsfeed", {
|
||||
* Registers the feeds to be used by the backend.
|
||||
*/
|
||||
registerFeeds: function () {
|
||||
for (var f in this.config.feeds) {
|
||||
var feed = this.config.feeds[f];
|
||||
for (let feed of this.config.feeds) {
|
||||
this.sendSocketNotification("ADD_FEED", {
|
||||
feed: feed,
|
||||
config: this.config
|
||||
@ -154,12 +161,11 @@ Module.register("newsfeed", {
|
||||
* @param {object} feeds An object with feeds returned by the node helper.
|
||||
*/
|
||||
generateFeed: function (feeds) {
|
||||
var newsItems = [];
|
||||
for (var feed in feeds) {
|
||||
var feedItems = feeds[feed];
|
||||
let newsItems = [];
|
||||
for (let feed in feeds) {
|
||||
const feedItems = feeds[feed];
|
||||
if (this.subscribedToFeed(feed)) {
|
||||
for (var i in feedItems) {
|
||||
var item = feedItems[i];
|
||||
for (let item of feedItems) {
|
||||
item.sourceTitle = this.titleForFeed(feed);
|
||||
if (!(this.config.ignoreOldItems && Date.now() - new Date(item.pubdate) > this.config.ignoreOlderThan)) {
|
||||
newsItems.push(item);
|
||||
@ -168,8 +174,8 @@ Module.register("newsfeed", {
|
||||
}
|
||||
}
|
||||
newsItems.sort(function (a, b) {
|
||||
var dateA = new Date(a.pubdate);
|
||||
var dateB = new Date(b.pubdate);
|
||||
const dateA = new Date(a.pubdate);
|
||||
const dateB = new Date(b.pubdate);
|
||||
return dateB - dateA;
|
||||
});
|
||||
if (this.config.maxNewsItems > 0) {
|
||||
@ -178,8 +184,8 @@ Module.register("newsfeed", {
|
||||
|
||||
if (this.config.prohibitedWords.length > 0) {
|
||||
newsItems = newsItems.filter(function (value) {
|
||||
for (var i = 0; i < this.config.prohibitedWords.length; i++) {
|
||||
if (value["title"].toLowerCase().indexOf(this.config.prohibitedWords[i].toLowerCase()) > -1) {
|
||||
for (let word of this.config.prohibitedWords) {
|
||||
if (value["title"].toLowerCase().indexOf(word.toLowerCase()) > -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -190,18 +196,18 @@ Module.register("newsfeed", {
|
||||
newsItems.forEach((item) => {
|
||||
//Remove selected tags from the beginning of rss feed items (title or description)
|
||||
if (this.config.removeStartTags === "title" || this.config.removeStartTags === "both") {
|
||||
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||
if (item.title.slice(0, this.config.startTags[f].length) === this.config.startTags[f]) {
|
||||
item.title = item.title.slice(this.config.startTags[f].length, item.title.length);
|
||||
for (let startTag of this.config.startTags) {
|
||||
if (item.title.slice(0, startTag.length) === startTag) {
|
||||
item.title = item.title.slice(startTag.length, item.title.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.config.removeStartTags === "description" || this.config.removeStartTags === "both") {
|
||||
if (this.isShowingDescription) {
|
||||
for (let f = 0; f < this.config.startTags.length; f++) {
|
||||
if (item.description.slice(0, this.config.startTags[f].length) === this.config.startTags[f]) {
|
||||
item.description = item.description.slice(this.config.startTags[f].length, item.description.length);
|
||||
for (let startTag of this.config.startTags) {
|
||||
if (item.description.slice(0, startTag.length) === startTag) {
|
||||
item.description = item.description.slice(startTag.length, item.description.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -210,16 +216,16 @@ Module.register("newsfeed", {
|
||||
//Remove selected tags from the end of rss feed items (title or description)
|
||||
|
||||
if (this.config.removeEndTags) {
|
||||
for (let f = 0; f < this.config.endTags.length; f++) {
|
||||
if (item.title.slice(-this.config.endTags[f].length) === this.config.endTags[f]) {
|
||||
item.title = item.title.slice(0, -this.config.endTags[f].length);
|
||||
for (let endTag of this.config.endTags) {
|
||||
if (item.title.slice(-endTag.length) === endTag) {
|
||||
item.title = item.title.slice(0, -endTag.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isShowingDescription) {
|
||||
for (let f = 0; f < this.config.endTags.length; f++) {
|
||||
if (item.description.slice(-this.config.endTags[f].length) === this.config.endTags[f]) {
|
||||
item.description = item.description.slice(0, -this.config.endTags[f].length);
|
||||
for (let endTag of this.config.endTags) {
|
||||
if (item.description.slice(-endTag.length) === endTag) {
|
||||
item.description = item.description.slice(0, -endTag.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,7 +233,7 @@ Module.register("newsfeed", {
|
||||
});
|
||||
|
||||
// get updated news items and broadcast them
|
||||
var updatedItems = [];
|
||||
const updatedItems = [];
|
||||
newsItems.forEach((value) => {
|
||||
if (this.newsItems.findIndex((value1) => value1 === value) === -1) {
|
||||
// Add item to updated items list
|
||||
@ -250,8 +256,7 @@ Module.register("newsfeed", {
|
||||
* @returns {boolean} True if it is subscribed, false otherwise
|
||||
*/
|
||||
subscribedToFeed: function (feedUrl) {
|
||||
for (var f in this.config.feeds) {
|
||||
var feed = this.config.feeds[f];
|
||||
for (let feed of this.config.feeds) {
|
||||
if (feed.url === feedUrl) {
|
||||
return true;
|
||||
}
|
||||
@ -266,8 +271,7 @@ Module.register("newsfeed", {
|
||||
* @returns {string} The title of the feed
|
||||
*/
|
||||
titleForFeed: function (feedUrl) {
|
||||
for (var f in this.config.feeds) {
|
||||
var feed = this.config.feeds[f];
|
||||
for (let feed of this.config.feeds) {
|
||||
if (feed.url === feedUrl) {
|
||||
return feed.title || "";
|
||||
}
|
||||
@ -279,22 +283,20 @@ Module.register("newsfeed", {
|
||||
* Schedule visual update.
|
||||
*/
|
||||
scheduleUpdateInterval: function () {
|
||||
var self = this;
|
||||
|
||||
self.updateDom(self.config.animationSpeed);
|
||||
this.updateDom(this.config.animationSpeed);
|
||||
|
||||
// Broadcast NewsFeed if needed
|
||||
if (self.config.broadcastNewsFeeds) {
|
||||
self.sendNotification("NEWS_FEED", { items: self.newsItems });
|
||||
if (this.config.broadcastNewsFeeds) {
|
||||
this.sendNotification("NEWS_FEED", { items: this.newsItems });
|
||||
}
|
||||
|
||||
this.timer = setInterval(function () {
|
||||
self.activeItem++;
|
||||
self.updateDom(self.config.animationSpeed);
|
||||
this.timer = setInterval(() => {
|
||||
this.activeItem++;
|
||||
this.updateDom(this.config.animationSpeed);
|
||||
|
||||
// Broadcast NewsFeed if needed
|
||||
if (self.config.broadcastNewsFeeds) {
|
||||
self.sendNotification("NEWS_FEED", { items: self.newsItems });
|
||||
if (this.config.broadcastNewsFeeds) {
|
||||
this.sendNotification("NEWS_FEED", { items: this.newsItems });
|
||||
}
|
||||
}, this.config.updateInterval);
|
||||
},
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{ sourceTitle }}{% if config.showPublishDate %}, {% else %}: {% endif %}
|
||||
{% endif %}
|
||||
{% if config.showPublishDate %}
|
||||
{{ publishDate }}:
|
||||
{{ publishDate }}:
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -21,8 +21,12 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% elseif error %}
|
||||
<div class="small dimmed">
|
||||
{{ "MODULE_CONFIG_ERROR" | translate({MODULE_NAME: "Newsfeed", ERROR: error}) | safe }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="small dimmed">
|
||||
{{ "LOADING" | translate | safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
@ -19,8 +19,6 @@ const iconv = require("iconv-lite");
|
||||
* @class
|
||||
*/
|
||||
const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings) {
|
||||
const self = this;
|
||||
|
||||
let reloadTimer = null;
|
||||
let items = [];
|
||||
|
||||
@ -36,14 +34,14 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
/**
|
||||
* Request the new items.
|
||||
*/
|
||||
const fetchNews = function () {
|
||||
const fetchNews = () => {
|
||||
clearTimeout(reloadTimer);
|
||||
reloadTimer = null;
|
||||
items = [];
|
||||
|
||||
const parser = new FeedMe();
|
||||
|
||||
parser.on("item", function (item) {
|
||||
parser.on("item", (item) => {
|
||||
const title = item.title;
|
||||
let description = item.description || item.summary || item.content || "";
|
||||
const pubdate = item.pubdate || item.published || item.updated || item["dc:date"];
|
||||
@ -68,13 +66,13 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
}
|
||||
});
|
||||
|
||||
parser.on("end", function () {
|
||||
self.broadcastItems();
|
||||
parser.on("end", () => {
|
||||
this.broadcastItems();
|
||||
scheduleTimer();
|
||||
});
|
||||
|
||||
parser.on("error", function (error) {
|
||||
fetchFailedCallback(self, error);
|
||||
parser.on("error", (error) => {
|
||||
fetchFailedCallback(this, error);
|
||||
scheduleTimer();
|
||||
});
|
||||
|
||||
@ -87,7 +85,7 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
|
||||
fetch(url, { headers: headers })
|
||||
.catch((error) => {
|
||||
fetchFailedCallback(self, error);
|
||||
fetchFailedCallback(this, error);
|
||||
scheduleTimer();
|
||||
})
|
||||
.then((res) => {
|
||||
@ -134,7 +132,7 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
|
||||
return;
|
||||
}
|
||||
Log.info("Newsfeed-Fetcher: Broadcasting " + items.length + " items.");
|
||||
itemsReceivedCallback(self);
|
||||
itemsReceivedCallback(this);
|
||||
};
|
||||
|
||||
this.onReceive = function (callback) {
|
||||
|
@ -74,8 +74,8 @@ module.exports = NodeHelper.create({
|
||||
* and broadcasts these using sendSocketNotification.
|
||||
*/
|
||||
broadcastFeeds: function () {
|
||||
var feeds = {};
|
||||
for (var f in this.fetchers) {
|
||||
const feeds = {};
|
||||
for (let f in this.fetchers) {
|
||||
feeds[f] = this.fetchers[f].items();
|
||||
}
|
||||
this.sendSocketNotification("NEWS_ITEMS", feeds);
|
||||
|
@ -3,8 +3,7 @@
|
||||
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
|
||||
* MIT Licensed.
|
||||
*/
|
||||
|
||||
var config = {
|
||||
let config = {
|
||||
port: 8080,
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
|
38
tests/configs/modules/newsfeed/incorrect_url.js
Normal file
38
tests/configs/modules/newsfeed/incorrect_url.js
Normal file
@ -0,0 +1,38 @@
|
||||
/* Magic Mirror Test config newsfeed module
|
||||
*
|
||||
* MIT Licensed.
|
||||
*/
|
||||
let config = {
|
||||
port: 8080,
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
language: "en",
|
||||
timeFormat: 12,
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
modules: [
|
||||
{
|
||||
module: "newsfeed",
|
||||
position: "bottom_bar",
|
||||
config: {
|
||||
feeds: [
|
||||
{
|
||||
title: "Incorrect Url",
|
||||
url: "this is not a valid url"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = config;
|
||||
}
|
39
tests/configs/modules/newsfeed/prohibited_words.js
Normal file
39
tests/configs/modules/newsfeed/prohibited_words.js
Normal file
@ -0,0 +1,39 @@
|
||||
/* Magic Mirror Test config newsfeed module
|
||||
*
|
||||
* MIT Licensed.
|
||||
*/
|
||||
let config = {
|
||||
port: 8080,
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
language: "en",
|
||||
timeFormat: 12,
|
||||
units: "metric",
|
||||
electronOptions: {
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
enableRemoteModule: true
|
||||
}
|
||||
},
|
||||
|
||||
modules: [
|
||||
{
|
||||
module: "newsfeed",
|
||||
position: "bottom_bar",
|
||||
config: {
|
||||
feeds: [
|
||||
{
|
||||
title: "Rodrigo Ramirez Blog",
|
||||
url: "http://localhost:8080/tests/configs/data/feed_test_rodrigoramirez.xml"
|
||||
}
|
||||
],
|
||||
prohibitedWords: ["QPanel"]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = config;
|
||||
}
|
@ -8,7 +8,7 @@ const afterEach = global.afterEach;
|
||||
describe("Newsfeed module", function () {
|
||||
helpers.setupTimeout(this);
|
||||
|
||||
var app = null;
|
||||
let app = null;
|
||||
|
||||
beforeEach(function () {
|
||||
return helpers
|
||||
@ -29,8 +29,32 @@ describe("Newsfeed module", function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/newsfeed/default.js";
|
||||
});
|
||||
|
||||
it("show title newsfeed", function () {
|
||||
return app.client.waitUntilTextExists(".newsfeed .small", "Rodrigo Ramirez Blog", 10000).should.be.fulfilled;
|
||||
it("should show the newsfeed title", function () {
|
||||
return app.client.waitUntilTextExists(".newsfeed .newsfeed-source", "Rodrigo Ramirez Blog", 10000);
|
||||
});
|
||||
|
||||
it("should show the newsfeed article", function () {
|
||||
return app.client.waitUntilTextExists(".newsfeed .newsfeed-title", "QPanel", 10000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Custom configuration", function () {
|
||||
before(function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/newsfeed/prohibited_words.js";
|
||||
});
|
||||
|
||||
it("should not show articles with prohibited words", function () {
|
||||
return app.client.waitUntilTextExists(".newsfeed .newsfeed-title", "Problema VirtualBox", 10000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Invalid configuration", function () {
|
||||
before(function () {
|
||||
process.env.MM_CONFIG_FILE = "tests/configs/modules/newsfeed/incorrect_url.js";
|
||||
});
|
||||
|
||||
it("should show invalid url warning", function () {
|
||||
return app.client.waitUntilTextExists(".newsfeed .small", "Error in the Newsfeed module. Incorrect url:", 10000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -27,6 +27,7 @@
|
||||
"NNW": "NNW",
|
||||
|
||||
"MODULE_CONFIG_CHANGED": "Die Konfigurationsoptionen für das {MODULE_NAME} Modul haben sich geändert. \nBitte überprüfen Sie die Dokumentation.",
|
||||
"MODULE_CONFIG_ERROR": "Fehler im {MODULE_NAME} Modul. {ERROR}",
|
||||
|
||||
"UPDATE_NOTIFICATION": "Aktualisierung für MagicMirror² verfügbar.",
|
||||
"UPDATE_NOTIFICATION_MODULE": "Aktualisierung für das {MODULE_NAME} Modul verfügbar.",
|
||||
|
@ -27,6 +27,7 @@
|
||||
"NNW": "NNW",
|
||||
|
||||
"MODULE_CONFIG_CHANGED": "The configuration options for the {MODULE_NAME} module have changed.\nPlease check the documentation.",
|
||||
"MODULE_CONFIG_ERROR": "Error in the {MODULE_NAME} module. {ERROR}",
|
||||
|
||||
"UPDATE_NOTIFICATION": "MagicMirror² update available.",
|
||||
"UPDATE_NOTIFICATION_MODULE": "Update available for {MODULE_NAME} module.",
|
||||
|
39
translations/gl.json
Normal file
39
translations/gl.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"LOADING": "Cargando …",
|
||||
|
||||
"TODAY": "Hoxe",
|
||||
"TOMORROW": "Mañá",
|
||||
"DAYAFTERTOMORROW": "Pasado mañá",
|
||||
"RUNNING": "Remata en",
|
||||
"EMPTY": "Non hai próximos eventos.",
|
||||
|
||||
"WEEK": "Semana {weekNumber}",
|
||||
|
||||
"N": "N",
|
||||
"NNE": "NNE",
|
||||
"NE": "NE",
|
||||
"ENE": "ENE",
|
||||
"E": "E",
|
||||
"ESE": "ESE",
|
||||
"SE": "SE",
|
||||
"SSE": "SSE",
|
||||
"S": "S",
|
||||
"SSW": "SSW",
|
||||
"SW": "SW",
|
||||
"WSW": "WSW",
|
||||
"W": "W",
|
||||
"WNW": "WNW",
|
||||
"NW": "NW",
|
||||
"NNW": "NNW",
|
||||
|
||||
"MODULE_CONFIG_CHANGED": "Cambiaron as opcións de configuración para o módulo {MODULE_NAME}.\nPor favor, verifique a documentación.",
|
||||
"MODULE_CONFIG_ERROR": "Hai un erro no módulo {MODULE_NAME}. {ERROR}",
|
||||
|
||||
"UPDATE_NOTIFICATION": "Actualización dispoñible para MagicMirror².",
|
||||
"UPDATE_NOTIFICATION_MODULE": "Actualización dispoñible para o módulo {MODULE_NAME}.",
|
||||
"UPDATE_INFO_SINGLE": "A instalación actual está {COMMIT_COUNT} commits detrás da rama {BRANCH_NAME}.",
|
||||
"UPDATE_INFO_MULTIPLE": "A instalación actual está {COMMIT_COUNT} commits detrás da rama {BRANCH_NAME}.",
|
||||
|
||||
"FEELS": "Semella como {DEGREE}",
|
||||
"PRECIP": "Precipitacións"
|
||||
}
|
@ -46,7 +46,8 @@ var translations = {
|
||||
he: "translations/he.json", // Hebrew
|
||||
uk: "translations/uk.json", // Ukrainian
|
||||
hi: "translations/hi.json", // Hindi
|
||||
gu: "translations/gu.json" // Gujarati
|
||||
gu: "translations/gu.json", // Gujarati
|
||||
gl: "translations/gl.json" // Galego
|
||||
};
|
||||
|
||||
if (typeof module !== "undefined") {
|
||||
|
Loading…
x
Reference in New Issue
Block a user