diff --git a/.travis.yml b/.travis.yml index 3ece585de..b3ebc4f25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,36 @@ +matrix: + include: + - os: linux + dist: trusty + sudo: required + - os: osx + osx_image: xcode8.3 + language: node_js + before_script: - yarn add global gulp-cli@1.2.2 - yarn add global gulpjs/gulp#4.0 - yarn add global node-sass - yarn install + script: - yarn lint - travis_wait yarn build + node_js: - '7' -os: osx -osx_image: xcode8.3 + +before_install: +- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt install libx11-dev libxext-dev libxss-dev libxkbfile-dev; fi + cache: yarn + notifications: email: false slack: secure: NjEDG+6YvJvFNwRT8t8XyVR145m+Pb1pmYgdBeuhqtJbMAr0IOb0lLLW9ixKEsL1NU+0R58QGiG9qqY+lLnMNpDYjzluFo0gQtl2NJrULT4xUFDSu65XTwoutKyvj+hoCsHiwrSrO2dHTx3ZK2vsSueg+8jM/xss7dTLA6BcTYl14wTOU37PqFQZk9JYR+Dfq1Jjhy/mq4BiAsb/1clNIulkjmRjSm6R0XT4ZsZZfj0ifXhL4cLGsUv2n+iePiX6bLwZPFjXV1COYTBafbCu17gw3nRMdNMMTDLbwrXXdJZFS/EjFOPgOhwF7CkZ3kSpB2ZIcAJxG7iAUl5j+jHBXc5dafRbjzE4oYve1vPexLoV3NjV76uANUFkcli6eHYD0uJoUJGBRbRGWp+8Bbw9EcBsn4s3vbf5XqHX3S46zvGgqX+LyhyMJQtEG/iv+9XOsOql18ryyejij0z1K7DxpI0gLV1ATZCphY1Fyz1yZDGlYN4ej/Rl2P1Q3yXilweJRF7Ts04w4U9iuP1u598/w++CKSu4q4EeEuqT/hIeFQUKUkwCEsO4xa39vhLPaxKrG9UEUH8OXN+NPZyTAK/LKuIX7C56O1kwvWNMWlPmTcvsq2RghvNTwgSGUIO0EKZKrQYAEG3Y/veSt5CgZoNzLgc/6Xj+g7daxUo9heLy26A= + deploy: provider: s3 access_key_id: AKIAIVRBS4YFL4ZBLCLA @@ -29,6 +44,7 @@ deploy: acl: public_read on: all_branches: true + env: global: - secure: fddJzSmNYVX024jnhnFXEuAK1spEYi3y3RZdWaBtjQnzoObAxkcRW263JNpXQy+b7egnp2hSy8FvlQU+L967911F5Y70Pe3An4oI72hnS3DL4Njp2Dw5PwviwMA+X2ddWhzK4+k/JU6r8jBv1FGQ6ZjwSeaO/t8UKOsE8wDBFLRhnHqoR7QbM7zmKjzh/1oofunGbHsPOHmN4f7jBwSuSFTZltEENcQg3ZP++0NHU8UJdlpfqZOkro8v4AJMngAHeHlNtjwaAHdVv+6+kkwc4E/0Cy6YNyyBkbzipyngNY3GwnwzmNzvsfICD1TGklksjBlMQq7ld7eCiaYRNvyHVEmXJ17qlq7HhxkYgNy32hPRwb5Cv6o4M4tv8qS8UUk4W1RvBJ5fcmfZGQwGXPyQ/m85RJtrNfbYtr84jYcprTnSeji/9PuZv0f87dxELYm3DYmNUa1cgJqEdLUsEd0bMwUYNLnCSfu4ea2zxwir6LSBtJJCbGKxX87s5IOTrHkrWDe+PWd52v+UjQks7MBRlJnntTWo69Yy+ayXV1TnGVOHA5znHvPOvFlAF+y8tLGd4AGvehK1SAkf0+idmc9Q9xKk0QypT3ibjJui4D50p7sSajkzz3P2pUqOS/9HmjMfPMPN+Nl+48GU0CvB2aBGhdmp9vu54VaFzUaAGNGj4WI= diff --git a/CHANGELOG.md b/CHANGELOG.md index e6551ed51..5b5a0755c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ + +# [5.0.0-beta.12](https://github.com/meetfranz/franz/compare/v5.0.0-beta.11...v5.0.0-beta.12) (2017-11-05) + +### Features + +* **Menu:** Add "About Franz" Menu item to Windows/Linux ([a21b770](https://github.com/meetfranz/franz/commit/a21b770)) +* **Menu:** Add menu item to toggle (service) dev tools ([e8da383](https://github.com/meetfranz/franz/commit/e8da383)) +* **Translation:** Add italian translation ([ab348cc](https://github.com/meetfranz/franz/commit/ab348cc)) ([dnlup](https://github.com/dnlup)) + + +### Bug Fixes + +* **App:** Add checks to service url validation to prevent app freeze ([db8515f](https://github.com/meetfranz/franz/commit/db8515f)) +* **macOS:** Fix disable launch Franz on start ([34bba09](https://github.com/meetfranz/franz/commit/34bba09)) +* **Windows:** Launch Franz on start when selected ([34bba09](https://github.com/meetfranz/franz/commit/34bba09)) +* **Onboarding:** Fix issue with import of on-premise services ([7c7d27d](https://github.com/meetfranz/franz/commit/7c7d27d)) +* **Shortcuts:** Flip shortcut to navigate to next/previous service ([37d5923](https://github.com/meetfranz/franz/commit/37d5923)) +* **Windows:** Open Window when app is pinned to taskbar and minimized to system tray ([777814a](https://github.com/meetfranz/franz/commit/777814a)) +* **Recipes:** Recipe developers don't need Premium Supporter Account for debugging ([7a9947a](https://github.com/meetfranz/franz/commit/7a9947a)), closes [#23](https://github.com/meetfranz/franz/issues/23) + + + # [5.0.0-beta.11](https://github.com/meetfranz/franz/compare/v5.0.0-beta.10...v5.0.0-beta.11) (2017-10-24) diff --git a/electron-builder.yml b/electron-builder.yml index 0a01a03d8..3f7ad1e85 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -29,5 +29,5 @@ linux: - target: deb nsis: - perMachine: true + perMachine: false oneClick: true diff --git a/package.json b/package.json index dcb05bf6a..057dc6d60 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "franz", "productName": "Franz", "appId": "com.meetfranz.franz", - "version": "5.0.0-beta.11", + "version": "5.0.0-beta.12", "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.", "copyright": "adlk x franz - Stefan Malzner", "main": "index.js", @@ -27,12 +27,13 @@ "license": "Apache-2.0", "dependencies": { "@paulcbetts/system-idle-time": "^1.0.4", + "address-rfc2822": "^2.0.1", + "auto-launch": "https://github.com/meetfranz/node-auto-launch.git", "babel-polyfill": "^6.23.0", "babel-runtime": "^6.23.0", "classnames": "^2.2.5", "electron-fetch": "^1.1.0", "electron-spellchecker": "^1.2.0", - "electron-squirrel-startup": "^1.0.0", "electron-updater": "^2.4.3", "electron-window-state": "^4.1.0", "fs-extra": "^3.0.1", diff --git a/src/actions/service.js b/src/actions/service.js index cdd4bbf16..ea6ea5acc 100644 --- a/src/actions/service.js +++ b/src/actions/service.js @@ -63,6 +63,7 @@ export default { needle: PropTypes.string.isRequired, }, resetFilter: {}, + resetStatus: {}, reorder: { oldIndex: PropTypes.number.isRequired, newIndex: PropTypes.number.isRequired, diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index 8b0b7563c..932b70cdc 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js @@ -499,7 +499,7 @@ export default class ServerApi { return recipe; }), - ).catch(err => console.error(err)); + ).catch(err => console.error('Can\'t load recipe', err)); } _mapRecipePreviewModel(recipes) { @@ -562,9 +562,16 @@ export default class ServerApi { .filter(file => fs.statSync(path.join(recipesDirectory, file)).isDirectory() && file !== 'temp'); const recipes = paths.map((id) => { - // eslint-disable-next-line - const Recipe = require(id)(RecipeModel); - return new Recipe(loadRecipeConfig(id)); + let Recipe; + try { + // eslint-disable-next-line + Recipe = require(id)(RecipeModel); + return new Recipe(loadRecipeConfig(id)); + } catch (err) { + console.error(err); + } + + return false; }).filter(recipe => recipe.id).map((data) => { const recipe = data; @@ -579,7 +586,7 @@ export default class ServerApi { return recipes; } catch (err) { - console.debug('Folder `recipe/dev` does not exist'); + console.debug('Could not load dev recipes'); return false; } } diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 4aee1ec60..6a5c0f365 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js @@ -52,7 +52,7 @@ export default class Sidebar extends Component { - - -))); + {services.map((service, index) => ( + setActive({ serviceId: service.id })} + service={service} + index={index} + shortcutIndex={index + 1} + reload={() => reload({ serviceId: service.id })} + toggleNotifications={() => toggleNotifications({ serviceId: service.id })} + deleteService={() => deleteService({ serviceId: service.id })} + disableService={() => disableService({ serviceId: service.id })} + openSettings={openSettings} + /> + ))} +
  • + +
  • + + ); + } +} + +export default SortableContainer(TabBarSortableList); diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index fac0f6b9a..9b359a78e 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js @@ -69,10 +69,6 @@ const messages = defineMessages({ export default class EditServiceForm extends Component { static propTypes = { recipe: PropTypes.instanceOf(Recipe).isRequired, - // service: PropTypes.oneOfType([ - // PropTypes.object, - // PropTypes.instanceOf(Service), - // ]), service(props, propName) { if (props.action === 'edit' && !(props[propName] instanceof Service)) { return new Error(`'${propName}'' is expected to be of type 'Service' @@ -207,7 +203,7 @@ export default class EditServiceForm extends Component { )} {recipe.hasCustomUrl && ( - {user.isPremium ? ( + {user.isPremium || recipe.author.find(a => a.email === user.email) ? (
    {form.error === 'url-validation-error' && ( diff --git a/src/containers/settings/ServicesScreen.js b/src/containers/settings/ServicesScreen.js index d0580041f..8cfe5efbf 100644 --- a/src/containers/settings/ServicesScreen.js +++ b/src/containers/settings/ServicesScreen.js @@ -18,6 +18,7 @@ export default class ServicesScreen extends Component { componentWillUnmount() { this.props.actions.service.resetFilter(); + this.props.actions.service.resetStatus(); } deleteService() { @@ -70,6 +71,7 @@ ServicesScreen.wrappedComponent.propTypes = { toggleService: PropTypes.func.isRequired, filter: PropTypes.func.isRequired, resetFilter: PropTypes.func.isRequired, + resetStatus: PropTypes.func.isRequired, }).isRequired, }).isRequired, }; diff --git a/src/i18n/languages.js b/src/i18n/languages.js index 9860295b3..72d7b26c1 100644 --- a/src/i18n/languages.js +++ b/src/i18n/languages.js @@ -10,4 +10,8 @@ module.exports = { pl: 'Polish', ru: 'Русский', ua: 'Українська', + it: 'Italian', + 'es-ES': 'Español - España', + 'zh-Hant': 'Chinese (Traditional)', + 'nb-NO': 'Norsk', }; diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 0964169a8..80b66db08 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Neustarten & Aktualisierung installieren", "infobar.requiredRequestsFailed": "Dienste und Benutzerinformationen konnten nicht geladen werden", "sidebar.settings": "Einstellungen", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Willkommen bei Franz", "services.getStarted": "Loslegen", "settings.account.headline": "Konto", diff --git a/src/i18n/locales/el-GR.json b/src/i18n/locales/el-GR.json index dfada77a2..3710bc9a2 100644 --- a/src/i18n/locales/el-GR.json +++ b/src/i18n/locales/el-GR.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Επανεκκίνηση & εγκατάσταση ενημερώσεων", "infobar.requiredRequestsFailed": "Δεν ήταν δυνατή η φόρτωση υπηρεσιών και πληροφοριών χρηστών", "sidebar.settings": "Ρυθμίσεις", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Καλώς ορίσατε στον Franz", "services.getStarted": "Ξεκινήστε", "settings.account.headline": "Λογαριασμός", diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index b9ed51b83..b1d260f0a 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Restart & install update", "infobar.requiredRequestsFailed": "Could not load services and user information", "sidebar.settings": "Settings", + "sidebar.addNewService": "Add new service", "services.welcome": "Welcome to Franz", "services.getStarted": "Get started", "settings.account.headline": "Account", diff --git a/src/i18n/locales/es-ES.json b/src/i18n/locales/es-ES.json new file mode 100644 index 000000000..f71b07b2d --- /dev/null +++ b/src/i18n/locales/es-ES.json @@ -0,0 +1,168 @@ +{ + "global.api.unhealthy": "No se pudo conectar con los servicios online de Franz", + "global.notConnectedToTheInternet": "No estás conectado a internet.", + "welcome.signupButton": "Crea una cuenta gratuita", + "welcome.loginButton": "Accede a tu cuenta", + "welcome.slogan": "Mensajería hecha para ti", + "login.headline": "Acceder", + "login.email.label": "Dirección de Email", + "login.password.label": "Contraseña", + "login.submit.label": "Acceder", + "login.invalidCredentials": "Email o contraseña no válidos", + "login.tokenExpired": "Tu sesión ha expirado. Por favor, accede de nuevo.", + "login.serverLogout": "Tu sesión ha expirado. Por favor, accede de nuevo.", + "login.link.signup": "Crea una cuenta gratuita", + "login.link.password": "Restablecer contraseña", + "password.headline": "Restablecer contraseña", + "password.email.label": "Dirección de Email", + "password.submit.label": "Enviar", + "password.noUser": "No hemos encontrado un usuario con ese email", + "password.successInfo": "Por favor, comprueba tu email", + "password.link.signup": "Crea una cuenta gratuita", + "password.link.login": "Accede a tu cuenta", + "signup.headline": "Crea tu cuenta", + "signup.firstname.label": "Nombre", + "signup.lastname.label": "Apellidos", + "signup.email.label": "Dirección de Email", + "signup.company.label": "Empresa", + "signup.password.label": "Contraseña", + "signup.submit.label": "Crear cuenta", + "signup.link.login": "¿Tienes ya una cuenta? Accede", + "signup.emailDuplicate": "Ya existe un usuario con esa dirección de email", + "signup.legal.info": "Al crear una cuenta de Franz aceptas los", + "signup.legal.terms": "Términos de servicio", + "signup.legal.privacy": "Política de privacidad", + "pricing.headline": "Ayuda a Franz", + "pricing.support.label": "Selecciona tu plan de ayuda", + "pricing.submit.label": "Quiero ayudar al desarrollo de Franz", + "pricing.link.skipPayment": "No quiero ayudar al desarrollo de Franz.", + "import.headline": "Importa tus servicios de Franz 4", + "import.notSupportedHeadline": "Servicios aún no disponibles en Franz 5", + "import.submit.label": "Importar servicios", + "import.skip.label": "Quiero añadir los servicios manualmente", + "invite.submit.label": "Enviar invitaciones", + "invite.headline.friends": "Invita a 3 de tus amigos o compañeros", + "invite.name.label": "Nombre", + "invite.email.label": "Dirección de Email", + "invite.skip.label": "Prefiero hacer esto luego", + "subscription.submit.label": "Quiero ayudar al desarrollo de Franz", + "subscription.paymentSessionError": "No se ha podido inicializar el formulario de pago", + "subscription.includedFeatures": "La cuenta de Franz Premium Supporter incluye", + "subscription.features.onpremise": "Añadir servicios in-situ/alojados como HipChat", + "subscription.features.customServices": "Servicios privados para ti y tu equipo", + "subscription.features.encryptedSync": "Sincronización de sesión encriptada", + "subscription.features.vpn": "Soporte para Proxy y VPN", + "subscription.features.ads": "¡Sin anuncios, para siempre!", + "subscription.features.comingSoon": "próximamente", + "infobar.servicesUpdated": "Tus servicios han sido actualizados.", + "infobar.updateAvailable": "Una nueva actualización para Franz está disponible.", + "infobar.buttonReloadServices": "Volver a cargar servicios", + "infobar.buttonInstallUpdate": "Reiniciar e instalar actualizaciones", + "infobar.requiredRequestsFailed": "No se han podido cargar los servicios y la información de usuario", + "sidebar.settings": "Ajustes", + "services.welcome": "Bienvenido a Franz", + "services.getStarted": "Comienza", + "settings.account.headline": "Mi cuenta", + "settings.account.headlineSubscription": "Tu suscripción", + "settings.account.headlineUpgrade": "Mejora tu cuenta y ayuda a Franz", + "settings.account.headlineInvoices": "Recibos", + "settings.account.manageSubscription.label": "Administra tu suscripción", + "settings.account.accountType.basic": "Cuenta Básica", + "settings.account.accountType.premium": "Cuenta Premium Supporter", + "settings.account.account.editButton": "Editar cuenta", + "settings.account.invoiceDownload": "Descargar", + "settings.account.userInfoRequestFailed": "No se ha podido cargar la información de usuario", + "settings.account.tryReloadUserInfoRequest": "TPrueba otra vez", + "settings.account.headlineProfile": "Actualizar perfil", + "settings.account.headlineAccount": "Información de la cuenta", + "settings.account.headlinePassword": "Cambiar contraseña", + "settings.account.successInfo": "Tus cambios han sido guardados", + "settings.account.buttonSave": "Actualizar perfil", + "settings.account.mining.thankyou": "Gracias por ayudar a Franz con tu procesador.", + "settings.account.mining.active": "Ahora mismo estás haciendo {hashes} cálculos por segundo.", + "settings.account.mining.moreInformation": "Obtén más información", + "settings.account.mining.cancel": "Cancelar minado", + "settings.navigation.availableServices": "Servicios disponibles", + "settings.navigation.yourServices": "Tus servicios", + "settings.navigation.account": "Cuenta", + "settings.navigation.settings": "Ajustes", + "settings.navigation.logout": "Desconectar", + "settings.recipes.headline": "Servicios disponibles", + "settings.recipes.mostPopular": "Más populares", + "settings.recipes.all": "Todos los servicios", + "settings.recipes.dev": "Desarrollo", + "settings.recipes.nothingFound": "Lo sentimos, no hemos encontrado nada.", + "settings.recipes.servicesSuccessfulAddedInfo": "Servicio añadido con éxito", + "settings.service.form.saveButton": "Guardar servicio", + "settings.service.form.deleteButton": "Eliminar servicio", + "settings.service.form.availableServices": "Servicios disponibles", + "settings.service.form.yourServices": "Tus servicios", + "settings.service.form.addServiceHeadline": "Añadir {name}", + "settings.service.form.editServiceHeadline": "Editar {name}", + "settings.service.form.tabHosted": "Alojados", + "settings.service.form.tabOnPremise": "Autoalojados ⭐️", + "settings.service.form.customUrlValidationError": "No se ha podido validar el servidor personalizado {name}.", + "settings.service.form.customUrlPremiumInfo": "Para añadir servicios autoalojados necesitas una cuenta de Franz Premium Supporter.", + "settings.service.form.customUrlUpgradeAccount": "Mejora tu cuenta", + "settings.service.form.indirectMessageInfo": "Serás notificado sobre todos los nuevos mensajes en un canal, no solo @username, @channel, @here, ...", + "settings.service.error.headline": "Error", + "settings.service.error.goBack": "Volver a los servicios", + "settings.service.error.message": "No se ha podido cargar el servicio.", + "settings.services.tooltip.isDisabled": "Servicio deshabilitado", + "settings.services.tooltip.notificationsDisabled": "Notificaciones deshabilitadas", + "settings.services.headline": "Tus servicios", + "settings.services.noServicesAdded": "Aún no has añadido ningún servicio.", + "settings.services.discoverServices": "Descubrir servicios", + "settings.services.updatedInfo": "Tu cambios han sido guardados", + "settings.services.deletedInfo": "Se ha eliminado el servicio", + "settings.app.headline": "Ajustes", + "settings.app.headlineGeneral": "Generales", + "settings.app.headlineLanguage": "Idioma", + "settings.app.headlineUpdates": "Actualizaciones", + "settings.app.buttonSearchForUpdate": "Buscar actualizaciones", + "settings.app.buttonInstallUpdate": "Reiniciar e instalar actualizaciones", + "settings.app.updateStatusSearching": "Buscando actualizaciones", + "settings.app.updateStatusAvailable": "Actualización disponible, descargando...", + "settings.app.updateStatusUpToDate": "Estás utilizando la última versión de Franz", + "settings.app.form.autoLaunchOnStart": "Iniciar Franz al encender", + "settings.app.form.autoLaunchInBackground": "Abrir en segundo plano", + "settings.app.form.enableSystemTray": "Mostrar Franz en la barra de tareas", + "settings.app.form.minimizeToSystemTray": "Minimizar Franz a la barra de tareas", + "settings.app.form.runInBackground": "Mantener Franz abierto en segundo plano al cerrar la ventana", + "settings.app.form.language": "Idioma", + "settings.app.form.beta": "Incluir versiones beta", + "settings.app.currentVersion": "Versión actual:", + "settings.service.form.name": "Nombre", + "settings.service.form.enableService": "Habilitar servicio", + "settings.service.form.enableNotification": "Habilitar notificaciones", + "settings.service.form.team": "Equipo", + "settings.service.form.customUrl": "Servidor personalizado", + "settings.service.form.indirectMessages": "Mostrar señal para todos los mensajes nuevos", + "settings.user.form.firstname": "Nombre", + "settings.user.form.lastname": "Apellidos", + "settings.user.form.email": "Email", + "settings.user.form.currentPassword": "Contraseña actual", + "settings.user.form.newPassword": "Nueva contraseña", + "settings.user.form.accountType.label": "Tipo de cuenta", + "settings.user.form.accountType.individual": "Individual", + "settings.user.form.accountType.non-profit": "Sin ánimo de lucro", + "settings.user.form.accountType.company": "Empresa", + "subscription.type.free": "gratis", + "subscription.type.month": "mensual", + "subscription.type.year": "anual", + "subscription.type.mining": "Ayuda a Franz con tu procesador", + "subscription.mining.headline": "¿Cómo funciona?", + "subscription.mining.experimental": "experimental", + "subscription.mining.line1": "Al habilitar \"Ayuda a Franz con tu procesador\", Franz utilizará entre un 20-50% de tu CPU para minar la criptomoneda Monero, lo que equivale a aproximadamente 5$ anuales.", + "subscription.mining.line2": "Adaptaremos el uso de CPU basándonos en tu carga de trabajo para no vaciar tu batería ni realentizar tu ordenador.", + "subscription.mining.line3": "Siempre que el minero esté activo, tendrás acceso ilimitado a todas las ventajas de la cuenta Franz Premium Supporter.", + "subscription.mining.moreInformation": "Obtén más información sobre este plan.", + "subscriptionPopup.buttonCancel": "Cancelar", + "subscriptionPopup.buttonDone": "Hecho", + "tabs.item.reload": "Recargar", + "tabs.item.edit": "Editar", + "tabs.item.disableNotifications": "Desactivar notificaciones", + "tabs.item.enableNotification": "Activar notificaciones", + "tabs.item.disableService": "Deshabilitar servicio", + "tabs.item.deleteService": "Eliminar servicio" +} diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 84cf54492..2863f47e4 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Redémarrer et installer la mise à jour", "infobar.requiredRequestsFailed": "Impossible de charger les services et les informations de l'utilisateur", "sidebar.settings": "Paramètres", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Bienvenue sur Franz", "services.getStarted": "Commencer", "settings.account.headline": "Compte", diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json new file mode 100644 index 000000000..dd87599bb --- /dev/null +++ b/src/i18n/locales/it.json @@ -0,0 +1,168 @@ +{ + "global.api.unhealthy": "Impossibile connettersi ai servizi online di Franz", + "global.notConnectedToTheInternet": "Non sei connesso ad internet.", + "welcome.signupButton": "Iscriviti gratis", + "welcome.loginButton": "Accedi", + "welcome.slogan": "Messagistica che lavora per te", + "login.headline": "Accedi", + "login.email.label": "Indirizzo email", + "login.password.label": "Password", + "login.submit.label": "Accedi", + "login.invalidCredentials": "Email o password non validi", + "login.tokenExpired": "La tua sessione è scaduta, accedi di nuovo per favore.", + "login.serverLogout": "La tua sessione è scaduta, accedi di nuovo per favore.", + "login.link.signup": "Iscriviti gratis", + "login.link.password": "Reimposta password", + "password.headline": "Reimposta password", + "password.email.label": "Indirizzo email", + "password.submit.label": "Invia", + "password.noUser": "Non è stato trovato nessun utente con questa email", + "password.successInfo": "Per favore controlla la tua email", + "password.link.signup": "Iscriviti gratis", + "password.link.login": "Accedi", + "signup.headline": "Accedi", + "signup.firstname.label": "Nome", + "signup.lastname.label": "Cognome", + "signup.email.label": "Indirizzo email", + "signup.company.label": "Azienda", + "signup.password.label": "Password", + "signup.submit.label": "Registrati", + "signup.link.login": "Hai già fatto l'iscrizione? Accedi", + "signup.emailDuplicate": "Esiste già un utente con questo indirizzo email", + "signup.legal.info": "Iscrivendoti a Franz accetti", + "signup.legal.terms": "Termini di servizio", + "signup.legal.privacy": "Informativa sulla Privacy", + "pricing.headline": "Supporta Franz", + "pricing.support.label": "Seleziona il tuo piano di sostegno", + "pricing.submit.label": "Voglio sostenere lo sviluppo di Franz", + "pricing.link.skipPayment": "Non voglio sostenere lo sviluppo Franz.", + "import.headline": "Importa i tuoi servizi di Franz 4", + "import.notSupportedHeadline": "Servzi non ancora supportati in Franz 5", + "import.submit.label": "Importa servizi", + "import.skip.label": "Voglio aggiungere i servizi a mano", + "invite.submit.label": "Manda inviti", + "invite.headline.friends": "Invita 3 dei tuoi amici o colleghi", + "invite.name.label": "Nome", + "invite.email.label": "Indirizzo email", + "invite.skip.label": "Voglio farlo dopo", + "subscription.submit.label": "Voglio sostenere lo sviluppo di Franz", + "subscription.paymentSessionError": "Impossibile inizializzare il modulo di pagamento", + "subscription.includedFeatures": "La sottoscrizione a pagamento Franz Premium Supporter include", + "subscription.features.onpremise": "Agiunge servizi on-premise/hosted come HipChat", + "subscription.features.customServices": "Servizi privati per te ed il tuo team", + "subscription.features.encryptedSync": "Sincronizzazione sessione crittografata", + "subscription.features.vpn": "Supporto di Proxy e VPN", + "subscription.features.ads": "Nessuna pubblicità", + "subscription.features.comingSoon": "Presto disponibile", + "infobar.servicesUpdated": "I tuoi servizi sono stati aggiornati.", + "infobar.updateAvailable": "È disponibile un nuovo aggiornamento per Franz.", + "infobar.buttonReloadServices": "Ricarica i servizi", + "infobar.buttonInstallUpdate": "Riavvia e installa l'aggiornamento", + "infobar.requiredRequestsFailed": "Impossibile caricare i servizi e le informazioni dell'utente", + "sidebar.settings": "Impostazioni", + "services.welcome": "Benvenuto in Franz", + "services.getStarted": "Inizia", + "settings.account.headline": "Conto", + "settings.account.headlineSubscription": "La tua sottoscrizione", + "settings.account.headlineUpgrade": "Aggiorna il tuo conto e supporta Franz", + "settings.account.headlineInvoices": "Fatture", + "settings.account.manageSubscription.label": "Gestisci la tua sottoscrizione", + "settings.account.accountType.basic": "Conto Base", + "settings.account.accountType.premium": "Conto Premium Supporter", + "settings.account.account.editButton": "Modifica conto", + "settings.account.invoiceDownload": "Scarica", + "settings.account.userInfoRequestFailed": "Impossibile caricare le informazioni dell'utente", + "settings.account.tryReloadUserInfoRequest": "Prova ancora", + "settings.account.headlineProfile": "Aggiorna profilo", + "settings.account.headlineAccount": "Informazioni sul conto", + "settings.account.headlinePassword": "Cambia la password", + "settings.account.successInfo": "Le tue modifiche sono state salvate", + "settings.account.buttonSave": "Aggiorna profilo", + "settings.account.mining.thankyou": "Grazie per supportare Franz con la tua potenza di calcolo.", + "settings.account.mining.active": "Al momento stai eseguendo {hashes} calcoli al secondo.", + "settings.account.mining.moreInformation": "Ottieni piú informazioni", + "settings.account.mining.cancel": "Annulla mining", + "settings.navigation.availableServices": "Servizi disponibili", + "settings.navigation.yourServices": "I tuoi servizi", + "settings.navigation.account": "Conto", + "settings.navigation.settings": "Impostazioni", + "settings.navigation.logout": "Disconnetti", + "settings.recipes.headline": "Servizi disponibili", + "settings.recipes.mostPopular": "Piú popolari", + "settings.recipes.all": "Tutti i servizi", + "settings.recipes.dev": "Sviluppo", + "settings.recipes.nothingFound": "Mi dispiace, nessuno servizio corrisponde alla tua ricerca.", + "settings.recipes.servicesSuccessfulAddedInfo": "Servizio aggiunto con successo", + "settings.service.form.saveButton": "Salva servizio", + "settings.service.form.deleteButton": "Elimina servizio", + "settings.service.form.availableServices": "Servizi disponibili", + "settings.service.form.yourServices": "I tuoi servizi", + "settings.service.form.addServiceHeadline": "Aggiungi {name}", + "settings.service.form.editServiceHeadline": "Modifica {name}", + "settings.service.form.tabHosted": "Hosted", + "settings.service.form.tabOnPremise": "Self hosted ⭐️", + "settings.service.form.customUrlValidationError": "Impossibile validare il server personale {name}.", + "settings.service.form.customUrlPremiumInfo": "Per aggiungere servizi self hosted devi avere un conto Franz Premium Supporter.", + "settings.service.form.customUrlUpgradeAccount": "Aggiorna il tuo conto", + "settings.service.form.indirectMessageInfo": "Riceverai notifiche per tutti i nuovi messaggi in un canale, non solo @username, @channel, @here, ...", + "settings.service.error.headline": "Errore", + "settings.service.error.goBack": "Torna ai servizi", + "settings.service.error.message": "Impossibile caricare le specifiche del servizio.", + "settings.services.tooltip.isDisabled": "Il servizio è disabilitato", + "settings.services.tooltip.notificationsDisabled": "Le notifiche sono disabilitate", + "settings.services.headline": "I tuoi servizi", + "settings.services.noServicesAdded": "Non hai ancora aggiunto nessun servizio.", + "settings.services.discoverServices": "Trova servizi", + "settings.services.updatedInfo": "Le tue modifiche sono state salvate", + "settings.services.deletedInfo": "Il servizio è stato eliminato", + "settings.app.headline": "Impostazioni", + "settings.app.headlineGeneral": "Generale", + "settings.app.headlineLanguage": "Lingua", + "settings.app.headlineUpdates": "Aggiornamento", + "settings.app.buttonSearchForUpdate": "Controlla aggiornamento versione", + "settings.app.buttonInstallUpdate": "Riavvia e installa l'aggiornamento", + "settings.app.updateStatusSearching": "Sto cercando l'aggiornamento", + "settings.app.updateStatusAvailable": "Aggiornamento disponibile, scarico...", + "settings.app.updateStatusUpToDate": "You are using the latest version of Franz", + "settings.app.form.autoLaunchOnStart": "Lancia Franz all'avvio", + "settings.app.form.autoLaunchInBackground": "Apri in background", + "settings.app.form.enableSystemTray": "Mostra Franz nella zona delle notifiche di sistema", + "settings.app.form.minimizeToSystemTray": "Minimizza Franz nella zona delle notifiche di sistema", + "settings.app.form.runInBackground": "Maniteni Franz attivo in background quando chiudi la finestra", + "settings.app.form.language": "Lingua", + "settings.app.form.beta": "Includi versioni beta", + "settings.app.currentVersion": "Versione corrente:", + "settings.service.form.name": "Nome", + "settings.service.form.enableService": "Abilita servizio", + "settings.service.form.enableNotification": "Abilita notifiche", + "settings.service.form.team": "Team", + "settings.service.form.customUrl": "Server personale", + "settings.service.form.indirectMessages": "Mostra il badge del messaggio per tutti i nuovi messaggi", + "settings.user.form.firstname": "Nome", + "settings.user.form.lastname": "Cognome", + "settings.user.form.email": "Email", + "settings.user.form.currentPassword": "Password corrente", + "settings.user.form.newPassword": "Nuova password", + "settings.user.form.accountType.label": "Tipo di conto", + "settings.user.form.accountType.individual": "Individuale", + "settings.user.form.accountType.non-profit": "Non-Profit", + "settings.user.form.accountType.company": "Azienda", + "subscription.type.free": "gratis", + "subscription.type.month": "mese", + "subscription.type.year": "anno", + "subscription.type.mining": "Supporta Franz con della potenza di calcolo", + "subscription.mining.headline": "Come funziona?", + "subscription.mining.experimental": "sperimentale", + "subscription.mining.line1": "Abilitando \"Supporta Franz con della potenza di calcolo\",Franz userà circa il 20-50% della tua CPU per fare il mining della criptovaluta Monero che equivale approssimativamente a 5$/anno.", + "subscription.mining.line2": "Adatteremo l'utilizzo della CPU in base all tue abitudini di lavoro per non scaricare la tua batteria e rallentare la tua macchina.", + "subscription.mining.line3": "Fino a che il mining è attivo, avrai accesso illimitato a tutte le funzionalità del conto Franz Premium Supporter.", + "subscription.mining.moreInformation": "Ottieni più informazioni su questo piano.", + "subscriptionPopup.buttonCancel": "Annulla", + "subscriptionPopup.buttonDone": "Fatto", + "tabs.item.reload": "Ricarica", + "tabs.item.edit": "Modifica", + "tabs.item.disableNotifications": "Disabilita le notifiche", + "tabs.item.enableNotification": "Abilita le notifiche", + "tabs.item.disableService": "Disabilita servizio", + "tabs.item.deleteService": "Elimina servizio" +} diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index a283154c9..98b7cbb19 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -60,12 +60,13 @@ "infobar.buttonInstallUpdate": "再起動して更新をインストールする", "infobar.requiredRequestsFailed": "サービスとユーザー情報が読み込めません", "sidebar.settings": "設定", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Franzにようこそ", "services.getStarted": "はじめる", "settings.account.headline": "アカウント", "settings.account.headlineSubscription": "サブスクリプション内容", "settings.account.headlineUpgrade": "アカウントをアップグレードし、Franzを支援する", - "settings.account.headlineInvoices": "Invoices", + "settings.account.headlineInvoices": "インボイス", "settings.account.manageSubscription.label": "サブスクリプションの管理", "settings.account.accountType.basic": "Basicアカウント", "settings.account.accountType.premium": "Premium Supporterアカウント", @@ -126,6 +127,7 @@ "settings.app.updateStatusUpToDate": "お使いのFranzは最新です", "settings.app.form.autoLaunchOnStart": "システム起動時にFranzを開く", "settings.app.form.autoLaunchInBackground": "バックグラウンドで開く", + "settings.app.form.enableSystemTray": "Franzをシステムトレイに表示する", "settings.app.form.minimizeToSystemTray": "Franzをシステムトレイに最小化する", "settings.app.form.runInBackground": "ウインドウを閉じた際にFranzをバックグラウンドで実行させておく", "settings.app.form.language": "言語", @@ -150,7 +152,7 @@ "subscription.type.month": "月間", "subscription.type.year": "年間", "subscription.type.mining": "PCの処理能力を使ってFranzを支援する", - "subscription.mining.headline": "これはどのように動作しているか", + "subscription.mining.headline": "これはどのような仕組みですか", "subscription.mining.experimental": "実験的", "subscription.mining.line1": "\"PCの処理能力を使ってFranzを支援する\"を有効にすることで、Franzはおよそ20-50%のCPUパワーを暗号通貨Moneroのマイニングに使用し、これはおよそ年間で5ドル分にあたります。", "subscription.mining.line2": "処理能力に基づいてCPUの使用率を適応しますのでバッテリーを無駄に消費したり、システムを遅くすることはありません。", diff --git a/src/i18n/locales/nb-NO.json b/src/i18n/locales/nb-NO.json new file mode 100644 index 000000000..976c54787 --- /dev/null +++ b/src/i18n/locales/nb-NO.json @@ -0,0 +1,169 @@ +{ + "global.api.unhealthy": "Kan ikke koble til Franz' tjenester", + "global.notConnectedToTheInternet": "Du er ikke koblet til internett.", + "welcome.signupButton": "Opprett en gratis konto", + "welcome.loginButton": "Logg inn til din konto", + "welcome.slogan": "Teksting som funker for deg", + "login.headline": "Logg inn", + "login.email.label": "Email adresse", + "login.password.label": "Passord", + "login.submit.label": "Logg inn", + "login.invalidCredentials": "Ugyldig email eller passord", + "login.tokenExpired": "Din økt utløpte, vennligst logg inn igjen.", + "login.serverLogout": "Din økt utløpte, vennligst logg inn igjen.", + "login.link.signup": "Opprett en gratis konto", + "login.link.password": "Reset passord", + "password.headline": "Reset passord", + "password.email.label": "Email adresse", + "password.submit.label": "Send inn", + "password.noUser": "Ingen bruker med den emailen finnes", + "password.successInfo": "Vennligst sjekk din email", + "password.link.signup": "Opprett en gratis konto", + "password.link.login": "Logg inn til din konto", + "signup.headline": "Registrer deg", + "signup.firstname.label": "Fornavn", + "signup.lastname.label": "Etternavn", + "signup.email.label": "Email adresse", + "signup.company.label": "Firma", + "signup.password.label": "Passord", + "signup.submit.label": "Opprett konto", + "signup.link.login": "Har du allerede en konto? Logg inn", + "signup.emailDuplicate": "En konto med den epost adresse eksiterer allerede", + "signup.legal.info": "Ved å opprette en Franz konto aksepterer du", + "signup.legal.terms": "Vilkår for bruk", + "signup.legal.privacy": "Personvern", + "pricing.headline": "Støtt Franz", + "pricing.support.label": "Velg din støtteplan", + "pricing.submit.label": "Jeg vil støtte utviklingen av Franz", + "pricing.link.skipPayment": "Jeg vil ikke støtte utviklingen av Franz.", + "import.headline": "Importer dine Franz 4 tjenester", + "import.notSupportedHeadline": "Tjenester ikke enda støttet i Franz 5", + "import.submit.label": "Importer tjenester", + "import.skip.label": "Jeg vil legge til en tjeneste manuelt", + "invite.submit.label": "Send invitasjoner", + "invite.headline.friends": "Inviter 3 av dine venner eller kolleger", + "invite.name.label": "Navn", + "invite.email.label": "Email adresse", + "invite.skip.label": "Jeg vil gjøre dette senere", + "subscription.submit.label": "Jeg vil ikke støtte utviklingen av Franz", + "subscription.paymentSessionError": "Kunne ikke laste betalingsskjemaet", + "subscription.includedFeatures": "Betalte Franz Premium konto inkluderer", + "subscription.features.onpremise": "Legg til on-premise/hosted tjenester som HipChat", + "subscription.features.customServices": "Private tjenester for deg og ditt lag", + "subscription.features.encryptedSync": "Kryptert øktsynkronisering", + "subscription.features.vpn": "Proxy & VPN støtte", + "subscription.features.ads": "Ingen annonser, noensinne!", + "subscription.features.comingSoon": "Kommer snart", + "infobar.servicesUpdated": "Dine tjenester er oppdatert.", + "infobar.updateAvailable": "En ny oppdatering for Franz er tilgjengelig.", + "infobar.buttonReloadServices": "Oppdater tjenester", + "infobar.buttonInstallUpdate": "Restart & installer oppdatering", + "infobar.requiredRequestsFailed": "Kunne ikke laste tjenester og brukerinformasjon", + "sidebar.settings": "Innstillinger", + "sidebar.addNewService": "Legg til ny tjeneste", + "services.welcome": "Velkommen til Franz", + "services.getStarted": "Kom i gang", + "settings.account.headline": "Konto", + "settings.account.headlineSubscription": "Ditt abonnement", + "settings.account.headlineUpgrade": "Oppgrader din konto og støtt Franz", + "settings.account.headlineInvoices": "Fakturaer", + "settings.account.manageSubscription.label": "Administrer dine abonnement", + "settings.account.accountType.basic": "Enkel Konto", + "settings.account.accountType.premium": "Premium Konto", + "settings.account.account.editButton": "Rediger konto", + "settings.account.invoiceDownload": "Last ned", + "settings.account.userInfoRequestFailed": "Kunne ikke laste brukerinformasjon", + "settings.account.tryReloadUserInfoRequest": "Prøv igjen", + "settings.account.headlineProfile": "Oppdater profil", + "settings.account.headlineAccount": "Kontoinformasjon", + "settings.account.headlinePassword": "Endre passord", + "settings.account.successInfo": "Dine endringer er lagret", + "settings.account.buttonSave": "Oppdater profil", + "settings.account.mining.thankyou": "Takk for at du støtter Franz med din prosessorkraft.", + "settings.account.mining.active": "Du utfører nå {hashes} beregninger per sekund.", + "settings.account.mining.moreInformation": "Få mer informasjon", + "settings.account.mining.cancel": "Avbryt mining", + "settings.navigation.availableServices": "Tilgjengelige tjenester", + "settings.navigation.yourServices": "Dine tjenester", + "settings.navigation.account": "Konto", + "settings.navigation.settings": "Innstillinger", + "settings.navigation.logout": "Logg ut", + "settings.recipes.headline": "Tilgjengelige tjenester", + "settings.recipes.mostPopular": "Mest populære", + "settings.recipes.all": "Alle tjenester", + "settings.recipes.dev": "Utvikling", + "settings.recipes.nothingFound": "Beklager, men ingen tjeneste samsvarer med søkeordet ditt.", + "settings.recipes.servicesSuccessfulAddedInfo": "Tjenesten ble lagt til", + "settings.service.form.saveButton": "Lagre tjeneste", + "settings.service.form.deleteButton": "Slett tjeneste", + "settings.service.form.availableServices": "Tilgjengelige tjenester", + "settings.service.form.yourServices": "Dine tjenester", + "settings.service.form.addServiceHeadline": "Legg til {name}", + "settings.service.form.editServiceHeadline": "Rediger {name}", + "settings.service.form.tabHosted": "Hosted", + "settings.service.form.tabOnPremise": "Selv hosted ⭐️", + "settings.service.form.customUrlValidationError": "Kunne ikke validere egendefinert {name} server.", + "settings.service.form.customUrlPremiumInfo": "For å legge til selvhost-baserte tjenester trenger du en Franz Premium konto.", + "settings.service.form.customUrlUpgradeAccount": "Oppgrader din konto", + "settings.service.form.indirectMessageInfo": "Du vil bli varslet om alle nye meldinger i en kanal, ikke bare @brukernavn, @kanal, @here, ...", + "settings.service.error.headline": "Error", + "settings.service.error.goBack": "Tilbake til tjenester", + "settings.service.error.message": "Kunne ikke laste tjeneste oppskrift.", + "settings.services.tooltip.isDisabled": "Tjenesten er deaktivert", + "settings.services.tooltip.notificationsDisabled": "Varsler er deaktivert", + "settings.services.headline": "Dine tjenester", + "settings.services.noServicesAdded": "Du har ikke lagt til noen tjenester enda.", + "settings.services.discoverServices": "Oppdag tjenester", + "settings.services.updatedInfo": "Dine endringer er lagret", + "settings.services.deletedInfo": "Tjenester har blitt slettet", + "settings.app.headline": "Innstillinger", + "settings.app.headlineGeneral": "Genelert", + "settings.app.headlineLanguage": "Språk", + "settings.app.headlineUpdates": "Oppdateringer", + "settings.app.buttonSearchForUpdate": "Se etter oppdateringer", + "settings.app.buttonInstallUpdate": "Restart & installer oppdatering", + "settings.app.updateStatusSearching": "Søker etter en oppdatering", + "settings.app.updateStatusAvailable": "Oppdatering tilgjengelig, laster ned...", + "settings.app.updateStatusUpToDate": "Du bruker siste versjon av Franz", + "settings.app.form.autoLaunchOnStart": "Start Franz ved oppstart", + "settings.app.form.autoLaunchInBackground": "Åpne i bakgrunnen", + "settings.app.form.enableSystemTray": "Vis Franz i systemfeltet", + "settings.app.form.minimizeToSystemTray": "Minimer Franz til systemfeltet", + "settings.app.form.runInBackground": "Behold Franz i bakgrunnen når du lukker vinduet", + "settings.app.form.language": "Språk", + "settings.app.form.beta": "Inkluder beta versjoner", + "settings.app.currentVersion": "Gjeldende versjon:", + "settings.service.form.name": "Navn", + "settings.service.form.enableService": "Slå på tjeneste", + "settings.service.form.enableNotification": "Slå på varsler", + "settings.service.form.team": "Lag", + "settings.service.form.customUrl": "Egendefinert server", + "settings.service.form.indirectMessages": "Vis merke for alle nye meldinger", + "settings.user.form.firstname": "Fornavn", + "settings.user.form.lastname": "Etternavn", + "settings.user.form.email": "Email", + "settings.user.form.currentPassword": "Gjeldende passord", + "settings.user.form.newPassword": "Nytt passord", + "settings.user.form.accountType.label": "Konto type", + "settings.user.form.accountType.individual": "Individuell", + "settings.user.form.accountType.non-profit": "Non-Profit", + "settings.user.form.accountType.company": "Firma", + "subscription.type.free": "gratis", + "subscription.type.month": "måned", + "subscription.type.year": "år", + "subscription.type.mining": "Støtt Franz med prosessorkraft", + "subscription.mining.headline": "Hvordan fungerer dette?", + "subscription.mining.experimental": "eksperimental", + "subscription.mining.line1": "Ved å aktivere \"Støtt Franz med prosessorkraft\" vil Franz bruke cirka 20-50% av prosessore din til å mine kryptovalutaen Monero, som vil tilsvare omtrent $5/år", + "subscription.mining.line2": "Vi vil tilpasse prosessor bruken basert på arbeidsadferd for å ikke tømme batteriet og senke hastigheten på maskinen din.", + "subscription.mining.line3": "Så lenge du miner, har du ubegrenset tilgang til alle Franz Premium funksjoner.", + "subscription.mining.moreInformation": "Få mer informasjon om denne planen.", + "subscriptionPopup.buttonCancel": "Kanseller", + "subscriptionPopup.buttonDone": "Ferdig", + "tabs.item.reload": "Reload", + "tabs.item.edit": "Rediger", + "tabs.item.disableNotifications": "Deaktiver varsler", + "tabs.item.enableNotification": "Aktiver varsler", + "tabs.item.disableService": "Deaktiver tjeneste", + "tabs.item.deleteService": "Slett tjeneste" +} diff --git a/src/i18n/locales/nl-BE.json b/src/i18n/locales/nl-BE.json index 40cc14c50..a19d51b2b 100644 --- a/src/i18n/locales/nl-BE.json +++ b/src/i18n/locales/nl-BE.json @@ -54,12 +54,13 @@ "subscription.features.vpn": "Proxy & VPN ondersteuning", "subscription.features.ads": "Geen reclame, nooit!", "subscription.features.comingSoon": "komt binnenkort", - "infobar.servicesUpdated": "Je services zijn geüpdated.", + "infobar.servicesUpdated": "Je services zijn geüpdatet.", "infobar.updateAvailable": "Er is een nieuwe update van Franz beschikbaar.", "infobar.buttonReloadServices": "Services herladen", "infobar.buttonInstallUpdate": "Herstarten & update installeren", "infobar.requiredRequestsFailed": "Kon services en gebruikersinformatie niet laden", "sidebar.settings": "Instellingen", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Welkom bij Franz", "services.getStarted": "Begin", "settings.account.headline": "Account", @@ -76,7 +77,7 @@ "settings.account.headlineProfile": "Profiel aanpassen", "settings.account.headlineAccount": "Accountinformatie", "settings.account.headlinePassword": "Wachtwoord veranderen", - "settings.account.successInfo": "Je wijzigingen werden bewaard", + "settings.account.successInfo": "Je wijzigingen zijn opgeslagen", "settings.account.buttonSave": "Profiel aanpassen", "settings.account.mining.thankyou": "Bedankt om Franz te steunen met je rekenkracht.", "settings.account.mining.active": "Op dit moment maak je {hashes} berekeningen per seconde.", @@ -113,7 +114,7 @@ "settings.services.headline": "Jouw services", "settings.services.noServicesAdded": "Je hebt nog geen services toegevoegd.", "settings.services.discoverServices": "Services ontdekken", - "settings.services.updatedInfo": "Je veranderingen werden bewaard", + "settings.services.updatedInfo": "Je wijzigingen werden bewaard", "settings.services.deletedInfo": "Service werd verwijderd", "settings.app.headline": "Instellingen", "settings.app.headlineGeneral": "Algemeen", diff --git a/src/i18n/locales/nl.json b/src/i18n/locales/nl.json index 159d1f328..aee1a52c8 100644 --- a/src/i18n/locales/nl.json +++ b/src/i18n/locales/nl.json @@ -10,7 +10,7 @@ "login.submit.label": "Inloggen", "login.invalidCredentials": "E-mailadres of wachtwoord ongeldig", "login.tokenExpired": "De sessie is verlopen, log opnieuw in alsjeblieft.", - "login.serverLogout": "De sessie is verlopen, log opnieuw in alsjeblieft..", + "login.serverLogout": "De sessie is verlopen, log opnieuw in alsjeblieft.", "login.link.signup": "Maak een gratis account", "login.link.password": "Wachtwoord vergeten", "password.headline": "Wachtwoord vergeten", @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Herstart & installeer update", "infobar.requiredRequestsFailed": "Kon services en gebruikerinformatie niet laden", "sidebar.settings": "Instellingen", + "sidebar.addNewService": "Voeg nieuwe service toe", "services.welcome": "Welkom bij Franz", "services.getStarted": "Beginnen", "settings.account.headline": "Account", @@ -157,7 +158,7 @@ "subscription.mining.line2": "We zullen het CPU-gebruik aanpassen aan je gebruik en daarmee voorkomen dat de batterij niet leegloopt of dat jij en je werk afgeremd wordt.", "subscription.mining.line3": "Zolang de miner actief is, heb je onbeperkt toegang tot alle Franz Premium Supporter Features.", "subscription.mining.moreInformation": "Verkrijg meer informatie over dit plan.", - "subscriptionPopup.buttonCancel": "Cancel", + "subscriptionPopup.buttonCancel": "Annuleer", "subscriptionPopup.buttonDone": "Klaar", "tabs.item.reload": "Herlaad", "tabs.item.edit": "Bewerk", diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index 1a8e9ad54..a884ef319 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Uruchom ponownie i zainstaluj aktualizacje", "infobar.requiredRequestsFailed": "Nie można wczytać usług i informacji o użytkowniku", "sidebar.settings": "Ustawienia", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Witaj w aplikcji Franz", "services.getStarted": "Zacznij", "settings.account.headline": "Konto", diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index 38f0836a7..8a139a4f5 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -59,7 +59,8 @@ "infobar.buttonReloadServices": "Recarregar serviços", "infobar.buttonInstallUpdate": "Reiniciar & instalar atualização", "infobar.requiredRequestsFailed": "Não foi possível carregar serviços e informações do usuário", - "sidebar.settings": "Configurações", + "sidebar.addNewService": "!!!Add new service", + "sidebar.settings": "Ajustes", "services.welcome": "Bem-vindo ao Franz", "services.getStarted": "Começar", "settings.account.headline": "Conta", @@ -85,7 +86,7 @@ "settings.navigation.availableServices": "Serviços disponíveis", "settings.navigation.yourServices": "Seus serviços", "settings.navigation.account": "Conta", - "settings.navigation.settings": "Configurações", + "settings.navigation.settings": "Ajustes", "settings.navigation.logout": "Logout", "settings.recipes.headline": "Serviços disponíveis", "settings.recipes.mostPopular": "Mais populares", @@ -115,7 +116,7 @@ "settings.services.discoverServices": "Descobrir serviços", "settings.services.updatedInfo": "Suas mudanças foram salvas", "settings.services.deletedInfo": "Serviço apagado", - "settings.app.headline": "Configurações", + "settings.app.headline": "Ajustes", "settings.app.headlineGeneral": "Geral", "settings.app.headlineLanguage": "Idioma", "settings.app.headlineUpdates": "Atualizações", @@ -126,6 +127,7 @@ "settings.app.updateStatusUpToDate": "Você está usando a última versão do Franz", "settings.app.form.autoLaunchOnStart": "Abrir o Franz iniciar o sistema", "settings.app.form.autoLaunchInBackground": "Abrir no fundo", + "settings.app.form.enableSystemTray": "Mostrar o Franz na bandeja do sistema", "settings.app.form.minimizeToSystemTray": "Minimizar o Franz para a bandeja do sistema", "settings.app.form.runInBackground": "Manter o Franz no fundo quando fechar a janela", "settings.app.form.language": "Idioma", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 44ced9e43..97b746097 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Перезапустить и обновить", "infobar.requiredRequestsFailed": "Невозможно загрузить сервисы и информацию пользователя", "sidebar.settings": "Настройки", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Добро пожаловать во Franz", "services.getStarted": "Начать работу", "settings.account.headline": "Аккаунт", diff --git a/src/i18n/locales/ua.json b/src/i18n/locales/ua.json index 63135e52c..fcb99c4e4 100644 --- a/src/i18n/locales/ua.json +++ b/src/i18n/locales/ua.json @@ -60,6 +60,7 @@ "infobar.buttonInstallUpdate": "Перезавантажити і встановити оновлення", "infobar.requiredRequestsFailed": "Не вдалося завантажити сервіси та інформацію користувача", "sidebar.settings": "Налаштування", + "sidebar.addNewService": "!!!Add new service", "services.welcome": "Ласкаво просимо в Franz", "services.getStarted": "Почати", "settings.account.headline": "Акаунт", diff --git a/src/i18n/locales/zh-Hant.json b/src/i18n/locales/zh-Hant.json new file mode 100644 index 000000000..e52b9ca26 --- /dev/null +++ b/src/i18n/locales/zh-Hant.json @@ -0,0 +1,168 @@ +{ + "global.api.unhealthy": "無法連接到Franz網路服務", + "global.notConnectedToTheInternet": "您未連上網際網路", + "welcome.signupButton": "建立一個免費帳戶", + "welcome.loginButton": "登入", + "welcome.slogan": "Messaging that works for you", + "login.headline": "登入", + "login.email.label": "電子郵件信箱", + "login.password.label": "密碼", + "login.submit.label": "登入", + "login.invalidCredentials": "電子郵件帳戶或密碼有誤", + "login.tokenExpired": "登入狀態過期,請重新登入", + "login.serverLogout": "登入狀態過期,請重新登入", + "login.link.signup": "建立一個免費帳戶", + "login.link.password": "密碼重設", + "password.headline": "密碼重設", + "password.email.label": "電子郵件信箱", + "password.submit.label": "送出", + "password.noUser": "此電子郵件帳戶不存在", + "password.successInfo": "請重新確認您的電子郵件信箱", + "password.link.signup": "建立一個免費帳戶", + "password.link.login": "登入您的帳戶", + "signup.headline": "註冊", + "signup.firstname.label": "名子", + "signup.lastname.label": "姓氏", + "signup.email.label": "電子郵件信箱", + "signup.company.label": "公司", + "signup.password.label": "密碼", + "signup.submit.label": "建立帳戶", + "signup.link.login": "您已有一個帳戶,請問是否要登入?", + "signup.emailDuplicate": "此電子郵件信箱已被註冊", + "signup.legal.info": "在建立帳戶同時,您同意:", + "signup.legal.terms": "服務條款", + "signup.legal.privacy": "隱私聲明", + "pricing.headline": "贊助 Franz", + "pricing.support.label": "選擇贊助方案", + "pricing.submit.label": "我想協助 Franz 的開發", + "pricing.link.skipPayment": "我不想協助 Franz 的開發", + "import.headline": "匯入您的 Franz 4 服務", + "import.notSupportedHeadline": "此服務不被 Franz 5 支持", + "import.submit.label": "匯入服務", + "import.skip.label": "我想手動匯入", + "invite.submit.label": "Send invites", + "invite.headline.friends": "邀請三個人", + "invite.name.label": "名子", + "invite.email.label": "電子郵件信箱", + "invite.skip.label": "我想晚點進行", + "subscription.submit.label": "我想協助 Franz 的開發", + "subscription.paymentSessionError": "無法初始化付費表單", + "subscription.includedFeatures": "Paid Franz Premium Supporter Account includes", + "subscription.features.onpremise": "Add on-premise/hosted services like HipChat", + "subscription.features.customServices": "Private services for you and your team", + "subscription.features.encryptedSync": "Encrypted session synchronization", + "subscription.features.vpn": "支援 Proxy & VPN", + "subscription.features.ads": "不再有任何廣告", + "subscription.features.comingSoon": "敬請期待", + "infobar.servicesUpdated": "您的服務已更新", + "infobar.updateAvailable": "有新的更新可安裝", + "infobar.buttonReloadServices": "重新載入", + "infobar.buttonInstallUpdate": "重新啟動並且更新", + "infobar.requiredRequestsFailed": "無法載入服務與帳戶資訊", + "sidebar.settings": "設定", + "services.welcome": "歡迎使用 Franz", + "services.getStarted": "開始使用", + "settings.account.headline": "帳戶", + "settings.account.headlineSubscription": "您的訂閱", + "settings.account.headlineUpgrade": "升級帳戶以及贊助 Franz", + "settings.account.headlineInvoices": "Invoices", + "settings.account.manageSubscription.label": "管理訂閱", + "settings.account.accountType.basic": "基本帳戶", + "settings.account.accountType.premium": "Premium Supporter Account", + "settings.account.account.editButton": "更改帳戶資訊", + "settings.account.invoiceDownload": "下載", + "settings.account.userInfoRequestFailed": "無法載入帳戶資訊", + "settings.account.tryReloadUserInfoRequest": "請重試", + "settings.account.headlineProfile": "更新帳戶資訊", + "settings.account.headlineAccount": "帳戶資訊", + "settings.account.headlinePassword": "更改密碼", + "settings.account.successInfo": "您的更改已經儲存", + "settings.account.buttonSave": "更新帳戶資訊", + "settings.account.mining.thankyou": "感謝您贊助運算能力", + "settings.account.mining.active": "您現在每秒執行 {hashes} 個計算", + "settings.account.mining.moreInformation": "取得更多資訊", + "settings.account.mining.cancel": "取消贊助運算", + "settings.navigation.availableServices": "可用服務", + "settings.navigation.yourServices": "您的服務", + "settings.navigation.account": "帳戶", + "settings.navigation.settings": "設定", + "settings.navigation.logout": "登出", + "settings.recipes.headline": "可用服務", + "settings.recipes.mostPopular": "熱門", + "settings.recipes.all": "全部", + "settings.recipes.dev": "開發中", + "settings.recipes.nothingFound": "抱歉,找不到您所要的服務", + "settings.recipes.servicesSuccessfulAddedInfo": "新增服務成功", + "settings.service.form.saveButton": "儲存", + "settings.service.form.deleteButton": "刪除", + "settings.service.form.availableServices": "可用服務", + "settings.service.form.yourServices": "您的服務", + "settings.service.form.addServiceHeadline": "新增 {name}", + "settings.service.form.editServiceHeadline": "更改 {name}", + "settings.service.form.tabHosted": "Hosted", + "settings.service.form.tabOnPremise": "Self hosted ⭐️", + "settings.service.form.customUrlValidationError": "Could not validate custom {name} server.", + "settings.service.form.customUrlPremiumInfo": "To add self hosted services, you need a Franz Premium Supporter Account.", + "settings.service.form.customUrlUpgradeAccount": "升級帳戶", + "settings.service.form.indirectMessageInfo": "除了 @username, @channel, @here 之外,當您參與的頻道有訊息時,就會通知", + "settings.service.error.headline": "錯誤", + "settings.service.error.goBack": "返回", + "settings.service.error.message": "無法載入服務元件", + "settings.services.tooltip.isDisabled": "已停用服務", + "settings.services.tooltip.notificationsDisabled": "已停用通知", + "settings.services.headline": "您的服務", + "settings.services.noServicesAdded": "您還沒加入任何服務", + "settings.services.discoverServices": "服務列表", + "settings.services.updatedInfo": "更動已經儲存", + "settings.services.deletedInfo": "服務已刪除", + "settings.app.headline": "設定", + "settings.app.headlineGeneral": "一般", + "settings.app.headlineLanguage": "語言", + "settings.app.headlineUpdates": "更新", + "settings.app.buttonSearchForUpdate": "檢查更新", + "settings.app.buttonInstallUpdate": "重新開啟並且更新", + "settings.app.updateStatusSearching": "檢查更新中...", + "settings.app.updateStatusAvailable": "有可用更新,下載中...", + "settings.app.updateStatusUpToDate": "已經是最新版本了", + "settings.app.form.autoLaunchOnStart": "開機時啟動", + "settings.app.form.autoLaunchInBackground": "背景啟動", + "settings.app.form.enableSystemTray": "在系統匣上顯示", + "settings.app.form.minimizeToSystemTray": "最小化至系統匣", + "settings.app.form.runInBackground": "關閉時保持在背景運作", + "settings.app.form.language": "語言", + "settings.app.form.beta": "包含開發中版本", + "settings.app.currentVersion": "當前版本:", + "settings.service.form.name": "Name", + "settings.service.form.enableService": "啟用服務", + "settings.service.form.enableNotification": "啟用通知", + "settings.service.form.team": "Team", + "settings.service.form.customUrl": "Custom server", + "settings.service.form.indirectMessages": "針對全部訊息顯示通知", + "settings.user.form.firstname": "名子", + "settings.user.form.lastname": "姓氏", + "settings.user.form.email": "電子郵件信箱", + "settings.user.form.currentPassword": "舊密碼", + "settings.user.form.newPassword": "新密碼", + "settings.user.form.accountType.label": "帳戶類型", + "settings.user.form.accountType.individual": "個人", + "settings.user.form.accountType.non-profit": "非營利", + "settings.user.form.accountType.company": "公司", + "subscription.type.free": "免費", + "subscription.type.month": "月", + "subscription.type.year": "年", + "subscription.type.mining": "用您機器的計算能力來贊助 Franz", + "subscription.mining.headline": "如何進行的?", + "subscription.mining.experimental": "實驗性功能", + "subscription.mining.line1": "Franz 運用您CPU的20%至50%的運算能力來挖門羅幣(一種開源加密貨幣),每年約莫可得到5美元。", + "subscription.mining.line2": "我們會調整運算強度,避免消耗過多電池電量及影響效能。", + "subscription.mining.line3": "當您允許我們挖掘門羅幣之時,我們便允許您使用全部的加值服務。", + "subscription.mining.moreInformation": "取得更多資訊", + "subscriptionPopup.buttonCancel": "取消", + "subscriptionPopup.buttonDone": "完成", + "tabs.item.reload": "重新載入", + "tabs.item.edit": "更改", + "tabs.item.disableNotifications": "停用通知", + "tabs.item.enableNotification": "啟用通知", + "tabs.item.disableService": "停用服務", + "tabs.item.deleteService": "刪除服務" +} diff --git a/src/index.js b/src/index.js index 9ca059f48..a3aa14732 100644 --- a/src/index.js +++ b/src/index.js @@ -2,18 +2,14 @@ import { app, BrowserWindow, shell } from 'electron'; import fs from 'fs-extra'; import path from 'path'; -/* eslint-disable */ -if (require('electron-squirrel-startup')) app.quit(); - import windowStateKeeper from 'electron-window-state'; import { isDevMode, isWindows } from './environment'; import ipcApi from './electron/ipc-api'; import Tray from './lib/Tray'; import Settings from './electron/Settings'; -import { appId } from './package.json'; +import { appId } from './package.json'; // eslint-disable-line import/no-unresolved import './electron/exception'; -/* eslint-enable */ // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. @@ -22,6 +18,7 @@ let willQuitApp = false; // Ensure that the recipe directory exists fs.ensureDir(path.join(app.getPath('userData'), 'recipes')); +fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); // Set App ID for Windows if (isWindows) { @@ -66,7 +63,7 @@ const createWindow = async () => { }); // Initialize System Tray - const trayIcon = new Tray(mainWindow); + const trayIcon = new Tray(); // Initialize ipcApi ipcApi({ mainWindow, settings, trayIcon }); @@ -114,6 +111,13 @@ const createWindow = async () => { app.isMaximized = true; }); + mainWindow.on('close', (e) => { + if (settings.get('minimizeToSystemTray')) { + e.preventDefault(); + mainWindow.minimize(); + } + }); + mainWindow.on('unmaximize', () => { app.isMaximized = false; }); diff --git a/src/lib/Menu.js b/src/lib/Menu.js index a6cde4d36..8f0a92c3d 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js @@ -1,9 +1,9 @@ import { remote, shell } from 'electron'; import { autorun, computed, observable, toJS } from 'mobx'; -import { isDevMode, isMac } from '../environment'; +import { isMac } from '../environment'; -const { app, Menu } = remote; +const { app, Menu, dialog } = remote; const template = [ { @@ -84,6 +84,28 @@ const template = [ label: 'Learn More', click() { shell.openExternal('http://meetfranz.com'); }, }, + { + label: 'Changelog', + click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); }, + }, + { + type: 'separator', + }, + { + label: 'Support', + click() { shell.openExternal('http://meetfranz.com/support'); }, + }, + { + type: 'separator', + }, + { + label: 'Terms of Service', + click() { shell.openExternal('https://meetfranz.com/terms'); }, + }, + { + label: 'Privacy Statement', + click() { shell.openExternal('https://meetfranz.com/privacy'); }, + }, ], }, ]; @@ -101,17 +123,15 @@ export default class FranzMenu { _build() { const tpl = toJS(this.tpl); - if (isDevMode) { - tpl[1].submenu.push({ - role: 'toggledevtools', - }, { - label: 'Toggle Service Developer Tools', - accelerator: 'CmdOrCtrl+Shift+Alt+i', - click: () => { - this.actions.service.openDevToolsForActiveService(); - }, - }); - } + tpl[1].submenu.push({ + role: 'toggledevtools', + }, { + label: 'Toggle Service Developer Tools', + accelerator: 'CmdOrCtrl+Shift+Alt+i', + click: () => { + this.actions.service.openDevToolsForActiveService(); + }, + }); tpl[1].submenu.unshift({ label: 'Reload Service', @@ -218,6 +238,18 @@ export default class FranzMenu { role: 'front', }, ]; + } else { + tpl[4].submenu.unshift({ + role: 'about', + click: () => { + dialog.showMessageBox({ + type: 'info', + title: 'Franz', + message: 'Franz', + detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, + }); + }, + }); } const serviceTpl = this.serviceTpl; diff --git a/src/lib/Tray.js b/src/lib/Tray.js index 67150971e..2efe71a71 100644 --- a/src/lib/Tray.js +++ b/src/lib/Tray.js @@ -6,12 +6,9 @@ const INDICATOR_TRAY_PLAIN = 'tray'; const INDICATOR_TRAY_UNREAD = 'tray-unread'; export default class TrayIcon { - mainWindow = null; trayIcon = null; - - constructor(mainWindow) { - this.mainWindow = mainWindow; - } + indicator = 0; + themeChangeSubscriberId = null; show() { if (this.trayIcon) return; @@ -21,7 +18,7 @@ export default class TrayIcon { { label: 'Show Franz', click() { - this.mainWindow.show(); + app.mainWindow.show(); }, }, { label: 'Quit Franz', @@ -35,30 +32,45 @@ export default class TrayIcon { this.trayIcon.setContextMenu(trayMenu); this.trayIcon.on('click', () => { - this.mainWindow.show(); + app.mainWindow.show(); }); + + if (process.platform === 'darwin') { + this.themeChangeSubscriberId = systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', () => { + this._refreshIcon(); + }); + } } hide() { - if (this.trayIcon) { - this.trayIcon.destroy(); - this.trayIcon = null; + if (!this.trayIcon) return; + + this.trayIcon.destroy(); + this.trayIcon = null; + + if (process.platform === 'darwin' && this.themeChangeSubscriberId) { + systemPreferences.unsubscribeNotification(this.themeChangeSubscriberId); + this.themeChangeSubscriberId = null; } } setIndicator(indicator) { + this.indicator = indicator; + this._refreshIcon(); + } + + _refreshIcon() { if (!this.trayIcon) return; - this.trayIcon.setImage(this._getAsset('tray', indicator !== 0 ? INDICATOR_TRAY_UNREAD : INDICATOR_TRAY_PLAIN)); + this.trayIcon.setImage(this._getAsset('tray', this.indicator !== 0 ? INDICATOR_TRAY_UNREAD : INDICATOR_TRAY_PLAIN)); if (process.platform === 'darwin') { this.trayIcon.setPressedImage( - this._getAsset('tray', `${indicator !== 0 ? INDICATOR_TRAY_UNREAD : INDICATOR_TRAY_PLAIN}-active`), + this._getAsset('tray', `${this.indicator !== 0 ? INDICATOR_TRAY_UNREAD : INDICATOR_TRAY_PLAIN}-active`), ); } } - _getAsset(type, asset) { let platform = process.platform; diff --git a/src/models/Recipe.js b/src/models/Recipe.js index 43a3450b1..9971df77c 100644 --- a/src/models/Recipe.js +++ b/src/models/Recipe.js @@ -1,7 +1,8 @@ +import emailParser from 'address-rfc2822'; + export default class Recipe { id = ''; name = ''; - author = ''; description = ''; version = '1.0'; path = ''; @@ -25,12 +26,13 @@ export default class Recipe { } if (!data.id) { - throw Error('Recipe requires Id'); + // Franz 4 recipes do not have an Id + throw Error(`Recipe '${data.name}' requires Id`); } this.id = data.id || this.id; this.name = data.name || this.name; - this.author = data.author || this.author; + this.rawAuthor = data.author || this.author; this.description = data.description || this.description; this.version = data.version || this.version; this.path = data.path; @@ -49,4 +51,15 @@ export default class Recipe { this.message = data.config.message || this.message; } + + get author() { + try { + const addresses = emailParser.parse(this.rawAuthor); + return addresses.map(a => ({ email: a.address, name: a.phrase })); + } catch (err) { + console.warn(`Not a valid author for ${this.name}`); + } + + return []; + } } diff --git a/src/models/Service.js b/src/models/Service.js index 7a0310ebc..484252e7c 100644 --- a/src/models/Service.js +++ b/src/models/Service.js @@ -58,7 +58,12 @@ export default class Service { @computed get url() { if (this.recipe.hasCustomUrl && this.customUrl) { - let url = normalizeUrl(this.customUrl); + let url; + try { + url = normalizeUrl(this.customUrl); + } catch (err) { + console.error(`Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`); + } if (typeof this.recipe.buildUrl === 'function') { url = this.recipe.buildUrl(url); diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 7dbef985d..ecfd621d3 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js @@ -2,19 +2,23 @@ import { remote, ipcRenderer, shell } from 'electron'; import { action, observable } from 'mobx'; import moment from 'moment'; import key from 'keymaster'; -import path from 'path'; +// import path from 'path'; import idleTimer from '@paulcbetts/system-idle-time'; +import AutoLaunch from 'auto-launch'; import Store from './lib/Store'; import Request from './lib/Request'; import { CHECK_INTERVAL } from '../config'; -import { isMac, isLinux } from '../environment'; +import { isMac } from '../environment'; import locales from '../i18n/translations'; import { gaEvent } from '../lib/analytics'; import Miner from '../lib/Miner'; -const { app, getCurrentWindow, powerMonitor } = remote; +const { app, powerMonitor } = remote; const defaultLocale = 'en-US'; +const autoLauncher = new AutoLaunch({ + name: 'Franz', +}); export default class AppStore extends Store { updateStatusTypes = { @@ -41,7 +45,7 @@ export default class AppStore extends Store { miner = null; @observable minerHashrate = 0.0; - constructor(...args: any) { + constructor(...args) { super(...args); // Register action handlers @@ -112,24 +116,15 @@ export default class AppStore extends Store { setTimeout(window.location.reload, 5000); }); - // Open Dev Tools (even in production mode) - key('⌘+ctrl+shift+alt+i, ctrl+shift+alt+i', () => { - getCurrentWindow().toggleDevTools(); - }); - - key('⌘+ctrl+shift+alt+pageup, ctrl+shift+alt+pageup', () => { - this.actions.service.openDevToolsForActiveService(); - }); - // Set active the next service key( - '⌘+pagedown, ctrl+pagedown, ⌘+shift+tab, ctrl+shift+tab', () => { + '⌘+pagedown, ctrl+pagedown, ⌘+tab, ctrl+tab', () => { this.actions.service.setActiveNext(); }); // Set active the prev service key( - '⌘+pageup, ctrl+pageup, ⌘+tab, ctrl+tab', () => { + '⌘+pageup, ctrl+pageup, ⌘+shift+tab, ctrl+shift+tab', () => { this.actions.service.setActivePrev(); }); @@ -161,33 +156,24 @@ export default class AppStore extends Store { indicator = '•'; } else if (unreadDirectMessageCount === 0 && unreadIndirectMessageCount === 0) { indicator = 0; + } else { + indicator = parseInt(indicator, 10); } ipcRenderer.send('updateAppIndicator', { indicator }); } - @action _launchOnStartup({ enable, openInBackground }) { + @action _launchOnStartup({ enable }) { this.autoLaunchOnStart = enable; - let settings = { - openAtLogin: enable, - }; - - // For Windows - if (process.platform === 'win32') { - settings = Object.assign({ - openAsHidden: openInBackground, - path: app.getPath('exe'), - args: [ - '--processStart', `"${path.basename(app.getPath('exe'))}"`, - ], - }, settings); - - if (openInBackground) { - settings.args.push( - '--process-start-args', '"--hidden"', - ); + try { + if (enable) { + autoLauncher.enable(); + } else { + autoLauncher.disable(); } + } catch (err) { + console.warn(err); } gaEvent('App', enable ? 'enable autostart' : 'disable autostart'); @@ -296,31 +282,19 @@ export default class AppStore extends Store { } async _autoStart() { - if (!isLinux) { - this._checkAutoStart(); - - // we need to wait until the settings request is resolved - await this.stores.settings.allSettingsRequest; + this.autoLaunchOnStart = await this._checkAutoStart(); - // We don't set autostart on first launch for macOS as disabling - // the option is currently broken - // https://github.com/meetfranz/franz/issues/17 - // https://github.com/electron/electron/issues/10880 - if (process.platform === 'darwin') return; + // we need to wait until the settings request is resolved + await this.stores.settings.allSettingsRequest; - if (!this.stores.settings.all.appStarts) { - this.actions.app.launchOnStartup({ - enable: true, - }); - } + if (!this.stores.settings.all.appStarts) { + this.actions.app.launchOnStartup({ + enable: true, + }); } } - _checkAutoStart() { - const loginItem = app.getLoginItemSettings({ - path: app.getPath('exe'), - }); - - this.autoLaunchOnStart = loginItem.openAtLogin; + async _checkAutoStart() { + return autoLauncher.isEnabled() || false; } } diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 19db05494..1d895d532 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -41,6 +41,7 @@ export default class ServicesStore extends Store { this.actions.service.openWindow.listen(this._openWindow.bind(this)); this.actions.service.filter.listen(this._filter.bind(this)); this.actions.service.resetFilter.listen(this._resetFilter.bind(this)); + this.actions.service.resetStatus.listen(this._resetStatus.bind(this)); this.actions.service.reload.listen(this._reload.bind(this)); this.actions.service.reloadActive.listen(this._reloadActive.bind(this)); this.actions.service.reloadAll.listen(this._reloadAll.bind(this)); @@ -144,12 +145,12 @@ export default class ServicesStore extends Store { serviceData.name = data.name; } - if (data.team) { + if (data.team && !data.customURL) { serviceData.team = data.team; } - if (data.team) { - serviceData.customUrl = data.customURL; + if (data.team && data.customURL) { + serviceData.customUrl = data.team; } this.actions.service.createService({ @@ -157,8 +158,6 @@ export default class ServicesStore extends Store { serviceData, redirect: false, }); - - return 'hello world'; } @action async _updateService({ serviceId, serviceData, redirect = true }) { @@ -295,9 +294,12 @@ export default class ServicesStore extends Store { } if (service.isNotificationEnabled) { + const title = typeof args[0].title === 'string' ? args[0].title : service.name; + options.body = typeof options.body === 'string' ? options.body : ''; + this.actions.app.notify({ notificationId: args[0].notificationId, - title: args[0].title, + title, options, serviceId, }); @@ -338,6 +340,10 @@ export default class ServicesStore extends Store { this.filterNeedle = null; } + @action _resetStatus() { + this.actionStatus = []; + } + @action _reload({ serviceId }) { const service = this.one(serviceId); service.resetMessageCount(); @@ -383,7 +389,7 @@ export default class ServicesStore extends Store { data.forEach((s) => { const service = s; - service.order = this.one(s.id).order; + service.order = services[s.id]; }); }); diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js index 1787f85e2..b8acc1258 100644 --- a/src/webview/lib/RecipeWebview.js +++ b/src/webview/lib/RecipeWebview.js @@ -64,6 +64,12 @@ class RecipeWebview { }); } + onNotify(fn) { + if (typeof fn === 'function') { + window.Notification.onNotify = fn; + } + } + initialize(fn) { if (typeof fn === 'function') { fn(); diff --git a/src/webview/notifications.js b/src/webview/notifications.js index 97ce9d69b..4055b10de 100644 --- a/src/webview/notifications.js +++ b/src/webview/notifications.js @@ -1,45 +1,46 @@ const { ipcRenderer } = require('electron'); const uuidV1 = require('uuid/v1'); -// const FranzNotificationStore = []; class Notification { + static permission = 'granted'; + constructor(title = '', options = {}) { this.title = title; this.options = options; this.notificationId = uuidV1(); - this.onclick = () => {}; - ipcRenderer.sendToHost('notification', { + ipcRenderer.sendToHost('notification', this.onNotify({ notificationId: this.notificationId, title, options, - }); + })); - ipcRenderer.on(`notification-onclick:${this.notificationId}`, () => { + ipcRenderer.once(`notification-onclick:${this.notificationId}`, () => { this.onclick(); }); } -} -Notification.permission = 'granted'; + static requestPermission(cb = null) { + if (!cb) { + return new Promise((resolve) => { + resolve(Notification.permission); + }); + } -Notification.requestPermission = (cb = null) => { - console.log(this); - if (!cb) { - return new Promise((resolve) => { - resolve(Notification.permission); - }); + if (typeof (cb) === 'function') { + return cb(Notification.permission); + } + + return Notification.permission; } - if (typeof (cb) === 'function') { - return cb(Notification.permission); + onNotify(data) { + return data; } - return Notification.permission; -}; + onClick() {} -Notification.close = () => { - // no implementation yet -}; + close() {} +} window.Notification = Notification; diff --git a/yarn.lock b/yarn.lock index 4e596b555..0bedbac27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,8 +32,8 @@ underscore "^1.6.0" "@paulcbetts/spellchecker@^4.0.5": - version "4.0.5" - resolved "https://registry.yarnpkg.com/@paulcbetts/spellchecker/-/spellchecker-4.0.5.tgz#4ea9bfb85faba53c094c0809a18986bf44265c5f" + version "4.0.6" + resolved "https://registry.yarnpkg.com/@paulcbetts/spellchecker/-/spellchecker-4.0.6.tgz#79ef1f9c19c5a3156921ccaa9ffdc3efbbee47e3" dependencies: nan "^2.0.0" @@ -80,6 +80,12 @@ acorn@^5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" +address-rfc2822@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/address-rfc2822/-/address-rfc2822-2.0.1.tgz#1a1bdb942b5e20e2c1ba5d5f396d5824ff7ae6ea" + dependencies: + email-addresses "^3.0.0" + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -151,6 +157,10 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +applescript@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/applescript/-/applescript-1.0.0.tgz#bb87af568cad034a4e48c4bdaf6067a3a2701317" + aproba@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" @@ -319,6 +329,16 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +"auto-launch@https://github.com/meetfranz/node-auto-launch.git": + version "5.0.1" + resolved "https://github.com/meetfranz/node-auto-launch.git#b90a0470467eb84435e6554ae9db1e2c6db79e61" + dependencies: + applescript "^1.0.0" + mkdirp "^0.5.1" + path-is-absolute "^1.0.0" + untildify "^3.0.2" + winreg "1.2.2" + aws-sign2@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" @@ -1998,12 +2018,6 @@ electron-spellchecker@^1.2.0: rxjs-serial-subscription "^0.1.1" spawn-rx "^2.0.7" -electron-squirrel-startup@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/electron-squirrel-startup/-/electron-squirrel-startup-1.0.0.tgz#19b4e55933fa0ef8f556784b9c660f772546a0b8" - dependencies: - debug "^2.2.0" - electron-to-chromium@^1.3.18: version "1.3.20" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.20.tgz#2eedd5ccbae7ddc557f68ad1fce9c172e915e4e5" @@ -2041,6 +2055,10 @@ electron@^1.7.9: electron-download "^3.0.1" extract-zip "^1.0.3" +email-addresses@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.0.1.tgz#c1fc20c189e7f96d4012d375db5feaccdd24391c" + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -5949,6 +5967,10 @@ universalify@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" +untildify@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.2.tgz#7f1f302055b3fea0f3e81dc78eb36766cb65e3f1" + unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" @@ -6133,6 +6155,10 @@ window-size@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" +winreg@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.2.tgz#8509afa3b71c5bbd110a6d7c6247ec67736c598f" + word-wrap@^1.0.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"