diff --git a/package.json b/package.json index c6334191..6ce8749b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@fontsource/montserrat": "4.4.5", "@material-ui/core": "5.0.0-beta.1", "@material-ui/icons": "5.0.0-beta.1", + "date-fns-tz": "^1.1.4", "react": "17.0.2", "react-clock": "3.0.0", "react-color-gradient-picker": "0.1.2", @@ -34,6 +35,7 @@ "@babel/plugin-transform-runtime": "^7.14.5", "@babel/preset-env": "^7.14.7", "@babel/preset-react": "^7.14.5", + "@eartharoid/deep-merge": "^0.0.1", "babel-loader": "^8.2.2", "babel-plugin-transform-react-class-to-function": "^1.2.2", "copy-webpack-plugin": "^9.0.1", @@ -45,7 +47,7 @@ "sass": "^1.35.2", "sass-loader": "^12.1.0", "source-map-loader": "^3.0.0", - "webpack": "^5.44.0", + "webpack": "^5.45.1", "webpack-cli": "^4.7.2", "webpack-dev-server": "^4.0.0-beta.3" }, diff --git a/scripts/updatetranslations.js b/scripts/updatetranslations.js new file mode 100644 index 00000000..e3f2f148 --- /dev/null +++ b/scripts/updatetranslations.js @@ -0,0 +1,12 @@ +const fs = require('fs'); +const merge = require('@eartharoid/deep-merge'); + +fs.readdirSync('../src/translations').forEach(file => { + if (file === 'en_GB.json') { + return; + } + + const newdata = merge(require('../src/translations/en_GB.json'), require('../src/translations/' + file)); + fs.writeFileSync('../src/translations/' + file, JSON.stringify(newdata, null, 2)); + fs.appendFileSync('../src/translations/' + file, '\n'); +}); diff --git a/src/components/modals/main/settings/sections/Advanced.jsx b/src/components/modals/main/settings/sections/Advanced.jsx index 2c08af41..d1fa5466 100644 --- a/src/components/modals/main/settings/sections/Advanced.jsx +++ b/src/components/modals/main/settings/sections/Advanced.jsx @@ -5,11 +5,14 @@ import FileUpload from '../FileUpload'; import Text from '../Text'; import Switch from '../Switch'; import ResetModal from '../ResetModal'; +import Dropdown from '../Dropdown'; import SettingsFunctions from '../../../../../modules/helpers/settings/modals'; import Modal from 'react-modal'; +const time_zones = require('../../../../widgets/time/timezones.json'); + export default class AdvancedSettings extends React.PureComponent { constructor() { super(); @@ -26,6 +29,12 @@ export default class AdvancedSettings extends React.PureComponent { <>

{advanced.title}

+ + + {time_zones.map((timezone) => ( + + ))} +

{advanced.data}

diff --git a/src/components/widgets/greeting/Greeting.jsx b/src/components/widgets/greeting/Greeting.jsx index 8a8e9fae..a3ecb789 100644 --- a/src/components/widgets/greeting/Greeting.jsx +++ b/src/components/widgets/greeting/Greeting.jsx @@ -1,6 +1,8 @@ import React from 'react'; +import { utcToZonedTime } from 'date-fns-tz'; import EventBus from '../../../modules/helpers/eventbus'; + import dtf from '../../../modules/helpers/date'; import './greeting.scss'; @@ -46,7 +48,12 @@ export default class Greeting extends React.PureComponent { getGreeting(time = (60000 - Date.now() % 60000)) { this.timer = setTimeout(() => { - const now = new Date(); + let now = new Date(); + const timezone = localStorage.getItem('timezone'); + if (timezone) { + now = utcToZonedTime(now, timezone); + } + const hour = now.getHours(); // Set the default greeting string to "Good evening" @@ -103,7 +110,7 @@ export default class Greeting extends React.PureComponent { componentDidMount() { EventBus.on('refresh', (data) => { - if (data === 'greeting') { + if (data === 'greeting' || data === 'timezone') { const element = document.querySelector('.greeting'); if (localStorage.getItem('greeting') === 'false') { diff --git a/src/components/widgets/time/Clock.jsx b/src/components/widgets/time/Clock.jsx index d52e233b..0b220a86 100644 --- a/src/components/widgets/time/Clock.jsx +++ b/src/components/widgets/time/Clock.jsx @@ -1,5 +1,6 @@ import React from 'react'; +import { utcToZonedTime } from 'date-fns-tz'; import EventBus from '../../../modules/helpers/eventbus'; import './clock.scss'; @@ -20,7 +21,11 @@ export default class Clock extends React.PureComponent { startTime(time = localStorage.getItem('seconds') === 'true' || localStorage.getItem('timeType') === 'analogue' ? (1000 - Date.now() % 1000) : (60000 - Date.now() % 60000)) { this.timer = setTimeout(() => { - const now = new Date(); + let now = new Date(); + const timezone = localStorage.getItem('timezone'); + if (timezone) { + now = utcToZonedTime(now, timezone); + } switch (localStorage.getItem('timeType')) { case 'percentageComplete': @@ -83,7 +88,7 @@ export default class Clock extends React.PureComponent { componentDidMount() { EventBus.on('refresh', (data) => { - if (data === 'clock') { + if (data === 'clock' || data === 'timezone') { const element = document.querySelector('.clock-container'); if (localStorage.getItem('time') === 'false') { diff --git a/src/components/widgets/time/Date.jsx b/src/components/widgets/time/Date.jsx index 860dde60..6c068017 100644 --- a/src/components/widgets/time/Date.jsx +++ b/src/components/widgets/time/Date.jsx @@ -1,5 +1,6 @@ import React from 'react'; +import { utcToZonedTime } from 'date-fns-tz'; import EventBus from '../../../modules/helpers/eventbus'; import dtf from '../../../modules/helpers/date'; @@ -33,7 +34,11 @@ export default class DateWidget extends React.PureComponent { } getDate() { - const date = new Date(); + let date = new Date(); + const timezone = localStorage.getItem('timezone'); + if (timezone) { + date = utcToZonedTime(date, timezone); + } if (localStorage.getItem('weeknumber') === 'true') { this.getWeekNumber(date); @@ -106,7 +111,7 @@ export default class DateWidget extends React.PureComponent { componentDidMount() { EventBus.on('refresh', (data) => { - if (data === 'date') { + if (data === 'date' || data === 'timezone') { const element = document.querySelector('.date'); if (localStorage.getItem('date') === 'false') { diff --git a/src/components/widgets/time/timezones.json b/src/components/widgets/time/timezones.json new file mode 100644 index 00000000..e90c8d6c --- /dev/null +++ b/src/components/widgets/time/timezones.json @@ -0,0 +1,350 @@ +[ + "Africa/Abidjan", + "Africa/Accra", + "Africa/Algiers", + "Africa/Bissau", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/El_Aaiun", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Khartoum", + "Africa/Lagos", + "Africa/Maputo", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Sao_Tome", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Asuncion", + "America/Atikokan", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Cayenne", + "America/Chicago", + "America/Chihuahua", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Fort_Nelson", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Port_of_Spain", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Sitka", + "America/St_Johns", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Vancouver", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Colombo", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kathmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Riyadh", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ulaanbaatar", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faroe", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/Stanley", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/Perth", + "Australia/Sydney", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Helsinki", + "Europe/Istanbul", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Lisbon", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Oslo", + "Europe/Paris", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zaporozhye", + "Europe/Zurich", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Reunion", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Wake", + "Pacific/Wallis" +] diff --git a/src/translations/de_DE.json b/src/translations/de_DE.json index 1dad90c7..67edc309 100644 --- a/src/translations/de_DE.json +++ b/src/translations/de_DE.json @@ -276,6 +276,10 @@ "custom_css": "Benutzerdefiniertes CSS", "custom_js": "Benutzerdefiniertes JS", "tab_name": "Tab Name", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Bitte beachten Sie, dass das Mue Team keinen Support leisten kann, wenn Sie den experimentellen Modus aktiviert haben. Bitte deaktivieren Sie ihn zuerst und schauen Sie, ob das Problem weiterhin auftritt, bevor Sie den Support kontaktieren." }, "experimental": { diff --git a/src/translations/en_GB.json b/src/translations/en_GB.json index 3e221e38..ad5dde3d 100644 --- a/src/translations/en_GB.json +++ b/src/translations/en_GB.json @@ -276,6 +276,10 @@ "custom_css": "Custom CSS", "custom_js": "Custom JS", "tab_name": "Tab name", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Please note that the Mue team cannot provide support if you have experimental mode on. Please disable it first and see if the issue continues to occur before contacting support." }, "experimental": { diff --git a/src/translations/en_US.json b/src/translations/en_US.json index a3654c8d..65582843 100644 --- a/src/translations/en_US.json +++ b/src/translations/en_US.json @@ -276,6 +276,10 @@ "custom_css": "Custom CSS", "custom_js": "Custom JS", "tab_name": "Tab name", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Please note that the Mue team cannot provide support if you have experimental mode on. Please disable it first and see if the issue continues to occur before contacting support." }, "experimental": { diff --git a/src/translations/es.json b/src/translations/es.json index 97a6cfdd..b4cf94f1 100644 --- a/src/translations/es.json +++ b/src/translations/es.json @@ -276,6 +276,10 @@ "custom_css": "CSS personalizado", "custom_js": "JS personalizado", "tab_name": "Nombre de la pestaña", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Por favor, ten en cuenta que el equipo de Mue no puede dar soporte si tienes el modo experimental activado. Por favor, desactívalo primero y comprueba si el problema sigue ocurriendo antes de contactar con el equipo de soporte." }, "experimental": { diff --git a/src/translations/fr.json b/src/translations/fr.json index ca9ca533..5c824c7f 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -276,6 +276,10 @@ "custom_css": "CSS personnalisé", "custom_js": "JS personnalisé", "tab_name": "Nom de l'onglet", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Veuillez noter que l'équipe Mue ne peut pas fournir d'assistance si vous avez activé le mode expérimental. Veuillez d'abord le désactiver et voir si le problème persiste avant de contacter le support." }, "experimental": { diff --git a/src/translations/nl.json b/src/translations/nl.json index 156bb47c..90f2bfbf 100644 --- a/src/translations/nl.json +++ b/src/translations/nl.json @@ -276,6 +276,10 @@ "custom_css": "Custom CSS", "custom_js": "Custom JS", "tab_name": "Tab name", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Please note that the Mue team cannot provide support if you have experimental mode on. Please disable it first and see if the issue continues to occur before contacting support." }, "experimental": { diff --git a/src/translations/no.json b/src/translations/no.json index 4f4fd090..1e166218 100644 --- a/src/translations/no.json +++ b/src/translations/no.json @@ -276,6 +276,10 @@ "custom_css": "Custom CSS", "custom_js": "Custom JS", "tab_name": "Tab name", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Please note that the Mue team cannot provide support if you have experimental mode on. Please disable it first and see if the issue continues to occur before contacting support." }, "experimental": { diff --git a/src/translations/ru.json b/src/translations/ru.json index a73495ce..9ec7107a 100644 --- a/src/translations/ru.json +++ b/src/translations/ru.json @@ -276,6 +276,10 @@ "custom_css": "Custom CSS", "custom_js": "Custom JS", "tab_name": "Tab name", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "Please note that the Mue team cannot provide support if you have experimental mode on. Please disable it first and see if the issue continues to occur before contacting support." }, "experimental": { @@ -370,6 +374,7 @@ }, "error": { "title": "Ошибка", + "description": "Could not connect to the server", "content": "Не удалось подключиться к серверу" }, "read_blog": "Прочитайте об изменениях в блоге", diff --git a/src/translations/zh_CN.json b/src/translations/zh_CN.json index 4fb30859..d470c432 100644 --- a/src/translations/zh_CN.json +++ b/src/translations/zh_CN.json @@ -276,6 +276,10 @@ "custom_css": "自定义 CSS", "custom_js": "自定义 JS", "tab_name": "标签页名称", + "timezone": { + "title": "Time Zone", + "automatic": "Automatic" + }, "experimental_warning": "请注意 Mue 团队无法提供实验性功能的支持。若您遇到问题,请先关闭实验性功能,再寻求帮助。" }, "experimental": {