aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.all-contributorsrc12
-rw-r--r--.eslintrc163
-rw-r--r--.eslintrc.js186
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md2
-rw-r--r--.github/workflows/dependency-updates.yml2
-rw-r--r--.github/workflows/ferdi-builds.yml34
-rw-r--r--.github/workflows/ferdi-first-time-contributor.yml40
-rw-r--r--@types/index.d.ts21
-rw-r--r--CHANGELOG.md80
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--Dockerfile15
-rw-r--r--README.md18
-rw-r--r--babel.config.json12
-rw-r--r--gulpfile.babel.js8
-rw-r--r--package-lock.json1605
-rw-r--r--package.json66
-rw-r--r--packages/forms/src/button/index.tsx70
-rw-r--r--packages/forms/src/input/scorePassword.ts10
-rw-r--r--packages/forms/src/select/index.tsx7
-rw-r--r--packages/forms/tsconfig.json2
-rw-r--r--packages/theme/src/themes/dark/index.ts2
-rw-r--r--packages/theme/tsconfig.json2
-rw-r--r--packages/ui/tsconfig.json2
m---------recipes0
-rw-r--r--scripts/add-crowdin-contributors.ts (renamed from scripts/add-crowdin-contributors.js)14
-rw-r--r--scripts/build-theme-info.js97
-rw-r--r--scripts/link-readme.ts (renamed from scripts/link-readme.js)14
-rw-r--r--scripts/postinstall.ts (renamed from scripts/postinstall.js)2
-rw-r--r--scripts/prepare.ts (renamed from scripts/prepare.js)0
-rw-r--r--src/I18n.js10
-rw-r--r--src/actions/app.ts (renamed from src/actions/app.js)0
-rw-r--r--src/actions/index.ts (renamed from src/actions/index.js)0
-rw-r--r--src/actions/lib/actions.js27
-rw-r--r--src/actions/lib/actions.ts34
-rw-r--r--src/actions/news.ts (renamed from src/actions/news.js)0
-rw-r--r--src/actions/recipe.ts (renamed from src/actions/recipe.js)0
-rw-r--r--src/actions/recipePreview.ts (renamed from src/actions/recipePreview.js)0
-rw-r--r--src/actions/requests.ts (renamed from src/actions/requests.js)0
-rw-r--r--src/actions/service.ts (renamed from src/actions/service.js)0
-rw-r--r--src/actions/settings.ts (renamed from src/actions/settings.js)0
-rw-r--r--src/actions/ui.ts (renamed from src/actions/ui.js)0
-rw-r--r--src/actions/user.ts (renamed from src/actions/user.js)0
-rw-r--r--src/api/AppApi.ts (renamed from src/api/AppApi.js)4
-rw-r--r--src/api/FeaturesApi.ts (renamed from src/api/FeaturesApi.js)4
-rw-r--r--src/api/LocalApi.ts (renamed from src/api/LocalApi.js)10
-rw-r--r--src/api/NewsApi.ts (renamed from src/api/NewsApi.js)8
-rw-r--r--src/api/RecipePreviewsApi.ts (renamed from src/api/RecipePreviewsApi.js)6
-rw-r--r--src/api/RecipesApi.ts (renamed from src/api/RecipesApi.js)8
-rw-r--r--src/api/ServicesApi.ts (renamed from src/api/ServicesApi.js)18
-rw-r--r--src/api/UserApi.ts (renamed from src/api/UserApi.js)17
-rw-r--r--src/api/apiBase.js42
-rw-r--r--src/api/apiBase.ts41
-rw-r--r--src/api/index.ts (renamed from src/api/index.js)10
-rw-r--r--src/api/server/LocalApi.ts19
-rw-r--r--src/api/server/ServerApi.js79
-rw-r--r--src/api/utils/auth.js27
-rw-r--r--src/api/utils/auth.ts38
-rw-r--r--src/app.js2
-rw-r--r--src/assets/themeInfo.json1
-rw-r--r--src/components/AppUpdateInfoBar.js16
-rw-r--r--src/components/auth/AuthLayout.js14
-rw-r--r--src/components/auth/ChangeServer.js79
-rw-r--r--src/components/auth/Import.js43
-rw-r--r--src/components/auth/Invite.js62
-rw-r--r--src/components/auth/Locked.js97
-rw-r--r--src/components/auth/Login.js134
-rw-r--r--src/components/auth/Password.js77
-rw-r--r--src/components/auth/SetupAssistant.js18
-rw-r--r--src/components/auth/Signup.js129
-rw-r--r--src/components/auth/Welcome.js57
-rw-r--r--src/components/layout/AppLayout.js27
-rw-r--r--src/components/layout/Sidebar.js108
-rw-r--r--src/components/services/content/ConnectionLostBanner.js16
-rw-r--r--src/components/services/content/ErrorHandlers/WebviewErrorHandler.js38
-rw-r--r--src/components/services/content/ServiceDisabled.js17
-rw-r--r--src/components/services/content/ServiceView.js45
-rw-r--r--src/components/services/content/ServiceWebview.js3
-rw-r--r--src/components/services/content/Services.js103
-rw-r--r--src/components/services/content/WebviewCrashHandler.js26
-rw-r--r--src/components/services/tabs/TabItem.js94
-rw-r--r--src/components/services/tabs/Tabbar.js20
-rw-r--r--src/components/settings/SettingsLayout.js14
-rw-r--r--src/components/settings/account/AccountDashboard.js41
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js49
-rw-r--r--src/components/settings/recipes/RecipeItem.js17
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js83
-rw-r--r--src/components/settings/services/EditServiceForm.js173
-rw-r--r--src/components/settings/services/ServiceError.js26
-rw-r--r--src/components/settings/services/ServiceItem.js48
-rw-r--r--src/components/settings/services/ServicesDashboard.js56
-rw-r--r--src/components/settings/settings/EditSettingsForm.js533
-rw-r--r--src/components/settings/supportFerdi/SupportFerdiDashboard.js141
-rw-r--r--src/components/settings/team/TeamDashboard.js54
-rw-r--r--src/components/settings/user/EditUserForm.js39
-rw-r--r--src/components/ui/AppLoader/index.js10
-rw-r--r--src/components/ui/Button.js14
-rw-r--r--src/components/ui/FAB.js17
-rw-r--r--src/components/ui/FeatureItem.js38
-rw-r--r--src/components/ui/FeatureList.js101
-rw-r--r--src/components/ui/FullscreenLoader/index.js23
-rw-r--r--src/components/ui/ImageUpload.js15
-rw-r--r--src/components/ui/InfoBar.js16
-rw-r--r--src/components/ui/Infobox.js16
-rw-r--r--src/components/ui/Input.js35
-rw-r--r--src/components/ui/Link.js14
-rw-r--r--src/components/ui/Loader.js17
-rw-r--r--src/components/ui/Modal/index.js21
-rw-r--r--src/components/ui/Radio.js26
-rw-r--r--src/components/ui/SearchInput.js30
-rw-r--r--src/components/ui/Select.js32
-rw-r--r--src/components/ui/Slider.js104
-rw-r--r--src/components/ui/StatusBarTargetUrl.js14
-rw-r--r--src/components/ui/Tabs/TabItem.js15
-rw-r--r--src/components/ui/Tabs/TabItem.tsx3
-rw-r--r--src/components/ui/Tabs/Tabs.js5
-rw-r--r--src/components/ui/Tabs/index.js6
-rw-r--r--src/components/ui/Toggle.js20
-rw-r--r--src/components/ui/ToggleRaw.js20
-rw-r--r--src/components/ui/WebviewLoader/index.js16
-rw-r--r--src/components/ui/effects/Appear.js10
-rw-r--r--src/components/util/ErrorBoundary/index.js19
-rw-r--r--src/config.ts64
-rw-r--r--src/containers/auth/AuthLayoutContainer.js3
-rw-r--r--src/containers/auth/ChangeServerScreen.js13
-rw-r--r--src/containers/auth/ImportScreen.js6
-rw-r--r--src/containers/auth/InviteScreen.js13
-rw-r--r--src/containers/auth/LockedScreen.js8
-rw-r--r--src/containers/auth/LoginScreen.js10
-rw-r--r--src/containers/auth/PasswordScreen.js6
-rw-r--r--src/containers/auth/SetupAssistantScreen.js3
-rw-r--r--src/containers/auth/SignupScreen.js8
-rw-r--r--src/containers/auth/WelcomeScreen.js6
-rw-r--r--src/containers/layout/AppLayoutContainer.js3
-rw-r--r--src/containers/settings/AccountScreen.js27
-rw-r--r--src/containers/settings/EditServiceScreen.js135
-rw-r--r--src/containers/settings/EditSettingsScreen.js179
-rw-r--r--src/containers/settings/EditUserScreen.js60
-rw-r--r--src/containers/settings/InviteScreen.js10
-rw-r--r--src/containers/settings/RecipesScreen.js95
-rw-r--r--src/containers/settings/ServicesScreen.js17
-rw-r--r--src/containers/settings/SettingsWindow.js25
-rw-r--r--src/containers/settings/SupportScreen.js9
-rw-r--r--src/containers/settings/TeamScreen.js11
-rw-r--r--src/dev-app-update.yml2
-rw-r--r--src/electron-util.ts30
-rw-r--r--src/electron/Settings.ts (renamed from src/electron/Settings.js)13
-rw-r--r--src/electron/deepLinking.ts (renamed from src/electron/deepLinking.js)0
-rw-r--r--src/electron/exception.ts (renamed from src/electron/exception.js)0
-rw-r--r--src/electron/ipc-api/appIndicator.ts (renamed from src/electron/ipc-api/appIndicator.js)44
-rw-r--r--src/electron/ipc-api/autoUpdate.ts (renamed from src/electron/ipc-api/autoUpdate.js)26
-rw-r--r--src/electron/ipc-api/cld.ts (renamed from src/electron/ipc-api/cld.js)11
-rw-r--r--src/electron/ipc-api/dnd.ts (renamed from src/electron/ipc-api/dnd.js)4
-rw-r--r--src/electron/ipc-api/download.js51
-rw-r--r--src/electron/ipc-api/download.ts59
-rw-r--r--src/electron/ipc-api/focusState.ts (renamed from src/electron/ipc-api/focusState.js)4
-rw-r--r--src/electron/ipc-api/index.ts (renamed from src/electron/ipc-api/index.js)11
-rw-r--r--src/electron/ipc-api/localServer.ts (renamed from src/electron/ipc-api/localServer.js)17
-rw-r--r--src/electron/ipc-api/sessionStorage.ts35
-rw-r--r--src/electron/ipc-api/settings.js14
-rw-r--r--src/electron/ipc-api/settings.ts14
-rw-r--r--src/electron/macOSPermissions.ts (renamed from src/electron/macOSPermissions.js)19
-rw-r--r--src/electron/webview-ime-focus.js41
-rw-r--r--src/electron/windowUtils.js11
-rw-r--r--src/electron/windowUtils.ts13
-rw-r--r--src/enforce-macos-app-location.ts46
-rw-r--r--src/environment-remote.ts93
-rw-r--r--src/environment.js173
-rw-r--r--src/environment.ts42
-rw-r--r--src/features/appearance/index.ts (renamed from src/features/appearance/index.js)133
-rw-r--r--src/features/basicAuth/Component.js41
-rw-r--r--src/features/basicAuth/Form.ts (renamed from src/features/basicAuth/Form.js)1
-rw-r--r--src/features/basicAuth/mainIpcHandler.ts (renamed from src/features/basicAuth/mainIpcHandler.js)4
-rw-r--r--src/features/basicAuth/store.ts (renamed from src/features/basicAuth/store.js)0
-rw-r--r--src/features/basicAuth/styles.ts (renamed from src/features/basicAuth/styles.js)0
-rw-r--r--src/features/communityRecipes/index.ts (renamed from src/features/communityRecipes/index.js)0
-rw-r--r--src/features/communityRecipes/store.ts (renamed from src/features/communityRecipes/store.js)21
-rw-r--r--src/features/nightlyBuilds/Component.js26
-rw-r--r--src/features/nightlyBuilds/store.ts (renamed from src/features/nightlyBuilds/store.js)0
-rw-r--r--src/features/publishDebugInfo/Component.js94
-rw-r--r--src/features/publishDebugInfo/store.ts (renamed from src/features/publishDebugInfo/store.js)0
-rw-r--r--src/features/quickSwitch/Component.js71
-rw-r--r--src/features/quickSwitch/store.ts (renamed from src/features/quickSwitch/store.js)0
-rw-r--r--src/features/serviceProxy/index.js38
-rw-r--r--src/features/serviceProxy/index.ts54
-rwxr-xr-xsrc/features/settingsWS/actions.ts (renamed from src/features/settingsWS/actions.js)0
-rwxr-xr-xsrc/features/settingsWS/index.ts (renamed from src/features/settingsWS/index.js)11
-rwxr-xr-xsrc/features/settingsWS/state.ts (renamed from src/features/settingsWS/state.js)0
-rwxr-xr-xsrc/features/settingsWS/store.js22
-rw-r--r--src/features/todos/actions.js28
-rw-r--r--src/features/todos/actions.ts31
-rw-r--r--src/features/todos/constants.ts (renamed from src/features/todos/constants.js)0
-rw-r--r--src/features/todos/index.ts (renamed from src/features/todos/index.js)11
-rw-r--r--src/features/todos/preload.js12
-rw-r--r--src/features/utils/ActionBinding.ts (renamed from src/features/utils/ActionBinding.js)0
-rw-r--r--src/features/utils/FeatureStore.js8
-rw-r--r--src/features/webControls/components/WebControls.js20
-rw-r--r--src/features/webControls/containers/WebControlsScreen.js28
-rw-r--r--src/features/workspaces/actions.js27
-rw-r--r--src/features/workspaces/actions.ts30
-rw-r--r--src/features/workspaces/api.ts (renamed from src/features/workspaces/api.js)44
-rw-r--r--src/features/workspaces/components/CreateWorkspaceForm.js21
-rw-r--r--src/features/workspaces/components/EditWorkspaceForm.js36
-rw-r--r--src/features/workspaces/components/WorkspaceDrawer.js59
-rw-r--r--src/features/workspaces/components/WorkspaceDrawerItem.js27
-rw-r--r--src/features/workspaces/components/WorkspaceItem.js14
-rw-r--r--src/features/workspaces/components/WorkspaceSwitchingIndicator.js12
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js26
-rw-r--r--src/features/workspaces/constants.ts (renamed from src/features/workspaces/constants.js)0
-rw-r--r--src/features/workspaces/index.ts (renamed from src/features/workspaces/index.js)6
-rw-r--r--src/features/workspaces/models/Workspace.ts (renamed from src/features/workspaces/models/Workspace.js)6
-rw-r--r--src/features/workspaces/store.js19
-rw-r--r--src/helpers/asar-helpers.ts7
-rw-r--r--src/helpers/i18n-helpers.ts12
-rw-r--r--src/helpers/password-helpers.ts14
-rw-r--r--src/helpers/recipe-helpers.ts16
-rw-r--r--src/helpers/schedule-helpers.ts8
-rw-r--r--src/helpers/serverless-helpers.ts (renamed from src/helpers/serverless-helpers.js)0
-rw-r--r--src/helpers/service-helpers.js16
-rw-r--r--src/helpers/service-helpers.ts21
-rw-r--r--src/helpers/url-helpers.ts2
-rw-r--r--src/helpers/userAgent-helpers.ts2
-rw-r--r--src/helpers/validation-helpers.js67
-rw-r--r--src/helpers/validation-helpers.ts96
-rw-r--r--src/i18n/apply-branding.ts (renamed from src/i18n/apply-branding.js)26
-rw-r--r--src/i18n/globalMessages.ts (renamed from src/i18n/globalMessages.js)38
-rw-r--r--src/i18n/languages.ts (renamed from src/i18n/languages.js)0
-rw-r--r--src/i18n/locales/af.json31
-rw-r--r--src/i18n/locales/ar.json105
-rw-r--r--src/i18n/locales/be.json31
-rw-r--r--src/i18n/locales/bs.json31
-rw-r--r--src/i18n/locales/ca.json87
-rw-r--r--src/i18n/locales/cs.json79
-rw-r--r--src/i18n/locales/da.json107
-rw-r--r--src/i18n/locales/de.json113
-rw-r--r--src/i18n/locales/defaultMessages.json6862
-rw-r--r--src/i18n/locales/el.json79
-rw-r--r--src/i18n/locales/en-US.json31
-rw-r--r--src/i18n/locales/es.json151
-rw-r--r--src/i18n/locales/fi.json109
-rw-r--r--src/i18n/locales/fr.json125
-rw-r--r--src/i18n/locales/ga.json79
-rw-r--r--src/i18n/locales/he.json89
-rw-r--r--src/i18n/locales/hi.json31
-rw-r--r--src/i18n/locales/hr.json71
-rw-r--r--src/i18n/locales/hu.json103
-rw-r--r--src/i18n/locales/id.json95
-rw-r--r--src/i18n/locales/it.json123
-rw-r--r--src/i18n/locales/ja.json93
-rw-r--r--src/i18n/locales/ka.json59
-rw-r--r--src/i18n/locales/ko.json99
-rw-r--r--src/i18n/locales/nl-BE.json91
-rw-r--r--src/i18n/locales/nl.json233
-rw-r--r--src/i18n/locales/no.json105
-rw-r--r--src/i18n/locales/pl.json121
-rw-r--r--src/i18n/locales/pt-BR.json69
-rw-r--r--src/i18n/locales/pt.json105
-rw-r--r--src/i18n/locales/ro.json33
-rw-r--r--src/i18n/locales/ru.json95
-rw-r--r--src/i18n/locales/sk.json97
-rw-r--r--src/i18n/locales/sl.json31
-rw-r--r--src/i18n/locales/sr.json79
-rw-r--r--src/i18n/locales/sv.json105
-rw-r--r--src/i18n/locales/te.json31
-rw-r--r--src/i18n/locales/tr.json91
-rw-r--r--src/i18n/locales/uk.json91
-rw-r--r--src/i18n/locales/vi.json123
-rw-r--r--src/i18n/locales/zh-CN.json413
-rw-r--r--src/i18n/locales/zh-HANT.json77
-rw-r--r--src/i18n/locales/zh.json43
-rw-r--r--src/i18n/manage-translations.js9
-rw-r--r--src/i18n/messages/src/components/AppUpdateInfoBar.json41
-rw-r--r--src/i18n/messages/src/components/auth/ChangeServer.json67
-rw-r--r--src/i18n/messages/src/components/auth/Import.json54
-rw-r--r--src/i18n/messages/src/components/auth/Invite.json93
-rw-r--r--src/i18n/messages/src/components/auth/Locked.json106
-rw-r--r--src/i18n/messages/src/components/auth/Login.json171
-rw-r--r--src/i18n/messages/src/components/auth/Password.json80
-rw-r--r--src/i18n/messages/src/components/auth/ServiceAssistant.json93
-rw-r--r--src/i18n/messages/src/components/auth/SetupAssistant.json54
-rw-r--r--src/i18n/messages/src/components/auth/Signup.json171
-rw-r--r--src/i18n/messages/src/components/auth/Welcome.json41
-rw-r--r--src/i18n/messages/src/components/layout/AppLayout.json54
-rw-r--r--src/i18n/messages/src/components/layout/Sidebar.json106
-rw-r--r--src/i18n/messages/src/components/services/content/ConnectionBanner.json67
-rw-r--r--src/i18n/messages/src/components/services/content/ConnectionLost.json67
-rw-r--r--src/i18n/messages/src/components/services/content/ConnectionLostBanner.json41
-rw-r--r--src/i18n/messages/src/components/services/content/ErrorHandlers/WebviewErrorHandler.json67
-rw-r--r--src/i18n/messages/src/components/services/content/ServiceDisabled.json28
-rw-r--r--src/i18n/messages/src/components/services/content/Services.json67
-rw-r--r--src/i18n/messages/src/components/services/content/WebControls.json67
-rw-r--r--src/i18n/messages/src/components/services/content/WebviewCrashHandler.json54
-rw-r--r--src/i18n/messages/src/components/services/tabs/TabItem.json171
-rw-r--r--src/i18n/messages/src/components/settings/SettingsLayout.json15
-rw-r--r--src/i18n/messages/src/components/settings/account/AccountDashboard.json158
-rw-r--r--src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json93
-rw-r--r--src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json171
-rw-r--r--src/i18n/messages/src/components/settings/services/EditServiceForm.json340
-rw-r--r--src/i18n/messages/src/components/settings/services/ServiceError.json54
-rw-r--r--src/i18n/messages/src/components/settings/services/ServiceItem.json41
-rw-r--r--src/i18n/messages/src/components/settings/services/ServicesDashboard.json119
-rw-r--r--src/i18n/messages/src/components/settings/settings/EditSettingsForm.json444
-rw-r--r--src/i18n/messages/src/components/settings/supportFerdi/SupportFerdiDashboard.json197
-rw-r--r--src/i18n/messages/src/components/settings/team/TeamDashboard.json93
-rw-r--r--src/i18n/messages/src/components/settings/user/EditUserForm.json80
-rw-r--r--src/i18n/messages/src/components/ui/FeatureList.json145
-rw-r--r--src/i18n/messages/src/components/ui/InfoBar.json15
-rw-r--r--src/i18n/messages/src/components/ui/Infobox.json15
-rw-r--r--src/i18n/messages/src/components/ui/Input.json15
-rw-r--r--src/i18n/messages/src/components/ui/WebviewLoader/index.json15
-rw-r--r--src/i18n/messages/src/components/util/ErrorBoundary/index.json28
-rw-r--r--src/i18n/messages/src/containers/settings/EditServiceScreen.json249
-rw-r--r--src/i18n/messages/src/containers/settings/EditSettingsScreen.json600
-rw-r--r--src/i18n/messages/src/containers/settings/EditUserScreen.json119
-rw-r--r--src/i18n/messages/src/features/basicAuth/Component.json15
-rw-r--r--src/i18n/messages/src/features/debugger/Component.json15
-rw-r--r--src/i18n/messages/src/features/nightlyBuilds/Component.json41
-rw-r--r--src/i18n/messages/src/features/publishDebugInfo/Component.json93
-rw-r--r--src/i18n/messages/src/features/quickSwitch/Component.json41
-rw-r--r--src/i18n/messages/src/features/recipeConnectionLost/components/WebControls.json67
-rw-r--r--src/i18n/messages/src/features/webControls/components/WebControls.json67
-rw-r--r--src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json28
-rw-r--r--src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json119
-rw-r--r--src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json67
-rw-r--r--src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json28
-rw-r--r--src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json15
-rw-r--r--src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json106
-rw-r--r--src/i18n/messages/src/helpers/validation-helpers.json67
-rw-r--r--src/i18n/messages/src/i18n/globalMessages.json236
-rw-r--r--src/i18n/messages/src/lib/Menu.json912
-rw-r--r--src/i18n/translations.js13
-rw-r--r--src/i18n/translations.ts15
-rw-r--r--src/index.html2
-rw-r--r--src/index.js150
-rw-r--r--src/internal-server/app/Controllers/Http/RecipeController.js53
-rw-r--r--src/internal-server/app/Controllers/Http/ServiceController.js18
-rw-r--r--src/internal-server/app/Controllers/Http/UserController.js176
-rw-r--r--src/internal-server/app/Controllers/Http/WorkspaceController.js59
-rw-r--r--src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js2
-rw-r--r--src/internal-server/app/Models/Recipe.js3
-rw-r--r--src/internal-server/app/Models/Service.js3
-rw-r--r--src/internal-server/app/Models/Token.js3
-rw-r--r--src/internal-server/app/Models/User.js3
-rw-r--r--src/internal-server/app/Models/Workspace.js3
-rw-r--r--src/internal-server/config/shield.js3
-rw-r--r--src/internal-server/public/js/transfer.js20
-rw-r--r--src/internal-server/start.ts (renamed from src/internal-server/start.js)18
-rw-r--r--src/internal-server/start/kernel.js10
-rw-r--r--src/internal-server/start/migrate.js26
-rw-r--r--src/internal-server/start/routes.js2
-rw-r--r--src/internal-server/test.js9
-rw-r--r--src/internal-server/test.ts9
-rw-r--r--src/lib/DBus.ts (renamed from src/lib/DBus.js)22
-rw-r--r--src/lib/Form.ts (renamed from src/lib/Form.js)0
-rw-r--r--src/lib/Menu.js205
-rw-r--r--src/lib/TouchBar.ts (renamed from src/lib/TouchBar.js)45
-rw-r--r--src/models/News.ts6
-rw-r--r--src/models/Recipe.ts92
-rw-r--r--src/models/RecipePreview.ts6
-rw-r--r--src/models/Service.js149
-rw-r--r--src/models/User.ts4
-rw-r--r--src/models/UserAgent.js24
-rw-r--r--src/prop-types.ts1
-rw-r--r--src/routes.js3
-rw-r--r--src/stores/AppStore.js41
-rw-r--r--src/stores/FeaturesStore.js16
-rw-r--r--src/stores/GlobalErrorStore.js10
-rw-r--r--src/stores/RecipesStore.js53
-rw-r--r--src/stores/RequestStore.js18
-rw-r--r--src/stores/ServicesStore.js317
-rw-r--r--src/stores/SettingsStore.js131
-rw-r--r--src/stores/UIStore.ts (renamed from src/stores/UIStore.js)66
-rw-r--r--src/stores/UserStore.js87
-rw-r--r--src/stores/index.ts4
-rw-r--r--src/stores/lib/CachedRequest.js96
-rw-r--r--src/stores/lib/Request.js2
-rw-r--r--src/stores/lib/Store.js6
-rw-r--r--src/styles/layout.scss4
-rw-r--r--src/styles/services.scss20
-rw-r--r--src/styles/tabs.scss13
-rw-r--r--src/webview/badge.ts14
-rw-r--r--src/webview/contextMenuBuilder.js250
-rw-r--r--src/webview/darkmode.ts6
-rw-r--r--src/webview/lib/RecipeWebview.js67
-rw-r--r--src/webview/lib/Userscript.js10
-rw-r--r--src/webview/notifications.js20
-rw-r--r--src/webview/recipe.js64
-rw-r--r--src/webview/sessionHandler.ts26
-rw-r--r--src/webview/spellchecker.ts28
-rw-r--r--tsconfig.json31
-rw-r--r--tsconfig.settings.json28
-rw-r--r--uidev/src/index.tsx2
-rw-r--r--uidev/src/stories/input.stories.tsx66
-rw-r--r--uidev/src/stories/select.stories.tsx31
-rw-r--r--uidev/src/stories/textarea.stories.tsx25
-rw-r--r--uidev/src/stories/toggle.stories.tsx46
-rw-r--r--uidev/tsconfig.json18
396 files changed, 8204 insertions, 20914 deletions
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 552b8cb93..1457084cb 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -974,7 +974,8 @@
974 "profile": "https://www.ekino.com", 974 "profile": "https://www.ekino.com",
975 "contributions": [ 975 "contributions": [
976 "code", 976 "code",
977 "bug" 977 "bug",
978 "userTesting"
978 ] 979 ]
979 }, 980 },
980 { 981 {
@@ -985,6 +986,15 @@
985 "contributions": [ 986 "contributions": [
986 "bug" 987 "bug"
987 ] 988 ]
989 },
990 {
991 "login": "niutech",
992 "name": "niu tech",
993 "avatar_url": "https://avatars.githubusercontent.com/u/384997?v=4",
994 "profile": "http://niute.ch",
995 "contributions": [
996 "code"
997 ]
988 } 998 }
989 ], 999 ],
990 "contributorsPerLine": 16, 1000 "contributorsPerLine": 16,
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 47811e7be..000000000
--- a/.eslintrc
+++ /dev/null
@@ -1,163 +0,0 @@
1{
2 "root": true,
3 "parser": "@babel/eslint-parser",
4 "extends": "eslint-config-airbnb",
5 "plugins": [
6 "jest"
7 ],
8 "overrides": [
9 {
10 "files": [
11 "**/*.ts",
12 "**/*.tsx"
13 ],
14 "env": {
15 "browser": true,
16 "es6": true,
17 "node": true
18 },
19 "extends": [
20 "airbnb-typescript"
21 ],
22 "parser": "@typescript-eslint/parser",
23 "parserOptions": {
24 "ecmaFeatures": {
25 "jsx": true
26 },
27 "ecmaVersion": 2018,
28 "sourceType": "module",
29 "project": "./tsconfig.json"
30 },
31 "plugins": [
32 "@typescript-eslint"
33 ],
34 "rules": {
35 // eslint
36 "arrow-parens": 0,
37 "array-callback-return": 1,
38 "class-methods-use-this": 0,
39 "consistent-return": 0,
40 "implicit-arrow-linebreak": 0,
41 "linebreak-style": 0,
42 "max-len": 0,
43 "no-confusing-arrow": 0,
44 "no-console": 0,
45 "no-param-reassign": 0,
46 "no-return-assign": 1,
47 "no-underscore-dangle": 0,
48 "no-use-before-define": 0,
49 "prefer-destructuring": 1,
50 "object-curly-newline": 0,
51 "operator-linebreak": 0,
52 // @typescript-eslint
53 "@typescript-eslint/indent": 0,
54 "@typescript-eslint/no-shadow": 0,
55 "@typescript-eslint/no-unused-expressions": 0,
56 // eslint-plugin-import
57 "import/extensions": 0,
58 "import/no-cycle": 1,
59 "import/no-extraneous-dependencies": 0,
60 "import/no-unresolved": 0,
61 "import/prefer-default-export": 0,
62 // eslint-plugin-react
63 "react/destructuring-assignment": 0,
64 "react/button-has-type": 0,
65 "react/forbid-prop-types": 0,
66 "react/jsx-curly-newline": 0,
67 "react/jsx-no-bind": 0,
68 "react/jsx-no-target-blank": 0,
69 "react/jsx-props-no-spreading": 0,
70 "react/no-deprecated": 1,
71 "react/no-array-index-key": 0,
72 "react/prefer-stateless-function": 0,
73 "react/sort-comp": 0,
74 "react/state-in-constructor": 0,
75 "react/static-property-placement": 0,
76 // eslint-plugin-jsx-a11y
77 "jsx-a11y/click-events-have-key-events": 1,
78 "jsx-a11y/mouse-events-have-key-events": 1,
79 "jsx-a11y/label-has-for": [
80 2,
81 {
82 "components": [
83 "Label"
84 ],
85 "required": {
86 "every": [
87 "id"
88 ]
89 },
90 "allowChildren": false
91 }
92 ],
93 "jsx-a11y/no-static-element-interactions": 0,
94 "jsx-a11y/no-noninteractive-element-interactions": 1
95 }
96 }
97 ],
98 "settings": {
99 "react": {
100 "pragma": "React", // Pragma to use, default to "React"
101 "version": "detect" // React version. "detect" automatically picks the version you have installed.
102 }
103 },
104 "globals": {
105 "window": true,
106 "document": true,
107 "FormData": true,
108 "localStorage": true,
109 "navigator": true,
110 "Element": true,
111 "use": true,
112 "FileReader": true
113 },
114 "env": {
115 "jest/globals": true
116 },
117 "rules": {
118 // eslint
119 "arrow-parens": 0,
120 "class-methods-use-this": 0,
121 "consistent-return": 1,
122 "implicit-arrow-linebreak": 0,
123 "function-paren-newline": 0,
124 "max-len": 0,
125 "no-await-in-loop": 1,
126 "no-console": [
127 1,
128 {
129 "allow": [
130 "warn",
131 "error"
132 ]
133 }
134 ],
135 "no-param-reassign": 1,
136 "no-restricted-syntax": 0,
137 "no-underscore-dangle": 0,
138 "operator-linebreak": 0,
139 "prefer-destructuring": 1,
140 "object-curly-newline": 0,
141 // eslint-plugin-import
142 "import/extensions": 1,
143 "import/prefer-default-export": 0,
144 "import/no-extraneous-dependencies": 0, // various false positives, re-enable at some point
145 "import/no-unresolved": 1,
146 // eslint-plugin-react
147 "react/forbid-prop-types": 1,
148 "react/destructuring-assignment": 0,
149 "react/jsx-curly-newline": 0,
150 "react/jsx-filename-extension": 1,
151 "react/jsx-one-expression-per-line": 0,
152 "react/jsx-no-bind": 1,
153 "react/jsx-props-no-spreading": 0,
154 "react/prefer-stateless-function": 1,
155 "react/static-property-placement": 0,
156 "react/state-in-constructor": 1,
157 "react/sort-comp": 0,
158 // eslint-plugin-jsx-a11y
159 "jsx-a11y/click-events-have-key-events": 1,
160 "jsx-a11y/no-static-element-interactions": 1,
161 "jsx-a11y/no-noninteractive-element-interactions": 1
162 }
163}
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 000000000..057631708
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,186 @@
1module.exports = {
2 root: true,
3 parser: '@babel/eslint-parser',
4 parserOptions: {
5 ecmaFeatures: {
6 jsx: true,
7 },
8 ecmaVersion: 2018,
9 sourceType: 'module',
10 project: './tsconfig.json',
11 },
12 extends: ['eslint-config-airbnb', 'plugin:unicorn/recommended'],
13 plugins: ['jest'],
14 settings: {
15 react: {
16 pragma: 'React', // Pragma to use, default to "React"
17 version: 'detect', // React version. "detect" automatically picks the version you have installed.
18 },
19 },
20 globals: {
21 window: true,
22 document: true,
23 FormData: true,
24 localStorage: true,
25 navigator: true,
26 Element: true,
27 use: true,
28 FileReader: true,
29 },
30 env: {
31 browser: true,
32 es6: true,
33 node: true,
34 jest: true,
35 },
36 overrides: [
37 {
38 files: ['**/*.ts', '**/*.tsx'],
39 extends: ['airbnb-typescript', 'plugin:unicorn/recommended'],
40 parser: '@typescript-eslint/parser',
41 plugins: ['@typescript-eslint'],
42 rules: {
43 // eslint
44 'arrow-parens': 0,
45 'array-callback-return': 1,
46 'class-methods-use-this': 0,
47 'consistent-return': 0,
48 'function-paren-newline': 0,
49 'implicit-arrow-linebreak': 0,
50 'linebreak-style': 0,
51 'max-len': 0,
52 'no-confusing-arrow': 0,
53 'no-console': 0,
54 'no-param-reassign': 0,
55 'no-restricted-syntax': 0,
56 'no-return-assign': 1,
57 'no-underscore-dangle': 0,
58 'no-use-before-define': 0,
59 'prefer-destructuring': 1,
60 'object-curly-newline': 0,
61 'operator-linebreak': 0,
62 // @typescript-eslint
63 '@typescript-eslint/indent': 0,
64 '@typescript-eslint/no-shadow': 0,
65 '@typescript-eslint/no-unused-expressions': 0,
66 // eslint-plugin-import
67 'import/extensions': 0,
68 'import/no-cycle': 1,
69 'import/no-extraneous-dependencies': 0,
70 'import/no-unresolved': 0,
71 'import/prefer-default-export': 0,
72 // eslint-plugin-react
73 'react/destructuring-assignment': 0,
74 'react/button-has-type': 0,
75 'react/forbid-prop-types': 0,
76 'react/jsx-curly-newline': 0,
77 'react/jsx-no-bind': 0,
78 'react/jsx-no-target-blank': 0,
79 'react/jsx-props-no-spreading': 0,
80 'react/no-deprecated': 1,
81 'react/no-array-index-key': 0,
82 'react/prefer-stateless-function': 0,
83 'react/sort-comp': 0,
84 'react/state-in-constructor': 0,
85 'react/static-property-placement': 0,
86 // eslint-plugin-jsx-a11y
87 'jsx-a11y/click-events-have-key-events': 1,
88 'jsx-a11y/mouse-events-have-key-events': 1,
89 'jsx-a11y/label-has-for': [
90 2,
91 {
92 components: ['Label'],
93 required: {
94 every: ['id'],
95 },
96 allowChildren: false,
97 },
98 ],
99 'jsx-a11y/no-static-element-interactions': 0,
100 'jsx-a11y/no-noninteractive-element-interactions': 1,
101 // eslint-plugin-unicorn
102 'unicorn/filename-case': 0,
103 'unicorn/no-null': 0,
104 'unicorn/no-useless-undefined': 0,
105 'unicorn/prefer-module': 0,
106 'unicorn/prevent-abbreviations': 0,
107 'unicorn/prefer-node-protocol': 0,
108 'unicorn/import-style': [
109 2,
110 {
111 styles: {
112 path: {
113 named: true,
114 },
115 },
116 },
117 ],
118 'unicorn/consistent-destructuring': 0,
119 },
120 },
121 ],
122 rules: {
123 // eslint
124 'arrow-parens': 0,
125 'class-methods-use-this': 0,
126 'consistent-return': 1,
127 'implicit-arrow-linebreak': 0,
128 indent: 0,
129 'function-paren-newline': 0,
130 'linebreak-style': 0,
131 'max-len': 0,
132 'no-await-in-loop': 1,
133 'no-console': [
134 1,
135 {
136 allow: ['warn', 'error'],
137 },
138 ],
139 'no-param-reassign': 1,
140 'no-restricted-syntax': 0,
141 'no-underscore-dangle': 0,
142 'operator-linebreak': 0,
143 'prefer-destructuring': 1,
144 'object-curly-newline': 0,
145 // eslint-plugin-import
146 'import/extensions': 0,
147 'import/prefer-default-export': 0,
148 'import/no-extraneous-dependencies': 0, // various false positives, re-enable at some point
149 'import/no-unresolved': 0,
150 // eslint-plugin-react
151 'react/forbid-prop-types': 1,
152 'react/destructuring-assignment': 0,
153 'react/jsx-curly-newline': 0,
154 'react/jsx-filename-extension': 1,
155 'react/jsx-one-expression-per-line': 0,
156 'react/jsx-no-bind': 1,
157 'react/jsx-props-no-spreading': 0,
158 'react/prefer-stateless-function': 1,
159 'react/prop-types': 0,
160 'react/static-property-placement': 0,
161 'react/state-in-constructor': 1,
162 'react/sort-comp': 0,
163 // eslint-plugin-jsx-a11y
164 'jsx-a11y/click-events-have-key-events': 1,
165 'jsx-a11y/no-static-element-interactions': 1,
166 'jsx-a11y/no-noninteractive-element-interactions': 1,
167 // eslint-plugin-unicorn
168 'unicorn/filename-case': 0,
169 'unicorn/no-null': 0,
170 'unicorn/no-useless-undefined': 0,
171 'unicorn/prefer-module': 0,
172 'unicorn/prevent-abbreviations': 0,
173 'unicorn/prefer-node-protocol': 0,
174 'unicorn/import-style': [
175 2,
176 {
177 styles: {
178 path: {
179 named: true,
180 },
181 },
182 },
183 ],
184 'unicorn/consistent-destructuring': 0,
185 },
186};
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index cad16ecae..020d6ff58 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -3,7 +3,7 @@ name: Bug report
3about: Create a report to help us improve 3about: Create a report to help us improve
4--- 4---
5<!-- 5<!--
6Please remember that if you are logging a bug for some service that has *stopped working*, please log the bug at https://github.com/getferdi/recipes/issue 6Please remember that if you are logging a bug for some service that has *stopped working*, please log the bug at https://github.com/getferdi/recipes/issues
7Please remember to read the self-help documentation at https://github.com/getferdi/ferdi#troubleshooting-recipes-self-help - in case it helps you unblock yourself. 7Please remember to read the self-help documentation at https://github.com/getferdi/ferdi#troubleshooting-recipes-self-help - in case it helps you unblock yourself.
8 8
9Please fill our form below, this way we can analyse and fix the problem as fast as possible. 9Please fill our form below, this way we can analyse and fix the problem as fast as possible.
diff --git a/.github/workflows/dependency-updates.yml b/.github/workflows/dependency-updates.yml
index d41ded354..eafa6645e 100644
--- a/.github/workflows/dependency-updates.yml
+++ b/.github/workflows/dependency-updates.yml
@@ -55,7 +55,7 @@ jobs:
55 - name: Install pnpm 55 - name: Install pnpm
56 uses: pnpm/action-setup@v2.0.1 56 uses: pnpm/action-setup@v2.0.1
57 with: 57 with:
58 version: 6.14.7 58 version: 6.16.0
59 - name: Uninstall locally and reinstall global npm modules 59 - name: Uninstall locally and reinstall global npm modules
60 run: | 60 run: |
61 npm uninstall node-gyp 61 npm uninstall node-gyp
diff --git a/.github/workflows/ferdi-builds.yml b/.github/workflows/ferdi-builds.yml
index e3e504731..062243659 100644
--- a/.github/workflows/ferdi-builds.yml
+++ b/.github/workflows/ferdi-builds.yml
@@ -46,6 +46,7 @@ jobs:
46 ref: nightly 46 ref: nightly
47 submodules: recursive 47 submodules: recursive
48 fetch-depth: 0 # Note: Needed to be able to pull the 'develop' branch as well for merging 48 fetch-depth: 0 # Note: Needed to be able to pull the 'develop' branch as well for merging
49 # ssh-key: ${{ secrets.FERDI_PUBLISH_TOKEN }}
49 - id: should_run 50 - id: should_run
50 name: Check whether there are any commits since this run was last triggered and push them and/or set the output 51 name: Check whether there are any commits since this run was last triggered and push them and/or set the output
51 if: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && contains(github.event.inputs.message, '[nightly branch]')) }} 52 if: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && contains(github.event.inputs.message, '[nightly branch]')) }}
@@ -57,12 +58,18 @@ jobs:
57 MANUAL_REBUILD="${{ github.event_name == 'workflow_dispatch' }}" 58 MANUAL_REBUILD="${{ github.event_name == 'workflow_dispatch' }}"
58 VERSION_BUMP="${{ contains(github.event.inputs.message, '[version bump]') }}" 59 VERSION_BUMP="${{ contains(github.event.inputs.message, '[version bump]') }}"
59 if [ $CHANGES_COUNT -gt 0 ] || [[ $MANUAL_REBUILD == "true" && $VERSION_BUMP == "true" ]]; then 60 if [ $CHANGES_COUNT -gt 0 ] || [[ $MANUAL_REBUILD == "true" && $VERSION_BUMP == "true" ]]; then
60 # Do the version bump in the 'develop' branch ONLY if there were other changes coming from the 'develop' branch 61 # Do the version bump in the 'develop' branch ONLY if
62 # there were other changes coming from the 'develop' branch (or)
63 # this is a manual trigger with the key-phrase
61 git checkout develop 64 git checkout develop
62 TAG_NAME=$(npm version -m "%s [skip ci]" prerelease --preid=nightly) 65 TAG_NAME=$(npm version -m "%s [skip ci]" prerelease --preid=nightly)
63 git push origin develop --no-verify 66 git push origin develop --no-verify
64 git tag -f $TAG_NAME 67 git tag -f $TAG_NAME
65 git push origin --tags --no-verify 68 git push origin --tags --no-verify
69 # Also tag the submodule so as to help identify which changes went into which nightly release
70 # TODO: Not working due to cross-repo access issues by the github-action bot
71 # git -C recipes tag -f $TAG_NAME
72 # git -C recipes push origin --tags --no-verify
66 73
67 git checkout nightly 74 git checkout nightly
68 fi 75 fi
@@ -83,7 +90,7 @@ jobs:
83 name: 'macos ${{ github.event.inputs.message }}' 90 name: 'macos ${{ github.event.inputs.message }}'
84 needs: check_updates 91 needs: check_updates
85 if: ${{ (needs.check_updates.outputs.should_run != 'false') && (github.event_name != 'workflow_dispatch' || (github.event_name == 'workflow_dispatch' && (contains(github.event.inputs.message, '[macOS]') || (!contains(github.event.inputs.message, '[macOS]') && !contains(github.event.inputs.message, '[Linux]') && !contains(github.event.inputs.message, '[Windows]'))))) }} 92 if: ${{ (needs.check_updates.outputs.should_run != 'false') && (github.event_name != 'workflow_dispatch' || (github.event_name == 'workflow_dispatch' && (contains(github.event.inputs.message, '[macOS]') || (!contains(github.event.inputs.message, '[macOS]') && !contains(github.event.inputs.message, '[Linux]') && !contains(github.event.inputs.message, '[Windows]'))))) }}
86 runs-on: macos-10.15 93 runs-on: macos-11
87 steps: 94 steps:
88 - name: Set env vars 95 - name: Set env vars
89 run: | 96 run: |
@@ -142,21 +149,15 @@ jobs:
142 uses: actions/setup-node@v2 149 uses: actions/setup-node@v2
143 with: 150 with:
144 node-version: 14.17.6 151 node-version: 14.17.6
145 - name: Upgrade Xcode version on the macOS 10.15 default runners provided by GH Actions
146 run: |
147 sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*
148 sudo xcode-select -s "/Applications/Xcode_12.4.app"
149 - name: Install pnpm 152 - name: Install pnpm
150 uses: pnpm/action-setup@v2.0.1 153 uses: pnpm/action-setup@v2.0.1
151 with: 154 with:
152 version: 6.14.7 155 version: 6.16.0
153 - name: Uninstall locally and reinstall global npm modules 156 - name: Uninstall locally and reinstall global npm modules
154 run: | 157 run: |
155 npm uninstall node-gyp 158 npm uninstall node-gyp
156 npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0 159 npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0
157 npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0 160 npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0
158 - name: Fix corrupted node cache
159 run: npm cache clean --force
160 - name: Install node dependencies recursively 161 - name: Install node dependencies recursively
161 run: npx lerna bootstrap 162 run: npx lerna bootstrap
162 - name: Package recipes 163 - name: Package recipes
@@ -170,7 +171,7 @@ jobs:
170 shell: bash 171 shell: bash
171 - name: Build Ferdi with publish for 'nightly' branch 172 - name: Build Ferdi with publish for 'nightly' branch
172 if: ${{ env.GIT_BRANCH_NAME == 'nightly' }} 173 if: ${{ env.GIT_BRANCH_NAME == 'nightly' }}
173 run: npm run build -- --publish always -c.publish.provider=github -c.publish.owner=${{ github.repository_owner }} -c.publish.repo=nightlies 174 run: npm run build -- --publish always -c.publish.provider=github -c.publish.owner=${{ github.repository_owner }}
174 shell: bash 175 shell: bash
175 env: 176 env:
176 GH_TOKEN: ${{ secrets.FERDI_PUBLISH_TOKEN }} 177 GH_TOKEN: ${{ secrets.FERDI_PUBLISH_TOKEN }}
@@ -255,14 +256,12 @@ jobs:
255 - name: Install pnpm 256 - name: Install pnpm
256 uses: pnpm/action-setup@v2.0.1 257 uses: pnpm/action-setup@v2.0.1
257 with: 258 with:
258 version: 6.14.7 259 version: 6.16.0
259 - name: Uninstall locally and reinstall global npm modules 260 - name: Uninstall locally and reinstall global npm modules
260 run: | 261 run: |
261 npm uninstall node-gyp 262 npm uninstall node-gyp
262 npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0 263 npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0
263 npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0 264 npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0
264 - name: Fix corrupted node cache
265 run: npm cache clean --force
266 - name: Install node dependencies recursively 265 - name: Install node dependencies recursively
267 run: npx lerna bootstrap 266 run: npx lerna bootstrap
268 - name: Figure out used package.json version 267 - name: Figure out used package.json version
@@ -286,7 +285,7 @@ jobs:
286 run: | 285 run: |
287 sudo snap install snapcraft --classic 286 sudo snap install snapcraft --classic
288 echo "$SNAPCRAFT_LOGIN" | snapcraft login --with - 287 echo "$SNAPCRAFT_LOGIN" | snapcraft login --with -
289 npm run build -- --publish always -c.publish.provider=github -c.publish.owner=${{ github.repository_owner }} -c.publish.repo=nightlies -c.snap.publish.provider=snapStore -c.snap.publish.repo=nightlies -c.snap.publish.channels=edge 288 npm run build -- --publish always -c.publish.provider=github -c.publish.owner=${{ github.repository_owner }} -c.snap.publish.provider=snapStore -c.snap.publish.repo=nightlies -c.snap.publish.channels=edge
290 snapcraft logout 289 snapcraft logout
291 shell: bash 290 shell: bash
292 - name: Build Ferdi with publish for 'release' beta branch 291 - name: Build Ferdi with publish for 'release' beta branch
@@ -382,16 +381,13 @@ jobs:
382 - name: Install pnpm 381 - name: Install pnpm
383 uses: pnpm/action-setup@v2.0.1 382 uses: pnpm/action-setup@v2.0.1
384 with: 383 with:
385 version: 6.14.7 384 version: 6.16.0
386 - name: Uninstall locally and reinstall global npm modules 385 - name: Uninstall locally and reinstall global npm modules
387 run: | 386 run: |
388 npm uninstall node-gyp 387 npm uninstall node-gyp
389 npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0 388 npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0
390 npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0 389 npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0
391 shell: bash 390 shell: bash
392 - name: Fix corrupted node cache
393 run: npm cache clean --force
394 shell: bash
395 - name: Install node dependencies recursively 391 - name: Install node dependencies recursively
396 run: npx lerna bootstrap 392 run: npx lerna bootstrap
397 shell: bash 393 shell: bash
@@ -408,7 +404,7 @@ jobs:
408 shell: bash 404 shell: bash
409 - name: Build Ferdi with publish for 'nightly' branch 405 - name: Build Ferdi with publish for 'nightly' branch
410 if: ${{ env.GIT_BRANCH_NAME == 'nightly' }} 406 if: ${{ env.GIT_BRANCH_NAME == 'nightly' }}
411 run: npm run build -- --publish always -c.publish.provider=github -c.publish.owner=${{ github.repository_owner }} -c.publish.repo=nightlies 407 run: npm run build -- --publish always -c.publish.provider=github -c.publish.owner=${{ github.repository_owner }}
412 shell: bash 408 shell: bash
413 env: 409 env:
414 GH_TOKEN: ${{ secrets.FERDI_PUBLISH_TOKEN }} 410 GH_TOKEN: ${{ secrets.FERDI_PUBLISH_TOKEN }}
diff --git a/.github/workflows/ferdi-first-time-contributor.yml b/.github/workflows/ferdi-first-time-contributor.yml
deleted file mode 100644
index 7a1382a03..000000000
--- a/.github/workflows/ferdi-first-time-contributor.yml
+++ /dev/null
@@ -1,40 +0,0 @@
1# Copied from: https://awesomeopensource.com/project/actions/github-script?categoryPage=7
2
3name: Welcome first time contributors
4
5on: pull_request
6
7jobs:
8 welcome:
9 runs-on: ubuntu-latest
10 steps:
11 - uses: actions/github-script@v4
12 with:
13 github-token: ${{ secrets.GITHUB_TOKEN }}
14 script: |
15 // Get a list of all issues created by the PR opener
16 // See: https://octokit.github.io/rest.js/#pagination
17 const creator = context.payload.sender.login
18 const opts = github.issues.listForRepo.endpoint.merge({
19 ...context.issue,
20 creator,
21 state: 'all'
22 })
23 const issues = await github.paginate(opts)
24
25 for (const issue of issues) {
26 if (issue.number === context.issue.number) {
27 continue
28 }
29
30 if (issue.pull_request) {
31 return // Creator is already a contributor.
32 }
33 }
34
35 await github.issues.createComment({
36 issue_number: context.issue.number,
37 owner: context.repo.owner,
38 repo: context.repo.repo,
39 body: `Welcome, ${ creator }! Thanks for contributing to Ferdi!`
40 })
diff --git a/@types/index.d.ts b/@types/index.d.ts
new file mode 100644
index 000000000..4bfdb28fc
--- /dev/null
+++ b/@types/index.d.ts
@@ -0,0 +1,21 @@
1declare global {
2 interface Window {
3 ferdi: any;
4 }
5
6 namespace NodeJS {
7 interface ProcessEnv {
8 GITHUB_AUTH_TOKEN: string;
9 NODE_ENV: 'development' | 'production';
10 FERDI_APPDATA_DIR?: string;
11 PORTABLE_EXECUTABLE_DIR?: string;
12 ELECTRON_IS_DEV?: string;
13 APPDATA?: string;
14 }
15 }
16}
17/**
18 * Workaround to make TS recognize this file as a module.
19 * https://fettblog.eu/typescript-augmenting-global-lib-dom/
20 */
21export {};
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fbf167d69..0171c3b5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,83 @@
1# [v5.6.3-nightly.12](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.10...v5.6.3-nightly.12) (2021-09-24)
2
3### Services
4
5- Update 'skype' and 'discord' to properly relinquish window object for image overlay 💖 @vraravam
6- Allow services to delineate favorites vs non-favorites in unread counts (eg Outlook) (getferdi/recipes#721) 💖 @vraravam
7
8# [v5.6.3-nightly.10](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.9...v5.6.3-nightly.10) (2021-09-22)
9
10### Services
11
12- Added `stackoverflow-chat` Recipe (getferdi/recipes#718) 💖 @vraravam
13- Allow self-hosted option for kimai-cloud service 💖 @vraravam
14- Remove call to 'clearStorageData' so that MS Teams can remember login creds across Ferdi restarts 💖 @vraravam
15
16# [v5.6.3-nightly.9](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.8...v5.6.3-nightly.9) (2021-09-21)
17
18### Bug fixes
19
20- Remove extra validation for `serviceUrl` for github since the url doesn't seem to be valid any more. (getferdi/recipes#715) 💖 @vraravam
21
22### Under the hood
23
24- Removed more references to `@electron/remote` from the codebase (#1968) 💖 @kris7t, @vraravam
25
26# [v5.6.3-nightly.8](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.7...v5.6.3-nightly.8) (2021-09-20)
27
28### Under the hood
29
30- Removed more references to `@electron/remote` from the codebase (#1967) 💖 #kris7t, @vraravam
31
32# [v5.6.3-nightly.7](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.4...v5.6.3-nightly.7) (2021-09-19)
33
34### Services
35
36- Added Pipefy Recipe (#711) 💖 @TanZng
37
38### Bug fixes
39
40- Fix images opening in browser instead of in Discord (#712) 💖 @briankendall
41- Fix accent color customization (#1963) (#1965) 💖 @kris7t
42
43### Under the hood
44
45- Progressing towards converting the whole code base from JS to TS (#1959) 💖 @mhatvan
46- Improved context isolation for sandboxing services (#1964) 💖 @kris7t
47
48# [v5.6.3-nightly.4](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.3...v5.6.3-nightly.4) (2021-09-16)
49
50### Features
51
52- Ferdi now support Split View Mode (#1926) 💖 @niutech
53
54### Bug fixes
55
56- Fix images opening in browser instead of in Discord (getferdi/recipes#712) 💖 @briankendall
57
58# [v5.6.3-nightly.3](https://github.com/getferdi/ferdi/compare/v5.6.3-nightly.2...v5.6.3-nightly.3) (2021-09-15)
59
60### Under the hood
61
62- Defensive programming to avoid javascript error for unread badges 💖 @vraravam
63- Progressing towards converting the whole code base from JS to TS (#1930) (#1934) 💖 @mhatvan
64- Translation updates and fixes 💖 @vraravam @mhatvan
65
66# [v5.6.3-nightly.2](https://github.com/getferdi/ferdi/compare/v5.6.2...v5.6.3-nightly.2) (2021-09-14)
67
68### Features
69
70- Upgrade to [electron 13.4.0](https://github.com/electron/electron/releases/tag/v13.4.0) 💖 @vraravam
71
72### Bug fixes
73
74- Revert "refactor: reuse method from the core electron framework for the `About` box (fixes #1928, #1929) 💖 @vraravam
75
76### Under the hood
77
78- chore: upgrade intl dependencies (#1920) 💖 @mhatvan
79- chore: update various defaultMessages (#1925) 💖 @mhatvan
80
1# [v5.6.2](https://github.com/getferdi/ferdi/compare/v5.6.1...v5.6.2) (2021-09-13) 81# [v5.6.2](https://github.com/getferdi/ferdi/compare/v5.6.1...v5.6.2) (2021-09-13)
2 82
3This is a hotfix for the 5.6.1 release, along with a couple of changes that were made over the weekend 83This is a hotfix for the 5.6.1 release, along with a couple of changes that were made over the weekend
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e0c5014a8..76ad5266b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -67,6 +67,8 @@ node -v
67v14.17.6 67v14.17.6
68npm -v 68npm -v
696.14.13 696.14.13
70pnpm -v
716.16.0
70``` 72```
71 73
72_Note:_ You can choose any package manager to manage multiple versions of `node` and `npm`. For eg, [nvm](https://github.com/nvm-sh/nvm) or [asdf](https://github.com/asdf-vm/asdf). 74_Note:_ You can choose any package manager to manage multiple versions of `node` and `npm`. For eg, [nvm](https://github.com/nvm-sh/nvm) or [asdf](https://github.com/asdf-vm/asdf).
diff --git a/Dockerfile b/Dockerfile
index d3589005b..cb3053708 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -16,14 +16,17 @@ RUN apt-get update -y \
16 16
17WORKDIR /usr/src/ferdi 17WORKDIR /usr/src/ferdi
18 18
19RUN npm i -g pnpm@6.14.7 \ 19RUN npm i -g pnpm@6.16.0 \
20 && npm i -g node-gyp@8.1.0 \ 20 && npm ls -g node-gyp@8.1.0 || npm i -g node-gyp@8.1.0 \
21 && npm i -g lerna@4.0.0 21 && npm ls -g lerna@4.0.0 || npm i -g lerna@4.0.0
22 22
23COPY . . 23COPY package*.json .
24COPY lerna.json .
25
26RUN npm i \
27 && npx lerna bootstrap
24 28
25# Note: Ideally this needs to be done before the COPY step - BUT moving this here resolves the issue with `preval-build-info-cli` not being found 29COPY . .
26RUN npx lerna bootstrap
27 30
28WORKDIR /usr/src/ferdi/recipes 31WORKDIR /usr/src/ferdi/recipes
29 32
diff --git a/README.md b/README.md
index d101347d9..52163017a 100644
--- a/README.md
+++ b/README.md
@@ -14,12 +14,13 @@
14<p align="center"> 14<p align="center">
15<img alt="GitHub Releases" src="https://img.shields.io/github/downloads/getferdi/ferdi/latest/total?label=Downloads&logo=iCloud&logoColor=%23FFFFFF"> 15<img alt="GitHub Releases" src="https://img.shields.io/github/downloads/getferdi/ferdi/latest/total?label=Downloads&logo=iCloud&logoColor=%23FFFFFF">
16<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --> 16<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
17<a href='#contributors-'><img src='https://img.shields.io/badge/contributors-99-default.svg?logo=github' alt='Contributors'/></a> 17<a href='#contributors-'><img src='https://img.shields.io/badge/contributors-100-default.svg?logo=github' alt='Contributors'/></a>
18<!-- ALL-CONTRIBUTORS-BADGE:END --> 18<!-- ALL-CONTRIBUTORS-BADGE:END -->
19<a href="#backers-via-opencollective"><img alt="Open Collective backers" src="https://img.shields.io/opencollective/backers/getferdi?logo=open-collective"></a> 19<a href="#backers-via-opencollective"><img alt="Open Collective backers" src="https://img.shields.io/opencollective/backers/getferdi?logo=open-collective"></a>
20<a href="#sponsors-via-opencollective"><img alt="Open Collective sponsors" src="https://img.shields.io/opencollective/sponsors/getferdi?logo=open-collective"></a> 20<a href="#sponsors-via-opencollective"><img alt="Open Collective sponsors" src="https://img.shields.io/opencollective/sponsors/getferdi?logo=open-collective"></a>
21<a href="https://github.com/getferdi/ferdi/actions/workflows/ferdi-builds.yml"><img alt="Build Status" src="https://github.com/getferdi/ferdi/actions/workflows/ferdi-builds.yml/badge.svg?branch=develop&event=push"></a> 21<a href="https://github.com/getferdi/ferdi/actions/workflows/ferdi-builds.yml"><img alt="Build Status" src="https://github.com/getferdi/ferdi/actions/workflows/ferdi-builds.yml/badge.svg?branch=develop&event=push"></a>
22<a href="https://gitter.im/getferdi/community?utm_source=share-link&utm_medium=link&utm_campaign=share-link"><img alt="Gitter Chat Room" src="https://img.shields.io/gitter/room/getferdi/community"></a> 22<a href="https://gitter.im/getferdi/community"><img alt="Gitter Chat Room" src="https://img.shields.io/gitter/room/getferdi/community"></a>
23<a href="https://chat.stackoverflow.com/rooms/237341/ferdi"><img alt="Stackoverflow Chat Room" src="https://img.shields.io/badge/stackoverflow--chat-ferdi-blue"></a>
23</p> 24</p>
24 25
25🤴🽠Hard-fork of [Franz](https://github.com/meetfranz/franz), adding awesome features and removing unwanted ones. 26🤴🽠Hard-fork of [Franz](https://github.com/meetfranz/franz), adding awesome features and removing unwanted ones.
@@ -60,7 +61,7 @@
60 61
61## What is Ferdi? 62## What is Ferdi?
62 63
63Ferdi is a desktop app that helps you organize how you use your favourite apps by combining them into one application. It is based on Franz - a software already used by thousands of people - with the difference that Ferdi gives you many additional features and doesn't restrict its usage! Ferdi is compatible with your existing Franz account so you can continue right where you left off. Find out more about Ferdi and its features on [getferdi.com](https://getferdi.com). 64Ferdi is a desktop app that helps you organize how you use your favourite apps by combining them into one application. It is based on Franz - a software already used by thousands of people - with the difference that Ferdi gives you many additional features and doesn't restrict its usage! Furthermore, Ferdi is compatible with your existing Franz account, so you can continue right where you left off. Please find out more about Ferdi and its features on [getferdi.com](https://getferdi.com).
64 65
65## Features 66## Features
66 67
@@ -99,7 +100,7 @@ Ferdi is a desktop app that helps you organize how you use your favourite apps b
99 100
100### Download Ferdi 101### Download Ferdi
101 102
102You can download Ferdi for Windows, Mac and Linux on [Ferdi's download page](https://getferdi.com/download) or you can find all variants in the [latest stable release](https://github.com/getferdi/ferdi/releases/latest) assets and [all the other release here](https://github.com/getferdi/ferdi/releases). 103You can download Ferdi for Windows, Mac and Linux on [Ferdi's download page](https://getferdi.com/download) or you can find all variants in the [latest stable release](https://github.com/getferdi/ferdi/releases/latest) assets and [all the other releases here](https://github.com/getferdi/ferdi/releases).
103 104
104### Or use Chocolatey (Windows only) 105### Or use Chocolatey (Windows only)
105 106
@@ -135,7 +136,7 @@ Ferdi has three separate AUR packages you can use:
135- **[ferdi-bin](https://aur.archlinux.org/packages/ferdi-bin/)**: Uses the latest Fedora release and extracts it to Arch. Use this version if you are having trouble with the `ferdi` package. 136- **[ferdi-bin](https://aur.archlinux.org/packages/ferdi-bin/)**: Uses the latest Fedora release and extracts it to Arch. Use this version if you are having trouble with the `ferdi` package.
136- **[ferdi-git](https://aur.archlinux.org/packages/ferdi-git/)**: Uses your system electron version to run the latest commit from the develop branch and may be unstable but may also give you features that are not yet available in other versions. Please only use `ferdi-git` if you accept these risks. 137- **[ferdi-git](https://aur.archlinux.org/packages/ferdi-git/)**: Uses your system electron version to run the latest commit from the develop branch and may be unstable but may also give you features that are not yet available in other versions. Please only use `ferdi-git` if you accept these risks.
137 138
138If you use an AUR Helper e.g. yay, simply install it via `yay -S ferdi`. 139If you use an AUR Helper, e.g. yay, install it via `yay -S ferdi`.
139 140
140## What makes Ferdi different from Franz? 141## What makes Ferdi different from Franz?
141 142
@@ -226,7 +227,7 @@ If you use an AUR Helper e.g. yay, simply install it via `yay -S ferdi`.
226 227
227### Adds internal changes 228### Adds internal changes
228 229
229- [x] Upgrades to Electron 13.3.0 230- [x] Upgrades to Electron 15.1.1
230- [x] Switches to [`electron-spellchecker`](https://github.com/electron-userland/electron-spellchecker) to improve application size 231- [x] Switches to [`electron-spellchecker`](https://github.com/electron-userland/electron-spellchecker) to improve application size
231- [x] Minifies build files to improve app size 232- [x] Minifies build files to improve app size
232- [x] Adds "npm run prepare-code" command for development to lint and beautify code 233- [x] Adds "npm run prepare-code" command for development to lint and beautify code
@@ -244,7 +245,7 @@ We welcome all contributors. Please read the [contributing guidelines](CONTRIBUT
244 245
245## Nightly releases 246## Nightly releases
246 247
247Nightly releases are automatically triggered every day ([details](https://github.com/getferdi/ferdi/pull/990)) and available in [getferdi/nightlies](https://github.com/getferdi/nightlies/releases). Maintainers still need to manually publish the draft releases as pre-releases for now. 248Nightly releases are automatically triggered every day ([details](https://github.com/getferdi/ferdi/pull/990)) and available in [getferdi/ferdi](https://github.com/getferdi/ferdi/releases). Maintainers still need to verify and manually publish the draft releases as pre-releases for now.
248 249
249## Troubleshooting recipes (self-help) 250## Troubleshooting recipes (self-help)
250 251
@@ -386,8 +387,9 @@ Thanks goes to these awesome people:
386 </tr> 387 </tr>
387 <tr> 388 <tr>
388 <td align="center"><a href='https://github.com/graves501' title='graves501: doc'><img src='https://avatars.githubusercontent.com/u/11211125?v=4' alt='graves501' style='border-radius:42px;width:42px;height:42px;'/></a></td> 389 <td align="center"><a href='https://github.com/graves501' title='graves501: doc'><img src='https://avatars.githubusercontent.com/u/11211125?v=4' alt='graves501' style='border-radius:42px;width:42px;height:42px;'/></a></td>
389 <td align="center"><a href='https://www.ekino.com' title='Sadetdin EYILI: code, bug'><img src='https://avatars.githubusercontent.com/u/5607440?v=4' alt='sad270' style='border-radius:42px;width:42px;height:42px;'/></a></td> 390 <td align="center"><a href='https://www.ekino.com' title='Sadetdin EYILI: code, bug, userTesting'><img src='https://avatars.githubusercontent.com/u/5607440?v=4' alt='sad270' style='border-radius:42px;width:42px;height:42px;'/></a></td>
390 <td align="center"><a href='https://github.com/Tsakatac' title='Tsakatac: bug'><img src='https://avatars.githubusercontent.com/u/89021195?v=4' alt='Tsakatac' style='border-radius:42px;width:42px;height:42px;'/></a></td> 391 <td align="center"><a href='https://github.com/Tsakatac' title='Tsakatac: bug'><img src='https://avatars.githubusercontent.com/u/89021195?v=4' alt='Tsakatac' style='border-radius:42px;width:42px;height:42px;'/></a></td>
392 <td align="center"><a href='http://niute.ch' title='niu tech: code'><img src='https://avatars.githubusercontent.com/u/384997?v=4' alt='niutech' style='border-radius:42px;width:42px;height:42px;'/></a></td>
391 </tr> 393 </tr>
392</table> 394</table>
393 395
diff --git a/babel.config.json b/babel.config.json
index 034e51ce5..d24207a8c 100644
--- a/babel.config.json
+++ b/babel.config.json
@@ -1,8 +1,5 @@
1{ 1{
2 "babelrcRoots": [ 2 "babelrcRoots": [".", "packages/*"],
3 ".",
4 "packages/*"
5 ],
6 "presets": [ 3 "presets": [
7 [ 4 [
8 "@babel/preset-env", 5 "@babel/preset-env",
@@ -31,11 +28,10 @@
31 "@babel/proposal-throw-expressions", 28 "@babel/proposal-throw-expressions",
32 "@babel/syntax-dynamic-import", 29 "@babel/syntax-dynamic-import",
33 [ 30 [
34 "react-intl", 31 "formatjs",
35 { 32 {
36 "messagesDir": "./src/i18n/messages/", 33 "idInterpolationPattern": "[sha512:contenthash:base64:6]",
37 "enforceDescriptions": false, 34 "ast": true
38 "extractSourceLocation": true
39 } 35 }
40 ], 36 ],
41 [ 37 [
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index 21b2e3d3b..d5fb607d9 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -33,7 +33,7 @@ const getTargetEnv = isDevBuild ? 'development' : 'production';
33const tsProject = ts.createProject('tsconfig.json'); 33const tsProject = ts.createProject('tsconfig.json');
34 34
35const styleConfig = Object.keys(rawStyleConfig).map(key => { 35const styleConfig = Object.keys(rawStyleConfig).map(key => {
36 const isHex = /^#[0-9A-F]{6}$/i.test(rawStyleConfig[key]); 36 const isHex = /^#[\da-f]{6}$/i.test(rawStyleConfig[key]);
37 return { 37 return {
38 [`$raw_${kebabCase(key)}`]: isHex 38 [`$raw_${kebabCase(key)}`]: isHex
39 ? hexRgb(rawStyleConfig[key], { format: 'array' }).splice(0, 3).join(',') 39 ? hexRgb(rawStyleConfig[key], { format: 'array' }).splice(0, 3).join(',')
@@ -79,7 +79,7 @@ const paths = {
79 ], 79 ],
80 }, 80 },
81 typescripts: { 81 typescripts: {
82 src: 'src/**/*.ts', 82 src: ['src/**/*.ts', 'src/**/*.tsx'],
83 dest: 'build/', 83 dest: 'build/',
84 watch: [ 84 watch: [
85 'src/**/*.ts', 85 'src/**/*.ts',
@@ -151,7 +151,7 @@ export function mvLernaPackages() {
151 151
152export function mvPostinstallScript() { 152export function mvPostinstallScript() {
153 return gulp 153 return gulp
154 .src(['./scripts/postinstall.js']) 154 .src(['./scripts/postinstall.ts'])
155 .pipe(gulp.dest(`${paths.dest}/scripts`)); 155 .pipe(gulp.dest(`${paths.dest}/scripts`));
156} 156}
157 157
@@ -227,7 +227,7 @@ export function processJavascripts() {
227 227
228export function processTypescripts() { 228export function processTypescripts() {
229 return gulp 229 return gulp
230 .src([paths.typescripts.src], { since: gulp.lastRun(processTypescripts) }) 230 .src(paths.typescripts.src, { since: gulp.lastRun(processTypescripts) })
231 .pipe(tsProject()) 231 .pipe(tsProject())
232 .js.pipe( 232 .js.pipe(
233 babel({ 233 babel({
diff --git a/package-lock.json b/package-lock.json
index 8ccf1f666..38d026e51 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
1{ 1{
2 "name": "ferdi", 2 "name": "ferdi",
3 "version": "5.6.2", 3 "version": "5.6.3-nightly.25",
4 "lockfileVersion": 1, 4 "lockfileVersion": 1,
5 "requires": true, 5 "requires": true,
6 "dependencies": { 6 "dependencies": {
@@ -57,6 +57,13 @@
57 "ms": "^2.1.1", 57 "ms": "^2.1.1",
58 "resetable": "^1.0.3", 58 "resetable": "^1.0.3",
59 "uuid": "^3.3.2" 59 "uuid": "^3.3.2"
60 },
61 "dependencies": {
62 "uuid": {
63 "version": "3.4.0",
64 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
65 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
66 }
60 } 67 }
61 }, 68 },
62 "@adonisjs/bodyparser": { 69 "@adonisjs/bodyparser": {
@@ -243,6 +250,11 @@
243 "jsonfile": "^4.0.0", 250 "jsonfile": "^4.0.0",
244 "universalify": "^0.1.0" 251 "universalify": "^0.1.0"
245 } 252 }
253 },
254 "uuid": {
255 "version": "3.4.0",
256 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
257 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
246 } 258 }
247 } 259 }
248 }, 260 },
@@ -257,6 +269,13 @@
257 "node-csp": "^1.0.1", 269 "node-csp": "^1.0.1",
258 "node-guard": "^1.0.0", 270 "node-guard": "^1.0.0",
259 "uuid": "^3.3.2" 271 "uuid": "^3.3.2"
272 },
273 "dependencies": {
274 "uuid": {
275 "version": "3.4.0",
276 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
277 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
278 }
260 } 279 }
261 }, 280 },
262 "@adonisjs/validator": { 281 "@adonisjs/validator": {
@@ -2319,6 +2338,21 @@
2319 } 2338 }
2320 } 2339 }
2321 }, 2340 },
2341 "@cspotcode/source-map-consumer": {
2342 "version": "0.8.0",
2343 "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
2344 "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
2345 "dev": true
2346 },
2347 "@cspotcode/source-map-support": {
2348 "version": "0.6.1",
2349 "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz",
2350 "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==",
2351 "dev": true,
2352 "requires": {
2353 "@cspotcode/source-map-consumer": "0.8.0"
2354 }
2355 },
2322 "@dabh/diagnostics": { 2356 "@dabh/diagnostics": {
2323 "version": "2.0.2", 2357 "version": "2.0.2",
2324 "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", 2358 "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz",
@@ -2488,6 +2522,233 @@
2488 } 2522 }
2489 } 2523 }
2490 }, 2524 },
2525 "@formatjs/cli": {
2526 "version": "4.2.33",
2527 "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-4.2.33.tgz",
2528 "integrity": "sha512-4Lg+KZ5QhXgF6+zjHyZlxMG8I0D3m3PZyrj3hRl97vdZ6rAWKVFWw8fkTO/iyhUCP2iC47Eh9r+ZTgGARX9Teg==",
2529 "dev": true,
2530 "requires": {
2531 "@formatjs/icu-messageformat-parser": "2.0.11",
2532 "@formatjs/ts-transformer": "3.4.10",
2533 "@types/estree": "^0.0.50",
2534 "@types/fs-extra": "^9.0.1",
2535 "@types/json-stable-stringify": "^1.0.32",
2536 "@types/node": "14",
2537 "@vue/compiler-core": "^3.0.5",
2538 "@vue/compiler-sfc": "^3.0.5",
2539 "chalk": "^4.0.0",
2540 "commander": "8",
2541 "fast-glob": "^3.2.7",
2542 "fs-extra": "10",
2543 "json-stable-stringify": "^1.0.1",
2544 "loud-rejection": "^2.2.0",
2545 "tslib": "^2.1.0",
2546 "typescript": "4"
2547 },
2548 "dependencies": {
2549 "ansi-styles": {
2550 "version": "4.3.0",
2551 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
2552 "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
2553 "dev": true,
2554 "requires": {
2555 "color-convert": "^2.0.1"
2556 }
2557 },
2558 "chalk": {
2559 "version": "4.1.2",
2560 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
2561 "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
2562 "dev": true,
2563 "requires": {
2564 "ansi-styles": "^4.1.0",
2565 "supports-color": "^7.1.0"
2566 }
2567 },
2568 "color-convert": {
2569 "version": "2.0.1",
2570 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
2571 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
2572 "dev": true,
2573 "requires": {
2574 "color-name": "~1.1.4"
2575 }
2576 },
2577 "color-name": {
2578 "version": "1.1.4",
2579 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
2580 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
2581 "dev": true
2582 },
2583 "commander": {
2584 "version": "8.2.0",
2585 "resolved": "https://registry.npmjs.org/commander/-/commander-8.2.0.tgz",
2586 "integrity": "sha512-LLKxDvHeL91/8MIyTAD5BFMNtoIwztGPMiM/7Bl8rIPmHCZXRxmSWr91h57dpOpnQ6jIUqEWdXE/uBYMfiVZDA==",
2587 "dev": true
2588 },
2589 "has-flag": {
2590 "version": "4.0.0",
2591 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
2592 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
2593 "dev": true
2594 },
2595 "supports-color": {
2596 "version": "7.2.0",
2597 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
2598 "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
2599 "dev": true,
2600 "requires": {
2601 "has-flag": "^4.0.0"
2602 }
2603 },
2604 "typescript": {
2605 "version": "4.4.3",
2606 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
2607 "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
2608 "dev": true
2609 }
2610 }
2611 },
2612 "@formatjs/ecma402-abstract": {
2613 "version": "1.9.8",
2614 "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.9.8.tgz",
2615 "integrity": "sha512-2U4n11bLmTij/k4ePCEFKJILPYwdMcJTdnKVBi+JMWBgu5O1N+XhCazlE6QXqVO1Agh2Doh0b/9Jf1mSmSVfhA==",
2616 "requires": {
2617 "@formatjs/intl-localematcher": "0.2.20",
2618 "tslib": "^2.1.0"
2619 }
2620 },
2621 "@formatjs/fast-memoize": {
2622 "version": "1.2.0",
2623 "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.0.tgz",
2624 "integrity": "sha512-fObitP9Tlc31SKrPHgkPgQpGo4+4yXfQQITTCNH8AZdEqB7Mq4nPrjpUL/tNGN3lEeJcFxDbi0haX8HM7QvQ8w==",
2625 "requires": {
2626 "tslib": "^2.1.0"
2627 }
2628 },
2629 "@formatjs/icu-messageformat-parser": {
2630 "version": "2.0.11",
2631 "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.11.tgz",
2632 "integrity": "sha512-5mWb8U8aulYGwnDZWrr+vdgn5PilvtrqQYQ1pvpgzQes/osi85TwmL2GqTGLlKIvBKD2XNA61kAqXYY95w4LWg==",
2633 "requires": {
2634 "@formatjs/ecma402-abstract": "1.9.8",
2635 "@formatjs/icu-skeleton-parser": "1.2.12",
2636 "tslib": "^2.1.0"
2637 }
2638 },
2639 "@formatjs/icu-skeleton-parser": {
2640 "version": "1.2.12",
2641 "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.2.12.tgz",
2642 "integrity": "sha512-DTFxWmEA02ZNW6fsYjGYSADvtrqqjCYF7DSgCmMfaaE0gLP4pCdAgOPE+lkXXU+jP8iCw/YhMT2Seyk/C5lBWg==",
2643 "requires": {
2644 "@formatjs/ecma402-abstract": "1.9.8",
2645 "tslib": "^2.1.0"
2646 }
2647 },
2648 "@formatjs/intl": {
2649 "version": "1.14.1",
2650 "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-1.14.1.tgz",
2651 "integrity": "sha512-mtL8oBgFwTu0GHFnxaF93fk/zNzNkPzl+27Fwg5AZ88pWHWb7037dpODzoCBnaIVk4FBO5emUn/6jI9Byj8hOw==",
2652 "requires": {
2653 "@formatjs/ecma402-abstract": "1.9.8",
2654 "@formatjs/fast-memoize": "1.2.0",
2655 "@formatjs/icu-messageformat-parser": "2.0.11",
2656 "@formatjs/intl-displaynames": "5.2.3",
2657 "@formatjs/intl-listformat": "6.3.3",
2658 "intl-messageformat": "9.9.1",
2659 "tslib": "^2.1.0"
2660 }
2661 },
2662 "@formatjs/intl-displaynames": {
2663 "version": "5.2.3",
2664 "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-5.2.3.tgz",
2665 "integrity": "sha512-5BmhSurLbfgdeo0OBcNPPkIS8ikMMYaHe2NclxEQZqcMvrnQzNMNnUE2dDF5vZx+mkvKq77aQYzpc8RfqVsRCQ==",
2666 "requires": {
2667 "@formatjs/ecma402-abstract": "1.9.8",
2668 "@formatjs/intl-localematcher": "0.2.20",
2669 "tslib": "^2.1.0"
2670 }
2671 },
2672 "@formatjs/intl-listformat": {
2673 "version": "6.3.3",
2674 "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-6.3.3.tgz",
2675 "integrity": "sha512-3nzAKgVS5rePDa5HiH0OwZgAhqxLtzlMc9Pg4QgajRHSP1TqFiMmQnnn52wd3+xVTb7cjZVm3JBnTv51/MhTOg==",
2676 "requires": {
2677 "@formatjs/ecma402-abstract": "1.9.8",
2678 "@formatjs/intl-localematcher": "0.2.20",
2679 "tslib": "^2.1.0"
2680 }
2681 },
2682 "@formatjs/intl-localematcher": {
2683 "version": "0.2.20",
2684 "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.20.tgz",
2685 "integrity": "sha512-/Ro85goRZnCojzxOegANFYL0LaDIpdPjAukR7xMTjOtRx+3yyjR0ifGTOW3/Kjhmab3t6GnyHBYWZSudxEOxPA==",
2686 "requires": {
2687 "tslib": "^2.1.0"
2688 }
2689 },
2690 "@formatjs/ts-transformer": {
2691 "version": "3.4.10",
2692 "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.4.10.tgz",
2693 "integrity": "sha512-5fu8x+8CtyrFe8zdwHvFsYLx9TEPjeJSODRS1ZJxkMVpTBHaNsPqsPkN1TuTk5x3+tSczxXmN1LGrAzUxNN3nQ==",
2694 "dev": true,
2695 "requires": {
2696 "@formatjs/icu-messageformat-parser": "2.0.11",
2697 "chalk": "^4.0.0",
2698 "tslib": "^2.1.0"
2699 },
2700 "dependencies": {
2701 "ansi-styles": {
2702 "version": "4.3.0",
2703 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
2704 "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
2705 "dev": true,
2706 "requires": {
2707 "color-convert": "^2.0.1"
2708 }
2709 },
2710 "chalk": {
2711 "version": "4.1.2",
2712 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
2713 "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
2714 "dev": true,
2715 "requires": {
2716 "ansi-styles": "^4.1.0",
2717 "supports-color": "^7.1.0"
2718 }
2719 },
2720 "color-convert": {
2721 "version": "2.0.1",
2722 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
2723 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
2724 "dev": true,
2725 "requires": {
2726 "color-name": "~1.1.4"
2727 }
2728 },
2729 "color-name": {
2730 "version": "1.1.4",
2731 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
2732 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
2733 "dev": true
2734 },
2735 "has-flag": {
2736 "version": "4.0.0",
2737 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
2738 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
2739 "dev": true
2740 },
2741 "supports-color": {
2742 "version": "7.2.0",
2743 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
2744 "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
2745 "dev": true,
2746 "requires": {
2747 "has-flag": "^4.0.0"
2748 }
2749 }
2750 }
2751 },
2491 "@hapi/hoek": { 2752 "@hapi/hoek": {
2492 "version": "9.2.0", 2753 "version": "9.2.0",
2493 "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz", 2754 "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.0.tgz",
@@ -5612,14 +5873,14 @@
5612 } 5873 }
5613 }, 5874 },
5614 "@mdi/font": { 5875 "@mdi/font": {
5615 "version": "5.9.55", 5876 "version": "6.2.95",
5616 "resolved": "https://registry.npmjs.org/@mdi/font/-/font-5.9.55.tgz", 5877 "resolved": "https://registry.npmjs.org/@mdi/font/-/font-6.2.95.tgz",
5617 "integrity": "sha512-jswRF6q3eq8NWpWiqct6q+6Fg/I7nUhrxYJfiEM8JJpap0wVJLQdbKtyS65GdlK7S7Ytnx3TTi/bmw+tBhkGmg==" 5878 "integrity": "sha512-0RKkhabkFZP3ALwKqrjhdKdhydQpoydIjX6cvjIwLyjADCsE0pG68YkGY+S3qnfdErmhS4m8adwvgrAFXp2AYQ=="
5618 }, 5879 },
5619 "@mdi/js": { 5880 "@mdi/js": {
5620 "version": "4.6.95", 5881 "version": "6.2.95",
5621 "resolved": "https://registry.npmjs.org/@mdi/js/-/js-4.6.95.tgz", 5882 "resolved": "https://registry.npmjs.org/@mdi/js/-/js-6.2.95.tgz",
5622 "integrity": "sha512-ga5GlIY/2hFQAuT5JKY21Rj+W9CnnbOp+ge6BEr/7omOiGVvsmUtetYOBOhyf8xgJ/BBtgvYHPzjZXORjh9cTg==" 5883 "integrity": "sha512-fbD22sEBathqVSQWcxshEtzhhRNFmMnV64z6T7DClRbQ9N5axorykt3Suv2zPzLDyiqH7UhNRu0VPvPCPDNpnQ=="
5623 }, 5884 },
5624 "@mdi/react": { 5885 "@mdi/react": {
5625 "version": "1.5.0", 5886 "version": "1.5.0",
@@ -6386,12 +6647,30 @@
6386 "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", 6647 "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
6387 "dev": true 6648 "dev": true
6388 }, 6649 },
6650 "@tsconfig/node10": {
6651 "version": "1.0.8",
6652 "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
6653 "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
6654 "dev": true
6655 },
6656 "@tsconfig/node12": {
6657 "version": "1.0.9",
6658 "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
6659 "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
6660 "dev": true
6661 },
6389 "@tsconfig/node14": { 6662 "@tsconfig/node14": {
6390 "version": "1.0.1", 6663 "version": "1.0.1",
6391 "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", 6664 "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
6392 "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", 6665 "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
6393 "dev": true 6666 "dev": true
6394 }, 6667 },
6668 "@tsconfig/node16": {
6669 "version": "1.0.2",
6670 "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
6671 "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
6672 "dev": true
6673 },
6395 "@types/babel__core": { 6674 "@types/babel__core": {
6396 "version": "7.1.15", 6675 "version": "7.1.15",
6397 "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", 6676 "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
@@ -6414,6 +6693,15 @@
6414 "@babel/types": "^7.0.0" 6693 "@babel/types": "^7.0.0"
6415 } 6694 }
6416 }, 6695 },
6696 "@types/babel__helper-plugin-utils": {
6697 "version": "7.10.0",
6698 "resolved": "https://registry.npmjs.org/@types/babel__helper-plugin-utils/-/babel__helper-plugin-utils-7.10.0.tgz",
6699 "integrity": "sha512-60YtHzhQ9HAkToHVV+TB4VLzBn9lrfgrsOjiJMtbv/c1jPdekBxaByd6DMsGBzROXWoIL6U3lEFvvbu69RkUoA==",
6700 "dev": true,
6701 "requires": {
6702 "@types/babel__core": "*"
6703 }
6704 },
6417 "@types/babel__template": { 6705 "@types/babel__template": {
6418 "version": "7.4.1", 6706 "version": "7.4.1",
6419 "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", 6707 "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
@@ -6472,6 +6760,12 @@
6472 "integrity": "sha512-vwNP+pzkI1ipznek2fCA4xj1kQyL9EJcfdBezD9eToe9eP2IgT3WLEBrVqiXal34LOyiAs8xCQKwugEYOKcMkw==", 6760 "integrity": "sha512-vwNP+pzkI1ipznek2fCA4xj1kQyL9EJcfdBezD9eToe9eP2IgT3WLEBrVqiXal34LOyiAs8xCQKwugEYOKcMkw==",
6473 "dev": true 6761 "dev": true
6474 }, 6762 },
6763 "@types/estree": {
6764 "version": "0.0.50",
6765 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
6766 "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==",
6767 "dev": true
6768 },
6475 "@types/expect.js": { 6769 "@types/expect.js": {
6476 "version": "0.3.29", 6770 "version": "0.3.29",
6477 "resolved": "https://registry.npmjs.org/@types/expect.js/-/expect.js-0.3.29.tgz", 6771 "resolved": "https://registry.npmjs.org/@types/expect.js/-/expect.js-0.3.29.tgz",
@@ -6506,6 +6800,15 @@
6506 "@types/node": "*" 6800 "@types/node": "*"
6507 } 6801 }
6508 }, 6802 },
6803 "@types/hoist-non-react-statics": {
6804 "version": "3.3.1",
6805 "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
6806 "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
6807 "requires": {
6808 "@types/react": "*",
6809 "hoist-non-react-statics": "^3.3.0"
6810 }
6811 },
6509 "@types/html-minifier-terser": { 6812 "@types/html-minifier-terser": {
6510 "version": "5.1.2", 6813 "version": "5.1.2",
6511 "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", 6814 "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz",
@@ -6542,6 +6845,12 @@
6542 "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", 6845 "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
6543 "dev": true 6846 "dev": true
6544 }, 6847 },
6848 "@types/json-stable-stringify": {
6849 "version": "1.0.33",
6850 "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.33.tgz",
6851 "integrity": "sha512-qEWiQff6q2tA5gcJGWwzplQcXdJtm+0oy6IHGHzlOf3eFAkGE/FIPXZK9ofWgNSHVp8AFFI33PJJshS0ei3Gvw==",
6852 "dev": true
6853 },
6545 "@types/json5": { 6854 "@types/json5": {
6546 "version": "0.0.29", 6855 "version": "0.0.29",
6547 "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", 6856 "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -6554,6 +6863,12 @@
6554 "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==", 6863 "integrity": "sha512-/BHF5HAx3em7/KkzVKm3LrsD6HZAXuXO1AJZQ3cRRBZj4oHZDviWPYu0aEplAqDFNHZPW6d3G7KN+ONcCCC7pw==",
6555 "dev": true 6864 "dev": true
6556 }, 6865 },
6866 "@types/mime-types": {
6867 "version": "2.1.1",
6868 "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.1.tgz",
6869 "integrity": "sha512-vXOTGVSLR2jMw440moWTC7H19iUyLtP3Z1YTj7cSsubOICinjMxFeb/V57v9QdyyPGbbWolUFSSmSiRSn94tFw==",
6870 "dev": true
6871 },
6557 "@types/minimatch": { 6872 "@types/minimatch": {
6558 "version": "3.0.5", 6873 "version": "3.0.5",
6559 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", 6874 "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz",
@@ -6625,14 +6940,12 @@
6625 "@types/prop-types": { 6940 "@types/prop-types": {
6626 "version": "15.7.4", 6941 "version": "15.7.4",
6627 "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", 6942 "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz",
6628 "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", 6943 "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
6629 "dev": true
6630 }, 6944 },
6631 "@types/react": { 6945 "@types/react": {
6632 "version": "16.14.6", 6946 "version": "16.14.6",
6633 "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.6.tgz", 6947 "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.6.tgz",
6634 "integrity": "sha512-Ol/aFKune+P0FSFKIgf+XbhGzYGyz0p7g5befSt4rmbzfGLaZR0q7jPew9k7d3bvrcuaL8dPy9Oz3XGZmf9n+w==", 6948 "integrity": "sha512-Ol/aFKune+P0FSFKIgf+XbhGzYGyz0p7g5befSt4rmbzfGLaZR0q7jPew9k7d3bvrcuaL8dPy9Oz3XGZmf9n+w==",
6635 "dev": true,
6636 "requires": { 6949 "requires": {
6637 "@types/prop-types": "*", 6950 "@types/prop-types": "*",
6638 "@types/scheduler": "*", 6951 "@types/scheduler": "*",
@@ -6657,8 +6970,7 @@
6657 "@types/scheduler": { 6970 "@types/scheduler": {
6658 "version": "0.16.2", 6971 "version": "0.16.2",
6659 "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", 6972 "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
6660 "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", 6973 "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
6661 "dev": true
6662 }, 6974 },
6663 "@types/semver": { 6975 "@types/semver": {
6664 "version": "7.3.8", 6976 "version": "7.3.8",
@@ -6716,9 +7028,15 @@
6716 } 7028 }
6717 }, 7029 },
6718 "@types/uuid": { 7030 "@types/uuid": {
6719 "version": "3.4.9", 7031 "version": "8.3.1",
6720 "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.9.tgz", 7032 "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.1.tgz",
6721 "integrity": "sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ==", 7033 "integrity": "sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==",
7034 "dev": true
7035 },
7036 "@types/validator": {
7037 "version": "13.6.3",
7038 "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.6.3.tgz",
7039 "integrity": "sha512-fWG42pMJOL4jKsDDZZREnXLjc3UE0R8LOJfARWYg6U966rxDT7TYejYzLnUF5cvSObGg34nd0+H2wHHU5Omdfw==",
6722 "dev": true 7040 "dev": true
6723 }, 7041 },
6724 "@types/verror": { 7042 "@types/verror": {
@@ -6795,13 +7113,13 @@
6795 "dev": true 7113 "dev": true
6796 }, 7114 },
6797 "@typescript-eslint/eslint-plugin": { 7115 "@typescript-eslint/eslint-plugin": {
6798 "version": "4.30.0", 7116 "version": "4.31.2",
6799 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.30.0.tgz", 7117 "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.2.tgz",
6800 "integrity": "sha512-NgAnqk55RQ/SD+tZFD9aPwNSeHmDHHe5rtUyhIq0ZeCWZEvo4DK9rYz7v9HDuQZFvn320Ot+AikaCKMFKLlD0g==", 7118 "integrity": "sha512-w63SCQ4bIwWN/+3FxzpnWrDjQRXVEGiTt9tJTRptRXeFvdZc/wLiz3FQUwNQ2CVoRGI6KUWMNUj/pk63noUfcA==",
6801 "dev": true, 7119 "dev": true,
6802 "requires": { 7120 "requires": {
6803 "@typescript-eslint/experimental-utils": "4.30.0", 7121 "@typescript-eslint/experimental-utils": "4.31.2",
6804 "@typescript-eslint/scope-manager": "4.30.0", 7122 "@typescript-eslint/scope-manager": "4.31.2",
6805 "debug": "^4.3.1", 7123 "debug": "^4.3.1",
6806 "functional-red-black-tree": "^1.0.1", 7124 "functional-red-black-tree": "^1.0.1",
6807 "regexpp": "^3.1.0", 7125 "regexpp": "^3.1.0",
@@ -6810,43 +7128,43 @@
6810 }, 7128 },
6811 "dependencies": { 7129 "dependencies": {
6812 "@typescript-eslint/experimental-utils": { 7130 "@typescript-eslint/experimental-utils": {
6813 "version": "4.30.0", 7131 "version": "4.31.2",
6814 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz", 7132 "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.2.tgz",
6815 "integrity": "sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw==", 7133 "integrity": "sha512-3tm2T4nyA970yQ6R3JZV9l0yilE2FedYg8dcXrTar34zC9r6JB7WyBQbpIVongKPlhEMjhQ01qkwrzWy38Bk1Q==",
6816 "dev": true, 7134 "dev": true,
6817 "requires": { 7135 "requires": {
6818 "@types/json-schema": "^7.0.7", 7136 "@types/json-schema": "^7.0.7",
6819 "@typescript-eslint/scope-manager": "4.30.0", 7137 "@typescript-eslint/scope-manager": "4.31.2",
6820 "@typescript-eslint/types": "4.30.0", 7138 "@typescript-eslint/types": "4.31.2",
6821 "@typescript-eslint/typescript-estree": "4.30.0", 7139 "@typescript-eslint/typescript-estree": "4.31.2",
6822 "eslint-scope": "^5.1.1", 7140 "eslint-scope": "^5.1.1",
6823 "eslint-utils": "^3.0.0" 7141 "eslint-utils": "^3.0.0"
6824 } 7142 }
6825 }, 7143 },
6826 "@typescript-eslint/scope-manager": { 7144 "@typescript-eslint/scope-manager": {
6827 "version": "4.30.0", 7145 "version": "4.31.2",
6828 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.30.0.tgz", 7146 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz",
6829 "integrity": "sha512-VJ/jAXovxNh7rIXCQbYhkyV2Y3Ac/0cVHP/FruTJSAUUm4Oacmn/nkN5zfWmWFEanN4ggP0vJSHOeajtHq3f8A==", 7147 "integrity": "sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w==",
6830 "dev": true, 7148 "dev": true,
6831 "requires": { 7149 "requires": {
6832 "@typescript-eslint/types": "4.30.0", 7150 "@typescript-eslint/types": "4.31.2",
6833 "@typescript-eslint/visitor-keys": "4.30.0" 7151 "@typescript-eslint/visitor-keys": "4.31.2"
6834 } 7152 }
6835 }, 7153 },
6836 "@typescript-eslint/types": { 7154 "@typescript-eslint/types": {
6837 "version": "4.30.0", 7155 "version": "4.31.2",
6838 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.30.0.tgz", 7156 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.2.tgz",
6839 "integrity": "sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw==", 7157 "integrity": "sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w==",
6840 "dev": true 7158 "dev": true
6841 }, 7159 },
6842 "@typescript-eslint/typescript-estree": { 7160 "@typescript-eslint/typescript-estree": {
6843 "version": "4.30.0", 7161 "version": "4.31.2",
6844 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz", 7162 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz",
6845 "integrity": "sha512-6WN7UFYvykr/U0Qgy4kz48iGPWILvYL34xXJxvDQeiRE018B7POspNRVtAZscWntEPZpFCx4hcz/XBT+erenfg==", 7163 "integrity": "sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA==",
6846 "dev": true, 7164 "dev": true,
6847 "requires": { 7165 "requires": {
6848 "@typescript-eslint/types": "4.30.0", 7166 "@typescript-eslint/types": "4.31.2",
6849 "@typescript-eslint/visitor-keys": "4.30.0", 7167 "@typescript-eslint/visitor-keys": "4.31.2",
6850 "debug": "^4.3.1", 7168 "debug": "^4.3.1",
6851 "globby": "^11.0.3", 7169 "globby": "^11.0.3",
6852 "is-glob": "^4.0.1", 7170 "is-glob": "^4.0.1",
@@ -6855,12 +7173,12 @@
6855 } 7173 }
6856 }, 7174 },
6857 "@typescript-eslint/visitor-keys": { 7175 "@typescript-eslint/visitor-keys": {
6858 "version": "4.30.0", 7176 "version": "4.31.2",
6859 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz", 7177 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz",
6860 "integrity": "sha512-pNaaxDt/Ol/+JZwzP7MqWc8PJQTUhZwoee/PVlQ+iYoYhagccvoHnC9e4l+C/krQYYkENxznhVSDwClIbZVxRw==", 7178 "integrity": "sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug==",
6861 "dev": true, 7179 "dev": true,
6862 "requires": { 7180 "requires": {
6863 "@typescript-eslint/types": "4.30.0", 7181 "@typescript-eslint/types": "4.31.2",
6864 "eslint-visitor-keys": "^2.0.0" 7182 "eslint-visitor-keys": "^2.0.0"
6865 } 7183 }
6866 }, 7184 },
@@ -6890,41 +7208,41 @@
6890 } 7208 }
6891 }, 7209 },
6892 "@typescript-eslint/parser": { 7210 "@typescript-eslint/parser": {
6893 "version": "4.29.1", 7211 "version": "4.31.2",
6894 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.1.tgz", 7212 "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.31.2.tgz",
6895 "integrity": "sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg==", 7213 "integrity": "sha512-EcdO0E7M/sv23S/rLvenHkb58l3XhuSZzKf6DBvLgHqOYdL6YFMYVtreGFWirxaU2mS1GYDby3Lyxco7X5+Vjw==",
6896 "dev": true, 7214 "dev": true,
6897 "requires": { 7215 "requires": {
6898 "@typescript-eslint/scope-manager": "4.29.1", 7216 "@typescript-eslint/scope-manager": "4.31.2",
6899 "@typescript-eslint/types": "4.29.1", 7217 "@typescript-eslint/types": "4.31.2",
6900 "@typescript-eslint/typescript-estree": "4.29.1", 7218 "@typescript-eslint/typescript-estree": "4.31.2",
6901 "debug": "^4.3.1" 7219 "debug": "^4.3.1"
6902 }, 7220 },
6903 "dependencies": { 7221 "dependencies": {
6904 "@typescript-eslint/scope-manager": { 7222 "@typescript-eslint/scope-manager": {
6905 "version": "4.29.1", 7223 "version": "4.31.2",
6906 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz", 7224 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.31.2.tgz",
6907 "integrity": "sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A==", 7225 "integrity": "sha512-2JGwudpFoR/3Czq6mPpE8zBPYdHWFGL6lUNIGolbKQeSNv4EAiHaR5GVDQaLA0FwgcdcMtRk+SBJbFGL7+La5w==",
6908 "dev": true, 7226 "dev": true,
6909 "requires": { 7227 "requires": {
6910 "@typescript-eslint/types": "4.29.1", 7228 "@typescript-eslint/types": "4.31.2",
6911 "@typescript-eslint/visitor-keys": "4.29.1" 7229 "@typescript-eslint/visitor-keys": "4.31.2"
6912 } 7230 }
6913 }, 7231 },
6914 "@typescript-eslint/types": { 7232 "@typescript-eslint/types": {
6915 "version": "4.29.1", 7233 "version": "4.31.2",
6916 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.1.tgz", 7234 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.31.2.tgz",
6917 "integrity": "sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA==", 7235 "integrity": "sha512-kWiTTBCTKEdBGrZKwFvOlGNcAsKGJSBc8xLvSjSppFO88AqGxGNYtF36EuEYG6XZ9vT0xX8RNiHbQUKglbSi1w==",
6918 "dev": true 7236 "dev": true
6919 }, 7237 },
6920 "@typescript-eslint/typescript-estree": { 7238 "@typescript-eslint/typescript-estree": {
6921 "version": "4.29.1", 7239 "version": "4.31.2",
6922 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz", 7240 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.2.tgz",
6923 "integrity": "sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw==", 7241 "integrity": "sha512-ieBq8U9at6PvaC7/Z6oe8D3czeW5d//Fo1xkF/s9394VR0bg/UaMYPdARiWyKX+lLEjY3w/FNZJxitMsiWv+wA==",
6924 "dev": true, 7242 "dev": true,
6925 "requires": { 7243 "requires": {
6926 "@typescript-eslint/types": "4.29.1", 7244 "@typescript-eslint/types": "4.31.2",
6927 "@typescript-eslint/visitor-keys": "4.29.1", 7245 "@typescript-eslint/visitor-keys": "4.31.2",
6928 "debug": "^4.3.1", 7246 "debug": "^4.3.1",
6929 "globby": "^11.0.3", 7247 "globby": "^11.0.3",
6930 "is-glob": "^4.0.1", 7248 "is-glob": "^4.0.1",
@@ -6933,12 +7251,12 @@
6933 } 7251 }
6934 }, 7252 },
6935 "@typescript-eslint/visitor-keys": { 7253 "@typescript-eslint/visitor-keys": {
6936 "version": "4.29.1", 7254 "version": "4.31.2",
6937 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz", 7255 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.2.tgz",
6938 "integrity": "sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag==", 7256 "integrity": "sha512-PrBId7EQq2Nibns7dd/ch6S6/M4/iwLM9McbgeEbCXfxdwRUNxJ4UNreJ6Gh3fI2GNKNrWnQxKL7oCPmngKBug==",
6939 "dev": true, 7257 "dev": true,
6940 "requires": { 7258 "requires": {
6941 "@typescript-eslint/types": "4.29.1", 7259 "@typescript-eslint/types": "4.31.2",
6942 "eslint-visitor-keys": "^2.0.0" 7260 "eslint-visitor-keys": "^2.0.0"
6943 } 7261 }
6944 }, 7262 },
@@ -7011,6 +7329,121 @@
7011 "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", 7329 "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
7012 "dev": true 7330 "dev": true
7013 }, 7331 },
7332 "@vue/compiler-core": {
7333 "version": "3.2.11",
7334 "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.11.tgz",
7335 "integrity": "sha512-bcbsLx5XyQg8WDDEGwmpX0BfEfv82wIs9fWFelpyVhNRGMaABvUTalYINyfhVT+jOqNaD4JBhJiVKd/8TmsHWg==",
7336 "dev": true,
7337 "requires": {
7338 "@babel/parser": "^7.15.0",
7339 "@babel/types": "^7.15.0",
7340 "@vue/shared": "3.2.11",
7341 "estree-walker": "^2.0.2",
7342 "source-map": "^0.6.1"
7343 },
7344 "dependencies": {
7345 "source-map": {
7346 "version": "0.6.1",
7347 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
7348 "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
7349 "dev": true
7350 }
7351 }
7352 },
7353 "@vue/compiler-dom": {
7354 "version": "3.2.11",
7355 "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.11.tgz",
7356 "integrity": "sha512-DNvhUHI/1Hn0/+ZYDYGAuDGasUm+XHKC3FE4GqkNCTO/fcLaJMRg/7eT1m1lkc7jPffUwwfh1rZru5mwzOjrNw==",
7357 "dev": true,
7358 "requires": {
7359 "@vue/compiler-core": "3.2.11",
7360 "@vue/shared": "3.2.11"
7361 }
7362 },
7363 "@vue/compiler-sfc": {
7364 "version": "3.2.11",
7365 "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.11.tgz",
7366 "integrity": "sha512-cUIaS8mgJrQ6yucj2AupWAwBRITK3W/a8wCOn9g5fJGtOl8h4APY8vN3lzP8HIJDyEeRF3I8SfRhL+oX97kSnw==",
7367 "dev": true,
7368 "requires": {
7369 "@babel/parser": "^7.15.0",
7370 "@babel/types": "^7.15.0",
7371 "@types/estree": "^0.0.48",
7372 "@vue/compiler-core": "3.2.11",
7373 "@vue/compiler-dom": "3.2.11",
7374 "@vue/compiler-ssr": "3.2.11",
7375 "@vue/ref-transform": "3.2.11",
7376 "@vue/shared": "3.2.11",
7377 "consolidate": "^0.16.0",
7378 "estree-walker": "^2.0.2",
7379 "hash-sum": "^2.0.0",
7380 "lru-cache": "^5.1.1",
7381 "magic-string": "^0.25.7",
7382 "merge-source-map": "^1.1.0",
7383 "postcss": "^8.1.10",
7384 "postcss-modules": "^4.0.0",
7385 "postcss-selector-parser": "^6.0.4",
7386 "source-map": "^0.6.1"
7387 },
7388 "dependencies": {
7389 "@types/estree": {
7390 "version": "0.0.48",
7391 "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz",
7392 "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==",
7393 "dev": true
7394 },
7395 "lru-cache": {
7396 "version": "5.1.1",
7397 "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
7398 "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
7399 "dev": true,
7400 "requires": {
7401 "yallist": "^3.0.2"
7402 }
7403 },
7404 "source-map": {
7405 "version": "0.6.1",
7406 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
7407 "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
7408 "dev": true
7409 },
7410 "yallist": {
7411 "version": "3.1.1",
7412 "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
7413 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
7414 "dev": true
7415 }
7416 }
7417 },
7418 "@vue/compiler-ssr": {
7419 "version": "3.2.11",
7420 "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.11.tgz",
7421 "integrity": "sha512-+ptAdUlFDij+Z0VGCbRRkxQlNev5LkbZAntvkxrFjc08CTMhZmiV4Js48n2hAmuSXaKNEpmGkDGU26c/vf1+xw==",
7422 "dev": true,
7423 "requires": {
7424 "@vue/compiler-dom": "3.2.11",
7425 "@vue/shared": "3.2.11"
7426 }
7427 },
7428 "@vue/ref-transform": {
7429 "version": "3.2.11",
7430 "resolved": "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.11.tgz",
7431 "integrity": "sha512-7rX0YsfYb7+1PeKPME1tQyUQcQgt0sIXRRnPD1Vw8Zs2KIo90YLy9CrvwalcRCxGw0ScsjBEhVjJtWIT79TElg==",
7432 "dev": true,
7433 "requires": {
7434 "@babel/parser": "^7.15.0",
7435 "@vue/compiler-core": "3.2.11",
7436 "@vue/shared": "3.2.11",
7437 "estree-walker": "^2.0.2",
7438 "magic-string": "^0.25.7"
7439 }
7440 },
7441 "@vue/shared": {
7442 "version": "3.2.11",
7443 "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.11.tgz",
7444 "integrity": "sha512-ovfXAsSsCvV9JVceWjkqC/7OF5HbgLOtCWjCIosmPGG8lxbPuavhIxRH1dTx4Dg9xLgRTNLvI3pVxG4ItQZekg==",
7445 "dev": true
7446 },
7014 "@webassemblyjs/ast": { 7447 "@webassemblyjs/ast": {
7015 "version": "1.9.0", 7448 "version": "1.9.0",
7016 "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", 7449 "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
@@ -8028,6 +8461,12 @@
8028 } 8461 }
8029 } 8462 }
8030 }, 8463 },
8464 "arg": {
8465 "version": "4.1.3",
8466 "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
8467 "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
8468 "dev": true
8469 },
8031 "argparse": { 8470 "argparse": {
8032 "version": "2.0.1", 8471 "version": "2.0.1",
8033 "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 8472 "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -8105,6 +8544,12 @@
8105 "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", 8544 "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
8106 "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" 8545 "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8="
8107 }, 8546 },
8547 "array-find-index": {
8548 "version": "1.0.2",
8549 "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
8550 "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
8551 "dev": true
8552 },
8108 "array-flatten": { 8553 "array-flatten": {
8109 "version": "2.1.2", 8554 "version": "2.1.2",
8110 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", 8555 "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
@@ -8543,6 +8988,86 @@
8543 "object.assign": "^4.1.0" 8988 "object.assign": "^4.1.0"
8544 } 8989 }
8545 }, 8990 },
8991 "babel-plugin-formatjs": {
8992 "version": "10.3.8",
8993 "resolved": "https://registry.npmjs.org/babel-plugin-formatjs/-/babel-plugin-formatjs-10.3.8.tgz",
8994 "integrity": "sha512-pLryt/Q5zmoQWRrybzwiaZ9i0M9I1JJwshHqOuyxn+MlqcxArp2N0E7/X9fhIC1X9yEdDV0zfGbY00J+krmZzQ==",
8995 "dev": true,
8996 "requires": {
8997 "@babel/core": "^7.10.4",
8998 "@babel/helper-plugin-utils": "^7.10.4",
8999 "@babel/plugin-syntax-jsx": "7",
9000 "@babel/traverse": "7",
9001 "@babel/types": "^7.12.11",
9002 "@formatjs/icu-messageformat-parser": "2.0.11",
9003 "@formatjs/ts-transformer": "3.4.10",
9004 "@types/babel__core": "^7.1.7",
9005 "@types/babel__helper-plugin-utils": "^7.10.0",
9006 "tslib": "^2.1.0"
9007 },
9008 "dependencies": {
9009 "@formatjs/ts-transformer": {
9010 "version": "3.4.10",
9011 "resolved": "https://registry.npmjs.org/@formatjs/ts-transformer/-/ts-transformer-3.4.10.tgz",
9012 "integrity": "sha512-5fu8x+8CtyrFe8zdwHvFsYLx9TEPjeJSODRS1ZJxkMVpTBHaNsPqsPkN1TuTk5x3+tSczxXmN1LGrAzUxNN3nQ==",
9013 "dev": true,
9014 "requires": {
9015 "@formatjs/icu-messageformat-parser": "2.0.11",
9016 "chalk": "^4.0.0",
9017 "tslib": "^2.1.0"
9018 }
9019 },
9020 "ansi-styles": {
9021 "version": "4.3.0",
9022 "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
9023 "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
9024 "dev": true,
9025 "requires": {
9026 "color-convert": "^2.0.1"
9027 }
9028 },
9029 "chalk": {
9030 "version": "4.1.2",
9031 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
9032 "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
9033 "dev": true,
9034 "requires": {
9035 "ansi-styles": "^4.1.0",
9036 "supports-color": "^7.1.0"
9037 }
9038 },
9039 "color-convert": {
9040 "version": "2.0.1",
9041 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
9042 "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
9043 "dev": true,
9044 "requires": {
9045 "color-name": "~1.1.4"
9046 }
9047 },
9048 "color-name": {
9049 "version": "1.1.4",
9050 "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
9051 "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
9052 "dev": true
9053 },
9054 "has-flag": {
9055 "version": "4.0.0",
9056 "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
9057 "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
9058 "dev": true
9059 },
9060 "supports-color": {
9061 "version": "7.2.0",
9062 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
9063 "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
9064 "dev": true,
9065 "requires": {
9066 "has-flag": "^4.0.0"
9067 }
9068 }
9069 }
9070 },
8546 "babel-plugin-istanbul": { 9071 "babel-plugin-istanbul": {
8547 "version": "6.0.0", 9072 "version": "6.0.0",
8548 "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", 9073 "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz",
@@ -8606,38 +9131,6 @@
8606 "@babel/helper-define-polyfill-provider": "^0.2.2" 9131 "@babel/helper-define-polyfill-provider": "^0.2.2"
8607 } 9132 }
8608 }, 9133 },
8609 "babel-plugin-react-intl": {
8610 "version": "3.5.1",
8611 "resolved": "https://registry.npmjs.org/babel-plugin-react-intl/-/babel-plugin-react-intl-3.5.1.tgz",
8612 "integrity": "sha512-1jlEJCSmLaJM4tjIKpu64UZ833COCHmwR77bFJDOye+zlwf80uR1b8p41l4tClx1QsrfI+qV6w/5AiPYQgaMUQ==",
8613 "dev": true,
8614 "requires": {
8615 "@babel/core": "^7.4.5",
8616 "@babel/helper-plugin-utils": "^7.0.0",
8617 "@types/babel__core": "^7.1.2",
8618 "fs-extra": "^8.0.1",
8619 "intl-messageformat-parser": "^1.8.1"
8620 },
8621 "dependencies": {
8622 "fs-extra": {
8623 "version": "8.1.0",
8624 "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
8625 "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
8626 "dev": true,
8627 "requires": {
8628 "graceful-fs": "^4.2.0",
8629 "jsonfile": "^4.0.0",
8630 "universalify": "^0.1.0"
8631 }
8632 },
8633 "intl-messageformat-parser": {
8634 "version": "1.8.1",
8635 "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.8.1.tgz",
8636 "integrity": "sha512-IMSCKVf0USrM/959vj3xac7s8f87sc+80Y/ipBzdKy4ifBv5Gsj2tZ41EAaURVg01QU71fYr77uA8Meh6kELbg==",
8637 "dev": true
8638 }
8639 }
8640 },
8641 "babel-preset-current-node-syntax": { 9134 "babel-preset-current-node-syntax": {
8642 "version": "1.0.1", 9135 "version": "1.0.1",
8643 "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", 9136 "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
@@ -9422,6 +9915,12 @@
9422 "sax": "^1.2.4" 9915 "sax": "^1.2.4"
9423 } 9916 }
9424 }, 9917 },
9918 "builtin-modules": {
9919 "version": "3.2.0",
9920 "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
9921 "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
9922 "dev": true
9923 },
9425 "builtin-status-codes": { 9924 "builtin-status-codes": {
9426 "version": "3.0.0", 9925 "version": "3.0.0",
9427 "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", 9926 "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
@@ -9698,9 +10197,9 @@
9698 } 10197 }
9699 }, 10198 },
9700 "caniuse-lite": { 10199 "caniuse-lite": {
9701 "version": "1.0.30001256", 10200 "version": "1.0.30001264",
9702 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001256.tgz", 10201 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001264.tgz",
9703 "integrity": "sha512-QirrvMLmB4txNnxiaG/xbm6FSzv9LqOZ3Jp9VtCYb3oPIfCHpr/oGn38pFq0udwlkctvXQgPthaXqJ76DaYGnA==", 10202 "integrity": "sha512-Ftfqqfcs/ePiUmyaySsQ4PUsdcYyXG2rfoBVsk3iY1ahHaJEw65vfb7Suzqm+cEkwwPIv/XWkg27iCpRavH4zA==",
9704 "dev": true 10203 "dev": true
9705 }, 10204 },
9706 "caseless": { 10205 "caseless": {
@@ -9921,6 +10420,31 @@
9921 "node-addon-api": "*", 10420 "node-addon-api": "*",
9922 "rimraf": "^2.4.0", 10421 "rimraf": "^2.4.0",
9923 "underscore": "^1.6.0" 10422 "underscore": "^1.6.0"
10423 },
10424 "dependencies": {
10425 "rimraf": {
10426 "version": "2.7.1",
10427 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
10428 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
10429 "requires": {
10430 "glob": "^7.1.3"
10431 },
10432 "dependencies": {
10433 "glob": {
10434 "version": "7.1.7",
10435 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
10436 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
10437 "requires": {
10438 "fs.realpath": "^1.0.0",
10439 "inflight": "^1.0.4",
10440 "inherits": "2",
10441 "minimatch": "^3.0.4",
10442 "once": "^1.3.0",
10443 "path-is-absolute": "^1.0.0"
10444 }
10445 }
10446 }
10447 }
9924 } 10448 }
9925 }, 10449 },
9926 "clean-css": { 10450 "clean-css": {
@@ -9940,6 +10464,15 @@
9940 } 10464 }
9941 } 10465 }
9942 }, 10466 },
10467 "clean-regexp": {
10468 "version": "1.0.0",
10469 "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz",
10470 "integrity": "sha1-jffHquUf02h06PjQW5GAvBGj/tc=",
10471 "dev": true,
10472 "requires": {
10473 "escape-string-regexp": "^1.0.5"
10474 }
10475 },
9943 "clean-stack": { 10476 "clean-stack": {
9944 "version": "2.2.0", 10477 "version": "2.2.0",
9945 "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", 10478 "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -10807,6 +11340,15 @@
10807 "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 11340 "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
10808 "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" 11341 "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
10809 }, 11342 },
11343 "consolidate": {
11344 "version": "0.16.0",
11345 "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.16.0.tgz",
11346 "integrity": "sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ==",
11347 "dev": true,
11348 "requires": {
11349 "bluebird": "^3.7.2"
11350 }
11351 },
10810 "constants-browserify": { 11352 "constants-browserify": {
10811 "version": "1.0.0", 11353 "version": "1.0.0",
10812 "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", 11354 "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
@@ -11282,6 +11824,31 @@
11282 "mkdirp": "^0.5.1", 11824 "mkdirp": "^0.5.1",
11283 "rimraf": "^2.5.4", 11825 "rimraf": "^2.5.4",
11284 "run-queue": "^1.0.0" 11826 "run-queue": "^1.0.0"
11827 },
11828 "dependencies": {
11829 "glob": {
11830 "version": "7.1.7",
11831 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
11832 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
11833 "dev": true,
11834 "requires": {
11835 "fs.realpath": "^1.0.0",
11836 "inflight": "^1.0.4",
11837 "inherits": "2",
11838 "minimatch": "^3.0.4",
11839 "once": "^1.3.0",
11840 "path-is-absolute": "^1.0.0"
11841 }
11842 },
11843 "rimraf": {
11844 "version": "2.7.1",
11845 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
11846 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
11847 "dev": true,
11848 "requires": {
11849 "glob": "^7.1.3"
11850 }
11851 }
11285 } 11852 }
11286 }, 11853 },
11287 "copy-descriptor": { 11854 "copy-descriptor": {
@@ -11440,6 +12007,12 @@
11440 "object-assign": "^4.1.1" 12007 "object-assign": "^4.1.1"
11441 } 12008 }
11442 }, 12009 },
12010 "create-require": {
12011 "version": "1.1.1",
12012 "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
12013 "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
12014 "dev": true
12015 },
11443 "cross-env": { 12016 "cross-env": {
11444 "version": "7.0.3", 12017 "version": "7.0.3",
11445 "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", 12018 "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
@@ -11546,24 +12119,6 @@
11546 "uid-safe": "2.1.5" 12119 "uid-safe": "2.1.5"
11547 } 12120 }
11548 }, 12121 },
11549 "css": {
11550 "version": "2.2.4",
11551 "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
11552 "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
11553 "requires": {
11554 "inherits": "^2.0.3",
11555 "source-map": "^0.6.1",
11556 "source-map-resolve": "^0.5.2",
11557 "urix": "^0.1.0"
11558 },
11559 "dependencies": {
11560 "source-map": {
11561 "version": "0.6.1",
11562 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
11563 "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
11564 }
11565 }
11566 },
11567 "css-select": { 12122 "css-select": {
11568 "version": "4.1.3", 12123 "version": "4.1.3",
11569 "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", 12124 "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
@@ -11609,6 +12164,12 @@
11609 "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", 12164 "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==",
11610 "dev": true 12165 "dev": true
11611 }, 12166 },
12167 "cssesc": {
12168 "version": "3.0.0",
12169 "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
12170 "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
12171 "dev": true
12172 },
11612 "csso": { 12173 "csso": {
11613 "version": "4.2.0", 12174 "version": "4.2.0",
11614 "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", 12175 "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
@@ -11646,6 +12207,15 @@
11646 "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", 12207 "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz",
11647 "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" 12208 "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw=="
11648 }, 12209 },
12210 "currently-unhandled": {
12211 "version": "0.4.1",
12212 "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
12213 "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
12214 "dev": true,
12215 "requires": {
12216 "array-find-index": "^1.0.1"
12217 }
12218 },
11649 "cyclist": { 12219 "cyclist": {
11650 "version": "1.0.1", 12220 "version": "1.0.1",
11651 "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", 12221 "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
@@ -12024,6 +12594,15 @@
12024 "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", 12594 "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
12025 "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", 12595 "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
12026 "dev": true 12596 "dev": true
12597 },
12598 "rimraf": {
12599 "version": "2.7.1",
12600 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
12601 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
12602 "dev": true,
12603 "requires": {
12604 "glob": "^7.1.3"
12605 }
12027 } 12606 }
12028 } 12607 }
12029 }, 12608 },
@@ -12487,12 +13066,12 @@
12487 } 13066 }
12488 }, 13067 },
12489 "electron": { 13068 "electron": {
12490 "version": "13.3.0", 13069 "version": "15.1.1",
12491 "resolved": "https://registry.npmjs.org/electron/-/electron-13.3.0.tgz", 13070 "resolved": "https://registry.npmjs.org/electron/-/electron-15.1.1.tgz",
12492 "integrity": "sha512-d/BvOLDjI4i7yf9tqCuLL2fFGA2TrM/D9PyRpua+rJolG0qrwp/FohP02L0m+44kmPpofIo4l3NPwLmzyKKimA==", 13071 "integrity": "sha512-ogVGNWL38KegiqAhUdgjWoKPOufTqDb+cNIqQF/WpVxgauNjzXEk/RNEk7qlw946B/g2dHpzpHeUhi+D/4EcIg==",
12493 "dev": true, 13072 "dev": true,
12494 "requires": { 13073 "requires": {
12495 "@electron/get": "^1.0.1", 13074 "@electron/get": "^1.13.0",
12496 "@types/node": "^14.6.2", 13075 "@types/node": "^14.6.2",
12497 "extract-zip": "^1.0.3" 13076 "extract-zip": "^1.0.3"
12498 } 13077 }
@@ -12688,11 +13267,6 @@
12688 "resolved": "https://registry.npmjs.org/electron-find/-/electron-find-1.0.7.tgz", 13267 "resolved": "https://registry.npmjs.org/electron-find/-/electron-find-1.0.7.tgz",
12689 "integrity": "sha512-C2FQJuk8567P2a2loBNwl5c8kwOTQVMB0capgHtPI7zKwZG16X0UxG+sNYZExQfnJ0PA+ecECA/4LcXxQa2TCA==" 13268 "integrity": "sha512-C2FQJuk8567P2a2loBNwl5c8kwOTQVMB0capgHtPI7zKwZG16X0UxG+sNYZExQfnJ0PA+ecECA/4LcXxQa2TCA=="
12690 }, 13269 },
12691 "electron-is-dev": {
12692 "version": "1.2.0",
12693 "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-1.2.0.tgz",
12694 "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw=="
12695 },
12696 "electron-notarize": { 13270 "electron-notarize": {
12697 "version": "1.1.0", 13271 "version": "1.1.0",
12698 "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.1.0.tgz", 13272 "resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.1.0.tgz",
@@ -12856,13 +13430,13 @@
12856 } 13430 }
12857 }, 13431 },
12858 "electron-react-titlebar": { 13432 "electron-react-titlebar": {
12859 "version": "0.8.2", 13433 "version": "1.0.0",
12860 "resolved": "https://registry.npmjs.org/electron-react-titlebar/-/electron-react-titlebar-0.8.2.tgz", 13434 "resolved": "https://registry.npmjs.org/electron-react-titlebar/-/electron-react-titlebar-1.0.0.tgz",
12861 "integrity": "sha512-Bbkaryi6JmtSuq8hAM+RNxlPhmQdE/7bdEsBasTtS+tbHHPsX0p4ilxVxKlFt23geV8kQaSq7qoZr30ixW8jtw==", 13435 "integrity": "sha512-/Ilv4kYPyJ1czijKtkQ1pXgvI/UeWaHjlNRnvuimWbrDzJJhsEtRHMdbnR1MaZEqRlT5pPlCIy3VflTP6ow3rg==",
12862 "requires": { 13436 "requires": {
12863 "classnames": "^2.2.6", 13437 "classnames": "^2.3.1",
12864 "lodash": "^4.17.15", 13438 "lodash": "^4.17.21",
12865 "react-virtualized": "^9.7.6" 13439 "react-virtualized": "^9.22.3"
12866 } 13440 }
12867 }, 13441 },
12868 "electron-to-chromium": { 13442 "electron-to-chromium": {
@@ -12886,15 +13460,6 @@
12886 "semver": "^7.3.5" 13460 "semver": "^7.3.5"
12887 } 13461 }
12888 }, 13462 },
12889 "electron-util": {
12890 "version": "0.17.2",
12891 "resolved": "https://registry.npmjs.org/electron-util/-/electron-util-0.17.2.tgz",
12892 "integrity": "sha512-4Kg/aZxJ2BZklgyfH86px/D2GyROPyIcnAZar+7KiNmKI2I5l09pwQTP7V95zM3FVhgDQwV9iuJta5dyEvuWAw==",
12893 "requires": {
12894 "electron-is-dev": "^1.1.0",
12895 "new-github-issue-url": "^0.2.1"
12896 }
12897 },
12898 "electron-window-state": { 13463 "electron-window-state": {
12899 "version": "5.0.3", 13464 "version": "5.0.3",
12900 "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-5.0.3.tgz", 13465 "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-5.0.3.tgz",
@@ -13554,15 +14119,10 @@
13554 } 14119 }
13555 }, 14120 },
13556 "eslint-config-airbnb-typescript": { 14121 "eslint-config-airbnb-typescript": {
13557 "version": "12.3.1", 14122 "version": "14.0.0",
13558 "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-12.3.1.tgz", 14123 "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-14.0.0.tgz",
13559 "integrity": "sha512-ql/Pe6/hppYuRp4m3iPaHJqkBB7dgeEmGPQ6X0UNmrQOfTF+dXw29/ZjU2kQ6RDoLxaxOA+Xqv07Vbef6oVTWw==", 14124 "integrity": "sha512-d2Nit2ByZARGRYK6tgSNl3nnmGZPyvsgbsKFcmm+nAhvT8VjVpifG5jI4tzObUUPb0sWw0E1oO/0pSpBD/pIuQ==",
13560 "dev": true, 14125 "dev": true
13561 "requires": {
13562 "@typescript-eslint/parser": "^4.4.1",
13563 "eslint-config-airbnb": "^18.2.0",
13564 "eslint-config-airbnb-base": "^14.2.0"
13565 }
13566 }, 14126 },
13567 "eslint-config-prettier": { 14127 "eslint-config-prettier": {
13568 "version": "8.3.0", 14128 "version": "8.3.0",
@@ -13850,9 +14410,9 @@
13850 } 14410 }
13851 }, 14411 },
13852 "eslint-plugin-prettier": { 14412 "eslint-plugin-prettier": {
13853 "version": "3.4.0", 14413 "version": "4.0.0",
13854 "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", 14414 "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz",
13855 "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", 14415 "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==",
13856 "dev": true, 14416 "dev": true,
13857 "requires": { 14417 "requires": {
13858 "prettier-linter-helpers": "^1.0.0" 14418 "prettier-linter-helpers": "^1.0.0"
@@ -13912,6 +14472,43 @@
13912 "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", 14472 "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
13913 "dev": true 14473 "dev": true
13914 }, 14474 },
14475 "eslint-plugin-unicorn": {
14476 "version": "36.0.0",
14477 "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-36.0.0.tgz",
14478 "integrity": "sha512-xxN2vSctGWnDW6aLElm/LKIwcrmk6mdiEcW55Uv5krcrVcIFSWMmEgc/hwpemYfZacKZ5npFERGNz4aThsp1AA==",
14479 "dev": true,
14480 "requires": {
14481 "@babel/helper-validator-identifier": "^7.14.9",
14482 "ci-info": "^3.2.0",
14483 "clean-regexp": "^1.0.0",
14484 "eslint-template-visitor": "^2.3.2",
14485 "eslint-utils": "^3.0.0",
14486 "is-builtin-module": "^3.1.0",
14487 "lodash": "^4.17.21",
14488 "pluralize": "^8.0.0",
14489 "read-pkg-up": "^7.0.1",
14490 "regexp-tree": "^0.1.23",
14491 "safe-regex": "^2.1.1",
14492 "semver": "^7.3.5"
14493 },
14494 "dependencies": {
14495 "pluralize": {
14496 "version": "8.0.0",
14497 "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
14498 "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
14499 "dev": true
14500 },
14501 "safe-regex": {
14502 "version": "2.1.1",
14503 "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz",
14504 "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==",
14505 "dev": true,
14506 "requires": {
14507 "regexp-tree": "~0.1.1"
14508 }
14509 }
14510 }
14511 },
13915 "eslint-scope": { 14512 "eslint-scope": {
13916 "version": "5.1.1", 14513 "version": "5.1.1",
13917 "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 14514 "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -13922,6 +14519,19 @@
13922 "estraverse": "^4.1.1" 14519 "estraverse": "^4.1.1"
13923 } 14520 }
13924 }, 14521 },
14522 "eslint-template-visitor": {
14523 "version": "2.3.2",
14524 "resolved": "https://registry.npmjs.org/eslint-template-visitor/-/eslint-template-visitor-2.3.2.tgz",
14525 "integrity": "sha512-3ydhqFpuV7x1M9EK52BPNj6V0Kwu0KKkcIAfpUhwHbR8ocRln/oUHgfxQupY8O1h4Qv/POHDumb/BwwNfxbtnA==",
14526 "dev": true,
14527 "requires": {
14528 "@babel/core": "^7.12.16",
14529 "@babel/eslint-parser": "^7.12.16",
14530 "eslint-visitor-keys": "^2.0.0",
14531 "esquery": "^1.3.1",
14532 "multimap": "^1.1.0"
14533 }
14534 },
13925 "eslint-utils": { 14535 "eslint-utils": {
13926 "version": "3.0.0", 14536 "version": "3.0.0",
13927 "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", 14537 "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
@@ -14001,6 +14611,12 @@
14001 "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", 14611 "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
14002 "dev": true 14612 "dev": true
14003 }, 14613 },
14614 "estree-walker": {
14615 "version": "2.0.2",
14616 "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
14617 "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
14618 "dev": true
14619 },
14004 "esutils": { 14620 "esutils": {
14005 "version": "2.0.3", 14621 "version": "2.0.3",
14006 "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 14622 "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -15177,6 +15793,31 @@
15177 "inherits": "~2.0.0", 15793 "inherits": "~2.0.0",
15178 "mkdirp": ">=0.5 0", 15794 "mkdirp": ">=0.5 0",
15179 "rimraf": "2" 15795 "rimraf": "2"
15796 },
15797 "dependencies": {
15798 "glob": {
15799 "version": "7.1.7",
15800 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
15801 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
15802 "optional": true,
15803 "requires": {
15804 "fs.realpath": "^1.0.0",
15805 "inflight": "^1.0.4",
15806 "inherits": "2",
15807 "minimatch": "^3.0.4",
15808 "once": "^1.3.0",
15809 "path-is-absolute": "^1.0.0"
15810 }
15811 },
15812 "rimraf": {
15813 "version": "2.7.1",
15814 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
15815 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
15816 "optional": true,
15817 "requires": {
15818 "glob": "^7.1.3"
15819 }
15820 }
15180 } 15821 }
15181 }, 15822 },
15182 "function-bind": { 15823 "function-bind": {
@@ -15238,6 +15879,15 @@
15238 } 15879 }
15239 } 15880 }
15240 }, 15881 },
15882 "generic-names": {
15883 "version": "2.0.1",
15884 "resolved": "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz",
15885 "integrity": "sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ==",
15886 "dev": true,
15887 "requires": {
15888 "loader-utils": "^1.1.0"
15889 }
15890 },
15241 "gensync": { 15891 "gensync": {
15242 "version": "1.0.0-beta.2", 15892 "version": "1.0.0-beta.2",
15243 "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 15893 "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -15566,9 +16216,9 @@
15566 }, 16216 },
15567 "dependencies": { 16217 "dependencies": {
15568 "core-js": { 16218 "core-js": {
15569 "version": "3.16.4", 16219 "version": "3.18.1",
15570 "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.16.4.tgz", 16220 "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.18.1.tgz",
15571 "integrity": "sha512-Tq4GVE6XCjE+hcyW6hPy0ofN3hwtLudz5ZRdrlCnsnD/xkm/PWQRudzYHiKgZKUcefV6Q57fhDHjZHJP5dpfSg==", 16221 "integrity": "sha512-vJlUi/7YdlCZeL6fXvWNaLUPh/id12WXj3MbkMw5uOyF0PfWPBNOCNbs53YqgrvtujLNlt9JQpruyIKkUZ+PKA==",
15572 "dev": true, 16222 "dev": true,
15573 "optional": true 16223 "optional": true
15574 } 16224 }
@@ -16440,6 +17090,12 @@
16440 } 17090 }
16441 } 17091 }
16442 }, 17092 },
17093 "hash-sum": {
17094 "version": "2.0.0",
17095 "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz",
17096 "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==",
17097 "dev": true
17098 },
16443 "hash.js": { 17099 "hash.js": {
16444 "version": "1.1.7", 17100 "version": "1.1.7",
16445 "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 17101 "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
@@ -16848,6 +17504,18 @@
16848 "safer-buffer": ">= 2.1.2 < 3" 17504 "safer-buffer": ">= 2.1.2 < 3"
16849 } 17505 }
16850 }, 17506 },
17507 "icss-replace-symbols": {
17508 "version": "1.1.0",
17509 "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
17510 "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
17511 "dev": true
17512 },
17513 "icss-utils": {
17514 "version": "5.1.0",
17515 "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
17516 "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
17517 "dev": true
17518 },
16851 "ieee754": { 17519 "ieee754": {
16852 "version": "1.2.1", 17520 "version": "1.2.1",
16853 "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 17521 "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -17214,30 +17882,14 @@
17214 "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 17882 "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
17215 "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" 17883 "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
17216 }, 17884 },
17217 "intl-format-cache": {
17218 "version": "2.2.9",
17219 "resolved": "https://registry.npmjs.org/intl-format-cache/-/intl-format-cache-2.2.9.tgz",
17220 "integrity": "sha512-Zv/u8wRpekckv0cLkwpVdABYST4hZNTDaX7reFetrYTJwxExR2VyTqQm+l0WmL0Qo8Mjb9Tf33qnfj0T7pjxdQ=="
17221 },
17222 "intl-messageformat": { 17885 "intl-messageformat": {
17223 "version": "2.2.0", 17886 "version": "9.9.1",
17224 "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-2.2.0.tgz", 17887 "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.9.1.tgz",
17225 "integrity": "sha1-NFvNRt5jC3aDMwwuUhd/9eq0hPw=", 17888 "integrity": "sha512-cuzS/XKHn//hvKka77JKU2dseiVY2dofQjIOZv6ZFxFt4Z9sPXnZ7KQ9Ak2r+4XBCjI04MqJ1PhKs/3X22AkfA==",
17226 "requires": { 17889 "requires": {
17227 "intl-messageformat-parser": "1.4.0" 17890 "@formatjs/fast-memoize": "1.2.0",
17228 } 17891 "@formatjs/icu-messageformat-parser": "2.0.11",
17229 }, 17892 "tslib": "^2.1.0"
17230 "intl-messageformat-parser": {
17231 "version": "1.4.0",
17232 "resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-1.4.0.tgz",
17233 "integrity": "sha1-tD1FqXRoytvkQzHXS7Ho3qRPwHU="
17234 },
17235 "intl-relativeformat": {
17236 "version": "2.2.0",
17237 "resolved": "https://registry.npmjs.org/intl-relativeformat/-/intl-relativeformat-2.2.0.tgz",
17238 "integrity": "sha512-4bV/7kSKaPEmu6ArxXf9xjv1ny74Zkwuey8Pm01NH4zggPP7JHwg2STk8Y3JdspCKRDriwIyLRfEXnj2ZLr4Bw==",
17239 "requires": {
17240 "intl-messageformat": "^2.0.0"
17241 } 17893 }
17242 }, 17894 },
17243 "invariant": { 17895 "invariant": {
@@ -17348,6 +18000,15 @@
17348 "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 18000 "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
17349 "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 18001 "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
17350 }, 18002 },
18003 "is-builtin-module": {
18004 "version": "3.1.0",
18005 "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.1.0.tgz",
18006 "integrity": "sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==",
18007 "dev": true,
18008 "requires": {
18009 "builtin-modules": "^3.0.0"
18010 }
18011 },
17351 "is-callable": { 18012 "is-callable": {
17352 "version": "1.2.4", 18013 "version": "1.2.4",
17353 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", 18014 "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
@@ -19536,6 +20197,12 @@
19536 "punycode": "^2.1.1", 20197 "punycode": "^2.1.1",
19537 "universalify": "^0.1.2" 20198 "universalify": "^0.1.2"
19538 } 20199 }
20200 },
20201 "ws": {
20202 "version": "7.5.5",
20203 "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
20204 "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
20205 "dev": true
19539 } 20206 }
19540 } 20207 }
19541 }, 20208 },
@@ -19930,6 +20597,11 @@
19930 "version": "2.0.0", 20597 "version": "2.0.0",
19931 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 20598 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
19932 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 20599 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
20600 },
20601 "uuid": {
20602 "version": "3.4.0",
20603 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
20604 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
19933 } 20605 }
19934 } 20606 }
19935 }, 20607 },
@@ -20505,6 +21177,16 @@
20505 "js-tokens": "^3.0.0 || ^4.0.0" 21177 "js-tokens": "^3.0.0 || ^4.0.0"
20506 } 21178 }
20507 }, 21179 },
21180 "loud-rejection": {
21181 "version": "2.2.0",
21182 "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-2.2.0.tgz",
21183 "integrity": "sha512-S0FayMXku80toa5sZ6Ro4C+s+EtFDCsyJNG/AzFMfX3AxD5Si4dZsgzm/kKnbOxHl5Cv8jBlno8+3XYIh2pNjQ==",
21184 "dev": true,
21185 "requires": {
21186 "currently-unhandled": "^0.4.1",
21187 "signal-exit": "^3.0.2"
21188 }
21189 },
20508 "lower-case": { 21190 "lower-case": {
20509 "version": "1.1.4", 21191 "version": "1.1.4",
20510 "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", 21192 "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
@@ -20574,6 +21256,15 @@
20574 } 21256 }
20575 } 21257 }
20576 }, 21258 },
21259 "magic-string": {
21260 "version": "0.25.7",
21261 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
21262 "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
21263 "dev": true,
21264 "requires": {
21265 "sourcemap-codec": "^1.4.4"
21266 }
21267 },
20577 "make-dir": { 21268 "make-dir": {
20578 "version": "2.1.0", 21269 "version": "2.1.0",
20579 "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", 21270 "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
@@ -20710,11 +21401,6 @@
20710 "object-visit": "^1.0.0" 21401 "object-visit": "^1.0.0"
20711 } 21402 }
20712 }, 21403 },
20713 "marked": {
20714 "version": "0.7.0",
20715 "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
20716 "integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg=="
20717 },
20718 "matchdep": { 21404 "matchdep": {
20719 "version": "2.0.0", 21405 "version": "2.0.0",
20720 "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", 21406 "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
@@ -20879,6 +21565,23 @@
20879 "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", 21565 "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
20880 "dev": true 21566 "dev": true
20881 }, 21567 },
21568 "merge-source-map": {
21569 "version": "1.1.0",
21570 "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
21571 "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
21572 "dev": true,
21573 "requires": {
21574 "source-map": "^0.6.1"
21575 },
21576 "dependencies": {
21577 "source-map": {
21578 "version": "0.6.1",
21579 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
21580 "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
21581 "dev": true
21582 }
21583 }
21584 },
20882 "merge-stream": { 21585 "merge-stream": {
20883 "version": "2.0.0", 21586 "version": "2.0.0",
20884 "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 21587 "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -21686,6 +22389,31 @@
21686 "mkdirp": "^0.5.1", 22389 "mkdirp": "^0.5.1",
21687 "rimraf": "^2.5.4", 22390 "rimraf": "^2.5.4",
21688 "run-queue": "^1.0.3" 22391 "run-queue": "^1.0.3"
22392 },
22393 "dependencies": {
22394 "glob": {
22395 "version": "7.1.7",
22396 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
22397 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
22398 "dev": true,
22399 "requires": {
22400 "fs.realpath": "^1.0.0",
22401 "inflight": "^1.0.4",
22402 "inherits": "2",
22403 "minimatch": "^3.0.4",
22404 "once": "^1.3.0",
22405 "path-is-absolute": "^1.0.0"
22406 }
22407 },
22408 "rimraf": {
22409 "version": "2.7.1",
22410 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
22411 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
22412 "dev": true,
22413 "requires": {
22414 "glob": "^7.1.3"
22415 }
22416 }
21689 } 22417 }
21690 }, 22418 },
21691 "ms": { 22419 "ms": {
@@ -21709,6 +22437,12 @@
21709 "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", 22437 "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
21710 "dev": true 22438 "dev": true
21711 }, 22439 },
22440 "multimap": {
22441 "version": "1.1.0",
22442 "resolved": "https://registry.npmjs.org/multimap/-/multimap-1.1.0.tgz",
22443 "integrity": "sha512-0ZIR9PasPxGXmRsEF8jsDzndzHDj7tIav+JUmvIFB/WHswliFnquxECT/De7GR4yg99ky/NlRKJT82G1y271bw==",
22444 "dev": true
22445 },
21712 "multimatch": { 22446 "multimatch": {
21713 "version": "5.0.0", 22447 "version": "5.0.0",
21714 "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", 22448 "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz",
@@ -21880,11 +22614,6 @@
21880 "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", 22614 "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
21881 "dev": true 22615 "dev": true
21882 }, 22616 },
21883 "new-github-issue-url": {
21884 "version": "0.2.1",
21885 "resolved": "https://registry.npmjs.org/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz",
21886 "integrity": "sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA=="
21887 },
21888 "next-tick": { 22617 "next-tick": {
21889 "version": "1.0.0", 22618 "version": "1.0.0",
21890 "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", 22619 "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
@@ -21905,23 +22634,6 @@
21905 "lower-case": "^1.1.1" 22634 "lower-case": "^1.1.1"
21906 } 22635 }
21907 }, 22636 },
21908 "node-abi": {
21909 "version": "2.30.0",
21910 "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.0.tgz",
21911 "integrity": "sha512-g6bZh3YCKQRdwuO/tSZZYJAw622SjsRfJ2X0Iy4sSOHZ34/sPPdVBn8fev2tj7njzLwuqPw9uMtGsGkO5kIQvg==",
21912 "dev": true,
21913 "requires": {
21914 "semver": "^5.4.1"
21915 },
21916 "dependencies": {
21917 "semver": {
21918 "version": "5.7.1",
21919 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
21920 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
21921 "dev": true
21922 }
21923 }
21924 },
21925 "node-addon-api": { 22637 "node-addon-api": {
21926 "version": "4.0.0", 22638 "version": "4.0.0",
21927 "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.0.0.tgz", 22639 "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.0.0.tgz",
@@ -22010,6 +22722,15 @@
22010 "path-is-absolute": "^1.0.0" 22722 "path-is-absolute": "^1.0.0"
22011 } 22723 }
22012 }, 22724 },
22725 "rimraf": {
22726 "version": "2.7.1",
22727 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
22728 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
22729 "optional": true,
22730 "requires": {
22731 "glob": "^7.1.3"
22732 }
22733 },
22013 "semver": { 22734 "semver": {
22014 "version": "5.3.0", 22735 "version": "5.3.0",
22015 "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 22736 "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
@@ -22150,6 +22871,19 @@
22150 "tar": "^4" 22871 "tar": "^4"
22151 }, 22872 },
22152 "dependencies": { 22873 "dependencies": {
22874 "glob": {
22875 "version": "7.1.7",
22876 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
22877 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
22878 "requires": {
22879 "fs.realpath": "^1.0.0",
22880 "inflight": "^1.0.4",
22881 "inherits": "2",
22882 "minimatch": "^3.0.4",
22883 "once": "^1.3.0",
22884 "path-is-absolute": "^1.0.0"
22885 }
22886 },
22153 "nopt": { 22887 "nopt": {
22154 "version": "4.0.3", 22888 "version": "4.0.3",
22155 "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", 22889 "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
@@ -22159,10 +22893,42 @@
22159 "osenv": "^0.1.4" 22893 "osenv": "^0.1.4"
22160 } 22894 }
22161 }, 22895 },
22896 "rimraf": {
22897 "version": "2.7.1",
22898 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
22899 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
22900 "requires": {
22901 "glob": "^7.1.3"
22902 }
22903 },
22904 "safe-buffer": {
22905 "version": "5.2.1",
22906 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
22907 "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
22908 },
22162 "semver": { 22909 "semver": {
22163 "version": "5.7.1", 22910 "version": "5.7.1",
22164 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 22911 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
22165 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 22912 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
22913 },
22914 "tar": {
22915 "version": "4.4.19",
22916 "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
22917 "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
22918 "requires": {
22919 "chownr": "^1.1.4",
22920 "fs-minipass": "^1.2.7",
22921 "minipass": "^2.9.0",
22922 "minizlib": "^1.3.3",
22923 "mkdirp": "^0.5.5",
22924 "safe-buffer": "^5.2.1",
22925 "yallist": "^3.1.1"
22926 }
22927 },
22928 "yallist": {
22929 "version": "3.1.1",
22930 "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
22931 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
22166 } 22932 }
22167 } 22933 }
22168 }, 22934 },
@@ -22335,6 +23101,32 @@
22335 "semver": "^5.7.1", 23101 "semver": "^5.7.1",
22336 "tar": "^4.4.12", 23102 "tar": "^4.4.12",
22337 "which": "^1.3.1" 23103 "which": "^1.3.1"
23104 },
23105 "dependencies": {
23106 "rimraf": {
23107 "version": "2.7.1",
23108 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
23109 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
23110 "dev": true,
23111 "requires": {
23112 "glob": "^7.1.3"
23113 }
23114 },
23115 "tar": {
23116 "version": "4.4.19",
23117 "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
23118 "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
23119 "dev": true,
23120 "requires": {
23121 "chownr": "^1.1.4",
23122 "fs-minipass": "^1.2.7",
23123 "minipass": "^2.9.0",
23124 "minizlib": "^1.3.3",
23125 "mkdirp": "^0.5.5",
23126 "safe-buffer": "^5.2.1",
23127 "yallist": "^3.1.1"
23128 }
23129 }
22338 } 23130 }
22339 }, 23131 },
22340 "nopt": { 23132 "nopt": {
@@ -22353,11 +23145,23 @@
22353 "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 23145 "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
22354 "dev": true 23146 "dev": true
22355 }, 23147 },
23148 "safe-buffer": {
23149 "version": "5.2.1",
23150 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
23151 "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
23152 "dev": true
23153 },
22356 "semver": { 23154 "semver": {
22357 "version": "5.7.1", 23155 "version": "5.7.1",
22358 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 23156 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
22359 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", 23157 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
22360 "dev": true 23158 "dev": true
23159 },
23160 "yallist": {
23161 "version": "3.1.1",
23162 "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
23163 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
23164 "dev": true
22361 } 23165 }
22362 } 23166 }
22363 }, 23167 },
@@ -23619,6 +24423,84 @@
23619 "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 24423 "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
23620 "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" 24424 "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
23621 }, 24425 },
24426 "postcss": {
24427 "version": "8.3.6",
24428 "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
24429 "integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==",
24430 "dev": true,
24431 "requires": {
24432 "colorette": "^1.2.2",
24433 "nanoid": "^3.1.23",
24434 "source-map-js": "^0.6.2"
24435 }
24436 },
24437 "postcss-modules": {
24438 "version": "4.2.2",
24439 "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.2.2.tgz",
24440 "integrity": "sha512-/H08MGEmaalv/OU8j6bUKi/kZr2kqGF6huAW8m9UAgOLWtpFdhA14+gPBoymtqyv+D4MLsmqaF2zvIegdCxJXg==",
24441 "dev": true,
24442 "requires": {
24443 "generic-names": "^2.0.1",
24444 "icss-replace-symbols": "^1.1.0",
24445 "lodash.camelcase": "^4.3.0",
24446 "postcss-modules-extract-imports": "^3.0.0",
24447 "postcss-modules-local-by-default": "^4.0.0",
24448 "postcss-modules-scope": "^3.0.0",
24449 "postcss-modules-values": "^4.0.0",
24450 "string-hash": "^1.1.1"
24451 }
24452 },
24453 "postcss-modules-extract-imports": {
24454 "version": "3.0.0",
24455 "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
24456 "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
24457 "dev": true
24458 },
24459 "postcss-modules-local-by-default": {
24460 "version": "4.0.0",
24461 "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
24462 "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
24463 "dev": true,
24464 "requires": {
24465 "icss-utils": "^5.0.0",
24466 "postcss-selector-parser": "^6.0.2",
24467 "postcss-value-parser": "^4.1.0"
24468 }
24469 },
24470 "postcss-modules-scope": {
24471 "version": "3.0.0",
24472 "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
24473 "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
24474 "dev": true,
24475 "requires": {
24476 "postcss-selector-parser": "^6.0.4"
24477 }
24478 },
24479 "postcss-modules-values": {
24480 "version": "4.0.0",
24481 "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
24482 "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
24483 "dev": true,
24484 "requires": {
24485 "icss-utils": "^5.0.0"
24486 }
24487 },
24488 "postcss-selector-parser": {
24489 "version": "6.0.6",
24490 "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
24491 "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
24492 "dev": true,
24493 "requires": {
24494 "cssesc": "^3.0.0",
24495 "util-deprecate": "^1.0.2"
24496 }
24497 },
24498 "postcss-value-parser": {
24499 "version": "4.1.0",
24500 "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
24501 "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
24502 "dev": true
24503 },
23622 "prelude-ls": { 24504 "prelude-ls": {
23623 "version": "1.2.1", 24505 "version": "1.2.1",
23624 "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 24506 "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -24577,48 +25459,30 @@
24577 } 25459 }
24578 }, 25460 },
24579 "react-intl": { 25461 "react-intl": {
24580 "version": "2.7.2", 25462 "version": "5.20.10",
24581 "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-2.7.2.tgz", 25463 "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-5.20.10.tgz",
24582 "integrity": "sha512-3dcNGLqEw2FKkX+1L2WYLgjP0MVJkvWuVd1uLcnwifIQe8JQvnd9Bss4hb4Gvg/YhBIRcs4LM6C2bAgyklucjw==", 25464 "integrity": "sha512-zy0ZQhpjkGsKcK1BFo2HbGM/q8GBVovzoXZGQ76DowR0yr6UzQuPLkrlIrObL2zxIYiDaxaz+hUJaoa2a1xqOQ==",
24583 "requires": { 25465 "requires": {
24584 "hoist-non-react-statics": "^2.5.5", 25466 "@formatjs/ecma402-abstract": "1.9.8",
24585 "intl-format-cache": "^2.0.5", 25467 "@formatjs/icu-messageformat-parser": "2.0.11",
24586 "intl-messageformat": "^2.1.0", 25468 "@formatjs/intl": "1.14.1",
24587 "intl-relativeformat": "^2.1.0", 25469 "@formatjs/intl-displaynames": "5.2.3",
24588 "invariant": "^2.1.1" 25470 "@formatjs/intl-listformat": "6.3.3",
24589 }, 25471 "@types/hoist-non-react-statics": "^3.3.1",
24590 "dependencies": { 25472 "@types/react": "17",
24591 "hoist-non-react-statics": { 25473 "hoist-non-react-statics": "^3.3.2",
24592 "version": "2.5.5", 25474 "intl-messageformat": "9.9.1",
24593 "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", 25475 "tslib": "^2.1.0"
24594 "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
24595 }
24596 }
24597 },
24598 "react-intl-translations-manager": {
24599 "version": "5.0.3",
24600 "resolved": "https://registry.npmjs.org/react-intl-translations-manager/-/react-intl-translations-manager-5.0.3.tgz",
24601 "integrity": "sha512-EfBeugnOGFcdUbQyY9TqBMbuauQ8wm73ZqFr0UqCljhbXl7YDHQcVzclWFRkVmlUffzxitLQFhAZEVVeRNQSwA==",
24602 "dev": true,
24603 "requires": {
24604 "chalk": "^2.3.2",
24605 "glob": "^7.1.2",
24606 "json-stable-stringify": "^1.0.1",
24607 "mkdirp": "^0.5.1"
24608 }, 25476 },
24609 "dependencies": { 25477 "dependencies": {
24610 "glob": { 25478 "@types/react": {
24611 "version": "7.1.7", 25479 "version": "17.0.20",
24612 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", 25480 "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.20.tgz",
24613 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", 25481 "integrity": "sha512-wWZrPlihslrPpcKyCSlmIlruakxr57/buQN1RjlIeaaTWDLtJkTtRW429MoQJergvVKc4IWBpRhWw7YNh/7GVA==",
24614 "dev": true,
24615 "requires": { 25482 "requires": {
24616 "fs.realpath": "^1.0.0", 25483 "@types/prop-types": "*",
24617 "inflight": "^1.0.4", 25484 "@types/scheduler": "*",
24618 "inherits": "2", 25485 "csstype": "^3.0.2"
24619 "minimatch": "^3.0.4",
24620 "once": "^1.3.0",
24621 "path-is-absolute": "^1.0.0"
24622 } 25486 }
24623 } 25487 }
24624 } 25488 }
@@ -24809,18 +25673,6 @@
24809 "loose-envify": "^1.4.0", 25673 "loose-envify": "^1.4.0",
24810 "prop-types": "^15.7.2", 25674 "prop-types": "^15.7.2",
24811 "react-lifecycles-compat": "^3.0.4" 25675 "react-lifecycles-compat": "^3.0.4"
24812 },
24813 "dependencies": {
24814 "prop-types": {
24815 "version": "15.7.2",
24816 "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
24817 "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
24818 "requires": {
24819 "loose-envify": "^1.4.0",
24820 "object-assign": "^4.1.1",
24821 "react-is": "^16.8.1"
24822 }
24823 }
24824 } 25676 }
24825 }, 25677 },
24826 "reactive-localstorage": { 25678 "reactive-localstorage": {
@@ -25218,6 +26070,12 @@
25218 } 26070 }
25219 } 26071 }
25220 }, 26072 },
26073 "regexp-tree": {
26074 "version": "0.1.23",
26075 "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.23.tgz",
26076 "integrity": "sha512-+7HWfb4Bvu8Rs2eQTUIpX9I/PlQkYOuTNbRpKLJlQpSgwSkzFYh+pUj0gtvglnOZLKB6YgnIgRuJ2/IlpL48qw==",
26077 "dev": true
26078 },
25221 "regexp.prototype.flags": { 26079 "regexp.prototype.flags": {
25222 "version": "1.3.1", 26080 "version": "1.3.1",
25223 "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", 26081 "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
@@ -25410,6 +26268,11 @@
25410 "version": "6.5.2", 26268 "version": "6.5.2",
25411 "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 26269 "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
25412 "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 26270 "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
26271 },
26272 "uuid": {
26273 "version": "3.4.0",
26274 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
26275 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
25413 } 26276 }
25414 } 26277 }
25415 }, 26278 },
@@ -25567,9 +26430,10 @@
25567 "dev": true 26430 "dev": true
25568 }, 26431 },
25569 "rimraf": { 26432 "rimraf": {
25570 "version": "2.7.1", 26433 "version": "3.0.2",
25571 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 26434 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
25572 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 26435 "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
26436 "dev": true,
25573 "requires": { 26437 "requires": {
25574 "glob": "^7.1.3" 26438 "glob": "^7.1.3"
25575 }, 26439 },
@@ -25578,6 +26442,7 @@
25578 "version": "7.1.7", 26442 "version": "7.1.7",
25579 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", 26443 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
25580 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", 26444 "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
26445 "dev": true,
25581 "requires": { 26446 "requires": {
25582 "fs.realpath": "^1.0.0", 26447 "fs.realpath": "^1.0.0",
25583 "inflight": "^1.0.4", 26448 "inflight": "^1.0.4",
@@ -26522,6 +27387,12 @@
26522 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 27387 "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
26523 "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" 27388 "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
26524 }, 27389 },
27390 "source-map-js": {
27391 "version": "0.6.2",
27392 "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
27393 "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
27394 "dev": true
27395 },
26525 "source-map-resolve": { 27396 "source-map-resolve": {
26526 "version": "0.5.3", 27397 "version": "0.5.3",
26527 "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", 27398 "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -26557,6 +27428,12 @@
26557 "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", 27428 "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
26558 "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" 27429 "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="
26559 }, 27430 },
27431 "sourcemap-codec": {
27432 "version": "1.4.8",
27433 "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
27434 "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
27435 "dev": true
27436 },
26560 "sparkles": { 27437 "sparkles": {
26561 "version": "1.0.1", 27438 "version": "1.0.1",
26562 "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", 27439 "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
@@ -26961,6 +27838,12 @@
26961 "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", 27838 "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
26962 "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" 27839 "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
26963 }, 27840 },
27841 "string-hash": {
27842 "version": "1.1.3",
27843 "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz",
27844 "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=",
27845 "dev": true
27846 },
26964 "string-length": { 27847 "string-length": {
26965 "version": "4.0.2", 27848 "version": "4.0.2",
26966 "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", 27849 "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -27295,28 +28178,57 @@
27295 "dev": true 28178 "dev": true
27296 }, 28179 },
27297 "tar": { 28180 "tar": {
27298 "version": "4.4.18", 28181 "version": "6.1.11",
27299 "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.18.tgz", 28182 "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
27300 "integrity": "sha512-ZuOtqqmkV9RE1+4odd+MhBpibmCxNP6PJhH/h2OqNuotTX7/XHPZQJv2pKvWMplFH9SIZZhitehh6vBH6LO8Pg==", 28183 "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
27301 "requires": { 28184 "requires": {
27302 "chownr": "^1.1.4", 28185 "chownr": "^2.0.0",
27303 "fs-minipass": "^1.2.7", 28186 "fs-minipass": "^2.0.0",
27304 "minipass": "^2.9.0", 28187 "minipass": "^3.0.0",
27305 "minizlib": "^1.3.3", 28188 "minizlib": "^2.1.1",
27306 "mkdirp": "^0.5.5", 28189 "mkdirp": "^1.0.3",
27307 "safe-buffer": "^5.2.1", 28190 "yallist": "^4.0.0"
27308 "yallist": "^3.1.1"
27309 }, 28191 },
27310 "dependencies": { 28192 "dependencies": {
27311 "safe-buffer": { 28193 "chownr": {
27312 "version": "5.2.1", 28194 "version": "2.0.0",
27313 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 28195 "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
27314 "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 28196 "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
28197 },
28198 "fs-minipass": {
28199 "version": "2.1.0",
28200 "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
28201 "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
28202 "requires": {
28203 "minipass": "^3.0.0"
28204 }
28205 },
28206 "minipass": {
28207 "version": "3.1.5",
28208 "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz",
28209 "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==",
28210 "requires": {
28211 "yallist": "^4.0.0"
28212 }
28213 },
28214 "minizlib": {
28215 "version": "2.1.2",
28216 "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
28217 "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
28218 "requires": {
28219 "minipass": "^3.0.0",
28220 "yallist": "^4.0.0"
28221 }
28222 },
28223 "mkdirp": {
28224 "version": "1.0.4",
28225 "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
28226 "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
27315 }, 28227 },
27316 "yallist": { 28228 "yallist": {
27317 "version": "3.1.1", 28229 "version": "4.0.0",
27318 "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 28230 "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
27319 "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 28231 "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
27320 } 28232 }
27321 } 28233 }
27322 }, 28234 },
@@ -27374,6 +28286,12 @@
27374 "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", 28286 "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz",
27375 "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", 28287 "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=",
27376 "dev": true 28288 "dev": true
28289 },
28290 "uuid": {
28291 "version": "3.4.0",
28292 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
28293 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
28294 "dev": true
27377 } 28295 }
27378 } 28296 }
27379 }, 28297 },
@@ -27385,6 +28303,14 @@
27385 "requires": { 28303 "requires": {
27386 "temp-dir": "^2.0.0", 28304 "temp-dir": "^2.0.0",
27387 "uuid": "^3.3.2" 28305 "uuid": "^3.3.2"
28306 },
28307 "dependencies": {
28308 "uuid": {
28309 "version": "3.4.0",
28310 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
28311 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
28312 "dev": true
28313 }
27388 } 28314 }
27389 }, 28315 },
27390 "terminal-link": { 28316 "terminal-link": {
@@ -27503,6 +28429,17 @@
27503 "ssri": "^6.0.1", 28429 "ssri": "^6.0.1",
27504 "unique-filename": "^1.1.1", 28430 "unique-filename": "^1.1.1",
27505 "y18n": "^4.0.0" 28431 "y18n": "^4.0.0"
28432 },
28433 "dependencies": {
28434 "rimraf": {
28435 "version": "2.7.1",
28436 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
28437 "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
28438 "dev": true,
28439 "requires": {
28440 "glob": "^7.1.3"
28441 }
28442 }
27506 } 28443 }
27507 }, 28444 },
27508 "glob": { 28445 "glob": {
@@ -27999,28 +28936,74 @@
27999 "requires": { 28936 "requires": {
28000 "ts-node": "7.0.1", 28937 "ts-node": "7.0.1",
28001 "tsconfig-paths": "^3.5.0" 28938 "tsconfig-paths": "^3.5.0"
28939 },
28940 "dependencies": {
28941 "diff": {
28942 "version": "3.5.0",
28943 "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
28944 "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
28945 "dev": true
28946 },
28947 "ts-node": {
28948 "version": "7.0.1",
28949 "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz",
28950 "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==",
28951 "dev": true,
28952 "requires": {
28953 "arrify": "^1.0.0",
28954 "buffer-from": "^1.1.0",
28955 "diff": "^3.1.0",
28956 "make-error": "^1.1.1",
28957 "minimist": "^1.2.0",
28958 "mkdirp": "^0.5.1",
28959 "source-map-support": "^0.5.6",
28960 "yn": "^2.0.0"
28961 }
28962 },
28963 "yn": {
28964 "version": "2.0.0",
28965 "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",
28966 "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=",
28967 "dev": true
28968 }
28002 } 28969 }
28003 }, 28970 },
28004 "ts-node": { 28971 "ts-node": {
28005 "version": "7.0.1", 28972 "version": "10.2.1",
28006 "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", 28973 "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz",
28007 "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", 28974 "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==",
28008 "dev": true, 28975 "dev": true,
28009 "requires": { 28976 "requires": {
28010 "arrify": "^1.0.0", 28977 "@cspotcode/source-map-support": "0.6.1",
28011 "buffer-from": "^1.1.0", 28978 "@tsconfig/node10": "^1.0.7",
28012 "diff": "^3.1.0", 28979 "@tsconfig/node12": "^1.0.7",
28980 "@tsconfig/node14": "^1.0.0",
28981 "@tsconfig/node16": "^1.0.2",
28982 "acorn": "^8.4.1",
28983 "acorn-walk": "^8.1.1",
28984 "arg": "^4.1.0",
28985 "create-require": "^1.1.0",
28986 "diff": "^4.0.1",
28013 "make-error": "^1.1.1", 28987 "make-error": "^1.1.1",
28014 "minimist": "^1.2.0", 28988 "yn": "3.1.1"
28015 "mkdirp": "^0.5.1",
28016 "source-map-support": "^0.5.6",
28017 "yn": "^2.0.0"
28018 }, 28989 },
28019 "dependencies": { 28990 "dependencies": {
28991 "acorn": {
28992 "version": "8.5.0",
28993 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
28994 "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==",
28995 "dev": true
28996 },
28997 "acorn-walk": {
28998 "version": "8.2.0",
28999 "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
29000 "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
29001 "dev": true
29002 },
28020 "diff": { 29003 "diff": {
28021 "version": "3.5.0", 29004 "version": "4.0.2",
28022 "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 29005 "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
28023 "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 29006 "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
28024 "dev": true 29007 "dev": true
28025 } 29008 }
28026 } 29009 }
@@ -28169,9 +29152,9 @@
28169 } 29152 }
28170 }, 29153 },
28171 "typescript": { 29154 "typescript": {
28172 "version": "3.9.10", 29155 "version": "4.2.4",
28173 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", 29156 "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
28174 "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", 29157 "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
28175 "dev": true 29158 "dev": true
28176 }, 29159 },
28177 "uglify-js": { 29160 "uglify-js": {
@@ -28686,9 +29669,9 @@
28686 "dev": true 29669 "dev": true
28687 }, 29670 },
28688 "uuid": { 29671 "uuid": {
28689 "version": "3.3.3", 29672 "version": "8.3.2",
28690 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", 29673 "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
28691 "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" 29674 "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
28692 }, 29675 },
28693 "v8-compile-cache": { 29676 "v8-compile-cache": {
28694 "version": "2.3.0", 29677 "version": "2.3.0",
@@ -28743,9 +29726,9 @@
28743 } 29726 }
28744 }, 29727 },
28745 "validator": { 29728 "validator": {
28746 "version": "11.0.0", 29729 "version": "13.6.0",
28747 "resolved": "https://registry.npmjs.org/validator/-/validator-11.0.0.tgz", 29730 "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz",
28748 "integrity": "sha512-+wnGLYqaKV2++nUv60uGzUJyJQwYVOin6pn1tgEiFCeCQO60yeu3Og9/yPccbBX574kxIcEJicogkzx6s6eyag==" 29731 "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg=="
28749 }, 29732 },
28750 "value-or-function": { 29733 "value-or-function": {
28751 "version": "3.0.0", 29734 "version": "3.0.0",
@@ -29719,6 +30702,12 @@
29719 "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", 30702 "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
29720 "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", 30703 "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
29721 "dev": true 30704 "dev": true
30705 },
30706 "uuid": {
30707 "version": "3.4.0",
30708 "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
30709 "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
30710 "dev": true
29722 } 30711 }
29723 } 30712 }
29724 }, 30713 },
@@ -30139,9 +31128,9 @@
30139 } 31128 }
30140 }, 31129 },
30141 "ws": { 31130 "ws": {
30142 "version": "7.4.6", 31131 "version": "8.2.2",
30143 "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", 31132 "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.2.tgz",
30144 "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" 31133 "integrity": "sha512-Q6B6H2oc8QY3llc3cB8kVmQ6pnJWVQbP7Q5algTcIxx7YEpc0oU4NBVHlztA7Ekzfhw2r0rPducMUiCGWKQRzw=="
30145 }, 31134 },
30146 "xdg-basedir": { 31135 "xdg-basedir": {
30147 "version": "4.0.0", 31136 "version": "4.0.0",
@@ -30313,9 +31302,9 @@
30313 } 31302 }
30314 }, 31303 },
30315 "yn": { 31304 "yn": {
30316 "version": "2.0.0", 31305 "version": "3.1.1",
30317 "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", 31306 "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
30318 "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", 31307 "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
30319 "dev": true 31308 "dev": true
30320 }, 31309 },
30321 "yocto-queue": { 31310 "yocto-queue": {
diff --git a/package.json b/package.json
index 351729726..a3d6ae2c9 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
3 "productName": "Ferdi", 3 "productName": "Ferdi",
4 "desktopName": "ferdi.desktop", 4 "desktopName": "ferdi.desktop",
5 "appId": "com.kytwb.ferdi", 5 "appId": "com.kytwb.ferdi",
6 "version": "5.6.2", 6 "version": "5.6.3-nightly.25",
7 "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.", 7 "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.",
8 "copyright": "kytwb", 8 "copyright": "kytwb",
9 "main": "index.js", 9 "main": "index.js",
@@ -17,7 +17,7 @@
17 }, 17 },
18 "engine-strict": true, 18 "engine-strict": true,
19 "scripts": { 19 "scripts": {
20 "prepare": "node scripts/prepare.js", 20 "prepare": "ts-node scripts/prepare.ts",
21 "start": "electron ./build", 21 "start": "electron ./build",
22 "start:local": "cross-env USE_LOCAL_API=1 npm start", 22 "start:local": "cross-env USE_LOCAL_API=1 npm start",
23 "start:live": "cross-env USE_LIVE_API=1 npm start", 23 "start:live": "cross-env USE_LIVE_API=1 npm start",
@@ -25,8 +25,11 @@
25 "dev": "cross-env NODE_ENV=development gulp dev", 25 "dev": "cross-env NODE_ENV=development gulp dev",
26 "test": "jest", 26 "test": "jest",
27 "test:watch": "jest --watch", 27 "test:watch": "jest --watch",
28 "lint": "eslint \"{src,scripts,packages,uidev}/**/*.{js,jsx,ts,tsx}\" --quiet --fix", 28 "lint": "eslint \"{src,scripts,packages,uidev}/**/*.{js,jsx,ts,tsx}\" --quiet",
29 "manage-translations": "node ./src/i18n/manage-translations.js", 29 "lint:fix": "npm run lint -- --fix",
30 "extract": "formatjs extract 'src/**/*.{js,ts}' --out-file temp.json --flatten --id-interpolation-pattern '[sha512:contenthash:base64:6]' --preserve-whitespace",
31 "compile": "formatjs compile 'temp.json' --out-file src/i18n/locales/en-US.json",
32 "manage-translations": "npm run extract && npm run compile && rimraf temp.json",
30 "prebuild": "preval-build-info-cli && gulp build", 33 "prebuild": "preval-build-info-cli && gulp build",
31 "build": "electron-builder", 34 "build": "electron-builder",
32 "commit": "git-cz", 35 "commit": "git-cz",
@@ -35,14 +38,14 @@
35 "reformat-files": "./node_modules/.bin/prettier --ignore-path .eslintignore --write --require-pragma \"**/*.{js,jsx,scss}\"", 38 "reformat-files": "./node_modules/.bin/prettier --ignore-path .eslintignore --write --require-pragma \"**/*.{js,jsx,scss}\"",
36 "packages": "npx lerna publish --no-git-tag-version", 39 "packages": "npx lerna publish --no-git-tag-version",
37 "uidev": "cd uidev && webpack-dev-server", 40 "uidev": "cd uidev && webpack-dev-server",
38 "postinstall": "node scripts/postinstall.js", 41 "postinstall": "ts-node scripts/postinstall.ts",
39 "apply-branding": "node ./src/i18n/apply-branding.js", 42 "apply-branding": "ts-node ./src/i18n/apply-branding.ts",
40 "update-submodules": "git submodule update --remote --force", 43 "update-submodules": "git submodule update --remote --force",
41 "prepare-code": "npm run lint && npm run reformat-files && npm run manage-translations && npm run apply-branding", 44 "prepare-code": "npm run lint && npm run reformat-files && npm run manage-translations && npm run apply-branding",
42 "build-theme-info": "node scripts/build-theme-info.js", 45 "link-readme": "ts-node scripts/link-readme.ts",
43 "link-readme": "node scripts/link-readme.js",
44 "minify-images": "./scripts/minify-images.sh", 46 "minify-images": "./scripts/minify-images.sh",
45 "start:server": "node src/internal-server/test.js" 47 "start:server": "ts-node src/internal-server/test.ts",
48 "add-crowdin-contributors": "ts-node scripts/add-crowdin-contributors.ts"
46 }, 49 },
47 "keywords": [], 50 "keywords": [],
48 "author": "Amine Mouafik <amine@mouafik.fr>", 51 "author": "Amine Mouafik <amine@mouafik.fr>",
@@ -61,19 +64,17 @@
61 "@adonisjs/shield": "1.0.8", 64 "@adonisjs/shield": "1.0.8",
62 "@adonisjs/validator": "5.0.6", 65 "@adonisjs/validator": "5.0.6",
63 "@electron/remote": "1.2.1", 66 "@electron/remote": "1.2.1",
64 "@mdi/font": "5.9.55", 67 "@mdi/font": "6.2.95",
65 "@mdi/js": "4.6.95", 68 "@mdi/js": "6.2.95",
66 "@meetfranz/forms": "file:packages/forms", 69 "@meetfranz/forms": "file:packages/forms",
67 "@meetfranz/theme": "file:packages/theme", 70 "@meetfranz/theme": "file:packages/theme",
68 "@meetfranz/ui": "file:packages/ui", 71 "@meetfranz/ui": "file:packages/ui",
69 "@sentry/electron": "2.5.3", 72 "@sentry/electron": "2.5.3",
70 "atob": "2.1.2",
71 "auto-launch": "5.0.5", 73 "auto-launch": "5.0.5",
72 "btoa": "1.2.1", 74 "btoa": "1.2.1",
73 "classnames": "2.3.1", 75 "classnames": "2.3.1",
74 "cld": "2.7.0", 76 "cld": "2.7.0",
75 "color": "4.0.1", 77 "color": "4.0.1",
76 "css": "2.2.4",
77 "csstype": "3.0.8", 78 "csstype": "3.0.8",
78 "darkreader": "4.9.34", 79 "darkreader": "4.9.34",
79 "dbus-next": "0.9.2", 80 "dbus-next": "0.9.2",
@@ -82,9 +83,8 @@
82 "electron-dl": "3.2.1", 83 "electron-dl": "3.2.1",
83 "electron-fetch": "1.7.4", 84 "electron-fetch": "1.7.4",
84 "electron-find": "1.0.7", 85 "electron-find": "1.0.7",
85 "electron-react-titlebar": "0.8.2", 86 "electron-react-titlebar": "1.0.0",
86 "electron-updater": "4.3.9", 87 "electron-updater": "4.3.9",
87 "electron-util": "0.17.2",
88 "electron-window-state": "5.0.3", 88 "electron-window-state": "5.0.3",
89 "fs-extra": "10.0.0", 89 "fs-extra": "10.0.0",
90 "jsonwebtoken": "8.5.1", 90 "jsonwebtoken": "8.5.1",
@@ -92,7 +92,6 @@
92 "lodash": "4.17.21", 92 "lodash": "4.17.21",
93 "macos-notification-state": "1.3.6", 93 "macos-notification-state": "1.3.6",
94 "macos-version": "5.2.1", 94 "macos-version": "5.2.1",
95 "marked": "0.7.0",
96 "mime-types": "2.1.32", 95 "mime-types": "2.1.32",
97 "minimist": "1.2.5", 96 "minimist": "1.2.5",
98 "mobx": "5.15.0", 97 "mobx": "5.15.0",
@@ -114,7 +113,7 @@
114 "react-dom": "16.14.0", 113 "react-dom": "16.14.0",
115 "react-dropzone": "11.3.4", 114 "react-dropzone": "11.3.4",
116 "react-electron-web-view": "2.0.1", 115 "react-electron-web-view": "2.0.1",
117 "react-intl": "2.7.2", 116 "react-intl": "5.20.10",
118 "react-jss": "8.6.1", 117 "react-jss": "8.6.1",
119 "react-loader": "2.4.7", 118 "react-loader": "2.4.7",
120 "react-modal": "3.14.3", 119 "react-modal": "3.14.3",
@@ -124,12 +123,12 @@
124 "route-parser": "0.0.5", 123 "route-parser": "0.0.5",
125 "semver": "7.3.5", 124 "semver": "7.3.5",
126 "sqlite3": "5.0.0", 125 "sqlite3": "5.0.0",
127 "tar": "4.4.18", 126 "tar": "6.1.11",
128 "tslib": "2.3.1", 127 "tslib": "2.3.1",
129 "useragent-generator": "1.1.1-amkt-22079-finish.0", 128 "useragent-generator": "1.1.1-amkt-22079-finish.0",
130 "uuid": "3.3.3", 129 "uuid": "8.3.2",
131 "validator": "11.0.0", 130 "validator": "13.6.0",
132 "ws": "7.4.6" 131 "ws": "8.2.2"
133 }, 132 },
134 "devDependencies": { 133 "devDependencies": {
135 "@babel/cli": "7.14.8", 134 "@babel/cli": "7.14.8",
@@ -146,12 +145,13 @@
146 "@babel/register": "7.15.3", 145 "@babel/register": "7.15.3",
147 "@commitlint/cli": "13.1.0", 146 "@commitlint/cli": "13.1.0",
148 "@commitlint/config-conventional": "13.1.0", 147 "@commitlint/config-conventional": "13.1.0",
149 "@tsconfig/node14": "1.0.1", 148 "@formatjs/cli": "4.2.33",
150 "@types/color": "3.0.2", 149 "@types/color": "3.0.2",
151 "@types/du": "1.0.1", 150 "@types/du": "1.0.1",
152 "@types/expect.js": "0.3.29", 151 "@types/expect.js": "0.3.29",
153 "@types/fs-extra": "9.0.12", 152 "@types/fs-extra": "9.0.12",
154 "@types/lodash": "4.14.172", 153 "@types/lodash": "4.14.172",
154 "@types/mime-types": "2.1.1",
155 "@types/mocha": "9.0.0", 155 "@types/mocha": "9.0.0",
156 "@types/ms": "0.7.31", 156 "@types/ms": "0.7.31",
157 "@types/node": "14.17.6", 157 "@types/node": "14.17.6",
@@ -159,30 +159,32 @@
159 "@types/react-dom": "16.9.13", 159 "@types/react-dom": "16.9.13",
160 "@types/route-parser": "0.1.3", 160 "@types/route-parser": "0.1.3",
161 "@types/tar": "4.0.5", 161 "@types/tar": "4.0.5",
162 "@types/uuid": "3.4.9", 162 "@types/uuid": "8.3.1",
163 "@typescript-eslint/eslint-plugin": "4.30.0", 163 "@types/validator": "13.6.3",
164 "@typescript-eslint/parser": "4.29.1", 164 "@typescript-eslint/eslint-plugin": "4.31.2",
165 "@typescript-eslint/parser": "4.31.2",
165 "all-contributors-cli": "6.20.0", 166 "all-contributors-cli": "6.20.0",
166 "babel-plugin-react-intl": "3.5.1", 167 "babel-plugin-formatjs": "10.3.8",
167 "commitizen": "4.2.4", 168 "commitizen": "4.2.4",
168 "concurrently": "6.2.1", 169 "concurrently": "6.2.1",
169 "conventional-changelog-cli": "2.1.1", 170 "conventional-changelog-cli": "2.1.1",
170 "cross-env": "7.0.3", 171 "cross-env": "7.0.3",
171 "cz-conventional-changelog": "3.3.0", 172 "cz-conventional-changelog": "3.3.0",
172 "dotenv": "10.0.0", 173 "dotenv": "10.0.0",
173 "electron": "13.3.0", 174 "electron": "15.1.1",
174 "electron-builder": "22.12.1", 175 "electron-builder": "22.12.1",
175 "electron-notarize": "1.1.0", 176 "electron-notarize": "1.1.0",
176 "eslint": "7.32.0", 177 "eslint": "7.32.0",
177 "eslint-config-airbnb": "18.2.1", 178 "eslint-config-airbnb": "18.2.1",
178 "eslint-config-airbnb-typescript": "12.3.1", 179 "eslint-config-airbnb-typescript": "14.0.0",
179 "eslint-config-prettier": "8.3.0", 180 "eslint-config-prettier": "8.3.0",
180 "eslint-plugin-import": "2.24.2", 181 "eslint-plugin-import": "2.24.2",
181 "eslint-plugin-jest": "24.4.0", 182 "eslint-plugin-jest": "24.4.0",
182 "eslint-plugin-jsx-a11y": "6.4.1", 183 "eslint-plugin-jsx-a11y": "6.4.1",
183 "eslint-plugin-prettier": "3.4.0", 184 "eslint-plugin-prettier": "4.0.0",
184 "eslint-plugin-react": "7.25.1", 185 "eslint-plugin-react": "7.25.1",
185 "eslint-plugin-react-hooks": "4.2.0", 186 "eslint-plugin-react-hooks": "4.2.0",
187 "eslint-plugin-unicorn": "36.0.0",
186 "expect.js": "0.3.1", 188 "expect.js": "0.3.1",
187 "gulp": "4.0.2", 189 "gulp": "4.0.2",
188 "gulp-babel": "8.0.0", 190 "gulp-babel": "8.0.0",
@@ -202,16 +204,16 @@
202 "kebab-case": "1.0.1", 204 "kebab-case": "1.0.1",
203 "lerna": "4.0.0", 205 "lerna": "4.0.0",
204 "mocha": "9.1.1", 206 "mocha": "9.1.1",
205 "node-abi": "2.30.0",
206 "prettier": "2.3.2", 207 "prettier": "2.3.2",
207 "preval-build-info": "1.0.3", 208 "preval-build-info": "1.0.3",
208 "react-intl-translations-manager": "5.0.3", 209 "rimraf": "3.0.2",
209 "sass": "1.37.5", 210 "sass": "1.37.5",
210 "simple-git": "2.45.0", 211 "simple-git": "2.45.0",
211 "terser": "4.8.0", 212 "terser": "4.8.0",
212 "ts-loader": "5.4.5", 213 "ts-loader": "5.4.5",
213 "ts-mocha": "8.0.0", 214 "ts-mocha": "8.0.0",
214 "typescript": "3.9.10", 215 "ts-node": "10.2.1",
216 "typescript": "4.2.4",
215 "wait-on": "6.0.0", 217 "wait-on": "6.0.0",
216 "webpack": "4.46.0", 218 "webpack": "4.46.0",
217 "webpack-cli": "3.3.12", 219 "webpack-cli": "3.3.12",
diff --git a/packages/forms/src/button/index.tsx b/packages/forms/src/button/index.tsx
index 48fb61635..c9ae47d55 100644
--- a/packages/forms/src/button/index.tsx
+++ b/packages/forms/src/button/index.tsx
@@ -227,44 +227,38 @@ class ButtonComponent extends Component<IProps> {
227 </> 227 </>
228 ); 228 );
229 229
230 let wrapperComponent: JSX.Element; 230 const wrapperComponent = !href ? (
231 231 <button
232 if (!href) { 232 id={id}
233 wrapperComponent = ( 233 type={type}
234 <button 234 onClick={onClick}
235 id={id} 235 className={classnames({
236 type={type} 236 [`${classes.button}`]: true,
237 onClick={onClick} 237 [`${classes[buttonType as ButtonType]}`]: true,
238 className={classnames({ 238 [`${classes.disabled}`]: disabled,
239 [`${classes.button}`]: true, 239 [`${className}`]: className,
240 [`${classes[buttonType as ButtonType]}`]: true, 240 })}
241 [`${classes.disabled}`]: disabled, 241 disabled={disabled}
242 [`${className}`]: className, 242 data-type="franz-button"
243 })} 243 >
244 disabled={disabled} 244 {content}
245 data-type="franz-button" 245 </button>
246 > 246 ) : (
247 {content} 247 <a
248 </button> 248 href={href}
249 ); 249 target={target}
250 } else { 250 onClick={onClick}
251 wrapperComponent = ( 251 className={classnames({
252 <a 252 [`${classes.button}`]: true,
253 href={href} 253 [`${classes[buttonType as ButtonType]}`]: true,
254 target={target} 254 [`${className}`]: className,
255 onClick={onClick} 255 })}
256 className={classnames({ 256 rel={target === '_blank' ? 'noopener' : ''}
257 [`${classes.button}`]: true, 257 data-type="franz-button"
258 [`${classes[buttonType as ButtonType]}`]: true, 258 >
259 [`${className}`]: className, 259 {content}
260 })} 260 </a>
261 rel={target === '_blank' ? 'noopener' : ''} 261 );
262 data-type="franz-button"
263 >
264 {content}
265 </a>
266 );
267 }
268 262
269 return wrapperComponent; 263 return wrapperComponent;
270 } 264 }
diff --git a/packages/forms/src/input/scorePassword.ts b/packages/forms/src/input/scorePassword.ts
index bc30de4b8..59502e2b0 100644
--- a/packages/forms/src/input/scorePassword.ts
+++ b/packages/forms/src/input/scorePassword.ts
@@ -18,9 +18,9 @@ export function scorePasswordFunc(password: string): number {
18 18
19 // award every unique letter until 5 repetitions 19 // award every unique letter until 5 repetitions
20 const letters: ILetters = {}; 20 const letters: ILetters = {};
21 for (let i = 0; i < password.length; i += 1) { 21 for (const element of password) {
22 letters[password[i]] = (letters[password[i]] || 0) + 1; 22 letters[element] = (letters[element] || 0) + 1;
23 score += 5.0 / letters[password[i]]; 23 score += 5 / letters[element];
24 } 24 }
25 25
26 // bonus points for mixing it up 26 // bonus points for mixing it up
@@ -32,9 +32,9 @@ export function scorePasswordFunc(password: string): number {
32 }; 32 };
33 33
34 let variationCount = 0; 34 let variationCount = 0;
35 Object.keys(variations).forEach(key => { 35 for (const key of Object.keys(variations)) {
36 variationCount += variations[key] === true ? 1 : 0; 36 variationCount += variations[key] === true ? 1 : 0;
37 }); 37 }
38 38
39 score += (variationCount - 1) * 10; 39 score += (variationCount - 1) * 10;
40 40
diff --git a/packages/forms/src/select/index.tsx b/packages/forms/src/select/index.tsx
index d7479f63e..7806baa2a 100644
--- a/packages/forms/src/select/index.tsx
+++ b/packages/forms/src/select/index.tsx
@@ -187,10 +187,8 @@ class SelectComponent extends Component<IProps> {
187 componentDidUpdate() { 187 componentDidUpdate() {
188 const { open } = this.state; 188 const { open } = this.state;
189 189
190 if (this.searchInputRef && this.searchInputRef.current) { 190 if (this.searchInputRef && this.searchInputRef.current && open) {
191 if (open) { 191 this.searchInputRef.current.focus();
192 this.searchInputRef.current.focus();
193 }
194 } 192 }
195 } 193 }
196 194
@@ -228,6 +226,7 @@ class SelectComponent extends Component<IProps> {
228 } 226 }
229 227
230 componentWillUnmount() { 228 componentWillUnmount() {
229 // eslint-disable-next-line unicorn/no-invalid-remove-event-listener
231 window.removeEventListener('keydown', this.arrowKeysHandler.bind(this)); 230 window.removeEventListener('keydown', this.arrowKeysHandler.bind(this));
232 } 231 }
233 232
diff --git a/packages/forms/tsconfig.json b/packages/forms/tsconfig.json
index 8b9507eac..015581136 100644
--- a/packages/forms/tsconfig.json
+++ b/packages/forms/tsconfig.json
@@ -1,5 +1,5 @@
1{ 1{
2 "extends": "../../tsconfig.settings.json", 2 "extends": "../../tsconfig.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "outDir": "lib", 4 "outDir": "lib",
5 "rootDir": "src" 5 "rootDir": "src"
diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts
index 87a68cb5d..aa132c743 100644
--- a/packages/theme/src/themes/dark/index.ts
+++ b/packages/theme/src/themes/dark/index.ts
@@ -9,7 +9,7 @@ export default (brandPrimary: string) => {
9 let brandPrimaryColor = color(legacyStyles.themeBrandPrimary); 9 let brandPrimaryColor = color(legacyStyles.themeBrandPrimary);
10 try { 10 try {
11 brandPrimaryColor = color(defaultStyles.brandPrimary); 11 brandPrimaryColor = color(defaultStyles.brandPrimary);
12 } catch (e) { 12 } catch {
13 // Ignore invalid color and fall back to default. 13 // Ignore invalid color and fall back to default.
14 } 14 }
15 15
diff --git a/packages/theme/tsconfig.json b/packages/theme/tsconfig.json
index 4deaa5dd7..8b4163e7f 100644
--- a/packages/theme/tsconfig.json
+++ b/packages/theme/tsconfig.json
@@ -1,5 +1,5 @@
1{ 1{
2 "extends": "../../tsconfig.settings.json", 2 "extends": "../../tsconfig.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "outDir": "lib", 4 "outDir": "lib",
5 "rootDir": "src" 5 "rootDir": "src"
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json
index 8b9507eac..015581136 100644
--- a/packages/ui/tsconfig.json
+++ b/packages/ui/tsconfig.json
@@ -1,5 +1,5 @@
1{ 1{
2 "extends": "../../tsconfig.settings.json", 2 "extends": "../../tsconfig.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "outDir": "lib", 4 "outDir": "lib",
5 "rootDir": "src" 5 "rootDir": "src"
diff --git a/recipes b/recipes
Subproject 9db43e100a672b6d6932ac68c0fbe503c129138 Subproject d3841b766f9d37d557646003899f67525c5f755
diff --git a/scripts/add-crowdin-contributors.js b/scripts/add-crowdin-contributors.ts
index 05e377a94..00d12eca1 100644
--- a/scripts/add-crowdin-contributors.js
+++ b/scripts/add-crowdin-contributors.ts
@@ -1,3 +1,7 @@
1import fs from 'fs-extra';
2import path from 'path';
3import allContributors from 'all-contributors-cli';
4
1/** 5/**
2 * Add CrowdIn Contributors to AllContributors list 6 * Add CrowdIn Contributors to AllContributors list
3 * 7 *
@@ -48,17 +52,13 @@ console.clear();
48console.log(JSON.stringify(members)); 52console.log(JSON.stringify(members));
49 53
50 * 3. Paste the output of the script (JSON Array) below to set 'list' to that value 54 * 3. Paste the output of the script (JSON Array) below to set 'list' to that value
51 * 4. Execute this script using 'node scripts/add-crowdin-contributors.js' 55 * 4. Execute this script using 'npm run add-crowdin-contributors'
52 * 5. Regenerate the README table using the CLI ('all-contributors generate') 56 * 5. Regenerate the README table using the CLI ('all-contributors generate')
53 * Please check if the generated data is ok and no data is lost. 57 * Please check if the generated data is ok and no data is lost.
54*/ 58*/
55const list = []; 59const list: any[] = [];
56
57const fs = require('fs-extra');
58const path = require('path');
59const allContributors = require('all-contributors-cli');
60 60
61const infoPath = path.join(__dirname, '..', '..', '.all-contributorsrc'); 61const infoPath = path.join(__dirname, '..', '.all-contributorsrc');
62 62
63(async () => { 63(async () => {
64 const info = await fs.readJSON(infoPath); 64 const info = await fs.readJSON(infoPath);
diff --git a/scripts/build-theme-info.js b/scripts/build-theme-info.js
deleted file mode 100644
index 4058be942..000000000
--- a/scripts/build-theme-info.js
+++ /dev/null
@@ -1,97 +0,0 @@
1/**
2 * Script to get information on which selectors use the brand color.
3 * This is needed to provide the accent color feature - the feature will create CSS rules
4 * to overwrite the color of these selectors.
5 */
6const css = require('css');
7const fs = require('fs-extra');
8const path = require('path');
9const theme = require('@meetfranz/theme');
10
11// Colors that should be replaced with the accent color
12const accentColors = [
13 theme.DEFAULT_ACCENT_COLOR.toLowerCase(),
14 '#7367f0',
15 '#5e50ee',
16];
17
18const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css');
19const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json');
20
21// Parse and extract the rules from a CSS stylesheet file
22async function getRulesFromCssFile(file) {
23 const cssSrc = (await fs.readFile(file)).toString();
24 const cssTree = css.parse(cssSrc);
25
26 return cssTree.stylesheet.rules;
27}
28
29/**
30 * Get all selectors from a list of parsed CSS rules that set any property to one of the specified
31 * values.
32 *
33 * This function will output an object in this format:
34 * {
35 * 'property-name': [ array of selectors ]
36 * }
37 *
38 * e.g.
39 * {
40 * 'background-color': [
41 * '.background',
42 * '.input-dark'
43 * ]
44 * }
45 *
46 * @param {Array} rules Rules as outputted by the `css` module
47 * @param {Array} values Array of values that should be searched for
48 */
49function getSelectorsDeclaringValues(rules, values) {
50 const output = {};
51
52 rules.forEach((rule) => {
53 if (rule.declarations) {
54 rule.declarations.forEach((declaration) => {
55 if (declaration.type === 'declaration'
56 && values.includes(declaration.value.toLowerCase())) {
57 if (!output[declaration.property]) {
58 output[declaration.property] = [];
59 }
60 output[declaration.property] = output[declaration.property].concat(rule.selectors);
61 }
62 });
63 }
64 });
65
66 return output;
67}
68
69async function generateThemeInfo() {
70 if (!await fs.pathExists(cssFile)) {
71 console.log('Please make sure to build the project first.');
72 return;
73 }
74
75 // Read and parse css bundle
76 const rules = await getRulesFromCssFile(cssFile);
77
78 console.log(`Found ${rules.length} rules`);
79
80 // Get rules specifying the brand colors
81 const brandRules = getSelectorsDeclaringValues(rules, accentColors);
82
83 console.log(`Found ${Object.keys(brandRules).join(', ')} properties that set color to brand color`);
84
85 // Join array of declarations into a single string
86 Object.keys(brandRules).forEach((rule) => {
87 brandRules[rule] = brandRules[rule].join(', ');
88 });
89
90 // Write object with theme info to file
91 fs.writeFile(
92 outputFile,
93 JSON.stringify(brandRules),
94 );
95}
96
97generateThemeInfo();
diff --git a/scripts/link-readme.js b/scripts/link-readme.ts
index 1e47cddf8..77b384ff4 100644
--- a/scripts/link-readme.js
+++ b/scripts/link-readme.ts
@@ -6,12 +6,12 @@
6 * and "@abc" => "[@abc](https://github.com/abc)" 6 * and "@abc" => "[@abc](https://github.com/abc)"
7 */ 7 */
8 8
9const fs = require('fs-extra'); 9import fs from 'fs-extra';
10const path = require('path'); 10import path from 'path';
11 11
12console.log('Linking issues and PRs in README.md'); 12console.log('Linking issues and PRs in README.md');
13 13
14const readmepath = path.join(__dirname, '..', '..', 'README.md'); 14const readmepath = path.join(__dirname, '..', 'README.md');
15 15
16// Read README.md 16// Read README.md
17let readme = fs.readFileSync(readmepath, 'utf-8'); 17let readme = fs.readFileSync(readmepath, 'utf-8');
@@ -22,7 +22,7 @@ let replacements = 0;
22// Regex matches strings that don't begin with a "[", i.e. are not already linked 22// Regex matches strings that don't begin with a "[", i.e. are not already linked
23// followed by a "franz#" and digits to indicate 23// followed by a "franz#" and digits to indicate
24// a GitHub issue, and not ending with a "]" 24// a GitHub issue, and not ending with a "]"
25readme = readme.replace(/(?<!\[)franz#\d{1,}(?![\]\d])/gi, (match) => { 25readme = readme.replace(/(?<!\[)franz#\d+(?![\d\]])/gi, match => {
26 const issueNr = match.replace('franz#', ''); 26 const issueNr = match.replace('franz#', '');
27 replacements += 1; 27 replacements += 1;
28 return `[franz#${issueNr}](https://github.com/meetfranz/franz/issues/${issueNr})`; 28 return `[franz#${issueNr}](https://github.com/meetfranz/franz/issues/${issueNr})`;
@@ -31,7 +31,7 @@ readme = readme.replace(/(?<!\[)franz#\d{1,}(?![\]\d])/gi, (match) => {
31// Replace external issues 31// Replace external issues
32// Regex matches strings that don't begin with a "[", followed a repo name in the format "user/repo" 32// Regex matches strings that don't begin with a "[", followed a repo name in the format "user/repo"
33// followed by a "#" and digits to indicate a GitHub issue, and not ending with a "]" 33// followed by a "#" and digits to indicate a GitHub issue, and not ending with a "]"
34readme = readme.replace(/(?<!\[)\w+\/\w+#\d{1,}(?![\]\d])/gi, (match) => { 34readme = readme.replace(/(?<!\[)\w+\/\w+#\d+(?![\d\]])/gi, match => {
35 const issueNr = match.replace(/\D/g, ''); 35 const issueNr = match.replace(/\D/g, '');
36 const repo = match.replace(/#\d+/g, ''); 36 const repo = match.replace(/#\d+/g, '');
37 replacements += 1; 37 replacements += 1;
@@ -42,7 +42,7 @@ readme = readme.replace(/(?<!\[)\w+\/\w+#\d{1,}(?![\]\d])/gi, (match) => {
42// Regex matches strings that don't begin with a "[", i.e. are not already linked and 42// Regex matches strings that don't begin with a "[", i.e. are not already linked and
43// don't begin with "franz", i.e. are not Franz issues, followed by a "#" and digits to indicate 43// don't begin with "franz", i.e. are not Franz issues, followed by a "#" and digits to indicate
44// a GitHub issue, and not ending with a "]" 44// a GitHub issue, and not ending with a "]"
45readme = readme.replace(/(?<!\[|franz)#\d{1,}(?![\]\d])/gi, (match) => { 45readme = readme.replace(/(?<!\[|franz)#\d+(?![\d\]])/gi, match => {
46 const issueNr = match.replace('#', ''); 46 const issueNr = match.replace('#', '');
47 replacements += 1; 47 replacements += 1;
48 return `[#${issueNr}](https://github.com/getferdi/ferdi/issues/${issueNr})`; 48 return `[#${issueNr}](https://github.com/getferdi/ferdi/issues/${issueNr})`;
@@ -51,7 +51,7 @@ readme = readme.replace(/(?<!\[|franz)#\d{1,}(?![\]\d])/gi, (match) => {
51// Link GitHub users 51// Link GitHub users
52// Regex matches strings that don't begin with a "[", i.e. are not already linked 52// Regex matches strings that don't begin with a "[", i.e. are not already linked
53// followed by a "@" and at least one word character and not ending with a "]" 53// followed by a "@" and at least one word character and not ending with a "]"
54readme = readme.replace(/(?<!\[)@\w+(?!\])/gi, (match) => { 54readme = readme.replace(/(?<!\[)@\w+(?!])/gi, match => {
55 const username = match.replace('@', ''); 55 const username = match.replace('@', '');
56 replacements += 1; 56 replacements += 1;
57 return `[@${username}](https://github.com/${username})`; 57 return `[@${username}](https://github.com/${username})`;
diff --git a/scripts/postinstall.js b/scripts/postinstall.ts
index 84e7492ef..4fa71c35f 100644
--- a/scripts/postinstall.js
+++ b/scripts/postinstall.ts
@@ -1,4 +1,4 @@
1const { exec } = require('child_process'); 1import { exec } from 'child_process';
2 2
3// eslint-disable-next-line no-console 3// eslint-disable-next-line no-console
4const log = (err, stdout, stderr) => console.log(err || stdout || stderr); 4const log = (err, stdout, stderr) => console.log(err || stdout || stderr);
diff --git a/scripts/prepare.js b/scripts/prepare.ts
index 0b4daa82b..0b4daa82b 100644
--- a/scripts/prepare.js
+++ b/scripts/prepare.ts
diff --git a/src/I18n.js b/src/I18n.js
index 13513fe73..6fb4cdc61 100644
--- a/src/I18n.js
+++ b/src/I18n.js
@@ -8,7 +8,9 @@ import translations from './i18n/translations';
8import UserStore from './stores/UserStore'; 8import UserStore from './stores/UserStore';
9import AppStore from './stores/AppStore'; 9import AppStore from './stores/AppStore';
10 10
11export default @inject('stores') @observer class I18N extends Component { 11@inject('stores')
12@observer
13class I18N extends Component {
12 componentDidUpdate() { 14 componentDidUpdate() {
13 window.ferdi.menu.rebuild(); 15 window.ferdi.menu.rebuild();
14 } 16 }
@@ -19,7 +21,9 @@ export default @inject('stores') @observer class I18N extends Component {
19 return ( 21 return (
20 <IntlProvider 22 <IntlProvider
21 {...{ locale, key: locale, messages: translations[locale] }} 23 {...{ locale, key: locale, messages: translations[locale] }}
22 ref={(intlProvider) => { window.ferdi.intl = intlProvider ? intlProvider.getChildContext().intl : null; }} 24 ref={intlProvider => {
25 window.ferdi.intl = intlProvider ? intlProvider.state.intl : null;
26 }}
23 > 27 >
24 {children} 28 {children}
25 </IntlProvider> 29 </IntlProvider>
@@ -34,3 +38,5 @@ I18N.wrappedComponent.propTypes = {
34 }).isRequired, 38 }).isRequired,
35 children: oneOrManyChildElements.isRequired, 39 children: oneOrManyChildElements.isRequired,
36}; 40};
41
42export default I18N;
diff --git a/src/actions/app.js b/src/actions/app.ts
index e6f7f22ba..e6f7f22ba 100644
--- a/src/actions/app.js
+++ b/src/actions/app.ts
diff --git a/src/actions/index.js b/src/actions/index.ts
index aecdac675..aecdac675 100644
--- a/src/actions/index.js
+++ b/src/actions/index.ts
diff --git a/src/actions/lib/actions.js b/src/actions/lib/actions.js
deleted file mode 100644
index 7be40f1cf..000000000
--- a/src/actions/lib/actions.js
+++ /dev/null
@@ -1,27 +0,0 @@
1export const createActionsFromDefinitions = (actionDefinitions, validate) => {
2 const actions = {};
3 Object.keys(actionDefinitions).forEach((actionName) => {
4 const action = (params = {}) => {
5 const schema = actionDefinitions[actionName];
6 validate(schema, params, actionName);
7 action.notify(params);
8 };
9 actions[actionName] = action;
10 action.listeners = [];
11 action.listen = (listener) => action.listeners.push(listener);
12 action.off = (listener) => {
13 const { listeners } = action;
14 listeners.splice(listeners.indexOf(listener), 1);
15 };
16 action.notify = (params) => action.listeners.forEach((listener) => listener(params));
17 });
18 return actions;
19};
20
21export default (definitions, validate) => {
22 const newActions = {};
23 Object.keys(definitions).forEach((scopeName) => {
24 newActions[scopeName] = createActionsFromDefinitions(definitions[scopeName], validate);
25 });
26 return newActions;
27};
diff --git a/src/actions/lib/actions.ts b/src/actions/lib/actions.ts
new file mode 100644
index 000000000..412a0d895
--- /dev/null
+++ b/src/actions/lib/actions.ts
@@ -0,0 +1,34 @@
1export const createActionsFromDefinitions = (actionDefinitions, validate) => {
2 const actions = {};
3 // eslint-disable-next-line unicorn/no-array-for-each
4 Object.keys(actionDefinitions).forEach(actionName => {
5 const action = (params = {}) => {
6 const schema = actionDefinitions[actionName];
7 validate(schema, params, actionName);
8 action.notify(params);
9 };
10 actions[actionName] = action;
11 action.listeners = [];
12 action.listen = listener => action.listeners.push(listener);
13 action.off = listener => {
14 const { listeners } = action;
15 listeners.splice(listeners.indexOf(listener), 1);
16 };
17 action.notify = params =>
18 // eslint-disable-next-line unicorn/no-array-for-each
19 action.listeners.forEach(listener => listener(params));
20 });
21 return actions;
22};
23
24export default (definitions, validate) => {
25 const newActions = {};
26 // eslint-disable-next-line unicorn/no-array-for-each
27 Object.keys(definitions).forEach(scopeName => {
28 newActions[scopeName] = createActionsFromDefinitions(
29 definitions[scopeName],
30 validate,
31 );
32 });
33 return newActions;
34};
diff --git a/src/actions/news.js b/src/actions/news.ts
index db106e84f..db106e84f 100644
--- a/src/actions/news.js
+++ b/src/actions/news.ts
diff --git a/src/actions/recipe.js b/src/actions/recipe.ts
index 29b0a151f..29b0a151f 100644
--- a/src/actions/recipe.js
+++ b/src/actions/recipe.ts
diff --git a/src/actions/recipePreview.js b/src/actions/recipePreview.ts
index 36de3d844..36de3d844 100644
--- a/src/actions/recipePreview.js
+++ b/src/actions/recipePreview.ts
diff --git a/src/actions/requests.js b/src/actions/requests.ts
index 89296e7ec..89296e7ec 100644
--- a/src/actions/requests.js
+++ b/src/actions/requests.ts
diff --git a/src/actions/service.js b/src/actions/service.ts
index e56513f8f..e56513f8f 100644
--- a/src/actions/service.js
+++ b/src/actions/service.ts
diff --git a/src/actions/settings.js b/src/actions/settings.ts
index fd29b798b..fd29b798b 100644
--- a/src/actions/settings.js
+++ b/src/actions/settings.ts
diff --git a/src/actions/ui.js b/src/actions/ui.ts
index b913b430b..b913b430b 100644
--- a/src/actions/ui.js
+++ b/src/actions/ui.ts
diff --git a/src/actions/user.js b/src/actions/user.ts
index 20d27ee53..20d27ee53 100644
--- a/src/actions/user.js
+++ b/src/actions/user.ts
diff --git a/src/api/AppApi.js b/src/api/AppApi.ts
index 411c187f4..6e5e5c806 100644
--- a/src/api/AppApi.js
+++ b/src/api/AppApi.ts
@@ -1,5 +1,7 @@
1export default class AppApi { 1export default class AppApi {
2 constructor(server) { 2 server: any;
3
4 constructor(server: any) {
3 this.server = server; 5 this.server = server;
4 } 6 }
5 7
diff --git a/src/api/FeaturesApi.js b/src/api/FeaturesApi.ts
index c66f28f5b..ccad4a189 100644
--- a/src/api/FeaturesApi.js
+++ b/src/api/FeaturesApi.ts
@@ -1,5 +1,7 @@
1export default class FeaturesApi { 1export default class FeaturesApi {
2 constructor(server) { 2 server: any;
3
4 constructor(server: any) {
3 this.server = server; 5 this.server = server;
4 } 6 }
5 7
diff --git a/src/api/LocalApi.js b/src/api/LocalApi.ts
index ccdedd3f5..1830369c7 100644
--- a/src/api/LocalApi.js
+++ b/src/api/LocalApi.ts
@@ -1,14 +1,18 @@
1export default class LocalApi { 1export default class LocalApi {
2 constructor(server, local) { 2 server: any;
3
4 local: any;
5
6 constructor(server: any, local: any) {
3 this.server = server; 7 this.server = server;
4 this.local = local; 8 this.local = local;
5 } 9 }
6 10
7 getAppSettings(type) { 11 getAppSettings(type: string) {
8 return this.local.getAppSettings(type); 12 return this.local.getAppSettings(type);
9 } 13 }
10 14
11 updateAppSettings(type, data) { 15 updateAppSettings(type: string, data: any) {
12 return this.local.updateAppSettings(type, data); 16 return this.local.updateAppSettings(type, data);
13 } 17 }
14 18
diff --git a/src/api/NewsApi.js b/src/api/NewsApi.ts
index 294957511..31d3d903b 100644
--- a/src/api/NewsApi.js
+++ b/src/api/NewsApi.ts
@@ -1,5 +1,9 @@
1export default class NewsApi { 1export default class NewsApi {
2 constructor(server, local) { 2 server: any;
3
4 local: any;
5
6 constructor(server: any, local: any) {
3 this.server = server; 7 this.server = server;
4 this.local = local; 8 this.local = local;
5 } 9 }
@@ -8,7 +12,7 @@ export default class NewsApi {
8 return this.server.getLatestNews(); 12 return this.server.getLatestNews();
9 } 13 }
10 14
11 hide(id) { 15 hide(id: any) {
12 return this.server.hideNews(id); 16 return this.server.hideNews(id);
13 } 17 }
14} 18}
diff --git a/src/api/RecipePreviewsApi.js b/src/api/RecipePreviewsApi.ts
index a56fa587f..78f2a9596 100644
--- a/src/api/RecipePreviewsApi.js
+++ b/src/api/RecipePreviewsApi.ts
@@ -1,5 +1,7 @@
1export default class RecipePreviewsApi { 1export default class RecipePreviewsApi {
2 constructor(server) { 2 server: any;
3
4 constructor(server: any) {
3 this.server = server; 5 this.server = server;
4 } 6 }
5 7
@@ -11,7 +13,7 @@ export default class RecipePreviewsApi {
11 return this.server.getFeaturedRecipePreviews(); 13 return this.server.getFeaturedRecipePreviews();
12 } 14 }
13 15
14 search(needle) { 16 search(needle: string) {
15 return this.server.searchRecipePreviews(needle); 17 return this.server.searchRecipePreviews(needle);
16 } 18 }
17} 19}
diff --git a/src/api/RecipesApi.js b/src/api/RecipesApi.ts
index 800888b00..11d2241b5 100644
--- a/src/api/RecipesApi.js
+++ b/src/api/RecipesApi.ts
@@ -1,5 +1,7 @@
1export default class RecipesApi { 1export default class RecipesApi {
2 constructor(server) { 2 server: any;
3
4 constructor(server: any) {
3 this.server = server; 5 this.server = server;
4 } 6 }
5 7
@@ -7,11 +9,11 @@ export default class RecipesApi {
7 return this.server.getInstalledRecipes(); 9 return this.server.getInstalledRecipes();
8 } 10 }
9 11
10 install(recipeId) { 12 install(recipeId: string) {
11 return this.server.getRecipePackage(recipeId); 13 return this.server.getRecipePackage(recipeId);
12 } 14 }
13 15
14 update(recipes) { 16 update(recipes: any) {
15 return this.server.getRecipeUpdates(recipes); 17 return this.server.getRecipeUpdates(recipes);
16 } 18 }
17} 19}
diff --git a/src/api/ServicesApi.js b/src/api/ServicesApi.ts
index 85efd26a6..5bd8aa60e 100644
--- a/src/api/ServicesApi.js
+++ b/src/api/ServicesApi.ts
@@ -1,30 +1,34 @@
1export default class ServicesApi { 1export default class ServicesApi {
2 constructor(server, local) { 2 server: any;
3 this.local = local; 3
4 local: any;
5
6 constructor(server: any, local: any) {
4 this.server = server; 7 this.server = server;
8 this.local = local;
5 } 9 }
6 10
7 all() { 11 all() {
8 return this.server.getServices(); 12 return this.server.getServices();
9 } 13 }
10 14
11 create(recipeId, data) { 15 create(recipeId: string, data: any) {
12 return this.server.createService(recipeId, data); 16 return this.server.createService(recipeId, data);
13 } 17 }
14 18
15 delete(serviceId) { 19 delete(serviceId: string) {
16 return this.server.deleteService(serviceId); 20 return this.server.deleteService(serviceId);
17 } 21 }
18 22
19 update(serviceId, data) { 23 update(serviceId: string, data: any) {
20 return this.server.updateService(serviceId, data); 24 return this.server.updateService(serviceId, data);
21 } 25 }
22 26
23 reorder(data) { 27 reorder(data: any) {
24 return this.server.reorderService(data); 28 return this.server.reorderService(data);
25 } 29 }
26 30
27 clearCache(serviceId) { 31 clearCache(serviceId: string) {
28 return this.local.clearCache(serviceId); 32 return this.local.clearCache(serviceId);
29 } 33 }
30} 34}
diff --git a/src/api/UserApi.js b/src/api/UserApi.ts
index edfb88988..31c8acead 100644
--- a/src/api/UserApi.js
+++ b/src/api/UserApi.ts
@@ -1,12 +1,17 @@
1import { BinaryLike } from 'crypto';
1import { hash } from '../helpers/password-helpers'; 2import { hash } from '../helpers/password-helpers';
2 3
3export default class UserApi { 4export default class UserApi {
4 constructor(server, local) { 5 server: any;
6
7 local: any;
8
9 constructor(server: any, local: any) {
5 this.server = server; 10 this.server = server;
6 this.local = local; 11 this.local = local;
7 } 12 }
8 13
9 login(email, password) { 14 login(email: string, password: BinaryLike) {
10 return this.server.login(email, hash(password)); 15 return this.server.login(email, hash(password));
11 } 16 }
12 17
@@ -14,18 +19,18 @@ export default class UserApi {
14 return this; 19 return this;
15 } 20 }
16 21
17 signup(data) { 22 signup(data: { password: BinaryLike }) {
18 Object.assign(data, { 23 Object.assign(data, {
19 password: hash(data.password), 24 password: hash(data.password),
20 }); 25 });
21 return this.server.signup(data); 26 return this.server.signup(data);
22 } 27 }
23 28
24 password(email) { 29 password(email: string) {
25 return this.server.retrievePassword(email); 30 return this.server.retrievePassword(email);
26 } 31 }
27 32
28 invite(data) { 33 invite(data: any) {
29 return this.server.inviteUser(data); 34 return this.server.inviteUser(data);
30 } 35 }
31 36
@@ -33,7 +38,7 @@ export default class UserApi {
33 return this.server.userInfo(); 38 return this.server.userInfo();
34 } 39 }
35 40
36 updateInfo(data) { 41 updateInfo(data: { oldPassword: string; newPassword: string }) {
37 const userData = data; 42 const userData = data;
38 if (userData.oldPassword && userData.newPassword) { 43 if (userData.oldPassword && userData.newPassword) {
39 userData.oldPassword = hash(userData.oldPassword); 44 userData.oldPassword = hash(userData.oldPassword);
diff --git a/src/api/apiBase.js b/src/api/apiBase.js
deleted file mode 100644
index 2fad7eb21..000000000
--- a/src/api/apiBase.js
+++ /dev/null
@@ -1,42 +0,0 @@
1/**
2 * Get API base URL from store
3 */
4import {
5 API_VERSION,
6} from '../environment';
7import {
8 DEV_API_FRANZ_WEBSITE,
9 LIVE_FRANZ_API,
10 LOCAL_HOSTNAME,
11 LOCAL_SERVER,
12 SERVER_NOT_LOADED,
13} from '../config';
14
15// Note: This cannot be used from the internal-server since we are not running within the context of a browser window
16const apiBase = (withVersion = true) => {
17 let url;
18
19 if (!window.ferdi
20 || !window.ferdi.stores.settings
21 || !window.ferdi.stores.settings.all
22 || !window.ferdi.stores.settings.all.app.server) {
23 // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded
24 return SERVER_NOT_LOADED;
25 }
26 if (window.ferdi.stores.settings.all.app.server === LOCAL_SERVER) {
27 // Use URL for local server
28 url = `http://${LOCAL_HOSTNAME}:${window.ferdi.stores.requests.localServerPort}`;
29 } else {
30 // Load URL from store
31 url = window.ferdi.stores.settings.all.app.server;
32 }
33
34 return withVersion ? `${url}/${API_VERSION}` : url;
35};
36
37export default apiBase;
38
39export function termsBase() {
40 // TODO: This needs to handle local vs ferdi vs franz servers
41 return window.ferdi.stores.settings.all.app.server !== LIVE_FRANZ_API ? window.ferdi.stores.settings.all.app.server : DEV_API_FRANZ_WEBSITE;
42}
diff --git a/src/api/apiBase.ts b/src/api/apiBase.ts
new file mode 100644
index 000000000..a30793848
--- /dev/null
+++ b/src/api/apiBase.ts
@@ -0,0 +1,41 @@
1/**
2 * Get API base URL from store
3 */
4import { API_VERSION } from '../environment-remote';
5import {
6 DEV_API_FRANZ_WEBSITE,
7 LIVE_FRANZ_API,
8 LOCAL_HOSTNAME,
9 LOCAL_SERVER,
10 SERVER_NOT_LOADED,
11} from '../config';
12
13// Note: This cannot be used from the internal-server since we are not running within the context of a browser window
14const apiBase = (withVersion = true) => {
15 if (
16 !(window as any).ferdi ||
17 !(window as any).ferdi.stores.settings ||
18 !(window as any).ferdi.stores.settings.all ||
19 !(window as any).ferdi.stores.settings.all.app.server
20 ) {
21 // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded
22 return SERVER_NOT_LOADED;
23 }
24 const url =
25 (window as any).ferdi.stores.settings.all.app.server === LOCAL_SERVER
26 ? `http://${LOCAL_HOSTNAME}:${
27 (window as any).ferdi.stores.requests.localServerPort
28 }`
29 : (window as any).ferdi.stores.settings.all.app.server;
30
31 return withVersion ? `${url}/${API_VERSION}` : url;
32};
33
34export default apiBase;
35
36export function termsBase() {
37 // TODO: This needs to handle local vs ferdi vs franz servers
38 return (window as any).ferdi.stores.settings.all.app.server !== LIVE_FRANZ_API
39 ? (window as any).ferdi.stores.settings.all.app.server
40 : DEV_API_FRANZ_WEBSITE;
41}
diff --git a/src/api/index.js b/src/api/index.ts
index ed6c13488..73f613da1 100644
--- a/src/api/index.js
+++ b/src/api/index.ts
@@ -7,12 +7,12 @@ import LocalApi from './LocalApi';
7import NewsApi from './NewsApi'; 7import NewsApi from './NewsApi';
8import FeaturesApi from './FeaturesApi'; 8import FeaturesApi from './FeaturesApi';
9 9
10export default (server, local) => ({ 10export default (server: any, local: any) => ({
11 app: new AppApi(server, local), 11 app: new AppApi(server),
12 services: new ServicesApi(server, local), 12 services: new ServicesApi(server, local),
13 recipePreviews: new RecipePreviewsApi(server, local), 13 recipePreviews: new RecipePreviewsApi(server),
14 recipes: new RecipesApi(server, local), 14 recipes: new RecipesApi(server),
15 features: new FeaturesApi(server, local), 15 features: new FeaturesApi(server),
16 user: new UserApi(server, local), 16 user: new UserApi(server, local),
17 local: new LocalApi(server, local), 17 local: new LocalApi(server, local),
18 news: new NewsApi(server, local), 18 news: new NewsApi(server, local),
diff --git a/src/api/server/LocalApi.ts b/src/api/server/LocalApi.ts
index 71721bb0f..19eacf9ff 100644
--- a/src/api/server/LocalApi.ts
+++ b/src/api/server/LocalApi.ts
@@ -1,5 +1,4 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import { session } from '@electron/remote';
3import du from 'du'; 2import du from 'du';
4 3
5import { getServicePartitionsDirectory } from '../../helpers/service-helpers'; 4import { getServicePartitionsDirectory } from '../../helpers/service-helpers';
@@ -8,7 +7,7 @@ const debug = require('debug')('Ferdi:LocalApi');
8 7
9export default class LocalApi { 8export default class LocalApi {
10 // Settings 9 // Settings
11 getAppSettings(type: any) { 10 getAppSettings(type: string) {
12 return new Promise(resolve => { 11 return new Promise(resolve => {
13 ipcRenderer.once('appSettings', (_event, resp) => { 12 ipcRenderer.once('appSettings', (_event, resp) => {
14 debug('LocalApi::getAppSettings resolves', resp.type, resp.data); 13 debug('LocalApi::getAppSettings resolves', resp.type, resp.data);
@@ -19,7 +18,7 @@ export default class LocalApi {
19 }); 18 });
20 } 19 }
21 20
22 async updateAppSettings(type: any, data: any) { 21 async updateAppSettings(type: string, data: any) {
23 debug('LocalApi::updateAppSettings resolves', type, data); 22 debug('LocalApi::updateAppSettings resolves', type, data);
24 ipcRenderer.send('updateAppSettings', { 23 ipcRenderer.send('updateAppSettings', {
25 type, 24 type,
@@ -31,7 +30,7 @@ export default class LocalApi {
31 async getAppCacheSize() { 30 async getAppCacheSize() {
32 const partitionsDir = getServicePartitionsDirectory(); 31 const partitionsDir = getServicePartitionsDirectory();
33 return new Promise((resolve, reject) => { 32 return new Promise((resolve, reject) => {
34 du(partitionsDir, (err: Error | null, size?: number | undefined) => { 33 du(partitionsDir, {}, (err: Error | null, size?: number | undefined) => {
35 if (err) reject(err); 34 if (err) reject(err);
36 35
37 debug('LocalApi::getAppCacheSize resolves', size); 36 debug('LocalApi::getAppCacheSize resolves', size);
@@ -41,12 +40,7 @@ export default class LocalApi {
41 } 40 }
42 41
43 async clearCache(serviceId: string | null = null) { 42 async clearCache(serviceId: string | null = null) {
44 const s = serviceId 43 const targetsToClear = {
45 ? session.fromPartition(`persist:service-${serviceId}`)
46 : session.defaultSession;
47
48 debug('LocalApi::clearCache resolves', serviceId || 'clearAppCache');
49 await s.clearStorageData({
50 storages: [ 44 storages: [
51 'appcache', 45 'appcache',
52 'filesystem', 46 'filesystem',
@@ -57,7 +51,8 @@ export default class LocalApi {
57 'cachestorage', 51 'cachestorage',
58 ], 52 ],
59 quotas: ['temporary', 'persistent', 'syncable'], 53 quotas: ['temporary', 'persistent', 'syncable'],
60 }); 54 };
61 return s.clearCache(); 55 ipcRenderer.send('clear-storage-data', { serviceId, targetsToClear });
56 return ipcRenderer.invoke('clear-cache', { serviceId });
62 } 57 }
63} 58}
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js
index b5042525a..e321f9372 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.js
@@ -1,7 +1,17 @@
1/* eslint-disable global-require */
1import { join } from 'path'; 2import { join } from 'path';
2import tar from 'tar'; 3import tar from 'tar';
3import { readdirSync, statSync, writeFileSync, copySync, ensureDirSync, pathExistsSync, readJsonSync, removeSync } from 'fs-extra'; 4import {
4import { require as remoteRequire } from '@electron/remote'; 5 readdirSync,
6 statSync,
7 writeFileSync,
8 copySync,
9 ensureDirSync,
10 pathExistsSync,
11 readJsonSync,
12 removeSync,
13} from 'fs-extra';
14import fetch from 'electron-fetch';
5 15
6import ServiceModel from '../../models/Service'; 16import ServiceModel from '../../models/Service';
7import RecipePreviewModel from '../../models/RecipePreview'; 17import RecipePreviewModel from '../../models/RecipePreview';
@@ -12,7 +22,9 @@ import UserModel from '../../models/User';
12import { sleep } from '../../helpers/async-helpers'; 22import { sleep } from '../../helpers/async-helpers';
13 23
14import { SERVER_NOT_LOADED } from '../../config'; 24import { SERVER_NOT_LOADED } from '../../config';
15import { osArch, osPlatform, asarRecipesPath, userDataRecipesPath, userDataPath, ferdiVersion } from '../../environment'; 25import { osArch, osPlatform } from '../../environment';
26import { userDataRecipesPath, userDataPath, ferdiVersion } from '../../environment-remote';
27import { asarRecipesPath } from '../../helpers/asar-helpers';
16import apiBase from '../apiBase'; 28import apiBase from '../apiBase';
17import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; 29import { prepareAuthRequest, sendAuthRequest } from '../utils/auth';
18 30
@@ -28,8 +40,6 @@ const debug = require('debug')('Ferdi:ServerApi');
28 40
29module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory()); 41module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory());
30 42
31const { default: fetch } = remoteRequire('electron-fetch');
32
33export default class ServerApi { 43export default class ServerApi {
34 recipePreviews = []; 44 recipePreviews = [];
35 45
@@ -310,22 +320,22 @@ export default class ServerApi {
310 // Recipes 320 // Recipes
311 async getInstalledRecipes() { 321 async getInstalledRecipes() {
312 const recipesDirectory = getRecipeDirectory(); 322 const recipesDirectory = getRecipeDirectory();
313 const paths = readdirSync(recipesDirectory) 323 const paths = readdirSync(recipesDirectory).filter(
314 .filter( 324 file =>
315 file => 325 statSync(join(recipesDirectory, file)).isDirectory() &&
316 statSync(join(recipesDirectory, file)).isDirectory() && 326 file !== 'temp' &&
317 file !== 'temp' && 327 file !== 'dev',
318 file !== 'dev', 328 );
319 );
320 329
321 this.recipes = paths 330 this.recipes = paths
322 .map(id => { 331 .map(id => {
323 // eslint-disable-next-line 332 // eslint-disable-next-line import/no-dynamic-require
324 const Recipe = require(id)(RecipeModel); 333 const Recipe = require(id)(RecipeModel);
325 return new Recipe(loadRecipeConfig(id)); 334 return new Recipe(loadRecipeConfig(id));
326 }) 335 })
327 .filter(recipe => recipe.id); 336 .filter(recipe => recipe.id);
328 337
338 // eslint-disable-next-line unicorn/prefer-spread
329 this.recipes = this.recipes.concat(this._getDevRecipes()); 339 this.recipes = this.recipes.concat(this._getDevRecipes());
330 340
331 debug('StubServerApi::getInstalledRecipes resolves', this.recipes); 341 debug('StubServerApi::getInstalledRecipes resolves', this.recipes);
@@ -425,8 +435,8 @@ export default class ServerApi {
425 removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz')); 435 removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz'));
426 436
427 return id; 437 return id;
428 } catch (err) { 438 } catch (error) {
429 console.error(err); 439 console.error(error);
430 440
431 return false; 441 return false;
432 } 442 }
@@ -434,7 +444,9 @@ export default class ServerApi {
434 444
435 // News 445 // News
436 async getLatestNews() { 446 async getLatestNews() {
437 const url = `${apiBase(true)}/news?platform=${osPlatform}&arch=${osArch}&version=${ferdiVersion}`; 447 const url = `${apiBase(
448 true,
449 )}/news?platform=${osPlatform}&arch=${osArch}&version=${ferdiVersion}`;
438 const request = await sendAuthRequest(url); 450 const request = await sendAuthRequest(url);
439 if (!request.ok) throw request; 451 if (!request.ok) throw request;
440 const data = await request.json(); 452 const data = await request.json();
@@ -494,7 +506,7 @@ export default class ServerApi {
494 debug('ServerApi::getLegacyServices resolves', services); 506 debug('ServerApi::getLegacyServices resolves', services);
495 return services; 507 return services;
496 } 508 }
497 } catch (err) { 509 } catch {
498 console.error('ServerApi::getLegacyServices no config found'); 510 console.error('ServerApi::getLegacyServices no config found');
499 } 511 }
500 512
@@ -523,8 +535,8 @@ export default class ServerApi {
523 } 535 }
524 536
525 return new ServiceModel(service, recipe); 537 return new ServiceModel(service, recipe);
526 } catch (e) { 538 } catch (error) {
527 debug(e); 539 debug(error);
528 return null; 540 return null;
529 } 541 }
530 } 542 }
@@ -559,7 +571,7 @@ export default class ServerApi {
559 571
560 return recipe; 572 return recipe;
561 }), 573 }),
562 ).catch(err => console.error("Can't load recipe", err)); 574 ).catch(error => console.error("Can't load recipe", error));
563 } 575 }
564 576
565 _mapRecipePreviewModel(recipes) { 577 _mapRecipePreviewModel(recipes) {
@@ -567,8 +579,8 @@ export default class ServerApi {
567 .map(recipe => { 579 .map(recipe => {
568 try { 580 try {
569 return new RecipePreviewModel(recipe); 581 return new RecipePreviewModel(recipe);
570 } catch (e) { 582 } catch (error) {
571 console.error(e); 583 console.error(error);
572 return null; 584 return null;
573 } 585 }
574 }) 586 })
@@ -580,8 +592,8 @@ export default class ServerApi {
580 .map(newsItem => { 592 .map(newsItem => {
581 try { 593 try {
582 return new NewsModel(newsItem); 594 return new NewsModel(newsItem);
583 } catch (e) { 595 } catch (error) {
584 console.error(e); 596 console.error(error);
585 return null; 597 return null;
586 } 598 }
587 }) 599 })
@@ -591,22 +603,21 @@ export default class ServerApi {
591 _getDevRecipes() { 603 _getDevRecipes() {
592 const recipesDirectory = getDevRecipeDirectory(); 604 const recipesDirectory = getDevRecipeDirectory();
593 try { 605 try {
594 const paths = readdirSync(recipesDirectory) 606 const paths = readdirSync(recipesDirectory).filter(
595 .filter( 607 file =>
596 file => 608 statSync(join(recipesDirectory, file)).isDirectory() &&
597 statSync(join(recipesDirectory, file)).isDirectory() && 609 file !== 'temp',
598 file !== 'temp', 610 );
599 );
600 611
601 const recipes = paths 612 const recipes = paths
602 .map(id => { 613 .map(id => {
603 let Recipe; 614 let Recipe;
604 try { 615 try {
605 // eslint-disable-next-line 616 // eslint-disable-next-line import/no-dynamic-require
606 Recipe = require(id)(RecipeModel); 617 Recipe = require(id)(RecipeModel);
607 return new Recipe(loadRecipeConfig(id)); 618 return new Recipe(loadRecipeConfig(id));
608 } catch (err) { 619 } catch (error) {
609 console.error(err); 620 console.error(error);
610 } 621 }
611 622
612 return false; 623 return false;
@@ -624,7 +635,7 @@ export default class ServerApi {
624 }); 635 });
625 636
626 return recipes; 637 return recipes;
627 } catch (err) { 638 } catch {
628 debug('Could not load dev recipes'); 639 debug('Could not load dev recipes');
629 return false; 640 return false;
630 } 641 }
diff --git a/src/api/utils/auth.js b/src/api/utils/auth.js
deleted file mode 100644
index e493b2962..000000000
--- a/src/api/utils/auth.js
+++ /dev/null
@@ -1,27 +0,0 @@
1import localStorage from 'mobx-localstorage';
2import { ferdiLocale, ferdiVersion } from '../../environment';
3
4export const prepareAuthRequest = (options = { method: 'GET' }, auth = true) => {
5 const request = Object.assign(options, {
6 mode: 'cors',
7 headers: {
8 'Content-Type': 'application/json',
9 'X-Franz-Source': 'desktop',
10 'X-Franz-Version': ferdiVersion,
11 'X-Franz-platform': process.platform,
12 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(),
13 'X-Franz-System-Locale': ferdiLocale,
14 ...options.headers,
15 },
16 });
17
18 if (auth) {
19 request.headers.Authorization = `Bearer ${localStorage.getItem('authToken')}`;
20 }
21
22 return request;
23};
24
25export const sendAuthRequest = (url, options, auth) => (
26 window.fetch(url, prepareAuthRequest(options, auth))
27);
diff --git a/src/api/utils/auth.ts b/src/api/utils/auth.ts
new file mode 100644
index 000000000..98295d1a4
--- /dev/null
+++ b/src/api/utils/auth.ts
@@ -0,0 +1,38 @@
1import localStorage from 'mobx-localstorage';
2import { ferdiLocale, ferdiVersion } from '../../environment-remote';
3
4export const prepareAuthRequest = (
5 // eslint-disable-next-line unicorn/no-object-as-default-parameter
6 options = { method: 'GET' },
7 auth = true,
8) => {
9 const request = Object.assign(options, {
10 mode: 'cors',
11 headers: {
12 'Content-Type': 'application/json',
13 'X-Franz-Source': 'desktop',
14 'X-Franz-Version': ferdiVersion,
15 'X-Franz-platform': process.platform,
16 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(),
17 'X-Franz-System-Locale': ferdiLocale,
18 // @ts-expect-error Property 'headers' does not exist on type '{ method: string; }'.
19 ...options.headers,
20 },
21 });
22
23 if (auth) {
24 request.headers.Authorization = `Bearer ${localStorage.getItem(
25 'authToken',
26 )}`;
27 }
28
29 return request;
30};
31
32export const sendAuthRequest = (
33 url: RequestInfo,
34 options: { method: string } | undefined,
35 auth?: boolean,
36) =>
37 // @ts-expect-error Argument of type '{ method: string; } & { mode: string; headers: any; }' is not assignable to parameter of type 'RequestInit | undefined'.
38 window.fetch(url, prepareAuthRequest(options, auth));
diff --git a/src/app.js b/src/app.js
index e0d2dbc5a..8a1f99320 100644
--- a/src/app.js
+++ b/src/app.js
@@ -44,7 +44,7 @@ window.addEventListener('load', () => {
44 </I18N> 44 </I18N>
45 </Provider> 45 </Provider>
46 ); 46 );
47 render(preparedApp, document.getElementById('root')); 47 render(preparedApp, document.querySelector('#root'));
48 }, 48 },
49 }; 49 };
50 window.ferdi.render(); 50 window.ferdi.render();
diff --git a/src/assets/themeInfo.json b/src/assets/themeInfo.json
deleted file mode 100644
index 54e833789..000000000
--- a/src/assets/themeInfo.json
+++ /dev/null
@@ -1 +0,0 @@
1{"color":".theme__dark .app .sidebar .sidebar__button.is-muted, .theme__dark .app .sidebar .sidebar__button.is-active, .sidebar .sidebar__button.is-muted, .sidebar .sidebar__button.is-active, .tab-item.is-active, .settings .account .invoices .invoices__action button, .settings-navigation .settings-navigation__link.is-active .badge, a.link, button.link, .auth .welcome .button:hover, .auth .welcome .button__inverted, .franz-form .franz-form__radio.is-selected, .theme__dark .franz-form__button.franz-form__button--inverted, .franz-form__button.franz-form__button--inverted","border-color":".theme__dark .settings, .franz-form .franz-form__radio.is-selected","background":".settings .settings__header, .settings .settings__close, .settings-navigation .settings-navigation__link.is-active, a.button, button.button, .auth, .info-bar, .info-bar.info-bar--primary, .infobox.infobox--primary, .theme__dark .badge.badge--primary, .theme__dark, .badge.badge--primary, .content-tabs .content-tabs__tabs .content-tabs__item.is-active, #electron-app-title-bar .toolbar-dropdown:not(.open) > .toolbar-button > button:hover, #electron-app-title-bar .list-item.selected .menu-item, #electron-app-title-bar .list-item.selected:focus .menu-item, .theme__dark .quick-switch .active, .franz-form .franz-form__toggle-wrapper .franz-form__toggle.is-active .franz-form__toggle-button, .theme__dark .franz-form__button, .franz-form__button, .ferdi__fab, .franz-form .franz-form__slider-wrapper .slider::-webkit-slider-thumb","border-right-color":".settings .settings__header .separator"}
diff --git a/src/components/AppUpdateInfoBar.js b/src/components/AppUpdateInfoBar.js
index 30804262a..47b730bde 100644
--- a/src/components/AppUpdateInfoBar.js
+++ b/src/components/AppUpdateInfoBar.js
@@ -1,6 +1,6 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl'; 3import { defineMessages, injectIntl } from 'react-intl';
4 4
5import InfoBar from './ui/InfoBar'; 5import InfoBar from './ui/InfoBar';
6import { GITHUB_FERDI_URL } from '../config'; 6import { GITHUB_FERDI_URL } from '../config';
@@ -9,15 +9,15 @@ import { openExternalUrl } from '../helpers/url-helpers';
9const messages = defineMessages({ 9const messages = defineMessages({
10 updateAvailable: { 10 updateAvailable: {
11 id: 'infobar.updateAvailable', 11 id: 'infobar.updateAvailable',
12 defaultMessage: '!!!A new update for Ferdi is available.', 12 defaultMessage: 'A new update for Ferdi is available.',
13 }, 13 },
14 changelog: { 14 changelog: {
15 id: 'infobar.buttonChangelog', 15 id: 'infobar.buttonChangelog',
16 defaultMessage: '!!!Changelog', 16 defaultMessage: 'What is new?',
17 }, 17 },
18 buttonInstallUpdate: { 18 buttonInstallUpdate: {
19 id: 'infobar.buttonInstallUpdate', 19 id: 'infobar.buttonInstallUpdate',
20 defaultMessage: '!!!Restart & install update', 20 defaultMessage: 'Restart & install update',
21 }, 21 },
22}); 22});
23 23
@@ -27,12 +27,8 @@ class AppUpdateInfoBar extends Component {
27 onHide: PropTypes.func.isRequired, 27 onHide: PropTypes.func.isRequired,
28 }; 28 };
29 29
30 static contextTypes = {
31 intl: intlShape,
32 };
33
34 render() { 30 render() {
35 const { intl } = this.context; 31 const { intl } = this.props;
36 const { onInstallUpdate, onHide } = this.props; 32 const { onInstallUpdate, onHide } = this.props;
37 33
38 return ( 34 return (
@@ -61,4 +57,4 @@ class AppUpdateInfoBar extends Component {
61 } 57 }
62} 58}
63 59
64export default AppUpdateInfoBar; 60export default injectIntl(AppUpdateInfoBar);
diff --git a/src/components/auth/AuthLayout.js b/src/components/auth/AuthLayout.js
index 8235932c2..17ac221a2 100644
--- a/src/components/auth/AuthLayout.js
+++ b/src/components/auth/AuthLayout.js
@@ -1,9 +1,9 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { intlShape } from 'react-intl'; 4import { TitleBar } from 'electron-react-titlebar/renderer';
5import { TitleBar } from 'electron-react-titlebar';
6 5
6import { injectIntl } from 'react-intl';
7import Link from '../ui/Link'; 7import Link from '../ui/Link';
8import InfoBar from '../ui/InfoBar'; 8import InfoBar from '../ui/InfoBar';
9 9
@@ -17,7 +17,6 @@ import { isWindows } from '../../environment';
17import AppUpdateInfoBar from '../AppUpdateInfoBar'; 17import AppUpdateInfoBar from '../AppUpdateInfoBar';
18import { GITHUB_FERDI_URL } from '../../config'; 18import { GITHUB_FERDI_URL } from '../../config';
19 19
20export default
21@observer 20@observer
22class AuthLayout extends Component { 21class AuthLayout extends Component {
23 static propTypes = { 22 static propTypes = {
@@ -36,10 +35,6 @@ class AuthLayout extends Component {
36 shouldShowAppUpdateInfoBar: true, 35 shouldShowAppUpdateInfoBar: true,
37 }; 36 };
38 37
39 static contextTypes = {
40 intl: intlShape,
41 };
42
43 render() { 38 render() {
44 const { 39 const {
45 children, 40 children,
@@ -52,7 +47,8 @@ class AuthLayout extends Component {
52 installAppUpdate, 47 installAppUpdate,
53 appUpdateIsDownloaded, 48 appUpdateIsDownloaded,
54 } = this.props; 49 } = this.props;
55 const { intl } = this.context; 50
51 const { intl } = this.props;
56 52
57 return ( 53 return (
58 <> 54 <>
@@ -108,3 +104,5 @@ class AuthLayout extends Component {
108 ); 104 );
109 } 105 }
110} 106}
107
108export default injectIntl(AuthLayout);
diff --git a/src/components/auth/ChangeServer.js b/src/components/auth/ChangeServer.js
index 8e8a7af32..b98fb50f7 100644
--- a/src/components/auth/ChangeServer.js
+++ b/src/components/auth/ChangeServer.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import Form from '../../lib/Form'; 5import Form from '../../lib/Form';
6import Input from '../ui/Input'; 6import Input from '../ui/Input';
7import Select from '../ui/Select'; 7import Select from '../ui/Select';
@@ -14,56 +14,65 @@ import globalMessages from '../../i18n/globalMessages';
14const messages = defineMessages({ 14const messages = defineMessages({
15 headline: { 15 headline: {
16 id: 'changeserver.headline', 16 id: 'changeserver.headline',
17 defaultMessage: '!!!Change server', 17 defaultMessage: 'Change server',
18 }, 18 },
19 label: { 19 label: {
20 id: 'changeserver.label', 20 id: 'changeserver.label',
21 defaultMessage: '!!!Server', 21 defaultMessage: 'Server',
22 }, 22 },
23 warning: { 23 warning: {
24 id: 'changeserver.warning', 24 id: 'changeserver.warning',
25 defaultMessage: '!!!Extra settings offered by Ferdi will not be saved', 25 defaultMessage: 'Extra settings offered by Ferdi will not be saved',
26 }, 26 },
27 customServerLabel: { 27 customServerLabel: {
28 id: 'changeserver.customServerLabel', 28 id: 'changeserver.customServerLabel',
29 defaultMessage: '!!!Custom server', 29 defaultMessage: 'Custom server',
30 }, 30 },
31 urlError: { 31 urlError: {
32 id: 'changeserver.urlError', 32 id: 'changeserver.urlError',
33 defaultMessage: '!!!Enter a valid URL', 33 defaultMessage: 'Enter a valid URL',
34 }, 34 },
35}); 35});
36 36
37export default @observer class ChangeServer extends Component { 37@observer
38class ChangeServer extends Component {
38 static propTypes = { 39 static propTypes = {
39 onSubmit: PropTypes.func.isRequired, 40 onSubmit: PropTypes.func.isRequired,
40 server: PropTypes.string.isRequired, 41 server: PropTypes.string.isRequired,
41 }; 42 };
42 43
43 static contextTypes = { 44 ferdiServer = LIVE_FERDI_API;
44 intl: intlShape,
45 };
46
47 ferdiServer=LIVE_FERDI_API;
48 45
49 franzServer=LIVE_FRANZ_API; 46 franzServer = LIVE_FRANZ_API;
50 47
51 defaultServers=[this.franzServer, this.ferdiServer]; 48 defaultServers = [this.franzServer, this.ferdiServer];
52 49
53 form = new Form({ 50 form = new Form(
54 fields: { 51 {
55 server: { 52 fields: {
56 label: this.context.intl.formatMessage(messages.label), 53 server: {
57 value: this.props.server, 54 label: this.props.intl.formatMessage(messages.label),
58 options: [{ value: this.ferdiServer, label: 'Ferdi' }, { value: this.franzServer, label: 'Franz' }, { value: this.defaultServers.includes(this.props.server) ? '' : this.props.server, label: 'Custom' }], 55 value: this.props.server,
59 }, 56 options: [
60 customServer: { 57 { value: this.ferdiServer, label: 'Ferdi' },
61 label: this.context.intl.formatMessage(messages.customServerLabel), 58 { value: this.franzServer, label: 'Franz' },
62 value: '', 59 {
63 validators: [url, required], 60 value: this.defaultServers.includes(this.props.server)
61 ? ''
62 : this.props.server,
63 label: 'Custom',
64 },
65 ],
66 },
67 customServer: {
68 label: this.props.intl.formatMessage(messages.customServerLabel),
69 value: '',
70 validators: [url, required],
71 },
64 }, 72 },
65 }, 73 },
66 }, this.context.intl); 74 this.props.intl,
75 );
67 76
68 componentDidMount() { 77 componentDidMount() {
69 if (this.defaultServers.includes(this.props.server)) { 78 if (this.defaultServers.includes(this.props.server)) {
@@ -77,13 +86,13 @@ export default @observer class ChangeServer extends Component {
77 submit(e) { 86 submit(e) {
78 e.preventDefault(); 87 e.preventDefault();
79 this.form.submit({ 88 this.form.submit({
80 onSuccess: (form) => { 89 onSuccess: form => {
81 if (!this.defaultServers.includes(form.values().server)) { 90 if (!this.defaultServers.includes(form.values().server)) {
82 form.$('server').onChange(form.values().customServer); 91 form.$('server').onChange(form.values().customServer);
83 } 92 }
84 this.props.onSubmit(form.values()); 93 this.props.onSubmit(form.values());
85 }, 94 },
86 onError: (form) => { 95 onError: form => {
87 if (this.defaultServers.includes(form.values().server)) { 96 if (this.defaultServers.includes(form.values().server)) {
88 this.props.onSubmit(form.values()); 97 this.props.onSubmit(form.values());
89 } 98 }
@@ -93,23 +102,21 @@ export default @observer class ChangeServer extends Component {
93 102
94 render() { 103 render() {
95 const { form } = this; 104 const { form } = this;
96 const { intl } = this.context; 105 const { intl } = this.props;
97 return ( 106 return (
98 <div className="auth__container"> 107 <div className="auth__container">
99 <form className="franz-form auth__form" onSubmit={(e) => this.submit(e)}> 108 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}>
100 <h1>{intl.formatMessage(messages.headline)}</h1> 109 <h1>{intl.formatMessage(messages.headline)}</h1>
101 {form.$('server').value === this.franzServer 110 {form.$('server').value === this.franzServer && (
102 && (
103 <Infobox type="warning"> 111 <Infobox type="warning">
104 {intl.formatMessage(messages.warning)} 112 {intl.formatMessage(messages.warning)}
105 </Infobox> 113 </Infobox>
106 )} 114 )}
107 <Select field={form.$('server')} /> 115 <Select field={form.$('server')} />
108 {!this.defaultServers.includes(form.$('server').value) 116 {!this.defaultServers.includes(form.$('server').value) && (
109 && (
110 <Input 117 <Input
111 placeholder="Custom Server" 118 placeholder="Custom Server"
112 onChange={(e) => this.submit(e)} 119 onChange={e => this.submit(e)}
113 field={form.$('customServer')} 120 field={form.$('customServer')}
114 /> 121 />
115 )} 122 )}
@@ -123,3 +130,5 @@ export default @observer class ChangeServer extends Component {
123 ); 130 );
124 } 131 }
125} 132}
133
134export default injectIntl(ChangeServer);
diff --git a/src/components/auth/Import.js b/src/components/auth/Import.js
index 3073cad73..44cb7e791 100644
--- a/src/components/auth/Import.js
+++ b/src/components/auth/Import.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7 7
@@ -12,23 +12,22 @@ import Button from '../ui/Button';
12const messages = defineMessages({ 12const messages = defineMessages({
13 headline: { 13 headline: {
14 id: 'import.headline', 14 id: 'import.headline',
15 defaultMessage: '!!!Import your Ferdi 4 services', 15 defaultMessage: 'Import your Ferdi 4 services',
16 }, 16 },
17 notSupportedHeadline: { 17 notSupportedHeadline: {
18 id: 'import.notSupportedHeadline', 18 id: 'import.notSupportedHeadline',
19 defaultMessage: '!!!Services not yet supported in Ferdi 5', 19 defaultMessage: 'Services not yet supported in Ferdi 5',
20 }, 20 },
21 submitButtonLabel: { 21 submitButtonLabel: {
22 id: 'import.submit.label', 22 id: 'import.submit.label',
23 defaultMessage: '!!!Import {count} services', 23 defaultMessage: 'Import {count} services',
24 }, 24 },
25 skipButtonLabel: { 25 skipButtonLabel: {
26 id: 'import.skip.label', 26 id: 'import.skip.label',
27 defaultMessage: '!!!I want to add services manually', 27 defaultMessage: 'I want to add services manually',
28 }, 28 },
29}); 29});
30 30
31export default
32@observer 31@observer
33class Import extends Component { 32class Import extends Component {
34 static propTypes = { 33 static propTypes = {
@@ -38,17 +37,13 @@ class Import extends Component {
38 inviteRoute: PropTypes.string.isRequired, 37 inviteRoute: PropTypes.string.isRequired,
39 }; 38 };
40 39
41 static contextTypes = {
42 intl: intlShape,
43 };
44
45 componentDidMount() { 40 componentDidMount() {
46 const config = { 41 const config = {
47 fields: { 42 fields: {
48 import: [ 43 import: [
49 ...this.props.services 44 ...this.props.services
50 .filter((s) => s.recipe) 45 .filter(s => s.recipe)
51 .map((s) => ({ 46 .map(s => ({
52 fields: { 47 fields: {
53 add: { 48 add: {
54 default: true, 49 default: true,
@@ -60,20 +55,20 @@ class Import extends Component {
60 }, 55 },
61 }; 56 };
62 57
63 this.form = new Form(config, this.context.intl); 58 this.form = new Form(config, this.props.intl);
64 } 59 }
65 60
66 submit(e) { 61 submit(e) {
67 const { services } = this.props; 62 const { services } = this.props;
68 e.preventDefault(); 63 e.preventDefault();
69 this.form.submit({ 64 this.form.submit({
70 onSuccess: (form) => { 65 onSuccess: form => {
71 const servicesImport = form 66 const servicesImport = form
72 .values() 67 .values()
73 .import.map( 68 .import.map(
74 (value, i) => !value.add || services.filter((s) => s.recipe)[i], 69 (value, i) => !value.add || services.filter(s => s.recipe)[i],
75 ) 70 )
76 .filter((s) => typeof s !== 'boolean'); 71 .filter(s => typeof s !== 'boolean');
77 72
78 this.props.onSubmit({ services: servicesImport }); 73 this.props.onSubmit({ services: servicesImport });
79 }, 74 },
@@ -82,18 +77,18 @@ class Import extends Component {
82 } 77 }
83 78
84 render() { 79 render() {
85 const { intl } = this.context; 80 const { intl } = this.props;
86 const { services, isSubmitting, inviteRoute } = this.props; 81 const { services, isSubmitting, inviteRoute } = this.props;
87 82
88 const availableServices = services.filter((s) => s.recipe); 83 const availableServices = services.filter(s => s.recipe);
89 const unavailableServices = services.filter((s) => !s.recipe); 84 const unavailableServices = services.filter(s => !s.recipe);
90 85
91 return ( 86 return (
92 <div className="auth__scroll-container"> 87 <div className="auth__scroll-container">
93 <div className="auth__container auth__container--signup"> 88 <div className="auth__container auth__container--signup">
94 <form 89 <form
95 className="franz-form auth__form" 90 className="franz-form auth__form"
96 onSubmit={(e) => this.submit(e)} 91 onSubmit={e => this.submit(e)}
97 > 92 >
98 <img src="./assets/images/logo.svg" className="auth__logo" alt="" /> 93 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
99 <h1>{intl.formatMessage(messages.headline)}</h1> 94 <h1>{intl.formatMessage(messages.headline)}</h1>
@@ -107,8 +102,8 @@ class Import extends Component {
107 <td className="service-table__column-icon"> 102 <td className="service-table__column-icon">
108 <img 103 <img
109 src={ 104 src={
110 availableServices[i].custom_icon 105 availableServices[i].custom_icon ||
111 || availableServices[i].recipe.icons.svg 106 availableServices[i].recipe.icons.svg
112 } 107 }
113 className={classnames({ 108 className={classnames({
114 'service-table__icon': true, 109 'service-table__icon': true,
@@ -133,7 +128,7 @@ class Import extends Component {
133 </strong> 128 </strong>
134 <p> 129 <p>
135 {services 130 {services
136 .filter((s) => !s.recipe) 131 .filter(s => !s.recipe)
137 .map((service, i) => ( 132 .map((service, i) => (
138 <span key={service.id}> 133 <span key={service.id}>
139 {service.name !== '' ? service.name : service.service} 134 {service.name !== '' ? service.name : service.service}
@@ -170,3 +165,5 @@ class Import extends Component {
170 ); 165 );
171 } 166 }
172} 167}
168
169export default injectIntl(Import);
diff --git a/src/components/auth/Invite.js b/src/components/auth/Invite.js
index 4b4d63a6b..df8980314 100644
--- a/src/components/auth/Invite.js
+++ b/src/components/auth/Invite.js
@@ -1,7 +1,7 @@
1import React, { Component, Fragment } from 'react'; 1import React, { Component, Fragment } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7 7
@@ -15,35 +15,34 @@ import Button from '../ui/Button';
15const messages = defineMessages({ 15const messages = defineMessages({
16 settingsHeadline: { 16 settingsHeadline: {
17 id: 'settings.invite.headline', 17 id: 'settings.invite.headline',
18 defaultMessage: '!!!Invite Friends', 18 defaultMessage: 'Invite Friends',
19 }, 19 },
20 headline: { 20 headline: {
21 id: 'invite.headline.friends', 21 id: 'invite.headline.friends',
22 defaultMessage: '!!!Invite 3 of your friends or colleagues', 22 defaultMessage: 'Invite 3 of your friends or colleagues',
23 }, 23 },
24 nameLabel: { 24 nameLabel: {
25 id: 'invite.name.label', 25 id: 'invite.name.label',
26 defaultMessage: '!!!Name', 26 defaultMessage: 'Name',
27 }, 27 },
28 emailLabel: { 28 emailLabel: {
29 id: 'invite.email.label', 29 id: 'invite.email.label',
30 defaultMessage: '!!!Email address', 30 defaultMessage: 'Email address',
31 }, 31 },
32 submitButtonLabel: { 32 submitButtonLabel: {
33 id: 'invite.submit.label', 33 id: 'invite.submit.label',
34 defaultMessage: '!!!Send invites', 34 defaultMessage: 'Send invites',
35 }, 35 },
36 skipButtonLabel: { 36 skipButtonLabel: {
37 id: 'invite.skip.label', 37 id: 'invite.skip.label',
38 defaultMessage: '!!!I want to do this later', 38 defaultMessage: 'I want to do this later',
39 }, 39 },
40 inviteSuccessInfo: { 40 inviteSuccessInfo: {
41 id: 'invite.successInfo', 41 id: 'invite.successInfo',
42 defaultMessage: '!!!Invitations sent successfully', 42 defaultMessage: 'Invitations sent successfully',
43 }, 43 },
44}); 44});
45 45
46export default
47@observer 46@observer
48class Invite extends Component { 47class Invite extends Component {
49 static propTypes = { 48 static propTypes = {
@@ -59,10 +58,6 @@ class Invite extends Component {
59 isLoadingInvite: false, 58 isLoadingInvite: false,
60 }; 59 };
61 60
62 static contextTypes = {
63 intl: intlShape,
64 };
65
66 state = { showSuccessInfo: false }; 61 state = { showSuccessInfo: false };
67 62
68 componentDidMount() { 63 componentDidMount() {
@@ -70,11 +65,11 @@ class Invite extends Component {
70 { 65 {
71 fields: { 66 fields: {
72 invite: [ 67 invite: [
73 ...Array(3).fill({ 68 ...Array.from({ length: 3 }).fill({
74 fields: { 69 fields: {
75 name: { 70 name: {
76 label: this.context.intl.formatMessage(messages.nameLabel), 71 label: this.props.intl.formatMessage(messages.nameLabel),
77 placeholder: this.context.intl.formatMessage( 72 placeholder: this.props.intl.formatMessage(
78 messages.nameLabel, 73 messages.nameLabel,
79 ), 74 ),
80 onChange: () => { 75 onChange: () => {
@@ -83,8 +78,8 @@ class Invite extends Component {
83 // related: ['invite.0.email'], // path accepted but does not work 78 // related: ['invite.0.email'], // path accepted but does not work
84 }, 79 },
85 email: { 80 email: {
86 label: this.context.intl.formatMessage(messages.emailLabel), 81 label: this.props.intl.formatMessage(messages.emailLabel),
87 placeholder: this.context.intl.formatMessage( 82 placeholder: this.props.intl.formatMessage(
88 messages.emailLabel, 83 messages.emailLabel,
89 ), 84 ),
90 onChange: () => { 85 onChange: () => {
@@ -97,22 +92,22 @@ class Invite extends Component {
97 ], 92 ],
98 }, 93 },
99 }, 94 },
100 this.context.intl, 95 this.props.intl,
101 ); 96 );
102 97
103 document.querySelector('input:first-child').focus(); 98 document.querySelector('input:first-child')?.focus();
104 } 99 }
105 100
106 submit(e) { 101 submit(e) {
107 e.preventDefault(); 102 e.preventDefault();
108 103
109 this.form.submit({ 104 this.form?.submit({
110 onSuccess: (form) => { 105 onSuccess: form => {
111 this.props.onSubmit({ invites: form.values().invite }); 106 this.props.onSubmit({ invites: form.values().invite });
112 107
113 this.form.clear(); 108 this.form?.clear();
114 // this.form.$('invite.0.name').focus(); // path accepted but does not focus ;( 109 // this.form.$('invite.0.name').focus(); // path accepted but does not focus ;(
115 document.querySelector('input:first-child').focus(); 110 document.querySelector('input:first-child')?.focus();
116 this.setState({ showSuccessInfo: true }); 111 this.setState({ showSuccessInfo: true });
117 }, 112 },
118 onError: () => {}, 113 onError: () => {},
@@ -121,13 +116,13 @@ class Invite extends Component {
121 116
122 render() { 117 render() {
123 const { form } = this; 118 const { form } = this;
124 const { intl } = this.context; 119 const { intl } = this.props;
125 const { embed, isInviteSuccessful, isLoadingInvite } = this.props; 120 const { embed, isInviteSuccessful, isLoadingInvite } = this.props;
126 121
127 const atLeastOneEmailAddress = form 122 const atLeastOneEmailAddress = form
128 .$('invite') 123 .$('invite')
129 .map((invite) => invite.$('email').value) 124 .map(invite => invite.$('email').value)
130 .some((emailValue) => emailValue.trim() !== ''); 125 .some(emailValue => emailValue.trim() !== '');
131 126
132 const sendButtonClassName = classnames({ 127 const sendButtonClassName = classnames({
133 auth__button: true, 128 auth__button: true,
@@ -148,17 +143,14 @@ class Invite extends Component {
148 </Appear> 143 </Appear>
149 )} 144 )}
150 145
151 <form 146 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}>
152 className="franz-form auth__form"
153 onSubmit={(e) => this.submit(e)}
154 >
155 {!embed && ( 147 {!embed && (
156 <img src="./assets/images/logo.svg" className="auth__logo" alt="" /> 148 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
157 )} 149 )}
158 <h1 className={embed && 'invite__embed'}> 150 <h1 className={embed && 'invite__embed'}>
159 {intl.formatMessage(messages.headline)} 151 {intl.formatMessage(messages.headline)}
160 </h1> 152 </h1>
161 {form.$('invite').map((invite) => ( 153 {form.$('invite').map(invite => (
162 <div className="grid" key={invite.key}> 154 <div className="grid" key={invite.key}>
163 <div className="grid__row"> 155 <div className="grid__row">
164 <Input field={invite.$('name')} showLabel={false} /> 156 <Input field={invite.$('name')} showLabel={false} />
@@ -193,9 +185,7 @@ class Invite extends Component {
193 > 185 >
194 {embed && ( 186 {embed && (
195 <div className="settings__header"> 187 <div className="settings__header">
196 <h1> 188 <h1>{this.props.intl.formatMessage(messages.settingsHeadline)}</h1>
197 {this.context.intl.formatMessage(messages.settingsHeadline)}
198 </h1>
199 </div> 189 </div>
200 )} 190 )}
201 {!embed ? ( 191 {!embed ? (
@@ -207,3 +197,5 @@ class Invite extends Component {
207 ); 197 );
208 } 198 }
209} 199}
200
201export default injectIntl(Invite);
diff --git a/src/components/auth/Locked.js b/src/components/auth/Locked.js
index 2ad8a2409..a507ba140 100644
--- a/src/components/auth/Locked.js
+++ b/src/components/auth/Locked.js
@@ -2,7 +2,7 @@ import { systemPreferences } from '@electron/remote';
2import React, { Component } from 'react'; 2import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { observer } from 'mobx-react'; 4import { observer } from 'mobx-react';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6 6
7import Form from '../../lib/Form'; 7import Form from '../../lib/Form';
8import Input from '../ui/Input'; 8import Input from '../ui/Input';
@@ -15,39 +15,41 @@ import { globalError as globalErrorPropType } from '../../prop-types';
15const messages = defineMessages({ 15const messages = defineMessages({
16 headline: { 16 headline: {
17 id: 'locked.headline', 17 id: 'locked.headline',
18 defaultMessage: '!!!Locked', 18 defaultMessage: 'Locked',
19 }, 19 },
20 info: { 20 info: {
21 id: 'locked.info', 21 id: 'locked.info',
22 defaultMessage: '!!!Ferdi is currently locked. Please unlock Ferdi with your password to see your messages.', 22 defaultMessage:
23 'Ferdi is currently locked. Please unlock Ferdi with your password to see your messages.',
23 }, 24 },
24 touchId: { 25 touchId: {
25 id: 'locked.touchId', 26 id: 'locked.touchId',
26 defaultMessage: '!!!Unlock with Touch ID', 27 defaultMessage: 'Unlock with Touch ID',
27 }, 28 },
28 touchIdPrompt: { 29 touchIdPrompt: {
29 id: 'locked.touchIdPrompt', 30 id: 'locked.touchIdPrompt',
30 defaultMessage: '!!!unlock via Touch ID', 31 defaultMessage: 'unlock via Touch ID',
31 }, 32 },
32 passwordLabel: { 33 passwordLabel: {
33 id: 'locked.password.label', 34 id: 'locked.password.label',
34 defaultMessage: '!!!Password', 35 defaultMessage: 'Password',
35 }, 36 },
36 submitButtonLabel: { 37 submitButtonLabel: {
37 id: 'locked.submit.label', 38 id: 'locked.submit.label',
38 defaultMessage: '!!!Unlock', 39 defaultMessage: 'Unlock',
39 }, 40 },
40 unlockWithPassword: { 41 unlockWithPassword: {
41 id: 'locked.unlockWithPassword', 42 id: 'locked.unlockWithPassword',
42 defaultMessage: '!!!Unlock with Password', 43 defaultMessage: 'Unlock with Password',
43 }, 44 },
44 invalidCredentials: { 45 invalidCredentials: {
45 id: 'locked.invalidCredentials', 46 id: 'locked.invalidCredentials',
46 defaultMessage: '!!!Password invalid', 47 defaultMessage: 'Password invalid',
47 }, 48 },
48}); 49});
49 50
50export default @observer class Locked extends Component { 51@observer
52class Locked extends Component {
51 static propTypes = { 53 static propTypes = {
52 onSubmit: PropTypes.func.isRequired, 54 onSubmit: PropTypes.func.isRequired,
53 unlock: PropTypes.func.isRequired, 55 unlock: PropTypes.func.isRequired,
@@ -56,62 +58,57 @@ export default @observer class Locked extends Component {
56 error: globalErrorPropType.isRequired, 58 error: globalErrorPropType.isRequired,
57 }; 59 };
58 60
59 static contextTypes = { 61 form = new Form(
60 intl: intlShape, 62 {
61 }; 63 fields: {
62 64 password: {
63 form = new Form({ 65 label: this.props.intl.formatMessage(messages.passwordLabel),
64 fields: { 66 value: '',
65 password: { 67 type: 'password',
66 label: this.context.intl.formatMessage(messages.passwordLabel), 68 },
67 value: '',
68 type: 'password',
69 }, 69 },
70 }, 70 },
71 }, this.context.intl); 71 this.props.intl,
72 );
72 73
73 submit(e) { 74 submit(e) {
74 e.preventDefault(); 75 e.preventDefault();
75 this.form.submit({ 76 this.form.submit({
76 onSuccess: (form) => { 77 onSuccess: form => {
77 this.props.onSubmit(form.values()); 78 this.props.onSubmit(form.values());
78 }, 79 },
79 onError: () => { }, 80 onError: () => {},
80 }); 81 });
81 } 82 }
82 83
83 touchIdUnlock() { 84 touchIdUnlock() {
84 const { intl } = this.context; 85 const { intl } = this.props;
85 86
86 systemPreferences.promptTouchID(intl.formatMessage(messages.touchIdPrompt)).then(() => { 87 systemPreferences
87 this.props.unlock(); 88 .promptTouchID(intl.formatMessage(messages.touchIdPrompt))
88 }); 89 .then(() => {
90 this.props.unlock();
91 });
89 } 92 }
90 93
91 render() { 94 render() {
92 const { form } = this; 95 const { form } = this;
93 const { intl } = this.context; 96 const { intl } = this.props;
94 const { 97 const { isSubmitting, error, useTouchIdToUnlock } = this.props;
95 isSubmitting,
96 error,
97 useTouchIdToUnlock,
98 } = this.props;
99 98
100 const touchIdEnabled = isMac ? (useTouchIdToUnlock && systemPreferences.canPromptTouchID()) : false; 99 const touchIdEnabled = isMac
101 const submitButtonLabel = touchIdEnabled ? intl.formatMessage(messages.unlockWithPassword) : intl.formatMessage(messages.submitButtonLabel); 100 ? useTouchIdToUnlock && systemPreferences.canPromptTouchID()
101 : false;
102 const submitButtonLabel = touchIdEnabled
103 ? intl.formatMessage(messages.unlockWithPassword)
104 : intl.formatMessage(messages.submitButtonLabel);
102 105
103 return ( 106 return (
104 <div className="auth__container"> 107 <div className="auth__container">
105 <form className="franz-form auth__form" onSubmit={(e) => this.submit(e)}> 108 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}>
106 <img 109 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
107 src="./assets/images/logo.svg"
108 className="auth__logo"
109 alt=""
110 />
111 <h1>{intl.formatMessage(messages.headline)}</h1> 110 <h1>{intl.formatMessage(messages.headline)}</h1>
112 <Infobox type="warning"> 111 <Infobox type="warning">{intl.formatMessage(messages.info)}</Infobox>
113 {intl.formatMessage(messages.info)}
114 </Infobox>
115 112
116 {touchIdEnabled && ( 113 {touchIdEnabled && (
117 <> 114 <>
@@ -125,13 +122,11 @@ export default @observer class Locked extends Component {
125 </> 122 </>
126 )} 123 )}
127 124
128 <Input 125 <Input field={form.$('password')} showPasswordToggle focus />
129 field={form.$('password')}
130 showPasswordToggle
131 focus
132 />
133 {error.code === 'invalid-credentials' && ( 126 {error.code === 'invalid-credentials' && (
134 <p className="error-message center">{intl.formatMessage(messages.invalidCredentials)}</p> 127 <p className="error-message center">
128 {intl.formatMessage(messages.invalidCredentials)}
129 </p>
135 )} 130 )}
136 {isSubmitting ? ( 131 {isSubmitting ? (
137 <Button 132 <Button
@@ -153,3 +148,5 @@ export default @observer class Locked extends Component {
153 ); 148 );
154 } 149 }
155} 150}
151
152export default injectIntl(Locked);
diff --git a/src/components/auth/Login.js b/src/components/auth/Login.js
index 9e6a8d046..2f9986858 100644
--- a/src/components/auth/Login.js
+++ b/src/components/auth/Login.js
@@ -2,10 +2,10 @@
2import React, { Component } from 'react'; 2import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { observer, inject } from 'mobx-react'; 4import { observer, inject } from 'mobx-react';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6 6
7import { LIVE_FRANZ_API } from '../../config'; 7import { LIVE_FRANZ_API } from '../../config';
8import { API_VERSION, isDevMode, useLiveAPI } from '../../environment'; 8import { API_VERSION, isDevMode, useLiveAPI } from '../../environment-remote';
9import Form from '../../lib/Form'; 9import Form from '../../lib/Form';
10import { required, email } from '../../helpers/validation-helpers'; 10import { required, email } from '../../helpers/validation-helpers';
11import serverlessLogin from '../../helpers/serverless-helpers'; 11import serverlessLogin from '../../helpers/serverless-helpers';
@@ -19,59 +19,61 @@ import { globalError as globalErrorPropType } from '../../prop-types';
19const messages = defineMessages({ 19const messages = defineMessages({
20 headline: { 20 headline: {
21 id: 'login.headline', 21 id: 'login.headline',
22 defaultMessage: '!!!Sign in', 22 defaultMessage: 'Sign in',
23 }, 23 },
24 emailLabel: { 24 emailLabel: {
25 id: 'login.email.label', 25 id: 'login.email.label',
26 defaultMessage: '!!!Email address', 26 defaultMessage: 'Email address',
27 }, 27 },
28 passwordLabel: { 28 passwordLabel: {
29 id: 'login.password.label', 29 id: 'login.password.label',
30 defaultMessage: '!!!Password', 30 defaultMessage: 'Password',
31 }, 31 },
32 submitButtonLabel: { 32 submitButtonLabel: {
33 id: 'login.submit.label', 33 id: 'login.submit.label',
34 defaultMessage: '!!!Sign in', 34 defaultMessage: 'Sign in',
35 }, 35 },
36 invalidCredentials: { 36 invalidCredentials: {
37 id: 'login.invalidCredentials', 37 id: 'login.invalidCredentials',
38 defaultMessage: '!!!Email or password not valid', 38 defaultMessage: 'Email or password not valid',
39 }, 39 },
40 customServerQuestion: { 40 customServerQuestion: {
41 id: 'login.customServerQuestion', 41 id: 'login.customServerQuestion',
42 defaultMessage: '!!!Using a Franz account to log in?', 42 defaultMessage: 'Using a Franz account to log in?',
43 }, 43 },
44 customServerSuggestion: { 44 customServerSuggestion: {
45 id: 'login.customServerSuggestion', 45 id: 'login.customServerSuggestion',
46 defaultMessage: '!!!Try importing your Franz account into Ferdi', 46 defaultMessage: 'Try importing your Franz account into Ferdi',
47 }, 47 },
48 tokenExpired: { 48 tokenExpired: {
49 id: 'login.tokenExpired', 49 id: 'login.tokenExpired',
50 defaultMessage: '!!!Your session expired, please login again.', 50 defaultMessage: 'Your session expired, please login again.',
51 }, 51 },
52 serverLogout: { 52 serverLogout: {
53 id: 'login.serverLogout', 53 id: 'login.serverLogout',
54 defaultMessage: '!!!Your session expired, please login again.', 54 defaultMessage: 'Your session expired, please login again.',
55 }, 55 },
56 signupLink: { 56 signupLink: {
57 id: 'login.link.signup', 57 id: 'login.link.signup',
58 defaultMessage: '!!!Create a free account', 58 defaultMessage: 'Create a free account',
59 }, 59 },
60 changeServer: { 60 changeServer: {
61 id: 'login.changeServer', 61 id: 'login.changeServer',
62 defaultMessage: '!!!Change server', 62 defaultMessage: 'Change server',
63 }, 63 },
64 serverless: { 64 serverless: {
65 id: 'services.serverless', 65 id: 'services.serverless',
66 defaultMessage: '!!!Use Ferdi without an Account', 66 defaultMessage: 'Use Ferdi without an Account',
67 }, 67 },
68 passwordLink: { 68 passwordLink: {
69 id: 'login.link.password', 69 id: 'login.link.password',
70 defaultMessage: '!!!Forgot password', 70 defaultMessage: 'Reset password',
71 }, 71 },
72}); 72});
73 73
74export default @inject('actions') @observer class Login extends Component { 74@inject('actions')
75@observer
76class Login extends Component {
75 static propTypes = { 77 static propTypes = {
76 onSubmit: PropTypes.func.isRequired, 78 onSubmit: PropTypes.func.isRequired,
77 isSubmitting: PropTypes.bool.isRequired, 79 isSubmitting: PropTypes.bool.isRequired,
@@ -84,35 +86,34 @@ export default @inject('actions') @observer class Login extends Component {
84 actions: PropTypes.object.isRequired, 86 actions: PropTypes.object.isRequired,
85 }; 87 };
86 88
87 static contextTypes = { 89 form = new Form(
88 intl: intlShape, 90 {
89 }; 91 fields: {
90 92 email: {
91 form = new Form({ 93 label: this.props.intl.formatMessage(messages.emailLabel),
92 fields: { 94 value: '',
93 email: { 95 validators: [required, email],
94 label: this.context.intl.formatMessage(messages.emailLabel), 96 },
95 value: '', 97 password: {
96 validators: [required, email], 98 label: this.props.intl.formatMessage(messages.passwordLabel),
97 }, 99 value: '',
98 password: { 100 validators: [required],
99 label: this.context.intl.formatMessage(messages.passwordLabel), 101 type: 'password',
100 value: '', 102 },
101 validators: [required],
102 type: 'password',
103 }, 103 },
104 }, 104 },
105 }, this.context.intl); 105 this.props.intl,
106 );
106 107
107 emailField = null; 108 emailField = null;
108 109
109 submit(e) { 110 submit(e) {
110 e.preventDefault(); 111 e.preventDefault();
111 this.form.submit({ 112 this.form.submit({
112 onSuccess: (form) => { 113 onSuccess: form => {
113 this.props.onSubmit(form.values()); 114 this.props.onSubmit(form.values());
114 }, 115 },
115 onError: () => { }, 116 onError: () => {},
116 }); 117 });
117 } 118 }
118 119
@@ -122,7 +123,7 @@ export default @inject('actions') @observer class Login extends Component {
122 123
123 render() { 124 render() {
124 const { form } = this; 125 const { form } = this;
125 const { intl } = this.context; 126 const { intl } = this.props;
126 const { 127 const {
127 isSubmitting, 128 isSubmitting,
128 isTokenExpired, 129 isTokenExpired,
@@ -135,42 +136,47 @@ export default @inject('actions') @observer class Login extends Component {
135 136
136 return ( 137 return (
137 <div className="auth__container"> 138 <div className="auth__container">
138 <form className="franz-form auth__form" onSubmit={(e) => this.submit(e)}> 139 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}>
139 <img 140 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
140 src="./assets/images/logo.svg"
141 className="auth__logo"
142 alt=""
143 />
144 <h1>{intl.formatMessage(messages.headline)}</h1> 141 <h1>{intl.formatMessage(messages.headline)}</h1>
145 {isDevMode && !useLiveAPI && ( 142 {isDevMode && !useLiveAPI && (
146 <Infobox type="warning"> 143 <Infobox type="warning">
147 In Dev Mode your data is not persistent. Please use the live app for accessing the production API. 144 In Dev Mode your data is not persistent. Please use the live app
145 for accessing the production API.
148 </Infobox> 146 </Infobox>
149 )} 147 )}
150 {isTokenExpired && ( 148 {isTokenExpired && (
151 <p className="error-message center">{intl.formatMessage(messages.tokenExpired)}</p> 149 <p className="error-message center">
150 {intl.formatMessage(messages.tokenExpired)}
151 </p>
152 )} 152 )}
153 {isServerLogout && ( 153 {isServerLogout && (
154 <p className="error-message center">{intl.formatMessage(messages.serverLogout)}</p> 154 <p className="error-message center">
155 {intl.formatMessage(messages.serverLogout)}
156 </p>
155 )} 157 )}
156 <Input 158 <Input
157 field={form.$('email')} 159 field={form.$('email')}
158 ref={(element) => { this.emailField = element; }} 160 ref={element => {
161 this.emailField = element;
162 }}
159 focus 163 focus
160 /> 164 />
161 <Input 165 <Input field={form.$('password')} showPasswordToggle />
162 field={form.$('password')}
163 showPasswordToggle
164 />
165 {error.code === 'invalid-credentials' && ( 166 {error.code === 'invalid-credentials' && (
166 <> 167 <>
167 <p className="error-message center">{intl.formatMessage(messages.invalidCredentials)}</p> 168 <p className="error-message center">
168 { window.ferdi.stores.settings.all.app.server !== LIVE_FRANZ_API && ( 169 {intl.formatMessage(messages.invalidCredentials)}
170 </p>
171 {window.ferdi.stores.settings.all.app.server !==
172 LIVE_FRANZ_API && (
169 <p className="error-message center"> 173 <p className="error-message center">
170 {intl.formatMessage(messages.customServerQuestion)} 174 {intl.formatMessage(messages.customServerQuestion)}{' '}
171 {' '}
172 <Link 175 <Link
173 to={`${window.ferdi.stores.settings.all.app.server.replace(API_VERSION, '')}/import`} 176 to={`${window.ferdi.stores.settings.all.app.server.replace(
177 API_VERSION,
178 '',
179 )}/import`}
174 target="_blank" 180 target="_blank"
175 style={{ cursor: 'pointer', textDecoration: 'underline' }} 181 style={{ cursor: 'pointer', textDecoration: 'underline' }}
176 > 182 >
@@ -197,12 +203,22 @@ export default @inject('actions') @observer class Login extends Component {
197 )} 203 )}
198 </form> 204 </form>
199 <div className="auth__links"> 205 <div className="auth__links">
200 <Link to={changeServerRoute}>{intl.formatMessage(messages.changeServer)}</Link> 206 <Link to={changeServerRoute}>
201 <a onClick={this.useLocalServer.bind(this)}>{intl.formatMessage(messages.serverless)}</a> 207 {intl.formatMessage(messages.changeServer)}
202 <Link to={signupRoute}>{intl.formatMessage(messages.signupLink)}</Link> 208 </Link>
203 <Link to={passwordRoute}>{intl.formatMessage(messages.passwordLink)}</Link> 209 <a onClick={this.useLocalServer.bind(this)}>
210 {intl.formatMessage(messages.serverless)}
211 </a>
212 <Link to={signupRoute}>
213 {intl.formatMessage(messages.signupLink)}
214 </Link>
215 <Link to={passwordRoute}>
216 {intl.formatMessage(messages.passwordLink)}
217 </Link>
204 </div> 218 </div>
205 </div> 219 </div>
206 ); 220 );
207 } 221 }
208} 222}
223
224export default injectIntl(Login);
diff --git a/src/components/auth/Password.js b/src/components/auth/Password.js
index 1be2097bd..3e678f638 100644
--- a/src/components/auth/Password.js
+++ b/src/components/auth/Password.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import Form from '../../lib/Form'; 6import Form from '../../lib/Form';
7import { required, email } from '../../helpers/validation-helpers'; 7import { required, email } from '../../helpers/validation-helpers';
@@ -14,31 +14,32 @@ import globalMessages from '../../i18n/globalMessages';
14const messages = defineMessages({ 14const messages = defineMessages({
15 headline: { 15 headline: {
16 id: 'password.headline', 16 id: 'password.headline',
17 defaultMessage: '!!!Forgot password', 17 defaultMessage: 'Reset password',
18 }, 18 },
19 emailLabel: { 19 emailLabel: {
20 id: 'password.email.label', 20 id: 'password.email.label',
21 defaultMessage: '!!!Email address', 21 defaultMessage: 'Email address',
22 }, 22 },
23 successInfo: { 23 successInfo: {
24 id: 'password.successInfo', 24 id: 'password.successInfo',
25 defaultMessage: '!!!Your new password was sent to your email address', 25 defaultMessage: 'Your new password was sent to your email address',
26 }, 26 },
27 noUser: { 27 noUser: {
28 id: 'password.noUser', 28 id: 'password.noUser',
29 defaultMessage: '!!!No user affiliated with that email address', 29 defaultMessage: 'No user with that email address was found',
30 }, 30 },
31 signupLink: { 31 signupLink: {
32 id: 'password.link.signup', 32 id: 'password.link.signup',
33 defaultMessage: '!!!Create a free account', 33 defaultMessage: 'Create a free account',
34 }, 34 },
35 loginLink: { 35 loginLink: {
36 id: 'password.link.login', 36 id: 'password.link.login',
37 defaultMessage: '!!!Sign in to your account', 37 defaultMessage: 'Sign in to your account',
38 }, 38 },
39}); 39});
40 40
41export default @observer class Password extends Component { 41@observer
42class Password extends Component {
42 static propTypes = { 43 static propTypes = {
43 onSubmit: PropTypes.func.isRequired, 44 onSubmit: PropTypes.func.isRequired,
44 isSubmitting: PropTypes.bool.isRequired, 45 isSubmitting: PropTypes.bool.isRequired,
@@ -47,24 +48,23 @@ export default @observer class Password extends Component {
47 status: MobxPropTypes.arrayOrObservableArray.isRequired, 48 status: MobxPropTypes.arrayOrObservableArray.isRequired,
48 }; 49 };
49 50
50 static contextTypes = { 51 form = new Form(
51 intl: intlShape, 52 {
52 }; 53 fields: {
53 54 email: {
54 form = new Form({ 55 label: this.props.intl.formatMessage(messages.emailLabel),
55 fields: { 56 value: '',
56 email: { 57 validators: [required, email],
57 label: this.context.intl.formatMessage(messages.emailLabel), 58 },
58 value: '',
59 validators: [required, email],
60 }, 59 },
61 }, 60 },
62 }, this.context.intl); 61 this.props.intl,
62 );
63 63
64 submit(e) { 64 submit(e) {
65 e.preventDefault(); 65 e.preventDefault();
66 this.form.submit({ 66 this.form.submit({
67 onSuccess: (form) => { 67 onSuccess: form => {
68 this.props.onSubmit(form.values()); 68 this.props.onSubmit(form.values());
69 }, 69 },
70 onError: () => {}, 70 onError: () => {},
@@ -73,37 +73,24 @@ export default @observer class Password extends Component {
73 73
74 render() { 74 render() {
75 const { form } = this; 75 const { form } = this;
76 const { intl } = this.context; 76 const { intl } = this.props;
77 const { 77 const { isSubmitting, signupRoute, loginRoute, status } = this.props;
78 isSubmitting,
79 signupRoute,
80 loginRoute,
81 status,
82 } = this.props;
83 78
84 return ( 79 return (
85 <div className="auth__container"> 80 <div className="auth__container">
86 <form className="franz-form auth__form" onSubmit={(e) => this.submit(e)}> 81 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}>
87 <img 82 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
88 src="./assets/images/logo.svg"
89 className="auth__logo"
90 alt=""
91 />
92 <h1>{intl.formatMessage(messages.headline)}</h1> 83 <h1>{intl.formatMessage(messages.headline)}</h1>
93 {status.length > 0 && status.includes('sent') && ( 84 {status.length > 0 && status.includes('sent') && (
94 <Infobox 85 <Infobox type="success" icon="checkbox-marked-circle-outline">
95 type="success"
96 icon="checkbox-marked-circle-outline"
97 >
98 {intl.formatMessage(messages.successInfo)} 86 {intl.formatMessage(messages.successInfo)}
99 </Infobox> 87 </Infobox>
100 )} 88 )}
101 <Input 89 <Input field={form.$('email')} focus />
102 field={form.$('email')}
103 focus
104 />
105 {status.length > 0 && status.includes('no-user') && ( 90 {status.length > 0 && status.includes('no-user') && (
106 <p className="error-message center">{intl.formatMessage(messages.noUser)}</p> 91 <p className="error-message center">
92 {intl.formatMessage(messages.noUser)}
93 </p>
107 )} 94 )}
108 {isSubmitting ? ( 95 {isSubmitting ? (
109 <Button 96 <Button
@@ -123,9 +110,13 @@ export default @observer class Password extends Component {
123 </form> 110 </form>
124 <div className="auth__links"> 111 <div className="auth__links">
125 <Link to={loginRoute}>{intl.formatMessage(messages.loginLink)}</Link> 112 <Link to={loginRoute}>{intl.formatMessage(messages.loginLink)}</Link>
126 <Link to={signupRoute}>{intl.formatMessage(messages.signupLink)}</Link> 113 <Link to={signupRoute}>
114 {intl.formatMessage(messages.signupLink)}
115 </Link>
127 </div> 116 </div>
128 </div> 117 </div>
129 ); 118 );
130 } 119 }
131} 120}
121
122export default injectIntl(Password);
diff --git a/src/components/auth/SetupAssistant.js b/src/components/auth/SetupAssistant.js
index ded36bbe7..299c40c63 100644
--- a/src/components/auth/SetupAssistant.js
+++ b/src/components/auth/SetupAssistant.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7 7
@@ -19,20 +19,20 @@ const SLACK_ID = 'slack';
19const messages = defineMessages({ 19const messages = defineMessages({
20 headline: { 20 headline: {
21 id: 'setupAssistant.headline', 21 id: 'setupAssistant.headline',
22 defaultMessage: "!!!Let's get started", 22 defaultMessage: "Let's get started",
23 }, 23 },
24 subHeadline: { 24 subHeadline: {
25 id: 'setupAssistant.subheadline', 25 id: 'setupAssistant.subheadline',
26 defaultMessage: 26 defaultMessage:
27 '!!!Choose from our most used services and get back on top of your messaging now.', 27 'Choose from our most used services and get back on top of your messaging now.',
28 }, 28 },
29 submitButtonLabel: { 29 submitButtonLabel: {
30 id: 'setupAssistant.submit.label', 30 id: 'setupAssistant.submit.label',
31 defaultMessage: "!!!Let's go", 31 defaultMessage: "Let's go",
32 }, 32 },
33 inviteSuccessInfo: { 33 inviteSuccessInfo: {
34 id: 'invite.successInfo', 34 id: 'invite.successInfo',
35 defaultMessage: '!!!Invitations sent successfully', 35 defaultMessage: 'Invitations sent successfully',
36 }, 36 },
37}); 37});
38 38
@@ -145,10 +145,6 @@ class SetupAssistant extends Component {
145 isInviteSuccessful: false, 145 isInviteSuccessful: false,
146 }; 146 };
147 147
148 static contextTypes = {
149 intl: intlShape,
150 };
151
152 state = { 148 state = {
153 services: [ 149 services: [
154 { 150 {
@@ -189,7 +185,7 @@ class SetupAssistant extends Component {
189 } 185 }
190 186
191 render() { 187 render() {
192 const { intl } = this.context; 188 const { intl } = this.props;
193 const { 189 const {
194 classes, 190 classes,
195 isInviteSuccessful, 191 isInviteSuccessful,
@@ -330,4 +326,4 @@ class SetupAssistant extends Component {
330 } 326 }
331} 327}
332 328
333export default SetupAssistant; 329export default injectIntl(SetupAssistant);
diff --git a/src/components/auth/Signup.js b/src/components/auth/Signup.js
index 6fb41a164..816a49669 100644
--- a/src/components/auth/Signup.js
+++ b/src/components/auth/Signup.js
@@ -2,9 +2,9 @@
2import React, { Component } from 'react'; 2import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { observer, inject } from 'mobx-react'; 4import { observer, inject } from 'mobx-react';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6 6
7import { isDevMode, useLiveAPI } from '../../environment'; 7import { isDevMode, useLiveAPI } from '../../environment-remote';
8import Form from '../../lib/Form'; 8import Form from '../../lib/Form';
9import { required, email, minLength } from '../../helpers/validation-helpers'; 9import { required, email, minLength } from '../../helpers/validation-helpers';
10import serverlessLogin from '../../helpers/serverless-helpers'; 10import serverlessLogin from '../../helpers/serverless-helpers';
@@ -19,63 +19,65 @@ import { termsBase } from '../../api/apiBase';
19const messages = defineMessages({ 19const messages = defineMessages({
20 headline: { 20 headline: {
21 id: 'signup.headline', 21 id: 'signup.headline',
22 defaultMessage: '!!!Sign up', 22 defaultMessage: 'Sign up',
23 }, 23 },
24 firstnameLabel: { 24 firstnameLabel: {
25 id: 'signup.firstname.label', 25 id: 'signup.firstname.label',
26 defaultMessage: '!!!Firstname', 26 defaultMessage: 'First Name',
27 }, 27 },
28 lastnameLabel: { 28 lastnameLabel: {
29 id: 'signup.lastname.label', 29 id: 'signup.lastname.label',
30 defaultMessage: '!!!Lastname', 30 defaultMessage: 'Last Name',
31 }, 31 },
32 emailLabel: { 32 emailLabel: {
33 id: 'signup.email.label', 33 id: 'signup.email.label',
34 defaultMessage: '!!!Email address', 34 defaultMessage: 'Email address',
35 }, 35 },
36 // companyLabel: { 36 // companyLabel: {
37 // id: 'signup.company.label', 37 // id: 'signup.company.label',
38 // defaultMessage: '!!!Company', 38 // defaultMessage: 'Company',
39 // }, 39 // },
40 passwordLabel: { 40 passwordLabel: {
41 id: 'signup.password.label', 41 id: 'signup.password.label',
42 defaultMessage: '!!!Password', 42 defaultMessage: 'Password',
43 }, 43 },
44 legalInfo: { 44 legalInfo: {
45 id: 'signup.legal.info', 45 id: 'signup.legal.info',
46 defaultMessage: '!!!By creating a Ferdi account you accept the', 46 defaultMessage: 'By creating a Ferdi account you accept the',
47 }, 47 },
48 terms: { 48 terms: {
49 id: 'signup.legal.terms', 49 id: 'signup.legal.terms',
50 defaultMessage: '!!!Terms of service', 50 defaultMessage: 'Terms of service',
51 }, 51 },
52 privacy: { 52 privacy: {
53 id: 'signup.legal.privacy', 53 id: 'signup.legal.privacy',
54 defaultMessage: '!!!Privacy Statement', 54 defaultMessage: 'Privacy Statement',
55 }, 55 },
56 submitButtonLabel: { 56 submitButtonLabel: {
57 id: 'signup.submit.label', 57 id: 'signup.submit.label',
58 defaultMessage: '!!!Create account', 58 defaultMessage: 'Create account',
59 }, 59 },
60 loginLink: { 60 loginLink: {
61 id: 'signup.link.login', 61 id: 'signup.link.login',
62 defaultMessage: '!!!Already have an account, sign in?', 62 defaultMessage: 'Already have an account, sign in?',
63 }, 63 },
64 changeServer: { 64 changeServer: {
65 id: 'login.changeServer', 65 id: 'login.changeServer',
66 defaultMessage: '!!!Change server', 66 defaultMessage: 'Change server',
67 }, 67 },
68 serverless: { 68 serverless: {
69 id: 'services.serverless', 69 id: 'services.serverless',
70 defaultMessage: '!!!Use Ferdi without an Account', 70 defaultMessage: 'Use Ferdi without an Account',
71 }, 71 },
72 emailDuplicate: { 72 emailDuplicate: {
73 id: 'signup.emailDuplicate', 73 id: 'signup.emailDuplicate',
74 defaultMessage: '!!!A user with that email address already exists', 74 defaultMessage: 'A user with that email address already exists',
75 }, 75 },
76}); 76});
77 77
78export default @inject('actions') @observer class Signup extends Component { 78@inject('actions')
79@observer
80class Signup extends Component {
79 static propTypes = { 81 static propTypes = {
80 onSubmit: PropTypes.func.isRequired, 82 onSubmit: PropTypes.func.isRequired,
81 isSubmitting: PropTypes.bool.isRequired, 83 isSubmitting: PropTypes.bool.isRequired,
@@ -85,40 +87,39 @@ export default @inject('actions') @observer class Signup extends Component {
85 actions: PropTypes.object.isRequired, 87 actions: PropTypes.object.isRequired,
86 }; 88 };
87 89
88 static contextTypes = { 90 form = new Form(
89 intl: intlShape, 91 {
90 }; 92 fields: {
91 93 firstname: {
92 form = new Form({ 94 label: this.props.intl.formatMessage(messages.firstnameLabel),
93 fields: { 95 value: '',
94 firstname: { 96 validators: [required],
95 label: this.context.intl.formatMessage(messages.firstnameLabel), 97 },
96 value: '', 98 lastname: {
97 validators: [required], 99 label: this.props.intl.formatMessage(messages.lastnameLabel),
98 }, 100 value: '',
99 lastname: { 101 validators: [required],
100 label: this.context.intl.formatMessage(messages.lastnameLabel), 102 },
101 value: '', 103 email: {
102 validators: [required], 104 label: this.props.intl.formatMessage(messages.emailLabel),
103 }, 105 value: '',
104 email: { 106 validators: [required, email],
105 label: this.context.intl.formatMessage(messages.emailLabel), 107 },
106 value: '', 108 password: {
107 validators: [required, email], 109 label: this.props.intl.formatMessage(messages.passwordLabel),
108 }, 110 value: '',
109 password: { 111 validators: [required, minLength(6)],
110 label: this.context.intl.formatMessage(messages.passwordLabel), 112 type: 'password',
111 value: '', 113 },
112 validators: [required, minLength(6)],
113 type: 'password',
114 }, 114 },
115 }, 115 },
116 }, this.context.intl); 116 this.props.intl,
117 );
117 118
118 submit(e) { 119 submit(e) {
119 e.preventDefault(); 120 e.preventDefault();
120 this.form.submit({ 121 this.form.submit({
121 onSuccess: (form) => { 122 onSuccess: form => {
122 this.props.onSubmit(form.values()); 123 this.props.onSubmit(form.values());
123 }, 124 },
124 onError: () => {}, 125 onError: () => {},
@@ -131,24 +132,22 @@ export default @inject('actions') @observer class Signup extends Component {
131 132
132 render() { 133 render() {
133 const { form } = this; 134 const { form } = this;
134 const { intl } = this.context; 135 const { intl } = this.props;
135 const { 136 const { isSubmitting, loginRoute, error, changeServerRoute } = this.props;
136 isSubmitting, loginRoute, error, changeServerRoute,
137 } = this.props;
138 137
139 return ( 138 return (
140 <div className="auth__scroll-container"> 139 <div className="auth__scroll-container">
141 <div className="auth__container auth__container--signup"> 140 <div className="auth__container auth__container--signup">
142 <form className="franz-form auth__form" onSubmit={(e) => this.submit(e)}> 141 <form
143 <img 142 className="franz-form auth__form"
144 src="./assets/images/logo.svg" 143 onSubmit={e => this.submit(e)}
145 className="auth__logo" 144 >
146 alt="" 145 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
147 />
148 <h1>{intl.formatMessage(messages.headline)}</h1> 146 <h1>{intl.formatMessage(messages.headline)}</h1>
149 {isDevMode && !useLiveAPI && ( 147 {isDevMode && !useLiveAPI && (
150 <Infobox type="warning"> 148 <Infobox type="warning">
151 In Dev Mode your data is not persistent. Please use the live app for accesing the production API. 149 In Dev Mode your data is not persistent. Please use the live app
150 for accesing the production API.
152 </Infobox> 151 </Infobox>
153 )} 152 )}
154 <div className="grid__row"> 153 <div className="grid__row">
@@ -162,7 +161,9 @@ export default @inject('actions') @observer class Signup extends Component {
162 scorePassword 161 scorePassword
163 /> 162 />
164 {error.code === 'email-duplicate' && ( 163 {error.code === 'email-duplicate' && (
165 <p className="error-message center">{intl.formatMessage(messages.emailDuplicate)}</p> 164 <p className="error-message center">
165 {intl.formatMessage(messages.emailDuplicate)}
166 </p>
166 )} 167 )}
167 {isSubmitting ? ( 168 {isSubmitting ? (
168 <Button 169 <Button
@@ -200,12 +201,20 @@ export default @inject('actions') @observer class Signup extends Component {
200 </p> 201 </p>
201 </form> 202 </form>
202 <div className="auth__links"> 203 <div className="auth__links">
203 <Link to={changeServerRoute}>{intl.formatMessage(messages.changeServer)}</Link> 204 <Link to={changeServerRoute}>
204 <a onClick={this.useLocalServer.bind(this)}>{intl.formatMessage(messages.serverless)}</a> 205 {intl.formatMessage(messages.changeServer)}
205 <Link to={loginRoute}>{intl.formatMessage(messages.loginLink)}</Link> 206 </Link>
207 <a onClick={this.useLocalServer.bind(this)}>
208 {intl.formatMessage(messages.serverless)}
209 </a>
210 <Link to={loginRoute}>
211 {intl.formatMessage(messages.loginLink)}
212 </Link>
206 </div> 213 </div>
207 </div> 214 </div>
208 </div> 215 </div>
209 ); 216 );
210 } 217 }
211} 218}
219
220export default injectIntl(Signup);
diff --git a/src/components/auth/Welcome.js b/src/components/auth/Welcome.js
index cb522e26e..2d2e2ab28 100644
--- a/src/components/auth/Welcome.js
+++ b/src/components/auth/Welcome.js
@@ -2,7 +2,7 @@
2import React, { Component } from 'react'; 2import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react'; 4import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import serverlessLogin from '../../helpers/serverless-helpers'; 6import serverlessLogin from '../../helpers/serverless-helpers';
7 7
8import Link from '../ui/Link'; 8import Link from '../ui/Link';
@@ -10,19 +10,21 @@ import Link from '../ui/Link';
10const messages = defineMessages({ 10const messages = defineMessages({
11 signupButton: { 11 signupButton: {
12 id: 'welcome.signupButton', 12 id: 'welcome.signupButton',
13 defaultMessage: '!!!Create a free account', 13 defaultMessage: 'Create a free account',
14 }, 14 },
15 loginButton: { 15 loginButton: {
16 id: 'welcome.loginButton', 16 id: 'welcome.loginButton',
17 defaultMessage: '!!!Login to your account', 17 defaultMessage: 'Login to your account',
18 }, 18 },
19 serverless: { 19 serverless: {
20 id: 'services.serverless', 20 id: 'services.serverless',
21 defaultMessage: '!!!Use Ferdi without an Account', 21 defaultMessage: 'Use Ferdi without an Account',
22 }, 22 },
23}); 23});
24 24
25export default @inject('actions') @observer class Login extends Component { 25@inject('actions')
26@observer
27class Login extends Component {
26 static propTypes = { 28 static propTypes = {
27 loginRoute: PropTypes.string.isRequired, 29 loginRoute: PropTypes.string.isRequired,
28 signupRoute: PropTypes.string.isRequired, 30 signupRoute: PropTypes.string.isRequired,
@@ -31,27 +33,22 @@ export default @inject('actions') @observer class Login extends Component {
31 actions: PropTypes.object.isRequired, 33 actions: PropTypes.object.isRequired,
32 }; 34 };
33 35
34 static contextTypes = {
35 intl: intlShape,
36 };
37
38 useLocalServer() { 36 useLocalServer() {
39 serverlessLogin(this.props.actions); 37 serverlessLogin(this.props.actions);
40 } 38 }
41 39
42 render() { 40 render() {
43 const { intl } = this.context; 41 const { intl } = this.props;
44 const { 42 const { loginRoute, signupRoute, changeServerRoute, recipes } = this.props;
45 loginRoute,
46 signupRoute,
47 changeServerRoute,
48 recipes,
49 } = this.props;
50 43
51 return ( 44 return (
52 <div className="welcome"> 45 <div className="welcome">
53 <div className="welcome__content"> 46 <div className="welcome__content">
54 <img src="./assets/images/logo.svg" className="welcome__logo" alt="" /> 47 <img
48 src="./assets/images/logo.svg"
49 className="welcome__logo"
50 alt=""
51 />
55 {/* <img src="./assets/images/welcome.png" className="welcome__services" alt="" /> */} 52 {/* <img src="./assets/images/welcome.png" className="welcome__services" alt="" /> */}
56 <div className="welcome__text"> 53 <div className="welcome__text">
57 <h1>Ferdi</h1> 54 <h1>Ferdi</h1>
@@ -73,27 +70,21 @@ export default @inject('actions') @observer class Login extends Component {
73 <br /> 70 <br />
74 71
75 <Link to={changeServerRoute}> 72 <Link to={changeServerRoute}>
76 <span style={{ 73 <span
77 textAlign: 'center', 74 style={{
78 width: '100%', 75 textAlign: 'center',
79 cursor: 'pointer', 76 width: '100%',
80 }} 77 cursor: 'pointer',
78 }}
81 > 79 >
82 Change server 80 Change server
83 </span> 81 </span>
84 </Link> 82 </Link>
85 </div> 83 </div>
86 <div className="welcome__featured-services"> 84 <div className="welcome__featured-services">
87 {recipes.map((recipe) => ( 85 {recipes.map(recipe => (
88 <div 86 <div key={recipe.id} className="welcome__featured-service">
89 key={recipe.id} 87 <img key={recipe.id} src={recipe.icons.svg} alt="" />
90 className="welcome__featured-service"
91 >
92 <img
93 key={recipe.id}
94 src={recipe.icons.svg}
95 alt=""
96 />
97 </div> 88 </div>
98 ))} 89 ))}
99 </div> 90 </div>
@@ -101,3 +92,5 @@ export default @inject('actions') @observer class Login extends Component {
101 ); 92 );
102 } 93 }
103} 94}
95
96export default injectIntl(Login);
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index e6e5d40fe..0a65dcffa 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -1,8 +1,8 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { TitleBar } from 'electron-react-titlebar'; 5import { TitleBar } from 'electron-react-titlebar/renderer';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7 7
8import InfoBar from '../ui/InfoBar'; 8import InfoBar from '../ui/InfoBar';
@@ -27,20 +27,20 @@ function createMarkup(HTMLString) {
27const messages = defineMessages({ 27const messages = defineMessages({
28 servicesUpdated: { 28 servicesUpdated: {
29 id: 'infobar.servicesUpdated', 29 id: 'infobar.servicesUpdated',
30 defaultMessage: '!!!Your services have been updated.', 30 defaultMessage: 'Your services have been updated.',
31 }, 31 },
32 buttonReloadServices: { 32 buttonReloadServices: {
33 id: 'infobar.buttonReloadServices', 33 id: 'infobar.buttonReloadServices',
34 defaultMessage: '!!!Reload services', 34 defaultMessage: 'Reload services',
35 }, 35 },
36 requiredRequestsFailed: { 36 requiredRequestsFailed: {
37 id: 'infobar.requiredRequestsFailed', 37 id: 'infobar.requiredRequestsFailed',
38 defaultMessage: '!!!Could not load services and user information', 38 defaultMessage: 'Could not load services and user information',
39 }, 39 },
40 authRequestFailed: { 40 authRequestFailed: {
41 id: 'infobar.authRequestFailed', 41 id: 'infobar.authRequestFailed',
42 defaultMessage: 42 defaultMessage:
43 '!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.', 43 'There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.',
44 }, 44 },
45}); 45});
46 46
@@ -88,16 +88,13 @@ class AppLayout extends Component {
88 88
89 state = { 89 state = {
90 shouldShowAppUpdateInfoBar: true, 90 shouldShowAppUpdateInfoBar: true,
91 shouldShowServicesUpdatedInfoBar: true,
91 }; 92 };
92 93
93 static defaultProps = { 94 static defaultProps = {
94 children: [], 95 children: [],
95 }; 96 };
96 97
97 static contextTypes = {
98 intl: intlShape,
99 };
100
101 render() { 98 render() {
102 const { 99 const {
103 classes, 100 classes,
@@ -119,7 +116,7 @@ class AppLayout extends Component {
119 areRequiredRequestsLoading, 116 areRequiredRequestsLoading,
120 } = this.props; 117 } = this.props;
121 118
122 const { intl } = this.context; 119 const { intl } = this.props;
123 120
124 return ( 121 return (
125 <ErrorBoundary> 122 <ErrorBoundary>
@@ -179,12 +176,14 @@ class AppLayout extends Component {
179 {intl.formatMessage(messages.authRequestFailed)} 176 {intl.formatMessage(messages.authRequestFailed)}
180 </InfoBar> 177 </InfoBar>
181 )} 178 )}
182 {showServicesUpdatedInfoBar && ( 179 {showServicesUpdatedInfoBar && this.state.shouldShowServicesUpdatedInfoBar && (
183 <InfoBar 180 <InfoBar
184 type="primary" 181 type="primary"
185 ctaLabel={intl.formatMessage(messages.buttonReloadServices)} 182 ctaLabel={intl.formatMessage(messages.buttonReloadServices)}
186 onClick={reloadServicesAfterUpdate} 183 onClick={reloadServicesAfterUpdate}
187 sticky 184 onHide={() => {
185 this.setState({ shouldShowServicesUpdatedInfoBar: false });
186 }}
188 > 187 >
189 <span className="mdi mdi-power-plug" /> 188 <span className="mdi mdi-power-plug" />
190 {intl.formatMessage(messages.servicesUpdated)} 189 {intl.formatMessage(messages.servicesUpdated)}
@@ -213,4 +212,4 @@ class AppLayout extends Component {
213 } 212 }
214} 213}
215 214
216export default AppLayout; 215export default injectIntl(AppLayout);
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js
index 1ee7733b9..87233f7ca 100644
--- a/src/components/layout/Sidebar.js
+++ b/src/components/layout/Sidebar.js
@@ -1,12 +1,19 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import ReactTooltip from 'react-tooltip'; 3import ReactTooltip from 'react-tooltip';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { inject, observer } from 'mobx-react'; 5import { inject, observer } from 'mobx-react';
6import { Link } from 'react-router'; 6import { Link } from 'react-router';
7 7
8import Tabbar from '../services/tabs/Tabbar'; 8import Tabbar from '../services/tabs/Tabbar';
9import { settingsShortcutKey, lockFerdiShortcutKey, todosToggleShortcutKey, workspaceToggleShortcutKey, addNewServiceShortcutKey, muteFerdiShortcutKey } from '../../environment'; 9import {
10 settingsShortcutKey,
11 lockFerdiShortcutKey,
12 todosToggleShortcutKey,
13 workspaceToggleShortcutKey,
14 addNewServiceShortcutKey,
15 muteFerdiShortcutKey,
16} from '../../environment';
10import { workspaceStore } from '../../features/workspaces'; 17import { workspaceStore } from '../../features/workspaces';
11import { todosStore } from '../../features/todos'; 18import { todosStore } from '../../features/todos';
12import { todoActions } from '../../features/todos/actions'; 19import { todoActions } from '../../features/todos/actions';
@@ -17,39 +24,41 @@ import globalMessages from '../../i18n/globalMessages';
17const messages = defineMessages({ 24const messages = defineMessages({
18 addNewService: { 25 addNewService: {
19 id: 'sidebar.addNewService', 26 id: 'sidebar.addNewService',
20 defaultMessage: '!!!Add new service', 27 defaultMessage: 'Add new service',
21 }, 28 },
22 mute: { 29 mute: {
23 id: 'sidebar.muteApp', 30 id: 'sidebar.muteApp',
24 defaultMessage: '!!!Disable notifications & audio', 31 defaultMessage: 'Disable notifications & audio',
25 }, 32 },
26 unmute: { 33 unmute: {
27 id: 'sidebar.unmuteApp', 34 id: 'sidebar.unmuteApp',
28 defaultMessage: '!!!Enable notifications & audio', 35 defaultMessage: 'Enable notifications & audio',
29 }, 36 },
30 openWorkspaceDrawer: { 37 openWorkspaceDrawer: {
31 id: 'sidebar.openWorkspaceDrawer', 38 id: 'sidebar.openWorkspaceDrawer',
32 defaultMessage: '!!!Open workspace drawer', 39 defaultMessage: 'Open workspace drawer',
33 }, 40 },
34 closeWorkspaceDrawer: { 41 closeWorkspaceDrawer: {
35 id: 'sidebar.closeWorkspaceDrawer', 42 id: 'sidebar.closeWorkspaceDrawer',
36 defaultMessage: '!!!Close workspace drawer', 43 defaultMessage: 'Close workspace drawer',
37 }, 44 },
38 openTodosDrawer: { 45 openTodosDrawer: {
39 id: 'sidebar.openTodosDrawer', 46 id: 'sidebar.openTodosDrawer',
40 defaultMessage: '!!!Open Ferdi Todos', 47 defaultMessage: 'Open Ferdi Todos',
41 }, 48 },
42 closeTodosDrawer: { 49 closeTodosDrawer: {
43 id: 'sidebar.closeTodosDrawer', 50 id: 'sidebar.closeTodosDrawer',
44 defaultMessage: '!!!Close Ferdi Todos', 51 defaultMessage: 'Close Ferdi Todos',
45 }, 52 },
46 lockFerdi: { 53 lockFerdi: {
47 id: 'sidebar.lockFerdi', 54 id: 'sidebar.lockFerdi',
48 defaultMessage: '!!!Lock Ferdi', 55 defaultMessage: 'Lock Ferdi',
49 }, 56 },
50}); 57});
51 58
52export default @inject('stores', 'actions') @observer class Sidebar extends Component { 59@inject('stores', 'actions')
60@observer
61class Sidebar extends Component {
53 static propTypes = { 62 static propTypes = {
54 openSettings: PropTypes.func.isRequired, 63 openSettings: PropTypes.func.isRequired,
55 closeSettings: PropTypes.func.isRequired, 64 closeSettings: PropTypes.func.isRequired,
@@ -79,10 +88,6 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
79 }).isRequired, 88 }).isRequired,
80 }; 89 };
81 90
82 static contextTypes = {
83 intl: intlShape,
84 };
85
86 state = { 91 state = {
87 tooltipEnabled: true, 92 tooltipEnabled: true,
88 }; 93 };
@@ -115,14 +120,14 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
115 actions, 120 actions,
116 isTodosServiceActive, 121 isTodosServiceActive,
117 } = this.props; 122 } = this.props;
118 const { intl } = this.context; 123 const { intl } = this.props;
119 const todosToggleMessage = ( 124 const todosToggleMessage = todosStore.isTodosPanelVisible
120 todosStore.isTodosPanelVisible ? messages.closeTodosDrawer : messages.openTodosDrawer 125 ? messages.closeTodosDrawer
121 ); 126 : messages.openTodosDrawer;
122 127
123 const workspaceToggleMessage = ( 128 const workspaceToggleMessage = isWorkspaceDrawerOpen
124 isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer 129 ? messages.closeWorkspaceDrawer
125 ); 130 : messages.openWorkspaceDrawer;
126 const isLoggedIn = Boolean(localStorage.getItem('authToken')); 131 const isLoggedIn = Boolean(localStorage.getItem('authToken'));
127 132
128 return ( 133 return (
@@ -133,9 +138,9 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
133 disableToolTip={() => this.disableToolTip()} 138 disableToolTip={() => this.disableToolTip()}
134 useVerticalStyle={stores.settings.all.app.useVerticalStyle} 139 useVerticalStyle={stores.settings.all.app.useVerticalStyle}
135 /> 140 />
136 { isLoggedIn ? ( 141 {isLoggedIn ? (
137 <> 142 <>
138 { stores.settings.all.app.lockingFeatureEnabled ? ( 143 {stores.settings.all.app.lockingFeatureEnabled ? (
139 <button 144 <button
140 type="button" 145 type="button"
141 className="sidebar__button" 146 className="sidebar__button"
@@ -147,12 +152,15 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
147 }, 152 },
148 }); 153 });
149 }} 154 }}
150 data-tip={`${intl.formatMessage(messages.lockFerdi)} (${lockFerdiShortcutKey(false)})`} 155 data-tip={`${intl.formatMessage(
156 messages.lockFerdi,
157 )} (${lockFerdiShortcutKey(false)})`}
151 > 158 >
152 <i className="mdi mdi-lock" /> 159 <i className="mdi mdi-lock" />
153 </button> 160 </button>
154 ) : null} 161 ) : null}
155 {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? ( 162 {todosStore.isFeatureEnabled &&
163 todosStore.isFeatureEnabledByUser ? (
156 <button 164 <button
157 type="button" 165 type="button"
158 onClick={() => { 166 onClick={() => {
@@ -160,12 +168,16 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
160 this.updateToolTip(); 168 this.updateToolTip();
161 }} 169 }}
162 disabled={isTodosServiceActive} 170 disabled={isTodosServiceActive}
163 className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`} 171 className={`sidebar__button sidebar__button--todos ${
164 data-tip={`${intl.formatMessage(todosToggleMessage)} (${todosToggleShortcutKey(false)})`} 172 todosStore.isTodosPanelVisible ? 'is-active' : ''
173 }`}
174 data-tip={`${intl.formatMessage(
175 todosToggleMessage,
176 )} (${todosToggleShortcutKey(false)})`}
165 > 177 >
166 <i className="mdi mdi-check-all" /> 178 <i className="mdi mdi-check-all" />
167 </button> 179 </button>
168 ) : null} 180 ) : null}
169 {workspaceStore.isFeatureEnabled ? ( 181 {workspaceStore.isFeatureEnabled ? (
170 <button 182 <button
171 type="button" 183 type="button"
@@ -173,8 +185,12 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
173 toggleWorkspaceDrawer(); 185 toggleWorkspaceDrawer();
174 this.updateToolTip(); 186 this.updateToolTip();
175 }} 187 }}
176 className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} 188 className={`sidebar__button sidebar__button--workspaces ${
177 data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${workspaceToggleShortcutKey(false)})`} 189 isWorkspaceDrawerOpen ? 'is-active' : ''
190 }`}
191 data-tip={`${intl.formatMessage(
192 workspaceToggleMessage,
193 )} (${workspaceToggleShortcutKey(false)})`}
178 > 194 >
179 <i className="mdi mdi-view-grid" /> 195 <i className="mdi mdi-view-grid" />
180 </button> 196 </button>
@@ -185,8 +201,12 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
185 toggleMuteApp(); 201 toggleMuteApp();
186 this.updateToolTip(); 202 this.updateToolTip();
187 }} 203 }}
188 className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} 204 className={`sidebar__button sidebar__button--audio ${
189 data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${muteFerdiShortcutKey(false)})`} 205 isAppMuted ? 'is-muted' : ''
206 }`}
207 data-tip={`${intl.formatMessage(
208 isAppMuted ? messages.unmute : messages.mute,
209 )} (${muteFerdiShortcutKey(false)})`}
190 > 210 >
191 <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} /> 211 <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} />
192 </button> 212 </button>
@@ -194,7 +214,9 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
194 type="button" 214 type="button"
195 onClick={() => openSettings({ path: 'recipes' })} 215 onClick={() => openSettings({ path: 'recipes' })}
196 className="sidebar__button sidebar__button--new-service" 216 className="sidebar__button sidebar__button--new-service"
197 data-tip={`${intl.formatMessage(messages.addNewService)} (${addNewServiceShortcutKey(false)})`} 217 data-tip={`${intl.formatMessage(
218 messages.addNewService,
219 )} (${addNewServiceShortcutKey(false)})`}
198 > 220 >
199 <i className="mdi mdi-plus-box" /> 221 <i className="mdi mdi-plus-box" />
200 </button> 222 </button>
@@ -212,15 +234,17 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
212 type="button" 234 type="button"
213 onClick={() => openSettings({ path: 'app' })} 235 onClick={() => openSettings({ path: 'app' })}
214 className="sidebar__button sidebar__button--settings" 236 className="sidebar__button sidebar__button--settings"
215 data-tip={`${intl.formatMessage(globalMessages.settings)} (${settingsShortcutKey(false)})`} 237 data-tip={`${intl.formatMessage(
238 globalMessages.settings,
239 )} (${settingsShortcutKey(false)})`}
216 > 240 >
217 <i className="mdi mdi-cog" /> 241 <i className="mdi mdi-cog" />
218 { (this.props.stores.app.updateStatus === this.props.stores.app.updateStatusTypes.AVAILABLE 242 {(this.props.stores.app.updateStatus ===
219 || this.props.stores.app.updateStatus === this.props.stores.app.updateStatusTypes.DOWNLOADED) && ( 243 this.props.stores.app.updateStatusTypes.AVAILABLE ||
220 <span className="update-available"> 244 this.props.stores.app.updateStatus ===
221 • 245 this.props.stores.app.updateStatusTypes.DOWNLOADED) && (
222 </span> 246 <span className="update-available">•</span>
223 ) } 247 )}
224 </button> 248 </button>
225 {this.state.tooltipEnabled && ( 249 {this.state.tooltipEnabled && (
226 <ReactTooltip place="right" type="dark" effect="solid" /> 250 <ReactTooltip place="right" type="dark" effect="solid" />
@@ -229,3 +253,5 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
229 ); 253 );
230 } 254 }
231} 255}
256
257export default injectIntl(Sidebar);
diff --git a/src/components/services/content/ConnectionLostBanner.js b/src/components/services/content/ConnectionLostBanner.js
index ebe863333..423edb3c7 100644
--- a/src/components/services/content/ConnectionLostBanner.js
+++ b/src/components/services/content/ConnectionLostBanner.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import { Icon } from '@meetfranz/ui'; 5import { Icon } from '@meetfranz/ui';
6import { intlShape, defineMessages } from 'react-intl'; 6import { defineMessages, injectIntl } from 'react-intl';
7 7
8import { mdiAlert } from '@mdi/js'; 8import { mdiAlert } from '@mdi/js';
9import { LIVE_API_FERDI_WEBSITE } from '../../../config'; 9import { LIVE_API_FERDI_WEBSITE } from '../../../config';
@@ -12,15 +12,15 @@ import { LIVE_API_FERDI_WEBSITE } from '../../../config';
12const messages = defineMessages({ 12const messages = defineMessages({
13 text: { 13 text: {
14 id: 'connectionLostBanner.message', 14 id: 'connectionLostBanner.message',
15 defaultMessage: '!!!Oh no! Ferdi lost the connection to {name}.', 15 defaultMessage: 'Oh no! Ferdi lost the connection to {name}.',
16 }, 16 },
17 moreInformation: { 17 moreInformation: {
18 id: 'connectionLostBanner.informationLink', 18 id: 'connectionLostBanner.informationLink',
19 defaultMessage: '!!!What happened?', 19 defaultMessage: 'What happened?',
20 }, 20 },
21 cta: { 21 cta: {
22 id: 'connectionLostBanner.cta', 22 id: 'connectionLostBanner.cta',
23 defaultMessage: '!!!Reload Service', 23 defaultMessage: 'Reload Service',
24 }, 24 },
25}); 25});
26 26
@@ -78,16 +78,12 @@ class ConnectionLostBanner extends Component {
78 reload: PropTypes.func.isRequired, 78 reload: PropTypes.func.isRequired,
79 }; 79 };
80 80
81 static contextTypes = {
82 intl: intlShape,
83 };
84
85 inputRef = React.createRef(); 81 inputRef = React.createRef();
86 82
87 render() { 83 render() {
88 const { classes, name, reload } = this.props; 84 const { classes, name, reload } = this.props;
89 85
90 const { intl } = this.context; 86 const { intl } = this.props;
91 87
92 return ( 88 return (
93 <div className={classes.root}> 89 <div className={classes.root}>
@@ -110,4 +106,4 @@ class ConnectionLostBanner extends Component {
110 } 106 }
111} 107}
112 108
113export default ConnectionLostBanner; 109export default injectIntl(ConnectionLostBanner);
diff --git a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
index 36e0ac418..b00db8c3f 100644
--- a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
+++ b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6 6
7import Button from '../../../ui/Button'; 7import Button from '../../../ui/Button';
@@ -11,27 +11,29 @@ import styles from './styles';
11const messages = defineMessages({ 11const messages = defineMessages({
12 headline: { 12 headline: {
13 id: 'service.errorHandler.headline', 13 id: 'service.errorHandler.headline',
14 defaultMessage: '!!!Oh no!', 14 defaultMessage: 'Oh no!',
15 }, 15 },
16 text: { 16 text: {
17 id: 'service.errorHandler.text', 17 id: 'service.errorHandler.text',
18 defaultMessage: '!!!{name} has failed to load.', 18 defaultMessage: '{name} has failed to load.',
19 }, 19 },
20 action: { 20 action: {
21 id: 'service.errorHandler.action', 21 id: 'service.errorHandler.action',
22 defaultMessage: '!!!Reload {name}', 22 defaultMessage: 'Reload {name}',
23 }, 23 },
24 editAction: { 24 editAction: {
25 id: 'service.errorHandler.editAction', 25 id: 'service.errorHandler.editAction',
26 defaultMessage: '!!!Edit {name}', 26 defaultMessage: 'Edit {name}',
27 }, 27 },
28 errorMessage: { 28 errorMessage: {
29 id: 'service.errorHandler.message', 29 id: 'service.errorHandler.message',
30 defaultMessage: '!!!Error:', 30 defaultMessage: 'Error',
31 }, 31 },
32}); 32});
33 33
34export default @injectSheet(styles) @observer class WebviewErrorHandler extends Component { 34@injectSheet(styles)
35@observer
36class WebviewErrorHandler extends Component {
35 static propTypes = { 37 static propTypes = {
36 name: PropTypes.string.isRequired, 38 name: PropTypes.string.isRequired,
37 reload: PropTypes.func.isRequired, 39 reload: PropTypes.func.isRequired,
@@ -40,30 +42,16 @@ export default @injectSheet(styles) @observer class WebviewErrorHandler extends
40 classes: PropTypes.object.isRequired, 42 classes: PropTypes.object.isRequired,
41 }; 43 };
42 44
43 static contextTypes = {
44 intl: intlShape,
45 };
46
47 render() { 45 render() {
48 const { 46 const { name, reload, edit, errorMessage, classes } = this.props;
49 name, 47 const { intl } = this.props;
50 reload,
51 edit,
52 errorMessage,
53 classes,
54 } = this.props;
55 const { intl } = this.context;
56 48
57 return ( 49 return (
58 <div className={classes.component}> 50 <div className={classes.component}>
59 <h1>{intl.formatMessage(messages.headline)}</h1> 51 <h1>{intl.formatMessage(messages.headline)}</h1>
60 <p>{intl.formatMessage(messages.text, { name })}</p> 52 <p>{intl.formatMessage(messages.text, { name })}</p>
61 <p> 53 <p>
62 <strong> 54 <strong>{intl.formatMessage(messages.errorMessage)}:</strong>{' '}
63 {intl.formatMessage(messages.errorMessage)}
64 :
65 </strong>
66 {' '}
67 {errorMessage} 55 {errorMessage}
68 </p> 56 </p>
69 <div className={classes.buttonContainer}> 57 <div className={classes.buttonContainer}>
@@ -82,3 +70,5 @@ export default @injectSheet(styles) @observer class WebviewErrorHandler extends
82 ); 70 );
83 } 71 }
84} 72}
73
74export default injectIntl(WebviewErrorHandler);
diff --git a/src/components/services/content/ServiceDisabled.js b/src/components/services/content/ServiceDisabled.js
index d0f12256e..e59ed58bd 100644
--- a/src/components/services/content/ServiceDisabled.js
+++ b/src/components/services/content/ServiceDisabled.js
@@ -1,38 +1,35 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import Button from '../../ui/Button'; 6import Button from '../../ui/Button';
7 7
8const messages = defineMessages({ 8const messages = defineMessages({
9 headline: { 9 headline: {
10 id: 'service.disabledHandler.headline', 10 id: 'service.disabledHandler.headline',
11 defaultMessage: '!!!{name} is disabled', 11 defaultMessage: '{name} is disabled',
12 }, 12 },
13 action: { 13 action: {
14 id: 'service.disabledHandler.action', 14 id: 'service.disabledHandler.action',
15 defaultMessage: '!!!Enable {name}', 15 defaultMessage: 'Enable {name}',
16 }, 16 },
17}); 17});
18 18
19export default @observer class ServiceDisabled extends Component { 19@observer
20class ServiceDisabled extends Component {
20 static propTypes = { 21 static propTypes = {
21 name: PropTypes.string.isRequired, 22 name: PropTypes.string.isRequired,
22 enable: PropTypes.func.isRequired, 23 enable: PropTypes.func.isRequired,
23 }; 24 };
24 25
25 static contextTypes = {
26 intl: intlShape,
27 };
28
29 countdownInterval = null; 26 countdownInterval = null;
30 27
31 countdownIntervalTimeout = 1000; 28 countdownIntervalTimeout = 1000;
32 29
33 render() { 30 render() {
34 const { name, enable } = this.props; 31 const { name, enable } = this.props;
35 const { intl } = this.context; 32 const { intl } = this.props;
36 33
37 return ( 34 return (
38 <div className="services__info-layer"> 35 <div className="services__info-layer">
@@ -46,3 +43,5 @@ export default @observer class ServiceDisabled extends Component {
46 ); 43 );
47 } 44 }
48} 45}
46
47export default injectIntl(ServiceDisabled);
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js
index 3fc084ff0..81401b1d2 100644
--- a/src/components/services/content/ServiceView.js
+++ b/src/components/services/content/ServiceView.js
@@ -15,7 +15,9 @@ import SettingsStore from '../../../stores/SettingsStore';
15import WebControlsScreen from '../../../features/webControls/containers/WebControlsScreen'; 15import WebControlsScreen from '../../../features/webControls/containers/WebControlsScreen';
16import { CUSTOM_WEBSITE_RECIPE_ID } from '../../../config'; 16import { CUSTOM_WEBSITE_RECIPE_ID } from '../../../config';
17 17
18export default @inject('stores', 'actions') @observer class ServiceView extends Component { 18@inject('stores', 'actions')
19@observer
20class ServiceView extends Component {
19 static propTypes = { 21 static propTypes = {
20 service: PropTypes.instanceOf(ServiceModel).isRequired, 22 service: PropTypes.instanceOf(ServiceModel).isRequired,
21 setWebviewReference: PropTypes.func.isRequired, 23 setWebviewReference: PropTypes.func.isRequired,
@@ -63,7 +65,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
63 clearTimeout(this.hibernationTimer); 65 clearTimeout(this.hibernationTimer);
64 } 66 }
65 67
66 updateTargetUrl = (event) => { 68 updateTargetUrl = event => {
67 let visible = true; 69 let visible = true;
68 if (event.url === '' || event.url === '#') { 70 if (event.url === '' || event.url === '#') {
69 visible = false; 71 visible = false;
@@ -86,11 +88,12 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
86 isSpellcheckerEnabled, 88 isSpellcheckerEnabled,
87 } = this.props; 89 } = this.props;
88 90
89 const { 91 const { navigationBarBehaviour } = stores.settings.app;
90 navigationBarBehaviour,
91 } = stores.settings.app;
92 92
93 const showNavBar = navigationBarBehaviour === 'always' || (navigationBarBehaviour === 'custom' && service.recipe.id === CUSTOM_WEBSITE_RECIPE_ID); 93 const showNavBar =
94 navigationBarBehaviour === 'always' ||
95 (navigationBarBehaviour === 'custom' &&
96 service.recipe.id === CUSTOM_WEBSITE_RECIPE_ID);
94 97
95 const webviewClasses = classnames({ 98 const webviewClasses = classnames({
96 services__webview: true, 99 services__webview: true,
@@ -101,13 +104,11 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
101 104
102 let statusBar = null; 105 let statusBar = null;
103 if (this.state.statusBarVisible) { 106 if (this.state.statusBarVisible) {
104 statusBar = ( 107 statusBar = <StatusBarTargetUrl text={this.state.targetUrl} />;
105 <StatusBarTargetUrl text={this.state.targetUrl} />
106 );
107 } 108 }
108 109
109 return ( 110 return (
110 <div className={webviewClasses}> 111 <div className={webviewClasses} data-name={service.name}>
111 {service.isActive && service.isEnabled && ( 112 {service.isActive && service.isEnabled && (
112 <> 113 <>
113 {service.hasCrashed && ( 114 {service.hasCrashed && (
@@ -117,11 +118,11 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
117 reload={reload} 118 reload={reload}
118 /> 119 />
119 )} 120 )}
120 {service.isEnabled && service.isLoading && service.isFirstLoad && !service.isServiceAccessRestricted && ( 121 {service.isEnabled &&
121 <WebviewLoader 122 service.isLoading &&
122 loaded={false} 123 service.isFirstLoad &&
123 name={service.name} 124 !service.isServiceAccessRestricted && (
124 /> 125 <WebviewLoader loaded={false} name={service.name} />
125 )} 126 )}
126 {service.isError && ( 127 {service.isError && (
127 <WebviewErrorHandler 128 <WebviewErrorHandler
@@ -147,9 +148,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
147 <> 148 <>
148 {!service.isHibernating ? ( 149 {!service.isHibernating ? (
149 <> 150 <>
150 {showNavBar && ( 151 {showNavBar && <WebControlsScreen service={service} />}
151 <WebControlsScreen service={service} />
152 )}
153 <ServiceWebview 152 <ServiceWebview
154 service={service} 153 service={service}
155 setWebviewReference={setWebviewReference} 154 setWebviewReference={setWebviewReference}
@@ -159,9 +158,11 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
159 </> 158 </>
160 ) : ( 159 ) : (
161 <div> 160 <div>
162 <span role="img" aria-label="Sleeping Emoji">😴</span> 161 <span role="img" aria-label="Sleeping Emoji">
163 {' '} 162 😴
164 This service is currently hibernating. If this page doesn&#x27;t close soon, please try reloading Ferdi. 163 </span>{' '}
164 This service is currently hibernating. If this page doesn&#x27;t
165 close soon, please try reloading Ferdi.
165 </div> 166 </div>
166 )} 167 )}
167 </> 168 </>
@@ -171,3 +172,5 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
171 ); 172 );
172 } 173 }
173} 174}
175
176export default ServiceView;
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js
index c0f48793a..d3170be53 100644
--- a/src/components/services/content/ServiceWebview.js
+++ b/src/components/services/content/ServiceWebview.js
@@ -85,7 +85,8 @@ class ServiceWebview extends Component {
85 useragent={service.userAgent} 85 useragent={service.userAgent}
86 disablewebsecurity={service.recipe.disablewebsecurity ? true : undefined} 86 disablewebsecurity={service.recipe.disablewebsecurity ? true : undefined}
87 allowpopups 87 allowpopups
88 webpreferences={`spellcheck=${isSpellcheckerEnabled ? 1 : 0}`} 88 nodeintegration
89 webpreferences={`spellcheck=${isSpellcheckerEnabled ? 1 : 0}, contextIsolation=1, enableRemoteModule=1`}
89 /> 90 />
90 ); 91 );
91 } 92 }
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js
index bb93ff7d4..fb43fb816 100644
--- a/src/components/services/content/Services.js
+++ b/src/components/services/content/Services.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
4import { Link } from 'react-router'; 4import { Link } from 'react-router';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import Confetti from 'react-confetti'; 6import Confetti from 'react-confetti';
7import ms from 'ms'; 7import ms from 'ms';
8import injectSheet from 'react-jss'; 8import injectSheet from 'react-jss';
@@ -14,23 +14,24 @@ import serverlessLogin from '../../../helpers/serverless-helpers';
14const messages = defineMessages({ 14const messages = defineMessages({
15 welcome: { 15 welcome: {
16 id: 'services.welcome', 16 id: 'services.welcome',
17 defaultMessage: '!!!Welcome to Ferdi', 17 defaultMessage: 'Welcome to Ferdi',
18 }, 18 },
19 getStarted: { 19 getStarted: {
20 id: 'services.getStarted', 20 id: 'services.getStarted',
21 defaultMessage: '!!!Get started', 21 defaultMessage: 'Get started',
22 }, 22 },
23 login: { 23 login: {
24 id: 'services.login', 24 id: 'services.login',
25 defaultMessage: '!!!Please login to use Ferdi.', 25 defaultMessage: 'Please login to use Ferdi.',
26 }, 26 },
27 serverless: { 27 serverless: {
28 id: 'services.serverless', 28 id: 'services.serverless',
29 defaultMessage: '!!!Use Ferdi without an Account', 29 defaultMessage: 'Use Ferdi without an Account',
30 }, 30 },
31 serverInfo: { 31 serverInfo: {
32 id: 'services.serverInfo', 32 id: 'services.serverInfo',
33 defaultMessage: '!!!Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!', 33 defaultMessage:
34 'Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!',
34 }, 35 },
35}); 36});
36 37
@@ -43,7 +44,10 @@ const styles = {
43 }, 44 },
44}; 45};
45 46
46export default @injectSheet(styles) @inject('actions') @observer class Services extends Component { 47@injectSheet(styles)
48@inject('actions')
49@observer
50class Services extends Component {
47 static propTypes = { 51 static propTypes = {
48 services: MobxPropTypes.arrayOrObservableArray, 52 services: MobxPropTypes.arrayOrObservableArray,
49 setWebviewReference: PropTypes.func.isRequired, 53 setWebviewReference: PropTypes.func.isRequired,
@@ -63,10 +67,6 @@ export default @injectSheet(styles) @inject('actions') @observer class Services
63 services: [], 67 services: [],
64 }; 68 };
65 69
66 static contextTypes = {
67 intl: intlShape,
68 };
69
70 state = { 70 state = {
71 showConfetti: true, 71 showConfetti: true,
72 }; 72 };
@@ -112,11 +112,9 @@ export default @injectSheet(styles) @inject('actions') @observer class Services
112 isSpellcheckerEnabled, 112 isSpellcheckerEnabled,
113 } = this.props; 113 } = this.props;
114 114
115 const { 115 const { showConfetti } = this.state;
116 showConfetti,
117 } = this.state;
118 116
119 const { intl } = this.context; 117 const { intl } = this.props;
120 const isLoggedIn = Boolean(localStorage.getItem('authToken')); 118 const isLoggedIn = Boolean(localStorage.getItem('authToken'));
121 119
122 return ( 120 return (
@@ -131,25 +129,28 @@ export default @injectSheet(styles) @inject('actions') @observer class Services
131 </div> 129 </div>
132 )} 130 )}
133 {services.length === 0 && ( 131 {services.length === 0 && (
134 <Appear 132 <Appear timeout={1500} transitionName="slideUp">
135 timeout={1500}
136 transitionName="slideUp"
137 >
138 <div className="services__no-service"> 133 <div className="services__no-service">
139 <img src="./assets/images/logo.svg" alt="Logo" style={{ maxHeight: '50vh' }} /> 134 <img
135 src="./assets/images/logo.svg"
136 alt="Logo"
137 style={{ maxHeight: '50vh' }}
138 />
140 <h1>{intl.formatMessage(messages.welcome)}</h1> 139 <h1>{intl.formatMessage(messages.welcome)}</h1>
141 { !isLoggedIn && ( 140 {!isLoggedIn && (
142 <> 141 <>
143 <p>{intl.formatMessage(messages.login)}</p> 142 <p>{intl.formatMessage(messages.login)}</p>
144 <p>{intl.formatMessage(messages.serverInfo)}</p> 143 <p>{intl.formatMessage(messages.serverInfo)}</p>
145 </> 144 </>
146 ) } 145 )}
147 <Appear 146 <Appear timeout={300} transitionName="slideUp">
148 timeout={300} 147 <Link
149 transitionName="slideUp" 148 to={isLoggedIn ? '/settings/recipes' : '/auth/welcome'}
150 > 149 className="button"
151 <Link to={isLoggedIn ? '/settings/recipes' : '/auth/welcome'} className="button"> 150 >
152 { isLoggedIn ? intl.formatMessage(messages.getStarted) : 'Login' } 151 {isLoggedIn
152 ? intl.formatMessage(messages.getStarted)
153 : 'Login'}
153 </Link> 154 </Link>
154 {!isLoggedIn && ( 155 {!isLoggedIn && (
155 <button 156 <button
@@ -167,27 +168,33 @@ export default @injectSheet(styles) @inject('actions') @observer class Services
167 </div> 168 </div>
168 </Appear> 169 </Appear>
169 )} 170 )}
170 {services.filter((service) => !service.isTodosService).map((service) => ( 171 {services
171 <ServiceView 172 .filter(service => !service.isTodosService)
172 key={service.id} 173 .map(service => (
173 service={service} 174 <ServiceView
174 handleIPCMessage={handleIPCMessage} 175 key={service.id}
175 setWebviewReference={setWebviewReference} 176 service={service}
176 detachService={detachService} 177 handleIPCMessage={handleIPCMessage}
177 openWindow={openWindow} 178 setWebviewReference={setWebviewReference}
178 reload={() => reload({ serviceId: service.id })} 179 detachService={detachService}
179 edit={() => openSettings({ path: `services/edit/${service.id}` })} 180 openWindow={openWindow}
180 enable={() => update({ 181 reload={() => reload({ serviceId: service.id })}
181 serviceId: service.id, 182 edit={() => openSettings({ path: `services/edit/${service.id}` })}
182 serviceData: { 183 enable={() =>
183 isEnabled: true, 184 update({
184 }, 185 serviceId: service.id,
185 redirect: false, 186 serviceData: {
186 })} 187 isEnabled: true,
187 isSpellcheckerEnabled={isSpellcheckerEnabled} 188 },
188 /> 189 redirect: false,
189 ))} 190 })
191 }
192 isSpellcheckerEnabled={isSpellcheckerEnabled}
193 />
194 ))}
190 </div> 195 </div>
191 ); 196 );
192 } 197 }
193} 198}
199
200export default injectIntl(Services);
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js
index 10ff0bbbb..a332602be 100644
--- a/src/components/services/content/WebviewCrashHandler.js
+++ b/src/components/services/content/WebviewCrashHandler.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import ms from 'ms'; 5import ms from 'ms';
6 6
7import Button from '../../ui/Button'; 7import Button from '../../ui/Button';
@@ -9,35 +9,33 @@ import Button from '../../ui/Button';
9const messages = defineMessages({ 9const messages = defineMessages({
10 headline: { 10 headline: {
11 id: 'service.crashHandler.headline', 11 id: 'service.crashHandler.headline',
12 defaultMessage: '!!!Oh no!', 12 defaultMessage: 'Oh no!',
13 }, 13 },
14 text: { 14 text: {
15 id: 'service.crashHandler.text', 15 id: 'service.crashHandler.text',
16 defaultMessage: '!!!{name} has caused an error.', 16 defaultMessage: '{name} has caused an error.',
17 }, 17 },
18 action: { 18 action: {
19 id: 'service.crashHandler.action', 19 id: 'service.crashHandler.action',
20 defaultMessage: '!!!Reload {name}', 20 defaultMessage: 'Reload {name}',
21 }, 21 },
22 autoReload: { 22 autoReload: {
23 id: 'service.crashHandler.autoReload', 23 id: 'service.crashHandler.autoReload',
24 defaultMessage: '!!!Trying to automatically restore {name} in {seconds} seconds', 24 defaultMessage:
25 'Trying to automatically restore {name} in {seconds} seconds',
25 }, 26 },
26}); 27});
27 28
28export default @observer class WebviewCrashHandler extends Component { 29@observer
30class WebviewCrashHandler extends Component {
29 static propTypes = { 31 static propTypes = {
30 name: PropTypes.string.isRequired, 32 name: PropTypes.string.isRequired,
31 reload: PropTypes.func.isRequired, 33 reload: PropTypes.func.isRequired,
32 }; 34 };
33 35
34 static contextTypes = {
35 intl: intlShape,
36 };
37
38 state = { 36 state = {
39 countdown: ms('10s'), 37 countdown: ms('10s'),
40 } 38 };
41 39
42 countdownInterval = null; 40 countdownInterval = null;
43 41
@@ -47,7 +45,7 @@ export default @observer class WebviewCrashHandler extends Component {
47 const { reload } = this.props; 45 const { reload } = this.props;
48 46
49 this.countdownInterval = setInterval(() => { 47 this.countdownInterval = setInterval(() => {
50 this.setState((prevState) => ({ 48 this.setState(prevState => ({
51 countdown: prevState.countdown - this.countdownIntervalTimeout, 49 countdown: prevState.countdown - this.countdownIntervalTimeout,
52 })); 50 }));
53 51
@@ -60,7 +58,7 @@ export default @observer class WebviewCrashHandler extends Component {
60 58
61 render() { 59 render() {
62 const { name, reload } = this.props; 60 const { name, reload } = this.props;
63 const { intl } = this.context; 61 const { intl } = this.props;
64 62
65 return ( 63 return (
66 <div className="services__info-layer"> 64 <div className="services__info-layer">
@@ -82,3 +80,5 @@ export default @observer class WebviewCrashHandler extends Component {
82 ); 80 );
83 } 81 }
84} 82}
83
84export default injectIntl(WebviewCrashHandler);
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js
index e5892be5d..2474682df 100644
--- a/src/components/services/tabs/TabItem.js
+++ b/src/components/services/tabs/TabItem.js
@@ -1,6 +1,6 @@
1import { Menu, dialog, app, getCurrentWindow } from '@electron/remote'; 1import { Menu, dialog, app } from '@electron/remote';
2import React, { Component } from 'react'; 2import React, { Component } from 'react';
3import { defineMessages, intlShape } from 'react-intl'; 3import { defineMessages, injectIntl } from 'react-intl';
4import PropTypes from 'prop-types'; 4import PropTypes from 'prop-types';
5import { observer } from 'mobx-react'; 5import { observer } from 'mobx-react';
6import classnames from 'classnames'; 6import classnames from 'classnames';
@@ -20,56 +20,55 @@ const IS_SERVICE_DEBUGGING_ENABLED = (
20const messages = defineMessages({ 20const messages = defineMessages({
21 reload: { 21 reload: {
22 id: 'tabs.item.reload', 22 id: 'tabs.item.reload',
23 defaultMessage: '!!!Reload', 23 defaultMessage: 'Reload',
24 }, 24 },
25 disableNotifications: { 25 disableNotifications: {
26 id: 'tabs.item.disableNotifications', 26 id: 'tabs.item.disableNotifications',
27 defaultMessage: '!!!Disable notifications', 27 defaultMessage: 'Disable notifications',
28 }, 28 },
29 enableNotifications: { 29 enableNotifications: {
30 id: 'tabs.item.enableNotification', 30 id: 'tabs.item.enableNotification',
31 defaultMessage: '!!!Enable notifications', 31 defaultMessage: 'Enable notifications',
32 }, 32 },
33 disableAudio: { 33 disableAudio: {
34 id: 'tabs.item.disableAudio', 34 id: 'tabs.item.disableAudio',
35 defaultMessage: '!!!Disable audio', 35 defaultMessage: 'Disable audio',
36 }, 36 },
37 enableAudio: { 37 enableAudio: {
38 id: 'tabs.item.enableAudio', 38 id: 'tabs.item.enableAudio',
39 defaultMessage: '!!!Enable audio', 39 defaultMessage: 'Enable audio',
40 }, 40 },
41 enableDarkMode: { 41 enableDarkMode: {
42 id: 'tabs.item.enableDarkMode', 42 id: 'tabs.item.enableDarkMode',
43 defaultMessage: '!!!Enable Dark mode', 43 defaultMessage: 'Enable Dark mode',
44 }, 44 },
45 disableDarkMode: { 45 disableDarkMode: {
46 id: 'tabs.item.disableDarkMode', 46 id: 'tabs.item.disableDarkMode',
47 defaultMessage: '!!!Disable Dark mode', 47 defaultMessage: 'Disable Dark mode',
48 }, 48 },
49 disableService: { 49 disableService: {
50 id: 'tabs.item.disableService', 50 id: 'tabs.item.disableService',
51 defaultMessage: '!!!Disable Service', 51 defaultMessage: 'Disable service',
52 }, 52 },
53 enableService: { 53 enableService: {
54 id: 'tabs.item.enableService', 54 id: 'tabs.item.enableService',
55 defaultMessage: '!!!Enable Service', 55 defaultMessage: 'Enable service',
56 }, 56 },
57 hibernateService: { 57 hibernateService: {
58 id: 'tabs.item.hibernateService', 58 id: 'tabs.item.hibernateService',
59 defaultMessage: '!!!Hibernate Service', 59 defaultMessage: 'Hibernate service',
60 }, 60 },
61 wakeUpService: { 61 wakeUpService: {
62 id: 'tabs.item.wakeUpService', 62 id: 'tabs.item.wakeUpService',
63 defaultMessage: '!!!Wake Up Service', 63 defaultMessage: 'Wake up service',
64 }, 64 },
65 deleteService: { 65 deleteService: {
66 id: 'tabs.item.deleteService', 66 id: 'tabs.item.deleteService',
67 defaultMessage: '!!!Delete Service', 67 defaultMessage: 'Delete service',
68 }, 68 },
69 confirmDeleteService: { 69 confirmDeleteService: {
70 id: 'tabs.item.confirmDeleteService', 70 id: 'tabs.item.confirmDeleteService',
71 defaultMessage: 71 defaultMessage: 'Do you really want to delete the {serviceName} service?',
72 '!!!Do you really want to delete the {serviceName} service?',
73 }, 72 },
74}); 73});
75 74
@@ -134,14 +133,44 @@ class TabItem extends Component {
134 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, 133 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
135 }; 134 };
136 135
137 static contextTypes = {
138 intl: intlShape,
139 };
140
141 @observable isPolled = false; 136 @observable isPolled = false;
142 137
143 @observable isPollAnswered = false; 138 @observable isPollAnswered = false;
144 139
140 constructor(props) {
141 super(props);
142 this.state = {
143 showShortcutIndex: false,
144 };
145 }
146
147 handleShowShortcutIndex = () => {
148 this.setState({ showShortcutIndex: true });
149 };
150
151 checkForLongPress = () => {
152 let longpressDelay = null;
153 const longpressDelayDuration = 1000;
154
155 document.addEventListener(
156 'keydown',
157 e => {
158 if (e.ctrlKey || e.metaKey) {
159 longpressDelay = setTimeout(
160 this.handleShowShortcutIndex,
161 longpressDelayDuration,
162 );
163 }
164 },
165 { capture: true },
166 );
167
168 document.addEventListener('keyup', () => {
169 clearTimeout(longpressDelay);
170 this.setState({ showShortcutIndex: false });
171 });
172 };
173
145 componentDidMount() { 174 componentDidMount() {
146 const { service } = this.props; 175 const { service } = this.props;
147 176
@@ -164,6 +193,8 @@ class TabItem extends Component {
164 } 193 }
165 }); 194 });
166 } 195 }
196
197 this.checkForLongPress();
167 } 198 }
168 199
169 render() { 200 render() {
@@ -185,7 +216,7 @@ class TabItem extends Component {
185 showMessageBadgeWhenMutedSetting, 216 showMessageBadgeWhenMutedSetting,
186 showMessageBadgesEvenWhenMuted, 217 showMessageBadgesEvenWhenMuted,
187 } = this.props; 218 } = this.props;
188 const { intl } = this.context; 219 const { intl } = this.props;
189 220
190 const menuTemplate = [ 221 const menuTemplate = [
191 { 222 {
@@ -240,8 +271,9 @@ class TabItem extends Component {
240 ? messages.wakeUpService 271 ? messages.wakeUpService
241 : messages.hibernateService, 272 : messages.hibernateService,
242 ), 273 ),
274 // eslint-disable-next-line no-confusing-arrow
243 click: () => 275 click: () =>
244 (service.isHibernating ? wakeUpService() : hibernateService()), 276 service.isHibernating ? wakeUpService() : hibernateService(),
245 enabled: service.canHibernate, 277 enabled: service.canHibernate,
246 }, 278 },
247 { 279 {
@@ -256,7 +288,10 @@ class TabItem extends Component {
256 detail: intl.formatMessage(messages.confirmDeleteService, { 288 detail: intl.formatMessage(messages.confirmDeleteService, {
257 serviceName: service.name || service.recipe.name, 289 serviceName: service.name || service.recipe.name,
258 }), 290 }),
259 buttons: [intl.formatMessage(globalMessages.yes), intl.formatMessage(globalMessages.no)], 291 buttons: [
292 intl.formatMessage(globalMessages.yes),
293 intl.formatMessage(globalMessages.no),
294 ],
260 }); 295 });
261 if (selection === 0) { 296 if (selection === 0) {
262 deleteService(); 297 deleteService();
@@ -283,7 +318,7 @@ class TabItem extends Component {
283 service.unreadDirectMessageCount === 0 && 318 service.unreadDirectMessageCount === 0 &&
284 service.isIndirectMessageBadgeEnabled && ( 319 service.isIndirectMessageBadgeEnabled && (
285 <span className="tab-item__message-count is-indirect">•</span> 320 <span className="tab-item__message-count is-indirect">•</span>
286 )} 321 )}
287 {service.isHibernating && ( 322 {service.isHibernating && (
288 <span className="tab-item__message-count hibernating">•</span> 323 <span className="tab-item__message-count hibernating">•</span>
289 )} 324 )}
@@ -302,9 +337,11 @@ class TabItem extends Component {
302 'is-disabled': !service.isEnabled, 337 'is-disabled': !service.isEnabled,
303 })} 338 })}
304 onClick={clickHandler} 339 onClick={clickHandler}
305 onContextMenu={() => menu.popup(getCurrentWindow())} 340 onContextMenu={() => menu.popup()}
306 data-tip={`${service.name} ${ 341 data-tip={`${service.name} ${
307 shortcutIndex <= 9 ? `(${cmdOrCtrlShortcutKey(false)}+${shortcutIndex})` : '' 342 shortcutIndex <= 9
343 ? `(${cmdOrCtrlShortcutKey(false)}+${shortcutIndex})`
344 : ''
308 }`} 345 }`}
309 > 346 >
310 <img src={service.icon} className="tab-item__icon" alt="" /> 347 <img src={service.icon} className="tab-item__icon" alt="" />
@@ -327,9 +364,12 @@ class TabItem extends Component {
327 /> 364 />
328 </> 365 </>
329 )} 366 )}
367 {shortcutIndex && this.state.showShortcutIndex && (
368 <span className="tab-item__shortcut-index">{shortcutIndex}</span>
369 )}
330 </li> 370 </li>
331 ); 371 );
332 } 372 }
333} 373}
334 374
335export default SortableElement(TabItem); 375export default injectIntl(SortableElement(TabItem));
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js
index c1421a2b1..a77799819 100644
--- a/src/components/services/tabs/Tabbar.js
+++ b/src/components/services/tabs/Tabbar.js
@@ -4,7 +4,8 @@ import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4 4
5import TabBarSortableList from './TabBarSortableList'; 5import TabBarSortableList from './TabBarSortableList';
6 6
7export default @observer class TabBar extends Component { 7@observer
8class TabBar extends Component {
8 static propTypes = { 9 static propTypes = {
9 services: MobxPropTypes.arrayOrObservableArray.isRequired, 10 services: MobxPropTypes.arrayOrObservableArray.isRequired,
10 setActive: PropTypes.func.isRequired, 11 setActive: PropTypes.func.isRequired,
@@ -26,16 +27,13 @@ export default @observer class TabBar extends Component {
26 }; 27 };
27 28
28 onSortEnd = ({ oldIndex, newIndex }) => { 29 onSortEnd = ({ oldIndex, newIndex }) => {
29 const { 30 const { enableToolTip, reorder } = this.props;
30 enableToolTip,
31 reorder,
32 } = this.props;
33 31
34 enableToolTip(); 32 enableToolTip();
35 reorder({ oldIndex, newIndex }); 33 reorder({ oldIndex, newIndex });
36 }; 34 };
37 35
38 shouldPreventSorting = (event) => event.target.tagName !== 'LI'; 36 shouldPreventSorting = event => event.target.tagName !== 'LI';
39 37
40 toggleService = ({ serviceId, isEnabled }) => { 38 toggleService = ({ serviceId, isEnabled }) => {
41 const { updateService } = this.props; 39 const { updateService } = this.props;
@@ -102,10 +100,10 @@ export default @observer class TabBar extends Component {
102 toggleAudio={toggleAudio} 100 toggleAudio={toggleAudio}
103 toggleDarkMode={toggleDarkMode} 101 toggleDarkMode={toggleDarkMode}
104 deleteService={deleteService} 102 deleteService={deleteService}
105 disableService={(args) => this.disableService(args)} 103 disableService={args => this.disableService(args)}
106 enableService={(args) => this.enableService(args)} 104 enableService={args => this.enableService(args)}
107 hibernateService={(args) => this.hibernateService(args)} 105 hibernateService={args => this.hibernateService(args)}
108 wakeUpService={(args) => this.wakeUpService(args)} 106 wakeUpService={args => this.wakeUpService(args)}
109 openSettings={openSettings} 107 openSettings={openSettings}
110 distance={20} 108 distance={20}
111 axis={axis} 109 axis={axis}
@@ -118,3 +116,5 @@ export default @observer class TabBar extends Component {
118 ); 116 );
119 } 117 }
120} 118}
119
120export default TabBar;
diff --git a/src/components/settings/SettingsLayout.js b/src/components/settings/SettingsLayout.js
index 5b3b754fa..71250bd4d 100644
--- a/src/components/settings/SettingsLayout.js
+++ b/src/components/settings/SettingsLayout.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import ErrorBoundary from '../util/ErrorBoundary'; 6import ErrorBoundary from '../util/ErrorBoundary';
7import { oneOrManyChildElements } from '../../prop-types'; 7import { oneOrManyChildElements } from '../../prop-types';
@@ -10,11 +10,10 @@ import Appear from '../ui/effects/Appear';
10const messages = defineMessages({ 10const messages = defineMessages({
11 closeSettings: { 11 closeSettings: {
12 id: 'settings.app.closeSettings', 12 id: 'settings.app.closeSettings',
13 defaultMessage: '!!!Close settings', 13 defaultMessage: 'Close settings',
14 }, 14 },
15}); 15});
16 16
17export default
18@observer 17@observer
19class SettingsLayout extends Component { 18class SettingsLayout extends Component {
20 static propTypes = { 19 static propTypes = {
@@ -23,10 +22,6 @@ class SettingsLayout extends Component {
23 closeSettings: PropTypes.func.isRequired, 22 closeSettings: PropTypes.func.isRequired,
24 }; 23 };
25 24
26 static contextTypes = {
27 intl: intlShape,
28 };
29
30 componentDidMount() { 25 componentDidMount() {
31 document.addEventListener('keydown', this.handleKeyDown.bind(this), false); 26 document.addEventListener('keydown', this.handleKeyDown.bind(this), false);
32 } 27 }
@@ -34,6 +29,7 @@ class SettingsLayout extends Component {
34 componentWillUnmount() { 29 componentWillUnmount() {
35 document.removeEventListener( 30 document.removeEventListener(
36 'keydown', 31 'keydown',
32 // eslint-disable-next-line unicorn/no-invalid-remove-event-listener
37 this.handleKeyDown.bind(this), 33 this.handleKeyDown.bind(this),
38 false, 34 false,
39 ); 35 );
@@ -49,7 +45,7 @@ class SettingsLayout extends Component {
49 render() { 45 render() {
50 const { navigation, children, closeSettings } = this.props; 46 const { navigation, children, closeSettings } = this.props;
51 47
52 const { intl } = this.context; 48 const { intl } = this.props;
53 49
54 return ( 50 return (
55 <Appear transitionName="fadeIn-fast"> 51 <Appear transitionName="fadeIn-fast">
@@ -77,3 +73,5 @@ class SettingsLayout extends Component {
77 ); 73 );
78 } 74 }
79} 75}
76
77export default injectIntl(SettingsLayout);
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index ef7748343..544821e9a 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import ReactTooltip from 'react-tooltip'; 5import ReactTooltip from 'react-tooltip';
6import { H1, H2 } from '@meetfranz/ui'; 6import { H1, H2 } from '@meetfranz/ui';
7 7
@@ -13,45 +13,45 @@ import { LOCAL_SERVER, LIVE_FRANZ_API } from '../../../config';
13const messages = defineMessages({ 13const messages = defineMessages({
14 headline: { 14 headline: {
15 id: 'settings.account.headline', 15 id: 'settings.account.headline',
16 defaultMessage: '!!!Account', 16 defaultMessage: 'Account',
17 }, 17 },
18 headlineDangerZone: { 18 headlineDangerZone: {
19 id: 'settings.account.headlineDangerZone', 19 id: 'settings.account.headlineDangerZone',
20 defaultMessage: '!!Danger Zone', 20 defaultMessage: 'Danger Zone',
21 }, 21 },
22 accountEditButton: { 22 accountEditButton: {
23 id: 'settings.account.account.editButton', 23 id: 'settings.account.account.editButton',
24 defaultMessage: '!!!Edit Account', 24 defaultMessage: 'Edit account',
25 }, 25 },
26 invoicesButton: { 26 invoicesButton: {
27 id: 'settings.account.headlineInvoices', 27 id: 'settings.account.headlineInvoices',
28 defaultMessage: '!!Invoices', 28 defaultMessage: 'Invoices',
29 }, 29 },
30 userInfoRequestFailed: { 30 userInfoRequestFailed: {
31 id: 'settings.account.userInfoRequestFailed', 31 id: 'settings.account.userInfoRequestFailed',
32 defaultMessage: '!!!Could not load user information', 32 defaultMessage: 'Could not load user information',
33 }, 33 },
34 tryReloadUserInfoRequest: { 34 tryReloadUserInfoRequest: {
35 id: 'settings.account.tryReloadUserInfoRequest', 35 id: 'settings.account.tryReloadUserInfoRequest',
36 defaultMessage: '!!!Try again', 36 defaultMessage: 'Try again',
37 }, 37 },
38 deleteAccount: { 38 deleteAccount: {
39 id: 'settings.account.deleteAccount', 39 id: 'settings.account.deleteAccount',
40 defaultMessage: '!!!Delete account', 40 defaultMessage: 'Delete account',
41 }, 41 },
42 deleteInfo: { 42 deleteInfo: {
43 id: 'settings.account.deleteInfo', 43 id: 'settings.account.deleteInfo',
44 defaultMessage: 44 defaultMessage:
45 "!!!If you don't need your Ferdi account any longer, you can delete your account and all related data here.", 45 "If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
46 }, 46 },
47 deleteEmailSent: { 47 deleteEmailSent: {
48 id: 'settings.account.deleteEmailSent', 48 id: 'settings.account.deleteEmailSent',
49 defaultMessage: 49 defaultMessage:
50 '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!', 50 'You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!',
51 }, 51 },
52 yourLicense: { 52 yourLicense: {
53 id: 'settings.account.yourLicense', 53 id: 'settings.account.yourLicense',
54 defaultMessage: '!!!Your Franz License:', 54 defaultMessage: 'Your Ferdi License:',
55 }, 55 },
56 accountUnavailable: { 56 accountUnavailable: {
57 id: 'settings.account.accountUnavailable', 57 id: 'settings.account.accountUnavailable',
@@ -59,7 +59,8 @@ const messages = defineMessages({
59 }, 59 },
60 accountUnavailableInfo: { 60 accountUnavailableInfo: {
61 id: 'settings.account.accountUnavailableInfo', 61 id: 'settings.account.accountUnavailableInfo',
62 defaultMessage: 'You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.', 62 defaultMessage:
63 'You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.',
63 }, 64 },
64}); 65});
65 66
@@ -78,10 +79,6 @@ class AccountDashboard extends Component {
78 server: PropTypes.string.isRequired, 79 server: PropTypes.string.isRequired,
79 }; 80 };
80 81
81 static contextTypes = {
82 intl: intlShape,
83 };
84
85 render() { 82 render() {
86 const { 83 const {
87 user, 84 user,
@@ -95,7 +92,7 @@ class AccountDashboard extends Component {
95 openInvoices, 92 openInvoices,
96 server, 93 server,
97 } = this.props; 94 } = this.props;
98 const { intl } = this.context; 95 const { intl } = this.props;
99 96
100 const isUsingWithoutAccount = server === LOCAL_SERVER; 97 const isUsingWithoutAccount = server === LOCAL_SERVER;
101 const isUsingFranzServer = server === LIVE_FRANZ_API; 98 const isUsingFranzServer = server === LIVE_FRANZ_API;
@@ -182,9 +179,7 @@ class AccountDashboard extends Component {
182 <div className="account"> 179 <div className="account">
183 <div className="account__box"> 180 <div className="account__box">
184 <H2>{intl.formatMessage(messages.yourLicense)}</H2> 181 <H2>{intl.formatMessage(messages.yourLicense)}</H2>
185 <p> 182 <p>Franz</p>
186 Franz
187 </p>
188 <div className="manage-user-links"> 183 <div className="manage-user-links">
189 <Button 184 <Button
190 label={intl.formatMessage( 185 label={intl.formatMessage(
@@ -203,7 +198,9 @@ class AccountDashboard extends Component {
203 {isUsingFranzServer && ( 198 {isUsingFranzServer && (
204 <div className="account franz-form"> 199 <div className="account franz-form">
205 <div className="account__box"> 200 <div className="account__box">
206 <H2>{intl.formatMessage(messages.headlineDangerZone)}</H2> 201 <H2>
202 {intl.formatMessage(messages.headlineDangerZone)}
203 </H2>
207 {!isDeleteAccountSuccessful && ( 204 {!isDeleteAccountSuccessful && (
208 <div className="account__subscription"> 205 <div className="account__subscription">
209 <p>{intl.formatMessage(messages.deleteInfo)}</p> 206 <p>{intl.formatMessage(messages.deleteInfo)}</p>
@@ -232,4 +229,4 @@ class AccountDashboard extends Component {
232 } 229 }
233} 230}
234 231
235export default AccountDashboard; 232export default injectIntl(AccountDashboard);
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index 0a5ace586..72c7faa66 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -1,6 +1,6 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl'; 3import { defineMessages, injectIntl } from 'react-intl';
4import { inject, observer } from 'mobx-react'; 4import { inject, observer } from 'mobx-react';
5import { RouterStore } from 'mobx-react-router'; 5import { RouterStore } from 'mobx-react-router';
6 6
@@ -15,35 +15,37 @@ import globalMessages from '../../../i18n/globalMessages';
15const messages = defineMessages({ 15const messages = defineMessages({
16 availableServices: { 16 availableServices: {
17 id: 'settings.navigation.availableServices', 17 id: 'settings.navigation.availableServices',
18 defaultMessage: '!!!Available services', 18 defaultMessage: 'Available services',
19 }, 19 },
20 yourServices: { 20 yourServices: {
21 id: 'settings.navigation.yourServices', 21 id: 'settings.navigation.yourServices',
22 defaultMessage: '!!!Your services', 22 defaultMessage: 'Your services',
23 }, 23 },
24 yourWorkspaces: { 24 yourWorkspaces: {
25 id: 'settings.navigation.yourWorkspaces', 25 id: 'settings.navigation.yourWorkspaces',
26 defaultMessage: '!!!Your workspaces', 26 defaultMessage: 'Your workspaces',
27 }, 27 },
28 account: { 28 account: {
29 id: 'settings.navigation.account', 29 id: 'settings.navigation.account',
30 defaultMessage: '!!!Account', 30 defaultMessage: 'Account',
31 }, 31 },
32 team: { 32 team: {
33 id: 'settings.navigation.team', 33 id: 'settings.navigation.team',
34 defaultMessage: '!!!Manage Team', 34 defaultMessage: 'Manage Team',
35 }, 35 },
36 supportFerdi: { 36 supportFerdi: {
37 id: 'settings.navigation.supportFerdi', 37 id: 'settings.navigation.supportFerdi',
38 defaultMessage: '!!!About Ferdi', 38 defaultMessage: 'About Ferdi',
39 }, 39 },
40 logout: { 40 logout: {
41 id: 'settings.navigation.logout', 41 id: 'settings.navigation.logout',
42 defaultMessage: '!!!Logout', 42 defaultMessage: 'Logout',
43 }, 43 },
44}); 44});
45 45
46export default @inject('stores', 'actions') @observer class SettingsNavigation extends Component { 46@inject('stores', 'actions')
47@observer
48class SettingsNavigation extends Component {
47 static propTypes = { 49 static propTypes = {
48 stores: PropTypes.shape({ 50 stores: PropTypes.shape({
49 ui: PropTypes.instanceOf(UIStore).isRequired, 51 ui: PropTypes.instanceOf(UIStore).isRequired,
@@ -58,13 +60,10 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
58 workspaceCount: PropTypes.number.isRequired, 60 workspaceCount: PropTypes.number.isRequired,
59 }; 61 };
60 62
61 static contextTypes = {
62 intl: intlShape,
63 };
64
65 handleLoginLogout() { 63 handleLoginLogout() {
66 const isLoggedIn = Boolean(localStorage.getItem('authToken')); 64 const isLoggedIn = Boolean(localStorage.getItem('authToken'));
67 const isUsingWithoutAccount = this.props.stores.settings.app.server === LOCAL_SERVER; 65 const isUsingWithoutAccount =
66 this.props.stores.settings.app.server === LOCAL_SERVER;
68 67
69 if (isLoggedIn) { 68 if (isLoggedIn) {
70 // Remove current auth token 69 // Remove current auth token
@@ -82,7 +81,9 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
82 this.props.stores.user.isLoggingOut = true; 81 this.props.stores.user.isLoggingOut = true;
83 } 82 }
84 83
85 this.props.stores.router.push(isLoggedIn ? '/auth/logout' : '/auth/welcome'); 84 this.props.stores.router.push(
85 isLoggedIn ? '/auth/logout' : '/auth/welcome',
86 );
86 87
87 if (isLoggedIn) { 88 if (isLoggedIn) {
88 // Reload Ferdi, otherwise many settings won't sync correctly with the server 89 // Reload Ferdi, otherwise many settings won't sync correctly with the server
@@ -93,7 +94,7 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
93 94
94 render() { 95 render() {
95 const { serviceCount, workspaceCount, stores } = this.props; 96 const { serviceCount, workspaceCount, stores } = this.props;
96 const { intl } = this.context; 97 const { intl } = this.props;
97 const isLoggedIn = Boolean(localStorage.getItem('authToken')); 98 const isLoggedIn = Boolean(localStorage.getItem('authToken'));
98 const isUsingWithoutAccount = stores.settings.app.server === LOCAL_SERVER; 99 const isUsingWithoutAccount = stores.settings.app.server === LOCAL_SERVER;
99 const isUsingFranzServer = stores.settings.app.server === LIVE_FRANZ_API; 100 const isUsingFranzServer = stores.settings.app.server === LIVE_FRANZ_API;
@@ -113,11 +114,8 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
113 activeClassName="is-active" 114 activeClassName="is-active"
114 disabled={!isLoggedIn} 115 disabled={!isLoggedIn}
115 > 116 >
116 {intl.formatMessage(messages.yourServices)} 117 {intl.formatMessage(messages.yourServices)}{' '}
117 {' '} 118 <span className="badge">{serviceCount}</span>
118 <span className="badge">
119 {serviceCount}
120 </span>
121 </Link> 119 </Link>
122 {workspaceStore.isFeatureEnabled ? ( 120 {workspaceStore.isFeatureEnabled ? (
123 <Link 121 <Link
@@ -126,8 +124,7 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
126 activeClassName="is-active" 124 activeClassName="is-active"
127 disabled={!isLoggedIn} 125 disabled={!isLoggedIn}
128 > 126 >
129 {intl.formatMessage(messages.yourWorkspaces)} 127 {intl.formatMessage(messages.yourWorkspaces)}{' '}
130 {' '}
131 <span className="badge">{workspaceCount}</span> 128 <span className="badge">{workspaceCount}</span>
132 </Link> 129 </Link>
133 ) : null} 130 ) : null}
@@ -172,9 +169,13 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
172 className="settings-navigation__link" 169 className="settings-navigation__link"
173 onClick={this.handleLoginLogout.bind(this)} 170 onClick={this.handleLoginLogout.bind(this)}
174 > 171 >
175 { isLoggedIn && !isUsingWithoutAccount ? intl.formatMessage(messages.logout) : 'Login'} 172 {isLoggedIn && !isUsingWithoutAccount
173 ? intl.formatMessage(messages.logout)
174 : 'Login'}
176 </button> 175 </button>
177 </div> 176 </div>
178 ); 177 );
179 } 178 }
180} 179}
180
181export default injectIntl(SettingsNavigation);
diff --git a/src/components/settings/recipes/RecipeItem.js b/src/components/settings/recipes/RecipeItem.js
index 55f415bd5..ca188aa99 100644
--- a/src/components/settings/recipes/RecipeItem.js
+++ b/src/components/settings/recipes/RecipeItem.js
@@ -4,7 +4,8 @@ import { observer } from 'mobx-react';
4 4
5import RecipePreviewModel from '../../../models/RecipePreview'; 5import RecipePreviewModel from '../../../models/RecipePreview';
6 6
7export default @observer class RecipeItem extends Component { 7@observer
8class RecipeItem extends Component {
8 static propTypes = { 9 static propTypes = {
9 recipe: PropTypes.instanceOf(RecipePreviewModel).isRequired, 10 recipe: PropTypes.instanceOf(RecipePreviewModel).isRequired,
10 onClick: PropTypes.func.isRequired, 11 onClick: PropTypes.func.isRequired,
@@ -14,19 +15,11 @@ export default @observer class RecipeItem extends Component {
14 const { recipe, onClick } = this.props; 15 const { recipe, onClick } = this.props;
15 16
16 return ( 17 return (
17 <button 18 <button type="button" className="recipe-teaser" onClick={onClick}>
18 type="button"
19 className="recipe-teaser"
20 onClick={onClick}
21 >
22 {recipe.isDevRecipe && ( 19 {recipe.isDevRecipe && (
23 <span className="recipe-teaser__dev-badge">dev</span> 20 <span className="recipe-teaser__dev-badge">dev</span>
24 )} 21 )}
25 <img 22 <img src={recipe.icons.svg} className="recipe-teaser__icon" alt="" />
26 src={recipe.icons.svg}
27 className="recipe-teaser__icon"
28 alt=""
29 />
30 <span className="recipe-teaser__label">{recipe.name}</span> 23 <span className="recipe-teaser__label">{recipe.name}</span>
31 {recipe.aliases && recipe.aliases.length > 0 && ( 24 {recipe.aliases && recipe.aliases.length > 0 && (
32 <span className="recipe-teaser__alias_label"> 25 <span className="recipe-teaser__alias_label">
@@ -37,3 +30,5 @@ export default @observer class RecipeItem extends Component {
37 ); 30 );
38 } 31 }
39} 32}
33
34export default RecipeItem;
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index 44ff2d0d7..44f5bc39a 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router';
6 6
7import { Button, Input } from '@meetfranz/forms'; 7import { Button, Input } from '@meetfranz/forms';
@@ -18,55 +18,56 @@ import RecipePreview from '../../../models/RecipePreview';
18const messages = defineMessages({ 18const messages = defineMessages({
19 headline: { 19 headline: {
20 id: 'settings.recipes.headline', 20 id: 'settings.recipes.headline',
21 defaultMessage: '!!!Available Services', 21 defaultMessage: 'Available services',
22 }, 22 },
23 searchService: { 23 searchService: {
24 id: 'settings.searchService', 24 id: 'settings.searchService',
25 defaultMessage: '!!!Search service', 25 defaultMessage: 'Search service',
26 }, 26 },
27 allRecipes: { 27 allRecipes: {
28 id: 'settings.recipes.all', 28 id: 'settings.recipes.all',
29 defaultMessage: '!!!All services', 29 defaultMessage: 'All services',
30 }, 30 },
31 customRecipes: { 31 customRecipes: {
32 id: 'settings.recipes.custom', 32 id: 'settings.recipes.custom',
33 defaultMessage: '!!!Custom Services', 33 defaultMessage: 'Custom Services',
34 }, 34 },
35 nothingFound: { 35 nothingFound: {
36 id: 'settings.recipes.nothingFound', 36 id: 'settings.recipes.nothingFound',
37 defaultMessage: '!!!Sorry, but no service matched your search term - but you can still probably add it using the "Custom Website" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.', 37 defaultMessage:
38 'Sorry, but no service matched your search term - but you can still probably add it using the "Custom Website" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.',
38 }, 39 },
39 servicesSuccessfulAddedInfo: { 40 servicesSuccessfulAddedInfo: {
40 id: 'settings.recipes.servicesSuccessfulAddedInfo', 41 id: 'settings.recipes.servicesSuccessfulAddedInfo',
41 defaultMessage: '!!!Service successfully added', 42 defaultMessage: 'Service successfully added',
42 }, 43 },
43 missingService: { 44 missingService: {
44 id: 'settings.recipes.missingService', 45 id: 'settings.recipes.missingService',
45 defaultMessage: '!!!Missing a service?', 46 defaultMessage: 'Missing a service?',
46 }, 47 },
47 customRecipeIntro: { 48 customRecipeIntro: {
48 id: 'settings.recipes.customService.intro', 49 id: 'settings.recipes.customService.intro',
49 defaultMessage: '!!!To add a custom service, copy the recipe folder into:', 50 defaultMessage: 'To add a custom service, copy the service recipe to:',
50 }, 51 },
51 openFolder: { 52 openFolder: {
52 id: 'settings.recipes.customService.openFolder', 53 id: 'settings.recipes.customService.openFolder',
53 defaultMessage: '!!!Open directory', 54 defaultMessage: 'Open folder',
54 }, 55 },
55 openDevDocs: { 56 openDevDocs: {
56 id: 'settings.recipes.customService.openDevDocs', 57 id: 'settings.recipes.customService.openDevDocs',
57 defaultMessage: '!!!Developer Documentation', 58 defaultMessage: 'Developer Documentation',
58 }, 59 },
59 headlineCustomRecipes: { 60 headlineCustomRecipes: {
60 id: 'settings.recipes.customService.headline.customRecipes', 61 id: 'settings.recipes.customService.headline.customRecipes',
61 defaultMessage: '!!!Custom 3rd Party Recipes', 62 defaultMessage: 'Custom 3rd Party Recipes',
62 }, 63 },
63 headlineCommunityRecipes: { 64 headlineCommunityRecipes: {
64 id: 'settings.recipes.customService.headline.communityRecipes', 65 id: 'settings.recipes.customService.headline.communityRecipes',
65 defaultMessage: '!!!Community 3rd Party Recipes', 66 defaultMessage: 'Community 3rd Party Recipes',
66 }, 67 },
67 headlineDevRecipes: { 68 headlineDevRecipes: {
68 id: 'settings.recipes.customService.headline.devRecipes', 69 id: 'settings.recipes.customService.headline.devRecipes',
69 defaultMessage: '!!!Your Development Service Recipes', 70 defaultMessage: 'Your Development Service Recipes',
70 }, 71 },
71}); 72});
72 73
@@ -81,7 +82,8 @@ const styles = {
81 marginTop: 20, 82 marginTop: 20,
82 83
83 '& > div': { 84 '& > div': {
84 fontFamily: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace', 85 fontFamily:
86 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace',
85 }, 87 },
86 }, 88 },
87 actionContainer: { 89 actionContainer: {
@@ -98,7 +100,9 @@ const styles = {
98 }, 100 },
99}; 101};
100 102
101export default @injectSheet(styles) @observer class RecipesDashboard extends Component { 103@injectSheet(styles)
104@observer
105class RecipesDashboard extends Component {
102 static propTypes = { 106 static propTypes = {
103 recipes: MobxPropTypes.arrayOrObservableArray.isRequired, 107 recipes: MobxPropTypes.arrayOrObservableArray.isRequired,
104 customWebsiteRecipe: PropTypes.instanceOf(RecipePreview).isRequired, 108 customWebsiteRecipe: PropTypes.instanceOf(RecipePreview).isRequired,
@@ -118,10 +122,6 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
118 static defaultProps = { 122 static defaultProps = {
119 searchNeedle: '', 123 searchNeedle: '',
120 recipeFilter: 'all', 124 recipeFilter: 'all',
121 }
122
123 static contextTypes = {
124 intl: intlShape,
125 }; 125 };
126 126
127 render() { 127 render() {
@@ -140,7 +140,7 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
140 openDevDocs, 140 openDevDocs,
141 classes, 141 classes,
142 } = this.props; 142 } = this.props;
143 const { intl } = this.context; 143 const { intl } = this.props;
144 144
145 const communityRecipes = recipes.filter(r => !r.isDevRecipe); 145 const communityRecipes = recipes.filter(r => !r.isDevRecipe);
146 const devRecipes = recipes.filter(r => r.isDevRecipe); 146 const devRecipes = recipes.filter(r => r.isDevRecipe);
@@ -188,9 +188,13 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
188 > 188 >
189 {intl.formatMessage(messages.customRecipes)} 189 {intl.formatMessage(messages.customRecipes)}
190 </Link> 190 </Link>
191 <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request" rel="noreferrer"> 191 <a
192 {intl.formatMessage(messages.missingService)} 192 href={FRANZ_SERVICE_REQUEST}
193 {' '} 193 target="_blank"
194 className="link recipes__service-request"
195 rel="noreferrer"
196 >
197 {intl.formatMessage(messages.missingService)}{' '}
194 <i className="mdi mdi-open-in-new" /> 198 <i className="mdi mdi-open-in-new" />
195 </a> 199 </a>
196 </div> 200 </div>
@@ -201,13 +205,9 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
201 <> 205 <>
202 {recipeFilter === 'dev' && ( 206 {recipeFilter === 'dev' && (
203 <> 207 <>
204 <H2> 208 <H2>{intl.formatMessage(messages.headlineCustomRecipes)}</H2>
205 {intl.formatMessage(messages.headlineCustomRecipes)}
206 </H2>
207 <div className={classes.devRecipeIntroContainer}> 209 <div className={classes.devRecipeIntroContainer}>
208 <p> 210 <p>{intl.formatMessage(messages.customRecipeIntro)}</p>
209 {intl.formatMessage(messages.customRecipeIntro)}
210 </p>
211 <Input 211 <Input
212 value={recipeDirectory} 212 value={recipeDirectory}
213 className={classes.path} 213 className={classes.path}
@@ -238,12 +238,19 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
238 <img src="./assets/images/emoji/dontknow.png" alt="" /> 238 <img src="./assets/images/emoji/dontknow.png" alt="" />
239 </span> 239 </span>
240 240
241 <p className="settings__empty-state-text">{intl.formatMessage(messages.nothingFound)}</p> 241 <p className="settings__empty-state-text">
242 {intl.formatMessage(messages.nothingFound)}
243 </p>
242 244
243 <RecipeItem 245 <RecipeItem
244 key={customWebsiteRecipe.id} 246 key={customWebsiteRecipe.id}
245 recipe={customWebsiteRecipe} 247 recipe={customWebsiteRecipe}
246 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: customWebsiteRecipe.id })} 248 onClick={() =>
249 isLoggedIn &&
250 showAddServiceInterface({
251 recipeId: customWebsiteRecipe.id,
252 })
253 }
247 /> 254 />
248 </div> 255 </div>
249 )} 256 )}
@@ -251,7 +258,10 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
251 <RecipeItem 258 <RecipeItem
252 key={recipe.id} 259 key={recipe.id}
253 recipe={recipe} 260 recipe={recipe}
254 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: recipe.id })} 261 onClick={() =>
262 isLoggedIn &&
263 showAddServiceInterface({ recipeId: recipe.id })
264 }
255 /> 265 />
256 ))} 266 ))}
257 </div> 267 </div>
@@ -263,7 +273,10 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
263 <RecipeItem 273 <RecipeItem
264 key={recipe.id} 274 key={recipe.id}
265 recipe={recipe} 275 recipe={recipe}
266 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: recipe.id })} 276 onClick={() =>
277 isLoggedIn &&
278 showAddServiceInterface({ recipeId: recipe.id })
279 }
267 /> 280 />
268 ))} 281 ))}
269 </div> 282 </div>
@@ -276,3 +289,5 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
276 ); 289 );
277 } 290 }
278} 291}
292
293export default injectIntl(RecipesDashboard);
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index c41cdd56a..22089ec45 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -2,13 +2,14 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { Link } from 'react-router'; 4import { Link } from 'react-router';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import normalizeUrl from 'normalize-url'; 6import normalizeUrl from 'normalize-url';
7 7
8import Form from '../../../lib/Form'; 8import Form from '../../../lib/Form';
9import Recipe from '../../../models/Recipe'; 9import Recipe from '../../../models/Recipe';
10import Service from '../../../models/Service'; 10import Service from '../../../models/Service';
11import Tabs, { TabItem } from '../../ui/Tabs'; 11import Tabs from '../../ui/Tabs/Tabs';
12import { TabItem } from '../../ui/Tabs/TabItem';
12import Input from '../../ui/Input'; 13import Input from '../../ui/Input';
13import Toggle from '../../ui/Toggle'; 14import Toggle from '../../ui/Toggle';
14import Slider from '../../ui/Slider'; 15import Slider from '../../ui/Slider';
@@ -22,111 +23,117 @@ import globalMessages from '../../../i18n/globalMessages';
22const messages = defineMessages({ 23const messages = defineMessages({
23 saveService: { 24 saveService: {
24 id: 'settings.service.form.saveButton', 25 id: 'settings.service.form.saveButton',
25 defaultMessage: '!!!Save service', 26 defaultMessage: 'Save service',
26 }, 27 },
27 deleteService: { 28 deleteService: {
28 id: 'settings.service.form.deleteButton', 29 id: 'settings.service.form.deleteButton',
29 defaultMessage: '!!!Delete Service', 30 defaultMessage: 'Delete service',
30 }, 31 },
31 openDarkmodeCss: { 32 openDarkmodeCss: {
32 id: 'settings.service.form.openDarkmodeCss', 33 id: 'settings.service.form.openDarkmodeCss',
33 defaultMessage: '!!!Open darkmode.css', 34 defaultMessage: 'Open darkmode.css',
34 }, 35 },
35 openUserCss: { 36 openUserCss: {
36 id: 'settings.service.form.openUserCss', 37 id: 'settings.service.form.openUserCss',
37 defaultMessage: '!!!Open user.css', 38 defaultMessage: 'Open user.css',
38 }, 39 },
39 openUserJs: { 40 openUserJs: {
40 id: 'settings.service.form.openUserJs', 41 id: 'settings.service.form.openUserJs',
41 defaultMessage: '!!!Open user.js', 42 defaultMessage: 'Open user.js',
42 }, 43 },
43 recipeFileInfo: { 44 recipeFileInfo: {
44 id: 'settings.service.form.recipeFileInfo', 45 id: 'settings.service.form.recipeFileInfo',
45 defaultMessage: '!!!Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.', 46 defaultMessage:
47 'Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.',
46 }, 48 },
47 availableServices: { 49 availableServices: {
48 id: 'settings.service.form.availableServices', 50 id: 'settings.service.form.availableServices',
49 defaultMessage: '!!!Available services', 51 defaultMessage: 'Available services',
50 }, 52 },
51 yourServices: { 53 yourServices: {
52 id: 'settings.service.form.yourServices', 54 id: 'settings.service.form.yourServices',
53 defaultMessage: '!!!Your services', 55 defaultMessage: 'Your services',
54 }, 56 },
55 addServiceHeadline: { 57 addServiceHeadline: {
56 id: 'settings.service.form.addServiceHeadline', 58 id: 'settings.service.form.addServiceHeadline',
57 defaultMessage: '!!!Add {name}', 59 defaultMessage: 'Add {name}',
58 }, 60 },
59 editServiceHeadline: { 61 editServiceHeadline: {
60 id: 'settings.service.form.editServiceHeadline', 62 id: 'settings.service.form.editServiceHeadline',
61 defaultMessage: '!!!Edit {name}', 63 defaultMessage: 'Edit {name}',
62 }, 64 },
63 tabHosted: { 65 tabHosted: {
64 id: 'settings.service.form.tabHosted', 66 id: 'settings.service.form.tabHosted',
65 defaultMessage: '!!!Hosted', 67 defaultMessage: 'Hosted',
66 }, 68 },
67 tabOnPremise: { 69 tabOnPremise: {
68 id: 'settings.service.form.tabOnPremise', 70 id: 'settings.service.form.tabOnPremise',
69 defaultMessage: '!!!Self hosted â­ï¸', 71 defaultMessage: 'Self hosted â­ï¸',
70 }, 72 },
71 useHostedService: { 73 useHostedService: {
72 id: 'settings.service.form.useHostedService', 74 id: 'settings.service.form.useHostedService',
73 defaultMessage: '!!!Use the hosted {name} service.', 75 defaultMessage: 'Use the hosted {name} service.',
74 }, 76 },
75 customUrlValidationError: { 77 customUrlValidationError: {
76 id: 'settings.service.form.customUrlValidationError', 78 id: 'settings.service.form.customUrlValidationError',
77 defaultMessage: '!!!Could not validate custom {name} server.', 79 defaultMessage: 'Could not validate custom {name} server.',
78 }, 80 },
79 indirectMessageInfo: { 81 indirectMessageInfo: {
80 id: 'settings.service.form.indirectMessageInfo', 82 id: 'settings.service.form.indirectMessageInfo',
81 defaultMessage: '!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...', 83 defaultMessage:
84 'You will be notified about all new messages in a channel, not just @username, @channel, @here, ...',
82 }, 85 },
83 isMutedInfo: { 86 isMutedInfo: {
84 id: 'settings.service.form.isMutedInfo', 87 id: 'settings.service.form.isMutedInfo',
85 defaultMessage: '!!!When disabled, all notification sounds and audio playback are muted', 88 defaultMessage:
89 'When disabled, all notification sounds and audio playback are muted',
86 }, 90 },
87 isHibernationEnabledInfo: { 91 isHibernationEnabledInfo: {
88 id: 'settings.service.form.isHibernatedEnabledInfo', 92 id: 'settings.service.form.isHibernatedEnabledInfo',
89 defaultMessage: '!!!When enabled, a service will be shut down after a period of time to save system resources.', 93 defaultMessage:
94 'When enabled, a service will be shut down after a period of time to save system resources.',
90 }, 95 },
91 headlineNotifications: { 96 headlineNotifications: {
92 id: 'settings.service.form.headlineNotifications', 97 id: 'settings.service.form.headlineNotifications',
93 defaultMessage: '!!!Notifications', 98 defaultMessage: 'Notifications',
94 }, 99 },
95 headlineBadges: { 100 headlineBadges: {
96 id: 'settings.service.form.headlineBadges', 101 id: 'settings.service.form.headlineBadges',
97 defaultMessage: '!!!Unread message badges', 102 defaultMessage: 'Unread message badges',
98 }, 103 },
99 headlineGeneral: { 104 headlineGeneral: {
100 id: 'settings.service.form.headlineGeneral', 105 id: 'settings.service.form.headlineGeneral',
101 defaultMessage: '!!!General', 106 defaultMessage: 'General',
102 }, 107 },
103 headlineDarkReaderSettings: { 108 headlineDarkReaderSettings: {
104 id: 'settings.service.form.headlineDarkReaderSettings', 109 id: 'settings.service.form.headlineDarkReaderSettings',
105 defaultMessage: '!!!Dark Reader Settings', 110 defaultMessage: 'Dark Reader Settings',
106 }, 111 },
107 iconDelete: { 112 iconDelete: {
108 id: 'settings.service.form.iconDelete', 113 id: 'settings.service.form.iconDelete',
109 defaultMessage: '!!!Delete', 114 defaultMessage: 'Delete',
110 }, 115 },
111 iconUpload: { 116 iconUpload: {
112 id: 'settings.service.form.iconUpload', 117 id: 'settings.service.form.iconUpload',
113 defaultMessage: '!!!Drop your image, or click here', 118 defaultMessage: 'Drop your image, or click here',
114 }, 119 },
115 headlineProxy: { 120 headlineProxy: {
116 id: 'settings.service.form.proxy.headline', 121 id: 'settings.service.form.proxy.headline',
117 defaultMessage: '!!!HTTP/HTTPS Proxy Settings', 122 defaultMessage: 'HTTP/HTTPS Proxy Settings',
118 }, 123 },
119 proxyRestartInfo: { 124 proxyRestartInfo: {
120 id: 'settings.service.form.proxy.restartInfo', 125 id: 'settings.service.form.proxy.restartInfo',
121 defaultMessage: '!!!Please restart Ferdi after changing proxy Settings.', 126 defaultMessage: 'Please restart Ferdi after changing proxy Settings.',
122 }, 127 },
123 proxyInfo: { 128 proxyInfo: {
124 id: 'settings.service.form.proxy.info', 129 id: 'settings.service.form.proxy.info',
125 defaultMessage: '!!!Proxy settings will not be synchronized with the Ferdi servers.', 130 defaultMessage:
131 'Proxy settings will not be synchronized with the Ferdi servers.',
126 }, 132 },
127}); 133});
128 134
129export default @observer class EditServiceForm extends Component { 135@observer
136class EditServiceForm extends Component {
130 static propTypes = { 137 static propTypes = {
131 recipe: PropTypes.instanceOf(Recipe).isRequired, 138 recipe: PropTypes.instanceOf(Recipe).isRequired,
132 service(props, propName) { 139 service(props, propName) {
@@ -151,20 +158,16 @@ export default @observer class EditServiceForm extends Component {
151 service: {}, 158 service: {},
152 }; 159 };
153 160
154 static contextTypes = {
155 intl: intlShape,
156 };
157
158 state = { 161 state = {
159 isValidatingCustomUrl: false, 162 isValidatingCustomUrl: false,
160 } 163 };
161 164
162 submit(e) { 165 submit(e) {
163 const { recipe } = this.props; 166 const { recipe } = this.props;
164 167
165 e.preventDefault(); 168 e.preventDefault();
166 this.props.form.submit({ 169 this.props.form.submit({
167 onSuccess: async (form) => { 170 onSuccess: async form => {
168 const values = form.values(); 171 const values = form.values();
169 let isValid = true; 172 let isValid = true;
170 173
@@ -176,10 +179,13 @@ export default @observer class EditServiceForm extends Component {
176 if (recipe.validateUrl && values.customUrl) { 179 if (recipe.validateUrl && values.customUrl) {
177 this.setState({ isValidatingCustomUrl: true }); 180 this.setState({ isValidatingCustomUrl: true });
178 try { 181 try {
179 values.customUrl = normalizeUrl(values.customUrl, { stripWWW: false, removeTrailingSlash: false }); 182 values.customUrl = normalizeUrl(values.customUrl, {
183 stripWWW: false,
184 removeTrailingSlash: false,
185 });
180 isValid = await recipe.validateUrl(values.customUrl); 186 isValid = await recipe.validateUrl(values.customUrl);
181 } catch (err) { 187 } catch (error) {
182 console.warn('ValidateURL', err); 188 console.warn('ValidateURL', error);
183 isValid = false; 189 isValid = false;
184 } 190 }
185 } 191 }
@@ -208,7 +214,7 @@ export default @observer class EditServiceForm extends Component {
208 openRecipeFile, 214 openRecipeFile,
209 isProxyFeatureEnabled, 215 isProxyFeatureEnabled,
210 } = this.props; 216 } = this.props;
211 const { intl } = this.context; 217 const { intl } = this.props;
212 218
213 const { isValidatingCustomUrl } = this.state; 219 const { isValidatingCustomUrl } = this.state;
214 220
@@ -236,7 +242,8 @@ export default @observer class EditServiceForm extends Component {
236 activeTabIndex = 2; 242 activeTabIndex = 2;
237 } 243 }
238 244
239 const requiresUserInput = !recipe.hasHostedOption && (recipe.hasTeamId || recipe.hasCustomUrl); 245 const requiresUserInput =
246 !recipe.hasHostedOption && (recipe.hasTeamId || recipe.hasCustomUrl);
240 247
241 return ( 248 return (
242 <div className="settings__main"> 249 <div className="settings__main">
@@ -254,29 +261,27 @@ export default @observer class EditServiceForm extends Component {
254 </span> 261 </span>
255 <span className="separator" /> 262 <span className="separator" />
256 <span className="settings__header-item"> 263 <span className="settings__header-item">
257 {action === 'add' ? ( 264 {action === 'add'
258 intl.formatMessage(messages.addServiceHeadline, { 265 ? intl.formatMessage(messages.addServiceHeadline, {
259 name: recipe.name, 266 name: recipe.name,
260 }) 267 })
261 ) : ( 268 : intl.formatMessage(messages.editServiceHeadline, {
262 intl.formatMessage(messages.editServiceHeadline, { 269 name: service.name !== '' ? service.name : recipe.name,
263 name: service.name !== '' ? service.name : recipe.name, 270 })}
264 })
265 )}
266 </span> 271 </span>
267 </div> 272 </div>
268 <div className="settings__body"> 273 <div className="settings__body">
269 <form onSubmit={(e) => this.submit(e)} id="form"> 274 <form onSubmit={e => this.submit(e)} id="form">
270 <div className="service-name"> 275 <div className="service-name">
271 <Input field={form.$('name')} focus /> 276 <Input field={form.$('name')} focus />
272 </div> 277 </div>
273 {(recipe.hasTeamId || recipe.hasCustomUrl) && ( 278 {(recipe.hasTeamId || recipe.hasCustomUrl) && (
274 <Tabs 279 <Tabs active={activeTabIndex}>
275 active={activeTabIndex}
276 >
277 {recipe.hasHostedOption && ( 280 {recipe.hasHostedOption && (
278 <TabItem title={recipe.name}> 281 <TabItem title={recipe.name}>
279 {intl.formatMessage(messages.useHostedService, { name: recipe.name })} 282 {intl.formatMessage(messages.useHostedService, {
283 name: recipe.name,
284 })}
280 </TabItem> 285 </TabItem>
281 )} 286 )}
282 {recipe.hasTeamId && ( 287 {recipe.hasTeamId && (
@@ -293,7 +298,9 @@ export default @observer class EditServiceForm extends Component {
293 <Input field={form.$('customUrl')} /> 298 <Input field={form.$('customUrl')} />
294 {form.error === 'url-validation-error' && ( 299 {form.error === 'url-validation-error' && (
295 <p className="franz-form__error"> 300 <p className="franz-form__error">
296 {intl.formatMessage(messages.customUrlValidationError, { name: recipe.name })} 301 {intl.formatMessage(messages.customUrlValidationError, {
302 name: recipe.name,
303 })}
297 </p> 304 </p>
298 )} 305 )}
299 </TabItem> 306 </TabItem>
@@ -326,13 +333,19 @@ export default @observer class EditServiceForm extends Component {
326 <div className="settings__settings-group"> 333 <div className="settings__settings-group">
327 <h3>{intl.formatMessage(messages.headlineBadges)}</h3> 334 <h3>{intl.formatMessage(messages.headlineBadges)}</h3>
328 <Toggle field={form.$('isBadgeEnabled')} /> 335 <Toggle field={form.$('isBadgeEnabled')} />
329 {recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && ( 336 {recipe.hasIndirectMessages &&
330 <> 337 form.$('isBadgeEnabled').value && (
331 <Toggle field={form.$('isIndirectMessageBadgeEnabled')} /> 338 <>
332 <p className="settings__help indented__help"> 339 <Toggle
333 {intl.formatMessage(messages.indirectMessageInfo)} 340 field={form.$('isIndirectMessageBadgeEnabled')}
334 </p> 341 />
335 </> 342 <p className="settings__help indented__help">
343 {intl.formatMessage(messages.indirectMessageInfo)}
344 </p>
345 </>
346 )}
347 {recipe.allowFavoritesDelineationInUnreadCount && (
348 <Toggle field={form.$('onlyShowFavoritesInUnreadCount')} />
336 )} 349 )}
337 </div> 350 </div>
338 351
@@ -344,15 +357,18 @@ export default @observer class EditServiceForm extends Component {
344 {intl.formatMessage(messages.isHibernationEnabledInfo)} 357 {intl.formatMessage(messages.isHibernationEnabledInfo)}
345 </p> 358 </p>
346 <Toggle field={form.$('isDarkModeEnabled')} /> 359 <Toggle field={form.$('isDarkModeEnabled')} />
347 {form.$('isDarkModeEnabled').value 360 {form.$('isDarkModeEnabled').value && (
348 && ( 361 <>
349 <> 362 <h3>
350 <h3>{intl.formatMessage(messages.headlineDarkReaderSettings)}</h3> 363 {intl.formatMessage(
351 <Slider field={form.$('darkReaderBrightness')} /> 364 messages.headlineDarkReaderSettings,
352 <Slider field={form.$('darkReaderContrast')} /> 365 )}
353 <Slider field={form.$('darkReaderSepia')} /> 366 </h3>
354 </> 367 <Slider field={form.$('darkReaderBrightness')} />
355 )} 368 <Slider field={form.$('darkReaderContrast')} />
369 <Slider field={form.$('darkReaderSepia')} />
370 </>
371 )}
356 </div> 372 </div>
357 </div> 373 </div>
358 <div className="service-icon"> 374 <div className="service-icon">
@@ -381,7 +397,10 @@ export default @observer class EditServiceForm extends Component {
381 <> 397 <>
382 <div className="grid"> 398 <div className="grid">
383 <div className="grid__row"> 399 <div className="grid__row">
384 <Input field={form.$('proxy.host')} className="proxyHost" /> 400 <Input
401 field={form.$('proxy.host')}
402 className="proxyHost"
403 />
385 <Input field={form.$('proxy.port')} /> 404 <Input field={form.$('proxy.port')} />
386 </div> 405 </div>
387 </div> 406 </div>
@@ -409,7 +428,9 @@ export default @observer class EditServiceForm extends Component {
409 428
410 <div className="user-agent"> 429 <div className="user-agent">
411 <Input field={form.$('userAgentPref')} /> 430 <Input field={form.$('userAgentPref')} />
412 <p className="settings__help">{intl.formatMessage(globalMessages.userAgentHelp)}</p> 431 <p className="settings__help">
432 {intl.formatMessage(globalMessages.userAgentHelp)}
433 </p>
413 </div> 434 </div>
414 </form> 435 </form>
415 436
@@ -464,7 +485,9 @@ export default @observer class EditServiceForm extends Component {
464 type="submit" 485 type="submit"
465 label={intl.formatMessage(messages.saveService)} 486 label={intl.formatMessage(messages.saveService)}
466 htmlForm="form" 487 htmlForm="form"
467 disabled={action !== 'edit' && (form.isPristine && requiresUserInput)} 488 disabled={
489 action !== 'edit' && form.isPristine && requiresUserInput
490 }
468 /> 491 />
469 )} 492 )}
470 </div> 493 </div>
@@ -472,3 +495,5 @@ export default @observer class EditServiceForm extends Component {
472 ); 495 );
473 } 496 }
474} 497}
498
499export default injectIntl(EditServiceForm);
diff --git a/src/components/settings/services/ServiceError.js b/src/components/settings/services/ServiceError.js
index 3cfc080d6..d16d76db2 100644
--- a/src/components/settings/services/ServiceError.js
+++ b/src/components/settings/services/ServiceError.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
3import { Link } from 'react-router'; 3import { Link } from 'react-router';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import Infobox from '../../ui/Infobox'; 6import Infobox from '../../ui/Infobox';
7import Button from '../../ui/Button'; 7import Button from '../../ui/Button';
@@ -9,29 +9,26 @@ import Button from '../../ui/Button';
9const messages = defineMessages({ 9const messages = defineMessages({
10 headline: { 10 headline: {
11 id: 'settings.service.error.headline', 11 id: 'settings.service.error.headline',
12 defaultMessage: '!!!Error', 12 defaultMessage: 'Error',
13 }, 13 },
14 goBack: { 14 goBack: {
15 id: 'settings.service.error.goBack', 15 id: 'settings.service.error.goBack',
16 defaultMessage: '!!!Back to services', 16 defaultMessage: 'Back to services',
17 }, 17 },
18 availableServices: { 18 availableServices: {
19 id: 'settings.service.form.availableServices', 19 id: 'settings.service.form.availableServices',
20 defaultMessage: '!!!Available services', 20 defaultMessage: 'Available services',
21 }, 21 },
22 errorMessage: { 22 errorMessage: {
23 id: 'settings.service.error.message', 23 id: 'settings.service.error.message',
24 defaultMessage: '!!!Could not load service recipe.', 24 defaultMessage: 'Could not load service recipe.',
25 }, 25 },
26}); 26});
27 27
28export default @observer class ServiceError extends Component { 28@observer
29 static contextTypes = { 29class ServiceError extends Component {
30 intl: intlShape,
31 };
32
33 render() { 30 render() {
34 const { intl } = this.context; 31 const { intl } = this.props;
35 32
36 return ( 33 return (
37 <div className="settings__main"> 34 <div className="settings__main">
@@ -47,10 +44,7 @@ export default @observer class ServiceError extends Component {
47 </span> 44 </span>
48 </div> 45 </div>
49 <div className="settings__body"> 46 <div className="settings__body">
50 <Infobox 47 <Infobox type="danger" icon="alert">
51 type="danger"
52 icon="alert"
53 >
54 {intl.formatMessage(messages.errorMessage)} 48 {intl.formatMessage(messages.errorMessage)}
55 </Infobox> 49 </Infobox>
56 </div> 50 </div>
@@ -65,3 +59,5 @@ export default @observer class ServiceError extends Component {
65 ); 59 );
66 } 60 }
67} 61}
62
63export default injectIntl(ServiceError);
diff --git a/src/components/settings/services/ServiceItem.js b/src/components/settings/services/ServiceItem.js
index ebc618a00..4916e4ecc 100644
--- a/src/components/settings/services/ServiceItem.js
+++ b/src/components/settings/services/ServiceItem.js
@@ -1,6 +1,6 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl'; 3import { defineMessages, injectIntl } from 'react-intl';
4import ReactTooltip from 'react-tooltip'; 4import ReactTooltip from 'react-tooltip';
5import { observer } from 'mobx-react'; 5import { observer } from 'mobx-react';
6import classnames from 'classnames'; 6import classnames from 'classnames';
@@ -10,35 +10,32 @@ import ServiceModel from '../../../models/Service';
10const messages = defineMessages({ 10const messages = defineMessages({
11 tooltipIsDisabled: { 11 tooltipIsDisabled: {
12 id: 'settings.services.tooltip.isDisabled', 12 id: 'settings.services.tooltip.isDisabled',
13 defaultMessage: '!!!Service is disabled', 13 defaultMessage: 'Service is disabled',
14 }, 14 },
15 tooltipNotificationsDisabled: { 15 tooltipNotificationsDisabled: {
16 id: 'settings.services.tooltip.notificationsDisabled', 16 id: 'settings.services.tooltip.notificationsDisabled',
17 defaultMessage: '!!!Notifications are disabled', 17 defaultMessage: 'Notifications are disabled',
18 }, 18 },
19 tooltipIsMuted: { 19 tooltipIsMuted: {
20 id: 'settings.services.tooltip.isMuted', 20 id: 'settings.services.tooltip.isMuted',
21 defaultMessage: '!!!All sounds are muted', 21 defaultMessage: 'All sounds are muted',
22 }, 22 },
23}); 23});
24 24
25export default @observer class ServiceItem extends Component { 25@observer
26class ServiceItem extends Component {
26 static propTypes = { 27 static propTypes = {
27 service: PropTypes.instanceOf(ServiceModel).isRequired, 28 service: PropTypes.instanceOf(ServiceModel).isRequired,
28 goToServiceForm: PropTypes.func.isRequired, 29 goToServiceForm: PropTypes.func.isRequired,
29 }; 30 };
30 31
31 static contextTypes = {
32 intl: intlShape,
33 };
34
35 render() { 32 render() {
36 const { 33 const {
37 service, 34 service,
38 // toggleAction, 35 // toggleAction,
39 goToServiceForm, 36 goToServiceForm,
40 } = this.props; 37 } = this.props;
41 const { intl } = this.context; 38 const { intl } = this.props;
42 39
43 return ( 40 return (
44 <tr 41 <tr
@@ -47,10 +44,7 @@ export default @observer class ServiceItem extends Component {
47 'service-table__row--disabled': !service.isEnabled, 44 'service-table__row--disabled': !service.isEnabled,
48 })} 45 })}
49 > 46 >
50 <td 47 <td className="service-table__column-icon" onClick={goToServiceForm}>
51 className="service-table__column-icon"
52 onClick={goToServiceForm}
53 >
54 <img 48 <img
55 src={service.icon} 49 src={service.icon}
56 className={classnames({ 50 className={classnames({
@@ -60,16 +54,10 @@ export default @observer class ServiceItem extends Component {
60 alt="" 54 alt=""
61 /> 55 />
62 </td> 56 </td>
63 <td 57 <td className="service-table__column-name" onClick={goToServiceForm}>
64 className="service-table__column-name"
65 onClick={goToServiceForm}
66 >
67 {service.name !== '' ? service.name : service.recipe.name} 58 {service.name !== '' ? service.name : service.recipe.name}
68 </td> 59 </td>
69 <td 60 <td className="service-table__column-info" onClick={goToServiceForm}>
70 className="service-table__column-info"
71 onClick={goToServiceForm}
72 >
73 {service.isMuted && ( 61 {service.isMuted && (
74 <span 62 <span
75 className="mdi mdi-bell-off" 63 className="mdi mdi-bell-off"
@@ -77,10 +65,7 @@ export default @observer class ServiceItem extends Component {
77 /> 65 />
78 )} 66 )}
79 </td> 67 </td>
80 <td 68 <td className="service-table__column-info" onClick={goToServiceForm}>
81 className="service-table__column-info"
82 onClick={goToServiceForm}
83 >
84 {!service.isEnabled && ( 69 {!service.isEnabled && (
85 <span 70 <span
86 className="mdi mdi-power" 71 className="mdi mdi-power"
@@ -88,14 +73,13 @@ export default @observer class ServiceItem extends Component {
88 /> 73 />
89 )} 74 )}
90 </td> 75 </td>
91 <td 76 <td className="service-table__column-info" onClick={goToServiceForm}>
92 className="service-table__column-info"
93 onClick={goToServiceForm}
94 >
95 {!service.isNotificationEnabled && ( 77 {!service.isNotificationEnabled && (
96 <span 78 <span
97 className="mdi mdi-message-bulleted-off" 79 className="mdi mdi-message-bulleted-off"
98 data-tip={intl.formatMessage(messages.tooltipNotificationsDisabled)} 80 data-tip={intl.formatMessage(
81 messages.tooltipNotificationsDisabled,
82 )}
99 /> 83 />
100 )} 84 )}
101 <ReactTooltip place="top" type="dark" effect="solid" /> 85 <ReactTooltip place="top" type="dark" effect="solid" />
@@ -104,3 +88,5 @@ export default @observer class ServiceItem extends Component {
104 ); 88 );
105 } 89 }
106} 90}
91
92export default injectIntl(ServiceItem);
diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js
index 11d3eaa79..bb52db97f 100644
--- a/src/components/settings/services/ServicesDashboard.js
+++ b/src/components/settings/services/ServicesDashboard.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { Link } from 'react-router'; 4import { Link } from 'react-router';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6 6
7import SearchInput from '../../ui/SearchInput'; 7import SearchInput from '../../ui/SearchInput';
8import Infobox from '../../ui/Infobox'; 8import Infobox from '../../ui/Infobox';
@@ -14,43 +14,45 @@ import Appear from '../../ui/effects/Appear';
14const messages = defineMessages({ 14const messages = defineMessages({
15 headline: { 15 headline: {
16 id: 'settings.services.headline', 16 id: 'settings.services.headline',
17 defaultMessage: '!!!Your services', 17 defaultMessage: 'Your services',
18 }, 18 },
19 searchService: { 19 searchService: {
20 id: 'settings.searchService', 20 id: 'settings.searchService',
21 defaultMessage: '!!!Search service', 21 defaultMessage: 'Search service',
22 }, 22 },
23 noServicesAdded: { 23 noServicesAdded: {
24 id: 'settings.services.noServicesAdded', 24 id: 'settings.services.noServicesAdded',
25 defaultMessage: '!!!Start by adding a service.', 25 defaultMessage: 'Start by adding a service.',
26 }, 26 },
27 noServiceFound: { 27 noServiceFound: {
28 id: 'settings.recipes.nothingFound', 28 id: 'settings.services.nothingFound',
29 defaultMessage: '!!!Sorry, but no service matched your search term. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.', 29 defaultMessage:
30 'Sorry, but no service matched your search term - but you can still probably add it using the "Custom Website" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.',
30 }, 31 },
31 discoverServices: { 32 discoverServices: {
32 id: 'settings.services.discoverServices', 33 id: 'settings.services.discoverServices',
33 defaultMessage: '!!!Discover services', 34 defaultMessage: 'Discover services',
34 }, 35 },
35 servicesRequestFailed: { 36 servicesRequestFailed: {
36 id: 'settings.services.servicesRequestFailed', 37 id: 'settings.services.servicesRequestFailed',
37 defaultMessage: '!!!Could not load your services', 38 defaultMessage: 'Could not load your services',
38 }, 39 },
39 tryReloadServices: { 40 tryReloadServices: {
40 id: 'settings.account.tryReloadServices', 41 id: 'settings.account.tryReloadServices',
41 defaultMessage: '!!!Try again', 42 defaultMessage: 'Try again',
42 }, 43 },
43 updatedInfo: { 44 updatedInfo: {
44 id: 'settings.services.updatedInfo', 45 id: 'settings.services.updatedInfo',
45 defaultMessage: '!!!Your changes have been saved', 46 defaultMessage: 'Your changes have been saved',
46 }, 47 },
47 deletedInfo: { 48 deletedInfo: {
48 id: 'settings.services.deletedInfo', 49 id: 'settings.services.deletedInfo',
49 defaultMessage: '!!!Service has been deleted', 50 defaultMessage: 'Service has been deleted',
50 }, 51 },
51}); 52});
52 53
53export default @observer class ServicesDashboard extends Component { 54@observer
55class ServicesDashboard extends Component {
54 static propTypes = { 56 static propTypes = {
55 services: MobxPropTypes.arrayOrObservableArray.isRequired, 57 services: MobxPropTypes.arrayOrObservableArray.isRequired,
56 isLoading: PropTypes.bool.isRequired, 58 isLoading: PropTypes.bool.isRequired,
@@ -68,10 +70,6 @@ export default @observer class ServicesDashboard extends Component {
68 searchNeedle: '', 70 searchNeedle: '',
69 }; 71 };
70 72
71 static contextTypes = {
72 intl: intlShape,
73 };
74
75 render() { 73 render() {
76 const { 74 const {
77 services, 75 services,
@@ -85,7 +83,7 @@ export default @observer class ServicesDashboard extends Component {
85 status, 83 status,
86 searchNeedle, 84 searchNeedle,
87 } = this.props; 85 } = this.props;
88 const { intl } = this.context; 86 const { intl } = this.props;
89 87
90 return ( 88 return (
91 <div className="settings__main"> 89 <div className="settings__main">
@@ -93,10 +91,10 @@ export default @observer class ServicesDashboard extends Component {
93 <h1>{intl.formatMessage(messages.headline)}</h1> 91 <h1>{intl.formatMessage(messages.headline)}</h1>
94 </div> 92 </div>
95 <div className="settings__body"> 93 <div className="settings__body">
96 {(services.length !== 0 || searchNeedle) && !isLoading && ( 94 {(services.length > 0 || searchNeedle) && !isLoading && (
97 <SearchInput 95 <SearchInput
98 placeholder={intl.formatMessage(messages.searchService)} 96 placeholder={intl.formatMessage(messages.searchService)}
99 onChange={(needle) => filterServices({ needle })} 97 onChange={needle => filterServices({ needle })}
100 onReset={() => resetFilter()} 98 onReset={() => resetFilter()}
101 autoFocus 99 autoFocus
102 /> 100 />
@@ -145,7 +143,9 @@ export default @observer class ServicesDashboard extends Component {
145 </span> 143 </span>
146 {intl.formatMessage(messages.noServicesAdded)} 144 {intl.formatMessage(messages.noServicesAdded)}
147 </p> 145 </p>
148 <Link to="/settings/recipes" className="button">{intl.formatMessage(messages.discoverServices)}</Link> 146 <Link to="/settings/recipes" className="button">
147 {intl.formatMessage(messages.discoverServices)}
148 </Link>
149 </div> 149 </div>
150 )} 150 )}
151 {!isLoading && services.length === 0 && searchNeedle && ( 151 {!isLoading && services.length === 0 && searchNeedle && (
@@ -163,12 +163,16 @@ export default @observer class ServicesDashboard extends Component {
163 ) : ( 163 ) : (
164 <table className="service-table"> 164 <table className="service-table">
165 <tbody> 165 <tbody>
166 {services.map((service) => ( 166 {services.map(service => (
167 <ServiceItem 167 <ServiceItem
168 key={service.id} 168 key={service.id}
169 service={service} 169 service={service}
170 toggleAction={() => toggleService({ serviceId: service.id })} 170 toggleAction={() =>
171 goToServiceForm={() => goTo(`/settings/services/edit/${service.id}`)} 171 toggleService({ serviceId: service.id })
172 }
173 goToServiceForm={() =>
174 goTo(`/settings/services/edit/${service.id}`)
175 }
172 /> 176 />
173 ))} 177 ))}
174 </tbody> 178 </tbody>
@@ -176,12 +180,12 @@ export default @observer class ServicesDashboard extends Component {
176 )} 180 )}
177 181
178 <FAB> 182 <FAB>
179 <Link to="/settings/recipes"> 183 <Link to="/settings/recipes">+</Link>
180 +
181 </Link>
182 </FAB> 184 </FAB>
183 </div> 185 </div>
184 </div> 186 </div>
185 ); 187 );
186 } 188 }
187} 189}
190
191export default injectIntl(ServicesDashboard);
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index 6a919b902..123ab4c2d 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -3,7 +3,7 @@ import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { observer } from 'mobx-react'; 4import { observer } from 'mobx-react';
5import prettyBytes from 'pretty-bytes'; 5import prettyBytes from 'pretty-bytes';
6import { defineMessages, intlShape } from 'react-intl'; 6import { defineMessages, injectIntl } from 'react-intl';
7 7
8import Form from '../../../lib/Form'; 8import Form from '../../../lib/Form';
9import Button from '../../ui/Button'; 9import Button from '../../ui/Button';
@@ -12,155 +12,172 @@ import ToggleRaw from '../../ui/ToggleRaw';
12import Select from '../../ui/Select'; 12import Select from '../../ui/Select';
13import Input from '../../ui/Input'; 13import Input from '../../ui/Input';
14 14
15import { FRANZ_TRANSLATION, GITHUB_FRANZ_URL } from '../../../config'; 15import { DEFAULT_APP_SETTINGS, FRANZ_TRANSLATION, GITHUB_FRANZ_URL } from '../../../config';
16import { DEFAULT_APP_SETTINGS, ferdiVersion, isMac, isWindows, lockFerdiShortcutKey, userDataPath, userDataRecipesPath } from '../../../environment'; 16import {
17 isMac,
18 isWindows,
19 lockFerdiShortcutKey,
20} from '../../../environment';
21import { ferdiVersion, userDataPath, userDataRecipesPath } from '../../../environment-remote';
17import { openPath } from '../../../helpers/url-helpers'; 22import { openPath } from '../../../helpers/url-helpers';
18import globalMessages from '../../../i18n/globalMessages'; 23import globalMessages from '../../../i18n/globalMessages';
19 24
25const debug = require('debug')('Ferdi:EditSettingsForm');
26
20const messages = defineMessages({ 27const messages = defineMessages({
21 headlineGeneral: { 28 headlineGeneral: {
22 id: 'settings.app.headlineGeneral', 29 id: 'settings.app.headlineGeneral',
23 defaultMessage: '!!!General', 30 defaultMessage: 'General',
24 }, 31 },
25 sentryInfo: { 32 sentryInfo: {
26 id: 'settings.app.sentryInfo', 33 id: 'settings.app.sentryInfo',
27 defaultMessage: '!!!Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!', 34 defaultMessage:
35 'Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!',
28 }, 36 },
29 hibernateInfo: { 37 hibernateInfo: {
30 id: 'settings.app.hibernateInfo', 38 id: 'settings.app.hibernateInfo',
31 defaultMessage: '!!!By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.', 39 defaultMessage:
40 'By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.',
32 }, 41 },
33 inactivityLockInfo: { 42 inactivityLockInfo: {
34 id: 'settings.app.inactivityLockInfo', 43 id: 'settings.app.inactivityLockInfo',
35 defaultMessage: '!!!Minutes of inactivity, after which Ferdi should automatically lock. Use 0 to disable', 44 defaultMessage:
45 'Minutes of inactivity, after which Ferdi should automatically lock. Use 0 to disable',
36 }, 46 },
37 todoServerInfo: { 47 todoServerInfo: {
38 id: 'settings.app.todoServerInfo', 48 id: 'settings.app.todoServerInfo',
39 defaultMessage: '!!!This server will be used for the "Franz Todo" feature. (default: https://app.franztodos.com)', 49 defaultMessage: 'This server will be used for the "Ferdi Todo" feature.',
40 }, 50 },
41 lockedPassword: { 51 lockedPassword: {
42 id: 'settings.app.lockedPassword', 52 id: 'settings.app.lockedPassword',
43 defaultMessage: '!!!Password', 53 defaultMessage: 'Password',
44 }, 54 },
45 lockedPasswordInfo: { 55 lockedPasswordInfo: {
46 id: 'settings.app.lockedPasswordInfo', 56 id: 'settings.app.lockedPasswordInfo',
47 defaultMessage: '!!!Please make sure to set a password you\'ll remember.\nIf you loose this password, you will have to reinstall Ferdi.', 57 defaultMessage:
58 "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
48 }, 59 },
49 lockInfo: { 60 lockInfo: {
50 id: 'settings.app.lockInfo', 61 id: 'settings.app.lockInfo',
51 defaultMessage: '!!!Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.', 62 defaultMessage:
63 'Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.',
52 }, 64 },
53 scheduledDNDTimeInfo: { 65 scheduledDNDTimeInfo: {
54 id: 'settings.app.scheduledDNDTimeInfo', 66 id: 'settings.app.scheduledDNDTimeInfo',
55 defaultMessage: '!!!Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.', 67 defaultMessage:
68 'Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.',
56 }, 69 },
57 scheduledDNDInfo: { 70 scheduledDNDInfo: {
58 id: 'settings.app.scheduledDNDInfo', 71 id: 'settings.app.scheduledDNDInfo',
59 defaultMessage: '!!!Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.', 72 defaultMessage:
73 'Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.',
60 }, 74 },
61 headlineLanguage: { 75 headlineLanguage: {
62 id: 'settings.app.headlineLanguage', 76 id: 'settings.app.headlineLanguage',
63 defaultMessage: '!!!Language', 77 defaultMessage: 'Language',
64 }, 78 },
65 headlineUpdates: { 79 headlineUpdates: {
66 id: 'settings.app.headlineUpdates', 80 id: 'settings.app.headlineUpdates',
67 defaultMessage: '!!!Updates', 81 defaultMessage: 'Updates',
68 }, 82 },
69 headlineAppearance: { 83 headlineAppearance: {
70 id: 'settings.app.headlineAppearance', 84 id: 'settings.app.headlineAppearance',
71 defaultMessage: '!!!Appearance', 85 defaultMessage: 'Appearance',
72 }, 86 },
73 universalDarkModeInfo: { 87 universalDarkModeInfo: {
74 id: 'settings.app.universalDarkModeInfo', 88 id: 'settings.app.universalDarkModeInfo',
75 defaultMessage: '!!!Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.', 89 defaultMessage:
90 'Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.',
76 }, 91 },
77 accentColorInfo: { 92 accentColorInfo: {
78 id: 'settings.app.accentColorInfo', 93 id: 'settings.app.accentColorInfo',
79 defaultMessage: '!!!Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})', 94 defaultMessage:
95 'Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})',
80 }, 96 },
81 headlinePrivacy: { 97 headlinePrivacy: {
82 id: 'settings.app.headlinePrivacy', 98 id: 'settings.app.headlinePrivacy',
83 defaultMessage: '!!!Privacy', 99 defaultMessage: 'Privacy',
84 }, 100 },
85 headlineAdvanced: { 101 headlineAdvanced: {
86 id: 'settings.app.headlineAdvanced', 102 id: 'settings.app.headlineAdvanced',
87 defaultMessage: '!!!Advanced', 103 defaultMessage: 'Advanced',
88 }, 104 },
89 translationHelp: { 105 translationHelp: {
90 id: 'settings.app.translationHelp', 106 id: 'settings.app.translationHelp',
91 defaultMessage: '!!!Help us to translate Ferdi into your language.', 107 defaultMessage: 'Help us to translate Ferdi into your language.',
92 }, 108 },
93 spellCheckerLanguageInfo: { 109 spellCheckerLanguageInfo: {
94 id: 'settings.app.spellCheckerLanguageInfo', 110 id: 'settings.app.spellCheckerLanguageInfo',
95 defaultMessage: '!!!Ferdi uses your Mac\'s build-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac\'s System Preferences.', 111 defaultMessage:
112 "Ferdi uses your Mac's build-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.",
96 }, 113 },
97 subheadlineCache: { 114 subheadlineCache: {
98 id: 'settings.app.subheadlineCache', 115 id: 'settings.app.subheadlineCache',
99 defaultMessage: '!!!Cache', 116 defaultMessage: 'Cache',
100 }, 117 },
101 cacheInfo: { 118 cacheInfo: {
102 id: 'settings.app.cacheInfo', 119 id: 'settings.app.cacheInfo',
103 defaultMessage: '!!!Ferdi cache is currently using {size} of disk space.', 120 defaultMessage: 'Ferdi cache is currently using {size} of disk space.',
104 }, 121 },
105 cacheNotCleared: { 122 cacheNotCleared: {
106 id: 'settings.app.cacheNotCleared', 123 id: 'settings.app.cacheNotCleared',
107 defaultMessage: '!!!Couldn\'t clear all cache', 124 defaultMessage: "Couldn't clear all cache",
108 }, 125 },
109 buttonClearAllCache: { 126 buttonClearAllCache: {
110 id: 'settings.app.buttonClearAllCache', 127 id: 'settings.app.buttonClearAllCache',
111 defaultMessage: '!!!Clear cache', 128 defaultMessage: 'Clear cache',
112 }, 129 },
113 subheadlineFerdiProfile: { 130 subheadlineFerdiProfile: {
114 id: 'settings.app.subheadlineFerdiProfile', 131 id: 'settings.app.subheadlineFerdiProfile',
115 defaultMessage: '!!!Ferdi Profile', 132 defaultMessage: 'Ferdi Profile',
116 }, 133 },
117 buttonOpenFerdiProfileFolder: { 134 buttonOpenFerdiProfileFolder: {
118 id: 'settings.app.buttonOpenFerdiProfileFolder', 135 id: 'settings.app.buttonOpenFerdiProfileFolder',
119 defaultMessage: '!!!Open Profile folder', 136 defaultMessage: 'Open Profile folder',
120 }, 137 },
121 buttonOpenFerdiServiceRecipesFolder: { 138 buttonOpenFerdiServiceRecipesFolder: {
122 id: 'settings.app.buttonOpenFerdiServiceRecipesFolder', 139 id: 'settings.app.buttonOpenFerdiServiceRecipesFolder',
123 defaultMessage: '!!!Open Service Recipes folder', 140 defaultMessage: 'Open Service Recipes folder',
124 }, 141 },
125 buttonSearchForUpdate: { 142 buttonSearchForUpdate: {
126 id: 'settings.app.buttonSearchForUpdate', 143 id: 'settings.app.buttonSearchForUpdate',
127 defaultMessage: '!!!Check for updates', 144 defaultMessage: 'Check for updates',
128 }, 145 },
129 buttonInstallUpdate: { 146 buttonInstallUpdate: {
130 id: 'settings.app.buttonInstallUpdate', 147 id: 'settings.app.buttonInstallUpdate',
131 defaultMessage: '!!!Restart & install update', 148 defaultMessage: 'Restart & install update',
132 }, 149 },
133 updateStatusSearching: { 150 updateStatusSearching: {
134 id: 'settings.app.updateStatusSearching', 151 id: 'settings.app.updateStatusSearching',
135 defaultMessage: '!!!Is searching for update', 152 defaultMessage: 'Is searching for update',
136 }, 153 },
137 updateStatusAvailable: { 154 updateStatusAvailable: {
138 id: 'settings.app.updateStatusAvailable', 155 id: 'settings.app.updateStatusAvailable',
139 defaultMessage: '!!!Update available, downloading...', 156 defaultMessage: 'Update available, downloading...',
140 }, 157 },
141 updateStatusUpToDate: { 158 updateStatusUpToDate: {
142 id: 'settings.app.updateStatusUpToDate', 159 id: 'settings.app.updateStatusUpToDate',
143 defaultMessage: '!!!You are using the latest version of Ferdi', 160 defaultMessage: 'You are using the latest version of Ferdi',
144 }, 161 },
145 currentVersion: { 162 currentVersion: {
146 id: 'settings.app.currentVersion', 163 id: 'settings.app.currentVersion',
147 defaultMessage: '!!!Current version:', 164 defaultMessage: 'Current version:',
148 }, 165 },
149 appRestartRequired: { 166 appRestartRequired: {
150 id: 'settings.app.restartRequired', 167 id: 'settings.app.restartRequired',
151 defaultMessage: '!!!Changes require restart', 168 defaultMessage: 'Changes require restart',
152 }, 169 },
153 languageDisclaimer: { 170 languageDisclaimer: {
154 id: 'settings.app.languageDisclaimer', 171 id: 'settings.app.languageDisclaimer',
155 defaultMessage: '!!!Official translations are English & German. All other languages are community based translations.', 172 defaultMessage:
173 'Official translations are English & German. All other languages are community based translations.',
156 }, 174 },
157}); 175});
158 176
159const Hr = () => ( 177const Hr = () => <hr style={{ marginBottom: 20 }} />;
160 <hr style={{ marginBottom: 20 }} />
161);
162 178
163export default @observer class EditSettingsForm extends Component { 179@observer
180class EditSettingsForm extends Component {
164 static propTypes = { 181 static propTypes = {
165 checkForUpdates: PropTypes.func.isRequired, 182 checkForUpdates: PropTypes.func.isRequired,
166 installUpdate: PropTypes.func.isRequired, 183 installUpdate: PropTypes.func.isRequired,
@@ -184,14 +201,10 @@ export default @observer class EditSettingsForm extends Component {
184 isOnline: PropTypes.bool.isRequired, 201 isOnline: PropTypes.bool.isRequired,
185 }; 202 };
186 203
187 static contextTypes = {
188 intl: intlShape,
189 };
190
191 state = { 204 state = {
192 activeSetttingsTab: 'general', 205 activeSetttingsTab: 'general',
193 clearCacheButtonClicked: false, 206 clearCacheButtonClicked: false,
194 } 207 };
195 208
196 setActiveSettingsTab(tab) { 209 setActiveSettingsTab(tab) {
197 this.setState({ 210 this.setState({
@@ -199,14 +212,14 @@ export default @observer class EditSettingsForm extends Component {
199 }); 212 });
200 } 213 }
201 214
202 onClearCacheClicked=() => { 215 onClearCacheClicked = () => {
203 this.setState({ clearCacheButtonClicked: true }); 216 this.setState({ clearCacheButtonClicked: true });
204 } 217 };
205 218
206 submit(e) { 219 submit(e) {
207 e.preventDefault(); 220 e.preventDefault();
208 this.props.form.submit({ 221 this.props.form.submit({
209 onSuccess: (form) => { 222 onSuccess: form => {
210 const values = form.values(); 223 const values = form.values();
211 this.props.onSubmit(values); 224 this.props.onSubmit(values);
212 }, 225 },
@@ -236,7 +249,7 @@ export default @observer class EditSettingsForm extends Component {
236 hasAddedTodosAsService, 249 hasAddedTodosAsService,
237 isOnline, 250 isOnline,
238 } = this.props; 251 } = this.props;
239 const { intl } = this.context; 252 const { intl } = this.props;
240 253
241 let updateButtonLabelMessage = messages.buttonSearchForUpdate; 254 let updateButtonLabelMessage = messages.buttonSearchForUpdate;
242 if (isCheckingForUpdates) { 255 if (isCheckingForUpdates) {
@@ -247,18 +260,21 @@ export default @observer class EditSettingsForm extends Component {
247 updateButtonLabelMessage = messages.buttonSearchForUpdate; 260 updateButtonLabelMessage = messages.buttonSearchForUpdate;
248 } 261 }
249 262
250 const { 263 const { lockingFeatureEnabled, scheduledDNDEnabled } =
251 lockingFeatureEnabled, 264 window.ferdi.stores.settings.all.app;
252 scheduledDNDEnabled,
253 } = window.ferdi.stores.settings.all.app;
254 265
255 let cacheSize; 266 let cacheSize;
256 let notCleared; 267 let notCleared;
257 if (this.state.activeSetttingsTab === 'advanced') { 268 if (this.state.activeSetttingsTab === 'advanced') {
258 const cacheSizeBytes = getCacheSize(); 269 const cacheSizeBytes = getCacheSize();
270 debug('cacheSizeBytes:', cacheSizeBytes);
259 if (typeof cacheSizeBytes === 'number') { 271 if (typeof cacheSizeBytes === 'number') {
260 cacheSize = prettyBytes(cacheSizeBytes); 272 cacheSize = prettyBytes(cacheSizeBytes);
261 notCleared = this.state.clearCacheButtonClicked && isClearingAllCache === false && cacheSizeBytes !== 0; 273 debug('cacheSize:', cacheSize);
274 notCleared =
275 this.state.clearCacheButtonClicked &&
276 isClearingAllCache === false &&
277 cacheSizeBytes !== 0;
262 } else { 278 } else {
263 cacheSize = '…'; 279 cacheSize = '…';
264 notCleared = false; 280 notCleared = false;
@@ -275,58 +291,94 @@ export default @observer class EditSettingsForm extends Component {
275 </div> 291 </div>
276 <div className="settings__body"> 292 <div className="settings__body">
277 <form 293 <form
278 onSubmit={(e) => this.submit(e)} 294 onSubmit={e => this.submit(e)}
279 onChange={(e) => this.submit(e)} 295 onChange={e => this.submit(e)}
280 id="form" 296 id="form"
281 > 297 >
282 {/* Titles */} 298 {/* Titles */}
283 <div className="recipes__navigation"> 299 <div className="recipes__navigation">
284 <h2 300 <h2
285 id="general" 301 id="general"
286 className={this.state.activeSetttingsTab === 'general' ? 'badge badge--primary' : 'badge'} 302 className={
287 onClick={() => { this.setActiveSettingsTab('general'); }} 303 this.state.activeSetttingsTab === 'general'
304 ? 'badge badge--primary'
305 : 'badge'
306 }
307 onClick={() => {
308 this.setActiveSettingsTab('general');
309 }}
288 > 310 >
289 {intl.formatMessage(messages.headlineGeneral)} 311 {intl.formatMessage(messages.headlineGeneral)}
290 </h2> 312 </h2>
291 <h2 313 <h2
292 id="appearance" 314 id="appearance"
293 className={this.state.activeSetttingsTab === 'appearance' ? 'badge badge--primary' : 'badge'} 315 className={
294 onClick={() => { this.setActiveSettingsTab('appearance'); }} 316 this.state.activeSetttingsTab === 'appearance'
317 ? 'badge badge--primary'
318 : 'badge'
319 }
320 onClick={() => {
321 this.setActiveSettingsTab('appearance');
322 }}
295 > 323 >
296 {intl.formatMessage(messages.headlineAppearance)} 324 {intl.formatMessage(messages.headlineAppearance)}
297 </h2> 325 </h2>
298 <h2 326 <h2
299 id="privacy" 327 id="privacy"
300 className={this.state.activeSetttingsTab === 'privacy' ? 'badge badge--primary' : 'badge'} 328 className={
301 onClick={() => { this.setActiveSettingsTab('privacy'); }} 329 this.state.activeSetttingsTab === 'privacy'
330 ? 'badge badge--primary'
331 : 'badge'
332 }
333 onClick={() => {
334 this.setActiveSettingsTab('privacy');
335 }}
302 > 336 >
303 {intl.formatMessage(messages.headlinePrivacy)} 337 {intl.formatMessage(messages.headlinePrivacy)}
304 </h2> 338 </h2>
305 <h2 339 <h2
306 id="language" 340 id="language"
307 className={this.state.activeSetttingsTab === 'language' ? 'badge badge--primary' : 'badge'} 341 className={
308 onClick={() => { this.setActiveSettingsTab('language'); }} 342 this.state.activeSetttingsTab === 'language'
343 ? 'badge badge--primary'
344 : 'badge'
345 }
346 onClick={() => {
347 this.setActiveSettingsTab('language');
348 }}
309 > 349 >
310 {intl.formatMessage(messages.headlineLanguage)} 350 {intl.formatMessage(messages.headlineLanguage)}
311 </h2> 351 </h2>
312 <h2 352 <h2
313 id="advanced" 353 id="advanced"
314 className={this.state.activeSetttingsTab === 'advanced' ? 'badge badge--primary' : 'badge'} 354 className={
315 onClick={() => { this.setActiveSettingsTab('advanced'); }} 355 this.state.activeSetttingsTab === 'advanced'
356 ? 'badge badge--primary'
357 : 'badge'
358 }
359 onClick={() => {
360 this.setActiveSettingsTab('advanced');
361 }}
316 > 362 >
317 {intl.formatMessage(messages.headlineAdvanced)} 363 {intl.formatMessage(messages.headlineAdvanced)}
318 </h2> 364 </h2>
319 <h2 365 <h2
320 id="updates" 366 id="updates"
321 className={this.state.activeSetttingsTab === 'updates' ? 'badge badge--primary' : 'badge'} 367 className={
322 onClick={() => { this.setActiveSettingsTab('updates'); }} 368 this.state.activeSetttingsTab === 'updates'
369 ? 'badge badge--primary'
370 : 'badge'
371 }
372 onClick={() => {
373 this.setActiveSettingsTab('updates');
374 }}
323 > 375 >
324 {intl.formatMessage(messages.headlineUpdates)} 376 {intl.formatMessage(messages.headlineUpdates)}
325 </h2> 377 </h2>
326 </div> 378 </div>
327 379
328 {/* General */} 380 {/* General */}
329 { this.state.activeSetttingsTab === 'general' && ( 381 {this.state.activeSetttingsTab === 'general' && (
330 <div> 382 <div>
331 <Toggle field={form.$('autoLaunchOnStart')} /> 383 <Toggle field={form.$('autoLaunchOnStart')} />
332 <Toggle field={form.$('runInBackground')} /> 384 <Toggle field={form.$('runInBackground')} />
@@ -334,12 +386,8 @@ export default @observer class EditSettingsForm extends Component {
334 <Toggle field={form.$('enableSystemTray')} /> 386 <Toggle field={form.$('enableSystemTray')} />
335 <Toggle field={form.$('reloadAfterResume')} /> 387 <Toggle field={form.$('reloadAfterResume')} />
336 <Toggle field={form.$('startMinimized')} /> 388 <Toggle field={form.$('startMinimized')} />
337 {isWindows && ( 389 {isWindows && <Toggle field={form.$('minimizeToSystemTray')} />}
338 <Toggle field={form.$('minimizeToSystemTray')} /> 390 {isWindows && <Toggle field={form.$('closeToSystemTray')} />}
339 )}
340 {isWindows && (
341 <Toggle field={form.$('closeToSystemTray')} />
342 )}
343 <Select field={form.$('navigationBarBehaviour')} /> 391 <Select field={form.$('navigationBarBehaviour')} />
344 392
345 <Hr /> 393 <Hr />
@@ -349,12 +397,13 @@ export default @observer class EditSettingsForm extends Component {
349 <p 397 <p
350 className="settings__message" 398 className="settings__message"
351 style={{ 399 style={{
352 borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', 400 borderTop: 0,
401 marginTop: 0,
402 paddingTop: 0,
403 marginBottom: '2rem',
353 }} 404 }}
354 > 405 >
355 <span> 406 <span>{intl.formatMessage(messages.hibernateInfo)}</span>
356 { intl.formatMessage(messages.hibernateInfo) }
357 </span>
358 </p> 407 </p>
359 408
360 <Select field={form.$('wakeUpStrategy')} /> 409 <Select field={form.$('wakeUpStrategy')} />
@@ -374,20 +423,24 @@ export default @observer class EditSettingsForm extends Component {
374 {isTodosActivated && ( 423 {isTodosActivated && (
375 <div> 424 <div>
376 <Select field={form.$('predefinedTodoServer')} /> 425 <Select field={form.$('predefinedTodoServer')} />
377 {form.$('predefinedTodoServer').value === 'isUsingCustomTodoService' && ( 426 {form.$('predefinedTodoServer').value ===
427 'isUsingCustomTodoService' && (
378 <div> 428 <div>
379 <Input 429 <Input
380 placeholder="Todo Server" 430 placeholder="Todo Server"
381 onChange={(e) => this.submit(e)} 431 onChange={e => this.submit(e)}
382 field={form.$('customTodoServer')} 432 field={form.$('customTodoServer')}
383 /> 433 />
384 <p 434 <p
385 className="settings__message" 435 className="settings__message"
386 style={{ 436 style={{
387 borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', 437 borderTop: 0,
438 marginTop: 0,
439 paddingTop: 0,
440 marginBottom: '2rem',
388 }} 441 }}
389 > 442 >
390 { intl.formatMessage(messages.todoServerInfo) } 443 {intl.formatMessage(messages.todoServerInfo)}
391 </p> 444 </p>
392 </div> 445 </div>
393 )} 446 )}
@@ -400,56 +453,58 @@ export default @observer class EditSettingsForm extends Component {
400 <Toggle field={form.$('scheduledDNDEnabled')} /> 453 <Toggle field={form.$('scheduledDNDEnabled')} />
401 {scheduledDNDEnabled && ( 454 {scheduledDNDEnabled && (
402 <> 455 <>
403 <div style={{ 456 <div
404 display: 'flex', 457 style={{
405 justifyContent: 'center', 458 display: 'flex',
406 }} 459 justifyContent: 'center',
407 >
408 <div style={{
409 padding: '0 1rem',
410 width: '100%',
411 }} 460 }}
461 >
462 <div
463 style={{
464 padding: '0 1rem',
465 width: '100%',
466 }}
412 > 467 >
413 <Input 468 <Input
414 placeholder="17:00" 469 placeholder="17:00"
415 onChange={(e) => this.submit(e)} 470 onChange={e => this.submit(e)}
416 field={form.$('scheduledDNDStart')} 471 field={form.$('scheduledDNDStart')}
417 type="time" 472 type="time"
418 /> 473 />
419 </div> 474 </div>
420 <div style={{ 475 <div
421 padding: '0 1rem', 476 style={{
422 width: '100%', 477 padding: '0 1rem',
423 }} 478 width: '100%',
479 }}
424 > 480 >
425 <Input 481 <Input
426 placeholder="09:00" 482 placeholder="09:00"
427 onChange={(e) => this.submit(e)} 483 onChange={e => this.submit(e)}
428 field={form.$('scheduledDNDEnd')} 484 field={form.$('scheduledDNDEnd')}
429 type="time" 485 type="time"
430 /> 486 />
431 </div> 487 </div>
432 </div> 488 </div>
433 <p> 489 <p>{intl.formatMessage(messages.scheduledDNDTimeInfo)}</p>
434 { intl.formatMessage(messages.scheduledDNDTimeInfo) }
435 </p>
436 </> 490 </>
437 )} 491 )}
438 <p 492 <p
439 className="settings__message" 493 className="settings__message"
440 style={{ 494 style={{
441 borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', 495 borderTop: 0,
496 marginTop: 0,
497 paddingTop: 0,
498 marginBottom: '2rem',
442 }} 499 }}
443 > 500 >
444 <span> 501 <span>{intl.formatMessage(messages.scheduledDNDInfo)}</span>
445 { intl.formatMessage(messages.scheduledDNDInfo) }
446 </span>
447 </p> 502 </p>
448 </div> 503 </div>
449 )} 504 )}
450 505
451 {/* Appearance */} 506 {/* Appearance */}
452 { this.state.activeSetttingsTab === 'appearance' && ( 507 {this.state.activeSetttingsTab === 'appearance' && (
453 <div> 508 <div>
454 <Toggle field={form.$('showDisabledServices')} /> 509 <Toggle field={form.$('showDisabledServices')} />
455 <Toggle field={form.$('showMessageBadgeWhenMuted')} /> 510 <Toggle field={form.$('showMessageBadgeWhenMuted')} />
@@ -459,25 +514,34 @@ export default @observer class EditSettingsForm extends Component {
459 <Hr /> 514 <Hr />
460 515
461 <Toggle field={form.$('adaptableDarkMode')} /> 516 <Toggle field={form.$('adaptableDarkMode')} />
462 {!isAdaptableDarkModeEnabled && <Toggle field={form.$('darkMode')} />} 517 {!isAdaptableDarkModeEnabled && (
518 <Toggle field={form.$('darkMode')} />
519 )}
463 {(isDarkmodeEnabled || isAdaptableDarkModeEnabled) && ( 520 {(isDarkmodeEnabled || isAdaptableDarkModeEnabled) && (
464 <> 521 <>
465 <Toggle field={form.$('universalDarkMode')} /> 522 <Toggle field={form.$('universalDarkMode')} />
466 <p 523 <p
467 className="settings__message" 524 className="settings__message"
468 style={{ 525 style={{
469 borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', 526 borderTop: 0,
470 }} 527 marginTop: 0,
471 > 528 paddingTop: 0,
472 <span> 529 marginBottom: '2rem',
473 { intl.formatMessage(messages.universalDarkModeInfo) } 530 }}
474 </span> 531 >
475 </p> 532 <span>
476 </> 533 {intl.formatMessage(messages.universalDarkModeInfo)}
534 </span>
535 </p>
536 </>
477 )} 537 )}
478 538
479 <Hr /> 539 <Hr />
480 540
541 <Toggle field={form.$('splitMode')} />
542
543 <Hr />
544
481 <Select field={form.$('serviceRibbonWidth')} /> 545 <Select field={form.$('serviceRibbonWidth')} />
482 546
483 <Toggle field={form.$('useVerticalStyle')} /> 547 <Toggle field={form.$('useVerticalStyle')} />
@@ -491,23 +555,25 @@ export default @observer class EditSettingsForm extends Component {
491 555
492 <Input 556 <Input
493 placeholder="Accent Color" 557 placeholder="Accent Color"
494 onChange={(e) => this.submit(e)} 558 onChange={e => this.submit(e)}
495 field={form.$('accentColor')} 559 field={form.$('accentColor')}
496 /> 560 />
497 <p> 561 <p>
498 {intl.formatMessage(messages.accentColorInfo, 562 {intl.formatMessage(messages.accentColorInfo, {
499 { defaultAccentColor: DEFAULT_APP_SETTINGS.accentColor })} 563 defaultAccentColor: DEFAULT_APP_SETTINGS.accentColor,
564 })}
500 </p> 565 </p>
501 </div> 566 </div>
502 )} 567 )}
503 568
504 {/* Privacy */} 569 {/* Privacy */}
505 { this.state.activeSetttingsTab === 'privacy' && ( 570 {this.state.activeSetttingsTab === 'privacy' && (
506 <div> 571 <div>
507 <Toggle field={form.$('privateNotifications')} /> 572 <Toggle field={form.$('privateNotifications')} />
508 <Toggle field={form.$('clipboardNotifications')} /> 573 <Toggle field={form.$('clipboardNotifications')} />
509 {(isWindows || isMac) && ( 574 {(isWindows || isMac) && (
510 <Toggle field={form.$('notifyTaskBarOnMessage')} />)} 575 <Toggle field={form.$('notifyTaskBarOnMessage')} />
576 )}
511 577
512 <Hr /> 578 <Hr />
513 579
@@ -516,8 +582,12 @@ export default @observer class EditSettingsForm extends Component {
516 <Hr /> 582 <Hr />
517 583
518 <Toggle field={form.$('sentry')} /> 584 <Toggle field={form.$('sentry')} />
519 <p className="settings__help">{intl.formatMessage(messages.sentryInfo)}</p> 585 <p className="settings__help">
520 <p className="settings__help">{intl.formatMessage(messages.appRestartRequired)}</p> 586 {intl.formatMessage(messages.sentryInfo)}
587 </p>
588 <p className="settings__help">
589 {intl.formatMessage(messages.appRestartRequired)}
590 </p>
521 591
522 <Hr /> 592 <Hr />
523 593
@@ -530,57 +600,60 @@ export default @observer class EditSettingsForm extends Component {
530 600
531 <Input 601 <Input
532 placeholder={intl.formatMessage(messages.lockedPassword)} 602 placeholder={intl.formatMessage(messages.lockedPassword)}
533 onChange={(e) => this.submit(e)} 603 onChange={e => this.submit(e)}
534 field={form.$('lockedPassword')} 604 field={form.$('lockedPassword')}
535 type="password" 605 type="password"
536 scorePassword 606 scorePassword
537 showPasswordToggle 607 showPasswordToggle
538 /> 608 />
539 <p> 609 <p>{intl.formatMessage(messages.lockedPasswordInfo)}</p>
540 { intl.formatMessage(messages.lockedPasswordInfo) }
541 </p>
542 610
543 <Input 611 <Input
544 placeholder="Lock after inactivity" 612 placeholder="Lock after inactivity"
545 onChange={(e) => this.submit(e)} 613 onChange={e => this.submit(e)}
546 field={form.$('inactivityLock')} 614 field={form.$('inactivityLock')}
547 autoFocus 615 autoFocus
548 /> 616 />
549 <p> 617 <p>{intl.formatMessage(messages.inactivityLockInfo)}</p>
550 { intl.formatMessage(messages.inactivityLockInfo) }
551 </p>
552 </> 618 </>
553 )} 619 )}
554 <p 620 <p
555 className="settings__message" 621 className="settings__message"
556 style={{ 622 style={{
557 borderTop: 0, marginTop: 0, paddingTop: 0, marginBottom: '2rem', 623 borderTop: 0,
624 marginTop: 0,
625 paddingTop: 0,
626 marginBottom: '2rem',
558 }} 627 }}
559 > 628 >
560 <span> 629 <span>
561 { intl.formatMessage(messages.lockInfo, { lockShortcut: `${lockFerdiShortcutKey(false)}` }) } 630 {intl.formatMessage(messages.lockInfo, {
631 lockShortcut: `${lockFerdiShortcutKey(false)}`,
632 })}
562 </span> 633 </span>
563 </p> 634 </p>
564 </div> 635 </div>
565 )} 636 )}
566 637
567 {/* Language */} 638 {/* Language */}
568 { this.state.activeSetttingsTab === 'language' && ( 639 {this.state.activeSetttingsTab === 'language' && (
569 <div> 640 <div>
570 <Select field={form.$('locale')} showLabel={false} /> 641 <Select field={form.$('locale')} showLabel={false} />
571 642
572 <Hr /> 643 <Hr />
573 644
574 <Toggle 645 <Toggle field={form.$('enableSpellchecking')} />
575 field={form.$('enableSpellchecking')}
576 />
577 {!isMac && form.$('enableSpellchecking').value && ( 646 {!isMac && form.$('enableSpellchecking').value && (
578 <Select field={form.$('spellcheckerLanguage')} /> 647 <Select field={form.$('spellcheckerLanguage')} />
579 )} 648 )}
580 {isMac && form.$('enableSpellchecking').value && ( 649 {isMac && form.$('enableSpellchecking').value && (
581 <p className="settings__help">{intl.formatMessage(messages.spellCheckerLanguageInfo)}</p> 650 <p className="settings__help">
651 {intl.formatMessage(messages.spellCheckerLanguageInfo)}
652 </p>
582 )} 653 )}
583 <p className="settings__help">{intl.formatMessage(messages.appRestartRequired)}</p> 654 <p className="settings__help">
655 {intl.formatMessage(messages.appRestartRequired)}
656 </p>
584 657
585 <Hr /> 658 <Hr />
586 659
@@ -590,52 +663,54 @@ export default @observer class EditSettingsForm extends Component {
590 className="link" 663 className="link"
591 rel="noreferrer" 664 rel="noreferrer"
592 > 665 >
593 {intl.formatMessage(messages.translationHelp)} 666 {intl.formatMessage(messages.translationHelp)}{' '}
594 {' '}
595 <i className="mdi mdi-open-in-new" /> 667 <i className="mdi mdi-open-in-new" />
596 </a> 668 </a>
597 </div> 669 </div>
598 )} 670 )}
599 671
600 {/* Advanced */} 672 {/* Advanced */}
601 { this.state.activeSetttingsTab === 'advanced' && ( 673 {this.state.activeSetttingsTab === 'advanced' && (
602 <div> 674 <div>
603 <Toggle field={form.$('enableGPUAcceleration')} /> 675 <Toggle field={form.$('enableGPUAcceleration')} />
604 <p className="settings__help indented__help">{intl.formatMessage(messages.appRestartRequired)}</p> 676 <p className="settings__help indented__help">
677 {intl.formatMessage(messages.appRestartRequired)}
678 </p>
605 679
606 <Hr /> 680 <Hr />
607 681
608 <Input 682 <Input
609 placeholder="User Agent" 683 placeholder="User Agent"
610 onChange={(e) => this.submit(e)} 684 onChange={e => this.submit(e)}
611 field={form.$('userAgentPref')} 685 field={form.$('userAgentPref')}
612 /> 686 />
613 <p className="settings__help">{intl.formatMessage(globalMessages.userAgentHelp)}</p> 687 <p className="settings__help">
614 <p className="settings__help">{intl.formatMessage(messages.appRestartRequired)}</p> 688 {intl.formatMessage(globalMessages.userAgentHelp)}
689 </p>
690 <p className="settings__help">
691 {intl.formatMessage(messages.appRestartRequired)}
692 </p>
615 693
616 <Hr /> 694 <Hr />
617 695
618 <div className="settings__settings-group"> 696 <div className="settings__settings-group">
619 <h3> 697 <h3>{intl.formatMessage(messages.subheadlineCache)}</h3>
620 {intl.formatMessage(messages.subheadlineCache)}
621 </h3>
622 <p> 698 <p>
623 {intl.formatMessage(messages.cacheInfo, { 699 {intl.formatMessage(messages.cacheInfo, {
624 size: cacheSize, 700 size: cacheSize,
625 })} 701 })}
626 </p> 702 </p>
627 { 703 {notCleared && (
628 notCleared && ( 704 <p>{intl.formatMessage(messages.cacheNotCleared)}</p>
629 <p> 705 )}
630 {intl.formatMessage(messages.cacheNotCleared)}
631 </p>
632 )
633 }
634 <p> 706 <p>
635 <Button 707 <Button
636 buttonType="secondary" 708 buttonType="secondary"
637 label={intl.formatMessage(messages.buttonClearAllCache)} 709 label={intl.formatMessage(messages.buttonClearAllCache)}
638 onClick={() => { onClearAllCache(); this.onClearCacheClicked(); }} 710 onClick={() => {
711 onClearAllCache();
712 this.onClearCacheClicked();
713 }}
639 disabled={isClearingAllCache} 714 disabled={isClearingAllCache}
640 loaded={!isClearingAllCache} 715 loaded={!isClearingAllCache}
641 /> 716 />
@@ -652,13 +727,17 @@ export default @observer class EditSettingsForm extends Component {
652 <div className="settings__open-settings-file-container"> 727 <div className="settings__open-settings-file-container">
653 <Button 728 <Button
654 buttonType="secondary" 729 buttonType="secondary"
655 label={intl.formatMessage(messages.buttonOpenFerdiProfileFolder)} 730 label={intl.formatMessage(
731 messages.buttonOpenFerdiProfileFolder,
732 )}
656 className="settings__open-settings-file-button" 733 className="settings__open-settings-file-button"
657 onClick={() => openPath(profileFolder)} 734 onClick={() => openPath(profileFolder)}
658 /> 735 />
659 <Button 736 <Button
660 buttonType="secondary" 737 buttonType="secondary"
661 label={intl.formatMessage(messages.buttonOpenFerdiServiceRecipesFolder)} 738 label={intl.formatMessage(
739 messages.buttonOpenFerdiServiceRecipesFolder,
740 )}
662 className="settings__open-settings-file-button" 741 className="settings__open-settings-file-button"
663 onClick={() => openPath(recipeFolder)} 742 onClick={() => openPath(recipeFolder)}
664 /> 743 />
@@ -669,66 +748,78 @@ export default @observer class EditSettingsForm extends Component {
669 )} 748 )}
670 749
671 {/* Updates */} 750 {/* Updates */}
672 { this.state.activeSetttingsTab === 'updates' && ( 751 {this.state.activeSetttingsTab === 'updates' && (
673 <div>
674 <Toggle field={form.$('automaticUpdates')} />
675 {automaticUpdates && (
676 <div> 752 <div>
677 <Toggle field={form.$('beta')} /> 753 <Toggle field={form.$('automaticUpdates')} />
678 <ToggleRaw 754 {automaticUpdates && (
679 field={{ 755 <div>
680 value: isNightlyEnabled, 756 <Toggle field={form.$('beta')} />
681 id: 'nightly', 757 <ToggleRaw
682 label: 'Include nightly versions', 758 field={{
683 name: 'Nightly builds', 759 value: isNightlyEnabled,
684 }} 760 id: 'nightly',
685 onChange={window.ferdi.features.nightlyBuilds.toggleFeature} 761 label: 'Include nightly versions',
686 /> 762 name: 'Nightly builds',
687 {updateIsReadyToInstall ? ( 763 }}
688 <Button 764 onChange={
689 label={intl.formatMessage(messages.buttonInstallUpdate)} 765 window.ferdi.features.nightlyBuilds.toggleFeature
690 onClick={installUpdate} 766 }
691 /> 767 />
692 ) : ( 768 {updateIsReadyToInstall ? (
693 <Button 769 <Button
694 buttonType="secondary" 770 label={intl.formatMessage(messages.buttonInstallUpdate)}
695 label={intl.formatMessage(updateButtonLabelMessage)} 771 onClick={installUpdate}
696 onClick={checkForUpdates} 772 />
697 disabled={!automaticUpdates || isCheckingForUpdates || isUpdateAvailable || !isOnline} 773 ) : (
698 loaded={!isCheckingForUpdates || !isUpdateAvailable} 774 <Button
699 /> 775 buttonType="secondary"
776 label={intl.formatMessage(updateButtonLabelMessage)}
777 onClick={checkForUpdates}
778 disabled={
779 !automaticUpdates ||
780 isCheckingForUpdates ||
781 isUpdateAvailable ||
782 !isOnline
783 }
784 loaded={!isCheckingForUpdates || !isUpdateAvailable}
785 />
786 )}
787 <br />
788 </div>
789 )}
790 {intl.formatMessage(messages.currentVersion)} {ferdiVersion}
791 {noUpdateAvailable && (
792 <>
793 <br />
794 <br />
795 {intl.formatMessage(messages.updateStatusUpToDate)}
796 </>
700 )} 797 )}
701 <br /> 798 <p className="settings__message">
799 <span className="mdi mdi-github-face" />
800 <span>
801 Ferdi is based on{' '}
802 <a
803 href={`${GITHUB_FRANZ_URL}/franz`}
804 target="_blank"
805 rel="noreferrer"
806 >
807 Franz
808 </a>
809 , a project published under the{' '}
810 <a
811 href={`${GITHUB_FRANZ_URL}/franz/blob/master/LICENSE`}
812 target="_blank"
813 rel="noreferrer"
814 >
815 Apache-2.0 License
816 </a>
817 </span>
818 <br />
819 <span className="mdi mdi-information" />
820 {intl.formatMessage(messages.languageDisclaimer)}
821 </p>
702 </div> 822 </div>
703 )}
704 {intl.formatMessage(messages.currentVersion)}
705 {' '}
706 {ferdiVersion}
707 {noUpdateAvailable && (
708 <>
709 <br />
710 <br />
711 {intl.formatMessage(messages.updateStatusUpToDate)}
712 </>
713 )}
714 <p className="settings__message">
715 <span className="mdi mdi-github-face" />
716 <span>
717
718 Ferdi is based on
719 {' '}
720 <a href={`${GITHUB_FRANZ_URL}/franz`} target="_blank" rel="noreferrer">Franz</a>
721
722 , a project published
723 under the
724 {' '}
725 <a href={`${GITHUB_FRANZ_URL}/franz/blob/master/LICENSE`} target="_blank" rel="noreferrer">Apache-2.0 License</a>
726 </span>
727 <br />
728 <span className="mdi mdi-information" />
729 {intl.formatMessage(messages.languageDisclaimer)}
730 </p>
731 </div>
732 )} 823 )}
733 </form> 824 </form>
734 </div> 825 </div>
@@ -736,3 +827,5 @@ export default @observer class EditSettingsForm extends Component {
736 ); 827 );
737 } 828 }
738} 829}
830
831export default injectIntl(EditSettingsForm);
diff --git a/src/components/settings/supportFerdi/SupportFerdiDashboard.js b/src/components/settings/supportFerdi/SupportFerdiDashboard.js
index b84e06739..f24e4bd62 100644
--- a/src/components/settings/supportFerdi/SupportFerdiDashboard.js
+++ b/src/components/settings/supportFerdi/SupportFerdiDashboard.js
@@ -1,76 +1,77 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import { defineMessages, FormattedHTMLMessage, intlShape } from 'react-intl'; 2import { defineMessages, injectIntl } from 'react-intl';
3import { BrowserWindow } from '@electron/remote'; 3import { BrowserWindow } from '@electron/remote';
4import InfoBar from '../../ui/InfoBar'; 4import InfoBar from '../../ui/InfoBar';
5 5
6const messages = defineMessages({ 6const messages = defineMessages({
7 headline: { 7 headline: {
8 id: 'settings.supportFerdi.headline', 8 id: 'settings.supportFerdi.headline',
9 defaultMessage: '!!!About Ferdi', 9 defaultMessage: 'About Ferdi',
10 }, 10 },
11 title: { 11 title: {
12 id: 'settings.supportFerdi.title', 12 id: 'settings.supportFerdi.title',
13 defaultMessage: '!!!Do you like Ferdi?', 13 defaultMessage: 'Do you like Ferdi?',
14 }, 14 },
15 aboutIntro: { 15 aboutIntro: {
16 id: 'settings.supportFerdi.aboutIntro', 16 id: 'settings.supportFerdi.aboutIntro',
17 defaultMessage: '!!!<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>', 17 defaultMessage:
18 '<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>',
18 }, 19 },
19 textListContributors: { 20 textListContributors: {
20 id: 'settings.supportFerdi.textListContributors', 21 id: 'settings.supportFerdi.textListContributors',
21 defaultMessage: '!!!Full list of contributor', 22 defaultMessage: 'Full list of contributors',
22 }, 23 },
23 textListContributorsHere: { 24 textListContributorsHere: {
24 id: 'settings.supportFerdi.textListContributorsHere', 25 id: 'settings.supportFerdi.textListContributorsHere',
25 defaultMessage: '!!!here', 26 defaultMessage: 'here',
26 }, 27 },
27 textVolunteers: { 28 textVolunteers: {
28 id: 'settings.supportFerdi.textVolunteers', 29 id: 'settings.supportFerdi.textVolunteers',
29 defaultMessage: '!!!The development of Ferdi is done by volunteers. People who use Ferdi like you. They maintain, fix, and improve Ferdi in their spare time.', 30 defaultMessage:
31 'The development of Ferdi is done by volunteers. People who use Ferdi like you. They maintain, fix, and improve Ferdi in their spare time.',
30 }, 32 },
31 textSupportWelcome: { 33 textSupportWelcome: {
32 id: 'settings.supportFerdi.textSupportWelcome', 34 id: 'settings.supportFerdi.textSupportWelcome',
33 defaultMessage: '!!!Support is always welcome. You can find a list of the help we need', 35 defaultMessage:
36 'Support is always welcome. You can find a list of the help we need',
34 }, 37 },
35 textSupportWelcomeHere: { 38 textSupportWelcomeHere: {
36 id: 'settings.supportFerdi.textSupportWelcomeHere', 39 id: 'settings.supportFerdi.textSupportWelcomeHere',
37 defaultMessage: '!!!here', 40 defaultMessage: 'here',
38 }, 41 },
39 textExpenses: { 42 textExpenses: {
40 id: 'settings.supportFerdi.textExpenses', 43 id: 'settings.supportFerdi.textExpenses',
41 defaultMessage: '!!!While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our', 44 defaultMessage:
45 'While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our',
42 }, 46 },
43 textOpenCollective: { 47 textOpenCollective: {
44 id: 'settings.supportFerdi.textOpenCollective', 48 id: 'settings.supportFerdi.textOpenCollective',
45 defaultMessage: '!!!Open Collective', 49 defaultMessage: 'Open Collective',
46 }, 50 },
47 textDonation: { 51 textDonation: {
48 id: 'settings.supportFerdi.textDonation', 52 id: 'settings.supportFerdi.textDonation',
49 defaultMessage: '!!!If you feel like supporting Ferdi development with a donation, you can do so on both,', 53 defaultMessage:
54 'If you feel like supporting Ferdi development with a donation, you can do so on both,',
50 }, 55 },
51 textDonationAnd: { 56 textDonationAnd: {
52 id: 'settings.supportFerdi.textDonationAnd', 57 id: 'settings.supportFerdi.textDonationAnd',
53 defaultMessage: '!!!and', 58 defaultMessage: 'and',
54 }, 59 },
55 textGitHubSponsors: { 60 textGitHubSponsors: {
56 id: 'settings.supportFerdi.textGitHubSponsors', 61 id: 'settings.supportFerdi.textGitHubSponsors',
57 defaultMessage: '!!!GitHub Sponsors', 62 defaultMessage: 'GitHub Sponsors',
58 }, 63 },
59 openSurvey: { 64 openSurvey: {
60 id: 'settings.supportFerdi.openSurvey', 65 id: 'settings.supportFerdi.openSurvey',
61 defaultMessage: '!!!Open Survey', 66 defaultMessage: 'Open survey',
62 }, 67 },
63 bannerText: { 68 bannerText: {
64 id: 'settings.supportFerdi.bannerText', 69 id: 'settings.supportFerdi.bannerText',
65 defaultMessage: '!!!Do you want to help us improve Ferdi?', 70 defaultMessage: 'Do you want to help us improve Ferdi?',
66 }, 71 },
67}); 72});
68 73
69class SupportFerdiDashboard extends Component { 74class SupportFerdiDashboard extends Component {
70 static contextTypes = {
71 intl: intlShape,
72 };
73
74 openSurveyWindow() { 75 openSurveyWindow() {
75 let win = new BrowserWindow({ width: 670, height: 400 }); 76 let win = new BrowserWindow({ width: 670, height: 400 });
76 win.on('closed', () => { 77 win.on('closed', () => {
@@ -81,7 +82,9 @@ class SupportFerdiDashboard extends Component {
81 } 82 }
82 83
83 render() { 84 render() {
84 const { intl } = this.context; 85 const { intl } = this.props;
86
87 const aboutIntro = intl.formatMessage(messages.aboutIntro);
85 88
86 return ( 89 return (
87 <div className="settings__main"> 90 <div className="settings__main">
@@ -94,22 +97,67 @@ class SupportFerdiDashboard extends Component {
94 <h1>{intl.formatMessage(messages.title)}</h1> 97 <h1>{intl.formatMessage(messages.title)}</h1>
95 <div> 98 <div>
96 <p className="settings__support-badges"> 99 <p className="settings__support-badges">
97 <a href="https://github.com/getferdi/ferdi" target="_blank" rel="noreferrer"><img alt="GitHub Stars" src="https://img.shields.io/github/stars/getferdi/ferdi?style=social" /></a> 100 <a
98 <a href="https://twitter.com/getferdi/" target="_blank" rel="noreferrer"><img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/getferdi?label=Follow&style=social" /></a> 101 href="https://github.com/getferdi/ferdi"
99 <a href="https://opencollective.com/getferdi#section-contributors" target="_blank" rel="noreferrer"><img alt="Open Collective backers" src="https://img.shields.io/opencollective/backers/getferdi?logo=open-collective" /></a> 102 target="_blank"
100 <a href="https://opencollective.com/getferdi#section-contributors" target="_blank" rel="noreferrer"><img alt="Open Collective sponsors" src="https://img.shields.io/opencollective/sponsors/getferdi?logo=open-collective" /></a> 103 rel="noreferrer"
104 >
105 <img
106 alt="GitHub Stars"
107 src="https://img.shields.io/github/stars/getferdi/ferdi?style=social"
108 />
109 </a>
110 <a
111 href="https://twitter.com/getferdi/"
112 target="_blank"
113 rel="noreferrer"
114 >
115 <img
116 alt="Twitter Follow"
117 src="https://img.shields.io/twitter/follow/getferdi?label=Follow&style=social"
118 />
119 </a>
120 <a
121 href="https://opencollective.com/getferdi#section-contributors"
122 target="_blank"
123 rel="noreferrer"
124 >
125 <img
126 alt="Open Collective backers"
127 src="https://img.shields.io/opencollective/backers/getferdi?logo=open-collective"
128 />
129 </a>
130 <a
131 href="https://opencollective.com/getferdi#section-contributors"
132 target="_blank"
133 rel="noreferrer"
134 >
135 <img
136 alt="Open Collective sponsors"
137 src="https://img.shields.io/opencollective/sponsors/getferdi?logo=open-collective"
138 />
139 </a>
101 </p> 140 </p>
102 <FormattedHTMLMessage {...messages.aboutIntro} /> 141 <span dangerouslySetInnerHTML={{ __html: aboutIntro }} />
103 <br /> 142 <br />
104 <br /> 143 <br />
105 <p> 144 <p>
106 <a href="#contributors-via-opencollective"> 145 <a href="#contributors-via-opencollective">
107 <img alt="GitHub contributors (non-exhaustive)" width="100%" src="https://opencollective.com/getferdi/contributors.svg?width=642&button=false" /> 146 <img
147 alt="GitHub contributors (non-exhaustive)"
148 width="100%"
149 src="https://opencollective.com/getferdi/contributors.svg?width=642&button=false"
150 />
108 </a> 151 </a>
109 </p> 152 </p>
110 <p> 153 <p>
111 {intl.formatMessage(messages.textListContributors)} 154 {intl.formatMessage(messages.textListContributors)}
112 <a href="https://github.com/getferdi/ferdi#contributors-" target="_blank" className="link" rel="noreferrer"> 155 <a
156 href="https://github.com/getferdi/ferdi#contributors-"
157 target="_blank"
158 className="link"
159 rel="noreferrer"
160 >
113 {' '} 161 {' '}
114 {intl.formatMessage(messages.textListContributorsHere)} 162 {intl.formatMessage(messages.textListContributorsHere)}
115 <i className="mdi mdi-open-in-new" /> 163 <i className="mdi mdi-open-in-new" />
@@ -117,12 +165,15 @@ class SupportFerdiDashboard extends Component {
117 <br /> 165 <br />
118 <br /> 166 <br />
119 </p> 167 </p>
120 <p> 168 <p>{intl.formatMessage(messages.textVolunteers)}</p>
121 {intl.formatMessage(messages.textVolunteers)}
122 </p>
123 <p> 169 <p>
124 {intl.formatMessage(messages.textSupportWelcome)} 170 {intl.formatMessage(messages.textSupportWelcome)}
125 <a href="https://help.getferdi.com/general/support" target="_blank" className="link" rel="noreferrer"> 171 <a
172 href="https://help.getferdi.com/general/support"
173 target="_blank"
174 className="link"
175 rel="noreferrer"
176 >
126 {' '} 177 {' '}
127 {intl.formatMessage(messages.textSupportWelcomeHere)} 178 {intl.formatMessage(messages.textSupportWelcomeHere)}
128 <i className="mdi mdi-open-in-new" /> 179 <i className="mdi mdi-open-in-new" />
@@ -130,7 +181,12 @@ class SupportFerdiDashboard extends Component {
130 </p> 181 </p>
131 <p> 182 <p>
132 {intl.formatMessage(messages.textExpenses)} 183 {intl.formatMessage(messages.textExpenses)}
133 <a href="https://opencollective.com/getferdi#section-budget" target="_blank" className="link" rel="noreferrer"> 184 <a
185 href="https://opencollective.com/getferdi#section-budget"
186 target="_blank"
187 className="link"
188 rel="noreferrer"
189 >
134 {' '} 190 {' '}
135 {intl.formatMessage(messages.textOpenCollective)} 191 {intl.formatMessage(messages.textOpenCollective)}
136 <i className="mdi mdi-open-in-new" /> 192 <i className="mdi mdi-open-in-new" />
@@ -138,14 +194,23 @@ class SupportFerdiDashboard extends Component {
138 </p> 194 </p>
139 <p> 195 <p>
140 {intl.formatMessage(messages.textDonation)} 196 {intl.formatMessage(messages.textDonation)}
141 <a href="https://opencollective.com/getferdi#section-contribute" target="_blank" className="link" rel="noreferrer"> 197 <a
198 href="https://opencollective.com/getferdi#section-contribute"
199 target="_blank"
200 className="link"
201 rel="noreferrer"
202 >
142 {' '} 203 {' '}
143 {intl.formatMessage(messages.textOpenCollective)} 204 {intl.formatMessage(messages.textOpenCollective)}
144 <i className="mdi mdi-open-in-new" /> 205 <i className="mdi mdi-open-in-new" />
145 </a> 206 </a>{' '}
146 {' '}
147 {intl.formatMessage(messages.textDonationAnd)} 207 {intl.formatMessage(messages.textDonationAnd)}
148 <a href="https://github.com/sponsors/getferdi" target="_blank" className="link" rel="noreferrer"> 208 <a
209 href="https://github.com/sponsors/getferdi"
210 target="_blank"
211 className="link"
212 rel="noreferrer"
213 >
149 {' '} 214 {' '}
150 {intl.formatMessage(messages.textGitHubSponsors)} 215 {intl.formatMessage(messages.textGitHubSponsors)}
151 <i className="mdi mdi-open-in-new" /> 216 <i className="mdi mdi-open-in-new" />
@@ -166,4 +231,4 @@ class SupportFerdiDashboard extends Component {
166 } 231 }
167} 232}
168 233
169export default SupportFerdiDashboard; 234export default injectIntl(SupportFerdiDashboard);
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js
index 437225058..06f244997 100644
--- a/src/components/settings/team/TeamDashboard.js
+++ b/src/components/settings/team/TeamDashboard.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import ReactTooltip from 'react-tooltip'; 5import ReactTooltip from 'react-tooltip';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7import classnames from 'classnames'; 7import classnames from 'classnames';
@@ -14,31 +14,34 @@ import { LIVE_FRANZ_API } from '../../../config';
14const messages = defineMessages({ 14const messages = defineMessages({
15 headline: { 15 headline: {
16 id: 'settings.team.headline', 16 id: 'settings.team.headline',
17 defaultMessage: '!!!Team', 17 defaultMessage: 'Team',
18 }, 18 },
19 contentHeadline: { 19 contentHeadline: {
20 id: 'settings.team.contentHeadline', 20 id: 'settings.team.contentHeadline',
21 defaultMessage: '!!!Franz Team Management', 21 defaultMessage: 'Franz Team Management',
22 }, 22 },
23 intro: { 23 intro: {
24 id: 'settings.team.intro', 24 id: 'settings.team.intro',
25 defaultMessage: '!!!Your are currently using Franz Servers, which is why you have access to Team Management.', 25 defaultMessage:
26 'You are currently using Franz Servers, which is why you have access to Team Management.',
26 }, 27 },
27 copy: { 28 copy: {
28 id: 'settings.team.copy', 29 id: 'settings.team.copy',
29 defaultMessage: '!!!Franz\'s Team Management allows you to manage Franz Subscriptions for multiple users. Please keep in mind that having a Franz Premium subscription will give you no advantages in using Ferdi: The only reason you still have access to Team Management is so you can manage your legacy Franz Teams and so that you don\'t loose any functionality in managing your account.', 30 defaultMessage:
31 "Franz's Team Management allows you to manage Franz Subscriptions for multiple users. Please keep in mind that having a Franz Premium subscription will give you no advantages in using Ferdi: The only reason you still have access to Team Management is so you can manage your legacy Franz Teams and so that you don't loose any functionality in managing your account.",
30 }, 32 },
31 manageButton: { 33 manageButton: {
32 id: 'settings.team.manageAction', 34 id: 'settings.team.manageAction',
33 defaultMessage: '!!!Manage your Team on meetfranz.com', 35 defaultMessage: 'Manage your Team on meetfranz.com',
34 }, 36 },
35 teamsUnavailable: { 37 teamsUnavailable: {
36 id: 'settings.team.teamsUnavailable', 38 id: 'settings.team.teamsUnavailable',
37 defaultMessage: '!!!Teams are unavailable', 39 defaultMessage: 'Teams are unavailable',
38 }, 40 },
39 teamsUnavailableInfo: { 41 teamsUnavailableInfo: {
40 id: 'settings.team.teamsUnavailableInfo', 42 id: 'settings.team.teamsUnavailableInfo',
41 defaultMessage: '!!!Teams are currently only available when using the Franz Server and after paying for Franz Professional. Please change your server to https://api.franzinfra.com to use teams.', 43 defaultMessage:
44 'Teams are currently only available when using the Franz Server and after paying for Franz Professional. Please change your server to https://api.franzinfra.com to use teams.',
42 }, 45 },
43}); 46});
44 47
@@ -87,7 +90,9 @@ const styles = {
87 }, 90 },
88}; 91};
89 92
90export default @injectSheet(styles) @observer class TeamDashboard extends Component { 93@injectSheet(styles)
94@observer
95class TeamDashboard extends Component {
91 static propTypes = { 96 static propTypes = {
92 isLoading: PropTypes.bool.isRequired, 97 isLoading: PropTypes.bool.isRequired,
93 userInfoRequestFailed: PropTypes.bool.isRequired, 98 userInfoRequestFailed: PropTypes.bool.isRequired,
@@ -97,10 +102,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
97 server: PropTypes.string.isRequired, 102 server: PropTypes.string.isRequired,
98 }; 103 };
99 104
100 static contextTypes = {
101 intl: intlShape,
102 };
103
104 render() { 105 render() {
105 const { 106 const {
106 isLoading, 107 isLoading,
@@ -110,7 +111,7 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
110 classes, 111 classes,
111 server, 112 server,
112 } = this.props; 113 } = this.props;
113 const { intl } = this.context; 114 const { intl } = this.props;
114 115
115 if (server === LIVE_FRANZ_API) { 116 if (server === LIVE_FRANZ_API) {
116 return ( 117 return (
@@ -121,9 +122,7 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
121 </span> 122 </span>
122 </div> 123 </div>
123 <div className="settings__body"> 124 <div className="settings__body">
124 {isLoading && ( 125 {isLoading && <Loader />}
125 <Loader />
126 )}
127 126
128 {!isLoading && userInfoRequestFailed && ( 127 {!isLoading && userInfoRequestFailed && (
129 <Infobox 128 <Infobox
@@ -142,20 +141,24 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
142 {!isLoading && ( 141 {!isLoading && (
143 <> 142 <>
144 <> 143 <>
145 <h1 className={classnames({ 144 <h1
146 [classes.headline]: true, 145 className={classnames({
147 [classes.headlineWithSpacing]: true, 146 [classes.headline]: true,
148 })} 147 [classes.headlineWithSpacing]: true,
148 })}
149 > 149 >
150 {intl.formatMessage(messages.contentHeadline)} 150 {intl.formatMessage(messages.contentHeadline)}
151
152 </h1> 151 </h1>
153 <div className={classes.container}> 152 <div className={classes.container}>
154 <div className={classes.content}> 153 <div className={classes.content}>
155 <p>{intl.formatMessage(messages.intro)}</p> 154 <p>{intl.formatMessage(messages.intro)}</p>
156 <p>{intl.formatMessage(messages.copy)}</p> 155 <p>{intl.formatMessage(messages.copy)}</p>
157 </div> 156 </div>
158 <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Ferdi for Teams" /> 157 <img
158 className={classes.image}
159 src="https://cdn.franzinfra.com/announcements/assets/teams.png"
160 alt="Ferdi for Teams"
161 />
159 </div> 162 </div>
160 <div className={classes.buttonContainer}> 163 <div className={classes.buttonContainer}>
161 <Button 164 <Button
@@ -188,7 +191,8 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
188 <p 191 <p
189 className="settings__message" 192 className="settings__message"
190 style={{ 193 style={{
191 borderTop: 0, marginTop: 0, 194 borderTop: 0,
195 marginTop: 0,
192 }} 196 }}
193 > 197 >
194 {intl.formatMessage(messages.teamsUnavailableInfo)} 198 {intl.formatMessage(messages.teamsUnavailableInfo)}
@@ -198,3 +202,5 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
198 ); 202 );
199 } 203 }
200} 204}
205
206export default injectIntl(TeamDashboard);
diff --git a/src/components/settings/user/EditUserForm.js b/src/components/settings/user/EditUserForm.js
index db78acb69..adc107ccc 100644
--- a/src/components/settings/user/EditUserForm.js
+++ b/src/components/settings/user/EditUserForm.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router';
6import { Input } from '@meetfranz/forms'; 6import { Input } from '@meetfranz/forms';
7 7
@@ -14,31 +14,32 @@ import Infobox from '../../ui/Infobox';
14const messages = defineMessages({ 14const messages = defineMessages({
15 headline: { 15 headline: {
16 id: 'settings.account.headline', 16 id: 'settings.account.headline',
17 defaultMessage: '!!!Account', 17 defaultMessage: 'Account',
18 }, 18 },
19 headlineProfile: { 19 headlineProfile: {
20 id: 'settings.account.headlineProfile', 20 id: 'settings.account.headlineProfile',
21 defaultMessage: '!!!Update Profile', 21 defaultMessage: 'Update profile',
22 }, 22 },
23 headlineAccount: { 23 headlineAccount: {
24 id: 'settings.account.headlineAccount', 24 id: 'settings.account.headlineAccount',
25 defaultMessage: '!!!Account Information', 25 defaultMessage: 'Account information',
26 }, 26 },
27 headlinePassword: { 27 headlinePassword: {
28 id: 'settings.account.headlinePassword', 28 id: 'settings.account.headlinePassword',
29 defaultMessage: '!!!Change Password', 29 defaultMessage: 'Change password',
30 }, 30 },
31 successInfo: { 31 successInfo: {
32 id: 'settings.account.successInfo', 32 id: 'settings.account.successInfo',
33 defaultMessage: '!!!Your changes have been saved', 33 defaultMessage: 'Your changes have been saved',
34 }, 34 },
35 buttonSave: { 35 buttonSave: {
36 id: 'settings.account.buttonSave', 36 id: 'settings.account.buttonSave',
37 defaultMessage: '!!!Update profile', 37 defaultMessage: 'Update profile',
38 }, 38 },
39}); 39});
40 40
41export default @observer class EditUserForm extends Component { 41@observer
42class EditUserForm extends Component {
42 static propTypes = { 43 static propTypes = {
43 status: MobxPropTypes.observableArray.isRequired, 44 status: MobxPropTypes.observableArray.isRequired,
44 form: PropTypes.instanceOf(Form).isRequired, 45 form: PropTypes.instanceOf(Form).isRequired,
@@ -46,14 +47,10 @@ export default @observer class EditUserForm extends Component {
46 isSaving: PropTypes.bool.isRequired, 47 isSaving: PropTypes.bool.isRequired,
47 }; 48 };
48 49
49 static contextTypes = {
50 intl: intlShape,
51 };
52
53 submit(e) { 50 submit(e) {
54 e.preventDefault(); 51 e.preventDefault();
55 this.props.form.submit({ 52 this.props.form.submit({
56 onSuccess: (form) => { 53 onSuccess: form => {
57 const values = form.values(); 54 const values = form.values();
58 this.props.onSubmit(values); 55 this.props.onSubmit(values);
59 }, 56 },
@@ -68,7 +65,7 @@ export default @observer class EditUserForm extends Component {
68 form, 65 form,
69 isSaving, 66 isSaving,
70 } = this.props; 67 } = this.props;
71 const { intl } = this.context; 68 const { intl } = this.props;
72 69
73 return ( 70 return (
74 <div className="settings__main"> 71 <div className="settings__main">
@@ -84,12 +81,9 @@ export default @observer class EditUserForm extends Component {
84 </span> 81 </span>
85 </div> 82 </div>
86 <div className="settings__body"> 83 <div className="settings__body">
87 <form onSubmit={(e) => this.submit(e)} id="form"> 84 <form onSubmit={e => this.submit(e)} id="form">
88 {status.length > 0 && status.includes('data-updated') && ( 85 {status.length > 0 && status.includes('data-updated') && (
89 <Infobox 86 <Infobox type="success" icon="checkbox-marked-circle-outline">
90 type="success"
91 icon="checkbox-marked-circle-outline"
92 >
93 {intl.formatMessage(messages.successInfo)} 87 {intl.formatMessage(messages.successInfo)}
94 </Infobox> 88 </Infobox>
95 )} 89 )}
@@ -104,10 +98,7 @@ export default @observer class EditUserForm extends Component {
104 <Input field={form.$('organization')} /> 98 <Input field={form.$('organization')} />
105 )} 99 )}
106 <h2>{intl.formatMessage(messages.headlinePassword)}</h2> 100 <h2>{intl.formatMessage(messages.headlinePassword)}</h2>
107 <Input 101 <Input {...form.$('oldPassword').bind()} showPasswordToggle />
108 {...form.$('oldPassword').bind()}
109 showPasswordToggle
110 />
111 <Input 102 <Input
112 {...form.$('newPassword').bind()} 103 {...form.$('newPassword').bind()}
113 showPasswordToggle 104 showPasswordToggle
@@ -137,3 +128,5 @@ export default @observer class EditUserForm extends Component {
137 ); 128 );
138 } 129 }
139} 130}
131
132export default injectIntl(EditUserForm);
diff --git a/src/components/ui/AppLoader/index.js b/src/components/ui/AppLoader/index.js
index bbfd5de28..fa4a719ab 100644
--- a/src/components/ui/AppLoader/index.js
+++ b/src/components/ui/AppLoader/index.js
@@ -19,7 +19,9 @@ const textList = shuffleArray([
19 'Fixing bugs', 19 'Fixing bugs',
20]); 20]);
21 21
22export default @injectSheet(styles) @withTheme class AppLoader extends Component { 22@injectSheet(styles)
23@withTheme
24class AppLoader extends Component {
23 static propTypes = { 25 static propTypes = {
24 classes: PropTypes.object.isRequired, 26 classes: PropTypes.object.isRequired,
25 theme: PropTypes.object.isRequired, 27 theme: PropTypes.object.isRequired,
@@ -28,7 +30,7 @@ export default @injectSheet(styles) @withTheme class AppLoader extends Component
28 30
29 static defaultProps = { 31 static defaultProps = {
30 texts: textList, 32 texts: textList,
31 } 33 };
32 34
33 state = { 35 state = {
34 step: 0, 36 step: 0,
@@ -38,7 +40,7 @@ export default @injectSheet(styles) @withTheme class AppLoader extends Component
38 40
39 componentDidMount() { 41 componentDidMount() {
40 this.interval = setInterval(() => { 42 this.interval = setInterval(() => {
41 this.setState((prevState) => ({ 43 this.setState(prevState => ({
42 step: prevState.step === textList.length - 1 ? 0 : prevState.step + 1, 44 step: prevState.step === textList.length - 1 ? 0 : prevState.step + 1,
43 })); 45 }));
44 }, 2500); 46 }, 2500);
@@ -73,3 +75,5 @@ export default @injectSheet(styles) @withTheme class AppLoader extends Component
73 ); 75 );
74 } 76 }
75} 77}
78
79export default AppLoader;
diff --git a/src/components/ui/Button.js b/src/components/ui/Button.js
index 5066b9c06..f6c9fd3d3 100644
--- a/src/components/ui/Button.js
+++ b/src/components/ui/Button.js
@@ -4,7 +4,9 @@ import { observer, inject } from 'mobx-react';
4import Loader from 'react-loader'; 4import Loader from 'react-loader';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6 6
7export default @inject('stores') @observer class Button extends Component { 7@inject('stores')
8@observer
9class Button extends Component {
8 static propTypes = { 10 static propTypes = {
9 className: PropTypes.string, 11 className: PropTypes.string,
10 label: PropTypes.string.isRequired, 12 label: PropTypes.string.isRequired,
@@ -26,7 +28,7 @@ export default @inject('stores') @observer class Button extends Component {
26 static defaultProps = { 28 static defaultProps = {
27 className: null, 29 className: null,
28 disabled: false, 30 disabled: false,
29 onClick: () => { }, 31 onClick: () => {},
30 type: 'button', 32 type: 'button',
31 buttonType: '', 33 buttonType: '',
32 loaded: true, 34 loaded: true,
@@ -76,7 +78,11 @@ export default @inject('stores') @observer class Button extends Component {
76 loaded={loaded} 78 loaded={loaded}
77 lines={10} 79 lines={10}
78 scale={0.4} 80 scale={0.4}
79 color={buttonType !== 'secondary' ? '#FFF' : this.props.stores.settings.app.accentColor} 81 color={
82 buttonType !== 'secondary'
83 ? '#FFF'
84 : this.props.stores.settings.app.accentColor
85 }
80 component="span" 86 component="span"
81 /> 87 />
82 {label} 88 {label}
@@ -85,3 +91,5 @@ export default @inject('stores') @observer class Button extends Component {
85 ); 91 );
86 } 92 }
87} 93}
94
95export default Button;
diff --git a/src/components/ui/FAB.js b/src/components/ui/FAB.js
index 633edbe2c..a3aa06bc9 100644
--- a/src/components/ui/FAB.js
+++ b/src/components/ui/FAB.js
@@ -8,7 +8,8 @@ import classnames from 'classnames';
8 8
9import { oneOrManyChildElements } from '../../prop-types'; 9import { oneOrManyChildElements } from '../../prop-types';
10 10
11export default @observer class Button extends Component { 11@observer
12class Button extends Component {
12 static propTypes = { 13 static propTypes = {
13 className: PropTypes.string, 14 className: PropTypes.string,
14 disabled: PropTypes.bool, 15 disabled: PropTypes.bool,
@@ -21,7 +22,7 @@ export default @observer class Button extends Component {
21 static defaultProps = { 22 static defaultProps = {
22 className: null, 23 className: null,
23 disabled: false, 24 disabled: false,
24 onClick: () => { }, 25 onClick: () => {},
25 type: 'button', 26 type: 'button',
26 htmlForm: '', 27 htmlForm: '',
27 }; 28 };
@@ -29,14 +30,8 @@ export default @observer class Button extends Component {
29 element = null; 30 element = null;
30 31
31 render() { 32 render() {
32 const { 33 const { className, disabled, onClick, type, children, htmlForm } =
33 className, 34 this.props;
34 disabled,
35 onClick,
36 type,
37 children,
38 htmlForm,
39 } = this.props;
40 35
41 const buttonProps = { 36 const buttonProps = {
42 className: classnames({ 37 className: classnames({
@@ -66,3 +61,5 @@ export default @observer class Button extends Component {
66 ); 61 );
67 } 62 }
68} 63}
64
65export default Button;
diff --git a/src/components/ui/FeatureItem.js b/src/components/ui/FeatureItem.js
deleted file mode 100644
index 646cf56ca..000000000
--- a/src/components/ui/FeatureItem.js
+++ /dev/null
@@ -1,38 +0,0 @@
1import React from 'react';
2import injectSheet from 'react-jss';
3import { Icon } from '@meetfranz/ui';
4import classnames from 'classnames';
5import { mdiCheckCircle } from '@mdi/js';
6
7const styles = (theme) => ({
8 featureItem: {
9 borderBottom: [1, 'solid', theme.defaultContentBorder],
10 padding: [8, 0],
11 display: 'flex',
12 alignItems: 'center',
13 textAlign: 'left',
14 },
15 featureIcon: {
16 fill: theme.brandSuccess,
17 marginRight: 10,
18 },
19});
20
21export const FeatureItem = injectSheet(styles)(({
22 classes, className, name, icon,
23}) => (
24 <li className={classnames({
25 [classes.featureItem]: true,
26 [className]: className,
27 })}
28 >
29 {icon ? (
30 <span className={classes.featureIcon}>{icon}</span>
31 ) : (
32 <Icon icon={mdiCheckCircle} className={classes.featureIcon} size={1.5} />
33 )}
34 {name}
35 </li>
36));
37
38export default FeatureItem;
diff --git a/src/components/ui/FeatureList.js b/src/components/ui/FeatureList.js
deleted file mode 100644
index cf2664830..000000000
--- a/src/components/ui/FeatureList.js
+++ /dev/null
@@ -1,101 +0,0 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl';
4
5import { FeatureItem } from './FeatureItem';
6
7const messages = defineMessages({
8 availableRecipes: {
9 id: 'pricing.features.recipes',
10 defaultMessage: '!!!Choose from more than 70 Services', // TODO: Make this dynamic
11 },
12 accountSync: {
13 id: 'pricing.features.accountSync',
14 defaultMessage: '!!!Account Synchronisation',
15 },
16 desktopNotifications: {
17 id: 'pricing.features.desktopNotifications',
18 defaultMessage: '!!!Desktop Notifications',
19 },
20 unlimitedServices: {
21 id: 'pricing.features.unlimitedServices',
22 defaultMessage: '!!!Add unlimited services',
23 },
24 spellchecker: {
25 id: 'pricing.features.spellchecker',
26 defaultMessage: '!!!Spellchecker support',
27 },
28 workspaces: {
29 id: 'pricing.features.workspaces',
30 defaultMessage: '!!!Workspaces',
31 },
32 customWebsites: {
33 id: 'pricing.features.customWebsites',
34 defaultMessage: '!!!Add Custom Websites',
35 },
36 onPremise: {
37 id: 'pricing.features.onPremise',
38 defaultMessage: '!!!On-premise & other Hosted Services',
39 },
40 thirdPartyServices: {
41 id: 'pricing.features.thirdPartyServices',
42 defaultMessage: '!!!Install 3rd party services',
43 },
44 serviceProxies: {
45 id: 'pricing.features.serviceProxies',
46 defaultMessage: '!!!Service Proxies',
47 },
48 teamManagement: {
49 id: 'pricing.features.teamManagement',
50 defaultMessage: '!!!Team Management',
51 },
52});
53
54export class FeatureList extends Component {
55 static propTypes = {
56 className: PropTypes.string,
57 featureClassName: PropTypes.string,
58 };
59
60 static defaultProps = {
61 className: '',
62 featureClassName: '',
63 }
64
65 static contextTypes = {
66 intl: intlShape,
67 };
68
69 render() {
70 const {
71 className,
72 featureClassName,
73 } = this.props;
74 const { intl } = this.context;
75
76 const features = [
77 messages.availableRecipes,
78 messages.accountSync,
79 messages.desktopNotifications,
80
81 messages.spellchecker,
82
83 messages.workspaces,
84 messages.customWebsites,
85 messages.thirdPartyServices,
86
87 messages.unlimitedServices,
88 messages.onPremise,
89 messages.serviceProxies,
90 messages.teamManagement,
91 ];
92
93 return (
94 <ul className={className}>
95 {features.map((feature) => <FeatureItem name={intl.formatMessage(feature)} className={featureClassName} />)}
96 </ul>
97 );
98 }
99}
100
101export default FeatureList;
diff --git a/src/components/ui/FullscreenLoader/index.js b/src/components/ui/FullscreenLoader/index.js
index 2952cd96b..ab5e2f365 100644
--- a/src/components/ui/FullscreenLoader/index.js
+++ b/src/components/ui/FullscreenLoader/index.js
@@ -8,7 +8,10 @@ import Loader from '../Loader';
8 8
9import styles from './styles'; 9import styles from './styles';
10 10
11export default @withTheme @injectSheet(styles) @observer class FullscreenLoader extends Component { 11@withTheme
12@injectSheet(styles)
13@observer
14class FullscreenLoader extends Component {
12 static propTypes = { 15 static propTypes = {
13 className: PropTypes.string, 16 className: PropTypes.string,
14 title: PropTypes.string.isRequired, 17 title: PropTypes.string.isRequired,
@@ -25,14 +28,8 @@ export default @withTheme @injectSheet(styles) @observer class FullscreenLoader
25 }; 28 };
26 29
27 render() { 30 render() {
28 const { 31 const { classes, title, children, spinnerColor, className, theme } =
29 classes, 32 this.props;
30 title,
31 children,
32 spinnerColor,
33 className,
34 theme,
35 } = this.props;
36 33
37 return ( 34 return (
38 <div className={classes.wrapper}> 35 <div className={classes.wrapper}>
@@ -44,13 +41,11 @@ export default @withTheme @injectSheet(styles) @observer class FullscreenLoader
44 > 41 >
45 <h1 className={classes.title}>{title}</h1> 42 <h1 className={classes.title}>{title}</h1>
46 <Loader color={spinnerColor || theme.colorFullscreenLoaderSpinner} /> 43 <Loader color={spinnerColor || theme.colorFullscreenLoaderSpinner} />
47 {children && ( 44 {children && <div className={classes.content}>{children}</div>}
48 <div className={classes.content}>
49 {children}
50 </div>
51 )}
52 </div> 45 </div>
53 </div> 46 </div>
54 ); 47 );
55 } 48 }
56} 49}
50
51export default FullscreenLoader;
diff --git a/src/components/ui/ImageUpload.js b/src/components/ui/ImageUpload.js
index bb4ea0565..49aff389b 100644
--- a/src/components/ui/ImageUpload.js
+++ b/src/components/ui/ImageUpload.js
@@ -6,7 +6,8 @@ import classnames from 'classnames';
6import Dropzone from 'react-dropzone'; 6import Dropzone from 'react-dropzone';
7import { isWindows } from '../../environment'; 7import { isWindows } from '../../environment';
8 8
9export default @observer class ImageUpload extends Component { 9@observer
10class ImageUpload extends Component {
10 static propTypes = { 11 static propTypes = {
11 field: PropTypes.instanceOf(Field).isRequired, 12 field: PropTypes.instanceOf(Field).isRequired,
12 className: PropTypes.string, 13 className: PropTypes.string,
@@ -29,22 +30,20 @@ export default @observer class ImageUpload extends Component {
29 onDrop(acceptedFiles) { 30 onDrop(acceptedFiles) {
30 const { field } = this.props; 31 const { field } = this.props;
31 32
32 acceptedFiles.forEach((file) => { 33 for (const file of acceptedFiles) {
33 const imgPath = isWindows ? file.path.replace(/\\/g, '/') : file.path; 34 const imgPath = isWindows ? file.path.replace(/\\/g, '/') : file.path;
34 this.setState({ 35 this.setState({
35 path: imgPath, 36 path: imgPath,
36 }); 37 });
37 38
38 this.props.field.onDrop(file); 39 this.props.field.onDrop(file);
39 }); 40 }
40 41
41 field.set(''); 42 field.set('');
42 } 43 }
43 44
44 render() { 45 render() {
45 const { 46 const { field, className, multiple, textDelete, textUpload } = this.props;
46 field, className, multiple, textDelete, textUpload,
47 } = this.props;
48 47
49 const cssClasses = classnames({ 48 const cssClasses = classnames({
50 'image-upload__dropzone': true, 49 'image-upload__dropzone': true,
@@ -86,7 +85,7 @@ export default @observer class ImageUpload extends Component {
86 </> 85 </>
87 ) : ( 86 ) : (
88 <Dropzone 87 <Dropzone
89 ref={(node) => { 88 ref={node => {
90 this.dropzoneRef = node; 89 this.dropzoneRef = node;
91 }} 90 }}
92 onDrop={this.onDrop.bind(this)} 91 onDrop={this.onDrop.bind(this)}
@@ -107,3 +106,5 @@ export default @observer class ImageUpload extends Component {
107 ); 106 );
108 } 107 }
109} 108}
109
110export default ImageUpload;
diff --git a/src/components/ui/InfoBar.js b/src/components/ui/InfoBar.js
index bd2af2296..dc6be10da 100644
--- a/src/components/ui/InfoBar.js
+++ b/src/components/ui/InfoBar.js
@@ -3,23 +3,21 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import Loader from 'react-loader'; 5import Loader from 'react-loader';
6import { defineMessages, intlShape } from 'react-intl'; 6import { defineMessages, injectIntl } from 'react-intl';
7 7
8// import { oneOrManyChildElements } from '../../prop-types';
9import Appear from './effects/Appear'; 8import Appear from './effects/Appear';
10 9
11const messages = defineMessages({ 10const messages = defineMessages({
12 hide: { 11 hide: {
13 id: 'infobar.hide', 12 id: 'infobar.hide',
14 defaultMessage: '!!!Hide', 13 defaultMessage: 'Hide',
15 }, 14 },
16}); 15});
17 16
18export default
19@observer 17@observer
20class InfoBar extends Component { 18class InfoBar extends Component {
21 static propTypes = { 19 static propTypes = {
22 // eslint-disable-next-line 20 // eslint-disable-next-line react/forbid-prop-types
23 children: PropTypes.any.isRequired, 21 children: PropTypes.any.isRequired,
24 onClick: PropTypes.func, 22 onClick: PropTypes.func,
25 type: PropTypes.string, 23 type: PropTypes.string,
@@ -42,10 +40,6 @@ class InfoBar extends Component {
42 onHide: () => null, 40 onHide: () => null,
43 }; 41 };
44 42
45 static contextTypes = {
46 intl: intlShape,
47 };
48
49 render() { 43 render() {
50 const { 44 const {
51 children, 45 children,
@@ -59,7 +53,7 @@ class InfoBar extends Component {
59 onHide, 53 onHide,
60 } = this.props; 54 } = this.props;
61 55
62 const { intl } = this.context; 56 const { intl } = this.props;
63 57
64 let transitionName = 'slideUp'; 58 let transitionName = 'slideUp';
65 if (position === 'top') { 59 if (position === 'top') {
@@ -103,3 +97,5 @@ class InfoBar extends Component {
103 ); 97 );
104 } 98 }
105} 99}
100
101export default injectIntl(InfoBar);
diff --git a/src/components/ui/Infobox.js b/src/components/ui/Infobox.js
index 73b48b957..9e34bf110 100644
--- a/src/components/ui/Infobox.js
+++ b/src/components/ui/Infobox.js
@@ -3,20 +3,20 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import Loader from 'react-loader'; 5import Loader from 'react-loader';
6import { defineMessages, intlShape } from 'react-intl'; 6import { defineMessages, injectIntl } from 'react-intl';
7 7
8const messages = defineMessages({ 8const messages = defineMessages({
9 dismiss: { 9 dismiss: {
10 id: 'infobox.dismiss', 10 id: 'infobox.dismiss',
11 defaultMessage: '!!!Dismiss', 11 defaultMessage: 'Dismiss',
12 }, 12 },
13}); 13});
14 14
15export default
16@observer 15@observer
17class Infobox extends Component { 16class Infobox extends Component {
18 static propTypes = { 17 static propTypes = {
19 children: PropTypes.any.isRequired, // eslint-disable-line 18 // eslint-disable-next-line react/forbid-prop-types
19 children: PropTypes.any.isRequired,
20 icon: PropTypes.string, 20 icon: PropTypes.string,
21 type: PropTypes.string, 21 type: PropTypes.string,
22 ctaOnClick: PropTypes.func, 22 ctaOnClick: PropTypes.func,
@@ -38,10 +38,6 @@ class Infobox extends Component {
38 onSeen: () => null, 38 onSeen: () => null,
39 }; 39 };
40 40
41 static contextTypes = {
42 intl: intlShape,
43 };
44
45 state = { 41 state = {
46 dismissed: false, 42 dismissed: false,
47 }; 43 };
@@ -63,7 +59,7 @@ class Infobox extends Component {
63 onDismiss, 59 onDismiss,
64 } = this.props; 60 } = this.props;
65 61
66 const { intl } = this.context; 62 const { intl } = this.props;
67 63
68 if (this.state.dismissed) { 64 if (this.state.dismissed) {
69 return null; 65 return null;
@@ -106,3 +102,5 @@ class Infobox extends Component {
106 ); 102 );
107 } 103 }
108} 104}
105
106export default injectIntl(Infobox);
diff --git a/src/components/ui/Input.js b/src/components/ui/Input.js
index 7417fef1c..43fab10ee 100644
--- a/src/components/ui/Input.js
+++ b/src/components/ui/Input.js
@@ -3,18 +3,17 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { Field } from 'mobx-react-form'; 4import { Field } from 'mobx-react-form';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6import { defineMessages, intlShape } from 'react-intl'; 6import { defineMessages, injectIntl } from 'react-intl';
7 7
8import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers'; 8import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers';
9 9
10const messages = defineMessages({ 10const messages = defineMessages({
11 passwordToggle: { 11 passwordToggle: {
12 id: 'settings.app.form.passwordToggle', 12 id: 'settings.app.form.passwordToggle',
13 defaultMessage: '!!!Password toggle', 13 defaultMessage: 'Password toggle',
14 }, 14 },
15}); 15});
16 16
17export default
18@observer 17@observer
19class Input extends Component { 18class Input extends Component {
20 static propTypes = { 19 static propTypes = {
@@ -38,16 +37,12 @@ class Input extends Component {
38 suffix: '', 37 suffix: '',
39 }; 38 };
40 39
41 static contextTypes = {
42 intl: intlShape,
43 };
44
45 state = { 40 state = {
46 showPassword: false, 41 showPassword: false,
47 passwordScore: 0, 42 passwordScore: 0,
48 }; 43 };
49 44
50 inputElement = null; 45 inputElement;
51 46
52 componentDidMount() { 47 componentDidMount() {
53 if (this.props.focus) { 48 if (this.props.focus) {
@@ -82,7 +77,7 @@ class Input extends Component {
82 77
83 const { passwordScore } = this.state; 78 const { passwordScore } = this.state;
84 79
85 const { intl } = this.context; 80 const { intl } = this.props;
86 81
87 let { type } = field; 82 let { type } = field;
88 if (type === 'password' && this.state.showPassword) { 83 if (type === 'password' && this.state.showPassword) {
@@ -106,10 +101,10 @@ class Input extends Component {
106 name={field.name} 101 name={field.name}
107 value={field.value} 102 value={field.value}
108 placeholder={field.placeholder} 103 placeholder={field.placeholder}
109 onChange={(e) => this.onChange(e)} 104 onChange={e => this.onChange(e)}
110 onBlur={field.onBlur} 105 onBlur={field.onBlur}
111 onFocus={field.onFocus} 106 onFocus={field.onFocus}
112 ref={(element) => { 107 ref={element => {
113 this.inputElement = element; 108 this.inputElement = element;
114 }} 109 }}
115 disabled={field.disabled} 110 disabled={field.disabled}
@@ -124,9 +119,11 @@ class Input extends Component {
124 'mdi-eye': !this.state.showPassword, 119 'mdi-eye': !this.state.showPassword,
125 'mdi-eye-off': this.state.showPassword, 120 'mdi-eye-off': this.state.showPassword,
126 })} 121 })}
127 onClick={() => this.setState((prevState) => ({ 122 onClick={() =>
128 showPassword: !prevState.showPassword, 123 this.setState(prevState => ({
129 }))} 124 showPassword: !prevState.showPassword,
125 }))
126 }
130 tabIndex={-1} 127 tabIndex={-1}
131 aria-label={intl.formatMessage(messages.passwordToggle)} 128 aria-label={intl.formatMessage(messages.passwordToggle)}
132 /> 129 />
@@ -136,10 +133,10 @@ class Input extends Component {
136 {/* <progress value={this.state.passwordScore} max="100" /> */} 133 {/* <progress value={this.state.passwordScore} max="100" /> */}
137 <meter 134 <meter
138 value={passwordScore < 5 ? 5 : passwordScore} 135 value={passwordScore < 5 ? 5 : passwordScore}
139 low="30" 136 low={30}
140 high="75" 137 high={75}
141 optimum="100" 138 optimum={100}
142 max="100" 139 max={100}
143 /> 140 />
144 </div> 141 </div>
145 )} 142 )}
@@ -154,3 +151,5 @@ class Input extends Component {
154 ); 151 );
155 } 152 }
156} 153}
154
155export default injectIntl(Input);
diff --git a/src/components/ui/Link.js b/src/components/ui/Link.js
index 003211e5c..94db3f842 100644
--- a/src/components/ui/Link.js
+++ b/src/components/ui/Link.js
@@ -9,7 +9,9 @@ import { matchRoute } from '../../helpers/routing-helpers';
9import { openExternalUrl } from '../../helpers/url-helpers'; 9import { openExternalUrl } from '../../helpers/url-helpers';
10 10
11// TODO: create container component for this component 11// TODO: create container component for this component
12export default @inject('stores') @observer class Link extends Component { 12@inject('stores')
13@observer
14class Link extends Component {
13 onClick(e) { 15 onClick(e) {
14 if (this.props.disabled) { 16 if (this.props.disabled) {
15 e.preventDefault(); 17 e.preventDefault();
@@ -50,7 +52,7 @@ export default @inject('stores') @observer class Link extends Component {
50 href={router.history.createHref(to)} 52 href={router.history.createHref(to)}
51 className={linkClasses} 53 className={linkClasses}
52 style={style} 54 style={style}
53 onClick={(e) => this.onClick(e)} 55 onClick={e => this.onClick(e)}
54 > 56 >
55 {children} 57 {children}
56 </a> 58 </a>
@@ -62,10 +64,8 @@ Link.wrappedComponent.propTypes = {
62 stores: PropTypes.shape({ 64 stores: PropTypes.shape({
63 router: PropTypes.instanceOf(RouterStore).isRequired, 65 router: PropTypes.instanceOf(RouterStore).isRequired,
64 }).isRequired, 66 }).isRequired,
65 children: PropTypes.oneOfType([ 67 children: PropTypes.oneOfType([oneOrManyChildElements, PropTypes.string])
66 oneOrManyChildElements, 68 .isRequired,
67 PropTypes.string,
68 ]).isRequired,
69 to: PropTypes.string.isRequired, 69 to: PropTypes.string.isRequired,
70 className: PropTypes.string, 70 className: PropTypes.string,
71 activeClassName: PropTypes.string, 71 activeClassName: PropTypes.string,
@@ -83,3 +83,5 @@ Link.wrappedComponent.defaultProps = {
83 target: '', 83 target: '',
84 style: {}, 84 style: {},
85}; 85};
86
87export default Link;
diff --git a/src/components/ui/Loader.js b/src/components/ui/Loader.js
index 4d7113aa1..46c1390bf 100644
--- a/src/components/ui/Loader.js
+++ b/src/components/ui/Loader.js
@@ -5,7 +5,9 @@ import Loader from 'react-loader';
5 5
6import { oneOrManyChildElements } from '../../prop-types'; 6import { oneOrManyChildElements } from '../../prop-types';
7 7
8export default @inject('stores') @observer class LoaderComponent extends Component { 8@inject('stores')
9@observer
10class LoaderComponent extends Component {
9 static propTypes = { 11 static propTypes = {
10 children: oneOrManyChildElements, 12 children: oneOrManyChildElements,
11 loaded: PropTypes.bool, 13 loaded: PropTypes.bool,
@@ -28,13 +30,12 @@ export default @inject('stores') @observer class LoaderComponent extends Compone
28 }; 30 };
29 31
30 render() { 32 render() {
31 const { 33 const { children, loaded, className } = this.props;
32 children,
33 loaded,
34 className,
35 } = this.props;
36 34
37 const color = this.props.color !== 'ACCENT' ? this.props.color : this.props.stores.settings.app.accentColor; 35 const color =
36 this.props.color !== 'ACCENT'
37 ? this.props.color
38 : this.props.stores.settings.app.accentColor;
38 39
39 return ( 40 return (
40 <Loader 41 <Loader
@@ -51,3 +52,5 @@ export default @inject('stores') @observer class LoaderComponent extends Compone
51 ); 52 );
52 } 53 }
53} 54}
55
56export default LoaderComponent;
diff --git a/src/components/ui/Modal/index.js b/src/components/ui/Modal/index.js
index a9fa0cd1b..3c7c66c59 100644
--- a/src/components/ui/Modal/index.js
+++ b/src/components/ui/Modal/index.js
@@ -10,7 +10,8 @@ import styles from './styles';
10 10
11// ReactModal.setAppElement('#root'); 11// ReactModal.setAppElement('#root');
12 12
13export default @injectCSS(styles) class Modal extends Component { 13@injectCSS(styles)
14class Modal extends Component {
14 static propTypes = { 15 static propTypes = {
15 children: PropTypes.node.isRequired, 16 children: PropTypes.node.isRequired,
16 className: PropTypes.string, 17 className: PropTypes.string,
@@ -20,14 +21,14 @@ export default @injectCSS(styles) class Modal extends Component {
20 close: PropTypes.func.isRequired, 21 close: PropTypes.func.isRequired,
21 shouldCloseOnOverlayClick: PropTypes.bool, 22 shouldCloseOnOverlayClick: PropTypes.bool,
22 showClose: PropTypes.bool, 23 showClose: PropTypes.bool,
23 } 24 };
24 25
25 static defaultProps = { 26 static defaultProps = {
26 className: null, 27 className: null,
27 portal: 'modal-portal', 28 portal: 'modal-portal',
28 shouldCloseOnOverlayClick: false, 29 shouldCloseOnOverlayClick: false,
29 showClose: true, 30 showClose: true,
30 } 31 };
31 32
32 render() { 33 render() {
33 const { 34 const {
@@ -53,21 +54,17 @@ export default @injectCSS(styles) class Modal extends Component {
53 portal={portal} 54 portal={portal}
54 onRequestClose={close} 55 onRequestClose={close}
55 shouldCloseOnOverlayClick={shouldCloseOnOverlayClick} 56 shouldCloseOnOverlayClick={shouldCloseOnOverlayClick}
56 appElement={document.getElementById('root')} 57 appElement={document.querySelector('#root')}
57 > 58 >
58 {showClose && close && ( 59 {showClose && close && (
59 <button 60 <button type="button" className={classes.close} onClick={close}>
60 type="button"
61 className={classes.close}
62 onClick={close}
63 >
64 <Icon icon={mdiClose} size={1.5} /> 61 <Icon icon={mdiClose} size={1.5} />
65 </button> 62 </button>
66 )} 63 )}
67 <div className={classes.content}> 64 <div className={classes.content}>{children}</div>
68 {children}
69 </div>
70 </ReactModal> 65 </ReactModal>
71 ); 66 );
72 } 67 }
73} 68}
69
70export default Modal;
diff --git a/src/components/ui/Radio.js b/src/components/ui/Radio.js
index e77714eb7..65a777ff1 100644
--- a/src/components/ui/Radio.js
+++ b/src/components/ui/Radio.js
@@ -4,7 +4,8 @@ import { observer } from 'mobx-react';
4import { Field } from 'mobx-react-form'; 4import { Field } from 'mobx-react-form';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6 6
7export default @observer class Radio extends Component { 7@observer
8class Radio extends Component {
8 static propTypes = { 9 static propTypes = {
9 field: PropTypes.instanceOf(Field).isRequired, 10 field: PropTypes.instanceOf(Field).isRequired,
10 className: PropTypes.string, 11 className: PropTypes.string,
@@ -31,11 +32,7 @@ export default @observer class Radio extends Component {
31 } 32 }
32 33
33 render() { 34 render() {
34 const { 35 const { field, className, showLabel } = this.props;
35 field,
36 className,
37 showLabel,
38 } = this.props;
39 36
40 return ( 37 return (
41 <div 38 <div
@@ -46,15 +43,12 @@ export default @observer class Radio extends Component {
46 })} 43 })}
47 > 44 >
48 {field.label && showLabel && ( 45 {field.label && showLabel && (
49 <label 46 <label className="franz-form__label" htmlFor={field.name}>
50 className="franz-form__label"
51 htmlFor={field.name}
52 >
53 {field.label} 47 {field.label}
54 </label> 48 </label>
55 )} 49 )}
56 <div className="franz-form__radio-wrapper"> 50 <div className="franz-form__radio-wrapper">
57 {field.options.map((type) => ( 51 {field.options.map(type => (
58 <label 52 <label
59 key={type.value} 53 key={type.value}
60 htmlFor={`${field.id}-${type.value}`} 54 htmlFor={`${field.id}-${type.value}`}
@@ -75,14 +69,10 @@ export default @observer class Radio extends Component {
75 </label> 69 </label>
76 ))} 70 ))}
77 </div> 71 </div>
78 {field.error && ( 72 {field.error && <div className="franz-form__error">{field.error}</div>}
79 <div
80 className="franz-form__error"
81 >
82 {field.error}
83 </div>
84 )}
85 </div> 73 </div>
86 ); 74 );
87 } 75 }
88} 76}
77
78export default Radio;
diff --git a/src/components/ui/SearchInput.js b/src/components/ui/SearchInput.js
index 0b25734dd..2d760beab 100644
--- a/src/components/ui/SearchInput.js
+++ b/src/components/ui/SearchInput.js
@@ -4,7 +4,8 @@ import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import { debounce } from 'lodash'; 5import { debounce } from 'lodash';
6 6
7export default @observer class SearchInput extends Component { 7@observer
8class SearchInput extends Component {
8 static propTypes = { 9 static propTypes = {
9 value: PropTypes.string, 10 value: PropTypes.string,
10 placeholder: PropTypes.string, 11 placeholder: PropTypes.string,
@@ -27,7 +28,7 @@ export default @observer class SearchInput extends Component {
27 onChange: () => null, 28 onChange: () => null,
28 onReset: () => null, 29 onReset: () => null,
29 autoFocus: false, 30 autoFocus: false,
30 } 31 };
31 32
32 input = null; 33 input = null;
33 34
@@ -38,7 +39,10 @@ export default @observer class SearchInput extends Component {
38 value: props.value, 39 value: props.value,
39 }; 40 };
40 41
41 this.throttledOnChange = debounce(this.throttledOnChange, this.props.throttleDelay); 42 this.throttledOnChange = debounce(
43 this.throttledOnChange,
44 this.props.throttleDelay,
45 );
42 } 46 }
43 47
44 componentDidMount() { 48 componentDidMount() {
@@ -80,24 +84,18 @@ export default @observer class SearchInput extends Component {
80 const { value } = this.state; 84 const { value } = this.state;
81 85
82 return ( 86 return (
83 <div 87 <div className={classnames([className, 'search-input'])}>
84 className={classnames([ 88 <label htmlFor={name} className="mdi mdi-magnify">
85 className,
86 'search-input',
87 ])}
88 >
89 <label
90 htmlFor={name}
91 className="mdi mdi-magnify"
92 >
93 <input 89 <input
94 name={name} 90 name={name}
95 id={name} 91 id={name}
96 type="text" 92 type="text"
97 placeholder={placeholder} 93 placeholder={placeholder}
98 value={value} 94 value={value}
99 onChange={(e) => this.onChange(e)} 95 onChange={e => this.onChange(e)}
100 ref={(ref) => { this.input = ref; }} 96 ref={ref => {
97 this.input = ref;
98 }}
101 /> 99 />
102 </label> 100 </label>
103 {value.length > 0 && ( 101 {value.length > 0 && (
@@ -110,3 +108,5 @@ export default @observer class SearchInput extends Component {
110 ); 108 );
111 } 109 }
112} 110}
111
112export default SearchInput;
diff --git a/src/components/ui/Select.js b/src/components/ui/Select.js
index e7a5eafa8..5ac7ddd6d 100644
--- a/src/components/ui/Select.js
+++ b/src/components/ui/Select.js
@@ -4,7 +4,8 @@ import { observer } from 'mobx-react';
4import { Field } from 'mobx-react-form'; 4import { Field } from 'mobx-react-form';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6 6
7export default @observer class Select extends Component { 7@observer
8class Select extends Component {
8 static propTypes = { 9 static propTypes = {
9 field: PropTypes.instanceOf(Field).isRequired, 10 field: PropTypes.instanceOf(Field).isRequired,
10 className: PropTypes.string, 11 className: PropTypes.string,
@@ -43,18 +44,12 @@ export default @observer class Select extends Component {
43 } 44 }
44 45
45 render() { 46 render() {
46 const { 47 const { field, className, showLabel, disabled, multiple } = this.props;
47 field,
48 className,
49 showLabel,
50 disabled,
51 multiple,
52 } = this.props;
53 48
54 let selected = field.value; 49 let selected = field.value;
55 50
56 if (multiple) { 51 if (multiple) {
57 if (typeof field.value === 'string' && field.value.substr(0, 1) === '[') { 52 if (typeof field.value === 'string' && field.value.slice(0, 1) === '[') {
58 // Value is JSON encoded 53 // Value is JSON encoded
59 selected = JSON.parse(field.value); 54 selected = JSON.parse(field.value);
60 } else if (typeof field.value === 'object') { 55 } else if (typeof field.value === 'object') {
@@ -74,15 +69,12 @@ export default @observer class Select extends Component {
74 })} 69 })}
75 > 70 >
76 {field.label && showLabel && ( 71 {field.label && showLabel && (
77 <label 72 <label className="franz-form__label" htmlFor={field.name}>
78 className="franz-form__label"
79 htmlFor={field.name}
80 >
81 {field.label} 73 {field.label}
82 </label> 74 </label>
83 )} 75 )}
84 <select 76 <select
85 onChange={multiple ? (e) => this.multipleChange(e) : field.onChange} 77 onChange={multiple ? e => this.multipleChange(e) : field.onChange}
86 id={field.id} 78 id={field.id}
87 defaultValue={selected} 79 defaultValue={selected}
88 className="franz-form__select" 80 className="franz-form__select"
@@ -90,7 +82,7 @@ export default @observer class Select extends Component {
90 multiple={multiple} 82 multiple={multiple}
91 ref={this.element} 83 ref={this.element}
92 > 84 >
93 {field.options.map((type) => ( 85 {field.options.map(type => (
94 <option 86 <option
95 key={type.value} 87 key={type.value}
96 value={type.value} 88 value={type.value}
@@ -100,14 +92,10 @@ export default @observer class Select extends Component {
100 </option> 92 </option>
101 ))} 93 ))}
102 </select> 94 </select>
103 {field.error && ( 95 {field.error && <div className="franz-form__error">{field.error}</div>}
104 <div
105 className="franz-form__error"
106 >
107 {field.error}
108 </div>
109 )}
110 </div> 96 </div>
111 ); 97 );
112 } 98 }
113} 99}
100
101export default Select;
diff --git a/src/components/ui/Slider.js b/src/components/ui/Slider.js
index f344449a0..6f17eae00 100644
--- a/src/components/ui/Slider.js
+++ b/src/components/ui/Slider.js
@@ -4,62 +4,64 @@ import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import { Field } from 'mobx-react-form'; 5import { Field } from 'mobx-react-form';
6 6
7export default @observer class Slider extends Component { 7@observer
8 static propTypes = { 8class Slider extends Component {
9 field: PropTypes.instanceOf(Field).isRequired, 9 static propTypes = {
10 className: PropTypes.string, 10 field: PropTypes.instanceOf(Field).isRequired,
11 showLabel: PropTypes.bool, 11 className: PropTypes.string,
12 disabled: PropTypes.bool, 12 showLabel: PropTypes.bool,
13 }; 13 disabled: PropTypes.bool,
14 };
14 15
15 static defaultProps = { 16 static defaultProps = {
16 className: '', 17 className: '',
17 showLabel: true, 18 showLabel: true,
18 disabled: false, 19 disabled: false,
19 }; 20 };
20 21
21 onChange(e) { 22 onChange(e) {
22 const { field } = this.props; 23 const { field } = this.props;
23 24
24 field.onChange(e); 25 field.onChange(e);
25 } 26 }
26
27 render() {
28 const {
29 field,
30 className,
31 showLabel,
32 disabled,
33 } = this.props;
34 27
35 if (field.value === '' && field.default !== '') { 28 render() {
36 field.value = field.default; 29 const { field, className, showLabel, disabled } = this.props;
37 }
38 30
39 return ( 31 if (field.value === '' && field.default !== '') {
40 <div 32 field.value = field.default;
41 className={classnames([ 33 }
42 'franz-form__field',
43 'franz-form__slider-wrapper',
44 className,
45 ])}
46 >
47 <div className="slider-container">
48 <input
49 className="slider"
50 type="range"
51 id={field.id}
52 name={field.name}
53 value={field.value}
54 min="1"
55 max="100"
56 onChange={(e) => (!disabled ? this.onChange(e) : null)}
57 />
58 </div>
59 34
60 {field.error && <div className={field.error}>{field.error}</div>} 35 return (
61 {field.label && showLabel && <label className="franz-form__label" htmlFor={field.id}>{field.label}</label>} 36 <div
37 className={classnames([
38 'franz-form__field',
39 'franz-form__slider-wrapper',
40 className,
41 ])}
42 >
43 <div className="slider-container">
44 <input
45 className="slider"
46 type="range"
47 id={field.id}
48 name={field.name}
49 value={field.value}
50 min="1"
51 max="100"
52 onChange={e => (!disabled ? this.onChange(e) : null)}
53 />
62 </div> 54 </div>
63 ); 55
64 } 56 {field.error && <div className={field.error}>{field.error}</div>}
57 {field.label && showLabel && (
58 <label className="franz-form__label" htmlFor={field.id}>
59 {field.label}
60 </label>
61 )}
62 </div>
63 );
64 }
65} 65}
66
67export default Slider;
diff --git a/src/components/ui/StatusBarTargetUrl.js b/src/components/ui/StatusBarTargetUrl.js
index 6fc50fe5c..ff4e8c795 100644
--- a/src/components/ui/StatusBarTargetUrl.js
+++ b/src/components/ui/StatusBarTargetUrl.js
@@ -5,7 +5,8 @@ import classnames from 'classnames';
5 5
6import Appear from './effects/Appear'; 6import Appear from './effects/Appear';
7 7
8export default @observer class StatusBarTargetUrl extends Component { 8@observer
9class StatusBarTargetUrl extends Component {
9 static propTypes = { 10 static propTypes = {
10 className: PropTypes.string, 11 className: PropTypes.string,
11 text: PropTypes.string, 12 text: PropTypes.string,
@@ -17,10 +18,7 @@ export default @observer class StatusBarTargetUrl extends Component {
17 }; 18 };
18 19
19 render() { 20 render() {
20 const { 21 const { className, text } = this.props;
21 className,
22 text,
23 } = this.props;
24 22
25 return ( 23 return (
26 <Appear 24 <Appear
@@ -29,10 +27,10 @@ export default @observer class StatusBarTargetUrl extends Component {
29 [`${className}`]: true, 27 [`${className}`]: true,
30 })} 28 })}
31 > 29 >
32 <div className="status-bar-target-url__content"> 30 <div className="status-bar-target-url__content">{text}</div>
33 {text}
34 </div>
35 </Appear> 31 </Appear>
36 ); 32 );
37 } 33 }
38} 34}
35
36export default StatusBarTargetUrl;
diff --git a/src/components/ui/Tabs/TabItem.js b/src/components/ui/Tabs/TabItem.js
deleted file mode 100644
index d0ef4e798..000000000
--- a/src/components/ui/Tabs/TabItem.js
+++ /dev/null
@@ -1,15 +0,0 @@
1import React, { Component } from 'react';
2
3import { oneOrManyChildElements } from '../../../prop-types';
4
5export default class TabItem extends Component {
6 static propTypes = {
7 children: oneOrManyChildElements.isRequired,
8 };
9
10 render() {
11 const { children } = this.props;
12
13 return <>{children}</>;
14 }
15}
diff --git a/src/components/ui/Tabs/TabItem.tsx b/src/components/ui/Tabs/TabItem.tsx
new file mode 100644
index 000000000..bd613ddc7
--- /dev/null
+++ b/src/components/ui/Tabs/TabItem.tsx
@@ -0,0 +1,3 @@
1import React from 'react';
2
3export const TabItem = ({ children }) => <>{children}</>;
diff --git a/src/components/ui/Tabs/Tabs.js b/src/components/ui/Tabs/Tabs.js
index 56c76f215..195398708 100644
--- a/src/components/ui/Tabs/Tabs.js
+++ b/src/components/ui/Tabs/Tabs.js
@@ -5,7 +5,6 @@ import classnames from 'classnames';
5 5
6import { oneOrManyChildElements } from '../../../prop-types'; 6import { oneOrManyChildElements } from '../../../prop-types';
7 7
8export default
9@observer 8@observer
10class Tab extends Component { 9class Tab extends Component {
11 constructor(props) { 10 constructor(props) {
@@ -28,7 +27,7 @@ class Tab extends Component {
28 27
29 render() { 28 render() {
30 const { children: childElements } = this.props; 29 const { children: childElements } = this.props;
31 const children = childElements.filter((c) => !!c); 30 const children = childElements.filter(c => !!c);
32 31
33 if (children.length === 1) { 32 if (children.length === 1) {
34 return <div>{children}</div>; 33 return <div>{children}</div>;
@@ -69,3 +68,5 @@ class Tab extends Component {
69 ); 68 );
70 } 69 }
71} 70}
71
72export default Tab;
diff --git a/src/components/ui/Tabs/index.js b/src/components/ui/Tabs/index.js
deleted file mode 100644
index e4adb62c7..000000000
--- a/src/components/ui/Tabs/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
1import Tabs from './Tabs';
2import TabItem from './TabItem';
3
4export default Tabs;
5
6export { TabItem };
diff --git a/src/components/ui/Toggle.js b/src/components/ui/Toggle.js
index 14330e5c7..bd7bc242d 100644
--- a/src/components/ui/Toggle.js
+++ b/src/components/ui/Toggle.js
@@ -4,7 +4,8 @@ import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import { Field } from 'mobx-react-form'; 5import { Field } from 'mobx-react-form';
6 6
7export default @observer class Toggle extends Component { 7@observer
8class Toggle extends Component {
8 static propTypes = { 9 static propTypes = {
9 field: PropTypes.instanceOf(Field).isRequired, 10 field: PropTypes.instanceOf(Field).isRequired,
10 className: PropTypes.string, 11 className: PropTypes.string,
@@ -25,12 +26,7 @@ export default @observer class Toggle extends Component {
25 } 26 }
26 27
27 render() { 28 render() {
28 const { 29 const { field, className, showLabel, disabled } = this.props;
29 field,
30 className,
31 showLabel,
32 disabled,
33 } = this.props;
34 30
35 if (field.value === '' && field.default !== '') { 31 if (field.value === '' && field.default !== '') {
36 field.value = field.default; 32 field.value = field.default;
@@ -59,12 +55,18 @@ export default @observer class Toggle extends Component {
59 name={field.name} 55 name={field.name}
60 value={field.name} 56 value={field.name}
61 checked={field.value} 57 checked={field.value}
62 onChange={(e) => (!disabled ? this.onChange(e) : null)} 58 onChange={e => (!disabled ? this.onChange(e) : null)}
63 /> 59 />
64 </label> 60 </label>
65 {field.error && <div className={field.error}>{field.error}</div>} 61 {field.error && <div className={field.error}>{field.error}</div>}
66 {field.label && showLabel && <label className="franz-form__label" htmlFor={field.id}>{field.label}</label>} 62 {field.label && showLabel && (
63 <label className="franz-form__label" htmlFor={field.id}>
64 {field.label}
65 </label>
66 )}
67 </div> 67 </div>
68 ); 68 );
69 } 69 }
70} 70}
71
72export default Toggle;
diff --git a/src/components/ui/ToggleRaw.js b/src/components/ui/ToggleRaw.js
index 4700127d4..1fde879ac 100644
--- a/src/components/ui/ToggleRaw.js
+++ b/src/components/ui/ToggleRaw.js
@@ -6,7 +6,8 @@ import PropTypes from 'prop-types';
6import { observer } from 'mobx-react'; 6import { observer } from 'mobx-react';
7import classnames from 'classnames'; 7import classnames from 'classnames';
8 8
9export default @observer class ToggleRaw extends Component { 9@observer
10class ToggleRaw extends Component {
10 static propTypes = { 11 static propTypes = {
11 onChange: PropTypes.func.isRequired, 12 onChange: PropTypes.func.isRequired,
12 field: PropTypes.shape({ 13 field: PropTypes.shape({
@@ -34,12 +35,7 @@ export default @observer class ToggleRaw extends Component {
34 } 35 }
35 36
36 render() { 37 render() {
37 const { 38 const { field, className, showLabel, disabled } = this.props;
38 field,
39 className,
40 showLabel,
41 disabled,
42 } = this.props;
43 39
44 return ( 40 return (
45 <div 41 <div
@@ -64,12 +60,18 @@ export default @observer class ToggleRaw extends Component {
64 name={field.name} 60 name={field.name}
65 value={field.name} 61 value={field.name}
66 checked={field.value} 62 checked={field.value}
67 onChange={(e) => (!disabled ? this.onChange(e) : null)} 63 onChange={e => (!disabled ? this.onChange(e) : null)}
68 /> 64 />
69 </label> 65 </label>
70 {field.error && <div className={field.error}>{field.error}</div>} 66 {field.error && <div className={field.error}>{field.error}</div>}
71 {field.label && showLabel && <label className="franz-form__label" htmlFor={field.id}>{field.label}</label>} 67 {field.label && showLabel && (
68 <label className="franz-form__label" htmlFor={field.id}>
69 {field.label}
70 </label>
71 )}
72 </div> 72 </div>
73 ); 73 );
74 } 74 }
75} 75}
76
77export default ToggleRaw;
diff --git a/src/components/ui/WebviewLoader/index.js b/src/components/ui/WebviewLoader/index.js
index c58d69374..8f4499e7b 100644
--- a/src/components/ui/WebviewLoader/index.js
+++ b/src/components/ui/WebviewLoader/index.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6 6
7import FullscreenLoader from '../FullscreenLoader'; 7import FullscreenLoader from '../FullscreenLoader';
8import styles from './styles'; 8import styles from './styles';
@@ -10,23 +10,21 @@ import styles from './styles';
10const messages = defineMessages({ 10const messages = defineMessages({
11 loading: { 11 loading: {
12 id: 'service.webviewLoader.loading', 12 id: 'service.webviewLoader.loading',
13 defaultMessage: '!!!Loading {service}', 13 defaultMessage: 'Loading {service}',
14 }, 14 },
15}); 15});
16 16
17export default @injectSheet(styles) @observer class WebviewLoader extends Component { 17@injectSheet(styles)
18@observer
19class WebviewLoader extends Component {
18 static propTypes = { 20 static propTypes = {
19 name: PropTypes.string.isRequired, 21 name: PropTypes.string.isRequired,
20 classes: PropTypes.object.isRequired, 22 classes: PropTypes.object.isRequired,
21 }; 23 };
22 24
23 static contextTypes = {
24 intl: intlShape,
25 };
26
27 render() { 25 render() {
28 const { classes, name } = this.props; 26 const { classes, name } = this.props;
29 const { intl } = this.context; 27 const { intl } = this.props;
30 return ( 28 return (
31 <FullscreenLoader 29 <FullscreenLoader
32 className={classes.component} 30 className={classes.component}
@@ -35,3 +33,5 @@ export default @injectSheet(styles) @observer class WebviewLoader extends Compon
35 ); 33 );
36 } 34 }
37} 35}
36
37export default injectIntl(WebviewLoader);
diff --git a/src/components/ui/effects/Appear.js b/src/components/ui/effects/Appear.js
index 1255fce2e..183181f8f 100644
--- a/src/components/ui/effects/Appear.js
+++ b/src/components/ui/effects/Appear.js
@@ -1,11 +1,11 @@
1/* eslint-disable react/no-did-mount-set-state */
2import React, { Component } from 'react'; 1import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
4import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; 3import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
5 4
6export default class Appear extends Component { 5export default class Appear extends Component {
7 static propTypes = { 6 static propTypes = {
8 children: PropTypes.any.isRequired, // eslint-disable-line 7 // eslint-disable-next-line react/forbid-prop-types
8 children: PropTypes.any.isRequired,
9 transitionName: PropTypes.string, 9 transitionName: PropTypes.string,
10 className: PropTypes.string, 10 className: PropTypes.string,
11 }; 11 };
@@ -24,11 +24,7 @@ export default class Appear extends Component {
24 } 24 }
25 25
26 render() { 26 render() {
27 const { 27 const { children, transitionName, className } = this.props;
28 children,
29 transitionName,
30 className,
31 } = this.props;
32 28
33 if (!this.state.mounted) { 29 if (!this.state.mounted) {
34 return null; 30 return null;
diff --git a/src/components/util/ErrorBoundary/index.js b/src/components/util/ErrorBoundary/index.js
index 5db0db226..9c789e981 100644
--- a/src/components/util/ErrorBoundary/index.js
+++ b/src/components/util/ErrorBoundary/index.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import injectSheet from 'react-jss'; 3import injectSheet from 'react-jss';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import Button from '../../ui/Button'; 6import Button from '../../ui/Button';
7 7
@@ -10,26 +10,23 @@ import styles from './styles';
10const messages = defineMessages({ 10const messages = defineMessages({
11 headline: { 11 headline: {
12 id: 'app.errorHandler.headline', 12 id: 'app.errorHandler.headline',
13 defaultMessage: '!!!Something went wrong.', 13 defaultMessage: 'Something went wrong.',
14 }, 14 },
15 action: { 15 action: {
16 id: 'app.errorHandler.action', 16 id: 'app.errorHandler.action',
17 defaultMessage: '!!!Reload', 17 defaultMessage: 'Reload',
18 }, 18 },
19}); 19});
20 20
21export default @injectSheet(styles) class ErrorBoundary extends Component { 21@injectSheet(styles)
22class ErrorBoundary extends Component {
22 state = { 23 state = {
23 hasError: false, 24 hasError: false,
24 } 25 };
25 26
26 static propTypes = { 27 static propTypes = {
27 classes: PropTypes.object.isRequired, 28 classes: PropTypes.object.isRequired,
28 children: PropTypes.node.isRequired, 29 children: PropTypes.node.isRequired,
29 }
30
31 static contextTypes = {
32 intl: intlShape,
33 }; 30 };
34 31
35 componentDidCatch() { 32 componentDidCatch() {
@@ -38,7 +35,7 @@ export default @injectSheet(styles) class ErrorBoundary extends Component {
38 35
39 render() { 36 render() {
40 const { classes } = this.props; 37 const { classes } = this.props;
41 const { intl } = this.context; 38 const { intl } = this.props;
42 39
43 if (this.state.hasError) { 40 if (this.state.hasError) {
44 return ( 41 return (
@@ -58,3 +55,5 @@ export default @injectSheet(styles) class ErrorBoundary extends Component {
58 return this.props.children; 55 return this.props.children;
59 } 56 }
60} 57}
58
59export default injectIntl(ErrorBoundary);
diff --git a/src/config.ts b/src/config.ts
index 7bb2525a5..fe9145021 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -2,10 +2,12 @@
2 2
3import ms from 'ms'; 3import ms from 'ms';
4 4
5import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme';
6
5export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks 7export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks
6 8
7export const LOCAL_HOSTNAME = 'localhost'; 9export const LOCAL_HOSTNAME = 'localhost';
8export const LOCAL_PORT = 45569; 10export const LOCAL_PORT = 45_569;
9export const LOCAL_API = 'http://localhost:3000'; 11export const LOCAL_API = 'http://localhost:3000';
10export const DEV_FRANZ_API = 'https://dev.franzinfra.com'; 12export const DEV_FRANZ_API = 'https://dev.franzinfra.com';
11 13
@@ -158,10 +160,6 @@ export const FRANZ_SERVICE_REQUEST = `${GITHUB_FERDI_URL}/recipes/issues`;
158export const FRANZ_TRANSLATION = 'https://crowdin.com/project/getferdi'; 160export const FRANZ_TRANSLATION = 'https://crowdin.com/project/getferdi';
159export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub'; 161export const FRANZ_DEV_DOCS = 'http://bit.ly/franz-dev-hub';
160 162
161export const GITHUB_ORG_NAME = 'getferdi';
162export const GITHUB_FERDI_REPO_NAME = 'ferdi';
163export const GITHUB_NIGHTLIES_REPO_NAME = 'nightlies';
164
165export const FILE_SYSTEM_SETTINGS_TYPES = ['app', 'proxy']; 163export const FILE_SYSTEM_SETTINGS_TYPES = ['app', 'proxy'];
166 164
167export const LOCAL_SERVER = 'You are using Ferdi without a server'; 165export const LOCAL_SERVER = 'You are using Ferdi without a server';
@@ -180,3 +178,59 @@ export const TODOS_PARTITION_ID = 'persist:todos';
180export const CUSTOM_WEBSITE_RECIPE_ID = 'franz-custom-website'; 178export const CUSTOM_WEBSITE_RECIPE_ID = 'franz-custom-website';
181 179
182export const DEFAULT_SERVICE_ORDER = 99; // something high enough that it gets added to the end of the already-added services on the left sidebar 180export const DEFAULT_SERVICE_ORDER = 99; // something high enough that it gets added to the end of the already-added services on the left sidebar
181
182export const DEFAULT_APP_SETTINGS = {
183 autoLaunchInBackground: false,
184 runInBackground: true,
185 reloadAfterResume: true,
186 enableSystemTray: true,
187 startMinimized: false,
188 confirmOnQuit: false,
189 minimizeToSystemTray: false,
190 closeToSystemTray: false,
191 privateNotifications: false,
192 clipboardNotifications: true,
193 notifyTaskBarOnMessage: false,
194 showDisabledServices: true,
195 showMessageBadgeWhenMuted: true,
196 showDragArea: false,
197 enableSpellchecking: true,
198 spellcheckerLanguage: 'en-us',
199 darkMode: false,
200 splitMode: false,
201 locale: '',
202 fallbackLocale: 'en-US',
203 beta: false,
204 isAppMuted: false,
205 enableGPUAcceleration: true,
206
207 // Ferdi specific options
208 server: LIVE_FERDI_API,
209 predefinedTodoServer: DEFAULT_TODO_SERVICE,
210 autohideMenuBar: false,
211 lockingFeatureEnabled: false,
212 locked: false,
213 lockedPassword: '',
214 useTouchIdToUnlock: true,
215 scheduledDNDEnabled: false,
216 scheduledDNDStart: '17:00',
217 scheduledDNDEnd: '09:00',
218 hibernateOnStartup: true,
219 hibernationStrategy: '300', // seconds
220 wakeUpStrategy: '300', // seconds
221 inactivityLock: 0,
222 automaticUpdates: true,
223 universalDarkMode: true,
224 userAgentPref: '',
225 adaptableDarkMode: true,
226 accentColor: DEFAULT_ACCENT_COLOR,
227 serviceRibbonWidth: 68,
228 iconSize: iconSizeBias,
229 sentry: false,
230 nightly: false,
231 navigationBarBehaviour: 'custom',
232 searchEngine: SEARCH_ENGINE_DDG,
233 useVerticalStyle: false,
234 alwaysShowWorkspaces: false,
235 liftSingleInstanceLock: false,
236};
diff --git a/src/containers/auth/AuthLayoutContainer.js b/src/containers/auth/AuthLayoutContainer.js
index a0d50ab54..7673ab9c7 100644
--- a/src/containers/auth/AuthLayoutContainer.js
+++ b/src/containers/auth/AuthLayoutContainer.js
@@ -14,7 +14,6 @@ import AppLoader from '../../components/ui/AppLoader';
14import { oneOrManyChildElements } from '../../prop-types'; 14import { oneOrManyChildElements } from '../../prop-types';
15import FeaturesStore from '../../stores/FeaturesStore'; 15import FeaturesStore from '../../stores/FeaturesStore';
16 16
17export default
18@inject('stores', 'actions') 17@inject('stores', 'actions')
19@observer 18@observer
20class AuthLayoutContainer extends Component { 19class AuthLayoutContainer extends Component {
@@ -85,3 +84,5 @@ AuthLayoutContainer.wrappedComponent.propTypes = {
85 settings: PropTypes.instanceOf(SettingsStore).isRequired, 84 settings: PropTypes.instanceOf(SettingsStore).isRequired,
86 }).isRequired, 85 }).isRequired,
87}; 86};
87
88export default AuthLayoutContainer;
diff --git a/src/containers/auth/ChangeServerScreen.js b/src/containers/auth/ChangeServerScreen.js
index 28ecc0198..a8910e7b1 100644
--- a/src/containers/auth/ChangeServerScreen.js
+++ b/src/containers/auth/ChangeServerScreen.js
@@ -5,7 +5,9 @@ import { RouterStore } from 'mobx-react-router';
5import ChangeServer from '../../components/auth/ChangeServer'; 5import ChangeServer from '../../components/auth/ChangeServer';
6import SettingsStore from '../../stores/SettingsStore'; 6import SettingsStore from '../../stores/SettingsStore';
7 7
8export default @inject('stores', 'actions') @observer class ChangeServerScreen extends Component { 8@inject('stores', 'actions')
9@observer
10class ChangeServerScreen extends Component {
9 constructor(props) { 11 constructor(props) {
10 super(props); 12 super(props);
11 13
@@ -28,12 +30,7 @@ export default @inject('stores', 'actions') @observer class ChangeServerScreen e
28 const { stores } = this.props; 30 const { stores } = this.props;
29 const { server } = stores.settings.all.app; 31 const { server } = stores.settings.all.app;
30 32
31 return ( 33 return <ChangeServer onSubmit={this.onSubmit} server={server} />;
32 <ChangeServer
33 onSubmit={this.onSubmit}
34 server={server}
35 />
36 );
37 } 34 }
38} 35}
39 36
@@ -46,3 +43,5 @@ ChangeServerScreen.wrappedComponent.propTypes = {
46 router: PropTypes.instanceOf(RouterStore).isRequired, 43 router: PropTypes.instanceOf(RouterStore).isRequired,
47 }).isRequired, 44 }).isRequired,
48}; 45};
46
47export default ChangeServerScreen;
diff --git a/src/containers/auth/ImportScreen.js b/src/containers/auth/ImportScreen.js
index 9143ef616..ce786bdb8 100644
--- a/src/containers/auth/ImportScreen.js
+++ b/src/containers/auth/ImportScreen.js
@@ -5,7 +5,9 @@ import { RouterStore } from 'mobx-react-router';
5import Import from '../../components/auth/Import'; 5import Import from '../../components/auth/Import';
6import UserStore from '../../stores/UserStore'; 6import UserStore from '../../stores/UserStore';
7 7
8export default @inject('stores', 'actions') @observer class ImportScreen extends Component { 8@inject('stores', 'actions')
9@observer
10class ImportScreen extends Component {
9 render() { 11 render() {
10 const { actions, stores } = this.props; 12 const { actions, stores } = this.props;
11 13
@@ -33,3 +35,5 @@ ImportScreen.wrappedComponent.propTypes = {
33 router: PropTypes.instanceOf(RouterStore).isRequired, 35 router: PropTypes.instanceOf(RouterStore).isRequired,
34 }).isRequired, 36 }).isRequired,
35}; 37};
38
39export default ImportScreen;
diff --git a/src/containers/auth/InviteScreen.js b/src/containers/auth/InviteScreen.js
index 66afaf7e1..d9d52a57c 100644
--- a/src/containers/auth/InviteScreen.js
+++ b/src/containers/auth/InviteScreen.js
@@ -3,16 +3,13 @@ import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react'; 3import { inject, observer } from 'mobx-react';
4import Invite from '../../components/auth/Invite'; 4import Invite from '../../components/auth/Invite';
5 5
6export default @inject('stores', 'actions') @observer class InviteScreen extends Component { 6@inject('stores', 'actions')
7@observer
8class InviteScreen extends Component {
7 render() { 9 render() {
8 const { actions } = this.props; 10 const { actions } = this.props;
9 11
10 return ( 12 return <Invite onSubmit={actions.user.invite} embed={false} />;
11 <Invite
12 onSubmit={actions.user.invite}
13 embed={false}
14 />
15 );
16 } 13 }
17} 14}
18 15
@@ -23,3 +20,5 @@ InviteScreen.wrappedComponent.propTypes = {
23 }).isRequired, 20 }).isRequired,
24 }).isRequired, 21 }).isRequired,
25}; 22};
23
24export default InviteScreen;
diff --git a/src/containers/auth/LockedScreen.js b/src/containers/auth/LockedScreen.js
index 4e97c6573..a49549731 100644
--- a/src/containers/auth/LockedScreen.js
+++ b/src/containers/auth/LockedScreen.js
@@ -7,10 +7,12 @@ import SettingsStore from '../../stores/SettingsStore';
7import { hash } from '../../helpers/password-helpers'; 7import { hash } from '../../helpers/password-helpers';
8import UserStore from '../../stores/UserStore'; 8import UserStore from '../../stores/UserStore';
9 9
10export default @inject('stores', 'actions') @observer class LockedScreen extends Component { 10@inject('stores', 'actions')
11@observer
12class LockedScreen extends Component {
11 state = { 13 state = {
12 error: false, 14 error: false,
13 } 15 };
14 16
15 constructor(props) { 17 constructor(props) {
16 super(props); 18 super(props);
@@ -83,3 +85,5 @@ LockedScreen.wrappedComponent.propTypes = {
83 user: PropTypes.instanceOf(UserStore).isRequired, 85 user: PropTypes.instanceOf(UserStore).isRequired,
84 }).isRequired, 86 }).isRequired,
85}; 87};
88
89export default LockedScreen;
diff --git a/src/containers/auth/LoginScreen.js b/src/containers/auth/LoginScreen.js
index e636f99e0..cab73316b 100644
--- a/src/containers/auth/LoginScreen.js
+++ b/src/containers/auth/LoginScreen.js
@@ -6,7 +6,9 @@ import UserStore from '../../stores/UserStore';
6 6
7import { globalError as globalErrorPropType } from '../../prop-types'; 7import { globalError as globalErrorPropType } from '../../prop-types';
8 8
9export default @inject('stores', 'actions') @observer class LoginScreen extends Component { 9@inject('stores', 'actions')
10@observer
11class LoginScreen extends Component {
10 static propTypes = { 12 static propTypes = {
11 error: globalErrorPropType.isRequired, 13 error: globalErrorPropType.isRequired,
12 }; 14 };
@@ -18,7 +20,9 @@ export default @inject('stores', 'actions') @observer class LoginScreen extends
18 onSubmit={actions.user.login} 20 onSubmit={actions.user.login}
19 isSubmitting={stores.user.loginRequest.isExecuting} 21 isSubmitting={stores.user.loginRequest.isExecuting}
20 isTokenExpired={stores.user.isTokenExpired} 22 isTokenExpired={stores.user.isTokenExpired}
21 isServerLogout={stores.user.logoutReason === stores.user.logoutReasonTypes.SERVER} 23 isServerLogout={
24 stores.user.logoutReason === stores.user.logoutReasonTypes.SERVER
25 }
22 signupRoute={stores.user.signupRoute} 26 signupRoute={stores.user.signupRoute}
23 passwordRoute={stores.user.passwordRoute} 27 passwordRoute={stores.user.passwordRoute}
24 changeServerRoute={stores.user.changeServerRoute} 28 changeServerRoute={stores.user.changeServerRoute}
@@ -36,3 +40,5 @@ LoginScreen.wrappedComponent.propTypes = {
36 user: PropTypes.instanceOf(UserStore).isRequired, 40 user: PropTypes.instanceOf(UserStore).isRequired,
37 }).isRequired, 41 }).isRequired,
38}; 42};
43
44export default LoginScreen;
diff --git a/src/containers/auth/PasswordScreen.js b/src/containers/auth/PasswordScreen.js
index 9c6732f1a..86a746b9b 100644
--- a/src/containers/auth/PasswordScreen.js
+++ b/src/containers/auth/PasswordScreen.js
@@ -4,7 +4,9 @@ import { inject, observer } from 'mobx-react';
4import Password from '../../components/auth/Password'; 4import Password from '../../components/auth/Password';
5import UserStore from '../../stores/UserStore'; 5import UserStore from '../../stores/UserStore';
6 6
7export default @inject('stores', 'actions') @observer class PasswordScreen extends Component { 7@inject('stores', 'actions')
8@observer
9class PasswordScreen extends Component {
8 render() { 10 render() {
9 const { actions, stores } = this.props; 11 const { actions, stores } = this.props;
10 12
@@ -28,3 +30,5 @@ PasswordScreen.wrappedComponent.propTypes = {
28 user: PropTypes.instanceOf(UserStore).isRequired, 30 user: PropTypes.instanceOf(UserStore).isRequired,
29 }).isRequired, 31 }).isRequired,
30}; 32};
33
34export default PasswordScreen;
diff --git a/src/containers/auth/SetupAssistantScreen.js b/src/containers/auth/SetupAssistantScreen.js
index d7036969a..efda2e9d2 100644
--- a/src/containers/auth/SetupAssistantScreen.js
+++ b/src/containers/auth/SetupAssistantScreen.js
@@ -14,7 +14,6 @@ import ServicesStore from '../../stores/ServicesStore';
14import RecipesStore from '../../stores/RecipesStore'; 14import RecipesStore from '../../stores/RecipesStore';
15import UserStore from '../../stores/UserStore'; 15import UserStore from '../../stores/UserStore';
16 16
17export default
18@inject('stores', 'actions') 17@inject('stores', 'actions')
19@observer 18@observer
20class SetupAssistantScreen extends Component { 19class SetupAssistantScreen extends Component {
@@ -134,3 +133,5 @@ SetupAssistantScreen.wrappedComponent.propTypes = {
134 recipe: PropTypes.instanceOf(RecipesStore).isRequired, 133 recipe: PropTypes.instanceOf(RecipesStore).isRequired,
135 }).isRequired, 134 }).isRequired,
136}; 135};
136
137export default SetupAssistantScreen;
diff --git a/src/containers/auth/SignupScreen.js b/src/containers/auth/SignupScreen.js
index 38c5dfb43..b20a7fd62 100644
--- a/src/containers/auth/SignupScreen.js
+++ b/src/containers/auth/SignupScreen.js
@@ -8,7 +8,9 @@ import FeaturesStore from '../../stores/FeaturesStore';
8 8
9import { globalError as globalErrorPropType } from '../../prop-types'; 9import { globalError as globalErrorPropType } from '../../prop-types';
10 10
11export default @inject('stores', 'actions') @observer class SignupScreen extends Component { 11@inject('stores', 'actions')
12@observer
13class SignupScreen extends Component {
12 static propTypes = { 14 static propTypes = {
13 error: globalErrorPropType.isRequired, 15 error: globalErrorPropType.isRequired,
14 }; 16 };
@@ -24,7 +26,7 @@ export default @inject('stores', 'actions') @observer class SignupScreen extends
24 26
25 return ( 27 return (
26 <Signup 28 <Signup
27 onSubmit={(values) => this.onSignup(values)} 29 onSubmit={values => this.onSignup(values)}
28 isSubmitting={stores.user.signupRequest.isExecuting} 30 isSubmitting={stores.user.signupRequest.isExecuting}
29 loginRoute={stores.user.loginRoute} 31 loginRoute={stores.user.loginRoute}
30 changeServerRoute={stores.user.changeServerRoute} 32 changeServerRoute={stores.user.changeServerRoute}
@@ -43,3 +45,5 @@ SignupScreen.wrappedComponent.propTypes = {
43 features: PropTypes.instanceOf(FeaturesStore).isRequired, 45 features: PropTypes.instanceOf(FeaturesStore).isRequired,
44 }).isRequired, 46 }).isRequired,
45}; 47};
48
49export default SignupScreen;
diff --git a/src/containers/auth/WelcomeScreen.js b/src/containers/auth/WelcomeScreen.js
index bfcc880d0..d169e5f0f 100644
--- a/src/containers/auth/WelcomeScreen.js
+++ b/src/containers/auth/WelcomeScreen.js
@@ -6,7 +6,9 @@ import Welcome from '../../components/auth/Welcome';
6import UserStore from '../../stores/UserStore'; 6import UserStore from '../../stores/UserStore';
7import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; 7import RecipePreviewsStore from '../../stores/RecipePreviewsStore';
8 8
9export default @inject('stores', 'actions') @observer class LoginScreen extends Component { 9@inject('stores', 'actions')
10@observer
11class LoginScreen extends Component {
10 render() { 12 render() {
11 const { user, recipePreviews } = this.props.stores; 13 const { user, recipePreviews } = this.props.stores;
12 14
@@ -27,3 +29,5 @@ LoginScreen.wrappedComponent.propTypes = {
27 recipePreviews: PropTypes.instanceOf(RecipePreviewsStore).isRequired, 29 recipePreviews: PropTypes.instanceOf(RecipePreviewsStore).isRequired,
28 }).isRequired, 30 }).isRequired,
29}; 31};
32
33export default LoginScreen;
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js
index 83a25168b..3e92b0610 100644
--- a/src/containers/layout/AppLayoutContainer.js
+++ b/src/containers/layout/AppLayoutContainer.js
@@ -25,7 +25,6 @@ import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawe
25import { workspaceStore } from '../../features/workspaces'; 25import { workspaceStore } from '../../features/workspaces';
26import WorkspacesStore from '../../features/workspaces/store'; 26import WorkspacesStore from '../../features/workspaces/store';
27 27
28export default
29@inject('stores', 'actions') 28@inject('stores', 'actions')
30@observer 29@observer
31class AppLayoutContainer extends Component { 30class AppLayoutContainer extends Component {
@@ -199,3 +198,5 @@ AppLayoutContainer.wrappedComponent.propTypes = {
199 }).isRequired, 198 }).isRequired,
200 children: oneOrManyChildElements, 199 children: oneOrManyChildElements,
201}; 200};
201
202export default AppLayoutContainer;
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js
index 8d92b01be..1515fc22b 100644
--- a/src/containers/settings/AccountScreen.js
+++ b/src/containers/settings/AccountScreen.js
@@ -10,9 +10,8 @@ import SettingsStore from '../../stores/SettingsStore';
10import AccountDashboard from '../../components/settings/account/AccountDashboard'; 10import AccountDashboard from '../../components/settings/account/AccountDashboard';
11import ErrorBoundary from '../../components/util/ErrorBoundary'; 11import ErrorBoundary from '../../components/util/ErrorBoundary';
12import { LIVE_FRANZ_API } from '../../config'; 12import { LIVE_FRANZ_API } from '../../config';
13import { WEBSITE } from '../../environment'; 13import { WEBSITE } from '../../environment-remote';
14 14
15export default
16@inject('stores', 'actions') 15@inject('stores', 'actions')
17@observer 16@observer
18class AccountScreen extends Component { 17class AccountScreen extends Component {
@@ -33,14 +32,12 @@ class AccountScreen extends Component {
33 32
34 const api = stores.settings.all.app.server; 33 const api = stores.settings.all.app.server;
35 34
36 let url; 35 const url =
37 if (api === LIVE_FRANZ_API) { 36 api === LIVE_FRANZ_API
38 url = stores.user.getAuthURL( 37 ? stores.user.getAuthURL(
39 `${WEBSITE}${route}?utm_source=app&utm_medium=account_dashboard`, 38 `${WEBSITE}${route}?utm_source=app&utm_medium=account_dashboard`,
40 ); 39 )
41 } else { 40 : `${api}${route}`;
42 url = `${api}${route}`;
43 }
44 41
45 actions.app.openExternalUrl({ url }); 42 actions.app.openExternalUrl({ url });
46 } 43 }
@@ -58,16 +55,16 @@ class AccountScreen extends Component {
58 user={user.data} 55 user={user.data}
59 isLoading={isLoadingUserInfo} 56 isLoading={isLoadingUserInfo}
60 userInfoRequestFailed={ 57 userInfoRequestFailed={
61 user.getUserInfoRequest.wasExecuted 58 user.getUserInfoRequest.wasExecuted &&
62 && user.getUserInfoRequest.isError 59 user.getUserInfoRequest.isError
63 } 60 }
64 retryUserInfoRequest={() => this.reloadData()} 61 retryUserInfoRequest={() => this.reloadData()}
65 onCloseSubscriptionWindow={() => this.onCloseWindow()} 62 onCloseSubscriptionWindow={() => this.onCloseWindow()}
66 deleteAccount={userActions.delete} 63 deleteAccount={userActions.delete}
67 isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} 64 isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting}
68 isDeleteAccountSuccessful={ 65 isDeleteAccountSuccessful={
69 user.deleteAccountRequest.wasExecuted 66 user.deleteAccountRequest.wasExecuted &&
70 && !user.deleteAccountRequest.isError 67 !user.deleteAccountRequest.isError
71 } 68 }
72 openEditAccount={() => this.handleWebsiteLink('/user/profile')} 69 openEditAccount={() => this.handleWebsiteLink('/user/profile')}
73 openInvoices={() => this.handleWebsiteLink('/user/invoices')} 70 openInvoices={() => this.handleWebsiteLink('/user/invoices')}
@@ -89,3 +86,5 @@ AccountScreen.wrappedComponent.propTypes = {
89 user: PropTypes.instanceOf(UserStore).isRequired, 86 user: PropTypes.instanceOf(UserStore).isRequired,
90 }).isRequired, 87 }).isRequired,
91}; 88};
89
90export default AccountScreen;
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js
index c880e97ae..dee7e7cff 100644
--- a/src/containers/settings/EditServiceScreen.js
+++ b/src/containers/settings/EditServiceScreen.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react'; 3import { inject, observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import { RouterStore } from 'mobx-react-router'; 6import { RouterStore } from 'mobx-react-router';
7import UserStore from '../../stores/UserStore'; 7import UserStore from '../../stores/UserStore';
@@ -27,87 +27,89 @@ import globalMessages from '../../i18n/globalMessages';
27const messages = defineMessages({ 27const messages = defineMessages({
28 name: { 28 name: {
29 id: 'settings.service.form.name', 29 id: 'settings.service.form.name',
30 defaultMessage: '!!!Name', 30 defaultMessage: 'Name',
31 }, 31 },
32 enableService: { 32 enableService: {
33 id: 'settings.service.form.enableService', 33 id: 'settings.service.form.enableService',
34 defaultMessage: '!!!Enable service', 34 defaultMessage: 'Enable service',
35 }, 35 },
36 enableHibernation: { 36 enableHibernation: {
37 id: 'settings.service.form.enableHibernation', 37 id: 'settings.service.form.enableHibernation',
38 defaultMessage: '!!!Enable hibernation', 38 defaultMessage: 'Enable hibernation',
39 }, 39 },
40 enableNotification: { 40 enableNotification: {
41 id: 'settings.service.form.enableNotification', 41 id: 'settings.service.form.enableNotification',
42 defaultMessage: '!!!Enable Notifications', 42 defaultMessage: 'Enable notifications',
43 }, 43 },
44 enableBadge: { 44 enableBadge: {
45 id: 'settings.service.form.enableBadge', 45 id: 'settings.service.form.enableBadge',
46 defaultMessage: '!!!Show unread message badges', 46 defaultMessage: 'Show unread message badges',
47 }, 47 },
48 enableAudio: { 48 enableAudio: {
49 id: 'settings.service.form.enableAudio', 49 id: 'settings.service.form.enableAudio',
50 defaultMessage: '!!!Enable audio', 50 defaultMessage: 'Enable audio',
51 }, 51 },
52 team: { 52 team: {
53 id: 'settings.service.form.team', 53 id: 'settings.service.form.team',
54 defaultMessage: '!!!Team', 54 defaultMessage: 'Team',
55 }, 55 },
56 customUrl: { 56 customUrl: {
57 id: 'settings.service.form.customUrl', 57 id: 'settings.service.form.customUrl',
58 defaultMessage: '!!!Service URL', 58 defaultMessage: 'Custom server',
59 }, 59 },
60 indirectMessages: { 60 indirectMessages: {
61 id: 'settings.service.form.indirectMessages', 61 id: 'settings.service.form.indirectMessages',
62 defaultMessage: '!!!Show message badge for all new messages', 62 defaultMessage: 'Show message badge for all new messages',
63 }, 63 },
64 icon: { 64 icon: {
65 id: 'settings.service.form.icon', 65 id: 'settings.service.form.icon',
66 defaultMessage: '!!!Custom icon', 66 defaultMessage: 'Custom icon',
67 }, 67 },
68 enableDarkMode: { 68 enableDarkMode: {
69 id: 'settings.service.form.enableDarkMode', 69 id: 'settings.service.form.enableDarkMode',
70 defaultMessage: '!!!Enable Dark Mode', 70 defaultMessage: 'Enable Dark Mode',
71 }, 71 },
72 darkReaderBrightness: { 72 darkReaderBrightness: {
73 id: 'settings.service.form.darkReaderBrightness', 73 id: 'settings.service.form.darkReaderBrightness',
74 defaultMessage: '!!!Dark Reader Brightness', 74 defaultMessage: 'Dark Reader Brightness',
75 }, 75 },
76 darkReaderContrast: { 76 darkReaderContrast: {
77 id: 'settings.service.form.darkReaderContrast', 77 id: 'settings.service.form.darkReaderContrast',
78 defaultMessage: '!!!Dark Reader Contrast', 78 defaultMessage: 'Dark Reader Contrast',
79 }, 79 },
80 darkReaderSepia: { 80 darkReaderSepia: {
81 id: 'settings.service.form.darkReaderSepia', 81 id: 'settings.service.form.darkReaderSepia',
82 defaultMessage: '!!!Dark Reader Sepia', 82 defaultMessage: 'Dark Reader Sepia',
83 },
84 onlyShowFavoritesInUnreadCount: {
85 id: 'settings.service.form.onlyShowFavoritesInUnreadCount',
86 defaultMessage: 'Only show Favorites in unread count',
83 }, 87 },
84 enableProxy: { 88 enableProxy: {
85 id: 'settings.service.form.proxy.isEnabled', 89 id: 'settings.service.form.proxy.isEnabled',
86 defaultMessage: '!!!Use Proxy', 90 defaultMessage: 'Use Proxy',
87 }, 91 },
88 proxyHost: { 92 proxyHost: {
89 id: 'settings.service.form.proxy.host', 93 id: 'settings.service.form.proxy.host',
90 defaultMessage: '!!!Proxy Host/IP', 94 defaultMessage: 'Proxy Host/IP',
91 }, 95 },
92 proxyPort: { 96 proxyPort: {
93 id: 'settings.service.form.proxy.port', 97 id: 'settings.service.form.proxy.port',
94 defaultMessage: '!!!Port', 98 defaultMessage: 'Port',
95 }, 99 },
96 proxyUser: { 100 proxyUser: {
97 id: 'settings.service.form.proxy.user', 101 id: 'settings.service.form.proxy.user',
98 defaultMessage: '!!!User', 102 defaultMessage: 'User (optional)',
99 }, 103 },
100 proxyPassword: { 104 proxyPassword: {
101 id: 'settings.service.form.proxy.password', 105 id: 'settings.service.form.proxy.password',
102 defaultMessage: '!!!Password', 106 defaultMessage: 'Password (optional)',
103 }, 107 },
104}); 108});
105 109
106export default @inject('stores', 'actions') @observer class EditServiceScreen extends Component { 110@inject('stores', 'actions')
107 static contextTypes = { 111@observer
108 intl: intlShape, 112class EditServiceScreen extends Component {
109 };
110
111 onSubmit(data) { 113 onSubmit(data) {
112 const { action } = this.props.router.params; 114 const { action } = this.props.router.params;
113 const { recipes, services } = this.props.stores; 115 const { recipes, services } = this.props.stores;
@@ -132,27 +134,31 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
132 } 134 }
133 135
134 prepareForm(recipe, service, proxy) { 136 prepareForm(recipe, service, proxy) {
135 const { 137 const { intl } = this.props;
136 intl,
137 } = this.context;
138 138
139 const { 139 const { stores, router } = this.props;
140 stores,
141 router,
142 } = this.props;
143 140
144 const { action } = router.params; 141 const { action } = router.params;
145 142
146 let defaultSpellcheckerLanguage = SPELLCHECKER_LOCALES[stores.settings.app.spellcheckerLanguage]; 143 let defaultSpellcheckerLanguage =
144 SPELLCHECKER_LOCALES[stores.settings.app.spellcheckerLanguage];
147 145
148 if (stores.settings.app.spellcheckerLanguage === 'automatic') { 146 if (stores.settings.app.spellcheckerLanguage === 'automatic') {
149 defaultSpellcheckerLanguage = intl.formatMessage(globalMessages.spellcheckerAutomaticDetectionShort); 147 defaultSpellcheckerLanguage = intl.formatMessage(
148 globalMessages.spellcheckerAutomaticDetectionShort,
149 );
150 } 150 }
151 151
152 const spellcheckerLanguage = getSelectOptions({ 152 const spellcheckerLanguage = getSelectOptions({
153 locales: SPELLCHECKER_LOCALES, 153 locales: SPELLCHECKER_LOCALES,
154 resetToDefaultText: intl.formatMessage(globalMessages.spellcheckerSystemDefault, { default: defaultSpellcheckerLanguage }), 154 resetToDefaultText: intl.formatMessage(
155 automaticDetectionText: stores.settings.app.spellcheckerLanguage !== 'automatic' ? intl.formatMessage(globalMessages.spellcheckerAutomaticDetection) : '', 155 globalMessages.spellcheckerSystemDefault,
156 { default: defaultSpellcheckerLanguage },
157 ),
158 automaticDetectionText:
159 stores.settings.app.spellcheckerLanguage !== 'automatic'
160 ? intl.formatMessage(globalMessages.spellcheckerAutomaticDetection)
161 : '',
156 }); 162 });
157 163
158 const config = { 164 const config = {
@@ -169,7 +175,10 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
169 }, 175 },
170 isHibernationEnabled: { 176 isHibernationEnabled: {
171 label: intl.formatMessage(messages.enableHibernation), 177 label: intl.formatMessage(messages.enableHibernation),
172 value: action !== 'edit' ? recipe.autoHibernate : service.isHibernationEnabled, 178 value:
179 action !== 'edit'
180 ? recipe.autoHibernate
181 : service.isHibernationEnabled,
173 default: true, 182 default: true,
174 }, 183 },
175 isNotificationEnabled: { 184 isNotificationEnabled: {
@@ -200,17 +209,23 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
200 }, 209 },
201 darkReaderBrightness: { 210 darkReaderBrightness: {
202 label: intl.formatMessage(messages.darkReaderBrightness), 211 label: intl.formatMessage(messages.darkReaderBrightness),
203 value: service.darkReaderSettings ? service.darkReaderSettings.brightness : undefined, 212 value: service.darkReaderSettings
213 ? service.darkReaderSettings.brightness
214 : undefined,
204 default: 100, 215 default: 100,
205 }, 216 },
206 darkReaderContrast: { 217 darkReaderContrast: {
207 label: intl.formatMessage(messages.darkReaderContrast), 218 label: intl.formatMessage(messages.darkReaderContrast),
208 value: service.darkReaderSettings ? service.darkReaderSettings.contrast : undefined, 219 value: service.darkReaderSettings
220 ? service.darkReaderSettings.contrast
221 : undefined,
209 default: 90, 222 default: 90,
210 }, 223 },
211 darkReaderSepia: { 224 darkReaderSepia: {
212 label: intl.formatMessage(messages.darkReaderSepia), 225 label: intl.formatMessage(messages.darkReaderSepia),
213 value: service.darkReaderSettings ? service.darkReaderSettings.sepia : undefined, 226 value: service.darkReaderSettings
227 ? service.darkReaderSettings.sepia
228 : undefined,
214 default: 10, 229 default: 10,
215 }, 230 },
216 spellcheckerLanguage: { 231 spellcheckerLanguage: {
@@ -252,7 +267,10 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
252 // More fine grained and use case specific validation rules 267 // More fine grained and use case specific validation rules
253 if (recipe.hasTeamId && recipe.hasCustomUrl) { 268 if (recipe.hasTeamId && recipe.hasCustomUrl) {
254 config.fields.team.validators = [oneRequired(['team', 'customUrl'])]; 269 config.fields.team.validators = [oneRequired(['team', 'customUrl'])];
255 config.fields.customUrl.validators = [url, oneRequired(['team', 'customUrl'])]; 270 config.fields.customUrl.validators = [
271 url,
272 oneRequired(['team', 'customUrl']),
273 ];
256 } 274 }
257 275
258 // If a service can be hosted and has a teamId or customUrl 276 // If a service can be hosted and has a teamId or customUrl
@@ -275,6 +293,16 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
275 }); 293 });
276 } 294 }
277 295
296 if (recipe.allowFavoritesDelineationInUnreadCount) {
297 Object.assign(config.fields, {
298 onlyShowFavoritesInUnreadCount: {
299 label: intl.formatMessage(messages.onlyShowFavoritesInUnreadCount),
300 value: service.onlyShowFavoritesInUnreadCount,
301 default: false,
302 },
303 });
304 }
305
278 if (proxy.isEnabled) { 306 if (proxy.isEnabled) {
279 const serviceProxyConfig = stores.settings.proxy[service.id] || {}; 307 const serviceProxyConfig = stores.settings.proxy[service.id] || {};
280 308
@@ -344,9 +372,7 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
344 } 372 }
345 373
346 render() { 374 render() {
347 const { 375 const { recipes, services, user } = this.props.stores;
348 recipes, services, user,
349 } = this.props.stores;
350 const { action } = this.props.router.params; 376 const { action } = this.props.router.params;
351 377
352 let recipe; 378 let recipe;
@@ -358,9 +384,7 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
358 384
359 // TODO: render error message when recipe is `null` 385 // TODO: render error message when recipe is `null`
360 if (!recipe) { 386 if (!recipe) {
361 return ( 387 return <ServiceError />;
362 <ServiceError />
363 );
364 } 388 }
365 } else { 389 } else {
366 service = services.activeSettings; 390 service = services.activeSettings;
@@ -372,13 +396,11 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
372 } 396 }
373 397
374 if (isLoading) { 398 if (isLoading) {
375 return (<div>Loading...</div>); 399 return <div>Loading...</div>;
376 } 400 }
377 401
378 if (!recipe) { 402 if (!recipe) {
379 return ( 403 return <div>something went wrong</div>;
380 <div>something went wrong</div>
381 );
382 } 404 }
383 405
384 const form = this.prepareForm(recipe, service, proxyFeature); 406 const form = this.prepareForm(recipe, service, proxyFeature);
@@ -392,11 +414,14 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
392 user={user.data} 414 user={user.data}
393 form={form} 415 form={form}
394 status={services.actionStatus} 416 status={services.actionStatus}
395 isSaving={services.updateServiceRequest.isExecuting || services.createServiceRequest.isExecuting} 417 isSaving={
418 services.updateServiceRequest.isExecuting ||
419 services.createServiceRequest.isExecuting
420 }
396 isDeleting={services.deleteServiceRequest.isExecuting} 421 isDeleting={services.deleteServiceRequest.isExecuting}
397 onSubmit={(d) => this.onSubmit(d)} 422 onSubmit={d => this.onSubmit(d)}
398 onDelete={() => this.deleteService()} 423 onDelete={() => this.deleteService()}
399 openRecipeFile={(file) => this.openRecipeFile(file)} 424 openRecipeFile={file => this.openRecipeFile(file)}
400 isProxyFeatureEnabled={proxyFeature.isEnabled} 425 isProxyFeatureEnabled={proxyFeature.isEnabled}
401 /> 426 />
402 </ErrorBoundary> 427 </ErrorBoundary>
@@ -417,3 +442,5 @@ EditServiceScreen.wrappedComponent.propTypes = {
417 service: PropTypes.instanceOf(ServicesStore).isRequired, 442 service: PropTypes.instanceOf(ServicesStore).isRequired,
418 }).isRequired, 443 }).isRequired,
419}; 444};
445
446export default injectIntl(EditServiceScreen);
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js
index 09244bc3c..1b05644f9 100644
--- a/src/containers/settings/EditSettingsScreen.js
+++ b/src/containers/settings/EditSettingsScreen.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react'; 3import { inject, observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import AppStore from '../../stores/AppStore'; 6import AppStore from '../../stores/AppStore';
7import SettingsStore from '../../stores/SettingsStore'; 7import SettingsStore from '../../stores/SettingsStore';
@@ -10,10 +10,18 @@ import TodosStore from '../../features/todos/store';
10import Form from '../../lib/Form'; 10import Form from '../../lib/Form';
11import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; 11import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages';
12import { 12import {
13 HIBERNATION_STRATEGIES, SIDEBAR_WIDTH, ICON_SIZES, NAVIGATION_BAR_BEHAVIOURS, SEARCH_ENGINE_NAMES, TODO_APPS, 13 DEFAULT_APP_SETTINGS,
14 DEFAULT_SETTING_KEEP_ALL_WORKSPACES_LOADED, DEFAULT_IS_FEATURE_ENABLED_BY_USER, WAKE_UP_STRATEGIES, 14 HIBERNATION_STRATEGIES,
15 SIDEBAR_WIDTH,
16 ICON_SIZES,
17 NAVIGATION_BAR_BEHAVIOURS,
18 SEARCH_ENGINE_NAMES,
19 TODO_APPS,
20 DEFAULT_SETTING_KEEP_ALL_WORKSPACES_LOADED,
21 DEFAULT_IS_FEATURE_ENABLED_BY_USER,
22 WAKE_UP_STRATEGIES,
15} from '../../config'; 23} from '../../config';
16import { DEFAULT_APP_SETTINGS, isMac } from '../../environment'; 24import { isMac } from '../../environment';
17 25
18import { getSelectOptions } from '../../helpers/i18n-helpers'; 26import { getSelectOptions } from '../../helpers/i18n-helpers';
19import { hash } from '../../helpers/password-helpers'; 27import { hash } from '../../helpers/password-helpers';
@@ -31,195 +39,197 @@ const debug = require('debug')('Ferdi:EditSettingsScreen');
31const messages = defineMessages({ 39const messages = defineMessages({
32 autoLaunchOnStart: { 40 autoLaunchOnStart: {
33 id: 'settings.app.form.autoLaunchOnStart', 41 id: 'settings.app.form.autoLaunchOnStart',
34 defaultMessage: '!!!Launch Ferdi on start', 42 defaultMessage: 'Launch Ferdi on start',
35 }, 43 },
36 autoLaunchInBackground: { 44 autoLaunchInBackground: {
37 id: 'settings.app.form.autoLaunchInBackground', 45 id: 'settings.app.form.autoLaunchInBackground',
38 defaultMessage: '!!!Open in background', 46 defaultMessage: 'Open in background',
39 }, 47 },
40 runInBackground: { 48 runInBackground: {
41 id: 'settings.app.form.runInBackground', 49 id: 'settings.app.form.runInBackground',
42 defaultMessage: '!!!Keep Ferdi in background when closing the window', 50 defaultMessage: 'Keep Ferdi in background when closing the window',
43 }, 51 },
44 startMinimized: { 52 startMinimized: {
45 id: 'settings.app.form.startMinimized', 53 id: 'settings.app.form.startMinimized',
46 defaultMessage: '!!!Start minimized', 54 defaultMessage: 'Start minimized',
47 }, 55 },
48 confirmOnQuit: { 56 confirmOnQuit: {
49 id: 'settings.app.form.confirmOnQuit', 57 id: 'settings.app.form.confirmOnQuit',
50 defaultMessage: '!!!Confirm when quitting Ferdi', 58 defaultMessage: 'Confirm when quitting Ferdi',
51 }, 59 },
52 enableSystemTray: { 60 enableSystemTray: {
53 id: 'settings.app.form.enableSystemTray', 61 id: 'settings.app.form.enableSystemTray',
54 defaultMessage: '!!!Always show Ferdi in System Tray', 62 defaultMessage: 'Always show Ferdi in System Tray',
55 }, 63 },
56 enableMenuBar: { 64 enableMenuBar: {
57 id: 'settings.app.form.enableMenuBar', 65 id: 'settings.app.form.enableMenuBar',
58 defaultMessage: '!!!Always show Ferdi in Menu Bar', 66 defaultMessage: 'Always show Ferdi in Menu Bar',
59 }, 67 },
60 reloadAfterResume: { 68 reloadAfterResume: {
61 id: 'settings.app.form.reloadAfterResume', 69 id: 'settings.app.form.reloadAfterResume',
62 defaultMessage: '!!!Reload Ferdi after system resume', 70 defaultMessage: 'Reload Ferdi after system resume',
63 }, 71 },
64 minimizeToSystemTray: { 72 minimizeToSystemTray: {
65 id: 'settings.app.form.minimizeToSystemTray', 73 id: 'settings.app.form.minimizeToSystemTray',
66 defaultMessage: '!!!Minimize Ferdi to system tray', 74 defaultMessage: 'Minimize Ferdi to system tray',
67 }, 75 },
68 closeToSystemTray: { 76 closeToSystemTray: {
69 id: 'settings.app.form.closeToSystemTray', 77 id: 'settings.app.form.closeToSystemTray',
70 defaultMessage: '!!!Close Ferdi to system tray', 78 defaultMessage: 'Close Ferdi to system tray',
71 }, 79 },
72 privateNotifications: { 80 privateNotifications: {
73 id: 'settings.app.form.privateNotifications', 81 id: 'settings.app.form.privateNotifications',
74 defaultMessage: '!!!Don\'t show message content in notifications', 82 defaultMessage: "Don't show message content in notifications",
75 }, 83 },
76 clipboardNotifications: { 84 clipboardNotifications: {
77 id: 'settings.app.form.clipboardNotifications', 85 id: 'settings.app.form.clipboardNotifications',
78 defaultMessage: '!!!Don\'t show notifications for clipboard events', 86 defaultMessage: "Don't show notifications for clipboard events",
79 }, 87 },
80 notifyTaskBarOnMessage: { 88 notifyTaskBarOnMessage: {
81 id: 'settings.app.form.notifyTaskBarOnMessage', 89 id: 'settings.app.form.notifyTaskBarOnMessage',
82 defaultMessage: '!!!Notify TaskBar/Dock on new message', 90 defaultMessage: 'Notify TaskBar/Dock on new message',
83 }, 91 },
84 navigationBarBehaviour: { 92 navigationBarBehaviour: {
85 id: 'settings.app.form.navigationBarBehaviour', 93 id: 'settings.app.form.navigationBarBehaviour',
86 defaultMessage: '!!!Navigation bar behaviour', 94 defaultMessage: 'Navigation bar behaviour',
87 }, 95 },
88 searchEngine: { 96 searchEngine: {
89 id: 'settings.app.form.searchEngine', 97 id: 'settings.app.form.searchEngine',
90 defaultMessage: '!!!Search engine', 98 defaultMessage: 'Search engine',
91 }, 99 },
92 sentry: { 100 sentry: {
93 id: 'settings.app.form.sentry', 101 id: 'settings.app.form.sentry',
94 defaultMessage: '!!!Send telemetry data', 102 defaultMessage: 'Send telemetry data',
95 }, 103 },
96 hibernateOnStartup: { 104 hibernateOnStartup: {
97 id: 'settings.app.form.hibernateOnStartup', 105 id: 'settings.app.form.hibernateOnStartup',
98 defaultMessage: '!!!Keep services in hibernation on startup', 106 defaultMessage: 'Keep services in hibernation on startup',
99 }, 107 },
100 hibernationStrategy: { 108 hibernationStrategy: {
101 id: 'settings.app.form.hibernationStrategy', 109 id: 'settings.app.form.hibernationStrategy',
102 defaultMessage: '!!!Hibernation strategy', 110 defaultMessage: 'Hibernation strategy',
103 }, 111 },
104 wakeUpStrategy: { 112 wakeUpStrategy: {
105 id: 'settings.app.form.wakeUpStrategy', 113 id: 'settings.app.form.wakeUpStrategy',
106 defaultMessage: '!!!Wake up strategy', 114 defaultMessage: 'Wake up strategy',
107 }, 115 },
108 predefinedTodoServer: { 116 predefinedTodoServer: {
109 id: 'settings.app.form.predefinedTodoServer', 117 id: 'settings.app.form.predefinedTodoServer',
110 defaultMessage: '!!!Todo Server', 118 defaultMessage: 'Todo Server',
111 }, 119 },
112 customTodoServer: { 120 customTodoServer: {
113 id: 'settings.app.form.customTodoServer', 121 id: 'settings.app.form.customTodoServer',
114 defaultMessage: '!!!Custom TodoServer', 122 defaultMessage: 'Custom Todo Server',
115 }, 123 },
116 enableLock: { 124 enableLock: {
117 id: 'settings.app.form.enableLock', 125 id: 'settings.app.form.enableLock',
118 defaultMessage: '!!!Enable Password Lock', 126 defaultMessage: 'Enable Password Lock',
119 }, 127 },
120 lockPassword: { 128 lockPassword: {
121 id: 'settings.app.form.lockPassword', 129 id: 'settings.app.form.lockPassword',
122 defaultMessage: '!!!Password', 130 defaultMessage: 'Password',
123 }, 131 },
124 useTouchIdToUnlock: { 132 useTouchIdToUnlock: {
125 id: 'settings.app.form.useTouchIdToUnlock', 133 id: 'settings.app.form.useTouchIdToUnlock',
126 defaultMessage: '!!!Allow using Touch ID to unlock', 134 defaultMessage: 'Allow using TouchID to unlock Ferdi',
127 }, 135 },
128 inactivityLock: { 136 inactivityLock: {
129 id: 'settings.app.form.inactivityLock', 137 id: 'settings.app.form.inactivityLock',
130 defaultMessage: '!!!Lock after inactivity', 138 defaultMessage: 'Lock after inactivity',
131 }, 139 },
132 scheduledDNDEnabled: { 140 scheduledDNDEnabled: {
133 id: 'settings.app.form.scheduledDNDEnabled', 141 id: 'settings.app.form.scheduledDNDEnabled',
134 defaultMessage: '!!!Enable scheduled Do-not-Disturb', 142 defaultMessage: 'Enable scheduled Do-not-Disturb',
135 }, 143 },
136 scheduledDNDStart: { 144 scheduledDNDStart: {
137 id: 'settings.app.form.scheduledDNDStart', 145 id: 'settings.app.form.scheduledDNDStart',
138 defaultMessage: '!!!From', 146 defaultMessage: 'From',
139 }, 147 },
140 scheduledDNDEnd: { 148 scheduledDNDEnd: {
141 id: 'settings.app.form.scheduledDNDEnd', 149 id: 'settings.app.form.scheduledDNDEnd',
142 defaultMessage: '!!!To', 150 defaultMessage: 'To',
143 }, 151 },
144 language: { 152 language: {
145 id: 'settings.app.form.language', 153 id: 'settings.app.form.language',
146 defaultMessage: '!!!Language', 154 defaultMessage: 'Language',
147 }, 155 },
148 darkMode: { 156 darkMode: {
149 id: 'settings.app.form.darkMode', 157 id: 'settings.app.form.darkMode',
150 defaultMessage: '!!!Dark Mode', 158 defaultMessage: 'Enable Dark Mode',
151 }, 159 },
152 adaptableDarkMode: { 160 adaptableDarkMode: {
153 id: 'settings.app.form.adaptableDarkMode', 161 id: 'settings.app.form.adaptableDarkMode',
154 defaultMessage: '!!!Synchronize dark mode with my OS\'s dark mode setting', 162 defaultMessage: "Synchronize dark mode with my OS's dark mode setting",
155 }, 163 },
156 universalDarkMode: { 164 universalDarkMode: {
157 id: 'settings.app.form.universalDarkMode', 165 id: 'settings.app.form.universalDarkMode',
158 defaultMessage: '!!!Enable universal Dark Mode', 166 defaultMessage: 'Enable universal Dark Mode',
167 },
168 splitMode: {
169 id: 'settings.app.form.splitMode',
170 defaultMessage: 'Enable Split View Mode',
159 }, 171 },
160 serviceRibbonWidth: { 172 serviceRibbonWidth: {
161 id: 'settings.app.form.serviceRibbonWidth', 173 id: 'settings.app.form.serviceRibbonWidth',
162 defaultMessage: '!!!Sidebar width', 174 defaultMessage: 'Sidebar width',
163 }, 175 },
164 iconSize: { 176 iconSize: {
165 id: 'settings.app.form.iconSize', 177 id: 'settings.app.form.iconSize',
166 defaultMessage: '!!!Service icon size', 178 defaultMessage: 'Service icon size',
167 }, 179 },
168 useVerticalStyle: { 180 useVerticalStyle: {
169 id: 'settings.app.form.useVerticalStyle', 181 id: 'settings.app.form.useVerticalStyle',
170 defaultMessage: '!!!Use horizontal style', 182 defaultMessage: 'Use horizontal style',
171 }, 183 },
172 alwaysShowWorkspaces: { 184 alwaysShowWorkspaces: {
173 id: 'settings.app.form.alwaysShowWorkspaces', 185 id: 'settings.app.form.alwaysShowWorkspaces',
174 defaultMessage: '!!!Always show workspace drawer', 186 defaultMessage: 'Always show workspace drawer',
175 }, 187 },
176 accentColor: { 188 accentColor: {
177 id: 'settings.app.form.accentColor', 189 id: 'settings.app.form.accentColor',
178 defaultMessage: '!!!Accent color', 190 defaultMessage: 'Accent color',
179 }, 191 },
180 showDisabledServices: { 192 showDisabledServices: {
181 id: 'settings.app.form.showDisabledServices', 193 id: 'settings.app.form.showDisabledServices',
182 defaultMessage: '!!!Display disabled services tabs', 194 defaultMessage: 'Display disabled services tabs',
183 }, 195 },
184 showMessageBadgeWhenMuted: { 196 showMessageBadgeWhenMuted: {
185 id: 'settings.app.form.showMessagesBadgesWhenMuted', 197 id: 'settings.app.form.showMessagesBadgesWhenMuted',
186 defaultMessage: '!!!Show unread message badge when notifications are disabled', 198 defaultMessage: 'Show unread message badge when notifications are disabled',
187 }, 199 },
188 showDragArea: { 200 showDragArea: {
189 id: 'settings.app.form.showDragArea', 201 id: 'settings.app.form.showDragArea',
190 defaultMessage: '!!!Show draggable area on window', 202 defaultMessage: 'Show draggable area on window',
191 }, 203 },
192 enableSpellchecking: { 204 enableSpellchecking: {
193 id: 'settings.app.form.enableSpellchecking', 205 id: 'settings.app.form.enableSpellchecking',
194 defaultMessage: '!!!Enable spell checking', 206 defaultMessage: 'Enable spell checking',
195 }, 207 },
196 enableGPUAcceleration: { 208 enableGPUAcceleration: {
197 id: 'settings.app.form.enableGPUAcceleration', 209 id: 'settings.app.form.enableGPUAcceleration',
198 defaultMessage: '!!!Enable GPU Acceleration', 210 defaultMessage: 'Enable GPU Acceleration',
199 }, 211 },
200 beta: { 212 beta: {
201 id: 'settings.app.form.beta', 213 id: 'settings.app.form.beta',
202 defaultMessage: '!!!Include beta versions', 214 defaultMessage: 'Include beta versions',
203 }, 215 },
204 automaticUpdates: { 216 automaticUpdates: {
205 id: 'settings.app.form.automaticUpdates', 217 id: 'settings.app.form.automaticUpdates',
206 defaultMessage: '!!!Enable updates', 218 defaultMessage: 'Enable updates',
207 }, 219 },
208 enableTodos: { 220 enableTodos: {
209 id: 'settings.app.form.enableTodos', 221 id: 'settings.app.form.enableTodos',
210 defaultMessage: '!!!Enable Franz Todos', 222 defaultMessage: 'Enable Ferdi Todos',
211 }, 223 },
212 keepAllWorkspacesLoaded: { 224 keepAllWorkspacesLoaded: {
213 id: 'settings.app.form.keepAllWorkspacesLoaded', 225 id: 'settings.app.form.keepAllWorkspacesLoaded',
214 defaultMessage: '!!!Keep all workspaces loaded', 226 defaultMessage: 'Keep all workspaces loaded',
215 }, 227 },
216}); 228});
217 229
218export default @inject('stores', 'actions') @observer class EditSettingsScreen extends Component { 230@inject('stores', 'actions')
219 static contextTypes = { 231@observer
220 intl: intlShape, 232class EditSettingsScreen extends Component {
221 };
222
223 constructor(props) { 233 constructor(props) {
224 super(props); 234 super(props);
225 235
@@ -283,12 +293,15 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
283 darkMode: Boolean(settingsData.darkMode), 293 darkMode: Boolean(settingsData.darkMode),
284 adaptableDarkMode: Boolean(settingsData.adaptableDarkMode), 294 adaptableDarkMode: Boolean(settingsData.adaptableDarkMode),
285 universalDarkMode: Boolean(settingsData.universalDarkMode), 295 universalDarkMode: Boolean(settingsData.universalDarkMode),
296 splitMode: Boolean(settingsData.splitMode),
286 serviceRibbonWidth: Number(settingsData.serviceRibbonWidth), 297 serviceRibbonWidth: Number(settingsData.serviceRibbonWidth),
287 iconSize: Number(settingsData.iconSize), 298 iconSize: Number(settingsData.iconSize),
288 useVerticalStyle: Boolean(settingsData.useVerticalStyle), 299 useVerticalStyle: Boolean(settingsData.useVerticalStyle),
289 alwaysShowWorkspaces: Boolean(settingsData.alwaysShowWorkspaces), 300 alwaysShowWorkspaces: Boolean(settingsData.alwaysShowWorkspaces),
290 accentColor: settingsData.accentColor, 301 accentColor: settingsData.accentColor,
291 showMessageBadgeWhenMuted: Boolean(settingsData.showMessageBadgeWhenMuted), 302 showMessageBadgeWhenMuted: Boolean(
303 settingsData.showMessageBadgeWhenMuted,
304 ),
292 showDragArea: Boolean(settingsData.showDragArea), 305 showDragArea: Boolean(settingsData.showDragArea),
293 enableSpellchecking: Boolean(settingsData.enableSpellchecking), 306 enableSpellchecking: Boolean(settingsData.enableSpellchecking),
294 spellcheckerLanguage: settingsData.spellcheckerLanguage, 307 spellcheckerLanguage: settingsData.spellcheckerLanguage,
@@ -309,24 +322,27 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
309 322
310 if (workspaces.isFeatureActive) { 323 if (workspaces.isFeatureActive) {
311 const { keepAllWorkspacesLoaded } = workspaces.settings; 324 const { keepAllWorkspacesLoaded } = workspaces.settings;
312 if (Boolean(keepAllWorkspacesLoaded) !== Boolean(settingsData.keepAllWorkspacesLoaded)) { 325 if (
326 Boolean(keepAllWorkspacesLoaded) !==
327 Boolean(settingsData.keepAllWorkspacesLoaded)
328 ) {
313 workspaceActions.toggleKeepAllWorkspacesLoadedSetting(); 329 workspaceActions.toggleKeepAllWorkspacesLoadedSetting();
314 } 330 }
315 } 331 }
316 332
317 if (todos.isFeatureActive) { 333 if (todos.isFeatureActive) {
318 const { isFeatureEnabledByUser } = todos.settings; 334 const { isFeatureEnabledByUser } = todos.settings;
319 if (Boolean(isFeatureEnabledByUser) !== Boolean(settingsData.enableTodos)) { 335 if (
336 Boolean(isFeatureEnabledByUser) !== Boolean(settingsData.enableTodos)
337 ) {
320 todosActions.toggleTodosFeatureVisibility(); 338 todosActions.toggleTodosFeatureVisibility();
321 } 339 }
322 } 340 }
323 } 341 }
324 342
325 prepareForm() { 343 prepareForm() {
326 const { 344 const { app, settings, user, todos, workspaces } = this.props.stores;
327 app, settings, user, todos, workspaces, 345 const { intl } = this.props;
328 } = this.props.stores;
329 const { intl } = this.context;
330 const { lockedPassword } = this.state; 346 const { lockedPassword } = this.state;
331 347
332 const locales = getSelectOptions({ 348 const locales = getSelectOptions({
@@ -370,7 +386,9 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
370 386
371 const spellcheckingLanguages = getSelectOptions({ 387 const spellcheckingLanguages = getSelectOptions({
372 locales: SPELLCHECKER_LOCALES, 388 locales: SPELLCHECKER_LOCALES,
373 automaticDetectionText: this.context.intl.formatMessage(globalMessages.spellcheckerAutomaticDetection), 389 automaticDetectionText: intl.formatMessage(
390 globalMessages.spellcheckerAutomaticDetection,
391 ),
374 }); 392 });
375 393
376 const config = { 394 const config = {
@@ -401,7 +419,9 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
401 default: DEFAULT_APP_SETTINGS.confirmOnQuit, 419 default: DEFAULT_APP_SETTINGS.confirmOnQuit,
402 }, 420 },
403 enableSystemTray: { 421 enableSystemTray: {
404 label: intl.formatMessage(isMac ? messages.enableMenuBar : messages.enableSystemTray), 422 label: intl.formatMessage(
423 isMac ? messages.enableMenuBar : messages.enableSystemTray,
424 ),
405 value: settings.all.app.enableSystemTray, 425 value: settings.all.app.enableSystemTray,
406 default: DEFAULT_APP_SETTINGS.enableSystemTray, 426 default: DEFAULT_APP_SETTINGS.enableSystemTray,
407 }, 427 },
@@ -566,6 +586,11 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
566 value: settings.all.app.universalDarkMode, 586 value: settings.all.app.universalDarkMode,
567 default: DEFAULT_APP_SETTINGS.universalDarkMode, 587 default: DEFAULT_APP_SETTINGS.universalDarkMode,
568 }, 588 },
589 splitMode: {
590 label: intl.formatMessage(messages.splitMode),
591 value: settings.all.app.splitMode,
592 default: DEFAULT_APP_SETTINGS.splitMode,
593 },
569 serviceRibbonWidth: { 594 serviceRibbonWidth: {
570 label: intl.formatMessage(messages.serviceRibbonWidth), 595 label: intl.formatMessage(messages.serviceRibbonWidth),
571 value: settings.all.app.serviceRibbonWidth, 596 value: settings.all.app.serviceRibbonWidth,
@@ -637,23 +662,15 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
637 } 662 }
638 663
639 render() { 664 render() {
640 const { 665 const { app, todos, workspaces, services } = this.props.stores;
641 app,
642 todos,
643 workspaces,
644 services,
645 } = this.props.stores;
646 const { 666 const {
647 updateStatus, 667 updateStatus,
648 updateStatusTypes, 668 updateStatusTypes,
649 isClearingAllCache, 669 isClearingAllCache,
650 lockingFeatureEnabled, 670 lockingFeatureEnabled,
651 } = app; 671 } = app;
652 const { 672 const { checkForUpdates, installUpdate, clearAllCache } =
653 checkForUpdates, 673 this.props.actions.app;
654 installUpdate,
655 clearAllCache,
656 } = this.props.actions.app;
657 const form = this.prepareForm(); 674 const form = this.prepareForm();
658 675
659 return ( 676 return (
@@ -666,7 +683,7 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
666 isUpdateAvailable={updateStatus === updateStatusTypes.AVAILABLE} 683 isUpdateAvailable={updateStatus === updateStatusTypes.AVAILABLE}
667 noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} 684 noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE}
668 updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} 685 updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED}
669 onSubmit={(d) => this.onSubmit(d)} 686 onSubmit={d => this.onSubmit(d)}
670 getCacheSize={() => app.cacheSize} 687 getCacheSize={() => app.cacheSize}
671 isClearingAllCache={isClearingAllCache} 688 isClearingAllCache={isClearingAllCache}
672 onClearAllCache={clearAllCache} 689 onClearAllCache={clearAllCache}
@@ -675,9 +692,13 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
675 lockingFeatureEnabled={lockingFeatureEnabled} 692 lockingFeatureEnabled={lockingFeatureEnabled}
676 automaticUpdates={this.props.stores.settings.app.automaticUpdates} 693 automaticUpdates={this.props.stores.settings.app.automaticUpdates}
677 isDarkmodeEnabled={this.props.stores.settings.app.darkMode} 694 isDarkmodeEnabled={this.props.stores.settings.app.darkMode}
678 isAdaptableDarkModeEnabled={this.props.stores.settings.app.adaptableDarkMode} 695 isAdaptableDarkModeEnabled={
696 this.props.stores.settings.app.adaptableDarkMode
697 }
679 isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser} 698 isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser}
680 isUsingCustomTodoService={this.props.stores.todos.isUsingCustomTodoService} 699 isUsingCustomTodoService={
700 this.props.stores.todos.isUsingCustomTodoService
701 }
681 isNightlyEnabled={this.props.stores.settings.app.nightly} 702 isNightlyEnabled={this.props.stores.settings.app.nightly}
682 hasAddedTodosAsService={services.isTodosServiceAdded} 703 hasAddedTodosAsService={services.isTodosServiceAdded}
683 isOnline={app.isOnline} 704 isOnline={app.isOnline}
@@ -704,3 +725,5 @@ EditSettingsScreen.wrappedComponent.propTypes = {
704 workspaces: PropTypes.instanceOf(WorkspacesStore).isRequired, 725 workspaces: PropTypes.instanceOf(WorkspacesStore).isRequired,
705 }).isRequired, 726 }).isRequired,
706}; 727};
728
729export default injectIntl(EditSettingsScreen);
diff --git a/src/containers/settings/EditUserScreen.js b/src/containers/settings/EditUserScreen.js
index 820b5e4d3..ca1363c59 100644
--- a/src/containers/settings/EditUserScreen.js
+++ b/src/containers/settings/EditUserScreen.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react'; 3import { inject, observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import UserStore from '../../stores/UserStore'; 6import UserStore from '../../stores/UserStore';
7import Form from '../../lib/Form'; 7import Form from '../../lib/Form';
@@ -13,47 +13,45 @@ import { required, email, minLength } from '../../helpers/validation-helpers';
13const messages = defineMessages({ 13const messages = defineMessages({
14 firstname: { 14 firstname: {
15 id: 'settings.user.form.firstname', 15 id: 'settings.user.form.firstname',
16 defaultMessage: '!!!Firstname', 16 defaultMessage: 'First Name',
17 }, 17 },
18 lastname: { 18 lastname: {
19 id: 'settings.user.form.lastname', 19 id: 'settings.user.form.lastname',
20 defaultMessage: '!!!Lastname', 20 defaultMessage: 'Last Name',
21 }, 21 },
22 email: { 22 email: {
23 id: 'settings.user.form.email', 23 id: 'settings.user.form.email',
24 defaultMessage: '!!!Email', 24 defaultMessage: 'Email',
25 }, 25 },
26 accountTypeLabel: { 26 accountTypeLabel: {
27 id: 'settings.user.form.accountType.label', 27 id: 'settings.user.form.accountType.label',
28 defaultMessage: '!!!Account type', 28 defaultMessage: 'Account type',
29 }, 29 },
30 accountTypeIndividual: { 30 accountTypeIndividual: {
31 id: 'settings.user.form.accountType.individual', 31 id: 'settings.user.form.accountType.individual',
32 defaultMessage: '!!!Individual', 32 defaultMessage: 'Individual',
33 }, 33 },
34 accountTypeNonProfit: { 34 accountTypeNonProfit: {
35 id: 'settings.user.form.accountType.non-profit', 35 id: 'settings.user.form.accountType.non-profit',
36 defaultMessage: '!!!Non-Profit', 36 defaultMessage: 'Non-Profit',
37 }, 37 },
38 accountTypeCompany: { 38 accountTypeCompany: {
39 id: 'settings.user.form.accountType.company', 39 id: 'settings.user.form.accountType.company',
40 defaultMessage: '!!!Company', 40 defaultMessage: 'Company',
41 }, 41 },
42 currentPassword: { 42 currentPassword: {
43 id: 'settings.user.form.currentPassword', 43 id: 'settings.user.form.currentPassword',
44 defaultMessage: '!!!Current password', 44 defaultMessage: 'Current password',
45 }, 45 },
46 newPassword: { 46 newPassword: {
47 id: 'settings.user.form.newPassword', 47 id: 'settings.user.form.newPassword',
48 defaultMessage: '!!!New password', 48 defaultMessage: 'New password',
49 }, 49 },
50}); 50});
51 51
52export default @inject('stores', 'actions') @observer class EditUserScreen extends Component { 52@inject('stores', 'actions')
53 static contextTypes = { 53@observer
54 intl: intlShape, 54class EditUserScreen extends Component {
55 };
56
57 componentWillUnmount() { 55 componentWillUnmount() {
58 this.props.actions.user.resetStatus(); 56 this.props.actions.user.resetStatus();
59 } 57 }
@@ -67,7 +65,7 @@ export default @inject('stores', 'actions') @observer class EditUserScreen exten
67 } 65 }
68 66
69 prepareForm(user) { 67 prepareForm(user) {
70 const { intl } = this.context; 68 const { intl } = this.props;
71 69
72 const config = { 70 const config = {
73 fields: { 71 fields: {
@@ -93,16 +91,20 @@ export default @inject('stores', 'actions') @observer class EditUserScreen exten
93 value: user.accountType, 91 value: user.accountType,
94 validators: [required], 92 validators: [required],
95 label: intl.formatMessage(messages.accountTypeLabel), 93 label: intl.formatMessage(messages.accountTypeLabel),
96 options: [{ 94 options: [
97 value: 'individual', 95 {
98 label: intl.formatMessage(messages.accountTypeIndividual), 96 value: 'individual',
99 }, { 97 label: intl.formatMessage(messages.accountTypeIndividual),
100 value: 'non-profit', 98 },
101 label: intl.formatMessage(messages.accountTypeNonProfit), 99 {
102 }, { 100 value: 'non-profit',
103 value: 'company', 101 label: intl.formatMessage(messages.accountTypeNonProfit),
104 label: intl.formatMessage(messages.accountTypeCompany), 102 },
105 }], 103 {
104 value: 'company',
105 label: intl.formatMessage(messages.accountTypeCompany),
106 },
107 ],
106 }, 108 },
107 organization: { 109 organization: {
108 label: intl.formatMessage(messages.accountTypeCompany), 110 label: intl.formatMessage(messages.accountTypeCompany),
@@ -129,7 +131,7 @@ export default @inject('stores', 'actions') @observer class EditUserScreen exten
129 const { user } = this.props.stores; 131 const { user } = this.props.stores;
130 132
131 if (user.getUserInfoRequest.isExecuting) { 133 if (user.getUserInfoRequest.isExecuting) {
132 return (<div>Loading...</div>); 134 return <div>Loading...</div>;
133 } 135 }
134 136
135 const form = this.prepareForm(user.data); 137 const form = this.prepareForm(user.data);
@@ -141,7 +143,7 @@ export default @inject('stores', 'actions') @observer class EditUserScreen exten
141 status={user.actionStatus} 143 status={user.actionStatus}
142 form={form} 144 form={form}
143 isSaving={user.updateUserInfoRequest.isExecuting} 145 isSaving={user.updateUserInfoRequest.isExecuting}
144 onSubmit={(d) => this.onSubmit(d)} 146 onSubmit={d => this.onSubmit(d)}
145 /> 147 />
146 </ErrorBoundary> 148 </ErrorBoundary>
147 ); 149 );
@@ -156,3 +158,5 @@ EditUserScreen.wrappedComponent.propTypes = {
156 user: PropTypes.instanceOf(UserStore).isRequired, 158 user: PropTypes.instanceOf(UserStore).isRequired,
157 }).isRequired, 159 }).isRequired,
158}; 160};
161
162export default injectIntl(EditUserScreen);
diff --git a/src/containers/settings/InviteScreen.js b/src/containers/settings/InviteScreen.js
index 4fdaef08b..bf393f42f 100644
--- a/src/containers/settings/InviteScreen.js
+++ b/src/containers/settings/InviteScreen.js
@@ -6,7 +6,9 @@ import Invite from '../../components/auth/Invite';
6import ErrorBoundary from '../../components/util/ErrorBoundary'; 6import ErrorBoundary from '../../components/util/ErrorBoundary';
7import UserStore from '../../stores/UserStore'; 7import UserStore from '../../stores/UserStore';
8 8
9export default @inject('stores', 'actions') @observer class InviteScreen extends Component { 9@inject('stores', 'actions')
10@observer
11class InviteScreen extends Component {
10 componentWillUnmount() { 12 componentWillUnmount() {
11 this.props.stores.user.inviteRequest.reset(); 13 this.props.stores.user.inviteRequest.reset();
12 } 14 }
@@ -20,7 +22,9 @@ export default @inject('stores', 'actions') @observer class InviteScreen extends
20 <Invite 22 <Invite
21 onSubmit={actions.user.invite} 23 onSubmit={actions.user.invite}
22 isLoadingInvite={user.inviteRequest.isExecuting} 24 isLoadingInvite={user.inviteRequest.isExecuting}
23 isInviteSuccessful={user.inviteRequest.wasExecuted && !user.inviteRequest.isError} 25 isInviteSuccessful={
26 user.inviteRequest.wasExecuted && !user.inviteRequest.isError
27 }
24 embed 28 embed
25 /> 29 />
26 </ErrorBoundary> 30 </ErrorBoundary>
@@ -36,3 +40,5 @@ InviteScreen.wrappedComponent.propTypes = {
36 user: PropTypes.instanceOf(UserStore).isRequired, 40 user: PropTypes.instanceOf(UserStore).isRequired,
37 }).isRequired, 41 }).isRequired,
38}; 42};
43
44export default InviteScreen;
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js
index 784052bbe..2e60ceefa 100644
--- a/src/containers/settings/RecipesScreen.js
+++ b/src/containers/settings/RecipesScreen.js
@@ -12,13 +12,16 @@ import UserStore from '../../stores/UserStore';
12import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; 12import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard';
13import ErrorBoundary from '../../components/util/ErrorBoundary'; 13import ErrorBoundary from '../../components/util/ErrorBoundary';
14import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; 14import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config';
15import { asarRecipesPath, userDataRecipesPath } from '../../environment'; 15import { userDataRecipesPath } from '../../environment-remote';
16import { asarRecipesPath } from '../../helpers/asar-helpers';
16import { communityRecipesStore } from '../../features/communityRecipes'; 17import { communityRecipesStore } from '../../features/communityRecipes';
17import RecipePreview from '../../models/RecipePreview'; 18import RecipePreview from '../../models/RecipePreview';
18import AppStore from '../../stores/AppStore'; 19import AppStore from '../../stores/AppStore';
19import { openPath } from '../../helpers/url-helpers'; 20import { openPath } from '../../helpers/url-helpers';
20 21
21export default @inject('stores', 'actions') @observer class RecipesScreen extends Component { 22@inject('stores', 'actions')
23@observer
24class RecipesScreen extends Component {
22 static propTypes = { 25 static propTypes = {
23 params: PropTypes.shape({ 26 params: PropTypes.shape({
24 filter: PropTypes.string, 27 filter: PropTypes.string,
@@ -75,25 +78,32 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
75 } 78 }
76 79
77 _sortByName(recipe1, recipe2) { 80 _sortByName(recipe1, recipe2) {
78 if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) { return -1; } 81 if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) {
79 if (recipe1.name.toLowerCase() > recipe2.name.toLowerCase()) { return 1; } 82 return -1;
83 }
84 if (recipe1.name.toLowerCase() > recipe2.name.toLowerCase()) {
85 return 1;
86 }
80 return 0; 87 return 0;
81 } 88 }
82 89
83 prepareRecipes(recipes) { 90 prepareRecipes(recipes) {
84 return recipes 91 return (
85 // Filter out duplicate recipes 92 recipes
86 .filter((recipe, index, self) => { 93 // Filter out duplicate recipes
87 const ids = self.map((rec) => rec.id); 94 .filter((recipe, index, self) => {
88 return ids.indexOf(recipe.id) === index; 95 const ids = self.map(rec => rec.id);
89 96 return ids.indexOf(recipe.id) === index;
90 // Sort alphabetically 97
91 }).sort(this._sortByName); 98 // Sort alphabetically
99 })
100 .sort(this._sortByName)
101 );
92 } 102 }
93 103
94 // Create an array of RecipePreviews from an array of recipe objects 104 // Create an array of RecipePreviews from an array of recipe objects
95 createPreviews(recipes) { 105 createPreviews(recipes) {
96 return recipes.map((recipe) => new RecipePreview(recipe)); 106 return recipes.map(recipe => new RecipePreview(recipe));
97 } 107 }
98 108
99 resetSearch() { 109 resetSearch() {
@@ -101,16 +111,9 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
101 } 111 }
102 112
103 render() { 113 render() {
104 const { 114 const { recipePreviews, recipes, services } = this.props.stores;
105 recipePreviews,
106 recipes,
107 services,
108 } = this.props.stores;
109 115
110 const { 116 const { app: appActions, service: serviceActions } = this.props.actions;
111 app: appActions,
112 service: serviceActions,
113 } = this.props.actions;
114 117
115 const { filter } = { filter: 'all', ...this.props.params }; 118 const { filter } = { filter: 'all', ...this.props.params };
116 let recipeFilter; 119 let recipeFilter;
@@ -125,21 +128,33 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
125 } 128 }
126 recipeFilter = recipeFilter.sort(this._sortByName); 129 recipeFilter = recipeFilter.sort(this._sortByName);
127 130
128 const allRecipes = this.state.needle ? this.prepareRecipes([ 131 const allRecipes = this.state.needle
129 // All search recipes from server 132 ? this.prepareRecipes([
130 ...recipePreviews.searchResults, 133 // All search recipes from server
131 // All search recipes from local recipes 134 ...recipePreviews.searchResults,
132 ...this.createPreviews( 135 // All search recipes from local recipes
133 this.customRecipes 136 ...this.createPreviews(
134 .filter((service) => service.name.toLowerCase().includes(this.state.needle.toLowerCase()) || (service.aliases || []).some(alias => alias.toLowerCase().includes(this.state.needle.toLowerCase()))), 137 this.customRecipes.filter(
135 ), 138 service =>
136 ]).sort(this._sortByName) : recipeFilter; 139 service.name
137 140 .toLowerCase()
138 const customWebsiteRecipe = recipePreviews.all.find((service) => service.id === CUSTOM_WEBSITE_RECIPE_ID); 141 .includes(this.state.needle.toLowerCase()) ||
142 (service.aliases || []).some(alias =>
143 alias.toLowerCase().includes(this.state.needle.toLowerCase()),
144 ),
145 ),
146 ),
147 ]).sort(this._sortByName)
148 : recipeFilter;
149
150 const customWebsiteRecipe = recipePreviews.all.find(
151 service => service.id === CUSTOM_WEBSITE_RECIPE_ID,
152 );
139 153
140 const isLoading = recipePreviews.allRecipePreviewsRequest.isExecuting 154 const isLoading =
141 || recipes.installRecipeRequest.isExecuting 155 recipePreviews.allRecipePreviewsRequest.isExecuting ||
142 || recipePreviews.searchRecipePreviewsRequest.isExecuting; 156 recipes.installRecipeRequest.isExecuting ||
157 recipePreviews.searchRecipePreviewsRequest.isExecuting;
143 158
144 const recipeDirectory = userDataRecipesPath('dev'); 159 const recipeDirectory = userDataRecipesPath('dev');
145 160
@@ -151,14 +166,16 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
151 isLoading={isLoading} 166 isLoading={isLoading}
152 addedServiceCount={services.all.length} 167 addedServiceCount={services.all.length}
153 showAddServiceInterface={serviceActions.showAddServiceInterface} 168 showAddServiceInterface={serviceActions.showAddServiceInterface}
154 searchRecipes={(e) => this.searchRecipes(e)} 169 searchRecipes={e => this.searchRecipes(e)}
155 resetSearch={() => this.resetSearch()} 170 resetSearch={() => this.resetSearch()}
156 searchNeedle={this.state.needle} 171 searchNeedle={this.state.needle}
157 serviceStatus={services.actionStatus} 172 serviceStatus={services.actionStatus}
158 recipeFilter={filter} 173 recipeFilter={filter}
159 recipeDirectory={recipeDirectory} 174 recipeDirectory={recipeDirectory}
160 openRecipeDirectory={() => openPath(recipeDirectory)} 175 openRecipeDirectory={() => openPath(recipeDirectory)}
161 openDevDocs={() => appActions.openExternalUrl({ url: FRANZ_DEV_DOCS })} 176 openDevDocs={() =>
177 appActions.openExternalUrl({ url: FRANZ_DEV_DOCS })
178 }
162 /> 179 />
163 </ErrorBoundary> 180 </ErrorBoundary>
164 ); 181 );
@@ -180,3 +197,5 @@ RecipesScreen.wrappedComponent.propTypes = {
180 }).isRequired, 197 }).isRequired,
181 }).isRequired, 198 }).isRequired,
182}; 199};
200
201export default RecipesScreen;
diff --git a/src/containers/settings/ServicesScreen.js b/src/containers/settings/ServicesScreen.js
index eb2b1bcb5..c9dfc68d0 100644
--- a/src/containers/settings/ServicesScreen.js
+++ b/src/containers/settings/ServicesScreen.js
@@ -10,7 +10,9 @@ import ServiceStore from '../../stores/ServicesStore';
10import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; 10import ServicesDashboard from '../../components/settings/services/ServicesDashboard';
11import ErrorBoundary from '../../components/util/ErrorBoundary'; 11import ErrorBoundary from '../../components/util/ErrorBoundary';
12 12
13export default @inject('stores', 'actions') @observer class ServicesScreen extends Component { 13@inject('stores', 'actions')
14@observer
15class ServicesScreen extends Component {
14 componentWillUnmount() { 16 componentWillUnmount() {
15 this.props.actions.service.resetFilter(); 17 this.props.actions.service.resetFilter();
16 this.props.actions.service.resetStatus(); 18 this.props.actions.service.resetStatus();
@@ -23,11 +25,7 @@ export default @inject('stores', 'actions') @observer class ServicesScreen exten
23 25
24 render() { 26 render() {
25 const { user, services, router } = this.props.stores; 27 const { user, services, router } = this.props.stores;
26 const { 28 const { toggleService, filter, resetFilter } = this.props.actions.service;
27 toggleService,
28 filter,
29 resetFilter,
30 } = this.props.actions.service;
31 const isLoading = services.allServicesRequest.isExecuting; 29 const isLoading = services.allServicesRequest.isExecuting;
32 30
33 let allServices = services.all; 31 let allServices = services.all;
@@ -47,7 +45,10 @@ export default @inject('stores', 'actions') @observer class ServicesScreen exten
47 filterServices={filter} 45 filterServices={filter}
48 resetFilter={resetFilter} 46 resetFilter={resetFilter}
49 goTo={router.push} 47 goTo={router.push}
50 servicesRequestFailed={services.allServicesRequest.wasExecuted && services.allServicesRequest.isError} 48 servicesRequestFailed={
49 services.allServicesRequest.wasExecuted &&
50 services.allServicesRequest.isError
51 }
51 retryServicesRequest={() => services.allServicesRequest.reload()} 52 retryServicesRequest={() => services.allServicesRequest.reload()}
52 searchNeedle={services.filterNeedle} 53 searchNeedle={services.filterNeedle}
53 /> 54 />
@@ -66,3 +67,5 @@ ServicesScreen.wrappedComponent.propTypes = {
66 service: PropTypes.instanceOf(ServiceStore).isRequired, 67 service: PropTypes.instanceOf(ServiceStore).isRequired,
67 }).isRequired, 68 }).isRequired,
68}; 69};
70
71export default ServicesScreen;
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js
index 9bb64b6fe..e03c4c1d2 100644
--- a/src/containers/settings/SettingsWindow.js
+++ b/src/containers/settings/SettingsWindow.js
@@ -11,17 +11,19 @@ import ErrorBoundary from '../../components/util/ErrorBoundary';
11import { workspaceStore } from '../../features/workspaces'; 11import { workspaceStore } from '../../features/workspaces';
12import UIStore from '../../stores/UIStore'; 12import UIStore from '../../stores/UIStore';
13 13
14export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { 14@inject('stores', 'actions')
15@observer
16class SettingsContainer extends Component {
15 portalRoot = document.querySelector('#portalContainer'); 17 portalRoot = document.querySelector('#portalContainer');
16 18
17 el = document.createElement('div'); 19 el = document.createElement('div');
18 20
19 componentDidMount() { 21 componentDidMount() {
20 this.portalRoot.appendChild(this.el); 22 this.portalRoot.append(this.el);
21 } 23 }
22 24
23 componentWillUnmount() { 25 componentWillUnmount() {
24 this.portalRoot.removeChild(this.el); 26 this.el.remove();
25 } 27 }
26 28
27 render() { 29 render() {
@@ -36,16 +38,11 @@ export default @inject('stores', 'actions') @observer class SettingsContainer ex
36 ); 38 );
37 39
38 return ReactDOM.createPortal( 40 return ReactDOM.createPortal(
39 ( 41 <ErrorBoundary>
40 <ErrorBoundary> 42 <Layout navigation={navigation} closeSettings={closeSettings}>
41 <Layout 43 {children}
42 navigation={navigation} 44 </Layout>
43 closeSettings={closeSettings} 45 </ErrorBoundary>,
44 >
45 {children}
46 </Layout>
47 </ErrorBoundary>
48 ),
49 this.el, 46 this.el,
50 ); 47 );
51 } 48 }
@@ -60,3 +57,5 @@ SettingsContainer.wrappedComponent.propTypes = {
60 ui: PropTypes.instanceOf(UIStore).isRequired, 57 ui: PropTypes.instanceOf(UIStore).isRequired,
61 }).isRequired, 58 }).isRequired,
62}; 59};
60
61export default SettingsContainer;
diff --git a/src/containers/settings/SupportScreen.js b/src/containers/settings/SupportScreen.js
index 7d3b22f19..646f672ce 100644
--- a/src/containers/settings/SupportScreen.js
+++ b/src/containers/settings/SupportScreen.js
@@ -6,7 +6,8 @@ import SupportFerdi from '../../components/settings/supportFerdi/SupportFerdiDas
6import ErrorBoundary from '../../components/util/ErrorBoundary'; 6import ErrorBoundary from '../../components/util/ErrorBoundary';
7import AppStore from '../../stores/AppStore'; 7import AppStore from '../../stores/AppStore';
8 8
9export default @inject('actions') class SupportScreen extends Component { 9@inject('actions')
10class SupportScreen extends Component {
10 constructor(props) { 11 constructor(props) {
11 super(props); 12 super(props);
12 13
@@ -20,9 +21,7 @@ export default @inject('actions') class SupportScreen extends Component {
20 render() { 21 render() {
21 return ( 22 return (
22 <ErrorBoundary> 23 <ErrorBoundary>
23 <SupportFerdi 24 <SupportFerdi openLink={this.openLink} />
24 openLink={this.openLink}
25 />
26 </ErrorBoundary> 25 </ErrorBoundary>
27 ); 26 );
28 } 27 }
@@ -33,3 +32,5 @@ SupportScreen.wrappedComponent.propTypes = {
33 app: PropTypes.instanceOf(AppStore).isRequired, 32 app: PropTypes.instanceOf(AppStore).isRequired,
34 }).isRequired, 33 }).isRequired,
35}; 34};
35
36export default SupportScreen;
diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js
index 10c2e36ef..ea447469b 100644
--- a/src/containers/settings/TeamScreen.js
+++ b/src/containers/settings/TeamScreen.js
@@ -10,7 +10,9 @@ import TeamDashboard from '../../components/settings/team/TeamDashboard';
10import ErrorBoundary from '../../components/util/ErrorBoundary'; 10import ErrorBoundary from '../../components/util/ErrorBoundary';
11import { DEV_API_FRANZ_WEBSITE } from '../../config'; 11import { DEV_API_FRANZ_WEBSITE } from '../../config';
12 12
13export default @inject('stores', 'actions') @observer class TeamScreen extends Component { 13@inject('stores', 'actions')
14@observer
15class TeamScreen extends Component {
14 handleWebsiteLink(route) { 16 handleWebsiteLink(route) {
15 const { actions, stores } = this.props; 17 const { actions, stores } = this.props;
16 18
@@ -29,7 +31,10 @@ export default @inject('stores', 'actions') @observer class TeamScreen extends C
29 <ErrorBoundary> 31 <ErrorBoundary>
30 <TeamDashboard 32 <TeamDashboard
31 isLoading={isLoadingUserInfo} 33 isLoading={isLoadingUserInfo}
32 userInfoRequestFailed={user.getUserInfoRequest.wasExecuted && user.getUserInfoRequest.isError} 34 userInfoRequestFailed={
35 user.getUserInfoRequest.wasExecuted &&
36 user.getUserInfoRequest.isError
37 }
33 retryUserInfoRequest={() => this.reloadData()} 38 retryUserInfoRequest={() => this.reloadData()}
34 openTeamManagement={() => this.handleWebsiteLink('/user/team')} 39 openTeamManagement={() => this.handleWebsiteLink('/user/team')}
35 server={server} 40 server={server}
@@ -50,3 +55,5 @@ TeamScreen.wrappedComponent.propTypes = {
50 user: PropTypes.instanceOf(UserStore).isRequired, 55 user: PropTypes.instanceOf(UserStore).isRequired,
51 }).isRequired, 56 }).isRequired,
52}; 57};
58
59export default TeamScreen;
diff --git a/src/dev-app-update.yml b/src/dev-app-update.yml
index 978e30a9b..9a32defa4 100644
--- a/src/dev-app-update.yml
+++ b/src/dev-app-update.yml
@@ -1,3 +1,3 @@
1owner: kytwb 1owner: kytwb
2repo: Ferdi 2repo: ferdi
3provider: github 3provider: github
diff --git a/src/electron-util.ts b/src/electron-util.ts
new file mode 100644
index 000000000..f4b26cb10
--- /dev/null
+++ b/src/electron-util.ts
@@ -0,0 +1,30 @@
1// Enhanced from: https://github.com/dertieran/electron-util/blob/replace-remote/source/api.js
2
3import electron from 'electron';
4import { initialize } from '@electron/remote/main';
5
6export const initializeRemote = () => {
7 if (process.type !== 'browser') {
8 throw new Error('The remote api must be initialized from the main process.');
9 }
10
11 initialize();
12};
13
14export const remote = new Proxy({}, {
15 get: (_target, property) => {
16 // eslint-disable-next-line global-require
17 const remote = require('@electron/remote');
18 return remote[property];
19 },
20});
21
22export const api = new Proxy(electron, {
23 get: (target, property) => {
24 if (target[property]) {
25 return target[property];
26 }
27
28 return remote[property];
29 },
30});
diff --git a/src/electron/Settings.js b/src/electron/Settings.ts
index 3e11bb175..98acfa1d5 100644
--- a/src/electron/Settings.js
+++ b/src/electron/Settings.ts
@@ -1,15 +1,17 @@
1import { observable, toJS } from 'mobx'; 1import { observable, toJS } from 'mobx';
2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; 2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra';
3import { userDataPath } from '../environment'; 3import { userDataPath } from '../environment-remote';
4 4
5const debug = require('debug')('Ferdi:Settings'); 5const debug = require('debug')('Ferdi:Settings');
6 6
7export default class Settings { 7export default class Settings {
8 type = ''; 8 type = '';
9 9
10 defaultState: {};
11
10 @observable store = {}; 12 @observable store = {};
11 13
12 constructor(type, defaultState = {}) { 14 constructor(type: string, defaultState = {}) {
13 this.type = type; 15 this.type = type;
14 this.store = defaultState; 16 this.store = defaultState;
15 this.defaultState = defaultState; 17 this.defaultState = defaultState;
@@ -35,7 +37,7 @@ export default class Settings {
35 return toJS(this.store); 37 return toJS(this.store);
36 } 38 }
37 39
38 get(key) { 40 get(key: string | number) {
39 return this.store[key]; 41 return this.store[key];
40 } 42 }
41 43
@@ -56,6 +58,9 @@ export default class Settings {
56 } 58 }
57 59
58 get settingsFile() { 60 get settingsFile() {
59 return userDataPath('config', `${this.type === 'app' ? 'settings' : this.type}.json`); 61 return userDataPath(
62 'config',
63 `${this.type === 'app' ? 'settings' : this.type}.json`,
64 );
60 } 65 }
61} 66}
diff --git a/src/electron/deepLinking.js b/src/electron/deepLinking.ts
index 70e5cfb6f..70e5cfb6f 100644
--- a/src/electron/deepLinking.js
+++ b/src/electron/deepLinking.ts
diff --git a/src/electron/exception.js b/src/electron/exception.ts
index 0065e2604..0065e2604 100644
--- a/src/electron/exception.js
+++ b/src/electron/exception.ts
diff --git a/src/electron/ipc-api/appIndicator.js b/src/electron/ipc-api/appIndicator.ts
index c6c261d0f..a51ed8161 100644
--- a/src/electron/ipc-api/appIndicator.js
+++ b/src/electron/ipc-api/appIndicator.ts
@@ -6,15 +6,22 @@ import { isMac, isWindows, isLinux } from '../../environment';
6const INDICATOR_TASKBAR = 'taskbar'; 6const INDICATOR_TASKBAR = 'taskbar';
7const FILE_EXTENSION = isWindows ? 'ico' : 'png'; 7const FILE_EXTENSION = isWindows ? 'ico' : 'png';
8 8
9let isTrayIconEnabled; 9let isTrayIconEnabled: boolean;
10 10
11function getAsset(type, asset) { 11function getAsset(type: 'tray' | 'taskbar', asset: string) {
12 return join( 12 return join(
13 __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, 13 __dirname,
14 '..',
15 '..',
16 'assets',
17 'images',
18 type,
19 process.platform,
20 `${asset}.${FILE_EXTENSION}`,
14 ); 21 );
15} 22}
16 23
17export default (params) => { 24export default params => {
18 autorun(() => { 25 autorun(() => {
19 isTrayIconEnabled = params.settings.app.get('enableSystemTray'); 26 isTrayIconEnabled = params.settings.app.get('enableSystemTray');
20 27
@@ -25,36 +32,37 @@ export default (params) => {
25 } 32 }
26 }); 33 });
27 34
28 ipcMain.on('updateAppIndicator', (event, args) => { 35 ipcMain.on('updateAppIndicator', (_event, args) => {
29 // Flash TaskBar for windows, bounce Dock on Mac 36 // Flash TaskBar for windows, bounce Dock on Mac
30 if (!app.mainWindow.isFocused()) { 37 if (!(app as any).mainWindow.isFocused() && params.settings.app.get('notifyTaskBarOnMessage')) {
31 if (params.settings.app.get('notifyTaskBarOnMessage')) {
32 if (isWindows) { 38 if (isWindows) {
33 app.mainWindow.flashFrame(true); 39 (app as any).mainWindow.flashFrame(true);
34 app.mainWindow.once('focus', () => app.mainWindow.flashFrame(false)); 40 (app as any).mainWindow.once('focus', () =>
41 (app as any).mainWindow.flashFrame(false),
42 );
35 } else if (isMac) { 43 } else if (isMac) {
36 app.dock.bounce('informational'); 44 app.dock.bounce('informational');
37 } 45 }
38 } 46 }
39 }
40 47
41 // Update badge 48 // Update badge
42 if (isMac 49 if (isMac && typeof args.indicator === 'string') {
43 && typeof (args.indicator) === 'string') {
44 app.dock.setBadge(args.indicator); 50 app.dock.setBadge(args.indicator);
45 } 51 }
46 52
47 if ((isMac || isLinux) 53 if ((isMac || isLinux) && typeof args.indicator === 'number') {
48 && typeof (args.indicator) === 'number'
49 ) {
50 app.badgeCount = args.indicator; 54 app.badgeCount = args.indicator;
51 } 55 }
52 56
53 if (isWindows) { 57 if (isWindows) {
54 if (typeof args.indicator === 'number' 58 if (typeof args.indicator === 'number' && args.indicator !== 0) {
55 && args.indicator !== 0) {
56 params.mainWindow.setOverlayIcon( 59 params.mainWindow.setOverlayIcon(
57 getAsset('taskbar', `${INDICATOR_TASKBAR}-${(args.indicator >= 10 ? 10 : args.indicator)}`), 60 getAsset(
61 'taskbar',
62 `${INDICATOR_TASKBAR}-${
63 args.indicator >= 10 ? 10 : args.indicator
64 }`,
65 ),
58 '', 66 '',
59 ); 67 );
60 } else if (typeof args.indicator === 'string') { 68 } else if (typeof args.indicator === 'string') {
diff --git a/src/electron/ipc-api/autoUpdate.js b/src/electron/ipc-api/autoUpdate.ts
index 255595b9e..e6b805edc 100644
--- a/src/electron/ipc-api/autoUpdate.js
+++ b/src/electron/ipc-api/autoUpdate.ts
@@ -1,11 +1,10 @@
1import { app, ipcMain } from 'electron'; 1import { app, ipcMain, BrowserWindow } from 'electron';
2import { autoUpdater } from 'electron-updater'; 2import { autoUpdater } from 'electron-updater';
3import { GITHUB_NIGHTLIES_REPO_NAME, GITHUB_ORG_NAME } from '../../config';
4import { isMac, isWindows } from '../../environment'; 3import { isMac, isWindows } from '../../environment';
5 4
6const debug = require('debug')('Ferdi:ipcApi:autoUpdate'); 5const debug = require('debug')('Ferdi:ipcApi:autoUpdate');
7 6
8export default (params) => { 7export default (params: { mainWindow: BrowserWindow; settings: any }) => {
9 const enableUpdate = Boolean(params.settings.app.get('automaticUpdates')); 8 const enableUpdate = Boolean(params.settings.app.get('automaticUpdates'));
10 9
11 if (!enableUpdate) { 10 if (!enableUpdate) {
@@ -16,17 +15,16 @@ export default (params) => {
16 if (enableUpdate) { 15 if (enableUpdate) {
17 try { 16 try {
18 autoUpdater.autoInstallOnAppQuit = false; 17 autoUpdater.autoInstallOnAppQuit = false;
19 autoUpdater.allowPrerelease = Boolean(params.settings.app.get('beta')); 18 autoUpdater.allowPrerelease = Boolean(
19 params.settings.app.get('beta'),
20 );
20 autoUpdater.channel = autoUpdater.allowPrerelease ? 'beta' : 'latest'; 21 autoUpdater.channel = autoUpdater.allowPrerelease ? 'beta' : 'latest';
21 22
22 if (params.settings.app.get('nightly')) { 23 if (params.settings.app.get('nightly')) {
23 autoUpdater.allowPrerelease = Boolean(params.settings.app.get('nightly')); 24 autoUpdater.allowPrerelease = Boolean(
25 params.settings.app.get('nightly'),
26 );
24 autoUpdater.channel = 'alpha'; 27 autoUpdater.channel = 'alpha';
25 autoUpdater.setFeedURL({
26 provider: 'github',
27 owner: GITHUB_ORG_NAME,
28 repo: GITHUB_NIGHTLIES_REPO_NAME,
29 });
30 } 28 }
31 29
32 if (args.action === 'check') { 30 if (args.action === 'check') {
@@ -40,8 +38,8 @@ export default (params) => {
40 app.quit(); 38 app.quit();
41 }, 20); 39 }, 20);
42 } 40 }
43 } catch (e) { 41 } catch (error) {
44 console.error(e); 42 console.error(error);
45 event.sender.send('autoUpdate', { error: true }); 43 event.sender.send('autoUpdate', { error: true });
46 } 44 }
47 } 45 }
@@ -52,7 +50,7 @@ export default (params) => {
52 params.mainWindow.webContents.send('autoUpdate', { available: false }); 50 params.mainWindow.webContents.send('autoUpdate', { available: false });
53 }); 51 });
54 52
55 autoUpdater.on('update-available', (event) => { 53 autoUpdater.on('update-available', event => {
56 debug('update-available'); 54 debug('update-available');
57 55
58 if (enableUpdate) { 56 if (enableUpdate) {
@@ -63,7 +61,7 @@ export default (params) => {
63 } 61 }
64 }); 62 });
65 63
66 autoUpdater.on('download-progress', (progressObj) => { 64 autoUpdater.on('download-progress', progressObj => {
67 let logMessage = `Download speed: ${progressObj.bytesPerSecond}`; 65 let logMessage = `Download speed: ${progressObj.bytesPerSecond}`;
68 logMessage = `${logMessage} - Downloaded ${progressObj.percent}%`; 66 logMessage = `${logMessage} - Downloaded ${progressObj.percent}%`;
69 logMessage = `${logMessage} (${progressObj.transferred}/${progressObj.total})`; 67 logMessage = `${logMessage} (${progressObj.transferred}/${progressObj.total})`;
diff --git a/src/electron/ipc-api/cld.js b/src/electron/ipc-api/cld.ts
index 73e320ad9..4221f9b22 100644
--- a/src/electron/ipc-api/cld.js
+++ b/src/electron/ipc-api/cld.ts
@@ -4,17 +4,20 @@ import cld from 'cld';
4const debug = require('debug')('Ferdi:ipcApi:cld'); 4const debug = require('debug')('Ferdi:ipcApi:cld');
5 5
6export default async () => { 6export default async () => {
7 ipcMain.handle('detect-language', async (event, { sample }) => { 7 ipcMain.handle('detect-language', async (_event, { sample }) => {
8 try { 8 try {
9 const result = await cld.detect(sample); 9 const result = await cld.detect(sample);
10 debug('Checking language', 'probability', result.languages); 10 debug('Checking language', 'probability', result.languages);
11 if (result.reliable) { 11 if (result.reliable) {
12 debug('Language detected reliably, setting spellchecker language to', result.languages[0].code); 12 debug(
13 'Language detected reliably, setting spellchecker language to',
14 result.languages[0].code,
15 );
13 16
14 return result.languages[0].code; 17 return result.languages[0].code;
15 } 18 }
16 } catch (e) { 19 } catch (error) {
17 console.error(e); 20 console.error(error);
18 } 21 }
19 }); 22 });
20}; 23};
diff --git a/src/electron/ipc-api/dnd.js b/src/electron/ipc-api/dnd.ts
index 6fb8999a3..afaef9a66 100644
--- a/src/electron/ipc-api/dnd.js
+++ b/src/electron/ipc-api/dnd.ts
@@ -15,8 +15,8 @@ export default async () => {
15 const isDND = getDoNotDisturb(); 15 const isDND = getDoNotDisturb();
16 debug('Fetching DND state, set to', isDND); 16 debug('Fetching DND state, set to', isDND);
17 return isDND; 17 return isDND;
18 } catch (e) { 18 } catch (error) {
19 console.error(e); 19 console.error(error);
20 return false; 20 return false;
21 } 21 }
22 }); 22 });
diff --git a/src/electron/ipc-api/download.js b/src/electron/ipc-api/download.js
deleted file mode 100644
index ba261ba1e..000000000
--- a/src/electron/ipc-api/download.js
+++ /dev/null
@@ -1,51 +0,0 @@
1import { ipcMain, dialog, BrowserWindow } from 'electron';
2import { download } from 'electron-dl';
3import mime from 'mime-types';
4import { writeFileSync } from 'fs-extra';
5
6const debug = require('debug')('Ferdi:ipcApi:download');
7
8function decodeBase64Image(dataString) {
9 const matches = dataString.match(/^data:([A-Za-z-+/]+);base64,(.+)$/);
10
11 if (matches.length !== 3) {
12 return new Error('Invalid input string');
13 }
14
15 return Buffer.from(matches[2], 'base64');
16}
17
18export default (params) => {
19 ipcMain.on('download-file', async (event, { url, content, fileOptions = {} }) => {
20 const win = BrowserWindow.getFocusedWindow();
21
22 try {
23 if (!content) {
24 const dl = await download(win, url, {
25 saveAs: true,
26 });
27 debug('File saved to', dl.savePath);
28 } else {
29 const extension = mime.extension(fileOptions.mime);
30 const filename = `${fileOptions.name}.${extension}`;
31
32 try {
33 const saveDialog = await dialog.showSaveDialog(params.mainWindow, {
34 defaultPath: filename,
35 });
36
37 if (saveDialog.canceled) return;
38
39 const binaryImage = decodeBase64Image(content);
40 writeFileSync(saveDialog.filePath, binaryImage, 'binary');
41
42 debug('File blob saved to', saveDialog.filePath);
43 } catch (err) {
44 console.log(err);
45 }
46 }
47 } catch (e) {
48 console.error(e);
49 }
50 });
51};
diff --git a/src/electron/ipc-api/download.ts b/src/electron/ipc-api/download.ts
new file mode 100644
index 000000000..af15b157e
--- /dev/null
+++ b/src/electron/ipc-api/download.ts
@@ -0,0 +1,59 @@
1import { ipcMain, dialog, BrowserWindow } from 'electron';
2import { download } from 'electron-dl';
3import mime from 'mime-types';
4import { writeFileSync } from 'fs-extra';
5import { PathLike } from 'fs';
6
7const debug = require('debug')('Ferdi:ipcApi:download');
8
9function decodeBase64Image(dataString: string) {
10 const matches = dataString.match(/^data:([+/A-Za-z-]+);base64,(.+)$/);
11
12 if (matches?.length !== 3) {
13 return new Error('Invalid input string');
14 }
15
16 return Buffer.from(matches[2], 'base64');
17}
18
19export default (params: { mainWindow: BrowserWindow }) => {
20 ipcMain.on(
21 'download-file',
22 async (_event, { url, content, fileOptions = {} }) => {
23 const win = BrowserWindow.getFocusedWindow();
24
25 try {
26 if (!content) {
27 const dl = await download(win!, url, {
28 saveAs: true,
29 });
30 debug('File saved to', dl.savePath);
31 } else {
32 const extension = mime.extension(fileOptions.mime);
33 const filename = `${fileOptions.name}.${extension}`;
34
35 try {
36 const saveDialog = await dialog.showSaveDialog(params.mainWindow, {
37 defaultPath: filename,
38 });
39
40 if (saveDialog.canceled) return;
41
42 const binaryImage = decodeBase64Image(content);
43 writeFileSync(
44 saveDialog.filePath as PathLike,
45 binaryImage as unknown as string,
46 'binary',
47 );
48
49 debug('File blob saved to', saveDialog.filePath);
50 } catch (error) {
51 console.log(error);
52 }
53 }
54 } catch (error) {
55 console.error(error);
56 }
57 },
58 );
59};
diff --git a/src/electron/ipc-api/focusState.js b/src/electron/ipc-api/focusState.ts
index 0b4a0d8f3..01aa1a971 100644
--- a/src/electron/ipc-api/focusState.js
+++ b/src/electron/ipc-api/focusState.ts
@@ -1,4 +1,6 @@
1export default (params) => { 1import { BrowserWindow } from 'electron';
2
3export default (params: { mainWindow: BrowserWindow }) => {
2 params.mainWindow.on('focus', () => { 4 params.mainWindow.on('focus', () => {
3 params.mainWindow.webContents.send('isWindowFocused', true); 5 params.mainWindow.webContents.send('isWindowFocused', true);
4 }); 6 });
diff --git a/src/electron/ipc-api/index.js b/src/electron/ipc-api/index.ts
index 5da1edc39..f03f61517 100644
--- a/src/electron/ipc-api/index.js
+++ b/src/electron/ipc-api/index.ts
@@ -1,5 +1,7 @@
1import { BrowserWindow, Tray } from 'electron';
1import autoUpdate from './autoUpdate'; 2import autoUpdate from './autoUpdate';
2import settings from './settings'; 3import settings from './settings';
4import sessionStorage from './sessionStorage';
3import appIndicator from './appIndicator'; 5import appIndicator from './appIndicator';
4import download from './download'; 6import download from './download';
5import localServer from './localServer'; 7import localServer from './localServer';
@@ -7,13 +9,18 @@ import cld from './cld';
7import dnd from './dnd'; 9import dnd from './dnd';
8import focusState from './focusState'; 10import focusState from './focusState';
9 11
10export default (params) => { 12export default (params: {
13 mainWindow: BrowserWindow;
14 settings: any;
15 tray: Tray;
16}) => {
11 settings(params); 17 settings(params);
18 sessionStorage();
12 autoUpdate(params); 19 autoUpdate(params);
13 appIndicator(params); 20 appIndicator(params);
14 download(params); 21 download(params);
15 localServer(params); 22 localServer(params);
16 cld(params); 23 cld();
17 dnd(); 24 dnd();
18 focusState(params); 25 focusState(params);
19}; 26};
diff --git a/src/electron/ipc-api/localServer.js b/src/electron/ipc-api/localServer.ts
index 591e70504..7ee642101 100644
--- a/src/electron/ipc-api/localServer.js
+++ b/src/electron/ipc-api/localServer.ts
@@ -1,12 +1,12 @@
1import { ipcMain } from 'electron'; 1import { ipcMain, BrowserWindow } from 'electron';
2import net from 'net'; 2import net from 'net';
3import { LOCAL_HOSTNAME, LOCAL_PORT } from '../../config'; 3import { LOCAL_HOSTNAME, LOCAL_PORT } from '../../config';
4import { userDataPath } from '../../environment'; 4import { userDataPath } from '../../environment-remote';
5import startServer from '../../internal-server/start'; 5import { server } from '../../internal-server/start';
6 6
7const portInUse = function (port) { 7const portInUse = (port: number): Promise<boolean> =>
8 return new Promise((resolve) => { 8 new Promise(resolve => {
9 const server = net.createServer((socket) => { 9 const server = net.createServer(socket => {
10 socket.write('Echo server\r\n'); 10 socket.write('Echo server\r\n');
11 socket.pipe(socket); 11 socket.pipe(socket);
12 }); 12 });
@@ -20,11 +20,10 @@ const portInUse = function (port) {
20 resolve(false); 20 resolve(false);
21 }); 21 });
22 }); 22 });
23};
24 23
25let localServerStarted = false; 24let localServerStarted = false;
26 25
27export default (params) => { 26export default (params: { mainWindow: BrowserWindow }) => {
28 ipcMain.on('startLocalServer', () => { 27 ipcMain.on('startLocalServer', () => {
29 if (!localServerStarted) { 28 if (!localServerStarted) {
30 // Find next unused port for server 29 // Find next unused port for server
@@ -36,7 +35,7 @@ export default (params) => {
36 } 35 }
37 console.log('Starting local server on port', port); 36 console.log('Starting local server on port', port);
38 37
39 startServer(userDataPath(), port); 38 server(userDataPath(), port);
40 39
41 params.mainWindow.webContents.send('localServerPort', { 40 params.mainWindow.webContents.send('localServerPort', {
42 port, 41 port,
diff --git a/src/electron/ipc-api/sessionStorage.ts b/src/electron/ipc-api/sessionStorage.ts
new file mode 100644
index 000000000..3eda568a1
--- /dev/null
+++ b/src/electron/ipc-api/sessionStorage.ts
@@ -0,0 +1,35 @@
1import { ipcMain, Session, session } from 'electron';
2
3import { TODOS_PARTITION_ID } from '../../config';
4
5const debug = require('debug')('Ferdi:ipcApi:sessionStorage');
6
7function deduceSession(serviceId: string | undefined | null): Session {
8 if (serviceId) {
9 return session.fromPartition(serviceId === TODOS_PARTITION_ID ? TODOS_PARTITION_ID : `persist:service-${serviceId}`);
10 }
11 return session.defaultSession;
12}
13
14export default async () => {
15 ipcMain.on('clear-storage-data', (_event, { serviceId, targetsToClear }) => {
16 try {
17 const serviceSession = deduceSession(serviceId);
18 serviceSession.flushStorageData();
19 if (targetsToClear) {
20 debug('Clearing targets:', targetsToClear);
21 serviceSession.clearStorageData(targetsToClear);
22 } else {
23 debug('Clearing all targets');
24 serviceSession.clearStorageData();
25 }
26 } catch (error) {
27 debug(error);
28 }
29 });
30
31 ipcMain.handle('clear-cache', (_event, { serviceId }) => {
32 const serviceSession = deduceSession(serviceId);
33 return serviceSession.clearCache();
34 });
35};
diff --git a/src/electron/ipc-api/settings.js b/src/electron/ipc-api/settings.js
deleted file mode 100644
index 15182739c..000000000
--- a/src/electron/ipc-api/settings.js
+++ /dev/null
@@ -1,14 +0,0 @@
1import { ipcMain } from 'electron';
2
3export default (params) => {
4 ipcMain.on('getAppSettings', (event, type) => {
5 params.mainWindow.webContents.send('appSettings', {
6 type,
7 data: params.settings[type].allSerialized,
8 });
9 });
10
11 ipcMain.on('updateAppSettings', (event, args) => {
12 params.settings[args.type].set(args.data);
13 });
14};
diff --git a/src/electron/ipc-api/settings.ts b/src/electron/ipc-api/settings.ts
new file mode 100644
index 000000000..72de6866d
--- /dev/null
+++ b/src/electron/ipc-api/settings.ts
@@ -0,0 +1,14 @@
1import { ipcMain, BrowserWindow, Settings } from 'electron';
2
3export default (params: { mainWindow: BrowserWindow; settings: Settings }) => {
4 ipcMain.on('getAppSettings', (_event, type) => {
5 params.mainWindow.webContents.send('appSettings', {
6 type,
7 data: params.settings[type].allSerialized,
8 });
9 });
10
11 ipcMain.on('updateAppSettings', (_event, args) => {
12 params.settings[args.type].set(args.data);
13 });
14};
diff --git a/src/electron/macOSPermissions.js b/src/electron/macOSPermissions.ts
index 887af2903..bcd5b5931 100644
--- a/src/electron/macOSPermissions.js
+++ b/src/electron/macOSPermissions.ts
@@ -1,18 +1,21 @@
1import { systemPreferences, dialog } from 'electron'; 1import { systemPreferences, BrowserWindow, dialog } from 'electron';
2import { pathExistsSync, mkdirSync, writeFileSync } from 'fs-extra'; 2import { pathExistsSync, mkdirSync, writeFileSync } from 'fs-extra';
3import macosVersion from 'macos-version'; 3import macosVersion from 'macos-version';
4import { dirname } from 'path'; 4import { dirname } from 'path';
5import { askForScreenCaptureAccess } from 'node-mac-permissions'; 5import { askForScreenCaptureAccess } from 'node-mac-permissions';
6import { userDataPath } from '../environment'; 6import { userDataPath } from '../environment-remote';
7 7
8const debug = require('debug')('Ferdi:macOSPermissions'); 8const debug = require('debug')('Ferdi:macOSPermissions');
9 9
10const isExplicitScreenCapturePermissionReqd = macosVersion.isGreaterThanOrEqualTo('10.15'); 10const isExplicitScreenCapturePermissionReqd =
11debug(`Should check explicitly for screen-capture permissions: ${isExplicitScreenCapturePermissionReqd}`); 11 macosVersion.isGreaterThanOrEqualTo('10.15');
12debug(
13 `Should check explicitly for screen-capture permissions: ${isExplicitScreenCapturePermissionReqd}`,
14);
12 15
13const filePath = userDataPath('.has-app-requested-screen-capture-permissions'); 16const filePath = userDataPath('.has-app-requested-screen-capture-permissions');
14 17
15function hasPromptedForScreenCapturePermission() { 18function hasPromptedForScreenCapturePermission(): string | boolean {
16 if (!isExplicitScreenCapturePermissionReqd) { 19 if (!isExplicitScreenCapturePermissionReqd) {
17 return false; 20 return false;
18 } 21 }
@@ -21,7 +24,7 @@ function hasPromptedForScreenCapturePermission() {
21 return filePath && pathExistsSync(filePath); 24 return filePath && pathExistsSync(filePath);
22} 25}
23 26
24function hasScreenCapturePermissionAlreadyBeenGranted() { 27function hasScreenCapturePermissionAlreadyBeenGranted(): boolean {
25 if (!isExplicitScreenCapturePermissionReqd) { 28 if (!isExplicitScreenCapturePermissionReqd) {
26 return true; 29 return true;
27 } 30 }
@@ -35,7 +38,7 @@ function createStatusFile() {
35 try { 38 try {
36 writeFileSync(filePath, ''); 39 writeFileSync(filePath, '');
37 } catch (error) { 40 } catch (error) {
38 if (error.code === 'ENOENT') { 41 if ((error as any).code === 'ENOENT') {
39 mkdirSync(dirname(filePath)); 42 mkdirSync(dirname(filePath));
40 writeFileSync(filePath, ''); 43 writeFileSync(filePath, '');
41 } 44 }
@@ -44,7 +47,7 @@ function createStatusFile() {
44 } 47 }
45} 48}
46 49
47export const askFormacOSPermissions = async mainWindow => { 50export const askFormacOSPermissions = async (mainWindow: BrowserWindow) => {
48 debug('Checking camera & microphone permissions'); 51 debug('Checking camera & microphone permissions');
49 systemPreferences.askForMediaAccess('camera'); 52 systemPreferences.askForMediaAccess('camera');
50 systemPreferences.askForMediaAccess('microphone'); 53 systemPreferences.askForMediaAccess('microphone');
diff --git a/src/electron/webview-ime-focus.js b/src/electron/webview-ime-focus.js
deleted file mode 100644
index e187ee0b4..000000000
--- a/src/electron/webview-ime-focus.js
+++ /dev/null
@@ -1,41 +0,0 @@
1import { webContents } from '@electron/remote';
2import { releaseDocumentFocus } from './webview-ime-focus-helpers';
3
4function giveWebviewDocumentFocus(element) {
5 releaseDocumentFocus();
6
7 window.requestAnimationFrame(() => {
8 element.send('claim-document-focus');
9 });
10}
11
12function elementIsUnfocusedWebview(element) {
13 return element.tagName === 'WEBVIEW' && !webContents.fromId(element.getWebContentsId()).isFocused();
14}
15
16function webviewDidAutofocus(element) {
17 function didKeyDown() {
18 element.removeEventListener('keydown', didKeyDown, true);
19 giveWebviewDocumentFocus(element);
20 }
21
22 element.addEventListener('keydown', didKeyDown, true);
23}
24
25function handleAutofocus(element) {
26 element.addEventListener('ipc-message', (event) => {
27 if (event.channel === 'autofocus') {
28 element.focus();
29 webviewDidAutofocus(element);
30 }
31 });
32}
33
34function didMouseDown(event) {
35 if (elementIsUnfocusedWebview(event.target)) {
36 giveWebviewDocumentFocus(event.target);
37 }
38}
39
40document.addEventListener('mousedown', didMouseDown, true);
41document.querySelectorAll('webview').forEach(handleAutofocus);
diff --git a/src/electron/windowUtils.js b/src/electron/windowUtils.js
deleted file mode 100644
index 23b946ac4..000000000
--- a/src/electron/windowUtils.js
+++ /dev/null
@@ -1,11 +0,0 @@
1/* eslint import/prefer-default-export: 0 */
2
3import { screen } from 'electron';
4
5export function isPositionValid(position) {
6 const displays = screen.getAllDisplays();
7 const { x, y } = position;
8 return displays.some(({
9 workArea,
10 }) => x >= workArea.x && x <= workArea.x + workArea.width && y >= workArea.y && y <= workArea.y + workArea.height);
11}
diff --git a/src/electron/windowUtils.ts b/src/electron/windowUtils.ts
new file mode 100644
index 000000000..1db1ff246
--- /dev/null
+++ b/src/electron/windowUtils.ts
@@ -0,0 +1,13 @@
1import { screen } from 'electron';
2
3export function isPositionValid(position: { x: number; y: number }) {
4 const displays = screen.getAllDisplays();
5 const { x, y } = position;
6 return displays.some(
7 ({ workArea }) =>
8 x >= workArea.x &&
9 x <= workArea.x + workArea.width &&
10 y >= workArea.y &&
11 y <= workArea.y + workArea.height,
12 );
13}
diff --git a/src/enforce-macos-app-location.ts b/src/enforce-macos-app-location.ts
new file mode 100644
index 000000000..0f858013d
--- /dev/null
+++ b/src/enforce-macos-app-location.ts
@@ -0,0 +1,46 @@
1// Enhanced from: https://github.com/dertieran/electron-util/blob/replace-remote/source/enforce-macos-app-location.js
2
3import { isMac } from './environment';
4import { isDevMode } from './environment-remote';
5import { api } from './electron-util';
6
7export function enforceMacOSAppLocation() {
8 if (isDevMode || !isMac || api.app.isInApplicationsFolder()) {
9 return;
10 }
11
12 const clickedButtonIndex = api.dialog.showMessageBoxSync({
13 type: 'error',
14 message: 'Move to Applications folder?',
15 detail: 'Ferdi must live in the Applications folder to be able to run correctly.',
16 buttons: [
17 'Move to Applications folder',
18 'Quit Ferdi',
19 ],
20 defaultId: 0,
21 cancelId: 1,
22 });
23
24 if (clickedButtonIndex === 1) {
25 api.app.quit();
26 return;
27 }
28
29 api.app.moveToApplicationsFolder({
30 conflictHandler: conflict => {
31 if (conflict === 'existsAndRunning') { // Can't replace the active version of the app
32 api.dialog.showMessageBoxSync({
33 type: 'error',
34 message: 'Another version of Ferdi is currently running. Quit it, then launch this version of the app again.',
35 buttons: [
36 'OK',
37 ],
38 });
39
40 api.app.quit();
41 }
42
43 return true;
44 },
45 });
46}
diff --git a/src/environment-remote.ts b/src/environment-remote.ts
new file mode 100644
index 000000000..192510f37
--- /dev/null
+++ b/src/environment-remote.ts
@@ -0,0 +1,93 @@
1import { join } from 'path';
2import osName from 'os-name';
3import { api as electronApi } from './electron-util';
4import {
5 LIVE_FERDI_API,
6 DEV_FRANZ_API,
7 LOCAL_API,
8 LOCAL_API_WEBSITE,
9 DEV_API_FRANZ_WEBSITE,
10 LIVE_API_FERDI_WEBSITE,
11 LIVE_WS_API,
12 LOCAL_WS_API,
13 DEV_WS_API,
14 LOCAL_TODOS_FRONTEND_URL,
15 PRODUCTION_TODOS_FRONTEND_URL,
16} from './config';
17import { chromeVersion, electronVersion, isWindows, nodeVersion, osArch } from './environment';
18
19// @ts-expect-error Cannot find module './buildInfo.json' or its corresponding type declarations.
20import * as buildInfo from './buildInfo.json';
21
22export const { app } = electronApi;
23export const ferdiVersion = app.getVersion();
24export const ferdiLocale = app.getLocale();
25
26// Set app directory before loading user modules
27if (process.env.FERDI_APPDATA_DIR != null) {
28 app.setPath('appData', process.env.FERDI_APPDATA_DIR);
29 app.setPath('userData', app.getPath('appData'));
30} else if (process.env.PORTABLE_EXECUTABLE_DIR != null) {
31 app.setPath('appData', join(process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`));
32 app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`));
33} else if (isWindows && process.env.APPDATA != null) {
34 app.setPath('appData', process.env.APPDATA);
35 app.setPath('userData', join(app.getPath('appData'), app.name));
36}
37
38export const isDevMode = process.env.ELECTRON_IS_DEV !== undefined ? Number.parseInt(process.env.ELECTRON_IS_DEV, 10) === 1 : !app.isPackaged;
39if (isDevMode) {
40 app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`));
41}
42
43export function userDataPath(...segments: string[]) {
44 return join(app.getPath('userData'), ...[segments].flat());
45}
46
47export function userDataRecipesPath(...segments: string[]) {
48 return userDataPath('recipes', ...[segments].flat());
49}
50
51const useLocalAPI = process.env.USE_LOCAL_API;
52export const useLiveAPI = process.env.USE_LIVE_API;
53
54let api: string;
55let wsApi: string;
56let web: string;
57let todos: string;
58if (!isDevMode || (isDevMode && useLiveAPI)) {
59 api = LIVE_FERDI_API;
60 wsApi = LIVE_WS_API;
61 web = LIVE_API_FERDI_WEBSITE;
62 todos = PRODUCTION_TODOS_FRONTEND_URL;
63} else if (isDevMode && useLocalAPI) {
64 api = LOCAL_API;
65 wsApi = LOCAL_WS_API;
66 web = LOCAL_API_WEBSITE;
67 todos = LOCAL_TODOS_FRONTEND_URL;
68} else {
69 api = DEV_FRANZ_API;
70 wsApi = DEV_WS_API;
71 web = DEV_API_FRANZ_WEBSITE;
72 todos = PRODUCTION_TODOS_FRONTEND_URL;
73}
74
75export const API = api;
76export const API_VERSION = 'v1';
77export const WS_API = wsApi;
78export const WEBSITE = web;
79export const TODOS_FRONTEND = todos;
80
81export function aboutAppDetails() {
82 return [
83 `Version: ${ferdiVersion}`,
84 `Electron: ${electronVersion}`,
85 `Chrome: ${chromeVersion}`,
86 `Node.js: ${nodeVersion}`,
87 `Platform: ${osName()}`,
88 `Arch: ${osArch}`,
89 `Build date: ${new Date(Number(buildInfo.timestamp))}`,
90 `Git SHA: ${buildInfo.gitHashShort}`,
91 `Git branch: ${buildInfo.gitBranch}`,
92 ].join('\n');
93}
diff --git a/src/environment.js b/src/environment.js
deleted file mode 100644
index 9d7ffaf78..000000000
--- a/src/environment.js
+++ /dev/null
@@ -1,173 +0,0 @@
1import os from 'os';
2import { join } from 'path';
3
4import { is, api as electronApi } from 'electron-util';
5
6import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme';
7
8import {
9 LIVE_FERDI_API,
10 DEV_FRANZ_API,
11 LOCAL_API,
12 LOCAL_API_WEBSITE,
13 DEV_API_FRANZ_WEBSITE,
14 LIVE_API_FERDI_WEBSITE,
15 LIVE_WS_API,
16 LOCAL_WS_API,
17 DEV_WS_API,
18 LOCAL_TODOS_FRONTEND_URL,
19 PRODUCTION_TODOS_FRONTEND_URL,
20 DEFAULT_TODO_SERVICE,
21 SEARCH_ENGINE_DDG,
22 iconSizeBias,
23} from './config';
24
25import { asarPath } from './helpers/asar-helpers';
26
27export const { app } = electronApi;
28export const ferdiVersion = app.getVersion();
29export const electronVersion = process.versions.electron;
30export const chromeVersion = process.versions.chrome;
31export const nodeVersion = process.versions.node;
32export const ferdiLocale = app.getLocale();
33
34// Set app directory before loading user modules
35if (process.env.FERDI_APPDATA_DIR != null) {
36 app.setPath('appData', process.env.FERDI_APPDATA_DIR);
37 app.setPath('userData', join(app.getPath('appData')));
38} else if (process.env.PORTABLE_EXECUTABLE_DIR != null) {
39 app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`);
40 app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`));
41} else if (is.windows) {
42 app.setPath('appData', process.env.APPDATA);
43 app.setPath('userData', join(app.getPath('appData'), app.name));
44}
45
46export const isDevMode = is.development;
47if (isDevMode) {
48 app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`));
49}
50
51export function userDataPath(...segments) {
52 return join(app.getPath('userData'), ...([segments].flat()));
53}
54
55export function userDataRecipesPath(...segments) {
56 return userDataPath('recipes', ...([segments].flat()));
57}
58
59// Replacing app.asar is not beautiful but unfortunately necessary
60export function asarRecipesPath(...segments) {
61 return join(asarPath(join(__dirname, 'recipes')), ...([segments].flat()));
62}
63
64export const useLiveAPI = process.env.USE_LIVE_API;
65const useLocalAPI = process.env.USE_LOCAL_API;
66
67export const isMac = is.macos;
68export const isWindows = is.windows;
69export const isLinux = is.linux;
70export const osPlatform = os.platform();
71export const osArch = os.arch();
72export const osRelease = os.release();
73export const is64Bit = osArch.match(/64/);
74
75// for accelerator, show the shortform that electron/OS understands
76// for tooltip, show symbol
77const ctrlKey = isMac ? '⌘' : 'Ctrl';
78const cmdKey = isMac ? 'Cmd' : 'Ctrl';
79
80export const altKey = (isAccelerator = true) => (!isAccelerator && isMac ? '⌥' : 'Alt');
81export const shiftKey = (isAccelerator = true) => (!isAccelerator && isMac ? '⇧' : 'Shift');
82
83// Platform specific shortcut keys
84export const cmdOrCtrlShortcutKey = (isAccelerator = true) => (isAccelerator ? cmdKey : ctrlKey);
85export const lockFerdiShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+L`;
86export const todosToggleShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+T`;
87export const workspaceToggleShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+D`;
88export const muteFerdiShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+M`;
89export const addNewServiceShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+N`;
90export const settingsShortcutKey = (isAccelerator = true) => `${cmdOrCtrlShortcutKey(isAccelerator)}+${isMac ? ',' : 'P'}`;
91
92let api;
93let wsApi;
94let web;
95let todos;
96if (!isDevMode || (isDevMode && useLiveAPI)) {
97 api = LIVE_FERDI_API;
98 wsApi = LIVE_WS_API;
99 web = LIVE_API_FERDI_WEBSITE;
100 todos = PRODUCTION_TODOS_FRONTEND_URL;
101} else if (isDevMode && useLocalAPI) {
102 api = LOCAL_API;
103 wsApi = LOCAL_WS_API;
104 web = LOCAL_API_WEBSITE;
105 todos = LOCAL_TODOS_FRONTEND_URL;
106} else {
107 api = DEV_FRANZ_API;
108 wsApi = DEV_WS_API;
109 web = DEV_API_FRANZ_WEBSITE;
110 todos = PRODUCTION_TODOS_FRONTEND_URL;
111}
112
113export const API = api;
114export const API_VERSION = 'v1';
115export const WS_API = wsApi;
116export const WEBSITE = web;
117export const TODOS_FRONTEND = todos;
118
119export const DEFAULT_APP_SETTINGS = {
120 autoLaunchInBackground: false,
121 runInBackground: true,
122 reloadAfterResume: true,
123 enableSystemTray: true,
124 startMinimized: false,
125 confirmOnQuit: false,
126 minimizeToSystemTray: false,
127 closeToSystemTray: false,
128 privateNotifications: false,
129 clipboardNotifications: true,
130 notifyTaskBarOnMessage: false,
131 showDisabledServices: true,
132 showMessageBadgeWhenMuted: true,
133 showDragArea: false,
134 enableSpellchecking: true,
135 spellcheckerLanguage: 'en-us',
136 darkMode: isMac && electronApi.nativeTheme.shouldUseDarkColors,
137 locale: '',
138 fallbackLocale: 'en-US',
139 beta: false,
140 isAppMuted: false,
141 enableGPUAcceleration: true,
142
143 // Ferdi specific options
144 server: LIVE_FERDI_API,
145 predefinedTodoServer: DEFAULT_TODO_SERVICE,
146 autohideMenuBar: false,
147 lockingFeatureEnabled: false,
148 locked: false,
149 lockedPassword: '',
150 useTouchIdToUnlock: true,
151 scheduledDNDEnabled: false,
152 scheduledDNDStart: '17:00',
153 scheduledDNDEnd: '09:00',
154 hibernateOnStartup: true,
155 hibernationStrategy: '300', // seconds
156 wakeUpStrategy: '300', // seconds
157 inactivityLock: 0,
158 automaticUpdates: true,
159 showServiceNavigationBar: false,
160 universalDarkMode: true,
161 userAgentPref: '',
162 adaptableDarkMode: true,
163 accentColor: DEFAULT_ACCENT_COLOR,
164 serviceRibbonWidth: 68,
165 iconSize: iconSizeBias,
166 sentry: false,
167 nightly: false,
168 navigationBarBehaviour: 'custom',
169 searchEngine: SEARCH_ENGINE_DDG,
170 useVerticalStyle: false,
171 alwaysShowWorkspaces: false,
172 liftSingleInstanceLock: false,
173};
diff --git a/src/environment.ts b/src/environment.ts
new file mode 100644
index 000000000..ce2a77e7a
--- /dev/null
+++ b/src/environment.ts
@@ -0,0 +1,42 @@
1// Note: This file has now become devoid of all references to values deduced from the remote process - all those now live in the `environment-remote.js` file
2
3import os from 'os';
4
5export const isMac = process.platform === 'darwin';
6export const isWindows = process.platform === 'win32';
7export const isLinux = process.platform === 'linux';
8
9export const electronVersion = process.versions.electron;
10export const chromeVersion = process.versions.chrome;
11export const nodeVersion = process.versions.node;
12
13export const osPlatform = os.platform();
14export const osArch = os.arch();
15export const osRelease = os.release();
16export const is64Bit = osArch.match(/64/);
17
18// for accelerator, show the shortform that electron/OS understands
19// for tooltip, show symbol
20const ctrlKey = isMac ? '⌘' : 'Ctrl';
21const cmdKey = isMac ? 'Cmd' : 'Ctrl';
22
23export const altKey = (isAccelerator = true) =>
24 !isAccelerator && isMac ? '⌥' : 'Alt';
25export const shiftKey = (isAccelerator = true) =>
26 !isAccelerator && isMac ? '⇧' : 'Shift';
27
28// Platform specific shortcut keys
29export const cmdOrCtrlShortcutKey = (isAccelerator = true) =>
30 isAccelerator ? cmdKey : ctrlKey;
31export const lockFerdiShortcutKey = (isAccelerator = true) =>
32 `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+L`;
33export const todosToggleShortcutKey = (isAccelerator = true) =>
34 `${cmdOrCtrlShortcutKey(isAccelerator)}+T`;
35export const workspaceToggleShortcutKey = (isAccelerator = true) =>
36 `${cmdOrCtrlShortcutKey(isAccelerator)}+D`;
37export const muteFerdiShortcutKey = (isAccelerator = true) =>
38 `${cmdOrCtrlShortcutKey(isAccelerator)}+${shiftKey(isAccelerator)}+M`;
39export const addNewServiceShortcutKey = (isAccelerator = true) =>
40 `${cmdOrCtrlShortcutKey(isAccelerator)}+N`;
41export const settingsShortcutKey = (isAccelerator = true) =>
42 `${cmdOrCtrlShortcutKey(isAccelerator)}+${isMac ? ',' : 'P'}`;
diff --git a/src/features/appearance/index.js b/src/features/appearance/index.ts
index 3aab2fcad..bb93507dc 100644
--- a/src/features/appearance/index.js
+++ b/src/features/appearance/index.ts
@@ -1,8 +1,6 @@
1import color from 'color'; 1import color from 'color';
2import { reaction } from 'mobx'; 2import { reaction } from 'mobx';
3import themeInfo from '../../assets/themeInfo.json'; 3import { DEFAULT_APP_SETTINGS, iconSizeBias } from '../../config';
4import { iconSizeBias } from '../../config';
5import { DEFAULT_APP_SETTINGS } from '../../environment';
6 4
7const STYLE_ELEMENT_ID = 'custom-appearance-style'; 5const STYLE_ELEMENT_ID = 'custom-appearance-style';
8 6
@@ -10,13 +8,15 @@ function createStyleElement() {
10 const styles = document.createElement('style'); 8 const styles = document.createElement('style');
11 styles.id = STYLE_ELEMENT_ID; 9 styles.id = STYLE_ELEMENT_ID;
12 10
13 document.querySelector('head').appendChild(styles); 11 document.querySelector('head')?.appendChild(styles);
14} 12}
15 13
16function setAppearance(style) { 14function setAppearance(style) {
17 const styleElement = document.getElementById(STYLE_ELEMENT_ID); 15 const styleElement = document.querySelector(`#${STYLE_ELEMENT_ID}`);
18 16
19 styleElement.innerHTML = style; 17 if (styleElement) {
18 styleElement.innerHTML = style;
19 }
20} 20}
21 21
22// See https://github.com/Qix-/color/issues/53#issuecomment-656590710 22// See https://github.com/Qix-/color/issues/53#issuecomment-656590710
@@ -26,24 +26,64 @@ function darkenAbsolute(originalColor, absoluteChange) {
26} 26}
27 27
28function generateAccentStyle(accentColorStr) { 28function generateAccentStyle(accentColorStr) {
29 let style = '';
30
31 Object.keys(themeInfo).forEach((property) => {
32 style += `
33 ${themeInfo[property]} {
34 ${property}: ${accentColorStr};
35 }
36 `;
37 });
38
39 let accentColor = color(DEFAULT_APP_SETTINGS.accentColor); 29 let accentColor = color(DEFAULT_APP_SETTINGS.accentColor);
40 try { 30 try {
41 accentColor = color(accentColorStr); 31 accentColor = color(accentColorStr);
42 } catch (e) { 32 } catch {
43 // Ignore invalid accent color. 33 // Ignore invalid accent color.
44 } 34 }
45 const darkerColorStr = darkenAbsolute(accentColor, 5).hex(); 35 const darkerColorStr = darkenAbsolute(accentColor, 5).hex();
46 style += ` 36 return `
37 .theme__dark .app .sidebar .sidebar__button.is-muted,
38 .theme__dark .app .sidebar .sidebar__button.is-active,
39 .sidebar .sidebar__button.is-muted,
40 .sidebar .sidebar__button.is-active,
41 .tab-item.is-active,
42 .settings .account .invoices .invoices__action button,
43 .settings-navigation .settings-navigation__link.is-active .badge,
44 a.link,
45 button.link,
46 .auth .welcome .button:hover,
47 .auth .welcome .button__inverted,
48 .franz-form .franz-form__radio.is-selected,
49 .theme__dark .franz-form__button.franz-form__button--inverted,
50 .franz-form__button.franz-form__button--inverted {
51 color: ${accentColorStr};
52 }
53
54 .settings .settings__header,
55 .settings .settings__close,
56 .settings-navigation .settings-navigation__link.is-active,
57 a.button,
58 button.button,
59 .auth,
60 .info-bar,
61 .info-bar.info-bar--primary,
62 .infobox.infobox--primary,
63 .theme__dark .badge.badge--primary,
64 .theme__dark,
65 .badge.badge--primary,
66 .content-tabs .content-tabs__tabs .content-tabs__item.is-active,
67 #electron-app-title-bar .toolbar-dropdown:not(.open) > .toolbar-button > button:hover,
68 #electron-app-title-bar .list-item.selected .menu-item,
69 #electron-app-title-bar .list-item.selected:focus .menu-item,
70 .theme__dark .quick-switch .active,
71 .franz-form .franz-form__toggle-wrapper .franz-form__toggle.is-active .franz-form__toggle-button,
72 .theme__dark .franz-form__button,
73 .franz-form__button,
74 .ferdi__fab,
75 .franz-form .franz-form__slider-wrapper .slider::-webkit-slider-thumb {
76 background: ${accentColorStr};
77 }
78
79 .settings .settings__header .separator {
80 border-right-color: ${accentColorStr};
81 }
82
83 .franz-form .franz-form__radio.is-selected {
84 border-color: ${accentColorStr};
85 }
86
47 a.button:hover, button.button:hover { 87 a.button:hover, button.button:hover {
48 background: ${darkenAbsolute(accentColor, 10).hex()}; 88 background: ${darkenAbsolute(accentColor, 10).hex()};
49 } 89 }
@@ -72,27 +112,27 @@ function generateAccentStyle(accentColorStr) {
72 background: ${accentColor.lighten(0.35).hex()}; 112 background: ${accentColor.lighten(0.35).hex()};
73 } 113 }
74 `; 114 `;
75
76 return style;
77} 115}
78 116
79function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) { 117function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) {
80 const width = Number(widthStr); 118 const width = Number(widthStr);
81 const iconSize = Number(iconSizeStr) - iconSizeBias; 119 const iconSize = Number(iconSizeStr) - iconSizeBias;
82 120
83 return vertical ? ` 121 return vertical
122 ? `
84 .tab-item { 123 .tab-item {
85 width: ${width - 2}px !important; 124 width: ${width - 2}px !important;
86 height: ${width - 5 + iconSize}px !important; 125 height: ${width - 5 + iconSize}px !important;
87 min-height: unset; 126 min-height: unset;
88 } 127 }
89 .tab-item .tab-item__icon { 128 .tab-item .tab-item__icon {
90 width: ${(width / 2) + iconSize}px !important; 129 width: ${width / 2 + iconSize}px !important;
91 } 130 }
92 .sidebar__button { 131 .sidebar__button {
93 font-size: ${width / 3}px !important; 132 font-size: ${width / 3}px !important;
94 } 133 }
95 ` : ` 134 `
135 : `
96 .sidebar { 136 .sidebar {
97 width: ${width}px !important; 137 width: ${width}px !important;
98 } 138 }
@@ -101,7 +141,7 @@ function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) {
101 height: ${width - 5 + iconSize}px !important; 141 height: ${width - 5 + iconSize}px !important;
102 } 142 }
103 .tab-item .tab-item__icon { 143 .tab-item .tab-item__icon {
104 width: ${(width / 2) + iconSize}px !important; 144 width: ${width / 2 + iconSize}px !important;
105 } 145 }
106 .sidebar__button { 146 .sidebar__button {
107 font-size: ${width / 3}px !important; 147 font-size: ${width / 3}px !important;
@@ -129,14 +169,14 @@ function generateShowDragAreaStyle(accentColor) {
129} 169}
130 170
131function generateVerticalStyle(widthStr, alwaysShowWorkspaces) { 171function generateVerticalStyle(widthStr, alwaysShowWorkspaces) {
132 if (!document.getElementById('vertical-style')) { 172 if (!document.querySelector('#vertical-style')) {
133 const link = document.createElement('link'); 173 const link = document.createElement('link');
134 link.id = 'vertical-style'; 174 link.id = 'vertical-style';
135 link.rel = 'stylesheet'; 175 link.rel = 'stylesheet';
136 link.type = 'text/css'; 176 link.type = 'text/css';
137 link.href = './styles/vertical.css'; 177 link.href = './styles/vertical.css';
138 178
139 document.head.appendChild(link); 179 document.head.append(link);
140 } 180 }
141 const width = Number(widthStr); 181 const width = Number(widthStr);
142 const sidebarWidth = width - 4; 182 const sidebarWidth = width - 4;
@@ -144,20 +184,19 @@ function generateVerticalStyle(widthStr, alwaysShowWorkspaces) {
144 184
145 return ` 185 return `
146 .sidebar { 186 .sidebar {
147 height: ${sidebarWidth + verticalStyleOffset + 1}px !important; 187 ${
148 ${alwaysShowWorkspaces ? ` 188 alwaysShowWorkspaces
189 ? `
149 width: calc(100% - 300px) !important; 190 width: calc(100% - 300px) !important;
150 ` : ''} 191 `
192 : ''
193 }
151 } 194 }
152 195
153 .sidebar .sidebar__button { 196 .sidebar .sidebar__button {
154 width: ${width}px; 197 width: ${width}px;
155 } 198 }
156 199
157 .app .app__content {
158 padding-top: ${sidebarWidth + verticalStyleOffset + 1}px !important;
159 }
160
161 .workspaces-drawer { 200 .workspaces-drawer {
162 margin-top: -${sidebarWidth - verticalStyleOffset - 1}px !important; 201 margin-top: -${sidebarWidth - verticalStyleOffset - 1}px !important;
163 } 202 }
@@ -192,21 +231,31 @@ function generateStyle(settings) {
192 alwaysShowWorkspaces, 231 alwaysShowWorkspaces,
193 } = settings; 232 } = settings;
194 233
195 if (accentColor.toLowerCase() !== DEFAULT_APP_SETTINGS.accentColor.toLowerCase()) { 234 if (
235 accentColor.toLowerCase() !== DEFAULT_APP_SETTINGS.accentColor.toLowerCase()
236 ) {
196 style += generateAccentStyle(accentColor); 237 style += generateAccentStyle(accentColor);
197 } 238 }
198 if (serviceRibbonWidth !== DEFAULT_APP_SETTINGS.serviceRibbonWidth 239 if (
199 || iconSize !== DEFAULT_APP_SETTINGS.iconSize) { 240 serviceRibbonWidth !== DEFAULT_APP_SETTINGS.serviceRibbonWidth ||
200 style += generateServiceRibbonWidthStyle(serviceRibbonWidth, iconSize, useVerticalStyle); 241 iconSize !== DEFAULT_APP_SETTINGS.iconSize
242 ) {
243 style += generateServiceRibbonWidthStyle(
244 serviceRibbonWidth,
245 iconSize,
246 useVerticalStyle,
247 );
201 } 248 }
202 if (showDragArea) { 249 if (showDragArea) {
203 style += generateShowDragAreaStyle(accentColor); 250 style += generateShowDragAreaStyle(accentColor);
204 } 251 }
205 if (useVerticalStyle) { 252 if (useVerticalStyle) {
206 style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces); 253 style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces);
207 } else if (document.getElementById('vertical-style')) { 254 } else if (document.querySelector('#vertical-style')) {
208 const link = document.getElementById('vertical-style'); 255 const link = document.querySelector('#vertical-style');
209 document.head.removeChild(link); 256 if (link) {
257 link.remove();
258 }
210 } 259 }
211 if (alwaysShowWorkspaces) { 260 if (alwaysShowWorkspaces) {
212 style += generateOpenWorkspaceStyle(); 261 style += generateOpenWorkspaceStyle();
@@ -225,14 +274,14 @@ export default function initAppearance(stores) {
225 274
226 // Update style when settings change 275 // Update style when settings change
227 reaction( 276 reaction(
228 () => ([ 277 () => [
229 settings.all.app.accentColor, 278 settings.all.app.accentColor,
230 settings.all.app.serviceRibbonWidth, 279 settings.all.app.serviceRibbonWidth,
231 settings.all.app.iconSize, 280 settings.all.app.iconSize,
232 settings.all.app.showDragArea, 281 settings.all.app.showDragArea,
233 settings.all.app.useVerticalStyle, 282 settings.all.app.useVerticalStyle,
234 settings.all.app.alwaysShowWorkspaces, 283 settings.all.app.alwaysShowWorkspaces,
235 ]), 284 ],
236 () => { 285 () => {
237 updateStyle(settings.all.app); 286 updateStyle(settings.all.app);
238 }, 287 },
diff --git a/src/features/basicAuth/Component.js b/src/features/basicAuth/Component.js
index a9601836b..3cf937f98 100644
--- a/src/features/basicAuth/Component.js
+++ b/src/features/basicAuth/Component.js
@@ -2,19 +2,14 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import injectSheet from 'react-jss'; 3import injectSheet from 'react-jss';
4import { observer } from 'mobx-react'; 4import { observer } from 'mobx-react';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7 7
8import Modal from '../../components/ui/Modal'; 8import Modal from '../../components/ui/Modal';
9import Input from '../../components/ui/Input'; 9import Input from '../../components/ui/Input';
10import Button from '../../components/ui/Button'; 10import Button from '../../components/ui/Button';
11 11
12import { 12import { state, resetState, sendCredentials, cancelLogin } from './store';
13 state,
14 resetState,
15 sendCredentials,
16 cancelLogin,
17} from './store';
18import Form from './Form'; 13import Form from './Form';
19 14
20import styles from './styles'; 15import styles from './styles';
@@ -23,17 +18,15 @@ import globalMessages from '../../i18n/globalMessages';
23const messages = defineMessages({ 18const messages = defineMessages({
24 signIn: { 19 signIn: {
25 id: 'feature.basicAuth.signIn', 20 id: 'feature.basicAuth.signIn',
26 defaultMessage: '!!!Sign In', 21 defaultMessage: 'Sign In',
27 }, 22 },
28}); 23});
29 24
30export default @injectSheet(styles) @observer class BasicAuthModal extends Component { 25@injectSheet(styles)
26@observer
27class BasicAuthModal extends Component {
31 static propTypes = { 28 static propTypes = {
32 classes: PropTypes.object.isRequired, 29 classes: PropTypes.object.isRequired,
33 }
34
35 static contextTypes = {
36 intl: intlShape,
37 }; 30 };
38 31
39 submit(e) { 32 submit(e) {
@@ -56,20 +49,15 @@ export default @injectSheet(styles) @observer class BasicAuthModal extends Compo
56 } 49 }
57 50
58 render() { 51 render() {
59 const { 52 const { classes } = this.props;
60 classes,
61 } = this.props;
62 53
63 const { 54 const { isModalVisible, authInfo } = state;
64 isModalVisible,
65 authInfo,
66 } = state;
67 55
68 if (!authInfo) { 56 if (!authInfo) {
69 return null; 57 return null;
70 } 58 }
71 59
72 const { intl } = this.context; 60 const { intl } = this.props;
73 61
74 return ( 62 return (
75 <Modal 63 <Modal
@@ -89,10 +77,7 @@ export default @injectSheet(styles) @observer class BasicAuthModal extends Compo
89 onSubmit={this.submit.bind(this)} 77 onSubmit={this.submit.bind(this)}
90 className={classnames('franz-form', classes.form)} 78 className={classnames('franz-form', classes.form)}
91 > 79 >
92 <Input 80 <Input field={Form.$('user')} showLabel={false} />
93 field={Form.$('user')}
94 showLabel={false}
95 />
96 <Input 81 <Input
97 field={Form.$('password')} 82 field={Form.$('password')}
98 showLabel={false} 83 showLabel={false}
@@ -105,13 +90,11 @@ export default @injectSheet(styles) @observer class BasicAuthModal extends Compo
105 buttonType="secondary" 90 buttonType="secondary"
106 onClick={this.cancel.bind(this)} 91 onClick={this.cancel.bind(this)}
107 /> 92 />
108 <Button 93 <Button type="submit" label={intl.formatMessage(messages.signIn)} />
109 type="submit"
110 label={intl.formatMessage(messages.signIn)}
111 />
112 </div> 94 </div>
113 </form> 95 </form>
114 </Modal> 96 </Modal>
115 ); 97 );
116 } 98 }
117} 99}
100export default injectIntl(BasicAuthModal);
diff --git a/src/features/basicAuth/Form.js b/src/features/basicAuth/Form.ts
index 95721d0e9..e84156d96 100644
--- a/src/features/basicAuth/Form.js
+++ b/src/features/basicAuth/Form.ts
@@ -1,5 +1,6 @@
1import Form from '../../lib/Form'; 1import Form from '../../lib/Form';
2 2
3// @ts-expect-error Expected 0 arguments, but got 1
3export default new Form({ 4export default new Form({
4 fields: { 5 fields: {
5 user: { 6 user: {
diff --git a/src/features/basicAuth/mainIpcHandler.js b/src/features/basicAuth/mainIpcHandler.ts
index ae4e7cf93..4ec3848e8 100644
--- a/src/features/basicAuth/mainIpcHandler.js
+++ b/src/features/basicAuth/mainIpcHandler.ts
@@ -1,6 +1,8 @@
1import { BrowserWindow } from 'electron';
2
1const debug = require('debug')('Ferdi:feature:basicAuth:main'); 3const debug = require('debug')('Ferdi:feature:basicAuth:main');
2 4
3export default function mainIpcHandler(mainWindow, authInfo) { 5export default function mainIpcHandler(mainWindow: BrowserWindow, authInfo) {
4 debug('Sending basic auth call', authInfo); 6 debug('Sending basic auth call', authInfo);
5 7
6 mainWindow.webContents.send('feature:basic-auth', { 8 mainWindow.webContents.send('feature:basic-auth', {
diff --git a/src/features/basicAuth/store.js b/src/features/basicAuth/store.ts
index 0713ff572..0713ff572 100644
--- a/src/features/basicAuth/store.js
+++ b/src/features/basicAuth/store.ts
diff --git a/src/features/basicAuth/styles.js b/src/features/basicAuth/styles.ts
index 6bdaf9a6e..6bdaf9a6e 100644
--- a/src/features/basicAuth/styles.js
+++ b/src/features/basicAuth/styles.ts
diff --git a/src/features/communityRecipes/index.js b/src/features/communityRecipes/index.ts
index 828c6d867..828c6d867 100644
--- a/src/features/communityRecipes/index.js
+++ b/src/features/communityRecipes/index.ts
diff --git a/src/features/communityRecipes/store.js b/src/features/communityRecipes/store.ts
index a3614dd11..a8d358ba0 100644
--- a/src/features/communityRecipes/store.js
+++ b/src/features/communityRecipes/store.ts
@@ -4,7 +4,11 @@ import { FeatureStore } from '../utils/FeatureStore';
4const debug = require('debug')('Ferdi:feature:communityRecipes:store'); 4const debug = require('debug')('Ferdi:feature:communityRecipes:store');
5 5
6export class CommunityRecipesStore extends FeatureStore { 6export class CommunityRecipesStore extends FeatureStore {
7 start(stores, actions) { 7 stores: any;
8
9 actions: any;
10
11 start(stores: any, actions: any) {
8 debug('start'); 12 debug('start');
9 this.stores = stores; 13 this.stores = stores;
10 this.actions = actions; 14 this.actions = actions;
@@ -18,12 +22,17 @@ export class CommunityRecipesStore extends FeatureStore {
18 @computed get communityRecipes() { 22 @computed get communityRecipes() {
19 if (!this.stores) return []; 23 if (!this.stores) return [];
20 24
21 return this.stores.recipePreviews.dev.map((r) => { 25 return this.stores.recipePreviews.dev.map(
22 // TODO: Need to figure out if this is even necessary/used 26 (recipePreview: { isDevRecipe: boolean; author: any[] }) => {
23 r.isDevRecipe = !!r.author.find((a) => a.email === this.stores.user.data.email); 27 // TODO: Need to figure out if this is even necessary/used
28 recipePreview.isDevRecipe = !!recipePreview.author.some(
29 (author: { email: any }) =>
30 author.email === this.stores.user.data.email,
31 );
24 32
25 return r; 33 return recipePreview;
26 }); 34 },
35 );
27 } 36 }
28} 37}
29 38
diff --git a/src/features/nightlyBuilds/Component.js b/src/features/nightlyBuilds/Component.js
index e43287db5..814d529d9 100644
--- a/src/features/nightlyBuilds/Component.js
+++ b/src/features/nightlyBuilds/Component.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, inject } from 'mobx-react'; 3import { observer, inject } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import { H1 } from '@meetfranz/ui'; 6import { H1 } from '@meetfranz/ui';
7 7
8import Modal from '../../components/ui/Modal'; 8import Modal from '../../components/ui/Modal';
@@ -16,15 +16,16 @@ import globalMessages from '../../i18n/globalMessages';
16const messages = defineMessages({ 16const messages = defineMessages({
17 title: { 17 title: {
18 id: 'feature.nightlyBuilds.title', 18 id: 'feature.nightlyBuilds.title',
19 defaultMessage: '!!!Nightly Builds', 19 defaultMessage: 'Nightly Builds',
20 }, 20 },
21 info: { 21 info: {
22 id: 'feature.nightlyBuilds.info', 22 id: 'feature.nightlyBuilds.info',
23 defaultMessage: '!!!Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don\'t know what you are doing, we suggest not activating nightly builds.', 23 defaultMessage:
24 "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
24 }, 25 },
25 activate: { 26 activate: {
26 id: 'feature.nightlyBuilds.activate', 27 id: 'feature.nightlyBuilds.activate',
27 defaultMessage: '!!!Activate', 28 defaultMessage: 'Activate',
28 }, 29 },
29}); 30});
30 31
@@ -52,11 +53,10 @@ const styles = () => ({
52 }, 53 },
53}); 54});
54 55
55export default @injectSheet(styles) @inject('stores', 'actions') @observer class NightlyBuildsModal extends Component { 56@injectSheet(styles)
56 static contextTypes = { 57@inject('stores', 'actions')
57 intl: intlShape, 58@observer
58 }; 59class NightlyBuildsModal extends Component {
59
60 close() { 60 close() {
61 ModalState.isModalVisible = false; 61 ModalState.isModalVisible = false;
62 62
@@ -84,11 +84,9 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
84 render() { 84 render() {
85 const { isModalVisible } = ModalState; 85 const { isModalVisible } = ModalState;
86 86
87 const { 87 const { classes } = this.props;
88 classes,
89 } = this.props;
90 88
91 const { intl } = this.context; 89 const { intl } = this.props;
92 90
93 return ( 91 return (
94 <Modal 92 <Modal
@@ -132,3 +130,5 @@ NightlyBuildsModal.wrappedComponent.propTypes = {
132 }).isRequired, 130 }).isRequired,
133 classes: PropTypes.object.isRequired, 131 classes: PropTypes.object.isRequired,
134}; 132};
133
134export default injectIntl(NightlyBuildsModal);
diff --git a/src/features/nightlyBuilds/store.js b/src/features/nightlyBuilds/store.ts
index ed06e5a7d..ed06e5a7d 100644
--- a/src/features/nightlyBuilds/store.js
+++ b/src/features/nightlyBuilds/store.ts
diff --git a/src/features/publishDebugInfo/Component.js b/src/features/publishDebugInfo/Component.js
index 5387bd358..5b5036752 100644
--- a/src/features/publishDebugInfo/Component.js
+++ b/src/features/publishDebugInfo/Component.js
@@ -2,7 +2,7 @@ import { H1 } from '@meetfranz/ui';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import React, { Component } from 'react'; 4import React, { Component } from 'react';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7import { state as ModalState } from './store'; 7import { state as ModalState } from './store';
8import { sendAuthRequest } from '../../api/utils/auth'; 8import { sendAuthRequest } from '../../api/utils/auth';
@@ -18,35 +18,37 @@ const debug = require('debug')('Ferdi:feature:publishDebugInfo');
18const messages = defineMessages({ 18const messages = defineMessages({
19 title: { 19 title: {
20 id: 'feature.publishDebugInfo.title', 20 id: 'feature.publishDebugInfo.title',
21 defaultMessage: '!!!Publish debug information', 21 defaultMessage: 'Publish debug information',
22 }, 22 },
23 info: { 23 info: {
24 id: 'feature.publishDebugInfo.info', 24 id: 'feature.publishDebugInfo.info',
25 defaultMessage: '!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger\'s privacy policy and terms of service', 25 defaultMessage:
26 "Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service",
26 }, 27 },
27 error: { 28 error: {
28 id: 'feature.publishDebugInfo.error', 29 id: 'feature.publishDebugInfo.error',
29 defaultMessage: '!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.', 30 defaultMessage:
31 'There was an error while trying to publish the debug information. Please try again later or view the console for more information.',
30 }, 32 },
31 privacy: { 33 privacy: {
32 id: 'feature.publishDebugInfo.privacy', 34 id: 'feature.publishDebugInfo.privacy',
33 defaultMessage: '!!!Privacy policy', 35 defaultMessage: 'Privacy policy',
34 }, 36 },
35 terms: { 37 terms: {
36 id: 'feature.publishDebugInfo.terms', 38 id: 'feature.publishDebugInfo.terms',
37 defaultMessage: '!!!Terms of service', 39 defaultMessage: 'Terms of service',
38 }, 40 },
39 publish: { 41 publish: {
40 id: 'feature.publishDebugInfo.publish', 42 id: 'feature.publishDebugInfo.publish',
41 defaultMessage: '!!!Accept and publish', 43 defaultMessage: 'Accept and publish',
42 }, 44 },
43 published: { 45 published: {
44 id: 'feature.publishDebugInfo.published', 46 id: 'feature.publishDebugInfo.published',
45 defaultMessage: '!!!Your debug log was published and is now availible at', 47 defaultMessage: 'Your debug log was published and is now availible at',
46 }, 48 },
47}); 49});
48 50
49const styles = (theme) => ({ 51const styles = theme => ({
50 container: { 52 container: {
51 minWidth: '70vw', 53 minWidth: '70vw',
52 }, 54 },
@@ -69,7 +71,8 @@ const styles = (theme) => ({
69 width: '100%', 71 width: '100%',
70 72
71 '& div': { 73 '& div': {
72 fontFamily: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace', 74 fontFamily:
75 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace',
73 }, 76 },
74 77
75 '& input': { 78 '& input': {
@@ -81,20 +84,19 @@ const styles = (theme) => ({
81 }, 84 },
82}); 85});
83 86
84export default @injectSheet(styles) @inject('stores', 'actions') @observer class PublishDebugLogModal extends Component { 87@injectSheet(styles)
88@inject('stores', 'actions')
89@observer
90class PublishDebugLogModal extends Component {
85 static propTypes = { 91 static propTypes = {
86 classes: PropTypes.object.isRequired, 92 classes: PropTypes.object.isRequired,
87 }; 93 };
88 94
89 static contextTypes = {
90 intl: intlShape,
91 };
92
93 state = { 95 state = {
94 log: null, 96 log: null,
95 error: false, 97 error: false,
96 isSendingLog: false, 98 isSendingLog: false,
97 } 99 };
98 100
99 // Close this modal 101 // Close this modal
100 close() { 102 close() {
@@ -109,12 +111,16 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
109 111
110 const debugInfo = JSON.stringify(this.props.stores.app.debugInfo); 112 const debugInfo = JSON.stringify(this.props.stores.app.debugInfo);
111 113
112 const request = await sendAuthRequest(`${DEBUG_API}/create`, { 114 const request = await sendAuthRequest(
113 method: 'POST', 115 `${DEBUG_API}/create`,
114 body: JSON.stringify({ 116 {
115 log: debugInfo, 117 method: 'POST',
116 }), 118 body: JSON.stringify({
117 }, false); 119 log: debugInfo,
120 }),
121 },
122 false,
123 );
118 124
119 debug(`debugInfo: publishing status: ${request.status}`); 125 debug(`debugInfo: publishing status: ${request.status}`);
120 if (request.status === 200) { 126 if (request.status === 200) {
@@ -140,17 +146,11 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
140 render() { 146 render() {
141 const { isModalVisible } = ModalState; 147 const { isModalVisible } = ModalState;
142 148
143 const { 149 const { classes } = this.props;
144 classes,
145 } = this.props;
146 150
147 const { 151 const { log, error, isSendingLog } = this.state;
148 log,
149 error,
150 isSendingLog,
151 } = this.state;
152 152
153 const { intl } = this.context; 153 const { intl } = this.props;
154 154
155 return ( 155 return (
156 <Modal 156 <Modal
@@ -159,12 +159,12 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
159 close={() => this.close()} 159 close={() => this.close()}
160 > 160 >
161 <div className={classes.container}> 161 <div className={classes.container}>
162 <H1> 162 <H1>{intl.formatMessage(messages.title)}</H1>
163 {intl.formatMessage(messages.title)} 163 {log && (
164 </H1>
165 { log && (
166 <> 164 <>
167 <p className={classes.info}>{intl.formatMessage(messages.published)}</p> 165 <p className={classes.info}>
166 {intl.formatMessage(messages.published)}
167 </p>
168 <Input 168 <Input
169 className={classes.url} 169 className={classes.url}
170 showLabel={false} 170 showLabel={false}
@@ -184,12 +184,24 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
184 184
185 {!log && !error && ( 185 {!log && !error && (
186 <> 186 <>
187 <p className={classes.info}>{intl.formatMessage(messages.info)}</p> 187 <p className={classes.info}>
188 188 {intl.formatMessage(messages.info)}
189 <a href={`${DEBUG_API}/privacy.html`} target="_blank" className={classes.link} rel="noreferrer"> 189 </p>
190
191 <a
192 href={`${DEBUG_API}/privacy.html`}
193 target="_blank"
194 className={classes.link}
195 rel="noreferrer"
196 >
190 {intl.formatMessage(messages.privacy)} 197 {intl.formatMessage(messages.privacy)}
191 </a> 198 </a>
192 <a href={`${DEBUG_API}/terms.html`} target="_blank" className={classes.link} rel="noreferrer"> 199 <a
200 href={`${DEBUG_API}/terms.html`}
201 target="_blank"
202 className={classes.link}
203 rel="noreferrer"
204 >
193 {intl.formatMessage(messages.terms)} 205 {intl.formatMessage(messages.terms)}
194 </a> 206 </a>
195 207
@@ -216,3 +228,5 @@ PublishDebugLogModal.wrappedComponent.propTypes = {
216 service: PropTypes.instanceOf(ServicesStore).isRequired, 228 service: PropTypes.instanceOf(ServicesStore).isRequired,
217 }).isRequired, 229 }).isRequired,
218}; 230};
231
232export default injectIntl(PublishDebugLogModal);
diff --git a/src/features/publishDebugInfo/store.js b/src/features/publishDebugInfo/store.ts
index ed06e5a7d..ed06e5a7d 100644
--- a/src/features/publishDebugInfo/store.js
+++ b/src/features/publishDebugInfo/store.ts
diff --git a/src/features/quickSwitch/Component.js b/src/features/quickSwitch/Component.js
index 78d5d94a0..f21db0ebd 100644
--- a/src/features/quickSwitch/Component.js
+++ b/src/features/quickSwitch/Component.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
4import { observer, inject } from 'mobx-react'; 4import { observer, inject } from 'mobx-react';
5import { reaction } from 'mobx'; 5import { reaction } from 'mobx';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7import { defineMessages, intlShape } from 'react-intl'; 7import { defineMessages, injectIntl } from 'react-intl';
8import { Input } from '@meetfranz/forms'; 8import { Input } from '@meetfranz/forms';
9import { H1 } from '@meetfranz/ui'; 9import { H1 } from '@meetfranz/ui';
10 10
@@ -16,19 +16,20 @@ import ServicesStore from '../../stores/ServicesStore';
16const messages = defineMessages({ 16const messages = defineMessages({
17 title: { 17 title: {
18 id: 'feature.quickSwitch.title', 18 id: 'feature.quickSwitch.title',
19 defaultMessage: '!!!QuickSwitch', 19 defaultMessage: 'QuickSwitch',
20 }, 20 },
21 search: { 21 search: {
22 id: 'feature.quickSwitch.search', 22 id: 'feature.quickSwitch.search',
23 defaultMessage: '!!!Search...', 23 defaultMessage: 'Search...',
24 }, 24 },
25 info: { 25 info: {
26 id: 'feature.quickSwitch.info', 26 id: 'feature.quickSwitch.info',
27 defaultMessage: '!!!Select a service with TAB, ↑ and ↓. Open a service with ENTER.', 27 defaultMessage:
28 'Select a service with TAB, ↑ and ↓. Open a service with ENTER.',
28 }, 29 },
29}); 30});
30 31
31const styles = (theme) => ({ 32const styles = theme => ({
32 modal: { 33 modal: {
33 width: '80%', 34 width: '80%',
34 maxWidth: 600, 35 maxWidth: 600,
@@ -80,20 +81,19 @@ const styles = (theme) => ({
80 }, 81 },
81}); 82});
82 83
83export default @injectSheet(styles) @inject('stores', 'actions') @observer class QuickSwitchModal extends Component { 84@injectSheet(styles)
85@inject('stores', 'actions')
86@observer
87class QuickSwitchModal extends Component {
84 static propTypes = { 88 static propTypes = {
85 classes: PropTypes.object.isRequired, 89 classes: PropTypes.object.isRequired,
86 }; 90 };
87 91
88 static contextTypes = {
89 intl: intlShape,
90 };
91
92 state = { 92 state = {
93 selected: 0, 93 selected: 0,
94 search: '', 94 search: '',
95 wasPrevVisible: false, 95 wasPrevVisible: false,
96 } 96 };
97 97
98 ARROW_DOWN = 40; 98 ARROW_DOWN = 40;
99 99
@@ -118,9 +118,7 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
118 this.openService = this.openService.bind(this); 118 this.openService = this.openService.bind(this);
119 119
120 reaction( 120 reaction(
121 () => ( 121 () => ModalState.isModalVisible,
122 ModalState.isModalVisible
123 ),
124 () => { 122 () => {
125 this._handleVisibilityChange(); 123 this._handleVisibilityChange();
126 }, 124 },
@@ -140,10 +138,17 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
140 // Get currently shown services 138 // Get currently shown services
141 services() { 139 services() {
142 let services = []; 140 let services = [];
143 if (this.state.search && compact(invoke(this.state.search, 'match', /^[a-z0-9]/i)).length > 0) { 141 if (
142 this.state.search &&
143 compact(invoke(this.state.search, 'match', /^[\da-z]/i)).length > 0
144 ) {
144 // Apply simple search algorythm to list of all services 145 // Apply simple search algorythm to list of all services
145 services = this.props.stores.services.allDisplayed; 146 services = this.props.stores.services.allDisplayed;
146 services = services.filter((service) => service.name.toLowerCase().search(this.state.search.toLowerCase()) !== -1); 147 services = services.filter(
148 service =>
149 service.name.toLowerCase().search(this.state.search.toLowerCase()) !==
150 -1,
151 );
147 } else { 152 } else {
148 // Add the currently active service first 153 // Add the currently active service first
149 const currentService = this.props.stores.services.active; 154 const currentService = this.props.stores.services.active;
@@ -186,14 +191,14 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
186 // Change the selected service 191 // Change the selected service
187 // factor should be -1 or 1 192 // factor should be -1 or 1
188 changeSelected(factor) { 193 changeSelected(factor) {
189 this.setState((state) => { 194 this.setState(state => {
190 let newSelected = state.selected + factor; 195 let newSelected = state.selected + factor;
191 const services = this.services().length; 196 const services = this.services().length;
192 197
193 // Roll around when on edge of list 198 // Roll around when on edge of list
194 if (state.selected < 1 && factor === -1) { 199 if (state.selected < 1 && factor === -1) {
195 newSelected = services - 1; 200 newSelected = services - 1;
196 } else if ((state.selected >= (services - 1)) && factor === 1) { 201 } else if (state.selected >= services - 1 && factor === 1) {
197 newSelected = 0; 202 newSelected = 0;
198 } 203 }
199 204
@@ -256,7 +261,7 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
256 // Wrapped inside timeout to let the modal render first 261 // Wrapped inside timeout to let the modal render first
257 setTimeout(() => { 262 setTimeout(() => {
258 if (this.inputRef.current) { 263 if (this.inputRef.current) {
259 this.inputRef.current.getElementsByTagName('input')[0].focus(); 264 this.inputRef.current.querySelectorAll('input')[0].focus();
260 } 265 }
261 }, 10); 266 }, 10);
262 267
@@ -268,7 +273,7 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
268 // search query change when modal not visible 273 // search query change when modal not visible
269 setTimeout(() => { 274 setTimeout(() => {
270 if (this.inputRef.current) { 275 if (this.inputRef.current) {
271 this.inputRef.current.getElementsByTagName('input')[0].blur(); 276 this.inputRef.current.querySelectorAll('input')[0].blur();
272 } 277 }
273 }, 100); 278 }, 100);
274 279
@@ -286,17 +291,13 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
286 render() { 291 render() {
287 const { isModalVisible } = ModalState; 292 const { isModalVisible } = ModalState;
288 293
289 const { 294 const { openService } = this;
290 openService,
291 } = this;
292 295
293 const { 296 const { classes } = this.props;
294 classes,
295 } = this.props;
296 297
297 const services = this.services(); 298 const services = this.services();
298 299
299 const { intl } = this.context; 300 const { intl } = this.props;
300 301
301 return ( 302 return (
302 <Modal 303 <Modal
@@ -318,12 +319,16 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
318 </div> 319 </div>
319 320
320 <div className={classes.services}> 321 <div className={classes.services}>
321 { services.map((service, index) => ( 322 {services.map((service, index) => (
322 <div 323 <div
323 className={`${classes.service} ${this.state.selected === index ? `${classes.activeService} active` : ''} service`} 324 className={`${classes.service} ${
325 this.state.selected === index
326 ? `${classes.activeService} active`
327 : ''
328 } service`}
324 onClick={() => openService(index)} 329 onClick={() => openService(index)}
325 key={service.id} 330 key={service.id}
326 ref={(el) => { 331 ref={el => {
327 this.serviceElements[index] = el; 332 this.serviceElements[index] = el;
328 }} 333 }}
329 > 334 >
@@ -332,9 +337,7 @@ export default @injectSheet(styles) @inject('stores', 'actions') @observer class
332 className={classes.serviceIcon} 337 className={classes.serviceIcon}
333 alt={service.recipe.name} 338 alt={service.recipe.name}
334 /> 339 />
335 <div> 340 <div>{service.name}</div>
336 { service.name }
337 </div>
338 </div> 341 </div>
339 ))} 342 ))}
340 </div> 343 </div>
@@ -356,3 +359,5 @@ QuickSwitchModal.wrappedComponent.propTypes = {
356 service: PropTypes.instanceOf(ServicesStore).isRequired, 359 service: PropTypes.instanceOf(ServicesStore).isRequired,
357 }).isRequired, 360 }).isRequired,
358}; 361};
362
363export default injectIntl(QuickSwitchModal);
diff --git a/src/features/quickSwitch/store.js b/src/features/quickSwitch/store.ts
index ed06e5a7d..ed06e5a7d 100644
--- a/src/features/quickSwitch/store.js
+++ b/src/features/quickSwitch/store.ts
diff --git a/src/features/serviceProxy/index.js b/src/features/serviceProxy/index.js
deleted file mode 100644
index eb7116651..000000000
--- a/src/features/serviceProxy/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
1import { autorun, observable } from 'mobx';
2import { session } from '@electron/remote';
3
4const debug = require('debug')('Ferdi:feature:serviceProxy');
5
6export const config = observable({
7 isEnabled: true,
8});
9
10export default function init(stores) {
11 debug('Initializing `serviceProxy` feature');
12
13 autorun(() => {
14 config.isEnabled = true;
15
16 const services = stores.services.enabled;
17 const proxySettings = stores.settings.proxy;
18
19 debug('Service Proxy autorun');
20
21 services.forEach((service) => {
22 const s = session.fromPartition(`persist:service-${service.id}`);
23
24 if (config.isEnabled) {
25 const serviceProxyConfig = proxySettings[service.id];
26
27 if (serviceProxyConfig && serviceProxyConfig.isEnabled && serviceProxyConfig.host) {
28 const proxyHost = `${serviceProxyConfig.host}${serviceProxyConfig.port ? `:${serviceProxyConfig.port}` : ''}`;
29 debug(`Setting proxy config from service settings for "${service.name}" (${service.id}) to`, proxyHost);
30
31 s.setProxy({ proxyRules: proxyHost }, () => {
32 debug(`Using proxy "${proxyHost}" for "${service.name}" (${service.id})`);
33 });
34 }
35 }
36 });
37 });
38}
diff --git a/src/features/serviceProxy/index.ts b/src/features/serviceProxy/index.ts
new file mode 100644
index 000000000..f095b286a
--- /dev/null
+++ b/src/features/serviceProxy/index.ts
@@ -0,0 +1,54 @@
1import { autorun, observable } from 'mobx';
2import { session } from '@electron/remote';
3
4const debug = require('debug')('Ferdi:feature:serviceProxy');
5
6export const config = observable({
7 isEnabled: true,
8});
9
10export default function init(stores: {
11 services: { enabled: any };
12 settings: { proxy: any };
13}) {
14 debug('Initializing `serviceProxy` feature');
15
16 autorun(() => {
17 config.isEnabled = true;
18
19 const services = stores.services.enabled;
20 const proxySettings = stores.settings.proxy;
21
22 debug('Service Proxy autorun');
23
24 for (const service of services) {
25 const s = session.fromPartition(`persist:service-${service.id}`);
26
27 if (config.isEnabled) {
28 const serviceProxyConfig = proxySettings[service.id];
29
30 if (
31 serviceProxyConfig &&
32 serviceProxyConfig.isEnabled &&
33 serviceProxyConfig.host
34 ) {
35 const proxyHost = `${serviceProxyConfig.host}${
36 serviceProxyConfig.port ? `:${serviceProxyConfig.port}` : ''
37 }`;
38 debug(
39 `Setting proxy config from service settings for "${service.name}" (${service.id}) to`,
40 proxyHost,
41 );
42
43 s.setProxy({ proxyRules: proxyHost })
44 .then(() => {
45 debug(
46 `Using proxy "${proxyHost}" for "${service.name}" (${service.id})`,
47 );
48 })
49 .catch(error => console.error(error));
50 }
51 }
52 }
53 });
54}
diff --git a/src/features/settingsWS/actions.js b/src/features/settingsWS/actions.ts
index 631670c8a..631670c8a 100755
--- a/src/features/settingsWS/actions.js
+++ b/src/features/settingsWS/actions.ts
diff --git a/src/features/settingsWS/index.js b/src/features/settingsWS/index.ts
index 7771421d6..9bb206d82 100755
--- a/src/features/settingsWS/index.js
+++ b/src/features/settingsWS/index.ts
@@ -5,15 +5,16 @@ const debug = require('debug')('Ferdi:feature:settingsWS');
5 5
6export const settingsStore = new SettingsWSStore(); 6export const settingsStore = new SettingsWSStore();
7 7
8export default function initSettingsWebSocket(stores, actions) { 8export default function initSettingsWebSocket(
9 stores: { features: any },
10 actions: any,
11) {
9 const { features } = stores; 12 const { features } = stores;
10 13
11 // Toggle SettingsWebSocket feature 14 // Toggle SettingsWebSocket feature
12 reaction( 15 reaction(
13 () => ( 16 () => features.features.isSettingsWSEnabled,
14 features.features.isSettingsWSEnabled 17 isEnabled => {
15 ),
16 (isEnabled) => {
17 if (isEnabled) { 18 if (isEnabled) {
18 debug('Initializing `settingsWS` feature'); 19 debug('Initializing `settingsWS` feature');
19 settingsStore.start(stores, actions); 20 settingsStore.start(stores, actions);
diff --git a/src/features/settingsWS/state.js b/src/features/settingsWS/state.ts
index 7b16b2b6e..7b16b2b6e 100755
--- a/src/features/settingsWS/state.js
+++ b/src/features/settingsWS/state.ts
diff --git a/src/features/settingsWS/store.js b/src/features/settingsWS/store.js
index 9100f33d1..3b9e10825 100755
--- a/src/features/settingsWS/store.js
+++ b/src/features/settingsWS/store.js
@@ -4,7 +4,7 @@ import ms from 'ms';
4 4
5import { FeatureStore } from '../utils/FeatureStore'; 5import { FeatureStore } from '../utils/FeatureStore';
6import { createReactions } from '../../stores/lib/Reaction'; 6import { createReactions } from '../../stores/lib/Reaction';
7import { WS_API } from '../../environment'; 7import { WS_API } from '../../environment-remote';
8 8
9const debug = require('debug')('Ferdi:feature:settingsWS:store'); 9const debug = require('debug')('Ferdi:feature:settingsWS:store');
10 10
@@ -25,11 +25,13 @@ export class SettingsWSStore extends FeatureStore {
25 this.stores = stores; 25 this.stores = stores;
26 this.actions = actions; 26 this.actions = actions;
27 27
28 this._registerReactions(createReactions([ 28 this._registerReactions(
29 this._initialize.bind(this), 29 createReactions([
30 this._reconnect.bind(this), 30 this._initialize.bind(this),
31 this._close.bind(this), 31 this._reconnect.bind(this),
32 ])); 32 this._close.bind(this),
33 ]),
34 );
33 } 35 }
34 36
35 connect() { 37 connect() {
@@ -51,12 +53,12 @@ export class SettingsWSStore extends FeatureStore {
51 this.heartbeat(); 53 this.heartbeat();
52 }); 54 });
53 55
54 this.ws.on('message', (data) => { 56 this.ws.on('message', data => {
55 const resp = JSON.parse(data); 57 const resp = JSON.parse(data);
56 debug('Received message', resp); 58 debug('Received message', resp);
57 59
58 if (resp.id) { 60 if (resp.id) {
59 this.stores.user.getUserInfoRequest.patch((result) => { 61 this.stores.user.getUserInfoRequest.patch(result => {
60 if (!result) return; 62 if (!result) return;
61 63
62 debug('Patching user object with new values'); 64 debug('Patching user object with new values');
@@ -66,8 +68,8 @@ export class SettingsWSStore extends FeatureStore {
66 }); 68 });
67 69
68 this.ws.on('ping', this.heartbeat.bind(this)); 70 this.ws.on('ping', this.heartbeat.bind(this));
69 } catch (err) { 71 } catch (error) {
70 console.err(err); 72 console.error(error);
71 } 73 }
72 } 74 }
73 75
diff --git a/src/features/todos/actions.js b/src/features/todos/actions.js
deleted file mode 100644
index cc17e919b..000000000
--- a/src/features/todos/actions.js
+++ /dev/null
@@ -1,28 +0,0 @@
1import PropTypes from 'prop-types';
2import { createActionsFromDefinitions } from '../../actions/lib/actions';
3
4export const todoActions = createActionsFromDefinitions({
5 resize: {
6 width: PropTypes.number.isRequired,
7 },
8 toggleTodosPanel: {},
9 toggleTodosFeatureVisibility: {},
10 setTodosWebview: {
11 webview: PropTypes.instanceOf(Element).isRequired,
12 },
13 handleHostMessage: {
14 action: PropTypes.string.isRequired,
15 data: PropTypes.object,
16 },
17 handleClientMessage: {
18 channel: PropTypes.string.isRequired,
19 message: PropTypes.shape({
20 action: PropTypes.string.isRequired,
21 data: PropTypes.object,
22 }),
23 },
24 openDevTools: {},
25 reload: {},
26}, PropTypes.checkPropTypes);
27
28export default todoActions;
diff --git a/src/features/todos/actions.ts b/src/features/todos/actions.ts
new file mode 100644
index 000000000..04e299e71
--- /dev/null
+++ b/src/features/todos/actions.ts
@@ -0,0 +1,31 @@
1import PropTypes from 'prop-types';
2import { createActionsFromDefinitions } from '../../actions/lib/actions';
3
4export const todoActions = createActionsFromDefinitions(
5 {
6 resize: {
7 width: PropTypes.number.isRequired,
8 },
9 toggleTodosPanel: {},
10 toggleTodosFeatureVisibility: {},
11 setTodosWebview: {
12 webview: PropTypes.instanceOf(Element).isRequired,
13 },
14 handleHostMessage: {
15 action: PropTypes.string.isRequired,
16 data: PropTypes.object,
17 },
18 handleClientMessage: {
19 channel: PropTypes.string.isRequired,
20 message: PropTypes.shape({
21 action: PropTypes.string.isRequired,
22 data: PropTypes.object,
23 }),
24 },
25 openDevTools: {},
26 reload: {},
27 },
28 PropTypes.checkPropTypes,
29);
30
31export default todoActions;
diff --git a/src/features/todos/constants.js b/src/features/todos/constants.ts
index 303a7a16e..303a7a16e 100644
--- a/src/features/todos/constants.js
+++ b/src/features/todos/constants.ts
diff --git a/src/features/todos/index.js b/src/features/todos/index.ts
index 573190881..3665812e6 100644
--- a/src/features/todos/index.js
+++ b/src/features/todos/index.ts
@@ -5,16 +5,17 @@ const debug = require('debug')('Ferdi:feature:todos');
5 5
6export const todosStore = new TodoStore(); 6export const todosStore = new TodoStore();
7 7
8export default function initTodos(stores, actions) { 8export default function initTodos(
9 stores: { todos?: any; features?: any },
10 actions: any,
11) {
9 stores.todos = todosStore; 12 stores.todos = todosStore;
10 const { features } = stores; 13 const { features } = stores;
11 14
12 // Toggle todos feature 15 // Toggle todos feature
13 reaction( 16 reaction(
14 () => ( 17 () => features.features.isTodosEnabled,
15 features.features.isTodosEnabled 18 isEnabled => {
16 ),
17 (isEnabled) => {
18 if (isEnabled) { 19 if (isEnabled) {
19 debug('Initializing `todos` feature'); 20 debug('Initializing `todos` feature');
20 todosStore.start(stores, actions); 21 todosStore.start(stores, actions);
diff --git a/src/features/todos/preload.js b/src/features/todos/preload.js
index 9bd76a704..3b86ddbc5 100644
--- a/src/features/todos/preload.js
+++ b/src/features/todos/preload.js
@@ -7,7 +7,9 @@ debug('Preloading Todos Webview');
7 7
8let hostMessageListener = ({ action }) => { 8let hostMessageListener = ({ action }) => {
9 switch (action) { 9 switch (action) {
10 case 'todos:initialize-as-service': ipcRenderer.sendToHost('hello'); break; 10 case 'todos:initialize-as-service':
11 ipcRenderer.sendToHost('hello');
12 break;
11 default: 13 default:
12 } 14 }
13}; 15};
@@ -15,7 +17,9 @@ let hostMessageListener = ({ action }) => {
15window.ferdi = { 17window.ferdi = {
16 onInitialize(ipcHostMessageListener) { 18 onInitialize(ipcHostMessageListener) {
17 hostMessageListener = ipcHostMessageListener; 19 hostMessageListener = ipcHostMessageListener;
18 ipcRenderer.sendToHost(IPC.TODOS_CLIENT_CHANNEL, { action: 'todos:initialized' }); 20 ipcRenderer.sendToHost(IPC.TODOS_CLIENT_CHANNEL, {
21 action: 'todos:initialized',
22 });
19 }, 23 },
20 sendToHost(message) { 24 sendToHost(message) {
21 ipcRenderer.sendToHost(IPC.TODOS_CLIENT_CHANNEL, message); 25 ipcRenderer.sendToHost(IPC.TODOS_CLIENT_CHANNEL, message);
@@ -30,7 +34,7 @@ ipcRenderer.on(IPC.TODOS_HOST_CHANNEL, (event, message) => {
30if (window.location.href === 'https://app.franztodos.com/login/') { 34if (window.location.href === 'https://app.franztodos.com/login/') {
31 // Insert info element informing about Franz accounts 35 // Insert info element informing about Franz accounts
32 const infoElement = document.createElement('p'); 36 const infoElement = document.createElement('p');
33 infoElement.innerText = `You are using Franz's official Todo Service. 37 infoElement.textContent = `You are using Franz's official Todo Service.
34This service will only work with accounts registered with Franz - no Ferdi accounts will work here! 38This service will only work with accounts registered with Franz - no Ferdi accounts will work here!
35If you do not have a Franz account you can change the Todo service by going into Ferdi's settings and changing the "Todo server". 39If you do not have a Franz account you can change the Todo service by going into Ferdi's settings and changing the "Todo server".
36You can choose any service as this Todo server, e.g. Todoist or Apple Notes.`; 40You can choose any service as this Todo server, e.g. Todoist or Apple Notes.`;
@@ -42,7 +46,7 @@ You can choose any service as this Todo server, e.g. Todoist or Apple Notes.`;
42 const textElement = document.querySelector('p'); 46 const textElement = document.querySelector('p');
43 if (textElement) { 47 if (textElement) {
44 clearInterval(waitForReact); 48 clearInterval(waitForReact);
45 textElement.parentElement.insertBefore(infoElement, textElement); 49 textElement.parentElement?.insertBefore(infoElement, textElement);
46 } else { 50 } else {
47 numChecks += 1; 51 numChecks += 1;
48 52
diff --git a/src/features/utils/ActionBinding.js b/src/features/utils/ActionBinding.ts
index 787166d44..787166d44 100644
--- a/src/features/utils/ActionBinding.js
+++ b/src/features/utils/ActionBinding.ts
diff --git a/src/features/utils/FeatureStore.js b/src/features/utils/FeatureStore.js
index 4d4e217a9..afe726294 100644
--- a/src/features/utils/FeatureStore.js
+++ b/src/features/utils/FeatureStore.js
@@ -16,11 +16,11 @@ export class FeatureStore {
16 } 16 }
17 17
18 _startActions(actions = this._actions) { 18 _startActions(actions = this._actions) {
19 actions.forEach((a) => a.start()); 19 for (const a of actions) a.start();
20 } 20 }
21 21
22 _stopActions(actions = this._actions) { 22 _stopActions(actions = this._actions) {
23 actions.forEach((a) => a.stop()); 23 for (const a of actions) a.stop();
24 } 24 }
25 25
26 // REACTIONS 26 // REACTIONS
@@ -31,10 +31,10 @@ export class FeatureStore {
31 } 31 }
32 32
33 _startReactions(reactions = this._reactions) { 33 _startReactions(reactions = this._reactions) {
34 reactions.forEach((r) => r.start()); 34 for (const r of reactions) r.start();
35 } 35 }
36 36
37 _stopReactions(reactions = this._reactions) { 37 _stopReactions(reactions = this._reactions) {
38 reactions.forEach((r) => r.stop()); 38 for (const r of reactions) r.stop();
39 } 39 }
40} 40}
diff --git a/src/features/webControls/components/WebControls.js b/src/features/webControls/components/WebControls.js
index bebf52c08..97fa20dcc 100644
--- a/src/features/webControls/components/WebControls.js
+++ b/src/features/webControls/components/WebControls.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import { Icon } from '@meetfranz/ui'; 5import { Icon } from '@meetfranz/ui';
6import { defineMessages, intlShape } from 'react-intl'; 6import { defineMessages, injectIntl } from 'react-intl';
7 7
8import { 8import {
9 mdiReload, 9 mdiReload,
@@ -16,23 +16,23 @@ import {
16const messages = defineMessages({ 16const messages = defineMessages({
17 goHome: { 17 goHome: {
18 id: 'webControls.goHome', 18 id: 'webControls.goHome',
19 defaultMessage: '!!!Home', 19 defaultMessage: 'Home',
20 }, 20 },
21 openInBrowser: { 21 openInBrowser: {
22 id: 'webControls.openInBrowser', 22 id: 'webControls.openInBrowser',
23 defaultMessage: '!!!Open in Browser', 23 defaultMessage: 'Open in Browser',
24 }, 24 },
25 back: { 25 back: {
26 id: 'webControls.back', 26 id: 'webControls.back',
27 defaultMessage: '!!!Back', 27 defaultMessage: 'Back',
28 }, 28 },
29 forward: { 29 forward: {
30 id: 'webControls.forward', 30 id: 'webControls.forward',
31 defaultMessage: '!!!Forward', 31 defaultMessage: 'Forward',
32 }, 32 },
33 reload: { 33 reload: {
34 id: 'webControls.reload', 34 id: 'webControls.reload',
35 defaultMessage: '!!!Reload', 35 defaultMessage: 'Reload',
36 }, 36 },
37}); 37});
38 38
@@ -109,10 +109,6 @@ class WebControls extends Component {
109 navigate: PropTypes.func.isRequired, 109 navigate: PropTypes.func.isRequired,
110 }; 110 };
111 111
112 static contextTypes = {
113 intl: intlShape,
114 };
115
116 static getDerivedStateFromProps(props, state) { 112 static getDerivedStateFromProps(props, state) {
117 const { url } = props; 113 const { url } = props;
118 const { editUrl } = state; 114 const { editUrl } = state;
@@ -148,7 +144,7 @@ class WebControls extends Component {
148 144
149 const { inputUrl, editUrl } = this.state; 145 const { inputUrl, editUrl } = this.state;
150 146
151 const { intl } = this.context; 147 const { intl } = this.props;
152 148
153 return ( 149 return (
154 <div className={classes.root}> 150 <div className={classes.root}>
@@ -241,4 +237,4 @@ class WebControls extends Component {
241 } 237 }
242} 238}
243 239
244export default WebControls; 240export default injectIntl(WebControls);
diff --git a/src/features/webControls/containers/WebControlsScreen.js b/src/features/webControls/containers/WebControlsScreen.js
index e1e1b9991..0273bb13e 100644
--- a/src/features/webControls/containers/WebControlsScreen.js
+++ b/src/features/webControls/containers/WebControlsScreen.js
@@ -16,7 +16,8 @@ const URL_EVENTS = [
16 'did-navigate-in-page', 16 'did-navigate-in-page',
17]; 17];
18 18
19@inject('stores', 'actions') @observer 19@inject('stores', 'actions')
20@observer
20class WebControlsScreen extends Component { 21class WebControlsScreen extends Component {
21 @observable url = ''; 22 @observable url = '';
22 23
@@ -36,15 +37,15 @@ class WebControlsScreen extends Component {
36 this.webview = service.webview; 37 this.webview = service.webview;
37 this.url = this.webview.getURL(); 38 this.url = this.webview.getURL();
38 39
39 URL_EVENTS.forEach((event) => { 40 for (const event of URL_EVENTS) {
40 this.webview.addEventListener(event, (e) => { 41 this.webview.addEventListener(event, e => {
41 if (!e.isMainFrame) return; 42 if (!e.isMainFrame) return;
42 43
43 this.url = e.url; 44 this.url = e.url;
44 this.canGoBack = this.webview.canGoBack(); 45 this.canGoBack = this.webview.canGoBack();
45 this.canGoForward = this.webview.canGoForward(); 46 this.canGoForward = this.webview.canGoForward();
46 }); 47 });
47 }); 48 }
48 } 49 }
49 }); 50 });
50 } 51 }
@@ -83,13 +84,16 @@ class WebControlsScreen extends Component {
83 84
84 try { 85 try {
85 url = new URL(url).toString(); 86 url = new URL(url).toString();
86 } catch (err) { 87 } catch {
87 // eslint-disable-next-line no-useless-escape 88 url =
88 if (url.match(/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$/)) { 89 // eslint-disable-next-line no-useless-escape
89 url = `http://${url}`; 90 /^((?!-))(xn--)?[\da-z][\d_a-z-]{0,61}[\da-z]{0,1}\.(xn--)?([\da-z\-]{1,61}|[\da-z-]{1,30}\.[a-z]{2,})$/.test(
90 } else { 91 url,
91 url = SEARCH_ENGINE_URLS[this.settings.app.searchEngine]({ searchTerm: url }); 92 )
92 } 93 ? `http://${url}`
94 : SEARCH_ENGINE_URLS[this.settings.app.searchEngine]({
95 searchTerm: url,
96 });
93 } 97 }
94 98
95 this.webview.loadURL(url); 99 this.webview.loadURL(url);
@@ -114,7 +118,7 @@ class WebControlsScreen extends Component {
114 goBack={() => this.goBack()} 118 goBack={() => this.goBack()}
115 canGoForward={this.canGoForward} 119 canGoForward={this.canGoForward}
116 goForward={() => this.goForward()} 120 goForward={() => this.goForward()}
117 navigate={(url) => this.navigate(url)} 121 navigate={url => this.navigate(url)}
118 url={this.url} 122 url={this.url}
119 /> 123 />
120 ); 124 );
diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js
deleted file mode 100644
index 5b5db422e..000000000
--- a/src/features/workspaces/actions.js
+++ /dev/null
@@ -1,27 +0,0 @@
1import PropTypes from 'prop-types';
2import Workspace from './models/Workspace';
3import { createActionsFromDefinitions } from '../../actions/lib/actions';
4
5export const workspaceActions = createActionsFromDefinitions({
6 edit: {
7 workspace: PropTypes.instanceOf(Workspace).isRequired,
8 },
9 create: {
10 name: PropTypes.string.isRequired,
11 },
12 delete: {
13 workspace: PropTypes.instanceOf(Workspace).isRequired,
14 },
15 update: {
16 workspace: PropTypes.instanceOf(Workspace).isRequired,
17 },
18 activate: {
19 workspace: PropTypes.instanceOf(Workspace).isRequired,
20 },
21 deactivate: {},
22 toggleWorkspaceDrawer: {},
23 openWorkspaceSettings: {},
24 toggleKeepAllWorkspacesLoadedSetting: {},
25}, PropTypes.checkPropTypes);
26
27export default workspaceActions;
diff --git a/src/features/workspaces/actions.ts b/src/features/workspaces/actions.ts
new file mode 100644
index 000000000..5e7e6e721
--- /dev/null
+++ b/src/features/workspaces/actions.ts
@@ -0,0 +1,30 @@
1import PropTypes from 'prop-types';
2import Workspace from './models/Workspace';
3import { createActionsFromDefinitions } from '../../actions/lib/actions';
4
5export const workspaceActions = createActionsFromDefinitions(
6 {
7 edit: {
8 workspace: PropTypes.instanceOf(Workspace).isRequired,
9 },
10 create: {
11 name: PropTypes.string.isRequired,
12 },
13 delete: {
14 workspace: PropTypes.instanceOf(Workspace).isRequired,
15 },
16 update: {
17 workspace: PropTypes.instanceOf(Workspace).isRequired,
18 },
19 activate: {
20 workspace: PropTypes.instanceOf(Workspace).isRequired,
21 },
22 deactivate: {},
23 toggleWorkspaceDrawer: {},
24 openWorkspaceSettings: {},
25 toggleKeepAllWorkspacesLoadedSetting: {},
26 },
27 PropTypes.checkPropTypes,
28);
29
30export default workspaceActions;
diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.ts
index 322695ed2..8447fc247 100644
--- a/src/features/workspaces/api.js
+++ b/src/features/workspaces/api.ts
@@ -12,12 +12,14 @@ export const workspaceApi = {
12 debug('getUserWorkspaces GET', url); 12 debug('getUserWorkspaces GET', url);
13 const result = await sendAuthRequest(url, { method: 'GET' }); 13 const result = await sendAuthRequest(url, { method: 'GET' });
14 debug('getUserWorkspaces RESULT', result); 14 debug('getUserWorkspaces RESULT', result);
15 if (!result.ok) throw result; 15 if (!result.ok) {
16 throw new Error("Couldn't getUserWorkspaces");
17 }
16 const workspaces = await result.json(); 18 const workspaces = await result.json();
17 return workspaces.map((data) => new Workspace(data)); 19 return workspaces.map(data => new Workspace(data));
18 }, 20 },
19 21
20 createWorkspace: async (name) => { 22 createWorkspace: async name => {
21 const url = `${apiBase()}/workspace`; 23 const url = `${apiBase()}/workspace`;
22 const options = { 24 const options = {
23 method: 'POST', 25 method: 'POST',
@@ -26,20 +28,24 @@ export const workspaceApi = {
26 debug('createWorkspace POST', url, options); 28 debug('createWorkspace POST', url, options);
27 const result = await sendAuthRequest(url, options); 29 const result = await sendAuthRequest(url, options);
28 debug('createWorkspace RESULT', result); 30 debug('createWorkspace RESULT', result);
29 if (!result.ok) throw result; 31 if (!result.ok) {
32 throw new Error("Couldn't createWorkspace");
33 }
30 return new Workspace(await result.json()); 34 return new Workspace(await result.json());
31 }, 35 },
32 36
33 deleteWorkspace: async (workspace) => { 37 deleteWorkspace: async workspace => {
34 const url = `${apiBase()}/workspace/${workspace.id}`; 38 const url = `${apiBase()}/workspace/${workspace.id}`;
35 debug('deleteWorkspace DELETE', url); 39 debug('deleteWorkspace DELETE', url);
36 const result = await sendAuthRequest(url, { method: 'DELETE' }); 40 const result = await sendAuthRequest(url, { method: 'DELETE' });
37 debug('deleteWorkspace RESULT', result); 41 debug('deleteWorkspace RESULT', result);
38 if (!result.ok) throw result; 42 if (!result.ok) {
43 throw new Error("Couldn't deleteWorkspace");
44 }
39 return true; 45 return true;
40 }, 46 },
41 47
42 updateWorkspace: async (workspace) => { 48 updateWorkspace: async workspace => {
43 const url = `${apiBase()}/workspace/${workspace.id}`; 49 const url = `${apiBase()}/workspace/${workspace.id}`;
44 const options = { 50 const options = {
45 method: 'PUT', 51 method: 'PUT',
@@ -48,15 +54,29 @@ export const workspaceApi = {
48 debug('updateWorkspace UPDATE', url, options); 54 debug('updateWorkspace UPDATE', url, options);
49 const result = await sendAuthRequest(url, options); 55 const result = await sendAuthRequest(url, options);
50 debug('updateWorkspace RESULT', result); 56 debug('updateWorkspace RESULT', result);
51 if (!result.ok) throw result; 57 if (!result.ok) {
58 throw new Error("Couldn't updateWorkspace");
59 }
52 return new Workspace(await result.json()); 60 return new Workspace(await result.json());
53 }, 61 },
54}; 62};
55 63
56export const getUserWorkspacesRequest = new Request(workspaceApi, 'getUserWorkspaces'); 64export const getUserWorkspacesRequest = new Request(
57export const createWorkspaceRequest = new Request(workspaceApi, 'createWorkspace'); 65 workspaceApi,
58export const deleteWorkspaceRequest = new Request(workspaceApi, 'deleteWorkspace'); 66 'getUserWorkspaces',
59export const updateWorkspaceRequest = new Request(workspaceApi, 'updateWorkspace'); 67);
68export const createWorkspaceRequest = new Request(
69 workspaceApi,
70 'createWorkspace',
71);
72export const deleteWorkspaceRequest = new Request(
73 workspaceApi,
74 'deleteWorkspace',
75);
76export const updateWorkspaceRequest = new Request(
77 workspaceApi,
78 'updateWorkspace',
79);
60 80
61export const resetApiRequests = () => { 81export const resetApiRequests = () => {
62 getUserWorkspacesRequest.reset(); 82 getUserWorkspacesRequest.reset();
diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js
index 15b97121d..c9b05b87f 100644
--- a/src/features/workspaces/components/CreateWorkspaceForm.js
+++ b/src/features/workspaces/components/CreateWorkspaceForm.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Input, Button } from '@meetfranz/forms'; 5import { Input, Button } from '@meetfranz/forms';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7import Form from '../../../lib/Form'; 7import Form from '../../../lib/Form';
@@ -11,11 +11,11 @@ import { workspaceStore } from '../index';
11const messages = defineMessages({ 11const messages = defineMessages({
12 submitButton: { 12 submitButton: {
13 id: 'settings.workspace.add.form.submitButton', 13 id: 'settings.workspace.add.form.submitButton',
14 defaultMessage: '!!!Create workspace', 14 defaultMessage: 'Create workspace',
15 }, 15 },
16 name: { 16 name: {
17 id: 'settings.workspace.add.form.name', 17 id: 'settings.workspace.add.form.name',
18 defaultMessage: '!!!Name', 18 defaultMessage: 'Name',
19 }, 19 },
20}); 20});
21 21
@@ -32,12 +32,9 @@ const styles = () => ({
32 }, 32 },
33}); 33});
34 34
35@injectSheet(styles) @observer 35@injectSheet(styles)
36@observer
36class CreateWorkspaceForm extends Component { 37class CreateWorkspaceForm extends Component {
37 static contextTypes = {
38 intl: intlShape,
39 };
40
41 static propTypes = { 38 static propTypes = {
42 classes: PropTypes.object.isRequired, 39 classes: PropTypes.object.isRequired,
43 isSubmitting: PropTypes.bool.isRequired, 40 isSubmitting: PropTypes.bool.isRequired,
@@ -45,7 +42,7 @@ class CreateWorkspaceForm extends Component {
45 }; 42 };
46 43
47 form = (() => { 44 form = (() => {
48 const { intl } = this.context; 45 const { intl } = this.props;
49 return new Form({ 46 return new Form({
50 fields: { 47 fields: {
51 name: { 48 name: {
@@ -61,7 +58,7 @@ class CreateWorkspaceForm extends Component {
61 submitForm() { 58 submitForm() {
62 const { form } = this; 59 const { form } = this;
63 form.submit({ 60 form.submit({
64 onSuccess: async (f) => { 61 onSuccess: async f => {
65 const { onSubmit } = this.props; 62 const { onSubmit } = this.props;
66 const values = f.values(); 63 const values = f.values();
67 onSubmit(values); 64 onSubmit(values);
@@ -70,7 +67,7 @@ class CreateWorkspaceForm extends Component {
70 } 67 }
71 68
72 render() { 69 render() {
73 const { intl } = this.context; 70 const { intl } = this.props;
74 const { classes, isSubmitting } = this.props; 71 const { classes, isSubmitting } = this.props;
75 const { form } = this; 72 const { form } = this;
76 return ( 73 return (
@@ -95,4 +92,4 @@ class CreateWorkspaceForm extends Component {
95 } 92 }
96} 93}
97 94
98export default CreateWorkspaceForm; 95export default injectIntl(CreateWorkspaceForm);
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js
index c97d4bd9c..f562733dd 100644
--- a/src/features/workspaces/components/EditWorkspaceForm.js
+++ b/src/features/workspaces/components/EditWorkspaceForm.js
@@ -1,7 +1,7 @@
1import React, { Component, Fragment } from 'react'; 1import React, { Component, Fragment } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router';
6import { Input, Button } from '@meetfranz/forms'; 6import { Input, Button } from '@meetfranz/forms';
7import injectSheet from 'react-jss'; 7import injectSheet from 'react-jss';
@@ -20,40 +20,40 @@ import Toggle from '../../../components/ui/Toggle';
20const messages = defineMessages({ 20const messages = defineMessages({
21 buttonDelete: { 21 buttonDelete: {
22 id: 'settings.workspace.form.buttonDelete', 22 id: 'settings.workspace.form.buttonDelete',
23 defaultMessage: '!!!Delete workspace', 23 defaultMessage: 'Delete workspace',
24 }, 24 },
25 buttonSave: { 25 buttonSave: {
26 id: 'settings.workspace.form.buttonSave', 26 id: 'settings.workspace.form.buttonSave',
27 defaultMessage: '!!!Save workspace', 27 defaultMessage: 'Save workspace',
28 }, 28 },
29 name: { 29 name: {
30 id: 'settings.workspace.form.name', 30 id: 'settings.workspace.form.name',
31 defaultMessage: '!!!Name', 31 defaultMessage: 'Name',
32 }, 32 },
33 yourWorkspaces: { 33 yourWorkspaces: {
34 id: 'settings.workspace.form.yourWorkspaces', 34 id: 'settings.workspace.form.yourWorkspaces',
35 defaultMessage: '!!!Your workspaces', 35 defaultMessage: 'Your workspaces',
36 }, 36 },
37 keepLoaded: { 37 keepLoaded: {
38 id: 'settings.workspace.form.keepLoaded', 38 id: 'settings.workspace.form.keepLoaded',
39 defaultMessage: '!!!Keep this workspace loaded*', 39 defaultMessage: 'Keep this workspace loaded*',
40 }, 40 },
41 keepLoadedInfo: { 41 keepLoadedInfo: {
42 id: 'settings.workspace.form.keepLoadedInfo', 42 id: 'settings.workspace.form.keepLoadedInfo',
43 defaultMessage: 43 defaultMessage:
44 '!!!*This option will be overwritten by the global "Keep all workspaces loaded" option.', 44 '*This option will be overwritten by the global "Keep all workspaces loaded" option.',
45 }, 45 },
46 servicesInWorkspaceHeadline: { 46 servicesInWorkspaceHeadline: {
47 id: 'settings.workspace.form.servicesInWorkspaceHeadline', 47 id: 'settings.workspace.form.servicesInWorkspaceHeadline',
48 defaultMessage: '!!!Services in this Workspace', 48 defaultMessage: 'Services in this Workspace',
49 }, 49 },
50 noServicesAdded: { 50 noServicesAdded: {
51 id: 'settings.services.noServicesAdded', 51 id: 'settings.services.noServicesAdded',
52 defaultMessage: '!!!Start by adding a service.', 52 defaultMessage: 'Start by adding a service.',
53 }, 53 },
54 discoverServices: { 54 discoverServices: {
55 id: 'settings.services.discoverServices', 55 id: 'settings.services.discoverServices',
56 defaultMessage: '!!!Discover services', 56 defaultMessage: 'Discover services',
57 }, 57 },
58}); 58});
59 59
@@ -72,10 +72,6 @@ const styles = () => ({
72@injectSheet(styles) 72@injectSheet(styles)
73@observer 73@observer
74class EditWorkspaceForm extends Component { 74class EditWorkspaceForm extends Component {
75 static contextTypes = {
76 intl: intlShape,
77 };
78
79 static propTypes = { 75 static propTypes = {
80 classes: PropTypes.object.isRequired, 76 classes: PropTypes.object.isRequired,
81 onDelete: PropTypes.func.isRequired, 77 onDelete: PropTypes.func.isRequired,
@@ -97,7 +93,7 @@ class EditWorkspaceForm extends Component {
97 } 93 }
98 94
99 prepareWorkspaceForm(workspace) { 95 prepareWorkspaceForm(workspace) {
100 const { intl } = this.context; 96 const { intl } = this.props;
101 return new Form({ 97 return new Form({
102 fields: { 98 fields: {
103 name: { 99 name: {
@@ -112,7 +108,7 @@ class EditWorkspaceForm extends Component {
112 default: false, 108 default: false,
113 }, 109 },
114 services: { 110 services: {
115 value: workspace.services.slice(), 111 value: [...workspace.services],
116 }, 112 },
117 }, 113 },
118 }); 114 });
@@ -120,7 +116,7 @@ class EditWorkspaceForm extends Component {
120 116
121 save(form) { 117 save(form) {
122 form.submit({ 118 form.submit({
123 onSuccess: async (f) => { 119 onSuccess: async f => {
124 const { onSave } = this.props; 120 const { onSave } = this.props;
125 const values = f.values(); 121 const values = f.values();
126 onSave(values); 122 onSave(values);
@@ -146,7 +142,7 @@ class EditWorkspaceForm extends Component {
146 } 142 }
147 143
148 render() { 144 render() {
149 const { intl } = this.context; 145 const { intl } = this.props;
150 const { 146 const {
151 classes, 147 classes,
152 workspace, 148 workspace,
@@ -194,7 +190,7 @@ class EditWorkspaceForm extends Component {
194 </div> 190 </div>
195 ) : ( 191 ) : (
196 <> 192 <>
197 {services.map((s) => ( 193 {services.map(s => (
198 <WorkspaceServiceListItem 194 <WorkspaceServiceListItem
199 key={s.id} 195 key={s.id}
200 service={s} 196 service={s}
@@ -233,4 +229,4 @@ class EditWorkspaceForm extends Component {
233 } 229 }
234} 230}
235 231
236export default EditWorkspaceForm; 232export default injectIntl(EditWorkspaceForm);
diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js
index 1138f23d7..3dac77bc2 100644
--- a/src/features/workspaces/components/WorkspaceDrawer.js
+++ b/src/features/workspaces/components/WorkspaceDrawer.js
@@ -2,11 +2,11 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import { defineMessages, intlShape } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import { H1, Icon } from '@meetfranz/ui'; 6import { H1, Icon } from '@meetfranz/ui';
7import ReactTooltip from 'react-tooltip'; 7import ReactTooltip from 'react-tooltip';
8 8
9import { mdiPlusBox, mdiSettings } from '@mdi/js'; 9import { mdiPlusBox, mdiCog } from '@mdi/js';
10import WorkspaceDrawerItem from './WorkspaceDrawerItem'; 10import WorkspaceDrawerItem from './WorkspaceDrawerItem';
11import { workspaceActions } from '../actions'; 11import { workspaceActions } from '../actions';
12import { workspaceStore } from '../index'; 12import { workspaceStore } from '../index';
@@ -14,27 +14,28 @@ import { workspaceStore } from '../index';
14const messages = defineMessages({ 14const messages = defineMessages({
15 headline: { 15 headline: {
16 id: 'workspaceDrawer.headline', 16 id: 'workspaceDrawer.headline',
17 defaultMessage: '!!!Workspaces', 17 defaultMessage: 'Workspaces',
18 }, 18 },
19 allServices: { 19 allServices: {
20 id: 'workspaceDrawer.allServices', 20 id: 'workspaceDrawer.allServices',
21 defaultMessage: '!!!All services', 21 defaultMessage: 'All services',
22 }, 22 },
23 workspacesSettingsTooltip: { 23 workspacesSettingsTooltip: {
24 id: 'workspaceDrawer.workspacesSettingsTooltip', 24 id: 'workspaceDrawer.workspacesSettingsTooltip',
25 defaultMessage: '!!!Workspaces settings', 25 defaultMessage: 'Edit workspaces settings',
26 }, 26 },
27 workspaceFeatureInfo: { 27 workspaceFeatureInfo: {
28 id: 'workspaceDrawer.workspaceFeatureInfo', 28 id: 'workspaceDrawer.workspaceFeatureInfo',
29 defaultMessage: '!!!Info about workspace feature', 29 defaultMessage:
30 '<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>',
30 }, 31 },
31 addNewWorkspaceLabel: { 32 addNewWorkspaceLabel: {
32 id: 'workspaceDrawer.addNewWorkspaceLabel', 33 id: 'workspaceDrawer.addNewWorkspaceLabel',
33 defaultMessage: '!!!add new workspace', 34 defaultMessage: 'Add new workspace',
34 }, 35 },
35}); 36});
36 37
37const styles = (theme) => ({ 38const styles = theme => ({
38 drawer: { 39 drawer: {
39 background: theme.workspaces.drawer.background, 40 background: theme.workspaces.drawer.background,
40 width: `${theme.workspaces.drawer.width}px`, 41 width: `${theme.workspaces.drawer.width}px`,
@@ -85,34 +86,26 @@ const styles = (theme) => ({
85 }, 86 },
86}); 87});
87 88
88@injectSheet(styles) @observer 89@injectSheet(styles)
90@observer
89class WorkspaceDrawer extends Component { 91class WorkspaceDrawer extends Component {
90 static propTypes = { 92 static propTypes = {
91 classes: PropTypes.object.isRequired, 93 classes: PropTypes.object.isRequired,
92 getServicesForWorkspace: PropTypes.func.isRequired, 94 getServicesForWorkspace: PropTypes.func.isRequired,
93 }; 95 };
94 96
95 static contextTypes = {
96 intl: intlShape,
97 };
98
99 componentDidMount() { 97 componentDidMount() {
100 ReactTooltip.rebuild(); 98 ReactTooltip.rebuild();
101 } 99 }
102 100
103 render() { 101 render() {
104 const { 102 const { classes, getServicesForWorkspace } = this.props;
105 classes, 103 const { intl } = this.props;
106 getServicesForWorkspace, 104 const { activeWorkspace, isSwitchingWorkspace, nextWorkspace, workspaces } =
107 } = this.props; 105 workspaceStore;
108 const { intl } = this.context; 106 const actualWorkspace = isSwitchingWorkspace
109 const { 107 ? nextWorkspace
110 activeWorkspace, 108 : activeWorkspace;
111 isSwitchingWorkspace,
112 nextWorkspace,
113 workspaces,
114 } = workspaceStore;
115 const actualWorkspace = isSwitchingWorkspace ? nextWorkspace : activeWorkspace;
116 return ( 109 return (
117 <div className={`${classes.drawer} workspaces-drawer`}> 110 <div className={`${classes.drawer} workspaces-drawer`}>
118 <H1 className={classes.headline}> 111 <H1 className={classes.headline}>
@@ -122,10 +115,12 @@ class WorkspaceDrawer extends Component {
122 onClick={() => { 115 onClick={() => {
123 workspaceActions.openWorkspaceSettings(); 116 workspaceActions.openWorkspaceSettings();
124 }} 117 }}
125 data-tip={`${intl.formatMessage(messages.workspacesSettingsTooltip)}`} 118 data-tip={`${intl.formatMessage(
119 messages.workspacesSettingsTooltip,
120 )}`}
126 > 121 >
127 <Icon 122 <Icon
128 icon={mdiSettings} 123 icon={mdiCog}
129 size={1.5} 124 size={1.5}
130 className={classes.workspacesSettingsButtonIcon} 125 className={classes.workspacesSettingsButtonIcon}
131 /> 126 />
@@ -152,7 +147,9 @@ class WorkspaceDrawer extends Component {
152 workspaceActions.activate({ workspace }); 147 workspaceActions.activate({ workspace });
153 workspaceActions.toggleWorkspaceDrawer(); 148 workspaceActions.toggleWorkspaceDrawer();
154 }} 149 }}
155 onContextMenuEditClick={() => workspaceActions.edit({ workspace })} 150 onContextMenuEditClick={() =>
151 workspaceActions.edit({ workspace })
152 }
156 services={getServicesForWorkspace(workspace)} 153 services={getServicesForWorkspace(workspace)}
157 shortcutIndex={index + 1} 154 shortcutIndex={index + 1}
158 /> 155 />
@@ -168,9 +165,7 @@ class WorkspaceDrawer extends Component {
168 size={1} 165 size={1}
169 className={classes.workspacesSettingsButtonIcon} 166 className={classes.workspacesSettingsButtonIcon}
170 /> 167 />
171 <span> 168 <span>{intl.formatMessage(messages.addNewWorkspaceLabel)}</span>
172 {intl.formatMessage(messages.addNewWorkspaceLabel)}
173 </span>
174 </div> 169 </div>
175 </div> 170 </div>
176 <ReactTooltip place="right" type="dark" effect="solid" /> 171 <ReactTooltip place="right" type="dark" effect="solid" />
@@ -179,4 +174,4 @@ class WorkspaceDrawer extends Component {
179 } 174 }
180} 175}
181 176
182export default WorkspaceDrawer; 177export default injectIntl(WorkspaceDrawer);
diff --git a/src/features/workspaces/components/WorkspaceDrawerItem.js b/src/features/workspaces/components/WorkspaceDrawerItem.js
index 252158364..4afb9c108 100644
--- a/src/features/workspaces/components/WorkspaceDrawerItem.js
+++ b/src/features/workspaces/components/WorkspaceDrawerItem.js
@@ -1,20 +1,20 @@
1import { Menu, getCurrentWindow } from '@electron/remote'; 1import { Menu } from '@electron/remote';
2import React, { Component } from 'react'; 2import React, { Component } from 'react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { observer } from 'mobx-react'; 4import { observer } from 'mobx-react';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7import { defineMessages, intlShape } from 'react-intl'; 7import { defineMessages, injectIntl } from 'react-intl';
8import { altKey, cmdOrCtrlShortcutKey } from '../../../environment'; 8import { altKey, cmdOrCtrlShortcutKey } from '../../../environment';
9 9
10const messages = defineMessages({ 10const messages = defineMessages({
11 noServicesAddedYet: { 11 noServicesAddedYet: {
12 id: 'workspaceDrawer.item.noServicesAddedYet', 12 id: 'workspaceDrawer.item.noServicesAddedYet',
13 defaultMessage: '!!!No services added yet', 13 defaultMessage: 'No services added yet',
14 }, 14 },
15 contextMenuEdit: { 15 contextMenuEdit: {
16 id: 'workspaceDrawer.item.contextMenuEdit', 16 id: 'workspaceDrawer.item.contextMenuEdit',
17 defaultMessage: '!!!edit', 17 defaultMessage: 'edit',
18 }, 18 },
19}); 19});
20 20
@@ -82,10 +82,6 @@ class WorkspaceDrawerItem extends Component {
82 onContextMenuEditClick: null, 82 onContextMenuEditClick: null,
83 }; 83 };
84 84
85 static contextTypes = {
86 intl: intlShape,
87 };
88
89 render() { 85 render() {
90 const { 86 const {
91 classes, 87 classes,
@@ -96,7 +92,8 @@ class WorkspaceDrawerItem extends Component {
96 services, 92 services,
97 shortcutIndex, 93 shortcutIndex,
98 } = this.props; 94 } = this.props;
99 const { intl } = this.context; 95
96 const { intl } = this.props;
100 97
101 const contextMenuTemplate = [ 98 const contextMenuTemplate = [
102 { 99 {
@@ -122,10 +119,14 @@ class WorkspaceDrawerItem extends Component {
122 ])} 119 ])}
123 onClick={onClick} 120 onClick={onClick}
124 onContextMenu={() => 121 onContextMenu={() =>
125 onContextMenuEditClick && contextMenu.popup(getCurrentWindow()) 122 onContextMenuEditClick && contextMenu.popup()
126 } 123 }
127 data-tip={`${ 124 data-tip={`${
128 shortcutIndex <= 9 ? `(${cmdOrCtrlShortcutKey(false)}+${altKey(false)}+${shortcutIndex})` : '' 125 shortcutIndex <= 9
126 ? `(${cmdOrCtrlShortcutKey(false)}+${altKey(
127 false,
128 )}+${shortcutIndex})`
129 : ''
129 }`} 130 }`}
130 > 131 >
131 <span 132 <span
@@ -142,7 +143,7 @@ class WorkspaceDrawerItem extends Component {
142 isActive ? classes.activeServices : null, 143 isActive ? classes.activeServices : null,
143 ])} 144 ])}
144 > 145 >
145 {services.length 146 {services.length > 0
146 ? services.join(', ') 147 ? services.join(', ')
147 : intl.formatMessage(messages.noServicesAddedYet)} 148 : intl.formatMessage(messages.noServicesAddedYet)}
148 </span> 149 </span>
@@ -151,4 +152,4 @@ class WorkspaceDrawerItem extends Component {
151 } 152 }
152} 153}
153 154
154export default WorkspaceDrawerItem; 155export default injectIntl(WorkspaceDrawerItem);
diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js
index 85fc02d51..ec7b19add 100644
--- a/src/features/workspaces/components/WorkspaceItem.js
+++ b/src/features/workspaces/components/WorkspaceItem.js
@@ -1,12 +1,11 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { intlShape } from 'react-intl';
4import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
5import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
6 5
7import Workspace from '../models/Workspace'; 6import Workspace from '../models/Workspace';
8 7
9const styles = (theme) => ({ 8const styles = theme => ({
10 row: { 9 row: {
11 height: theme.workspaces.settings.listItems.height, 10 height: theme.workspaces.settings.listItems.height,
12 borderBottom: `1px solid ${theme.workspaces.settings.listItems.borderColor}`, 11 borderBottom: `1px solid ${theme.workspaces.settings.listItems.borderColor}`,
@@ -17,7 +16,8 @@ const styles = (theme) => ({
17 columnName: {}, 16 columnName: {},
18}); 17});
19 18
20@injectSheet(styles) @observer 19@injectSheet(styles)
20@observer
21class WorkspaceItem extends Component { 21class WorkspaceItem extends Component {
22 static propTypes = { 22 static propTypes = {
23 classes: PropTypes.object.isRequired, 23 classes: PropTypes.object.isRequired,
@@ -25,18 +25,12 @@ class WorkspaceItem extends Component {
25 onItemClick: PropTypes.func.isRequired, 25 onItemClick: PropTypes.func.isRequired,
26 }; 26 };
27 27
28 static contextTypes = {
29 intl: intlShape,
30 };
31
32 render() { 28 render() {
33 const { classes, workspace, onItemClick } = this.props; 29 const { classes, workspace, onItemClick } = this.props;
34 30
35 return ( 31 return (
36 <tr className={classes.row}> 32 <tr className={classes.row}>
37 <td onClick={() => onItemClick(workspace)}> 33 <td onClick={() => onItemClick(workspace)}>{workspace.name}</td>
38 {workspace.name}
39 </td>
40 </tr> 34 </tr>
41 ); 35 );
42 } 36 }
diff --git a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js
index c8ec0bc4c..33a82cf4b 100644
--- a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js
+++ b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js
@@ -4,14 +4,14 @@ import { observer } from 'mobx-react';
4import injectSheet from 'react-jss'; 4import injectSheet from 'react-jss';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6import { Loader } from '@meetfranz/ui'; 6import { Loader } from '@meetfranz/ui';
7import { defineMessages, intlShape } from 'react-intl'; 7import { defineMessages, injectIntl } from 'react-intl';
8 8
9import { workspaceStore } from '../index'; 9import { workspaceStore } from '../index';
10 10
11const messages = defineMessages({ 11const messages = defineMessages({
12 switchingTo: { 12 switchingTo: {
13 id: 'workspaces.switchingIndicator.switchingTo', 13 id: 'workspaces.switchingIndicator.switchingTo',
14 defaultMessage: '!!!Switching to', 14 defaultMessage: 'Switching to',
15 }, 15 },
16}); 16});
17 17
@@ -61,13 +61,9 @@ class WorkspaceSwitchingIndicator extends Component {
61 theme: PropTypes.object.isRequired, 61 theme: PropTypes.object.isRequired,
62 }; 62 };
63 63
64 static contextTypes = {
65 intl: intlShape,
66 };
67
68 render() { 64 render() {
69 const { classes, theme } = this.props; 65 const { classes, theme } = this.props;
70 const { intl } = this.context; 66 const { intl } = this.props;
71 const { isSwitchingWorkspace, nextWorkspace } = workspaceStore; 67 const { isSwitchingWorkspace, nextWorkspace } = workspaceStore;
72 if (!isSwitchingWorkspace) return null; 68 if (!isSwitchingWorkspace) return null;
73 const nextWorkspaceName = nextWorkspace 69 const nextWorkspaceName = nextWorkspace
@@ -89,4 +85,4 @@ class WorkspaceSwitchingIndicator extends Component {
89 } 85 }
90} 86}
91 87
92export default WorkspaceSwitchingIndicator; 88export default injectIntl(WorkspaceSwitchingIndicator);
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
index 5f34204f1..49552df6b 100644
--- a/src/features/workspaces/components/WorkspacesDashboard.js
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -1,7 +1,7 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6import { Infobox } from '@meetfranz/ui'; 6import { Infobox } from '@meetfranz/ui';
7 7
@@ -16,35 +16,35 @@ import UIStore from '../../../stores/UIStore';
16const messages = defineMessages({ 16const messages = defineMessages({
17 headline: { 17 headline: {
18 id: 'settings.workspaces.headline', 18 id: 'settings.workspaces.headline',
19 defaultMessage: '!!!Your workspaces', 19 defaultMessage: 'Your workspaces',
20 }, 20 },
21 noServicesAdded: { 21 noServicesAdded: {
22 id: 'settings.workspaces.noWorkspacesAdded', 22 id: 'settings.workspaces.noWorkspacesAdded',
23 defaultMessage: "!!!You haven't created any workspaces yet.", 23 defaultMessage: "You haven't created any workspaces yet.",
24 }, 24 },
25 workspacesRequestFailed: { 25 workspacesRequestFailed: {
26 id: 'settings.workspaces.workspacesRequestFailed', 26 id: 'settings.workspaces.workspacesRequestFailed',
27 defaultMessage: '!!!Could not load your workspaces', 27 defaultMessage: 'Could not load your workspaces',
28 }, 28 },
29 tryReloadWorkspaces: { 29 tryReloadWorkspaces: {
30 id: 'settings.workspaces.tryReloadWorkspaces', 30 id: 'settings.workspaces.tryReloadWorkspaces',
31 defaultMessage: '!!!Try again', 31 defaultMessage: 'Try again',
32 }, 32 },
33 updatedInfo: { 33 updatedInfo: {
34 id: 'settings.workspaces.updatedInfo', 34 id: 'settings.workspaces.updatedInfo',
35 defaultMessage: '!!!Your changes have been saved', 35 defaultMessage: 'Your changes have been saved',
36 }, 36 },
37 deletedInfo: { 37 deletedInfo: {
38 id: 'settings.workspaces.deletedInfo', 38 id: 'settings.workspaces.deletedInfo',
39 defaultMessage: '!!!Workspace has been deleted', 39 defaultMessage: 'Workspace has been deleted',
40 }, 40 },
41 workspaceFeatureInfo: { 41 workspaceFeatureInfo: {
42 id: 'settings.workspaces.workspaceFeatureInfo', 42 id: 'settings.workspaces.workspaceFeatureInfo',
43 defaultMessage: '!!!Info about workspace feature', 43 defaultMessage: 'Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.',
44 }, 44 },
45 workspaceFeatureHeadline: { 45 workspaceFeatureHeadline: {
46 id: 'settings.workspaces.workspaceFeatureHeadline', 46 id: 'settings.workspaces.workspaceFeatureHeadline',
47 defaultMessage: '!!!Less is More: Introducing Ferdi Workspaces', 47 defaultMessage: 'Less is More: Introducing Ferdi Workspaces',
48 }, 48 },
49}); 49});
50 50
@@ -83,10 +83,6 @@ class WorkspacesDashboard extends Component {
83 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, 83 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired,
84 }; 84 };
85 85
86 static contextTypes = {
87 intl: intlShape,
88 };
89
90 render() { 86 render() {
91 const { 87 const {
92 classes, 88 classes,
@@ -99,7 +95,7 @@ class WorkspacesDashboard extends Component {
99 workspaces, 95 workspaces,
100 } = this.props; 96 } = this.props;
101 97
102 const { intl } = this.context; 98 const { intl } = this.props;
103 99
104 return ( 100 return (
105 <div className="settings__main"> 101 <div className="settings__main">
@@ -193,7 +189,7 @@ class WorkspacesDashboard extends Component {
193 } 189 }
194} 190}
195 191
196export default WorkspacesDashboard; 192export default injectIntl(WorkspacesDashboard);
197 193
198WorkspacesDashboard.wrappedComponent.propTypes = { 194WorkspacesDashboard.wrappedComponent.propTypes = {
199 stores: PropTypes.shape({ 195 stores: PropTypes.shape({
diff --git a/src/features/workspaces/constants.js b/src/features/workspaces/constants.ts
index 2d1416ee0..2d1416ee0 100644
--- a/src/features/workspaces/constants.js
+++ b/src/features/workspaces/constants.ts
diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.ts
index 83e4d9049..ecca64b41 100644
--- a/src/features/workspaces/index.js
+++ b/src/features/workspaces/index.ts
@@ -12,10 +12,8 @@ export default function initWorkspaces(stores, actions) {
12 12
13 // Toggle workspace feature 13 // Toggle workspace feature
14 reaction( 14 reaction(
15 () => ( 15 () => features.features.isWorkspaceEnabled,
16 features.features.isWorkspaceEnabled 16 isEnabled => {
17 ),
18 (isEnabled) => {
19 if (isEnabled && !workspaceStore.isFeatureActive) { 17 if (isEnabled && !workspaceStore.isFeatureActive) {
20 debug('Initializing `workspaces` feature'); 18 debug('Initializing `workspaces` feature');
21 workspaceStore.start(stores, actions); 19 workspaceStore.start(stores, actions);
diff --git a/src/features/workspaces/models/Workspace.js b/src/features/workspaces/models/Workspace.ts
index d9488e991..cd3918fba 100644
--- a/src/features/workspaces/models/Workspace.js
+++ b/src/features/workspaces/models/Workspace.ts
@@ -15,7 +15,7 @@ export default class Workspace {
15 15
16 constructor(data) { 16 constructor(data) {
17 if (!data.id) { 17 if (!data.id) {
18 throw Error('Workspace requires Id'); 18 throw new Error('Workspace requires Id');
19 } 19 }
20 20
21 this.id = data.id; 21 this.id = data.id;
@@ -28,8 +28,10 @@ export default class Workspace {
28 services.push(KEEP_WS_LOADED_USID); 28 services.push(KEEP_WS_LOADED_USID);
29 } else if (data.saving && data.services.includes(KEEP_WS_LOADED_USID)) { 29 } else if (data.saving && data.services.includes(KEEP_WS_LOADED_USID)) {
30 // Don't keep loaded 30 // Don't keep loaded
31 services = services.filter((e) => e !== KEEP_WS_LOADED_USID); 31 services = services.filter(e => e !== KEEP_WS_LOADED_USID);
32 } 32 }
33
34 // @ts-expect-error Property 'replace' does not exist on type 'never[]'.
33 this.services.replace(services); 35 this.services.replace(services);
34 36
35 this.userId = data.userId; 37 this.userId = data.userId;
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index ec9d7ee7f..db2b69f99 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -190,6 +190,12 @@ export default class WorkspacesStore extends FeatureStore {
190 setTimeout(() => { 190 setTimeout(() => {
191 this.isSwitchingWorkspace = false; 191 this.isSwitchingWorkspace = false;
192 this.nextWorkspace = null; 192 this.nextWorkspace = null;
193 if (this.stores.settings.app.splitMode) {
194 const serviceNames = new Set(this.getWorkspaceServices(workspace).map(service => service.name));
195 for (const wrapper of document.querySelectorAll('.services__webview-wrapper')) {
196 wrapper.style.display = serviceNames.has(wrapper.dataset.name) ? '' : 'none';
197 }
198 }
193 }, 1000); 199 }, 1000);
194 }; 200 };
195 201
@@ -205,6 +211,11 @@ export default class WorkspacesStore extends FeatureStore {
205 // Indicate that we are done switching to the default workspace 211 // Indicate that we are done switching to the default workspace
206 setTimeout(() => { 212 setTimeout(() => {
207 this.isSwitchingWorkspace = false; 213 this.isSwitchingWorkspace = false;
214 if (this.stores.settings.app.splitMode) {
215 for (const wrapper of document.querySelectorAll('.services__webview-wrapper')) {
216 wrapper.style.display = '';
217 }
218 }
208 }, 1000); 219 }, 1000);
209 }; 220 };
210 221
@@ -302,8 +313,8 @@ export default class WorkspacesStore extends FeatureStore {
302 const { allServicesRequest } = services; 313 const { allServicesRequest } = services;
303 const servicesHaveBeenLoaded = allServicesRequest.wasExecuted && !allServicesRequest.isError; 314 const servicesHaveBeenLoaded = allServicesRequest.wasExecuted && !allServicesRequest.isError;
304 // Loop through all workspaces and remove invalid service ids (locally) 315 // Loop through all workspaces and remove invalid service ids (locally)
305 this.workspaces.forEach((workspace) => { 316 for (const workspace of this.workspaces) {
306 workspace.services.forEach((serviceId) => { 317 for (const serviceId of workspace.services) {
307 if ( 318 if (
308 servicesHaveBeenLoaded 319 servicesHaveBeenLoaded
309 && !services.one(serviceId) 320 && !services.one(serviceId)
@@ -311,7 +322,7 @@ export default class WorkspacesStore extends FeatureStore {
311 ) { 322 ) {
312 workspace.services.remove(serviceId); 323 workspace.services.remove(serviceId);
313 } 324 }
314 }); 325 }
315 }); 326 }
316 }; 327 };
317} 328}
diff --git a/src/helpers/asar-helpers.ts b/src/helpers/asar-helpers.ts
index 3d9f0d941..9d975c193 100644
--- a/src/helpers/asar-helpers.ts
+++ b/src/helpers/asar-helpers.ts
@@ -1,3 +1,10 @@
1import { join } from 'path';
2
1export function asarPath(dir: string = '') { 3export function asarPath(dir: string = '') {
2 return dir.replace('app.asar', 'app.asar.unpacked'); 4 return dir.replace('app.asar', 'app.asar.unpacked');
3} 5}
6
7// Replacing app.asar is not beautiful but unfortunately necessary
8export function asarRecipesPath(...segments: string[]) {
9 return join(asarPath(join(__dirname, '..', 'recipes')), ...[segments].flat());
10}
diff --git a/src/helpers/i18n-helpers.ts b/src/helpers/i18n-helpers.ts
index c1f18f446..ec7dc8e98 100644
--- a/src/helpers/i18n-helpers.ts
+++ b/src/helpers/i18n-helpers.ts
@@ -4,13 +4,11 @@ export function getLocale({
4 let localeStr = locale; 4 let localeStr = locale;
5 if (locales[locale] === undefined) { 5 if (locales[locale] === undefined) {
6 let localeFuzzy: string | undefined; 6 let localeFuzzy: string | undefined;
7 Object.keys(locales).forEach((localStr) => { 7 for (const localStr of Object.keys(locales)) {
8 if (locales && Object.hasOwnProperty.call(locales, localStr)) { 8 if (locales && Object.hasOwnProperty.call(locales, localStr) && locale.slice(0, 2) === localStr.slice(0, 2)) {
9 if (locale.substring(0, 2) === localStr.substring(0, 2)) {
10 localeFuzzy = localStr; 9 localeFuzzy = localStr;
11 } 10 }
12 } 11 }
13 });
14 12
15 if (localeFuzzy !== undefined) { 13 if (localeFuzzy !== undefined) {
16 localeStr = localeFuzzy; 14 localeStr = localeFuzzy;
@@ -61,12 +59,12 @@ export function getSelectOptions({
61 if (sort) { 59 if (sort) {
62 keys = keys.sort(Intl.Collator().compare); 60 keys = keys.sort(Intl.Collator().compare);
63 } 61 }
64 keys.forEach((key) => { 62 for (const key of keys) {
65 options.push({ 63 options.push({
66 value: key, 64 value: key,
67 label: locales[key], 65 label: locales[key],
68 }); 66 });
69 }); 67 }
70 68
71 return options; 69 return options;
72} 70}
diff --git a/src/helpers/password-helpers.ts b/src/helpers/password-helpers.ts
index 89c75c752..e5d9a4a25 100644
--- a/src/helpers/password-helpers.ts
+++ b/src/helpers/password-helpers.ts
@@ -12,9 +12,9 @@ export function scorePassword(password: string) {
12 12
13 // award every unique letter until 5 repetitions 13 // award every unique letter until 5 repetitions
14 const letters = {}; 14 const letters = {};
15 for (let i = 0; i < password.length; i += 1) { 15 for (const letter of password) {
16 letters[password[i]] = (letters[password[i]] || 0) + 1; 16 letters[letter] = (letters[letter] || 0) + 1;
17 score += 5.0 / letters[password[i]]; 17 score += 5 / letters[letter];
18 } 18 }
19 19
20 // bonus points for mixing it up 20 // bonus points for mixing it up
@@ -26,11 +26,11 @@ export function scorePassword(password: string) {
26 }; 26 };
27 27
28 let variationCount = 0; 28 let variationCount = 0;
29 Object.keys(variations).forEach((key) => { 29 for (const key of Object.keys(variations)) {
30 variationCount += (variations[key] === true) ? 1 : 0; 30 variationCount += variations[key] === true ? 1 : 0;
31 }); 31 }
32 32
33 score += (variationCount - 1) * 10; 33 score += (variationCount - 1) * 10;
34 34
35 return parseInt(score.toString(), 10); 35 return Number.parseInt(score.toString(), 10);
36} 36}
diff --git a/src/helpers/recipe-helpers.ts b/src/helpers/recipe-helpers.ts
index 965429210..d482dffab 100644
--- a/src/helpers/recipe-helpers.ts
+++ b/src/helpers/recipe-helpers.ts
@@ -1,5 +1,6 @@
1/* eslint-disable global-require */
1import { parse } from 'path'; 2import { parse } from 'path';
2import { userDataRecipesPath } from '../environment'; 3import { userDataRecipesPath } from '../environment-remote';
3 4
4export function getRecipeDirectory(id: string = ''): string { 5export function getRecipeDirectory(id: string = ''): string {
5 return userDataRecipesPath(id); 6 return userDataRecipesPath(id);
@@ -15,20 +16,17 @@ export function loadRecipeConfig(recipeId: string) {
15 // Delete module from cache 16 // Delete module from cache
16 delete require.cache[require.resolve(configPath)]; 17 delete require.cache[require.resolve(configPath)];
17 18
18 // eslint-disable-next-line 19 // eslint-disable-next-line import/no-dynamic-require
19 let config = require(configPath); 20 const config = require(configPath);
20 21
21 const moduleConfigPath = require.resolve(configPath); 22 const moduleConfigPath = require.resolve(configPath);
22 config.path = parse(moduleConfigPath).dir; 23 config.path = parse(moduleConfigPath).dir;
23 24
24 return config; 25 return config;
25 } catch (e) { 26 } catch (error) {
26 console.error(e); 27 console.error(error);
27 return null; 28 return null;
28 } 29 }
29} 30}
30 31
31module.paths.unshift( 32module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory());
32 getDevRecipeDirectory(),
33 getRecipeDirectory(),
34);
diff --git a/src/helpers/schedule-helpers.ts b/src/helpers/schedule-helpers.ts
index 754fd5556..55b7c1e6f 100644
--- a/src/helpers/schedule-helpers.ts
+++ b/src/helpers/schedule-helpers.ts
@@ -5,15 +5,15 @@ export function isInTimeframe(start: string, end: string) {
5 startHourStr, 5 startHourStr,
6 startMinuteStr, 6 startMinuteStr,
7 ] = start.split(':'); 7 ] = start.split(':');
8 const startHour = parseInt(startHourStr, 10); 8 const startHour = Number.parseInt(startHourStr, 10);
9 const startMinute = parseInt(startMinuteStr, 10); 9 const startMinute = Number.parseInt(startMinuteStr, 10);
10 10
11 const [ 11 const [
12 endHourStr, 12 endHourStr,
13 endMinuteStr, 13 endMinuteStr,
14 ] = end.split(':'); 14 ] = end.split(':');
15 const endHour = parseInt(endHourStr, 10); 15 const endHour = Number.parseInt(endHourStr, 10);
16 const endMinute = parseInt(endMinuteStr, 10); 16 const endMinute = Number.parseInt(endMinuteStr, 10);
17 17
18 const currentHour = new Date().getHours(); 18 const currentHour = new Date().getHours();
19 const currentMinute = new Date().getMinutes(); 19 const currentMinute = new Date().getMinutes();
diff --git a/src/helpers/serverless-helpers.js b/src/helpers/serverless-helpers.ts
index 01549e038..01549e038 100644
--- a/src/helpers/serverless-helpers.js
+++ b/src/helpers/serverless-helpers.ts
diff --git a/src/helpers/service-helpers.js b/src/helpers/service-helpers.js
deleted file mode 100644
index 745f40dd9..000000000
--- a/src/helpers/service-helpers.js
+++ /dev/null
@@ -1,16 +0,0 @@
1import { readdirSync, removeSync } from 'fs-extra';
2import { userDataPath } from '../environment';
3
4export function getServicePartitionsDirectory(...segments) {
5 return userDataPath('Partitions', ...([segments].flat()));
6}
7
8export function removeServicePartitionDirectory(id = '', addServicePrefix = false) {
9 const servicePartition = getServicePartitionsDirectory(`${addServicePrefix ? 'service-' : ''}${id}`);
10 return removeSync(servicePartition);
11}
12
13export async function getServiceIdsFromPartitions() {
14 const files = readdirSync(getServicePartitionsDirectory());
15 return files.filter((n) => n !== '__chrome_extension');
16}
diff --git a/src/helpers/service-helpers.ts b/src/helpers/service-helpers.ts
new file mode 100644
index 000000000..678d5024f
--- /dev/null
+++ b/src/helpers/service-helpers.ts
@@ -0,0 +1,21 @@
1import { readdirSync, removeSync } from 'fs-extra';
2import { userDataPath } from '../environment-remote';
3
4export function getServicePartitionsDirectory(...segments) {
5 return userDataPath('Partitions', ...[segments].flat());
6}
7
8export function removeServicePartitionDirectory(
9 id = '',
10 addServicePrefix = false,
11) {
12 const servicePartition = getServicePartitionsDirectory(
13 `${addServicePrefix ? 'service-' : ''}${id}`,
14 );
15 return removeSync(servicePartition);
16}
17
18export async function getServiceIdsFromPartitions() {
19 const files = readdirSync(getServicePartitionsDirectory());
20 return files.filter(n => n !== '__chrome_extension');
21}
diff --git a/src/helpers/url-helpers.ts b/src/helpers/url-helpers.ts
index 3657ae693..1e87ecabb 100644
--- a/src/helpers/url-helpers.ts
+++ b/src/helpers/url-helpers.ts
@@ -12,7 +12,7 @@ export function isValidExternalURL(url: string | URL) {
12 let parsedUrl: URL; 12 let parsedUrl: URL;
13 try { 13 try {
14 parsedUrl = new URL(url.toString()); 14 parsedUrl = new URL(url.toString());
15 } catch (_) { 15 } catch {
16 return false; 16 return false;
17 } 17 }
18 18
diff --git a/src/helpers/userAgent-helpers.ts b/src/helpers/userAgent-helpers.ts
index 73c8bfd03..091a76400 100644
--- a/src/helpers/userAgent-helpers.ts
+++ b/src/helpers/userAgent-helpers.ts
@@ -8,7 +8,7 @@ import {
8function macOS() { 8function macOS() {
9 const version = macosVersion() || ''; 9 const version = macosVersion() || '';
10 let cpuName = os.cpus()[0].model.split(' ')[0]; 10 let cpuName = os.cpus()[0].model.split(' ')[0];
11 if (cpuName && cpuName.match(/\(/)) { 11 if (cpuName && /\(/.test(cpuName)) {
12 cpuName = cpuName.split('(')[0]; 12 cpuName = cpuName.split('(')[0];
13 } 13 }
14 return `Macintosh; ${cpuName} Mac OS X ${version.replace(/\./g, '_')}`; 14 return `Macintosh; ${cpuName} Mac OS X ${version.replace(/\./g, '_')}`;
diff --git a/src/helpers/validation-helpers.js b/src/helpers/validation-helpers.js
deleted file mode 100644
index 116f19905..000000000
--- a/src/helpers/validation-helpers.js
+++ /dev/null
@@ -1,67 +0,0 @@
1import { defineMessages } from 'react-intl';
2import isEmail from 'validator/lib/isEmail';
3
4const messages = defineMessages({
5 required: {
6 id: 'validation.required',
7 defaultMessage: '!!!Field is required',
8 },
9 email: {
10 id: 'validation.email',
11 defaultMessage: '!!!Email not valid',
12 },
13 url: {
14 id: 'validation.url',
15 defaultMessage: '!!!Not a valid URL',
16 },
17 minLength: {
18 id: 'validation.minLength',
19 defaultMessage: '!!!Too few characters',
20 },
21 oneRequired: {
22 id: 'validation.oneRequired',
23 defaultMessage: '!!!At least one is required',
24 },
25});
26
27export function required({ field }) {
28 const isValid = (field.value.trim() !== '');
29 return [isValid, window.ferdi.intl.formatMessage(messages.required, { field: field.label })];
30}
31
32export function email({ field }) {
33 const value = field.value.trim();
34 const isValid = isEmail(value);
35 return [isValid, window.ferdi.intl.formatMessage(messages.email, { field: field.label })];
36}
37
38export function url({ field }) {
39 const value = field.value.trim();
40 let isValid = false;
41
42 if (value !== '') {
43 // eslint-disable-next-line
44 isValid = Boolean(value.match(/(^|[\s.:;?\-\]<(])(https?:\/\/[-\w;/?:@&=+$|_.!~*|'()[\]%#,☺]+[\w/#](\(\))?)(?=$|[\s',|().:;?\-[\]>)])/i));
45 } else {
46 isValid = true;
47 }
48
49 return [isValid, window.ferdi.intl.formatMessage(messages.url, { field: field.label })];
50}
51
52export function minLength(length) {
53 return ({ field }) => {
54 let isValid = true;
55 if (field.touched) {
56 isValid = field.value.length >= length;
57 }
58 return [isValid, window.ferdi.intl.formatMessage(messages.minLength, { field: field.label, length })];
59 };
60}
61
62export function oneRequired(targets) {
63 return ({ field, form }) => {
64 const invalidFields = targets.filter((target) => form.$(target).value === '');
65 return [targets.length !== invalidFields.length, window.ferdi.intl.formatMessage(messages.required, { field: field.label })];
66 };
67}
diff --git a/src/helpers/validation-helpers.ts b/src/helpers/validation-helpers.ts
new file mode 100644
index 000000000..23c297443
--- /dev/null
+++ b/src/helpers/validation-helpers.ts
@@ -0,0 +1,96 @@
1import { defineMessages } from 'react-intl';
2import isEmail from 'validator/lib/isEmail';
3
4const messages = defineMessages({
5 required: {
6 id: 'validation.required',
7 defaultMessage: '{field} is required',
8 },
9 email: {
10 id: 'validation.email',
11 defaultMessage: '{field} is not valid',
12 },
13 url: {
14 id: 'validation.url',
15 defaultMessage: '{field} is not a valid URL',
16 },
17 minLength: {
18 id: 'validation.minLength',
19 defaultMessage: '{field} should be at least {length} characters long',
20 },
21 oneRequired: {
22 id: 'validation.oneRequired',
23 defaultMessage: 'At least one is required',
24 },
25});
26
27export function required({ field }) {
28 const isValid = field.value.trim() !== '';
29 return [
30 isValid,
31 (window as any).ferdi.intl.formatMessage(messages.required, {
32 field: field.label,
33 }),
34 ];
35}
36
37export function email({ field }) {
38 const value = field.value.trim();
39 const isValid = isEmail(value);
40 return [
41 isValid,
42 (window as any).ferdi.intl.formatMessage(messages.email, {
43 field: field.label,
44 }),
45 ];
46}
47
48export function url({ field }) {
49 const value = field.value.trim();
50 let isValid = false;
51
52 isValid =
53 value !== ''
54 ? Boolean(
55 // eslint-disable-next-line unicorn/better-regex
56 /(^|[\s.:;?\-\]<(])(https?:\/\/[-\w;/?:@&=+$|_.!~*|'()[\]%#,☺]+[\w/#](\(\))?)(?=$|[\s',|().:;?\-[\]>)])/i.test(
57 value,
58 ),
59 )
60 : true;
61
62 return [
63 isValid,
64 (window as any).ferdi.intl.formatMessage(messages.url, {
65 field: field.label,
66 }),
67 ];
68}
69
70export function minLength(length: number) {
71 return ({ field }) => {
72 let isValid = true;
73 if (field.touched) {
74 isValid = field.value.length >= length;
75 }
76 return [
77 isValid,
78 (window as any).ferdi.intl.formatMessage(messages.minLength, {
79 field: field.label,
80 length,
81 }),
82 ];
83 };
84}
85
86export function oneRequired(targets: string[]) {
87 return ({ field, form }) => {
88 const invalidFields = targets.filter(target => form.$(target).value === '');
89 return [
90 targets.length !== invalidFields.length,
91 (window as any).ferdi.intl.formatMessage(messages.required, {
92 field: field.label,
93 }),
94 ];
95 };
96}
diff --git a/src/i18n/apply-branding.js b/src/i18n/apply-branding.ts
index 40a07ded0..801a4a525 100644
--- a/src/i18n/apply-branding.js
+++ b/src/i18n/apply-branding.ts
@@ -1,13 +1,13 @@
1/** 1/**
2 * Apply Ferdi branding to i18n translations 2 * Apply Ferdi branding to i18n translations
3 */ 3 */
4const fs = require('fs-extra'); 4import fs from 'fs-extra';
5const path = require('path'); 5import path from 'path';
6 6
7console.log('Applying Ferdi branding to translations...'); 7console.log('Applying Ferdi branding to translations...');
8 8
9// Keys to ignore when applying branding 9// Keys to ignore when applying branding
10const ignore = [ 10const ignore = new Set([
11 'login.customServerSuggestion', 11 'login.customServerSuggestion',
12 'login.customServerQuestion', 12 'login.customServerQuestion',
13 'settings.app.todoServerInfo', 13 'settings.app.todoServerInfo',
@@ -18,15 +18,10 @@ const ignore = [
18 'settings.team.copy', 18 'settings.team.copy',
19 'settings.team.manageAction', 19 'settings.team.manageAction',
20 'settings.app.serverMoneyInfo', 20 'settings.app.serverMoneyInfo',
21]; 21]);
22 22
23// Files to ignore when applying branding 23// Files to ignore when applying branding
24const ignoreFiles = [ 24const ignoreFiles = new Set(['.DS_Store', '.', '..']);
25 'defaultMessages.json',
26 '.DS_Store',
27 '.',
28 '..',
29];
30 25
31// What to replace 26// What to replace
32const replace = { 27const replace = {
@@ -43,14 +38,15 @@ const replaceFind = Object.keys(replace);
43const replaceReplaceWith = Object.values(replace); 38const replaceReplaceWith = Object.values(replace);
44 39
45const replaceStr = (str, find, replaceWith) => { 40const replaceStr = (str, find, replaceWith) => {
46 for (let i = 0; i < find.length; i += 1) { 41 for (const [i, element] of find.entries()) {
47 str = str.replace(new RegExp(find[i], 'gi'), replaceWith[i]); 42 str = str.replace(new RegExp(element, 'gi'), replaceWith[i]);
48 } 43 }
49 return str; 44 return str;
50}; 45};
51 46
52files.forEach(async (file) => { 47// eslint-disable-next-line unicorn/no-array-for-each
53 if (ignoreFiles.includes(file)) return; 48files.forEach(async file => {
49 if (ignoreFiles.has(file)) return;
54 50
55 // Read locale data 51 // Read locale data
56 const filePath = path.join(locales, file); 52 const filePath = path.join(locales, file);
@@ -58,7 +54,7 @@ files.forEach(async (file) => {
58 54
59 // Replace branding 55 // Replace branding
60 for (const key in locale) { 56 for (const key in locale) {
61 if (!ignore.includes(key)) { 57 if (!ignore.has(key)) {
62 locale[key] = replaceStr(locale[key], replaceFind, replaceReplaceWith); 58 locale[key] = replaceStr(locale[key], replaceFind, replaceReplaceWith);
63 } 59 }
64 } 60 }
diff --git a/src/i18n/globalMessages.js b/src/i18n/globalMessages.ts
index 66fce8d0f..8e1df10f7 100644
--- a/src/i18n/globalMessages.js
+++ b/src/i18n/globalMessages.ts
@@ -3,75 +3,75 @@ import { defineMessages } from 'react-intl';
3export default defineMessages({ 3export default defineMessages({
4 APIUnhealthy: { 4 APIUnhealthy: {
5 id: 'global.api.unhealthy', 5 id: 'global.api.unhealthy',
6 defaultMessage: '!!!Can\'t connect to Ferdi Online Services', 6 defaultMessage: "Can't connect to Ferdi online services",
7 }, 7 },
8 notConnectedToTheInternet: { 8 notConnectedToTheInternet: {
9 id: 'global.notConnectedToTheInternet', 9 id: 'global.notConnectedToTheInternet',
10 defaultMessage: '!!!You are not connected to the internet.', 10 defaultMessage: 'You are not connected to the internet.',
11 }, 11 },
12 spellcheckerLanguage: { 12 spellcheckerLanguage: {
13 id: 'global.spellchecking.language', 13 id: 'global.spellchecking.language',
14 defaultMessage: '!!!Spell checking language', 14 defaultMessage: 'Spell checking language',
15 }, 15 },
16 spellcheckerSystemDefault: { 16 spellcheckerSystemDefault: {
17 id: 'global.spellchecker.useDefault', 17 id: 'global.spellchecker.useDefault',
18 defaultMessage: '!!!Use System Default ({default})', 18 defaultMessage: 'Use System Default ({default})',
19 }, 19 },
20 spellcheckerAutomaticDetection: { 20 spellcheckerAutomaticDetection: {
21 id: 'global.spellchecking.autodetect', 21 id: 'global.spellchecking.autodetect',
22 defaultMessage: '!!!Detect language automatically', 22 defaultMessage: 'Detect language automatically',
23 }, 23 },
24 spellcheckerAutomaticDetectionShort: { 24 spellcheckerAutomaticDetectionShort: {
25 id: 'global.spellchecking.autodetect.short', 25 id: 'global.spellchecking.autodetect.short',
26 defaultMessage: '!!!Automatic', 26 defaultMessage: 'Automatic',
27 }, 27 },
28 userAgentPref: { 28 userAgentPref: {
29 id: 'global.userAgentPref', 29 id: 'global.userAgentPref',
30 defaultMessage: '!!!User Agent', 30 defaultMessage: 'User Agent',
31 }, 31 },
32 userAgentHelp: { 32 userAgentHelp: {
33 id: 'global.userAgentHelp', 33 id: 'global.userAgentHelp',
34 defaultMessage: "!!!Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 34 defaultMessage:
35 "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
35 }, 36 },
36 yes: { 37 yes: {
37 id: 'global.yes', 38 id: 'global.yes',
38 defaultMessage: '!!!Yes', 39 defaultMessage: 'Yes',
39 }, 40 },
40 no: { 41 no: {
41 id: 'global.no', 42 id: 'global.no',
42 defaultMessage: '!!!No', 43 defaultMessage: 'No',
43 }, 44 },
44 ok: { 45 ok: {
45 id: 'global.ok', 46 id: 'global.ok',
46 defaultMessage: '!!!Ok', 47 defaultMessage: 'Ok',
47 }, 48 },
48 cancel: { 49 cancel: {
49 id: 'global.cancel', 50 id: 'global.cancel',
50 defaultMessage: '!!!Cancel', 51 defaultMessage: 'Cancel',
51 }, 52 },
52 save: { 53 save: {
53 id: 'global.save', 54 id: 'global.save',
54 defaultMessage: '!!!Save', 55 defaultMessage: 'Save',
55 }, 56 },
56 submit: { 57 submit: {
57 id: 'global.submit', 58 id: 'global.submit',
58 defaultMessage: '!!!Submit', 59 defaultMessage: 'Submit',
59 }, 60 },
60 quit: { 61 quit: {
61 id: 'global.quit', 62 id: 'global.quit',
62 defaultMessage: '!!!Quit', 63 defaultMessage: 'Quit',
63 }, 64 },
64 quitConfirmation: { 65 quitConfirmation: {
65 id: 'global.quitConfirmation', 66 id: 'global.quitConfirmation',
66 defaultMessage: 67 defaultMessage: 'Do you really want to quit Ferdi?',
67 '!!!Do you really want to quit Ferdi?',
68 }, 68 },
69 settings: { 69 settings: {
70 id: 'global.settings', 70 id: 'global.settings',
71 defaultMessage: '!!!Settings', 71 defaultMessage: 'Settings',
72 }, 72 },
73 edit: { 73 edit: {
74 id: 'global.edit', 74 id: 'global.edit',
75 defaultMessage: '!!!Edit', 75 defaultMessage: 'Edit',
76 }, 76 },
77}); 77});
diff --git a/src/i18n/languages.js b/src/i18n/languages.ts
index e7713b42b..e7713b42b 100644
--- a/src/i18n/languages.js
+++ b/src/i18n/languages.ts
diff --git a/src/i18n/locales/af.json b/src/i18n/locales/af.json
index 2c145d6f4..041b02632 100644
--- a/src/i18n/locales/af.json
+++ b/src/i18n/locales/af.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/ar.json b/src/i18n/locales/ar.json
index ae2952f86..2ab80e865 100644
--- a/src/i18n/locales/ar.json
+++ b/src/i18n/locales/ar.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "إعادة التحميل", 2 "app.errorHandler.action": "إعادة التحميل",
3 "app.errorHandler.headline": "لقد حدث خطب ما", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "خادم مخصص", 4 "changeserver.customServerLabel": "خادم مخصص",
5 "changeserver.headline": "تغيير الخادم", 5 "changeserver.headline": "تغيير الخادم",
6 "changeserver.label": "خادم", 6 "changeserver.label": "خادم",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "ماذا حدث؟", 10 "connectionLostBanner.informationLink": "ماذا حدث؟",
11 "connectionLostBanner.message": "أوه لا! Ùقد Ùردي الاتصال بـ.", 11 "connectionLostBanner.message": "أوه لا! Ùقد Ùردي الاتصال بـ.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "نشر معلومات تصحيح الأخطاء",
14 "feature.nightlyBuilds.activate": "تÙعيل", 13 "feature.nightlyBuilds.activate": "تÙعيل",
15 "feature.nightlyBuilds.info": "الإصدارات الليلية هي إصدارات تجريبية للغاية من Ùردي والتي قد تحتوي على ميزات غير مصقولة أو غير كاملة. يتم استخدام هذه الإنشاءات الليلية بشكل أساسي من قبل المطورين لاختبار ميزاتهم المطورة حديثًا وكيÙية أدائهم ÙÙŠ التصميم النهائي. إذا كنت لا تعر٠ما تÙعله ØŒ Ùنقترح عدم تنشيط الإنشاءات الليلية.", 14 "feature.nightlyBuilds.info": "الإصدارات الليلية هي إصدارات تجريبية للغاية من Ùردي والتي قد تحتوي على ميزات غير مصقولة أو غير كاملة. يتم استخدام هذه الإنشاءات الليلية بشكل أساسي من قبل المطورين لاختبار ميزاتهم المطورة حديثًا وكيÙية أدائهم ÙÙŠ التصميم النهائي. إذا كنت لا تعر٠ما تÙعله ØŒ Ùنقترح عدم تنشيط الإنشاءات الليلية.",
16 "feature.nightlyBuilds.title": "المباني الليلية", 15 "feature.nightlyBuilds.title": "المباني الليلية",
@@ -24,30 +23,30 @@
24 "feature.quickSwitch.info": "حدد خدمة من خلال زر تاب، ↑ Ùˆ ↓. اÙتح الخدمة بالظغط على زر الدخول.", 23 "feature.quickSwitch.info": "حدد خدمة من خلال زر تاب، ↑ Ùˆ ↓. اÙتح الخدمة بالظغط على زر الدخول.",
25 "feature.quickSwitch.search": "بحث...", 24 "feature.quickSwitch.search": "بحث...",
26 "feature.quickSwitch.title": "تبديل سريع", 25 "feature.quickSwitch.title": "تبديل سريع",
27 "global.api.unhealthy": "لا يمكن الإتصال بخدمات Ùردي عبر الإنترنت", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "إلغاء", 27 "global.cancel": "Cancel",
29 "global.edit": "تعديل", 28 "global.edit": "تعديل",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "أنت غير متصل بالإنترنت.", 30 "global.notConnectedToTheInternet": "أنت غير متصل بالإنترنت.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "خروج", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "الإعدادات", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "إستخدم الإعدادت الاÙتراضية ({default})", 36 "global.spellchecker.useDefault": "إستخدم الإعدادت الاÙتراضية ({default})",
38 "global.spellchecking.autodetect": "الكش٠عن اللغة تلقائياً", 37 "global.spellchecking.autodetect": "الكش٠عن اللغة تلقائياً",
39 "global.spellchecking.autodetect.short": "تلقائي", 38 "global.spellchecking.autodetect.short": "تلقائي",
40 "global.spellchecking.language": "لغة التدقيق الإملائي", 39 "global.spellchecking.language": "لغة التدقيق الإملائي",
41 "global.submit": "إرسال", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "استخدم 'https://whatmyuseragent.com/' (لاكتشاÙ) أو 'https://developers.whatismybrowser.com/useragents/explore/' (لاختار) وكيل المستخدم المنشود Ùˆ نسخه لصقه هنا.", 41 "global.userAgentHelp": "استخدم 'https://whatmyuseragent.com/' (لاكتشاÙ) أو 'https://developers.whatismybrowser.com/useragents/explore/' (لاختار) وكيل المستخدم المنشود Ùˆ نسخه لصقه هنا.",
43 "global.userAgentPref": "وكيل المستخدم", 42 "global.userAgentPref": "وكيل المستخدم",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "استيراد خدمات Ùردي الأربع", 44 "import.headline": "استيراد خدمات Ùردي الأربع",
46 "import.notSupportedHeadline": "الخدمات غير مدعومة بعد ÙÙŠ Ùردي الإصدار 5", 45 "import.notSupportedHeadline": "الخدمات غير مدعومة بعد ÙÙŠ Ùردي الإصدار 5",
47 "import.skip.label": "أريد أن أضي٠الخدمات يدوياً", 46 "import.skip.label": "أريد أن أضي٠الخدمات يدوياً",
48 "import.submit.label": "خدمات الاستيراد", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "حدثت أخطاء أثناء محاولة تنÙيذ طلب المصادقة. الرجاء محاولة تسجيل الخروج والدخول مرة أخرى إذا استمر هذا الخطأ.", 48 "infobar.authRequestFailed": "حدثت أخطاء أثناء محاولة تنÙيذ طلب المصادقة. الرجاء محاولة تسجيل الخروج والدخول مرة أخرى إذا استمر هذا الخطأ.",
50 "infobar.buttonChangelog": "ما الجديد؟", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "إعادة التشغيل وتثبيت التحديث", 50 "infobar.buttonInstallUpdate": "إعادة التشغيل وتثبيت التحديث",
52 "infobar.buttonReloadServices": "إعادة تحميل الخدمات", 51 "infobar.buttonReloadServices": "إعادة تحميل الخدمات",
53 "infobar.hide": "إخÙاء", 52 "infobar.hide": "إخÙاء",
@@ -75,7 +74,7 @@
75 "login.email.label": "البريد الإلكتروني", 74 "login.email.label": "البريد الإلكتروني",
76 "login.headline": "تسجيل الدخول", 75 "login.headline": "تسجيل الدخول",
77 "login.invalidCredentials": "البريد الإلكتروني أو كلمة المرور غير صالحة", 76 "login.invalidCredentials": "البريد الإلكتروني أو كلمة المرور غير صالحة",
78 "login.link.password": "إعادة تعيين كلمة المرور", 77 "login.link.password": "Reset password",
79 "login.link.signup": "إنشاء حساب مجاني", 78 "login.link.signup": "إنشاء حساب مجاني",
80 "login.password.label": "كلمة المرور", 79 "login.password.label": "كلمة المرور",
81 "login.serverLogout": "انتهت صلاحية جلستك، الرجاء تسجيل الدخول مرة أخرى.", 80 "login.serverLogout": "انتهت صلاحية جلستك، الرجاء تسجيل الدخول مرة أخرى.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "الدعم الÙني", 116 "menu.help.support": "الدعم الÙني",
118 "menu.help.tos": "شروط الخدمة", 117 "menu.help.tos": "شروط الخدمة",
119 "menu.services": "الخدمات", 118 "menu.services": "الخدمات",
120 "menu.services.activatePreviousService": "تÙعيل الخدمة السابقة", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "إضاÙØ© خدمة جديدة", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "الرئيسية", 121 "menu.services.goHome": "الرئيسية",
123 "menu.services.setNextServiceActive": "تÙعيل الخدمة التالية", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "المهام", 123 "menu.todos": "المهام",
125 "menu.todos.enableTodos": "تÙعيل المهام", 124 "menu.todos.enableTodos": "تÙعيل المهام",
126 "menu.view": "عرض", 125 "menu.view": "عرض",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "جميع الخدمات", 147 "menu.workspaces.defaultWorkspace": "جميع الخدمات",
149 "menu.workspaces.openWorkspaceDrawer": "Ùتح٠دÙرج٠مساحة العمل", 148 "menu.workspaces.openWorkspaceDrawer": "Ùتح٠دÙرج٠مساحة العمل",
150 "password.email.label": "البريد الإلكتروني", 149 "password.email.label": "البريد الإلكتروني",
151 "password.headline": "إعادة تعيين كلمة المرور", 150 "password.headline": "Reset password",
152 "password.link.login": "سجل الدخول لحسابك", 151 "password.link.login": "سجل الدخول لحسابك",
153 "password.link.signup": "إنشاء حساب مجاني", 152 "password.link.signup": "إنشاء حساب مجاني",
154 "password.noUser": "لم ÙŠÙعثر على Ù…Ùستخدم٠بعنوان٠البريد٠هذا", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "رجاءً تحقق من عنوان بريدك الإلكتروني", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "مزامنة٠الحساب",
157 "pricing.features.customWebsites": "إضاÙØ© مواقع مخصصة",
158 "pricing.features.desktopNotifications": "إشعارات سطح المكتب",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "اختر من بين ما يزيد على 70 خدمة",
161 "pricing.features.serviceProxies": "وكلاء الخدمة",
162 "pricing.features.spellchecker": "دعم المدقق الإملائي",
163 "pricing.features.teamManagement": "Ùريق الإدارة",
164 "pricing.features.thirdPartyServices": "تنصيب خدمات الطر٠الثالث",
165 "pricing.features.unlimitedServices": "إمكانية إضاÙØ© خدمات غير محدودة",
166 "pricing.features.workspaces": "مساحات٠العمل",
167 "service.crashHandler.action": "أعادة تحميل {name}", 155 "service.crashHandler.action": "أعادة تحميل {name}",
168 "service.crashHandler.autoReload": "محاولة الاستعادة التلقائية {name} ÙÙŠ غضون {seconds} ثانية", 156 "service.crashHandler.autoReload": "محاولة الاستعادة التلقائية {name} ÙÙŠ غضون {seconds} ثانية",
169 "service.crashHandler.headline": "أوه لا!", 157 "service.crashHandler.headline": "أوه لا!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "استخدام Ùردي بدون حساب", 170 "services.serverless": "استخدام Ùردي بدون حساب",
183 "services.welcome": "مرحبا بكم ÙÙŠ Ùردي", 171 "services.welcome": "مرحبا بكم ÙÙŠ Ùردي",
184 "settings.account.account.editButton": "تعديل الحساب", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "الحساب غير متوÙر", 173 "settings.account.accountUnavailable": "الحساب غير متوÙر",
186 "settings.account.accountUnavailableInfo": "أنت تستخدم Ùردي بدون حساب. إذا كنت ترغب ÙÙŠ استخدام Ùردي مع حساب والحÙاظ على مزامنة خدماتك عبر مختل٠الحواسيب، الرجاء تحديد خادم ÙÙŠ علامة تبويب الإعدادات ثم سجل الدخول.", 174 "settings.account.accountUnavailableInfo": "أنت تستخدم Ùردي بدون حساب. إذا كنت ترغب ÙÙŠ استخدام Ùردي مع حساب والحÙاظ على مزامنة خدماتك عبر مختل٠الحواسيب، الرجاء تحديد خادم ÙÙŠ علامة تبويب الإعدادات ثم سجل الدخول.",
187 "settings.account.buttonSave": "تحديث المل٠الشخصي", 175 "settings.account.buttonSave": "تحديث المل٠الشخصي",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "لقد تلقيت رسالة بريد إلكتروني مع رابط لتأكيد حذ٠حسابك. لا يمكن استعادة حسابك وبياناتك!", 177 "settings.account.deleteEmailSent": "لقد تلقيت رسالة بريد إلكتروني مع رابط لتأكيد حذ٠حسابك. لا يمكن استعادة حسابك وبياناتك!",
190 "settings.account.deleteInfo": "إذا كنت لا تحتاج إلى حساب Ùردي الخاص بك بعد الآن، يمكنك حذ٠حسابك وجميع البيانات ذات الصلة من هنا.", 178 "settings.account.deleteInfo": "إذا كنت لا تحتاج إلى حساب Ùردي الخاص بك بعد الآن، يمكنك حذ٠حسابك وجميع البيانات ذات الصلة من هنا.",
191 "settings.account.headline": "الحساب", 179 "settings.account.headline": "الحساب",
192 "settings.account.headlineAccount": "معلومات الحساب", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "منطقة الخطر", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "الÙواتير", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "تغيير كلمة المرور", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "تحديث المل٠الشخصي", 184 "settings.account.headlineProfile": "تحديث المل٠الشخصي",
197 "settings.account.successInfo": "تم Ø­Ùظ التغييرات الخاصة بك", 185 "settings.account.successInfo": "تم Ø­Ùظ التغييرات الخاصة بك",
198 "settings.account.tryReloadServices": "حاول مجددًا", 186 "settings.account.tryReloadServices": "حاول مجددًا",
199 "settings.account.tryReloadUserInfoRequest": "حاول مجددًا", 187 "settings.account.tryReloadUserInfoRequest": "حاول مجددًا",
200 "settings.account.userInfoRequestFailed": "تعذر تحميل معلومات المستخدم", 188 "settings.account.userInfoRequestFailed": "تعذر تحميل معلومات المستخدم",
201 "settings.account.yourLicense": "رخصة Ùردي الخاصة بك", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "مسح ذاكرة التخزين المؤقت", 191 "settings.app.buttonClearAllCache": "مسح ذاكرة التخزين المؤقت",
204 "settings.app.buttonInstallUpdate": "إعادة التشغيل وتثبيت التحديث", 192 "settings.app.buttonInstallUpdate": "إعادة التشغيل وتثبيت التحديث",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "خادم مهام مخصص", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "تÙعي٠الوضع المظلم", 211 "settings.app.form.darkMode": "تÙكي٠الوضع المظلم",
224 "settings.app.form.enableGPUAcceleration": "تÙعيل التسريع بوحدة معالجة الرسومات", 212 "settings.app.form.enableGPUAcceleration": "تÙعيل التسريع بوحدة معالجة الرسومات",
225 "settings.app.form.enableLock": "تÙعيل القÙÙ„ بكلمة المرور", 213 "settings.app.form.enableLock": "تÙعيل القÙÙ„ بكلمة المرور",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "تÙعيل التصحيح الإملائي", 215 "settings.app.form.enableSpellchecking": "تÙعيل التصحيح الإملائي",
228 "settings.app.form.enableSystemTray": "إظهار Ùردي ÙÙŠ شريط النظام", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "تÙعيل Ùردي للمهام", 217 "settings.app.form.enableTodos": "تÙعيل Ùردي للمهام",
230 "settings.app.form.hibernateOnStartup": "الإبقاء على الخدمات ÙÙŠ وضع النوم عند بدء التشغيل", 218 "settings.app.form.hibernateOnStartup": "الإبقاء على الخدمات ÙÙŠ وضع النوم عند بدء التشغيل",
231 "settings.app.form.hibernationStrategy": "استراتيجية وضع النوم", 219 "settings.app.form.hibernationStrategy": "استراتيجية وضع النوم",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "عرض تبويبات الخدمات المعطلة", 239 "settings.app.form.showDisabledServices": "عرض تبويبات الخدمات المعطلة",
252 "settings.app.form.showDragArea": "إظهار المنطقة القابلة للسحب على الناÙذة", 240 "settings.app.form.showDragArea": "إظهار المنطقة القابلة للسحب على الناÙذة",
253 "settings.app.form.showMessagesBadgesWhenMuted": "إظهار شارة رسالة غير مقروءة عند تعطيل الإشعارات", 241 "settings.app.form.showMessagesBadgesWhenMuted": "إظهار شارة رسالة غير مقروءة عند تعطيل الإشعارات",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "البدء بناÙذة مصغرة", 243 "settings.app.form.startMinimized": "البدء بناÙذة مصغرة",
255 "settings.app.form.universalDarkMode": "تمكين الوضع المظلم الكامل", 244 "settings.app.form.universalDarkMode": "تمكين الوضع المظلم الكامل",
256 "settings.app.form.useTouchIdToUnlock": "السماح باستخدام TouchID Ù„Ùتح Ùردي", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "استخدام النمط الأÙقي", 246 "settings.app.form.useVerticalStyle": "استخدام النمط الأÙقي",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "متقدم", 248 "settings.app.headlineAdvanced": "متقدم",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "الترجمات الرسمية هي الإنكليزية والألمانية. وجميع اللغات الأخرى مبنية على ترجمات مساهمين.", 256 "settings.app.languageDisclaimer": "الترجمات الرسمية هي الإنكليزية والألمانية. وجميع اللغات الأخرى مبنية على ترجمات مساهمين.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "كلمة المرور", 258 "settings.app.lockedPassword": "كلمة المرور",
270 "settings.app.lockedPasswordInfo": "الرجاء التأكد من تعيين كلمة مرور سو٠تتذكرها.\nإذما Ùقدت كلمة المرور هذه، سو٠تضطر إلى إعادة تثبيت Ùيردي.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "التغيرات تتطلب إعادة تشغيل", 260 "settings.app.restartRequired": "التغيرات تتطلب إعادة تشغيل",
272 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.", 261 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.", 262 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes", 283 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes",
295 "settings.recipes.customService.headline.customRecipes": "وصÙات طر٠ثالث مخصصة", 284 "settings.recipes.customService.headline.customRecipes": "وصÙات طر٠ثالث مخصصة",
296 "settings.recipes.customService.headline.devRecipes": "وصÙات خدمة التطوير الخاصة بك", 285 "settings.recipes.customService.headline.devRecipes": "وصÙات خدمة التطوير الخاصة بك",
297 "settings.recipes.customService.intro": "لإضاÙØ© خدمة مخصصة، انسخ وصÙØ© الخدمة إلى:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "وثائق المطور", 287 "settings.recipes.customService.openDevDocs": "وثائق المطور",
299 "settings.recipes.customService.openFolder": "Ùتح المجلد", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "الخدمات المتاحة", 289 "settings.recipes.headline": "الخدمات المتاحة",
301 "settings.recipes.missingService": "خدمة Ù…Ùقودة؟", 290 "settings.recipes.missingService": "خدمة Ù…Ùقودة؟",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "سطوع الشاشة ÙÙŠ وضع القراءة المظلم", 301 "settings.service.form.darkReaderBrightness": "سطوع الشاشة ÙÙŠ وضع القراءة المظلم",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "حذ٠الخدمة", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "تحرير {name}", 305 "settings.service.form.editServiceHeadline": "تحرير {name}",
317 "settings.service.form.enableAudio": "تمكين الصوت", 306 "settings.service.form.enableAudio": "تمكين الصوت",
318 "settings.service.form.enableBadge": "إظهار شارات الرسائل غير المقروءة", 307 "settings.service.form.enableBadge": "إظهار شارات الرسائل غير المقروءة",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "الاسم", 323 "settings.service.form.name": "الاسم",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Ùتح user.css", 326 "settings.service.form.openUserCss": "Ùتح user.css",
337 "settings.service.form.openUserJs": "Ùتح user.js", 327 "settings.service.form.openUserJs": "Ùتح user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "استخدام بروكسي", 331 "settings.service.form.proxy.isEnabled": "استخدام بروكسي",
342 "settings.service.form.proxy.password": "كلمة المرور (اختياري)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "المنÙØ°", 333 "settings.service.form.proxy.port": "المنÙØ°",
344 "settings.service.form.proxy.restartInfo": "الرجاء إعادة تشغيل Ùيردي بعد تغيير إعدادات البروكسي.", 334 "settings.service.form.proxy.restartInfo": "الرجاء إعادة تشغيل Ùيردي بعد تغيير إعدادات البروكسي.",
345 "settings.service.form.proxy.user": "المستخدم (اختياري)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Ø­Ùظ الخدمة", 337 "settings.service.form.saveButton": "Ø­Ùظ الخدمة",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "اكتش٠الخدمات", 344 "settings.services.discoverServices": "اكتش٠الخدمات",
355 "settings.services.headline": "خدماتك", 345 "settings.services.headline": "خدماتك",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "تعذرَ تحميل خدماتك", 348 "settings.services.servicesRequestFailed": "تعذرَ تحميل خدماتك",
358 "settings.services.tooltip.isDisabled": "الخدمة معطّلة", 349 "settings.services.tooltip.isDisabled": "الخدمة معطّلة",
359 "settings.services.tooltip.isMuted": "تم كتم جميع الأصوات", 350 "settings.services.tooltip.isMuted": "تم كتم جميع الأصوات",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "غير ربحي", 378 "settings.user.form.accountType.non-profit": "غير ربحي",
388 "settings.user.form.currentPassword": "الكلمة السرية الحالية", 379 "settings.user.form.currentPassword": "الكلمة السرية الحالية",
389 "settings.user.form.email": "البريد الألكتروني", 380 "settings.user.form.email": "البريد الألكتروني",
390 "settings.user.form.firstname": "الاسم الأول", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "اسم العائلة", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "كلمة سرّ جديدة", 383 "settings.user.form.newPassword": "كلمة سرّ جديدة",
393 "settings.workspace.add.form.name": "الاسم", 384 "settings.workspace.add.form.name": "الاسم",
394 "settings.workspace.add.form.submitButton": "إنشاء مساحة عمل", 385 "settings.workspace.add.form.submitButton": "إنشاء مساحة عمل",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "تمكين الإشعارات والصوت", 411 "sidebar.unmuteApp": "تمكين الإشعارات والصوت",
421 "signup.email.label": "البريد الإلكتروني", 412 "signup.email.label": "البريد الإلكتروني",
422 "signup.emailDuplicate": "مستخدم بهذا البريد الإلكتروني موجود بالÙعل", 413 "signup.emailDuplicate": "مستخدم بهذا البريد الإلكتروني موجود بالÙعل",
423 "signup.firstname.label": "الاسم الأول", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "التسجيل", 415 "signup.headline": "التسجيل",
425 "signup.lastname.label": "اسم العائلة", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "من خلال إنشاء حساب Ùيردي Ùإنك تقبل", 417 "signup.legal.info": "من خلال إنشاء حساب Ùيردي Ùإنك تقبل",
427 "signup.legal.privacy": "بيان الخصوصية", 418 "signup.legal.privacy": "بيان الخصوصية",
428 "signup.legal.terms": "بنود الخدمة", 419 "signup.legal.terms": "بنود الخدمة",
@@ -430,11 +421,11 @@
430 "signup.password.label": "كلمة المرور", 421 "signup.password.label": "كلمة المرور",
431 "signup.submit.label": "أنشئ حساب", 422 "signup.submit.label": "أنشئ حساب",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "حذ٠الخدمة", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "تعطيل الصوت", 425 "tabs.item.disableAudio": "تعطيل الصوت",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "تعطيل الإشعارات", 427 "tabs.item.disableNotifications": "تعطيل الإشعارات",
437 "tabs.item.disableService": "تعطيل الخدمة", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "تمكين الصوت", 429 "tabs.item.enableAudio": "تمكين الصوت",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "تÙعيل الإشعارات", 431 "tabs.item.enableNotification": "تÙعيل الإشعارات",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "إعادة التحميل", 434 "tabs.item.reload": "إعادة التحميل",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} غير صالح", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} يجب أن يكون على الأقل {length} حرÙاً", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} مطلوب", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} ليس عنوان URL صالح", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "الرجوع", 441 "webControls.back": "الرجوع",
451 "webControls.forward": "تقدم", 442 "webControls.forward": "تقدم",
452 "webControls.goHome": "الرئيسية", 443 "webControls.goHome": "الرئيسية",
@@ -454,12 +445,12 @@
454 "webControls.reload": "إعادة التحميل", 445 "webControls.reload": "إعادة التحميل",
455 "welcome.loginButton": "تسجيل الدخول إلى حسابك", 446 "welcome.loginButton": "تسجيل الدخول إلى حسابك",
456 "welcome.signupButton": "إنشاء حساب مجاني", 447 "welcome.signupButton": "إنشاء حساب مجاني",
457 "workspaceDrawer.addNewWorkspaceLabel": "إضاÙØ© مساحة عمل جديدة", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "جميع الخدمات", 449 "workspaceDrawer.allServices": "جميع الخدمات",
459 "workspaceDrawer.headline": "مساحات٠العمل", 450 "workspaceDrawer.headline": "مساحات٠العمل",
460 "workspaceDrawer.item.contextMenuEdit": "تعديل", 451 "workspaceDrawer.item.contextMenuEdit": "تعديل",
461 "workspaceDrawer.item.noServicesAddedYet": "لم تض٠أي خدمات بعد", 452 "workspaceDrawer.item.noServicesAddedYet": "لم تض٠أي خدمات بعد",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>ÙŠÙمكنك Ùيردي من التركيز على ما هو مهم لديك الآن. أنشاء مجموعات مختلÙØ© من الخدمات وإداراتها والتنقل بينها بسهولة ÙÙŠ أي وقت.<p><p/>أنتَ من يقرر أيّ الخدمات تحتاج ساعة تحتاج وأين تحتاج, لذا نستطيع مساعدتك لتبقى محاÙظ مع مستجدات ما تقوم به أو تستريح إن شئت.<p/>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "تعديل إعدادات مساحات العمل", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "التبديل إلى" 455 "workspaces.switchingIndicator.switchingTo": "التبديل إلى"
465} 456}
diff --git a/src/i18n/locales/be.json b/src/i18n/locales/be.json
index 31a5111a9..8caf73fe6 100644
--- a/src/i18n/locales/be.json
+++ b/src/i18n/locales/be.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Ðбнавіць", 2 "app.errorHandler.action": "Ðбнавіць",
3 "app.errorHandler.headline": "Ðешта пайшло не так", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "ПаÑлужнік", 6 "changeserver.label": "ПаÑлужнік",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/bs.json b/src/i18n/locales/bs.json
index 2c145d6f4..041b02632 100644
--- a/src/i18n/locales/bs.json
+++ b/src/i18n/locales/bs.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/ca.json b/src/i18n/locales/ca.json
index 3cb52af9b..6e33be919 100644
--- a/src/i18n/locales/ca.json
+++ b/src/i18n/locales/ca.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Recarrega", 2 "app.errorHandler.action": "Recarrega",
3 "app.errorHandler.headline": "Quelcom ha anat malament", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Servidor personalitzat", 4 "changeserver.customServerLabel": "Servidor personalitzat",
5 "changeserver.headline": "Canvía de Servidor", 5 "changeserver.headline": "Canvía de Servidor",
6 "changeserver.label": "Servidor", 6 "changeserver.label": "Servidor",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Què ha passat?", 10 "connectionLostBanner.informationLink": "Què ha passat?",
11 "connectionLostBanner.message": "Oh no! Ferdi ha perdut la connexió a {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi ha perdut la connexió a {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Registra la informació de depuració",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Seleccioneu un servei amb TAB, ↑ i ↓. Obriu un servei amb ENTER.", 23 "feature.quickSwitch.info": "Seleccioneu un servei amb TAB, ↑ i ↓. Obriu un servei amb ENTER.",
25 "feature.quickSwitch.search": "Cerca...", 24 "feature.quickSwitch.search": "Cerca...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "No es pot connectar amb els serveis en línia de Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Cancel·la", 27 "global.cancel": "Cancel",
29 "global.edit": "Edita", 28 "global.edit": "Edita",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "No esteu connectat a Internet.", 30 "global.notConnectedToTheInternet": "No esteu connectat a Internet.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Configuració", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Utilitzar el predeterminat del sistema ({default})", 36 "global.spellchecker.useDefault": "Utilitzar el predeterminat del sistema ({default})",
38 "global.spellchecking.autodetect": "Detectar l'idioma automàticament", 37 "global.spellchecking.autodetect": "Detectar l'idioma automàticament",
39 "global.spellchecking.autodetect.short": "Automàtic", 38 "global.spellchecking.autodetect.short": "Automàtic",
40 "global.spellchecking.language": "Corrector ortogràfic", 39 "global.spellchecking.language": "Corrector ortogràfic",
41 "global.submit": "Enviar", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importa els teus serveis Ferdi 4", 44 "import.headline": "Importa els teus serveis Ferdi 4",
46 "import.notSupportedHeadline": "Serveis que encara no s'admeten a Ferdi 5", 45 "import.notSupportedHeadline": "Serveis que encara no s'admeten a Ferdi 5",
47 "import.skip.label": "Vull afegir serveis manualment", 46 "import.skip.label": "Vull afegir serveis manualment",
48 "import.submit.label": "Importa serveis", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "S'han produït errors al intentar realitzar una sol·licitud autentificada. Proveu de tancar la sessió i tornar-hi si aquest error continua.", 48 "infobar.authRequestFailed": "S'han produït errors al intentar realitzar una sol·licitud autentificada. Proveu de tancar la sessió i tornar-hi si aquest error continua.",
50 "infobar.buttonChangelog": "Que hi ha de nou?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Reinicia i instal·la l'actualització", 50 "infobar.buttonInstallUpdate": "Reinicia i instal·la l'actualització",
52 "infobar.buttonReloadServices": "Recarrega els serveis", 51 "infobar.buttonReloadServices": "Recarrega els serveis",
53 "infobar.hide": "Amaga", 52 "infobar.hide": "Amaga",
@@ -75,7 +74,7 @@
75 "login.email.label": "Correu electrònic", 74 "login.email.label": "Correu electrònic",
76 "login.headline": "Accedir-hi", 75 "login.headline": "Accedir-hi",
77 "login.invalidCredentials": "El correu electrònic o la contrasenya no són vàlids", 76 "login.invalidCredentials": "El correu electrònic o la contrasenya no són vàlids",
78 "login.link.password": "Restablir la contrasenya", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Crea un compte gratuït", 78 "login.link.signup": "Crea un compte gratuït",
80 "login.password.label": "Contrasenya", 79 "login.password.label": "Contrasenya",
81 "login.serverLogout": "La teva sessió ha caducat, torna-la a iniciar.", 80 "login.serverLogout": "La teva sessió ha caducat, torna-la a iniciar.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Suport", 116 "menu.help.support": "Suport",
118 "menu.help.tos": "Condicions del Servei", 117 "menu.help.tos": "Condicions del Servei",
119 "menu.services": "Serveis", 118 "menu.services": "Serveis",
120 "menu.services.activatePreviousService": "Activa el servei anterior", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Inici", 121 "menu.services.goHome": "Inici",
123 "menu.services.setNextServiceActive": "Activa el següent servei", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Tasques", 123 "menu.todos": "Tasques",
125 "menu.todos.enableTodos": "Activar Tasques", 124 "menu.todos.enableTodos": "Activar Tasques",
126 "menu.view": "Visualitza", 125 "menu.view": "Visualitza",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Tots els serveis", 147 "menu.workspaces.defaultWorkspace": "Tots els serveis",
149 "menu.workspaces.openWorkspaceDrawer": "Obrir el calaix d'espais de treball", 148 "menu.workspaces.openWorkspaceDrawer": "Obrir el calaix d'espais de treball",
150 "password.email.label": "Correu electrònic", 149 "password.email.label": "Correu electrònic",
151 "password.headline": "Restablir la contrasenya", 150 "password.headline": "Reset password",
152 "password.link.login": "Inicia la sessió al teu compte", 151 "password.link.login": "Inicia la sessió al teu compte",
153 "password.link.signup": "Crea un compte gratuït", 152 "password.link.signup": "Crea un compte gratuït",
154 "password.noUser": "No s'ha trobat cap usuari amb aquesta adreça de correu electrònic", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Comproveu el vostre correu electrònic", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Sincronització de Conte",
157 "pricing.features.customWebsites": "Afegir llocs web personalitzats",
158 "pricing.features.desktopNotifications": "Notificacions a l'escriptori",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Espais de treball",
167 "service.crashHandler.action": "Recarrega {name}", 155 "service.crashHandler.action": "Recarrega {name}",
168 "service.crashHandler.autoReload": "Intentant restablir automàticament {name} en {seconds} segons", 156 "service.crashHandler.autoReload": "Intentant restablir automàticament {name} en {seconds} segons",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Benvingut a Ferdi", 171 "services.welcome": "Benvingut a Ferdi",
184 "settings.account.account.editButton": "Editar Compte", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Actualitzar el perfil", 175 "settings.account.buttonSave": "Actualitzar el perfil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Has rebut un correu electrònic amb un enllaç per confirmar l'eliminació del compte. El teu compte i la seva informació no podran ser restaurats!", 177 "settings.account.deleteEmailSent": "Has rebut un correu electrònic amb un enllaç per confirmar l'eliminació del compte. El teu compte i la seva informació no podran ser restaurats!",
190 "settings.account.deleteInfo": "Si ja no necessites el teu compte de Ferdi, pots esborrar el teu compte i tota la seva informació emmagatzemada aquí.", 178 "settings.account.deleteInfo": "Si ja no necessites el teu compte de Ferdi, pots esborrar el teu compte i tota la seva informació emmagatzemada aquí.",
191 "settings.account.headline": "Compte", 179 "settings.account.headline": "Compte",
192 "settings.account.headlineAccount": "Informació del compte", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Zona de perill", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Factures", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Canvia la contrasenya", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Actualitzar el perfil", 184 "settings.account.headlineProfile": "Actualitzar el perfil",
197 "settings.account.successInfo": "S'han desat els canvis", 185 "settings.account.successInfo": "S'han desat els canvis",
198 "settings.account.tryReloadServices": "Torna a provar-ho", 186 "settings.account.tryReloadServices": "Torna a provar-ho",
199 "settings.account.tryReloadUserInfoRequest": "Torna a provar-ho", 187 "settings.account.tryReloadUserInfoRequest": "Torna a provar-ho",
200 "settings.account.userInfoRequestFailed": "No s'ha pogut carregar la informació de l'usuari", 188 "settings.account.userInfoRequestFailed": "No s'ha pogut carregar la informació de l'usuari",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Buida la memòria cau", 191 "settings.app.buttonClearAllCache": "Buida la memòria cau",
204 "settings.app.buttonInstallUpdate": "Reinicia i instal·la l'actualització", 192 "settings.app.buttonInstallUpdate": "Reinicia i instal·la l'actualització",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Activar el Mode Fosc",
224 "settings.app.form.enableGPUAcceleration": "Activar acceleració GPU", 212 "settings.app.form.enableGPUAcceleration": "Activar acceleració GPU",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Habilita la comprobació ortogràfica", 215 "settings.app.form.enableSpellchecking": "Habilita la comprobació ortogràfica",
228 "settings.app.form.enableSystemTray": "Mostra Ferdi a la safata del sistema", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Mostra les pestanyes dels serveis desactivats", 239 "settings.app.form.showDisabledServices": "Mostra les pestanyes dels serveis desactivats",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Mostra la insígnia de missatges no llegits quan les notificacions estiguin desactivades", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Mostra la insígnia de missatges no llegits quan les notificacions estiguin desactivades",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Suprimeix el servei", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Edita {name}", 305 "settings.service.form.editServiceHeadline": "Edita {name}",
317 "settings.service.form.enableAudio": "Activa l'àudio", 306 "settings.service.form.enableAudio": "Activa l'àudio",
318 "settings.service.form.enableBadge": "Mostra les insígnies als missatges no llegits.", 307 "settings.service.form.enableBadge": "Mostra les insígnies als missatges no llegits.",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Quan es desactiva, tots els sons de notificació i reproducció d'àudio es silenciaran", 322 "settings.service.form.isMutedInfo": "Quan es desactiva, tots els sons de notificació i reproducció d'àudio es silenciaran",
334 "settings.service.form.name": "Nom", 323 "settings.service.form.name": "Nom",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "Ajustaments Proxy HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "Ajustaments Proxy HTTP/HTTPS",
339 "settings.service.form.proxy.host": "Host Proxy / IP", 329 "settings.service.form.proxy.host": "Host Proxy / IP",
340 "settings.service.form.proxy.info": "Els ajustaments del Proxy no es sincronitzaran amb els servidors de Ferdi", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Utilitzar Proxy", 331 "settings.service.form.proxy.isEnabled": "Utilitzar Proxy",
342 "settings.service.form.proxy.password": "Contrasenya (opcional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Siusplau, reinicieu el Ferdi després de canviar els ajustaments de proxy", 334 "settings.service.form.proxy.restartInfo": "Siusplau, reinicieu el Ferdi després de canviar els ajustaments de proxy",
345 "settings.service.form.proxy.user": "Usuari (opcional)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Desa el servei", 337 "settings.service.form.saveButton": "Desa el servei",
348 "settings.service.form.tabHosted": "Allotjat", 338 "settings.service.form.tabHosted": "Allotjat",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Descobrir serveis", 344 "settings.services.discoverServices": "Descobrir serveis",
355 "settings.services.headline": "Els vostres serveis", 345 "settings.services.headline": "Els vostres serveis",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "El servei està desactivat", 349 "settings.services.tooltip.isDisabled": "El servei està desactivat",
359 "settings.services.tooltip.isMuted": "Tots els sons estan desactivats", 350 "settings.services.tooltip.isMuted": "Tots els sons estan desactivats",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Sense ànim de lucre", 378 "settings.user.form.accountType.non-profit": "Sense ànim de lucre",
388 "settings.user.form.currentPassword": "Contrasenya actual", 379 "settings.user.form.currentPassword": "Contrasenya actual",
389 "settings.user.form.email": "Correu electrònic", 380 "settings.user.form.email": "Correu electrònic",
390 "settings.user.form.firstname": "Nom", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Cognoms", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nova contrasenya", 383 "settings.user.form.newPassword": "Nova contrasenya",
393 "settings.workspace.add.form.name": "Nom", 384 "settings.workspace.add.form.name": "Nom",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Activar notificacions i àudio", 411 "sidebar.unmuteApp": "Activar notificacions i àudio",
421 "signup.email.label": "Correu electrònic", 412 "signup.email.label": "Correu electrònic",
422 "signup.emailDuplicate": "Ja existeix un usuari amb aquesta adreça de correu electrònic", 413 "signup.emailDuplicate": "Ja existeix un usuari amb aquesta adreça de correu electrònic",
423 "signup.firstname.label": "Nom", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Donar-se d'alta", 415 "signup.headline": "Donar-se d'alta",
425 "signup.lastname.label": "Cognoms", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "En crear un compte de Ferdi, accepteu", 417 "signup.legal.info": "En crear un compte de Ferdi, accepteu",
427 "signup.legal.privacy": "Declaració de privacitat", 418 "signup.legal.privacy": "Declaració de privacitat",
428 "signup.legal.terms": "Termes del Servei", 419 "signup.legal.terms": "Termes del Servei",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Contrasenya", 421 "signup.password.label": "Contrasenya",
431 "signup.submit.label": "Crea un compte", 422 "signup.submit.label": "Crea un compte",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Suprimeix el servei", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Desactiva l'àudio", 425 "tabs.item.disableAudio": "Desactiva l'àudio",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Desactiva les notificacions", 427 "tabs.item.disableNotifications": "Desactiva les notificacions",
437 "tabs.item.disableService": "Desactiva el servei", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Activa l'àudio", 429 "tabs.item.enableAudio": "Activa l'àudio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Activa les notificacions", 431 "tabs.item.enableNotification": "Activa les notificacions",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Recarrega", 434 "tabs.item.reload": "Recarrega",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} no es vàlid", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} ha de ser al menys {length} caràcters de llargada", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} es requerit", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} es una URL no vàlida", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Enrere", 441 "webControls.back": "Enrere",
451 "webControls.forward": "Endavant", 442 "webControls.forward": "Endavant",
452 "webControls.goHome": "Inici", 443 "webControls.goHome": "Inici",
diff --git a/src/i18n/locales/cs.json b/src/i18n/locales/cs.json
index 1a82d3016..08468e307 100644
--- a/src/i18n/locales/cs.json
+++ b/src/i18n/locales/cs.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Obnovit", 2 "app.errorHandler.action": "Obnovit",
3 "app.errorHandler.headline": "Něco se pokazilo", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Vlastní server", 4 "changeserver.customServerLabel": "Vlastní server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Nemůžeme připojit Ferdi k online službám", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Zrušit", 27 "global.cancel": "Cancel",
29 "global.edit": "Upravit", 28 "global.edit": "Upravit",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Připojení k internetu není k dispozici.", 30 "global.notConnectedToTheInternet": "Připojení k internetu není k dispozici.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Nastavení", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use System Default ({default})", 36 "global.spellchecker.useDefault": "Use System Default ({default})",
38 "global.spellchecking.autodetect": "Automaticky rozpoznat jazyk", 37 "global.spellchecking.autodetect": "Automaticky rozpoznat jazyk",
39 "global.spellchecking.autodetect.short": "Automaticky", 38 "global.spellchecking.autodetect.short": "Automaticky",
40 "global.spellchecking.language": "Oprava překlepů jazyka", 39 "global.spellchecking.language": "Oprava překlepů jazyka",
41 "global.submit": "Odeslat", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importovat služby z Ferdi 4", 44 "import.headline": "Importovat služby z Ferdi 4",
46 "import.notSupportedHeadline": "Služby nejsou podporovány ve verzi Ferdi 5", 45 "import.notSupportedHeadline": "Služby nejsou podporovány ve verzi Ferdi 5",
47 "import.skip.label": "Chci pÅ™idat službu ruÄnÄ›", 46 "import.skip.label": "Chci pÅ™idat službu ruÄnÄ›",
48 "import.submit.label": "Importovat služby", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Co je nového?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restartovat a nainstalovat aktualizace", 50 "infobar.buttonInstallUpdate": "Restartovat a nainstalovat aktualizace",
52 "infobar.buttonReloadServices": "Obnovit služby", 51 "infobar.buttonReloadServices": "Obnovit služby",
53 "infobar.hide": "Skrýt", 52 "infobar.hide": "Skrýt",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-mailová adresa", 74 "login.email.label": "E-mailová adresa",
76 "login.headline": "Přihlásit se", 75 "login.headline": "Přihlásit se",
77 "login.invalidCredentials": "Email nebo heslo nesouhlasí", 76 "login.invalidCredentials": "Email nebo heslo nesouhlasí",
78 "login.link.password": "Obnovit heslo", 77 "login.link.password": "Reset password",
79 "login.link.signup": "VytvoÅ™it uživatelský úÄet zdarma", 78 "login.link.signup": "VytvoÅ™it uživatelský úÄet zdarma",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "Sezení vypršelo, je třeba se znovu přihlásit.", 80 "login.serverLogout": "Sezení vypršelo, je třeba se znovu přihlásit.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Podmínky použití", 117 "menu.help.tos": "Podmínky použití",
119 "menu.services": "Služby", 118 "menu.services": "Služby",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Všechny služby", 147 "menu.workspaces.defaultWorkspace": "Všechny služby",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "E-mailová adresa", 149 "password.email.label": "E-mailová adresa",
151 "password.headline": "Obnovit heslo", 150 "password.headline": "Reset password",
152 "password.link.login": "PÅ™ihlásit se k úÄtu", 151 "password.link.login": "PÅ™ihlásit se k úÄtu",
153 "password.link.signup": "VytvoÅ™it uživatelský úÄet zdarma", 152 "password.link.signup": "VytvoÅ™it uživatelský úÄet zdarma",
154 "password.noUser": "Pro emailovou adresu nebyl nalezený žádný uživatel", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Prosím, zkontrolujte svůj e-mail", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "NaÄíst znovu {name}", 155 "service.crashHandler.action": "NaÄíst znovu {name}",
168 "service.crashHandler.autoReload": "Pokus o automatické obnovení {name} za {seconds} sekund", 156 "service.crashHandler.autoReload": "Pokus o automatické obnovení {name} za {seconds} sekund",
169 "service.crashHandler.headline": "Ale ne!", 157 "service.crashHandler.headline": "Ale ne!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Vítejte v programu Ferdi", 171 "services.welcome": "Vítejte v programu Ferdi",
184 "settings.account.account.editButton": "Upravit úÄet", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Aktualizovat profil", 175 "settings.account.buttonSave": "Aktualizovat profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Na váš mail byl odeslán email s odkazem pro potvrzení smazání úÄtu. Váš úÄet a data poté nepůjde obnovit!", 177 "settings.account.deleteEmailSent": "Na váš mail byl odeslán email s odkazem pro potvrzení smazání úÄtu. Váš úÄet a data poté nepůjde obnovit!",
190 "settings.account.deleteInfo": "Pokud již nepotÅ™ebujete váš Ferdi úÄet, můžete zde váš úÄet, a vÅ¡echna data v nÄ›m, smazat.", 178 "settings.account.deleteInfo": "Pokud již nepotÅ™ebujete váš Ferdi úÄet, můžete zde váš úÄet, a vÅ¡echna data v nÄ›m, smazat.",
191 "settings.account.headline": "ÚÄet", 179 "settings.account.headline": "ÚÄet",
192 "settings.account.headlineAccount": "Informace o úÄtu", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "NebezpeÄná zóna", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Faktury", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Změnit heslo", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Aktualizovat profil", 184 "settings.account.headlineProfile": "Aktualizovat profil",
197 "settings.account.successInfo": "Vaše změny byly uloženy", 185 "settings.account.successInfo": "Vaše změny byly uloženy",
198 "settings.account.tryReloadServices": "Zkusit opět", 186 "settings.account.tryReloadServices": "Zkusit opět",
199 "settings.account.tryReloadUserInfoRequest": "Zkusit opět", 187 "settings.account.tryReloadUserInfoRequest": "Zkusit opět",
200 "settings.account.userInfoRequestFailed": "Nelze naÄíst informace o uživateli.", 188 "settings.account.userInfoRequestFailed": "Nelze naÄíst informace o uživateli.",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Vyprázdnit mezipaměti", 191 "settings.app.buttonClearAllCache": "Vyprázdnit mezipaměti",
204 "settings.app.buttonInstallUpdate": "Restartovat a nainstalovat aktualizace", 192 "settings.app.buttonInstallUpdate": "Restartovat a nainstalovat aktualizace",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Povolit Tmavý vzhled",
224 "settings.app.form.enableGPUAcceleration": "Aktivovat GPU zrychlení", 212 "settings.app.form.enableGPUAcceleration": "Aktivovat GPU zrychlení",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Zapnout kontrolu pravopisu", 215 "settings.app.form.enableSpellchecking": "Zapnout kontrolu pravopisu",
228 "settings.app.form.enableSystemTray": "Zobrazit Ferdi v systémové liště", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Zobrazit záložky vypnutých služeb", 239 "settings.app.form.showDisabledServices": "Zobrazit záložky vypnutých služeb",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Zobrazit odznak pro nepÅ™eÄtené zprávy když jsou upozornÄ›ní vypnutá", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Zobrazit odznak pro nepÅ™eÄtené zprávy když jsou upozornÄ›ní vypnutá",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Odstranit službu", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Upravit {name}", 305 "settings.service.form.editServiceHeadline": "Upravit {name}",
317 "settings.service.form.enableAudio": "Zapnout zvuk", 306 "settings.service.form.enableAudio": "Zapnout zvuk",
318 "settings.service.form.enableBadge": "Ukázat odznaky nepÅ™eÄtených zpráv", 307 "settings.service.form.enableBadge": "Ukázat odznaky nepÅ™eÄtených zpráv",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Pokud je vypnuto, všechny zvuky notifikací a jiného audia budou ztišeny", 322 "settings.service.form.isMutedInfo": "Pokud je vypnuto, všechny zvuky notifikací a jiného audia budou ztišeny",
334 "settings.service.form.name": "Jméno", 323 "settings.service.form.name": "Jméno",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "Nastavení HTTP/HTTPS Proxy", 328 "settings.service.form.proxy.headline": "Nastavení HTTP/HTTPS Proxy",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Objevte služby", 344 "settings.services.discoverServices": "Objevte služby",
355 "settings.services.headline": "Vaše služby", 345 "settings.services.headline": "Vaše služby",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Služba je zakázána", 349 "settings.services.tooltip.isDisabled": "Služba je zakázána",
359 "settings.services.tooltip.isMuted": "Všechny zvuky jsou ztišeny", 350 "settings.services.tooltip.isMuted": "Všechny zvuky jsou ztišeny",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Nezisková organizace", 378 "settings.user.form.accountType.non-profit": "Nezisková organizace",
388 "settings.user.form.currentPassword": "Aktuální heslo", 379 "settings.user.form.currentPassword": "Aktuální heslo",
389 "settings.user.form.email": "Email", 380 "settings.user.form.email": "Email",
390 "settings.user.form.firstname": "Jméno", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Příjmení", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nové heslo", 383 "settings.user.form.newPassword": "Nové heslo",
393 "settings.workspace.add.form.name": "Jméno", 384 "settings.workspace.add.form.name": "Jméno",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Zapnout upozornění a zvuky", 411 "sidebar.unmuteApp": "Zapnout upozornění a zvuky",
421 "signup.email.label": "E-mailová adresa", 412 "signup.email.label": "E-mailová adresa",
422 "signup.emailDuplicate": "Uživatel s touto emailovou adresou již existuje", 413 "signup.emailDuplicate": "Uživatel s touto emailovou adresou již existuje",
423 "signup.firstname.label": "Jméno", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Přihlásit se", 415 "signup.headline": "Přihlásit se",
425 "signup.lastname.label": "Příjmení", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "VytvoÅ™ením úÄtu Ferdi souhlasíte s", 417 "signup.legal.info": "VytvoÅ™ením úÄtu Ferdi souhlasíte s",
427 "signup.legal.privacy": "Prohlášení o ochraně soukromí", 418 "signup.legal.privacy": "Prohlášení o ochraně soukromí",
428 "signup.legal.terms": "Podmínky služby", 419 "signup.legal.terms": "Podmínky služby",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "VytvoÅ™it úÄet", 422 "signup.submit.label": "VytvoÅ™it úÄet",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Odstranit službu", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Vypnout zvuk", 425 "tabs.item.disableAudio": "Vypnout zvuk",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Zakázat upozornění", 427 "tabs.item.disableNotifications": "Zakázat upozornění",
437 "tabs.item.disableService": "Zakázat službu", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Zapnout zvuk", 429 "tabs.item.enableAudio": "Zapnout zvuk",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Povolit upozornění", 431 "tabs.item.enableNotification": "Povolit upozornění",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Obnovit", 434 "tabs.item.reload": "Obnovit",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} není validní", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} musí být alespoň {length} znaků dlouhé", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} je povinné", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} není validní URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Back", 441 "webControls.back": "Back",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
diff --git a/src/i18n/locales/da.json b/src/i18n/locales/da.json
index 31271cae5..9a6d0cf7e 100644
--- a/src/i18n/locales/da.json
+++ b/src/i18n/locales/da.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Genindlæs", 2 "app.errorHandler.action": "Genindlæs",
3 "app.errorHandler.headline": "Noget gik galt", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Brugerdefineret server", 4 "changeserver.customServerLabel": "Brugerdefineret server",
5 "changeserver.headline": "Skift server", 5 "changeserver.headline": "Skift server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Hvad skete der?", 10 "connectionLostBanner.informationLink": "Hvad skete der?",
11 "connectionLostBanner.message": "Ã…h nej! Ferdi mistede forbindelsen til {name}.", 11 "connectionLostBanner.message": "Ã…h nej! Ferdi mistede forbindelsen til {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Udgiv fejlfindingsoplysninger",
14 "feature.nightlyBuilds.activate": "Aktiver", 13 "feature.nightlyBuilds.activate": "Aktiver",
15 "feature.nightlyBuilds.info": "Natlige byg af Ferdi er meget eksperimentelle versioner, der kan indeholde ikke polerede eller ufærdige funktioner. Disse natlige byg bruges hovedsageligt af udviklere til at teste deres nyudviklede funktioner, og hvordan de vil opføre sig i den endelige version. Hvis du er usikker, foreslår vi ikke at aktivere natlige byg.", 14 "feature.nightlyBuilds.info": "Natlige byg af Ferdi er meget eksperimentelle versioner, der kan indeholde ikke polerede eller ufærdige funktioner. Disse natlige byg bruges hovedsageligt af udviklere til at teste deres nyudviklede funktioner, og hvordan de vil opføre sig i den endelige version. Hvis du er usikker, foreslår vi ikke at aktivere natlige byg.",
16 "feature.nightlyBuilds.title": "Natlige byg", 15 "feature.nightlyBuilds.title": "Natlige byg",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Vælg en tjeneste med TAB, ↑ og ↓. Åbn en tjeneste med ENTER.", 23 "feature.quickSwitch.info": "Vælg en tjeneste med TAB, ↑ og ↓. Åbn en tjeneste med ENTER.",
25 "feature.quickSwitch.search": "Søg...", 24 "feature.quickSwitch.search": "Søg...",
26 "feature.quickSwitch.title": "Hurtigskift", 25 "feature.quickSwitch.title": "Hurtigskift",
27 "global.api.unhealthy": "Kan ikke oprette forbindelse til Ferdi onlinetjenester", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Annuller", 27 "global.cancel": "Cancel",
29 "global.edit": "Rediger", 28 "global.edit": "Rediger",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Du har ikke forbindelse til internettet.", 30 "global.notConnectedToTheInternet": "Du har ikke forbindelse til internettet.",
@@ -33,7 +32,7 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Indstillinger", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Benyt systemstandard ({default})", 36 "global.spellchecker.useDefault": "Benyt systemstandard ({default})",
38 "global.spellchecking.autodetect": "Vælg sprog automatisk", 37 "global.spellchecking.autodetect": "Vælg sprog automatisk",
39 "global.spellchecking.autodetect.short": "Automatisk", 38 "global.spellchecking.autodetect.short": "Automatisk",
@@ -45,9 +44,9 @@
45 "import.headline": "Importer dine Ferdi 4-tjenester", 44 "import.headline": "Importer dine Ferdi 4-tjenester",
46 "import.notSupportedHeadline": "Tjenester endnu ikke understøttet i Ferdi 5", 45 "import.notSupportedHeadline": "Tjenester endnu ikke understøttet i Ferdi 5",
47 "import.skip.label": "Jeg ønsker at tilføje tjenester manuelt", 46 "import.skip.label": "Jeg ønsker at tilføje tjenester manuelt",
48 "import.submit.label": "Importer tjenester", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Der var fejl under forsøget på at udføre en godkendt anmodning. Prøv at logge ud og ind igen hvis fejlen fortsætter.", 48 "infobar.authRequestFailed": "Der var fejl under forsøget på at udføre en godkendt anmodning. Prøv at logge ud og ind igen hvis fejlen fortsætter.",
50 "infobar.buttonChangelog": "Hvad er nyt?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Genstart og installer opdatering", 50 "infobar.buttonInstallUpdate": "Genstart og installer opdatering",
52 "infobar.buttonReloadServices": "Genindlæs tjenester", 51 "infobar.buttonReloadServices": "Genindlæs tjenester",
53 "infobar.hide": "Skjul", 52 "infobar.hide": "Skjul",
@@ -75,7 +74,7 @@
75 "login.email.label": "Mailadresse", 74 "login.email.label": "Mailadresse",
76 "login.headline": "Log ind", 75 "login.headline": "Log ind",
77 "login.invalidCredentials": "Ugyldig mail eller adgangskode", 76 "login.invalidCredentials": "Ugyldig mail eller adgangskode",
78 "login.link.password": "Nulstil adgangskode", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Opret en gratis konto", 78 "login.link.signup": "Opret en gratis konto",
80 "login.password.label": "Adgangskode", 79 "login.password.label": "Adgangskode",
81 "login.serverLogout": "Din session er udløbet, log ind igen.", 80 "login.serverLogout": "Din session er udløbet, log ind igen.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Support", 116 "menu.help.support": "Support",
118 "menu.help.tos": "Servicevilkår", 117 "menu.help.tos": "Servicevilkår",
119 "menu.services": "Tjenester", 118 "menu.services": "Tjenester",
120 "menu.services.activatePreviousService": "GÃ¥ til forrige tjeneste", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Hjem", 121 "menu.services.goHome": "Hjem",
123 "menu.services.setNextServiceActive": "Gå til næste tjeneste", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Aktiver Todos", 124 "menu.todos.enableTodos": "Aktiver Todos",
126 "menu.view": "Vis", 125 "menu.view": "Vis",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Alle tjenester", 147 "menu.workspaces.defaultWorkspace": "Alle tjenester",
149 "menu.workspaces.openWorkspaceDrawer": "Ã…bn arbejdsrumspanel", 148 "menu.workspaces.openWorkspaceDrawer": "Ã…bn arbejdsrumspanel",
150 "password.email.label": "Mailadresse", 149 "password.email.label": "Mailadresse",
151 "password.headline": "Nulstil adgangskode", 150 "password.headline": "Reset password",
152 "password.link.login": "Log ind på din konto", 151 "password.link.login": "Log ind på din konto",
153 "password.link.signup": "Opret en gratis konto", 152 "password.link.signup": "Opret en gratis konto",
154 "password.noUser": "Der blev ikke fundet nogen bruger med den mailadresse", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Tjek venligst din mail", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Kontosynkronisering",
157 "pricing.features.customWebsites": "Tilføj brugerdefinerede hjemmesider",
158 "pricing.features.desktopNotifications": "Skrivebordsnotifikationer",
159 "pricing.features.onPremise": "Lokale- & andre hostede tjenester",
160 "pricing.features.recipes": "Vælg mellem mere end 70 tjenester",
161 "pricing.features.serviceProxies": "Tjeneste-proxyer",
162 "pricing.features.spellchecker": "Understøttelse af stavekontrol",
163 "pricing.features.teamManagement": "Teamhåndtering",
164 "pricing.features.thirdPartyServices": "Installer tredjeparts tjenester",
165 "pricing.features.unlimitedServices": "Tilføj ubegrænsede tjenester",
166 "pricing.features.workspaces": "Arbejdsrum",
167 "service.crashHandler.action": "Genindlæs {name}", 155 "service.crashHandler.action": "Genindlæs {name}",
168 "service.crashHandler.autoReload": "Forsøger automatisk at gendanne {name} om {seconds} sekunder", 156 "service.crashHandler.autoReload": "Forsøger automatisk at gendanne {name} om {seconds} sekunder",
169 "service.crashHandler.headline": "Ã…h nej!", 157 "service.crashHandler.headline": "Ã…h nej!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Brug Ferdi uden en konto", 170 "services.serverless": "Brug Ferdi uden en konto",
183 "services.welcome": "Velkommen til Ferdi", 171 "services.welcome": "Velkommen til Ferdi",
184 "settings.account.account.editButton": "Rediger konto", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Konto utilgængelig", 173 "settings.account.accountUnavailable": "Konto utilgængelig",
186 "settings.account.accountUnavailableInfo": "Du bruger Ferdi uden en konto. Hvis du ønsker at bruge Ferdi med en konto og holde dine tjenester synkroniseret på tværs af enheder, vælg en server under fanen Indstillinger, og log derefter ind.", 174 "settings.account.accountUnavailableInfo": "Du bruger Ferdi uden en konto. Hvis du ønsker at bruge Ferdi med en konto og holde dine tjenester synkroniseret på tværs af enheder, vælg en server under fanen Indstillinger, og log derefter ind.",
187 "settings.account.buttonSave": "Opdater profil", 175 "settings.account.buttonSave": "Opdater profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Du har modtaget en mail med et link til at bekræfte sletning af din konto. Din konto og data kan ikke gendannes!", 177 "settings.account.deleteEmailSent": "Du har modtaget en mail med et link til at bekræfte sletning af din konto. Din konto og data kan ikke gendannes!",
190 "settings.account.deleteInfo": "Hvis du ikke længere har brug for din Ferdi-konto, kan du slette den og alle relaterede data her.", 178 "settings.account.deleteInfo": "Hvis du ikke længere har brug for din Ferdi-konto, kan du slette den og alle relaterede data her.",
191 "settings.account.headline": "Konto", 179 "settings.account.headline": "Konto",
192 "settings.account.headlineAccount": "Kontooplysninger", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Farezone", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Fakturaer", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Skift adgangskode", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Opdater profil", 184 "settings.account.headlineProfile": "Opdater profil",
197 "settings.account.successInfo": "Dine ændringer er blevet gemt", 185 "settings.account.successInfo": "Dine ændringer er blevet gemt",
198 "settings.account.tryReloadServices": "Prøv igen", 186 "settings.account.tryReloadServices": "Prøv igen",
199 "settings.account.tryReloadUserInfoRequest": "Prøv igen", 187 "settings.account.tryReloadUserInfoRequest": "Prøv igen",
200 "settings.account.userInfoRequestFailed": "Kunne ikke indlæse brugerinformation", 188 "settings.account.userInfoRequestFailed": "Kunne ikke indlæse brugerinformation",
201 "settings.account.yourLicense": "Din Ferdi-licens", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Ryd cache", 191 "settings.app.buttonClearAllCache": "Ryd cache",
204 "settings.app.buttonInstallUpdate": "Genstart og installer opdatering", 192 "settings.app.buttonInstallUpdate": "Genstart og installer opdatering",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Luk Ferdi til systembakken", 208 "settings.app.form.closeToSystemTray": "Luk Ferdi til systembakken",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Brugerdefineret Todo server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Aktiver mørk tilstand", 211 "settings.app.form.darkMode": "Aktiver mørk tilstand",
224 "settings.app.form.enableGPUAcceleration": "Aktiver GPU-acceleration", 212 "settings.app.form.enableGPUAcceleration": "Aktiver GPU-acceleration",
225 "settings.app.form.enableLock": "Aktiver adgangskodelås", 213 "settings.app.form.enableLock": "Aktiver adgangskodelås",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Aktiver stavekontrol", 215 "settings.app.form.enableSpellchecking": "Aktiver stavekontrol",
228 "settings.app.form.enableSystemTray": "Vis Ferdi i systembakken", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Aktiver Ferdi Todos", 217 "settings.app.form.enableTodos": "Aktiver Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Sæt tjenester i dvale ved opstart", 218 "settings.app.form.hibernateOnStartup": "Sæt tjenester i dvale ved opstart",
231 "settings.app.form.hibernationStrategy": "Dvale strategi", 219 "settings.app.form.hibernationStrategy": "Dvale strategi",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Vis faneblade for deaktiverede tjenester", 239 "settings.app.form.showDisabledServices": "Vis faneblade for deaktiverede tjenester",
252 "settings.app.form.showDragArea": "Vis trækområde i vinduet", 240 "settings.app.form.showDragArea": "Vis trækområde i vinduet",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Vis ulæst beskedikon når notifikationer er deaktiveret", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Vis ulæst beskedikon når notifikationer er deaktiveret",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimeret", 243 "settings.app.form.startMinimized": "Start minimeret",
255 "settings.app.form.universalDarkMode": "Aktiver universel mørk tilstand", 244 "settings.app.form.universalDarkMode": "Aktiver universel mørk tilstand",
256 "settings.app.form.useTouchIdToUnlock": "Tillad brug af TouchID for at låse Ferdi op", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Avanceret", 248 "settings.app.headlineAdvanced": "Avanceret",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Officielle oversættelser er engelske og tyske. Alle andre sprog er fællesskabsstyrede oversættelser.", 256 "settings.app.languageDisclaimer": "Officielle oversættelser er engelske og tyske. Alle andre sprog er fællesskabsstyrede oversættelser.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Adgangskode", 258 "settings.app.lockedPassword": "Adgangskode",
270 "settings.app.lockedPasswordInfo": "Sørg for at angive en adgangskode, du husker.\nHvis du mister denne adgangskode, vil du blive nødt til at geninstallere Ferdi.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Ændringer kræver genstart", 260 "settings.app.restartRequired": "Ændringer kræver genstart",
272 "settings.app.scheduledDNDInfo": "Planlagt Forstyr ikke giver dig mulighed for at definere et tidsrum, hvor du ikke ønsker at få meddelelser fra Ferdi.", 261 "settings.app.scheduledDNDInfo": "Planlagt Forstyr ikke giver dig mulighed for at definere et tidsrum, hvor du ikke ønsker at få meddelelser fra Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Tider er i 24-timer format. Sluttidspunktet kan være før starttidspunktet (f.eks. fra 17:00 til 09:00) for at aktivere Forstyr ikke natten over.", 262 "settings.app.scheduledDNDTimeInfo": "Tider er i 24-timer format. Sluttidspunktet kan være før starttidspunktet (f.eks. fra 17:00 til 09:00) for at aktivere Forstyr ikke natten over.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi bruger din Macs indbyggede stavekontrol. Hvis du ønsker at ændre de sprog, stavekontrollen kontrollerer for, kan du gøre det i din Macs systemindstillinger.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi bruger din Macs indbyggede stavekontrol. Hvis du ønsker at ændre de sprog, stavekontrollen kontrollerer for, kan du gøre det i din Macs systemindstillinger.",
276 "settings.app.subheadlineCache": "Cache", 265 "settings.app.subheadlineCache": "Cache",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Denne server vil blive brugt til funktionen \"Ferdi Todo\".", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Hjælp os med at oversætte Ferdi til dit sprog.", 268 "settings.app.translationHelp": "Hjælp os med at oversætte Ferdi til dit sprog.",
280 "settings.app.universalDarkModeInfo": "Universel mørk tilstand forsøger at dynamisk generere mørk tilstand stilarter for tjenester, der ellers ikke er understøttet.", 269 "settings.app.universalDarkModeInfo": "Universel mørk tilstand forsøger at dynamisk generere mørk tilstand stilarter for tjenester, der ellers ikke er understøttet.",
281 "settings.app.updateStatusAvailable": "Opdatering tilgængelig, downloader...", 270 "settings.app.updateStatusAvailable": "Opdatering tilgængelig, downloader...",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Fællesskabstyrede Tredjepartsopskrifter", 283 "settings.recipes.customService.headline.communityRecipes": "Fællesskabstyrede Tredjepartsopskrifter",
295 "settings.recipes.customService.headline.customRecipes": "Brugerdefinerede Tredjepartsopskrifter", 284 "settings.recipes.customService.headline.customRecipes": "Brugerdefinerede Tredjepartsopskrifter",
296 "settings.recipes.customService.headline.devRecipes": "Dine Udviklingsopskrifter", 285 "settings.recipes.customService.headline.devRecipes": "Dine Udviklingsopskrifter",
297 "settings.recipes.customService.intro": "For at tilføje en brugerdefineret tjeneste, kopier tjenestens opskrift til:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Udvikler Dokumentation", 287 "settings.recipes.customService.openDevDocs": "Udvikler Dokumentation",
299 "settings.recipes.customService.openFolder": "Ã…bn mappe", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Tilgængelige tjenester", 289 "settings.recipes.headline": "Tilgængelige tjenester",
301 "settings.recipes.missingService": "Mangler du en service?", 290 "settings.recipes.missingService": "Mangler du en service?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Mørk læser lysstyrke", 301 "settings.service.form.darkReaderBrightness": "Mørk læser lysstyrke",
313 "settings.service.form.darkReaderContrast": "Mørk læser kontrast", 302 "settings.service.form.darkReaderContrast": "Mørk læser kontrast",
314 "settings.service.form.darkReaderSepia": "Mørk læser sepia", 303 "settings.service.form.darkReaderSepia": "Mørk læser sepia",
315 "settings.service.form.deleteButton": "Slet tjeneste", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Rediger {name}", 305 "settings.service.form.editServiceHeadline": "Rediger {name}",
317 "settings.service.form.enableAudio": "Aktiver lyd", 306 "settings.service.form.enableAudio": "Aktiver lyd",
318 "settings.service.form.enableBadge": "Vis ulæste beskedbadges", 307 "settings.service.form.enableBadge": "Vis ulæste beskedbadges",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Når deaktiveret, er alle notifikationslyde og lydafspilning slået fra", 322 "settings.service.form.isMutedInfo": "Når deaktiveret, er alle notifikationslyde og lydafspilning slået fra",
334 "settings.service.form.name": "Navn", 323 "settings.service.form.name": "Navn",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Ã…bn darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Ã…bn darkmode.css",
336 "settings.service.form.openUserCss": "Ã…bn user.css", 326 "settings.service.form.openUserCss": "Ã…bn user.css",
337 "settings.service.form.openUserJs": "Ã…bn user.js", 327 "settings.service.form.openUserJs": "Ã…bn user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS proxyindstillinger", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS proxyindstillinger",
339 "settings.service.form.proxy.host": "Proxy vært/IP", 329 "settings.service.form.proxy.host": "Proxy vært/IP",
340 "settings.service.form.proxy.info": "Proxyindstillinger synkroniseres ikke med Ferdi serverne.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Brug Proxy", 331 "settings.service.form.proxy.isEnabled": "Brug Proxy",
342 "settings.service.form.proxy.password": "Adgangskode (valgfri)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Genstart Ferdi efter ændring af proxyindstillinger.", 334 "settings.service.form.proxy.restartInfo": "Genstart Ferdi efter ændring af proxyindstillinger.",
345 "settings.service.form.proxy.user": "Bruger (valgfri)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Dine brugerfiler vil blive indsat i websiden, så du kan tilpasse tjenester lige som du ønsker. Brugerfiler gemmes kun lokalt og overføres ikke til andre enheder der bruger samme konto.", 336 "settings.service.form.recipeFileInfo": "Dine brugerfiler vil blive indsat i websiden, så du kan tilpasse tjenester lige som du ønsker. Brugerfiler gemmes kun lokalt og overføres ikke til andre enheder der bruger samme konto.",
347 "settings.service.form.saveButton": "Gem service", 337 "settings.service.form.saveButton": "Gem service",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Opdag tjenester", 344 "settings.services.discoverServices": "Opdag tjenester",
355 "settings.services.headline": "Dine tjenester", 345 "settings.services.headline": "Dine tjenester",
356 "settings.services.noServicesAdded": "Start med at tilføje en tjeneste.", 346 "settings.services.noServicesAdded": "Start med at tilføje en tjeneste.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Kunne ikke indlæse dine tjenester", 348 "settings.services.servicesRequestFailed": "Kunne ikke indlæse dine tjenester",
358 "settings.services.tooltip.isDisabled": "Tjenesten er deaktiveret", 349 "settings.services.tooltip.isDisabled": "Tjenesten er deaktiveret",
359 "settings.services.tooltip.isMuted": "Alle lyde er slået fra", 350 "settings.services.tooltip.isMuted": "Alle lyde er slået fra",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi er et \"open source\" og fællesskabsstyret program.</p><p>Tak til de personer, der gør dette muligt:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi er et \"open source\" og fællesskabsstyret program.</p><p>Tak til de personer, der gør dette muligt:</p>",
363 "settings.supportFerdi.bannerText": "Vil du hjælpe os med at forbedre Ferdi?", 354 "settings.supportFerdi.bannerText": "Vil du hjælpe os med at forbedre Ferdi?",
364 "settings.supportFerdi.headline": "Om Ferdi", 355 "settings.supportFerdi.headline": "Om Ferdi",
365 "settings.supportFerdi.openSurvey": "Åbn undersøgelse", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "Hvis du har lyst til at støtte Ferdi's udviklere med en donation, kan du gøre det på både,", 357 "settings.supportFerdi.textDonation": "Hvis du har lyst til at støtte Ferdi's udviklere med en donation, kan du gøre det på både,",
367 "settings.supportFerdi.textDonationAnd": "og", 358 "settings.supportFerdi.textDonationAnd": "og",
368 "settings.supportFerdi.textExpenses": "Omend frivillige gør det meste af arbejdet, er vi stadig nødt til at betale for servere og certifikater. Som et fællesskab er vi fuldt ud gennemsigtige med hensyn til de midler, vi indsamler og bruger - se vores", 359 "settings.supportFerdi.textExpenses": "Omend frivillige gør det meste af arbejdet, er vi stadig nødt til at betale for servere og certifikater. Som et fællesskab er vi fuldt ud gennemsigtige med hensyn til de midler, vi indsamler og bruger - se vores",
369 "settings.supportFerdi.textGitHubSponsors": "GitHub Sponsors", 360 "settings.supportFerdi.textGitHubSponsors": "GitHub Sponsors",
370 "settings.supportFerdi.textListContributors": "Fuld liste over bidragsydere", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "her", 362 "settings.supportFerdi.textListContributorsHere": "her",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Støtte er altid velkommen. Du kan finde en liste over den hjælp, vi har brug for", 364 "settings.supportFerdi.textSupportWelcome": "Støtte er altid velkommen. Du kan finde en liste over den hjælp, vi har brug for",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Nonprofit", 378 "settings.user.form.accountType.non-profit": "Nonprofit",
388 "settings.user.form.currentPassword": "Nuværende adgangskode", 379 "settings.user.form.currentPassword": "Nuværende adgangskode",
389 "settings.user.form.email": "Mailadresse", 380 "settings.user.form.email": "Mailadresse",
390 "settings.user.form.firstname": "Fornavn", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Efternavn", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Ny adgangskode", 383 "settings.user.form.newPassword": "Ny adgangskode",
393 "settings.workspace.add.form.name": "Navn", 384 "settings.workspace.add.form.name": "Navn",
394 "settings.workspace.add.form.submitButton": "Opret arbejdsrum", 385 "settings.workspace.add.form.submitButton": "Opret arbejdsrum",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Prøv igen", 396 "settings.workspaces.tryReloadWorkspaces": "Prøv igen",
406 "settings.workspaces.updatedInfo": "Dine ændringer er blevet gemt", 397 "settings.workspaces.updatedInfo": "Dine ændringer er blevet gemt",
407 "settings.workspaces.workspaceFeatureHeadline": "Mindre er mere: Introducerer Ferdi arbejdsrum", 398 "settings.workspaces.workspaceFeatureHeadline": "Mindre er mere: Introducerer Ferdi arbejdsrum",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdi Arbejdsrum lader dig fokusere på, hvad der er vigtigt lige nu. Konfigurer forskellige sæt af tjenester og skift nemt mellem dem til enhver tid. Du bestemmer hvilke tjenester du har brug for hvor og hvornår, så vi kan hjælpe dig med at holde dig på toppen - eller nemt lukke ned for arbejdet, når du vil.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Kunne ikke indlæse dine arbejdsrum", 400 "settings.workspaces.workspacesRequestFailed": "Kunne ikke indlæse dine arbejdsrum",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Aktiver notifikationer og lyd", 411 "sidebar.unmuteApp": "Aktiver notifikationer og lyd",
421 "signup.email.label": "Mailadresse", 412 "signup.email.label": "Mailadresse",
422 "signup.emailDuplicate": "Der findes allerede en bruger med den mailadresse", 413 "signup.emailDuplicate": "Der findes allerede en bruger med den mailadresse",
423 "signup.firstname.label": "Fornavn", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Tilmeld dig", 415 "signup.headline": "Tilmeld dig",
425 "signup.lastname.label": "Efternavn", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Ved at oprette en Ferdi konto accepterer du", 417 "signup.legal.info": "Ved at oprette en Ferdi konto accepterer du",
427 "signup.legal.privacy": "Privatlivspolitik", 418 "signup.legal.privacy": "Privatlivspolitik",
428 "signup.legal.terms": "Servicevilkårene", 419 "signup.legal.terms": "Servicevilkårene",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Adgangskode", 421 "signup.password.label": "Adgangskode",
431 "signup.submit.label": "Opret konto", 422 "signup.submit.label": "Opret konto",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Slet tjeneste", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Deaktiver lyd", 425 "tabs.item.disableAudio": "Deaktiver lyd",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Deaktiver notifikationer", 427 "tabs.item.disableNotifications": "Deaktiver notifikationer",
437 "tabs.item.disableService": "Deaktiver tjeneste", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Aktiver lyd", 429 "tabs.item.enableAudio": "Aktiver lyd",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Aktiver notifikationer", 431 "tabs.item.enableNotification": "Aktiver notifikationer",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Genindlæs", 434 "tabs.item.reload": "Genindlæs",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} er ugyldigt", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} skal være på mindst {length} tegn", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Mindst én er påkrævet", 438 "validation.oneRequired": "Mindst én er påkrævet",
448 "validation.required": "{field} er obligatorisk", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} er ikke en gyldig URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Tilbage", 441 "webControls.back": "Tilbage",
451 "webControls.forward": "Fremad", 442 "webControls.forward": "Fremad",
452 "webControls.goHome": "Hjem", 443 "webControls.goHome": "Hjem",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Genindlæs", 445 "webControls.reload": "Genindlæs",
455 "welcome.loginButton": "Log ind på din konto", 446 "welcome.loginButton": "Log ind på din konto",
456 "welcome.signupButton": "Opret en gratis konto", 447 "welcome.signupButton": "Opret en gratis konto",
457 "workspaceDrawer.addNewWorkspaceLabel": "Tilføj nyt arbejdsrum", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Alle tjenester", 449 "workspaceDrawer.allServices": "Alle tjenester",
459 "workspaceDrawer.headline": "Arbejdsrum", 450 "workspaceDrawer.headline": "Arbejdsrum",
460 "workspaceDrawer.item.contextMenuEdit": "rediger", 451 "workspaceDrawer.item.contextMenuEdit": "rediger",
461 "workspaceDrawer.item.noServicesAddedYet": "Ingen tjenester tilføjet endnu", 452 "workspaceDrawer.item.noServicesAddedYet": "Ingen tjenester tilføjet endnu",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Arbejdsrum lader dig fokusere på, hvad der er vigtigt lige nu. Konfigurer forskellige sæt af tjenester og skift nemt mellem dem til enhver tid.</p>\n<p>Du bestemmer hvilke tjenester du har brug for hvor og hvornår, så vi kan hjælpe dig med at holde dig på toppen - eller nemt lukke ned for arbejdet, når du vil.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Rediger indstillinger for arbejdsrum", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Skifter til" 455 "workspaces.switchingIndicator.switchingTo": "Skifter til"
465} 456}
diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json
index 1deee8e54..0baa4cf5e 100644
--- a/src/i18n/locales/de.json
+++ b/src/i18n/locales/de.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Neu laden", 2 "app.errorHandler.action": "Neu laden",
3 "app.errorHandler.headline": "Es ist ein Fehler aufgetreten", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Eigener Server", 4 "changeserver.customServerLabel": "Eigener Server",
5 "changeserver.headline": "Server wechseln", 5 "changeserver.headline": "Server wechseln",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Was ist passiert?", 10 "connectionLostBanner.informationLink": "Was ist passiert?",
11 "connectionLostBanner.message": "Oh nein! Ferdi hat die Verbindung zu {name} verloren.", 11 "connectionLostBanner.message": "Oh nein! Ferdi hat die Verbindung zu {name} verloren.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Debug-Informationen veröffentlichen",
14 "feature.nightlyBuilds.activate": "Aktivieren", 13 "feature.nightlyBuilds.activate": "Aktivieren",
15 "feature.nightlyBuilds.info": "Nightly builds sind experimentelle Versionen von Ferdi die unfertige Funktionen enthalten kann. Nightly builds werden hauptsächlich von Entwicklern genutzt um neu entwickelte Features zu testen und zu sehen wie sie sich in der finalen Version verhalten. Wenn du nicht genau weisst was du tust, empfehlen wir dir Nightly Builds nicht zu aktivieren.", 14 "feature.nightlyBuilds.info": "Nightly builds sind experimentelle Versionen von Ferdi die unfertige Funktionen enthalten kann. Nightly builds werden hauptsächlich von Entwicklern genutzt um neu entwickelte Features zu testen und zu sehen wie sie sich in der finalen Version verhalten. Wenn du nicht genau weisst was du tust, empfehlen wir dir Nightly Builds nicht zu aktivieren.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Wähle einen Service mit TAB, ↑ und ↓. Um einen Service zu öffnen, drücke ENTER.", 23 "feature.quickSwitch.info": "Wähle einen Service mit TAB, ↑ und ↓. Um einen Service zu öffnen, drücke ENTER.",
25 "feature.quickSwitch.search": "Suchen...", 24 "feature.quickSwitch.search": "Suchen...",
26 "feature.quickSwitch.title": "Schnellauswahl", 25 "feature.quickSwitch.title": "Schnellauswahl",
27 "global.api.unhealthy": "Verbindung zu den Ferdi Online Services fehlgeschlagen", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Abbrechen", 27 "global.cancel": "Cancel",
29 "global.edit": "Bearbeiten", 28 "global.edit": "Bearbeiten",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Du bist nicht mit dem Internet verbunden.", 30 "global.notConnectedToTheInternet": "Du bist nicht mit dem Internet verbunden.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Einstellungen", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Standard benutzen ({default})", 36 "global.spellchecker.useDefault": "Standard benutzen ({default})",
38 "global.spellchecking.autodetect": "Sprache automatisch erkennen", 37 "global.spellchecking.autodetect": "Sprache automatisch erkennen",
39 "global.spellchecking.autodetect.short": "Automatisch", 38 "global.spellchecking.autodetect.short": "Automatisch",
40 "global.spellchecking.language": "Sprache für Rechtschreibprüfung", 39 "global.spellchecking.language": "Sprache für Rechtschreibprüfung",
41 "global.submit": "Absenden", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Benutze 'https://whatmyuseragent.com/' (für das Entdecken) oder 'https://developers.whatismybrowser.com/useragents/explore/' (für die Wahl) deines gewünschten User Agenten und kopiere ihn hier hinein.", 41 "global.userAgentHelp": "Benutze 'https://whatmyuseragent.com/' (für das Entdecken) oder 'https://developers.whatismybrowser.com/useragents/explore/' (für die Wahl) deines gewünschten User Agenten und kopiere ihn hier hinein.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Deine Ferdi-4-Dienste importieren", 44 "import.headline": "Deine Ferdi-4-Dienste importieren",
46 "import.notSupportedHeadline": "Dienste, die noch nicht von Ferdi 5 unterstützt werden", 45 "import.notSupportedHeadline": "Dienste, die noch nicht von Ferdi 5 unterstützt werden",
47 "import.skip.label": "Ich möchte Dienste selbst hinzufügen", 46 "import.skip.label": "Ich möchte Dienste selbst hinzufügen",
48 "import.submit.label": "Dienste importieren", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Es sind Fehler während einem authentifizierten Anfrage an den Ferdi Server aufgetreten. Sollte dieser Fehler bestehen, logge dich bitte aus und wieder ein.", 48 "infobar.authRequestFailed": "Es sind Fehler während einem authentifizierten Anfrage an den Ferdi Server aufgetreten. Sollte dieser Fehler bestehen, logge dich bitte aus und wieder ein.",
50 "infobar.buttonChangelog": "Was gibt es Neues?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Neu starten & Update installieren", 50 "infobar.buttonInstallUpdate": "Neu starten & Update installieren",
52 "infobar.buttonReloadServices": "Dienste neu laden", 51 "infobar.buttonReloadServices": "Dienste neu laden",
53 "infobar.hide": "Ausblenden", 52 "infobar.hide": "Ausblenden",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-Mail-Adresse", 74 "login.email.label": "E-Mail-Adresse",
76 "login.headline": "Anmelden", 75 "login.headline": "Anmelden",
77 "login.invalidCredentials": "E-Mail-Adresse oder Passwort ungültig", 76 "login.invalidCredentials": "E-Mail-Adresse oder Passwort ungültig",
78 "login.link.password": "Passwort zurücksetzen", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Kostenloses Konto erstellen", 78 "login.link.signup": "Kostenloses Konto erstellen",
80 "login.password.label": "Passwort", 79 "login.password.label": "Passwort",
81 "login.serverLogout": "Deine Sitzung ist abgelaufen, bitte melde Dich erneut an.", 80 "login.serverLogout": "Deine Sitzung ist abgelaufen, bitte melde Dich erneut an.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Hilfe", 116 "menu.help.support": "Hilfe",
118 "menu.help.tos": "Nutzungsbedingungen", 117 "menu.help.tos": "Nutzungsbedingungen",
119 "menu.services": "Dienste", 118 "menu.services": "Dienste",
120 "menu.services.activatePreviousService": "Vorheriger Dienst", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Neuen Dienst hinzufügen", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Startseite", 121 "menu.services.goHome": "Startseite",
123 "menu.services.setNextServiceActive": "Nächster Dienst", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Todos aktivieren", 124 "menu.todos.enableTodos": "Todos aktivieren",
126 "menu.view": "Darstellung", 125 "menu.view": "Darstellung",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Alle Dienste", 147 "menu.workspaces.defaultWorkspace": "Alle Dienste",
149 "menu.workspaces.openWorkspaceDrawer": "Workspaces schließen", 148 "menu.workspaces.openWorkspaceDrawer": "Workspaces schließen",
150 "password.email.label": "E-Mail-Adresse", 149 "password.email.label": "E-Mail-Adresse",
151 "password.headline": "Passwort zurücksetzen", 150 "password.headline": "Reset password",
152 "password.link.login": "Mit deinem Konto anmelden", 151 "password.link.login": "Mit deinem Konto anmelden",
153 "password.link.signup": "Kostenloses Konto erstellen", 152 "password.link.signup": "Kostenloses Konto erstellen",
154 "password.noUser": "Es wurde kein Benutzer mit dieser E-Mail-Adresse gefunden", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Wir haben Dir eine E-Mail mit weiteren Anweisungen geschickt", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Konto-Synchronisierung",
157 "pricing.features.customWebsites": "Hinzufügen von eigenen Websites",
158 "pricing.features.desktopNotifications": "Desktop Benachrichtigungen",
159 "pricing.features.onPremise": "On-premise & andere Hosted Services",
160 "pricing.features.recipes": "Wählen Sie aus mehr als 70 Diensten",
161 "pricing.features.serviceProxies": "Service-Proxies",
162 "pricing.features.spellchecker": "Rechtschreibprüfung",
163 "pricing.features.teamManagement": "Team-Management",
164 "pricing.features.thirdPartyServices": "Integration von Services über Drittanbieter",
165 "pricing.features.unlimitedServices": "Unbegrenztes hinzufügen von Services",
166 "pricing.features.workspaces": "Arbeitsbereiche",
167 "service.crashHandler.action": "{name} neu laden", 155 "service.crashHandler.action": "{name} neu laden",
168 "service.crashHandler.autoReload": "{name} wird in {seconds} Sekunden automatisch wiederhergestellt", 156 "service.crashHandler.autoReload": "{name} wird in {seconds} Sekunden automatisch wiederhergestellt",
169 "service.crashHandler.headline": "Oh nein!", 157 "service.crashHandler.headline": "Oh nein!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Ferdi ohne ein Konto verwenden", 170 "services.serverless": "Ferdi ohne ein Konto verwenden",
183 "services.welcome": "Willkommen bei Ferdi!", 171 "services.welcome": "Willkommen bei Ferdi!",
184 "settings.account.account.editButton": "Konto bearbeiten", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Konto nicht verfügbar", 173 "settings.account.accountUnavailable": "Konto nicht verfügbar",
186 "settings.account.accountUnavailableInfo": "Du verwendest Ferdi ohne ein Konto. Wenn du Ferdi mit einem Konto verwenden möchtest und deine Dienste über alle verschiedene Computer hinweg synchronisieren möchtest, wählen bitte einen Server in den Einstellungen und melde dich danach an.", 174 "settings.account.accountUnavailableInfo": "Du verwendest Ferdi ohne ein Konto. Wenn du Ferdi mit einem Konto verwenden möchtest und deine Dienste über alle verschiedene Computer hinweg synchronisieren möchtest, wählen bitte einen Server in den Einstellungen und melde dich danach an.",
187 "settings.account.buttonSave": "Profil aktualisieren", 175 "settings.account.buttonSave": "Profil aktualisieren",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Du hast eine E-Mail zur Bestätigung der Löschung Deines Benutzerkontos erhalten. Dein Benutzerkonto und Deine Daten können nach der Löschung nicht wiederhergestellt werden!", 177 "settings.account.deleteEmailSent": "Du hast eine E-Mail zur Bestätigung der Löschung Deines Benutzerkontos erhalten. Dein Benutzerkonto und Deine Daten können nach der Löschung nicht wiederhergestellt werden!",
190 "settings.account.deleteInfo": "Wenn du dein Ferdi-Benutzerkonto nicht mehr länger benötigst, kannst du es hier mit allen dazugehörigen Daten löschen.", 178 "settings.account.deleteInfo": "Wenn du dein Ferdi-Benutzerkonto nicht mehr länger benötigst, kannst du es hier mit allen dazugehörigen Daten löschen.",
191 "settings.account.headline": "Konto", 179 "settings.account.headline": "Konto",
192 "settings.account.headlineAccount": "Konto-Informationen", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Benutzerkonto löschen", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Rechnungen", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Passwort ändern", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Profil aktualisieren", 184 "settings.account.headlineProfile": "Profil aktualisieren",
197 "settings.account.successInfo": "Deine Änderungen wurden gespeichert", 185 "settings.account.successInfo": "Deine Änderungen wurden gespeichert",
198 "settings.account.tryReloadServices": "Erneut versuchen", 186 "settings.account.tryReloadServices": "Erneut versuchen",
199 "settings.account.tryReloadUserInfoRequest": "Erneut versuchen", 187 "settings.account.tryReloadUserInfoRequest": "Erneut versuchen",
200 "settings.account.userInfoRequestFailed": "Benutzerinformationen konnten nicht geladen werden", 188 "settings.account.userInfoRequestFailed": "Benutzerinformationen konnten nicht geladen werden",
201 "settings.account.yourLicense": "Deine Ferdi Lizenz", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Schreibe deine Akzentfarbe in einem CSS-kompatiblen Format. (Standard: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Schreibe deine Akzentfarbe in einem CSS-kompatiblen Format. (Standard: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Cache leeren", 191 "settings.app.buttonClearAllCache": "Cache leeren",
204 "settings.app.buttonInstallUpdate": "Neu starten & Update installieren", 192 "settings.app.buttonInstallUpdate": "Neu starten & Update installieren",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Keine Benachrichtigungen für Zwischenablagenereignisse anzeigen", 207 "settings.app.form.clipboardNotifications": "Keine Benachrichtigungen für Zwischenablagenereignisse anzeigen",
220 "settings.app.form.closeToSystemTray": "Ferdi in Infobereich minimieren", 208 "settings.app.form.closeToSystemTray": "Ferdi in Infobereich minimieren",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Eigener Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Dunkles Design verwenden", 211 "settings.app.form.darkMode": "Dark Mode aktivieren",
224 "settings.app.form.enableGPUAcceleration": "Hardwarebeschleunigung aktivieren", 212 "settings.app.form.enableGPUAcceleration": "Hardwarebeschleunigung aktivieren",
225 "settings.app.form.enableLock": "Passwort-Sperre aktivieren", 213 "settings.app.form.enableLock": "Passwort-Sperre aktivieren",
226 "settings.app.form.enableMenuBar": "Ferdi immer in der Menüleiste anzeigen", 214 "settings.app.form.enableMenuBar": "Ferdi immer in der Menüleiste anzeigen",
227 "settings.app.form.enableSpellchecking": "Rechtschreibprüfung aktivieren", 215 "settings.app.form.enableSpellchecking": "Rechtschreibprüfung aktivieren",
228 "settings.app.form.enableSystemTray": "Ferdi im Infobereich anzeigen", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Ferdi Todos aktivieren", 217 "settings.app.form.enableTodos": "Ferdi Todos aktivieren",
230 "settings.app.form.hibernateOnStartup": "Behalte Dienste im Ruhezustand beim Start", 218 "settings.app.form.hibernateOnStartup": "Behalte Dienste im Ruhezustand beim Start",
231 "settings.app.form.hibernationStrategy": "\"Service Hibernation\"-Strategie", 219 "settings.app.form.hibernationStrategy": "\"Service Hibernation\"-Strategie",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Deaktivierte Services-Tabs anzeigen", 239 "settings.app.form.showDisabledServices": "Deaktivierte Services-Tabs anzeigen",
252 "settings.app.form.showDragArea": "Zeige ziehbare Fläche im Fenster", 240 "settings.app.form.showDragArea": "Zeige ziehbare Fläche im Fenster",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Ungelesene Nachrichten zeigen, wenn die Benachrichtigungen deaktiviert sind", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Ungelesene Nachrichten zeigen, wenn die Benachrichtigungen deaktiviert sind",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Minimiert starten", 243 "settings.app.form.startMinimized": "Minimiert starten",
255 "settings.app.form.universalDarkMode": "Universellen Dark Mode aktivieren", 244 "settings.app.form.universalDarkMode": "Universellen Dark Mode aktivieren",
256 "settings.app.form.useTouchIdToUnlock": "Verwenden von Touch ID zum Entsperren von Ferdi erlauben", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Erweitert", 248 "settings.app.headlineAdvanced": "Erweitert",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Offizielle Ãœbersetzungen: Englisch & Deutsch. Alle anderen Sprachen sind Ãœbersetzungen der Ferdi Community.", 256 "settings.app.languageDisclaimer": "Offizielle Ãœbersetzungen: Englisch & Deutsch. Alle anderen Sprachen sind Ãœbersetzungen der Ferdi Community.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Passwort", 258 "settings.app.lockedPassword": "Passwort",
270 "settings.app.lockedPasswordInfo": "Bitte stelle sicher, dass du ein Passwort setzt, an welches du dich erinnern kannst.\nSolltest du dieses Passwort vergessen, musst du Ferdi neu installieren.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Änderungen werden erst nach einem Neustart wirksam.", 260 "settings.app.restartRequired": "Änderungen werden erst nach einem Neustart wirksam.",
272 "settings.app.scheduledDNDInfo": "Die geplante \"Nicht-stören\"-Funktion erlaubt es dir eine Zeitspanne festzulegen, in der du keine Benachrichtigungen von Ferdi erhalten möchtest.", 261 "settings.app.scheduledDNDInfo": "Die geplante \"Nicht-stören\"-Funktion erlaubt es dir eine Zeitspanne festzulegen, in der du keine Benachrichtigungen von Ferdi erhalten möchtest.",
273 "settings.app.scheduledDNDTimeInfo": "Zeiten im 24-Stunden-Format (z.B. 18:00). Endzeit kann vor Beginn der Startzeit sein (z.B. 17:00 Uhr, Ende 09:00), um die Funktion über Nacht zu aktivieren.", 262 "settings.app.scheduledDNDTimeInfo": "Zeiten im 24-Stunden-Format (z.B. 18:00). Endzeit kann vor Beginn der Startzeit sein (z.B. 17:00 Uhr, Ende 09:00), um die Funktion über Nacht zu aktivieren.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi verwendet den eingebauten Rechtschreibprüfer deines Macs, um nach Tippfehlern zu suchen. Wenn du die zu überprüfenden Sprachen ändern möchtest, kannst du das in deinen Systemeinstellungen tun.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi verwendet den eingebauten Rechtschreibprüfer deines Macs, um nach Tippfehlern zu suchen. Wenn du die zu überprüfenden Sprachen ändern möchtest, kannst du das in deinen Systemeinstellungen tun.",
276 "settings.app.subheadlineCache": "Cache", 265 "settings.app.subheadlineCache": "Cache",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Dieser Server wird für die \"Ferdi Todo\"-Funktion verwendet.", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Hilf uns, Ferdi in Deine Sprache zu übersetzen.", 268 "settings.app.translationHelp": "Hilf uns, Ferdi in Deine Sprache zu übersetzen.",
280 "settings.app.universalDarkModeInfo": "Universeller Dark Mode versucht dynamisch Dienste abzudunkeln, die vom normalen Dark Mode noch nicht unterstützt werden.", 269 "settings.app.universalDarkModeInfo": "Universeller Dark Mode versucht dynamisch Dienste abzudunkeln, die vom normalen Dark Mode noch nicht unterstützt werden.",
281 "settings.app.updateStatusAvailable": "Update verfügbar, lädt herunter ...", 270 "settings.app.updateStatusAvailable": "Update verfügbar, lädt herunter ...",
@@ -294,12 +283,12 @@
294 "settings.recipes.customService.headline.communityRecipes": "Community Recipes", 283 "settings.recipes.customService.headline.communityRecipes": "Community Recipes",
295 "settings.recipes.customService.headline.customRecipes": "Benutzerdefinierte Recipes", 284 "settings.recipes.customService.headline.customRecipes": "Benutzerdefinierte Recipes",
296 "settings.recipes.customService.headline.devRecipes": "Eigene Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Eigene Recipes",
297 "settings.recipes.customService.intro": "Um ein benutzerdefiniertes Service hinzuzufügen, kopiere das Service Recipe nach:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Entwicklerdokumentation", 287 "settings.recipes.customService.openDevDocs": "Entwicklerdokumentation",
299 "settings.recipes.customService.openFolder": "Ordner öffnen", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Verfügbare Dienste", 289 "settings.recipes.headline": "Verfügbare Dienste",
301 "settings.recipes.missingService": "Fehlt ein Dienst?", 290 "settings.recipes.missingService": "Fehlt ein Dienst?",
302 "settings.recipes.nothingFound": "Leider hat kein Dienst zu deinem Suchbegriff gepasst - aber du kannst ihn wahrscheinlich trotzdem über die Option \"Eigene Website\" hinzufügen. Bitte beachte, dass die Website möglicherweise weitere Dienste anzeigt, die seit deiner aktuellen Version zu Ferdi hinzugefügt wurden. Um diese neuen Dienste zu erhalten, erwäge bitte ein Upgrade auf eine neuere Version von Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
303 "settings.recipes.servicesSuccessfulAddedInfo": "Dienst erfolgreich hinzugefügt", 292 "settings.recipes.servicesSuccessfulAddedInfo": "Dienst erfolgreich hinzugefügt",
304 "settings.searchService": "Dienst suchen", 293 "settings.searchService": "Dienst suchen",
305 "settings.service.error.goBack": "Zurück zu den Diensten", 294 "settings.service.error.goBack": "Zurück zu den Diensten",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Helligkeit", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Helligkeit",
313 "settings.service.form.darkReaderContrast": "Dark Reader Kontrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Kontrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Dienst löschen", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "{name} bearbeiten", 305 "settings.service.form.editServiceHeadline": "{name} bearbeiten",
317 "settings.service.form.enableAudio": "Audio aktivieren", 306 "settings.service.form.enableAudio": "Audio aktivieren",
318 "settings.service.form.enableBadge": "Nachrichten-Badge anzeigen", 307 "settings.service.form.enableBadge": "Nachrichten-Badge anzeigen",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Wenn aktiviert, wird ein Dienst nach einer Zeitspanne heruntergefahren, um Systemressourcen zu sparen.", 321 "settings.service.form.isHibernatedEnabledInfo": "Wenn aktiviert, wird ein Dienst nach einer Zeitspanne heruntergefahren, um Systemressourcen zu sparen.",
333 "settings.service.form.isMutedInfo": "Sämtliche Wiedergabe von Tönen wird deaktiviert", 322 "settings.service.form.isMutedInfo": "Sämtliche Wiedergabe von Tönen wird deaktiviert",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Öffne darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Öffne darkmode.css",
336 "settings.service.form.openUserCss": "Öffne user.css", 326 "settings.service.form.openUserCss": "Öffne user.css",
337 "settings.service.form.openUserJs": "Öffne user.js", 327 "settings.service.form.openUserJs": "Öffne user.js",
338 "settings.service.form.proxy.headline": "HTTP-/HTTPS-Proxy-Einstellungen", 328 "settings.service.form.proxy.headline": "HTTP-/HTTPS-Proxy-Einstellungen",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy-Einstellungen werden nicht mit den Ferdi Servern synchronisiert.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Proxy-Server verwenden", 331 "settings.service.form.proxy.isEnabled": "Proxy-Server verwenden",
342 "settings.service.form.proxy.password": "Passwort (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Bitte starte Ferdi nach dem Ändern der Proxy-Einstellungen neu.", 334 "settings.service.form.proxy.restartInfo": "Bitte starte Ferdi nach dem Ändern der Proxy-Einstellungen neu.",
345 "settings.service.form.proxy.user": "Benutzer (optional)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Deine \"user\" Dateien werden in die Webseite eingefügt, so dass du die Dienste in beliebiger Weise anpassen können. \"user\" Dateien werden nur lokal gespeichert und nicht auf andere Computer, welche das gleiche Konto nutzen, übertragen.", 336 "settings.service.form.recipeFileInfo": "Deine \"user\" Dateien werden in die Webseite eingefügt, so dass du die Dienste in beliebiger Weise anpassen können. \"user\" Dateien werden nur lokal gespeichert und nicht auf andere Computer, welche das gleiche Konto nutzen, übertragen.",
347 "settings.service.form.saveButton": "Dienst speichern", 337 "settings.service.form.saveButton": "Dienst speichern",
348 "settings.service.form.tabHosted": "Gehostet", 338 "settings.service.form.tabHosted": "Gehostet",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Dienste entdecken", 344 "settings.services.discoverServices": "Dienste entdecken",
355 "settings.services.headline": "Deine Dienste", 345 "settings.services.headline": "Deine Dienste",
356 "settings.services.noServicesAdded": "Beginne indem du einen Dienst hinzufügst.", 346 "settings.services.noServicesAdded": "Beginne indem du einen Dienst hinzufügst.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Dienste konnten nicht geladen werden", 348 "settings.services.servicesRequestFailed": "Dienste konnten nicht geladen werden",
358 "settings.services.tooltip.isDisabled": "Dienst ist deaktiviert", 349 "settings.services.tooltip.isDisabled": "Dienst ist deaktiviert",
359 "settings.services.tooltip.isMuted": "Alle Töne sind deaktiviert", 350 "settings.services.tooltip.isMuted": "Alle Töne sind deaktiviert",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi ist eine Open-Source und von der Community-geführte Anwendung.</p><p>Danke an die Personen, die das möglich machen:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi ist eine Open-Source und von der Community-geführte Anwendung.</p><p>Danke an die Personen, die das möglich machen:</p>",
363 "settings.supportFerdi.bannerText": "Willst du uns helfen, Ferdi zu verbessern?", 354 "settings.supportFerdi.bannerText": "Willst du uns helfen, Ferdi zu verbessern?",
364 "settings.supportFerdi.headline": "Ãœber Ferdi", 355 "settings.supportFerdi.headline": "Ãœber Ferdi",
365 "settings.supportFerdi.openSurvey": "Umfrage öffnen", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "Wenn du Lust hast, die Entwicklung von Ferdi mit einer Spende zu unterstützen, kannst du dies auf folgenden Seiten tun,", 357 "settings.supportFerdi.textDonation": "Wenn du Lust hast, die Entwicklung von Ferdi mit einer Spende zu unterstützen, kannst du dies auf folgenden Seiten tun,",
367 "settings.supportFerdi.textDonationAnd": "und", 358 "settings.supportFerdi.textDonationAnd": "und",
368 "settings.supportFerdi.textExpenses": "Während die meiste Arbeit von Freiwilligen geleistet wird, müssen wir dennoch für Server und Zertifikate bezahlen. Als Community sind wir völlig transparent über die Gelder, die wir sammeln und ausgeben - siehe unsere", 359 "settings.supportFerdi.textExpenses": "Während die meiste Arbeit von Freiwilligen geleistet wird, müssen wir dennoch für Server und Zertifikate bezahlen. Als Community sind wir völlig transparent über die Gelder, die wir sammeln und ausgeben - siehe unsere",
369 "settings.supportFerdi.textGitHubSponsors": "GitHub Sponsoren", 360 "settings.supportFerdi.textGitHubSponsors": "GitHub Sponsoren",
370 "settings.supportFerdi.textListContributors": "Vollständige Liste der Mitwirkenden", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "hier", 362 "settings.supportFerdi.textListContributorsHere": "hier",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Unterstützung ist immer willkommen. Du findest eine Liste über Unterstützungen die wir benötigen", 364 "settings.supportFerdi.textSupportWelcome": "Unterstützung ist immer willkommen. Du findest eine Liste über Unterstützungen die wir benötigen",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Non-Profit", 378 "settings.user.form.accountType.non-profit": "Non-Profit",
388 "settings.user.form.currentPassword": "Aktuelles Passwort", 379 "settings.user.form.currentPassword": "Aktuelles Passwort",
389 "settings.user.form.email": "E-Mail", 380 "settings.user.form.email": "E-Mail",
390 "settings.user.form.firstname": "Vorname", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Nachname", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Neues Passwort", 383 "settings.user.form.newPassword": "Neues Passwort",
393 "settings.workspace.add.form.name": "Name", 384 "settings.workspace.add.form.name": "Name",
394 "settings.workspace.add.form.submitButton": "Workspace erstellen", 385 "settings.workspace.add.form.submitButton": "Workspace erstellen",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Erneut versuchen", 396 "settings.workspaces.tryReloadWorkspaces": "Erneut versuchen",
406 "settings.workspaces.updatedInfo": "Deine Änderungen wurden gespeichert", 397 "settings.workspaces.updatedInfo": "Deine Änderungen wurden gespeichert",
407 "settings.workspaces.workspaceFeatureHeadline": "Weniger ist mehr: Ferdi Workspaces", 398 "settings.workspaces.workspaceFeatureHeadline": "Weniger ist mehr: Ferdi Workspaces",
408 "settings.workspaces.workspaceFeatureInfo": "Mit Ferdi Workspaces hast du alles im Blick, was gerade wichtig ist - und nur das. Erstelle unterschiedliche Sets von Services, und wechsle jederzeit zwischen ihnen hin und her. Du entscheidest welche Services du wann und wo brauchst, um ungestört arbeiten zu können - oder zu Hause besser abzuschalten.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Workspaces konnte nicht geladen werden", 400 "settings.workspaces.workspacesRequestFailed": "Workspaces konnte nicht geladen werden",
410 "setupAssistant.headline": "Los geht's", 401 "setupAssistant.headline": "Los geht's",
411 "setupAssistant.subheadline": "Wähle von unseren meistgenutzten Diensten und bekomm deine Nachrichten wieder in den Griff.", 402 "setupAssistant.subheadline": "Wähle von unseren meistgenutzten Diensten und bekomm deine Nachrichten wieder in den Griff.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Benachrichtigungen & Audio aktivieren", 411 "sidebar.unmuteApp": "Benachrichtigungen & Audio aktivieren",
421 "signup.email.label": "E-Mail-Adresse", 412 "signup.email.label": "E-Mail-Adresse",
422 "signup.emailDuplicate": "Es existiert bereits ein Benutzer mit dieser E-Mail Adresse.", 413 "signup.emailDuplicate": "Es existiert bereits ein Benutzer mit dieser E-Mail Adresse.",
423 "signup.firstname.label": "Vorname", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Anmelden", 415 "signup.headline": "Anmelden",
425 "signup.lastname.label": "Nachname", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Mit der Erstellung eines Ferdi-Kontos akzeptierst Du die", 417 "signup.legal.info": "Mit der Erstellung eines Ferdi-Kontos akzeptierst Du die",
427 "signup.legal.privacy": "Datenschutzerklärung", 418 "signup.legal.privacy": "Datenschutzerklärung",
428 "signup.legal.terms": "Nutzungsbedingungen", 419 "signup.legal.terms": "Nutzungsbedingungen",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Passwort", 421 "signup.password.label": "Passwort",
431 "signup.submit.label": "Konto erstellen", 422 "signup.submit.label": "Konto erstellen",
432 "tabs.item.confirmDeleteService": "Willst du den {serviceName} Dienst wirklich löschen?", 423 "tabs.item.confirmDeleteService": "Willst du den {serviceName} Dienst wirklich löschen?",
433 "tabs.item.deleteService": "Dienst löschen", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Audio deaktivieren", 425 "tabs.item.disableAudio": "Audio deaktivieren",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Benachrichtigungen deaktivieren", 427 "tabs.item.disableNotifications": "Benachrichtigungen deaktivieren",
437 "tabs.item.disableService": "Dienst deaktivieren", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Audio aktivieren", 429 "tabs.item.enableAudio": "Audio aktivieren",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Benachrichtigungen aktivieren", 431 "tabs.item.enableNotification": "Benachrichtigungen aktivieren",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Neu laden", 434 "tabs.item.reload": "Neu laden",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} ist ungültig", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} muss mindestens {length} Zeichen enthalten", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Mindestens ein Wert wird benötigt", 438 "validation.oneRequired": "Mindestens ein Wert wird benötigt",
448 "validation.required": "{field} wird benötigt", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} ist keine gültige URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Zurück", 441 "webControls.back": "Zurück",
451 "webControls.forward": "Vorwärts", 442 "webControls.forward": "Vorwärts",
452 "webControls.goHome": "Startseite", 443 "webControls.goHome": "Startseite",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Neu laden", 445 "webControls.reload": "Neu laden",
455 "welcome.loginButton": "Bei Ferdi einloggen", 446 "welcome.loginButton": "Bei Ferdi einloggen",
456 "welcome.signupButton": "Kostenloses Konto erstellen", 447 "welcome.signupButton": "Kostenloses Konto erstellen",
457 "workspaceDrawer.addNewWorkspaceLabel": "Neuen Workspace hinzufügen", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Alle Dienste", 449 "workspaceDrawer.allServices": "Alle Dienste",
459 "workspaceDrawer.headline": "Arbeitsbereiche", 450 "workspaceDrawer.headline": "Arbeitsbereiche",
460 "workspaceDrawer.item.contextMenuEdit": "Bearbeiten", 451 "workspaceDrawer.item.contextMenuEdit": "Bearbeiten",
461 "workspaceDrawer.item.noServicesAddedYet": "Noch keine Services hinzugefügt", 452 "workspaceDrawer.item.noServicesAddedYet": "Noch keine Services hinzugefügt",
462 "workspaceDrawer.workspaceFeatureInfo": "Mit Ferdi Workspaces hast du alles im Blick, was gerade wichtig ist - und nur das. Erstelle unterschiedliche Sets von Services, und wechsle jederzeit zwischen ihnen hin und her. Du entscheidest welche Services du wann und wo brauchst, um ungestört arbeiten zu können - oder zu Hause besser abzuschalten.", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Workspaces bearbeiten", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Wechsle zu" 455 "workspaces.switchingIndicator.switchingTo": "Wechsle zu"
465} 456}
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
deleted file mode 100644
index 3a41c66f6..000000000
--- a/src/i18n/locales/defaultMessages.json
+++ /dev/null
@@ -1,6862 +0,0 @@
1[
2 {
3 "descriptors": [
4 {
5 "defaultMessage": "!!!A new update for Ferdi is available.",
6 "end": {
7 "column": 3,
8 "line": 13
9 },
10 "file": "src/components/AppUpdateInfoBar.js",
11 "id": "infobar.updateAvailable",
12 "start": {
13 "column": 19,
14 "line": 10
15 }
16 },
17 {
18 "defaultMessage": "!!!Changelog",
19 "end": {
20 "column": 3,
21 "line": 17
22 },
23 "file": "src/components/AppUpdateInfoBar.js",
24 "id": "infobar.buttonChangelog",
25 "start": {
26 "column": 13,
27 "line": 14
28 }
29 },
30 {
31 "defaultMessage": "!!!Restart & install update",
32 "end": {
33 "column": 3,
34 "line": 21
35 },
36 "file": "src/components/AppUpdateInfoBar.js",
37 "id": "infobar.buttonInstallUpdate",
38 "start": {
39 "column": 23,
40 "line": 18
41 }
42 }
43 ],
44 "path": "src/components/AppUpdateInfoBar.json"
45 },
46 {
47 "descriptors": [
48 {
49 "defaultMessage": "!!!Change server",
50 "end": {
51 "column": 3,
52 "line": 18
53 },
54 "file": "src/components/auth/ChangeServer.js",
55 "id": "changeserver.headline",
56 "start": {
57 "column": 12,
58 "line": 15
59 }
60 },
61 {
62 "defaultMessage": "!!!Server",
63 "end": {
64 "column": 3,
65 "line": 22
66 },
67 "file": "src/components/auth/ChangeServer.js",
68 "id": "changeserver.label",
69 "start": {
70 "column": 9,
71 "line": 19
72 }
73 },
74 {
75 "defaultMessage": "!!!Extra settings offered by Ferdi will not be saved",
76 "end": {
77 "column": 3,
78 "line": 26
79 },
80 "file": "src/components/auth/ChangeServer.js",
81 "id": "changeserver.warning",
82 "start": {
83 "column": 11,
84 "line": 23
85 }
86 },
87 {
88 "defaultMessage": "!!!Custom server",
89 "end": {
90 "column": 3,
91 "line": 30
92 },
93 "file": "src/components/auth/ChangeServer.js",
94 "id": "changeserver.customServerLabel",
95 "start": {
96 "column": 21,
97 "line": 27
98 }
99 },
100 {
101 "defaultMessage": "!!!Enter a valid URL",
102 "end": {
103 "column": 3,
104 "line": 34
105 },
106 "file": "src/components/auth/ChangeServer.js",
107 "id": "changeserver.urlError",
108 "start": {
109 "column": 12,
110 "line": 31
111 }
112 }
113 ],
114 "path": "src/components/auth/ChangeServer.json"
115 },
116 {
117 "descriptors": [
118 {
119 "defaultMessage": "!!!Import your Ferdi 4 services",
120 "end": {
121 "column": 3,
122 "line": 16
123 },
124 "file": "src/components/auth/Import.js",
125 "id": "import.headline",
126 "start": {
127 "column": 12,
128 "line": 13
129 }
130 },
131 {
132 "defaultMessage": "!!!Services not yet supported in Ferdi 5",
133 "end": {
134 "column": 3,
135 "line": 20
136 },
137 "file": "src/components/auth/Import.js",
138 "id": "import.notSupportedHeadline",
139 "start": {
140 "column": 24,
141 "line": 17
142 }
143 },
144 {
145 "defaultMessage": "!!!Import {count} services",
146 "end": {
147 "column": 3,
148 "line": 24
149 },
150 "file": "src/components/auth/Import.js",
151 "id": "import.submit.label",
152 "start": {
153 "column": 21,
154 "line": 21
155 }
156 },
157 {
158 "defaultMessage": "!!!I want to add services manually",
159 "end": {
160 "column": 3,
161 "line": 28
162 },
163 "file": "src/components/auth/Import.js",
164 "id": "import.skip.label",
165 "start": {
166 "column": 19,
167 "line": 25
168 }
169 }
170 ],
171 "path": "src/components/auth/Import.json"
172 },
173 {
174 "descriptors": [
175 {
176 "defaultMessage": "!!!Invite Friends",
177 "end": {
178 "column": 3,
179 "line": 19
180 },
181 "file": "src/components/auth/Invite.js",
182 "id": "settings.invite.headline",
183 "start": {
184 "column": 20,
185 "line": 16
186 }
187 },
188 {
189 "defaultMessage": "!!!Invite 3 of your friends or colleagues",
190 "end": {
191 "column": 3,
192 "line": 23
193 },
194 "file": "src/components/auth/Invite.js",
195 "id": "invite.headline.friends",
196 "start": {
197 "column": 12,
198 "line": 20
199 }
200 },
201 {
202 "defaultMessage": "!!!Name",
203 "end": {
204 "column": 3,
205 "line": 27
206 },
207 "file": "src/components/auth/Invite.js",
208 "id": "invite.name.label",
209 "start": {
210 "column": 13,
211 "line": 24
212 }
213 },
214 {
215 "defaultMessage": "!!!Email address",
216 "end": {
217 "column": 3,
218 "line": 31
219 },
220 "file": "src/components/auth/Invite.js",
221 "id": "invite.email.label",
222 "start": {
223 "column": 14,
224 "line": 28
225 }
226 },
227 {
228 "defaultMessage": "!!!Send invites",
229 "end": {
230 "column": 3,
231 "line": 35
232 },
233 "file": "src/components/auth/Invite.js",
234 "id": "invite.submit.label",
235 "start": {
236 "column": 21,
237 "line": 32
238 }
239 },
240 {
241 "defaultMessage": "!!!I want to do this later",
242 "end": {
243 "column": 3,
244 "line": 39
245 },
246 "file": "src/components/auth/Invite.js",
247 "id": "invite.skip.label",
248 "start": {
249 "column": 19,
250 "line": 36
251 }
252 },
253 {
254 "defaultMessage": "!!!Invitations sent successfully",
255 "end": {
256 "column": 3,
257 "line": 43
258 },
259 "file": "src/components/auth/Invite.js",
260 "id": "invite.successInfo",
261 "start": {
262 "column": 21,
263 "line": 40
264 }
265 }
266 ],
267 "path": "src/components/auth/Invite.json"
268 },
269 {
270 "descriptors": [
271 {
272 "defaultMessage": "!!!Locked",
273 "end": {
274 "column": 3,
275 "line": 19
276 },
277 "file": "src/components/auth/Locked.js",
278 "id": "locked.headline",
279 "start": {
280 "column": 12,
281 "line": 16
282 }
283 },
284 {
285 "defaultMessage": "!!!Ferdi is currently locked. Please unlock Ferdi with your password to see your messages.",
286 "end": {
287 "column": 3,
288 "line": 23
289 },
290 "file": "src/components/auth/Locked.js",
291 "id": "locked.info",
292 "start": {
293 "column": 8,
294 "line": 20
295 }
296 },
297 {
298 "defaultMessage": "!!!Unlock with Touch ID",
299 "end": {
300 "column": 3,
301 "line": 27
302 },
303 "file": "src/components/auth/Locked.js",
304 "id": "locked.touchId",
305 "start": {
306 "column": 11,
307 "line": 24
308 }
309 },
310 {
311 "defaultMessage": "!!!unlock via Touch ID",
312 "end": {
313 "column": 3,
314 "line": 31
315 },
316 "file": "src/components/auth/Locked.js",
317 "id": "locked.touchIdPrompt",
318 "start": {
319 "column": 17,
320 "line": 28
321 }
322 },
323 {
324 "defaultMessage": "!!!Password",
325 "end": {
326 "column": 3,
327 "line": 35
328 },
329 "file": "src/components/auth/Locked.js",
330 "id": "locked.password.label",
331 "start": {
332 "column": 17,
333 "line": 32
334 }
335 },
336 {
337 "defaultMessage": "!!!Unlock",
338 "end": {
339 "column": 3,
340 "line": 39
341 },
342 "file": "src/components/auth/Locked.js",
343 "id": "locked.submit.label",
344 "start": {
345 "column": 21,
346 "line": 36
347 }
348 },
349 {
350 "defaultMessage": "!!!Unlock with Password",
351 "end": {
352 "column": 3,
353 "line": 43
354 },
355 "file": "src/components/auth/Locked.js",
356 "id": "locked.unlockWithPassword",
357 "start": {
358 "column": 22,
359 "line": 40
360 }
361 },
362 {
363 "defaultMessage": "!!!Password invalid",
364 "end": {
365 "column": 3,
366 "line": 47
367 },
368 "file": "src/components/auth/Locked.js",
369 "id": "locked.invalidCredentials",
370 "start": {
371 "column": 22,
372 "line": 44
373 }
374 }
375 ],
376 "path": "src/components/auth/Locked.json"
377 },
378 {
379 "descriptors": [
380 {
381 "defaultMessage": "!!!Sign in",
382 "end": {
383 "column": 3,
384 "line": 23
385 },
386 "file": "src/components/auth/Login.js",
387 "id": "login.headline",
388 "start": {
389 "column": 12,
390 "line": 20
391 }
392 },
393 {
394 "defaultMessage": "!!!Email address",
395 "end": {
396 "column": 3,
397 "line": 27
398 },
399 "file": "src/components/auth/Login.js",
400 "id": "login.email.label",
401 "start": {
402 "column": 14,
403 "line": 24
404 }
405 },
406 {
407 "defaultMessage": "!!!Password",
408 "end": {
409 "column": 3,
410 "line": 31
411 },
412 "file": "src/components/auth/Login.js",
413 "id": "login.password.label",
414 "start": {
415 "column": 17,
416 "line": 28
417 }
418 },
419 {
420 "defaultMessage": "!!!Sign in",
421 "end": {
422 "column": 3,
423 "line": 35
424 },
425 "file": "src/components/auth/Login.js",
426 "id": "login.submit.label",
427 "start": {
428 "column": 21,
429 "line": 32
430 }
431 },
432 {
433 "defaultMessage": "!!!Email or password not valid",
434 "end": {
435 "column": 3,
436 "line": 39
437 },
438 "file": "src/components/auth/Login.js",
439 "id": "login.invalidCredentials",
440 "start": {
441 "column": 22,
442 "line": 36
443 }
444 },
445 {
446 "defaultMessage": "!!!Using a Franz account to log in?",
447 "end": {
448 "column": 3,
449 "line": 43
450 },
451 "file": "src/components/auth/Login.js",
452 "id": "login.customServerQuestion",
453 "start": {
454 "column": 24,
455 "line": 40
456 }
457 },
458 {
459 "defaultMessage": "!!!Try importing your Franz account into Ferdi",
460 "end": {
461 "column": 3,
462 "line": 47
463 },
464 "file": "src/components/auth/Login.js",
465 "id": "login.customServerSuggestion",
466 "start": {
467 "column": 26,
468 "line": 44
469 }
470 },
471 {
472 "defaultMessage": "!!!Your session expired, please login again.",
473 "end": {
474 "column": 3,
475 "line": 51
476 },
477 "file": "src/components/auth/Login.js",
478 "id": "login.tokenExpired",
479 "start": {
480 "column": 16,
481 "line": 48
482 }
483 },
484 {
485 "defaultMessage": "!!!Your session expired, please login again.",
486 "end": {
487 "column": 3,
488 "line": 55
489 },
490 "file": "src/components/auth/Login.js",
491 "id": "login.serverLogout",
492 "start": {
493 "column": 16,
494 "line": 52
495 }
496 },
497 {
498 "defaultMessage": "!!!Create a free account",
499 "end": {
500 "column": 3,
501 "line": 59
502 },
503 "file": "src/components/auth/Login.js",
504 "id": "login.link.signup",
505 "start": {
506 "column": 14,
507 "line": 56
508 }
509 },
510 {
511 "defaultMessage": "!!!Change server",
512 "end": {
513 "column": 3,
514 "line": 63
515 },
516 "file": "src/components/auth/Login.js",
517 "id": "login.changeServer",
518 "start": {
519 "column": 16,
520 "line": 60
521 }
522 },
523 {
524 "defaultMessage": "!!!Use Ferdi without an Account",
525 "end": {
526 "column": 3,
527 "line": 67
528 },
529 "file": "src/components/auth/Login.js",
530 "id": "services.serverless",
531 "start": {
532 "column": 14,
533 "line": 64
534 }
535 },
536 {
537 "defaultMessage": "!!!Forgot password",
538 "end": {
539 "column": 3,
540 "line": 71
541 },
542 "file": "src/components/auth/Login.js",
543 "id": "login.link.password",
544 "start": {
545 "column": 16,
546 "line": 68
547 }
548 }
549 ],
550 "path": "src/components/auth/Login.json"
551 },
552 {
553 "descriptors": [
554 {
555 "defaultMessage": "!!!Forgot password",
556 "end": {
557 "column": 3,
558 "line": 18
559 },
560 "file": "src/components/auth/Password.js",
561 "id": "password.headline",
562 "start": {
563 "column": 12,
564 "line": 15
565 }
566 },
567 {
568 "defaultMessage": "!!!Email address",
569 "end": {
570 "column": 3,
571 "line": 22
572 },
573 "file": "src/components/auth/Password.js",
574 "id": "password.email.label",
575 "start": {
576 "column": 14,
577 "line": 19
578 }
579 },
580 {
581 "defaultMessage": "!!!Your new password was sent to your email address",
582 "end": {
583 "column": 3,
584 "line": 26
585 },
586 "file": "src/components/auth/Password.js",
587 "id": "password.successInfo",
588 "start": {
589 "column": 15,
590 "line": 23
591 }
592 },
593 {
594 "defaultMessage": "!!!No user affiliated with that email address",
595 "end": {
596 "column": 3,
597 "line": 30
598 },
599 "file": "src/components/auth/Password.js",
600 "id": "password.noUser",
601 "start": {
602 "column": 10,
603 "line": 27
604 }
605 },
606 {
607 "defaultMessage": "!!!Create a free account",
608 "end": {
609 "column": 3,
610 "line": 34
611 },
612 "file": "src/components/auth/Password.js",
613 "id": "password.link.signup",
614 "start": {
615 "column": 14,
616 "line": 31
617 }
618 },
619 {
620 "defaultMessage": "!!!Sign in to your account",
621 "end": {
622 "column": 3,
623 "line": 38
624 },
625 "file": "src/components/auth/Password.js",
626 "id": "password.link.login",
627 "start": {
628 "column": 13,
629 "line": 35
630 }
631 }
632 ],
633 "path": "src/components/auth/Password.json"
634 },
635 {
636 "descriptors": [
637 {
638 "defaultMessage": "!!!Invite Friends",
639 "end": {
640 "column": 3,
641 "line": 19
642 },
643 "file": "src/components/auth/ServiceAssistant.js",
644 "id": "settings.invite.headline",
645 "start": {
646 "column": 20,
647 "line": 16
648 }
649 },
650 {
651 "defaultMessage": "!!!Invite 3 of your friends or colleagues",
652 "end": {
653 "column": 3,
654 "line": 23
655 },
656 "file": "src/components/auth/ServiceAssistant.js",
657 "id": "invite.headline.friends",
658 "start": {
659 "column": 12,
660 "line": 20
661 }
662 },
663 {
664 "defaultMessage": "!!!Name",
665 "end": {
666 "column": 3,
667 "line": 27
668 },
669 "file": "src/components/auth/ServiceAssistant.js",
670 "id": "invite.name.label",
671 "start": {
672 "column": 13,
673 "line": 24
674 }
675 },
676 {
677 "defaultMessage": "!!!Email address",
678 "end": {
679 "column": 3,
680 "line": 31
681 },
682 "file": "src/components/auth/ServiceAssistant.js",
683 "id": "invite.email.label",
684 "start": {
685 "column": 14,
686 "line": 28
687 }
688 },
689 {
690 "defaultMessage": "!!!Send invites",
691 "end": {
692 "column": 3,
693 "line": 35
694 },
695 "file": "src/components/auth/ServiceAssistant.js",
696 "id": "invite.submit.label",
697 "start": {
698 "column": 21,
699 "line": 32
700 }
701 },
702 {
703 "defaultMessage": "!!!I want to do this later",
704 "end": {
705 "column": 3,
706 "line": 39
707 },
708 "file": "src/components/auth/ServiceAssistant.js",
709 "id": "invite.skip.label",
710 "start": {
711 "column": 19,
712 "line": 36
713 }
714 },
715 {
716 "defaultMessage": "!!!Invitations sent successfully",
717 "end": {
718 "column": 3,
719 "line": 43
720 },
721 "file": "src/components/auth/ServiceAssistant.js",
722 "id": "invite.successInfo",
723 "start": {
724 "column": 21,
725 "line": 40
726 }
727 }
728 ],
729 "path": "src/components/auth/ServiceAssistant.json"
730 },
731 {
732 "descriptors": [
733 {
734 "defaultMessage": "!!!Let's get started",
735 "end": {
736 "column": 3,
737 "line": 23
738 },
739 "file": "src/components/auth/SetupAssistant.js",
740 "id": "setupAssistant.headline",
741 "start": {
742 "column": 12,
743 "line": 20
744 }
745 },
746 {
747 "defaultMessage": "!!!Choose from our most used services and get back on top of your messaging now.",
748 "end": {
749 "column": 3,
750 "line": 28
751 },
752 "file": "src/components/auth/SetupAssistant.js",
753 "id": "setupAssistant.subheadline",
754 "start": {
755 "column": 15,
756 "line": 24
757 }
758 },
759 {
760 "defaultMessage": "!!!Let's go",
761 "end": {
762 "column": 3,
763 "line": 32
764 },
765 "file": "src/components/auth/SetupAssistant.js",
766 "id": "setupAssistant.submit.label",
767 "start": {
768 "column": 21,
769 "line": 29
770 }
771 },
772 {
773 "defaultMessage": "!!!Invitations sent successfully",
774 "end": {
775 "column": 3,
776 "line": 36
777 },
778 "file": "src/components/auth/SetupAssistant.js",
779 "id": "invite.successInfo",
780 "start": {
781 "column": 21,
782 "line": 33
783 }
784 }
785 ],
786 "path": "src/components/auth/SetupAssistant.json"
787 },
788 {
789 "descriptors": [
790 {
791 "defaultMessage": "!!!Sign up",
792 "end": {
793 "column": 3,
794 "line": 23
795 },
796 "file": "src/components/auth/Signup.js",
797 "id": "signup.headline",
798 "start": {
799 "column": 12,
800 "line": 20
801 }
802 },
803 {
804 "defaultMessage": "!!!Firstname",
805 "end": {
806 "column": 3,
807 "line": 27
808 },
809 "file": "src/components/auth/Signup.js",
810 "id": "signup.firstname.label",
811 "start": {
812 "column": 18,
813 "line": 24
814 }
815 },
816 {
817 "defaultMessage": "!!!Lastname",
818 "end": {
819 "column": 3,
820 "line": 31
821 },
822 "file": "src/components/auth/Signup.js",
823 "id": "signup.lastname.label",
824 "start": {
825 "column": 17,
826 "line": 28
827 }
828 },
829 {
830 "defaultMessage": "!!!Email address",
831 "end": {
832 "column": 3,
833 "line": 35
834 },
835 "file": "src/components/auth/Signup.js",
836 "id": "signup.email.label",
837 "start": {
838 "column": 14,
839 "line": 32
840 }
841 },
842 {
843 "defaultMessage": "!!!Password",
844 "end": {
845 "column": 3,
846 "line": 43
847 },
848 "file": "src/components/auth/Signup.js",
849 "id": "signup.password.label",
850 "start": {
851 "column": 17,
852 "line": 40
853 }
854 },
855 {
856 "defaultMessage": "!!!By creating a Ferdi account you accept the",
857 "end": {
858 "column": 3,
859 "line": 47
860 },
861 "file": "src/components/auth/Signup.js",
862 "id": "signup.legal.info",
863 "start": {
864 "column": 13,
865 "line": 44
866 }
867 },
868 {
869 "defaultMessage": "!!!Terms of service",
870 "end": {
871 "column": 3,
872 "line": 51
873 },
874 "file": "src/components/auth/Signup.js",
875 "id": "signup.legal.terms",
876 "start": {
877 "column": 9,
878 "line": 48
879 }
880 },
881 {
882 "defaultMessage": "!!!Privacy Statement",
883 "end": {
884 "column": 3,
885 "line": 55
886 },
887 "file": "src/components/auth/Signup.js",
888 "id": "signup.legal.privacy",
889 "start": {
890 "column": 11,
891 "line": 52
892 }
893 },
894 {
895 "defaultMessage": "!!!Create account",
896 "end": {
897 "column": 3,
898 "line": 59
899 },
900 "file": "src/components/auth/Signup.js",
901 "id": "signup.submit.label",
902 "start": {
903 "column": 21,
904 "line": 56
905 }
906 },
907 {
908 "defaultMessage": "!!!Already have an account, sign in?",
909 "end": {
910 "column": 3,
911 "line": 63
912 },
913 "file": "src/components/auth/Signup.js",
914 "id": "signup.link.login",
915 "start": {
916 "column": 13,
917 "line": 60
918 }
919 },
920 {
921 "defaultMessage": "!!!Change server",
922 "end": {
923 "column": 3,
924 "line": 67
925 },
926 "file": "src/components/auth/Signup.js",
927 "id": "login.changeServer",
928 "start": {
929 "column": 16,
930 "line": 64
931 }
932 },
933 {
934 "defaultMessage": "!!!Use Ferdi without an Account",
935 "end": {
936 "column": 3,
937 "line": 71
938 },
939 "file": "src/components/auth/Signup.js",
940 "id": "services.serverless",
941 "start": {
942 "column": 14,
943 "line": 68
944 }
945 },
946 {
947 "defaultMessage": "!!!A user with that email address already exists",
948 "end": {
949 "column": 3,
950 "line": 75
951 },
952 "file": "src/components/auth/Signup.js",
953 "id": "signup.emailDuplicate",
954 "start": {
955 "column": 18,
956 "line": 72
957 }
958 }
959 ],
960 "path": "src/components/auth/Signup.json"
961 },
962 {
963 "descriptors": [
964 {
965 "defaultMessage": "!!!Create a free account",
966 "end": {
967 "column": 3,
968 "line": 14
969 },
970 "file": "src/components/auth/Welcome.js",
971 "id": "welcome.signupButton",
972 "start": {
973 "column": 16,
974 "line": 11
975 }
976 },
977 {
978 "defaultMessage": "!!!Login to your account",
979 "end": {
980 "column": 3,
981 "line": 18
982 },
983 "file": "src/components/auth/Welcome.js",
984 "id": "welcome.loginButton",
985 "start": {
986 "column": 15,
987 "line": 15
988 }
989 },
990 {
991 "defaultMessage": "!!!Use Ferdi without an Account",
992 "end": {
993 "column": 3,
994 "line": 22
995 },
996 "file": "src/components/auth/Welcome.js",
997 "id": "services.serverless",
998 "start": {
999 "column": 14,
1000 "line": 19
1001 }
1002 }
1003 ],
1004 "path": "src/components/auth/Welcome.json"
1005 },
1006 {
1007 "descriptors": [
1008 {
1009 "defaultMessage": "!!!Your services have been updated.",
1010 "end": {
1011 "column": 3,
1012 "line": 31
1013 },
1014 "file": "src/components/layout/AppLayout.js",
1015 "id": "infobar.servicesUpdated",
1016 "start": {
1017 "column": 19,
1018 "line": 28
1019 }
1020 },
1021 {
1022 "defaultMessage": "!!!Reload services",
1023 "end": {
1024 "column": 3,
1025 "line": 35
1026 },
1027 "file": "src/components/layout/AppLayout.js",
1028 "id": "infobar.buttonReloadServices",
1029 "start": {
1030 "column": 24,
1031 "line": 32
1032 }
1033 },
1034 {
1035 "defaultMessage": "!!!Could not load services and user information",
1036 "end": {
1037 "column": 3,
1038 "line": 39
1039 },
1040 "file": "src/components/layout/AppLayout.js",
1041 "id": "infobar.requiredRequestsFailed",
1042 "start": {
1043 "column": 26,
1044 "line": 36
1045 }
1046 },
1047 {
1048 "defaultMessage": "!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
1049 "end": {
1050 "column": 3,
1051 "line": 44
1052 },
1053 "file": "src/components/layout/AppLayout.js",
1054 "id": "infobar.authRequestFailed",
1055 "start": {
1056 "column": 21,
1057 "line": 40
1058 }
1059 }
1060 ],
1061 "path": "src/components/layout/AppLayout.json"
1062 },
1063 {
1064 "descriptors": [
1065 {
1066 "defaultMessage": "!!!Add new service",
1067 "end": {
1068 "column": 3,
1069 "line": 21
1070 },
1071 "file": "src/components/layout/Sidebar.js",
1072 "id": "sidebar.addNewService",
1073 "start": {
1074 "column": 17,
1075 "line": 18
1076 }
1077 },
1078 {
1079 "defaultMessage": "!!!Disable notifications & audio",
1080 "end": {
1081 "column": 3,
1082 "line": 25
1083 },
1084 "file": "src/components/layout/Sidebar.js",
1085 "id": "sidebar.muteApp",
1086 "start": {
1087 "column": 8,
1088 "line": 22
1089 }
1090 },
1091 {
1092 "defaultMessage": "!!!Enable notifications & audio",
1093 "end": {
1094 "column": 3,
1095 "line": 29
1096 },
1097 "file": "src/components/layout/Sidebar.js",
1098 "id": "sidebar.unmuteApp",
1099 "start": {
1100 "column": 10,
1101 "line": 26
1102 }
1103 },
1104 {
1105 "defaultMessage": "!!!Open workspace drawer",
1106 "end": {
1107 "column": 3,
1108 "line": 33
1109 },
1110 "file": "src/components/layout/Sidebar.js",
1111 "id": "sidebar.openWorkspaceDrawer",
1112 "start": {
1113 "column": 23,
1114 "line": 30
1115 }
1116 },
1117 {
1118 "defaultMessage": "!!!Close workspace drawer",
1119 "end": {
1120 "column": 3,
1121 "line": 37
1122 },
1123 "file": "src/components/layout/Sidebar.js",
1124 "id": "sidebar.closeWorkspaceDrawer",
1125 "start": {
1126 "column": 24,
1127 "line": 34
1128 }
1129 },
1130 {
1131 "defaultMessage": "!!!Open Ferdi Todos",
1132 "end": {
1133 "column": 3,
1134 "line": 41
1135 },
1136 "file": "src/components/layout/Sidebar.js",
1137 "id": "sidebar.openTodosDrawer",
1138 "start": {
1139 "column": 19,
1140 "line": 38
1141 }
1142 },
1143 {
1144 "defaultMessage": "!!!Close Ferdi Todos",
1145 "end": {
1146 "column": 3,
1147 "line": 45
1148 },
1149 "file": "src/components/layout/Sidebar.js",
1150 "id": "sidebar.closeTodosDrawer",
1151 "start": {
1152 "column": 20,
1153 "line": 42
1154 }
1155 },
1156 {
1157 "defaultMessage": "!!!Lock Ferdi",
1158 "end": {
1159 "column": 3,
1160 "line": 49
1161 },
1162 "file": "src/components/layout/Sidebar.js",
1163 "id": "sidebar.lockFerdi",
1164 "start": {
1165 "column": 13,
1166 "line": 46
1167 }
1168 }
1169 ],
1170 "path": "src/components/layout/Sidebar.json"
1171 },
1172 {
1173 "descriptors": [
1174 {
1175 "defaultMessage": "!!!Home",
1176 "end": {
1177 "column": 3,
1178 "line": 16
1179 },
1180 "file": "src/components/services/content/ConnectionBanner.js",
1181 "id": "webControls.goHome",
1182 "start": {
1183 "column": 10,
1184 "line": 13
1185 }
1186 },
1187 {
1188 "defaultMessage": "!!!Open in Browser",
1189 "end": {
1190 "column": 3,
1191 "line": 20
1192 },
1193 "file": "src/components/services/content/ConnectionBanner.js",
1194 "id": "webControls.openInBrowser",
1195 "start": {
1196 "column": 17,
1197 "line": 17
1198 }
1199 },
1200 {
1201 "defaultMessage": "!!!Back",
1202 "end": {
1203 "column": 3,
1204 "line": 24
1205 },
1206 "file": "src/components/services/content/ConnectionBanner.js",
1207 "id": "webControls.back",
1208 "start": {
1209 "column": 8,
1210 "line": 21
1211 }
1212 },
1213 {
1214 "defaultMessage": "!!!Forward",
1215 "end": {
1216 "column": 3,
1217 "line": 28
1218 },
1219 "file": "src/components/services/content/ConnectionBanner.js",
1220 "id": "webControls.forward",
1221 "start": {
1222 "column": 11,
1223 "line": 25
1224 }
1225 },
1226 {
1227 "defaultMessage": "!!!Reload",
1228 "end": {
1229 "column": 3,
1230 "line": 32
1231 },
1232 "file": "src/components/services/content/ConnectionBanner.js",
1233 "id": "webControls.reload",
1234 "start": {
1235 "column": 10,
1236 "line": 29
1237 }
1238 }
1239 ],
1240 "path": "src/components/services/content/ConnectionBanner.json"
1241 },
1242 {
1243 "descriptors": [
1244 {
1245 "defaultMessage": "!!!Home",
1246 "end": {
1247 "column": 3,
1248 "line": 16
1249 },
1250 "file": "src/components/services/content/ConnectionLost.js",
1251 "id": "webControls.goHome",
1252 "start": {
1253 "column": 10,
1254 "line": 13
1255 }
1256 },
1257 {
1258 "defaultMessage": "!!!Open in Browser",
1259 "end": {
1260 "column": 3,
1261 "line": 20
1262 },
1263 "file": "src/components/services/content/ConnectionLost.js",
1264 "id": "webControls.openInBrowser",
1265 "start": {
1266 "column": 17,
1267 "line": 17
1268 }
1269 },
1270 {
1271 "defaultMessage": "!!!Back",
1272 "end": {
1273 "column": 3,
1274 "line": 24
1275 },
1276 "file": "src/components/services/content/ConnectionLost.js",
1277 "id": "webControls.back",
1278 "start": {
1279 "column": 8,
1280 "line": 21
1281 }
1282 },
1283 {
1284 "defaultMessage": "!!!Forward",
1285 "end": {
1286 "column": 3,
1287 "line": 28
1288 },
1289 "file": "src/components/services/content/ConnectionLost.js",
1290 "id": "webControls.forward",
1291 "start": {
1292 "column": 11,
1293 "line": 25
1294 }
1295 },
1296 {
1297 "defaultMessage": "!!!Reload",
1298 "end": {
1299 "column": 3,
1300 "line": 32
1301 },
1302 "file": "src/components/services/content/ConnectionLost.js",
1303 "id": "webControls.reload",
1304 "start": {
1305 "column": 10,
1306 "line": 29
1307 }
1308 }
1309 ],
1310 "path": "src/components/services/content/ConnectionLost.json"
1311 },
1312 {
1313 "descriptors": [
1314 {
1315 "defaultMessage": "!!!Oh no! Ferdi lost the connection to {name}.",
1316 "end": {
1317 "column": 3,
1318 "line": 16
1319 },
1320 "file": "src/components/services/content/ConnectionLostBanner.js",
1321 "id": "connectionLostBanner.message",
1322 "start": {
1323 "column": 8,
1324 "line": 13
1325 }
1326 },
1327 {
1328 "defaultMessage": "!!!What happened?",
1329 "end": {
1330 "column": 3,
1331 "line": 20
1332 },
1333 "file": "src/components/services/content/ConnectionLostBanner.js",
1334 "id": "connectionLostBanner.informationLink",
1335 "start": {
1336 "column": 19,
1337 "line": 17
1338 }
1339 },
1340 {
1341 "defaultMessage": "!!!Reload Service",
1342 "end": {
1343 "column": 3,
1344 "line": 24
1345 },
1346 "file": "src/components/services/content/ConnectionLostBanner.js",
1347 "id": "connectionLostBanner.cta",
1348 "start": {
1349 "column": 7,
1350 "line": 21
1351 }
1352 }
1353 ],
1354 "path": "src/components/services/content/ConnectionLostBanner.json"
1355 },
1356 {
1357 "descriptors": [
1358 {
1359 "defaultMessage": "!!!Oh no!",
1360 "end": {
1361 "column": 3,
1362 "line": 15
1363 },
1364 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
1365 "id": "service.errorHandler.headline",
1366 "start": {
1367 "column": 12,
1368 "line": 12
1369 }
1370 },
1371 {
1372 "defaultMessage": "!!!{name} has failed to load.",
1373 "end": {
1374 "column": 3,
1375 "line": 19
1376 },
1377 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
1378 "id": "service.errorHandler.text",
1379 "start": {
1380 "column": 8,
1381 "line": 16
1382 }
1383 },
1384 {
1385 "defaultMessage": "!!!Reload {name}",
1386 "end": {
1387 "column": 3,
1388 "line": 23
1389 },
1390 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
1391 "id": "service.errorHandler.action",
1392 "start": {
1393 "column": 10,
1394 "line": 20
1395 }
1396 },
1397 {
1398 "defaultMessage": "!!!Edit {name}",
1399 "end": {
1400 "column": 3,
1401 "line": 27
1402 },
1403 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
1404 "id": "service.errorHandler.editAction",
1405 "start": {
1406 "column": 14,
1407 "line": 24
1408 }
1409 },
1410 {
1411 "defaultMessage": "!!!Error:",
1412 "end": {
1413 "column": 3,
1414 "line": 31
1415 },
1416 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
1417 "id": "service.errorHandler.message",
1418 "start": {
1419 "column": 16,
1420 "line": 28
1421 }
1422 }
1423 ],
1424 "path": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.json"
1425 },
1426 {
1427 "descriptors": [
1428 {
1429 "defaultMessage": "!!!{name} is disabled",
1430 "end": {
1431 "column": 3,
1432 "line": 12
1433 },
1434 "file": "src/components/services/content/ServiceDisabled.js",
1435 "id": "service.disabledHandler.headline",
1436 "start": {
1437 "column": 12,
1438 "line": 9
1439 }
1440 },
1441 {
1442 "defaultMessage": "!!!Enable {name}",
1443 "end": {
1444 "column": 3,
1445 "line": 16
1446 },
1447 "file": "src/components/services/content/ServiceDisabled.js",
1448 "id": "service.disabledHandler.action",
1449 "start": {
1450 "column": 10,
1451 "line": 13
1452 }
1453 }
1454 ],
1455 "path": "src/components/services/content/ServiceDisabled.json"
1456 },
1457 {
1458 "descriptors": [
1459 {
1460 "defaultMessage": "!!!Welcome to Ferdi",
1461 "end": {
1462 "column": 3,
1463 "line": 18
1464 },
1465 "file": "src/components/services/content/Services.js",
1466 "id": "services.welcome",
1467 "start": {
1468 "column": 11,
1469 "line": 15
1470 }
1471 },
1472 {
1473 "defaultMessage": "!!!Get started",
1474 "end": {
1475 "column": 3,
1476 "line": 22
1477 },
1478 "file": "src/components/services/content/Services.js",
1479 "id": "services.getStarted",
1480 "start": {
1481 "column": 14,
1482 "line": 19
1483 }
1484 },
1485 {
1486 "defaultMessage": "!!!Please login to use Ferdi.",
1487 "end": {
1488 "column": 3,
1489 "line": 26
1490 },
1491 "file": "src/components/services/content/Services.js",
1492 "id": "services.login",
1493 "start": {
1494 "column": 9,
1495 "line": 23
1496 }
1497 },
1498 {
1499 "defaultMessage": "!!!Use Ferdi without an Account",
1500 "end": {
1501 "column": 3,
1502 "line": 30
1503 },
1504 "file": "src/components/services/content/Services.js",
1505 "id": "services.serverless",
1506 "start": {
1507 "column": 14,
1508 "line": 27
1509 }
1510 },
1511 {
1512 "defaultMessage": "!!!Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
1513 "end": {
1514 "column": 3,
1515 "line": 34
1516 },
1517 "file": "src/components/services/content/Services.js",
1518 "id": "services.serverInfo",
1519 "start": {
1520 "column": 14,
1521 "line": 31
1522 }
1523 }
1524 ],
1525 "path": "src/components/services/content/Services.json"
1526 },
1527 {
1528 "descriptors": [
1529 {
1530 "defaultMessage": "!!!Home",
1531 "end": {
1532 "column": 3,
1533 "line": 16
1534 },
1535 "file": "src/components/services/content/WebControls.js",
1536 "id": "webControls.goHome",
1537 "start": {
1538 "column": 10,
1539 "line": 13
1540 }
1541 },
1542 {
1543 "defaultMessage": "!!!Open in Browser",
1544 "end": {
1545 "column": 3,
1546 "line": 20
1547 },
1548 "file": "src/components/services/content/WebControls.js",
1549 "id": "webControls.openInBrowser",
1550 "start": {
1551 "column": 17,
1552 "line": 17
1553 }
1554 },
1555 {
1556 "defaultMessage": "!!!Back",
1557 "end": {
1558 "column": 3,
1559 "line": 24
1560 },
1561 "file": "src/components/services/content/WebControls.js",
1562 "id": "webControls.back",
1563 "start": {
1564 "column": 8,
1565 "line": 21
1566 }
1567 },
1568 {
1569 "defaultMessage": "!!!Forward",
1570 "end": {
1571 "column": 3,
1572 "line": 28
1573 },
1574 "file": "src/components/services/content/WebControls.js",
1575 "id": "webControls.forward",
1576 "start": {
1577 "column": 11,
1578 "line": 25
1579 }
1580 },
1581 {
1582 "defaultMessage": "!!!Reload",
1583 "end": {
1584 "column": 3,
1585 "line": 32
1586 },
1587 "file": "src/components/services/content/WebControls.js",
1588 "id": "webControls.reload",
1589 "start": {
1590 "column": 10,
1591 "line": 29
1592 }
1593 }
1594 ],
1595 "path": "src/components/services/content/WebControls.json"
1596 },
1597 {
1598 "descriptors": [
1599 {
1600 "defaultMessage": "!!!Oh no!",
1601 "end": {
1602 "column": 3,
1603 "line": 13
1604 },
1605 "file": "src/components/services/content/WebviewCrashHandler.js",
1606 "id": "service.crashHandler.headline",
1607 "start": {
1608 "column": 12,
1609 "line": 10
1610 }
1611 },
1612 {
1613 "defaultMessage": "!!!{name} has caused an error.",
1614 "end": {
1615 "column": 3,
1616 "line": 17
1617 },
1618 "file": "src/components/services/content/WebviewCrashHandler.js",
1619 "id": "service.crashHandler.text",
1620 "start": {
1621 "column": 8,
1622 "line": 14
1623 }
1624 },
1625 {
1626 "defaultMessage": "!!!Reload {name}",
1627 "end": {
1628 "column": 3,
1629 "line": 21
1630 },
1631 "file": "src/components/services/content/WebviewCrashHandler.js",
1632 "id": "service.crashHandler.action",
1633 "start": {
1634 "column": 10,
1635 "line": 18
1636 }
1637 },
1638 {
1639 "defaultMessage": "!!!Trying to automatically restore {name} in {seconds} seconds",
1640 "end": {
1641 "column": 3,
1642 "line": 25
1643 },
1644 "file": "src/components/services/content/WebviewCrashHandler.js",
1645 "id": "service.crashHandler.autoReload",
1646 "start": {
1647 "column": 14,
1648 "line": 22
1649 }
1650 }
1651 ],
1652 "path": "src/components/services/content/WebviewCrashHandler.json"
1653 },
1654 {
1655 "descriptors": [
1656 {
1657 "defaultMessage": "!!!Reload",
1658 "end": {
1659 "column": 3,
1660 "line": 24
1661 },
1662 "file": "src/components/services/tabs/TabItem.js",
1663 "id": "tabs.item.reload",
1664 "start": {
1665 "column": 10,
1666 "line": 21
1667 }
1668 },
1669 {
1670 "defaultMessage": "!!!Disable notifications",
1671 "end": {
1672 "column": 3,
1673 "line": 28
1674 },
1675 "file": "src/components/services/tabs/TabItem.js",
1676 "id": "tabs.item.disableNotifications",
1677 "start": {
1678 "column": 24,
1679 "line": 25
1680 }
1681 },
1682 {
1683 "defaultMessage": "!!!Enable notifications",
1684 "end": {
1685 "column": 3,
1686 "line": 32
1687 },
1688 "file": "src/components/services/tabs/TabItem.js",
1689 "id": "tabs.item.enableNotification",
1690 "start": {
1691 "column": 23,
1692 "line": 29
1693 }
1694 },
1695 {
1696 "defaultMessage": "!!!Disable audio",
1697 "end": {
1698 "column": 3,
1699 "line": 36
1700 },
1701 "file": "src/components/services/tabs/TabItem.js",
1702 "id": "tabs.item.disableAudio",
1703 "start": {
1704 "column": 16,
1705 "line": 33
1706 }
1707 },
1708 {
1709 "defaultMessage": "!!!Enable audio",
1710 "end": {
1711 "column": 3,
1712 "line": 40
1713 },
1714 "file": "src/components/services/tabs/TabItem.js",
1715 "id": "tabs.item.enableAudio",
1716 "start": {
1717 "column": 15,
1718 "line": 37
1719 }
1720 },
1721 {
1722 "defaultMessage": "!!!Enable Dark mode",
1723 "end": {
1724 "column": 3,
1725 "line": 44
1726 },
1727 "file": "src/components/services/tabs/TabItem.js",
1728 "id": "tabs.item.enableDarkMode",
1729 "start": {
1730 "column": 18,
1731 "line": 41
1732 }
1733 },
1734 {
1735 "defaultMessage": "!!!Disable Dark mode",
1736 "end": {
1737 "column": 3,
1738 "line": 48
1739 },
1740 "file": "src/components/services/tabs/TabItem.js",
1741 "id": "tabs.item.disableDarkMode",
1742 "start": {
1743 "column": 19,
1744 "line": 45
1745 }
1746 },
1747 {
1748 "defaultMessage": "!!!Disable Service",
1749 "end": {
1750 "column": 3,
1751 "line": 52
1752 },
1753 "file": "src/components/services/tabs/TabItem.js",
1754 "id": "tabs.item.disableService",
1755 "start": {
1756 "column": 18,
1757 "line": 49
1758 }
1759 },
1760 {
1761 "defaultMessage": "!!!Enable Service",
1762 "end": {
1763 "column": 3,
1764 "line": 56
1765 },
1766 "file": "src/components/services/tabs/TabItem.js",
1767 "id": "tabs.item.enableService",
1768 "start": {
1769 "column": 17,
1770 "line": 53
1771 }
1772 },
1773 {
1774 "defaultMessage": "!!!Hibernate Service",
1775 "end": {
1776 "column": 3,
1777 "line": 60
1778 },
1779 "file": "src/components/services/tabs/TabItem.js",
1780 "id": "tabs.item.hibernateService",
1781 "start": {
1782 "column": 20,
1783 "line": 57
1784 }
1785 },
1786 {
1787 "defaultMessage": "!!!Wake Up Service",
1788 "end": {
1789 "column": 3,
1790 "line": 64
1791 },
1792 "file": "src/components/services/tabs/TabItem.js",
1793 "id": "tabs.item.wakeUpService",
1794 "start": {
1795 "column": 17,
1796 "line": 61
1797 }
1798 },
1799 {
1800 "defaultMessage": "!!!Delete Service",
1801 "end": {
1802 "column": 3,
1803 "line": 68
1804 },
1805 "file": "src/components/services/tabs/TabItem.js",
1806 "id": "tabs.item.deleteService",
1807 "start": {
1808 "column": 17,
1809 "line": 65
1810 }
1811 },
1812 {
1813 "defaultMessage": "!!!Do you really want to delete the {serviceName} service?",
1814 "end": {
1815 "column": 3,
1816 "line": 73
1817 },
1818 "file": "src/components/services/tabs/TabItem.js",
1819 "id": "tabs.item.confirmDeleteService",
1820 "start": {
1821 "column": 24,
1822 "line": 69
1823 }
1824 }
1825 ],
1826 "path": "src/components/services/tabs/TabItem.json"
1827 },
1828 {
1829 "descriptors": [
1830 {
1831 "defaultMessage": "!!!Account",
1832 "end": {
1833 "column": 3,
1834 "line": 17
1835 },
1836 "file": "src/components/settings/account/AccountDashboard.js",
1837 "id": "settings.account.headline",
1838 "start": {
1839 "column": 12,
1840 "line": 14
1841 }
1842 },
1843 {
1844 "defaultMessage": "!!Danger Zone",
1845 "end": {
1846 "column": 3,
1847 "line": 21
1848 },
1849 "file": "src/components/settings/account/AccountDashboard.js",
1850 "id": "settings.account.headlineDangerZone",
1851 "start": {
1852 "column": 22,
1853 "line": 18
1854 }
1855 },
1856 {
1857 "defaultMessage": "!!!Edit Account",
1858 "end": {
1859 "column": 3,
1860 "line": 25
1861 },
1862 "file": "src/components/settings/account/AccountDashboard.js",
1863 "id": "settings.account.account.editButton",
1864 "start": {
1865 "column": 21,
1866 "line": 22
1867 }
1868 },
1869 {
1870 "defaultMessage": "!!Invoices",
1871 "end": {
1872 "column": 3,
1873 "line": 29
1874 },
1875 "file": "src/components/settings/account/AccountDashboard.js",
1876 "id": "settings.account.headlineInvoices",
1877 "start": {
1878 "column": 18,
1879 "line": 26
1880 }
1881 },
1882 {
1883 "defaultMessage": "!!!Could not load user information",
1884 "end": {
1885 "column": 3,
1886 "line": 33
1887 },
1888 "file": "src/components/settings/account/AccountDashboard.js",
1889 "id": "settings.account.userInfoRequestFailed",
1890 "start": {
1891 "column": 25,
1892 "line": 30
1893 }
1894 },
1895 {
1896 "defaultMessage": "!!!Try again",
1897 "end": {
1898 "column": 3,
1899 "line": 37
1900 },
1901 "file": "src/components/settings/account/AccountDashboard.js",
1902 "id": "settings.account.tryReloadUserInfoRequest",
1903 "start": {
1904 "column": 28,
1905 "line": 34
1906 }
1907 },
1908 {
1909 "defaultMessage": "!!!Delete account",
1910 "end": {
1911 "column": 3,
1912 "line": 41
1913 },
1914 "file": "src/components/settings/account/AccountDashboard.js",
1915 "id": "settings.account.deleteAccount",
1916 "start": {
1917 "column": 17,
1918 "line": 38
1919 }
1920 },
1921 {
1922 "defaultMessage": "!!!If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
1923 "end": {
1924 "column": 3,
1925 "line": 46
1926 },
1927 "file": "src/components/settings/account/AccountDashboard.js",
1928 "id": "settings.account.deleteInfo",
1929 "start": {
1930 "column": 14,
1931 "line": 42
1932 }
1933 },
1934 {
1935 "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
1936 "end": {
1937 "column": 3,
1938 "line": 51
1939 },
1940 "file": "src/components/settings/account/AccountDashboard.js",
1941 "id": "settings.account.deleteEmailSent",
1942 "start": {
1943 "column": 19,
1944 "line": 47
1945 }
1946 },
1947 {
1948 "defaultMessage": "!!!Your Franz License:",
1949 "end": {
1950 "column": 3,
1951 "line": 55
1952 },
1953 "file": "src/components/settings/account/AccountDashboard.js",
1954 "id": "settings.account.yourLicense",
1955 "start": {
1956 "column": 15,
1957 "line": 52
1958 }
1959 },
1960 {
1961 "defaultMessage": "Account is unavailable",
1962 "end": {
1963 "column": 3,
1964 "line": 59
1965 },
1966 "file": "src/components/settings/account/AccountDashboard.js",
1967 "id": "settings.account.accountUnavailable",
1968 "start": {
1969 "column": 22,
1970 "line": 56
1971 }
1972 },
1973 {
1974 "defaultMessage": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
1975 "end": {
1976 "column": 3,
1977 "line": 63
1978 },
1979 "file": "src/components/settings/account/AccountDashboard.js",
1980 "id": "settings.account.accountUnavailableInfo",
1981 "start": {
1982 "column": 26,
1983 "line": 60
1984 }
1985 }
1986 ],
1987 "path": "src/components/settings/account/AccountDashboard.json"
1988 },
1989 {
1990 "descriptors": [
1991 {
1992 "defaultMessage": "!!!Available services",
1993 "end": {
1994 "column": 3,
1995 "line": 19
1996 },
1997 "file": "src/components/settings/navigation/SettingsNavigation.js",
1998 "id": "settings.navigation.availableServices",
1999 "start": {
2000 "column": 21,
2001 "line": 16
2002 }
2003 },
2004 {
2005 "defaultMessage": "!!!Your services",
2006 "end": {
2007 "column": 3,
2008 "line": 23
2009 },
2010 "file": "src/components/settings/navigation/SettingsNavigation.js",
2011 "id": "settings.navigation.yourServices",
2012 "start": {
2013 "column": 16,
2014 "line": 20
2015 }
2016 },
2017 {
2018 "defaultMessage": "!!!Your workspaces",
2019 "end": {
2020 "column": 3,
2021 "line": 27
2022 },
2023 "file": "src/components/settings/navigation/SettingsNavigation.js",
2024 "id": "settings.navigation.yourWorkspaces",
2025 "start": {
2026 "column": 18,
2027 "line": 24
2028 }
2029 },
2030 {
2031 "defaultMessage": "!!!Account",
2032 "end": {
2033 "column": 3,
2034 "line": 31
2035 },
2036 "file": "src/components/settings/navigation/SettingsNavigation.js",
2037 "id": "settings.navigation.account",
2038 "start": {
2039 "column": 11,
2040 "line": 28
2041 }
2042 },
2043 {
2044 "defaultMessage": "!!!Manage Team",
2045 "end": {
2046 "column": 3,
2047 "line": 35
2048 },
2049 "file": "src/components/settings/navigation/SettingsNavigation.js",
2050 "id": "settings.navigation.team",
2051 "start": {
2052 "column": 8,
2053 "line": 32
2054 }
2055 },
2056 {
2057 "defaultMessage": "!!!About Ferdi",
2058 "end": {
2059 "column": 3,
2060 "line": 39
2061 },
2062 "file": "src/components/settings/navigation/SettingsNavigation.js",
2063 "id": "settings.navigation.supportFerdi",
2064 "start": {
2065 "column": 16,
2066 "line": 36
2067 }
2068 },
2069 {
2070 "defaultMessage": "!!!Logout",
2071 "end": {
2072 "column": 3,
2073 "line": 43
2074 },
2075 "file": "src/components/settings/navigation/SettingsNavigation.js",
2076 "id": "settings.navigation.logout",
2077 "start": {
2078 "column": 10,
2079 "line": 40
2080 }
2081 }
2082 ],
2083 "path": "src/components/settings/navigation/SettingsNavigation.json"
2084 },
2085 {
2086 "descriptors": [
2087 {
2088 "defaultMessage": "!!!Available Services",
2089 "end": {
2090 "column": 3,
2091 "line": 22
2092 },
2093 "file": "src/components/settings/recipes/RecipesDashboard.js",
2094 "id": "settings.recipes.headline",
2095 "start": {
2096 "column": 12,
2097 "line": 19
2098 }
2099 },
2100 {
2101 "defaultMessage": "!!!Search service",
2102 "end": {
2103 "column": 3,
2104 "line": 26
2105 },
2106 "file": "src/components/settings/recipes/RecipesDashboard.js",
2107 "id": "settings.searchService",
2108 "start": {
2109 "column": 17,
2110 "line": 23
2111 }
2112 },
2113 {
2114 "defaultMessage": "!!!All services",
2115 "end": {
2116 "column": 3,
2117 "line": 30
2118 },
2119 "file": "src/components/settings/recipes/RecipesDashboard.js",
2120 "id": "settings.recipes.all",
2121 "start": {
2122 "column": 14,
2123 "line": 27
2124 }
2125 },
2126 {
2127 "defaultMessage": "!!!Custom Services",
2128 "end": {
2129 "column": 3,
2130 "line": 34
2131 },
2132 "file": "src/components/settings/recipes/RecipesDashboard.js",
2133 "id": "settings.recipes.custom",
2134 "start": {
2135 "column": 17,
2136 "line": 31
2137 }
2138 },
2139 {
2140 "defaultMessage": "!!!Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
2141 "end": {
2142 "column": 3,
2143 "line": 38
2144 },
2145 "file": "src/components/settings/recipes/RecipesDashboard.js",
2146 "id": "settings.recipes.nothingFound",
2147 "start": {
2148 "column": 16,
2149 "line": 35
2150 }
2151 },
2152 {
2153 "defaultMessage": "!!!Service successfully added",
2154 "end": {
2155 "column": 3,
2156 "line": 42
2157 },
2158 "file": "src/components/settings/recipes/RecipesDashboard.js",
2159 "id": "settings.recipes.servicesSuccessfulAddedInfo",
2160 "start": {
2161 "column": 31,
2162 "line": 39
2163 }
2164 },
2165 {
2166 "defaultMessage": "!!!Missing a service?",
2167 "end": {
2168 "column": 3,
2169 "line": 46
2170 },
2171 "file": "src/components/settings/recipes/RecipesDashboard.js",
2172 "id": "settings.recipes.missingService",
2173 "start": {
2174 "column": 18,
2175 "line": 43
2176 }
2177 },
2178 {
2179 "defaultMessage": "!!!To add a custom service, copy the recipe folder into:",
2180 "end": {
2181 "column": 3,
2182 "line": 50
2183 },
2184 "file": "src/components/settings/recipes/RecipesDashboard.js",
2185 "id": "settings.recipes.customService.intro",
2186 "start": {
2187 "column": 21,
2188 "line": 47
2189 }
2190 },
2191 {
2192 "defaultMessage": "!!!Open directory",
2193 "end": {
2194 "column": 3,
2195 "line": 54
2196 },
2197 "file": "src/components/settings/recipes/RecipesDashboard.js",
2198 "id": "settings.recipes.customService.openFolder",
2199 "start": {
2200 "column": 14,
2201 "line": 51
2202 }
2203 },
2204 {
2205 "defaultMessage": "!!!Developer Documentation",
2206 "end": {
2207 "column": 3,
2208 "line": 58
2209 },
2210 "file": "src/components/settings/recipes/RecipesDashboard.js",
2211 "id": "settings.recipes.customService.openDevDocs",
2212 "start": {
2213 "column": 15,
2214 "line": 55
2215 }
2216 },
2217 {
2218 "defaultMessage": "!!!Custom 3rd Party Recipes",
2219 "end": {
2220 "column": 3,
2221 "line": 62
2222 },
2223 "file": "src/components/settings/recipes/RecipesDashboard.js",
2224 "id": "settings.recipes.customService.headline.customRecipes",
2225 "start": {
2226 "column": 25,
2227 "line": 59
2228 }
2229 },
2230 {
2231 "defaultMessage": "!!!Community 3rd Party Recipes",
2232 "end": {
2233 "column": 3,
2234 "line": 66
2235 },
2236 "file": "src/components/settings/recipes/RecipesDashboard.js",
2237 "id": "settings.recipes.customService.headline.communityRecipes",
2238 "start": {
2239 "column": 28,
2240 "line": 63
2241 }
2242 },
2243 {
2244 "defaultMessage": "!!!Your Development Service Recipes",
2245 "end": {
2246 "column": 3,
2247 "line": 70
2248 },
2249 "file": "src/components/settings/recipes/RecipesDashboard.js",
2250 "id": "settings.recipes.customService.headline.devRecipes",
2251 "start": {
2252 "column": 22,
2253 "line": 67
2254 }
2255 }
2256 ],
2257 "path": "src/components/settings/recipes/RecipesDashboard.json"
2258 },
2259 {
2260 "descriptors": [
2261 {
2262 "defaultMessage": "!!!Save service",
2263 "end": {
2264 "column": 3,
2265 "line": 26
2266 },
2267 "file": "src/components/settings/services/EditServiceForm.js",
2268 "id": "settings.service.form.saveButton",
2269 "start": {
2270 "column": 15,
2271 "line": 23
2272 }
2273 },
2274 {
2275 "defaultMessage": "!!!Delete Service",
2276 "end": {
2277 "column": 3,
2278 "line": 30
2279 },
2280 "file": "src/components/settings/services/EditServiceForm.js",
2281 "id": "settings.service.form.deleteButton",
2282 "start": {
2283 "column": 17,
2284 "line": 27
2285 }
2286 },
2287 {
2288 "defaultMessage": "!!!Open darkmode.css",
2289 "end": {
2290 "column": 3,
2291 "line": 34
2292 },
2293 "file": "src/components/settings/services/EditServiceForm.js",
2294 "id": "settings.service.form.openDarkmodeCss",
2295 "start": {
2296 "column": 19,
2297 "line": 31
2298 }
2299 },
2300 {
2301 "defaultMessage": "!!!Open user.css",
2302 "end": {
2303 "column": 3,
2304 "line": 38
2305 },
2306 "file": "src/components/settings/services/EditServiceForm.js",
2307 "id": "settings.service.form.openUserCss",
2308 "start": {
2309 "column": 15,
2310 "line": 35
2311 }
2312 },
2313 {
2314 "defaultMessage": "!!!Open user.js",
2315 "end": {
2316 "column": 3,
2317 "line": 42
2318 },
2319 "file": "src/components/settings/services/EditServiceForm.js",
2320 "id": "settings.service.form.openUserJs",
2321 "start": {
2322 "column": 14,
2323 "line": 39
2324 }
2325 },
2326 {
2327 "defaultMessage": "!!!Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
2328 "end": {
2329 "column": 3,
2330 "line": 46
2331 },
2332 "file": "src/components/settings/services/EditServiceForm.js",
2333 "id": "settings.service.form.recipeFileInfo",
2334 "start": {
2335 "column": 18,
2336 "line": 43
2337 }
2338 },
2339 {
2340 "defaultMessage": "!!!Available services",
2341 "end": {
2342 "column": 3,
2343 "line": 50
2344 },
2345 "file": "src/components/settings/services/EditServiceForm.js",
2346 "id": "settings.service.form.availableServices",
2347 "start": {
2348 "column": 21,
2349 "line": 47
2350 }
2351 },
2352 {
2353 "defaultMessage": "!!!Your services",
2354 "end": {
2355 "column": 3,
2356 "line": 54
2357 },
2358 "file": "src/components/settings/services/EditServiceForm.js",
2359 "id": "settings.service.form.yourServices",
2360 "start": {
2361 "column": 16,
2362 "line": 51
2363 }
2364 },
2365 {
2366 "defaultMessage": "!!!Add {name}",
2367 "end": {
2368 "column": 3,
2369 "line": 58
2370 },
2371 "file": "src/components/settings/services/EditServiceForm.js",
2372 "id": "settings.service.form.addServiceHeadline",
2373 "start": {
2374 "column": 22,
2375 "line": 55
2376 }
2377 },
2378 {
2379 "defaultMessage": "!!!Edit {name}",
2380 "end": {
2381 "column": 3,
2382 "line": 62
2383 },
2384 "file": "src/components/settings/services/EditServiceForm.js",
2385 "id": "settings.service.form.editServiceHeadline",
2386 "start": {
2387 "column": 23,
2388 "line": 59
2389 }
2390 },
2391 {
2392 "defaultMessage": "!!!Hosted",
2393 "end": {
2394 "column": 3,
2395 "line": 66
2396 },
2397 "file": "src/components/settings/services/EditServiceForm.js",
2398 "id": "settings.service.form.tabHosted",
2399 "start": {
2400 "column": 13,
2401 "line": 63
2402 }
2403 },
2404 {
2405 "defaultMessage": "!!!Self hosted â­ï¸",
2406 "end": {
2407 "column": 3,
2408 "line": 70
2409 },
2410 "file": "src/components/settings/services/EditServiceForm.js",
2411 "id": "settings.service.form.tabOnPremise",
2412 "start": {
2413 "column": 16,
2414 "line": 67
2415 }
2416 },
2417 {
2418 "defaultMessage": "!!!Use the hosted {name} service.",
2419 "end": {
2420 "column": 3,
2421 "line": 74
2422 },
2423 "file": "src/components/settings/services/EditServiceForm.js",
2424 "id": "settings.service.form.useHostedService",
2425 "start": {
2426 "column": 20,
2427 "line": 71
2428 }
2429 },
2430 {
2431 "defaultMessage": "!!!Could not validate custom {name} server.",
2432 "end": {
2433 "column": 3,
2434 "line": 78
2435 },
2436 "file": "src/components/settings/services/EditServiceForm.js",
2437 "id": "settings.service.form.customUrlValidationError",
2438 "start": {
2439 "column": 28,
2440 "line": 75
2441 }
2442 },
2443 {
2444 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
2445 "end": {
2446 "column": 3,
2447 "line": 82
2448 },
2449 "file": "src/components/settings/services/EditServiceForm.js",
2450 "id": "settings.service.form.indirectMessageInfo",
2451 "start": {
2452 "column": 23,
2453 "line": 79
2454 }
2455 },
2456 {
2457 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted",
2458 "end": {
2459 "column": 3,
2460 "line": 86
2461 },
2462 "file": "src/components/settings/services/EditServiceForm.js",
2463 "id": "settings.service.form.isMutedInfo",
2464 "start": {
2465 "column": 15,
2466 "line": 83
2467 }
2468 },
2469 {
2470 "defaultMessage": "!!!When enabled, a service will be shut down after a period of time to save system resources.",
2471 "end": {
2472 "column": 3,
2473 "line": 90
2474 },
2475 "file": "src/components/settings/services/EditServiceForm.js",
2476 "id": "settings.service.form.isHibernatedEnabledInfo",
2477 "start": {
2478 "column": 28,
2479 "line": 87
2480 }
2481 },
2482 {
2483 "defaultMessage": "!!!Notifications",
2484 "end": {
2485 "column": 3,
2486 "line": 94
2487 },
2488 "file": "src/components/settings/services/EditServiceForm.js",
2489 "id": "settings.service.form.headlineNotifications",
2490 "start": {
2491 "column": 25,
2492 "line": 91
2493 }
2494 },
2495 {
2496 "defaultMessage": "!!!Unread message badges",
2497 "end": {
2498 "column": 3,
2499 "line": 98
2500 },
2501 "file": "src/components/settings/services/EditServiceForm.js",
2502 "id": "settings.service.form.headlineBadges",
2503 "start": {
2504 "column": 18,
2505 "line": 95
2506 }
2507 },
2508 {
2509 "defaultMessage": "!!!General",
2510 "end": {
2511 "column": 3,
2512 "line": 102
2513 },
2514 "file": "src/components/settings/services/EditServiceForm.js",
2515 "id": "settings.service.form.headlineGeneral",
2516 "start": {
2517 "column": 19,
2518 "line": 99
2519 }
2520 },
2521 {
2522 "defaultMessage": "!!!Dark Reader Settings",
2523 "end": {
2524 "column": 3,
2525 "line": 106
2526 },
2527 "file": "src/components/settings/services/EditServiceForm.js",
2528 "id": "settings.service.form.headlineDarkReaderSettings",
2529 "start": {
2530 "column": 30,
2531 "line": 103
2532 }
2533 },
2534 {
2535 "defaultMessage": "!!!Delete",
2536 "end": {
2537 "column": 3,
2538 "line": 110
2539 },
2540 "file": "src/components/settings/services/EditServiceForm.js",
2541 "id": "settings.service.form.iconDelete",
2542 "start": {
2543 "column": 14,
2544 "line": 107
2545 }
2546 },
2547 {
2548 "defaultMessage": "!!!Drop your image, or click here",
2549 "end": {
2550 "column": 3,
2551 "line": 114
2552 },
2553 "file": "src/components/settings/services/EditServiceForm.js",
2554 "id": "settings.service.form.iconUpload",
2555 "start": {
2556 "column": 14,
2557 "line": 111
2558 }
2559 },
2560 {
2561 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings",
2562 "end": {
2563 "column": 3,
2564 "line": 118
2565 },
2566 "file": "src/components/settings/services/EditServiceForm.js",
2567 "id": "settings.service.form.proxy.headline",
2568 "start": {
2569 "column": 17,
2570 "line": 115
2571 }
2572 },
2573 {
2574 "defaultMessage": "!!!Please restart Ferdi after changing proxy Settings.",
2575 "end": {
2576 "column": 3,
2577 "line": 122
2578 },
2579 "file": "src/components/settings/services/EditServiceForm.js",
2580 "id": "settings.service.form.proxy.restartInfo",
2581 "start": {
2582 "column": 20,
2583 "line": 119
2584 }
2585 },
2586 {
2587 "defaultMessage": "!!!Proxy settings will not be synchronized with the Ferdi servers.",
2588 "end": {
2589 "column": 3,
2590 "line": 126
2591 },
2592 "file": "src/components/settings/services/EditServiceForm.js",
2593 "id": "settings.service.form.proxy.info",
2594 "start": {
2595 "column": 13,
2596 "line": 123
2597 }
2598 }
2599 ],
2600 "path": "src/components/settings/services/EditServiceForm.json"
2601 },
2602 {
2603 "descriptors": [
2604 {
2605 "defaultMessage": "!!!Error",
2606 "end": {
2607 "column": 3,
2608 "line": 13
2609 },
2610 "file": "src/components/settings/services/ServiceError.js",
2611 "id": "settings.service.error.headline",
2612 "start": {
2613 "column": 12,
2614 "line": 10
2615 }
2616 },
2617 {
2618 "defaultMessage": "!!!Back to services",
2619 "end": {
2620 "column": 3,
2621 "line": 17
2622 },
2623 "file": "src/components/settings/services/ServiceError.js",
2624 "id": "settings.service.error.goBack",
2625 "start": {
2626 "column": 10,
2627 "line": 14
2628 }
2629 },
2630 {
2631 "defaultMessage": "!!!Available services",
2632 "end": {
2633 "column": 3,
2634 "line": 21
2635 },
2636 "file": "src/components/settings/services/ServiceError.js",
2637 "id": "settings.service.form.availableServices",
2638 "start": {
2639 "column": 21,
2640 "line": 18
2641 }
2642 },
2643 {
2644 "defaultMessage": "!!!Could not load service recipe.",
2645 "end": {
2646 "column": 3,
2647 "line": 25
2648 },
2649 "file": "src/components/settings/services/ServiceError.js",
2650 "id": "settings.service.error.message",
2651 "start": {
2652 "column": 16,
2653 "line": 22
2654 }
2655 }
2656 ],
2657 "path": "src/components/settings/services/ServiceError.json"
2658 },
2659 {
2660 "descriptors": [
2661 {
2662 "defaultMessage": "!!!Service is disabled",
2663 "end": {
2664 "column": 3,
2665 "line": 14
2666 },
2667 "file": "src/components/settings/services/ServiceItem.js",
2668 "id": "settings.services.tooltip.isDisabled",
2669 "start": {
2670 "column": 21,
2671 "line": 11
2672 }
2673 },
2674 {
2675 "defaultMessage": "!!!Notifications are disabled",
2676 "end": {
2677 "column": 3,
2678 "line": 18
2679 },
2680 "file": "src/components/settings/services/ServiceItem.js",
2681 "id": "settings.services.tooltip.notificationsDisabled",
2682 "start": {
2683 "column": 32,
2684 "line": 15
2685 }
2686 },
2687 {
2688 "defaultMessage": "!!!All sounds are muted",
2689 "end": {
2690 "column": 3,
2691 "line": 22
2692 },
2693 "file": "src/components/settings/services/ServiceItem.js",
2694 "id": "settings.services.tooltip.isMuted",
2695 "start": {
2696 "column": 18,
2697 "line": 19
2698 }
2699 }
2700 ],
2701 "path": "src/components/settings/services/ServiceItem.json"
2702 },
2703 {
2704 "descriptors": [
2705 {
2706 "defaultMessage": "!!!Your services",
2707 "end": {
2708 "column": 3,
2709 "line": 18
2710 },
2711 "file": "src/components/settings/services/ServicesDashboard.js",
2712 "id": "settings.services.headline",
2713 "start": {
2714 "column": 12,
2715 "line": 15
2716 }
2717 },
2718 {
2719 "defaultMessage": "!!!Search service",
2720 "end": {
2721 "column": 3,
2722 "line": 22
2723 },
2724 "file": "src/components/settings/services/ServicesDashboard.js",
2725 "id": "settings.searchService",
2726 "start": {
2727 "column": 17,
2728 "line": 19
2729 }
2730 },
2731 {
2732 "defaultMessage": "!!!Start by adding a service.",
2733 "end": {
2734 "column": 3,
2735 "line": 26
2736 },
2737 "file": "src/components/settings/services/ServicesDashboard.js",
2738 "id": "settings.services.noServicesAdded",
2739 "start": {
2740 "column": 19,
2741 "line": 23
2742 }
2743 },
2744 {
2745 "defaultMessage": "!!!Sorry, but no service matched your search term. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
2746 "end": {
2747 "column": 3,
2748 "line": 30
2749 },
2750 "file": "src/components/settings/services/ServicesDashboard.js",
2751 "id": "settings.recipes.nothingFound",
2752 "start": {
2753 "column": 18,
2754 "line": 27
2755 }
2756 },
2757 {
2758 "defaultMessage": "!!!Discover services",
2759 "end": {
2760 "column": 3,
2761 "line": 34
2762 },
2763 "file": "src/components/settings/services/ServicesDashboard.js",
2764 "id": "settings.services.discoverServices",
2765 "start": {
2766 "column": 20,
2767 "line": 31
2768 }
2769 },
2770 {
2771 "defaultMessage": "!!!Could not load your services",
2772 "end": {
2773 "column": 3,
2774 "line": 38
2775 },
2776 "file": "src/components/settings/services/ServicesDashboard.js",
2777 "id": "settings.services.servicesRequestFailed",
2778 "start": {
2779 "column": 25,
2780 "line": 35
2781 }
2782 },
2783 {
2784 "defaultMessage": "!!!Try again",
2785 "end": {
2786 "column": 3,
2787 "line": 42
2788 },
2789 "file": "src/components/settings/services/ServicesDashboard.js",
2790 "id": "settings.account.tryReloadServices",
2791 "start": {
2792 "column": 21,
2793 "line": 39
2794 }
2795 },
2796 {
2797 "defaultMessage": "!!!Your changes have been saved",
2798 "end": {
2799 "column": 3,
2800 "line": 46
2801 },
2802 "file": "src/components/settings/services/ServicesDashboard.js",
2803 "id": "settings.services.updatedInfo",
2804 "start": {
2805 "column": 15,
2806 "line": 43
2807 }
2808 },
2809 {
2810 "defaultMessage": "!!!Service has been deleted",
2811 "end": {
2812 "column": 3,
2813 "line": 50
2814 },
2815 "file": "src/components/settings/services/ServicesDashboard.js",
2816 "id": "settings.services.deletedInfo",
2817 "start": {
2818 "column": 15,
2819 "line": 47
2820 }
2821 }
2822 ],
2823 "path": "src/components/settings/services/ServicesDashboard.json"
2824 },
2825 {
2826 "descriptors": [
2827 {
2828 "defaultMessage": "!!!General",
2829 "end": {
2830 "column": 3,
2831 "line": 24
2832 },
2833 "file": "src/components/settings/settings/EditSettingsForm.js",
2834 "id": "settings.app.headlineGeneral",
2835 "start": {
2836 "column": 19,
2837 "line": 21
2838 }
2839 },
2840 {
2841 "defaultMessage": "!!!Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!",
2842 "end": {
2843 "column": 3,
2844 "line": 28
2845 },
2846 "file": "src/components/settings/settings/EditSettingsForm.js",
2847 "id": "settings.app.sentryInfo",
2848 "start": {
2849 "column": 14,
2850 "line": 25
2851 }
2852 },
2853 {
2854 "defaultMessage": "!!!By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.",
2855 "end": {
2856 "column": 3,
2857 "line": 32
2858 },
2859 "file": "src/components/settings/settings/EditSettingsForm.js",
2860 "id": "settings.app.hibernateInfo",
2861 "start": {
2862 "column": 17,
2863 "line": 29
2864 }
2865 },
2866 {
2867 "defaultMessage": "!!!Minutes of inactivity, after which Ferdi should automatically lock. Use 0 to disable",
2868 "end": {
2869 "column": 3,
2870 "line": 36
2871 },
2872 "file": "src/components/settings/settings/EditSettingsForm.js",
2873 "id": "settings.app.inactivityLockInfo",
2874 "start": {
2875 "column": 22,
2876 "line": 33
2877 }
2878 },
2879 {
2880 "defaultMessage": "!!!This server will be used for the \"Franz Todo\" feature. (default: https://app.franztodos.com)",
2881 "end": {
2882 "column": 3,
2883 "line": 40
2884 },
2885 "file": "src/components/settings/settings/EditSettingsForm.js",
2886 "id": "settings.app.todoServerInfo",
2887 "start": {
2888 "column": 18,
2889 "line": 37
2890 }
2891 },
2892 {
2893 "defaultMessage": "!!!Password",
2894 "end": {
2895 "column": 3,
2896 "line": 44
2897 },
2898 "file": "src/components/settings/settings/EditSettingsForm.js",
2899 "id": "settings.app.lockedPassword",
2900 "start": {
2901 "column": 18,
2902 "line": 41
2903 }
2904 },
2905 {
2906 "defaultMessage": "!!!Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
2907 "end": {
2908 "column": 3,
2909 "line": 48
2910 },
2911 "file": "src/components/settings/settings/EditSettingsForm.js",
2912 "id": "settings.app.lockedPasswordInfo",
2913 "start": {
2914 "column": 22,
2915 "line": 45
2916 }
2917 },
2918 {
2919 "defaultMessage": "!!!Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
2920 "end": {
2921 "column": 3,
2922 "line": 52
2923 },
2924 "file": "src/components/settings/settings/EditSettingsForm.js",
2925 "id": "settings.app.lockInfo",
2926 "start": {
2927 "column": 12,
2928 "line": 49
2929 }
2930 },
2931 {
2932 "defaultMessage": "!!!Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
2933 "end": {
2934 "column": 3,
2935 "line": 56
2936 },
2937 "file": "src/components/settings/settings/EditSettingsForm.js",
2938 "id": "settings.app.scheduledDNDTimeInfo",
2939 "start": {
2940 "column": 24,
2941 "line": 53
2942 }
2943 },
2944 {
2945 "defaultMessage": "!!!Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.",
2946 "end": {
2947 "column": 3,
2948 "line": 60
2949 },
2950 "file": "src/components/settings/settings/EditSettingsForm.js",
2951 "id": "settings.app.scheduledDNDInfo",
2952 "start": {
2953 "column": 20,
2954 "line": 57
2955 }
2956 },
2957 {
2958 "defaultMessage": "!!!Language",
2959 "end": {
2960 "column": 3,
2961 "line": 64
2962 },
2963 "file": "src/components/settings/settings/EditSettingsForm.js",
2964 "id": "settings.app.headlineLanguage",
2965 "start": {
2966 "column": 20,
2967 "line": 61
2968 }
2969 },
2970 {
2971 "defaultMessage": "!!!Updates",
2972 "end": {
2973 "column": 3,
2974 "line": 68
2975 },
2976 "file": "src/components/settings/settings/EditSettingsForm.js",
2977 "id": "settings.app.headlineUpdates",
2978 "start": {
2979 "column": 19,
2980 "line": 65
2981 }
2982 },
2983 {
2984 "defaultMessage": "!!!Appearance",
2985 "end": {
2986 "column": 3,
2987 "line": 72
2988 },
2989 "file": "src/components/settings/settings/EditSettingsForm.js",
2990 "id": "settings.app.headlineAppearance",
2991 "start": {
2992 "column": 22,
2993 "line": 69
2994 }
2995 },
2996 {
2997 "defaultMessage": "!!!Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.",
2998 "end": {
2999 "column": 3,
3000 "line": 76
3001 },
3002 "file": "src/components/settings/settings/EditSettingsForm.js",
3003 "id": "settings.app.universalDarkModeInfo",
3004 "start": {
3005 "column": 25,
3006 "line": 73
3007 }
3008 },
3009 {
3010 "defaultMessage": "!!!Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
3011 "end": {
3012 "column": 3,
3013 "line": 80
3014 },
3015 "file": "src/components/settings/settings/EditSettingsForm.js",
3016 "id": "settings.app.accentColorInfo",
3017 "start": {
3018 "column": 19,
3019 "line": 77
3020 }
3021 },
3022 {
3023 "defaultMessage": "!!!Privacy",
3024 "end": {
3025 "column": 3,
3026 "line": 84
3027 },
3028 "file": "src/components/settings/settings/EditSettingsForm.js",
3029 "id": "settings.app.headlinePrivacy",
3030 "start": {
3031 "column": 19,
3032 "line": 81
3033 }
3034 },
3035 {
3036 "defaultMessage": "!!!Advanced",
3037 "end": {
3038 "column": 3,
3039 "line": 88
3040 },
3041 "file": "src/components/settings/settings/EditSettingsForm.js",
3042 "id": "settings.app.headlineAdvanced",
3043 "start": {
3044 "column": 20,
3045 "line": 85
3046 }
3047 },
3048 {
3049 "defaultMessage": "!!!Help us to translate Ferdi into your language.",
3050 "end": {
3051 "column": 3,
3052 "line": 92
3053 },
3054 "file": "src/components/settings/settings/EditSettingsForm.js",
3055 "id": "settings.app.translationHelp",
3056 "start": {
3057 "column": 19,
3058 "line": 89
3059 }
3060 },
3061 {
3062 "defaultMessage": "!!!Ferdi uses your Mac's build-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.",
3063 "end": {
3064 "column": 3,
3065 "line": 96
3066 },
3067 "file": "src/components/settings/settings/EditSettingsForm.js",
3068 "id": "settings.app.spellCheckerLanguageInfo",
3069 "start": {
3070 "column": 28,
3071 "line": 93
3072 }
3073 },
3074 {
3075 "defaultMessage": "!!!Cache",
3076 "end": {
3077 "column": 3,
3078 "line": 100
3079 },
3080 "file": "src/components/settings/settings/EditSettingsForm.js",
3081 "id": "settings.app.subheadlineCache",
3082 "start": {
3083 "column": 20,
3084 "line": 97
3085 }
3086 },
3087 {
3088 "defaultMessage": "!!!Ferdi cache is currently using {size} of disk space.",
3089 "end": {
3090 "column": 3,
3091 "line": 104
3092 },
3093 "file": "src/components/settings/settings/EditSettingsForm.js",
3094 "id": "settings.app.cacheInfo",
3095 "start": {
3096 "column": 13,
3097 "line": 101
3098 }
3099 },
3100 {
3101 "defaultMessage": "!!!Couldn't clear all cache",
3102 "end": {
3103 "column": 3,
3104 "line": 108
3105 },
3106 "file": "src/components/settings/settings/EditSettingsForm.js",
3107 "id": "settings.app.cacheNotCleared",
3108 "start": {
3109 "column": 19,
3110 "line": 105
3111 }
3112 },
3113 {
3114 "defaultMessage": "!!!Clear cache",
3115 "end": {
3116 "column": 3,
3117 "line": 112
3118 },
3119 "file": "src/components/settings/settings/EditSettingsForm.js",
3120 "id": "settings.app.buttonClearAllCache",
3121 "start": {
3122 "column": 23,
3123 "line": 109
3124 }
3125 },
3126 {
3127 "defaultMessage": "!!!Ferdi Profile",
3128 "end": {
3129 "column": 3,
3130 "line": 116
3131 },
3132 "file": "src/components/settings/settings/EditSettingsForm.js",
3133 "id": "settings.app.subheadlineFerdiProfile",
3134 "start": {
3135 "column": 27,
3136 "line": 113
3137 }
3138 },
3139 {
3140 "defaultMessage": "!!!Open Profile folder",
3141 "end": {
3142 "column": 3,
3143 "line": 120
3144 },
3145 "file": "src/components/settings/settings/EditSettingsForm.js",
3146 "id": "settings.app.buttonOpenFerdiProfileFolder",
3147 "start": {
3148 "column": 32,
3149 "line": 117
3150 }
3151 },
3152 {
3153 "defaultMessage": "!!!Open Service Recipes folder",
3154 "end": {
3155 "column": 3,
3156 "line": 124
3157 },
3158 "file": "src/components/settings/settings/EditSettingsForm.js",
3159 "id": "settings.app.buttonOpenFerdiServiceRecipesFolder",
3160 "start": {
3161 "column": 39,
3162 "line": 121
3163 }
3164 },
3165 {
3166 "defaultMessage": "!!!Check for updates",
3167 "end": {
3168 "column": 3,
3169 "line": 128
3170 },
3171 "file": "src/components/settings/settings/EditSettingsForm.js",
3172 "id": "settings.app.buttonSearchForUpdate",
3173 "start": {
3174 "column": 25,
3175 "line": 125
3176 }
3177 },
3178 {
3179 "defaultMessage": "!!!Restart & install update",
3180 "end": {
3181 "column": 3,
3182 "line": 132
3183 },
3184 "file": "src/components/settings/settings/EditSettingsForm.js",
3185 "id": "settings.app.buttonInstallUpdate",
3186 "start": {
3187 "column": 23,
3188 "line": 129
3189 }
3190 },
3191 {
3192 "defaultMessage": "!!!Is searching for update",
3193 "end": {
3194 "column": 3,
3195 "line": 136
3196 },
3197 "file": "src/components/settings/settings/EditSettingsForm.js",
3198 "id": "settings.app.updateStatusSearching",
3199 "start": {
3200 "column": 25,
3201 "line": 133
3202 }
3203 },
3204 {
3205 "defaultMessage": "!!!Update available, downloading...",
3206 "end": {
3207 "column": 3,
3208 "line": 140
3209 },
3210 "file": "src/components/settings/settings/EditSettingsForm.js",
3211 "id": "settings.app.updateStatusAvailable",
3212 "start": {
3213 "column": 25,
3214 "line": 137
3215 }
3216 },
3217 {
3218 "defaultMessage": "!!!You are using the latest version of Ferdi",
3219 "end": {
3220 "column": 3,
3221 "line": 144
3222 },
3223 "file": "src/components/settings/settings/EditSettingsForm.js",
3224 "id": "settings.app.updateStatusUpToDate",
3225 "start": {
3226 "column": 24,
3227 "line": 141
3228 }
3229 },
3230 {
3231 "defaultMessage": "!!!Current version:",
3232 "end": {
3233 "column": 3,
3234 "line": 148
3235 },
3236 "file": "src/components/settings/settings/EditSettingsForm.js",
3237 "id": "settings.app.currentVersion",
3238 "start": {
3239 "column": 18,
3240 "line": 145
3241 }
3242 },
3243 {
3244 "defaultMessage": "!!!Changes require restart",
3245 "end": {
3246 "column": 3,
3247 "line": 152
3248 },
3249 "file": "src/components/settings/settings/EditSettingsForm.js",
3250 "id": "settings.app.restartRequired",
3251 "start": {
3252 "column": 22,
3253 "line": 149
3254 }
3255 },
3256 {
3257 "defaultMessage": "!!!Official translations are English & German. All other languages are community based translations.",
3258 "end": {
3259 "column": 3,
3260 "line": 156
3261 },
3262 "file": "src/components/settings/settings/EditSettingsForm.js",
3263 "id": "settings.app.languageDisclaimer",
3264 "start": {
3265 "column": 22,
3266 "line": 153
3267 }
3268 }
3269 ],
3270 "path": "src/components/settings/settings/EditSettingsForm.json"
3271 },
3272 {
3273 "descriptors": [
3274 {
3275 "defaultMessage": "!!!Close settings",
3276 "end": {
3277 "column": 3,
3278 "line": 14
3279 },
3280 "file": "src/components/settings/SettingsLayout.js",
3281 "id": "settings.app.closeSettings",
3282 "start": {
3283 "column": 17,
3284 "line": 11
3285 }
3286 }
3287 ],
3288 "path": "src/components/settings/SettingsLayout.json"
3289 },
3290 {
3291 "descriptors": [
3292 {
3293 "defaultMessage": "!!!About Ferdi",
3294 "end": {
3295 "column": 3,
3296 "line": 10
3297 },
3298 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3299 "id": "settings.supportFerdi.headline",
3300 "start": {
3301 "column": 12,
3302 "line": 7
3303 }
3304 },
3305 {
3306 "defaultMessage": "!!!Do you like Ferdi?",
3307 "end": {
3308 "column": 3,
3309 "line": 14
3310 },
3311 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3312 "id": "settings.supportFerdi.title",
3313 "start": {
3314 "column": 9,
3315 "line": 11
3316 }
3317 },
3318 {
3319 "defaultMessage": "!!!<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>",
3320 "end": {
3321 "column": 3,
3322 "line": 18
3323 },
3324 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3325 "id": "settings.supportFerdi.aboutIntro",
3326 "start": {
3327 "column": 14,
3328 "line": 15
3329 }
3330 },
3331 {
3332 "defaultMessage": "!!!Full list of contributor",
3333 "end": {
3334 "column": 3,
3335 "line": 22
3336 },
3337 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3338 "id": "settings.supportFerdi.textListContributors",
3339 "start": {
3340 "column": 24,
3341 "line": 19
3342 }
3343 },
3344 {
3345 "defaultMessage": "!!!here",
3346 "end": {
3347 "column": 3,
3348 "line": 26
3349 },
3350 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3351 "id": "settings.supportFerdi.textListContributorsHere",
3352 "start": {
3353 "column": 28,
3354 "line": 23
3355 }
3356 },
3357 {
3358 "defaultMessage": "!!!The development of Ferdi is done by volunteers. People who use Ferdi like you. They maintain, fix, and improve Ferdi in their spare time.",
3359 "end": {
3360 "column": 3,
3361 "line": 30
3362 },
3363 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3364 "id": "settings.supportFerdi.textVolunteers",
3365 "start": {
3366 "column": 18,
3367 "line": 27
3368 }
3369 },
3370 {
3371 "defaultMessage": "!!!Support is always welcome. You can find a list of the help we need",
3372 "end": {
3373 "column": 3,
3374 "line": 34
3375 },
3376 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3377 "id": "settings.supportFerdi.textSupportWelcome",
3378 "start": {
3379 "column": 22,
3380 "line": 31
3381 }
3382 },
3383 {
3384 "defaultMessage": "!!!here",
3385 "end": {
3386 "column": 3,
3387 "line": 38
3388 },
3389 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3390 "id": "settings.supportFerdi.textSupportWelcomeHere",
3391 "start": {
3392 "column": 26,
3393 "line": 35
3394 }
3395 },
3396 {
3397 "defaultMessage": "!!!While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our",
3398 "end": {
3399 "column": 3,
3400 "line": 42
3401 },
3402 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3403 "id": "settings.supportFerdi.textExpenses",
3404 "start": {
3405 "column": 16,
3406 "line": 39
3407 }
3408 },
3409 {
3410 "defaultMessage": "!!!Open Collective",
3411 "end": {
3412 "column": 3,
3413 "line": 46
3414 },
3415 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3416 "id": "settings.supportFerdi.textOpenCollective",
3417 "start": {
3418 "column": 22,
3419 "line": 43
3420 }
3421 },
3422 {
3423 "defaultMessage": "!!!If you feel like supporting Ferdi development with a donation, you can do so on both,",
3424 "end": {
3425 "column": 3,
3426 "line": 50
3427 },
3428 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3429 "id": "settings.supportFerdi.textDonation",
3430 "start": {
3431 "column": 16,
3432 "line": 47
3433 }
3434 },
3435 {
3436 "defaultMessage": "!!!and",
3437 "end": {
3438 "column": 3,
3439 "line": 54
3440 },
3441 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3442 "id": "settings.supportFerdi.textDonationAnd",
3443 "start": {
3444 "column": 19,
3445 "line": 51
3446 }
3447 },
3448 {
3449 "defaultMessage": "!!!GitHub Sponsors",
3450 "end": {
3451 "column": 3,
3452 "line": 58
3453 },
3454 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3455 "id": "settings.supportFerdi.textGitHubSponsors",
3456 "start": {
3457 "column": 22,
3458 "line": 55
3459 }
3460 },
3461 {
3462 "defaultMessage": "!!!Open Survey",
3463 "end": {
3464 "column": 3,
3465 "line": 62
3466 },
3467 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3468 "id": "settings.supportFerdi.openSurvey",
3469 "start": {
3470 "column": 14,
3471 "line": 59
3472 }
3473 },
3474 {
3475 "defaultMessage": "!!!Do you want to help us improve Ferdi?",
3476 "end": {
3477 "column": 3,
3478 "line": 66
3479 },
3480 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
3481 "id": "settings.supportFerdi.bannerText",
3482 "start": {
3483 "column": 14,
3484 "line": 63
3485 }
3486 }
3487 ],
3488 "path": "src/components/settings/supportFerdi/SupportFerdiDashboard.json"
3489 },
3490 {
3491 "descriptors": [
3492 {
3493 "defaultMessage": "!!!Team",
3494 "end": {
3495 "column": 3,
3496 "line": 18
3497 },
3498 "file": "src/components/settings/team/TeamDashboard.js",
3499 "id": "settings.team.headline",
3500 "start": {
3501 "column": 12,
3502 "line": 15
3503 }
3504 },
3505 {
3506 "defaultMessage": "!!!Franz Team Management",
3507 "end": {
3508 "column": 3,
3509 "line": 22
3510 },
3511 "file": "src/components/settings/team/TeamDashboard.js",
3512 "id": "settings.team.contentHeadline",
3513 "start": {
3514 "column": 19,
3515 "line": 19
3516 }
3517 },
3518 {
3519 "defaultMessage": "!!!Your are currently using Franz Servers, which is why you have access to Team Management.",
3520 "end": {
3521 "column": 3,
3522 "line": 26
3523 },
3524 "file": "src/components/settings/team/TeamDashboard.js",
3525 "id": "settings.team.intro",
3526 "start": {
3527 "column": 9,
3528 "line": 23
3529 }
3530 },
3531 {
3532 "defaultMessage": "!!!Franz's Team Management allows you to manage Franz Subscriptions for multiple users. Please keep in mind that having a Franz Premium subscription will give you no advantages in using Ferdi: The only reason you still have access to Team Management is so you can manage your legacy Franz Teams and so that you don't loose any functionality in managing your account.",
3533 "end": {
3534 "column": 3,
3535 "line": 30
3536 },
3537 "file": "src/components/settings/team/TeamDashboard.js",
3538 "id": "settings.team.copy",
3539 "start": {
3540 "column": 8,
3541 "line": 27
3542 }
3543 },
3544 {
3545 "defaultMessage": "!!!Manage your Team on meetfranz.com",
3546 "end": {
3547 "column": 3,
3548 "line": 34
3549 },
3550 "file": "src/components/settings/team/TeamDashboard.js",
3551 "id": "settings.team.manageAction",
3552 "start": {
3553 "column": 16,
3554 "line": 31
3555 }
3556 },
3557 {
3558 "defaultMessage": "!!!Teams are unavailable",
3559 "end": {
3560 "column": 3,
3561 "line": 38
3562 },
3563 "file": "src/components/settings/team/TeamDashboard.js",
3564 "id": "settings.team.teamsUnavailable",
3565 "start": {
3566 "column": 20,
3567 "line": 35
3568 }
3569 },
3570 {
3571 "defaultMessage": "!!!Teams are currently only available when using the Franz Server and after paying for Franz Professional. Please change your server to https://api.franzinfra.com to use teams.",
3572 "end": {
3573 "column": 3,
3574 "line": 42
3575 },
3576 "file": "src/components/settings/team/TeamDashboard.js",
3577 "id": "settings.team.teamsUnavailableInfo",
3578 "start": {
3579 "column": 24,
3580 "line": 39
3581 }
3582 }
3583 ],
3584 "path": "src/components/settings/team/TeamDashboard.json"
3585 },
3586 {
3587 "descriptors": [
3588 {
3589 "defaultMessage": "!!!Account",
3590 "end": {
3591 "column": 3,
3592 "line": 18
3593 },
3594 "file": "src/components/settings/user/EditUserForm.js",
3595 "id": "settings.account.headline",
3596 "start": {
3597 "column": 12,
3598 "line": 15
3599 }
3600 },
3601 {
3602 "defaultMessage": "!!!Update Profile",
3603 "end": {
3604 "column": 3,
3605 "line": 22
3606 },
3607 "file": "src/components/settings/user/EditUserForm.js",
3608 "id": "settings.account.headlineProfile",
3609 "start": {
3610 "column": 19,
3611 "line": 19
3612 }
3613 },
3614 {
3615 "defaultMessage": "!!!Account Information",
3616 "end": {
3617 "column": 3,
3618 "line": 26
3619 },
3620 "file": "src/components/settings/user/EditUserForm.js",
3621 "id": "settings.account.headlineAccount",
3622 "start": {
3623 "column": 19,
3624 "line": 23
3625 }
3626 },
3627 {
3628 "defaultMessage": "!!!Change Password",
3629 "end": {
3630 "column": 3,
3631 "line": 30
3632 },
3633 "file": "src/components/settings/user/EditUserForm.js",
3634 "id": "settings.account.headlinePassword",
3635 "start": {
3636 "column": 20,
3637 "line": 27
3638 }
3639 },
3640 {
3641 "defaultMessage": "!!!Your changes have been saved",
3642 "end": {
3643 "column": 3,
3644 "line": 34
3645 },
3646 "file": "src/components/settings/user/EditUserForm.js",
3647 "id": "settings.account.successInfo",
3648 "start": {
3649 "column": 15,
3650 "line": 31
3651 }
3652 },
3653 {
3654 "defaultMessage": "!!!Update profile",
3655 "end": {
3656 "column": 3,
3657 "line": 38
3658 },
3659 "file": "src/components/settings/user/EditUserForm.js",
3660 "id": "settings.account.buttonSave",
3661 "start": {
3662 "column": 14,
3663 "line": 35
3664 }
3665 }
3666 ],
3667 "path": "src/components/settings/user/EditUserForm.json"
3668 },
3669 {
3670 "descriptors": [
3671 {
3672 "defaultMessage": "!!!Choose from more than 70 Services",
3673 "end": {
3674 "column": 3,
3675 "line": 11
3676 },
3677 "file": "src/components/ui/FeatureList.js",
3678 "id": "pricing.features.recipes",
3679 "start": {
3680 "column": 20,
3681 "line": 8
3682 }
3683 },
3684 {
3685 "defaultMessage": "!!!Account Synchronisation",
3686 "end": {
3687 "column": 3,
3688 "line": 15
3689 },
3690 "file": "src/components/ui/FeatureList.js",
3691 "id": "pricing.features.accountSync",
3692 "start": {
3693 "column": 15,
3694 "line": 12
3695 }
3696 },
3697 {
3698 "defaultMessage": "!!!Desktop Notifications",
3699 "end": {
3700 "column": 3,
3701 "line": 19
3702 },
3703 "file": "src/components/ui/FeatureList.js",
3704 "id": "pricing.features.desktopNotifications",
3705 "start": {
3706 "column": 24,
3707 "line": 16
3708 }
3709 },
3710 {
3711 "defaultMessage": "!!!Add unlimited services",
3712 "end": {
3713 "column": 3,
3714 "line": 23
3715 },
3716 "file": "src/components/ui/FeatureList.js",
3717 "id": "pricing.features.unlimitedServices",
3718 "start": {
3719 "column": 21,
3720 "line": 20
3721 }
3722 },
3723 {
3724 "defaultMessage": "!!!Spellchecker support",
3725 "end": {
3726 "column": 3,
3727 "line": 27
3728 },
3729 "file": "src/components/ui/FeatureList.js",
3730 "id": "pricing.features.spellchecker",
3731 "start": {
3732 "column": 16,
3733 "line": 24
3734 }
3735 },
3736 {
3737 "defaultMessage": "!!!Workspaces",
3738 "end": {
3739 "column": 3,
3740 "line": 31
3741 },
3742 "file": "src/components/ui/FeatureList.js",
3743 "id": "pricing.features.workspaces",
3744 "start": {
3745 "column": 14,
3746 "line": 28
3747 }
3748 },
3749 {
3750 "defaultMessage": "!!!Add Custom Websites",
3751 "end": {
3752 "column": 3,
3753 "line": 35
3754 },
3755 "file": "src/components/ui/FeatureList.js",
3756 "id": "pricing.features.customWebsites",
3757 "start": {
3758 "column": 18,
3759 "line": 32
3760 }
3761 },
3762 {
3763 "defaultMessage": "!!!On-premise & other Hosted Services",
3764 "end": {
3765 "column": 3,
3766 "line": 39
3767 },
3768 "file": "src/components/ui/FeatureList.js",
3769 "id": "pricing.features.onPremise",
3770 "start": {
3771 "column": 13,
3772 "line": 36
3773 }
3774 },
3775 {
3776 "defaultMessage": "!!!Install 3rd party services",
3777 "end": {
3778 "column": 3,
3779 "line": 43
3780 },
3781 "file": "src/components/ui/FeatureList.js",
3782 "id": "pricing.features.thirdPartyServices",
3783 "start": {
3784 "column": 22,
3785 "line": 40
3786 }
3787 },
3788 {
3789 "defaultMessage": "!!!Service Proxies",
3790 "end": {
3791 "column": 3,
3792 "line": 47
3793 },
3794 "file": "src/components/ui/FeatureList.js",
3795 "id": "pricing.features.serviceProxies",
3796 "start": {
3797 "column": 18,
3798 "line": 44
3799 }
3800 },
3801 {
3802 "defaultMessage": "!!!Team Management",
3803 "end": {
3804 "column": 3,
3805 "line": 51
3806 },
3807 "file": "src/components/ui/FeatureList.js",
3808 "id": "pricing.features.teamManagement",
3809 "start": {
3810 "column": 18,
3811 "line": 48
3812 }
3813 }
3814 ],
3815 "path": "src/components/ui/FeatureList.json"
3816 },
3817 {
3818 "descriptors": [
3819 {
3820 "defaultMessage": "!!!Hide",
3821 "end": {
3822 "column": 3,
3823 "line": 15
3824 },
3825 "file": "src/components/ui/InfoBar.js",
3826 "id": "infobar.hide",
3827 "start": {
3828 "column": 8,
3829 "line": 12
3830 }
3831 }
3832 ],
3833 "path": "src/components/ui/InfoBar.json"
3834 },
3835 {
3836 "descriptors": [
3837 {
3838 "defaultMessage": "!!!Dismiss",
3839 "end": {
3840 "column": 3,
3841 "line": 12
3842 },
3843 "file": "src/components/ui/Infobox.js",
3844 "id": "infobox.dismiss",
3845 "start": {
3846 "column": 11,
3847 "line": 9
3848 }
3849 }
3850 ],
3851 "path": "src/components/ui/Infobox.json"
3852 },
3853 {
3854 "descriptors": [
3855 {
3856 "defaultMessage": "!!!Password toggle",
3857 "end": {
3858 "column": 3,
3859 "line": 14
3860 },
3861 "file": "src/components/ui/Input.js",
3862 "id": "settings.app.form.passwordToggle",
3863 "start": {
3864 "column": 18,
3865 "line": 11
3866 }
3867 }
3868 ],
3869 "path": "src/components/ui/Input.json"
3870 },
3871 {
3872 "descriptors": [
3873 {
3874 "defaultMessage": "!!!Loading {service}",
3875 "end": {
3876 "column": 3,
3877 "line": 14
3878 },
3879 "file": "src/components/ui/WebviewLoader/index.js",
3880 "id": "service.webviewLoader.loading",
3881 "start": {
3882 "column": 11,
3883 "line": 11
3884 }
3885 }
3886 ],
3887 "path": "src/components/ui/WebviewLoader/index.json"
3888 },
3889 {
3890 "descriptors": [
3891 {
3892 "defaultMessage": "!!!Something went wrong.",
3893 "end": {
3894 "column": 3,
3895 "line": 14
3896 },
3897 "file": "src/components/util/ErrorBoundary/index.js",
3898 "id": "app.errorHandler.headline",
3899 "start": {
3900 "column": 12,
3901 "line": 11
3902 }
3903 },
3904 {
3905 "defaultMessage": "!!!Reload",
3906 "end": {
3907 "column": 3,
3908 "line": 18
3909 },
3910 "file": "src/components/util/ErrorBoundary/index.js",
3911 "id": "app.errorHandler.action",
3912 "start": {
3913 "column": 10,
3914 "line": 15
3915 }
3916 }
3917 ],
3918 "path": "src/components/util/ErrorBoundary/index.json"
3919 },
3920 {
3921 "descriptors": [
3922 {
3923 "defaultMessage": "!!!Name",
3924 "end": {
3925 "column": 3,
3926 "line": 31
3927 },
3928 "file": "src/containers/settings/EditServiceScreen.js",
3929 "id": "settings.service.form.name",
3930 "start": {
3931 "column": 8,
3932 "line": 28
3933 }
3934 },
3935 {
3936 "defaultMessage": "!!!Enable service",
3937 "end": {
3938 "column": 3,
3939 "line": 35
3940 },
3941 "file": "src/containers/settings/EditServiceScreen.js",
3942 "id": "settings.service.form.enableService",
3943 "start": {
3944 "column": 17,
3945 "line": 32
3946 }
3947 },
3948 {
3949 "defaultMessage": "!!!Enable hibernation",
3950 "end": {
3951 "column": 3,
3952 "line": 39
3953 },
3954 "file": "src/containers/settings/EditServiceScreen.js",
3955 "id": "settings.service.form.enableHibernation",
3956 "start": {
3957 "column": 21,
3958 "line": 36
3959 }
3960 },
3961 {
3962 "defaultMessage": "!!!Enable Notifications",
3963 "end": {
3964 "column": 3,
3965 "line": 43
3966 },
3967 "file": "src/containers/settings/EditServiceScreen.js",
3968 "id": "settings.service.form.enableNotification",
3969 "start": {
3970 "column": 22,
3971 "line": 40
3972 }
3973 },
3974 {
3975 "defaultMessage": "!!!Show unread message badges",
3976 "end": {
3977 "column": 3,
3978 "line": 47
3979 },
3980 "file": "src/containers/settings/EditServiceScreen.js",
3981 "id": "settings.service.form.enableBadge",
3982 "start": {
3983 "column": 15,
3984 "line": 44
3985 }
3986 },
3987 {
3988 "defaultMessage": "!!!Enable audio",
3989 "end": {
3990 "column": 3,
3991 "line": 51
3992 },
3993 "file": "src/containers/settings/EditServiceScreen.js",
3994 "id": "settings.service.form.enableAudio",
3995 "start": {
3996 "column": 15,
3997 "line": 48
3998 }
3999 },
4000 {
4001 "defaultMessage": "!!!Team",
4002 "end": {
4003 "column": 3,
4004 "line": 55
4005 },
4006 "file": "src/containers/settings/EditServiceScreen.js",
4007 "id": "settings.service.form.team",
4008 "start": {
4009 "column": 8,
4010 "line": 52
4011 }
4012 },
4013 {
4014 "defaultMessage": "!!!Service URL",
4015 "end": {
4016 "column": 3,
4017 "line": 59
4018 },
4019 "file": "src/containers/settings/EditServiceScreen.js",
4020 "id": "settings.service.form.customUrl",
4021 "start": {
4022 "column": 13,
4023 "line": 56
4024 }
4025 },
4026 {
4027 "defaultMessage": "!!!Show message badge for all new messages",
4028 "end": {
4029 "column": 3,
4030 "line": 63
4031 },
4032 "file": "src/containers/settings/EditServiceScreen.js",
4033 "id": "settings.service.form.indirectMessages",
4034 "start": {
4035 "column": 20,
4036 "line": 60
4037 }
4038 },
4039 {
4040 "defaultMessage": "!!!Custom icon",
4041 "end": {
4042 "column": 3,
4043 "line": 67
4044 },
4045 "file": "src/containers/settings/EditServiceScreen.js",
4046 "id": "settings.service.form.icon",
4047 "start": {
4048 "column": 8,
4049 "line": 64
4050 }
4051 },
4052 {
4053 "defaultMessage": "!!!Enable Dark Mode",
4054 "end": {
4055 "column": 3,
4056 "line": 71
4057 },
4058 "file": "src/containers/settings/EditServiceScreen.js",
4059 "id": "settings.service.form.enableDarkMode",
4060 "start": {
4061 "column": 18,
4062 "line": 68
4063 }
4064 },
4065 {
4066 "defaultMessage": "!!!Dark Reader Brightness",
4067 "end": {
4068 "column": 3,
4069 "line": 75
4070 },
4071 "file": "src/containers/settings/EditServiceScreen.js",
4072 "id": "settings.service.form.darkReaderBrightness",
4073 "start": {
4074 "column": 24,
4075 "line": 72
4076 }
4077 },
4078 {
4079 "defaultMessage": "!!!Dark Reader Contrast",
4080 "end": {
4081 "column": 3,
4082 "line": 79
4083 },
4084 "file": "src/containers/settings/EditServiceScreen.js",
4085 "id": "settings.service.form.darkReaderContrast",
4086 "start": {
4087 "column": 22,
4088 "line": 76
4089 }
4090 },
4091 {
4092 "defaultMessage": "!!!Dark Reader Sepia",
4093 "end": {
4094 "column": 3,
4095 "line": 83
4096 },
4097 "file": "src/containers/settings/EditServiceScreen.js",
4098 "id": "settings.service.form.darkReaderSepia",
4099 "start": {
4100 "column": 19,
4101 "line": 80
4102 }
4103 },
4104 {
4105 "defaultMessage": "!!!Use Proxy",
4106 "end": {
4107 "column": 3,
4108 "line": 87
4109 },
4110 "file": "src/containers/settings/EditServiceScreen.js",
4111 "id": "settings.service.form.proxy.isEnabled",
4112 "start": {
4113 "column": 15,
4114 "line": 84
4115 }
4116 },
4117 {
4118 "defaultMessage": "!!!Proxy Host/IP",
4119 "end": {
4120 "column": 3,
4121 "line": 91
4122 },
4123 "file": "src/containers/settings/EditServiceScreen.js",
4124 "id": "settings.service.form.proxy.host",
4125 "start": {
4126 "column": 13,
4127 "line": 88
4128 }
4129 },
4130 {
4131 "defaultMessage": "!!!Port",
4132 "end": {
4133 "column": 3,
4134 "line": 95
4135 },
4136 "file": "src/containers/settings/EditServiceScreen.js",
4137 "id": "settings.service.form.proxy.port",
4138 "start": {
4139 "column": 13,
4140 "line": 92
4141 }
4142 },
4143 {
4144 "defaultMessage": "!!!User",
4145 "end": {
4146 "column": 3,
4147 "line": 99
4148 },
4149 "file": "src/containers/settings/EditServiceScreen.js",
4150 "id": "settings.service.form.proxy.user",
4151 "start": {
4152 "column": 13,
4153 "line": 96
4154 }
4155 },
4156 {
4157 "defaultMessage": "!!!Password",
4158 "end": {
4159 "column": 3,
4160 "line": 103
4161 },
4162 "file": "src/containers/settings/EditServiceScreen.js",
4163 "id": "settings.service.form.proxy.password",
4164 "start": {
4165 "column": 17,
4166 "line": 100
4167 }
4168 }
4169 ],
4170 "path": "src/containers/settings/EditServiceScreen.json"
4171 },
4172 {
4173 "descriptors": [
4174 {
4175 "defaultMessage": "!!!Launch Ferdi on start",
4176 "end": {
4177 "column": 3,
4178 "line": 35
4179 },
4180 "file": "src/containers/settings/EditSettingsScreen.js",
4181 "id": "settings.app.form.autoLaunchOnStart",
4182 "start": {
4183 "column": 21,
4184 "line": 32
4185 }
4186 },
4187 {
4188 "defaultMessage": "!!!Open in background",
4189 "end": {
4190 "column": 3,
4191 "line": 39
4192 },
4193 "file": "src/containers/settings/EditSettingsScreen.js",
4194 "id": "settings.app.form.autoLaunchInBackground",
4195 "start": {
4196 "column": 26,
4197 "line": 36
4198 }
4199 },
4200 {
4201 "defaultMessage": "!!!Keep Ferdi in background when closing the window",
4202 "end": {
4203 "column": 3,
4204 "line": 43
4205 },
4206 "file": "src/containers/settings/EditSettingsScreen.js",
4207 "id": "settings.app.form.runInBackground",
4208 "start": {
4209 "column": 19,
4210 "line": 40
4211 }
4212 },
4213 {
4214 "defaultMessage": "!!!Start minimized",
4215 "end": {
4216 "column": 3,
4217 "line": 47
4218 },
4219 "file": "src/containers/settings/EditSettingsScreen.js",
4220 "id": "settings.app.form.startMinimized",
4221 "start": {
4222 "column": 18,
4223 "line": 44
4224 }
4225 },
4226 {
4227 "defaultMessage": "!!!Confirm when quitting Ferdi",
4228 "end": {
4229 "column": 3,
4230 "line": 51
4231 },
4232 "file": "src/containers/settings/EditSettingsScreen.js",
4233 "id": "settings.app.form.confirmOnQuit",
4234 "start": {
4235 "column": 17,
4236 "line": 48
4237 }
4238 },
4239 {
4240 "defaultMessage": "!!!Always show Ferdi in System Tray",
4241 "end": {
4242 "column": 3,
4243 "line": 55
4244 },
4245 "file": "src/containers/settings/EditSettingsScreen.js",
4246 "id": "settings.app.form.enableSystemTray",
4247 "start": {
4248 "column": 20,
4249 "line": 52
4250 }
4251 },
4252 {
4253 "defaultMessage": "!!!Always show Ferdi in Menu Bar",
4254 "end": {
4255 "column": 3,
4256 "line": 59
4257 },
4258 "file": "src/containers/settings/EditSettingsScreen.js",
4259 "id": "settings.app.form.enableMenuBar",
4260 "start": {
4261 "column": 17,
4262 "line": 56
4263 }
4264 },
4265 {
4266 "defaultMessage": "!!!Reload Ferdi after system resume",
4267 "end": {
4268 "column": 3,
4269 "line": 63
4270 },
4271 "file": "src/containers/settings/EditSettingsScreen.js",
4272 "id": "settings.app.form.reloadAfterResume",
4273 "start": {
4274 "column": 21,
4275 "line": 60
4276 }
4277 },
4278 {
4279 "defaultMessage": "!!!Minimize Ferdi to system tray",
4280 "end": {
4281 "column": 3,
4282 "line": 67
4283 },
4284 "file": "src/containers/settings/EditSettingsScreen.js",
4285 "id": "settings.app.form.minimizeToSystemTray",
4286 "start": {
4287 "column": 24,
4288 "line": 64
4289 }
4290 },
4291 {
4292 "defaultMessage": "!!!Close Ferdi to system tray",
4293 "end": {
4294 "column": 3,
4295 "line": 71
4296 },
4297 "file": "src/containers/settings/EditSettingsScreen.js",
4298 "id": "settings.app.form.closeToSystemTray",
4299 "start": {
4300 "column": 21,
4301 "line": 68
4302 }
4303 },
4304 {
4305 "defaultMessage": "!!!Don't show message content in notifications",
4306 "end": {
4307 "column": 3,
4308 "line": 75
4309 },
4310 "file": "src/containers/settings/EditSettingsScreen.js",
4311 "id": "settings.app.form.privateNotifications",
4312 "start": {
4313 "column": 24,
4314 "line": 72
4315 }
4316 },
4317 {
4318 "defaultMessage": "!!!Don't show notifications for clipboard events",
4319 "end": {
4320 "column": 3,
4321 "line": 79
4322 },
4323 "file": "src/containers/settings/EditSettingsScreen.js",
4324 "id": "settings.app.form.clipboardNotifications",
4325 "start": {
4326 "column": 26,
4327 "line": 76
4328 }
4329 },
4330 {
4331 "defaultMessage": "!!!Notify TaskBar/Dock on new message",
4332 "end": {
4333 "column": 3,
4334 "line": 83
4335 },
4336 "file": "src/containers/settings/EditSettingsScreen.js",
4337 "id": "settings.app.form.notifyTaskBarOnMessage",
4338 "start": {
4339 "column": 26,
4340 "line": 80
4341 }
4342 },
4343 {
4344 "defaultMessage": "!!!Navigation bar behaviour",
4345 "end": {
4346 "column": 3,
4347 "line": 87
4348 },
4349 "file": "src/containers/settings/EditSettingsScreen.js",
4350 "id": "settings.app.form.navigationBarBehaviour",
4351 "start": {
4352 "column": 26,
4353 "line": 84
4354 }
4355 },
4356 {
4357 "defaultMessage": "!!!Search engine",
4358 "end": {
4359 "column": 3,
4360 "line": 91
4361 },
4362 "file": "src/containers/settings/EditSettingsScreen.js",
4363 "id": "settings.app.form.searchEngine",
4364 "start": {
4365 "column": 16,
4366 "line": 88
4367 }
4368 },
4369 {
4370 "defaultMessage": "!!!Send telemetry data",
4371 "end": {
4372 "column": 3,
4373 "line": 95
4374 },
4375 "file": "src/containers/settings/EditSettingsScreen.js",
4376 "id": "settings.app.form.sentry",
4377 "start": {
4378 "column": 10,
4379 "line": 92
4380 }
4381 },
4382 {
4383 "defaultMessage": "!!!Keep services in hibernation on startup",
4384 "end": {
4385 "column": 3,
4386 "line": 99
4387 },
4388 "file": "src/containers/settings/EditSettingsScreen.js",
4389 "id": "settings.app.form.hibernateOnStartup",
4390 "start": {
4391 "column": 22,
4392 "line": 96
4393 }
4394 },
4395 {
4396 "defaultMessage": "!!!Hibernation strategy",
4397 "end": {
4398 "column": 3,
4399 "line": 103
4400 },
4401 "file": "src/containers/settings/EditSettingsScreen.js",
4402 "id": "settings.app.form.hibernationStrategy",
4403 "start": {
4404 "column": 23,
4405 "line": 100
4406 }
4407 },
4408 {
4409 "defaultMessage": "!!!Wake up strategy",
4410 "end": {
4411 "column": 3,
4412 "line": 107
4413 },
4414 "file": "src/containers/settings/EditSettingsScreen.js",
4415 "id": "settings.app.form.wakeUpStrategy",
4416 "start": {
4417 "column": 18,
4418 "line": 104
4419 }
4420 },
4421 {
4422 "defaultMessage": "!!!Todo Server",
4423 "end": {
4424 "column": 3,
4425 "line": 111
4426 },
4427 "file": "src/containers/settings/EditSettingsScreen.js",
4428 "id": "settings.app.form.predefinedTodoServer",
4429 "start": {
4430 "column": 24,
4431 "line": 108
4432 }
4433 },
4434 {
4435 "defaultMessage": "!!!Custom TodoServer",
4436 "end": {
4437 "column": 3,
4438 "line": 115
4439 },
4440 "file": "src/containers/settings/EditSettingsScreen.js",
4441 "id": "settings.app.form.customTodoServer",
4442 "start": {
4443 "column": 20,
4444 "line": 112
4445 }
4446 },
4447 {
4448 "defaultMessage": "!!!Enable Password Lock",
4449 "end": {
4450 "column": 3,
4451 "line": 119
4452 },
4453 "file": "src/containers/settings/EditSettingsScreen.js",
4454 "id": "settings.app.form.enableLock",
4455 "start": {
4456 "column": 14,
4457 "line": 116
4458 }
4459 },
4460 {
4461 "defaultMessage": "!!!Password",
4462 "end": {
4463 "column": 3,
4464 "line": 123
4465 },
4466 "file": "src/containers/settings/EditSettingsScreen.js",
4467 "id": "settings.app.form.lockPassword",
4468 "start": {
4469 "column": 16,
4470 "line": 120
4471 }
4472 },
4473 {
4474 "defaultMessage": "!!!Allow using Touch ID to unlock",
4475 "end": {
4476 "column": 3,
4477 "line": 127
4478 },
4479 "file": "src/containers/settings/EditSettingsScreen.js",
4480 "id": "settings.app.form.useTouchIdToUnlock",
4481 "start": {
4482 "column": 22,
4483 "line": 124
4484 }
4485 },
4486 {
4487 "defaultMessage": "!!!Lock after inactivity",
4488 "end": {
4489 "column": 3,
4490 "line": 131
4491 },
4492 "file": "src/containers/settings/EditSettingsScreen.js",
4493 "id": "settings.app.form.inactivityLock",
4494 "start": {
4495 "column": 18,
4496 "line": 128
4497 }
4498 },
4499 {
4500 "defaultMessage": "!!!Enable scheduled Do-not-Disturb",
4501 "end": {
4502 "column": 3,
4503 "line": 135
4504 },
4505 "file": "src/containers/settings/EditSettingsScreen.js",
4506 "id": "settings.app.form.scheduledDNDEnabled",
4507 "start": {
4508 "column": 23,
4509 "line": 132
4510 }
4511 },
4512 {
4513 "defaultMessage": "!!!From",
4514 "end": {
4515 "column": 3,
4516 "line": 139
4517 },
4518 "file": "src/containers/settings/EditSettingsScreen.js",
4519 "id": "settings.app.form.scheduledDNDStart",
4520 "start": {
4521 "column": 21,
4522 "line": 136
4523 }
4524 },
4525 {
4526 "defaultMessage": "!!!To",
4527 "end": {
4528 "column": 3,
4529 "line": 143
4530 },
4531 "file": "src/containers/settings/EditSettingsScreen.js",
4532 "id": "settings.app.form.scheduledDNDEnd",
4533 "start": {
4534 "column": 19,
4535 "line": 140
4536 }
4537 },
4538 {
4539 "defaultMessage": "!!!Language",
4540 "end": {
4541 "column": 3,
4542 "line": 147
4543 },
4544 "file": "src/containers/settings/EditSettingsScreen.js",
4545 "id": "settings.app.form.language",
4546 "start": {
4547 "column": 12,
4548 "line": 144
4549 }
4550 },
4551 {
4552 "defaultMessage": "!!!Dark Mode",
4553 "end": {
4554 "column": 3,
4555 "line": 151
4556 },
4557 "file": "src/containers/settings/EditSettingsScreen.js",
4558 "id": "settings.app.form.darkMode",
4559 "start": {
4560 "column": 12,
4561 "line": 148
4562 }
4563 },
4564 {
4565 "defaultMessage": "!!!Synchronize dark mode with my OS's dark mode setting",
4566 "end": {
4567 "column": 3,
4568 "line": 155
4569 },
4570 "file": "src/containers/settings/EditSettingsScreen.js",
4571 "id": "settings.app.form.adaptableDarkMode",
4572 "start": {
4573 "column": 21,
4574 "line": 152
4575 }
4576 },
4577 {
4578 "defaultMessage": "!!!Enable universal Dark Mode",
4579 "end": {
4580 "column": 3,
4581 "line": 159
4582 },
4583 "file": "src/containers/settings/EditSettingsScreen.js",
4584 "id": "settings.app.form.universalDarkMode",
4585 "start": {
4586 "column": 21,
4587 "line": 156
4588 }
4589 },
4590 {
4591 "defaultMessage": "!!!Sidebar width",
4592 "end": {
4593 "column": 3,
4594 "line": 163
4595 },
4596 "file": "src/containers/settings/EditSettingsScreen.js",
4597 "id": "settings.app.form.serviceRibbonWidth",
4598 "start": {
4599 "column": 22,
4600 "line": 160
4601 }
4602 },
4603 {
4604 "defaultMessage": "!!!Service icon size",
4605 "end": {
4606 "column": 3,
4607 "line": 167
4608 },
4609 "file": "src/containers/settings/EditSettingsScreen.js",
4610 "id": "settings.app.form.iconSize",
4611 "start": {
4612 "column": 12,
4613 "line": 164
4614 }
4615 },
4616 {
4617 "defaultMessage": "!!!Use horizontal style",
4618 "end": {
4619 "column": 3,
4620 "line": 171
4621 },
4622 "file": "src/containers/settings/EditSettingsScreen.js",
4623 "id": "settings.app.form.useVerticalStyle",
4624 "start": {
4625 "column": 20,
4626 "line": 168
4627 }
4628 },
4629 {
4630 "defaultMessage": "!!!Always show workspace drawer",
4631 "end": {
4632 "column": 3,
4633 "line": 175
4634 },
4635 "file": "src/containers/settings/EditSettingsScreen.js",
4636 "id": "settings.app.form.alwaysShowWorkspaces",
4637 "start": {
4638 "column": 24,
4639 "line": 172
4640 }
4641 },
4642 {
4643 "defaultMessage": "!!!Accent color",
4644 "end": {
4645 "column": 3,
4646 "line": 179
4647 },
4648 "file": "src/containers/settings/EditSettingsScreen.js",
4649 "id": "settings.app.form.accentColor",
4650 "start": {
4651 "column": 15,
4652 "line": 176
4653 }
4654 },
4655 {
4656 "defaultMessage": "!!!Display disabled services tabs",
4657 "end": {
4658 "column": 3,
4659 "line": 183
4660 },
4661 "file": "src/containers/settings/EditSettingsScreen.js",
4662 "id": "settings.app.form.showDisabledServices",
4663 "start": {
4664 "column": 24,
4665 "line": 180
4666 }
4667 },
4668 {
4669 "defaultMessage": "!!!Show unread message badge when notifications are disabled",
4670 "end": {
4671 "column": 3,
4672 "line": 187
4673 },
4674 "file": "src/containers/settings/EditSettingsScreen.js",
4675 "id": "settings.app.form.showMessagesBadgesWhenMuted",
4676 "start": {
4677 "column": 29,
4678 "line": 184
4679 }
4680 },
4681 {
4682 "defaultMessage": "!!!Show draggable area on window",
4683 "end": {
4684 "column": 3,
4685 "line": 191
4686 },
4687 "file": "src/containers/settings/EditSettingsScreen.js",
4688 "id": "settings.app.form.showDragArea",
4689 "start": {
4690 "column": 16,
4691 "line": 188
4692 }
4693 },
4694 {
4695 "defaultMessage": "!!!Enable spell checking",
4696 "end": {
4697 "column": 3,
4698 "line": 195
4699 },
4700 "file": "src/containers/settings/EditSettingsScreen.js",
4701 "id": "settings.app.form.enableSpellchecking",
4702 "start": {
4703 "column": 23,
4704 "line": 192
4705 }
4706 },
4707 {
4708 "defaultMessage": "!!!Enable GPU Acceleration",
4709 "end": {
4710 "column": 3,
4711 "line": 199
4712 },
4713 "file": "src/containers/settings/EditSettingsScreen.js",
4714 "id": "settings.app.form.enableGPUAcceleration",
4715 "start": {
4716 "column": 25,
4717 "line": 196
4718 }
4719 },
4720 {
4721 "defaultMessage": "!!!Include beta versions",
4722 "end": {
4723 "column": 3,
4724 "line": 203
4725 },
4726 "file": "src/containers/settings/EditSettingsScreen.js",
4727 "id": "settings.app.form.beta",
4728 "start": {
4729 "column": 8,
4730 "line": 200
4731 }
4732 },
4733 {
4734 "defaultMessage": "!!!Enable updates",
4735 "end": {
4736 "column": 3,
4737 "line": 207
4738 },
4739 "file": "src/containers/settings/EditSettingsScreen.js",
4740 "id": "settings.app.form.automaticUpdates",
4741 "start": {
4742 "column": 20,
4743 "line": 204
4744 }
4745 },
4746 {
4747 "defaultMessage": "!!!Enable Franz Todos",
4748 "end": {
4749 "column": 3,
4750 "line": 211
4751 },
4752 "file": "src/containers/settings/EditSettingsScreen.js",
4753 "id": "settings.app.form.enableTodos",
4754 "start": {
4755 "column": 15,
4756 "line": 208
4757 }
4758 },
4759 {
4760 "defaultMessage": "!!!Keep all workspaces loaded",
4761 "end": {
4762 "column": 3,
4763 "line": 215
4764 },
4765 "file": "src/containers/settings/EditSettingsScreen.js",
4766 "id": "settings.app.form.keepAllWorkspacesLoaded",
4767 "start": {
4768 "column": 27,
4769 "line": 212
4770 }
4771 }
4772 ],
4773 "path": "src/containers/settings/EditSettingsScreen.json"
4774 },
4775 {
4776 "descriptors": [
4777 {
4778 "defaultMessage": "!!!Firstname",
4779 "end": {
4780 "column": 3,
4781 "line": 17
4782 },
4783 "file": "src/containers/settings/EditUserScreen.js",
4784 "id": "settings.user.form.firstname",
4785 "start": {
4786 "column": 13,
4787 "line": 14
4788 }
4789 },
4790 {
4791 "defaultMessage": "!!!Lastname",
4792 "end": {
4793 "column": 3,
4794 "line": 21
4795 },
4796 "file": "src/containers/settings/EditUserScreen.js",
4797 "id": "settings.user.form.lastname",
4798 "start": {
4799 "column": 12,
4800 "line": 18
4801 }
4802 },
4803 {
4804 "defaultMessage": "!!!Email",
4805 "end": {
4806 "column": 3,
4807 "line": 25
4808 },
4809 "file": "src/containers/settings/EditUserScreen.js",
4810 "id": "settings.user.form.email",
4811 "start": {
4812 "column": 9,
4813 "line": 22
4814 }
4815 },
4816 {
4817 "defaultMessage": "!!!Account type",
4818 "end": {
4819 "column": 3,
4820 "line": 29
4821 },
4822 "file": "src/containers/settings/EditUserScreen.js",
4823 "id": "settings.user.form.accountType.label",
4824 "start": {
4825 "column": 20,
4826 "line": 26
4827 }
4828 },
4829 {
4830 "defaultMessage": "!!!Individual",
4831 "end": {
4832 "column": 3,
4833 "line": 33
4834 },
4835 "file": "src/containers/settings/EditUserScreen.js",
4836 "id": "settings.user.form.accountType.individual",
4837 "start": {
4838 "column": 25,
4839 "line": 30
4840 }
4841 },
4842 {
4843 "defaultMessage": "!!!Non-Profit",
4844 "end": {
4845 "column": 3,
4846 "line": 37
4847 },
4848 "file": "src/containers/settings/EditUserScreen.js",
4849 "id": "settings.user.form.accountType.non-profit",
4850 "start": {
4851 "column": 24,
4852 "line": 34
4853 }
4854 },
4855 {
4856 "defaultMessage": "!!!Company",
4857 "end": {
4858 "column": 3,
4859 "line": 41
4860 },
4861 "file": "src/containers/settings/EditUserScreen.js",
4862 "id": "settings.user.form.accountType.company",
4863 "start": {
4864 "column": 22,
4865 "line": 38
4866 }
4867 },
4868 {
4869 "defaultMessage": "!!!Current password",
4870 "end": {
4871 "column": 3,
4872 "line": 45
4873 },
4874 "file": "src/containers/settings/EditUserScreen.js",
4875 "id": "settings.user.form.currentPassword",
4876 "start": {
4877 "column": 19,
4878 "line": 42
4879 }
4880 },
4881 {
4882 "defaultMessage": "!!!New password",
4883 "end": {
4884 "column": 3,
4885 "line": 49
4886 },
4887 "file": "src/containers/settings/EditUserScreen.js",
4888 "id": "settings.user.form.newPassword",
4889 "start": {
4890 "column": 15,
4891 "line": 46
4892 }
4893 }
4894 ],
4895 "path": "src/containers/settings/EditUserScreen.json"
4896 },
4897 {
4898 "descriptors": [
4899 {
4900 "defaultMessage": "!!!Sign In",
4901 "end": {
4902 "column": 3,
4903 "line": 27
4904 },
4905 "file": "src/features/basicAuth/Component.js",
4906 "id": "feature.basicAuth.signIn",
4907 "start": {
4908 "column": 10,
4909 "line": 24
4910 }
4911 }
4912 ],
4913 "path": "src/features/basicAuth/Component.json"
4914 },
4915 {
4916 "descriptors": [
4917 {
4918 "defaultMessage": "!!!Publish debugging information",
4919 "end": {
4920 "column": 3,
4921 "line": 19
4922 },
4923 "file": "src/features/debugger/Component.js",
4924 "id": "feature.debugger.title",
4925 "start": {
4926 "column": 9,
4927 "line": 16
4928 }
4929 }
4930 ],
4931 "path": "src/features/debugger/Component.json"
4932 },
4933 {
4934 "descriptors": [
4935 {
4936 "defaultMessage": "!!!Nightly Builds",
4937 "end": {
4938 "column": 3,
4939 "line": 20
4940 },
4941 "file": "src/features/nightlyBuilds/Component.js",
4942 "id": "feature.nightlyBuilds.title",
4943 "start": {
4944 "column": 9,
4945 "line": 17
4946 }
4947 },
4948 {
4949 "defaultMessage": "!!!Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
4950 "end": {
4951 "column": 3,
4952 "line": 24
4953 },
4954 "file": "src/features/nightlyBuilds/Component.js",
4955 "id": "feature.nightlyBuilds.info",
4956 "start": {
4957 "column": 8,
4958 "line": 21
4959 }
4960 },
4961 {
4962 "defaultMessage": "!!!Activate",
4963 "end": {
4964 "column": 3,
4965 "line": 28
4966 },
4967 "file": "src/features/nightlyBuilds/Component.js",
4968 "id": "feature.nightlyBuilds.activate",
4969 "start": {
4970 "column": 12,
4971 "line": 25
4972 }
4973 }
4974 ],
4975 "path": "src/features/nightlyBuilds/Component.json"
4976 },
4977 {
4978 "descriptors": [
4979 {
4980 "defaultMessage": "!!!Publish debug information",
4981 "end": {
4982 "column": 3,
4983 "line": 22
4984 },
4985 "file": "src/features/publishDebugInfo/Component.js",
4986 "id": "feature.publishDebugInfo.title",
4987 "start": {
4988 "column": 9,
4989 "line": 19
4990 }
4991 },
4992 {
4993 "defaultMessage": "!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service",
4994 "end": {
4995 "column": 3,
4996 "line": 26
4997 },
4998 "file": "src/features/publishDebugInfo/Component.js",
4999 "id": "feature.publishDebugInfo.info",
5000 "start": {
5001 "column": 8,
5002 "line": 23
5003 }
5004 },
5005 {
5006 "defaultMessage": "!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.",
5007 "end": {
5008 "column": 3,
5009 "line": 30
5010 },
5011 "file": "src/features/publishDebugInfo/Component.js",
5012 "id": "feature.publishDebugInfo.error",
5013 "start": {
5014 "column": 9,
5015 "line": 27
5016 }
5017 },
5018 {
5019 "defaultMessage": "!!!Privacy policy",
5020 "end": {
5021 "column": 3,
5022 "line": 34
5023 },
5024 "file": "src/features/publishDebugInfo/Component.js",
5025 "id": "feature.publishDebugInfo.privacy",
5026 "start": {
5027 "column": 11,
5028 "line": 31
5029 }
5030 },
5031 {
5032 "defaultMessage": "!!!Terms of service",
5033 "end": {
5034 "column": 3,
5035 "line": 38
5036 },
5037 "file": "src/features/publishDebugInfo/Component.js",
5038 "id": "feature.publishDebugInfo.terms",
5039 "start": {
5040 "column": 9,
5041 "line": 35
5042 }
5043 },
5044 {
5045 "defaultMessage": "!!!Accept and publish",
5046 "end": {
5047 "column": 3,
5048 "line": 42
5049 },
5050 "file": "src/features/publishDebugInfo/Component.js",
5051 "id": "feature.publishDebugInfo.publish",
5052 "start": {
5053 "column": 11,
5054 "line": 39
5055 }
5056 },
5057 {
5058 "defaultMessage": "!!!Your debug log was published and is now availible at",
5059 "end": {
5060 "column": 3,
5061 "line": 46
5062 },
5063 "file": "src/features/publishDebugInfo/Component.js",
5064 "id": "feature.publishDebugInfo.published",
5065 "start": {
5066 "column": 13,
5067 "line": 43
5068 }
5069 }
5070 ],
5071 "path": "src/features/publishDebugInfo/Component.json"
5072 },
5073 {
5074 "descriptors": [
5075 {
5076 "defaultMessage": "!!!QuickSwitch",
5077 "end": {
5078 "column": 3,
5079 "line": 20
5080 },
5081 "file": "src/features/quickSwitch/Component.js",
5082 "id": "feature.quickSwitch.title",
5083 "start": {
5084 "column": 9,
5085 "line": 17
5086 }
5087 },
5088 {
5089 "defaultMessage": "!!!Search...",
5090 "end": {
5091 "column": 3,
5092 "line": 24
5093 },
5094 "file": "src/features/quickSwitch/Component.js",
5095 "id": "feature.quickSwitch.search",
5096 "start": {
5097 "column": 10,
5098 "line": 21
5099 }
5100 },
5101 {
5102 "defaultMessage": "!!!Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
5103 "end": {
5104 "column": 3,
5105 "line": 28
5106 },
5107 "file": "src/features/quickSwitch/Component.js",
5108 "id": "feature.quickSwitch.info",
5109 "start": {
5110 "column": 8,
5111 "line": 25
5112 }
5113 }
5114 ],
5115 "path": "src/features/quickSwitch/Component.json"
5116 },
5117 {
5118 "descriptors": [
5119 {
5120 "defaultMessage": "!!!Home",
5121 "end": {
5122 "column": 3,
5123 "line": 16
5124 },
5125 "file": "src/features/recipeConnectionLost/components/WebControls.js",
5126 "id": "webControls.goHome",
5127 "start": {
5128 "column": 10,
5129 "line": 13
5130 }
5131 },
5132 {
5133 "defaultMessage": "!!!Open in Browser",
5134 "end": {
5135 "column": 3,
5136 "line": 20
5137 },
5138 "file": "src/features/recipeConnectionLost/components/WebControls.js",
5139 "id": "webControls.openInBrowser",
5140 "start": {
5141 "column": 17,
5142 "line": 17
5143 }
5144 },
5145 {
5146 "defaultMessage": "!!!Back",
5147 "end": {
5148 "column": 3,
5149 "line": 24
5150 },
5151 "file": "src/features/recipeConnectionLost/components/WebControls.js",
5152 "id": "webControls.back",
5153 "start": {
5154 "column": 8,
5155 "line": 21
5156 }
5157 },
5158 {
5159 "defaultMessage": "!!!Forward",
5160 "end": {
5161 "column": 3,
5162 "line": 28
5163 },
5164 "file": "src/features/recipeConnectionLost/components/WebControls.js",
5165 "id": "webControls.forward",
5166 "start": {
5167 "column": 11,
5168 "line": 25
5169 }
5170 },
5171 {
5172 "defaultMessage": "!!!Reload",
5173 "end": {
5174 "column": 3,
5175 "line": 32
5176 },
5177 "file": "src/features/recipeConnectionLost/components/WebControls.js",
5178 "id": "webControls.reload",
5179 "start": {
5180 "column": 10,
5181 "line": 29
5182 }
5183 }
5184 ],
5185 "path": "src/features/recipeConnectionLost/components/WebControls.json"
5186 },
5187 {
5188 "descriptors": [
5189 {
5190 "defaultMessage": "!!!Home",
5191 "end": {
5192 "column": 3,
5193 "line": 20
5194 },
5195 "file": "src/features/webControls/components/WebControls.js",
5196 "id": "webControls.goHome",
5197 "start": {
5198 "column": 10,
5199 "line": 17
5200 }
5201 },
5202 {
5203 "defaultMessage": "!!!Open in Browser",
5204 "end": {
5205 "column": 3,
5206 "line": 24
5207 },
5208 "file": "src/features/webControls/components/WebControls.js",
5209 "id": "webControls.openInBrowser",
5210 "start": {
5211 "column": 17,
5212 "line": 21
5213 }
5214 },
5215 {
5216 "defaultMessage": "!!!Back",
5217 "end": {
5218 "column": 3,
5219 "line": 28
5220 },
5221 "file": "src/features/webControls/components/WebControls.js",
5222 "id": "webControls.back",
5223 "start": {
5224 "column": 8,
5225 "line": 25
5226 }
5227 },
5228 {
5229 "defaultMessage": "!!!Forward",
5230 "end": {
5231 "column": 3,
5232 "line": 32
5233 },
5234 "file": "src/features/webControls/components/WebControls.js",
5235 "id": "webControls.forward",
5236 "start": {
5237 "column": 11,
5238 "line": 29
5239 }
5240 },
5241 {
5242 "defaultMessage": "!!!Reload",
5243 "end": {
5244 "column": 3,
5245 "line": 36
5246 },
5247 "file": "src/features/webControls/components/WebControls.js",
5248 "id": "webControls.reload",
5249 "start": {
5250 "column": 10,
5251 "line": 33
5252 }
5253 }
5254 ],
5255 "path": "src/features/webControls/components/WebControls.json"
5256 },
5257 {
5258 "descriptors": [
5259 {
5260 "defaultMessage": "!!!Create workspace",
5261 "end": {
5262 "column": 3,
5263 "line": 15
5264 },
5265 "file": "src/features/workspaces/components/CreateWorkspaceForm.js",
5266 "id": "settings.workspace.add.form.submitButton",
5267 "start": {
5268 "column": 16,
5269 "line": 12
5270 }
5271 },
5272 {
5273 "defaultMessage": "!!!Name",
5274 "end": {
5275 "column": 3,
5276 "line": 19
5277 },
5278 "file": "src/features/workspaces/components/CreateWorkspaceForm.js",
5279 "id": "settings.workspace.add.form.name",
5280 "start": {
5281 "column": 8,
5282 "line": 16
5283 }
5284 }
5285 ],
5286 "path": "src/features/workspaces/components/CreateWorkspaceForm.json"
5287 },
5288 {
5289 "descriptors": [
5290 {
5291 "defaultMessage": "!!!Delete workspace",
5292 "end": {
5293 "column": 3,
5294 "line": 24
5295 },
5296 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5297 "id": "settings.workspace.form.buttonDelete",
5298 "start": {
5299 "column": 16,
5300 "line": 21
5301 }
5302 },
5303 {
5304 "defaultMessage": "!!!Save workspace",
5305 "end": {
5306 "column": 3,
5307 "line": 28
5308 },
5309 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5310 "id": "settings.workspace.form.buttonSave",
5311 "start": {
5312 "column": 14,
5313 "line": 25
5314 }
5315 },
5316 {
5317 "defaultMessage": "!!!Name",
5318 "end": {
5319 "column": 3,
5320 "line": 32
5321 },
5322 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5323 "id": "settings.workspace.form.name",
5324 "start": {
5325 "column": 8,
5326 "line": 29
5327 }
5328 },
5329 {
5330 "defaultMessage": "!!!Your workspaces",
5331 "end": {
5332 "column": 3,
5333 "line": 36
5334 },
5335 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5336 "id": "settings.workspace.form.yourWorkspaces",
5337 "start": {
5338 "column": 18,
5339 "line": 33
5340 }
5341 },
5342 {
5343 "defaultMessage": "!!!Keep this workspace loaded*",
5344 "end": {
5345 "column": 3,
5346 "line": 40
5347 },
5348 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5349 "id": "settings.workspace.form.keepLoaded",
5350 "start": {
5351 "column": 14,
5352 "line": 37
5353 }
5354 },
5355 {
5356 "defaultMessage": "!!!*This option will be overwritten by the global \"Keep all workspaces loaded\" option.",
5357 "end": {
5358 "column": 3,
5359 "line": 45
5360 },
5361 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5362 "id": "settings.workspace.form.keepLoadedInfo",
5363 "start": {
5364 "column": 18,
5365 "line": 41
5366 }
5367 },
5368 {
5369 "defaultMessage": "!!!Services in this Workspace",
5370 "end": {
5371 "column": 3,
5372 "line": 49
5373 },
5374 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5375 "id": "settings.workspace.form.servicesInWorkspaceHeadline",
5376 "start": {
5377 "column": 31,
5378 "line": 46
5379 }
5380 },
5381 {
5382 "defaultMessage": "!!!Start by adding a service.",
5383 "end": {
5384 "column": 3,
5385 "line": 53
5386 },
5387 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5388 "id": "settings.services.noServicesAdded",
5389 "start": {
5390 "column": 19,
5391 "line": 50
5392 }
5393 },
5394 {
5395 "defaultMessage": "!!!Discover services",
5396 "end": {
5397 "column": 3,
5398 "line": 57
5399 },
5400 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
5401 "id": "settings.services.discoverServices",
5402 "start": {
5403 "column": 20,
5404 "line": 54
5405 }
5406 }
5407 ],
5408 "path": "src/features/workspaces/components/EditWorkspaceForm.json"
5409 },
5410 {
5411 "descriptors": [
5412 {
5413 "defaultMessage": "!!!Workspaces",
5414 "end": {
5415 "column": 3,
5416 "line": 18
5417 },
5418 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
5419 "id": "workspaceDrawer.headline",
5420 "start": {
5421 "column": 12,
5422 "line": 15
5423 }
5424 },
5425 {
5426 "defaultMessage": "!!!All services",
5427 "end": {
5428 "column": 3,
5429 "line": 22
5430 },
5431 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
5432 "id": "workspaceDrawer.allServices",
5433 "start": {
5434 "column": 15,
5435 "line": 19
5436 }
5437 },
5438 {
5439 "defaultMessage": "!!!Workspaces settings",
5440 "end": {
5441 "column": 3,
5442 "line": 26
5443 },
5444 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
5445 "id": "workspaceDrawer.workspacesSettingsTooltip",
5446 "start": {
5447 "column": 29,
5448 "line": 23
5449 }
5450 },
5451 {
5452 "defaultMessage": "!!!Info about workspace feature",
5453 "end": {
5454 "column": 3,
5455 "line": 30
5456 },
5457 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
5458 "id": "workspaceDrawer.workspaceFeatureInfo",
5459 "start": {
5460 "column": 24,
5461 "line": 27
5462 }
5463 },
5464 {
5465 "defaultMessage": "!!!add new workspace",
5466 "end": {
5467 "column": 3,
5468 "line": 34
5469 },
5470 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
5471 "id": "workspaceDrawer.addNewWorkspaceLabel",
5472 "start": {
5473 "column": 24,
5474 "line": 31
5475 }
5476 }
5477 ],
5478 "path": "src/features/workspaces/components/WorkspaceDrawer.json"
5479 },
5480 {
5481 "descriptors": [
5482 {
5483 "defaultMessage": "!!!No services added yet",
5484 "end": {
5485 "column": 3,
5486 "line": 14
5487 },
5488 "file": "src/features/workspaces/components/WorkspaceDrawerItem.js",
5489 "id": "workspaceDrawer.item.noServicesAddedYet",
5490 "start": {
5491 "column": 22,
5492 "line": 11
5493 }
5494 },
5495 {
5496 "defaultMessage": "!!!edit",
5497 "end": {
5498 "column": 3,
5499 "line": 18
5500 },
5501 "file": "src/features/workspaces/components/WorkspaceDrawerItem.js",
5502 "id": "workspaceDrawer.item.contextMenuEdit",
5503 "start": {
5504 "column": 19,
5505 "line": 15
5506 }
5507 }
5508 ],
5509 "path": "src/features/workspaces/components/WorkspaceDrawerItem.json"
5510 },
5511 {
5512 "descriptors": [
5513 {
5514 "defaultMessage": "!!!Your workspaces",
5515 "end": {
5516 "column": 3,
5517 "line": 20
5518 },
5519 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5520 "id": "settings.workspaces.headline",
5521 "start": {
5522 "column": 12,
5523 "line": 17
5524 }
5525 },
5526 {
5527 "defaultMessage": "!!!You haven't created any workspaces yet.",
5528 "end": {
5529 "column": 3,
5530 "line": 24
5531 },
5532 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5533 "id": "settings.workspaces.noWorkspacesAdded",
5534 "start": {
5535 "column": 19,
5536 "line": 21
5537 }
5538 },
5539 {
5540 "defaultMessage": "!!!Could not load your workspaces",
5541 "end": {
5542 "column": 3,
5543 "line": 28
5544 },
5545 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5546 "id": "settings.workspaces.workspacesRequestFailed",
5547 "start": {
5548 "column": 27,
5549 "line": 25
5550 }
5551 },
5552 {
5553 "defaultMessage": "!!!Try again",
5554 "end": {
5555 "column": 3,
5556 "line": 32
5557 },
5558 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5559 "id": "settings.workspaces.tryReloadWorkspaces",
5560 "start": {
5561 "column": 23,
5562 "line": 29
5563 }
5564 },
5565 {
5566 "defaultMessage": "!!!Your changes have been saved",
5567 "end": {
5568 "column": 3,
5569 "line": 36
5570 },
5571 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5572 "id": "settings.workspaces.updatedInfo",
5573 "start": {
5574 "column": 15,
5575 "line": 33
5576 }
5577 },
5578 {
5579 "defaultMessage": "!!!Workspace has been deleted",
5580 "end": {
5581 "column": 3,
5582 "line": 40
5583 },
5584 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5585 "id": "settings.workspaces.deletedInfo",
5586 "start": {
5587 "column": 15,
5588 "line": 37
5589 }
5590 },
5591 {
5592 "defaultMessage": "!!!Info about workspace feature",
5593 "end": {
5594 "column": 3,
5595 "line": 44
5596 },
5597 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5598 "id": "settings.workspaces.workspaceFeatureInfo",
5599 "start": {
5600 "column": 24,
5601 "line": 41
5602 }
5603 },
5604 {
5605 "defaultMessage": "!!!Less is More: Introducing Ferdi Workspaces",
5606 "end": {
5607 "column": 3,
5608 "line": 48
5609 },
5610 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
5611 "id": "settings.workspaces.workspaceFeatureHeadline",
5612 "start": {
5613 "column": 28,
5614 "line": 45
5615 }
5616 }
5617 ],
5618 "path": "src/features/workspaces/components/WorkspacesDashboard.json"
5619 },
5620 {
5621 "descriptors": [
5622 {
5623 "defaultMessage": "!!!Switching to",
5624 "end": {
5625 "column": 3,
5626 "line": 15
5627 },
5628 "file": "src/features/workspaces/components/WorkspaceSwitchingIndicator.js",
5629 "id": "workspaces.switchingIndicator.switchingTo",
5630 "start": {
5631 "column": 15,
5632 "line": 12
5633 }
5634 }
5635 ],
5636 "path": "src/features/workspaces/components/WorkspaceSwitchingIndicator.json"
5637 },
5638 {
5639 "descriptors": [
5640 {
5641 "defaultMessage": "!!!Field is required",
5642 "end": {
5643 "column": 3,
5644 "line": 8
5645 },
5646 "file": "src/helpers/validation-helpers.js",
5647 "id": "validation.required",
5648 "start": {
5649 "column": 12,
5650 "line": 5
5651 }
5652 },
5653 {
5654 "defaultMessage": "!!!Email not valid",
5655 "end": {
5656 "column": 3,
5657 "line": 12
5658 },
5659 "file": "src/helpers/validation-helpers.js",
5660 "id": "validation.email",
5661 "start": {
5662 "column": 9,
5663 "line": 9
5664 }
5665 },
5666 {
5667 "defaultMessage": "!!!Not a valid URL",
5668 "end": {
5669 "column": 3,
5670 "line": 16
5671 },
5672 "file": "src/helpers/validation-helpers.js",
5673 "id": "validation.url",
5674 "start": {
5675 "column": 7,
5676 "line": 13
5677 }
5678 },
5679 {
5680 "defaultMessage": "!!!Too few characters",
5681 "end": {
5682 "column": 3,
5683 "line": 20
5684 },
5685 "file": "src/helpers/validation-helpers.js",
5686 "id": "validation.minLength",
5687 "start": {
5688 "column": 13,
5689 "line": 17
5690 }
5691 },
5692 {
5693 "defaultMessage": "!!!At least one is required",
5694 "end": {
5695 "column": 3,
5696 "line": 24
5697 },
5698 "file": "src/helpers/validation-helpers.js",
5699 "id": "validation.oneRequired",
5700 "start": {
5701 "column": 15,
5702 "line": 21
5703 }
5704 }
5705 ],
5706 "path": "src/helpers/validation-helpers.json"
5707 },
5708 {
5709 "descriptors": [
5710 {
5711 "defaultMessage": "!!!Can't connect to Ferdi Online Services",
5712 "end": {
5713 "column": 3,
5714 "line": 7
5715 },
5716 "file": "src/i18n/globalMessages.js",
5717 "id": "global.api.unhealthy",
5718 "start": {
5719 "column": 16,
5720 "line": 4
5721 }
5722 },
5723 {
5724 "defaultMessage": "!!!You are not connected to the internet.",
5725 "end": {
5726 "column": 3,
5727 "line": 11
5728 },
5729 "file": "src/i18n/globalMessages.js",
5730 "id": "global.notConnectedToTheInternet",
5731 "start": {
5732 "column": 29,
5733 "line": 8
5734 }
5735 },
5736 {
5737 "defaultMessage": "!!!Spell checking language",
5738 "end": {
5739 "column": 3,
5740 "line": 15
5741 },
5742 "file": "src/i18n/globalMessages.js",
5743 "id": "global.spellchecking.language",
5744 "start": {
5745 "column": 24,
5746 "line": 12
5747 }
5748 },
5749 {
5750 "defaultMessage": "!!!Use System Default ({default})",
5751 "end": {
5752 "column": 3,
5753 "line": 19
5754 },
5755 "file": "src/i18n/globalMessages.js",
5756 "id": "global.spellchecker.useDefault",
5757 "start": {
5758 "column": 29,
5759 "line": 16
5760 }
5761 },
5762 {
5763 "defaultMessage": "!!!Detect language automatically",
5764 "end": {
5765 "column": 3,
5766 "line": 23
5767 },
5768 "file": "src/i18n/globalMessages.js",
5769 "id": "global.spellchecking.autodetect",
5770 "start": {
5771 "column": 34,
5772 "line": 20
5773 }
5774 },
5775 {
5776 "defaultMessage": "!!!Automatic",
5777 "end": {
5778 "column": 3,
5779 "line": 27
5780 },
5781 "file": "src/i18n/globalMessages.js",
5782 "id": "global.spellchecking.autodetect.short",
5783 "start": {
5784 "column": 39,
5785 "line": 24
5786 }
5787 },
5788 {
5789 "defaultMessage": "!!!User Agent",
5790 "end": {
5791 "column": 3,
5792 "line": 31
5793 },
5794 "file": "src/i18n/globalMessages.js",
5795 "id": "global.userAgentPref",
5796 "start": {
5797 "column": 17,
5798 "line": 28
5799 }
5800 },
5801 {
5802 "defaultMessage": "!!!Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
5803 "end": {
5804 "column": 3,
5805 "line": 35
5806 },
5807 "file": "src/i18n/globalMessages.js",
5808 "id": "global.userAgentHelp",
5809 "start": {
5810 "column": 17,
5811 "line": 32
5812 }
5813 },
5814 {
5815 "defaultMessage": "!!!Yes",
5816 "end": {
5817 "column": 3,
5818 "line": 39
5819 },
5820 "file": "src/i18n/globalMessages.js",
5821 "id": "global.yes",
5822 "start": {
5823 "column": 7,
5824 "line": 36
5825 }
5826 },
5827 {
5828 "defaultMessage": "!!!No",
5829 "end": {
5830 "column": 3,
5831 "line": 43
5832 },
5833 "file": "src/i18n/globalMessages.js",
5834 "id": "global.no",
5835 "start": {
5836 "column": 6,
5837 "line": 40
5838 }
5839 },
5840 {
5841 "defaultMessage": "!!!Ok",
5842 "end": {
5843 "column": 3,
5844 "line": 47
5845 },
5846 "file": "src/i18n/globalMessages.js",
5847 "id": "global.ok",
5848 "start": {
5849 "column": 6,
5850 "line": 44
5851 }
5852 },
5853 {
5854 "defaultMessage": "!!!Cancel",
5855 "end": {
5856 "column": 3,
5857 "line": 51
5858 },
5859 "file": "src/i18n/globalMessages.js",
5860 "id": "global.cancel",
5861 "start": {
5862 "column": 10,
5863 "line": 48
5864 }
5865 },
5866 {
5867 "defaultMessage": "!!!Save",
5868 "end": {
5869 "column": 3,
5870 "line": 55
5871 },
5872 "file": "src/i18n/globalMessages.js",
5873 "id": "global.save",
5874 "start": {
5875 "column": 8,
5876 "line": 52
5877 }
5878 },
5879 {
5880 "defaultMessage": "!!!Submit",
5881 "end": {
5882 "column": 3,
5883 "line": 59
5884 },
5885 "file": "src/i18n/globalMessages.js",
5886 "id": "global.submit",
5887 "start": {
5888 "column": 10,
5889 "line": 56
5890 }
5891 },
5892 {
5893 "defaultMessage": "!!!Quit",
5894 "end": {
5895 "column": 3,
5896 "line": 63
5897 },
5898 "file": "src/i18n/globalMessages.js",
5899 "id": "global.quit",
5900 "start": {
5901 "column": 8,
5902 "line": 60
5903 }
5904 },
5905 {
5906 "defaultMessage": "!!!Do you really want to quit Ferdi?",
5907 "end": {
5908 "column": 3,
5909 "line": 68
5910 },
5911 "file": "src/i18n/globalMessages.js",
5912 "id": "global.quitConfirmation",
5913 "start": {
5914 "column": 20,
5915 "line": 64
5916 }
5917 },
5918 {
5919 "defaultMessage": "!!!Settings",
5920 "end": {
5921 "column": 3,
5922 "line": 72
5923 },
5924 "file": "src/i18n/globalMessages.js",
5925 "id": "global.settings",
5926 "start": {
5927 "column": 12,
5928 "line": 69
5929 }
5930 },
5931 {
5932 "defaultMessage": "!!!Edit",
5933 "end": {
5934 "column": 3,
5935 "line": 76
5936 },
5937 "file": "src/i18n/globalMessages.js",
5938 "id": "global.edit",
5939 "start": {
5940 "column": 8,
5941 "line": 73
5942 }
5943 }
5944 ],
5945 "path": "src/i18n/globalMessages.json"
5946 },
5947 {
5948 "descriptors": [
5949 {
5950 "defaultMessage": "!!!Edit",
5951 "end": {
5952 "column": 3,
5953 "line": 35
5954 },
5955 "file": "src/lib/Menu.js",
5956 "id": "menu.edit",
5957 "start": {
5958 "column": 8,
5959 "line": 32
5960 }
5961 },
5962 {
5963 "defaultMessage": "!!!Undo",
5964 "end": {
5965 "column": 3,
5966 "line": 39
5967 },
5968 "file": "src/lib/Menu.js",
5969 "id": "menu.edit.undo",
5970 "start": {
5971 "column": 8,
5972 "line": 36
5973 }
5974 },
5975 {
5976 "defaultMessage": "!!!Redo",
5977 "end": {
5978 "column": 3,
5979 "line": 43
5980 },
5981 "file": "src/lib/Menu.js",
5982 "id": "menu.edit.redo",
5983 "start": {
5984 "column": 8,
5985 "line": 40
5986 }
5987 },
5988 {
5989 "defaultMessage": "!!!Cut",
5990 "end": {
5991 "column": 3,
5992 "line": 47
5993 },
5994 "file": "src/lib/Menu.js",
5995 "id": "menu.edit.cut",
5996 "start": {
5997 "column": 7,
5998 "line": 44
5999 }
6000 },
6001 {
6002 "defaultMessage": "!!!Copy",
6003 "end": {
6004 "column": 3,
6005 "line": 51
6006 },
6007 "file": "src/lib/Menu.js",
6008 "id": "menu.edit.copy",
6009 "start": {
6010 "column": 8,
6011 "line": 48
6012 }
6013 },
6014 {
6015 "defaultMessage": "!!!Paste",
6016 "end": {
6017 "column": 3,
6018 "line": 55
6019 },
6020 "file": "src/lib/Menu.js",
6021 "id": "menu.edit.paste",
6022 "start": {
6023 "column": 9,
6024 "line": 52
6025 }
6026 },
6027 {
6028 "defaultMessage": "!!!Paste And Match Style",
6029 "end": {
6030 "column": 3,
6031 "line": 59
6032 },
6033 "file": "src/lib/Menu.js",
6034 "id": "menu.edit.pasteAndMatchStyle",
6035 "start": {
6036 "column": 22,
6037 "line": 56
6038 }
6039 },
6040 {
6041 "defaultMessage": "!!!Delete",
6042 "end": {
6043 "column": 3,
6044 "line": 63
6045 },
6046 "file": "src/lib/Menu.js",
6047 "id": "menu.edit.delete",
6048 "start": {
6049 "column": 10,
6050 "line": 60
6051 }
6052 },
6053 {
6054 "defaultMessage": "!!!Select All",
6055 "end": {
6056 "column": 3,
6057 "line": 67
6058 },
6059 "file": "src/lib/Menu.js",
6060 "id": "menu.edit.selectAll",
6061 "start": {
6062 "column": 13,
6063 "line": 64
6064 }
6065 },
6066 {
6067 "defaultMessage": "!!!Find in Page",
6068 "end": {
6069 "column": 3,
6070 "line": 71
6071 },
6072 "file": "src/lib/Menu.js",
6073 "id": "menu.edit.findInPage",
6074 "start": {
6075 "column": 14,
6076 "line": 68
6077 }
6078 },
6079 {
6080 "defaultMessage": "!!!Speech",
6081 "end": {
6082 "column": 3,
6083 "line": 75
6084 },
6085 "file": "src/lib/Menu.js",
6086 "id": "menu.edit.speech",
6087 "start": {
6088 "column": 10,
6089 "line": 72
6090 }
6091 },
6092 {
6093 "defaultMessage": "!!!Start Speaking",
6094 "end": {
6095 "column": 3,
6096 "line": 79
6097 },
6098 "file": "src/lib/Menu.js",
6099 "id": "menu.edit.startSpeaking",
6100 "start": {
6101 "column": 17,
6102 "line": 76
6103 }
6104 },
6105 {
6106 "defaultMessage": "!!!Stop Speaking",
6107 "end": {
6108 "column": 3,
6109 "line": 83
6110 },
6111 "file": "src/lib/Menu.js",
6112 "id": "menu.edit.stopSpeaking",
6113 "start": {
6114 "column": 16,
6115 "line": 80
6116 }
6117 },
6118 {
6119 "defaultMessage": "!!!Start Dictation",
6120 "end": {
6121 "column": 3,
6122 "line": 87
6123 },
6124 "file": "src/lib/Menu.js",
6125 "id": "menu.edit.startDictation",
6126 "start": {
6127 "column": 18,
6128 "line": 84
6129 }
6130 },
6131 {
6132 "defaultMessage": "!!!Emoji & Symbols",
6133 "end": {
6134 "column": 3,
6135 "line": 91
6136 },
6137 "file": "src/lib/Menu.js",
6138 "id": "menu.edit.emojiSymbols",
6139 "start": {
6140 "column": 16,
6141 "line": 88
6142 }
6143 },
6144 {
6145 "defaultMessage": "!!!Open Quick Switch",
6146 "end": {
6147 "column": 3,
6148 "line": 95
6149 },
6150 "file": "src/lib/Menu.js",
6151 "id": "menu.view.openQuickSwitch",
6152 "start": {
6153 "column": 19,
6154 "line": 92
6155 }
6156 },
6157 {
6158 "defaultMessage": "!!!Back",
6159 "end": {
6160 "column": 3,
6161 "line": 99
6162 },
6163 "file": "src/lib/Menu.js",
6164 "id": "menu.view.back",
6165 "start": {
6166 "column": 8,
6167 "line": 96
6168 }
6169 },
6170 {
6171 "defaultMessage": "!!!Forward",
6172 "end": {
6173 "column": 3,
6174 "line": 103
6175 },
6176 "file": "src/lib/Menu.js",
6177 "id": "menu.view.forward",
6178 "start": {
6179 "column": 11,
6180 "line": 100
6181 }
6182 },
6183 {
6184 "defaultMessage": "!!!Actual Size",
6185 "end": {
6186 "column": 3,
6187 "line": 107
6188 },
6189 "file": "src/lib/Menu.js",
6190 "id": "menu.view.resetZoom",
6191 "start": {
6192 "column": 13,
6193 "line": 104
6194 }
6195 },
6196 {
6197 "defaultMessage": "!!!Zoom In",
6198 "end": {
6199 "column": 3,
6200 "line": 111
6201 },
6202 "file": "src/lib/Menu.js",
6203 "id": "menu.view.zoomIn",
6204 "start": {
6205 "column": 10,
6206 "line": 108
6207 }
6208 },
6209 {
6210 "defaultMessage": "!!!Zoom Out",
6211 "end": {
6212 "column": 3,
6213 "line": 115
6214 },
6215 "file": "src/lib/Menu.js",
6216 "id": "menu.view.zoomOut",
6217 "start": {
6218 "column": 11,
6219 "line": 112
6220 }
6221 },
6222 {
6223 "defaultMessage": "!!!Toggle Full Screen",
6224 "end": {
6225 "column": 3,
6226 "line": 119
6227 },
6228 "file": "src/lib/Menu.js",
6229 "id": "menu.view.toggleFullScreen",
6230 "start": {
6231 "column": 20,
6232 "line": 116
6233 }
6234 },
6235 {
6236 "defaultMessage": "!!!Toggle Dark Mode",
6237 "end": {
6238 "column": 3,
6239 "line": 123
6240 },
6241 "file": "src/lib/Menu.js",
6242 "id": "menu.view.toggleDarkMode",
6243 "start": {
6244 "column": 18,
6245 "line": 120
6246 }
6247 },
6248 {
6249 "defaultMessage": "!!!Toggle Developer Tools",
6250 "end": {
6251 "column": 3,
6252 "line": 127
6253 },
6254 "file": "src/lib/Menu.js",
6255 "id": "menu.view.toggleDevTools",
6256 "start": {
6257 "column": 18,
6258 "line": 124
6259 }
6260 },
6261 {
6262 "defaultMessage": "!!!Toggle Todos Developer Tools",
6263 "end": {
6264 "column": 3,
6265 "line": 131
6266 },
6267 "file": "src/lib/Menu.js",
6268 "id": "menu.view.toggleTodosDevTools",
6269 "start": {
6270 "column": 23,
6271 "line": 128
6272 }
6273 },
6274 {
6275 "defaultMessage": "!!!Toggle Service Developer Tools",
6276 "end": {
6277 "column": 3,
6278 "line": 135
6279 },
6280 "file": "src/lib/Menu.js",
6281 "id": "menu.view.toggleServiceDevTools",
6282 "start": {
6283 "column": 25,
6284 "line": 132
6285 }
6286 },
6287 {
6288 "defaultMessage": "!!!Reload Service",
6289 "end": {
6290 "column": 3,
6291 "line": 139
6292 },
6293 "file": "src/lib/Menu.js",
6294 "id": "menu.view.reloadService",
6295 "start": {
6296 "column": 17,
6297 "line": 136
6298 }
6299 },
6300 {
6301 "defaultMessage": "!!!Reload Ferdi",
6302 "end": {
6303 "column": 3,
6304 "line": 143
6305 },
6306 "file": "src/lib/Menu.js",
6307 "id": "menu.view.reloadFerdi",
6308 "start": {
6309 "column": 15,
6310 "line": 140
6311 }
6312 },
6313 {
6314 "defaultMessage": "!!!Lock Ferdi",
6315 "end": {
6316 "column": 3,
6317 "line": 147
6318 },
6319 "file": "src/lib/Menu.js",
6320 "id": "menu.view.lockFerdi",
6321 "start": {
6322 "column": 13,
6323 "line": 144
6324 }
6325 },
6326 {
6327 "defaultMessage": "!!!Reload ToDos",
6328 "end": {
6329 "column": 3,
6330 "line": 151
6331 },
6332 "file": "src/lib/Menu.js",
6333 "id": "menu.view.reloadTodos",
6334 "start": {
6335 "column": 15,
6336 "line": 148
6337 }
6338 },
6339 {
6340 "defaultMessage": "!!!Minimize",
6341 "end": {
6342 "column": 3,
6343 "line": 155
6344 },
6345 "file": "src/lib/Menu.js",
6346 "id": "menu.window.minimize",
6347 "start": {
6348 "column": 12,
6349 "line": 152
6350 }
6351 },
6352 {
6353 "defaultMessage": "!!!Close",
6354 "end": {
6355 "column": 3,
6356 "line": 159
6357 },
6358 "file": "src/lib/Menu.js",
6359 "id": "menu.window.close",
6360 "start": {
6361 "column": 9,
6362 "line": 156
6363 }
6364 },
6365 {
6366 "defaultMessage": "!!!Learn More",
6367 "end": {
6368 "column": 3,
6369 "line": 163
6370 },
6371 "file": "src/lib/Menu.js",
6372 "id": "menu.help.learnMore",
6373 "start": {
6374 "column": 13,
6375 "line": 160
6376 }
6377 },
6378 {
6379 "defaultMessage": "!!!Changelog",
6380 "end": {
6381 "column": 3,
6382 "line": 167
6383 },
6384 "file": "src/lib/Menu.js",
6385 "id": "menu.help.changelog",
6386 "start": {
6387 "column": 13,
6388 "line": 164
6389 }
6390 },
6391 {
6392 "defaultMessage": "!!!Import/Export Configuration Data",
6393 "end": {
6394 "column": 3,
6395 "line": 171
6396 },
6397 "file": "src/lib/Menu.js",
6398 "id": "menu.help.importExportData",
6399 "start": {
6400 "column": 20,
6401 "line": 168
6402 }
6403 },
6404 {
6405 "defaultMessage": "!!!Support",
6406 "end": {
6407 "column": 3,
6408 "line": 175
6409 },
6410 "file": "src/lib/Menu.js",
6411 "id": "menu.help.support",
6412 "start": {
6413 "column": 11,
6414 "line": 172
6415 }
6416 },
6417 {
6418 "defaultMessage": "!!!Copy Debug Information",
6419 "end": {
6420 "column": 3,
6421 "line": 179
6422 },
6423 "file": "src/lib/Menu.js",
6424 "id": "menu.help.debugInfo",
6425 "start": {
6426 "column": 13,
6427 "line": 176
6428 }
6429 },
6430 {
6431 "defaultMessage": "!!!Publish Debug Information",
6432 "end": {
6433 "column": 3,
6434 "line": 183
6435 },
6436 "file": "src/lib/Menu.js",
6437 "id": "menu.help.publishDebugInfo",
6438 "start": {
6439 "column": 20,
6440 "line": 180
6441 }
6442 },
6443 {
6444 "defaultMessage": "!!!Ferdi Debug Information",
6445 "end": {
6446 "column": 3,
6447 "line": 187
6448 },
6449 "file": "src/lib/Menu.js",
6450 "id": "menu.help.debugInfoCopiedHeadline",
6451 "start": {
6452 "column": 27,
6453 "line": 184
6454 }
6455 },
6456 {
6457 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.",
6458 "end": {
6459 "column": 3,
6460 "line": 192
6461 },
6462 "file": "src/lib/Menu.js",
6463 "id": "menu.help.debugInfoCopiedBody",
6464 "start": {
6465 "column": 23,
6466 "line": 188
6467 }
6468 },
6469 {
6470 "defaultMessage": "!!!Unlock with Touch ID",
6471 "end": {
6472 "column": 3,
6473 "line": 196
6474 },
6475 "file": "src/lib/Menu.js",
6476 "id": "locked.touchId",
6477 "start": {
6478 "column": 11,
6479 "line": 193
6480 }
6481 },
6482 {
6483 "defaultMessage": "!!!unlock via Touch ID",
6484 "end": {
6485 "column": 3,
6486 "line": 200
6487 },
6488 "file": "src/lib/Menu.js",
6489 "id": "locked.touchIdPrompt",
6490 "start": {
6491 "column": 17,
6492 "line": 197
6493 }
6494 },
6495 {
6496 "defaultMessage": "!!!Terms of Service",
6497 "end": {
6498 "column": 3,
6499 "line": 204
6500 },
6501 "file": "src/lib/Menu.js",
6502 "id": "menu.help.tos",
6503 "start": {
6504 "column": 7,
6505 "line": 201
6506 }
6507 },
6508 {
6509 "defaultMessage": "!!!Privacy Statement",
6510 "end": {
6511 "column": 3,
6512 "line": 208
6513 },
6514 "file": "src/lib/Menu.js",
6515 "id": "menu.help.privacy",
6516 "start": {
6517 "column": 11,
6518 "line": 205
6519 }
6520 },
6521 {
6522 "defaultMessage": "!!!File",
6523 "end": {
6524 "column": 3,
6525 "line": 212
6526 },
6527 "file": "src/lib/Menu.js",
6528 "id": "menu.file",
6529 "start": {
6530 "column": 8,
6531 "line": 209
6532 }
6533 },
6534 {
6535 "defaultMessage": "!!!View",
6536 "end": {
6537 "column": 3,
6538 "line": 216
6539 },
6540 "file": "src/lib/Menu.js",
6541 "id": "menu.view",
6542 "start": {
6543 "column": 8,
6544 "line": 213
6545 }
6546 },
6547 {
6548 "defaultMessage": "!!!Services",
6549 "end": {
6550 "column": 3,
6551 "line": 220
6552 },
6553 "file": "src/lib/Menu.js",
6554 "id": "menu.services",
6555 "start": {
6556 "column": 12,
6557 "line": 217
6558 }
6559 },
6560 {
6561 "defaultMessage": "!!!Window",
6562 "end": {
6563 "column": 3,
6564 "line": 224
6565 },
6566 "file": "src/lib/Menu.js",
6567 "id": "menu.window",
6568 "start": {
6569 "column": 10,
6570 "line": 221
6571 }
6572 },
6573 {
6574 "defaultMessage": "!!!Help",
6575 "end": {
6576 "column": 3,
6577 "line": 228
6578 },
6579 "file": "src/lib/Menu.js",
6580 "id": "menu.help",
6581 "start": {
6582 "column": 8,
6583 "line": 225
6584 }
6585 },
6586 {
6587 "defaultMessage": "!!!About Ferdi",
6588 "end": {
6589 "column": 3,
6590 "line": 232
6591 },
6592 "file": "src/lib/Menu.js",
6593 "id": "menu.app.about",
6594 "start": {
6595 "column": 9,
6596 "line": 229
6597 }
6598 },
6599 {
6600 "defaultMessage": "!!!Check for updates",
6601 "end": {
6602 "column": 3,
6603 "line": 236
6604 },
6605 "file": "src/lib/Menu.js",
6606 "id": "menu.app.checkForUpdates",
6607 "start": {
6608 "column": 19,
6609 "line": 233
6610 }
6611 },
6612 {
6613 "defaultMessage": "!!!Hide",
6614 "end": {
6615 "column": 3,
6616 "line": 240
6617 },
6618 "file": "src/lib/Menu.js",
6619 "id": "menu.app.hide",
6620 "start": {
6621 "column": 8,
6622 "line": 237
6623 }
6624 },
6625 {
6626 "defaultMessage": "!!!Hide Others",
6627 "end": {
6628 "column": 3,
6629 "line": 244
6630 },
6631 "file": "src/lib/Menu.js",
6632 "id": "menu.app.hideOthers",
6633 "start": {
6634 "column": 14,
6635 "line": 241
6636 }
6637 },
6638 {
6639 "defaultMessage": "!!!Unhide",
6640 "end": {
6641 "column": 3,
6642 "line": 248
6643 },
6644 "file": "src/lib/Menu.js",
6645 "id": "menu.app.unhide",
6646 "start": {
6647 "column": 10,
6648 "line": 245
6649 }
6650 },
6651 {
6652 "defaultMessage": "!!!Auto-hide menu bar",
6653 "end": {
6654 "column": 3,
6655 "line": 252
6656 },
6657 "file": "src/lib/Menu.js",
6658 "id": "menu.app.autohideMenuBar",
6659 "start": {
6660 "column": 19,
6661 "line": 249
6662 }
6663 },
6664 {
6665 "defaultMessage": "!!!Add New Service...",
6666 "end": {
6667 "column": 3,
6668 "line": 256
6669 },
6670 "file": "src/lib/Menu.js",
6671 "id": "menu.services.addNewService",
6672 "start": {
6673 "column": 17,
6674 "line": 253
6675 }
6676 },
6677 {
6678 "defaultMessage": "!!!Add New Workspace...",
6679 "end": {
6680 "column": 3,
6681 "line": 260
6682 },
6683 "file": "src/lib/Menu.js",
6684 "id": "menu.workspaces.addNewWorkspace",
6685 "start": {
6686 "column": 19,
6687 "line": 257
6688 }
6689 },
6690 {
6691 "defaultMessage": "!!!Open workspace drawer",
6692 "end": {
6693 "column": 3,
6694 "line": 264
6695 },
6696 "file": "src/lib/Menu.js",
6697 "id": "menu.workspaces.openWorkspaceDrawer",
6698 "start": {
6699 "column": 23,
6700 "line": 261
6701 }
6702 },
6703 {
6704 "defaultMessage": "!!!Close workspace drawer",
6705 "end": {
6706 "column": 3,
6707 "line": 268
6708 },
6709 "file": "src/lib/Menu.js",
6710 "id": "menu.workspaces.closeWorkspaceDrawer",
6711 "start": {
6712 "column": 24,
6713 "line": 265
6714 }
6715 },
6716 {
6717 "defaultMessage": "!!!Activate next service...",
6718 "end": {
6719 "column": 3,
6720 "line": 272
6721 },
6722 "file": "src/lib/Menu.js",
6723 "id": "menu.services.setNextServiceActive",
6724 "start": {
6725 "column": 23,
6726 "line": 269
6727 }
6728 },
6729 {
6730 "defaultMessage": "!!!Activate previous service...",
6731 "end": {
6732 "column": 3,
6733 "line": 276
6734 },
6735 "file": "src/lib/Menu.js",
6736 "id": "menu.services.activatePreviousService",
6737 "start": {
6738 "column": 27,
6739 "line": 273
6740 }
6741 },
6742 {
6743 "defaultMessage": "!!!Disable notifications & audio",
6744 "end": {
6745 "column": 3,
6746 "line": 280
6747 },
6748 "file": "src/lib/Menu.js",
6749 "id": "sidebar.muteApp",
6750 "start": {
6751 "column": 11,
6752 "line": 277
6753 }
6754 },
6755 {
6756 "defaultMessage": "!!!Enable notifications & audio",
6757 "end": {
6758 "column": 3,
6759 "line": 284
6760 },
6761 "file": "src/lib/Menu.js",
6762 "id": "sidebar.unmuteApp",
6763 "start": {
6764 "column": 13,
6765 "line": 281
6766 }
6767 },
6768 {
6769 "defaultMessage": "!!!Workspaces",
6770 "end": {
6771 "column": 3,
6772 "line": 288
6773 },
6774 "file": "src/lib/Menu.js",
6775 "id": "menu.workspaces",
6776 "start": {
6777 "column": 14,
6778 "line": 285
6779 }
6780 },
6781 {
6782 "defaultMessage": "!!!Default",
6783 "end": {
6784 "column": 3,
6785 "line": 292
6786 },
6787 "file": "src/lib/Menu.js",
6788 "id": "menu.workspaces.defaultWorkspace",
6789 "start": {
6790 "column": 20,
6791 "line": 289
6792 }
6793 },
6794 {
6795 "defaultMessage": "!!!Todos",
6796 "end": {
6797 "column": 3,
6798 "line": 296
6799 },
6800 "file": "src/lib/Menu.js",
6801 "id": "menu.todos",
6802 "start": {
6803 "column": 9,
6804 "line": 293
6805 }
6806 },
6807 {
6808 "defaultMessage": "!!!Open Todos drawer",
6809 "end": {
6810 "column": 3,
6811 "line": 300
6812 },
6813 "file": "src/lib/Menu.js",
6814 "id": "menu.Todoss.openTodosDrawer",
6815 "start": {
6816 "column": 19,
6817 "line": 297
6818 }
6819 },
6820 {
6821 "defaultMessage": "!!!Close Todos drawer",
6822 "end": {
6823 "column": 3,
6824 "line": 304
6825 },
6826 "file": "src/lib/Menu.js",
6827 "id": "menu.Todoss.closeTodosDrawer",
6828 "start": {
6829 "column": 20,
6830 "line": 301
6831 }
6832 },
6833 {
6834 "defaultMessage": "!!!Enable Todos",
6835 "end": {
6836 "column": 3,
6837 "line": 308
6838 },
6839 "file": "src/lib/Menu.js",
6840 "id": "menu.todos.enableTodos",
6841 "start": {
6842 "column": 15,
6843 "line": 305
6844 }
6845 },
6846 {
6847 "defaultMessage": "!!!Home",
6848 "end": {
6849 "column": 3,
6850 "line": 312
6851 },
6852 "file": "src/lib/Menu.js",
6853 "id": "menu.services.goHome",
6854 "start": {
6855 "column": 17,
6856 "line": 309
6857 }
6858 }
6859 ],
6860 "path": "src/lib/Menu.json"
6861 }
6862] \ No newline at end of file
diff --git a/src/i18n/locales/el.json b/src/i18n/locales/el.json
index 6964a93f1..4c658297e 100644
--- a/src/i18n/locales/el.json
+++ b/src/i18n/locales/el.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "ΕπαναφόÏτωση", 2 "app.errorHandler.action": "ΕπαναφόÏτωση",
3 "app.errorHandler.headline": "Κάτι δεν λειτουÏγεί", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "ΠÏοσαÏμοσμένος διακομιστής", 4 "changeserver.customServerLabel": "ΠÏοσαÏμοσμένος διακομιστής",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Διακομιστής", 6 "changeserver.label": "Διακομιστής",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Τι συνέβη;", 10 "connectionLostBanner.informationLink": "Τι συνέβη;",
11 "connectionLostBanner.message": "Ωχ όχι! Ο Ferdi έχασε την επικοινωνία με το", 11 "connectionLostBanner.message": "Ωχ όχι! Ο Ferdi έχασε την επικοινωνία με το",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "ΕγγÏαφή πληÏοφοÏιών ÎµÎ½Ï„Î¿Ï€Î¹ÏƒÎ¼Î¿Ï ÏƒÏ†Î±Î»Î¼Î¬Ï„Ï‰Î½",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Δεν είναι δυνατή η σÏνδεση με τις ζωντανές υπηÏεσίες του Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "ΑκÏÏωση", 27 "global.cancel": "Cancel",
29 "global.edit": "ΕπεξεÏγασία", 28 "global.edit": "ΕπεξεÏγασία",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Έχετε αποσυνδεθεί από το Διαδίκτυο", 30 "global.notConnectedToTheInternet": "Έχετε αποσυνδεθεί από το Διαδίκτυο",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Ρυθμίσεις", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use System Default ({default})", 36 "global.spellchecker.useDefault": "Use System Default ({default})",
38 "global.spellchecking.autodetect": "Detect language automatically", 37 "global.spellchecking.autodetect": "Detect language automatically",
39 "global.spellchecking.autodetect.short": "Automatic", 38 "global.spellchecking.autodetect.short": "Automatic",
40 "global.spellchecking.language": "Spell checking language", 39 "global.spellchecking.language": "Spell checking language",
41 "global.submit": "Υποβολή", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Εισαγάγετε τις υπηÏεσίες σας Ferdi 4", 44 "import.headline": "Εισαγάγετε τις υπηÏεσίες σας Ferdi 4",
46 "import.notSupportedHeadline": "ΥπηÏεσίες που δεν υποστηÏίζονται ακόμα στο Ferdi 5", 45 "import.notSupportedHeadline": "ΥπηÏεσίες που δεν υποστηÏίζονται ακόμα στο Ferdi 5",
47 "import.skip.label": "Θέλω να Ï€Ïοσθέσω υπηÏεσίες χειÏοκίνητα", 46 "import.skip.label": "Θέλω να Ï€Ïοσθέσω υπηÏεσίες χειÏοκίνητα",
48 "import.submit.label": "Εισαγωγή υπηÏεσιών", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Τι νέο υπάÏχει;", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Επανεκκίνηση & εγκατάσταση ενημεÏώσεων", 50 "infobar.buttonInstallUpdate": "Επανεκκίνηση & εγκατάσταση ενημεÏώσεων",
52 "infobar.buttonReloadServices": "Ανανέωση υπηÏεσιών", 51 "infobar.buttonReloadServices": "Ανανέωση υπηÏεσιών",
53 "infobar.hide": "ΑπόκÏυψη", 52 "infobar.hide": "ΑπόκÏυψη",
@@ -75,7 +74,7 @@
75 "login.email.label": "ΔιεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου", 74 "login.email.label": "ΔιεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου",
76 "login.headline": "ΣÏνδεση", 75 "login.headline": "ΣÏνδεση",
77 "login.invalidCredentials": "Το email ή ο κωδικός Ï€Ïόσβασης δεν είναι έγκυÏος", 76 "login.invalidCredentials": "Το email ή ο κωδικός Ï€Ïόσβασης δεν είναι έγκυÏος",
78 "login.link.password": "ΕπαναφοÏά ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης", 77 "login.link.password": "Reset password",
79 "login.link.signup": "ΔημιουÏγία δωÏεάν λογαÏιασμοÏ", 78 "login.link.signup": "ΔημιουÏγία δωÏεάν λογαÏιασμοÏ",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "Η συνεδÏία σας έληξε, συνδεθείτε ξανά.", 80 "login.serverLogout": "Η συνεδÏία σας έληξε, συνδεθείτε ξανά.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "ÎŒÏοι ΧÏήσης", 117 "menu.help.tos": "ÎŒÏοι ΧÏήσης",
119 "menu.services": "ΥπηÏεσίες", 118 "menu.services": "ΥπηÏεσίες",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Όλες οι υπηÏεσίες", 147 "menu.workspaces.defaultWorkspace": "Όλες οι υπηÏεσίες",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "ΔιεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου", 149 "password.email.label": "ΔιεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου",
151 "password.headline": "ΕπαναφοÏά ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης", 150 "password.headline": "Reset password",
152 "password.link.login": "ΣÏνδεση στο λογαÏιασμό σας", 151 "password.link.login": "ΣÏνδεση στο λογαÏιασμό σας",
153 "password.link.signup": "ΔημιουÏγία δωÏεάν λογαÏιασμοÏ", 152 "password.link.signup": "ΔημιουÏγία δωÏεάν λογαÏιασμοÏ",
154 "password.noUser": "Δεν βÏέθηκε χÏήστης με τη συγκεκÏιμένη διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Ελέγξτε το email σας", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "ΕπαναφόÏτωση {name}", 155 "service.crashHandler.action": "ΕπαναφόÏτωση {name}",
168 "service.crashHandler.autoReload": "Γίνεται Ï€Ïοσπάθεια αυτόματης ανάκτησης του {name} σε {seconds} δευτεÏόλεπτα", 156 "service.crashHandler.autoReload": "Γίνεται Ï€Ïοσπάθεια αυτόματης ανάκτησης του {name} σε {seconds} δευτεÏόλεπτα",
169 "service.crashHandler.headline": "Ω, όχι!", 157 "service.crashHandler.headline": "Ω, όχι!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Καλώς οÏίσατε στον Ferdi", 171 "services.welcome": "Καλώς οÏίσατε στον Ferdi",
184 "settings.account.account.editButton": "ΕπεξεÏγασία λογαÏιασμοÏ", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "ΕνημέÏωση Ï€Ïοφίλ", 175 "settings.account.buttonSave": "ΕνημέÏωση Ï€Ïοφίλ",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Έχετε λάβει ένα email με έναν σÏνδεσμο για την επιβεβαίωση της διαγÏαφής του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚. Ο λογαÏιασμός και τα δεδομένα σας δεν μποÏοÏν να ανακτηθοÏν!", 177 "settings.account.deleteEmailSent": "Έχετε λάβει ένα email με έναν σÏνδεσμο για την επιβεβαίωση της διαγÏαφής του λογαÏÎ¹Î±ÏƒÎ¼Î¿Ï ÏƒÎ±Ï‚. Ο λογαÏιασμός και τα δεδομένα σας δεν μποÏοÏν να ανακτηθοÏν!",
190 "settings.account.deleteInfo": "Εάν δεν χÏειάζεστε πλέον το λογαÏιασμό σας στο Ferdi, μποÏείτε να διαγÏάψετε το λογαÏιασμό σας και όλα τα δεδομένα που σχετίζονται με αυτόν εδώ.", 178 "settings.account.deleteInfo": "Εάν δεν χÏειάζεστε πλέον το λογαÏιασμό σας στο Ferdi, μποÏείτε να διαγÏάψετε το λογαÏιασμό σας και όλα τα δεδομένα που σχετίζονται με αυτόν εδώ.",
191 "settings.account.headline": "ΛογαÏιασμός", 179 "settings.account.headline": "ΛογαÏιασμός",
192 "settings.account.headlineAccount": "ΠληÏοφοÏίες λογαÏιασμοÏ", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Επικίνδυνη Ζώνη", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Τιμολόγια", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Αλλαγή ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "ΕνημέÏωση Ï€Ïοφίλ", 184 "settings.account.headlineProfile": "ΕνημέÏωση Ï€Ïοφίλ",
197 "settings.account.successInfo": "Οι αλλαγές σας έχουν αποθηκευτεί", 185 "settings.account.successInfo": "Οι αλλαγές σας έχουν αποθηκευτεί",
198 "settings.account.tryReloadServices": "Δοκιμάστε ξανά", 186 "settings.account.tryReloadServices": "Δοκιμάστε ξανά",
199 "settings.account.tryReloadUserInfoRequest": "Δοκιμάστε ξανά", 187 "settings.account.tryReloadUserInfoRequest": "Δοκιμάστε ξανά",
200 "settings.account.userInfoRequestFailed": "Δεν ήταν δυνατή η φόÏτωση πληÏοφοÏιών χÏήστη", 188 "settings.account.userInfoRequestFailed": "Δεν ήταν δυνατή η φόÏτωση πληÏοφοÏιών χÏήστη",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "ΚαθαÏισμός λανθάνουσας μνήμης", 191 "settings.app.buttonClearAllCache": "ΚαθαÏισμός λανθάνουσας μνήμης",
204 "settings.app.buttonInstallUpdate": "Επανεκκίνηση & εγκατάσταση ενημεÏώσεων", 192 "settings.app.buttonInstallUpdate": "Επανεκκίνηση & εγκατάσταση ενημεÏώσεων",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "ΕνεÏγοποιήση Ενίσχυσης GPU ", 212 "settings.app.form.enableGPUAcceleration": "ΕνεÏγοποιήση Ενίσχυσης GPU ",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "ΕνεÏγοποίηση οÏθογÏÎ±Ï†Î¹ÎºÎ¿Ï ÎµÎ»Î­Î³Ï‡Î¿Ï…", 215 "settings.app.form.enableSpellchecking": "ΕνεÏγοποίηση οÏθογÏÎ±Ï†Î¹ÎºÎ¿Ï ÎµÎ»Î­Î³Ï‡Î¿Ï…",
228 "settings.app.form.enableSystemTray": "Εμφάνιση του Ferdi στη γÏαμμή ειδοποιήσεων", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "ΠÏοβολή καÏτελών των απενεÏγοποιημένων υπηÏεσιών", 239 "settings.app.form.showDisabledServices": "ΠÏοβολή καÏτελών των απενεÏγοποιημένων υπηÏεσιών",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "ΠÏοβολή του εικονιδίου μη αναγνωσμένου μηνÏματος όταν οι ειδοποιήσεις είναι απενεÏγοποιημένες", 241 "settings.app.form.showMessagesBadgesWhenMuted": "ΠÏοβολή του εικονιδίου μη αναγνωσμένου μηνÏματος όταν οι ειδοποιήσεις είναι απενεÏγοποιημένες",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "ΔιαγÏαφή υπηÏεσίας", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "ΕπεξεÏγασία {name}", 305 "settings.service.form.editServiceHeadline": "ΕπεξεÏγασία {name}",
317 "settings.service.form.enableAudio": "ΕνεÏγοποίηση ήχου", 306 "settings.service.form.enableAudio": "ΕνεÏγοποίηση ήχου",
318 "settings.service.form.enableBadge": "Εμφάνιση εικονιδίων μη αναγνωσμένου μηνÏματος", 307 "settings.service.form.enableBadge": "Εμφάνιση εικονιδίων μη αναγνωσμένου μηνÏματος",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Όλοι οι ήχοι καθώς και η αναπαÏαγωγή ήχου θα απενεÏγοποιηθοÏν", 322 "settings.service.form.isMutedInfo": "Όλοι οι ήχοι καθώς και η αναπαÏαγωγή ήχου θα απενεÏγοποιηθοÏν",
334 "settings.service.form.name": "Όνομα", 323 "settings.service.form.name": "Όνομα",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "ΑνακαλÏψτε υπηÏεσίες", 344 "settings.services.discoverServices": "ΑνακαλÏψτε υπηÏεσίες",
355 "settings.services.headline": "Οι υπηÏεσίες σας", 345 "settings.services.headline": "Οι υπηÏεσίες σας",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Η υπηÏεσία είναι απενεÏγοποιημένη", 349 "settings.services.tooltip.isDisabled": "Η υπηÏεσία είναι απενεÏγοποιημένη",
359 "settings.services.tooltip.isMuted": "Όλοι οι ήχοι είναι απενεÏγοποιημένοι", 350 "settings.services.tooltip.isMuted": "Όλοι οι ήχοι είναι απενεÏγοποιημένοι",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Μη κεÏδοσκοπικός", 378 "settings.user.form.accountType.non-profit": "Μη κεÏδοσκοπικός",
388 "settings.user.form.currentPassword": "ΤÏέχων κωδικός Ï€Ïόσβασης", 379 "settings.user.form.currentPassword": "ΤÏέχων κωδικός Ï€Ïόσβασης",
389 "settings.user.form.email": "Email", 380 "settings.user.form.email": "Email",
390 "settings.user.form.firstname": "Όνομα", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Επίθετο", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Îέος κωδικός Ï€Ïόσβασης", 383 "settings.user.form.newPassword": "Îέος κωδικός Ï€Ïόσβασης",
393 "settings.workspace.add.form.name": "Όνομα", 384 "settings.workspace.add.form.name": "Όνομα",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "ΕνεÏγοποίηση ειδοποιήσεων & ήχου", 411 "sidebar.unmuteApp": "ΕνεÏγοποίηση ειδοποιήσεων & ήχου",
421 "signup.email.label": "ΔιεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου", 412 "signup.email.label": "ΔιεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου",
422 "signup.emailDuplicate": "Ένας χÏήστης με τη συγκεκÏιμένη διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου υπάÏχει ήδη", 413 "signup.emailDuplicate": "Ένας χÏήστης με τη συγκεκÏιμένη διεÏθυνση ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου υπάÏχει ήδη",
423 "signup.firstname.label": "Όνομα", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "ΕγγÏαφή", 415 "signup.headline": "ΕγγÏαφή",
425 "signup.lastname.label": "Επίθετο", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "ΔημιουÏγώντας έναν λογαÏιασμό Ferdi αποδέχεστε τους", 417 "signup.legal.info": "ΔημιουÏγώντας έναν λογαÏιασμό Ferdi αποδέχεστε τους",
427 "signup.legal.privacy": "Δήλωση αποÏÏήτου", 418 "signup.legal.privacy": "Δήλωση αποÏÏήτου",
428 "signup.legal.terms": "ÎŒÏοι υπηÏεσίας", 419 "signup.legal.terms": "ÎŒÏοι υπηÏεσίας",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "ΔημιουÏγία λογαÏιασμοÏ", 422 "signup.submit.label": "ΔημιουÏγία λογαÏιασμοÏ",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "ΔιαγÏαφή υπηÏεσίας", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "ΑπενεÏγοποίηση ήχου", 425 "tabs.item.disableAudio": "ΑπενεÏγοποίηση ήχου",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "ΑπενεÏγοποίηση ειδοποιήσεων", 427 "tabs.item.disableNotifications": "ΑπενεÏγοποίηση ειδοποιήσεων",
437 "tabs.item.disableService": "ΑπενεÏγοποίηση υπηÏεσίας", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "ΕνεÏγοποίηση ήχου", 429 "tabs.item.enableAudio": "ΕνεÏγοποίηση ήχου",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "ΕνεÏγοποίηση ειδοποιήσεων", 431 "tabs.item.enableNotification": "ΕνεÏγοποίηση ειδοποιήσεων",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "ΕπαναφόÏτωση", 434 "tabs.item.reload": "ΕπαναφόÏτωση",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} δεν είναι έγκυÏο", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} Ï€Ïέπει να είναι τουλάχιστον {length} χαÏακτήÏες", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} είναι υποχÏεωτικό", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} δεν είναι έγκυÏος σÏνδεσμος URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Back", 441 "webControls.back": "Back",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index be9bbb961..812ec8c4c 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json
index 9a5c248a2..518e862ba 100644
--- a/src/i18n/locales/es.json
+++ b/src/i18n/locales/es.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Volver a cargar", 2 "app.errorHandler.action": "Volver a cargar",
3 "app.errorHandler.headline": "Algo salió mal.", 3 "app.errorHandler.headline": "Algo ha fallado.",
4 "changeserver.customServerLabel": "Servidor personalizado", 4 "changeserver.customServerLabel": "Servidor personalizado",
5 "changeserver.headline": "Cambiar servidor", 5 "changeserver.headline": "Cambiar servidor",
6 "changeserver.label": "Servidor", 6 "changeserver.label": "Servidor",
@@ -9,13 +9,12 @@
9 "connectionLostBanner.cta": "Recargar Servicio", 9 "connectionLostBanner.cta": "Recargar Servicio",
10 "connectionLostBanner.informationLink": "¿Qué ocurrió?", 10 "connectionLostBanner.informationLink": "¿Qué ocurrió?",
11 "connectionLostBanner.message": "¡Oh no! Ferdi perdió la conexión con {name}.", 11 "connectionLostBanner.message": "¡Oh no! Ferdi perdió la conexión con {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Iniciar Sesión",
13 "feature.debugger.title": "Publica la información de depuración",
14 "feature.nightlyBuilds.activate": "Activar", 13 "feature.nightlyBuilds.activate": "Activar",
15 "feature.nightlyBuilds.info": "Las \"Nightly builds\" son versiones altamente experimentales de Ferdi que pueden contener características sin pulir o sin completar. Estas versiones son utilizadas principalmente por los desarrolladores para probar sus nuevas características desarrolladas y cómo se comportarán en la versión final. Si no sabe lo que está haciendo, le sugerimos que no active las estas versiones.", 14 "feature.nightlyBuilds.info": "Las \"Nightly builds\" son versiones altamente experimentales de Ferdi que pueden contener características sin pulir o sin completar. Estas versiones son utilizadas principalmente por los desarrolladores para probar sus nuevas características desarrolladas y cómo se comportarán en la versión final. Si no sabe lo que está haciendo, le sugerimos que no active las estas versiones.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
17 "feature.publishDebugInfo.error": "Hubo un error al intentar publicar la información de depuración. Por favor, inténtalo de nuevo más tarde o revisa la consola para más información.", 16 "feature.publishDebugInfo.error": "Hubo un error al intentar publicar la información de depuración. Por favor, inténtalo de nuevo más tarde o revisa la consola para más información.",
18 "feature.publishDebugInfo.info": "Publicar tu información de depuración nos ayuda a encontrar problemas y errores en Ferdi. Al publicar tu información de depuración aceptas la política de privacidad y las condiciones de servicio de Ferdi Debuggger", 17 "feature.publishDebugInfo.info": "Publicar tu información de depuración nos ayuda a encontrar problemas y errores en Ferdi. Al publicar tu información de depuración aceptas la política de privacidad y las condiciones de servicio de depuración de Ferdi",
19 "feature.publishDebugInfo.privacy": "Política de Privacidad", 18 "feature.publishDebugInfo.privacy": "Política de Privacidad",
20 "feature.publishDebugInfo.publish": "Aceptar y publicar", 19 "feature.publishDebugInfo.publish": "Aceptar y publicar",
21 "feature.publishDebugInfo.published": "Su registro de depuración fue publicado y ahora está disponible en", 20 "feature.publishDebugInfo.published": "Su registro de depuración fue publicado y ahora está disponible en",
@@ -23,29 +22,29 @@
23 "feature.publishDebugInfo.title": "Publica la información de depuración", 22 "feature.publishDebugInfo.title": "Publica la información de depuración",
24 "feature.quickSwitch.info": "Puede seleccionar un servicio usando TAB, ↑ y ↓. Puede abrir servicio usando ENTER.", 23 "feature.quickSwitch.info": "Puede seleccionar un servicio usando TAB, ↑ y ↓. Puede abrir servicio usando ENTER.",
25 "feature.quickSwitch.search": "Buscar...", 24 "feature.quickSwitch.search": "Buscar...",
26 "feature.quickSwitch.title": "Cambiar rápidamente", 25 "feature.quickSwitch.title": "Cambio rápido",
27 "global.api.unhealthy": "No es posible conectarse a los servicios en línea de Ferdi.", 26 "global.api.unhealthy": "No es posible conectarse a los servicios en línea de Ferdi",
28 "global.cancel": "Cancelar", 27 "global.cancel": "Cancelar",
29 "global.edit": "Editar", 28 "global.edit": "Editar",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "No estás conectado a Internet", 30 "global.notConnectedToTheInternet": "No estás conectado a Internet",
32 "global.ok": "Ok", 31 "global.ok": "Aceptar",
33 "global.quit": "Quit", 32 "global.quit": "Salir",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "¿Estás seguro de que quieres salir de Ferdi?",
35 "global.save": "Save", 34 "global.save": "Guardar",
36 "global.settings": "Configuración", 35 "global.settings": "Configuración",
37 "global.spellchecker.useDefault": "Utilizar estándar del sistema ({default})", 36 "global.spellchecker.useDefault": "Utilizar estándar del sistema ({default})",
38 "global.spellchecking.autodetect": "Detectar el idioma automáticamente", 37 "global.spellchecking.autodetect": "Detectar el idioma automáticamente",
39 "global.spellchecking.autodetect.short": "Automático", 38 "global.spellchecking.autodetect.short": "Automático",
40 "global.spellchecking.language": "Corrector de ortografía", 39 "global.spellchecking.language": "Idioma de corrección ortográfica",
41 "global.submit": "Enviar", 40 "global.submit": "Enviar",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (para descubrir) o 'https://developeropers.whatismybrowser.com/useragents/explore/' (para elegir) su agente de usuario deseado y copiarlo aquí.",
43 "global.userAgentPref": "Navegador", 42 "global.userAgentPref": "Agente de Usuario",
44 "global.yes": "Yes", 43 "global.yes": "Sí",
45 "import.headline": "Importa tus servicios de Ferdi 4", 44 "import.headline": "Importa tus servicios de Ferdi 4",
46 "import.notSupportedHeadline": "Servicios aún no admitidos en Ferdi 5", 45 "import.notSupportedHeadline": "Servicios aún no admitidos en Ferdi 5",
47 "import.skip.label": "Quiero agregar servicios manualmente", 46 "import.skip.label": "Quiero agregar servicios manualmente",
48 "import.submit.label": "Importar servicios", 47 "import.submit.label": "Importar {count} servicios",
49 "infobar.authRequestFailed": "Error al intentar realizar la solicitud de autenticación. Por favor, cerrar la sesión y volver a entrar si este error persiste.", 48 "infobar.authRequestFailed": "Error al intentar realizar la solicitud de autenticación. Por favor, cerrar la sesión y volver a entrar si este error persiste.",
50 "infobar.buttonChangelog": "¿Qué hay de nuevo?", 49 "infobar.buttonChangelog": "¿Qué hay de nuevo?",
51 "infobar.buttonInstallUpdate": "Reiniciar e instalar actualización", 50 "infobar.buttonInstallUpdate": "Reiniciar e instalar actualización",
@@ -54,15 +53,15 @@
54 "infobar.requiredRequestsFailed": "No se han podido cargar los servicios ni la información de usuario", 53 "infobar.requiredRequestsFailed": "No se han podido cargar los servicios ni la información de usuario",
55 "infobar.servicesUpdated": "Tus servicios han sido actualizados.", 54 "infobar.servicesUpdated": "Tus servicios han sido actualizados.",
56 "infobar.updateAvailable": "Una nueva actualización de Ferdi está disponible", 55 "infobar.updateAvailable": "Una nueva actualización de Ferdi está disponible",
57 "infobox.dismiss": "Descargar", 56 "infobox.dismiss": "Descartar",
58 "invite.email.label": "Dirección de correo electrónico", 57 "invite.email.label": "Dirección de correo electrónico",
59 "invite.headline.friends": "Invita a 3 de tus amigos o compañeros", 58 "invite.headline.friends": "Invita a 3 de tus amigos o compañeros",
60 "invite.name.label": "Nombre", 59 "invite.name.label": "Nombre",
61 "invite.skip.label": "Lo haré más tarde", 60 "invite.skip.label": "Deseo continuar más tarde",
62 "invite.submit.label": "Enviar invitaciones", 61 "invite.submit.label": "Enviar invitaciones",
63 "invite.successInfo": "Invitaciones enviadas correctamente", 62 "invite.successInfo": "Invitaciones enviadas correctamente",
64 "locked.headline": "Bloqueado", 63 "locked.headline": "Bloqueado",
65 "locked.info": "Ferdi está bloqueado. Debe desbloquear Ferdi con su contraseña para ver mensajes.", 64 "locked.info": "Ferdi está actualmente bloqueado. Por favor, desbloquea Ferdi con tu contraseña para ver tus mensajes.",
66 "locked.invalidCredentials": "Contraseña incorrecta", 65 "locked.invalidCredentials": "Contraseña incorrecta",
67 "locked.password.label": "Contraseña", 66 "locked.password.label": "Contraseña",
68 "locked.submit.label": "Desbloquear", 67 "locked.submit.label": "Desbloquear",
@@ -70,8 +69,8 @@
70 "locked.touchIdPrompt": "desbloquear con Touch ID", 69 "locked.touchIdPrompt": "desbloquear con Touch ID",
71 "locked.unlockWithPassword": "Desbloquear con contraseña", 70 "locked.unlockWithPassword": "Desbloquear con contraseña",
72 "login.changeServer": "Cambiar servidor", 71 "login.changeServer": "Cambiar servidor",
73 "login.customServerQuestion": "Using a custom Ferdi server?", 72 "login.customServerQuestion": "¿Utilizar una cuenta de Franz para iniciar sesión?",
74 "login.customServerSuggestion": "Try importing your Franz account", 73 "login.customServerSuggestion": "Intenta importar tu cuenta de Franz en Ferdi",
75 "login.email.label": "Dirección de correo electrónico", 74 "login.email.label": "Dirección de correo electrónico",
76 "login.headline": "Iniciar sesión", 75 "login.headline": "Iniciar sesión",
77 "login.invalidCredentials": "Correo electrónico o contraseña no válidos ", 76 "login.invalidCredentials": "Correo electrónico o contraseña no válidos ",
@@ -87,30 +86,30 @@
87 "menu.app.autohideMenuBar": "Auto-ocultar barra de menú", 86 "menu.app.autohideMenuBar": "Auto-ocultar barra de menú",
88 "menu.app.checkForUpdates": "Comprobar actualizaciones", 87 "menu.app.checkForUpdates": "Comprobar actualizaciones",
89 "menu.app.hide": "Ocultar", 88 "menu.app.hide": "Ocultar",
90 "menu.app.hideOthers": "Hide Others", 89 "menu.app.hideOthers": "Ocultar otros",
91 "menu.app.unhide": "Unhide", 90 "menu.app.unhide": "Mostrar",
92 "menu.edit": "Editar", 91 "menu.edit": "Editar",
93 "menu.edit.copy": "Copy", 92 "menu.edit.copy": "Copiar",
94 "menu.edit.cut": "Cut", 93 "menu.edit.cut": "Cortar",
95 "menu.edit.delete": "Borrar", 94 "menu.edit.delete": "Borrar",
96 "menu.edit.emojiSymbols": "Emoji y Símbolos", 95 "menu.edit.emojiSymbols": "Emoji y Símbolos",
97 "menu.edit.findInPage": "Buscar en la página", 96 "menu.edit.findInPage": "Buscar en la página",
98 "menu.edit.paste": "Paste", 97 "menu.edit.paste": "Pegar",
99 "menu.edit.pasteAndMatchStyle": "Paste And Match Style", 98 "menu.edit.pasteAndMatchStyle": "Pegar y ajustar estilo",
100 "menu.edit.redo": "Redo", 99 "menu.edit.redo": "Rehacer",
101 "menu.edit.selectAll": "Select All", 100 "menu.edit.selectAll": "Seleccionar Todo",
102 "menu.edit.speech": "Leer", 101 "menu.edit.speech": "Leer",
103 "menu.edit.startDictation": "Empezar dictado", 102 "menu.edit.startDictation": "Empezar dictado",
104 "menu.edit.startSpeaking": "Empezar lectura", 103 "menu.edit.startSpeaking": "Empezar lectura",
105 "menu.edit.stopSpeaking": "Detener lectura", 104 "menu.edit.stopSpeaking": "Detener lectura",
106 "menu.edit.undo": "Undo", 105 "menu.edit.undo": "Deshacer",
107 "menu.file": "Archivo", 106 "menu.file": "Archivo",
108 "menu.help": "Help", 107 "menu.help": "Ayuda",
109 "menu.help.changelog": "Registro de cambios", 108 "menu.help.changelog": "Registro de cambios",
110 "menu.help.debugInfo": "Copiar información de depuración", 109 "menu.help.debugInfo": "Copiar información de depuración",
111 "menu.help.debugInfoCopiedBody": "Tu información de depuración ha sido copiada a tu portapapeles", 110 "menu.help.debugInfoCopiedBody": "Tu información de depuración ha sido copiada a tu portapapeles",
112 "menu.help.debugInfoCopiedHeadline": "Información de depurador de Ferdi", 111 "menu.help.debugInfoCopiedHeadline": "Información de depurador de Ferdi",
113 "menu.help.importExportData": "Import/Export Configuration Data", 112 "menu.help.importExportData": "Importar/Exportar datos de configuración",
114 "menu.help.learnMore": "Conocer más", 113 "menu.help.learnMore": "Conocer más",
115 "menu.help.privacy": "Declaración de privacidad", 114 "menu.help.privacy": "Declaración de privacidad",
116 "menu.help.publishDebugInfo": "Escribir información de depuración", 115 "menu.help.publishDebugInfo": "Escribir información de depuración",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Términos del Servicio", 117 "menu.help.tos": "Términos del Servicio",
119 "menu.services": "Servicios", 118 "menu.services": "Servicios",
120 "menu.services.activatePreviousService": "Activa el servicio previo", 119 "menu.services.activatePreviousService": "Activa el servicio previo",
121 "menu.services.addNewService": "Añadir Nuevo Servicio", 120 "menu.services.addNewService": "Añadir Nuevo Servicio...",
122 "menu.services.goHome": "Inicio", 121 "menu.services.goHome": "Inicio",
123 "menu.services.setNextServiceActive": "Activa el siguiente servicio", 122 "menu.services.setNextServiceActive": "Activa el siguiente servicio",
124 "menu.todos": "Tareas pendientes", 123 "menu.todos": "Tareas pendientes",
@@ -128,20 +127,20 @@
128 "menu.view.forward": "Siguiente", 127 "menu.view.forward": "Siguiente",
129 "menu.view.lockFerdi": "Bloquear Ferdi", 128 "menu.view.lockFerdi": "Bloquear Ferdi",
130 "menu.view.openQuickSwitch": "Abrir Cambio Rápido", 129 "menu.view.openQuickSwitch": "Abrir Cambio Rápido",
131 "menu.view.reloadFerdi": "Reload Ferdi", 130 "menu.view.reloadFerdi": "Recargar Ferdi",
132 "menu.view.reloadService": "Recargar Servicio", 131 "menu.view.reloadService": "Recargar Servicio",
133 "menu.view.reloadTodos": "Recargar Pendientes", 132 "menu.view.reloadTodos": "Recargar Pendientes",
134 "menu.view.resetZoom": "Actual Size", 133 "menu.view.resetZoom": "Tamaño Real",
135 "menu.view.toggleDarkMode": "Cambiar a modo oscuro", 134 "menu.view.toggleDarkMode": "Cambiar a modo oscuro",
136 "menu.view.toggleDevTools": "Activar las Herramientas para Desarrolladores", 135 "menu.view.toggleDevTools": "Activar las Herramientas para Desarrolladores",
137 "menu.view.toggleFullScreen": "Toggle Full Screen", 136 "menu.view.toggleFullScreen": "Cambiar a Pantalla Completa",
138 "menu.view.toggleServiceDevTools": "Mostrar Herramientas de Servicios para Desarrolladores", 137 "menu.view.toggleServiceDevTools": "Mostrar Herramientas de Servicios para Desarrolladores",
139 "menu.view.toggleTodosDevTools": "Tareas pendientes: Herramientas para desarrolladores", 138 "menu.view.toggleTodosDevTools": "Tareas pendientes: Herramientas para desarrolladores",
140 "menu.view.zoomIn": "Zoom In", 139 "menu.view.zoomIn": "Ampliar",
141 "menu.view.zoomOut": "Zoom Out", 140 "menu.view.zoomOut": "Reducir",
142 "menu.window": "Window", 141 "menu.window": "Ventana",
143 "menu.window.close": "Close", 142 "menu.window.close": "Cerrar",
144 "menu.window.minimize": "Minimize", 143 "menu.window.minimize": "Minimizar",
145 "menu.workspaces": "Espacios de trabajo", 144 "menu.workspaces": "Espacios de trabajo",
146 "menu.workspaces.addNewWorkspace": "Añadir nuevo espacio de trabajo...", 145 "menu.workspaces.addNewWorkspace": "Añadir nuevo espacio de trabajo...",
147 "menu.workspaces.closeWorkspaceDrawer": "Cerrar cajón de espacio de trabajo", 146 "menu.workspaces.closeWorkspaceDrawer": "Cerrar cajón de espacio de trabajo",
@@ -152,18 +151,7 @@
152 "password.link.login": "Inicia sesión en tu cuenta", 151 "password.link.login": "Inicia sesión en tu cuenta",
153 "password.link.signup": "Crear una cuenta gratuita", 152 "password.link.signup": "Crear una cuenta gratuita",
154 "password.noUser": "No se encontró un usuario con esa dirección de correo electrónico", 153 "password.noUser": "No se encontró un usuario con esa dirección de correo electrónico",
155 "password.successInfo": "Por favor revisa tu correo electrónico", 154 "password.successInfo": "Tu nueva contraseña ha sido enviada a tu dirección de email",
156 "pricing.features.accountSync": "Sincronización de cuenta",
157 "pricing.features.customWebsites": "Agregue sitios personalizados",
158 "pricing.features.desktopNotifications": "Notificaciones de escritorio",
159 "pricing.features.onPremise": "En sitio y otros servicios alojados",
160 "pricing.features.recipes": "Elegir entre más de 70 servicios",
161 "pricing.features.serviceProxies": "Apoderados de Servicio",
162 "pricing.features.spellchecker": "Soporte de corrector ortográfico",
163 "pricing.features.teamManagement": "Administración de Equipo",
164 "pricing.features.thirdPartyServices": "Instalar servicios de terceros",
165 "pricing.features.unlimitedServices": "Agregar servicios ilimitados",
166 "pricing.features.workspaces": "Espacios de trabajo",
167 "service.crashHandler.action": "Recargar {name}", 155 "service.crashHandler.action": "Recargar {name}",
168 "service.crashHandler.autoReload": "Intentando recuperar automáticamente {name} en {seconds} segundos", 156 "service.crashHandler.autoReload": "Intentando recuperar automáticamente {name} en {seconds} segundos",
169 "service.crashHandler.headline": "¡Oh, no!", 157 "service.crashHandler.headline": "¡Oh, no!",
@@ -174,11 +162,11 @@
174 "service.errorHandler.editAction": "Editar {name}", 162 "service.errorHandler.editAction": "Editar {name}",
175 "service.errorHandler.headline": "¡Oh, no!", 163 "service.errorHandler.headline": "¡Oh, no!",
176 "service.errorHandler.message": "Error", 164 "service.errorHandler.message": "Error",
177 "service.errorHandler.text": "{name} ha fallado la carga", 165 "service.errorHandler.text": "{name} no ha podido cargar.",
178 "service.webviewLoader.loading": "Cargando {service}", 166 "service.webviewLoader.loading": "Cargando {service}",
179 "services.getStarted": "Primeros pasos", 167 "services.getStarted": "Primeros pasos",
180 "services.login": "Iniciar sesión para usar Ferdi.", 168 "services.login": "Iniciar sesión para usar Ferdi.",
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Opcionalmente, puede cambiar su servidor Ferdi haciendo clic en el engranaje en la esquina inferior izquierda. Si está cambiando (de uno de los servidores alojados) a usar Ferdi sin una cuenta, por favor tenga en cuenta que puede exportar sus datos desde ese servidor y posteriormente importarlos usando el menú Ayuda para restaurar todos sus espacios de trabajo y servicios configurados!",
182 "services.serverless": "Usar Ferdi sin una cuenta", 170 "services.serverless": "Usar Ferdi sin una cuenta",
183 "services.welcome": "Bienvenido a Ferdi", 171 "services.welcome": "Bienvenido a Ferdi",
184 "settings.account.account.editButton": "Editar cuenta", 172 "settings.account.account.editButton": "Editar cuenta",
@@ -198,12 +186,12 @@
198 "settings.account.tryReloadServices": "Intentar de nuevo", 186 "settings.account.tryReloadServices": "Intentar de nuevo",
199 "settings.account.tryReloadUserInfoRequest": "Intentar de nuevo", 187 "settings.account.tryReloadUserInfoRequest": "Intentar de nuevo",
200 "settings.account.userInfoRequestFailed": "No se pudo cargar la información de usuario", 188 "settings.account.userInfoRequestFailed": "No se pudo cargar la información de usuario",
201 "settings.account.yourLicense": "Su Licencia Ferdi", 189 "settings.account.yourLicense": "Su Licencia Ferdi:",
202 "settings.app.accentColorInfo": "Escribe tu color de acento en un formato compatible con CSS. (Predeterminado: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Escribe tu color de acento en un formato compatible con CSS. (Predeterminado: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Limpiar caché", 191 "settings.app.buttonClearAllCache": "Limpiar caché",
204 "settings.app.buttonInstallUpdate": "Reiniciar e instalar actualización", 192 "settings.app.buttonInstallUpdate": "Reiniciar e instalar actualización",
205 "settings.app.buttonOpenFerdiProfileFolder": "Open Profile folder", 193 "settings.app.buttonOpenFerdiProfileFolder": "Abrir Carpeta de Perfil",
206 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open Service Recipes folder", 194 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Abrir carpeta de recetas de servicio",
207 "settings.app.buttonSearchForUpdate": "Comprobar actualizaciones", 195 "settings.app.buttonSearchForUpdate": "Comprobar actualizaciones",
208 "settings.app.cacheInfo": "El cache de Ferdi actualmente usa {size} de espacio en disco.", 196 "settings.app.cacheInfo": "El cache de Ferdi actualmente usa {size} de espacio en disco.",
209 "settings.app.cacheNotCleared": "No se ha podido eliminar el cache", 197 "settings.app.cacheNotCleared": "No se ha podido eliminar el cache",
@@ -218,14 +206,14 @@
218 "settings.app.form.beta": "Incluir versiones beta", 206 "settings.app.form.beta": "Incluir versiones beta",
219 "settings.app.form.clipboardNotifications": "Dejar de mostrar notificaciones acerca del portapapeles", 207 "settings.app.form.clipboardNotifications": "Dejar de mostrar notificaciones acerca del portapapeles",
220 "settings.app.form.closeToSystemTray": "Cerrar Ferdi a la barra de tareas", 208 "settings.app.form.closeToSystemTray": "Cerrar Ferdi a la barra de tareas",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirmar al salir de Ferdi",
222 "settings.app.form.customTodoServer": "Servidor de Todo personalizado", 210 "settings.app.form.customTodoServer": "Servidor de TODO personalizado",
223 "settings.app.form.darkMode": "Activar tema oscuro", 211 "settings.app.form.darkMode": "Habilitar modo oscuro",
224 "settings.app.form.enableGPUAcceleration": "Habilitar aceleración de GPU", 212 "settings.app.form.enableGPUAcceleration": "Habilitar aceleración de GPU",
225 "settings.app.form.enableLock": "Activar bloqueo por contraseña", 213 "settings.app.form.enableLock": "Activar bloqueo por contraseña",
226 "settings.app.form.enableMenuBar": "Mostrar a Ferdi en la barra de menús", 214 "settings.app.form.enableMenuBar": "Mostrar a Ferdi en la barra de menús",
227 "settings.app.form.enableSpellchecking": "Activar corrección ortográfica", 215 "settings.app.form.enableSpellchecking": "Activar corrección ortográfica",
228 "settings.app.form.enableSystemTray": "Mostrar Ferdi en la bandeja del sistema", 216 "settings.app.form.enableSystemTray": "Mostrar siempre icono de Ferdi en la bandeja del sistema",
229 "settings.app.form.enableTodos": "Activar Ferdi Todos", 217 "settings.app.form.enableTodos": "Activar Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Mantener los servicios en hibernación al iniciar", 218 "settings.app.form.hibernateOnStartup": "Mantener los servicios en hibernación al iniciar",
231 "settings.app.form.hibernationStrategy": "Estrategia de hibernación", 219 "settings.app.form.hibernationStrategy": "Estrategia de hibernación",
@@ -237,7 +225,7 @@
237 "settings.app.form.minimizeToSystemTray": "Minimizar Ferdi a la bandeja del sistema", 225 "settings.app.form.minimizeToSystemTray": "Minimizar Ferdi a la bandeja del sistema",
238 "settings.app.form.navigationBarBehaviour": "Comportamiento de la barra de navegación", 226 "settings.app.form.navigationBarBehaviour": "Comportamiento de la barra de navegación",
239 "settings.app.form.notifyTaskBarOnMessage": "Notificar en la Barra de tareas / Dock los nuevos mensajes", 227 "settings.app.form.notifyTaskBarOnMessage": "Notificar en la Barra de tareas / Dock los nuevos mensajes",
240 "settings.app.form.passwordToggle": "Password toggle", 228 "settings.app.form.passwordToggle": "Cambio de contraseña",
241 "settings.app.form.predefinedTodoServer": "Servidor de tareas", 229 "settings.app.form.predefinedTodoServer": "Servidor de tareas",
242 "settings.app.form.privateNotifications": "No mostrar contenido de mensajes en notificaciones", 230 "settings.app.form.privateNotifications": "No mostrar contenido de mensajes en notificaciones",
243 "settings.app.form.reloadAfterResume": "Recargar Ferdi después de reanudar el sistema", 231 "settings.app.form.reloadAfterResume": "Recargar Ferdi después de reanudar el sistema",
@@ -251,11 +239,12 @@
251 "settings.app.form.showDisabledServices": "Mostrar pestañas de servicios desactivados", 239 "settings.app.form.showDisabledServices": "Mostrar pestañas de servicios desactivados",
252 "settings.app.form.showDragArea": "Mostrar área arrastrable en la ventana", 240 "settings.app.form.showDragArea": "Mostrar área arrastrable en la ventana",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Mostrar la insignia de mensajes sin leer cuando las notificaciones están desactivadas", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Mostrar la insignia de mensajes sin leer cuando las notificaciones están desactivadas",
242 "settings.app.form.splitMode": "Activar el modo de vista separada",
254 "settings.app.form.startMinimized": "Iniciar minimizado", 243 "settings.app.form.startMinimized": "Iniciar minimizado",
255 "settings.app.form.universalDarkMode": "Activar modo oscuro universal", 244 "settings.app.form.universalDarkMode": "Activar modo oscuro universal",
256 "settings.app.form.useTouchIdToUnlock": "Permitir usar TouchID para desbloquear Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Permitir usar TouchID para desbloquear Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Usar estilo horizontal",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Estrategia para despertar",
259 "settings.app.headlineAdvanced": "Avanzado", 248 "settings.app.headlineAdvanced": "Avanzado",
260 "settings.app.headlineAppearance": "Apariencia", 249 "settings.app.headlineAppearance": "Apariencia",
261 "settings.app.headlineGeneral": "General", 250 "settings.app.headlineGeneral": "General",
@@ -265,16 +254,16 @@
265 "settings.app.hibernateInfo": "Por defecto, Ferdi mantendrá todos sus servicios abiertos y cargados en segundo plano para que estén listos cuando los necesite. La hibernación del servicio desactivará los mismos tras el tiempo especificado. Esto es útil para ahorrar RAM y evitar que los servicios ralentizen su sistema.", 254 "settings.app.hibernateInfo": "Por defecto, Ferdi mantendrá todos sus servicios abiertos y cargados en segundo plano para que estén listos cuando los necesite. La hibernación del servicio desactivará los mismos tras el tiempo especificado. Esto es útil para ahorrar RAM y evitar que los servicios ralentizen su sistema.",
266 "settings.app.inactivityLockInfo": "Minutos de inactividad, tras los cuales Ferdi debe bloquear automáticamente. Utilice 0 para desactivar", 255 "settings.app.inactivityLockInfo": "Minutos de inactividad, tras los cuales Ferdi debe bloquear automáticamente. Utilice 0 para desactivar",
267 "settings.app.languageDisclaimer": "Las traducciones oficiales son en inglés y alemán. Todos los demás idiomas son traducciones basadas en la comunidad.", 256 "settings.app.languageDisclaimer": "Las traducciones oficiales son en inglés y alemán. Todos los demás idiomas son traducciones basadas en la comunidad.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "El bloqueo de contraseña le permite mantener los mensajes protegidos.\nSi activa el bloqueo de contraseña, se le pedirá introducirla cada vez que inicie o bloquee Ferdi usando el símbolo de la esquina inferior izquierda o bien el acceso directo {lockShortcut}.",
269 "settings.app.lockedPassword": "Contraseña", 258 "settings.app.lockedPassword": "Contraseña",
270 "settings.app.lockedPasswordInfo": "Por favor, asegúrese de recordar la contraseña que establezca.\nSi la perdiera u olvidara, tendría que reinstalar Ferdi.", 259 "settings.app.lockedPasswordInfo": "Por favor, asegúrese de establecer una contraseña que usted pueda recordar.\nSi pierde esta contraseña, tendrá que reinstalar Ferdi.",
271 "settings.app.restartRequired": "Los cambios requieren reiniciar", 260 "settings.app.restartRequired": "Los cambios requieren reiniciar",
272 "settings.app.scheduledDNDInfo": "El \"No molestar\" programado permite definir un período de tiempo en el que no recibir notificaciones de Ferdi.", 261 "settings.app.scheduledDNDInfo": "El \"No molestar\" programado permite definir un período de tiempo en el que no recibir notificaciones de Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Horas en formato 24 horas. La hora de finalización puede ser anterior a la hora de inicio (por ejemplo, inicio 17:00, final 09:00) para habilitar No molestar la noche.", 262 "settings.app.scheduledDNDTimeInfo": "Horas en formato 24 horas. La hora de finalización puede ser anterior a la hora de inicio (por ejemplo, inicio 17:00, final 09:00) para habilitar No molestar la noche.",
274 "settings.app.sentryInfo": "Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!", 263 "settings.app.sentryInfo": "El envío de datos de telemetría nos permite encontrar errores en Ferdi - ¡No enviaremos ninguna información personal como sus mensajes!",
275 "settings.app.spellCheckerLanguageInfo": "Ferdi utiliza el corrector ortográfico incluido en su Mac. Si desea cambiar los lenguajes que el corrector ortográfico revisa, lo puede hacer en las Preferencias del Sistema de su Mac.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi utiliza el corrector ortográfico incluido en su Mac. Si desea cambiar los lenguajes que el corrector ortográfico revisa, lo puede hacer en las Preferencias del Sistema de su Mac.",
276 "settings.app.subheadlineCache": "Caché", 265 "settings.app.subheadlineCache": "Caché",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Perfil de Ferdi",
278 "settings.app.todoServerInfo": "Este servidor se utilizará para la función \"Ferdi Todo\".", 267 "settings.app.todoServerInfo": "Este servidor se utilizará para la función \"Ferdi Todo\".",
279 "settings.app.translationHelp": "Ayúdanos a traducir Ferdi a tu idioma.", 268 "settings.app.translationHelp": "Ayúdanos a traducir Ferdi a tu idioma.",
280 "settings.app.universalDarkModeInfo": "El Modo Oscuro Universal intenta generar dinámicamente estilos de modo oscuro para servicios que de otro modo no están soportados actualmente.", 269 "settings.app.universalDarkModeInfo": "El Modo Oscuro Universal intenta generar dinámicamente estilos de modo oscuro para servicios que de otro modo no están soportados actualmente.",
@@ -294,7 +283,7 @@
294 "settings.recipes.customService.headline.communityRecipes": "Recetas de terceros comunitarios", 283 "settings.recipes.customService.headline.communityRecipes": "Recetas de terceros comunitarios",
295 "settings.recipes.customService.headline.customRecipes": "Recetas de terceros comunitarios", 284 "settings.recipes.customService.headline.customRecipes": "Recetas de terceros comunitarios",
296 "settings.recipes.customService.headline.devRecipes": "Sus recetas de Servicio de Desarrollo", 285 "settings.recipes.customService.headline.devRecipes": "Sus recetas de Servicio de Desarrollo",
297 "settings.recipes.customService.intro": "Para añadir un servicio personalizado, copia la receta de servicio a:", 286 "settings.recipes.customService.intro": "Para añadir un servicio personalizado, copie la receta de servicio a:",
298 "settings.recipes.customService.openDevDocs": "Documentación para desarrolladores", 287 "settings.recipes.customService.openDevDocs": "Documentación para desarrolladores",
299 "settings.recipes.customService.openFolder": "Abrir carpeta", 288 "settings.recipes.customService.openFolder": "Abrir carpeta",
300 "settings.recipes.headline": "Servicios disponibles", 289 "settings.recipes.headline": "Servicios disponibles",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Cuando se activa, un servicio se apagará después de un período de tiempo para ahorrar recursos del sistema.", 321 "settings.service.form.isHibernatedEnabledInfo": "Cuando se activa, un servicio se apagará después de un período de tiempo para ahorrar recursos del sistema.",
333 "settings.service.form.isMutedInfo": "Cuando estén desactivados, todos los sonidos de notificación y la reproducción de audio serán silenciados", 322 "settings.service.form.isMutedInfo": "Cuando estén desactivados, todos los sonidos de notificación y la reproducción de audio serán silenciados",
334 "settings.service.form.name": "Nombre", 323 "settings.service.form.name": "Nombre",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Solo mostrar Favoritos en el recuento de no leídos",
335 "settings.service.form.openDarkmodeCss": "Abrir darkmode.css (modo oscuro)", 325 "settings.service.form.openDarkmodeCss": "Abrir darkmode.css (modo oscuro)",
336 "settings.service.form.openUserCss": "Abrir user.css", 326 "settings.service.form.openUserCss": "Abrir user.css",
337 "settings.service.form.openUserJs": "Abrir user.js", 327 "settings.service.form.openUserJs": "Abrir user.js",
338 "settings.service.form.proxy.headline": "Ajustes Proxy HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "Ajustes Proxy HTTP/HTTPS",
339 "settings.service.form.proxy.host": "Servidor/IP Proxy", 329 "settings.service.form.proxy.host": "Servidor/IP Proxy",
340 "settings.service.form.proxy.info": "Las configuraciones de Proxy no se sincronizarán con los servidores de Ferdi.", 330 "settings.service.form.proxy.info": "Las configuraciones del Proxy no se sincronizarán con los servidores de Ferdi.",
341 "settings.service.form.proxy.isEnabled": "Utilizar Proxy", 331 "settings.service.form.proxy.isEnabled": "Utilizar Proxy",
342 "settings.service.form.proxy.password": "Contraseña (opcional)", 332 "settings.service.form.proxy.password": "Contraseña (opcional)",
343 "settings.service.form.proxy.port": "Puerto", 333 "settings.service.form.proxy.port": "Puerto",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Descubrir servicios", 344 "settings.services.discoverServices": "Descubrir servicios",
355 "settings.services.headline": "Tus servicios", 345 "settings.services.headline": "Tus servicios",
356 "settings.services.noServicesAdded": "Empieze añadiendo un servicio.", 346 "settings.services.noServicesAdded": "Empieze añadiendo un servicio.",
347 "settings.services.nothingFound": "Lo sentimos, pero no pudimos encontrar ningún servicio similar a tu búsqueda, sin embargo: puedes agregarlo utilizando la opción de \"Sitio web personalizado\". \nRecuerda que pueden aparecer más servicios de los que has agregado a Ferdi desde la versión que estás utilizando. Para poder utilizar los nuevos servicios disponibles, considera actualizar a la versión más reciente.",
357 "settings.services.servicesRequestFailed": "No pudo cargar tus servicios", 348 "settings.services.servicesRequestFailed": "No pudo cargar tus servicios",
358 "settings.services.tooltip.isDisabled": "El servicio está desactivado", 349 "settings.services.tooltip.isDisabled": "El servicio está desactivado",
359 "settings.services.tooltip.isMuted": "Todos los sonidos están silenciados", 350 "settings.services.tooltip.isMuted": "Todos los sonidos están silenciados",
@@ -377,7 +368,7 @@
377 "settings.team.contentHeadline": "Administración de Equipo", 368 "settings.team.contentHeadline": "Administración de Equipo",
378 "settings.team.copy": "La gestión de equipos de Franz's te permite administrar suscripciones de Franz para múltiples usuarios. Por favor, ten en cuenta que tener una suscripción a Franz Premium no te dará ninguna ventaja en el uso de Ferdi: la única razón por la que todavía tienes acceso a la Gestión de Equipos es para que puedas gestionar tus equipos de Franz y para que no pierdas ninguna funcionalidad en la gestión de tu cuenta.", 369 "settings.team.copy": "La gestión de equipos de Franz's te permite administrar suscripciones de Franz para múltiples usuarios. Por favor, ten en cuenta que tener una suscripción a Franz Premium no te dará ninguna ventaja en el uso de Ferdi: la única razón por la que todavía tienes acceso a la Gestión de Equipos es para que puedas gestionar tus equipos de Franz y para que no pierdas ninguna funcionalidad en la gestión de tu cuenta.",
379 "settings.team.headline": "Equipo", 370 "settings.team.headline": "Equipo",
380 "settings.team.intro": "You are currently using Franz Servers, which is why you have access to Team Management.", 371 "settings.team.intro": "Actualmente estás usando servidores Franz, por lo que tienes acceso a la Gestión de Equipos.",
381 "settings.team.manageAction": "Administra tu equipo en meetfranz.com", 372 "settings.team.manageAction": "Administra tu equipo en meetfranz.com",
382 "settings.team.teamsUnavailable": "Los equipos no están disponibles", 373 "settings.team.teamsUnavailable": "Los equipos no están disponibles",
383 "settings.team.teamsUnavailableInfo": "Los equipos están disponibles actualmente sólo cuando se utiliza el servidor Franz y después de pagar por Franz Professional. Por favor, cambie su servidor a https://api.franz)[video] .com para usar equipos.", 374 "settings.team.teamsUnavailableInfo": "Los equipos están disponibles actualmente sólo cuando se utiliza el servidor Franz y después de pagar por Franz Professional. Por favor, cambie su servidor a https://api.franz)[video] .com para usar equipos.",
@@ -388,7 +379,7 @@
388 "settings.user.form.currentPassword": "Contraseña actual", 379 "settings.user.form.currentPassword": "Contraseña actual",
389 "settings.user.form.email": "Correo electrónico", 380 "settings.user.form.email": "Correo electrónico",
390 "settings.user.form.firstname": "Nombre", 381 "settings.user.form.firstname": "Nombre",
391 "settings.user.form.lastname": "Apellido", 382 "settings.user.form.lastname": "Apellidos",
392 "settings.user.form.newPassword": "Nueva contraseña", 383 "settings.user.form.newPassword": "Nueva contraseña",
393 "settings.workspace.add.form.name": "Nombre", 384 "settings.workspace.add.form.name": "Nombre",
394 "settings.workspace.add.form.submitButton": "Crear un sitio de trabajo", 385 "settings.workspace.add.form.submitButton": "Crear un sitio de trabajo",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Intentar de nuevo", 396 "settings.workspaces.tryReloadWorkspaces": "Intentar de nuevo",
406 "settings.workspaces.updatedInfo": "Tus cambios han sido guardados", 397 "settings.workspaces.updatedInfo": "Tus cambios han sido guardados",
407 "settings.workspaces.workspaceFeatureHeadline": "Menos es más: Presentación de Ferdi Workspaces", 398 "settings.workspaces.workspaceFeatureHeadline": "Menos es más: Presentación de Ferdi Workspaces",
408 "settings.workspaces.workspaceFeatureInfo": "Los espacios de trabajo Ferdi permiten centrarse en lo que es importante. Configure diferentes conjuntos de servicios y cambie fácilmente entre ellos en cualquier momento. Usted decide qué servicios necesita, cuándo y dónde, para que podamos ayudarte a mantenerte al tanto - o apartarte fácilmente del trabajo cuando asi lo desees.", 399 "settings.workspaces.workspaceFeatureInfo": "Los espacios de trabajo Ferdi permiten centrarse en lo que es importante. Configure diferentes conjuntos de servicios y cambie fácilmente entre ellos en cualquier momento. Usted decide qué servicios necesita, cuándo y dónde, para que podamos ayudarte a mantenerte al tanto - o apartarte fácilmente del trabajo cuando así lo desees.",
409 "settings.workspaces.workspacesRequestFailed": "No se han podido cargar sus áreas de trabajo", 400 "settings.workspaces.workspacesRequestFailed": "No se han podido cargar sus áreas de trabajo",
410 "setupAssistant.headline": "Empecemos", 401 "setupAssistant.headline": "Empecemos",
411 "setupAssistant.subheadline": "Elige entre nuestros servicios más utilizados y vuelve a ponerte al tanto de tu mensajería ahora.", 402 "setupAssistant.subheadline": "Elige entre nuestros servicios más utilizados y vuelve a ponerte al tanto de tu mensajería ahora.",
@@ -422,7 +413,7 @@
422 "signup.emailDuplicate": "Ya existe un usuario con esa dirección de correo electrónico", 413 "signup.emailDuplicate": "Ya existe un usuario con esa dirección de correo electrónico",
423 "signup.firstname.label": "Nombre", 414 "signup.firstname.label": "Nombre",
424 "signup.headline": "Registrarse", 415 "signup.headline": "Registrarse",
425 "signup.lastname.label": "Apellido", 416 "signup.lastname.label": "Apellidos",
426 "signup.legal.info": "Al crear una cuenta en Ferdi usted acepta", 417 "signup.legal.info": "Al crear una cuenta en Ferdi usted acepta",
427 "signup.legal.privacy": "Declaración de privacidad", 418 "signup.legal.privacy": "Declaración de privacidad",
428 "signup.legal.terms": "Términos de servicio", 419 "signup.legal.terms": "Términos de servicio",
@@ -432,21 +423,21 @@
432 "tabs.item.confirmDeleteService": "¿Estás seguro que quieres elimiar el servicio de {serviceName}?", 423 "tabs.item.confirmDeleteService": "¿Estás seguro que quieres elimiar el servicio de {serviceName}?",
433 "tabs.item.deleteService": "Eliminar servicio", 424 "tabs.item.deleteService": "Eliminar servicio",
434 "tabs.item.disableAudio": "Desactivar sonido", 425 "tabs.item.disableAudio": "Desactivar sonido",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Desactivar modo oscuro",
436 "tabs.item.disableNotifications": "Desactivar notificaciones", 427 "tabs.item.disableNotifications": "Desactivar notificaciones",
437 "tabs.item.disableService": "Desactivar servicio", 428 "tabs.item.disableService": "Desactivar servicio",
438 "tabs.item.enableAudio": "Habilitar audio", 429 "tabs.item.enableAudio": "Habilitar audio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Habilitar modo oscuro",
440 "tabs.item.enableNotification": "Activar notificaciones", 431 "tabs.item.enableNotification": "Activar notificaciones",
441 "tabs.item.enableService": "Activar servicio", 432 "tabs.item.enableService": "Activar servicio",
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernar servicio",
443 "tabs.item.reload": "Volver a cargar", 434 "tabs.item.reload": "Volver a cargar",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Despertar servicio",
445 "validation.email": "{field} no es válido", 436 "validation.email": "{field} no es válido",
446 "validation.minLength": "{field} debería tener al menos {length} caracteres", 437 "validation.minLength": "{field} debería tener al menos {length} caracteres",
447 "validation.oneRequired": "Al menos uno es requerido", 438 "validation.oneRequired": "Al menos uno es requerido",
448 "validation.required": "{field} es obligatorio", 439 "validation.required": "{field} es obligatorio",
449 "validation.url": "{field} no es una URL válida", 440 "validation.url": "{field} no es una dirección URL válida",
450 "webControls.back": "Volver", 441 "webControls.back": "Volver",
451 "webControls.forward": "Siguiente", 442 "webControls.forward": "Siguiente",
452 "webControls.goHome": "Inicio", 443 "webControls.goHome": "Inicio",
@@ -459,7 +450,7 @@
459 "workspaceDrawer.headline": "Espacios de trabajo", 450 "workspaceDrawer.headline": "Espacios de trabajo",
460 "workspaceDrawer.item.contextMenuEdit": "editar", 451 "workspaceDrawer.item.contextMenuEdit": "editar",
461 "workspaceDrawer.item.noServicesAddedYet": "Ningún servicio ha sido añadido", 452 "workspaceDrawer.item.noServicesAddedYet": "Ningún servicio ha sido añadido",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Los espacios de trabajo Ferdi permiten centrarse en lo que es importante. Configure diferentes conjuntos de servicios y cambie fácilmente entre ellos en cualquier momento. </p><p>Usted decide qué servicios necesita, cuándo y dónde, para que podamos ayudarte a mantenerte al tanto - o apartarte fácilmente del trabajo cuando asi lo desees.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Los espacios de trabajo Ferdi permiten centrarse en lo que es importante. Configure diferentes conjuntos de servicios y cambie fácilmente entre ellos en cualquier momento. </p><p>Usted decide qué servicios necesita, cuándo y dónde, para que podamos ayudarte a mantenerte al tanto - o apartarte fácilmente del trabajo cuando así lo desees.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Editar ajustes de áreas de trabajo", 454 "workspaceDrawer.workspacesSettingsTooltip": "Editar ajustes de áreas de trabajo",
464 "workspaces.switchingIndicator.switchingTo": "Cambiando a" 455 "workspaces.switchingIndicator.switchingTo": "Cambiando a"
465} 456}
diff --git a/src/i18n/locales/fi.json b/src/i18n/locales/fi.json
index 5ccea37e5..e6c756935 100644
--- a/src/i18n/locales/fi.json
+++ b/src/i18n/locales/fi.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Lataa uudelleen", 2 "app.errorHandler.action": "Lataa uudelleen",
3 "app.errorHandler.headline": "Jotain meni pieleen", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Mukautettu palvelin", 4 "changeserver.customServerLabel": "Mukautettu palvelin",
5 "changeserver.headline": "Vaihda palvelinta", 5 "changeserver.headline": "Vaihda palvelinta",
6 "changeserver.label": "Palvelin", 6 "changeserver.label": "Palvelin",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Mitä tapahtui?", 10 "connectionLostBanner.informationLink": "Mitä tapahtui?",
11 "connectionLostBanner.message": "Voi ei! Ferdi menetti yhteyden {name}.", 11 "connectionLostBanner.message": "Voi ei! Ferdi menetti yhteyden {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Julkaise virheraportti",
14 "feature.nightlyBuilds.activate": "Aktivoi", 13 "feature.nightlyBuilds.activate": "Aktivoi",
15 "feature.nightlyBuilds.info": "Uusimmat versiot ovat Ferdin kokeellisia versioita, jotka voivat sisältää viimeistelemättömiä tai keskeneräisiä ominaisuuksia. Näitä uusimpia versioita käyttävät pääasiassa kehittäjät testaamaan uusia ominaisuuksia ja miten ne toimivat lopullisessa versiossa. Jos et tiedä mitä olet tekemässä, suosittelemme ettet aktivoi uusimpia versioita.", 14 "feature.nightlyBuilds.info": "Uusimmat versiot ovat Ferdin kokeellisia versioita, jotka voivat sisältää viimeistelemättömiä tai keskeneräisiä ominaisuuksia. Näitä uusimpia versioita käyttävät pääasiassa kehittäjät testaamaan uusia ominaisuuksia ja miten ne toimivat lopullisessa versiossa. Jos et tiedä mitä olet tekemässä, suosittelemme ettet aktivoi uusimpia versioita.",
16 "feature.nightlyBuilds.title": "Uusimmat versiot", 15 "feature.nightlyBuilds.title": "Uusimmat versiot",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Valitse palvelu painamalla TAB, ↑ ja ↓. Avaa palvelu painamalla ENTER.", 23 "feature.quickSwitch.info": "Valitse palvelu painamalla TAB, ↑ ja ↓. Avaa palvelu painamalla ENTER.",
25 "feature.quickSwitch.search": "Etsi...", 24 "feature.quickSwitch.search": "Etsi...",
26 "feature.quickSwitch.title": "Pikavalitsin", 25 "feature.quickSwitch.title": "Pikavalitsin",
27 "global.api.unhealthy": "Ferdin verkkopalveluihin ei saada yhteyttä", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Peruuta", 27 "global.cancel": "Cancel",
29 "global.edit": "Muokkaa", 28 "global.edit": "Muokkaa",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Et ole yhteydessä internetiin.", 30 "global.notConnectedToTheInternet": "Et ole yhteydessä internetiin.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Asetukset", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Käytä järjestelmän oletusasetusta ({default})", 36 "global.spellchecker.useDefault": "Käytä järjestelmän oletusasetusta ({default})",
38 "global.spellchecking.autodetect": "Tunnista kieli automaattisesti", 37 "global.spellchecking.autodetect": "Tunnista kieli automaattisesti",
39 "global.spellchecking.autodetect.short": "Automaattinen", 38 "global.spellchecking.autodetect.short": "Automaattinen",
40 "global.spellchecking.language": "Oikeinkirjoituksen tarkistuskieli", 39 "global.spellchecking.language": "Oikeinkirjoituksen tarkistuskieli",
41 "global.submit": "Jatka", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Tuo Ferdin 4 palveluasi", 44 "import.headline": "Tuo Ferdin 4 palveluasi",
46 "import.notSupportedHeadline": "Palvelut eivät vielä tue Ferdi 5-versiota", 45 "import.notSupportedHeadline": "Palvelut eivät vielä tue Ferdi 5-versiota",
47 "import.skip.label": "Haluan lisätä palvelut manuaalisesti", 46 "import.skip.label": "Haluan lisätä palvelut manuaalisesti",
48 "import.submit.label": "Tuo palveluita", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Todennuspyynnön suoritamisessa tapahtui virhe. Jos tämä virhe toistuu, ole hyvä ja yritä kirjautua ulos. Kirjaudu sen jälkeen uudestaan sisälle.", 48 "infobar.authRequestFailed": "Todennuspyynnön suoritamisessa tapahtui virhe. Jos tämä virhe toistuu, ole hyvä ja yritä kirjautua ulos. Kirjaudu sen jälkeen uudestaan sisälle.",
50 "infobar.buttonChangelog": "Mitä uutta?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Käynnistä uudelleen ja asenna päivitys", 50 "infobar.buttonInstallUpdate": "Käynnistä uudelleen ja asenna päivitys",
52 "infobar.buttonReloadServices": "Lataa palvelut uudestaan", 51 "infobar.buttonReloadServices": "Lataa palvelut uudestaan",
53 "infobar.hide": "Piilota", 52 "infobar.hide": "Piilota",
@@ -75,7 +74,7 @@
75 "login.email.label": "Sähköpostiosoite", 74 "login.email.label": "Sähköpostiosoite",
76 "login.headline": "Kirjaudu sisään", 75 "login.headline": "Kirjaudu sisään",
77 "login.invalidCredentials": "Sähköpostiosoite tai salasana ei kelpaa", 76 "login.invalidCredentials": "Sähköpostiosoite tai salasana ei kelpaa",
78 "login.link.password": "Nollaa salasana", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Luo ilmainen tili", 78 "login.link.signup": "Luo ilmainen tili",
80 "login.password.label": "Salasana", 79 "login.password.label": "Salasana",
81 "login.serverLogout": "Istuntosi on vanhentunut. Kirjaudu uudelleen sisään.", 80 "login.serverLogout": "Istuntosi on vanhentunut. Kirjaudu uudelleen sisään.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Tuki", 116 "menu.help.support": "Tuki",
118 "menu.help.tos": "Käyttöehdot", 117 "menu.help.tos": "Käyttöehdot",
119 "menu.services": "Palvelut", 118 "menu.services": "Palvelut",
120 "menu.services.activatePreviousService": "Aktivoi edellinen palvelu", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Etusivu", 121 "menu.services.goHome": "Etusivu",
123 "menu.services.setNextServiceActive": "Aktivoi seuraava palvelu", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos-tehtävät", 123 "menu.todos": "Todos-tehtävät",
125 "menu.todos.enableTodos": "Ota Todos käyttöön", 124 "menu.todos.enableTodos": "Ota Todos käyttöön",
126 "menu.view": "Katso", 125 "menu.view": "Katso",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Kaikki palvelut", 147 "menu.workspaces.defaultWorkspace": "Kaikki palvelut",
149 "menu.workspaces.openWorkspaceDrawer": "Avaa työtilan valikko", 148 "menu.workspaces.openWorkspaceDrawer": "Avaa työtilan valikko",
150 "password.email.label": "Sähköpostiosoite", 149 "password.email.label": "Sähköpostiosoite",
151 "password.headline": "Nollaa salasana", 150 "password.headline": "Reset password",
152 "password.link.login": "Kirjaudu tilillesi", 151 "password.link.login": "Kirjaudu tilillesi",
153 "password.link.signup": "Luo ilmainen tili", 152 "password.link.signup": "Luo ilmainen tili",
154 "password.noUser": "Tälle sähköpostiosoiteelle ei löytynyt käyttäjää", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Ole hyvä ja tarkista sähköpostisi", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Tilin Synkronointi",
157 "pricing.features.customWebsites": "Lisää mukautettuja sivustoja",
158 "pricing.features.desktopNotifications": "Työpöytäilmoitukset",
159 "pricing.features.onPremise": "Toimitila ja muut Hosting-palvelut",
160 "pricing.features.recipes": "Valitse yli 70 Palvelusta",
161 "pricing.features.serviceProxies": "Palveluiden Välityspalvelimet",
162 "pricing.features.spellchecker": "Oikoluvun tuki",
163 "pricing.features.teamManagement": "Tiimin Hallinta",
164 "pricing.features.thirdPartyServices": "Asenna kolmannen osapuolen palveluita",
165 "pricing.features.unlimitedServices": "Lisää rajattomat palvelut",
166 "pricing.features.workspaces": "Työtilat",
167 "service.crashHandler.action": "Lataa uudestaan {name}", 155 "service.crashHandler.action": "Lataa uudestaan {name}",
168 "service.crashHandler.autoReload": "Yritetään palauttaa {name} automaattisesti {seconds} sekunnin kuluttua", 156 "service.crashHandler.autoReload": "Yritetään palauttaa {name} automaattisesti {seconds} sekunnin kuluttua",
169 "service.crashHandler.headline": "Voi ei!", 157 "service.crashHandler.headline": "Voi ei!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Käytä Ferdia ilman tiliä", 170 "services.serverless": "Käytä Ferdia ilman tiliä",
183 "services.welcome": "Tervetuloa Ferdiin", 171 "services.welcome": "Tervetuloa Ferdiin",
184 "settings.account.account.editButton": "Muokkaa tiliä", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Tili ei ole käytettävissä", 173 "settings.account.accountUnavailable": "Tili ei ole käytettävissä",
186 "settings.account.accountUnavailableInfo": "Käytät Ferdia ilman tiliä. Jos haluat käyttää Ferdia tilin kanssa ja pitää palvelusi synkronoituna kaikissa asennuksissa, valitse Asetukset-välilehdessä palvelin ja kirjaudu sisään.", 174 "settings.account.accountUnavailableInfo": "Käytät Ferdia ilman tiliä. Jos haluat käyttää Ferdia tilin kanssa ja pitää palvelusi synkronoituna kaikissa asennuksissa, valitse Asetukset-välilehdessä palvelin ja kirjaudu sisään.",
187 "settings.account.buttonSave": "Päivitä profiili", 175 "settings.account.buttonSave": "Päivitä profiili",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Olet saanut sähköpostiviestissä linkin, jonka kautta voit vahvistaa tilisi poistamisen. Tiliäsi ja tietoja ei voi palauttaa!", 177 "settings.account.deleteEmailSent": "Olet saanut sähköpostiviestissä linkin, jonka kautta voit vahvistaa tilisi poistamisen. Tiliäsi ja tietoja ei voi palauttaa!",
190 "settings.account.deleteInfo": "Jos et enää tarvitse Ferdi-tiliäsi, voit poistaa tilisi ja kaikki siihen liittyvät tiedot täältä.", 178 "settings.account.deleteInfo": "Jos et enää tarvitse Ferdi-tiliäsi, voit poistaa tilisi ja kaikki siihen liittyvät tiedot täältä.",
191 "settings.account.headline": "Tili", 179 "settings.account.headline": "Tili",
192 "settings.account.headlineAccount": "Tilin tiedot", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Vaaravyöhyke", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Laskut", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Vaihda salasana", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Päivitä profiili", 184 "settings.account.headlineProfile": "Päivitä profiili",
197 "settings.account.successInfo": "Tekemäsi muutokset on tallennettu", 185 "settings.account.successInfo": "Tekemäsi muutokset on tallennettu",
198 "settings.account.tryReloadServices": "Yritä uudelleen", 186 "settings.account.tryReloadServices": "Yritä uudelleen",
199 "settings.account.tryReloadUserInfoRequest": "Yritä uudelleen", 187 "settings.account.tryReloadUserInfoRequest": "Yritä uudelleen",
200 "settings.account.userInfoRequestFailed": "Käyttäjätietoja ei voitu ladata", 188 "settings.account.userInfoRequestFailed": "Käyttäjätietoja ei voitu ladata",
201 "settings.account.yourLicense": "Sinun Ferdi-lisenssi", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Tyhjennä välimuisti", 191 "settings.app.buttonClearAllCache": "Tyhjennä välimuisti",
204 "settings.app.buttonInstallUpdate": "Käynnistä uudelleen ja asenna päivitys", 192 "settings.app.buttonInstallUpdate": "Käynnistä uudelleen ja asenna päivitys",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Mukautettu Todo-Palvelin", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Ota tumma tila käyttöön", 211 "settings.app.form.darkMode": "Ota tumma tila käyttöön",
224 "settings.app.form.enableGPUAcceleration": "Ota Gpu-kiihdytys käyttöön", 212 "settings.app.form.enableGPUAcceleration": "Ota Gpu-kiihdytys käyttöön",
225 "settings.app.form.enableLock": "Ota Salasanan lukitus käyttöön", 213 "settings.app.form.enableLock": "Ota Salasanan lukitus käyttöön",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Ota oikoluku käyttöön", 215 "settings.app.form.enableSpellchecking": "Ota oikoluku käyttöön",
228 "settings.app.form.enableSystemTray": "Näytä Ferdi ilmoitusalueella", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Ota Ferdi Todos käyttöön", 217 "settings.app.form.enableTodos": "Ota Ferdi Todos käyttöön",
230 "settings.app.form.hibernateOnStartup": "Pidä palvelut horrostilassa käynnistettäessä", 218 "settings.app.form.hibernateOnStartup": "Pidä palvelut horrostilassa käynnistettäessä",
231 "settings.app.form.hibernationStrategy": "Horrostila-suunnitelma", 219 "settings.app.form.hibernationStrategy": "Horrostila-suunnitelma",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Näytä Estetyt palvelut -välilehdet", 239 "settings.app.form.showDisabledServices": "Näytä Estetyt palvelut -välilehdet",
252 "settings.app.form.showDragArea": "Näytä ikkunassa siirrettävä alue", 240 "settings.app.form.showDragArea": "Näytä ikkunassa siirrettävä alue",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Näytä merkki lukemattomasta viestistä kun ilmoitukset on poistettu käytöstä", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Näytä merkki lukemattomasta viestistä kun ilmoitukset on poistettu käytöstä",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Käynnistä pienennettynä", 243 "settings.app.form.startMinimized": "Käynnistä pienennettynä",
255 "settings.app.form.universalDarkMode": "Ota käyttöön yleinen tumma tila", 244 "settings.app.form.universalDarkMode": "Ota käyttöön yleinen tumma tila",
256 "settings.app.form.useTouchIdToUnlock": "Salli TouchID:n käyttö Ferdin avaamiseksi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Lisäasetukset", 248 "settings.app.headlineAdvanced": "Lisäasetukset",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Viralliset käännökset ovat englanti ja saksa. Kaikki muut kielet ovat yhteisön kääntämiä.", 256 "settings.app.languageDisclaimer": "Viralliset käännökset ovat englanti ja saksa. Kaikki muut kielet ovat yhteisön kääntämiä.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Salasana", 258 "settings.app.lockedPassword": "Salasana",
270 "settings.app.lockedPasswordInfo": "Varmista, että luot salasanan, jonka muistat.\nJos hukkaat tämän salasanan, sinun täytyy asentaa Ferdi uudelleen.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Muutokset vaativat uudelleenkäynnistyksen", 260 "settings.app.restartRequired": "Muutokset vaativat uudelleenkäynnistyksen",
272 "settings.app.scheduledDNDInfo": "Ajastetun Älä häiritse-tilan avulla voit määritellä ajanjakson, jonka aikana et halua saada ilmoituksia Ferdistä.", 261 "settings.app.scheduledDNDInfo": "Ajastetun Älä häiritse-tilan avulla voit määritellä ajanjakson, jonka aikana et halua saada ilmoituksia Ferdistä.",
273 "settings.app.scheduledDNDTimeInfo": "Ajastin 24 tunnin järjestelmässä. Kun Älä häiritse-tila otetaan yöksi käyttöön, päättymisaika voi olla ennen alkamisaikaa (esim. alku 17:00, loppu 09:00).", 262 "settings.app.scheduledDNDTimeInfo": "Ajastin 24 tunnin järjestelmässä. Kun Älä häiritse-tila otetaan yöksi käyttöön, päättymisaika voi olla ennen alkamisaikaa (esim. alku 17:00, loppu 09:00).",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi käyttää Macin sisäänrakennettua oikolukua tarkastaessaan kirjoitusvirheitä. Jos haluat muuttaa tarkastettavaa kieltä, voit tehdä sen Macin järjestelmän asetuksissa.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi käyttää Macin sisäänrakennettua oikolukua tarkastaessaan kirjoitusvirheitä. Jos haluat muuttaa tarkastettavaa kieltä, voit tehdä sen Macin järjestelmän asetuksissa.",
276 "settings.app.subheadlineCache": "Välimuisti", 265 "settings.app.subheadlineCache": "Välimuisti",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Tätä palvelinta käytetään \"Ferdi Todo\" -toiminnossa.", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Auta meitä kääntämään Ferdi omalle kielellesi.", 268 "settings.app.translationHelp": "Auta meitä kääntämään Ferdi omalle kielellesi.",
280 "settings.app.universalDarkModeInfo": "Yleinen Tumma-tila yrittää luoda palveluille tyylejä, joita ei tueta tällä hetkellä.", 269 "settings.app.universalDarkModeInfo": "Yleinen Tumma-tila yrittää luoda palveluille tyylejä, joita ei tueta tällä hetkellä.",
281 "settings.app.updateStatusAvailable": "Päivitys saatavilla, ladataan...", 270 "settings.app.updateStatusAvailable": "Päivitys saatavilla, ladataan...",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Yhteisön Kolmannen osapuolen Ohjeet", 283 "settings.recipes.customService.headline.communityRecipes": "Yhteisön Kolmannen osapuolen Ohjeet",
295 "settings.recipes.customService.headline.customRecipes": "Kolmannen osapuolen ohjeet", 284 "settings.recipes.customService.headline.customRecipes": "Kolmannen osapuolen ohjeet",
296 "settings.recipes.customService.headline.devRecipes": "Ohjeet palvelun kehittämiseen", 285 "settings.recipes.customService.headline.devRecipes": "Ohjeet palvelun kehittämiseen",
297 "settings.recipes.customService.intro": "Jos haluat lisätä mukautetun palvelun, kopioi palvelun ohje:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Ohjelmoijan dokumentaatio", 287 "settings.recipes.customService.openDevDocs": "Ohjelmoijan dokumentaatio",
299 "settings.recipes.customService.openFolder": "Avaa kansio", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Käytettävissä olevat palvelut", 289 "settings.recipes.headline": "Käytettävissä olevat palvelut",
301 "settings.recipes.missingService": "Palvelu puuttuu?", 290 "settings.recipes.missingService": "Palvelu puuttuu?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Tumman tilan kirkkaus", 301 "settings.service.form.darkReaderBrightness": "Tumman tilan kirkkaus",
313 "settings.service.form.darkReaderContrast": "Tumman tilan kontrasti", 302 "settings.service.form.darkReaderContrast": "Tumman tilan kontrasti",
314 "settings.service.form.darkReaderSepia": "Tumman tilan seepia", 303 "settings.service.form.darkReaderSepia": "Tumman tilan seepia",
315 "settings.service.form.deleteButton": "Poista palvelu", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Muokkaa {name}", 305 "settings.service.form.editServiceHeadline": "Muokkaa {name}",
317 "settings.service.form.enableAudio": "Ota ääni käyttöön", 306 "settings.service.form.enableAudio": "Ota ääni käyttöön",
318 "settings.service.form.enableBadge": "Näytä lukemattomat viestit", 307 "settings.service.form.enableBadge": "Näytä lukemattomat viestit",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Kun poistettu käytöstä, kaikki ilmoitusäänet ja äänentoisto on mykistetty", 322 "settings.service.form.isMutedInfo": "Kun poistettu käytöstä, kaikki ilmoitusäänet ja äänentoisto on mykistetty",
334 "settings.service.form.name": "Nimi", 323 "settings.service.form.name": "Nimi",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Avaa darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Avaa darkmode.css",
336 "settings.service.form.openUserCss": "Avaa user.css", 326 "settings.service.form.openUserCss": "Avaa user.css",
337 "settings.service.form.openUserJs": "Avaa user.js", 327 "settings.service.form.openUserJs": "Avaa user.js",
338 "settings.service.form.proxy.headline": "Http/Https välityspalvelimen asetukset", 328 "settings.service.form.proxy.headline": "Http/Https välityspalvelimen asetukset",
339 "settings.service.form.proxy.host": "Välityspalvelimen Host/IP", 329 "settings.service.form.proxy.host": "Välityspalvelimen Host/IP",
340 "settings.service.form.proxy.info": "Välityspalvelimen asetukset eivät synkronoidu Ferdin palvelimiin.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Käytä välityspalvelinta", 331 "settings.service.form.proxy.isEnabled": "Käytä välityspalvelinta",
342 "settings.service.form.proxy.password": "Salasana (valinnainen)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Portti", 333 "settings.service.form.proxy.port": "Portti",
344 "settings.service.form.proxy.restartInfo": "Käynnistä Ferdi välityspalvelimen asetusten vaihtamisen jälkeen.", 334 "settings.service.form.proxy.restartInfo": "Käynnistä Ferdi välityspalvelimen asetusten vaihtamisen jälkeen.",
345 "settings.service.form.proxy.user": "Käyttäjä (valinnainen)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Käyttäjän tiedostot lisätään web-sivulle, jotta voit muokata palveluita millä tahansa tavalla. Käyttäjätiedostot tallennetaan vain paikallisesti eikä niitä siirretä muille tietokoneille käyttäen samaa tiliä.", 336 "settings.service.form.recipeFileInfo": "Käyttäjän tiedostot lisätään web-sivulle, jotta voit muokata palveluita millä tahansa tavalla. Käyttäjätiedostot tallennetaan vain paikallisesti eikä niitä siirretä muille tietokoneille käyttäen samaa tiliä.",
347 "settings.service.form.saveButton": "Tallenna palvelu", 337 "settings.service.form.saveButton": "Tallenna palvelu",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Selaa palveluita", 344 "settings.services.discoverServices": "Selaa palveluita",
355 "settings.services.headline": "Sinun palvelusi", 345 "settings.services.headline": "Sinun palvelusi",
356 "settings.services.noServicesAdded": "Aloita lisäämällä palvelu.", 346 "settings.services.noServicesAdded": "Aloita lisäämällä palvelu.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Palveluita ei voitu ladata", 348 "settings.services.servicesRequestFailed": "Palveluita ei voitu ladata",
358 "settings.services.tooltip.isDisabled": "Palvelu poistettu käytöstä", 349 "settings.services.tooltip.isDisabled": "Palvelu poistettu käytöstä",
359 "settings.services.tooltip.isMuted": "Kaikki äänet on mykistetty", 350 "settings.services.tooltip.isMuted": "Kaikki äänet on mykistetty",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi on yhteisöjohtoinen ja avoimen lähdekoodin sovellus.</p><p>Kiitos henkilöille, jotka tekevät tämän mahdolliseksi:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi on yhteisöjohtoinen ja avoimen lähdekoodin sovellus.</p><p>Kiitos henkilöille, jotka tekevät tämän mahdolliseksi:</p>",
363 "settings.supportFerdi.bannerText": "Haluatko auttaa meitä kehittämään Ferdiä?", 354 "settings.supportFerdi.bannerText": "Haluatko auttaa meitä kehittämään Ferdiä?",
364 "settings.supportFerdi.headline": "Tietoja Ferdistä", 355 "settings.supportFerdi.headline": "Tietoja Ferdistä",
365 "settings.supportFerdi.openSurvey": "Avaa mielipidekysely", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "Jos haluat tukea Ferdin kehitystä lahjoituksella, voit tehdä niin molemmilla tavoilla,", 357 "settings.supportFerdi.textDonation": "Jos haluat tukea Ferdin kehitystä lahjoituksella, voit tehdä niin molemmilla tavoilla,",
367 "settings.supportFerdi.textDonationAnd": "ja", 358 "settings.supportFerdi.textDonationAnd": "ja",
368 "settings.supportFerdi.textExpenses": "Vaikka vapaaehtoiset tekevät suurimman osan työstä, meidän on silti maksettava palvelemista ja sertifikaateista. Olemme yhteisönä täysin läpinäkyviä keräämiämme ja käyttämiemme varojen suhteen", 359 "settings.supportFerdi.textExpenses": "Vaikka vapaaehtoiset tekevät suurimman osan työstä, meidän on silti maksettava palvelemista ja sertifikaateista. Olemme yhteisönä täysin läpinäkyviä keräämiämme ja käyttämiemme varojen suhteen",
369 "settings.supportFerdi.textGitHubSponsors": "GitHub sponsorit", 360 "settings.supportFerdi.textGitHubSponsors": "GitHub sponsorit",
370 "settings.supportFerdi.textListContributors": "Täydellinen luettelo tukijoista", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "tästä", 362 "settings.supportFerdi.textListContributorsHere": "tästä",
372 "settings.supportFerdi.textOpenCollective": "Avoin Kollektiivi", 363 "settings.supportFerdi.textOpenCollective": "Avoin Kollektiivi",
373 "settings.supportFerdi.textSupportWelcome": "Tuki on aina tervetullutta. Voit saada listan tarvitsemastamme avusta", 364 "settings.supportFerdi.textSupportWelcome": "Tuki on aina tervetullutta. Voit saada listan tarvitsemastamme avusta",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Voittoa tavoittelematon", 378 "settings.user.form.accountType.non-profit": "Voittoa tavoittelematon",
388 "settings.user.form.currentPassword": "Nykyinen salasana", 379 "settings.user.form.currentPassword": "Nykyinen salasana",
389 "settings.user.form.email": "Sähköposti", 380 "settings.user.form.email": "Sähköposti",
390 "settings.user.form.firstname": "Etunimi", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Sukunimi", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Uusi salasana", 383 "settings.user.form.newPassword": "Uusi salasana",
393 "settings.workspace.add.form.name": "Nimi", 384 "settings.workspace.add.form.name": "Nimi",
394 "settings.workspace.add.form.submitButton": "Luo työtila", 385 "settings.workspace.add.form.submitButton": "Luo työtila",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Yritä uudelleen", 396 "settings.workspaces.tryReloadWorkspaces": "Yritä uudelleen",
406 "settings.workspaces.updatedInfo": "Tekemäsi muutokset on tallennettu", 397 "settings.workspaces.updatedInfo": "Tekemäsi muutokset on tallennettu",
407 "settings.workspaces.workspaceFeatureHeadline": "Vähemmän on enemmän: Esittelyssä Ferdi Työtilat", 398 "settings.workspaces.workspaceFeatureHeadline": "Vähemmän on enemmän: Esittelyssä Ferdi Työtilat",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdi Työtilat antavat sinun keskittyä siihen, mikä on tärkeää juuri nyt. Määritä erilaisia palveluja ja vaihda helposti niiden välillä milloin tahansa. Sinä päätät mitä palveluita tarvitset milloin ja missä, jotta voimme auttaa sinua pysymään töissä - tai helposti pois töistä aina kun haluat.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Työtiloja ei voitu ladata", 400 "settings.workspaces.workspacesRequestFailed": "Työtiloja ei voitu ladata",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Käytä ilmoituksia ja ääniä", 411 "sidebar.unmuteApp": "Käytä ilmoituksia ja ääniä",
421 "signup.email.label": "Sähköpostiosoite", 412 "signup.email.label": "Sähköpostiosoite",
422 "signup.emailDuplicate": "Käyttäjä, jolla on tämä sähköpostiosoite, on jo olemassa", 413 "signup.emailDuplicate": "Käyttäjä, jolla on tämä sähköpostiosoite, on jo olemassa",
423 "signup.firstname.label": "Etunimi", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Kirjaudu", 415 "signup.headline": "Kirjaudu",
425 "signup.lastname.label": "Sukunimi", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Luomalla Ferdi-tilin hyväksyt", 417 "signup.legal.info": "Luomalla Ferdi-tilin hyväksyt",
427 "signup.legal.privacy": "Tietosuojalauseke", 418 "signup.legal.privacy": "Tietosuojalauseke",
428 "signup.legal.terms": "Käyttöehdot", 419 "signup.legal.terms": "Käyttöehdot",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Salasana", 421 "signup.password.label": "Salasana",
431 "signup.submit.label": "Luo tili", 422 "signup.submit.label": "Luo tili",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Poista palvelu", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Poista ääni käytöstä", 425 "tabs.item.disableAudio": "Poista ääni käytöstä",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Poista ilmoitukset käytöstä", 427 "tabs.item.disableNotifications": "Poista ilmoitukset käytöstä",
437 "tabs.item.disableService": "Poista palvelu", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Ota ääni käyttöön", 429 "tabs.item.enableAudio": "Ota ääni käyttöön",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Ota ilmoitukset käyttöön", 431 "tabs.item.enableNotification": "Ota ilmoitukset käyttöön",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Lataa uudelleen", 434 "tabs.item.reload": "Lataa uudelleen",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} ei ole kelvollinen", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} pitää olla vähintään {length} kirjainta", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Vähintään yksi kohde valittava", 438 "validation.oneRequired": "Vähintään yksi kohde valittava",
448 "validation.required": "{field} on pakollinen", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} ei ole kelvollinen URL-osoite", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Takaisin", 441 "webControls.back": "Takaisin",
451 "webControls.forward": "Eteenpäin", 442 "webControls.forward": "Eteenpäin",
452 "webControls.goHome": "Etusivu", 443 "webControls.goHome": "Etusivu",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Lataa uudelleen", 445 "webControls.reload": "Lataa uudelleen",
455 "welcome.loginButton": "Kirjaudu tilillesi", 446 "welcome.loginButton": "Kirjaudu tilillesi",
456 "welcome.signupButton": "Luo ilmainen tili", 447 "welcome.signupButton": "Luo ilmainen tili",
457 "workspaceDrawer.addNewWorkspaceLabel": "Lisää uusi työtila", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Kaikki palvelut", 449 "workspaceDrawer.allServices": "Kaikki palvelut",
459 "workspaceDrawer.headline": "Työtilat", 450 "workspaceDrawer.headline": "Työtilat",
460 "workspaceDrawer.item.contextMenuEdit": "muokkaa", 451 "workspaceDrawer.item.contextMenuEdit": "muokkaa",
461 "workspaceDrawer.item.noServicesAddedYet": "Palveluja ei ole vielä lisätty", 452 "workspaceDrawer.item.noServicesAddedYet": "Palveluja ei ole vielä lisätty",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces auttaa sinun keskittymään mikä on tärkeää juuri nyt. Määritä erilaisia palvelukokonaisuuksia ja vaihda helposti niiden välillä milloin tahansa.</p><p>Sinä päätät mitä palveluita tarvitset milloin ja missä, jotta voimme auttaa sinua pysymään työsi äärellä - tai helpottamaan poistumista aina kun haluat.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Muokkaa työtilojen asetuksia", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Vaihdetaan" 455 "workspaces.switchingIndicator.switchingTo": "Vaihdetaan"
465} 456}
diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json
index d81d23d79..80b32f495 100644
--- a/src/i18n/locales/fr.json
+++ b/src/i18n/locales/fr.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Actualiser", 2 "app.errorHandler.action": "Actualiser",
3 "app.errorHandler.headline": "On dirait que quelque chose ne va pas", 3 "app.errorHandler.headline": "Quelque chose a mal tourné.",
4 "changeserver.customServerLabel": "Serveur personnalisé", 4 "changeserver.customServerLabel": "Serveur personnalisé",
5 "changeserver.headline": "Changer de serveur", 5 "changeserver.headline": "Changer de serveur",
6 "changeserver.label": "Serveur", 6 "changeserver.label": "Serveur",
@@ -9,8 +9,7 @@
9 "connectionLostBanner.cta": "Redémarrer le service", 9 "connectionLostBanner.cta": "Redémarrer le service",
10 "connectionLostBanner.informationLink": "Que s'est-il passé?", 10 "connectionLostBanner.informationLink": "Que s'est-il passé?",
11 "connectionLostBanner.message": "Oh non ! Ferdi a perdu la connexion avec {name}.", 11 "connectionLostBanner.message": "Oh non ! Ferdi a perdu la connexion avec {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Connexion",
13 "feature.debugger.title": "Publier les informations de débogage",
14 "feature.nightlyBuilds.activate": "Activer", 13 "feature.nightlyBuilds.activate": "Activer",
15 "feature.nightlyBuilds.info": "Les versions de développement sont des versions expérimentales de Ferdi qui peuvent contenir des fonctionnalités non optimisées ou incomplètes. Ces versions de développement sont principalement utilisés par les développeurs pour tester leurs nouvelles fonctionnalités et leurs performances. Si vous ne savez pas ce que vous faites, nous vous suggérons de ne pas activer les versions de développement.", 14 "feature.nightlyBuilds.info": "Les versions de développement sont des versions expérimentales de Ferdi qui peuvent contenir des fonctionnalités non optimisées ou incomplètes. Ces versions de développement sont principalement utilisés par les développeurs pour tester leurs nouvelles fonctionnalités et leurs performances. Si vous ne savez pas ce que vous faites, nous vous suggérons de ne pas activer les versions de développement.",
16 "feature.nightlyBuilds.title": "Versions de développement", 15 "feature.nightlyBuilds.title": "Versions de développement",
@@ -27,27 +26,27 @@
27 "global.api.unhealthy": "Impossible de se connecter aux services en ligne de Ferdi", 26 "global.api.unhealthy": "Impossible de se connecter aux services en ligne de Ferdi",
28 "global.cancel": "Annuler", 27 "global.cancel": "Annuler",
29 "global.edit": "Éditer", 28 "global.edit": "Éditer",
30 "global.no": "No", 29 "global.no": "Non",
31 "global.notConnectedToTheInternet": "Vous n'êtes pas connecté à Internet.", 30 "global.notConnectedToTheInternet": "Vous n'êtes pas connecté à Internet.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Quit", 32 "global.quit": "Quitter",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Voulez-vous vraiment quitter Ferdi ?",
35 "global.save": "Save", 34 "global.save": "Sauver",
36 "global.settings": "Paramètres", 35 "global.settings": "Paramètres",
37 "global.spellchecker.useDefault": "Par défaut ({default})", 36 "global.spellchecker.useDefault": "Par défaut ({default})",
38 "global.spellchecking.autodetect": "Détecter automatiquement la langue", 37 "global.spellchecking.autodetect": "Détecter automatiquement la langue",
39 "global.spellchecking.autodetect.short": "Automatiquement", 38 "global.spellchecking.autodetect.short": "Automatiquement",
40 "global.spellchecking.language": "Langue de la vérification orthographique", 39 "global.spellchecking.language": "Langue de la vérification orthographique",
41 "global.submit": "Soumettre", 40 "global.submit": "Envoyer",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Utilisez 'https://whatmyuseragent.com/' (pour découvrir) ou 'https://developers.whatismybrowser.com/useragents/explore/' (pour choisir) votre agent utilisateur désiré et copier-coller ici.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Oui",
45 "import.headline": "Importez vos services depuis la version 4 de Ferdi", 44 "import.headline": "Importez vos services depuis la version 4 de Ferdi",
46 "import.notSupportedHeadline": "Ces services ne sont pas encore supportés par la version 5 de Ferdi", 45 "import.notSupportedHeadline": "Ces services ne sont pas encore supportés par la version 5 de Ferdi",
47 "import.skip.label": "Je veux ajouter des services manuellement", 46 "import.skip.label": "Je veux ajouter des services manuellement",
48 "import.submit.label": "Importer des services", 47 "import.submit.label": "Importer {count} services",
49 "infobar.authRequestFailed": "Il y a eu des erreurs pendant l'authentification demandée. Essayer de vous déconnecter et de vous reconnecter pour voir si cette erreur persiste.", 48 "infobar.authRequestFailed": "Il y a eu des erreurs pendant l'authentification demandée. Essayer de vous déconnecter et de vous reconnecter pour voir si cette erreur persiste.",
50 "infobar.buttonChangelog": "Nouveautés?", 49 "infobar.buttonChangelog": "Quoi de neuf ?",
51 "infobar.buttonInstallUpdate": "Redémarrer et installer la mise à jour", 50 "infobar.buttonInstallUpdate": "Redémarrer et installer la mise à jour",
52 "infobar.buttonReloadServices": "Recharger les services", 51 "infobar.buttonReloadServices": "Recharger les services",
53 "infobar.hide": "Masquer", 52 "infobar.hide": "Masquer",
@@ -75,7 +74,7 @@
75 "login.email.label": "Adresse Email", 74 "login.email.label": "Adresse Email",
76 "login.headline": "S'identifier", 75 "login.headline": "S'identifier",
77 "login.invalidCredentials": "Email ou mot de passe invalide", 76 "login.invalidCredentials": "Email ou mot de passe invalide",
78 "login.link.password": "Réinitialiser le mot de passe", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Créer un compte gratuit", 78 "login.link.signup": "Créer un compte gratuit",
80 "login.password.label": "Mot de passe", 79 "login.password.label": "Mot de passe",
81 "login.serverLogout": "Votre session a expiré. Reconnectez-vous s'il vous plaît.", 80 "login.serverLogout": "Votre session a expiré. Reconnectez-vous s'il vous plaît.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Assistance", 116 "menu.help.support": "Assistance",
118 "menu.help.tos": "Conditions d'utilisation", 117 "menu.help.tos": "Conditions d'utilisation",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activer le service précédent", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Ajouter un nouveau service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Accueil", 121 "menu.services.goHome": "Accueil",
123 "menu.services.setNextServiceActive": "Activer le service suivant", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Activer Todos", 124 "menu.todos.enableTodos": "Activer Todos",
126 "menu.view": "Aperçu", 125 "menu.view": "Aperçu",
@@ -131,39 +130,28 @@
131 "menu.view.reloadFerdi": "Reload Ferdi", 130 "menu.view.reloadFerdi": "Reload Ferdi",
132 "menu.view.reloadService": "Redémarrer le service", 131 "menu.view.reloadService": "Redémarrer le service",
133 "menu.view.reloadTodos": "Recharger les Todos", 132 "menu.view.reloadTodos": "Recharger les Todos",
134 "menu.view.resetZoom": "Actual Size", 133 "menu.view.resetZoom": "Taille actuelle",
135 "menu.view.toggleDarkMode": "Activer le mode sombre", 134 "menu.view.toggleDarkMode": "Activer le mode sombre",
136 "menu.view.toggleDevTools": "Activer les outils de développeur", 135 "menu.view.toggleDevTools": "Activer les outils de développeur",
137 "menu.view.toggleFullScreen": "Toggle Full Screen", 136 "menu.view.toggleFullScreen": "Activer/désactiver le mode plein écran",
138 "menu.view.toggleServiceDevTools": "Activer les outils de développeur du service", 137 "menu.view.toggleServiceDevTools": "Activer les outils de développeur du service",
139 "menu.view.toggleTodosDevTools": "Activer les outils de développeur Todos", 138 "menu.view.toggleTodosDevTools": "Activer les outils de développeur Todos",
140 "menu.view.zoomIn": "Zoom In", 139 "menu.view.zoomIn": "Zoom avant",
141 "menu.view.zoomOut": "Zoom Out", 140 "menu.view.zoomOut": "Zoom arrière",
142 "menu.window": "Window", 141 "menu.window": "Fenêtre",
143 "menu.window.close": "Close", 142 "menu.window.close": "Fermer",
144 "menu.window.minimize": "Minimize", 143 "menu.window.minimize": "Réduire",
145 "menu.workspaces": "Espace de travail", 144 "menu.workspaces": "Espace de travail",
146 "menu.workspaces.addNewWorkspace": "Ajouter un nouvel espace de travail...", 145 "menu.workspaces.addNewWorkspace": "Ajouter un nouvel espace de travail...",
147 "menu.workspaces.closeWorkspaceDrawer": "Fermer l'espace de travail", 146 "menu.workspaces.closeWorkspaceDrawer": "Fermer l'espace de travail",
148 "menu.workspaces.defaultWorkspace": "Tous les services", 147 "menu.workspaces.defaultWorkspace": "Tous les services",
149 "menu.workspaces.openWorkspaceDrawer": "Ouvrir l'espace de travail", 148 "menu.workspaces.openWorkspaceDrawer": "Ouvrir l'espace de travail",
150 "password.email.label": "Adresse Email", 149 "password.email.label": "Adresse Email",
151 "password.headline": "Réinitialiser le mot de passe", 150 "password.headline": "Reset password",
152 "password.link.login": "Connectez-vous à votre compte", 151 "password.link.login": "Connectez-vous à votre compte",
153 "password.link.signup": "Créer un compte gratuit", 152 "password.link.signup": "Créer un compte gratuit",
154 "password.noUser": "Aucun utilisateur n'a été trouvé avec cette adresse email", 153 "password.noUser": "Aucun utilisateur n'a été trouvé avec cette adresse email",
155 "password.successInfo": "Merci de consulter vos emails", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Synchronisation de compte",
157 "pricing.features.customWebsites": "Ajouter des sites web modifiés",
158 "pricing.features.desktopNotifications": "Notifications de bureau",
159 "pricing.features.onPremise": "Services hébergés sur place et autres",
160 "pricing.features.recipes": "Choisissez parmi de plus de 70 services",
161 "pricing.features.serviceProxies": "Service Proxy",
162 "pricing.features.spellchecker": "Support du correcteur orthographique",
163 "pricing.features.teamManagement": "Gestion d'équipe",
164 "pricing.features.thirdPartyServices": "Installer des services tiers",
165 "pricing.features.unlimitedServices": "Ajouter des services illimités",
166 "pricing.features.workspaces": "Espace de travail",
167 "service.crashHandler.action": "Recharger {name}", 155 "service.crashHandler.action": "Recharger {name}",
168 "service.crashHandler.autoReload": "Tentative de restauration automatique de {name} dans {seconds} secondes", 156 "service.crashHandler.autoReload": "Tentative de restauration automatique de {name} dans {seconds} secondes",
169 "service.crashHandler.headline": "Oh non!", 157 "service.crashHandler.headline": "Oh non!",
@@ -190,7 +178,7 @@
190 "settings.account.deleteInfo": "Si vous n'avez plus besoin de votre compte Ferdi, vous pouvez le supprimer avec toutes ses données associées.", 178 "settings.account.deleteInfo": "Si vous n'avez plus besoin de votre compte Ferdi, vous pouvez le supprimer avec toutes ses données associées.",
191 "settings.account.headline": "Compte", 179 "settings.account.headline": "Compte",
192 "settings.account.headlineAccount": "Informations sur le compte", 180 "settings.account.headlineAccount": "Informations sur le compte",
193 "settings.account.headlineDangerZone": "Zone dangereuse", 181 "settings.account.headlineDangerZone": "Zone à risque",
194 "settings.account.headlineInvoices": "Factures", 182 "settings.account.headlineInvoices": "Factures",
195 "settings.account.headlinePassword": "Changer le mot de passe", 183 "settings.account.headlinePassword": "Changer le mot de passe",
196 "settings.account.headlineProfile": "Mettre à jour le profil", 184 "settings.account.headlineProfile": "Mettre à jour le profil",
@@ -198,16 +186,16 @@
198 "settings.account.tryReloadServices": "Réessayer", 186 "settings.account.tryReloadServices": "Réessayer",
199 "settings.account.tryReloadUserInfoRequest": "Réessayer", 187 "settings.account.tryReloadUserInfoRequest": "Réessayer",
200 "settings.account.userInfoRequestFailed": "Impossible de charger les informations de l'utilisateur", 188 "settings.account.userInfoRequestFailed": "Impossible de charger les informations de l'utilisateur",
201 "settings.account.yourLicense": "Votre licence Ferdi", 189 "settings.account.yourLicense": "Votre licence Ferdi :",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Vider le cache", 191 "settings.app.buttonClearAllCache": "Vider le cache",
204 "settings.app.buttonInstallUpdate": "Redémarrer et installer la mise à jour", 192 "settings.app.buttonInstallUpdate": "Redémarrer et installer la mise à jour",
205 "settings.app.buttonOpenFerdiProfileFolder": "Open Profile folder", 193 "settings.app.buttonOpenFerdiProfileFolder": "Afficher le dossier du profil",
206 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open Service Recipes folder", 194 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open Service Recipes folder",
207 "settings.app.buttonSearchForUpdate": "Vérifier les mises à jour", 195 "settings.app.buttonSearchForUpdate": "Vérifier les mises à jour",
208 "settings.app.cacheInfo": "Le cache de Ferdi occupe actuellement {size} en espace disque.", 196 "settings.app.cacheInfo": "Le cache de Ferdi occupe actuellement {size} en espace disque.",
209 "settings.app.cacheNotCleared": "Impossible de vider toute la cache", 197 "settings.app.cacheNotCleared": "Impossible de vider toute la cache",
210 "settings.app.closeSettings": "Close settings", 198 "settings.app.closeSettings": "Fermer les paramètres",
211 "settings.app.currentVersion": "Version actuelle :", 199 "settings.app.currentVersion": "Version actuelle :",
212 "settings.app.form.accentColor": "Couleur d'accentuation", 200 "settings.app.form.accentColor": "Couleur d'accentuation",
213 "settings.app.form.adaptableDarkMode": "Synchroniser le mode sombre avec l'option mode sombre du système", 201 "settings.app.form.adaptableDarkMode": "Synchroniser le mode sombre avec l'option mode sombre du système",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Afficher Ferdi dans la barre d'état système", 208 "settings.app.form.closeToSystemTray": "Afficher Ferdi dans la barre d'état système",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Serveur Todo personnalisé", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Activer le mode sombre", 211 "settings.app.form.darkMode": "Activer le mode sombre",
224 "settings.app.form.enableGPUAcceleration": "Activer l'accélération GPU", 212 "settings.app.form.enableGPUAcceleration": "Activer l'accélération GPU",
225 "settings.app.form.enableLock": "Activer le verrouillage par mot de passe", 213 "settings.app.form.enableLock": "Activer le verrouillage par mot de passe",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Activer la vérification orthographique", 215 "settings.app.form.enableSpellchecking": "Activer la vérification orthographique",
228 "settings.app.form.enableSystemTray": "Afficher Ferdi dans la barre d'état système", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Activer Ferdi Todos", 217 "settings.app.form.enableTodos": "Activer Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Garder les services en veille prolongée au démarrage", 218 "settings.app.form.hibernateOnStartup": "Garder les services en veille prolongée au démarrage",
231 "settings.app.form.hibernationStrategy": "Stratégie d'hibernation", 219 "settings.app.form.hibernationStrategy": "Stratégie d'hibernation",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Afficher les onglets des services désactivés", 239 "settings.app.form.showDisabledServices": "Afficher les onglets des services désactivés",
252 "settings.app.form.showDragArea": "Afficher les zones de glisser-déposer dans la fenêtre", 240 "settings.app.form.showDragArea": "Afficher les zones de glisser-déposer dans la fenêtre",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Afficher les badges de messages non lus quand les notifications sont désactivées", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Afficher les badges de messages non lus quand les notifications sont désactivées",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Démarrage minimisé", 243 "settings.app.form.startMinimized": "Démarrage minimisé",
255 "settings.app.form.universalDarkMode": "Activer le mode sombre universel", 244 "settings.app.form.universalDarkMode": "Activer le mode sombre universel",
256 "settings.app.form.useTouchIdToUnlock": "Autoriser l'utilisation de TouchID pour déverrouiller Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Paramètres avancés", 248 "settings.app.headlineAdvanced": "Paramètres avancés",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Les traductions officielles sont l'anglais et l'allemand. Toutes les autres langues sont des traductions faites par la communauté.", 256 "settings.app.languageDisclaimer": "Les traductions officielles sont l'anglais et l'allemand. Toutes les autres langues sont des traductions faites par la communauté.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Mot de passe", 258 "settings.app.lockedPassword": "Mot de passe",
270 "settings.app.lockedPasswordInfo": "S'il vous plaît soyez sûre de mettre un mot de passe que vous allez vous rappelez.\nSi vous perdez ce mot de passe vous allez devoir réinstaller Ferdi.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Les modifications nécessitent un redémarrage", 260 "settings.app.restartRequired": "Les modifications nécessitent un redémarrage",
272 "settings.app.scheduledDNDInfo": "Planifier le Ne-pas-Déranger vous permet de définir une période de temps dans lequel vous ne voulez pas de notifications de Ferdi.", 261 "settings.app.scheduledDNDInfo": "Planifier le Ne-pas-Déranger vous permet de définir une période de temps dans lequel vous ne voulez pas de notifications de Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Le temps est en format 24 heures. La fin du temps peut être avant le début du temps (ex: début 17:00, fin 09:00) pour activer le Ne-pas-Déranger durant la nuit.", 262 "settings.app.scheduledDNDTimeInfo": "Le temps est en format 24 heures. La fin du temps peut être avant le début du temps (ex: début 17:00, fin 09:00) pour activer le Ne-pas-Déranger durant la nuit.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi utilise le correcteur orthographique intégré de votre Mac pour vérifier les fautes de frappe. Si vous voulez changer les langues pour lesquelles le correcteur vérifie l'orthographe, vous pouvez le faire dans les préférences système de votre Mac.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi utilise le correcteur orthographique intégré de votre Mac pour vérifier les fautes de frappe. Si vous voulez changer les langues pour lesquelles le correcteur vérifie l'orthographe, vous pouvez le faire dans les préférences système de votre Mac.",
276 "settings.app.subheadlineCache": "Cache", 265 "settings.app.subheadlineCache": "Cache",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Ce serveur sera utilisé pour la fonctionnalité \"Ferdi Todo\".", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Aidez-nous à traduire Ferdi dans votre langue.", 268 "settings.app.translationHelp": "Aidez-nous à traduire Ferdi dans votre langue.",
280 "settings.app.universalDarkModeInfo": "Le mode sombre universel tente de générer dynamiquement des styles de mode sombre pour les services qui ne sont pas encore supportés.", 269 "settings.app.universalDarkModeInfo": "Le mode sombre universel tente de générer dynamiquement des styles de mode sombre pour les services qui ne sont pas encore supportés.",
281 "settings.app.updateStatusAvailable": "Mise à jour disponible, téléchargement en cours...", 270 "settings.app.updateStatusAvailable": "Mise à jour disponible, téléchargement en cours...",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Recettes tiers communautaire", 283 "settings.recipes.customService.headline.communityRecipes": "Recettes tiers communautaire",
295 "settings.recipes.customService.headline.customRecipes": "Recettes tiers modifiées", 284 "settings.recipes.customService.headline.customRecipes": "Recettes tiers modifiées",
296 "settings.recipes.customService.headline.devRecipes": "Vos recettes de service de développement", 285 "settings.recipes.customService.headline.devRecipes": "Vos recettes de service de développement",
297 "settings.recipes.customService.intro": "Pour ajouter un service modifié, copié la recette à:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Documentation de Développeur", 287 "settings.recipes.customService.openDevDocs": "Documentation de Développeur",
299 "settings.recipes.customService.openFolder": "Ouvrir le dossier", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Services disponibles", 289 "settings.recipes.headline": "Services disponibles",
301 "settings.recipes.missingService": "Un service est manquant?", 290 "settings.recipes.missingService": "Un service est manquant?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Luminosité de Dark Reader", 301 "settings.service.form.darkReaderBrightness": "Luminosité de Dark Reader",
313 "settings.service.form.darkReaderContrast": "Contraste de Dark Reader", 302 "settings.service.form.darkReaderContrast": "Contraste de Dark Reader",
314 "settings.service.form.darkReaderSepia": "Sepia de Dark Reader", 303 "settings.service.form.darkReaderSepia": "Sepia de Dark Reader",
315 "settings.service.form.deleteButton": "Supprimer le service", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Modifier {name}", 305 "settings.service.form.editServiceHeadline": "Modifier {name}",
317 "settings.service.form.enableAudio": "Activer l'audio", 306 "settings.service.form.enableAudio": "Activer l'audio",
318 "settings.service.form.enableBadge": "Afficher le badge des messages non lus", 307 "settings.service.form.enableBadge": "Afficher le badge des messages non lus",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Quand activé, les services seront éteints après un moment pour économiser les ressources systèmes.", 321 "settings.service.form.isHibernatedEnabledInfo": "Quand activé, les services seront éteints après un moment pour économiser les ressources systèmes.",
333 "settings.service.form.isMutedInfo": "Lorsque désactivé, tous les sons de notifications ainsi que l'audio sont coupés", 322 "settings.service.form.isMutedInfo": "Lorsque désactivé, tous les sons de notifications ainsi que l'audio sont coupés",
334 "settings.service.form.name": "Nom", 323 "settings.service.form.name": "Nom",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Ouvrir darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Ouvrir darkmode.css",
336 "settings.service.form.openUserCss": "Ouvrir user.css", 326 "settings.service.form.openUserCss": "Ouvrir user.css",
337 "settings.service.form.openUserJs": "Ouvrir user.js", 327 "settings.service.form.openUserJs": "Ouvrir user.js",
338 "settings.service.form.proxy.headline": "Paramètres proxy HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "Paramètres proxy HTTP/HTTPS",
339 "settings.service.form.proxy.host": "Hôte/IP du proxy", 329 "settings.service.form.proxy.host": "Hôte/IP du proxy",
340 "settings.service.form.proxy.info": "Les paramètres de proxy ne seront pas synchronisés avec les serveurs de Ferdi.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Utiliser un proxy", 331 "settings.service.form.proxy.isEnabled": "Utiliser un proxy",
342 "settings.service.form.proxy.password": "Mot de passe (facultatif)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Veuillez redémarrer Ferdi après avoir modifié les paramètres proxy.", 334 "settings.service.form.proxy.restartInfo": "Veuillez redémarrer Ferdi après avoir modifié les paramètres proxy.",
345 "settings.service.form.proxy.user": "Utilisateur (facultatif)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Vos fichiers utilisateur seront insérés dans la page Web afin que vous puissiez personnaliser les services comme vous le souhaitez. Les fichiers utilisateurs sont stockés localement et ne sont pas transférés à d'autres ordinateurs en utilisant le même compte.", 336 "settings.service.form.recipeFileInfo": "Vos fichiers utilisateur seront insérés dans la page Web afin que vous puissiez personnaliser les services comme vous le souhaitez. Les fichiers utilisateurs sont stockés localement et ne sont pas transférés à d'autres ordinateurs en utilisant le même compte.",
347 "settings.service.form.saveButton": "Enregistrer le service", 337 "settings.service.form.saveButton": "Enregistrer le service",
348 "settings.service.form.tabHosted": "Hébergé", 338 "settings.service.form.tabHosted": "Hébergé",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Découvrir les services", 344 "settings.services.discoverServices": "Découvrir les services",
355 "settings.services.headline": "Vos services", 345 "settings.services.headline": "Vos services",
356 "settings.services.noServicesAdded": "Commencez par ajouter un service.", 346 "settings.services.noServicesAdded": "Commencez par ajouter un service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Impossible de charger vos services", 348 "settings.services.servicesRequestFailed": "Impossible de charger vos services",
358 "settings.services.tooltip.isDisabled": "Ce service est désactivé", 349 "settings.services.tooltip.isDisabled": "Ce service est désactivé",
359 "settings.services.tooltip.isMuted": "Tous les sons sont coupés", 350 "settings.services.tooltip.isMuted": "Tous les sons sont coupés",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi est une application open-source et dirigée par la communauté.</p><p>Merci à toutes les personnes qui rendent cela possible :</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi est une application open-source et dirigée par la communauté.</p><p>Merci à toutes les personnes qui rendent cela possible :</p>",
363 "settings.supportFerdi.bannerText": "Voulez-vous nous aider à améliorer Ferdi ?", 354 "settings.supportFerdi.bannerText": "Voulez-vous nous aider à améliorer Ferdi ?",
364 "settings.supportFerdi.headline": "À propos de Ferdi", 355 "settings.supportFerdi.headline": "À propos de Ferdi",
365 "settings.supportFerdi.openSurvey": "Ouvrir l'enquête", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "Si vous avez envie de soutenir le développement de Ferdi par un don, vous pouvez le faire via", 357 "settings.supportFerdi.textDonation": "Si vous avez envie de soutenir le développement de Ferdi par un don, vous pouvez le faire via",
367 "settings.supportFerdi.textDonationAnd": "et", 358 "settings.supportFerdi.textDonationAnd": "et",
368 "settings.supportFerdi.textExpenses": "Bien que les bénévoles fassent la majeure partie du travail, nous avons besoin de payer pour les serveurs et les certificats. En tant que communauté, nous sommes totalement transparents sur les fonds que nous collectons et dépensons - voir nos", 359 "settings.supportFerdi.textExpenses": "Bien que les bénévoles fassent la majeure partie du travail, nous avons besoin de payer pour les serveurs et les certificats. En tant que communauté, nous sommes totalement transparents sur les fonds que nous collectons et dépensons - voir nos",
369 "settings.supportFerdi.textGitHubSponsors": "Sponsors sur GitHub", 360 "settings.supportFerdi.textGitHubSponsors": "Sponsors sur GitHub",
370 "settings.supportFerdi.textListContributors": "Liste complète des contributeurs", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "ici", 362 "settings.supportFerdi.textListContributorsHere": "ici",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Toute aide est toujours la bienvenue. Vous pouvez trouver une liste de l'aide dont nous avons besoin", 364 "settings.supportFerdi.textSupportWelcome": "Toute aide est toujours la bienvenue. Vous pouvez trouver une liste de l'aide dont nous avons besoin",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Non-lucratif", 378 "settings.user.form.accountType.non-profit": "Non-lucratif",
388 "settings.user.form.currentPassword": "Mot de passe actuel", 379 "settings.user.form.currentPassword": "Mot de passe actuel",
389 "settings.user.form.email": "Email", 380 "settings.user.form.email": "Email",
390 "settings.user.form.firstname": "Prénom", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Nom", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nouveau mot de passe", 383 "settings.user.form.newPassword": "Nouveau mot de passe",
393 "settings.workspace.add.form.name": "Nom", 384 "settings.workspace.add.form.name": "Nom",
394 "settings.workspace.add.form.submitButton": "Créer l'espace de travail", 385 "settings.workspace.add.form.submitButton": "Créer l'espace de travail",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Réessayer", 396 "settings.workspaces.tryReloadWorkspaces": "Réessayer",
406 "settings.workspaces.updatedInfo": "Vos modifications ont été enregistrées", 397 "settings.workspaces.updatedInfo": "Vos modifications ont été enregistrées",
407 "settings.workspaces.workspaceFeatureHeadline": "Présentation des Espaces de travail de Ferdi", 398 "settings.workspaces.workspaceFeatureHeadline": "Présentation des Espaces de travail de Ferdi",
408 "settings.workspaces.workspaceFeatureInfo": "Les Espaces de travail de Ferdi vous permettant de rester concentré sur ce qui est important. Créez différents groupes de services et naviguez facilement entre eux à n'importe quel moment. Vous décidez de quels services vous avez besoin, où et quand, ainsi nous pouvons vous aider à rester concentré sur votre travail - ou à le quitter dès que vous le souhaitez.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Impossible de charger vos espaces de travail", 400 "settings.workspaces.workspacesRequestFailed": "Impossible de charger vos espaces de travail",
410 "setupAssistant.headline": "Commençons", 401 "setupAssistant.headline": "Commençons",
411 "setupAssistant.subheadline": "Choisissez parmi nos services les plus utilisés et revenez maintenant sur votre messagerie.", 402 "setupAssistant.subheadline": "Choisissez parmi nos services les plus utilisés et revenez maintenant sur votre messagerie.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Activer les notifications et les sons", 411 "sidebar.unmuteApp": "Activer les notifications et les sons",
421 "signup.email.label": "Adresse Email", 412 "signup.email.label": "Adresse Email",
422 "signup.emailDuplicate": "Cette adresse email est déjà utilisée", 413 "signup.emailDuplicate": "Cette adresse email est déjà utilisée",
423 "signup.firstname.label": "Prénom", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "S'inscrire", 415 "signup.headline": "S'inscrire",
425 "signup.lastname.label": "Nom", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "En créant un compte Ferdi, vous acceptez la", 417 "signup.legal.info": "En créant un compte Ferdi, vous acceptez la",
427 "signup.legal.privacy": "Déclaration de confidentialité", 418 "signup.legal.privacy": "Déclaration de confidentialité",
428 "signup.legal.terms": "Conditions d'utilisation", 419 "signup.legal.terms": "Conditions d'utilisation",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Mot de passe", 421 "signup.password.label": "Mot de passe",
431 "signup.submit.label": "Créer un compte", 422 "signup.submit.label": "Créer un compte",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Supprimer le service", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Désactiver l'audio", 425 "tabs.item.disableAudio": "Désactiver l'audio",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Désactiver les notifications", 427 "tabs.item.disableNotifications": "Désactiver les notifications",
437 "tabs.item.disableService": "Désactiver le service", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Activer l'audio", 429 "tabs.item.enableAudio": "Activer l'audio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Activer les notifications", 431 "tabs.item.enableNotification": "Activer les notifications",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Actualiser", 434 "tabs.item.reload": "Actualiser",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} n'est pas valide", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} doit contenir au moins {length} caractère(s)", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Au moins un de ces champs est requis", 438 "validation.oneRequired": "Au moins un de ces champs est requis",
448 "validation.required": "{field} est requis", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} n'est pas une URL valide", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Revenir", 441 "webControls.back": "Revenir",
451 "webControls.forward": "Avancer", 442 "webControls.forward": "Avancer",
452 "webControls.goHome": "Accueil", 443 "webControls.goHome": "Accueil",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Actualiser", 445 "webControls.reload": "Actualiser",
455 "welcome.loginButton": "Se connecter sur son compte", 446 "welcome.loginButton": "Se connecter sur son compte",
456 "welcome.signupButton": "Créer un compte gratuit", 447 "welcome.signupButton": "Créer un compte gratuit",
457 "workspaceDrawer.addNewWorkspaceLabel": "Ajouter un nouvel espace de travail", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Tous les services", 449 "workspaceDrawer.allServices": "Tous les services",
459 "workspaceDrawer.headline": "Espace de travail", 450 "workspaceDrawer.headline": "Espace de travail",
460 "workspaceDrawer.item.contextMenuEdit": "Modifier", 451 "workspaceDrawer.item.contextMenuEdit": "Modifier",
461 "workspaceDrawer.item.noServicesAddedYet": "Aucun services ajoutés pour l'instant", 452 "workspaceDrawer.item.noServicesAddedYet": "Aucun services ajoutés pour l'instant",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Les Espaces de travail de Ferdi vous permettant de rester concentré sur ce qui est important. Créez différents groupes de services et naviguez facilement entre eux à n'importe quel moment.</p><p>Vous décidez de quels services vous avez besoin, où et quand, ainsi nous pouvons vous aider à rester concentré sur votre travail - ou à le quitter dès que vous le souhaitez.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Éditer les paramètres de l'espace de travail", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Changement vers" 455 "workspaces.switchingIndicator.switchingTo": "Changement vers"
465} 456}
diff --git a/src/i18n/locales/ga.json b/src/i18n/locales/ga.json
index a78c90771..46dc1acc4 100644
--- a/src/i18n/locales/ga.json
+++ b/src/i18n/locales/ga.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Athlódáil", 2 "app.errorHandler.action": "Athlódáil",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Freastalaí saincheaptha", 4 "changeserver.customServerLabel": "Freastalaí saincheaptha",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Ní féidir nascadh le seirbhísí Ferdi ar líne", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Cealaigh", 27 "global.cancel": "Cancel",
29 "global.edit": "Cuir in eagar", 28 "global.edit": "Cuir in eagar",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Níl tú nasctha leis an Idirlíon.", 30 "global.notConnectedToTheInternet": "Níl tú nasctha leis an Idirlíon.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Socruithe", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use System Default ({default})", 36 "global.spellchecker.useDefault": "Use System Default ({default})",
38 "global.spellchecking.autodetect": "Detect language automatically", 37 "global.spellchecking.autodetect": "Detect language automatically",
39 "global.spellchecking.autodetect.short": "Automatic", 38 "global.spellchecking.autodetect.short": "Automatic",
40 "global.spellchecking.language": "Spell checking language", 39 "global.spellchecking.language": "Spell checking language",
41 "global.submit": "Cuir isteach", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Iompórtáil do sheirbhísí Ferdi 4", 44 "import.headline": "Iompórtáil do sheirbhísí Ferdi 4",
46 "import.notSupportedHeadline": "Níl na seirbhísí seo taca ag Ferdi 5 go fóill", 45 "import.notSupportedHeadline": "Níl na seirbhísí seo taca ag Ferdi 5 go fóill",
47 "import.skip.label": "Ba mhaith liom seirbhísí a chur de láimh", 46 "import.skip.label": "Ba mhaith liom seirbhísí a chur de láimh",
48 "import.submit.label": "Iompórtáil seirbhísí", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Cad atá nua?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Atosaigh ⊠suiteáil nuashonrú", 50 "infobar.buttonInstallUpdate": "Atosaigh ⊠suiteáil nuashonrú",
52 "infobar.buttonReloadServices": "Athlódáil seirbhísí", 51 "infobar.buttonReloadServices": "Athlódáil seirbhísí",
53 "infobar.hide": "Cuir Ferdi i bhfolach", 52 "infobar.hide": "Cuir Ferdi i bhfolach",
@@ -75,7 +74,7 @@
75 "login.email.label": "Seoladh ríomhphoist", 74 "login.email.label": "Seoladh ríomhphoist",
76 "login.headline": "Logáil isteach", 75 "login.headline": "Logáil isteach",
77 "login.invalidCredentials": "Seoladh ríomhphoist nó pasfhocal neamhbhailí", 76 "login.invalidCredentials": "Seoladh ríomhphoist nó pasfhocal neamhbhailí",
78 "login.link.password": "Athshocraigh pasfhocal", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Cruthaigh cuntas saor in aisce", 78 "login.link.signup": "Cruthaigh cuntas saor in aisce",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "D'éag do sheisiún, logáil isteach arís le do thoil.", 80 "login.serverLogout": "D'éag do sheisiún, logáil isteach arís le do thoil.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Téarmaí tagartha", 117 "menu.help.tos": "Téarmaí tagartha",
119 "menu.services": "Seirbhísí", 118 "menu.services": "Seirbhísí",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Gach seirbhís", 147 "menu.workspaces.defaultWorkspace": "Gach seirbhís",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "Seoladh ríomhphoist", 149 "password.email.label": "Seoladh ríomhphoist",
151 "password.headline": "Athshocraigh pasfhocal", 150 "password.headline": "Reset password",
152 "password.link.login": "Logáil isteach i do chuntas", 151 "password.link.login": "Logáil isteach i do chuntas",
153 "password.link.signup": "Cruthaigh cuntas saor in aisce", 152 "password.link.signup": "Cruthaigh cuntas saor in aisce",
154 "password.noUser": "Níor aimsíodh úsáideoir leis an seoladh ríomhphoist seo", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Seiceáil do chuid ríomhphoist le do thoil", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Athlódáil {name}", 155 "service.crashHandler.action": "Athlódáil {name}",
168 "service.crashHandler.autoReload": "Ag iarraidh {name} a thabhairt ar ais go huathoibríoch i gceann {seconds} shoicind", 156 "service.crashHandler.autoReload": "Ag iarraidh {name} a thabhairt ar ais go huathoibríoch i gceann {seconds} shoicind",
169 "service.crashHandler.headline": "Oró, ní hea!", 157 "service.crashHandler.headline": "Oró, ní hea!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Fáilte go Ferdi", 171 "services.welcome": "Fáilte go Ferdi",
184 "settings.account.account.editButton": "Cuir cuntas in eagar", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Nuashonraigh próifíl", 175 "settings.account.buttonSave": "Nuashonraigh próifíl",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Fuair tú ríomhphost chun scriosadh do chuntais a dheimhniú. Ní féidir do chuntas agus do chuid sonraí a thabhairt ar ais!", 177 "settings.account.deleteEmailSent": "Fuair tú ríomhphost chun scriosadh do chuntais a dheimhniú. Ní féidir do chuntas agus do chuid sonraí a thabhairt ar ais!",
190 "settings.account.deleteInfo": "Más rud é nár ghá cuntas Ferdi a bheith agat a thuilleadh, is féidir do chuntas agus gach sonraí riachtanach a scriosadh anseo.", 178 "settings.account.deleteInfo": "Más rud é nár ghá cuntas Ferdi a bheith agat a thuilleadh, is féidir do chuntas agus gach sonraí riachtanach a scriosadh anseo.",
191 "settings.account.headline": "Cuntas", 179 "settings.account.headline": "Cuntas",
192 "settings.account.headlineAccount": "Eolas faoin gcuntas", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Scrios cuntas", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Sonraisc", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Athraigh pasfhocal", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Nuashonraigh próifíl", 184 "settings.account.headlineProfile": "Nuashonraigh próifíl",
197 "settings.account.successInfo": "Sábháladh do chuid athruithe", 185 "settings.account.successInfo": "Sábháladh do chuid athruithe",
198 "settings.account.tryReloadServices": "Atriail", 186 "settings.account.tryReloadServices": "Atriail",
199 "settings.account.tryReloadUserInfoRequest": "Atriail", 187 "settings.account.tryReloadUserInfoRequest": "Atriail",
200 "settings.account.userInfoRequestFailed": "Ní féidir eolas úsáideora a lódáil", 188 "settings.account.userInfoRequestFailed": "Ní féidir eolas úsáideora a lódáil",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Glan taisce", 191 "settings.app.buttonClearAllCache": "Glan taisce",
204 "settings.app.buttonInstallUpdate": "Atosaigh ⊠suiteáil nuashonrú", 192 "settings.app.buttonInstallUpdate": "Atosaigh ⊠suiteáil nuashonrú",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Cumasaigh luasghéarú APG", 212 "settings.app.form.enableGPUAcceleration": "Cumasaigh luasghéarú APG",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Cumasaigh seiceáil litrithe", 215 "settings.app.form.enableSpellchecking": "Cumasaigh seiceáil litrithe",
228 "settings.app.form.enableSystemTray": "Taispeáin Ferdi i dtráidire an chórais", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Taispeáin tabanna do sheirbhísí dhíchumasaithe", 239 "settings.app.form.showDisabledServices": "Taispeáin tabanna do sheirbhísí dhíchumasaithe",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Taispeáin teachtaireachtaí neamhléite, nuair a dhíchumasaítear fógraí", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Taispeáin teachtaireachtaí neamhléite, nuair a dhíchumasaítear fógraí",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Scrios seirbhís", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Cuir {name} in eagar", 305 "settings.service.form.editServiceHeadline": "Cuir {name} in eagar",
317 "settings.service.form.enableAudio": "Cumasaigh fuaim", 306 "settings.service.form.enableAudio": "Cumasaigh fuaim",
318 "settings.service.form.enableBadge": "Taispeáin comhartha do theachtaireachtaí neamhléite", 307 "settings.service.form.enableBadge": "Taispeáin comhartha do theachtaireachtaí neamhléite",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Tachtar gach fuaim fógraí agus athchasadh fuaime", 322 "settings.service.form.isMutedInfo": "Tachtar gach fuaim fógraí agus athchasadh fuaime",
334 "settings.service.form.name": "Ainm", 323 "settings.service.form.name": "Ainm",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Aimsigh seirbhísí", 344 "settings.services.discoverServices": "Aimsigh seirbhísí",
355 "settings.services.headline": "Do sheirbhísí", 345 "settings.services.headline": "Do sheirbhísí",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Seirbhís díchumasaithe", 349 "settings.services.tooltip.isDisabled": "Seirbhís díchumasaithe",
359 "settings.services.tooltip.isMuted": "Tachtar gach fuaim", 350 "settings.services.tooltip.isMuted": "Tachtar gach fuaim",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Neamhbhrabúis", 378 "settings.user.form.accountType.non-profit": "Neamhbhrabúis",
388 "settings.user.form.currentPassword": "Pasfhocal reatha", 379 "settings.user.form.currentPassword": "Pasfhocal reatha",
389 "settings.user.form.email": "Ríomhphost", 380 "settings.user.form.email": "Ríomhphost",
390 "settings.user.form.firstname": "Céadainm", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Sloinne", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Pasfhocal nua", 383 "settings.user.form.newPassword": "Pasfhocal nua",
393 "settings.workspace.add.form.name": "Ainm", 384 "settings.workspace.add.form.name": "Ainm",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Cumasaigh fógraí ⊠fuaim", 411 "sidebar.unmuteApp": "Cumasaigh fógraí ⊠fuaim",
421 "signup.email.label": "Seoladh ríomhphoist", 412 "signup.email.label": "Seoladh ríomhphoist",
422 "signup.emailDuplicate": "Tá úsáideoir leis an seoladh ríomhphoist sin cheana féin", 413 "signup.emailDuplicate": "Tá úsáideoir leis an seoladh ríomhphoist sin cheana féin",
423 "signup.firstname.label": "Céadainm", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Cláraigh", 415 "signup.headline": "Cláraigh",
425 "signup.lastname.label": "Sloinne", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Agus tú ag cruthú cuntas Ferdi glacann tú le", 417 "signup.legal.info": "Agus tú ag cruthú cuntas Ferdi glacann tú le",
427 "signup.legal.privacy": "Ráiteas phríobháideachais", 418 "signup.legal.privacy": "Ráiteas phríobháideachais",
428 "signup.legal.terms": "Tearmaí seirbhíse", 419 "signup.legal.terms": "Tearmaí seirbhíse",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "Cruthaigh cuntas", 422 "signup.submit.label": "Cruthaigh cuntas",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Scrios seirbhís", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Díchumasaigh fuaim", 425 "tabs.item.disableAudio": "Díchumasaigh fuaim",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Díchumasaigh fógraí", 427 "tabs.item.disableNotifications": "Díchumasaigh fógraí",
437 "tabs.item.disableService": "Díchumasaigh seirbhís", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Cumasaigh fuaim", 429 "tabs.item.enableAudio": "Cumasaigh fuaim",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Cumasaigh fógraí", 431 "tabs.item.enableNotification": "Cumasaigh fógraí",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Athlódáil", 434 "tabs.item.reload": "Athlódáil",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "Níl {field} neamhbhailí", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "Ba cheart go mbeadh {field} ar a laghad {length} charactar fada", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "Tá {field} de dhíth", 439 "validation.required": "{field} is required",
449 "validation.url": "Ní AAA bhailí é {field}", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Back", 441 "webControls.back": "Back",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
diff --git a/src/i18n/locales/he.json b/src/i18n/locales/he.json
index 79e1532b5..5bec0bf13 100644
--- a/src/i18n/locales/he.json
+++ b/src/i18n/locales/he.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "רענן", 2 "app.errorHandler.action": "רענן",
3 "app.errorHandler.headline": "משהו השתבש", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "שרת מות×× ×ישית", 4 "changeserver.customServerLabel": "שרת מות×× ×ישית",
5 "changeserver.headline": "החלף שרת", 5 "changeserver.headline": "החלף שרת",
6 "changeserver.label": "שרת", 6 "changeserver.label": "שרת",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "מה קרה?", 10 "connectionLostBanner.informationLink": "מה קרה?",
11 "connectionLostBanner.message": "הו ל×! פרדי ×יבד ×ת החיבור ל {name}.", 11 "connectionLostBanner.message": "הו ל×! פרדי ×יבד ×ת החיבור ל {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "×¤×¨×¡× ×ת פרטי ניפוי השגי×ות",
14 "feature.nightlyBuilds.activate": "הפעל", 13 "feature.nightlyBuilds.activate": "הפעל",
15 "feature.nightlyBuilds.info": "גרס×ות נייטלי ×”× ×’×¨×¡×ות נסיוניות ביותר של פרדי, העשויות להכיל פיצ'×¨×™× ×‘×œ×ª×™ גמורי×. גרס×ות ×לה מיועדות בעיקר לשימוש ×ž×¤×ª×—×™× ×¢×œ מנת לנסות ×ת הפיצ'×¨×™× ×”×—×“×©×™× ×”× ×ž×¦××™× ×‘×¤×™×ª×•×— - לפני ×”×›× ×¡×ª× ×œ×’×¨×¡×” הסופית. ×× ×תה ×œ× ×™×•×“×¢ מה ×תה עושה, ×נו ×ž×ž×œ×™×¦×™× ×©×œ× ×ª×¤×¢×™×œ ×ת ×”×ופציה ×”×–×ת.", 14 "feature.nightlyBuilds.info": "גרס×ות נייטלי ×”× ×’×¨×¡×ות נסיוניות ביותר של פרדי, העשויות להכיל פיצ'×¨×™× ×‘×œ×ª×™ גמורי×. גרס×ות ×לה מיועדות בעיקר לשימוש ×ž×¤×ª×—×™× ×¢×œ מנת לנסות ×ת הפיצ'×¨×™× ×”×—×“×©×™× ×”× ×ž×¦××™× ×‘×¤×™×ª×•×— - לפני ×”×›× ×¡×ª× ×œ×’×¨×¡×” הסופית. ×× ×תה ×œ× ×™×•×“×¢ מה ×תה עושה, ×נו ×ž×ž×œ×™×¦×™× ×©×œ× ×ª×¤×¢×™×œ ×ת ×”×ופציה ×”×–×ת.",
16 "feature.nightlyBuilds.title": "גרס×ות נייטלי", 15 "feature.nightlyBuilds.title": "גרס×ות נייטלי",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "בחר שירות ×¢× ×ž×§×© ×” TAB, ↑ ו ↓. פתח שירות ב×מצעות מקש ×” ENTER.", 23 "feature.quickSwitch.info": "בחר שירות ×¢× ×ž×§×© ×” TAB, ↑ ו ↓. פתח שירות ב×מצעות מקש ×” ENTER.",
25 "feature.quickSwitch.search": "חיפוש...", 24 "feature.quickSwitch.search": "חיפוש...",
26 "feature.quickSwitch.title": "החלפה מהירה", 25 "feature.quickSwitch.title": "החלפה מהירה",
27 "global.api.unhealthy": "×œ× × ×™×ª×Ÿ להתחבר לשרותי ×”×ינטרנת של Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "בטל", 27 "global.cancel": "Cancel",
29 "global.edit": "ערוך", 28 "global.edit": "ערוך",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "נר××” ש×תה ×œ× ×ž×—×•×‘×¨ ל×ינטרנט.", 30 "global.notConnectedToTheInternet": "נר××” ש×תה ×œ× ×ž×—×•×‘×¨ ל×ינטרנט.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "הגדרות", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "השתמש בברירת המחדל של המערכת ({default})", 36 "global.spellchecker.useDefault": "השתמש בברירת המחדל של המערכת ({default})",
38 "global.spellchecking.autodetect": "×–×”×” שפה ב×ופן ×וטומטי", 37 "global.spellchecking.autodetect": "×–×”×” שפה ב×ופן ×וטומטי",
39 "global.spellchecking.autodetect.short": "×וטומטי", 38 "global.spellchecking.autodetect.short": "×וטומטי",
40 "global.spellchecking.language": "שפה לבדיקת ×יות", 39 "global.spellchecking.language": "שפה לבדיקת ×יות",
41 "global.submit": "שלח", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "סוכן משתמש", 42 "global.userAgentPref": "סוכן משתמש",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "×™×™×‘× ×ת ×”×©×™×¨×•×ª×™× ×©×œ×š מפרדי גרסה 4", 44 "import.headline": "×™×™×‘× ×ת ×”×©×™×¨×•×ª×™× ×©×œ×š מפרדי גרסה 4",
46 "import.notSupportedHeadline": "השירות עדיין ×ינו נתמך בפרדי גרסה 5", 45 "import.notSupportedHeadline": "השירות עדיין ×ינו נתמך בפרדי גרסה 5",
47 "import.skip.label": "×× ×™ רוצה להוסיף ×©×™×¨×•×ª×™× ×‘×ופן ידני", 46 "import.skip.label": "×× ×™ רוצה להוסיף ×©×™×¨×•×ª×™× ×‘×ופן ידני",
48 "import.submit.label": "×™×™×‘× ×©×™×¨×•×ª×™×", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "×ירעה שגי××” בניסיון ההתחברות. נסה להתנתק ולהתחבר מחדש.", 48 "infobar.authRequestFailed": "×ירעה שגי××” בניסיון ההתחברות. נסה להתנתק ולהתחבר מחדש.",
50 "infobar.buttonChangelog": "מה חדש?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "הפעל מחדש והתקן עדכוני×", 50 "infobar.buttonInstallUpdate": "הפעל מחדש והתקן עדכוני×",
52 "infobar.buttonReloadServices": "טען מחדש ×ת השירותי×", 51 "infobar.buttonReloadServices": "טען מחדש ×ת השירותי×",
53 "infobar.hide": "הסתר", 52 "infobar.hide": "הסתר",
@@ -75,7 +74,7 @@
75 "login.email.label": "כתובת דו×\"ל", 74 "login.email.label": "כתובת דו×\"ל",
76 "login.headline": "התחבר", 75 "login.headline": "התחבר",
77 "login.invalidCredentials": "כתובת הדו×\"ל ×ו ×”×¡×™×¡×ž× ××™× × ×ª×§×™× ×™×", 76 "login.invalidCredentials": "כתובת הדו×\"ל ×ו ×”×¡×™×¡×ž× ××™× × ×ª×§×™× ×™×",
78 "login.link.password": "×יפוס סיסמה", 77 "login.link.password": "Reset password",
79 "login.link.signup": "צור חשבון חדש בחינ×", 78 "login.link.signup": "צור חשבון חדש בחינ×",
80 "login.password.label": "סיסמ×", 79 "login.password.label": "סיסמ×",
81 "login.serverLogout": "פג תוקף ההתחברות, ×× × ×”×ª×—×‘×¨ שוב.", 80 "login.serverLogout": "פג תוקף ההתחברות, ×× × ×”×ª×—×‘×¨ שוב.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "תמיכה", 116 "menu.help.support": "תמיכה",
118 "menu.help.tos": "תנ××™ שימוש", 117 "menu.help.tos": "תנ××™ שימוש",
119 "menu.services": "שירותי×", 118 "menu.services": "שירותי×",
120 "menu.services.activatePreviousService": "הפעל ×ת השירות הקוד×", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "הוסף שירות חדש", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "בית", 121 "menu.services.goHome": "בית",
123 "menu.services.setNextServiceActive": "הפעל ×ת השירות הב×", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "משימות", 123 "menu.todos": "משימות",
125 "menu.todos.enableTodos": "×פשר משימות", 124 "menu.todos.enableTodos": "×פשר משימות",
126 "menu.view": "הצג", 125 "menu.view": "הצג",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "כל השירותי×", 147 "menu.workspaces.defaultWorkspace": "כל השירותי×",
149 "menu.workspaces.openWorkspaceDrawer": "פתח ×ת סרגל סביבות העבודה", 148 "menu.workspaces.openWorkspaceDrawer": "פתח ×ת סרגל סביבות העבודה",
150 "password.email.label": "כתובת דו×\"ל", 149 "password.email.label": "כתובת דו×\"ל",
151 "password.headline": "×יפוס סיסמה", 150 "password.headline": "Reset password",
152 "password.link.login": "היכנס לחשבונך", 151 "password.link.login": "היכנס לחשבונך",
153 "password.link.signup": "צור חשבון חדש בחינ×", 152 "password.link.signup": "צור חשבון חדש בחינ×",
154 "password.noUser": "×œ× × ×ž×¦× ×ž×©×ª×ž×© ×¢× ×›×ª×•×‘×ª הדו×\"ל ×”×–×ת", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "×× × ×‘×“×•×§ ×ת הדו×\"ל שלך", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "סנכון החשבון",
157 "pricing.features.customWebsites": "הוסף ××ª×¨×™× ×ž×•×ª××ž×™× ×ישית",
158 "pricing.features.desktopNotifications": "התר×ות שולחן העבודה",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "בחר מתוך יותר מ 70 שירותי×",
161 "pricing.features.serviceProxies": "פרוקסי לשירותי×",
162 "pricing.features.spellchecker": "תמיכה בבדיקת ×יות",
163 "pricing.features.teamManagement": "ניהול צוות",
164 "pricing.features.thirdPartyServices": "התקן שירותי צד שלישי",
165 "pricing.features.unlimitedServices": "הוסף ×©×™×¨×•×ª×™× ×‘×œ×™ הגבלה",
166 "pricing.features.workspaces": "סביבות עבודה",
167 "service.crashHandler.action": "טען מחדש {name}", 155 "service.crashHandler.action": "טען מחדש {name}",
168 "service.crashHandler.autoReload": "מנסה לשחזר ×ת {name} ב×ופן ×וטומטי בעוד {seconds} שניות", 156 "service.crashHandler.autoReload": "מנסה לשחזר ×ת {name} ב×ופן ×וטומטי בעוד {seconds} שניות",
169 "service.crashHandler.headline": "הו, ל×!", 157 "service.crashHandler.headline": "הו, ל×!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "השתמש בפרדי ×œ×œ× ×—×©×‘×•×Ÿ", 170 "services.serverless": "השתמש בפרדי ×œ×œ× ×—×©×‘×•×Ÿ",
183 "services.welcome": "ברוך ×”×‘× ×œ×¤×¨×“×™", 171 "services.welcome": "ברוך ×”×‘× ×œ×¤×¨×“×™",
184 "settings.account.account.editButton": "ערוך ×ת החשבון", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "החשבון ×ינו זמין", 173 "settings.account.accountUnavailable": "החשבון ×ינו זמין",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "עדכן פרופיל", 175 "settings.account.buttonSave": "עדכן פרופיל",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", 177 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
190 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.", 178 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
191 "settings.account.headline": "חשבון", 179 "settings.account.headline": "חשבון",
192 "settings.account.headlineAccount": "פרטי חשבון", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "×זור מסוכן", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "חשבוניות", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "שנה סיסמה", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "עדכן פרופיל", 184 "settings.account.headlineProfile": "עדכן פרופיל",
197 "settings.account.successInfo": "×”×©×™× ×•×™×™× ×©×œ×š נשמרו", 185 "settings.account.successInfo": "×”×©×™× ×•×™×™× ×©×œ×š נשמרו",
198 "settings.account.tryReloadServices": "נסה שוב", 186 "settings.account.tryReloadServices": "נסה שוב",
199 "settings.account.tryReloadUserInfoRequest": "נסה שוב", 187 "settings.account.tryReloadUserInfoRequest": "נסה שוב",
200 "settings.account.userInfoRequestFailed": "××™ ×פשר לטעון ×ת פרטי המשתמש", 188 "settings.account.userInfoRequestFailed": "××™ ×פשר לטעון ×ת פרטי המשתמש",
201 "settings.account.yourLicense": "רישיון הפרדי שלך", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "ניקוי המטמון", 191 "settings.app.buttonClearAllCache": "ניקוי המטמון",
204 "settings.app.buttonInstallUpdate": "הפעל מחדש והתקן עדכוני×", 192 "settings.app.buttonInstallUpdate": "הפעל מחדש והתקן עדכוני×",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "שרת מות×× ×ישית לרשימת המשימות", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "×פשר מצב לילה", 211 "settings.app.form.darkMode": "×פשר מצב לילה",
224 "settings.app.form.enableGPUAcceleration": "×פשר ×”×צת חומרה (GPU)", 212 "settings.app.form.enableGPUAcceleration": "×פשר ×”×צת חומרה (GPU)",
225 "settings.app.form.enableLock": "×פשר נעילה ב×מצעות סיסמ×", 213 "settings.app.form.enableLock": "×פשר נעילה ב×מצעות סיסמ×",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "הפעל בדיקת ×יות", 215 "settings.app.form.enableSpellchecking": "הפעל בדיקת ×יות",
228 "settings.app.form.enableSystemTray": "הצג ×ת פרדי בסרגל הכלי×", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "×פשר ×ת רשימת המשימות של Ferdi", 217 "settings.app.form.enableTodos": "×פשר ×ת רשימת המשימות של Ferdi",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "התחלה במצב ממוזער", 243 "settings.app.form.startMinimized": "התחלה במצב ממוזער",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -296,7 +285,7 @@
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "תיעוד למפתחי×", 287 "settings.recipes.customService.openDevDocs": "תיעוד למפתחי×",
299 "settings.recipes.customService.openFolder": "פתח תיקיה", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "×©×™×¨×•×ª×™× ×–×ž×™× ×™×", 289 "settings.recipes.headline": "×©×™×¨×•×ª×™× ×–×ž×™× ×™×",
301 "settings.recipes.missingService": "×œ× ×ž×•×¦× ×ת השירות שלך?", 290 "settings.recipes.missingService": "×œ× ×ž×•×¦× ×ת השירות שלך?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "מחק שירות", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "ערוך {name}", 305 "settings.service.form.editServiceHeadline": "ערוך {name}",
317 "settings.service.form.enableAudio": "×פשר ×ודיו", 306 "settings.service.form.enableAudio": "×פשר ×ודיו",
318 "settings.service.form.enableBadge": "הצג חיווי על הודעות ×©×œ× × ×§×¨×ו", 307 "settings.service.form.enableBadge": "הצג חיווי על הודעות ×©×œ× × ×§×¨×ו",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "ש×", 323 "settings.service.form.name": "ש×",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "פתח ×ת darkmode.css", 325 "settings.service.form.openDarkmodeCss": "פתח ×ת darkmode.css",
336 "settings.service.form.openUserCss": "פתח ×ת user.css", 326 "settings.service.form.openUserCss": "פתח ×ת user.css",
337 "settings.service.form.openUserJs": "פתח ×ת user.js", 327 "settings.service.form.openUserJs": "פתח ×ת user.js",
338 "settings.service.form.proxy.headline": "הגדרות פרוקסי ל HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "הגדרות פרוקסי ל HTTP/HTTPS",
339 "settings.service.form.proxy.host": "מ×רח\\IP פרוקסי", 329 "settings.service.form.proxy.host": "מ×רח\\IP פרוקסי",
340 "settings.service.form.proxy.info": "הגדרות הפרוקסי ×œ× ×™×¡×•× ×›×¨× ×• ×¢× ×©×¨×ª×™ פרדי.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "השתמש בפרוקסי", 331 "settings.service.form.proxy.isEnabled": "השתמש בפרוקסי",
342 "settings.service.form.proxy.password": "סיסמה (×ופציונלית)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "פורט", 333 "settings.service.form.proxy.port": "פורט",
344 "settings.service.form.proxy.restartInfo": "×× × ×”×¤×¢×œ מחדש ×ת פרדי ×חרי שינוי הגדרות פרוקסי.", 334 "settings.service.form.proxy.restartInfo": "×× × ×”×¤×¢×œ מחדש ×ת פרדי ×חרי שינוי הגדרות פרוקסי.",
345 "settings.service.form.proxy.user": "משתמש (×ופציונלי)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "קבצי המשתמש שלך יוכנסו לתוך דף ×”×ינטרנט על מנת שתוכל להת××™× ×ת ×”×©×™×¨×•×ª×™× ×©×œ×š כפי שתרצה. קבצי משתמש מ××•×—×¡× ×™× ×œ×•×§×לית ו××™× × ×ž×•×¢×‘×¨×™× ×œ×ž×—×©×‘×™× ××—×¨×™× ×”×ž×©×ª×ž×©×™× ×‘×ותו חשבון.", 336 "settings.service.form.recipeFileInfo": "קבצי המשתמש שלך יוכנסו לתוך דף ×”×ינטרנט על מנת שתוכל להת××™× ×ת ×”×©×™×¨×•×ª×™× ×©×œ×š כפי שתרצה. קבצי משתמש מ××•×—×¡× ×™× ×œ×•×§×לית ו××™× × ×ž×•×¢×‘×¨×™× ×œ×ž×—×©×‘×™× ××—×¨×™× ×”×ž×©×ª×ž×©×™× ×‘×ותו חשבון.",
347 "settings.service.form.saveButton": "שמור שירות", 337 "settings.service.form.saveButton": "שמור שירות",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "גלה ×©×™×¨×•×ª×™× ×—×“×©×™×", 344 "settings.services.discoverServices": "גלה ×©×™×¨×•×ª×™× ×—×“×©×™×",
355 "settings.services.headline": "×”×©×™×¨×•×ª×™× ×©×œ×š", 345 "settings.services.headline": "×”×©×™×¨×•×ª×™× ×©×œ×š",
356 "settings.services.noServicesAdded": "התחל להוסיף שירותי×.", 346 "settings.services.noServicesAdded": "התחל להוסיף שירותי×.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "×œ× × ×™×ª לטעון ×ת ×”×©×™×¨×•×ª×™× ×©×œ×š", 348 "settings.services.servicesRequestFailed": "×œ× × ×™×ª לטעון ×ת ×”×©×™×¨×•×ª×™× ×©×œ×š",
358 "settings.services.tooltip.isDisabled": "השירות מושבת", 349 "settings.services.tooltip.isDisabled": "השירות מושבת",
359 "settings.services.tooltip.isMuted": "כל ×”×¦×œ×™×œ×™× ×ž×•×©×ª×§×™×", 350 "settings.services.tooltip.isMuted": "כל ×”×¦×œ×™×œ×™× ×ž×•×©×ª×§×™×",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>",
363 "settings.supportFerdi.bannerText": "×”×× ×ª×¨×¦×” לעזור לנו לשפר ×ת פרדי?", 354 "settings.supportFerdi.bannerText": "×”×× ×ª×¨×¦×” לעזור לנו לשפר ×ת פרדי?",
364 "settings.supportFerdi.headline": "×ודות פרדי", 355 "settings.supportFerdi.headline": "×ודות פרדי",
365 "settings.supportFerdi.openSurvey": "פתח סקר", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "×× ×ª×¨×¦×” לתמוך בפרדי ב×מצעות תרומה, ×תה יכול לעשות ×–×ת ×’×,", 357 "settings.supportFerdi.textDonation": "×× ×ª×¨×¦×” לתמוך בפרדי ב×מצעות תרומה, ×תה יכול לעשות ×–×ת ×’×,",
367 "settings.supportFerdi.textDonationAnd": "וג×", 358 "settings.supportFerdi.textDonationAnd": "וג×",
368 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our", 359 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our",
369 "settings.supportFerdi.textGitHubSponsors": "×ª×•×ž×›×™× ×‘×’×™×˜×”×ב", 360 "settings.supportFerdi.textGitHubSponsors": "×ª×•×ž×›×™× ×‘×’×™×˜×”×ב",
370 "settings.supportFerdi.textListContributors": "רשימת ×”×ª×•×ž×›×™× ×”×ž×œ××”", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "×›×ן", 362 "settings.supportFerdi.textListContributorsHere": "×›×ן",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Support is always welcome. You can find a list of the help we need", 364 "settings.supportFerdi.textSupportWelcome": "Support is always welcome. You can find a list of the help we need",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "×œ×œ× ×›×•×•× ×ª רווח", 378 "settings.user.form.accountType.non-profit": "×œ×œ× ×›×•×•× ×ª רווח",
388 "settings.user.form.currentPassword": "×”×¡×™×¡×ž× ×”× ×•×›×—×™×ª", 379 "settings.user.form.currentPassword": "×”×¡×™×¡×ž× ×”× ×•×›×—×™×ª",
389 "settings.user.form.email": "דו×\"ל", 380 "settings.user.form.email": "דו×\"ל",
390 "settings.user.form.firstname": "×©× ×¤×¨×˜×™", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "×©× ×ž×©×¤×—×”", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "×¡×™×¡×ž× ×—×“×©×”", 383 "settings.user.form.newPassword": "×¡×™×¡×ž× ×—×“×©×”",
393 "settings.workspace.add.form.name": "ש×", 384 "settings.workspace.add.form.name": "ש×",
394 "settings.workspace.add.form.submitButton": "צור סביבת עבודה", 385 "settings.workspace.add.form.submitButton": "צור סביבת עבודה",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "×פשר התר×ות ו×ודיו", 411 "sidebar.unmuteApp": "×פשר התר×ות ו×ודיו",
421 "signup.email.label": "כתובת דו×\"ל", 412 "signup.email.label": "כתובת דו×\"ל",
422 "signup.emailDuplicate": "כבר ×§×™×™× ×—×©×‘×•×Ÿ ×¢× ×›×ª×•×‘×ª דו×\"ל זו", 413 "signup.emailDuplicate": "כבר ×§×™×™× ×—×©×‘×•×Ÿ ×¢× ×›×ª×•×‘×ª דו×\"ל זו",
423 "signup.firstname.label": "×©× ×¤×¨×˜×™", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "הרש×", 415 "signup.headline": "הרש×",
425 "signup.lastname.label": "×©× ×ž×©×¤×—×”", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "ביצירת חשבון פרדי ×תה ×ž×¡×›×™× ×œ", 417 "signup.legal.info": "ביצירת חשבון פרדי ×תה ×ž×¡×›×™× ×œ",
427 "signup.legal.privacy": "הצהרת פרטיות", 418 "signup.legal.privacy": "הצהרת פרטיות",
428 "signup.legal.terms": "תנ××™ שימוש", 419 "signup.legal.terms": "תנ××™ שימוש",
@@ -430,11 +421,11 @@
430 "signup.password.label": "סיסמ×", 421 "signup.password.label": "סיסמ×",
431 "signup.submit.label": "צור חשבון", 422 "signup.submit.label": "צור חשבון",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "מחק שירות", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "כבה ×ודיו", 425 "tabs.item.disableAudio": "כבה ×ודיו",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "כבה התר×ות", 427 "tabs.item.disableNotifications": "כבה התר×ות",
437 "tabs.item.disableService": "כבה שירות", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "×פשר ×ודיו", 429 "tabs.item.enableAudio": "×פשר ×ודיו",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "×פשר התר×ות", 431 "tabs.item.enableNotification": "×פשר התר×ות",
@@ -454,12 +445,12 @@
454 "webControls.reload": "רענן", 445 "webControls.reload": "רענן",
455 "welcome.loginButton": "התחבר לחשבון שלך", 446 "welcome.loginButton": "התחבר לחשבון שלך",
456 "welcome.signupButton": "צור חשבון חדש בחינ×", 447 "welcome.signupButton": "צור חשבון חדש בחינ×",
457 "workspaceDrawer.addNewWorkspaceLabel": "הוסף סביבת עבודה חדשה", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "כל השירותי×", 449 "workspaceDrawer.allServices": "כל השירותי×",
459 "workspaceDrawer.headline": "סביבות עבודה", 450 "workspaceDrawer.headline": "סביבות עבודה",
460 "workspaceDrawer.item.contextMenuEdit": "ערוך", 451 "workspaceDrawer.item.contextMenuEdit": "ערוך",
461 "workspaceDrawer.item.noServicesAddedYet": "×œ× × ×•×¡×¤×• שירותי×…", 452 "workspaceDrawer.item.noServicesAddedYet": "×œ× × ×•×¡×¤×• שירותי×…",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "הגדרות סביבת עבודה", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "מעבר ל" 455 "workspaces.switchingIndicator.switchingTo": "מעבר ל"
465} 456}
diff --git a/src/i18n/locales/hi.json b/src/i18n/locales/hi.json
index be9bbb961..812ec8c4c 100644
--- a/src/i18n/locales/hi.json
+++ b/src/i18n/locales/hi.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/hr.json b/src/i18n/locales/hr.json
index f7e046ed9..6dcd65032 100644
--- a/src/i18n/locales/hr.json
+++ b/src/i18n/locales/hr.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Ponovno uÄitavanje", 2 "app.errorHandler.action": "Ponovno uÄitavanje",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Prilagođen server", 4 "changeserver.customServerLabel": "Prilagođen server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Nije se moguće povezati na Francove on-line servise. ", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Odustani", 27 "global.cancel": "Cancel",
29 "global.edit": "Uredi", 28 "global.edit": "Uredi",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Sada ste povezani s internetom. ", 30 "global.notConnectedToTheInternet": "Sada ste povezani s internetom. ",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Postavke", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use System Default ({default})", 36 "global.spellchecker.useDefault": "Use System Default ({default})",
38 "global.spellchecking.autodetect": "Detect language automatically", 37 "global.spellchecking.autodetect": "Detect language automatically",
39 "global.spellchecking.autodetect.short": "Automatic", 38 "global.spellchecking.autodetect.short": "Automatic",
40 "global.spellchecking.language": "Spell checking language", 39 "global.spellchecking.language": "Spell checking language",
41 "global.submit": "Pošalji", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Uvezite svoje Franc 4 servise. ", 44 "import.headline": "Uvezite svoje Franc 4 servise. ",
46 "import.notSupportedHeadline": "Franc 5 trenutno ne podržava taj servis", 45 "import.notSupportedHeadline": "Franc 5 trenutno ne podržava taj servis",
47 "import.skip.label": "Želim ruÄno dodati ove usluge", 46 "import.skip.label": "Želim ruÄno dodati ove usluge",
48 "import.submit.label": "Uvezi servise", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Å ta je novo?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje", 50 "infobar.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje",
52 "infobar.buttonReloadServices": "Ponovo uÄitaj servise", 51 "infobar.buttonReloadServices": "Ponovo uÄitaj servise",
53 "infobar.hide": "Hide", 52 "infobar.hide": "Hide",
@@ -75,7 +74,7 @@
75 "login.email.label": "Vaša e-adresa:", 74 "login.email.label": "Vaša e-adresa:",
76 "login.headline": "Prijavite se", 75 "login.headline": "Prijavite se",
77 "login.invalidCredentials": "E-mail ili lozinka nisu toÄni", 76 "login.invalidCredentials": "E-mail ili lozinka nisu toÄni",
78 "login.link.password": "Stvaranje nove lozinke", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Stvorite besplatan raÄun", 78 "login.link.signup": "Stvorite besplatan raÄun",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "Vaša sesija je istekla, prijavite se ponovo.", 80 "login.serverLogout": "Vaša sesija je istekla, prijavite se ponovo.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Sve usluge", 147 "menu.workspaces.defaultWorkspace": "Sve usluge",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "Vaša e-adresa:", 149 "password.email.label": "Vaša e-adresa:",
151 "password.headline": "Stvaranje nove lozinke", 150 "password.headline": "Reset password",
152 "password.link.login": "Prijavite se na VaÅ¡ raÄun", 151 "password.link.login": "Prijavite se na VaÅ¡ raÄun",
153 "password.link.signup": "Stvorite besplatan raÄun", 152 "password.link.signup": "Stvorite besplatan raÄun",
154 "password.noUser": "Ne postoji ni jedan korisnik s tom e-mail adresom", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Molimo Vas da provjerite svoju e-mail adresu", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Osvježi okvir", 155 "service.crashHandler.action": "Osvježi okvir",
168 "service.crashHandler.autoReload": "Pokušati ću automatski povratiti {name} u {seconds} sekundi", 156 "service.crashHandler.autoReload": "Pokušati ću automatski povratiti {name} u {seconds} sekundi",
169 "service.crashHandler.headline": "O, ne! ", 157 "service.crashHandler.headline": "O, ne! ",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Dobrodošli u Ferdi", 171 "services.welcome": "Dobrodošli u Ferdi",
184 "settings.account.account.editButton": "Uredi raÄun", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Ažuriraj profil", 175 "settings.account.buttonSave": "Ažuriraj profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Dobili ste email s linkom putem kojeg ćete potvrditi brisanje raÄuna. VaÅ¡ raÄun i podatke neće biti moguće vratiti. ", 177 "settings.account.deleteEmailSent": "Dobili ste email s linkom putem kojeg ćete potvrditi brisanje raÄuna. VaÅ¡ raÄun i podatke neće biti moguće vratiti. ",
190 "settings.account.deleteInfo": "Ako viÅ¡e ne trebate Ferdi raÄun, ovdje možete obrisati sve vezane podatke kao i raÄun.", 178 "settings.account.deleteInfo": "Ako viÅ¡e ne trebate Ferdi raÄun, ovdje možete obrisati sve vezane podatke kao i raÄun.",
191 "settings.account.headline": "KorisniÄki raÄun", 179 "settings.account.headline": "KorisniÄki raÄun",
192 "settings.account.headlineAccount": "Informacije o raÄunu", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Opasnost", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Fakture", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Promijenite lozinku", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Ažuriraj profil", 184 "settings.account.headlineProfile": "Ažuriraj profil",
197 "settings.account.successInfo": "Vaše promjene su spremljene", 185 "settings.account.successInfo": "Vaše promjene su spremljene",
198 "settings.account.tryReloadServices": "Pokušajte ponovno", 186 "settings.account.tryReloadServices": "Pokušajte ponovno",
199 "settings.account.tryReloadUserInfoRequest": "Pokušajte ponovno", 187 "settings.account.tryReloadUserInfoRequest": "Pokušajte ponovno",
200 "settings.account.userInfoRequestFailed": "Nije moguće uÄitati informacije o korisniku", 188 "settings.account.userInfoRequestFailed": "Nije moguće uÄitati informacije o korisniku",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "OÄisti memoriju", 191 "settings.app.buttonClearAllCache": "OÄisti memoriju",
204 "settings.app.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje", 192 "settings.app.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Omogući provjeru pravopisa", 215 "settings.app.form.enableSpellchecking": "Omogući provjeru pravopisa",
228 "settings.app.form.enableSystemTray": "Prikaži aplikaciju u sustavskoj traci", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Prikaži ploÄe s onemogućenim servisima", 239 "settings.app.form.showDisabledServices": "Prikaži ploÄe s onemogućenim servisima",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Pokaži neproÄitane znaÄke poruka kad se obavjeÅ¡tenja onemoguće", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Pokaži neproÄitane znaÄke poruka kad se obavjeÅ¡tenja onemoguće",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Izbriši uslugu", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Uredite {name}", 305 "settings.service.form.editServiceHeadline": "Uredite {name}",
317 "settings.service.form.enableAudio": "Omogućite zvuk", 306 "settings.service.form.enableAudio": "Omogućite zvuk",
318 "settings.service.form.enableBadge": "Show unread message badges", 307 "settings.service.form.enableBadge": "Show unread message badges",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Kada je onemogućeno, sve obavijesti, svi zvukovi i sva pozadinska podrÅ¡ka će biti neÄujna. ", 322 "settings.service.form.isMutedInfo": "Kada je onemogućeno, sve obavijesti, svi zvukovi i sva pozadinska podrÅ¡ka će biti neÄujna. ",
334 "settings.service.form.name": "Ime", 323 "settings.service.form.name": "Ime",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Pronađite usluge", 344 "settings.services.discoverServices": "Pronađite usluge",
355 "settings.services.headline": "Vaše usluge", 345 "settings.services.headline": "Vaše usluge",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Usluga je onemogućena. ", 349 "settings.services.tooltip.isDisabled": "Usluga je onemogućena. ",
359 "settings.services.tooltip.isMuted": "Svi zvukovi su onemogućeni. ", 350 "settings.services.tooltip.isMuted": "Svi zvukovi su onemogućeni. ",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Neprofitno ", 378 "settings.user.form.accountType.non-profit": "Neprofitno ",
388 "settings.user.form.currentPassword": "Trenutna lozinka:", 379 "settings.user.form.currentPassword": "Trenutna lozinka:",
389 "settings.user.form.email": "E-pošta", 380 "settings.user.form.email": "E-pošta",
390 "settings.user.form.firstname": "Ime", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Prezime", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nova lozinka", 383 "settings.user.form.newPassword": "Nova lozinka",
393 "settings.workspace.add.form.name": "Ime", 384 "settings.workspace.add.form.name": "Ime",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Omogući obavijesti i zvuk", 411 "sidebar.unmuteApp": "Omogući obavijesti i zvuk",
421 "signup.email.label": "Vaša e-adresa:", 412 "signup.email.label": "Vaša e-adresa:",
422 "signup.emailDuplicate": "Već postoji korisnik s tom e-mail adresom", 413 "signup.emailDuplicate": "Već postoji korisnik s tom e-mail adresom",
423 "signup.firstname.label": "Ime", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Prijava", 415 "signup.headline": "Prijava",
425 "signup.lastname.label": "Prezime", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Prilikom stvaranja Ferdi raÄuna, slažete se sa sljedećim stavkama:", 417 "signup.legal.info": "Prilikom stvaranja Ferdi raÄuna, slažete se sa sljedećim stavkama:",
427 "signup.legal.privacy": "Izjava o privatnosti ", 418 "signup.legal.privacy": "Izjava o privatnosti ",
428 "signup.legal.terms": "Uvjeti korištenja", 419 "signup.legal.terms": "Uvjeti korištenja",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "Napravite novi raÄun", 422 "signup.submit.label": "Napravite novi raÄun",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Izbriši uslugu", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Onemogući zvuk", 425 "tabs.item.disableAudio": "Onemogući zvuk",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Onemogući obavijesti", 427 "tabs.item.disableNotifications": "Onemogući obavijesti",
437 "tabs.item.disableService": "Onemogući servis", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Omogućite zvuk", 429 "tabs.item.enableAudio": "Omogućite zvuk",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Omogućite obavijesti", 431 "tabs.item.enableNotification": "Omogućite obavijesti",
diff --git a/src/i18n/locales/hu.json b/src/i18n/locales/hu.json
index 84c8496b8..8d83fea42 100644
--- a/src/i18n/locales/hu.json
+++ b/src/i18n/locales/hu.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Újratöltés", 2 "app.errorHandler.action": "Újratöltés",
3 "app.errorHandler.headline": "Valami nem jött össze", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Egyéni szerver", 4 "changeserver.customServerLabel": "Egyéni szerver",
5 "changeserver.headline": "Szerver megváltoztatása", 5 "changeserver.headline": "Szerver megváltoztatása",
6 "changeserver.label": "Szerver", 6 "changeserver.label": "Szerver",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Mi történt?", 10 "connectionLostBanner.informationLink": "Mi történt?",
11 "connectionLostBanner.message": "Ja ne! Ferdi nem tud kapcsolodni {name}-hez.", 11 "connectionLostBanner.message": "Ja ne! Ferdi nem tud kapcsolodni {name}-hez.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Hibakeresési napló publikálása",
14 "feature.nightlyBuilds.activate": "Aktiválás", 13 "feature.nightlyBuilds.activate": "Aktiválás",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly verziók", 15 "feature.nightlyBuilds.title": "Nightly verziók",
@@ -24,30 +23,30 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Keresés...", 24 "feature.quickSwitch.search": "Keresés...",
26 "feature.quickSwitch.title": "Gyorsváltó", 25 "feature.quickSwitch.title": "Gyorsváltó",
27 "global.api.unhealthy": "Nem lehet csatlakozni a Ferdi online szolgáltatáshoz", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Mégsem", 27 "global.cancel": "Cancel",
29 "global.edit": "Szerkesztés", 28 "global.edit": "Szerkesztés",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Nincs hálózati kapcsolat.", 30 "global.notConnectedToTheInternet": "Nincs hálózati kapcsolat.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Kilépés", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Beállítások", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Rendszer alapbeállítás használata ({default})", 36 "global.spellchecker.useDefault": "Rendszer alapbeállítás használata ({default})",
38 "global.spellchecking.autodetect": "Automatikus nyelvdetektálás", 37 "global.spellchecking.autodetect": "Automatikus nyelvdetektálás",
39 "global.spellchecking.autodetect.short": "Automatikus", 38 "global.spellchecking.autodetect.short": "Automatikus",
40 "global.spellchecking.language": "Helyesírás-ellenőrző nyelve", 39 "global.spellchecking.language": "Helyesírás-ellenőrző nyelve",
41 "global.submit": "Küldés", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importáld szolgáltatásaidat a Ferdi 4-ből", 44 "import.headline": "Importáld szolgáltatásaidat a Ferdi 4-ből",
46 "import.notSupportedHeadline": "Még nem támogatott szolgáltatások a Ferdi 5-ben", 45 "import.notSupportedHeadline": "Még nem támogatott szolgáltatások a Ferdi 5-ben",
47 "import.skip.label": "Manuálisan szeretném hozzáadni a szolgáltatásokat", 46 "import.skip.label": "Manuálisan szeretném hozzáadni a szolgáltatásokat",
48 "import.submit.label": "Szolgáltatások importálása", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Mi változott?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Újraindítás és frissítés telepítése", 50 "infobar.buttonInstallUpdate": "Újraindítás és frissítés telepítése",
52 "infobar.buttonReloadServices": "Szolgáltatások újratöltése", 51 "infobar.buttonReloadServices": "Szolgáltatások újratöltése",
53 "infobar.hide": "Elrejt", 52 "infobar.hide": "Elrejt",
@@ -75,7 +74,7 @@
75 "login.email.label": "Email cím", 74 "login.email.label": "Email cím",
76 "login.headline": "Bejelentkezés", 75 "login.headline": "Bejelentkezés",
77 "login.invalidCredentials": "Hibás email cím vagy jelszó", 76 "login.invalidCredentials": "Hibás email cím vagy jelszó",
78 "login.link.password": "Jelszó visszaállítás", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Új fiók létrehozása", 78 "login.link.signup": "Új fiók létrehozása",
80 "login.password.label": "Jelszó", 79 "login.password.label": "Jelszó",
81 "login.serverLogout": "A munkamenet lejárt, kérlek lépj be újra.", 80 "login.serverLogout": "A munkamenet lejárt, kérlek lépj be újra.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Támogatás", 116 "menu.help.support": "Támogatás",
118 "menu.help.tos": "Felhasználói feltételek", 117 "menu.help.tos": "Felhasználói feltételek",
119 "menu.services": "Szolgáltatások", 118 "menu.services": "Szolgáltatások",
120 "menu.services.activatePreviousService": "Előző szolgáltatás", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Kezdőlap", 121 "menu.services.goHome": "Kezdőlap",
123 "menu.services.setNextServiceActive": "Következő szolgáltatás", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Tennivalók", 123 "menu.todos": "Tennivalók",
125 "menu.todos.enableTodos": "Enable Todos", 124 "menu.todos.enableTodos": "Enable Todos",
126 "menu.view": "Nézet", 125 "menu.view": "Nézet",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Összes szolgáltatás", 147 "menu.workspaces.defaultWorkspace": "Összes szolgáltatás",
149 "menu.workspaces.openWorkspaceDrawer": "Munkaterület panel kinyitása", 148 "menu.workspaces.openWorkspaceDrawer": "Munkaterület panel kinyitása",
150 "password.email.label": "Email cím", 149 "password.email.label": "Email cím",
151 "password.headline": "Jelszó visszaállítás", 150 "password.headline": "Reset password",
152 "password.link.login": "Jelentkezz be a fiókodba", 151 "password.link.login": "Jelentkezz be a fiókodba",
153 "password.link.signup": "Új fiók létrehozása", 152 "password.link.signup": "Új fiók létrehozása",
154 "password.noUser": "Nem található felhasználó a megadott email címmel", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Ellenőrizd az email fiókodat", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Fiók szinkronizálás",
157 "pricing.features.customWebsites": "Egyéni weboldalak megadása",
158 "pricing.features.desktopNotifications": "Asztali értesítések",
159 "pricing.features.onPremise": "Helyi és egyéb távoli szolgáltatások",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Szolgáltatás Proxy-k",
162 "pricing.features.spellchecker": "Helyesírás-ellenőrzés támogatás",
163 "pricing.features.teamManagement": "Csapatkezelés",
164 "pricing.features.thirdPartyServices": "Harmadik féltől származó szolgáltatások használata",
165 "pricing.features.unlimitedServices": "Korlátlan szolgáltatások felvitele",
166 "pricing.features.workspaces": "Munkaterületek",
167 "service.crashHandler.action": "{name} újratöltése", 155 "service.crashHandler.action": "{name} újratöltése",
168 "service.crashHandler.autoReload": "{name} automatikusan helyreállítása {seconds} másodpercen belül", 156 "service.crashHandler.autoReload": "{name} automatikusan helyreállítása {seconds} másodpercen belül",
169 "service.crashHandler.headline": "Jajj ne!", 157 "service.crashHandler.headline": "Jajj ne!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Üdvözöl a Ferdi", 171 "services.welcome": "Üdvözöl a Ferdi",
184 "settings.account.account.editButton": "Fiók szerkesztése", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "A Fiók nem érhető el", 173 "settings.account.accountUnavailable": "A Fiók nem érhető el",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Profil frissítése", 175 "settings.account.buttonSave": "Profil frissítése",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "A fiókod törléséhez egy e-mailt küldtük a törlést megerősítő linkkel. A linkre kattintást követően a fiókod és az adatait már nem állíthatók vissza többé!", 177 "settings.account.deleteEmailSent": "A fiókod törléséhez egy e-mailt küldtük a törlést megerősítő linkkel. A linkre kattintást követően a fiókod és az adatait már nem állíthatók vissza többé!",
190 "settings.account.deleteInfo": "Ha még nem szeretnéd fenntartani a Ferdi-fiókodat, akkor itt törölheted minden hozzá kapcsolódó adattal együtt.", 178 "settings.account.deleteInfo": "Ha még nem szeretnéd fenntartani a Ferdi-fiókodat, akkor itt törölheted minden hozzá kapcsolódó adattal együtt.",
191 "settings.account.headline": "Fiók", 179 "settings.account.headline": "Fiók",
192 "settings.account.headlineAccount": "Fiókinformációk", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Veszélyes terület", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Számlák", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Jelszócsere", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Profil frissítése", 184 "settings.account.headlineProfile": "Profil frissítése",
197 "settings.account.successInfo": "A módosításokat elmentettük", 185 "settings.account.successInfo": "A módosításokat elmentettük",
198 "settings.account.tryReloadServices": "Próbáld újra", 186 "settings.account.tryReloadServices": "Próbáld újra",
199 "settings.account.tryReloadUserInfoRequest": "Próbáld újra", 187 "settings.account.tryReloadUserInfoRequest": "Próbáld újra",
200 "settings.account.userInfoRequestFailed": "A felhasználói adatok betöltése sikertelen", 188 "settings.account.userInfoRequestFailed": "A felhasználói adatok betöltése sikertelen",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Gyorsítótár törlése", 191 "settings.app.buttonClearAllCache": "Gyorsítótár törlése",
204 "settings.app.buttonInstallUpdate": "Újraindítás és frissítés telepítése", 192 "settings.app.buttonInstallUpdate": "Újraindítás és frissítés telepítése",
@@ -225,7 +213,7 @@
225 "settings.app.form.enableLock": "Jelszavas zár engedélyezése", 213 "settings.app.form.enableLock": "Jelszavas zár engedélyezése",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Helyesírás-ellenőrzés engedélyezése", 215 "settings.app.form.enableSpellchecking": "Helyesírás-ellenőrzés engedélyezése",
228 "settings.app.form.enableSystemTray": "Ferdi mutatása a tálcán", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Ferdi Tennivalók bekapcsolása", 217 "settings.app.form.enableTodos": "Ferdi Tennivalók bekapcsolása",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Letiltott szolgáltatások megjelenítése", 239 "settings.app.form.showDisabledServices": "Letiltott szolgáltatások megjelenítése",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Mutassa az 'olvasatlan üzenet' jelzést, amikor az értesítések le vannak tiltva", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Mutassa az 'olvasatlan üzenet' jelzést, amikor az értesítések le vannak tiltva",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Indítás minimalizálva", 243 "settings.app.form.startMinimized": "Indítás minimalizálva",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes", 283 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes",
295 "settings.recipes.customService.headline.customRecipes": "Egyéni, harmadik féltől származó receptek", 284 "settings.recipes.customService.headline.customRecipes": "Egyéni, harmadik féltől származó receptek",
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "Az egyéni szolgáltatás hozzáadásához, másoljuk be annak receptjét:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Fejlesztői dokumentáció", 287 "settings.recipes.customService.openDevDocs": "Fejlesztői dokumentáció",
299 "settings.recipes.customService.openFolder": "Könyvtár megnyitása", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Elérhető szolgáltatások", 289 "settings.recipes.headline": "Elérhető szolgáltatások",
301 "settings.recipes.missingService": "Hiányzik egy szolgáltatás?", 290 "settings.recipes.missingService": "Hiányzik egy szolgáltatás?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Szolgáltatás törlése", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "{name} szerkesztése", 305 "settings.service.form.editServiceHeadline": "{name} szerkesztése",
317 "settings.service.form.enableAudio": "Hang engedélyezése", 306 "settings.service.form.enableAudio": "Hang engedélyezése",
318 "settings.service.form.enableBadge": "Mutasd az olvasatlan jelzéseket", 307 "settings.service.form.enableBadge": "Mutasd az olvasatlan jelzéseket",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Ha kikapcsolod, minden értesítési és lejátszott hang némításra kerül", 322 "settings.service.form.isMutedInfo": "Ha kikapcsolod, minden értesítési és lejátszott hang némításra kerül",
334 "settings.service.form.name": "Név", 323 "settings.service.form.name": "Név",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "User.css megnyitása", 326 "settings.service.form.openUserCss": "User.css megnyitása",
337 "settings.service.form.openUserJs": "User.js megnyitása", 327 "settings.service.form.openUserJs": "User.js megnyitása",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy beállítások", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy beállítások",
339 "settings.service.form.proxy.host": "Proxy hoszt/IP", 329 "settings.service.form.proxy.host": "Proxy hoszt/IP",
340 "settings.service.form.proxy.info": "Proxy beállítások nem szinkronizálódnak a Ferdi kiszolgálókkal.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Proxy használata", 331 "settings.service.form.proxy.isEnabled": "Proxy használata",
342 "settings.service.form.proxy.password": "Jelszó (opcionális)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Kérjük indítsd újra a Ferdi-ot a proxy beállítások megváltoztatása után.", 334 "settings.service.form.proxy.restartInfo": "Kérjük indítsd újra a Ferdi-ot a proxy beállítások megváltoztatása után.",
345 "settings.service.form.proxy.user": "Felhasználó (opcionális)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Szolgáltatás mentése", 337 "settings.service.form.saveButton": "Szolgáltatás mentése",
348 "settings.service.form.tabHosted": "Ãœzemeltetett", 338 "settings.service.form.tabHosted": "Ãœzemeltetett",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Szolgáltatások felfedezése", 344 "settings.services.discoverServices": "Szolgáltatások felfedezése",
355 "settings.services.headline": "Szolgáltatásaid", 345 "settings.services.headline": "Szolgáltatásaid",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Szolgáltatásaid betöltése sikertelen", 348 "settings.services.servicesRequestFailed": "Szolgáltatásaid betöltése sikertelen",
358 "settings.services.tooltip.isDisabled": "A szolgáltatás le van tiltva", 349 "settings.services.tooltip.isDisabled": "A szolgáltatás le van tiltva",
359 "settings.services.tooltip.isMuted": "Minden hang lenémítva", 350 "settings.services.tooltip.isMuted": "Minden hang lenémítva",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Nonprofit", 378 "settings.user.form.accountType.non-profit": "Nonprofit",
388 "settings.user.form.currentPassword": "Jelenlegi jelszó", 379 "settings.user.form.currentPassword": "Jelenlegi jelszó",
389 "settings.user.form.email": "Email", 380 "settings.user.form.email": "Email",
390 "settings.user.form.firstname": "Keresztnév", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Vezetéknév", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Új jelszó", 383 "settings.user.form.newPassword": "Új jelszó",
393 "settings.workspace.add.form.name": "Név", 384 "settings.workspace.add.form.name": "Név",
394 "settings.workspace.add.form.submitButton": "Új munkaterület", 385 "settings.workspace.add.form.submitButton": "Új munkaterület",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Próbáld újra", 396 "settings.workspaces.tryReloadWorkspaces": "Próbáld újra",
406 "settings.workspaces.updatedInfo": "A módosításokat elmentettük", 397 "settings.workspaces.updatedInfo": "A módosításokat elmentettük",
407 "settings.workspaces.workspaceFeatureHeadline": "A kevesebb több: Bemutatjuk a Ferdi Munkaterületeket", 398 "settings.workspaces.workspaceFeatureHeadline": "A kevesebb több: Bemutatjuk a Ferdi Munkaterületeket",
408 "settings.workspaces.workspaceFeatureInfo": "A Ferdi Munkaterületek lehetÅ‘vé teszik, hogy összpontosíts a jelenleg fontos dolgokra. Ãllítsd be a különbözÅ‘ szolgáltatáskészleteket és könnyedén válthatsz közöttük bármikor. Te döntöd el, hogy mely szolgáltatásokra van szükséged, mikor és hol, így segíthetünk abban, hogy a teljesítményed csúcsán maradhass, vagy ha csak akarod, egyszerűen kikapcsold a munkával kapcsolatos dolgokat.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Nem sikerült betölteni a munkaterületeket", 400 "settings.workspaces.workspacesRequestFailed": "Nem sikerült betölteni a munkaterületeket",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Értesítések és hangok engedélyezése", 411 "sidebar.unmuteApp": "Értesítések és hangok engedélyezése",
421 "signup.email.label": "Email cím", 412 "signup.email.label": "Email cím",
422 "signup.emailDuplicate": "Ezzel az e-mail címmel már létezik felhasználó", 413 "signup.emailDuplicate": "Ezzel az e-mail címmel már létezik felhasználó",
423 "signup.firstname.label": "Keresztnév", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Regisztráció", 415 "signup.headline": "Regisztráció",
425 "signup.lastname.label": "Vezetéknév", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "A Ferdi fiók létrehozásával elfogadod az", 417 "signup.legal.info": "A Ferdi fiók létrehozásával elfogadod az",
427 "signup.legal.privacy": "Adatvédelmi Nyilatkozatot", 418 "signup.legal.privacy": "Adatvédelmi Nyilatkozatot",
428 "signup.legal.terms": "Felhasználási Feltételeket", 419 "signup.legal.terms": "Felhasználási Feltételeket",
@@ -430,23 +421,23 @@
430 "signup.password.label": "Jelszó", 421 "signup.password.label": "Jelszó",
431 "signup.submit.label": "Fiók létrehozása", 422 "signup.submit.label": "Fiók létrehozása",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Szolgáltatás törlése", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Hang letiltása", 425 "tabs.item.disableAudio": "Hang letiltása",
435 "tabs.item.disableDarkMode": "Sötét mód kikapcsolása", 426 "tabs.item.disableDarkMode": "Sötét mód kikapcsolása",
436 "tabs.item.disableNotifications": "Értesítések letiltása", 427 "tabs.item.disableNotifications": "Értesítések letiltása",
437 "tabs.item.disableService": "Szolgáltatás letiltása", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Hang engedélyezése", 429 "tabs.item.enableAudio": "Hang engedélyezése",
439 "tabs.item.enableDarkMode": "Sötét mód bekapcsolása", 430 "tabs.item.enableDarkMode": "Sötét mód bekapcsolása",
440 "tabs.item.enableNotification": "Értesítések engedélyezése", 431 "tabs.item.enableNotification": "Értesítések engedélyezése",
441 "tabs.item.enableService": "Szolgáltatás engedélyezése", 432 "tabs.item.enableService": "Szolgáltatás engedélyezése",
442 "tabs.item.hibernateService": "Szlgáltatás hibernálása", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Újratöltés", 434 "tabs.item.reload": "Újratöltés",
444 "tabs.item.wakeUpService": "Szolgáltatás felébresztése", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} nem érvényes", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} mezőnek legalább {length} karakter hosszúnak kell lennie", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Legalább egy kitöltése szükséges", 438 "validation.oneRequired": "Legalább egy kitöltése szükséges",
448 "validation.required": "{field} kitöltése kötelező", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} nem érvényes URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Vissza", 441 "webControls.back": "Vissza",
451 "webControls.forward": "Előre", 442 "webControls.forward": "Előre",
452 "webControls.goHome": "Kezdőlap", 443 "webControls.goHome": "Kezdőlap",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Újratöltés", 445 "webControls.reload": "Újratöltés",
455 "welcome.loginButton": "Jelentkezz be a fiókodba", 446 "welcome.loginButton": "Jelentkezz be a fiókodba",
456 "welcome.signupButton": "Új fiók létrehozása", 447 "welcome.signupButton": "Új fiók létrehozása",
457 "workspaceDrawer.addNewWorkspaceLabel": "Munkaterület hozzáadása", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Összes szolgáltatás", 449 "workspaceDrawer.allServices": "Összes szolgáltatás",
459 "workspaceDrawer.headline": "Munkaterületek", 450 "workspaceDrawer.headline": "Munkaterületek",
460 "workspaceDrawer.item.contextMenuEdit": "szerkeszt", 451 "workspaceDrawer.item.contextMenuEdit": "szerkeszt",
461 "workspaceDrawer.item.noServicesAddedYet": "Még nincsenek hozzáadott szolgáltatások", 452 "workspaceDrawer.item.noServicesAddedYet": "Még nincsenek hozzáadott szolgáltatások",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>A Ferdi Munkaterületek lehetÅ‘vé teszik, hogy összpontosíts a jelenleg fontos dolgokra. Ãllítsd be a különbözÅ‘ szolgáltatáskészleteket és könnyedén válthatsz közöttük bármikor.</p><p>Te döntöd el, hogy mely szolgáltatásokra van szükséged, mikor és hol, így segíthetünk abban, hogy a teljesítményed csúcsán maradhass, vagy ha csak akarod, egyszerűen kikapcsold a munkával kapcsolatos dolgokat.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Munkaterület beállítások szerkesztése", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Váltás" 455 "workspaces.switchingIndicator.switchingTo": "Váltás"
465} 456}
diff --git a/src/i18n/locales/id.json b/src/i18n/locales/id.json
index 7a716a00c..5a2aa1ea7 100644
--- a/src/i18n/locales/id.json
+++ b/src/i18n/locales/id.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Muat Ulang", 2 "app.errorHandler.action": "Muat Ulang",
3 "app.errorHandler.headline": "Terjadi kesalahan", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Server khusus", 4 "changeserver.customServerLabel": "Server khusus",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Ada apa ini?", 10 "connectionLostBanner.informationLink": "Ada apa ini?",
11 "connectionLostBanner.message": "Yah! Ferdi terputus dari {name}.", 11 "connectionLostBanner.message": "Yah! Ferdi terputus dari {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Terbitkan informasi debug",
14 "feature.nightlyBuilds.activate": "Mengaktifkan", 13 "feature.nightlyBuilds.activate": "Mengaktifkan",
15 "feature.nightlyBuilds.info": "Nightly builds adalah versi eksperimen dari Ferdi yang mungkin berisi fitur-fitur yang masih kasar dan tidak lengkap. Nightly builds ini biasa digunakan untuk para developer untuk mengetes fitur-fitur terbaru mereka dan bagaimana fitur-fitur itu berjalan di versi terakhir. Jika anda tidak tahu apa yang anda lakukan, kami sarankan untuk tidak mengaktivasi nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds adalah versi eksperimen dari Ferdi yang mungkin berisi fitur-fitur yang masih kasar dan tidak lengkap. Nightly builds ini biasa digunakan untuk para developer untuk mengetes fitur-fitur terbaru mereka dan bagaimana fitur-fitur itu berjalan di versi terakhir. Jika anda tidak tahu apa yang anda lakukan, kami sarankan untuk tidak mengaktivasi nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Tidak dapat tersambung ke layanan Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Batalkan", 27 "global.cancel": "Cancel",
29 "global.edit": "Edit", 28 "global.edit": "Edit",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Anda tidak tersambung ke internet.", 30 "global.notConnectedToTheInternet": "Anda tidak tersambung ke internet.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Pengaturan", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Gunakan Bawaan Sistem ({default})", 36 "global.spellchecker.useDefault": "Gunakan Bawaan Sistem ({default})",
38 "global.spellchecking.autodetect": "Deteksi bahasa secara otomatis", 37 "global.spellchecking.autodetect": "Deteksi bahasa secara otomatis",
39 "global.spellchecking.autodetect.short": "Otomatis", 38 "global.spellchecking.autodetect.short": "Otomatis",
40 "global.spellchecking.language": "Periksa ejaan", 39 "global.spellchecking.language": "Periksa ejaan",
41 "global.submit": "Kirim", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Impor layanan Ferdi 4 Anda", 44 "import.headline": "Impor layanan Ferdi 4 Anda",
46 "import.notSupportedHeadline": "Layanan belum didukung di Ferdi 5", 45 "import.notSupportedHeadline": "Layanan belum didukung di Ferdi 5",
47 "import.skip.label": "Saya ingin menambahkan layanan secara manual", 46 "import.skip.label": "Saya ingin menambahkan layanan secara manual",
48 "import.submit.label": "Impor layanan", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Yang baru", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Mulai ulang & instal pembaruan", 50 "infobar.buttonInstallUpdate": "Mulai ulang & instal pembaruan",
52 "infobar.buttonReloadServices": "Muat ulang layanan", 51 "infobar.buttonReloadServices": "Muat ulang layanan",
53 "infobar.hide": "Sembunyikan", 52 "infobar.hide": "Sembunyikan",
@@ -75,7 +74,7 @@
75 "login.email.label": "Alamat email", 74 "login.email.label": "Alamat email",
76 "login.headline": "Masuk", 75 "login.headline": "Masuk",
77 "login.invalidCredentials": "Email atau kata sandi tidak valid", 76 "login.invalidCredentials": "Email atau kata sandi tidak valid",
78 "login.link.password": "Setel ulang sandi", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Buat akun gratis", 78 "login.link.signup": "Buat akun gratis",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "Sesi Anda telah berakhir, silakan masuk kembali.", 80 "login.serverLogout": "Sesi Anda telah berakhir, silakan masuk kembali.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Dukungan", 116 "menu.help.support": "Dukungan",
118 "menu.help.tos": "Ketentuan Layanan", 117 "menu.help.tos": "Ketentuan Layanan",
119 "menu.services": "Layanan", 118 "menu.services": "Layanan",
120 "menu.services.activatePreviousService": "Aktifkan layanan sebelumnya", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Aktifkan layanan berikutnya", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Enable Todos", 124 "menu.todos.enableTodos": "Enable Todos",
126 "menu.view": "Tampilan", 125 "menu.view": "Tampilan",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Semua layanan", 147 "menu.workspaces.defaultWorkspace": "Semua layanan",
149 "menu.workspaces.openWorkspaceDrawer": "Buka laci ruang kerja", 148 "menu.workspaces.openWorkspaceDrawer": "Buka laci ruang kerja",
150 "password.email.label": "Alamat email", 149 "password.email.label": "Alamat email",
151 "password.headline": "Setel ulang sandi", 150 "password.headline": "Reset password",
152 "password.link.login": "Masuk ke akun Anda", 151 "password.link.login": "Masuk ke akun Anda",
153 "password.link.signup": "Buat akun gratis", 152 "password.link.signup": "Buat akun gratis",
154 "password.noUser": "Tidak ditemukan pengguna dengan email tersebut", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Periksa email Anda", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Ruang kerja",
167 "service.crashHandler.action": "Muat Ulang {name}", 155 "service.crashHandler.action": "Muat Ulang {name}",
168 "service.crashHandler.autoReload": "Mencoba memulihkan {name} secara otomatis dalam {seconds} detik", 156 "service.crashHandler.autoReload": "Mencoba memulihkan {name} secara otomatis dalam {seconds} detik",
169 "service.crashHandler.headline": "Ya Ampun!", 157 "service.crashHandler.headline": "Ya Ampun!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Selamat datang di Ferdi", 171 "services.welcome": "Selamat datang di Ferdi",
184 "settings.account.account.editButton": "Edit akun", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Perbarui profil", 175 "settings.account.buttonSave": "Perbarui profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Anda menerima email dengan tautan untuk mengonfirmasi penghapusan akun. Akun dan data Anda tidak bisa dipulihkan!", 177 "settings.account.deleteEmailSent": "Anda menerima email dengan tautan untuk mengonfirmasi penghapusan akun. Akun dan data Anda tidak bisa dipulihkan!",
190 "settings.account.deleteInfo": "Jika Anda tidak membutuhkan akun Ferdi lagi, Anda bisa menghapus akun dan semua data terkait di sini.", 178 "settings.account.deleteInfo": "Jika Anda tidak membutuhkan akun Ferdi lagi, Anda bisa menghapus akun dan semua data terkait di sini.",
191 "settings.account.headline": "Akun", 179 "settings.account.headline": "Akun",
192 "settings.account.headlineAccount": "Informasi akun", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Wilayah Berbahaya", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Tagihan", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Ubah sandi", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Perbarui profil", 184 "settings.account.headlineProfile": "Perbarui profil",
197 "settings.account.successInfo": "Perubahan Anda telah disimpan", 185 "settings.account.successInfo": "Perubahan Anda telah disimpan",
198 "settings.account.tryReloadServices": "Coba lagi", 186 "settings.account.tryReloadServices": "Coba lagi",
199 "settings.account.tryReloadUserInfoRequest": "Coba lagi", 187 "settings.account.tryReloadUserInfoRequest": "Coba lagi",
200 "settings.account.userInfoRequestFailed": "Gagal memuat informasi pengguna", 188 "settings.account.userInfoRequestFailed": "Gagal memuat informasi pengguna",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Bersihkan singgahan", 191 "settings.app.buttonClearAllCache": "Bersihkan singgahan",
204 "settings.app.buttonInstallUpdate": "Mulai ulang & instal pembaruan", 192 "settings.app.buttonInstallUpdate": "Mulai ulang & instal pembaruan",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Aktifkan Mode Gelap",
224 "settings.app.form.enableGPUAcceleration": "Aktifkan Akselerasi GPU", 212 "settings.app.form.enableGPUAcceleration": "Aktifkan Akselerasi GPU",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Aktifkan pemeriksaan ejaan", 215 "settings.app.form.enableSpellchecking": "Aktifkan pemeriksaan ejaan",
228 "settings.app.form.enableSystemTray": "Tampilkan Ferdi di baki sistem", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Tampilkan tab layanan yang dinonaktifkan", 239 "settings.app.form.showDisabledServices": "Tampilkan tab layanan yang dinonaktifkan",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Tampilkan lencana pesan belum dibaca saat pemberitahuan dinonaktifkan", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Tampilkan lencana pesan belum dibaca saat pemberitahuan dinonaktifkan",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Hapus layanan", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Edit {name}", 305 "settings.service.form.editServiceHeadline": "Edit {name}",
317 "settings.service.form.enableAudio": "Aktifkan audio", 306 "settings.service.form.enableAudio": "Aktifkan audio",
318 "settings.service.form.enableBadge": "Tampilkan lencana pesan belum dibaca", 307 "settings.service.form.enableBadge": "Tampilkan lencana pesan belum dibaca",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Saat dinonaktifkan, semua suara pemberitahuan dan pemutaran audio akan dibisukan", 322 "settings.service.form.isMutedInfo": "Saat dinonaktifkan, semua suara pemberitahuan dan pemutaran audio akan dibisukan",
334 "settings.service.form.name": "Nama", 323 "settings.service.form.name": "Nama",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "Pengaturan Proxy HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "Pengaturan Proxy HTTP/HTTPS",
339 "settings.service.form.proxy.host": "Host/IP Proksi", 329 "settings.service.form.proxy.host": "Host/IP Proksi",
340 "settings.service.form.proxy.info": "Pengaturan proksi tidak akan disinkronkan dengan server Ferdi.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Gunakan Proksi", 331 "settings.service.form.proxy.isEnabled": "Gunakan Proksi",
342 "settings.service.form.proxy.password": "Sandi (opsional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Silahkan mulai ulang Ferdi setelah mengubah Setelan proxy", 334 "settings.service.form.proxy.restartInfo": "Silahkan mulai ulang Ferdi setelah mengubah Setelan proxy",
345 "settings.service.form.proxy.user": "Pengguna (opsional)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Simpan layanan", 337 "settings.service.form.saveButton": "Simpan layanan",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Temukan layanan", 344 "settings.services.discoverServices": "Temukan layanan",
355 "settings.services.headline": "Layanan Anda", 345 "settings.services.headline": "Layanan Anda",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Tidak dapat memuat layanan Anda", 348 "settings.services.servicesRequestFailed": "Tidak dapat memuat layanan Anda",
358 "settings.services.tooltip.isDisabled": "Layanan dinonaktifkan", 349 "settings.services.tooltip.isDisabled": "Layanan dinonaktifkan",
359 "settings.services.tooltip.isMuted": "Semua suara dibisukan", 350 "settings.services.tooltip.isMuted": "Semua suara dibisukan",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Nirlaba", 378 "settings.user.form.accountType.non-profit": "Nirlaba",
388 "settings.user.form.currentPassword": "Sandi saat ini", 379 "settings.user.form.currentPassword": "Sandi saat ini",
389 "settings.user.form.email": "Email", 380 "settings.user.form.email": "Email",
390 "settings.user.form.firstname": "Nama Depan", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Nama Belakang", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Sandi baru", 383 "settings.user.form.newPassword": "Sandi baru",
393 "settings.workspace.add.form.name": "Nama", 384 "settings.workspace.add.form.name": "Nama",
394 "settings.workspace.add.form.submitButton": "Buat ruang kerja", 385 "settings.workspace.add.form.submitButton": "Buat ruang kerja",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Coba lagi", 396 "settings.workspaces.tryReloadWorkspaces": "Coba lagi",
406 "settings.workspaces.updatedInfo": "Perubahan Anda telah disimpan", 397 "settings.workspaces.updatedInfo": "Perubahan Anda telah disimpan",
407 "settings.workspaces.workspaceFeatureHeadline": "Sedikit Namun Banyak: Memperkenalkan Ruang Kerja Ferdi", 398 "settings.workspaces.workspaceFeatureHeadline": "Sedikit Namun Banyak: Memperkenalkan Ruang Kerja Ferdi",
408 "settings.workspaces.workspaceFeatureInfo": "Ruang Kerja Ferdi dapat digunakan untuk tetap fokus pada hal penting saat ini. Siapkan sekelompok layanan yang berbeda dan dengan mudah beralih ke yang lain. Anda yang memutuskan layanan mana yang Anda perlukan dan kapan, agar kami bisa membantu Anda tetap berada di garis depan - atau dengan mudah mengakhiri hari kerja kapan saja Anda inginkan.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Tidak dapat memuat ruang kerja Anda", 400 "settings.workspaces.workspacesRequestFailed": "Tidak dapat memuat ruang kerja Anda",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Aktifkan pemberitahuan", 411 "sidebar.unmuteApp": "Aktifkan pemberitahuan",
421 "signup.email.label": "Alamat email", 412 "signup.email.label": "Alamat email",
422 "signup.emailDuplicate": "Pengguna dengan alamat email ini sudah ada", 413 "signup.emailDuplicate": "Pengguna dengan alamat email ini sudah ada",
423 "signup.firstname.label": "Nama Depan", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Daftar", 415 "signup.headline": "Daftar",
425 "signup.lastname.label": "Nama Belakang", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Dengan membuat akun Ferdi, Anda menyetujui", 417 "signup.legal.info": "Dengan membuat akun Ferdi, Anda menyetujui",
427 "signup.legal.privacy": "Pernyataan Privasi", 418 "signup.legal.privacy": "Pernyataan Privasi",
428 "signup.legal.terms": "Ketentuan layanan", 419 "signup.legal.terms": "Ketentuan layanan",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "Buat akun", 422 "signup.submit.label": "Buat akun",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Hapus layanan", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Nonaktifkan audio", 425 "tabs.item.disableAudio": "Nonaktifkan audio",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Nonaktifkan pemberitahuan", 427 "tabs.item.disableNotifications": "Nonaktifkan pemberitahuan",
437 "tabs.item.disableService": "Nonaktifkan layanan", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Aktifkan audio", 429 "tabs.item.enableAudio": "Aktifkan audio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Aktifkan pemberitahuan", 431 "tabs.item.enableNotification": "Aktifkan pemberitahuan",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Muat Ulang", 434 "tabs.item.reload": "Muat Ulang",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} tidak benar", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} setidaknya harus {length} karakter", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Setidaknya diperlukan satu", 438 "validation.oneRequired": "Setidaknya diperlukan satu",
448 "validation.required": "{field} wajib diisi", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} bukan URL yang benar", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Back", 441 "webControls.back": "Back",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Muat Ulang", 445 "webControls.reload": "Muat Ulang",
455 "welcome.loginButton": "Masuk ke akun Anda", 446 "welcome.loginButton": "Masuk ke akun Anda",
456 "welcome.signupButton": "Buat akun gratis", 447 "welcome.signupButton": "Buat akun gratis",
457 "workspaceDrawer.addNewWorkspaceLabel": "Tambah ruang kerja baru", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Semua layanan", 449 "workspaceDrawer.allServices": "Semua layanan",
459 "workspaceDrawer.headline": "Ruang kerja", 450 "workspaceDrawer.headline": "Ruang kerja",
460 "workspaceDrawer.item.contextMenuEdit": "edit", 451 "workspaceDrawer.item.contextMenuEdit": "edit",
461 "workspaceDrawer.item.noServicesAddedYet": "Belum ada layanan yang ditambahkan", 452 "workspaceDrawer.item.noServicesAddedYet": "Belum ada layanan yang ditambahkan",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ruang Kerja Ferdi dapat digunakan untuk tetap fokus pada hal penting saat ini. Siapkan sekelompok layanan yang berbeda dan dengan mudah beralih ke yang lain.</p><p>Anda yang memutuskan layanan mana yang Anda perlukan dan kapan, agar kami bisa membantu Anda tetap berada di garis depan - atau dengan mudah mengakhiri hari kerja kapan saja Anda inginkan.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Edit setelan ruang kerja", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Beralih ke" 455 "workspaces.switchingIndicator.switchingTo": "Beralih ke"
465} 456}
diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json
index d5539aa30..004bd2d26 100644
--- a/src/i18n/locales/it.json
+++ b/src/i18n/locales/it.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Ricarica", 2 "app.errorHandler.action": "Ricarica",
3 "app.errorHandler.headline": "Qualcosa è andato storto", 3 "app.errorHandler.headline": "Qualcosa è andato storto.",
4 "changeserver.customServerLabel": "Server personalizzato", 4 "changeserver.customServerLabel": "Server personalizzato",
5 "changeserver.headline": "Cambia Server", 5 "changeserver.headline": "Cambia Server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -9,8 +9,7 @@
9 "connectionLostBanner.cta": "Ricarica Servizio", 9 "connectionLostBanner.cta": "Ricarica Servizio",
10 "connectionLostBanner.informationLink": "Cos'è successo?", 10 "connectionLostBanner.informationLink": "Cos'è successo?",
11 "connectionLostBanner.message": "Oh no! Ferdi ha perso la connessione con {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi ha perso la connessione con {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Accedi",
13 "feature.debugger.title": "Pubblica informazioni di debug",
14 "feature.nightlyBuilds.activate": "Attivato", 13 "feature.nightlyBuilds.activate": "Attivato",
15 "feature.nightlyBuilds.info": "Le 'Nightly Builds' sono versioni sperimentali di Ferdi che possono contenere funzionalità incomplete o non perfettamente funzionanti. Queste versioni sono principalmente usate dagli sviluppatori per effettuare dei test sulle nuove caratteristiche e verificare come si integrano nella versione finale di Ferdi. Se non sei sicuro di quello che stai facendo, ti consigliamo di non attivare le 'Nightly Builds'.", 14 "feature.nightlyBuilds.info": "Le 'Nightly Builds' sono versioni sperimentali di Ferdi che possono contenere funzionalità incomplete o non perfettamente funzionanti. Queste versioni sono principalmente usate dagli sviluppatori per effettuare dei test sulle nuove caratteristiche e verificare come si integrano nella versione finale di Ferdi. Se non sei sicuro di quello che stai facendo, ti consigliamo di non attivare le 'Nightly Builds'.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -30,9 +29,9 @@
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Non sei connesso a Internet.", 30 "global.notConnectedToTheInternet": "Non sei connesso a Internet.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Quit", 32 "global.quit": "Esci",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Sei sicuro di voler uscire da Ferdi?",
35 "global.save": "Save", 34 "global.save": "Salva",
36 "global.settings": "Impostazioni", 35 "global.settings": "Impostazioni",
37 "global.spellchecker.useDefault": "Usa le impostazioni predefinite di sistema ({default})", 36 "global.spellchecker.useDefault": "Usa le impostazioni predefinite di sistema ({default})",
38 "global.spellchecking.autodetect": "Rileva automaticamente la lingua", 37 "global.spellchecking.autodetect": "Rileva automaticamente la lingua",
@@ -41,11 +40,11 @@
41 "global.submit": "Invia", 40 "global.submit": "Invia",
42 "global.userAgentHelp": "Usa 'https://whatmyuseragent.com/' (per scoprire) o 'https://developers.whatismybrowser.com/useragents/explore/' (per scegliere) il tuo user agent desiderato e copialo qui.", 41 "global.userAgentHelp": "Usa 'https://whatmyuseragent.com/' (per scoprire) o 'https://developers.whatismybrowser.com/useragents/explore/' (per scegliere) il tuo user agent desiderato e copialo qui.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Si",
45 "import.headline": "Importa i servizi di Ferdi 4", 44 "import.headline": "Importa i servizi di Ferdi 4",
46 "import.notSupportedHeadline": "Servizi non ancora supportati in Ferdi 5", 45 "import.notSupportedHeadline": "Servizi non ancora supportati in Ferdi 5",
47 "import.skip.label": "Voglio aggiungere i servizi manualmente", 46 "import.skip.label": "Voglio aggiungere i servizi manualmente",
48 "import.submit.label": "Importa servizi", 47 "import.submit.label": "Importa {count} servizi",
49 "infobar.authRequestFailed": "Si sono verificati errori durante il tentativo di eseguire una richiesta autenticata. Si prega di provare a disconnettersi e tornare indietro se questo errore persiste.", 48 "infobar.authRequestFailed": "Si sono verificati errori durante il tentativo di eseguire una richiesta autenticata. Si prega di provare a disconnettersi e tornare indietro se questo errore persiste.",
50 "infobar.buttonChangelog": "Cosa c'è di nuovo?", 49 "infobar.buttonChangelog": "Cosa c'è di nuovo?",
51 "infobar.buttonInstallUpdate": "Riavvia e installa l'aggiornamento", 50 "infobar.buttonInstallUpdate": "Riavvia e installa l'aggiornamento",
@@ -87,30 +86,30 @@
87 "menu.app.autohideMenuBar": "Nascondi automaticamente la barra del menù", 86 "menu.app.autohideMenuBar": "Nascondi automaticamente la barra del menù",
88 "menu.app.checkForUpdates": "Controlla aggiornamenti", 87 "menu.app.checkForUpdates": "Controlla aggiornamenti",
89 "menu.app.hide": "Nascondi", 88 "menu.app.hide": "Nascondi",
90 "menu.app.hideOthers": "Hide Others", 89 "menu.app.hideOthers": "Nascondi altri",
91 "menu.app.unhide": "Unhide", 90 "menu.app.unhide": "Mostra",
92 "menu.edit": "Modifica", 91 "menu.edit": "Modifica",
93 "menu.edit.copy": "Copy", 92 "menu.edit.copy": "Copia",
94 "menu.edit.cut": "Cut", 93 "menu.edit.cut": "Taglia",
95 "menu.edit.delete": "Elimina", 94 "menu.edit.delete": "Elimina",
96 "menu.edit.emojiSymbols": "Emoji e simboli", 95 "menu.edit.emojiSymbols": "Emoji e simboli",
97 "menu.edit.findInPage": "Trova nella pagina", 96 "menu.edit.findInPage": "Trova nella pagina",
98 "menu.edit.paste": "Paste", 97 "menu.edit.paste": "Incolla",
99 "menu.edit.pasteAndMatchStyle": "Paste And Match Style", 98 "menu.edit.pasteAndMatchStyle": "Incolla e abbina stile",
100 "menu.edit.redo": "Redo", 99 "menu.edit.redo": "Ripeti",
101 "menu.edit.selectAll": "Select All", 100 "menu.edit.selectAll": "Seleziona Tutto",
102 "menu.edit.speech": "Sintesi Vocale", 101 "menu.edit.speech": "Sintesi Vocale",
103 "menu.edit.startDictation": "Avvia Dettatura", 102 "menu.edit.startDictation": "Avvia Dettatura",
104 "menu.edit.startSpeaking": "Avvia Pronuncia", 103 "menu.edit.startSpeaking": "Avvia Pronuncia",
105 "menu.edit.stopSpeaking": "Interrompi Pronuncia", 104 "menu.edit.stopSpeaking": "Interrompi Pronuncia",
106 "menu.edit.undo": "Undo", 105 "menu.edit.undo": "Annulla",
107 "menu.file": "File", 106 "menu.file": "File",
108 "menu.help": "Help", 107 "menu.help": "Aiuto",
109 "menu.help.changelog": "Changelog", 108 "menu.help.changelog": "Changelog",
110 "menu.help.debugInfo": "Copia informazioni di debug", 109 "menu.help.debugInfo": "Copia informazioni di debug",
111 "menu.help.debugInfoCopiedBody": "Le tue informazioni di debug sono state copiate nella tua clipboard.", 110 "menu.help.debugInfoCopiedBody": "Le tue informazioni di debug sono state copiate nella tua clipboard.",
112 "menu.help.debugInfoCopiedHeadline": "Informazioni di debug di Ferdi", 111 "menu.help.debugInfoCopiedHeadline": "Informazioni di debug di Ferdi",
113 "menu.help.importExportData": "Import/Export Configuration Data", 112 "menu.help.importExportData": "Importa/Esporta Dati Di Configurazione",
114 "menu.help.learnMore": "Maggiori Informazioni", 113 "menu.help.learnMore": "Maggiori Informazioni",
115 "menu.help.privacy": "Dichiarazione della Privacy", 114 "menu.help.privacy": "Dichiarazione della Privacy",
116 "menu.help.publishDebugInfo": "Pubblica le informazioni di debug", 115 "menu.help.publishDebugInfo": "Pubblica le informazioni di debug",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Termini di Servizio", 117 "menu.help.tos": "Termini di Servizio",
119 "menu.services": "Servizi", 118 "menu.services": "Servizi",
120 "menu.services.activatePreviousService": "Attiva servizio precedente", 119 "menu.services.activatePreviousService": "Attiva servizio precedente",
121 "menu.services.addNewService": "Aggiungi un Nuovo Servizio", 120 "menu.services.addNewService": "Aggiungi nuovo servizio...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Attiva servizio seguente", 122 "menu.services.setNextServiceActive": "Attiva servizio seguente",
124 "menu.todos": "Todo", 123 "menu.todos": "Todo",
@@ -128,20 +127,20 @@
128 "menu.view.forward": "Avanti", 127 "menu.view.forward": "Avanti",
129 "menu.view.lockFerdi": "Blocca Ferdi", 128 "menu.view.lockFerdi": "Blocca Ferdi",
130 "menu.view.openQuickSwitch": "Apri Cambio Rapido", 129 "menu.view.openQuickSwitch": "Apri Cambio Rapido",
131 "menu.view.reloadFerdi": "Reload Ferdi", 130 "menu.view.reloadFerdi": "Ricarica Ferdi",
132 "menu.view.reloadService": "Ricarica Servizio", 131 "menu.view.reloadService": "Ricarica Servizio",
133 "menu.view.reloadTodos": "Ricarica ToDos", 132 "menu.view.reloadTodos": "Ricarica ToDos",
134 "menu.view.resetZoom": "Actual Size", 133 "menu.view.resetZoom": "Dimensione attuale",
135 "menu.view.toggleDarkMode": "Attiva la modalità scura", 134 "menu.view.toggleDarkMode": "Attiva la modalità scura",
136 "menu.view.toggleDevTools": "Attiva/Disattiva Strumenti Sviluppo", 135 "menu.view.toggleDevTools": "Attiva/Disattiva Strumenti Sviluppo",
137 "menu.view.toggleFullScreen": "Toggle Full Screen", 136 "menu.view.toggleFullScreen": "Attiva/Disattiva Schermo Intero",
138 "menu.view.toggleServiceDevTools": "Attiva/Disattiva Strumenti per Sviluppatori di Servizi", 137 "menu.view.toggleServiceDevTools": "Attiva/Disattiva Strumenti per Sviluppatori di Servizi",
139 "menu.view.toggleTodosDevTools": "Attiva/Disattiva gli strumenti di sviluppo delle Attività", 138 "menu.view.toggleTodosDevTools": "Attiva/Disattiva gli strumenti di sviluppo delle Attività",
140 "menu.view.zoomIn": "Zoom In", 139 "menu.view.zoomIn": "Aumenta zoom",
141 "menu.view.zoomOut": "Zoom Out", 140 "menu.view.zoomOut": "Diminuisci Zoom",
142 "menu.window": "Window", 141 "menu.window": "Finestra",
143 "menu.window.close": "Close", 142 "menu.window.close": "Chiudi",
144 "menu.window.minimize": "Minimize", 143 "menu.window.minimize": "Riduzione a icona",
145 "menu.workspaces": "Aree di lavoro", 144 "menu.workspaces": "Aree di lavoro",
146 "menu.workspaces.addNewWorkspace": "Aggiungi un'area di lavoro...", 145 "menu.workspaces.addNewWorkspace": "Aggiungi un'area di lavoro...",
147 "menu.workspaces.closeWorkspaceDrawer": "Chiudi il menu dei workspace", 146 "menu.workspaces.closeWorkspaceDrawer": "Chiudi il menu dei workspace",
@@ -152,18 +151,7 @@
152 "password.link.login": "Accedi al tuo account", 151 "password.link.login": "Accedi al tuo account",
153 "password.link.signup": "Crea un account gratuito", 152 "password.link.signup": "Crea un account gratuito",
154 "password.noUser": "Non è stato trovato nessun utente con questo indirizzo email", 153 "password.noUser": "Non è stato trovato nessun utente con questo indirizzo email",
155 "password.successInfo": "Per favore controlla la tua email", 154 "password.successInfo": "Una nuova password è stata inviata al tuo indirizzo email",
156 "pricing.features.accountSync": "Sincronizzazione account",
157 "pricing.features.customWebsites": "Aggiungi siti web personalizzati",
158 "pricing.features.desktopNotifications": "Notifiche desktop",
159 "pricing.features.onPremise": "Servizi ospitati & on-premise",
160 "pricing.features.recipes": "Scegli tra più di 70 Servizi",
161 "pricing.features.serviceProxies": "Proxy di servizio",
162 "pricing.features.spellchecker": "Supporto per il correttore ortografico",
163 "pricing.features.teamManagement": "Gestione del team",
164 "pricing.features.thirdPartyServices": "Installa servizi di terze parti",
165 "pricing.features.unlimitedServices": "Aggiungi servizi illimitati",
166 "pricing.features.workspaces": "Aree di lavoro",
167 "service.crashHandler.action": "Ricarica {name}", 155 "service.crashHandler.action": "Ricarica {name}",
168 "service.crashHandler.autoReload": "Tentativo di ripristino automatico di {name} in {seconds} secondi", 156 "service.crashHandler.autoReload": "Tentativo di ripristino automatico di {name} in {seconds} secondi",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -178,7 +166,7 @@
178 "service.webviewLoader.loading": "Caricamento {service}", 166 "service.webviewLoader.loading": "Caricamento {service}",
179 "services.getStarted": "Iniziamo", 167 "services.getStarted": "Iniziamo",
180 "services.login": "Effettua il login per utlizzare Ferdi.", 168 "services.login": "Effettua il login per utlizzare Ferdi.",
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Facoltativamente, puoi cambiare il tuo server Ferdi cliccando l'ingranaggio nell'angolo in basso a sinistra. Se stai passando (da uno dei server ospitati) ad usare Ferdi senza un account, sappi che puoi esportare i tuoi dati da quel server e successivamente importarli usando il menu Aiuto per ripristinare tutti i tuoi spazi di lavoro e servizi configurati!",
182 "services.serverless": "Usa Ferdi senza account", 170 "services.serverless": "Usa Ferdi senza account",
183 "services.welcome": "Benvenuto su Ferdi", 171 "services.welcome": "Benvenuto su Ferdi",
184 "settings.account.account.editButton": "Modifica account", 172 "settings.account.account.editButton": "Modifica account",
@@ -198,12 +186,12 @@
198 "settings.account.tryReloadServices": "Riprova", 186 "settings.account.tryReloadServices": "Riprova",
199 "settings.account.tryReloadUserInfoRequest": "Riprova", 187 "settings.account.tryReloadUserInfoRequest": "Riprova",
200 "settings.account.userInfoRequestFailed": "Impossibile caricare le informazioni dell'utente.", 188 "settings.account.userInfoRequestFailed": "Impossibile caricare le informazioni dell'utente.",
201 "settings.account.yourLicense": "La tua licenza Ferdi", 189 "settings.account.yourLicense": "La tua licenza Ferdi:",
202 "settings.app.accentColorInfo": "Inserisci il tuo colore in risalto in un formato compatibile con CSS. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Inserisci il tuo colore in risalto in un formato compatibile con CSS. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Svuota la cache", 191 "settings.app.buttonClearAllCache": "Svuota la cache",
204 "settings.app.buttonInstallUpdate": "Riavvia e installa l'aggiornamento", 192 "settings.app.buttonInstallUpdate": "Riavvia e installa l'aggiornamento",
205 "settings.app.buttonOpenFerdiProfileFolder": "Open Profile folder", 193 "settings.app.buttonOpenFerdiProfileFolder": "Apri cartella del profilo utente",
206 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open Service Recipes folder", 194 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Apri cartella ricette dei servizi",
207 "settings.app.buttonSearchForUpdate": "Controlla aggiornamenti", 195 "settings.app.buttonSearchForUpdate": "Controlla aggiornamenti",
208 "settings.app.cacheInfo": "Ferdi sta utilizzando {size} di spazio su disco.", 196 "settings.app.cacheInfo": "Ferdi sta utilizzando {size} di spazio su disco.",
209 "settings.app.cacheNotCleared": "Impossibile eliminare tutta la cache", 197 "settings.app.cacheNotCleared": "Impossibile eliminare tutta la cache",
@@ -218,14 +206,14 @@
218 "settings.app.form.beta": "Includi versioni beta", 206 "settings.app.form.beta": "Includi versioni beta",
219 "settings.app.form.clipboardNotifications": "Non mostrare notifiche per eventi dagli appunti", 207 "settings.app.form.clipboardNotifications": "Non mostrare notifiche per eventi dagli appunti",
220 "settings.app.form.closeToSystemTray": "Chiudi Ferdi nell'area di notifica", 208 "settings.app.form.closeToSystemTray": "Chiudi Ferdi nell'area di notifica",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Conferma quando esci da Ferdi",
222 "settings.app.form.customTodoServer": "Server Todo personalizzato", 210 "settings.app.form.customTodoServer": "Server Todo personalizzato",
223 "settings.app.form.darkMode": "Attiva modalità scura", 211 "settings.app.form.darkMode": "Attiva la modalità scura.",
224 "settings.app.form.enableGPUAcceleration": "Attiva Accelerazione GPU", 212 "settings.app.form.enableGPUAcceleration": "Attiva Accelerazione GPU",
225 "settings.app.form.enableLock": "Abilita blocco con password", 213 "settings.app.form.enableLock": "Abilita blocco con password",
226 "settings.app.form.enableMenuBar": "Mostra sempre Ferdi nella barra dei menù", 214 "settings.app.form.enableMenuBar": "Mostra sempre Ferdi nella barra dei menù",
227 "settings.app.form.enableSpellchecking": "Attiva controllo ortografico", 215 "settings.app.form.enableSpellchecking": "Attiva controllo ortografico",
228 "settings.app.form.enableSystemTray": "Mostra Ferdi nell'area di notifica", 216 "settings.app.form.enableSystemTray": "Mostra sempre icona Ferdi in area di notifica",
229 "settings.app.form.enableTodos": "Abilità le Attività Ferdi", 217 "settings.app.form.enableTodos": "Abilità le Attività Ferdi",
230 "settings.app.form.hibernateOnStartup": "Mantieni i servizi in ibernazione all'avvio", 218 "settings.app.form.hibernateOnStartup": "Mantieni i servizi in ibernazione all'avvio",
231 "settings.app.form.hibernationStrategy": "Strategia di ibernazione", 219 "settings.app.form.hibernationStrategy": "Strategia di ibernazione",
@@ -251,11 +239,12 @@
251 "settings.app.form.showDisabledServices": "Mostra schede servizi disattivati", 239 "settings.app.form.showDisabledServices": "Mostra schede servizi disattivati",
252 "settings.app.form.showDragArea": "Mostra area trascinabile nella finestra", 240 "settings.app.form.showDragArea": "Mostra area trascinabile nella finestra",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Mostra l'etichetta dei messaggi non letti quando le notifiche sono disattivate", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Mostra l'etichetta dei messaggi non letti quando le notifiche sono disattivate",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Avvio ridotto a icona", 243 "settings.app.form.startMinimized": "Avvio ridotto a icona",
255 "settings.app.form.universalDarkMode": "Abilita la modalità scura universale", 244 "settings.app.form.universalDarkMode": "Abilita la modalità scura universale",
256 "settings.app.form.useTouchIdToUnlock": "Consenti l'utilizzo di TouchID per sbloccare Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Consenti l'utilizzo di TouchID per sbloccare Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Usa stile orizzontale",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Strategia di risveglio",
259 "settings.app.headlineAdvanced": "Avanzate", 248 "settings.app.headlineAdvanced": "Avanzate",
260 "settings.app.headlineAppearance": "Aspetto", 249 "settings.app.headlineAppearance": "Aspetto",
261 "settings.app.headlineGeneral": "Generale", 250 "settings.app.headlineGeneral": "Generale",
@@ -265,17 +254,17 @@
265 "settings.app.hibernateInfo": "Per impostazione predefinita, Ferdi manterrà tutti i servizi aperti e caricati in background in modo che siano pronti quando si desidera utilizzarli. Il servizio Hibernation sospenderà i servizi dopo un tempo specificato. Questo è utile per risparmiare RAM o per evitare che i servizi rallentino il computer.", 254 "settings.app.hibernateInfo": "Per impostazione predefinita, Ferdi manterrà tutti i servizi aperti e caricati in background in modo che siano pronti quando si desidera utilizzarli. Il servizio Hibernation sospenderà i servizi dopo un tempo specificato. Questo è utile per risparmiare RAM o per evitare che i servizi rallentino il computer.",
266 "settings.app.inactivityLockInfo": "Minuti di inattività oltre i quali Ferdi si bloccherà automaticamente, 0 per disabilitare", 255 "settings.app.inactivityLockInfo": "Minuti di inattività oltre i quali Ferdi si bloccherà automaticamente, 0 per disabilitare",
267 "settings.app.languageDisclaimer": "Le traduzioni ufficiali sono in Inglese e Tedesco. Tutte le altre lingue sono tradotte dalla community.", 256 "settings.app.languageDisclaimer": "Le traduzioni ufficiali sono in Inglese e Tedesco. Tutte le altre lingue sono tradotte dalla community.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock ti permette di mantenere i tuoi messaggi protetti. Usando Password Lock, ti verrà richiesto di inserire la tua password ogni volta che avvii Ferdi o di bloccare Ferdi stesso usando il simbolo del lucchetto nell'angolo in basso a sinistra o la scorciatoia {lockShortcut}.",
269 "settings.app.lockedPassword": "Password", 258 "settings.app.lockedPassword": "Password",
270 "settings.app.lockedPasswordInfo": "Assicurati di impostare una password che ricordi.\nSe perdi questa password, dovrai reinstallare Ferdi.", 259 "settings.app.lockedPasswordInfo": "Assicurati di impostare una password che ricordi.\nSe perdi questa password, dovrai reinstallare Ferdi.",
271 "settings.app.restartRequired": "Le modifiche richiedono un riavvio", 260 "settings.app.restartRequired": "Le modifiche richiedono un riavvio",
272 "settings.app.scheduledDNDInfo": "I Do-not-Disturb pianificati consentono di definire un periodo di tempo nel quale le notifiche da Ferdi saranno disabilitate.", 261 "settings.app.scheduledDNDInfo": "I Do-not-Disturb pianificati consentono di definire un periodo di tempo nel quale le notifiche da Ferdi saranno disabilitate.",
273 "settings.app.scheduledDNDTimeInfo": "Ora in formato 24 ore. L'ora di fine può essere prima dell'ora di inizio (ad esempio inizio 17:00, fine 09:00) per abilitare Do-not-Disturb durante la notte.", 262 "settings.app.scheduledDNDTimeInfo": "Ora in formato 24 ore. L'ora di fine può essere prima dell'ora di inizio (ad esempio inizio 17:00, fine 09:00) per abilitare Do-not-Disturb durante la notte.",
274 "settings.app.sentryInfo": "Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!", 263 "settings.app.sentryInfo": "L'invio dei dati di telemetria ci permette di trovare errori in Ferdi - non invieremo nessuna informazione personale come i dati del tuo messaggio!",
275 "settings.app.spellCheckerLanguageInfo": "Ferdi utilizza il controllo ortografico del tuo Mac per verificare la presenza di errori. Se si desidera modificare le lingue del controllo ortografico, è possibile farlo nelle preferenze di sistema del vostro Mac.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi utilizza il controllo ortografico del tuo Mac per verificare la presenza di errori. Se si desidera modificare le lingue del controllo ortografico, è possibile farlo nelle preferenze di sistema del vostro Mac.",
276 "settings.app.subheadlineCache": "Cache", 265 "settings.app.subheadlineCache": "Cache",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Profilo Ferdi",
278 "settings.app.todoServerInfo": "Questo server verrà usato per le funzionalità 'Ferdi Todo'.", 267 "settings.app.todoServerInfo": "Questo server sarà utilizzato per la funzione \"Ferdi Todo\".",
279 "settings.app.translationHelp": "Aiutaci a tradurre Ferdi nella tua lingua.", 268 "settings.app.translationHelp": "Aiutaci a tradurre Ferdi nella tua lingua.",
280 "settings.app.universalDarkModeInfo": "La modalità 'Dark Mode' universale cerca di generare dinamicamente uno stile di visualizzazione a sfondo scuro per quei servizi che non lo supportano nativamente.", 269 "settings.app.universalDarkModeInfo": "La modalità 'Dark Mode' universale cerca di generare dinamicamente uno stile di visualizzazione a sfondo scuro per quei servizi che non lo supportano nativamente.",
281 "settings.app.updateStatusAvailable": "Aggiornamento disponibile, download in corso...", 270 "settings.app.updateStatusAvailable": "Aggiornamento disponibile, download in corso...",
@@ -294,12 +283,12 @@
294 "settings.recipes.customService.headline.communityRecipes": "'Recipe' (istruzioni) per applicazioni di terze parti della community", 283 "settings.recipes.customService.headline.communityRecipes": "'Recipe' (istruzioni) per applicazioni di terze parti della community",
295 "settings.recipes.customService.headline.customRecipes": "'Recipe' (istruzioni) per applicazioni di terze parti personalizzate", 284 "settings.recipes.customService.headline.customRecipes": "'Recipe' (istruzioni) per applicazioni di terze parti personalizzate",
296 "settings.recipes.customService.headline.devRecipes": "Le tue 'Recipe' (istruzioni) per applicazioni", 285 "settings.recipes.customService.headline.devRecipes": "Le tue 'Recipe' (istruzioni) per applicazioni",
297 "settings.recipes.customService.intro": "Per aggiungere un servizio personalizzato copia la sua 'recipe' (istruzioni) in:", 286 "settings.recipes.customService.intro": "Per aggiungere un servizio personalizzato copia la sua 'recipe' in:",
298 "settings.recipes.customService.openDevDocs": "Documentazione per sviluppatori", 287 "settings.recipes.customService.openDevDocs": "Documentazione per sviluppatori",
299 "settings.recipes.customService.openFolder": "Apri cartella", 288 "settings.recipes.customService.openFolder": "Apri cartella",
300 "settings.recipes.headline": "Servizi disponibili", 289 "settings.recipes.headline": "Servizi disponibili",
301 "settings.recipes.missingService": "Manca un servizio?", 290 "settings.recipes.missingService": "Manca un servizio?",
302 "settings.recipes.nothingFound": "Ci scusiamo, ma nessun servizio corrisponde ai tuoi termini di ricerca - tuttavia è probabile che tu possa aggiungerlo in ogni caso utilizzando l'opzione \"Sito Web Personalizzato\". Ti informiamo che il sito web ufficiale potrebbe mostrare un numero maggiore di servizi rispetto alla versione attualmente in uso. Per ottenere tali servizi, è consigliato l'aggiornamento a una versione più recente di Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
303 "settings.recipes.servicesSuccessfulAddedInfo": "Servizio aggiunto con successo", 292 "settings.recipes.servicesSuccessfulAddedInfo": "Servizio aggiunto con successo",
304 "settings.searchService": "Cerca servizio", 293 "settings.searchService": "Cerca servizio",
305 "settings.service.error.goBack": "Torna ai servizi", 294 "settings.service.error.goBack": "Torna ai servizi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Quando abilitato, un servizio verrà disattivato dopo un lasso di tempo per preservare le risorse del sistema.", 321 "settings.service.form.isHibernatedEnabledInfo": "Quando abilitato, un servizio verrà disattivato dopo un lasso di tempo per preservare le risorse del sistema.",
333 "settings.service.form.isMutedInfo": "Se disattivato, tutte le notifiche sonore e le riproduzioni audio saranno mutate", 322 "settings.service.form.isMutedInfo": "Se disattivato, tutte le notifiche sonore e le riproduzioni audio saranno mutate",
334 "settings.service.form.name": "Nome", 323 "settings.service.form.name": "Nome",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Apri 'darkmode.css'", 325 "settings.service.form.openDarkmodeCss": "Apri 'darkmode.css'",
336 "settings.service.form.openUserCss": "Apri user.css", 326 "settings.service.form.openUserCss": "Apri user.css",
337 "settings.service.form.openUserJs": "Apri il file 'user.js'", 327 "settings.service.form.openUserJs": "Apri il file 'user.js'",
338 "settings.service.form.proxy.headline": "Impostazioni Proxy HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "Impostazioni Proxy HTTP/HTTPS",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Le impostazioni proxy non verranno sincronizzate con i server Ferdi.", 330 "settings.service.form.proxy.info": "Le impostazioni proxy non saranno sincronizzate con i server Ferdi.",
341 "settings.service.form.proxy.isEnabled": "Usa un Proxy", 331 "settings.service.form.proxy.isEnabled": "Usa un Proxy",
342 "settings.service.form.proxy.password": "Password (opzionale)", 332 "settings.service.form.proxy.password": "Password (opzionale)",
343 "settings.service.form.proxy.port": "Porta", 333 "settings.service.form.proxy.port": "Porta",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Scopri servizi", 344 "settings.services.discoverServices": "Scopri servizi",
355 "settings.services.headline": "I tuoi servizi", 345 "settings.services.headline": "I tuoi servizi",
356 "settings.services.noServicesAdded": "Inizia aggiungendo un servizio.", 346 "settings.services.noServicesAdded": "Inizia aggiungendo un servizio.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Impossibile caricare il servizio", 348 "settings.services.servicesRequestFailed": "Impossibile caricare il servizio",
358 "settings.services.tooltip.isDisabled": "Il servizio è disattivato", 349 "settings.services.tooltip.isDisabled": "Il servizio è disattivato",
359 "settings.services.tooltip.isMuted": "Tutti i suoni sono disattivati", 350 "settings.services.tooltip.isMuted": "Tutti i suoni sono disattivati",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi è un'applicazione open source sviluppata dalla community.</p><p>Un ringraziamento a tutti coloro che hanno reso questo possibile:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi è un'applicazione open source sviluppata dalla community.</p><p>Un ringraziamento a tutti coloro che hanno reso questo possibile:</p>",
363 "settings.supportFerdi.bannerText": "Vuoi aiutarci a migliorare Ferdi?", 354 "settings.supportFerdi.bannerText": "Vuoi aiutarci a migliorare Ferdi?",
364 "settings.supportFerdi.headline": "Info su Ferdi", 355 "settings.supportFerdi.headline": "Info su Ferdi",
365 "settings.supportFerdi.openSurvey": "Sondaggio aperto", 356 "settings.supportFerdi.openSurvey": "Apri sondaggio",
366 "settings.supportFerdi.textDonation": "Se vuoi aiutare lo sviluppo di Ferdi con una donazione, puoi farlo", 357 "settings.supportFerdi.textDonation": "Se vuoi aiutare lo sviluppo di Ferdi con una donazione, puoi farlo",
367 "settings.supportFerdi.textDonationAnd": "e", 358 "settings.supportFerdi.textDonationAnd": "e",
368 "settings.supportFerdi.textExpenses": "Nonostante la maggior parte del lavoro sia svolto da volontari è comunque necessario pagare per la gestione di server e certificati. Essendo una comunità vogliamo essere completamente trasparenti rispetto a come raccogliamo e spendiamo fondi", 359 "settings.supportFerdi.textExpenses": "Nonostante la maggior parte del lavoro sia svolto da volontari è comunque necessario pagare per la gestione di server e certificati. Essendo una comunità vogliamo essere completamente trasparenti rispetto a come raccogliamo e spendiamo fondi",
369 "settings.supportFerdi.textGitHubSponsors": "Sponsor GitHub", 360 "settings.supportFerdi.textGitHubSponsors": "Sponsor GitHub",
370 "settings.supportFerdi.textListContributors": "Elenco dei contributori", 361 "settings.supportFerdi.textListContributors": "Elenco completo dei contributori",
371 "settings.supportFerdi.textListContributorsHere": "qui", 362 "settings.supportFerdi.textListContributorsHere": "qui",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Il tuo supporto è il benvenuto. Puoi trovare un elenco degli aiuti che ci servono", 364 "settings.supportFerdi.textSupportWelcome": "Il tuo supporto è il benvenuto. Puoi trovare un elenco degli aiuti che ci servono",
@@ -377,7 +368,7 @@
377 "settings.team.contentHeadline": "Franz Team Management", 368 "settings.team.contentHeadline": "Franz Team Management",
378 "settings.team.copy": "Il gestore di Team di Franz (Franz's Team Management) ti consente di gestire gli abbonamenti Franz (Franz Subscriptions) per più utenti. È importante ricordare che possedere un abbonamento Premium Franz non dà alcun beneficio nell'usare Ferdi. L'unico motivo per cui hai accesso al gestore di Team è perchè tu posa gestire i tuoi Team di Franz creati in precedenza così da non perdere alcuna funzionalità nella gestione del tuo account.", 369 "settings.team.copy": "Il gestore di Team di Franz (Franz's Team Management) ti consente di gestire gli abbonamenti Franz (Franz Subscriptions) per più utenti. È importante ricordare che possedere un abbonamento Premium Franz non dà alcun beneficio nell'usare Ferdi. L'unico motivo per cui hai accesso al gestore di Team è perchè tu posa gestire i tuoi Team di Franz creati in precedenza così da non perdere alcuna funzionalità nella gestione del tuo account.",
379 "settings.team.headline": "Gruppo", 370 "settings.team.headline": "Gruppo",
380 "settings.team.intro": "You are currently using Franz Servers, which is why you have access to Team Management.", 371 "settings.team.intro": "Attualmente stai usando server di Franz, ed è per questo che hai accesso al Team Management.",
381 "settings.team.manageAction": "Gestisci i tuoi Team su meetfranz.com", 372 "settings.team.manageAction": "Gestisci i tuoi Team su meetfranz.com",
382 "settings.team.teamsUnavailable": "I Teams non sono disponibili", 373 "settings.team.teamsUnavailable": "I Teams non sono disponibili",
383 "settings.team.teamsUnavailableInfo": "I Team sono disponibili esclusivamente usando Franz Server e dopo aver attivato Franz Professional (a pagamento). Per poter utilizzare i Team è necessario modificare il server in https://api.franzinfra.com.", 374 "settings.team.teamsUnavailableInfo": "I Team sono disponibili esclusivamente usando Franz Server e dopo aver attivato Franz Professional (a pagamento). Per poter utilizzare i Team è necessario modificare il server in https://api.franzinfra.com.",
@@ -432,20 +423,20 @@
432 "tabs.item.confirmDeleteService": "Vuoi davvero eliminare il servizio {serviceName}?", 423 "tabs.item.confirmDeleteService": "Vuoi davvero eliminare il servizio {serviceName}?",
433 "tabs.item.deleteService": "Elimina servizio", 424 "tabs.item.deleteService": "Elimina servizio",
434 "tabs.item.disableAudio": "Disattiva audio", 425 "tabs.item.disableAudio": "Disattiva audio",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disattiva modalità scura",
436 "tabs.item.disableNotifications": "Disattiva notifiche", 427 "tabs.item.disableNotifications": "Disattiva notifiche",
437 "tabs.item.disableService": "Disattiva servizio", 428 "tabs.item.disableService": "Disattiva servizio",
438 "tabs.item.enableAudio": "Attiva audio", 429 "tabs.item.enableAudio": "Attiva audio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Attiva modalità scura",
440 "tabs.item.enableNotification": "Attiva le notifiche", 431 "tabs.item.enableNotification": "Attiva le notifiche",
441 "tabs.item.enableService": "Attiva il servizio", 432 "tabs.item.enableService": "Attiva il servizio",
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Iberna servizio",
443 "tabs.item.reload": "Ricarica", 434 "tabs.item.reload": "Ricarica",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Risveglia servizio",
445 "validation.email": "{field} non valido", 436 "validation.email": "{field} non valido",
446 "validation.minLength": "{field} dovrebbe contenere almeno {length} caratteri", 437 "validation.minLength": "{field} dovrebbe contenere almeno {length} caratteri",
447 "validation.oneRequired": "Almeno un campo è richiesto", 438 "validation.oneRequired": "Almeno un campo è richiesto",
448 "validation.required": "{field} è necessario", 439 "validation.required": "{field} è obbligatorio",
449 "validation.url": "{field} non è un URL valido", 440 "validation.url": "{field} non è un URL valido",
450 "webControls.back": "Indietro", 441 "webControls.back": "Indietro",
451 "webControls.forward": "Avanti", 442 "webControls.forward": "Avanti",
@@ -459,7 +450,7 @@
459 "workspaceDrawer.headline": "Aree di lavoro", 450 "workspaceDrawer.headline": "Aree di lavoro",
460 "workspaceDrawer.item.contextMenuEdit": "Modifica", 451 "workspaceDrawer.item.contextMenuEdit": "Modifica",
461 "workspaceDrawer.item.noServicesAddedYet": "Nessun servizio aggiunto", 452 "workspaceDrawer.item.noServicesAddedYet": "Nessun servizio aggiunto",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>I workspace di Ferdi ti permettono di concentrarti su ciò che è importante. Configura diversi insiemi di servizi e passa facilmente da uno all’altro quando vuoi.</p><p>Decidi di quali servizi hai bisogno quando e dove, così che ti possiamo aiutare a dare sempre il massimo - o semplicemente staccare dal lavoro quando ne hai bisogno.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Le aree di lavoro di Ferdi ti permettono di concentrarti su ciò che è importante. Configura diversi insiemi di servizi e passa facilmente da uno all’altro quando vuoi.</p><p> Decidi di quali servizi hai bisogno quando e dove, così che ti possiamo aiutare a dare sempre il massimo - o semplicemente staccare dal lavoro quando ne hai bisogno.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Modifica le impostazioni dei workspace", 454 "workspaceDrawer.workspacesSettingsTooltip": "Modifica le impostazioni dell'area di lavoro",
464 "workspaces.switchingIndicator.switchingTo": "Passa a " 455 "workspaces.switchingIndicator.switchingTo": "Passa a "
465} 456}
diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json
index 118a2fb8e..d07ed53af 100644
--- a/src/i18n/locales/ja.json
+++ b/src/i18n/locales/ja.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "å†èª­ã¿è¾¼ã¿", 2 "app.errorHandler.action": "å†èª­ã¿è¾¼ã¿",
3 "app.errorHandler.headline": "é–“é•ãˆã¦ãる部分ãŒãã‚Šã¾ã™", 3 "app.errorHandler.headline": "åé¡ŒãŒç™ºç”Ÿãã¾ããŸã‚",
4 "changeserver.customServerLabel": "独自サーãƒãƒ¼", 4 "changeserver.customServerLabel": "独自サーãƒãƒ¼",
5 "changeserver.headline": "サーãƒãƒ¼ã®å¤‰æ›´", 5 "changeserver.headline": "サーãƒãƒ¼ã®å¤‰æ›´",
6 "changeserver.label": "サーãƒãƒ¼", 6 "changeserver.label": "サーãƒãƒ¼",
@@ -9,8 +9,7 @@
9 "connectionLostBanner.cta": "サービスをリロードã™ã‚‹", 9 "connectionLostBanner.cta": "サービスをリロードã™ã‚‹",
10 "connectionLostBanner.informationLink": "何ãŒèµ·ãã¾ã—ãŸã‹ï¼Ÿ", 10 "connectionLostBanner.informationLink": "何ãŒèµ·ãã¾ã—ãŸã‹ï¼Ÿ",
11 "connectionLostBanner.message": "{name}ã¸ã®æŽ¥ç¶šãŒåˆ‡æ–­ã•ã‚Œã¾ã—ãŸã€‚", 11 "connectionLostBanner.message": "{name}ã¸ã®æŽ¥ç¶šãŒåˆ‡æ–­ã•ã‚Œã¾ã—ãŸã€‚",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "サインイン",
13 "feature.debugger.title": "デãƒãƒƒã‚°æƒ…å ±ã®è¨˜éŒ²",
14 "feature.nightlyBuilds.activate": "有効化", 13 "feature.nightlyBuilds.activate": "有効化",
15 "feature.nightlyBuilds.info": "Nightlyビルドã¯æœªæ¤œè¨¼ã‚„未完æˆã®æ©Ÿèƒ½ãŒå«ã¾ã‚Œã‚‹éžå¸¸ã«å®Ÿé¨“çš„ãªãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™ã€‚ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯ã€ä¸»ã«æ–°æ©Ÿèƒ½ã®ãƒ†ã‚¹ãƒˆã‚„最新ビルドã§ã®æ¤œè¨¼ã‚’è¡Œã†é–‹ç™ºè€…ãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚ã“れをç†è§£ã—ã¦ã„ãªã„æ–¹ã¯ã€Nightlyビルドを有効化ã—ãªã„ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚", 14 "feature.nightlyBuilds.info": "Nightlyビルドã¯æœªæ¤œè¨¼ã‚„未完æˆã®æ©Ÿèƒ½ãŒå«ã¾ã‚Œã‚‹éžå¸¸ã«å®Ÿé¨“çš„ãªãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã™ã€‚ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯ã€ä¸»ã«æ–°æ©Ÿèƒ½ã®ãƒ†ã‚¹ãƒˆã‚„最新ビルドã§ã®æ¤œè¨¼ã‚’è¡Œã†é–‹ç™ºè€…ãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚ã“れをç†è§£ã—ã¦ã„ãªã„æ–¹ã¯ã€Nightlyビルドを有効化ã—ãªã„ã“ã¨ã‚’ãŠã™ã™ã‚ã—ã¾ã™ã€‚",
16 "feature.nightlyBuilds.title": "Nightlyビルド", 15 "feature.nightlyBuilds.title": "Nightlyビルド",
@@ -27,12 +26,12 @@
27 "global.api.unhealthy": "Ferdiã®ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã‚µãƒ¼ãƒ“スã«æŽ¥ç¶šã§ãã¾ã›ã‚“。", 26 "global.api.unhealthy": "Ferdiã®ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã‚µãƒ¼ãƒ“スã«æŽ¥ç¶šã§ãã¾ã›ã‚“。",
28 "global.cancel": "キャンセル", 27 "global.cancel": "キャンセル",
29 "global.edit": "編集", 28 "global.edit": "編集",
30 "global.no": "No", 29 "global.no": "ã„ã„ãˆ",
31 "global.notConnectedToTheInternet": "インターãƒãƒƒãƒˆã«æŽ¥ç¶šã•ã‚Œã¦ã„ã¾ã›ã‚“。", 30 "global.notConnectedToTheInternet": "インターãƒãƒƒãƒˆã«æŽ¥ç¶šã•ã‚Œã¦ã„ã¾ã›ã‚“。",
32 "global.ok": "Ok", 31 "global.ok": "ã¯ã„",
33 "global.quit": "終了", 32 "global.quit": "終了",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Ferdiを本当ã«çµ‚了ã—ã¾ã™ã‹ï¼Ÿ",
35 "global.save": "Save", 34 "global.save": "ä¿å­˜",
36 "global.settings": "設定", 35 "global.settings": "設定",
37 "global.spellchecker.useDefault": "システムデフォルトを使用ã™ã‚‹({default})", 36 "global.spellchecker.useDefault": "システムデフォルトを使用ã™ã‚‹({default})",
38 "global.spellchecking.autodetect": "言語を自動的ã«æ¤œå‡ºã™ã‚‹", 37 "global.spellchecking.autodetect": "言語を自動的ã«æ¤œå‡ºã™ã‚‹",
@@ -41,13 +40,13 @@
41 "global.submit": "é€ä¿¡", 40 "global.submit": "é€ä¿¡",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "ユーザーエージェント", 42 "global.userAgentPref": "ユーザーエージェント",
44 "global.yes": "Yes", 43 "global.yes": "ã¯ã„",
45 "import.headline": "Ferdi 4ã®ã‚µãƒ¼ãƒ“スをインãƒãƒ¼ãƒˆã—ã¦ä¸‹ã•ã„", 44 "import.headline": "Ferdi 4ã®ã‚µãƒ¼ãƒ“スをインãƒãƒ¼ãƒˆã—ã¦ä¸‹ã•ã„",
46 "import.notSupportedHeadline": "Ferdi 5ã§ã¯ã“ã®ã‚µãƒ¼ãƒ“スã«ã¾ã å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“", 45 "import.notSupportedHeadline": "Ferdi 5ã§ã¯ã“ã®ã‚µãƒ¼ãƒ“スã«ã¾ã å¯¾å¿œã—ã¦ã„ã¾ã›ã‚“",
47 "import.skip.label": "手動ã§ã‚µãƒ¼ãƒ“スを追加ã™ã‚‹", 46 "import.skip.label": "手動ã§ã‚µãƒ¼ãƒ“スを追加ã™ã‚‹",
48 "import.submit.label": "サービスをインãƒãƒ¼ãƒˆãã¦ä¸ã•ã„", 47 "import.submit.label": "{count}個ã®ã‚µãƒ¼ãƒ“スをインãƒãƒ¼ãƒˆãã‹",
49 "infobar.authRequestFailed": "èªè¨¼æ¸ˆã¿ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®å®Ÿè¡Œä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã“ã®ã‚¨ãƒ©ãƒ¼ãŒä½•åº¦ã‚‚発生ã™ã‚‹å ´åˆã¯ã€ãƒ­ã‚°ã‚¢ã‚¦ãƒˆã—ã¦å†åº¦ãŠè©¦ã—ãã ã•ã„。", 48 "infobar.authRequestFailed": "èªè¨¼æ¸ˆã¿ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®å®Ÿè¡Œä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã“ã®ã‚¨ãƒ©ãƒ¼ãŒä½•åº¦ã‚‚発生ã™ã‚‹å ´åˆã¯ã€ãƒ­ã‚°ã‚¢ã‚¦ãƒˆã—ã¦å†åº¦ãŠè©¦ã—ãã ã•ã„。",
50 "infobar.buttonChangelog": "更新履歴を見る", 49 "infobar.buttonChangelog": "æ–°ç€æƒ…å ±",
51 "infobar.buttonInstallUpdate": "å†èµ·å‹•ã—ã¦æ›´æ–°ã‚’インストールã™ã‚‹", 50 "infobar.buttonInstallUpdate": "å†èµ·å‹•ã—ã¦æ›´æ–°ã‚’インストールã™ã‚‹",
52 "infobar.buttonReloadServices": "サービスã®å†èª­ã¿è¾¼ã¿", 51 "infobar.buttonReloadServices": "サービスã®å†èª­ã¿è¾¼ã¿",
53 "infobar.hide": "éš ã™", 52 "infobar.hide": "éš ã™",
@@ -57,7 +56,7 @@
57 "infobox.dismiss": "é–‰ã˜ã‚‹", 56 "infobox.dismiss": "é–‰ã˜ã‚‹",
58 "invite.email.label": "メールアドレス", 57 "invite.email.label": "メールアドレス",
59 "invite.headline.friends": "ã‚ãªãŸã®å‹äººã‚„åŒåƒšã®æ–¹ã‚’3åã¾ã§Ferdiã«æ‹›å¾…ã§ãã¾ã™", 58 "invite.headline.friends": "ã‚ãªãŸã®å‹äººã‚„åŒåƒšã®æ–¹ã‚’3åã¾ã§Ferdiã«æ‹›å¾…ã§ãã¾ã™",
60 "invite.name.label": "æ°å", 59 "invite.name.label": "åå‰",
61 "invite.skip.label": "後ã§", 60 "invite.skip.label": "後ã§",
62 "invite.submit.label": "招待をé€ã‚‹", 61 "invite.submit.label": "招待をé€ã‚‹",
63 "invite.successInfo": "招待ã¯ç„¡äº‹ã«é€ä¿¡ã•ã‚Œã¾ã—ãŸ", 62 "invite.successInfo": "招待ã¯ç„¡äº‹ã«é€ä¿¡ã•ã‚Œã¾ã—ãŸ",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "サービス利用è¦ç´„", 117 "menu.help.tos": "サービス利用è¦ç´„",
119 "menu.services": "サービス", 118 "menu.services": "サービス",
120 "menu.services.activatePreviousService": "å‰ã®ã‚µãƒ¼ãƒ“スを有効ã«ã™ã‚‹", 119 "menu.services.activatePreviousService": "å‰ã®ã‚µãƒ¼ãƒ“スを有効ã«ã™ã‚‹",
121 "menu.services.addNewService": "サービスを追加", 120 "menu.services.addNewService": "サービスを追加...",
122 "menu.services.goHome": "ホーム", 121 "menu.services.goHome": "ホーム",
123 "menu.services.setNextServiceActive": "次ã®ã‚µãƒ¼ãƒ“スを有効ã«ã™ã‚‹", 122 "menu.services.setNextServiceActive": "次ã®ã‚µãƒ¼ãƒ“スを有効ã«ã™ã‚‹",
124 "menu.todos": "ToDo", 123 "menu.todos": "ToDo",
@@ -151,19 +150,8 @@
151 "password.headline": "パスワードをリセット", 150 "password.headline": "パスワードをリセット",
152 "password.link.login": "サインイン", 151 "password.link.login": "サインイン",
153 "password.link.signup": "無料アカウントを作æˆ", 152 "password.link.signup": "無料アカウントを作æˆ",
154 "password.noUser": "ã“ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ã¾ã ç™»éŒ²ã•ã‚Œã¦ã„ã¾ã›ã‚“", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "メールを確èªã—ã¦ä¸‹ã•ã„", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "アカウントã®åŒæœŸ",
157 "pricing.features.customWebsites": "カスタムサイトを追加",
158 "pricing.features.desktopNotifications": "デスクトップ通知",
159 "pricing.features.onPremise": "オンプレミスãŠã‚ˆã³ãã®ä»–ã®ãƒ›ã‚¹ãƒ†ã‚£ãƒ³ã‚°ã‚µãƒ¼ãƒ“ス",
160 "pricing.features.recipes": "70以上ã®ã‚µãƒ¼ãƒ“スã‹ã‚‰é¸æŠž",
161 "pricing.features.serviceProxies": "サービスプロキシ",
162 "pricing.features.spellchecker": "スペルãƒã‚§ãƒƒã‚¯ã®ã‚µãƒãƒ¼ãƒˆ",
163 "pricing.features.teamManagement": "ãƒãƒ¼ãƒ ç®¡ç†",
164 "pricing.features.thirdPartyServices": "サードパーティ製サービスをインストール",
165 "pricing.features.unlimitedServices": "無制é™ã«ã‚µãƒ¼ãƒ“スを追加",
166 "pricing.features.workspaces": "ワークスペース",
167 "service.crashHandler.action": "{name}ã‚’å†èª­ã¿è¾¼ã¿", 155 "service.crashHandler.action": "{name}ã‚’å†èª­ã¿è¾¼ã¿",
168 "service.crashHandler.autoReload": "{seconds}秒後ã€è‡ªå‹•çš„ã«{name}ã®å¾©æ—§ã‚’試ã¿ã¾ã™", 156 "service.crashHandler.autoReload": "{seconds}秒後ã€è‡ªå‹•çš„ã«{name}ã®å¾©æ—§ã‚’試ã¿ã¾ã™",
169 "service.crashHandler.headline": "ã—ã¾ã£ãŸï¼", 157 "service.crashHandler.headline": "ã—ã¾ã£ãŸï¼",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "オプションã¨ã—ã¦ã€å·¦ä¸‹ã®æ­¯è»Šã‚’クリックã—ã¦Ferdiサーãƒãƒ¼ã‚’変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ä»–ã®ãƒ›ã‚¹ãƒˆã•ã‚ŒãŸã‚µãƒ¼ãƒã‹ã‚‰ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãªã—ã§Ferdiを使ã†ã‚ˆã†ã«å¤‰æ›´ã™ã‚‹å ´åˆã¯ã€ãã®ã‚µãƒ¼ãƒã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’エクスãƒãƒ¼ãƒˆã—ã€ãã®å¾Œãƒ˜ãƒ«ãƒ—メニューを使ã£ã¦ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã“ã¨ã§ã™ã¹ã¦ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã¨è¨­å®šã—ãŸã‚µãƒ¼ãƒ“スを復元ã•ã›ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚", 169 "services.serverInfo": "オプションã¨ã—ã¦ã€å·¦ä¸‹ã®æ­¯è»Šã‚’クリックã—ã¦Ferdiサーãƒãƒ¼ã‚’変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ä»–ã®ãƒ›ã‚¹ãƒˆã•ã‚ŒãŸã‚µãƒ¼ãƒã‹ã‚‰ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãªã—ã§Ferdiを使ã†ã‚ˆã†ã«å¤‰æ›´ã™ã‚‹å ´åˆã¯ã€ãã®ã‚µãƒ¼ãƒã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’エクスãƒãƒ¼ãƒˆã—ã€ãã®å¾Œãƒ˜ãƒ«ãƒ—メニューを使ã£ã¦ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã“ã¨ã§ã™ã¹ã¦ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã¨è¨­å®šã—ãŸã‚µãƒ¼ãƒ“スを復元ã•ã›ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚",
182 "services.serverless": "アカウントãªã—ã§Ferdiを使用ã™ã‚‹", 170 "services.serverless": "アカウントãªã—ã§Ferdiを使用ã™ã‚‹",
183 "services.welcome": "Ferdiã«ã‚ˆã†ã“ã", 171 "services.welcome": "Ferdiã«ã‚ˆã†ã“ã",
184 "settings.account.account.editButton": "アカウントã®ç·¨é›†", 172 "settings.account.account.editButton": "アカウントを編集",
185 "settings.account.accountUnavailable": "アカウントãŒåˆ©ç”¨ã§ãã¾ã›ã‚“", 173 "settings.account.accountUnavailable": "アカウントãŒåˆ©ç”¨ã§ãã¾ã›ã‚“",
186 "settings.account.accountUnavailableInfo": "アカウントãªã—ã§Ferdiを使用ã—ã¦ã„ã¾ã™ã€‚ Ferdiã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’使用ã—ã¦ã‚³ãƒ³ãƒ”ューター間ã§ã‚µãƒ¼ãƒ“スをåŒæœŸã•ã›ã‚‹å ´åˆã€ 設定タブã§ã‚µãƒ¼ãƒãƒ¼ã‚’é¸æŠžã—ã¦ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。", 174 "settings.account.accountUnavailableInfo": "アカウントãªã—ã§Ferdiを使用ã—ã¦ã„ã¾ã™ã€‚ Ferdiã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’使用ã—ã¦ã‚³ãƒ³ãƒ”ューター間ã§ã‚µãƒ¼ãƒ“スをåŒæœŸã•ã›ã‚‹å ´åˆã€ 設定タブã§ã‚µãƒ¼ãƒãƒ¼ã‚’é¸æŠžã—ã¦ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。",
187 "settings.account.buttonSave": "プロフィールã®æ›´æ–°", 175 "settings.account.buttonSave": "プロフィールã®æ›´æ–°",
@@ -190,7 +178,7 @@
190 "settings.account.deleteInfo": "今後Ferdiã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒå¿…è¦ãªã‘ã‚Œã°ã€ã“ã¡ã‚‰ã§ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¨é–¢é€£ã™ã‚‹æƒ…報を削除ã§ãã¾ã™ã€‚", 178 "settings.account.deleteInfo": "今後Ferdiã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒå¿…è¦ãªã‘ã‚Œã°ã€ã“ã¡ã‚‰ã§ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¨é–¢é€£ã™ã‚‹æƒ…報を削除ã§ãã¾ã™ã€‚",
191 "settings.account.headline": "アカウント", 179 "settings.account.headline": "アカウント",
192 "settings.account.headlineAccount": "アカウント情報", 180 "settings.account.headlineAccount": "アカウント情報",
193 "settings.account.headlineDangerZone": "注æ„ï¼", 181 "settings.account.headlineDangerZone": "å±é™ºãªæ“作",
194 "settings.account.headlineInvoices": "請求書", 182 "settings.account.headlineInvoices": "請求書",
195 "settings.account.headlinePassword": "パスワードã®å¤‰æ›´", 183 "settings.account.headlinePassword": "パスワードã®å¤‰æ›´",
196 "settings.account.headlineProfile": "プロフィールã®æ›´æ–°", 184 "settings.account.headlineProfile": "プロフィールã®æ›´æ–°",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "ã‚‚ã†ä¸€åº¦è©¦ã™", 186 "settings.account.tryReloadServices": "ã‚‚ã†ä¸€åº¦è©¦ã™",
199 "settings.account.tryReloadUserInfoRequest": "ã‚‚ã†ä¸€åº¦è©¦ã™", 187 "settings.account.tryReloadUserInfoRequest": "ã‚‚ã†ä¸€åº¦è©¦ã™",
200 "settings.account.userInfoRequestFailed": "ユーザ情報を読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸ", 188 "settings.account.userInfoRequestFailed": "ユーザ情報を読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸ",
201 "settings.account.yourLicense": "ã”利用中ã®Ferdiライセンス", 189 "settings.account.yourLicense": "ã”利用中ã®Ferdiライセンス:",
202 "settings.app.accentColorInfo": "CSSフォーマットã§ã‚¢ã‚¯ã‚»ãƒ³ãƒˆã‚«ãƒ©ãƒ¼ã‚’記述ã—ã¦ãã ã•ã„。(デフォルト: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "CSSフォーマットã§ã‚¢ã‚¯ã‚»ãƒ³ãƒˆã‚«ãƒ©ãƒ¼ã‚’記述ã—ã¦ãã ã•ã„。(デフォルト: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "キャッシュを消去ã™ã‚‹", 191 "settings.app.buttonClearAllCache": "キャッシュを消去ã™ã‚‹",
204 "settings.app.buttonInstallUpdate": "å†èµ·å‹•ã—ã¦æ›´æ–°ã‚’インストールã™ã‚‹", 192 "settings.app.buttonInstallUpdate": "å†èµ·å‹•ã—ã¦æ›´æ–°ã‚’インストールã™ã‚‹",
@@ -218,14 +206,14 @@
218 "settings.app.form.beta": "Betaãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’å«ã‚ã‚‹", 206 "settings.app.form.beta": "Betaãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’å«ã‚ã‚‹",
219 "settings.app.form.clipboardNotifications": "クリップボードイベントã®é€šçŸ¥ã‚’表示ã—ãªã„", 207 "settings.app.form.clipboardNotifications": "クリップボードイベントã®é€šçŸ¥ã‚’表示ã—ãªã„",
220 "settings.app.form.closeToSystemTray": "Ferdiをシステムトレイã«é–‰ã˜ã‚‹", 208 "settings.app.form.closeToSystemTray": "Ferdiをシステムトレイã«é–‰ã˜ã‚‹",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Ferdiã®çµ‚了時ã«ç¢ºèªã™ã‚‹",
222 "settings.app.form.customTodoServer": "カスタムToDoサーãƒãƒ¼", 210 "settings.app.form.customTodoServer": "カスタムToDoサーãƒãƒ¼",
223 "settings.app.form.darkMode": "ダークモードを有効ã«ã™ã‚‹", 211 "settings.app.form.darkMode": "ダークモードを有効ã«ã™ã‚‹",
224 "settings.app.form.enableGPUAcceleration": "GPUアクセラレーションを有効ã«ã™ã‚‹", 212 "settings.app.form.enableGPUAcceleration": "GPUアクセラレーションを有効ã«ã™ã‚‹",
225 "settings.app.form.enableLock": "パスワードロックを有効ã«ã™ã‚‹", 213 "settings.app.form.enableLock": "パスワードロックを有効ã«ã™ã‚‹",
226 "settings.app.form.enableMenuBar": "Ferdi内ã«ãƒ¡ãƒ‹ãƒ¥ãƒ¼ãƒãƒ¼ã‚’常時表示ã™ã‚‹", 214 "settings.app.form.enableMenuBar": "Ferdi内ã«ãƒ¡ãƒ‹ãƒ¥ãƒ¼ãƒãƒ¼ã‚’常時表示ã™ã‚‹",
227 "settings.app.form.enableSpellchecking": "スペルãƒã‚§ãƒƒã‚¯ã‚’有効ã«ã™ã‚‹", 215 "settings.app.form.enableSpellchecking": "スペルãƒã‚§ãƒƒã‚¯ã‚’有効ã«ã™ã‚‹",
228 "settings.app.form.enableSystemTray": "Ferdiをシステムトレイã«è¡¨ç¤ºã™ã‚‹", 216 "settings.app.form.enableSystemTray": "Ferdiを常時システムトレイã«è¡¨ç¤ºã™ã‚‹",
229 "settings.app.form.enableTodos": "Ferdi ToDoを有効ã«ã™ã‚‹", 217 "settings.app.form.enableTodos": "Ferdi ToDoを有効ã«ã™ã‚‹",
230 "settings.app.form.hibernateOnStartup": "起動時ã«ã‚µãƒ¼ãƒ“スを休止状態ã«ã™ã‚‹", 218 "settings.app.form.hibernateOnStartup": "起動時ã«ã‚µãƒ¼ãƒ“スを休止状態ã«ã™ã‚‹",
231 "settings.app.form.hibernationStrategy": "休止状態ã®æ–¹æ³•", 219 "settings.app.form.hibernationStrategy": "休止状態ã®æ–¹æ³•",
@@ -251,10 +239,11 @@
251 "settings.app.form.showDisabledServices": "無効化ã•ã‚ŒãŸã‚µãƒ¼ãƒ“スã®ã‚¿ãƒ–を表示ã™ã‚‹", 239 "settings.app.form.showDisabledServices": "無効化ã•ã‚ŒãŸã‚µãƒ¼ãƒ“スã®ã‚¿ãƒ–を表示ã™ã‚‹",
252 "settings.app.form.showDragArea": "ドラッグå¯èƒ½ãªé ˜åŸŸã‚’ウィンドウã«è¡¨ç¤º", 240 "settings.app.form.showDragArea": "ドラッグå¯èƒ½ãªé ˜åŸŸã‚’ウィンドウã«è¡¨ç¤º",
253 "settings.app.form.showMessagesBadgesWhenMuted": "通知ã®ç„¡åŠ¹æ™‚ã«æœªèª­ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ä»¶æ•°ã‚’表示ã™ã‚‹", 241 "settings.app.form.showMessagesBadgesWhenMuted": "通知ã®ç„¡åŠ¹æ™‚ã«æœªèª­ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ä»¶æ•°ã‚’表示ã™ã‚‹",
242 "settings.app.form.splitMode": "分割表示モードを有効ã«ã™ã‚‹",
254 "settings.app.form.startMinimized": "最å°åŒ–ã—ã¦èµ·å‹•", 243 "settings.app.form.startMinimized": "最å°åŒ–ã—ã¦èµ·å‹•",
255 "settings.app.form.universalDarkMode": "ユニãƒãƒ¼ã‚µãƒ«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’有効ã«ã™ã‚‹", 244 "settings.app.form.universalDarkMode": "ユニãƒãƒ¼ã‚µãƒ«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’有効ã«ã™ã‚‹",
256 "settings.app.form.useTouchIdToUnlock": "Touch IDを使用ã—ã¦Ferdiã®ãƒ­ãƒƒã‚¯ã‚’解除ã™ã‚‹", 245 "settings.app.form.useTouchIdToUnlock": "Ferdiã®ãƒ­ãƒƒã‚¯ã‚’解除ã«Touch IDを使用ã§ãるよã†ã«ã™ã‚‹",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "水平レイアウトを使用ã™ã‚‹",
258 "settings.app.form.wakeUpStrategy": "起動方法", 247 "settings.app.form.wakeUpStrategy": "起動方法",
259 "settings.app.headlineAdvanced": "詳細", 248 "settings.app.headlineAdvanced": "詳細",
260 "settings.app.headlineAppearance": "表示スタイル", 249 "settings.app.headlineAppearance": "表示スタイル",
@@ -265,9 +254,9 @@
265 "settings.app.hibernateInfo": "デフォルトã§ã¯ã€Ferdiã¯ã™ã¹ã¦ã®ã‚µãƒ¼ãƒ“スをãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã§é–‹ã„ã¦èª­ã¿è¾¼ã‚“ã§ãŠãã®ã§ã€ä½¿ã„ãŸã„ã¨ãã«ã™ãã«ä½¿ãˆã¾ã™ã€‚ サービス休止機能ã¯è¨­å®šã—ãŸæ™‚é–“ãŒçµŒéŽã—ãŸã‚‰èª­ã¿è¾¼ã‚“ã ã‚µãƒ¼ãƒ“スを解放ã—ã¾ã™ã€‚ã“ã‚Œã¯RAMを節約ã—ãŸã‚Šã€ã‚µãƒ¼ãƒ“スã§ã‚³ãƒ³ãƒ”ューターã®å‹•ä½œãŒé‡ããªã‚‹ã®ã‚’防ãã®ã«å½¹ç«‹ã¡ã¾ã™ã€‚", 254 "settings.app.hibernateInfo": "デフォルトã§ã¯ã€Ferdiã¯ã™ã¹ã¦ã®ã‚µãƒ¼ãƒ“スをãƒãƒƒã‚¯ã‚°ãƒ©ã‚¦ãƒ³ãƒ‰ã§é–‹ã„ã¦èª­ã¿è¾¼ã‚“ã§ãŠãã®ã§ã€ä½¿ã„ãŸã„ã¨ãã«ã™ãã«ä½¿ãˆã¾ã™ã€‚ サービス休止機能ã¯è¨­å®šã—ãŸæ™‚é–“ãŒçµŒéŽã—ãŸã‚‰èª­ã¿è¾¼ã‚“ã ã‚µãƒ¼ãƒ“スを解放ã—ã¾ã™ã€‚ã“ã‚Œã¯RAMを節約ã—ãŸã‚Šã€ã‚µãƒ¼ãƒ“スã§ã‚³ãƒ³ãƒ”ューターã®å‹•ä½œãŒé‡ããªã‚‹ã®ã‚’防ãã®ã«å½¹ç«‹ã¡ã¾ã™ã€‚",
266 "settings.app.inactivityLockInfo": "休止状態ã¾ã§ã®æ™‚é–“(分)ã€ã“ã®æ™‚é–“ãŒçµŒéŽå¾ŒFerdiã¯è‡ªå‹•ã§ãƒ­ãƒƒã‚¯ã—ã¾ã™ã€‚0ã§ç„¡åŠ¹åŒ–", 255 "settings.app.inactivityLockInfo": "休止状態ã¾ã§ã®æ™‚é–“(分)ã€ã“ã®æ™‚é–“ãŒçµŒéŽå¾ŒFerdiã¯è‡ªå‹•ã§ãƒ­ãƒƒã‚¯ã—ã¾ã™ã€‚0ã§ç„¡åŠ¹åŒ–",
267 "settings.app.languageDisclaimer": "å…¬å¼ã®è¨€èªžã¯è‹±èªžã¨ãƒ‰ã‚¤ãƒ„語ã§ã™ã€‚ä»–ã®è¨€èªžã¯ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã«ã‚ˆã‚‹ç¿»è¨³ã§ã™ã€‚", 256 "settings.app.languageDisclaimer": "å…¬å¼ã®è¨€èªžã¯è‹±èªžã¨ãƒ‰ã‚¤ãƒ„語ã§ã™ã€‚ä»–ã®è¨€èªžã¯ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã«ã‚ˆã‚‹ç¿»è¨³ã§ã™ã€‚",
268 "settings.app.lockInfo": "パスワードロックã¯ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’ä¿è­·ã§ãã¾ã™ã€‚\nパスワードロックを使用ã™ã‚‹ã¨ã€Ferdiã®èµ·å‹•æ™‚ã€ã¾ãŸã¯è‡ªåˆ†ã§å·¦ä¸‹ã®ãƒ­ãƒƒã‚¯ãƒœã‚¿ãƒ³ã‚’押ã™ã‹ã‚·ãƒ§ãƒ¼ãƒˆã‚«ãƒƒãƒˆ{lockShortcut}ã§Ferdiをロックã—ãŸã¨ãã«ã€ãã®éƒ½åº¦ãƒ‘スワードã®å…¥åŠ›ãŒæ±‚ã‚られã¾ã™ã€‚", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "パスワード", 258 "settings.app.lockedPassword": "パスワード",
270 "settings.app.lockedPasswordInfo": "覚ãˆã‚‰ã‚Œã‚‹ãƒ‘スワードを設定ã™ã‚‹ã‚ˆã†ã«ã—ã¦ãã ã•ã„。\nパスワードを紛失ã™ã‚‹ã¨ã€Ferdiã®å†ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "変更ã«ã¯å†èµ·å‹•ãŒå¿…è¦ã§ã™", 260 "settings.app.restartRequired": "変更ã«ã¯å†èµ·å‹•ãŒå¿…è¦ã§ã™",
272 "settings.app.scheduledDNDInfo": "集中モードã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’有効ã«ã™ã‚‹ã¨ã€Ferdiã‹ã‚‰ã®é€šçŸ¥ã‚’å—ã‘å–らãªã„時間帯を設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚", 261 "settings.app.scheduledDNDInfo": "集中モードã®ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’有効ã«ã™ã‚‹ã¨ã€Ferdiã‹ã‚‰ã®é€šçŸ¥ã‚’å—ã‘å–らãªã„時間帯を設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚",
273 "settings.app.scheduledDNDTimeInfo": "24時間形å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„。終了時刻を開始時刻よりも早ã設定ã™ã‚‹ã¨(例: 17:00開始ã€9:00終了)ã€é›†ä¸­ãƒ¢ãƒ¼ãƒ‰ã‚’一晩中有効ã«ã§ãã¾ã™ã€‚", 262 "settings.app.scheduledDNDTimeInfo": "24時間形å¼ã§å…¥åŠ›ã—ã¦ãã ã•ã„。終了時刻を開始時刻よりも早ã設定ã™ã‚‹ã¨(例: 17:00開始ã€9:00終了)ã€é›†ä¸­ãƒ¢ãƒ¼ãƒ‰ã‚’一晩中有効ã«ã§ãã¾ã™ã€‚",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdiã¯ã‚¹ãƒšãƒ«ãƒã‚§ãƒƒã‚¯ã«macOSシステムã®ã‚¹ãƒšãƒ«ãƒã‚§ãƒƒã‚«ãƒ¼ã‚’使用ã—ã¦ã„ã¾ã™ã€‚スペルãƒã‚§ãƒƒã‚«ãƒ¼ã§ãƒã‚§ãƒƒã‚¯ã™ã‚‹è¨€èªžã‚’変更ã™ã‚‹ã«ã¯ã€macOSã®ã‚·ã‚¹ãƒ†ãƒ ç’°å¢ƒè¨­å®šã‹ã‚‰è¡Œã£ã¦ãã ã•ã„。", 264 "settings.app.spellCheckerLanguageInfo": "Ferdiã¯ã‚¹ãƒšãƒ«ãƒã‚§ãƒƒã‚¯ã«macOSシステムã®ã‚¹ãƒšãƒ«ãƒã‚§ãƒƒã‚«ãƒ¼ã‚’使用ã—ã¦ã„ã¾ã™ã€‚スペルãƒã‚§ãƒƒã‚«ãƒ¼ã§ãƒã‚§ãƒƒã‚¯ã™ã‚‹è¨€èªžã‚’変更ã™ã‚‹ã«ã¯ã€macOSã®ã‚·ã‚¹ãƒ†ãƒ ç’°å¢ƒè¨­å®šã‹ã‚‰è¡Œã£ã¦ãã ã•ã„。",
276 "settings.app.subheadlineCache": "キャッシュ", 265 "settings.app.subheadlineCache": "キャッシュ",
277 "settings.app.subheadlineFerdiProfile": "Ferdiプロフィール", 266 "settings.app.subheadlineFerdiProfile": "Ferdiプロフィール",
278 "settings.app.todoServerInfo": "ã“ã®ã‚µãƒ¼ãƒãƒ¼ã¯ã€ŒFerdi ToDoã€ã®æ©Ÿèƒ½ã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Ferdiã®ç¿»è¨³ä½œæ¥­ã«ã”å”力をãŠé¡˜ã„ã—ã¾ã™ã€‚", 268 "settings.app.translationHelp": "Ferdiã®ç¿»è¨³ä½œæ¥­ã«ã”å”力をãŠé¡˜ã„ã—ã¾ã™ã€‚",
280 "settings.app.universalDarkModeInfo": "ユニãƒãƒ¼ã‚µãƒ«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã¯ã€ç¾åœ¨ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„サービスå‘ã‘ã«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’å‹•çš„ã«ç”Ÿæˆã—ã¾ã™ã€‚", 269 "settings.app.universalDarkModeInfo": "ユニãƒãƒ¼ã‚µãƒ«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã¯ã€ç¾åœ¨ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„サービスå‘ã‘ã«ãƒ€ãƒ¼ã‚¯ãƒ¢ãƒ¼ãƒ‰ã‚’å‹•çš„ã«ç”Ÿæˆã—ã¾ã™ã€‚",
281 "settings.app.updateStatusAvailable": "æ›´æ–°ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚ダウンロードã—ã¦ã„ã¾ã™...", 270 "settings.app.updateStatusAvailable": "æ›´æ–°ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸã€‚ダウンロードã—ã¦ã„ã¾ã™...",
@@ -294,12 +283,12 @@
294 "settings.recipes.customService.headline.communityRecipes": "コミュニティã®ã‚µãƒ¼ãƒ‰ãƒ‘ーティレシピ", 283 "settings.recipes.customService.headline.communityRecipes": "コミュニティã®ã‚µãƒ¼ãƒ‰ãƒ‘ーティレシピ",
295 "settings.recipes.customService.headline.customRecipes": "カスタムサードパーティレシピ", 284 "settings.recipes.customService.headline.customRecipes": "カスタムサードパーティレシピ",
296 "settings.recipes.customService.headline.devRecipes": "開発サービスã®ãƒ¬ã‚·ãƒ”", 285 "settings.recipes.customService.headline.devRecipes": "開発サービスã®ãƒ¬ã‚·ãƒ”",
297 "settings.recipes.customService.intro": "カスタムサービスを追加ã™ã‚‹ã«ã¯ã€ã‚µãƒ¼ãƒ“スレシピを以下ã«ã‚³ãƒ”ーã—ã¾ã™:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "開発者ドキュメント", 287 "settings.recipes.customService.openDevDocs": "開発者ドキュメント",
299 "settings.recipes.customService.openFolder": "フォルダーを開ã", 288 "settings.recipes.customService.openFolder": "フォルダーを開ã",
300 "settings.recipes.headline": "利用å¯èƒ½ãªã‚µãƒ¼ãƒ“ス", 289 "settings.recipes.headline": "利用å¯èƒ½ãªã‚µãƒ¼ãƒ“ス",
301 "settings.recipes.missingService": "使ã„ãŸã„サービスãŒä¸€è¦§ã«ã‚ã‚Šã¾ã›ã‚“ã‹?", 290 "settings.recipes.missingService": "使ã„ãŸã„サービスãŒä¸€è¦§ã«ã‚ã‚Šã¾ã›ã‚“ã‹?",
302 "settings.recipes.nothingFound": "残念ãªãŒã‚‰ã€æ¤œç´¢èªžã«ä¸€è‡´ã™ã‚‹ã‚µãƒ¼ãƒ“スã¯ã‚ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚ã—ã‹ã—ã€ã€Œã‚«ã‚¹ã‚¿ãƒ ã‚¦ã‚§ãƒ–サイトã€ã®ã‚ªãƒ—ションを使用ã—ã¦è¿½åŠ ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®Ferdiã§ã¯ã‚¦ã‚§ãƒ–サイトã§ç´¹ä»‹ã•ã‚Œã¦ã„るよã†ãªã€ã‚ˆã‚Šå¤šãã®ã‚µãƒ¼ãƒ“スãŒè¿½åŠ ã•ã‚Œã¦ã„ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚ãれらã®æ–°ã—ã„サービスを追加ã™ã‚‹ã«ã¯ã€Ferdiã®ã‚¢ãƒƒãƒ—デートをã”検討ãã ã•ã„。", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
303 "settings.recipes.servicesSuccessfulAddedInfo": "サービスãŒè¿½åŠ ã•ã‚Œã¾ã—ãŸ", 292 "settings.recipes.servicesSuccessfulAddedInfo": "サービスãŒè¿½åŠ ã•ã‚Œã¾ã—ãŸ",
304 "settings.searchService": "サービスを検索", 293 "settings.searchService": "サービスを検索",
305 "settings.service.error.goBack": "サービスã«æˆ»ã‚‹", 294 "settings.service.error.goBack": "サービスã«æˆ»ã‚‹",
@@ -331,18 +320,19 @@
331 "settings.service.form.indirectMessages": "ã™ã¹ã¦ã®æ–°è¦ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã«ã¤ã„ã¦ãƒãƒƒã‚¸ã‚’表示ã™ã‚‹", 320 "settings.service.form.indirectMessages": "ã™ã¹ã¦ã®æ–°è¦ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã«ã¤ã„ã¦ãƒãƒƒã‚¸ã‚’表示ã™ã‚‹",
332 "settings.service.form.isHibernatedEnabledInfo": "有効ã«ã™ã‚‹ã¨ã€ã‚·ã‚¹ãƒ†ãƒ ãƒªã‚½ãƒ¼ã‚¹ã‚’節約ã™ã‚‹ãŸã‚ã«ä¸€å®šæ™‚間後ã«ã‚µãƒ¼ãƒ“スãŒé–‰ã˜ã‚‰ã‚Œã¾ã™ã€‚", 321 "settings.service.form.isHibernatedEnabledInfo": "有効ã«ã™ã‚‹ã¨ã€ã‚·ã‚¹ãƒ†ãƒ ãƒªã‚½ãƒ¼ã‚¹ã‚’節約ã™ã‚‹ãŸã‚ã«ä¸€å®šæ™‚間後ã«ã‚µãƒ¼ãƒ“スãŒé–‰ã˜ã‚‰ã‚Œã¾ã™ã€‚",
333 "settings.service.form.isMutedInfo": "無効化ã•ã‚Œã¦ã„ã‚‹å ´åˆã€å…¨ã¦ã®é€šçŸ¥éŸ³ã‚„オーディオå†ç”Ÿã¯ç„¡éŸ³ã«ãªã‚Šã¾ã™", 322 "settings.service.form.isMutedInfo": "無効化ã•ã‚Œã¦ã„ã‚‹å ´åˆã€å…¨ã¦ã®é€šçŸ¥éŸ³ã‚„オーディオå†ç”Ÿã¯ç„¡éŸ³ã«ãªã‚Šã¾ã™",
334 "settings.service.form.name": "æ°å", 323 "settings.service.form.name": "åå‰",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "darkmode.cssã‚’é–‹ã", 325 "settings.service.form.openDarkmodeCss": "darkmode.cssã‚’é–‹ã",
336 "settings.service.form.openUserCss": "user.cssã‚’é–‹ã", 326 "settings.service.form.openUserCss": "user.cssã‚’é–‹ã",
337 "settings.service.form.openUserJs": "user.jsã‚’é–‹ã", 327 "settings.service.form.openUserJs": "user.jsã‚’é–‹ã",
338 "settings.service.form.proxy.headline": "HTTP/HTTPSã®ãƒ—ロキシ設定", 328 "settings.service.form.proxy.headline": "HTTP/HTTPSã®ãƒ—ロキシ設定",
339 "settings.service.form.proxy.host": "プロキシサーãƒãƒ¼/IP", 329 "settings.service.form.proxy.host": "プロキシサーãƒãƒ¼/IP",
340 "settings.service.form.proxy.info": "プロキシ設定ã¯Ferdi アカウントã§åŒæœŸã•ã‚Œã¾ã›ã‚“。", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "プロキシ設定を有効ã«ã™ã‚‹", 331 "settings.service.form.proxy.isEnabled": "プロキシ設定を有効ã«ã™ã‚‹",
342 "settings.service.form.proxy.password": "パスワード(任æ„)", 332 "settings.service.form.proxy.password": "パスワード(オプション)",
343 "settings.service.form.proxy.port": "ãƒãƒ¼ãƒˆ", 333 "settings.service.form.proxy.port": "ãƒãƒ¼ãƒˆ",
344 "settings.service.form.proxy.restartInfo": "プロキシ設定を変更ã—ã¦ã‹ã‚‰ã€Ferdiã‚’å†èµ·å‹•ã—ã¦ãã ã•ã„", 334 "settings.service.form.proxy.restartInfo": "プロキシ設定を変更ã—ã¦ã‹ã‚‰ã€Ferdiã‚’å†èµ·å‹•ã—ã¦ãã ã•ã„",
345 "settings.service.form.proxy.user": "ユーザーå(任æ„)", 335 "settings.service.form.proxy.user": "ユーザー(オプション)",
346 "settings.service.form.recipeFileInfo": "ユーザーファイルãŒã‚¦ã‚§ãƒ–ページã«æŒ¿å…¥ã•ã‚Œã‚‹ã®ã§ã€ä»»æ„ã®æ–¹æ³•ã§ã‚µãƒ¼ãƒ“スをカスタマイズã§ãã¾ã™ã€‚ ユーザーファイルã¯ãƒ­ãƒ¼ã‚«ãƒ«ã«ã®ã¿ä¿å­˜ã•ã‚Œã€åŒã˜ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’使用ã™ã‚‹ä»–ã®ã‚³ãƒ³ãƒ”ューターã«ã¯è»¢é€ã•ã‚Œã¾ã›ã‚“。", 336 "settings.service.form.recipeFileInfo": "ユーザーファイルãŒã‚¦ã‚§ãƒ–ページã«æŒ¿å…¥ã•ã‚Œã‚‹ã®ã§ã€ä»»æ„ã®æ–¹æ³•ã§ã‚µãƒ¼ãƒ“スをカスタマイズã§ãã¾ã™ã€‚ ユーザーファイルã¯ãƒ­ãƒ¼ã‚«ãƒ«ã«ã®ã¿ä¿å­˜ã•ã‚Œã€åŒã˜ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’使用ã™ã‚‹ä»–ã®ã‚³ãƒ³ãƒ”ューターã«ã¯è»¢é€ã•ã‚Œã¾ã›ã‚“。",
347 "settings.service.form.saveButton": "サービスã®ä¿å­˜", 337 "settings.service.form.saveButton": "サービスã®ä¿å­˜",
348 "settings.service.form.tabHosted": "ホスト", 338 "settings.service.form.tabHosted": "ホスト",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "サービスを探ã™", 344 "settings.services.discoverServices": "サービスを探ã™",
355 "settings.services.headline": "利用中ã®ã‚µãƒ¼ãƒ“ス", 345 "settings.services.headline": "利用中ã®ã‚µãƒ¼ãƒ“ス",
356 "settings.services.noServicesAdded": "ã¾ãšã¯ã‚µãƒ¼ãƒ“スを追加ã—ã¾ã™ã€‚", 346 "settings.services.noServicesAdded": "ã¾ãšã¯ã‚µãƒ¼ãƒ“スを追加ã—ã¾ã™ã€‚",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "サービスを読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸ", 348 "settings.services.servicesRequestFailed": "サービスを読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸ",
358 "settings.services.tooltip.isDisabled": "サービスãŒç„¡åŠ¹ã§ã™", 349 "settings.services.tooltip.isDisabled": "サービスãŒç„¡åŠ¹ã§ã™",
359 "settings.services.tooltip.isMuted": "無音ã¨ãªã£ã¦ã„ã¾ã™", 350 "settings.services.tooltip.isMuted": "無音ã¨ãªã£ã¦ã„ã¾ã™",
@@ -367,7 +358,7 @@
367 "settings.supportFerdi.textDonationAnd": "ã¨", 358 "settings.supportFerdi.textDonationAnd": "ã¨",
368 "settings.supportFerdi.textExpenses": "ボランティアãŒã‹ãªã‚Šã®éƒ¨åˆ†ã®ä½œæ¥­ã‚’è¡Œã£ã¦ã„ã¾ã™ãŒã€ç§ãŸã¡ã‚‚サーãƒãƒ¼ä»£ã¨è¨¼æ˜Žæ›¸ã‚’支払ã‚ãªãã¦ã¯ãªã‚Šã¾ã›ã‚“。コミュニティã¨åŒæ§˜ã«ã€ç§ãŸã¡ã®åŽæ”¯ã¯å…¨ã¦å…¬é–‹ã•ã‚Œã¦ã„ã¾ã™ã€‚以下をå‚ç…§ã—ã¦ãã ã•ã„。", 359 "settings.supportFerdi.textExpenses": "ボランティアãŒã‹ãªã‚Šã®éƒ¨åˆ†ã®ä½œæ¥­ã‚’è¡Œã£ã¦ã„ã¾ã™ãŒã€ç§ãŸã¡ã‚‚サーãƒãƒ¼ä»£ã¨è¨¼æ˜Žæ›¸ã‚’支払ã‚ãªãã¦ã¯ãªã‚Šã¾ã›ã‚“。コミュニティã¨åŒæ§˜ã«ã€ç§ãŸã¡ã®åŽæ”¯ã¯å…¨ã¦å…¬é–‹ã•ã‚Œã¦ã„ã¾ã™ã€‚以下をå‚ç…§ã—ã¦ãã ã•ã„。",
369 "settings.supportFerdi.textGitHubSponsors": "GitHub Sponsors", 360 "settings.supportFerdi.textGitHubSponsors": "GitHub Sponsors",
370 "settings.supportFerdi.textListContributors": "å…¨ã¦ã®è²¢çŒ®è€…ã®ãƒªã‚¹ãƒˆ", 361 "settings.supportFerdi.textListContributors": "å…¨ã¦ã®è²¢çŒ®è€…リスト",
371 "settings.supportFerdi.textListContributorsHere": "ã“ã“", 362 "settings.supportFerdi.textListContributorsHere": "ã“ã“",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "支æ´ã¯ã„ã¤ã§ã‚‚æ­“è¿Žã§ã™ã€‚ç§ãŸã¡ãŒå¿…è¦ã¨ã—ã¦ã„る支æ´ã®ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™", 364 "settings.supportFerdi.textSupportWelcome": "支æ´ã¯ã„ã¤ã§ã‚‚æ­“è¿Žã§ã™ã€‚ç§ãŸã¡ãŒå¿…è¦ã¨ã—ã¦ã„る支æ´ã®ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™",
@@ -390,13 +381,13 @@
390 "settings.user.form.firstname": "å", 381 "settings.user.form.firstname": "å",
391 "settings.user.form.lastname": "姓", 382 "settings.user.form.lastname": "姓",
392 "settings.user.form.newPassword": "æ–°ã—ã„パスワード", 383 "settings.user.form.newPassword": "æ–°ã—ã„パスワード",
393 "settings.workspace.add.form.name": "æ°å", 384 "settings.workspace.add.form.name": "åå‰",
394 "settings.workspace.add.form.submitButton": "ワークスペースを作æˆ", 385 "settings.workspace.add.form.submitButton": "ワークスペースを作æˆ",
395 "settings.workspace.form.buttonDelete": "ワークスペースを削除", 386 "settings.workspace.form.buttonDelete": "ワークスペースを削除",
396 "settings.workspace.form.buttonSave": "ワークスペースをä¿å­˜", 387 "settings.workspace.form.buttonSave": "ワークスペースをä¿å­˜",
397 "settings.workspace.form.keepLoaded": "ã“ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã‚’読ã¿è¾¼ã‚“ã ã¾ã¾ã«ã—ã¦ãŠã*", 388 "settings.workspace.form.keepLoaded": "ã“ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã‚’読ã¿è¾¼ã‚“ã ã¾ã¾ã«ã—ã¦ãŠã*",
398 "settings.workspace.form.keepLoadedInfo": "*ã“ã®ã‚ªãƒ—ションã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«ã®ã€Œã™ã¹ã¦ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã‚’ロードã—ãŸã¾ã¾ã«ã™ã‚‹ã€ã‚ªãƒ—ションã«ã‚ˆã£ã¦ä¸Šæ›¸ãã•ã‚Œã¾ã™ã€‚", 389 "settings.workspace.form.keepLoadedInfo": "*ã“ã®ã‚ªãƒ—ションã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«ã®ã€Œã™ã¹ã¦ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã‚’ロードã—ãŸã¾ã¾ã«ã™ã‚‹ã€ã‚ªãƒ—ションã«ã‚ˆã£ã¦ä¸Šæ›¸ãã•ã‚Œã¾ã™ã€‚",
399 "settings.workspace.form.name": "æ°å", 390 "settings.workspace.form.name": "åå‰",
400 "settings.workspace.form.servicesInWorkspaceHeadline": "ã“ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã®ã‚µãƒ¼ãƒ“ス", 391 "settings.workspace.form.servicesInWorkspaceHeadline": "ã“ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹ã®ã‚µãƒ¼ãƒ“ス",
401 "settings.workspace.form.yourWorkspaces": "利用中ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹", 392 "settings.workspace.form.yourWorkspaces": "利用中ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒšãƒ¼ã‚¹",
402 "settings.workspaces.deletedInfo": "ワークスペースを削除ã—ã¾ã—ãŸ", 393 "settings.workspaces.deletedInfo": "ワークスペースを削除ã—ã¾ã—ãŸ",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "ã‚‚ã†ä¸€åº¦è©¦ã™", 396 "settings.workspaces.tryReloadWorkspaces": "ã‚‚ã†ä¸€åº¦è©¦ã™",
406 "settings.workspaces.updatedInfo": "変更内容ãŒä¿å­˜ã•ã‚Œã¾ã—ãŸ", 397 "settings.workspaces.updatedInfo": "変更内容ãŒä¿å­˜ã•ã‚Œã¾ã—ãŸ",
407 "settings.workspaces.workspaceFeatureHeadline": "ヒント: Ferdiワークスペースã®ç´¹ä»‹", 398 "settings.workspaces.workspaceFeatureHeadline": "ヒント: Ferdiワークスペースã®ç´¹ä»‹",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdiワークスペースを使用ã™ã‚‹ã¨ã€ã™ãã«é‡è¦ãªã“ã¨ã«é›†ä¸­ã§ãã¾ã™ã€‚ç•°ãªã‚‹ã‚µãƒ¼ãƒ“ス群を設定ã—ã€ã„ã¤ã§ã‚‚ç°¡å˜ã«åˆ‡ã‚Šæ›¿ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ å¿…è¦ãªã‚µãƒ¼ãƒ“スをã€å¿…è¦ãªæ™‚ã«ã€å¿…è¦ãªå ´æ‰€ã§ã”利用ã„ãŸã ã‘ã¾ã™ã®ã§ã€ä»•äº‹ã«é›†ä¸­ã™ã‚‹ã“ã¨ã‚‚ã€å¥½ããªæ™‚ã«ä»•äº‹ã‹ã‚‰é›¢ã‚Œã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdiワークスペースを使用ã™ã‚‹ã¨ã€ã™ãã«é‡è¦ãªã“ã¨ã«é›†ä¸­ã§ãã¾ã™ã€‚様々ãªã‚µãƒ¼ãƒ“スã®ã‚»ãƒƒãƒˆã‚’設定ã—ã€ã„ã¤ã§ã‚‚ç°¡å˜ã«åˆ‡ã‚Šæ›¿ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ å¿…è¦ãªã‚µãƒ¼ãƒ“スをã€å¿…è¦ãªæ™‚ã«ã€å¿…è¦ãªå ´æ‰€ã§ã”利用ã„ãŸã ã‘ã¾ã™ã®ã§ã€ä»•äº‹ã«é›†ä¸­ã™ã‚‹ã“ã¨ã‚‚ã€å¥½ããªæ™‚ã«ä»•äº‹ã‹ã‚‰é›¢ã‚Œã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚",
409 "settings.workspaces.workspacesRequestFailed": "ワークスペースを読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸ", 400 "settings.workspaces.workspacesRequestFailed": "ワークスペースを読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸ",
410 "setupAssistant.headline": "始ã‚ã¾ã—ょã†", 401 "setupAssistant.headline": "始ã‚ã¾ã—ょã†",
411 "setupAssistant.subheadline": "最も使用ã•ã‚Œã¦ã„るサービスã®ä¸­ã‹ã‚‰é¸æŠžã—ã€ã™ãã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãƒ³ã‚°ã®æœ€æ–°ã®ã‚„ã‚Šã¨ã‚Šã«æˆ»ã£ã¦ãã ã•ã„。", 402 "setupAssistant.subheadline": "最も使用ã•ã‚Œã¦ã„るサービスã®ä¸­ã‹ã‚‰é¸æŠžã—ã€ã™ãã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãƒ³ã‚°ã®æœ€æ–°ã®ã‚„ã‚Šã¨ã‚Šã«æˆ»ã£ã¦ãã ã•ã„。",
@@ -434,7 +425,7 @@
434 "tabs.item.disableAudio": "オーディオã®ç„¡åŠ¹åŒ–", 425 "tabs.item.disableAudio": "オーディオã®ç„¡åŠ¹åŒ–",
435 "tabs.item.disableDarkMode": "ダークモードを無効ã«ã™ã‚‹", 426 "tabs.item.disableDarkMode": "ダークモードを無効ã«ã™ã‚‹",
436 "tabs.item.disableNotifications": "通知を無効ã«ã™ã‚‹", 427 "tabs.item.disableNotifications": "通知を無効ã«ã™ã‚‹",
437 "tabs.item.disableService": "サービスを無効ã«ã™ã‚‹", 428 "tabs.item.disableService": "サービスã®ç„¡åŠ¹åŒ–",
438 "tabs.item.enableAudio": "オーディオを有効ã«ã™ã‚‹", 429 "tabs.item.enableAudio": "オーディオを有効ã«ã™ã‚‹",
439 "tabs.item.enableDarkMode": "ダークモードを有効ã«ã™ã‚‹", 430 "tabs.item.enableDarkMode": "ダークモードを有効ã«ã™ã‚‹",
440 "tabs.item.enableNotification": "通知を有効ã«ã™ã‚‹", 431 "tabs.item.enableNotification": "通知を有効ã«ã™ã‚‹",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "サービスã®ä¼‘æ­¢", 433 "tabs.item.hibernateService": "サービスã®ä¼‘æ­¢",
443 "tabs.item.reload": "å†èª­ã¿è¾¼ã¿", 434 "tabs.item.reload": "å†èª­ã¿è¾¼ã¿",
444 "tabs.item.wakeUpService": "サービスã®èµ·å‹•", 435 "tabs.item.wakeUpService": "サービスã®èµ·å‹•",
445 "validation.email": "{field}ã¯æ­£ã—ãã‚ã‚Šã¾ã›ã‚“", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field}ã¯å°‘ãªãã¨ã‚‚{length}文字以上ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "å°‘ãªãã¨ã‚‚1ã¤ã¯å¿…è¦ã§ã™", 438 "validation.oneRequired": "å°‘ãªãã¨ã‚‚1ã¤ã¯å¿…è¦ã§ã™",
448 "validation.required": "{field}ã¯å¿…é ˆã§ã™", 439 "validation.required": "{field} is required",
449 "validation.url": "{field}ã¯æ­£ã—ã„URLã§ã¯ã‚ã‚Šã¾ã›ã‚“", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "戻る", 441 "webControls.back": "戻る",
451 "webControls.forward": "次ã¸", 442 "webControls.forward": "次ã¸",
452 "webControls.goHome": "ホーム", 443 "webControls.goHome": "ホーム",
@@ -459,7 +450,7 @@
459 "workspaceDrawer.headline": "ワークスペース", 450 "workspaceDrawer.headline": "ワークスペース",
460 "workspaceDrawer.item.contextMenuEdit": "編集", 451 "workspaceDrawer.item.contextMenuEdit": "編集",
461 "workspaceDrawer.item.noServicesAddedYet": "ã¾ã ã‚µãƒ¼ãƒ“スãŒè¿½åŠ ã•ã‚Œã¦ã„ã¾ã›ã‚“", 452 "workspaceDrawer.item.noServicesAddedYet": "ã¾ã ã‚µãƒ¼ãƒ“スãŒè¿½åŠ ã•ã‚Œã¦ã„ã¾ã›ã‚“",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdiワークスペースを使用ã™ã‚‹ã¨ã€ã™ãã«é‡è¦ãªã“ã¨ã«é›†ä¸­ã§ãã¾ã™ã€‚ç•°ãªã‚‹ã‚µãƒ¼ãƒ“ス群を設定ã—ã€ã„ã¤ã§ã‚‚ç°¡å˜ã«åˆ‡ã‚Šæ›¿ãˆã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚</p><p> å¿…è¦ãªã‚µãƒ¼ãƒ“スをã€å¿…è¦ãªæ™‚ã«ã€å¿…è¦ãªå ´æ‰€ã§ã”利用ã„ãŸã ã‘ã¾ã™ã®ã§ã€ä»•äº‹ã«é›†ä¸­ã™ã‚‹ã“ã¨ã‚‚ã€å¥½ããªæ™‚ã«ä»•äº‹ã‹ã‚‰é›¢ã‚Œã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "ワークスペースã®è¨­å®šã‚’編集ã™ã‚‹", 454 "workspaceDrawer.workspacesSettingsTooltip": "ワークスペースã®è¨­å®šã‚’編集ã™ã‚‹",
464 "workspaces.switchingIndicator.switchingTo": "切り替ãˆå…ˆ:" 455 "workspaces.switchingIndicator.switchingTo": "切り替ãˆå…ˆ:"
465} 456}
diff --git a/src/i18n/locales/ka.json b/src/i18n/locales/ka.json
index cc5a04aff..f327c1e51 100644
--- a/src/i18n/locales/ka.json
+++ b/src/i18n/locales/ka.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ", 2 "app.errorHandler.action": "ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვáƒ",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "კერძრსერვერი", 4 "changeserver.customServerLabel": "კერძრსერვერი",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Ferdi-ის áƒáƒœáƒšáƒáƒ˜áƒœ სერვისთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბრვერ მáƒáƒ®áƒ”რხდáƒ", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ", 27 "global.cancel": "Cancel",
29 "global.edit": "რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბáƒ", 28 "global.edit": "რედáƒáƒ¥áƒ¢áƒ˜áƒ áƒ”ბáƒ",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "თქვენ áƒáƒ  ხáƒáƒ áƒ— ინტერნეტთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბული.", 30 "global.notConnectedToTheInternet": "თქვენ áƒáƒ  ხáƒáƒ áƒ— ინტერნეტთáƒáƒœ დáƒáƒ™áƒáƒ•áƒ¨áƒ˜áƒ áƒ”ბული.",
@@ -33,19 +32,19 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "პáƒáƒ áƒáƒ›áƒ”ტრები", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use System Default ({default})", 36 "global.spellchecker.useDefault": "Use System Default ({default})",
38 "global.spellchecking.autodetect": "Detect language automatically", 37 "global.spellchecking.autodetect": "Detect language automatically",
39 "global.spellchecking.autodetect.short": "Automatic", 38 "global.spellchecking.autodetect.short": "Automatic",
40 "global.spellchecking.language": "Spell checking language", 39 "global.spellchecking.language": "Spell checking language",
41 "global.submit": "დáƒáƒ“áƒáƒ¡áƒ¢áƒ£áƒ áƒ”ბáƒ", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "შემáƒáƒ˜áƒ¢áƒáƒœáƒ” Ferdi 4-ის სერვისები", 44 "import.headline": "შემáƒáƒ˜áƒ¢áƒáƒœáƒ” Ferdi 4-ის სერვისები",
46 "import.notSupportedHeadline": "სერვისები ჯერ áƒáƒ  áƒáƒ áƒ˜áƒ¡ მხáƒáƒ áƒ“áƒáƒ­áƒ”რილი Ferdi 5-ში", 45 "import.notSupportedHeadline": "სერვისები ჯერ áƒáƒ  áƒáƒ áƒ˜áƒ¡ მხáƒáƒ áƒ“áƒáƒ­áƒ”რილი Ferdi 5-ში",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "მáƒáƒ¬áƒ•áƒ”ვის გáƒáƒ’ზáƒáƒ•áƒœáƒ", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ეთ დრდáƒáƒáƒ§áƒ”ნეთ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ", 50 "infobar.buttonInstallUpdate": "გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ეთ დრდáƒáƒáƒ§áƒ”ნეთ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ",
@@ -75,7 +74,7 @@
75 "login.email.label": "მეილი", 74 "login.email.label": "მეილი",
76 "login.headline": "შესვლáƒ", 75 "login.headline": "შესვლáƒ",
77 "login.invalidCredentials": "მეილი áƒáƒœ პáƒáƒ áƒáƒšáƒ˜ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ", 76 "login.invalidCredentials": "მეილი áƒáƒœ პáƒáƒ áƒáƒšáƒ˜ áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜áƒ",
78 "login.link.password": "პáƒáƒ áƒáƒšáƒ˜áƒ¡ áƒáƒ¦áƒ“გენáƒ", 77 "login.link.password": "Reset password",
79 "login.link.signup": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ შექმნáƒ", 78 "login.link.signup": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ შექმნáƒ",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "თქვენს სესიáƒáƒ¡ ვáƒáƒ“რგáƒáƒ£áƒ•áƒ˜áƒ“áƒ, შედით áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜ ხელáƒáƒ®áƒšáƒ.", 80 "login.serverLogout": "თქვენს სესიáƒáƒ¡ ვáƒáƒ“რგáƒáƒ£áƒ•áƒ˜áƒ“áƒ, შედით áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜ ხელáƒáƒ®áƒšáƒ.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "ყველრსერვისი", 147 "menu.workspaces.defaultWorkspace": "ყველრსერვისი",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "მეილი", 149 "password.email.label": "მეილი",
151 "password.headline": "პáƒáƒ áƒáƒšáƒ˜áƒ¡ áƒáƒ¦áƒ“გენáƒ", 150 "password.headline": "Reset password",
152 "password.link.login": "შედით თქვენს áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜", 151 "password.link.login": "შედით თქვენს áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ¨áƒ˜",
153 "password.link.signup": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ შექმნáƒ", 152 "password.link.signup": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ შექმნáƒ",
154 "password.noUser": "მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბელი მითითებული მეილით ვერ მáƒáƒ˜áƒ«áƒ”ბნáƒ", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "გთხáƒáƒ•áƒ— შეáƒáƒ›áƒáƒ¬áƒ›áƒ”თ მეილი", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "მáƒáƒ’ესáƒáƒšáƒ›áƒ”ბით Ferdi-ზე", 171 "services.welcome": "მáƒáƒ’ესáƒáƒšáƒ›áƒ”ბით Ferdi-ზე",
184 "settings.account.account.editButton": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ მáƒáƒ áƒ—ვáƒ", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "პრáƒáƒ¤áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ", 175 "settings.account.buttonSave": "პრáƒáƒ¤áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", 177 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
190 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.", 178 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
191 "settings.account.headline": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜", 179 "settings.account.headline": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜",
192 "settings.account.headlineAccount": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Danger Zone", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "ინვáƒáƒ˜áƒ¡áƒ”ბი", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "პáƒáƒ áƒáƒšáƒ˜áƒ¡ შეცვლáƒ", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "პრáƒáƒ¤áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ", 184 "settings.account.headlineProfile": "პრáƒáƒ¤áƒ˜áƒšáƒ˜áƒ¡ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ",
197 "settings.account.successInfo": "თქვენი ცვლილებები შენáƒáƒ®áƒ£áƒšáƒ˜áƒ", 185 "settings.account.successInfo": "თქვენი ცვლილებები შენáƒáƒ®áƒ£áƒšáƒ˜áƒ",
198 "settings.account.tryReloadServices": "სცáƒáƒ“ეთ ხელáƒáƒ®áƒšáƒ", 186 "settings.account.tryReloadServices": "სცáƒáƒ“ეთ ხელáƒáƒ®áƒšáƒ",
199 "settings.account.tryReloadUserInfoRequest": "სცáƒáƒ“ეთ ხელáƒáƒ®áƒšáƒ", 187 "settings.account.tryReloadUserInfoRequest": "სცáƒáƒ“ეთ ხელáƒáƒ®áƒšáƒ",
200 "settings.account.userInfoRequestFailed": "მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრვერ მáƒáƒ®áƒ”რხდáƒ", 188 "settings.account.userInfoRequestFailed": "მáƒáƒ›áƒ®áƒ›áƒáƒ áƒ”ბლის ინფáƒáƒ áƒ›áƒáƒªáƒ˜áƒ˜áƒ¡ ჩáƒáƒ¢áƒ•áƒ˜áƒ áƒ—ვრვერ მáƒáƒ®áƒ”რხდáƒ",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ეთ დრდáƒáƒáƒ§áƒ”ნეთ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ", 192 "settings.app.buttonInstallUpdate": "გáƒáƒ“áƒáƒ¢áƒ•áƒ˜áƒ áƒ—ეთ დრდáƒáƒáƒ§áƒ”ნეთ გáƒáƒœáƒáƒ®áƒšáƒ”ბáƒ",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "áƒáƒ©áƒ•áƒ”ნეთ Ferdi სისტემის უჯრáƒáƒ¨áƒ˜", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "სერვისის წáƒáƒ¨áƒšáƒ", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "შეáƒáƒ¡áƒ¬áƒáƒ áƒ” {name}", 305 "settings.service.form.editServiceHeadline": "შეáƒáƒ¡áƒ¬áƒáƒ áƒ” {name}",
317 "settings.service.form.enableAudio": "Enable audio", 306 "settings.service.form.enableAudio": "Enable audio",
318 "settings.service.form.enableBadge": "Show unread message badges", 307 "settings.service.form.enableBadge": "Show unread message badges",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "სáƒáƒ®áƒ”ლი ", 323 "settings.service.form.name": "სáƒáƒ®áƒ”ლი ",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "áƒáƒ¦áƒ›áƒáƒáƒ©áƒ˜áƒœáƒ”თ სერვისები", 344 "settings.services.discoverServices": "áƒáƒ¦áƒ›áƒáƒáƒ©áƒ˜áƒœáƒ”თ სერვისები",
355 "settings.services.headline": "თქვენი სერვისები", 345 "settings.services.headline": "თქვენი სერვისები",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "სერვისი გáƒáƒ—იშულიáƒ", 349 "settings.services.tooltip.isDisabled": "სერვისი გáƒáƒ—იშულიáƒ",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ შექმნáƒ", 422 "signup.submit.label": "áƒáƒœáƒ’áƒáƒ áƒ˜áƒ¨áƒ˜áƒ¡ შექმნáƒ",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "სერვისის წáƒáƒ¨áƒšáƒ", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Disable audio", 425 "tabs.item.disableAudio": "Disable audio",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "შეტყáƒáƒ‘ინებების გáƒáƒ›áƒáƒ áƒ—ვáƒ", 427 "tabs.item.disableNotifications": "შეტყáƒáƒ‘ინებების გáƒáƒ›áƒáƒ áƒ—ვáƒ",
437 "tabs.item.disableService": "სერვისის გáƒáƒ£áƒ¥áƒ›áƒ”ბáƒ", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Enable audio", 429 "tabs.item.enableAudio": "Enable audio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "შეტყáƒáƒ‘ინებების ჩáƒáƒ áƒ—ვáƒ", 431 "tabs.item.enableNotification": "შეტყáƒáƒ‘ინებების ჩáƒáƒ áƒ—ვáƒ",
diff --git a/src/i18n/locales/ko.json b/src/i18n/locales/ko.json
index dfbfd63a3..3be2b27ff 100644
--- a/src/i18n/locales/ko.json
+++ b/src/i18n/locales/ko.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "새로고침", 2 "app.errorHandler.action": "새로고침",
3 "app.errorHandler.headline": "문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "ì‚¬ìš©ìž ì •ì˜ ì„œë²„", 4 "changeserver.customServerLabel": "ì‚¬ìš©ìž ì •ì˜ ì„œë²„",
5 "changeserver.headline": "서버 번경", 5 "changeserver.headline": "서버 번경",
6 "changeserver.label": "서버", 6 "changeserver.label": "서버",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "무슨 ì¼ì¸ê°€ìš”?", 10 "connectionLostBanner.informationLink": "무슨 ì¼ì¸ê°€ìš”?",
11 "connectionLostBanner.message": "오 저런! Ferdiê°€ {name} ê³¼ ì—°ê²°ì´ ëŠê²¼ìŠµë‹ˆë‹¤.", 11 "connectionLostBanner.message": "오 저런! Ferdiê°€ {name} ê³¼ ì—°ê²°ì´ ëŠê²¼ìŠµë‹ˆë‹¤.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "디버깅 정보 공개",
14 "feature.nightlyBuilds.activate": "활성화", 13 "feature.nightlyBuilds.activate": "활성화",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "나ì´í‹€ë¦¬ 빌드", 15 "feature.nightlyBuilds.title": "나ì´í‹€ë¦¬ 빌드",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "서비스를 TAB, ↑, â†“ì„ ì´ìš©í•´ ì„ íƒí•  수 있습니다. ENTER를 ì´ìš©í•˜ì—¬ 서비스를 ì—´ 수 있습니다.", 23 "feature.quickSwitch.info": "서비스를 TAB, ↑, â†“ì„ ì´ìš©í•´ ì„ íƒí•  수 있습니다. ENTER를 ì´ìš©í•˜ì—¬ 서비스를 ì—´ 수 있습니다.",
25 "feature.quickSwitch.search": "검색...", 24 "feature.quickSwitch.search": "검색...",
26 "feature.quickSwitch.title": "빠른 검색", 25 "feature.quickSwitch.title": "빠른 검색",
27 "global.api.unhealthy": "Ferdi 온ë¼ì¸ ì„œë¹„ìŠ¤ì— ì—°ê²°í•  수 없습니다.", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "취소", 27 "global.cancel": "Cancel",
29 "global.edit": "편집", 28 "global.edit": "편집",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "ì¸í„°ë„·ì— ì—°ê²°í•  수 없습니다.", 30 "global.notConnectedToTheInternet": "ì¸í„°ë„·ì— ì—°ê²°í•  수 없습니다.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "설정", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "시스템 기본 사용 ({default})", 36 "global.spellchecker.useDefault": "시스템 기본 사용 ({default})",
38 "global.spellchecking.autodetect": "언어 ìžë™ íƒìƒ‰", 37 "global.spellchecking.autodetect": "언어 ìžë™ íƒìƒ‰",
39 "global.spellchecking.autodetect.short": "ìžë™", 38 "global.spellchecking.autodetect.short": "ìžë™",
40 "global.spellchecking.language": "ì² ìž ê²€ì‚¬", 39 "global.spellchecking.language": "ì² ìž ê²€ì‚¬",
41 "global.submit": "제출", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Ferdi 5ì—ì„œ ì•„ì§ ì§€ì›ë˜ì§€ 않는 서비스입니다.", 45 "import.notSupportedHeadline": "Ferdi 5ì—ì„œ ì•„ì§ ì§€ì›ë˜ì§€ 않는 서비스입니다.",
47 "import.skip.label": "수ë™ìœ¼ë¡œ 서비스 추가", 46 "import.skip.label": "수ë™ìœ¼ë¡œ 서비스 추가",
48 "import.submit.label": "서비스 가져오기", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "새로운 기능", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "재시작 후 ì—…ë°ì´íŠ¸ 설치", 50 "infobar.buttonInstallUpdate": "재시작 후 ì—…ë°ì´íŠ¸ 설치",
52 "infobar.buttonReloadServices": "서비스 재시작", 51 "infobar.buttonReloadServices": "서비스 재시작",
53 "infobar.hide": "숨기기", 52 "infobar.hide": "숨기기",
@@ -75,7 +74,7 @@
75 "login.email.label": "ì´ë©”ì¼ ì£¼ì†Œ", 74 "login.email.label": "ì´ë©”ì¼ ì£¼ì†Œ",
76 "login.headline": "로그ì¸", 75 "login.headline": "로그ì¸",
77 "login.invalidCredentials": "ì´ë©”ì¼ ë˜ëŠ” 비밀번호가 ì¼ì¹˜í•˜ì§€ 않습니다", 76 "login.invalidCredentials": "ì´ë©”ì¼ ë˜ëŠ” 비밀번호가 ì¼ì¹˜í•˜ì§€ 않습니다",
78 "login.link.password": "비밀번호 초기화", 77 "login.link.password": "Reset password",
79 "login.link.signup": "무료 계정 ìƒì„±", 78 "login.link.signup": "무료 계정 ìƒì„±",
80 "login.password.label": "비밀번호", 79 "login.password.label": "비밀번호",
81 "login.serverLogout": "ì„¸ì…˜ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤. 다시 ë¡œê·¸ì¸ í•˜ì„¸ìš”.", 80 "login.serverLogout": "ì„¸ì…˜ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤. 다시 ë¡œê·¸ì¸ í•˜ì„¸ìš”.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "지ì›", 116 "menu.help.support": "지ì›",
118 "menu.help.tos": "ì´ìš© 약관", 117 "menu.help.tos": "ì´ìš© 약관",
119 "menu.services": "서비스", 118 "menu.services": "서비스",
120 "menu.services.activatePreviousService": "ì´ì „ 서비스 활성화", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "새로운 서비스 추가", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "홈", 121 "menu.services.goHome": "홈",
123 "menu.services.setNextServiceActive": "ë‹¤ìŒ ì„œë¹„ìŠ¤ 활성화", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Todos 허용", 124 "menu.todos.enableTodos": "Todos 허용",
126 "menu.view": "View", 125 "menu.view": "View",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "모든 서비스", 147 "menu.workspaces.defaultWorkspace": "모든 서비스",
149 "menu.workspaces.openWorkspaceDrawer": "ìž‘ì—…ì˜ì—­ ì„œëž ì—´ê¸°", 148 "menu.workspaces.openWorkspaceDrawer": "ìž‘ì—…ì˜ì—­ ì„œëž ì—´ê¸°",
150 "password.email.label": "ì´ë©”ì¼ ì£¼ì†Œ", 149 "password.email.label": "ì´ë©”ì¼ ì£¼ì†Œ",
151 "password.headline": "비밀번호 초기화", 150 "password.headline": "Reset password",
152 "password.link.login": "ê³„ì •ì— ë¡œê·¸ì¸í•˜ì„¸ìš”.", 151 "password.link.login": "ê³„ì •ì— ë¡œê·¸ì¸í•˜ì„¸ìš”.",
153 "password.link.signup": "무료 계정 ìƒì„±", 152 "password.link.signup": "무료 계정 ìƒì„±",
154 "password.noUser": "해당 ì´ë©”ì¼ì„ 사용하는 유저를 ì°¾ì„ ìˆ˜ 없습니다.", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "ì´ë©”ì¼ì„ 확ì¸í•´ 주세요.", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "계정 ë™ê¸°í™”",
157 "pricing.features.customWebsites": "ì‚¬ìš©ìž ì§€ì • 웹사ì´íŠ¸ 추가",
158 "pricing.features.desktopNotifications": "ë°ìŠ¤í¬íƒ‘ 알림",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "서비스 프ë¡ì‹œ",
162 "pricing.features.spellchecker": "ì² ìž ê²€ì‚¬ 지ì›",
163 "pricing.features.teamManagement": "팀 관리",
164 "pricing.features.thirdPartyServices": "ì¨ë“œíŒŒí‹° 서비스 설치",
165 "pricing.features.unlimitedServices": "무제한 서비스 추가",
166 "pricing.features.workspaces": "작업 공간",
167 "service.crashHandler.action": "재시작 {name}", 155 "service.crashHandler.action": "재시작 {name}",
168 "service.crashHandler.autoReload": "{seconds} ì´ˆë‚´ì— ìžë™ìœ¼ë¡œ {name} ì„ ë³µì›í•©ë‹ˆë‹¤.", 156 "service.crashHandler.autoReload": "{seconds} ì´ˆë‚´ì— ìžë™ìœ¼ë¡œ {name} ì„ ë³µì›í•©ë‹ˆë‹¤.",
169 "service.crashHandler.headline": "ì´ëŸ°!", 157 "service.crashHandler.headline": "ì´ëŸ°!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "ê³„ì •ì—†ì´ Ferdi 사용하기", 170 "services.serverless": "ê³„ì •ì—†ì´ Ferdi 사용하기",
183 "services.welcome": "Ferdiì— ì˜¤ì‹  ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤.", 171 "services.welcome": "Ferdiì— ì˜¤ì‹  ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤.",
184 "settings.account.account.editButton": "계정 편집", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "ê³„ì •ì„ ì‚¬ìš©í•  수 없습니다.", 173 "settings.account.accountUnavailable": "ê³„ì •ì„ ì‚¬ìš©í•  수 없습니다.",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "프로필 수정", 175 "settings.account.buttonSave": "프로필 수정",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "ë°›ì€ ì´ë©”ì¼ì— 있는 ë§í¬ë¥¼ 통해 계정 삭제를 확ì¸í–ˆë‹¤ë©´ 계정과 ë°ì´í„°ëŠ” 복구ë˜ì§€ 않습니다.", 177 "settings.account.deleteEmailSent": "ë°›ì€ ì´ë©”ì¼ì— 있는 ë§í¬ë¥¼ 통해 계정 삭제를 확ì¸í–ˆë‹¤ë©´ 계정과 ë°ì´í„°ëŠ” 복구ë˜ì§€ 않습니다.",
190 "settings.account.deleteInfo": "ë” ì´ìƒ Ferdi ê³„ì •ì´ í•„ìš”í•˜ì§€ 않다면 여기서 모든 관련한 ë°ì´í„°ì™€ ê³„ì •ì„ ì‚­ì œí•  수 있습니다.", 178 "settings.account.deleteInfo": "ë” ì´ìƒ Ferdi ê³„ì •ì´ í•„ìš”í•˜ì§€ 않다면 여기서 모든 관련한 ë°ì´í„°ì™€ ê³„ì •ì„ ì‚­ì œí•  수 있습니다.",
191 "settings.account.headline": "계정", 179 "settings.account.headline": "계정",
192 "settings.account.headlineAccount": "계정 정보", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "위험 설정", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "청구서", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "비밀번호 변경", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "프로필 수정", 184 "settings.account.headlineProfile": "프로필 수정",
197 "settings.account.successInfo": "ë³€ê²½ì‚¬í•­ì´ ì €ìž¥ë˜ì—ˆìŠµë‹ˆë‹¤.", 185 "settings.account.successInfo": "ë³€ê²½ì‚¬í•­ì´ ì €ìž¥ë˜ì—ˆìŠµë‹ˆë‹¤.",
198 "settings.account.tryReloadServices": "다시 ì‹œë„하세요.", 186 "settings.account.tryReloadServices": "다시 ì‹œë„하세요.",
199 "settings.account.tryReloadUserInfoRequest": "다시 ì‹œë„하세요.", 187 "settings.account.tryReloadUserInfoRequest": "다시 ì‹œë„하세요.",
200 "settings.account.userInfoRequestFailed": "ì‚¬ìš©ìž ì •ë³´ë¥¼ 불러올 수 없습니다.", 188 "settings.account.userInfoRequestFailed": "ì‚¬ìš©ìž ì •ë³´ë¥¼ 불러올 수 없습니다.",
201 "settings.account.yourLicense": "Ferdi ë¼ì´ì„¼ìŠ¤", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "ìºì‹œ 지우기", 191 "settings.app.buttonClearAllCache": "ìºì‹œ 지우기",
204 "settings.app.buttonInstallUpdate": "재시작 후 ì—…ë°ì´íŠ¸ 설치", 192 "settings.app.buttonInstallUpdate": "재시작 후 ì—…ë°ì´íŠ¸ 설치",
@@ -225,7 +213,7 @@
225 "settings.app.form.enableLock": "암호 잠금 활성화", 213 "settings.app.form.enableLock": "암호 잠금 활성화",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "맞춤법 검사 활성화", 215 "settings.app.form.enableSpellchecking": "맞춤법 검사 활성화",
228 "settings.app.form.enableSystemTray": "Ferdi 시스템 트레ì´ì— 표시", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "하ì´ë²„네ì´ì…˜ ì „ëžµ", 219 "settings.app.form.hibernationStrategy": "하ì´ë²„네ì´ì…˜ ì „ëžµ",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "사용하지 않는 서비스 출력", 239 "settings.app.form.showDisabledServices": "사용하지 않는 서비스 출력",
252 "settings.app.form.showDragArea": "드래그 가능 ì˜ì—­ 보기", 240 "settings.app.form.showDragArea": "드래그 가능 ì˜ì—­ 보기",
253 "settings.app.form.showMessagesBadgesWhenMuted": "ì•Œë¦¼ì´ ë¹„í™œì„±í™”ìž‰ã„¹ ë•Œ ì½ì§€ ì•Šì€ ë©”ì„¸ì§€ 배지 표시", 241 "settings.app.form.showMessagesBadgesWhenMuted": "ì•Œë¦¼ì´ ë¹„í™œì„±í™”ìž‰ã„¹ ë•Œ ì½ì§€ ì•Šì€ ë©”ì„¸ì§€ 배지 표시",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "최소화 ëœ ìƒíƒœë¡œ 시작", 243 "settings.app.form.startMinimized": "최소화 ëœ ìƒíƒœë¡œ 시작",
255 "settings.app.form.universalDarkMode": "ì „ì²´ ë‹¤í¬ ëª¨ë“œ 활성화", 244 "settings.app.form.universalDarkMode": "ì „ì²´ ë‹¤í¬ ëª¨ë“œ 활성화",
256 "settings.app.form.useTouchIdToUnlock": "TouchIDë¡œ Ferdi 여는 ê²ƒì„ í—ˆìš©", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "고급", 248 "settings.app.headlineAdvanced": "고급",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "ê³µì‹ ì§€ìš°ë„ˆ 언어는 ì˜ì–´ì™€ ë…ì¼ì–´ì´ë©° ì´ì™¸ ì–¸ì–´ë“¤ì€ ì»¤ë®¤ë‹ˆí‹°ì— ì˜í•´ 번역ë˜ê³  있습니다.", 256 "settings.app.languageDisclaimer": "ê³µì‹ ì§€ìš°ë„ˆ 언어는 ì˜ì–´ì™€ ë…ì¼ì–´ì´ë©° ì´ì™¸ ì–¸ì–´ë“¤ì€ ì»¤ë®¤ë‹ˆí‹°ì— ì˜í•´ 번역ë˜ê³  있습니다.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "비밀번호", 258 "settings.app.lockedPassword": "비밀번호",
270 "settings.app.lockedPasswordInfo": "기억할 수 있는 비밀번호로 설정해주세요.\n만약 비밀번호를 잃어버리면 Ferdi 재설치를 해야합니다.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "ë³€ê²½ì‚¬í•­ì„ ì ìš©í•˜ê¸° 위해 재시작", 260 "settings.app.restartRequired": "ë³€ê²½ì‚¬í•­ì„ ì ìš©í•˜ê¸° 위해 재시작",
272 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.", 261 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.", 262 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
@@ -296,7 +285,7 @@
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "개발 문서", 287 "settings.recipes.customService.openDevDocs": "개발 문서",
299 "settings.recipes.customService.openFolder": "í´ë” 열기", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "사용가능 한 서비스", 289 "settings.recipes.headline": "사용가능 한 서비스",
301 "settings.recipes.missingService": "서비스가 ë³´ì´ì§€ 않습니까?", 290 "settings.recipes.missingService": "서비스가 ë³´ì´ì§€ 않습니까?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "서비스 삭제", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "편집 {name}", 305 "settings.service.form.editServiceHeadline": "편집 {name}",
317 "settings.service.form.enableAudio": "오디오 활성화", 306 "settings.service.form.enableAudio": "오디오 활성화",
318 "settings.service.form.enableBadge": "ì½ì§€ ì•Šì€ ë©”ì„¸ì§€ 배지 표시", 307 "settings.service.form.enableBadge": "ì½ì§€ ì•Šì€ ë©”ì„¸ì§€ 배지 표시",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "비활성화 ì‹œ 모든 알림 ì†Œë¦¬ë„ êº¼ì§‘ë‹ˆë‹¤.", 322 "settings.service.form.isMutedInfo": "비활성화 ì‹œ 모든 알림 ì†Œë¦¬ë„ êº¼ì§‘ë‹ˆë‹¤.",
334 "settings.service.form.name": "ì´ë¦„", 323 "settings.service.form.name": "ì´ë¦„",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "darkmode.css 열기", 325 "settings.service.form.openDarkmodeCss": "darkmode.css 열기",
336 "settings.service.form.openUserCss": "user.css 열기", 326 "settings.service.form.openUserCss": "user.css 열기",
337 "settings.service.form.openUserJs": "user.js 열기", 327 "settings.service.form.openUserJs": "user.js 열기",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS 프ë¡ì‹œ 설정", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS 프ë¡ì‹œ 설정",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "프ë¡ì‹œ ì„¤ì •ì´ Ferdi 서버와 ë™ê¸°í™”ë˜ì§€ 않았습니다.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "프ë¡ì‹œ 사용하기", 331 "settings.service.form.proxy.isEnabled": "프ë¡ì‹œ 사용하기",
342 "settings.service.form.proxy.password": "비밀번호 (ì„ íƒ)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "í¬íŠ¸", 333 "settings.service.form.proxy.port": "í¬íŠ¸",
344 "settings.service.form.proxy.restartInfo": "프ë¡ì‹œ 설정 변경 후 Ferdi를 재시작 해주세요.", 334 "settings.service.form.proxy.restartInfo": "프ë¡ì‹œ 설정 변경 후 Ferdi를 재시작 해주세요.",
345 "settings.service.form.proxy.user": "ì‚¬ìš©ìž ì˜µì…˜", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "서비스 저장", 337 "settings.service.form.saveButton": "서비스 저장",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "서비스 발견", 344 "settings.services.discoverServices": "서비스 발견",
355 "settings.services.headline": "서비스", 345 "settings.services.headline": "서비스",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "서비스를 불러올 수 없습니다.", 348 "settings.services.servicesRequestFailed": "서비스를 불러올 수 없습니다.",
358 "settings.services.tooltip.isDisabled": "서비스를 사용할 수 없습니다.", 349 "settings.services.tooltip.isDisabled": "서비스를 사용할 수 없습니다.",
359 "settings.services.tooltip.isMuted": "모든 소리가 꺼져있습니다.", 350 "settings.services.tooltip.isMuted": "모든 소리가 꺼져있습니다.",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>",
363 "settings.supportFerdi.bannerText": "Ferdi 서비스 í–¥ìƒì— ë„ì›€ì„ ì£¼ê¸°ë¥¼ ì›í•˜ì‹­ë‹ˆê¹Œ?", 354 "settings.supportFerdi.bannerText": "Ferdi 서비스 í–¥ìƒì— ë„ì›€ì„ ì£¼ê¸°ë¥¼ ì›í•˜ì‹­ë‹ˆê¹Œ?",
364 "settings.supportFerdi.headline": "Ferdiì— ëŒ€í•´", 355 "settings.supportFerdi.headline": "Ferdiì— ëŒ€í•´",
365 "settings.supportFerdi.openSurvey": "설문조사 열기", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "If you feel like supporting Ferdi development with a donation, you can do so on both,", 357 "settings.supportFerdi.textDonation": "If you feel like supporting Ferdi development with a donation, you can do so on both,",
367 "settings.supportFerdi.textDonationAnd": "그리고", 358 "settings.supportFerdi.textDonationAnd": "그리고",
368 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our", 359 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our",
369 "settings.supportFerdi.textGitHubSponsors": "깃허브 후ì›ìž", 360 "settings.supportFerdi.textGitHubSponsors": "깃허브 후ì›ìž",
370 "settings.supportFerdi.textListContributors": "ê¸°ì—¬ìž ì „ì²´ 목ë¡", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "here", 362 "settings.supportFerdi.textListContributorsHere": "here",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Support is always welcome. You can find a list of the help we need", 364 "settings.supportFerdi.textSupportWelcome": "Support is always welcome. You can find a list of the help we need",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "비ì˜ë¦¬", 378 "settings.user.form.accountType.non-profit": "비ì˜ë¦¬",
388 "settings.user.form.currentPassword": "현재 비밀번호", 379 "settings.user.form.currentPassword": "현재 비밀번호",
389 "settings.user.form.email": "ì´ë©”ì¼", 380 "settings.user.form.email": "ì´ë©”ì¼",
390 "settings.user.form.firstname": "ì´ë¦„(성 제외)", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "성", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "새로운 비밀번호", 383 "settings.user.form.newPassword": "새로운 비밀번호",
393 "settings.workspace.add.form.name": "ì´ë¦„", 384 "settings.workspace.add.form.name": "ì´ë¦„",
394 "settings.workspace.add.form.submitButton": "새로운 ìž‘ì—…ì˜ì—­ ìƒì„±í•˜ê¸°", 385 "settings.workspace.add.form.submitButton": "새로운 ìž‘ì—…ì˜ì—­ ìƒì„±í•˜ê¸°",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "알림과 오디오 활성화", 411 "sidebar.unmuteApp": "알림과 오디오 활성화",
421 "signup.email.label": "ì´ë©”ì¼ ì£¼ì†Œ", 412 "signup.email.label": "ì´ë©”ì¼ ì£¼ì†Œ",
422 "signup.emailDuplicate": "해당 ì´ë©”ì¼ì„ 가진 사용ìžê°€ ì´ë¯¸ 존재합니다", 413 "signup.emailDuplicate": "해당 ì´ë©”ì¼ì„ 가진 사용ìžê°€ ì´ë¯¸ 존재합니다",
423 "signup.firstname.label": "ì´ë¦„(성 제외)", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "íšŒì› ê°€ìž…", 415 "signup.headline": "íšŒì› ê°€ìž…",
425 "signup.lastname.label": "성", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "By creating a Ferdi account you accept the", 417 "signup.legal.info": "By creating a Ferdi account you accept the",
427 "signup.legal.privacy": "ê°œì¸ì •ë³´ë³´í˜¸ì •ì±…", 418 "signup.legal.privacy": "ê°œì¸ì •ë³´ë³´í˜¸ì •ì±…",
428 "signup.legal.terms": "ì´ìš© 약관", 419 "signup.legal.terms": "ì´ìš© 약관",
@@ -430,11 +421,11 @@
430 "signup.password.label": "비밀번호", 421 "signup.password.label": "비밀번호",
431 "signup.submit.label": "계정 만들기", 422 "signup.submit.label": "계정 만들기",
432 "tabs.item.confirmDeleteService": "{serviceName} 서비스를 ì •ë§ë¡œ 삭제하시겠습니까?", 423 "tabs.item.confirmDeleteService": "{serviceName} 서비스를 ì •ë§ë¡œ 삭제하시겠습니까?",
433 "tabs.item.deleteService": "서비스 삭제", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "오디오 비활성화", 425 "tabs.item.disableAudio": "오디오 비활성화",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "알림 비활성화", 427 "tabs.item.disableNotifications": "알림 비활성화",
437 "tabs.item.disableService": "서비스 비활성화", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "오디오 활성화", 429 "tabs.item.enableAudio": "오디오 활성화",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "알림 허용", 431 "tabs.item.enableNotification": "알림 허용",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "새로고침", 434 "tabs.item.reload": "새로고침",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} 는 유효하지 않습니다.", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} 는 최소한 {length} 보다 길어야 합니다.", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "ì ì–´ë„ 하나는 í•„ìš” 합니다.", 438 "validation.oneRequired": "ì ì–´ë„ 하나는 í•„ìš” 합니다.",
448 "validation.required": "{field} 는 필수입니다.", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} 는 유효하지 ì•Šì€ URL입니다.", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "뒤로가기", 441 "webControls.back": "뒤로가기",
451 "webControls.forward": "앞으로 가기", 442 "webControls.forward": "앞으로 가기",
452 "webControls.goHome": "홈", 443 "webControls.goHome": "홈",
@@ -454,12 +445,12 @@
454 "webControls.reload": "새로고침", 445 "webControls.reload": "새로고침",
455 "welcome.loginButton": "ê³„ì •ì— ë¡œê·¸ì¸í•˜ì„¸ìš”.", 446 "welcome.loginButton": "ê³„ì •ì— ë¡œê·¸ì¸í•˜ì„¸ìš”.",
456 "welcome.signupButton": "무료 계정 ìƒì„±", 447 "welcome.signupButton": "무료 계정 ìƒì„±",
457 "workspaceDrawer.addNewWorkspaceLabel": "새 ìž‘ì—…ì˜ì—­ì„ 만듭니다.", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "모든 서비스", 449 "workspaceDrawer.allServices": "모든 서비스",
459 "workspaceDrawer.headline": "작업 공간", 450 "workspaceDrawer.headline": "작업 공간",
460 "workspaceDrawer.item.contextMenuEdit": "편집", 451 "workspaceDrawer.item.contextMenuEdit": "편집",
461 "workspaceDrawer.item.noServicesAddedYet": "ì¶”ê°€ëœ ì„œë¹„ìŠ¤ê°€ 없습니다.", 452 "workspaceDrawer.item.noServicesAddedYet": "ì¶”ê°€ëœ ì„œë¹„ìŠ¤ê°€ 없습니다.",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "작업공간 설정 편집", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Switching to" 455 "workspaces.switchingIndicator.switchingTo": "Switching to"
465} 456}
diff --git a/src/i18n/locales/nl-BE.json b/src/i18n/locales/nl-BE.json
index b9ca228ba..5104d1bc2 100644
--- a/src/i18n/locales/nl-BE.json
+++ b/src/i18n/locales/nl-BE.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Herladen", 2 "app.errorHandler.action": "Herladen",
3 "app.errorHandler.headline": "Er ging iets mis", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Aangepaste server", 4 "changeserver.customServerLabel": "Aangepaste server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Kan geen verbinding maken met de Ferdi services", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Annuleren", 27 "global.cancel": "Cancel",
29 "global.edit": "Bewerken", 28 "global.edit": "Bewerken",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Je hebt geen internet verbinding.", 30 "global.notConnectedToTheInternet": "Je hebt geen internet verbinding.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Instellingen", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Gebruik Systeemstandaard ({default})", 36 "global.spellchecker.useDefault": "Gebruik Systeemstandaard ({default})",
38 "global.spellchecking.autodetect": "Taal automatisch herkennen", 37 "global.spellchecking.autodetect": "Taal automatisch herkennen",
39 "global.spellchecking.autodetect.short": "Automatisch", 38 "global.spellchecking.autodetect.short": "Automatisch",
40 "global.spellchecking.language": "Taal spellingscontrole", 39 "global.spellchecking.language": "Taal spellingscontrole",
41 "global.submit": "Verzenden", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importeer je Ferdi 4 services", 44 "import.headline": "Importeer je Ferdi 4 services",
46 "import.notSupportedHeadline": "De volgende services worden nog niet ondersteund in Ferdi 5", 45 "import.notSupportedHeadline": "De volgende services worden nog niet ondersteund in Ferdi 5",
47 "import.skip.label": "Ik wil services handmatig toevoegen", 46 "import.skip.label": "Ik wil services handmatig toevoegen",
48 "import.submit.label": "Importeer services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Wat is er nieuw?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Opnieuw opstarten & update installeren", 50 "infobar.buttonInstallUpdate": "Opnieuw opstarten & update installeren",
52 "infobar.buttonReloadServices": "Services opnieuw laden", 51 "infobar.buttonReloadServices": "Services opnieuw laden",
53 "infobar.hide": "Verbergen", 52 "infobar.hide": "Verbergen",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-mailadres", 74 "login.email.label": "E-mailadres",
76 "login.headline": "Inloggen", 75 "login.headline": "Inloggen",
77 "login.invalidCredentials": "E-mailadres of wachtwoord ongeldig", 76 "login.invalidCredentials": "E-mailadres of wachtwoord ongeldig",
78 "login.link.password": "Wachtwoord resetten", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Maak een gratis account aan", 78 "login.link.signup": "Maak een gratis account aan",
80 "login.password.label": "Password", 79 "login.password.label": "Password",
81 "login.serverLogout": "De sessie is verlopen, log opnieuw in alsjeblieft.", 80 "login.serverLogout": "De sessie is verlopen, log opnieuw in alsjeblieft.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Ondersteuning", 116 "menu.help.support": "Ondersteuning",
118 "menu.help.tos": "Servicevoorwaarden", 117 "menu.help.tos": "Servicevoorwaarden",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Vorige dienst activeren", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Volgende dienst activeren", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Enable Todos", 124 "menu.todos.enableTodos": "Enable Todos",
126 "menu.view": "Weergave", 125 "menu.view": "Weergave",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Alle services", 147 "menu.workspaces.defaultWorkspace": "Alle services",
149 "menu.workspaces.openWorkspaceDrawer": "Werkruimtepagina openen", 148 "menu.workspaces.openWorkspaceDrawer": "Werkruimtepagina openen",
150 "password.email.label": "E-mailadres", 149 "password.email.label": "E-mailadres",
151 "password.headline": "Wachtwoord resetten", 150 "password.headline": "Reset password",
152 "password.link.login": "Log in op je account", 151 "password.link.login": "Log in op je account",
153 "password.link.signup": "Maak een gratis account aan", 152 "password.link.signup": "Maak een gratis account aan",
154 "password.noUser": "Geen gebruiker gevonden met dat e-mailadres", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Controleer alsjeblieft je e-mail", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Werkruimten",
167 "service.crashHandler.action": "{naam} herladen", 155 "service.crashHandler.action": "{naam} herladen",
168 "service.crashHandler.autoReload": "Ga proberen om {name} te herstellen over {seconds} seconden", 156 "service.crashHandler.autoReload": "Ga proberen om {name} te herstellen over {seconds} seconden",
169 "service.crashHandler.headline": "Oh nee!", 157 "service.crashHandler.headline": "Oh nee!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Welkom bij Ferdi", 171 "services.welcome": "Welkom bij Ferdi",
184 "settings.account.account.editButton": "Account bewerken", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Profiel bijwerken", 175 "settings.account.buttonSave": "Profiel bijwerken",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "U heeft een email ontvangen met een bevestiginslink om uw account te verwijderen. Uw account en de bijhorende gegevens kunnen niet meer worden herstel na deze actie!", 177 "settings.account.deleteEmailSent": "U heeft een email ontvangen met een bevestiginslink om uw account te verwijderen. Uw account en de bijhorende gegevens kunnen niet meer worden herstel na deze actie!",
190 "settings.account.deleteInfo": "Indien u uw Ferdi account niet meer nodig heeft, kan u hier uw account en alle gerelateerde gegevens verwijderen.", 178 "settings.account.deleteInfo": "Indien u uw Ferdi account niet meer nodig heeft, kan u hier uw account en alle gerelateerde gegevens verwijderen.",
191 "settings.account.headline": "Account", 179 "settings.account.headline": "Account",
192 "settings.account.headlineAccount": "Account informatie", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Gevarenzone", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Facturen", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Wijzig wachtwoord", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Profiel bijwerken", 184 "settings.account.headlineProfile": "Profiel bijwerken",
197 "settings.account.successInfo": "Je wijzigingen zijn opgeslagen", 185 "settings.account.successInfo": "Je wijzigingen zijn opgeslagen",
198 "settings.account.tryReloadServices": "Probeer opnieuw", 186 "settings.account.tryReloadServices": "Probeer opnieuw",
199 "settings.account.tryReloadUserInfoRequest": "Probeer opnieuw", 187 "settings.account.tryReloadUserInfoRequest": "Probeer opnieuw",
200 "settings.account.userInfoRequestFailed": "Kon gebruikersinformatie niet laden", 188 "settings.account.userInfoRequestFailed": "Kon gebruikersinformatie niet laden",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Cache wissen", 191 "settings.app.buttonClearAllCache": "Cache wissen",
204 "settings.app.buttonInstallUpdate": "Opnieuw opstarten & update installeren", 192 "settings.app.buttonInstallUpdate": "Opnieuw opstarten & update installeren",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Dark Mode aanzetten",
224 "settings.app.form.enableGPUAcceleration": "GPU Acceleratie Activeren", 212 "settings.app.form.enableGPUAcceleration": "GPU Acceleratie Activeren",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Spellingcontrole inschakelen", 215 "settings.app.form.enableSpellchecking": "Spellingcontrole inschakelen",
228 "settings.app.form.enableSystemTray": "Toon Ferdi in de systeembalk", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Toon uitgeschakelde services", 239 "settings.app.form.showDisabledServices": "Toon uitgeschakelde services",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Toon badge met ongelezen berichten wanneer meldingen zijn uitgeschakeld", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Toon badge met ongelezen berichten wanneer meldingen zijn uitgeschakeld",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Service verwijderen", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Bewerk {name}", 305 "settings.service.form.editServiceHeadline": "Bewerk {name}",
317 "settings.service.form.enableAudio": "Audio inschakelen", 306 "settings.service.form.enableAudio": "Audio inschakelen",
318 "settings.service.form.enableBadge": "Toon badges met ongelezen berichten", 307 "settings.service.form.enableBadge": "Toon badges met ongelezen berichten",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Indien uitgeschakeld zullen alle meldingsgeluiden en afgespeelde audio uitgeschakeld zijn", 322 "settings.service.form.isMutedInfo": "Indien uitgeschakeld zullen alle meldingsgeluiden en afgespeelde audio uitgeschakeld zijn",
334 "settings.service.form.name": "Naam", 323 "settings.service.form.name": "Naam",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Instellingen", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Instellingen",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy instellingen worden niet gesynchroniseerd met de Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Proxy gebruiken", 331 "settings.service.form.proxy.isEnabled": "Proxy gebruiken",
342 "settings.service.form.proxy.password": "Wachtwoord (optioneel)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Poort", 333 "settings.service.form.proxy.port": "Poort",
344 "settings.service.form.proxy.restartInfo": "Start Ferdi opnieuw op na het aanpassen van proxy Instellingen.", 334 "settings.service.form.proxy.restartInfo": "Start Ferdi opnieuw op na het aanpassen van proxy Instellingen.",
345 "settings.service.form.proxy.user": "Gebruiker (optioneel)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Service opslaan", 337 "settings.service.form.saveButton": "Service opslaan",
348 "settings.service.form.tabHosted": "Gehost", 338 "settings.service.form.tabHosted": "Gehost",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Services ontdekken", 344 "settings.services.discoverServices": "Services ontdekken",
355 "settings.services.headline": "Jouw services", 345 "settings.services.headline": "Jouw services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Kan je diensten niet laden", 348 "settings.services.servicesRequestFailed": "Kan je diensten niet laden",
358 "settings.services.tooltip.isDisabled": "Service is uitgeschakeld", 349 "settings.services.tooltip.isDisabled": "Service is uitgeschakeld",
359 "settings.services.tooltip.isMuted": "Alle geluiden zijn uitgeschakeld", 350 "settings.services.tooltip.isMuted": "Alle geluiden zijn uitgeschakeld",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Non-Profit", 378 "settings.user.form.accountType.non-profit": "Non-Profit",
388 "settings.user.form.currentPassword": "Huidig wachtwoord", 379 "settings.user.form.currentPassword": "Huidig wachtwoord",
389 "settings.user.form.email": "Email", 380 "settings.user.form.email": "Email",
390 "settings.user.form.firstname": "Voornaam", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Achternaam", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nieuw wachtwoord", 383 "settings.user.form.newPassword": "Nieuw wachtwoord",
393 "settings.workspace.add.form.name": "Naam", 384 "settings.workspace.add.form.name": "Naam",
394 "settings.workspace.add.form.submitButton": "Maak werkruimte aan", 385 "settings.workspace.add.form.submitButton": "Maak werkruimte aan",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Berichten & geluid inschakelen", 411 "sidebar.unmuteApp": "Berichten & geluid inschakelen",
421 "signup.email.label": "E-mailadres", 412 "signup.email.label": "E-mailadres",
422 "signup.emailDuplicate": "Er bestaat al een gebruiker met dat e-mailadres", 413 "signup.emailDuplicate": "Er bestaat al een gebruiker met dat e-mailadres",
423 "signup.firstname.label": "Voornaam", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Registreren", 415 "signup.headline": "Registreren",
425 "signup.lastname.label": "Achternaam", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Door een account aan te maken aanvaard je de", 417 "signup.legal.info": "Door een account aan te maken aanvaard je de",
427 "signup.legal.privacy": "Privacyverklaring", 418 "signup.legal.privacy": "Privacyverklaring",
428 "signup.legal.terms": "Servicevoorwaarden", 419 "signup.legal.terms": "Servicevoorwaarden",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Password", 421 "signup.password.label": "Password",
431 "signup.submit.label": "Account aanmaken", 422 "signup.submit.label": "Account aanmaken",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Service verwijderen", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Audio uitschakelen", 425 "tabs.item.disableAudio": "Audio uitschakelen",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Notificaties uitschakelen", 427 "tabs.item.disableNotifications": "Notificaties uitschakelen",
437 "tabs.item.disableService": "Service uitschakelen", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Audio inschakelen", 429 "tabs.item.enableAudio": "Audio inschakelen",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Notificaties aanzetten", 431 "tabs.item.enableNotification": "Notificaties aanzetten",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Herladen", 434 "tabs.item.reload": "Herladen",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} is niet geldig", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} moet minimaal {length} karakters lang zijn", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Ten minste één is vereist", 438 "validation.oneRequired": "Ten minste één is vereist",
448 "validation.required": "{field} is vereist", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} is niet een geldige URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Back", 441 "webControls.back": "Back",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Herladen", 445 "webControls.reload": "Herladen",
455 "welcome.loginButton": "Inloggen op je account", 446 "welcome.loginButton": "Inloggen op je account",
456 "welcome.signupButton": "Maak een gratis account aan", 447 "welcome.signupButton": "Maak een gratis account aan",
457 "workspaceDrawer.addNewWorkspaceLabel": "Voeg een nieuwe werkruimte toe", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Alle services", 449 "workspaceDrawer.allServices": "Alle services",
459 "workspaceDrawer.headline": "Werkruimten", 450 "workspaceDrawer.headline": "Werkruimten",
460 "workspaceDrawer.item.contextMenuEdit": "bewerken", 451 "workspaceDrawer.item.contextMenuEdit": "bewerken",
461 "workspaceDrawer.item.noServicesAddedYet": "Nog geen diensten toegevoegd", 452 "workspaceDrawer.item.noServicesAddedYet": "Nog geen diensten toegevoegd",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Pas werkruimte instellingen aan", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Overschakelen naar" 455 "workspaces.switchingIndicator.switchingTo": "Overschakelen naar"
465} 456}
diff --git a/src/i18n/locales/nl.json b/src/i18n/locales/nl.json
index eac72627f..6899e02ee 100644
--- a/src/i18n/locales/nl.json
+++ b/src/i18n/locales/nl.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Herladen", 2 "app.errorHandler.action": "Herladen",
3 "app.errorHandler.headline": "Er is iets mis gegaan", 3 "app.errorHandler.headline": "Er is iets mis gegaan.",
4 "changeserver.customServerLabel": "Aangepaste server", 4 "changeserver.customServerLabel": "Aangepaste server",
5 "changeserver.headline": "Server wijzigen", 5 "changeserver.headline": "Server wijzigen",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -9,13 +9,12 @@
9 "connectionLostBanner.cta": "Een service opnieuw laden", 9 "connectionLostBanner.cta": "Een service opnieuw laden",
10 "connectionLostBanner.informationLink": "Wat gebeurde er?", 10 "connectionLostBanner.informationLink": "Wat gebeurde er?",
11 "connectionLostBanner.message": "Oh nee! Ferdi heeft de verbinding met {name} verloren.", 11 "connectionLostBanner.message": "Oh nee! Ferdi heeft de verbinding met {name} verloren.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Log in",
13 "feature.debugger.title": "Foutopsporingsinformatie publiceren",
14 "feature.nightlyBuilds.activate": "Activeren", 13 "feature.nightlyBuilds.activate": "Activeren",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nachtelijke builds zijn zeer experimentele versies van Ferdi die ongepolijste of onvoltooide functies kunnen bevatten. Deze nightly builds worden voornamelijk gebruikt door ontwikkelaars om hun nieuwe functies te testen en hoe ze zullen presteren in de finale build. Als je niet weet wat je aan het doen bent, raden we aan om nachtelijke versies niet te activeren.",
16 "feature.nightlyBuilds.title": "Nachtelijke builds", 15 "feature.nightlyBuilds.title": "Nachtelijke builds",
17 "feature.publishDebugInfo.error": "Er is een fout opgetreden tijdens het publiceren van de debug informatie. Probeer het later opnieuw of bekijk de console voor meer informatie.", 16 "feature.publishDebugInfo.error": "Er is een fout opgetreden tijdens het publiceren van de debug informatie. Probeer het later opnieuw of bekijk de console voor meer informatie.",
18 "feature.publishDebugInfo.info": "Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service", 17 "feature.publishDebugInfo.info": "Publiceren van uw debug informatie helpt ons problemen en fouten te vinden in Ferdi. Door uw debug informatie te publiceren, accepteert u het privacybeleid en de gebruiksvoorwaarden van Ferdi Debugger",
19 "feature.publishDebugInfo.privacy": "Privacybeleid", 18 "feature.publishDebugInfo.privacy": "Privacybeleid",
20 "feature.publishDebugInfo.publish": "Accepteren en publiceren", 19 "feature.publishDebugInfo.publish": "Accepteren en publiceren",
21 "feature.publishDebugInfo.published": "Je foutopsporingslogboek is gepubliceerd en is nu beschikbaar op", 20 "feature.publishDebugInfo.published": "Je foutopsporingslogboek is gepubliceerd en is nu beschikbaar op",
@@ -23,30 +22,30 @@
23 "feature.publishDebugInfo.title": "Foutopsporingsinformatie publiceren", 22 "feature.publishDebugInfo.title": "Foutopsporingsinformatie publiceren",
24 "feature.quickSwitch.info": "Selecteer een service met TAB, ↑ en ↓. Open een service met ENTER.", 23 "feature.quickSwitch.info": "Selecteer een service met TAB, ↑ en ↓. Open een service met ENTER.",
25 "feature.quickSwitch.search": "Zoeken...", 24 "feature.quickSwitch.search": "Zoeken...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "Quickswitch",
27 "global.api.unhealthy": "Kan geen verbinding maken met de Ferdi-services.", 26 "global.api.unhealthy": "Kan geen verbinding maken met de Ferdi-services",
28 "global.cancel": "Annuleer", 27 "global.cancel": "Annuleer",
29 "global.edit": "Bewerk", 28 "global.edit": "Bewerk",
30 "global.no": "No", 29 "global.no": "Nee",
31 "global.notConnectedToTheInternet": "U bent niet verbonden met het internet.", 30 "global.notConnectedToTheInternet": "U bent niet verbonden met het internet.",
32 "global.ok": "Ok", 31 "global.ok": "Oké",
33 "global.quit": "Quit", 32 "global.quit": "Afsluiten",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Wil je echt stoppen?",
35 "global.save": "Save", 34 "global.save": "Opslaan",
36 "global.settings": "Instellingen", 35 "global.settings": "Instellingen",
37 "global.spellchecker.useDefault": "Gebruik systeemstandaard ({default})", 36 "global.spellchecker.useDefault": "Gebruik systeemstandaard ({default})",
38 "global.spellchecking.autodetect": "Taal automatisch herkennen", 37 "global.spellchecking.autodetect": "Taal automatisch herkennen",
39 "global.spellchecking.autodetect.short": "Automatisch", 38 "global.spellchecking.autodetect.short": "Automatisch",
40 "global.spellchecking.language": "Taal voor spellingcontrole", 39 "global.spellchecking.language": "Taal voor spellingcontrole",
41 "global.submit": "Verzenden", 40 "global.submit": "Verzenden",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Gebruik 'https://whatmyuseragent.com/' om te ontdekken of 'https://developers.whatismybrowser.com/useragents/explore/' om je gewenste user-agent te kiezen en het hier te kopiëren en plakken.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Ja",
45 "import.headline": "Importeer uw Ferdi 4-services", 44 "import.headline": "Importeer uw Ferdi 4-services",
46 "import.notSupportedHeadline": "Services die (nog) niet ondersteund worden in Ferdi 5", 45 "import.notSupportedHeadline": "Services die (nog) niet ondersteund worden in Ferdi 5",
47 "import.skip.label": "Ik wil diensten handmatig toevoegen", 46 "import.skip.label": "Ik wil diensten handmatig toevoegen",
48 "import.submit.label": "Importeer services", 47 "import.submit.label": "Importeer {count} diensten",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "Er zijn fouten opgetreden tijdens het uitvoeren van een geverifieerd verzoek. Probeer opnieuw in te loggen als deze fout zich blijft voordoen.",
50 "infobar.buttonChangelog": "Wat is er nieuw?", 49 "infobar.buttonChangelog": "Wat is er nieuw?",
51 "infobar.buttonInstallUpdate": "Opnieuw opstarten & update installeren", 50 "infobar.buttonInstallUpdate": "Opnieuw opstarten & update installeren",
52 "infobar.buttonReloadServices": "Services opnieuw laden", 51 "infobar.buttonReloadServices": "Services opnieuw laden",
@@ -54,7 +53,7 @@
54 "infobar.requiredRequestsFailed": "Kan de services en gebruikersinformatie niet laden", 53 "infobar.requiredRequestsFailed": "Kan de services en gebruikersinformatie niet laden",
55 "infobar.servicesUpdated": "Je services zijn bijgewerkt.", 54 "infobar.servicesUpdated": "Je services zijn bijgewerkt.",
56 "infobar.updateAvailable": "Een nieuwe update voor Ferdi is beschikbaar.", 55 "infobar.updateAvailable": "Een nieuwe update voor Ferdi is beschikbaar.",
57 "infobox.dismiss": "Dismiss", 56 "infobox.dismiss": "Negeren",
58 "invite.email.label": "E-mailadres", 57 "invite.email.label": "E-mailadres",
59 "invite.headline.friends": "Nodig 3 vrienden of collega's uit", 58 "invite.headline.friends": "Nodig 3 vrienden of collega's uit",
60 "invite.name.label": "Naam", 59 "invite.name.label": "Naam",
@@ -75,95 +74,84 @@
75 "login.email.label": "E-mailadres", 74 "login.email.label": "E-mailadres",
76 "login.headline": "Inloggen", 75 "login.headline": "Inloggen",
77 "login.invalidCredentials": "E-mailadres of wachtwoord ongeldig", 76 "login.invalidCredentials": "E-mailadres of wachtwoord ongeldig",
78 "login.link.password": "Wachtwoord vergeten", 77 "login.link.password": "Wachtwoord opnieuw instellen",
79 "login.link.signup": "Maak een gratis account aan", 78 "login.link.signup": "Maak een gratis account aan",
80 "login.password.label": "Wachtwoord", 79 "login.password.label": "Wachtwoord",
81 "login.serverLogout": "De sessie is verlopen, log alsjeblieft opnieuw in.", 80 "login.serverLogout": "De sessie is verlopen, log alsjeblieft opnieuw in.",
82 "login.submit.label": "Inloggen", 81 "login.submit.label": "Inloggen",
83 "login.tokenExpired": "De sessie is verlopen, log alsjeblieft opnieuw in.", 82 "login.tokenExpired": "De sessie is verlopen, log alsjeblieft opnieuw in.",
84 "menu.Todoss.closeTodosDrawer": "Close Todos drawer", 83 "menu.Todoss.closeTodosDrawer": "Sluit Todos overzicht",
85 "menu.Todoss.openTodosDrawer": "Open Todos drawer", 84 "menu.Todoss.openTodosDrawer": "Open Todos overzicht",
86 "menu.app.about": "Over Ferdi", 85 "menu.app.about": "Over Ferdi",
87 "menu.app.autohideMenuBar": "Menubalk automatisch verbergen", 86 "menu.app.autohideMenuBar": "Menubalk automatisch verbergen",
88 "menu.app.checkForUpdates": "Controleer op updates", 87 "menu.app.checkForUpdates": "Controleer op updates",
89 "menu.app.hide": "Verbergen", 88 "menu.app.hide": "Verbergen",
90 "menu.app.hideOthers": "Hide Others", 89 "menu.app.hideOthers": "Verberg overigen",
91 "menu.app.unhide": "Unhide", 90 "menu.app.unhide": "Weergeven",
92 "menu.edit": "Bewerk", 91 "menu.edit": "Bewerk",
93 "menu.edit.copy": "Copy", 92 "menu.edit.copy": "Kopiëren",
94 "menu.edit.cut": "Cut", 93 "menu.edit.cut": "Knippen",
95 "menu.edit.delete": "Verwijderen", 94 "menu.edit.delete": "Verwijderen",
96 "menu.edit.emojiSymbols": "Emoji's en symbolen", 95 "menu.edit.emojiSymbols": "Emoji's en symbolen",
97 "menu.edit.findInPage": "Zoeken op pagina", 96 "menu.edit.findInPage": "Zoeken op pagina",
98 "menu.edit.paste": "Paste", 97 "menu.edit.paste": "Plakken",
99 "menu.edit.pasteAndMatchStyle": "Paste And Match Style", 98 "menu.edit.pasteAndMatchStyle": "Plakken en opmaak behouden",
100 "menu.edit.redo": "Redo", 99 "menu.edit.redo": "Opnieuw",
101 "menu.edit.selectAll": "Select All", 100 "menu.edit.selectAll": "Alles selecteren",
102 "menu.edit.speech": "Spraak", 101 "menu.edit.speech": "Spraak",
103 "menu.edit.startDictation": "Beginnen met dicteren", 102 "menu.edit.startDictation": "Beginnen met dicteren",
104 "menu.edit.startSpeaking": "Begin met spreken", 103 "menu.edit.startSpeaking": "Begin met spreken",
105 "menu.edit.stopSpeaking": "Stop met spreken", 104 "menu.edit.stopSpeaking": "Stop met spreken",
106 "menu.edit.undo": "Undo", 105 "menu.edit.undo": "Ongedaan maken",
107 "menu.file": "Bestand", 106 "menu.file": "Bestand",
108 "menu.help": "Help", 107 "menu.help": "Help",
109 "menu.help.changelog": "Wijzigingenlogboek", 108 "menu.help.changelog": "Wijzigingenlogboek",
110 "menu.help.debugInfo": "Copy Debug Information", 109 "menu.help.debugInfo": "Debug informatie kopiëren",
111 "menu.help.debugInfoCopiedBody": "Your Debug Information has been copied to your clipboard.", 110 "menu.help.debugInfoCopiedBody": "Uw debug informatie is gekopieerd naar uw klembord.",
112 "menu.help.debugInfoCopiedHeadline": "Ferdi Debug Information", 111 "menu.help.debugInfoCopiedHeadline": "Ferdi Debug Informatie",
113 "menu.help.importExportData": "Import/Export Configuration Data", 112 "menu.help.importExportData": "Import/Export Configuratie Data",
114 "menu.help.learnMore": "Meer informatie", 113 "menu.help.learnMore": "Meer informatie",
115 "menu.help.privacy": "Privacyvoorwaarden", 114 "menu.help.privacy": "Privacyvoorwaarden",
116 "menu.help.publishDebugInfo": "Publish Debug Information", 115 "menu.help.publishDebugInfo": "Publiceer Debug Informatie",
117 "menu.help.support": "Ondersteuning", 116 "menu.help.support": "Ondersteuning",
118 "menu.help.tos": "Servicevoorwaarden", 117 "menu.help.tos": "Servicevoorwaarden",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activeer vorige service", 119 "menu.services.activatePreviousService": "Activeer vorige service",
121 "menu.services.addNewService": "Nieuwe service toevoegen", 120 "menu.services.addNewService": "Nieuwe service toevoegen...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activeer volgende service", 122 "menu.services.setNextServiceActive": "Activeer volgende service",
124 "menu.todos": "Taken", 123 "menu.todos": "Taken",
125 "menu.todos.enableTodos": "Enable Todos", 124 "menu.todos.enableTodos": "Todos inschakelen",
126 "menu.view": "Weergave", 125 "menu.view": "Weergave",
127 "menu.view.back": "Terug", 126 "menu.view.back": "Terug",
128 "menu.view.forward": "Forward", 127 "menu.view.forward": "Doorsturen",
129 "menu.view.lockFerdi": "Ferdi vergrendelen", 128 "menu.view.lockFerdi": "Ferdi vergrendelen",
130 "menu.view.openQuickSwitch": "Open Quick Switch", 129 "menu.view.openQuickSwitch": "Open Quick Switch",
131 "menu.view.reloadFerdi": "Reload Ferdi", 130 "menu.view.reloadFerdi": "Ferdi opnieuw laden",
132 "menu.view.reloadService": "Een service opnieuw laden", 131 "menu.view.reloadService": "Een service opnieuw laden",
133 "menu.view.reloadTodos": "Reload ToDos", 132 "menu.view.reloadTodos": "ToDos opnieuw laden",
134 "menu.view.resetZoom": "Actual Size", 133 "menu.view.resetZoom": "Werkelijke grootte",
135 "menu.view.toggleDarkMode": "Donkere modus aan/uit", 134 "menu.view.toggleDarkMode": "Donkere modus aan/uit",
136 "menu.view.toggleDevTools": "Ontwikkelaarstools aan/uit", 135 "menu.view.toggleDevTools": "Ontwikkelaarstools aan/uit",
137 "menu.view.toggleFullScreen": "Toggle Full Screen", 136 "menu.view.toggleFullScreen": "Volledig scherm in-/uitschakelen",
138 "menu.view.toggleServiceDevTools": "Service ontwikkelaarstools aan/uit", 137 "menu.view.toggleServiceDevTools": "Service ontwikkelaarstools aan/uit",
139 "menu.view.toggleTodosDevTools": "Toggle Todos Developer Tools", 138 "menu.view.toggleTodosDevTools": "Todos Developer Tools in-/uitschakelen",
140 "menu.view.zoomIn": "Zoom In", 139 "menu.view.zoomIn": "Inzoomen",
141 "menu.view.zoomOut": "Zoom Out", 140 "menu.view.zoomOut": "Uitzoomen",
142 "menu.window": "Window", 141 "menu.window": "Venster",
143 "menu.window.close": "Close", 142 "menu.window.close": "Sluiten",
144 "menu.window.minimize": "Minimize", 143 "menu.window.minimize": "Minimaliseren",
145 "menu.workspaces": "Werkruimtes", 144 "menu.workspaces": "Werkruimtes",
146 "menu.workspaces.addNewWorkspace": "Voeg nieuwe werkruimte toe...", 145 "menu.workspaces.addNewWorkspace": "Voeg nieuwe werkruimte toe...",
147 "menu.workspaces.closeWorkspaceDrawer": "Werkruimtepagina sluiten", 146 "menu.workspaces.closeWorkspaceDrawer": "Werkruimtepagina sluiten",
148 "menu.workspaces.defaultWorkspace": "Alle services", 147 "menu.workspaces.defaultWorkspace": "Alle services",
149 "menu.workspaces.openWorkspaceDrawer": "Werkruimtepagina openen", 148 "menu.workspaces.openWorkspaceDrawer": "Werkruimtepagina openen",
150 "password.email.label": "E-mailadres", 149 "password.email.label": "E-mailadres",
151 "password.headline": "Wachtwoord vergeten", 150 "password.headline": "Wachtwoord opnieuw instellen",
152 "password.link.login": "Log in op je account", 151 "password.link.login": "Log in op je account",
153 "password.link.signup": "Maak een gratis account aan", 152 "password.link.signup": "Maak een gratis account aan",
154 "password.noUser": "Geen gebruiker bekend met dat e-mailadres", 153 "password.noUser": "Er is geen gebruiker met dit e-mailadres gevonden",
155 "password.successInfo": "Controleer je e-mail", 154 "password.successInfo": "Uw nieuwe wachtwoord is verzonden naar uw e-mailadres",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker ondersteuning",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Installeer diensten van derden",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Werkruimtes",
167 "service.crashHandler.action": "Laad {name} opnieuw", 155 "service.crashHandler.action": "Laad {name} opnieuw",
168 "service.crashHandler.autoReload": "Bezig om {name} te herstellen over {seconds} seconden", 156 "service.crashHandler.autoReload": "Bezig om {name} te herstellen over {seconds} seconden",
169 "service.crashHandler.headline": "Oh nee!", 157 "service.crashHandler.headline": "Oh nee!",
@@ -177,80 +165,81 @@
177 "service.errorHandler.text": "{name} kon niet geladen worden.", 165 "service.errorHandler.text": "{name} kon niet geladen worden.",
178 "service.webviewLoader.loading": "{service} wordt geladen", 166 "service.webviewLoader.loading": "{service} wordt geladen",
179 "services.getStarted": "Begin", 167 "services.getStarted": "Begin",
180 "services.login": "Please login to use Ferdi.", 168 "services.login": "Log alstublieft in om Ferdi te gebruiken.",
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "U kunt ook uw Ferdi server veranderen door op het tandwieltje in de linker onderhoek te klikken. Als u overschakelt (van een van de gehoste servers) naar Ferdi zonder account wees u ervan bewust dat u uw gegevens van de server kunt exporteren en deze vervolgens kunt importeren via het Help-menu om al uw werkruimtes en geconfigureerde diensten weer te genereren!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Gebruik Ferdi zonder account",
183 "services.welcome": "Welkom bij Ferdi", 171 "services.welcome": "Welkom bij Ferdi",
184 "settings.account.account.editButton": "Bewerk account", 172 "settings.account.account.editButton": "Account bewerken",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is niet beschikbaar",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "U gebruikt Ferdi zonder account. Als u Ferdi wilt gebruiken met een account en uw services gesynchroniseerd wilt houden tussen installaties, selecteer een server in het tabblad Instellingen en log in.",
187 "settings.account.buttonSave": "Update profiel", 175 "settings.account.buttonSave": "Update profiel",
188 "settings.account.deleteAccount": "Verwijder account", 176 "settings.account.deleteAccount": "Verwijder account",
189 "settings.account.deleteEmailSent": "Je hebt een e-mail ontvangen met een link om het verwijderen van je account te bevestigen. Je accountgegevens en -data kunnen na verwijderen niet meer worden teruggehaald!", 177 "settings.account.deleteEmailSent": "Je hebt een e-mail ontvangen met een link om het verwijderen van je account te bevestigen. Je accountgegevens en -data kunnen na verwijderen niet meer worden teruggehaald!",
190 "settings.account.deleteInfo": "Wanneer je je Ferdi-account niet langer wilt gebruiken, kun je je account en alle gerelateerde data verwijderen.", 178 "settings.account.deleteInfo": "Wanneer je je Ferdi-account niet langer wilt gebruiken, kun je je account en alle gerelateerde data verwijderen.",
191 "settings.account.headline": "Account", 179 "settings.account.headline": "Account",
192 "settings.account.headlineAccount": "Accountinformatie", 180 "settings.account.headlineAccount": "Account informatie",
193 "settings.account.headlineDangerZone": "Gevarenzone", 181 "settings.account.headlineDangerZone": "Gevarenzone",
194 "settings.account.headlineInvoices": "Facturen", 182 "settings.account.headlineInvoices": "Facturen",
195 "settings.account.headlinePassword": "Wijzig wachtwoord", 183 "settings.account.headlinePassword": "Wachtwoord wijzigen",
196 "settings.account.headlineProfile": "Update profiel", 184 "settings.account.headlineProfile": "Update profiel",
197 "settings.account.successInfo": "Je wijzigingen zijn opgeslagen", 185 "settings.account.successInfo": "Je wijzigingen zijn opgeslagen",
198 "settings.account.tryReloadServices": "Probeer opnieuw", 186 "settings.account.tryReloadServices": "Probeer opnieuw",
199 "settings.account.tryReloadUserInfoRequest": "Probeer opnieuw", 187 "settings.account.tryReloadUserInfoRequest": "Probeer opnieuw",
200 "settings.account.userInfoRequestFailed": "Kon gebruikersinformatie niet laden", 188 "settings.account.userInfoRequestFailed": "Kon gebruikersinformatie niet laden",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Uw Ferdi licentie:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Schrijf uw accentkleur in een CSS-compatibel formaat (standaard: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Cache legen", 191 "settings.app.buttonClearAllCache": "Cache legen",
204 "settings.app.buttonInstallUpdate": "Opnieuw opstarten & update installeren", 192 "settings.app.buttonInstallUpdate": "Opnieuw opstarten & update installeren",
205 "settings.app.buttonOpenFerdiProfileFolder": "Open Profile folder", 193 "settings.app.buttonOpenFerdiProfileFolder": "Profielmap openen",
206 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open Service Recipes folder", 194 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open de map servicerecepten",
207 "settings.app.buttonSearchForUpdate": "Controleer op updates", 195 "settings.app.buttonSearchForUpdate": "Controleer op updates",
208 "settings.app.cacheInfo": "Ferdi gebruikt op dit moment {size} schijfruimte aan tijdelijke bestanden.", 196 "settings.app.cacheInfo": "Ferdi gebruikt op dit moment {size} schijfruimte aan tijdelijke bestanden.",
209 "settings.app.cacheNotCleared": "Couldn't clear all cache", 197 "settings.app.cacheNotCleared": "Kon alle cache niet legen",
210 "settings.app.closeSettings": "Close settings", 198 "settings.app.closeSettings": "Instellingen sluiten",
211 "settings.app.currentVersion": "Huidige versie:", 199 "settings.app.currentVersion": "Huidige versie:",
212 "settings.app.form.accentColor": "Accent color", 200 "settings.app.form.accentColor": "Accent kleur",
213 "settings.app.form.adaptableDarkMode": "Synchronize dark mode with my OS's dark mode setting", 201 "settings.app.form.adaptableDarkMode": "Donkere modus synchroniseren met de instelling van mijn OS",
214 "settings.app.form.alwaysShowWorkspaces": "Always show workspace drawer", 202 "settings.app.form.alwaysShowWorkspaces": "Werkruimte lade altijd weergeven",
215 "settings.app.form.autoLaunchInBackground": "Open op de achtergrond", 203 "settings.app.form.autoLaunchInBackground": "Open op de achtergrond",
216 "settings.app.form.autoLaunchOnStart": "Open Ferdi bij opstarten", 204 "settings.app.form.autoLaunchOnStart": "Open Ferdi bij opstarten",
217 "settings.app.form.automaticUpdates": "Enable updates", 205 "settings.app.form.automaticUpdates": "Updates inschakelen",
218 "settings.app.form.beta": "Inclusief bètaversies", 206 "settings.app.form.beta": "Inclusief bètaversies",
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Meldingen voor klembord niet weergeven",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Minimaliseer Ferdi naar systeemvak",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Bevestigen bij het sluiten van Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Aangepaste Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Dark mode aanzetten",
224 "settings.app.form.enableGPUAcceleration": "Schakel videokaart-acceleratie in ", 212 "settings.app.form.enableGPUAcceleration": "Schakel videokaart-acceleratie in ",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Wachtwoordvergrendeling inschakelen",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Altijd Ferdi weergeven in de menubalk",
227 "settings.app.form.enableSpellchecking": "Zet spellingcontrole aan", 215 "settings.app.form.enableSpellchecking": "Zet spellingcontrole aan",
228 "settings.app.form.enableSystemTray": "Pictogram voor Ferdi in systeemvak tonen", 216 "settings.app.form.enableSystemTray": "Laat Ferdi altijd in systeembalk zien",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Ferdi Todos inschakelen",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Diensten in slaapstand houden bij opstarten",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Slaapstand strategie",
232 "settings.app.form.iconSize": "Service icon size", 220 "settings.app.form.iconSize": "Service icoongrootte",
233 "settings.app.form.inactivityLock": "Lock after inactivity", 221 "settings.app.form.inactivityLock": "Vergrendel na inactiviteit",
234 "settings.app.form.keepAllWorkspacesLoaded": "Keep all workspaces loaded", 222 "settings.app.form.keepAllWorkspacesLoaded": "Houd alle werkruimtes geladen",
235 "settings.app.form.language": "Taal", 223 "settings.app.form.language": "Taal",
236 "settings.app.form.lockPassword": "Wachtwoord", 224 "settings.app.form.lockPassword": "Wachtwoord",
237 "settings.app.form.minimizeToSystemTray": "Minimaliseer Ferdi naar systeemvak", 225 "settings.app.form.minimizeToSystemTray": "Minimaliseer Ferdi naar systeemvak",
238 "settings.app.form.navigationBarBehaviour": "Navigation bar behaviour", 226 "settings.app.form.navigationBarBehaviour": "Navigatiebalk gedrag",
239 "settings.app.form.notifyTaskBarOnMessage": "Notify TaskBar/Dock on new message", 227 "settings.app.form.notifyTaskBarOnMessage": "Informeer TakenBalk / Dock op een nieuw bericht",
240 "settings.app.form.passwordToggle": "Password toggle", 228 "settings.app.form.passwordToggle": "Wachtwoord wijzigen",
241 "settings.app.form.predefinedTodoServer": "Todo Server", 229 "settings.app.form.predefinedTodoServer": "Taak Server",
242 "settings.app.form.privateNotifications": "Toon geen bericht-inhoud in meldingen", 230 "settings.app.form.privateNotifications": "Toon geen bericht-inhoud in meldingen",
243 "settings.app.form.reloadAfterResume": "Reload Ferdi after system resume", 231 "settings.app.form.reloadAfterResume": "Herlaad Ferdi na systeem hervatten",
244 "settings.app.form.runInBackground": "Houd Ferdi open op de achtergrond wanneer het venster gesloten wordt", 232 "settings.app.form.runInBackground": "Houd Ferdi open op de achtergrond wanneer het venster gesloten wordt",
245 "settings.app.form.scheduledDNDEnabled": "Enable scheduled Do-not-Disturb", 233 "settings.app.form.scheduledDNDEnabled": "Activeer geplande niet-storen modus",
246 "settings.app.form.scheduledDNDEnd": "To", 234 "settings.app.form.scheduledDNDEnd": "To",
247 "settings.app.form.scheduledDNDStart": "From", 235 "settings.app.form.scheduledDNDStart": "Van",
248 "settings.app.form.searchEngine": "Search engine", 236 "settings.app.form.searchEngine": "Zoekmachine",
249 "settings.app.form.sentry": "Send telemetry data", 237 "settings.app.form.sentry": "Verzend telemetrie gegevens",
250 "settings.app.form.serviceRibbonWidth": "Sidebar width", 238 "settings.app.form.serviceRibbonWidth": "Sidebar width",
251 "settings.app.form.showDisabledServices": "Toon uitgeschakelde services", 239 "settings.app.form.showDisabledServices": "Toon uitgeschakelde services",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Toon badge met ongelezen berichten wanneer meldingen zijn uitgeschakeld", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Toon badge met ongelezen berichten wanneer meldingen zijn uitgeschakeld",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Ferdi spreekt officieel Engels en Duits. Alle andere talen worden beheerd door de community.", 256 "settings.app.languageDisclaimer": "Ferdi spreekt officieel Engels en Duits. Alle andere talen worden beheerd door de community.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Wachtwoord", 258 "settings.app.lockedPassword": "Wachtwoord",
270 "settings.app.lockedPasswordInfo": "Zorg ervoor dat je een wachtwoord instelt dat je niet vergeet.\nAls je dit wachtwoord verliest, moet je Ferdi opnieuw installeren.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Deze wijziging heeft een herstart nodig", 260 "settings.app.restartRequired": "Deze wijziging heeft een herstart nodig",
272 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.", 261 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.", 262 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Verwijder service", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Bewerk {name}", 305 "settings.service.form.editServiceHeadline": "Bewerk {name}",
317 "settings.service.form.enableAudio": "Audio inschakelen", 306 "settings.service.form.enableAudio": "Audio inschakelen",
318 "settings.service.form.enableBadge": "Toon badges met ongelezen berichten", 307 "settings.service.form.enableBadge": "Toon badges met ongelezen berichten",
@@ -332,18 +321,19 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Indien uitgeschakeld, worden meldingen en audio niet afgespeeld", 322 "settings.service.form.isMutedInfo": "Indien uitgeschakeld, worden meldingen en audio niet afgespeeld",
334 "settings.service.form.name": "Naam", 323 "settings.service.form.name": "Naam",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy instellingen", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy instellingen",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy instellingen worden niet gesynchroniseerd met de Ferdi servers", 330 "settings.service.form.proxy.info": "Proxy instellingen worden niet gesynchroniseerd met de Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Proxy gebruiken", 331 "settings.service.form.proxy.isEnabled": "Proxy gebruiken",
342 "settings.service.form.proxy.password": "Wachtwoord (optioneel)", 332 "settings.service.form.proxy.password": "Wachtwoord (optioneel)",
343 "settings.service.form.proxy.port": "Poort", 333 "settings.service.form.proxy.port": "Poort",
344 "settings.service.form.proxy.restartInfo": "Start Ferdi opnieuw na het aanpassen van proxy instellingen.", 334 "settings.service.form.proxy.restartInfo": "Start Ferdi opnieuw na het aanpassen van proxy instellingen.",
345 "settings.service.form.proxy.user": "Gebruiker (optioneel)", 335 "settings.service.form.proxy.user": "Gebruiker (optioneel)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Je gebruikersbestanden worden op de webpagina ingevoegd zodat je diensten op elke manier kunt aanpassen. Gebruikersbestanden worden alleen lokaal opgeslagen en worden niet overgebracht naar andere computers met hetzelfde account.",
347 "settings.service.form.saveButton": "Service opslaan", 337 "settings.service.form.saveButton": "Service opslaan",
348 "settings.service.form.tabHosted": "Gehost", 338 "settings.service.form.tabHosted": "Gehost",
349 "settings.service.form.tabOnPremise": "Zelf-gehost â­ï¸", 339 "settings.service.form.tabOnPremise": "Zelf-gehost â­ï¸",
@@ -353,7 +343,8 @@
353 "settings.services.deletedInfo": "Service is verwijderd", 343 "settings.services.deletedInfo": "Service is verwijderd",
354 "settings.services.discoverServices": "Ontdek services", 344 "settings.services.discoverServices": "Ontdek services",
355 "settings.services.headline": "Jouw services", 345 "settings.services.headline": "Jouw services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start met een service toe te voegen.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Kan jouw services niet laden", 348 "settings.services.servicesRequestFailed": "Kan jouw services niet laden",
358 "settings.services.tooltip.isDisabled": "Service is uitgeschakeld", 349 "settings.services.tooltip.isDisabled": "Service is uitgeschakeld",
359 "settings.services.tooltip.isMuted": "Geluid is uitgeschakeld", 350 "settings.services.tooltip.isMuted": "Geluid is uitgeschakeld",
@@ -384,7 +375,7 @@
384 "settings.user.form.accountType.company": "Bedrijf", 375 "settings.user.form.accountType.company": "Bedrijf",
385 "settings.user.form.accountType.individual": "Individueel", 376 "settings.user.form.accountType.individual": "Individueel",
386 "settings.user.form.accountType.label": "Accounttype", 377 "settings.user.form.accountType.label": "Accounttype",
387 "settings.user.form.accountType.non-profit": "Non-Profit", 378 "settings.user.form.accountType.non-profit": "Non-profit",
388 "settings.user.form.currentPassword": "Huidige wachtwoord", 379 "settings.user.form.currentPassword": "Huidige wachtwoord",
389 "settings.user.form.email": "E-mailadres", 380 "settings.user.form.email": "E-mailadres",
390 "settings.user.form.firstname": "Voornaam", 381 "settings.user.form.firstname": "Voornaam",
@@ -405,13 +396,13 @@
405 "settings.workspaces.tryReloadWorkspaces": "Probeer opnieuw", 396 "settings.workspaces.tryReloadWorkspaces": "Probeer opnieuw",
406 "settings.workspaces.updatedInfo": "Je wijzigingen zijn opgeslagen", 397 "settings.workspaces.updatedInfo": "Je wijzigingen zijn opgeslagen",
407 "settings.workspaces.workspaceFeatureHeadline": "Less is More: Zie hier Ferdi Werkruimtes", 398 "settings.workspaces.workspaceFeatureHeadline": "Less is More: Zie hier Ferdi Werkruimtes",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdi werkruimtes laat je aandacht geven aan wat nu belangrijk is. Maak verschillende sets van services aan en schakel wanneer je wilt tussen de verschillende sets. Jij beslist welke services je wanneer en waar nodig hebt. Zo helpen wij jou je focus te behouden - of net zo gemakkelijk te switchen van werk naar ontspanning.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Kan jouw werkruimtes niet laden", 400 "settings.workspaces.workspacesRequestFailed": "Kan jouw werkruimtes niet laden",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Laten we beginnen",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
412 "setupAssistant.submit.label": "Let's go", 403 "setupAssistant.submit.label": "Let's go",
413 "sidebar.addNewService": "Voeg service toe", 404 "sidebar.addNewService": "Voeg service toe",
414 "sidebar.closeTodosDrawer": "Close Ferdi Todos", 405 "sidebar.closeTodosDrawer": "Sluit Ferdi Todos",
415 "sidebar.closeWorkspaceDrawer": "Werkruimtepagina sluiten", 406 "sidebar.closeWorkspaceDrawer": "Werkruimtepagina sluiten",
416 "sidebar.lockFerdi": "Ferdi vergrendelen", 407 "sidebar.lockFerdi": "Ferdi vergrendelen",
417 "sidebar.muteApp": "Berichten & geluid uitschakelen", 408 "sidebar.muteApp": "Berichten & geluid uitschakelen",
@@ -430,36 +421,36 @@
430 "signup.password.label": "Wachtwoord", 421 "signup.password.label": "Wachtwoord",
431 "signup.submit.label": "Account aanmaken", 422 "signup.submit.label": "Account aanmaken",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Verwijder service", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Audio uitschakelen", 425 "tabs.item.disableAudio": "Audio uitschakelen",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Meldingen uitschakelen", 427 "tabs.item.disableNotifications": "Meldingen uitschakelen",
437 "tabs.item.disableService": "Service uitschakelen", 428 "tabs.item.disableService": "Service uitschakelen",
438 "tabs.item.enableAudio": "Audio inschakelen", 429 "tabs.item.enableAudio": "Audio inschakelen",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Donkere modus inschakelen",
440 "tabs.item.enableNotification": "Meldingen inschakelen", 431 "tabs.item.enableNotification": "Meldingen inschakelen",
441 "tabs.item.enableService": "Service inschakelen", 432 "tabs.item.enableService": "Service inschakelen",
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Herladen", 434 "tabs.item.reload": "Herladen",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} is niet geldig", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} dient minimaal {length} karakters lang te zijn", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Minstens één vereist", 438 "validation.oneRequired": "Minstens één vereist",
448 "validation.required": "{field} is vereist", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} is geen geldige URL", 440 "validation.url": "{field} is geen geldige URL",
450 "webControls.back": "Terug", 441 "webControls.back": "Terug",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Doorsturen",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
453 "webControls.openInBrowser": "Open in Browser", 444 "webControls.openInBrowser": "Openen in Browser",
454 "webControls.reload": "Herladen", 445 "webControls.reload": "Herladen",
455 "welcome.loginButton": "Log in op je account", 446 "welcome.loginButton": "Log in op je account",
456 "welcome.signupButton": "Maak een gratis account aan", 447 "welcome.signupButton": "Maak een gratis account aan",
457 "workspaceDrawer.addNewWorkspaceLabel": "Voeg een nieuwe werkruimte toe", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Alle services", 449 "workspaceDrawer.allServices": "Alle services",
459 "workspaceDrawer.headline": "Werkruimtes", 450 "workspaceDrawer.headline": "Werkruimtes",
460 "workspaceDrawer.item.contextMenuEdit": "bewerken", 451 "workspaceDrawer.item.contextMenuEdit": "bewerken",
461 "workspaceDrawer.item.noServicesAddedYet": "Nog geen services toegevoegd", 452 "workspaceDrawer.item.noServicesAddedYet": "Nog geen services toegevoegd",
462 "workspaceDrawer.workspaceFeatureInfo": "Ferdi werkruimtes laat je aandacht geven aan wat nu belangrijk is. Maak verschillende sets van services aan en schakel wanneer je wilt tussen de verschillende sets. Jij beslist welke services je wanneer en waar nodig hebt. Zo helpen wij jou je focus te behouden - of net zo gemakkelijk te switchen van werk naar ontspanning.", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Werkruimte instellingen aanpassen", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Overschakelen naar" 455 "workspaces.switchingIndicator.switchingTo": "Overschakelen naar"
465} 456}
diff --git a/src/i18n/locales/no.json b/src/i18n/locales/no.json
index 548cba3ce..cfa523a35 100644
--- a/src/i18n/locales/no.json
+++ b/src/i18n/locales/no.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Last inn på nytt", 2 "app.errorHandler.action": "Last inn på nytt",
3 "app.errorHandler.headline": "Noe gikk galt", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Egendefinert tjener", 4 "changeserver.customServerLabel": "Egendefinert tjener",
5 "changeserver.headline": "Bytt tjener", 5 "changeserver.headline": "Bytt tjener",
6 "changeserver.label": "Tjener", 6 "changeserver.label": "Tjener",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Hva skjedde?", 10 "connectionLostBanner.informationLink": "Hva skjedde?",
11 "connectionLostBanner.message": "Ã… nei! Ferdi mistet forbindelsen til {name}.", 11 "connectionLostBanner.message": "Ã… nei! Ferdi mistet forbindelsen til {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publiser feilsøkingsinformasjon",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Velg en tjeneste med TAB, ↑ og ↓. Åpne en tjeneste med ENTER.", 23 "feature.quickSwitch.info": "Velg en tjeneste med TAB, ↑ og ↓. Åpne en tjeneste med ENTER.",
25 "feature.quickSwitch.search": "Søk...", 24 "feature.quickSwitch.search": "Søk...",
26 "feature.quickSwitch.title": "Hurtigbytte", 25 "feature.quickSwitch.title": "Hurtigbytte",
27 "global.api.unhealthy": "Kan ikke koble til Ferdi online-tjenester", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Avbryt", 27 "global.cancel": "Cancel",
29 "global.edit": "Rediger", 28 "global.edit": "Rediger",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Du er ikke koblet til Internett.", 30 "global.notConnectedToTheInternet": "Du er ikke koblet til Internett.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Innstillinger", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Bruk systemstandarden ({default})", 36 "global.spellchecker.useDefault": "Bruk systemstandarden ({default})",
38 "global.spellchecking.autodetect": "Oppdag språk automatisk", 37 "global.spellchecking.autodetect": "Oppdag språk automatisk",
39 "global.spellchecking.autodetect.short": "Automatisk", 38 "global.spellchecking.autodetect.short": "Automatisk",
40 "global.spellchecking.language": "Språk for stavekontroll", 39 "global.spellchecking.language": "Språk for stavekontroll",
41 "global.submit": "Send", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importer Ferdi 4-tjenestene dine", 44 "import.headline": "Importer Ferdi 4-tjenestene dine",
46 "import.notSupportedHeadline": "Tjenester som ikke støttes enda i Ferdi 5", 45 "import.notSupportedHeadline": "Tjenester som ikke støttes enda i Ferdi 5",
47 "import.skip.label": "Jeg ønsker å legge til tjenester manuelt", 46 "import.skip.label": "Jeg ønsker å legge til tjenester manuelt",
48 "import.submit.label": "Importer tjenester", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Det oppstod en feil under forsøket med en autentisert forespørsel. Prøv å logge ut og inn igjen om denne feilen vedvarer.", 48 "infobar.authRequestFailed": "Det oppstod en feil under forsøket med en autentisert forespørsel. Prøv å logge ut og inn igjen om denne feilen vedvarer.",
50 "infobar.buttonChangelog": "Hva er nytt?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Start på nytt og installer oppdatering", 50 "infobar.buttonInstallUpdate": "Start på nytt og installer oppdatering",
52 "infobar.buttonReloadServices": "Last inn tjenestene på nytt", 51 "infobar.buttonReloadServices": "Last inn tjenestene på nytt",
53 "infobar.hide": "Skjul", 52 "infobar.hide": "Skjul",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-postadresse", 74 "login.email.label": "E-postadresse",
76 "login.headline": "Logg inn", 75 "login.headline": "Logg inn",
77 "login.invalidCredentials": "E-posten eller passordet er ikke gyldig", 76 "login.invalidCredentials": "E-posten eller passordet er ikke gyldig",
78 "login.link.password": "Tilbakestill passord", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Opprett en gratis konto", 78 "login.link.signup": "Opprett en gratis konto",
80 "login.password.label": "Passord", 79 "login.password.label": "Passord",
81 "login.serverLogout": "Din økt er utløpet, vennligst logg inn igjen.", 80 "login.serverLogout": "Din økt er utløpet, vennligst logg inn igjen.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Brukerstøtte", 116 "menu.help.support": "Brukerstøtte",
118 "menu.help.tos": "Vilkår for bruk", 117 "menu.help.tos": "Vilkår for bruk",
119 "menu.services": "Tjenester", 118 "menu.services": "Tjenester",
120 "menu.services.activatePreviousService": "Aktiver forrige tjeneste", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Hjem", 121 "menu.services.goHome": "Hjem",
123 "menu.services.setNextServiceActive": "Aktiver neste tjeneste", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Gjøremål", 123 "menu.todos": "Gjøremål",
125 "menu.todos.enableTodos": "Aktiver gjøremål", 124 "menu.todos.enableTodos": "Aktiver gjøremål",
126 "menu.view": "Vis", 125 "menu.view": "Vis",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Alle tjenester", 147 "menu.workspaces.defaultWorkspace": "Alle tjenester",
149 "menu.workspaces.openWorkspaceDrawer": "Åpne skuff for arbeidsområder", 148 "menu.workspaces.openWorkspaceDrawer": "Åpne skuff for arbeidsområder",
150 "password.email.label": "E-postadresse", 149 "password.email.label": "E-postadresse",
151 "password.headline": "Tilbakestill passord", 150 "password.headline": "Reset password",
152 "password.link.login": "Logg inn på kontoen din", 151 "password.link.login": "Logg inn på kontoen din",
153 "password.link.signup": "Opprett en gratis konto", 152 "password.link.signup": "Opprett en gratis konto",
154 "password.noUser": "Ingen bruker med den e-postadressen ble funnet", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Vennligst sjekk e-posten din", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Konto synkronisering",
157 "pricing.features.customWebsites": "Legg til egendefinerte nettsteder",
158 "pricing.features.desktopNotifications": "Skrivebord varsler",
159 "pricing.features.onPremise": "On-premise og andre selvbetjente tjenester",
160 "pricing.features.recipes": "Velg fra mer enn 70 tjenester",
161 "pricing.features.serviceProxies": "Mellomtjenere for tjenester",
162 "pricing.features.spellchecker": "Støtte for stavekontroll",
163 "pricing.features.teamManagement": "Team-administrasjon",
164 "pricing.features.thirdPartyServices": "Installer tredjepartstjenester",
165 "pricing.features.unlimitedServices": "Legg til ubegrenset antall tjenester",
166 "pricing.features.workspaces": "Arbeidsområder",
167 "service.crashHandler.action": "Last {name} inn på nytt", 155 "service.crashHandler.action": "Last {name} inn på nytt",
168 "service.crashHandler.autoReload": "Prøver å automatisk gjenopprette {name} om {seconds} sekunder", 156 "service.crashHandler.autoReload": "Prøver å automatisk gjenopprette {name} om {seconds} sekunder",
169 "service.crashHandler.headline": "Ã… nei!", 157 "service.crashHandler.headline": "Ã… nei!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Bruk Ferdi uten en konto", 170 "services.serverless": "Bruk Ferdi uten en konto",
183 "services.welcome": "Velkommen til Ferdi", 171 "services.welcome": "Velkommen til Ferdi",
184 "settings.account.account.editButton": "Rediger konto", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Kontoen er ikke tilgjengelig", 173 "settings.account.accountUnavailable": "Kontoen er ikke tilgjengelig",
186 "settings.account.accountUnavailableInfo": "Du bruker Ferdi uten en konto. Hvis du ønsker å bruke Ferdi med en konto og hold tjenestene dine synkronisert på tvers av installasjoner, velg en tjener i fanen innstillinger og logg inn.", 174 "settings.account.accountUnavailableInfo": "Du bruker Ferdi uten en konto. Hvis du ønsker å bruke Ferdi med en konto og hold tjenestene dine synkronisert på tvers av installasjoner, velg en tjener i fanen innstillinger og logg inn.",
187 "settings.account.buttonSave": "Oppdater profil", 175 "settings.account.buttonSave": "Oppdater profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Du har mottatt en e-post med en lenke for å bekrefte sletting av kontoen din. Din konto og dine data kan ikke gjenopprettes!", 177 "settings.account.deleteEmailSent": "Du har mottatt en e-post med en lenke for å bekrefte sletting av kontoen din. Din konto og dine data kan ikke gjenopprettes!",
190 "settings.account.deleteInfo": "Hvis du ikke trenger Ferdi-kontoen din lenger, så kan du slette kontoen din og alle de relaterte dataene her.", 178 "settings.account.deleteInfo": "Hvis du ikke trenger Ferdi-kontoen din lenger, så kan du slette kontoen din og alle de relaterte dataene her.",
191 "settings.account.headline": "Konto", 179 "settings.account.headline": "Konto",
192 "settings.account.headlineAccount": "Kontoinformasjon", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Faresone", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Fakturaer", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Endre passord", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Oppdater profil", 184 "settings.account.headlineProfile": "Oppdater profil",
197 "settings.account.successInfo": "Dine endringer har blitt lagret", 185 "settings.account.successInfo": "Dine endringer har blitt lagret",
198 "settings.account.tryReloadServices": "Prøv igjen", 186 "settings.account.tryReloadServices": "Prøv igjen",
199 "settings.account.tryReloadUserInfoRequest": "Prøv igjen", 187 "settings.account.tryReloadUserInfoRequest": "Prøv igjen",
200 "settings.account.userInfoRequestFailed": "Kunne ikke laste brukerinformasjonen", 188 "settings.account.userInfoRequestFailed": "Kunne ikke laste brukerinformasjonen",
201 "settings.account.yourLicense": "Din Ferdi lisens", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Tøm hurtiglager", 191 "settings.app.buttonClearAllCache": "Tøm hurtiglager",
204 "settings.app.buttonInstallUpdate": "Start på nytt og installer oppdatering", 192 "settings.app.buttonInstallUpdate": "Start på nytt og installer oppdatering",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Egendefinerte gjøremål-tjener", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Aktiver mørkt tema", 211 "settings.app.form.darkMode": "Aktiver mørkt tema",
224 "settings.app.form.enableGPUAcceleration": "Aktiver GPU-akselerasjon", 212 "settings.app.form.enableGPUAcceleration": "Aktiver GPU-akselerasjon",
225 "settings.app.form.enableLock": "Aktiver passordlås", 213 "settings.app.form.enableLock": "Aktiver passordlås",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Aktiver stavekontroll", 215 "settings.app.form.enableSpellchecking": "Aktiver stavekontroll",
228 "settings.app.form.enableSystemTray": "Vis Ferdi i systemstatusfeltet", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Aktiver Ferdi gjøremål", 217 "settings.app.form.enableTodos": "Aktiver Ferdi gjøremål",
230 "settings.app.form.hibernateOnStartup": "Hold tjenestene i dvalemodus ved oppstart", 218 "settings.app.form.hibernateOnStartup": "Hold tjenestene i dvalemodus ved oppstart",
231 "settings.app.form.hibernationStrategy": "Dvalemodus-strategi", 219 "settings.app.form.hibernationStrategy": "Dvalemodus-strategi",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Vis deaktiverte tjenestefaner", 239 "settings.app.form.showDisabledServices": "Vis deaktiverte tjenestefaner",
252 "settings.app.form.showDragArea": "Vis flyttbart område i vinduet", 240 "settings.app.form.showDragArea": "Vis flyttbart område i vinduet",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Vis uleste meldingsetiketter når varsler er deaktivert", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Vis uleste meldingsetiketter når varsler er deaktivert",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimert", 243 "settings.app.form.startMinimized": "Start minimert",
255 "settings.app.form.universalDarkMode": "Aktiver universelt mørkt tema", 244 "settings.app.form.universalDarkMode": "Aktiver universelt mørkt tema",
256 "settings.app.form.useTouchIdToUnlock": "Tillat å bruke TouchID for å låse opp Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Avansert", 248 "settings.app.headlineAdvanced": "Avansert",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Offisielle oversettelser er engelsk & tysk. Alle andre språk er samfunnsbaserte oversettelser.", 256 "settings.app.languageDisclaimer": "Offisielle oversettelser er engelsk & tysk. Alle andre språk er samfunnsbaserte oversettelser.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Passord", 258 "settings.app.lockedPassword": "Passord",
270 "settings.app.lockedPasswordInfo": "Vennligst angi et passord du vil huske.\nHvis du mister dette passordet må du installere Ferdi på nytt.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Endringer krever omstart", 260 "settings.app.restartRequired": "Endringer krever omstart",
272 "settings.app.scheduledDNDInfo": "Planlagt ikke-forstyrr lar deg definere en tidsperiode hvor du ikke vil få varsler fra Ferdi.", 261 "settings.app.scheduledDNDInfo": "Planlagt ikke-forstyrr lar deg definere en tidsperiode hvor du ikke vil få varsler fra Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Tider i 24-Hour-Format. Sluttiden kan være før starttiden (f.eks start 17:00, slutt 09:00) for å aktivere ikke-forstyrr over natten.", 262 "settings.app.scheduledDNDTimeInfo": "Tider i 24-Hour-Format. Sluttiden kan være før starttiden (f.eks start 17:00, slutt 09:00) for å aktivere ikke-forstyrr over natten.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi bruker Mac'en sin innebygde stavekontroll, for å se etter skrivefeil. Hvis du vil endre språket på stavekontrollen, så kan du gjøre det under Mac'ens system-innstillinger.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi bruker Mac'en sin innebygde stavekontroll, for å se etter skrivefeil. Hvis du vil endre språket på stavekontrollen, så kan du gjøre det under Mac'ens system-innstillinger.",
276 "settings.app.subheadlineCache": "Hurtiglager", 265 "settings.app.subheadlineCache": "Hurtiglager",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Denne tjeneren vil ble brukt for \"Ferdi gjøremål\" funksjonen.", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Hjelp oss med å oversette Ferdi til ditt språk.", 268 "settings.app.translationHelp": "Hjelp oss med å oversette Ferdi til ditt språk.",
280 "settings.app.universalDarkModeInfo": "Universelt mørkt tema prøver å dynamisk generere mørke stiler for tjenester som ikke har denne støtten enda.", 269 "settings.app.universalDarkModeInfo": "Universelt mørkt tema prøver å dynamisk generere mørke stiler for tjenester som ikke har denne støtten enda.",
281 "settings.app.updateStatusAvailable": "Oppdatering tilgjengelig, laster ned...", 270 "settings.app.updateStatusAvailable": "Oppdatering tilgjengelig, laster ned...",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Fellesskap 3. parts oppskrifter", 283 "settings.recipes.customService.headline.communityRecipes": "Fellesskap 3. parts oppskrifter",
295 "settings.recipes.customService.headline.customRecipes": "Tilpassede 3. parts oppskrifter", 284 "settings.recipes.customService.headline.customRecipes": "Tilpassede 3. parts oppskrifter",
296 "settings.recipes.customService.headline.devRecipes": "Dine utviklingstjeneste oppskrifter", 285 "settings.recipes.customService.headline.devRecipes": "Dine utviklingstjeneste oppskrifter",
297 "settings.recipes.customService.intro": "Hvis du vil legge til en egendefinert tjeneste, så kan du kopiere oppskriften for tjenesten til:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Utviklerdokumentasjon", 287 "settings.recipes.customService.openDevDocs": "Utviklerdokumentasjon",
299 "settings.recipes.customService.openFolder": "Ã…pne mappe", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Tilgjengelige tjenester", 289 "settings.recipes.headline": "Tilgjengelige tjenester",
301 "settings.recipes.missingService": "Mangler en tjeneste?", 290 "settings.recipes.missingService": "Mangler en tjeneste?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Lysstyrke for lesing i mørket", 301 "settings.service.form.darkReaderBrightness": "Lysstyrke for lesing i mørket",
313 "settings.service.form.darkReaderContrast": "Kontrast for lesing i mørket", 302 "settings.service.form.darkReaderContrast": "Kontrast for lesing i mørket",
314 "settings.service.form.darkReaderSepia": "Sepia for lesing i mørket", 303 "settings.service.form.darkReaderSepia": "Sepia for lesing i mørket",
315 "settings.service.form.deleteButton": "Slett tjeneste", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Rediger {name}", 305 "settings.service.form.editServiceHeadline": "Rediger {name}",
317 "settings.service.form.enableAudio": "Aktiver lyd", 306 "settings.service.form.enableAudio": "Aktiver lyd",
318 "settings.service.form.enableBadge": "Vis uleste meldingsetiketter", 307 "settings.service.form.enableBadge": "Vis uleste meldingsetiketter",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "NÃ¥r deaktivert, blir alle varslingslyder og lydavspillinger dempet", 322 "settings.service.form.isMutedInfo": "NÃ¥r deaktivert, blir alle varslingslyder og lydavspillinger dempet",
334 "settings.service.form.name": "Navn", 323 "settings.service.form.name": "Navn",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Ã…pne darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Ã…pne darkmode.css",
336 "settings.service.form.openUserCss": "Ã…pne user.css", 326 "settings.service.form.openUserCss": "Ã…pne user.css",
337 "settings.service.form.openUserJs": "Ã…pne user.js", 327 "settings.service.form.openUserJs": "Ã…pne user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS mellomtjener-innstillinger", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS mellomtjener-innstillinger",
339 "settings.service.form.proxy.host": "Mellomtjener vert/IP", 329 "settings.service.form.proxy.host": "Mellomtjener vert/IP",
340 "settings.service.form.proxy.info": "Mellomtjener-innstillinger vil ikke blir synkronisert med Ferdi tjenerne.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Bruk mellomtjener", 331 "settings.service.form.proxy.isEnabled": "Bruk mellomtjener",
342 "settings.service.form.proxy.password": "Passord (valgfritt)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Vennligst start Ferdig på nytt etter å ha endre mellomtjener-innstillingene.", 334 "settings.service.form.proxy.restartInfo": "Vennligst start Ferdig på nytt etter å ha endre mellomtjener-innstillingene.",
345 "settings.service.form.proxy.user": "Bruker (valgfritt)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Brukerfilene dine vil bli plassert på nettsiden slik at du kan tilpasse tjenestene på alle måter du ønsker. Brukerfilene lagres bare lokalt og overføres ikke til andre datamaskiner som bruker samme konto.", 336 "settings.service.form.recipeFileInfo": "Brukerfilene dine vil bli plassert på nettsiden slik at du kan tilpasse tjenestene på alle måter du ønsker. Brukerfilene lagres bare lokalt og overføres ikke til andre datamaskiner som bruker samme konto.",
347 "settings.service.form.saveButton": "Lagre tjeneste", 337 "settings.service.form.saveButton": "Lagre tjeneste",
348 "settings.service.form.tabHosted": "Selvbetjent", 338 "settings.service.form.tabHosted": "Selvbetjent",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Oppdag tjenester", 344 "settings.services.discoverServices": "Oppdag tjenester",
355 "settings.services.headline": "Dine tjenester", 345 "settings.services.headline": "Dine tjenester",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Kunne ikke laste dine tjenester", 348 "settings.services.servicesRequestFailed": "Kunne ikke laste dine tjenester",
358 "settings.services.tooltip.isDisabled": "Tjenesten er deaktivert", 349 "settings.services.tooltip.isDisabled": "Tjenesten er deaktivert",
359 "settings.services.tooltip.isMuted": "Alle lyder er dempet", 350 "settings.services.tooltip.isMuted": "Alle lyder er dempet",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Ikke-profittbasert", 378 "settings.user.form.accountType.non-profit": "Ikke-profittbasert",
388 "settings.user.form.currentPassword": "Nåværende passord", 379 "settings.user.form.currentPassword": "Nåværende passord",
389 "settings.user.form.email": "E-post", 380 "settings.user.form.email": "E-post",
390 "settings.user.form.firstname": "Fornavn", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Etternavn", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nytt passord", 383 "settings.user.form.newPassword": "Nytt passord",
393 "settings.workspace.add.form.name": "Navn", 384 "settings.workspace.add.form.name": "Navn",
394 "settings.workspace.add.form.submitButton": "Opprett arbeidsområde", 385 "settings.workspace.add.form.submitButton": "Opprett arbeidsområde",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Prøv igjen", 396 "settings.workspaces.tryReloadWorkspaces": "Prøv igjen",
406 "settings.workspaces.updatedInfo": "Dine endringer har blitt lagret", 397 "settings.workspaces.updatedInfo": "Dine endringer har blitt lagret",
407 "settings.workspaces.workspaceFeatureHeadline": "Mindre er mer: Vi innfører Ferdi arbeidsområder", 398 "settings.workspaces.workspaceFeatureHeadline": "Mindre er mer: Vi innfører Ferdi arbeidsområder",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdi arbeidsområder lar deg fokusere på hva som er viktig akkurat nå. Sett opp forskjellige sett av tjenester, og veksle enkelt mellom dem når som helst. Du bestemmer hvilke tjenester du trenger når og hvor, så vi kan hjelpe deg med å bli best i spillet - eller enkelt koble av fra jobb når du måtte trenge det.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Kunne ikke laste dine arbeidsområder", 400 "settings.workspaces.workspacesRequestFailed": "Kunne ikke laste dine arbeidsområder",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Aktiver varsler og lyd", 411 "sidebar.unmuteApp": "Aktiver varsler og lyd",
421 "signup.email.label": "E-postadresse", 412 "signup.email.label": "E-postadresse",
422 "signup.emailDuplicate": "Det finnes allerede en bruker med den e-postadressen", 413 "signup.emailDuplicate": "Det finnes allerede en bruker med den e-postadressen",
423 "signup.firstname.label": "Fornavn", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Registrer deg", 415 "signup.headline": "Registrer deg",
425 "signup.lastname.label": "Etternavn", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Ved å opprette en Ferdi-konto godtar du", 417 "signup.legal.info": "Ved å opprette en Ferdi-konto godtar du",
427 "signup.legal.privacy": "Personvernerklæring", 418 "signup.legal.privacy": "Personvernerklæring",
428 "signup.legal.terms": "Vilkår for bruk", 419 "signup.legal.terms": "Vilkår for bruk",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Passord", 421 "signup.password.label": "Passord",
431 "signup.submit.label": "Opprett konto", 422 "signup.submit.label": "Opprett konto",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Slett tjeneste", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Deaktiver lyd", 425 "tabs.item.disableAudio": "Deaktiver lyd",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Deaktiver varslinger", 427 "tabs.item.disableNotifications": "Deaktiver varslinger",
437 "tabs.item.disableService": "Deaktiver tjeneste", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Aktiver lyd", 429 "tabs.item.enableAudio": "Aktiver lyd",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Aktiver varsler", 431 "tabs.item.enableNotification": "Aktiver varsler",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Last inn på nytt", 434 "tabs.item.reload": "Last inn på nytt",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} er ikke gyldig", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} bør være minst {length} tegn", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Minst en er påkrevd", 438 "validation.oneRequired": "Minst en er påkrevd",
448 "validation.required": "{field} er påkrevd", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} er ikke en gyldig nettadresse", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Tilbake", 441 "webControls.back": "Tilbake",
451 "webControls.forward": "Videresend", 442 "webControls.forward": "Videresend",
452 "webControls.goHome": "Hjem", 443 "webControls.goHome": "Hjem",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Last inn på nytt", 445 "webControls.reload": "Last inn på nytt",
455 "welcome.loginButton": "Logg på kontoen din", 446 "welcome.loginButton": "Logg på kontoen din",
456 "welcome.signupButton": "Opprett en gratis konto", 447 "welcome.signupButton": "Opprett en gratis konto",
457 "workspaceDrawer.addNewWorkspaceLabel": "Opprett nytt arbeidsområde", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Alle tjenester", 449 "workspaceDrawer.allServices": "Alle tjenester",
459 "workspaceDrawer.headline": "Arbeidsområder", 450 "workspaceDrawer.headline": "Arbeidsområder",
460 "workspaceDrawer.item.contextMenuEdit": "rediger", 451 "workspaceDrawer.item.contextMenuEdit": "rediger",
461 "workspaceDrawer.item.noServicesAddedYet": "Ingen tjenester er lagt til ennå", 452 "workspaceDrawer.item.noServicesAddedYet": "Ingen tjenester er lagt til ennå",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi arbeidsområder lar deg fokusere på hva som er viktig akkurat nå. Sett opp forskjellige sett av tjenester, og veksle enkelt mellom dem når som helst.</p><p>Du bestemmer hvilke tjenester du trenger når og hvor, så vi kan hjelpe deg med å bli best i spillet - eller enkelt koble av fra jobb når du måtte trenge det.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Rediger innstillinger for arbeidsområder", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Bytter til" 455 "workspaces.switchingIndicator.switchingTo": "Bytter til"
465} 456}
diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json
index ea37ec76c..a19c7c444 100644
--- a/src/i18n/locales/pl.json
+++ b/src/i18n/locales/pl.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Odśwież", 2 "app.errorHandler.action": "Odśwież",
3 "app.errorHandler.headline": "Coś poszło nie tak", 3 "app.errorHandler.headline": "Coś poszło nie tak.",
4 "changeserver.customServerLabel": "Spersonalizowany serwer", 4 "changeserver.customServerLabel": "Spersonalizowany serwer",
5 "changeserver.headline": "Zmień serwer", 5 "changeserver.headline": "Zmień serwer",
6 "changeserver.label": "Serwer", 6 "changeserver.label": "Serwer",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Co się stało?", 10 "connectionLostBanner.informationLink": "Co się stało?",
11 "connectionLostBanner.message": "O nie! Ferdi stracił połączenie z {name}.", 11 "connectionLostBanner.message": "O nie! Ferdi stracił połączenie z {name}.",
12 "feature.basicAuth.signIn": "Zaloguj siÄ™", 12 "feature.basicAuth.signIn": "Zaloguj siÄ™",
13 "feature.debugger.title": "Opublikuj dane diagnostyczne",
14 "feature.nightlyBuilds.activate": "Aktywuj", 13 "feature.nightlyBuilds.activate": "Aktywuj",
15 "feature.nightlyBuilds.info": "Kompilacje testowe to wysoce eksperymentalne wersje Ferdi, które mogą zawierać niedopracowane lub nieukończone funkcje. Te kompilacje są przewidziane głównie dla programistów testujących nowe funkcje będące w opracowaniu oraz ostateczne działanie ukończonej kompilacji. Jeśli nie masz pewności co do tej funkcji, zalecamy nie włączać wersji testowych.", 14 "feature.nightlyBuilds.info": "Kompilacje testowe to wysoce eksperymentalne wersje Ferdi, które mogą zawierać niedopracowane lub nieukończone funkcje. Te kompilacje są przewidziane głównie dla programistów testujących nowe funkcje będące w opracowaniu oraz ostateczne działanie ukończonej kompilacji. Jeśli nie masz pewności co do tej funkcji, zalecamy nie włączać wersji testowych.",
16 "feature.nightlyBuilds.title": "Kompilacje testowe", 15 "feature.nightlyBuilds.title": "Kompilacje testowe",
@@ -23,15 +22,15 @@
23 "feature.publishDebugInfo.title": "Opublikuj dane diagnostyczne", 22 "feature.publishDebugInfo.title": "Opublikuj dane diagnostyczne",
24 "feature.quickSwitch.info": "Wybierz usługę naciskając TAB, ↑ oraz ↓. Otwórz usługę naciskając ENTER.", 23 "feature.quickSwitch.info": "Wybierz usługę naciskając TAB, ↑ oraz ↓. Otwórz usługę naciskając ENTER.",
25 "feature.quickSwitch.search": "Szukaj...", 24 "feature.quickSwitch.search": "Szukaj...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "Szybkie przełączenie",
27 "global.api.unhealthy": "Nie można połączyć się z usługami Ferdi online", 26 "global.api.unhealthy": "Nie można połączyć z usługami Ferdi",
28 "global.cancel": "Anuluj", 27 "global.cancel": "Anuluj",
29 "global.edit": "Edytuj", 28 "global.edit": "Edytuj",
30 "global.no": "Nie", 29 "global.no": "Nie",
31 "global.notConnectedToTheInternet": "Nie masz połączenia z Internetem.", 30 "global.notConnectedToTheInternet": "Nie masz połączenia z Internetem.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Wyjdź", 32 "global.quit": "Wyjdź",
34 "global.quitConfirmation": "Czy napewno chcesz wyjść z Ferdi?", 33 "global.quitConfirmation": "Czy chcesz wyjść z Ferdi?",
35 "global.save": "Zapisz", 34 "global.save": "Zapisz",
36 "global.settings": "Ustawienia", 35 "global.settings": "Ustawienia",
37 "global.spellchecker.useDefault": "Użyj domyślnego dla systemu ({default})", 36 "global.spellchecker.useDefault": "Użyj domyślnego dla systemu ({default})",
@@ -45,7 +44,7 @@
45 "import.headline": "Importuj usługi Ferdi 4", 44 "import.headline": "Importuj usługi Ferdi 4",
46 "import.notSupportedHeadline": "Usługi, które nie są jeszcze obsługiwane w Ferdi 5", 45 "import.notSupportedHeadline": "Usługi, które nie są jeszcze obsługiwane w Ferdi 5",
47 "import.skip.label": "Chcę dodać usługi samodzielnie", 46 "import.skip.label": "Chcę dodać usługi samodzielnie",
48 "import.submit.label": "Zaimportuj usługi", 47 "import.submit.label": "Importuj {count} usług",
49 "infobar.authRequestFailed": "Pojawiły się błędy podczas próby uwierzytelniania. Proszę spróbuj się wylogować i zalogować ponownie, jeśli ten błąd będzie się powtarzał.", 48 "infobar.authRequestFailed": "Pojawiły się błędy podczas próby uwierzytelniania. Proszę spróbuj się wylogować i zalogować ponownie, jeśli ten błąd będzie się powtarzał.",
50 "infobar.buttonChangelog": "Co nowego?", 49 "infobar.buttonChangelog": "Co nowego?",
51 "infobar.buttonInstallUpdate": "Uruchom ponownie i zainstaluj aktualizacjÄ™", 50 "infobar.buttonInstallUpdate": "Uruchom ponownie i zainstaluj aktualizacjÄ™",
@@ -70,13 +69,13 @@
70 "locked.touchIdPrompt": "odblokuj przez Touch ID", 69 "locked.touchIdPrompt": "odblokuj przez Touch ID",
71 "locked.unlockWithPassword": "Odblokuj hasłem", 70 "locked.unlockWithPassword": "Odblokuj hasłem",
72 "login.changeServer": "Zmień serwer", 71 "login.changeServer": "Zmień serwer",
73 "login.customServerQuestion": "Using a custom Ferdi server?", 72 "login.customServerQuestion": "Używasz niestandardowego serwera Ferdi?",
74 "login.customServerSuggestion": "Try importing your Franz account", 73 "login.customServerSuggestion": "Spróbuj zaimportować konto Franz",
75 "login.email.label": "Adres email", 74 "login.email.label": "Adres email",
76 "login.headline": "Zaloguj siÄ™", 75 "login.headline": "Zaloguj siÄ™",
77 "login.invalidCredentials": "Adres email lub hasło są błędne", 76 "login.invalidCredentials": "Adres email lub hasło są błędne",
78 "login.link.password": "Zresetuj hasło", 77 "login.link.password": "Resetuj hasło",
79 "login.link.signup": "Załóż darmowe konto", 78 "login.link.signup": "Załóż konto",
80 "login.password.label": "Hasło", 79 "login.password.label": "Hasło",
81 "login.serverLogout": "Twoja sesja wygasła, zaloguj się ponownie.", 80 "login.serverLogout": "Twoja sesja wygasła, zaloguj się ponownie.",
82 "login.submit.label": "Zaloguj siÄ™", 81 "login.submit.label": "Zaloguj siÄ™",
@@ -117,17 +116,17 @@
117 "menu.help.support": "Wsparcie", 116 "menu.help.support": "Wsparcie",
118 "menu.help.tos": "Warunki użytkowania", 117 "menu.help.tos": "Warunki użytkowania",
119 "menu.services": "Usługi", 118 "menu.services": "Usługi",
120 "menu.services.activatePreviousService": "Poprzednia usługa", 119 "menu.services.activatePreviousService": "Aktywuj poprzednią usługę",
121 "menu.services.addNewService": "Dodaj nową usługę", 120 "menu.services.addNewService": "Dodaj nową usługę...",
122 "menu.services.goHome": "Strona główna", 121 "menu.services.goHome": "Strona główna",
123 "menu.services.setNextServiceActive": "Następna usługa", 122 "menu.services.setNextServiceActive": "Aktywuj następną usługę",
124 "menu.todos": "Lista zadań", 123 "menu.todos": "Lista zadań",
125 "menu.todos.enableTodos": "Włącz listę zadań", 124 "menu.todos.enableTodos": "Włącz listę zadań",
126 "menu.view": "Widok", 125 "menu.view": "Widok",
127 "menu.view.back": "Wstecz", 126 "menu.view.back": "Wstecz",
128 "menu.view.forward": "Prześlij dalej", 127 "menu.view.forward": "Prześlij dalej",
129 "menu.view.lockFerdi": "Zablokuj Ferdi", 128 "menu.view.lockFerdi": "Zablokuj Ferdi",
130 "menu.view.openQuickSwitch": "Otwórz Quick Switch", 129 "menu.view.openQuickSwitch": "Otwórz szybki wybór",
131 "menu.view.reloadFerdi": "Przeładuj Ferdi", 130 "menu.view.reloadFerdi": "Przeładuj Ferdi",
132 "menu.view.reloadService": "Przeładuj usługę", 131 "menu.view.reloadService": "Przeładuj usługę",
133 "menu.view.reloadTodos": "Odśwież Zadania", 132 "menu.view.reloadTodos": "Odśwież Zadania",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Wszystkie usługi", 147 "menu.workspaces.defaultWorkspace": "Wszystkie usługi",
149 "menu.workspaces.openWorkspaceDrawer": "Otwórz edytor obszaru roboczego", 148 "menu.workspaces.openWorkspaceDrawer": "Otwórz edytor obszaru roboczego",
150 "password.email.label": "Adres email", 149 "password.email.label": "Adres email",
151 "password.headline": "Zresetuj hasło", 150 "password.headline": "Resetuj hasło",
152 "password.link.login": "Zaloguj siÄ™ na swoje konto", 151 "password.link.login": "Zaloguj siÄ™ na swoje konto",
153 "password.link.signup": "Załóż darmowe konto", 152 "password.link.signup": "Załóż darmowe konto",
154 "password.noUser": "Nie znaleziono użytkownika z takim adresem email", 153 "password.noUser": "Użytkownik z podanym adresem email nie istnieje",
155 "password.successInfo": "Proszę sprawdzić swój email", 154 "password.successInfo": "Twoje nowe hasło zostało wysłane na Twoją skrzynkę mailową",
156 "pricing.features.accountSync": "Synchronizacja konta",
157 "pricing.features.customWebsites": "Dodawanie dowolnych stron internetowych",
158 "pricing.features.desktopNotifications": "Powiadomienia na pulpicie",
159 "pricing.features.onPremise": "Lokalne i inne hostowane usługi",
160 "pricing.features.recipes": "Wybierz spośród ponad 70 usług",
161 "pricing.features.serviceProxies": "Proxy usługi",
162 "pricing.features.spellchecker": "Obsługa sprawdzania pisowni",
163 "pricing.features.teamManagement": "Zarządzanie zespołem",
164 "pricing.features.thirdPartyServices": "Instalacja zewnętrznych usług",
165 "pricing.features.unlimitedServices": "Dodawanie nielimitowanych usług",
166 "pricing.features.workspaces": "Obszary robocze",
167 "service.crashHandler.action": "Przeładuj {name}", 155 "service.crashHandler.action": "Przeładuj {name}",
168 "service.crashHandler.autoReload": "Próba automatycznego odnowienia {name} za {seconds} sekund/y", 156 "service.crashHandler.autoReload": "Próba automatycznego odnowienia {name} za {seconds} sekund/y",
169 "service.crashHandler.headline": "O nie!", 157 "service.crashHandler.headline": "O nie!",
@@ -178,10 +166,10 @@
178 "service.webviewLoader.loading": "Wczytywanie {service}", 166 "service.webviewLoader.loading": "Wczytywanie {service}",
179 "services.getStarted": "Zacznij", 167 "services.getStarted": "Zacznij",
180 "services.login": "Zaloguj się, aby używać Ferdi.", 168 "services.login": "Zaloguj się, aby używać Ferdi.",
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Opcjonalnie możesz zmienić swój serwer Ferdi klikając zębatkę w lewym dolnym rogu. Jeżeli przełączasz się (z jednego z hostowanych serwerów) do serwerów Ferdi bez konta, pamiętaj, że możesz wyeksportować swoje dane z tego serwera a następnie zaimportować je używając opcji Pomoc w menu aby przywrócić swoje obszary robocze i skonfigurowane usługi!",
182 "services.serverless": "Używaj Ferdi bez konta", 170 "services.serverless": "Używaj Ferdi bez konta",
183 "services.welcome": "Witaj w programie Ferdi", 171 "services.welcome": "Witaj w programie Ferdi",
184 "settings.account.account.editButton": "Modyfikuj konta", 172 "settings.account.account.editButton": "Edytuj konto",
185 "settings.account.accountUnavailable": "Konto jest niedostępne", 173 "settings.account.accountUnavailable": "Konto jest niedostępne",
186 "settings.account.accountUnavailableInfo": "Używasz Ferdi bez konta. Jeśli chcesz używać Ferdi z kontem i synchronizować swoje usługi pomiędzy klientami, wybierz serwer w zakładce Ustawienia i zaloguj się.", 174 "settings.account.accountUnavailableInfo": "Używasz Ferdi bez konta. Jeśli chcesz używać Ferdi z kontem i synchronizować swoje usługi pomiędzy klientami, wybierz serwer w zakładce Ustawienia i zaloguj się.",
187 "settings.account.buttonSave": "Uaktualnij profil", 175 "settings.account.buttonSave": "Uaktualnij profil",
@@ -190,7 +178,7 @@
190 "settings.account.deleteInfo": "Jeżeli nie potrzebujesz już konta Ferdi, możesz je usunąć oraz wszystkie dane na nim zapisane.", 178 "settings.account.deleteInfo": "Jeżeli nie potrzebujesz już konta Ferdi, możesz je usunąć oraz wszystkie dane na nim zapisane.",
191 "settings.account.headline": "Konto", 179 "settings.account.headline": "Konto",
192 "settings.account.headlineAccount": "Informacje o koncie", 180 "settings.account.headlineAccount": "Informacje o koncie",
193 "settings.account.headlineDangerZone": "Niebezpieczna strefa", 181 "settings.account.headlineDangerZone": "Strefa niebezpieczna",
194 "settings.account.headlineInvoices": "Faktury", 182 "settings.account.headlineInvoices": "Faktury",
195 "settings.account.headlinePassword": "Zmień hasło", 183 "settings.account.headlinePassword": "Zmień hasło",
196 "settings.account.headlineProfile": "Uaktualnij profil", 184 "settings.account.headlineProfile": "Uaktualnij profil",
@@ -198,12 +186,12 @@
198 "settings.account.tryReloadServices": "Spróbuj ponownie", 186 "settings.account.tryReloadServices": "Spróbuj ponownie",
199 "settings.account.tryReloadUserInfoRequest": "Spróbuj ponownie", 187 "settings.account.tryReloadUserInfoRequest": "Spróbuj ponownie",
200 "settings.account.userInfoRequestFailed": "Nie można wczytać informacji o użytkowniku", 188 "settings.account.userInfoRequestFailed": "Nie można wczytać informacji o użytkowniku",
201 "settings.account.yourLicense": "Twoja licencja Ferdi", 189 "settings.account.yourLicense": " Twoja licencja Ferdi:",
202 "settings.app.accentColorInfo": "Zdefiniuj kolor akcentu w formacie zgodnym z CSS. (Domyślnie: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Zdefiniuj kolor akcentu w formacie zgodnym z CSS. (Domyślnie: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Wyczyść pamięć podręczną (cache)", 191 "settings.app.buttonClearAllCache": "Wyczyść pamięć podręczną (cache)",
204 "settings.app.buttonInstallUpdate": "Uruchom ponownie i zainstaluj aktualizacjÄ™", 192 "settings.app.buttonInstallUpdate": "Uruchom ponownie i zainstaluj aktualizacjÄ™",
205 "settings.app.buttonOpenFerdiProfileFolder": "Pokaż folder z profilami", 193 "settings.app.buttonOpenFerdiProfileFolder": "Pokaż folder z profilami",
206 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Open Service Recipes folder", 194 "settings.app.buttonOpenFerdiServiceRecipesFolder": "Otwórz folder usług",
207 "settings.app.buttonSearchForUpdate": "Sprawdź aktualizacje", 195 "settings.app.buttonSearchForUpdate": "Sprawdź aktualizacje",
208 "settings.app.cacheInfo": "Pamięć podręczna zajmuje obecnie {size} przestrzeni dyskowej", 196 "settings.app.cacheInfo": "Pamięć podręczna zajmuje obecnie {size} przestrzeni dyskowej",
209 "settings.app.cacheNotCleared": "Błąd czyszczenia pamięci podręcznej", 197 "settings.app.cacheNotCleared": "Błąd czyszczenia pamięci podręcznej",
@@ -219,24 +207,24 @@
219 "settings.app.form.clipboardNotifications": "Nie wyświetlaj powiadomień dla schowka", 207 "settings.app.form.clipboardNotifications": "Nie wyświetlaj powiadomień dla schowka",
220 "settings.app.form.closeToSystemTray": "Zminimalizuj Ferdi do paska zadań", 208 "settings.app.form.closeToSystemTray": "Zminimalizuj Ferdi do paska zadań",
221 "settings.app.form.confirmOnQuit": "Potwierdź podczas opuszczania Ferdi", 209 "settings.app.form.confirmOnQuit": "Potwierdź podczas opuszczania Ferdi",
222 "settings.app.form.customTodoServer": "Własny serwer listy zadań", 210 "settings.app.form.customTodoServer": "Niestandardowy serwer Todo",
223 "settings.app.form.darkMode": "WÅ‚Ä…cz tryb ciemny", 211 "settings.app.form.darkMode": "WÅ‚Ä…cz Ciemny motyw",
224 "settings.app.form.enableGPUAcceleration": "WÅ‚Ä…cz akceleracjÄ™ GPU", 212 "settings.app.form.enableGPUAcceleration": "WÅ‚Ä…cz akceleracjÄ™ GPU",
225 "settings.app.form.enableLock": "Włącz blokadę hasłem", 213 "settings.app.form.enableLock": "Włącz blokadę hasłem",
226 "settings.app.form.enableMenuBar": "Zawsze wyświetlaj Ferdi na pasku zadań", 214 "settings.app.form.enableMenuBar": "Zawsze wyświetlaj Ferdi na pasku zadań",
227 "settings.app.form.enableSpellchecking": "WÅ‚Ä…cz sprawdzanie pisowni", 215 "settings.app.form.enableSpellchecking": "WÅ‚Ä…cz sprawdzanie pisowni",
228 "settings.app.form.enableSystemTray": "Pokaż Ferdia w obszarze powiadomień", 216 "settings.app.form.enableSystemTray": "Zawsze pokazuj Ferdi na pasku zadań",
229 "settings.app.form.enableTodos": "WÅ‚Ä…cz Zadania Ferdi", 217 "settings.app.form.enableTodos": "WÅ‚Ä…cz Zadania Ferdi",
230 "settings.app.form.hibernateOnStartup": "Hibernacja usług po starcie systemu", 218 "settings.app.form.hibernateOnStartup": "Hibernacja usług po starcie systemu",
231 "settings.app.form.hibernationStrategy": "Strategia hibernacji", 219 "settings.app.form.hibernationStrategy": "Strategia hibernacji",
232 "settings.app.form.iconSize": "Rozmiar ikony usługi", 220 "settings.app.form.iconSize": "Rozmiar ikony usługi",
233 "settings.app.form.inactivityLock": "Zablokuj przy braku aktywności", 221 "settings.app.form.inactivityLock": "Zablokuj przy braku aktywności",
234 "settings.app.form.keepAllWorkspacesLoaded": "Keep all workspaces loaded", 222 "settings.app.form.keepAllWorkspacesLoaded": "Trzymaj wszystkie pola robocze załadowane",
235 "settings.app.form.language": "Język", 223 "settings.app.form.language": "Język",
236 "settings.app.form.lockPassword": "Hasło", 224 "settings.app.form.lockPassword": "Hasło",
237 "settings.app.form.minimizeToSystemTray": "Zminimalizuj aplikacjÄ™ Ferdi", 225 "settings.app.form.minimizeToSystemTray": "Zminimalizuj aplikacjÄ™ Ferdi",
238 "settings.app.form.navigationBarBehaviour": "Zachowanie paska nawigacji", 226 "settings.app.form.navigationBarBehaviour": "Zachowanie paska nawigacji",
239 "settings.app.form.notifyTaskBarOnMessage": "Notify TaskBar/Dock on new message", 227 "settings.app.form.notifyTaskBarOnMessage": "Powiadom na pasku zadań o nowej wiadomości",
240 "settings.app.form.passwordToggle": "Przełącznik hasła", 228 "settings.app.form.passwordToggle": "Przełącznik hasła",
241 "settings.app.form.predefinedTodoServer": "Serwer Todo", 229 "settings.app.form.predefinedTodoServer": "Serwer Todo",
242 "settings.app.form.privateNotifications": "Nie pokazuj treści wiadomości w powiadomieniach", 230 "settings.app.form.privateNotifications": "Nie pokazuj treści wiadomości w powiadomieniach",
@@ -249,11 +237,12 @@
249 "settings.app.form.sentry": "Wysyłaj dane telemetrii", 237 "settings.app.form.sentry": "Wysyłaj dane telemetrii",
250 "settings.app.form.serviceRibbonWidth": "Szerokość paska bocznego", 238 "settings.app.form.serviceRibbonWidth": "Szerokość paska bocznego",
251 "settings.app.form.showDisabledServices": "Wyświetlaj karty wyłączonych usług", 239 "settings.app.form.showDisabledServices": "Wyświetlaj karty wyłączonych usług",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Pokaż obszar do przeciągania w oknie",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Pokaż licznik nieprzeczytanych wiadomości gdy powiadomienia są wyłączone", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Pokaż licznik nieprzeczytanych wiadomości gdy powiadomienia są wyłączone",
242 "settings.app.form.splitMode": "Aktywuj tryb podzielonego widoku",
254 "settings.app.form.startMinimized": "Uruchom zminimalizowany", 243 "settings.app.form.startMinimized": "Uruchom zminimalizowany",
255 "settings.app.form.universalDarkMode": "WÅ‚Ä…cz uniwersalny tryb ciemny", 244 "settings.app.form.universalDarkMode": "WÅ‚Ä…cz uniwersalny tryb ciemny",
256 "settings.app.form.useTouchIdToUnlock": "Zezwól na odblokowanie Ferdi przez Touch ID", 245 "settings.app.form.useTouchIdToUnlock": "Zawsze używaj TouchID do odblokowania Ferdi",
257 "settings.app.form.useVerticalStyle": "Użyj stylu poziomego", 246 "settings.app.form.useVerticalStyle": "Użyj stylu poziomego",
258 "settings.app.form.wakeUpStrategy": "Strategia wybudzania", 247 "settings.app.form.wakeUpStrategy": "Strategia wybudzania",
259 "settings.app.headlineAdvanced": "Zaawansowane", 248 "settings.app.headlineAdvanced": "Zaawansowane",
@@ -262,8 +251,8 @@
262 "settings.app.headlineLanguage": "Język", 251 "settings.app.headlineLanguage": "Język",
263 "settings.app.headlinePrivacy": "Prywatność", 252 "settings.app.headlinePrivacy": "Prywatność",
264 "settings.app.headlineUpdates": "Aktualizacje", 253 "settings.app.headlineUpdates": "Aktualizacje",
265 "settings.app.hibernateInfo": "By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.", 254 "settings.app.hibernateInfo": "Domyślnie, Ferdi trzyma wszystkie Twoje usługi włączone w tle, aby były gotowe w momencie kiedy będziesz ich potrzebował. Hibernacja usług odłączy Twoje usługi po określonym czasie. Dzięki temu zachowasz pamięć RAM lub zachowasz usługi od spowolnienia komputera.",
266 "settings.app.inactivityLockInfo": "Minutes of inactivity, after which Ferdi should automatically lock. Use 0 to disable", 255 "settings.app.inactivityLockInfo": "Minut do dezaktywacji, po których Ferdi automatycznie zablokuje. Wybierz 0 aby dezaktywować",
267 "settings.app.languageDisclaimer": "Oficjalnymi językami są Angielski i Niemiecki. Inne języki są tłumaczone przez społeczność Ferdi.", 256 "settings.app.languageDisclaimer": "Oficjalnymi językami są Angielski i Niemiecki. Inne języki są tłumaczone przez społeczność Ferdi.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Hasło", 258 "settings.app.lockedPassword": "Hasło",
@@ -296,7 +285,7 @@
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Dokumentacja deweloperska", 287 "settings.recipes.customService.openDevDocs": "Dokumentacja deweloperska",
299 "settings.recipes.customService.openFolder": "Otwórz folder", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Dostępne usługi", 289 "settings.recipes.headline": "Dostępne usługi",
301 "settings.recipes.missingService": "Brak usługi?", 290 "settings.recipes.missingService": "Brak usługi?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Usuń usługę", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Edytuj {name}", 305 "settings.service.form.editServiceHeadline": "Edytuj {name}",
317 "settings.service.form.enableAudio": "Włącz dźwięk", 306 "settings.service.form.enableAudio": "Włącz dźwięk",
318 "settings.service.form.enableBadge": "Pokaż znacznik nieprzeczytanych wiadomości", 307 "settings.service.form.enableBadge": "Pokaż znacznik nieprzeczytanych wiadomości",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Kiedy nieaktywne, wszystkie dźwięki powiadomień są wyciszone", 322 "settings.service.form.isMutedInfo": "Kiedy nieaktywne, wszystkie dźwięki powiadomień są wyciszone",
334 "settings.service.form.name": "ImiÄ™", 323 "settings.service.form.name": "ImiÄ™",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Otwórz darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Otwórz darkmode.css",
336 "settings.service.form.openUserCss": "Otwórz user.css", 326 "settings.service.form.openUserCss": "Otwórz user.css",
337 "settings.service.form.openUserJs": "Otwórz user.js", 327 "settings.service.form.openUserJs": "Otwórz user.js",
338 "settings.service.form.proxy.headline": "Ustawienia Proxy HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "Ustawienia Proxy HTTP/HTTPS",
339 "settings.service.form.proxy.host": "Host Proxy/IP", 329 "settings.service.form.proxy.host": "Host Proxy/IP",
340 "settings.service.form.proxy.info": "Ustawienia proxy nie będą zsynchronizowane z serwerami Ferdia.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Użyj Proxy", 331 "settings.service.form.proxy.isEnabled": "Użyj Proxy",
342 "settings.service.form.proxy.password": "Hasło (opcjonalnie)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Uruchom ponownie Ferdi po zmianie ustawień proxy.", 334 "settings.service.form.proxy.restartInfo": "Uruchom ponownie Ferdi po zmianie ustawień proxy.",
345 "settings.service.form.proxy.user": "Użytkownik (opcjonalnie)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Zapisz usługę", 337 "settings.service.form.saveButton": "Zapisz usługę",
348 "settings.service.form.tabHosted": "Hostowane", 338 "settings.service.form.tabHosted": "Hostowane",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Przeglądaj usługi", 344 "settings.services.discoverServices": "Przeglądaj usługi",
355 "settings.services.headline": "Twoje usługi", 345 "settings.services.headline": "Twoje usługi",
356 "settings.services.noServicesAdded": "Rozpocznij od dodania usługi.", 346 "settings.services.noServicesAdded": "Rozpocznij od dodania usługi.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Nie udało się załadować twoich usług", 348 "settings.services.servicesRequestFailed": "Nie udało się załadować twoich usług",
358 "settings.services.tooltip.isDisabled": "Usługa jest nieaktywna", 349 "settings.services.tooltip.isDisabled": "Usługa jest nieaktywna",
359 "settings.services.tooltip.isMuted": "Wszystkie dźwięki są wyciszone", 350 "settings.services.tooltip.isMuted": "Wszystkie dźwięki są wyciszone",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>",
363 "settings.supportFerdi.bannerText": "Do you want to help us improve Ferdi?", 354 "settings.supportFerdi.bannerText": "Do you want to help us improve Ferdi?",
364 "settings.supportFerdi.headline": "O Ferdi", 355 "settings.supportFerdi.headline": "O Ferdi",
365 "settings.supportFerdi.openSurvey": "Otwarta ankieta", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "If you feel like supporting Ferdi development with a donation, you can do so on both,", 357 "settings.supportFerdi.textDonation": "If you feel like supporting Ferdi development with a donation, you can do so on both,",
367 "settings.supportFerdi.textDonationAnd": "i", 358 "settings.supportFerdi.textDonationAnd": "i",
368 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our", 359 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our",
369 "settings.supportFerdi.textGitHubSponsors": "Sponsor na Guthub", 360 "settings.supportFerdi.textGitHubSponsors": "Sponsor na Guthub",
370 "settings.supportFerdi.textListContributors": "Pełna lista współtwórców", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "tutaj", 362 "settings.supportFerdi.textListContributorsHere": "tutaj",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Doceniamy każde wsparcie. Listę rzeczy, z którymi potrzebujemy pomocy znajdziesz", 364 "settings.supportFerdi.textSupportWelcome": "Doceniamy każde wsparcie. Listę rzeczy, z którymi potrzebujemy pomocy znajdziesz",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Non-Profit", 378 "settings.user.form.accountType.non-profit": "Non-Profit",
388 "settings.user.form.currentPassword": "Obecne hasło", 379 "settings.user.form.currentPassword": "Obecne hasło",
389 "settings.user.form.email": "Adres email", 380 "settings.user.form.email": "Adres email",
390 "settings.user.form.firstname": "ImiÄ™", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Nazwisko", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nowe hasło", 383 "settings.user.form.newPassword": "Nowe hasło",
393 "settings.workspace.add.form.name": "ImiÄ™", 384 "settings.workspace.add.form.name": "ImiÄ™",
394 "settings.workspace.add.form.submitButton": "Stwórz obszar roboczy", 385 "settings.workspace.add.form.submitButton": "Stwórz obszar roboczy",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Spróbuj ponownie", 396 "settings.workspaces.tryReloadWorkspaces": "Spróbuj ponownie",
406 "settings.workspaces.updatedInfo": "Twoje zmiany zostały zapisane", 397 "settings.workspaces.updatedInfo": "Twoje zmiany zostały zapisane",
407 "settings.workspaces.workspaceFeatureHeadline": "Mniej znaczy więcej: Wprowadzenie do obszarów roboczych Ferdi", 398 "settings.workspaces.workspaceFeatureHeadline": "Mniej znaczy więcej: Wprowadzenie do obszarów roboczych Ferdi",
408 "settings.workspaces.workspaceFeatureInfo": "Obszary robocze programu Ferdi pozawala Ci na skupieniu się na tym co ważne w danym momencie. Ustaw różne zestawy usług i przełączaj się między nimi w łatwiejszy sposób w dowolnym momencie. Decyduj, które usługi potrzebujesz , więc pomagamy Ci pozostawać na szczycie gry - lub łatwiej wyłączyć się z pracy kiedy tego potrzebujesz.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Nie można załadować obszaru roboczego", 400 "settings.workspaces.workspacesRequestFailed": "Nie można załadować obszaru roboczego",
410 "setupAssistant.headline": "Zaczynajmy", 401 "setupAssistant.headline": "Zaczynajmy",
411 "setupAssistant.subheadline": "Wybierz spośród naszych najczęściej używanych usług i powróć do rutynowej komunikacji.", 402 "setupAssistant.subheadline": "Wybierz spośród naszych najczęściej używanych usług i powróć do rutynowej komunikacji.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Włącz powiadomienia i dźwięki", 411 "sidebar.unmuteApp": "Włącz powiadomienia i dźwięki",
421 "signup.email.label": "Adres email", 412 "signup.email.label": "Adres email",
422 "signup.emailDuplicate": "Użytkownik z takim adresem email już istnieje", 413 "signup.emailDuplicate": "Użytkownik z takim adresem email już istnieje",
423 "signup.firstname.label": "ImiÄ™", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Zarejestruj siÄ™", 415 "signup.headline": "Zarejestruj siÄ™",
425 "signup.lastname.label": "Nazwisko", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Poprzez utworzenie konta Ferdi akceptujesz", 417 "signup.legal.info": "Poprzez utworzenie konta Ferdi akceptujesz",
427 "signup.legal.privacy": "Polityka prywatności", 418 "signup.legal.privacy": "Polityka prywatności",
428 "signup.legal.terms": "Warunki świadczenia usług", 419 "signup.legal.terms": "Warunki świadczenia usług",
@@ -430,23 +421,23 @@
430 "signup.password.label": "Hasło", 421 "signup.password.label": "Hasło",
431 "signup.submit.label": "Stwórz konto", 422 "signup.submit.label": "Stwórz konto",
432 "tabs.item.confirmDeleteService": "Czy na pewno chcesz usunąć usługę {serviceName}?", 423 "tabs.item.confirmDeleteService": "Czy na pewno chcesz usunąć usługę {serviceName}?",
433 "tabs.item.deleteService": "Usuń usługę", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Wyłącz dźwięk", 425 "tabs.item.disableAudio": "Wyłącz dźwięk",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Wyłącz powiadomienia", 427 "tabs.item.disableNotifications": "Wyłącz powiadomienia",
437 "tabs.item.disableService": "Wyłącz usługę", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Włącz dźwięk", 429 "tabs.item.enableAudio": "Włącz dźwięk",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Aktywuj powiadomienia", 431 "tabs.item.enableNotification": "Aktywuj powiadomienia",
441 "tabs.item.enableService": "Aktywuj usługę", 432 "tabs.item.enableService": "Aktywuj usługę",
442 "tabs.item.hibernateService": "Hibernuj usługę", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Odśwież", 434 "tabs.item.reload": "Odśwież",
444 "tabs.item.wakeUpService": "Wybudź usługę", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "Pole {field} nie jest poprawne", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "Pole {field} powinno składać się z co najmniej {length} znaków", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Przynajmniej jeden jest wymagany", 438 "validation.oneRequired": "Przynajmniej jeden jest wymagany",
448 "validation.required": "Pole {field} jest wymagane", 439 "validation.required": "{field} is required",
449 "validation.url": "Pole {field} nie jest poprawnym ciÄ…giem URL.", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Wstecz", 441 "webControls.back": "Wstecz",
451 "webControls.forward": "Prześlij dalej", 442 "webControls.forward": "Prześlij dalej",
452 "webControls.goHome": "Strona główna", 443 "webControls.goHome": "Strona główna",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Odśwież", 445 "webControls.reload": "Odśwież",
455 "welcome.loginButton": "Zaloguj siÄ™ na swoje konto", 446 "welcome.loginButton": "Zaloguj siÄ™ na swoje konto",
456 "welcome.signupButton": "Załóż darmowe konto", 447 "welcome.signupButton": "Załóż darmowe konto",
457 "workspaceDrawer.addNewWorkspaceLabel": "Dodaj nowy obszar roboczy", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Wszystkie usługi", 449 "workspaceDrawer.allServices": "Wszystkie usługi",
459 "workspaceDrawer.headline": "Obszary robocze", 450 "workspaceDrawer.headline": "Obszary robocze",
460 "workspaceDrawer.item.contextMenuEdit": "Edycja", 451 "workspaceDrawer.item.contextMenuEdit": "Edycja",
461 "workspaceDrawer.item.noServicesAddedYet": "Żadne usługi nie zostały jeszcze dodane", 452 "workspaceDrawer.item.noServicesAddedYet": "Żadne usługi nie zostały jeszcze dodane",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Obszary robocze programu Ferdi pozawala Ci na skupieniu się na tym co ważne w danym momencie. Ustaw różne zestawy usług i przełączaj się między nimi w łatwiejszy sposób w dowolnym momencie. </p><p>Decyduj, które usługi potrzebujesz , więc pomagamy Ci pozostawać na szczycie gry - lub łatwiej wyłączyć się z pracy kiedy tego potrzebujesz.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Edytuj ustawienia obszaru roboczego", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Przełącz do" 455 "workspaces.switchingIndicator.switchingTo": "Przełącz do"
465} 456}
diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json
index 7760834a4..1d068e87e 100644
--- a/src/i18n/locales/pt-BR.json
+++ b/src/i18n/locales/pt-BR.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Recarregar", 2 "app.errorHandler.action": "Recarregar",
3 "app.errorHandler.headline": "Algo deu errado", 3 "app.errorHandler.headline": "Algo deu errado.",
4 "changeserver.customServerLabel": "Servidor personalizado", 4 "changeserver.customServerLabel": "Servidor personalizado",
5 "changeserver.headline": "Alterar servidor", 5 "changeserver.headline": "Alterar servidor",
6 "changeserver.label": "Servidor", 6 "changeserver.label": "Servidor",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "O que aconteceu?", 10 "connectionLostBanner.informationLink": "O que aconteceu?",
11 "connectionLostBanner.message": "Ah não! Ferdi perdeu a conexão com {name}.", 11 "connectionLostBanner.message": "Ah não! Ferdi perdeu a conexão com {name}.",
12 "feature.basicAuth.signIn": "Acessar", 12 "feature.basicAuth.signIn": "Acessar",
13 "feature.debugger.title": "Publicar informações de depuração",
14 "feature.nightlyBuilds.activate": "Ativar", 13 "feature.nightlyBuilds.activate": "Ativar",
15 "feature.nightlyBuilds.info": "Versões noturnas são versões do Ferdi altamente experimentais que podem conter funcionalidades não finalizadas ou não concluídas. Essas compilações noturnas são usadas principalmente por desenvolvedores para testar seus recursos recém-desenvolvidos e como eles irão se comportar na versão final. Se você não sabe o que está fazendo, sugerimos não ativar versões noturnas.", 14 "feature.nightlyBuilds.info": "Versões noturnas são versões do Ferdi altamente experimentais que podem conter funcionalidades não finalizadas ou não concluídas. Essas compilações noturnas são usadas principalmente por desenvolvedores para testar seus recursos recém-desenvolvidos e como eles irão se comportar na versão final. Se você não sabe o que está fazendo, sugerimos não ativar versões noturnas.",
16 "feature.nightlyBuilds.title": "Versões noturnas", 15 "feature.nightlyBuilds.title": "Versões noturnas",
@@ -24,7 +23,7 @@
24 "feature.quickSwitch.info": "Selecione um serviço com TAB, ↑ e ↓. Abra um serviço com ENTER.", 23 "feature.quickSwitch.info": "Selecione um serviço com TAB, ↑ e ↓. Abra um serviço com ENTER.",
25 "feature.quickSwitch.search": "Localizar...", 24 "feature.quickSwitch.search": "Localizar...",
26 "feature.quickSwitch.title": "Troca Rápida", 25 "feature.quickSwitch.title": "Troca Rápida",
27 "global.api.unhealthy": "Não foi possível estabelecer ligação aos serviços do Ferdi", 26 "global.api.unhealthy": "Não foi possível conectar ao serviço FreeCite",
28 "global.cancel": "Cancelar", 27 "global.cancel": "Cancelar",
29 "global.edit": "Editar", 28 "global.edit": "Editar",
30 "global.no": "Não", 29 "global.no": "Não",
@@ -45,7 +44,7 @@
45 "import.headline": "Importar os seus serviços do Ferdi 4", 44 "import.headline": "Importar os seus serviços do Ferdi 4",
46 "import.notSupportedHeadline": "Estes serviços ainda não são suportados pelo Ferdi 5", 45 "import.notSupportedHeadline": "Estes serviços ainda não são suportados pelo Ferdi 5",
47 "import.skip.label": "Eu quero adicionar serviços manualmente", 46 "import.skip.label": "Eu quero adicionar serviços manualmente",
48 "import.submit.label": "Importar serviços", 47 "import.submit.label": "Importar {count} serviços",
49 "infobar.authRequestFailed": "Ocorreram erros ao tentar autenticar. Por favor, tente desconectar e autenticar novamente se o erro persistir.", 48 "infobar.authRequestFailed": "Ocorreram erros ao tentar autenticar. Por favor, tente desconectar e autenticar novamente se o erro persistir.",
50 "infobar.buttonChangelog": "O que há de novo?", 49 "infobar.buttonChangelog": "O que há de novo?",
51 "infobar.buttonInstallUpdate": "Reiniciar e instalar atualizações", 50 "infobar.buttonInstallUpdate": "Reiniciar e instalar atualizações",
@@ -75,7 +74,7 @@
75 "login.email.label": "Endereço de e-mail", 74 "login.email.label": "Endereço de e-mail",
76 "login.headline": "Iniciar Sessão", 75 "login.headline": "Iniciar Sessão",
77 "login.invalidCredentials": "O email ou a palavra-passe incorretos", 76 "login.invalidCredentials": "O email ou a palavra-passe incorretos",
78 "login.link.password": "Repor a minha palavra-passe", 77 "login.link.password": "Redefinir senha",
79 "login.link.signup": "Criar uma conta gratuita", 78 "login.link.signup": "Criar uma conta gratuita",
80 "login.password.label": "Senha", 79 "login.password.label": "Senha",
81 "login.serverLogout": "A sua sessão expirou, inicie sessão novamente.", 80 "login.serverLogout": "A sua sessão expirou, inicie sessão novamente.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Termos do Serviço", 117 "menu.help.tos": "Termos do Serviço",
119 "menu.services": "Serviços", 118 "menu.services": "Serviços",
120 "menu.services.activatePreviousService": "Ativar o serviço anterior", 119 "menu.services.activatePreviousService": "Ativar o serviço anterior",
121 "menu.services.addNewService": "Adicionar Novo Serviço", 120 "menu.services.addNewService": "Adicionar Novo Serviço...",
122 "menu.services.goHome": "Início", 121 "menu.services.goHome": "Início",
123 "menu.services.setNextServiceActive": "Ativar o próximo serviço", 122 "menu.services.setNextServiceActive": "Ativar o próximo serviço",
124 "menu.todos": "Tarefas", 123 "menu.todos": "Tarefas",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Todos os serviços", 147 "menu.workspaces.defaultWorkspace": "Todos os serviços",
149 "menu.workspaces.openWorkspaceDrawer": "Abrir a janela da Ãrea de trabalho", 148 "menu.workspaces.openWorkspaceDrawer": "Abrir a janela da Ãrea de trabalho",
150 "password.email.label": "Endereço de e-mail", 149 "password.email.label": "Endereço de e-mail",
151 "password.headline": "Repor a minha palavra-passe", 150 "password.headline": "Redefinir senha",
152 "password.link.login": "Iniciar sessão", 151 "password.link.login": "Iniciar sessão",
153 "password.link.signup": "Criar uma conta gratuita", 152 "password.link.signup": "Criar uma conta gratuita",
154 "password.noUser": "Não existe nenhuma conta associada a esse endereço de e-mail", 153 "password.noUser": "Não existe nenhuma conta associada a esse endereço de e-mail",
155 "password.successInfo": "Por favor, verifique seu e-mail", 154 "password.successInfo": "Uma nova senha foi enviada a seu endereço de e-mail",
156 "pricing.features.accountSync": "Sincronização da conta",
157 "pricing.features.customWebsites": "Adicionar Websites Personalizados",
158 "pricing.features.desktopNotifications": "Notificações no ambiente de trabalho",
159 "pricing.features.onPremise": "On-Premise & Outros serviços hospedados",
160 "pricing.features.recipes": "Escolha entre mais de 70 serviços",
161 "pricing.features.serviceProxies": "Serviços de proxy",
162 "pricing.features.spellchecker": "Suporte ao corretor ortográfico",
163 "pricing.features.teamManagement": "Gestão de Equipes",
164 "pricing.features.thirdPartyServices": "Instalar serviços de terceiros",
165 "pricing.features.unlimitedServices": "Instalar serviços ilimitados",
166 "pricing.features.workspaces": "Ãreas de trabalho",
167 "service.crashHandler.action": "Recarregar {name}", 155 "service.crashHandler.action": "Recarregar {name}",
168 "service.crashHandler.autoReload": "A tentar restaurar automaticamente {name} em {seconds} segundos", 156 "service.crashHandler.autoReload": "A tentar restaurar automaticamente {name} em {seconds} segundos",
169 "service.crashHandler.headline": "Oh não!", 157 "service.crashHandler.headline": "Oh não!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Tentar novamente", 186 "settings.account.tryReloadServices": "Tentar novamente",
199 "settings.account.tryReloadUserInfoRequest": "Tentar novamente", 187 "settings.account.tryReloadUserInfoRequest": "Tentar novamente",
200 "settings.account.userInfoRequestFailed": "Não é possível carregar a informação do utilizador", 188 "settings.account.userInfoRequestFailed": "Não é possível carregar a informação do utilizador",
201 "settings.account.yourLicense": "Sua lincença Ferdi", 189 "settings.account.yourLicense": "Sua lincença Ferdi:",
202 "settings.app.accentColorInfo": "Informe sua cor de destaque em um formato compatível com CSS. (Padrão: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Informe sua cor de destaque em um formato compatível com CSS. (Padrão: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Limpar cache", 191 "settings.app.buttonClearAllCache": "Limpar cache",
204 "settings.app.buttonInstallUpdate": "Reiniciar e instalar atualizações", 192 "settings.app.buttonInstallUpdate": "Reiniciar e instalar atualizações",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Fechar o Ferdi para a barra do sistema", 208 "settings.app.form.closeToSystemTray": "Fechar o Ferdi para a barra do sistema",
221 "settings.app.form.confirmOnQuit": "Exigir confirmação ao sair do Ferdi", 209 "settings.app.form.confirmOnQuit": "Exigir confirmação ao sair do Ferdi",
222 "settings.app.form.customTodoServer": "Servidor de Tarefas Personalizado", 210 "settings.app.form.customTodoServer": "Servidor de Tarefas Personalizado",
223 "settings.app.form.darkMode": "Habilitar modo noturno", 211 "settings.app.form.darkMode": "Ativar o Tema Escuro",
224 "settings.app.form.enableGPUAcceleration": "Ativar Aceleração de GPU", 212 "settings.app.form.enableGPUAcceleration": "Ativar Aceleração de GPU",
225 "settings.app.form.enableLock": "Habilitar bloqueio por senha", 213 "settings.app.form.enableLock": "Habilitar bloqueio por senha",
226 "settings.app.form.enableMenuBar": "Sempre exibir Ferdi na Barra de Menu", 214 "settings.app.form.enableMenuBar": "Sempre exibir Ferdi na Barra de Menu",
227 "settings.app.form.enableSpellchecking": "Ativar verificação ortográfica", 215 "settings.app.form.enableSpellchecking": "Ativar verificação ortográfica",
228 "settings.app.form.enableSystemTray": "Mostrar o Ferdi na barra do sistema", 216 "settings.app.form.enableSystemTray": "Sempre mostrar o ícone na Bandeja de Sistema",
229 "settings.app.form.enableTodos": "Ativar Tarefas", 217 "settings.app.form.enableTodos": "Ativar Tarefas",
230 "settings.app.form.hibernateOnStartup": "Manter os serviços em hibernação ao inicializar", 218 "settings.app.form.hibernateOnStartup": "Manter os serviços em hibernação ao inicializar",
231 "settings.app.form.hibernationStrategy": "Estratégia de Hibernação", 219 "settings.app.form.hibernationStrategy": "Estratégia de Hibernação",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Apresentar separadores de serviços desativados", 239 "settings.app.form.showDisabledServices": "Apresentar separadores de serviços desativados",
252 "settings.app.form.showDragArea": "Mostrar área arrastável na janela", 240 "settings.app.form.showDragArea": "Mostrar área arrastável na janela",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Apresentar emblema com o número de mensagens não lidas quando as notificações estão desativadas", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Apresentar emblema com o número de mensagens não lidas quando as notificações estão desativadas",
242 "settings.app.form.splitMode": "Ativar modo de visualização dividida",
254 "settings.app.form.startMinimized": "Iniciar minimizado", 243 "settings.app.form.startMinimized": "Iniciar minimizado",
255 "settings.app.form.universalDarkMode": "Habilitar modo noturno universal", 244 "settings.app.form.universalDarkMode": "Habilitar modo noturno universal",
256 "settings.app.form.useTouchIdToUnlock": "Permitir usar TouchID para desbloquear Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Permitir usar TouchID para desbloquear Ferdi",
@@ -265,9 +254,9 @@
265 "settings.app.hibernateInfo": "Por padrão, Ferdi manterá todos seus serviços abertos e carregados, assim eles estarão disponíveis quando você for usá-los. O Serviço de Hibernação irá finalizar seus serviços após um período específico. Isso é útil para evitar consumo excessivo de memória RAM evitando também que seu computador fique lento.", 254 "settings.app.hibernateInfo": "Por padrão, Ferdi manterá todos seus serviços abertos e carregados, assim eles estarão disponíveis quando você for usá-los. O Serviço de Hibernação irá finalizar seus serviços após um período específico. Isso é útil para evitar consumo excessivo de memória RAM evitando também que seu computador fique lento.",
266 "settings.app.inactivityLockInfo": "Minutos de inatividade, após este tempo Ferdi irá automaticamente bloquear. Utilize 0 para desabilitar", 255 "settings.app.inactivityLockInfo": "Minutos de inatividade, após este tempo Ferdi irá automaticamente bloquear. Utilize 0 para desabilitar",
267 "settings.app.languageDisclaimer": "As traduções oficiais são em inglês e alemão. As demais traduções são baseadas na ajuda da comunidade.", 256 "settings.app.languageDisclaimer": "As traduções oficiais são em inglês e alemão. As demais traduções são baseadas na ajuda da comunidade.",
268 "settings.app.lockInfo": "O bloqueio por senha permite a você proteger suas mensagens.\nUsando o bloqueio por senha, será necessário informar sua senha toda vez que o Ferdi for iniciado ou você solicite o bloqueio.", 257 "settings.app.lockInfo": "O bloqueio por senha permite a você proteger suas mensagens.\nUsando o bloqueio por senha, será necessário informar sua senha toda vez que o Ferdi for iniciado ou você solicite o bloqueio {lockShortcut}.",
269 "settings.app.lockedPassword": "Senha", 258 "settings.app.lockedPassword": "Senha",
270 "settings.app.lockedPasswordInfo": "Tenha certeza que a senha definida será lembrada.\nCaso você esqueça a senha, será necessário reinstalar o Ferdi.", 259 "settings.app.lockedPasswordInfo": "Por favor certifique-se de definir uma senha que você se lembrará.\nSe você perder esta senha, você terá que reinstalar o Ferdi.",
271 "settings.app.restartRequired": "Essa alteração requer uma reinicialização", 260 "settings.app.restartRequired": "Essa alteração requer uma reinicialização",
272 "settings.app.scheduledDNDInfo": "O modo Não perturbe agendado permite definir um período de tempo em que você não deseja receber notificações do Ferdi.", 261 "settings.app.scheduledDNDInfo": "O modo Não perturbe agendado permite definir um período de tempo em que você não deseja receber notificações do Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Horários no formato de 24 horas. O horário de término pode ser anterior ao horário de início (por exemplo, início às 17:00 e término às 09:00) para ativar a opção Não perturbe da noite para o dia.", 262 "settings.app.scheduledDNDTimeInfo": "Horários no formato de 24 horas. O horário de término pode ser anterior ao horário de início (por exemplo, início às 17:00 e término às 09:00) para ativar a opção Não perturbe da noite para o dia.",
@@ -294,12 +283,12 @@
294 "settings.recipes.customService.headline.communityRecipes": "Serviços da comunidade", 283 "settings.recipes.customService.headline.communityRecipes": "Serviços da comunidade",
295 "settings.recipes.customService.headline.customRecipes": "Serviços personalizados", 284 "settings.recipes.customService.headline.customRecipes": "Serviços personalizados",
296 "settings.recipes.customService.headline.devRecipes": "Serviços em Desenvolvimento", 285 "settings.recipes.customService.headline.devRecipes": "Serviços em Desenvolvimento",
297 "settings.recipes.customService.intro": "Para adicionar um serviço personalizado, copie o serviço para:", 286 "settings.recipes.customService.intro": "Para adicionar um serviço personalizado, copie os dados do serviço para:",
298 "settings.recipes.customService.openDevDocs": "Documentação do Desenvolvedor", 287 "settings.recipes.customService.openDevDocs": "Documentação do Desenvolvedor",
299 "settings.recipes.customService.openFolder": "Abrir pasta", 288 "settings.recipes.customService.openFolder": "Abrir pasta",
300 "settings.recipes.headline": "Serviços disponíveis", 289 "settings.recipes.headline": "Serviços disponíveis",
301 "settings.recipes.missingService": "Falta um serviço?", 290 "settings.recipes.missingService": "Falta um serviço?",
302 "settings.recipes.nothingFound": "Desculpe, nenhum serviço corresponde ao seu termo de pesquisa - mas você provavelmente pode adicioná-lo usando a opção \"Site personalizado\". Por favor, note que o site pode mostrar mais serviços que foram adicionados ao Ferdi desde a versão em que você está atualmente. Para obter esses novos serviços, por favor, considere atualizar para uma versão mais recente da Ferdi.", 291 "settings.recipes.nothingFound": "Desculpe, mas nenhum serviço corresponde ao seu termo de pesquisa - mas você provavelmente pode adicioná-lo usando a opção \"Site personalizado\". Por favor, note que o site pode mostrar mais serviços que foram adicionados ao Ferdi desde a versão em que você está atualmente. Para obter esses novos serviços, por favor, considere atualizar para uma versão mais recente do Ferdi.",
303 "settings.recipes.servicesSuccessfulAddedInfo": "Serviço adicionado com sucesso", 292 "settings.recipes.servicesSuccessfulAddedInfo": "Serviço adicionado com sucesso",
304 "settings.searchService": "Pesquisar serviço", 293 "settings.searchService": "Pesquisar serviço",
305 "settings.service.error.goBack": "Voltar aos serviços", 294 "settings.service.error.goBack": "Voltar aos serviços",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Brilho do Dark Reader", 301 "settings.service.form.darkReaderBrightness": "Brilho do Dark Reader",
313 "settings.service.form.darkReaderContrast": "Contraste do Dark Reader", 302 "settings.service.form.darkReaderContrast": "Contraste do Dark Reader",
314 "settings.service.form.darkReaderSepia": "Sépia do Dark Reader", 303 "settings.service.form.darkReaderSepia": "Sépia do Dark Reader",
315 "settings.service.form.deleteButton": "Apagar serviço", 304 "settings.service.form.deleteButton": "Deletar serviço",
316 "settings.service.form.editServiceHeadline": "Editar {name}", 305 "settings.service.form.editServiceHeadline": "Editar {name}",
317 "settings.service.form.enableAudio": "Ativar áudio", 306 "settings.service.form.enableAudio": "Ativar áudio",
318 "settings.service.form.enableBadge": "Mostrar emblemas de mensagens não lidas", 307 "settings.service.form.enableBadge": "Mostrar emblemas de mensagens não lidas",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Quando ativado, o serviço será encerrado após um período de tempo para poupar recursos do sistema.", 321 "settings.service.form.isHibernatedEnabledInfo": "Quando ativado, o serviço será encerrado após um período de tempo para poupar recursos do sistema.",
333 "settings.service.form.isMutedInfo": "Quando desativado, todos os sons e reproduções de áudio serão silenciados", 322 "settings.service.form.isMutedInfo": "Quando desativado, todos os sons e reproduções de áudio serão silenciados",
334 "settings.service.form.name": "Nome", 323 "settings.service.form.name": "Nome",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Mostrar apenas os Favoritos na contagem de não lidos",
335 "settings.service.form.openDarkmodeCss": "Abrir darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Abrir darkmode.css",
336 "settings.service.form.openUserCss": "Abrir user.css", 326 "settings.service.form.openUserCss": "Abrir user.css",
337 "settings.service.form.openUserJs": "Abrir user.js", 327 "settings.service.form.openUserJs": "Abrir user.js",
338 "settings.service.form.proxy.headline": "Definições HTTP/HTTPS Proxy", 328 "settings.service.form.proxy.headline": "Definições HTTP/HTTPS Proxy",
339 "settings.service.form.proxy.host": "Host/IP proxy", 329 "settings.service.form.proxy.host": "Host/IP proxy",
340 "settings.service.form.proxy.info": "As definições do proxy não serão guardadas nos servidores do Ferdi.", 330 "settings.service.form.proxy.info": "Os ajustes de proxy não serão sincronizados com os servidores do Ferdi.",
341 "settings.service.form.proxy.isEnabled": "Usar Proxy", 331 "settings.service.form.proxy.isEnabled": "Usar Proxy",
342 "settings.service.form.proxy.password": "Palavra-chave (opcional)", 332 "settings.service.form.proxy.password": "Senha (opcional)",
343 "settings.service.form.proxy.port": "Porta", 333 "settings.service.form.proxy.port": "Porta",
344 "settings.service.form.proxy.restartInfo": "Reinicie, por favor, após atualizar as definições do Ferdi", 334 "settings.service.form.proxy.restartInfo": "Reinicie, por favor, após atualizar as definições do Ferdi",
345 "settings.service.form.proxy.user": "Utilizador (opcional)", 335 "settings.service.form.proxy.user": "Usuário (opcional)",
346 "settings.service.form.recipeFileInfo": "Seus arquivos de usuário serão inseridos na página web para que você possa personalizar os serviços da forma que preferir. Os arquivos de usuário são armazenados localmente e não são transferidos para outros computadores utilizando a mesma conta.", 336 "settings.service.form.recipeFileInfo": "Seus arquivos de usuário serão inseridos na página web para que você possa personalizar os serviços da forma que preferir. Os arquivos de usuário são armazenados localmente e não são transferidos para outros computadores utilizando a mesma conta.",
347 "settings.service.form.saveButton": "Salvar serviço", 337 "settings.service.form.saveButton": "Salvar serviço",
348 "settings.service.form.tabHosted": "Com domínio", 338 "settings.service.form.tabHosted": "Com domínio",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Descobrir serviços", 344 "settings.services.discoverServices": "Descobrir serviços",
355 "settings.services.headline": "Seus serviços", 345 "settings.services.headline": "Seus serviços",
356 "settings.services.noServicesAdded": "Comece adicionando um serviço.", 346 "settings.services.noServicesAdded": "Comece adicionando um serviço.",
347 "settings.services.nothingFound": "Desculpe, mas nenhum serviço corresponde ao seu termo de pesquisa - mas você provavelmente pode adicioná-lo usando a opção \"Site personalizado\". Por favor, note que o site pode mostrar mais serviços que foram adicionados ao Ferdi desde a versão em que você está atualmente. Para obter esses novos serviços, por favor, considere atualizar para uma versão mais recente do Ferdi.",
357 "settings.services.servicesRequestFailed": "Não foi possível ler os seus serviços", 348 "settings.services.servicesRequestFailed": "Não foi possível ler os seus serviços",
358 "settings.services.tooltip.isDisabled": "O serviço está desativado", 349 "settings.services.tooltip.isDisabled": "O serviço está desativado",
359 "settings.services.tooltip.isMuted": "Todos os sons estão silenciados", 350 "settings.services.tooltip.isMuted": "Todos os sons estão silenciados",
@@ -377,7 +368,7 @@
377 "settings.team.contentHeadline": "Gerenciamento de Equipe Franz", 368 "settings.team.contentHeadline": "Gerenciamento de Equipe Franz",
378 "settings.team.copy": "O Gerenciamento de Equipes de Franz permite gerenciar assinaturas do Franz para múltiplos usuários. Por favor, entenda que ter uma assinatura Franz Premium não lhe dará nenhuma vantagem em usar o Ferdi. A única razão em manter o acesso ao Gerenciamento de Equipes é permitir o gerenciamento de suas equipes legadas e não perder nenhuma funcionalidade no gerenciamento da sua conta.", 369 "settings.team.copy": "O Gerenciamento de Equipes de Franz permite gerenciar assinaturas do Franz para múltiplos usuários. Por favor, entenda que ter uma assinatura Franz Premium não lhe dará nenhuma vantagem em usar o Ferdi. A única razão em manter o acesso ao Gerenciamento de Equipes é permitir o gerenciamento de suas equipes legadas e não perder nenhuma funcionalidade no gerenciamento da sua conta.",
379 "settings.team.headline": "Equipa", 370 "settings.team.headline": "Equipa",
380 "settings.team.intro": "Você está atualmente usando os Servidores de Franz, por isso tem acesso ao Gerenciamento de Times.", 371 "settings.team.intro": "Você está atualmente usando os Servidores do Franz, por isso tem acesso ao Gerenciamento de Times.",
381 "settings.team.manageAction": "Gerencie sua Equipe em meetfranz.com", 372 "settings.team.manageAction": "Gerencie sua Equipe em meetfranz.com",
382 "settings.team.teamsUnavailable": "A funcionalidade de Equipes está indisponível", 373 "settings.team.teamsUnavailable": "A funcionalidade de Equipes está indisponível",
383 "settings.team.teamsUnavailableInfo": "Atualmente a funcionalidade de Equipes está disponível apenas utilizando o servidor Franz após adquirir um plano Franz Profissional. Por favor altere o seridor par https://api.franzinfra.com para utilizar esta funcionalidade.", 374 "settings.team.teamsUnavailableInfo": "Atualmente a funcionalidade de Equipes está disponível apenas utilizando o servidor Franz após adquirir um plano Franz Profissional. Por favor altere o seridor par https://api.franzinfra.com para utilizar esta funcionalidade.",
@@ -388,7 +379,7 @@
388 "settings.user.form.currentPassword": "Palavra-passe atual", 379 "settings.user.form.currentPassword": "Palavra-passe atual",
389 "settings.user.form.email": "E-mail", 380 "settings.user.form.email": "E-mail",
390 "settings.user.form.firstname": "Primeiro Nome", 381 "settings.user.form.firstname": "Primeiro Nome",
391 "settings.user.form.lastname": "Último Nome", 382 "settings.user.form.lastname": "Sobrenome",
392 "settings.user.form.newPassword": "Nova palavra-passe", 383 "settings.user.form.newPassword": "Nova palavra-passe",
393 "settings.workspace.add.form.name": "Nome", 384 "settings.workspace.add.form.name": "Nome",
394 "settings.workspace.add.form.submitButton": "Nova Ãrea de Trabalho", 385 "settings.workspace.add.form.submitButton": "Nova Ãrea de Trabalho",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Tentar novamente", 396 "settings.workspaces.tryReloadWorkspaces": "Tentar novamente",
406 "settings.workspaces.updatedInfo": "As suas alterações foram efetuadas com sucesso", 397 "settings.workspaces.updatedInfo": "As suas alterações foram efetuadas com sucesso",
407 "settings.workspaces.workspaceFeatureHeadline": "Menos é Mais: Introduzindo as Ãreas de trabalho Ferdi", 398 "settings.workspaces.workspaceFeatureHeadline": "Menos é Mais: Introduzindo as Ãreas de trabalho Ferdi",
408 "settings.workspaces.workspaceFeatureInfo": "As áreas de trabalho do Ferdi permite você focar no que realmente é importante agora. Configure diferentes conjuntos de serviços e alterne entre eles facilmente em qualquer momento. Você decide quais serviços você precisa e onde deseja colocá-los, então nós podemos te ajudar a aumentar a produtividade de suas tarefas. Ou facilmente deletar os aplicativos que você nunca irá precisar.", 399 "settings.workspaces.workspaceFeatureInfo": "Os espaços de trabalho do Ferdi te ajudam a focar no que realmente é importante agora. Configure diferente conjuntos de serviços e mude entre eles facilmente em qualquer momento. Você decide quais serviços precisa e onde deseja posicioná-los, e então nós podemos te ajudar a aumentar a sua produtividade - ou facilmente desconectá-lo do trabalho quando você quiser.",
409 "settings.workspaces.workspacesRequestFailed": "Não foi possível carregar suas áreas de trabalho", 400 "settings.workspaces.workspacesRequestFailed": "Não foi possível carregar suas áreas de trabalho",
410 "setupAssistant.headline": "Vamos começar", 401 "setupAssistant.headline": "Vamos começar",
411 "setupAssistant.subheadline": "Escolha entre os serviços mais usados e volte a ter o controle das suas mensagens agora.", 402 "setupAssistant.subheadline": "Escolha entre os serviços mais usados e volte a ter o controle das suas mensagens agora.",
@@ -422,7 +413,7 @@
422 "signup.emailDuplicate": "Já existe uma conta associada a este endereço de email", 413 "signup.emailDuplicate": "Já existe uma conta associada a este endereço de email",
423 "signup.firstname.label": "Primeiro Nome", 414 "signup.firstname.label": "Primeiro Nome",
424 "signup.headline": "Criar conta", 415 "signup.headline": "Criar conta",
425 "signup.lastname.label": "Último Nome", 416 "signup.lastname.label": "Sobrenome",
426 "signup.legal.info": "Ao criar uma conta Ferdi, aceita", 417 "signup.legal.info": "Ao criar uma conta Ferdi, aceita",
427 "signup.legal.privacy": "Declaração de privacidade", 418 "signup.legal.privacy": "Declaração de privacidade",
428 "signup.legal.terms": "Termos do Serviço", 419 "signup.legal.terms": "Termos do Serviço",
@@ -430,7 +421,7 @@
430 "signup.password.label": "Senha", 421 "signup.password.label": "Senha",
431 "signup.submit.label": "Criar uma conta", 422 "signup.submit.label": "Criar uma conta",
432 "tabs.item.confirmDeleteService": "Tem certeza de que deseja excluir o serviço {serviceName}?", 423 "tabs.item.confirmDeleteService": "Tem certeza de que deseja excluir o serviço {serviceName}?",
433 "tabs.item.deleteService": "Apagar serviço", 424 "tabs.item.deleteService": "Deletar serviço",
434 "tabs.item.disableAudio": "Desativar áudio", 425 "tabs.item.disableAudio": "Desativar áudio",
435 "tabs.item.disableDarkMode": "Desativar o modo escuro", 426 "tabs.item.disableDarkMode": "Desativar o modo escuro",
436 "tabs.item.disableNotifications": "Desativar notificações", 427 "tabs.item.disableNotifications": "Desativar notificações",
@@ -446,7 +437,7 @@
446 "validation.minLength": "{field} deveria ter pelo menos {length} caracteres", 437 "validation.minLength": "{field} deveria ter pelo menos {length} caracteres",
447 "validation.oneRequired": "É necessário pelo menos um", 438 "validation.oneRequired": "É necessário pelo menos um",
448 "validation.required": "{field} é obrigatório", 439 "validation.required": "{field} é obrigatório",
449 "validation.url": "{field} não é uma hiperligação válida", 440 "validation.url": "{field} não é uma URL válida",
450 "webControls.back": "Anterior", 441 "webControls.back": "Anterior",
451 "webControls.forward": "Próximo", 442 "webControls.forward": "Próximo",
452 "webControls.goHome": "Início", 443 "webControls.goHome": "Início",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Recarregar", 445 "webControls.reload": "Recarregar",
455 "welcome.loginButton": "Iniciar sessão", 446 "welcome.loginButton": "Iniciar sessão",
456 "welcome.signupButton": "Criar uma conta gratuita", 447 "welcome.signupButton": "Criar uma conta gratuita",
457 "workspaceDrawer.addNewWorkspaceLabel": "Adicionar uma nova área de trabalho", 448 "workspaceDrawer.addNewWorkspaceLabel": "Adicionar novo espaço de trabalho",
458 "workspaceDrawer.allServices": "Todos os serviços", 449 "workspaceDrawer.allServices": "Todos os serviços",
459 "workspaceDrawer.headline": "Ãreas de trabalho", 450 "workspaceDrawer.headline": "Ãreas de trabalho",
460 "workspaceDrawer.item.contextMenuEdit": "editar", 451 "workspaceDrawer.item.contextMenuEdit": "editar",
461 "workspaceDrawer.item.noServicesAddedYet": "Nenhum serviço foi adicionado", 452 "workspaceDrawer.item.noServicesAddedYet": "Nenhum serviço foi adicionado",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>As áreas de trabalho do Ferdi te ajuda a focar no que realmente é importante agora. Configure diferente cenários para serviços e mude entre eles facilmente em qualquer momento. </p><p>Você decide quais serviços precisa e onde deseja posicioná-los, e então nós iremos te ajudar em aumentar a sua produtividade. Você pode desligar os serviços que não são úteis para você.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Os espaços de trabalho do Ferdi te ajuda a focar no que realmente é importante agora. Configure diferente conjuntos de serviços e mude entre eles facilmente em qualquer momento.</p><p>Você decide quais serviços precisa e onde deseja posicioná-los, e então nós podemos te ajudar a aumentar a sua produtividade - ou facilmente desconectá-lo do trabalho quando você quiser.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Editar configurações das áreas de trabalho", 454 "workspaceDrawer.workspacesSettingsTooltip": "Editar configurações dos espaços de trabalho",
464 "workspaces.switchingIndicator.switchingTo": "Trocando para" 455 "workspaces.switchingIndicator.switchingTo": "Trocando para"
465} 456}
diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json
index da431f4e3..9675d5d77 100644
--- a/src/i18n/locales/pt.json
+++ b/src/i18n/locales/pt.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Atualizar", 2 "app.errorHandler.action": "Atualizar",
3 "app.errorHandler.headline": "Alguma coisa correu mal", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Servidor personalizado", 4 "changeserver.customServerLabel": "Servidor personalizado",
5 "changeserver.headline": "Alterar servidor", 5 "changeserver.headline": "Alterar servidor",
6 "changeserver.label": "Servidor", 6 "changeserver.label": "Servidor",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "O que aconteceu?", 10 "connectionLostBanner.informationLink": "O que aconteceu?",
11 "connectionLostBanner.message": "Oh não! O Ferdi perdeu a ligação com {name}.", 11 "connectionLostBanner.message": "Oh não! O Ferdi perdeu a ligação com {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publicar informações de depuração",
14 "feature.nightlyBuilds.activate": "Activar", 13 "feature.nightlyBuilds.activate": "Activar",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Seleccione um serviço com TAB, ↑ e ↓. Abra um serviço com ENTER.", 23 "feature.quickSwitch.info": "Seleccione um serviço com TAB, ↑ e ↓. Abra um serviço com ENTER.",
25 "feature.quickSwitch.search": "A procurar...", 24 "feature.quickSwitch.search": "A procurar...",
26 "feature.quickSwitch.title": "Troca Rápida", 25 "feature.quickSwitch.title": "Troca Rápida",
27 "global.api.unhealthy": "Não é possível ligar aos serviços online de Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Cancelar", 27 "global.cancel": "Cancel",
29 "global.edit": "Editar", 28 "global.edit": "Editar",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Não está ligado à internet.", 30 "global.notConnectedToTheInternet": "Não está ligado à internet.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Configurações", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use o padrão de sistema ({default})", 36 "global.spellchecker.useDefault": "Use o padrão de sistema ({default})",
38 "global.spellchecking.autodetect": "Detectar idioma automaticamente", 37 "global.spellchecking.autodetect": "Detectar idioma automaticamente",
39 "global.spellchecking.autodetect.short": "Automático", 38 "global.spellchecking.autodetect.short": "Automático",
40 "global.spellchecking.language": "Idioma para corrector ortográfico", 39 "global.spellchecking.language": "Idioma para corrector ortográfico",
41 "global.submit": "Enviar", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importe os seus serviços do Ferdi 4", 44 "import.headline": "Importe os seus serviços do Ferdi 4",
46 "import.notSupportedHeadline": "Serviços ainda não são suportados por Ferdi 5", 45 "import.notSupportedHeadline": "Serviços ainda não são suportados por Ferdi 5",
47 "import.skip.label": "Quero adicionar serviços manualmente", 46 "import.skip.label": "Quero adicionar serviços manualmente",
48 "import.submit.label": "Importar serviços", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Houve erros na autenticaçao. Se este erro persistir, por favor, tente desligar e autenticar novamente.", 48 "infobar.authRequestFailed": "Houve erros na autenticaçao. Se este erro persistir, por favor, tente desligar e autenticar novamente.",
50 "infobar.buttonChangelog": "O que há de novo?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Reiniciar e instalar atualizações", 50 "infobar.buttonInstallUpdate": "Reiniciar e instalar atualizações",
52 "infobar.buttonReloadServices": "Reiniciar serviços", 51 "infobar.buttonReloadServices": "Reiniciar serviços",
53 "infobar.hide": "Ocultar", 52 "infobar.hide": "Ocultar",
@@ -75,7 +74,7 @@
75 "login.email.label": "Endereço de E-mail", 74 "login.email.label": "Endereço de E-mail",
76 "login.headline": "Entrar", 75 "login.headline": "Entrar",
77 "login.invalidCredentials": "E-mail ou palavra-passe inválidos", 76 "login.invalidCredentials": "E-mail ou palavra-passe inválidos",
78 "login.link.password": "Redefinir palavra-passe", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Criar uma conta gratuita", 78 "login.link.signup": "Criar uma conta gratuita",
80 "login.password.label": "Palavra-passe", 79 "login.password.label": "Palavra-passe",
81 "login.serverLogout": "A sua sessão expirou, faça login novamente.", 80 "login.serverLogout": "A sua sessão expirou, faça login novamente.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Suporte", 116 "menu.help.support": "Suporte",
118 "menu.help.tos": "Termos de Serviço", 117 "menu.help.tos": "Termos de Serviço",
119 "menu.services": "Serviços", 118 "menu.services": "Serviços",
120 "menu.services.activatePreviousService": "Ativar serviço anterior", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Início", 121 "menu.services.goHome": "Início",
123 "menu.services.setNextServiceActive": "Ativar próximo serviço", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Tarefas", 123 "menu.todos": "Tarefas",
125 "menu.todos.enableTodos": "Ativar Tarefas", 124 "menu.todos.enableTodos": "Ativar Tarefas",
126 "menu.view": "Visualizar", 125 "menu.view": "Visualizar",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Todos os serviços", 147 "menu.workspaces.defaultWorkspace": "Todos os serviços",
149 "menu.workspaces.openWorkspaceDrawer": "Abrir a barra lateral da área de trabalho", 148 "menu.workspaces.openWorkspaceDrawer": "Abrir a barra lateral da área de trabalho",
150 "password.email.label": "Endereço de E-mail", 149 "password.email.label": "Endereço de E-mail",
151 "password.headline": "Redefinir palavra-passe", 150 "password.headline": "Reset password",
152 "password.link.login": "Entrar na sua conta", 151 "password.link.login": "Entrar na sua conta",
153 "password.link.signup": "Criar uma conta gratuita", 152 "password.link.signup": "Criar uma conta gratuita",
154 "password.noUser": "Não foi encontrado nenhum utilizador com este e-mail", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Por favor, verifique o seu e-mail", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Sincronização de conta",
157 "pricing.features.customWebsites": "Adicionar Websites Personalizados",
158 "pricing.features.desktopNotifications": "Notificações no ambiente de trabalho",
159 "pricing.features.onPremise": "En sitio y otros servicios alojados",
160 "pricing.features.recipes": "Escolha entre mais de 70 serviços",
161 "pricing.features.serviceProxies": "Proxies de Serviço",
162 "pricing.features.spellchecker": "Suporte de correção ortográfica",
163 "pricing.features.teamManagement": "Gestão de Equipa",
164 "pricing.features.thirdPartyServices": "Instalar serviços de terceiros",
165 "pricing.features.unlimitedServices": "Adicionar serviços ilimitados",
166 "pricing.features.workspaces": "Ãreas de trabalho",
167 "service.crashHandler.action": "Recarregar {name}", 155 "service.crashHandler.action": "Recarregar {name}",
168 "service.crashHandler.autoReload": "A tentar restabelecer {name} automaticamente em {seconds} segundos", 156 "service.crashHandler.autoReload": "A tentar restabelecer {name} automaticamente em {seconds} segundos",
169 "service.crashHandler.headline": "Oh não!", 157 "service.crashHandler.headline": "Oh não!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi sem conta", 170 "services.serverless": "Use Ferdi sem conta",
183 "services.welcome": "Bem-vindo ao Ferdi", 171 "services.welcome": "Bem-vindo ao Ferdi",
184 "settings.account.account.editButton": "Editar conta", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Conta indisponível", 173 "settings.account.accountUnavailable": "Conta indisponível",
186 "settings.account.accountUnavailableInfo": "Está a usar o Ferdi sem uma conta. Se deseja usar o Ferdi com uma conta e manter os seus serviços sincronizados entre instalações, por favor, selecione um servidor no separador Configurações e faça a autenticação.", 174 "settings.account.accountUnavailableInfo": "Está a usar o Ferdi sem uma conta. Se deseja usar o Ferdi com uma conta e manter os seus serviços sincronizados entre instalações, por favor, selecione um servidor no separador Configurações e faça a autenticação.",
187 "settings.account.buttonSave": "Atualizar perfil", 175 "settings.account.buttonSave": "Atualizar perfil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Recebeu um e-mail com um link para confirmar o cancelamento da sua conta. Atenção! A sua conta e dados não poderão ser restaurados!", 177 "settings.account.deleteEmailSent": "Recebeu um e-mail com um link para confirmar o cancelamento da sua conta. Atenção! A sua conta e dados não poderão ser restaurados!",
190 "settings.account.deleteInfo": "Se não precisa mais de sua conta Ferdi, pode apagá-la juntamente com toda a sua informação aqui.", 178 "settings.account.deleteInfo": "Se não precisa mais de sua conta Ferdi, pode apagá-la juntamente com toda a sua informação aqui.",
191 "settings.account.headline": "Conta", 179 "settings.account.headline": "Conta",
192 "settings.account.headlineAccount": "Informações de conta", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Zona Perigosa", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Recibos", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Mudar palavra-passe", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Atualizar perfil", 184 "settings.account.headlineProfile": "Atualizar perfil",
197 "settings.account.successInfo": "As suas alterações foram gravadas", 185 "settings.account.successInfo": "As suas alterações foram gravadas",
198 "settings.account.tryReloadServices": "Tente novamente", 186 "settings.account.tryReloadServices": "Tente novamente",
199 "settings.account.tryReloadUserInfoRequest": "Tente novamente", 187 "settings.account.tryReloadUserInfoRequest": "Tente novamente",
200 "settings.account.userInfoRequestFailed": "Não foi possível carregar as informações de utilizador", 188 "settings.account.userInfoRequestFailed": "Não foi possível carregar as informações de utilizador",
201 "settings.account.yourLicense": "A sua licença Ferdi", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Limpar cache", 191 "settings.app.buttonClearAllCache": "Limpar cache",
204 "settings.app.buttonInstallUpdate": "Reiniciar e instalar atualizações", 192 "settings.app.buttonInstallUpdate": "Reiniciar e instalar atualizações",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Servidor Personalizado de Tarefas", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Ativar modo noturno", 211 "settings.app.form.darkMode": "Ativar modo noturno",
224 "settings.app.form.enableGPUAcceleration": "Ativar Aceleração de GPU", 212 "settings.app.form.enableGPUAcceleration": "Ativar Aceleração de GPU",
225 "settings.app.form.enableLock": "Ativar palavra-passe", 213 "settings.app.form.enableLock": "Ativar palavra-passe",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Ativar correção ortográfica", 215 "settings.app.form.enableSpellchecking": "Ativar correção ortográfica",
228 "settings.app.form.enableSystemTray": "Mostrar Ferdi na barra de sistema", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Ativar Tarefas Ferdi", 217 "settings.app.form.enableTodos": "Ativar Tarefas Ferdi",
230 "settings.app.form.hibernateOnStartup": "Manter os serviços em hibernação durante a inicialização", 218 "settings.app.form.hibernateOnStartup": "Manter os serviços em hibernação durante a inicialização",
231 "settings.app.form.hibernationStrategy": "Estratégia de hibernação", 219 "settings.app.form.hibernationStrategy": "Estratégia de hibernação",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Mostrar separadores de serviços desativados", 239 "settings.app.form.showDisabledServices": "Mostrar separadores de serviços desativados",
252 "settings.app.form.showDragArea": "Mostrar área arrastável na janela", 240 "settings.app.form.showDragArea": "Mostrar área arrastável na janela",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Mostrar ícone de mensagem não lida quando as notificações estiverem desativadas", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Mostrar ícone de mensagem não lida quando as notificações estiverem desativadas",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Iniciar minimizado", 243 "settings.app.form.startMinimized": "Iniciar minimizado",
255 "settings.app.form.universalDarkMode": "Ativar o Modo Noturno Universal", 244 "settings.app.form.universalDarkMode": "Ativar o Modo Noturno Universal",
256 "settings.app.form.useTouchIdToUnlock": "Permite usar o TouchID para desbloquear Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Avançado", 248 "settings.app.headlineAdvanced": "Avançado",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "As traduções oficiais são Inglês e Alemão. Todas as outras traduções são feitas pela comunidade.", 256 "settings.app.languageDisclaimer": "As traduções oficiais são Inglês e Alemão. Todas as outras traduções são feitas pela comunidade.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Palavra-passe", 258 "settings.app.lockedPassword": "Palavra-passe",
270 "settings.app.lockedPasswordInfo": "Por favor certifique-se de definir uma palavra-passe que se lembre.\nSe perder esta palavra-passe, terá que reinstalar Ferdi.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "As mudanças requerem reinício de sistema", 260 "settings.app.restartRequired": "As mudanças requerem reinício de sistema",
272 "settings.app.scheduledDNDInfo": "O Não Incomodar permite definir um período de tempo em que não quer receber notificações.", 261 "settings.app.scheduledDNDInfo": "O Não Incomodar permite definir um período de tempo em que não quer receber notificações.",
273 "settings.app.scheduledDNDTimeInfo": "Horas em formato 24h. Pode definir a hora do fim antes da hora de início (p. ex. início 17:00, fim 09:00) para ativar o modo \"Não incomodar\" durante a noite.", 262 "settings.app.scheduledDNDTimeInfo": "Horas em formato 24h. Pode definir a hora do fim antes da hora de início (p. ex. início 17:00, fim 09:00) para ativar o modo \"Não incomodar\" durante a noite.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi usa o corretor ortográfico do seu Mac para verificar se há erros ortográficos. Se você quiser alterar os idiomas que o corretor ortográfico verifica, pode fazê-lo nas Preferências do Sistema do Mac.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi usa o corretor ortográfico do seu Mac para verificar se há erros ortográficos. Se você quiser alterar os idiomas que o corretor ortográfico verifica, pode fazê-lo nas Preferências do Sistema do Mac.",
276 "settings.app.subheadlineCache": "Memória cache", 265 "settings.app.subheadlineCache": "Memória cache",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Este servidor será usado para a funcionalidade \"Tarefas Ferdi\".", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Ajude-nos a traduzir o Ferdi para o seu idioma.", 268 "settings.app.translationHelp": "Ajude-nos a traduzir o Ferdi para o seu idioma.",
280 "settings.app.universalDarkModeInfo": "O Modo Noturno Universal tenta gerar dinamicamente os estilos do modo noturno para serviços que não o suportem de outra forma atualmente.", 269 "settings.app.universalDarkModeInfo": "O Modo Noturno Universal tenta gerar dinamicamente os estilos do modo noturno para serviços que não o suportem de outra forma atualmente.",
281 "settings.app.updateStatusAvailable": "Atualização disponível, a fazer download...", 270 "settings.app.updateStatusAvailable": "Atualização disponível, a fazer download...",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Receitas da comunidade de terceiros", 283 "settings.recipes.customService.headline.communityRecipes": "Receitas da comunidade de terceiros",
295 "settings.recipes.customService.headline.customRecipes": "Receitas personalizadas de terceiros", 284 "settings.recipes.customService.headline.customRecipes": "Receitas personalizadas de terceiros",
296 "settings.recipes.customService.headline.devRecipes": "As suas Receitas de Serviço de Desenvolvimento", 285 "settings.recipes.customService.headline.devRecipes": "As suas Receitas de Serviço de Desenvolvimento",
297 "settings.recipes.customService.intro": "Para adicionar um serviço personalizado, copie a receita do serviço para:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Documentação para programadores", 287 "settings.recipes.customService.openDevDocs": "Documentação para programadores",
299 "settings.recipes.customService.openFolder": "Abrir pasta", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Serviços disponíveis", 289 "settings.recipes.headline": "Serviços disponíveis",
301 "settings.recipes.missingService": "Sente falta de algum serviço?", 290 "settings.recipes.missingService": "Sente falta de algum serviço?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Brilho do Leitor Escuro", 301 "settings.service.form.darkReaderBrightness": "Brilho do Leitor Escuro",
313 "settings.service.form.darkReaderContrast": "Contraste do Leitor Noturno", 302 "settings.service.form.darkReaderContrast": "Contraste do Leitor Noturno",
314 "settings.service.form.darkReaderSepia": "Leitor Noturno Sépia", 303 "settings.service.form.darkReaderSepia": "Leitor Noturno Sépia",
315 "settings.service.form.deleteButton": "Apagar serviço", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Editar {name}", 305 "settings.service.form.editServiceHeadline": "Editar {name}",
317 "settings.service.form.enableAudio": "Ativar áudio", 306 "settings.service.form.enableAudio": "Ativar áudio",
318 "settings.service.form.enableBadge": "Mostrar aviso de mensagens não lidas", 307 "settings.service.form.enableBadge": "Mostrar aviso de mensagens não lidas",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Quando desativado, as notificações sonoras e áudio serão silenciados", 322 "settings.service.form.isMutedInfo": "Quando desativado, as notificações sonoras e áudio serão silenciados",
334 "settings.service.form.name": "Nome", 323 "settings.service.form.name": "Nome",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Abrir darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Abrir darkmode.css",
336 "settings.service.form.openUserCss": "Abrir user.css", 326 "settings.service.form.openUserCss": "Abrir user.css",
337 "settings.service.form.openUserJs": "Abrir user.js", 327 "settings.service.form.openUserJs": "Abrir user.js",
338 "settings.service.form.proxy.headline": "Configurações de HTTP/HTTPS Proxy", 328 "settings.service.form.proxy.headline": "Configurações de HTTP/HTTPS Proxy",
339 "settings.service.form.proxy.host": "Servidor/IP Proxy", 329 "settings.service.form.proxy.host": "Servidor/IP Proxy",
340 "settings.service.form.proxy.info": "As configurações de proxy não serão sincronizadas com os servidores de Ferdi.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Usar Proxy", 331 "settings.service.form.proxy.isEnabled": "Usar Proxy",
342 "settings.service.form.proxy.password": "Palavra-passe (opcional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Porta", 333 "settings.service.form.proxy.port": "Porta",
344 "settings.service.form.proxy.restartInfo": "Por favor, reinicie o Ferdi após alterar as configurações de proxy.", 334 "settings.service.form.proxy.restartInfo": "Por favor, reinicie o Ferdi após alterar as configurações de proxy.",
345 "settings.service.form.proxy.user": "Utilizador (opcional)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Os seus ficheiros serão inseridos na página da web para que possa personalizar os serviços da maneira que desejar. Os ficheiros são apenas armazenados localmente e não são transferidos para outros computadores usando a mesma conta.", 336 "settings.service.form.recipeFileInfo": "Os seus ficheiros serão inseridos na página da web para que possa personalizar os serviços da maneira que desejar. Os ficheiros são apenas armazenados localmente e não são transferidos para outros computadores usando a mesma conta.",
347 "settings.service.form.saveButton": "Gravar serviço", 337 "settings.service.form.saveButton": "Gravar serviço",
348 "settings.service.form.tabHosted": "Alojado", 338 "settings.service.form.tabHosted": "Alojado",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Descobrir serviços", 344 "settings.services.discoverServices": "Descobrir serviços",
355 "settings.services.headline": "Os seus serviços", 345 "settings.services.headline": "Os seus serviços",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Não foi possível carregar os seus serviços", 348 "settings.services.servicesRequestFailed": "Não foi possível carregar os seus serviços",
358 "settings.services.tooltip.isDisabled": "O serviço está desativado", 349 "settings.services.tooltip.isDisabled": "O serviço está desativado",
359 "settings.services.tooltip.isMuted": "Sem som", 350 "settings.services.tooltip.isMuted": "Sem som",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Sem fins lucrativos", 378 "settings.user.form.accountType.non-profit": "Sem fins lucrativos",
388 "settings.user.form.currentPassword": "Palavra-passe atual", 379 "settings.user.form.currentPassword": "Palavra-passe atual",
389 "settings.user.form.email": "E-mail", 380 "settings.user.form.email": "E-mail",
390 "settings.user.form.firstname": "Nome", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Apelido", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nova palavra-passe", 383 "settings.user.form.newPassword": "Nova palavra-passe",
393 "settings.workspace.add.form.name": "Nome", 384 "settings.workspace.add.form.name": "Nome",
394 "settings.workspace.add.form.submitButton": "Criar área de trabalho", 385 "settings.workspace.add.form.submitButton": "Criar área de trabalho",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Tente novamente", 396 "settings.workspaces.tryReloadWorkspaces": "Tente novamente",
406 "settings.workspaces.updatedInfo": "As suas alterações foram gravadas", 397 "settings.workspaces.updatedInfo": "As suas alterações foram gravadas",
407 "settings.workspaces.workspaceFeatureHeadline": "Menos é Mais: Apresentando áreas de trabalho Ferdi", 398 "settings.workspaces.workspaceFeatureHeadline": "Menos é Mais: Apresentando áreas de trabalho Ferdi",
408 "settings.workspaces.workspaceFeatureInfo": "As áreas de trabalho do Ferdi permitem que se concentre no que realmente é importante. Configure diferentes conjuntos de serviços e mude-os facilmente e a qualquer momento. Você decide quais os serviços que precisa e onde colocá-los, para que o possamos ajudar a estar no seu melhor. - Ou desligar do trabalho quando quiser.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Não foi possível carregar suas áreas de trabalho", 400 "settings.workspaces.workspacesRequestFailed": "Não foi possível carregar suas áreas de trabalho",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Ativar notificações e áudio", 411 "sidebar.unmuteApp": "Ativar notificações e áudio",
421 "signup.email.label": "Endereço de E-mail", 412 "signup.email.label": "Endereço de E-mail",
422 "signup.emailDuplicate": "Já existe um utilizador com este endereço de e-mail", 413 "signup.emailDuplicate": "Já existe um utilizador com este endereço de e-mail",
423 "signup.firstname.label": "Nome", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Entrar", 415 "signup.headline": "Entrar",
425 "signup.lastname.label": "Apelido", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Ao criar uma conta Ferdi, você aceita os", 417 "signup.legal.info": "Ao criar uma conta Ferdi, você aceita os",
427 "signup.legal.privacy": "Declaração de Privacidade", 418 "signup.legal.privacy": "Declaração de Privacidade",
428 "signup.legal.terms": "Termos de serviço", 419 "signup.legal.terms": "Termos de serviço",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Palavra-passe", 421 "signup.password.label": "Palavra-passe",
431 "signup.submit.label": "Criar conta", 422 "signup.submit.label": "Criar conta",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Apagar serviço", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Desativar áudio", 425 "tabs.item.disableAudio": "Desativar áudio",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Desativar notificações", 427 "tabs.item.disableNotifications": "Desativar notificações",
437 "tabs.item.disableService": "Desativar serviço", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Ativar áudio", 429 "tabs.item.enableAudio": "Ativar áudio",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Ativar notificações", 431 "tabs.item.enableNotification": "Ativar notificações",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Atualizar", 434 "tabs.item.reload": "Atualizar",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} é inválido", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} deve ter pelo menos {length} caracteres", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "É necessário pelo menos um", 438 "validation.oneRequired": "É necessário pelo menos um",
448 "validation.required": "{field} é obrigatório", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} não é um URL válido", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Anterior", 441 "webControls.back": "Anterior",
451 "webControls.forward": "Seguinte", 442 "webControls.forward": "Seguinte",
452 "webControls.goHome": "Início", 443 "webControls.goHome": "Início",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Atualizar", 445 "webControls.reload": "Atualizar",
455 "welcome.loginButton": "Entrar na sua conta", 446 "welcome.loginButton": "Entrar na sua conta",
456 "welcome.signupButton": "Criar uma conta gratuita", 447 "welcome.signupButton": "Criar uma conta gratuita",
457 "workspaceDrawer.addNewWorkspaceLabel": "Adicionar nova área de trabalho", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Todos os serviços", 449 "workspaceDrawer.allServices": "Todos os serviços",
459 "workspaceDrawer.headline": "Ãreas de trabalho", 450 "workspaceDrawer.headline": "Ãreas de trabalho",
460 "workspaceDrawer.item.contextMenuEdit": "editar", 451 "workspaceDrawer.item.contextMenuEdit": "editar",
461 "workspaceDrawer.item.noServicesAddedYet": "Nenhum serviço adicionado", 452 "workspaceDrawer.item.noServicesAddedYet": "Nenhum serviço adicionado",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>As áreas de trabalho do Ferdi permitem que se concentre no que realmente é importante. Configure diferentes conjuntos de serviços e mude-os facilmente e a qualquer momento.</p><p>Você decide quais os serviços que precisa e onde colocá-los, para que o possamos ajudar a estar no seu melhor. - Ou desligar do trabalho quando quiser.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Editar configurações das áreas de trabalho", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "A mudar para" 455 "workspaces.switchingIndicator.switchingTo": "A mudar para"
465} 456}
diff --git a/src/i18n/locales/ro.json b/src/i18n/locales/ro.json
index 6e2ee4c19..fad6dae82 100644
--- a/src/i18n/locales/ro.json
+++ b/src/i18n/locales/ro.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reîncărcare", 2 "app.errorHandler.action": "Reîncărcare",
3 "app.errorHandler.headline": "Ceva nu a funcționat corect", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Ce s-a întâmplat?", 10 "connectionLostBanner.informationLink": "Ce s-a întâmplat?",
11 "connectionLostBanner.message": "Oh nu! Ferdi a pierdut conexiunea cu {name}.", 11 "connectionLostBanner.message": "Oh nu! Ferdi a pierdut conexiunea cu {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activare", 13 "feature.nightlyBuilds.activate": "Activare",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,7 +23,7 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Căutare...", 24 "feature.quickSwitch.search": "Căutare...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Nu se pot conecta la Ferdi servicii online", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Cancel", 27 "global.cancel": "Cancel",
29 "global.edit": "Edit", 28 "global.edit": "Edit",
30 "global.no": "No", 29 "global.no": "No",
@@ -45,7 +44,7 @@
45 "import.headline": "Importă serviciile tale Ferdi 4", 44 "import.headline": "Importă serviciile tale Ferdi 4",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json
index 4a7222914..f7d25e08b 100644
--- a/src/i18n/locales/ru.json
+++ b/src/i18n/locales/ru.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Перезагрузить", 2 "app.errorHandler.action": "Перезагрузить",
3 "app.errorHandler.headline": "Что-то пошло не так", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "ПользовательÑкий Ñервер", 4 "changeserver.customServerLabel": "ПользовательÑкий Ñервер",
5 "changeserver.headline": "Изменить Ñервер", 5 "changeserver.headline": "Изменить Ñервер",
6 "changeserver.label": "Сервер", 6 "changeserver.label": "Сервер",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Что ÑлучилоÑÑŒ?", 10 "connectionLostBanner.informationLink": "Что ÑлучилоÑÑŒ?",
11 "connectionLostBanner.message": "О нет! Ферди потерÑл ÑвÑзь Ñ {name}.", 11 "connectionLostBanner.message": "О нет! Ферди потерÑл ÑвÑзь Ñ {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Опубликовать отладочную информацию",
14 "feature.nightlyBuilds.activate": "Ðктивировать", 13 "feature.nightlyBuilds.activate": "Ðктивировать",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Выберите ÑÐµÑ€Ð²Ð¸Ñ Ñ Tab, вверх и вниз. Откройте ÑÐµÑ€Ð²Ð¸Ñ Ð½Ð°Ð¶Ð°Ð² на ENTER.", 23 "feature.quickSwitch.info": "Выберите ÑÐµÑ€Ð²Ð¸Ñ Ñ Tab, вверх и вниз. Откройте ÑÐµÑ€Ð²Ð¸Ñ Ð½Ð°Ð¶Ð°Ð² на ENTER.",
25 "feature.quickSwitch.search": "ПоиÑк...", 24 "feature.quickSwitch.search": "ПоиÑк...",
26 "feature.quickSwitch.title": "БыÑтрое переключение", 25 "feature.quickSwitch.title": "БыÑтрое переключение",
27 "global.api.unhealthy": "Ðевозможно подключитьÑÑ Ðº онлайн-ÑервиÑам Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Отмена", 27 "global.cancel": "Cancel",
29 "global.edit": "Правка", 28 "global.edit": "Правка",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Ð’Ñ‹ не подключены к Ñети Интернет", 30 "global.notConnectedToTheInternet": "Ð’Ñ‹ не подключены к Ñети Интернет",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "ÐаÑтройки", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "ИÑпользовать ÑиÑтемные параметры по умолчанию ({default})", 36 "global.spellchecker.useDefault": "ИÑпользовать ÑиÑтемные параметры по умолчанию ({default})",
38 "global.spellchecking.autodetect": "Ðайти Ñзык автоматичеÑки", 37 "global.spellchecking.autodetect": "Ðайти Ñзык автоматичеÑки",
39 "global.spellchecking.autodetect.short": "Ðвто", 38 "global.spellchecking.autodetect.short": "Ðвто",
40 "global.spellchecking.language": "Проверка правопиÑаниÑ", 39 "global.spellchecking.language": "Проверка правопиÑаниÑ",
41 "global.submit": "ПринÑÑ‚ÑŒ", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Импортировать ваши ÑервиÑÑ‹ из Ferdi 4", 44 "import.headline": "Импортировать ваши ÑервиÑÑ‹ из Ferdi 4",
46 "import.notSupportedHeadline": "СервиÑÑ‹ пока ещё не поддерживаютÑÑ Ð² Ferdi 5", 45 "import.notSupportedHeadline": "СервиÑÑ‹ пока ещё не поддерживаютÑÑ Ð² Ferdi 5",
47 "import.skip.label": "Я хочу добавить ÑервиÑÑ‹ вручную", 46 "import.skip.label": "Я хочу добавить ÑервиÑÑ‹ вручную",
48 "import.submit.label": "Импортировать ÑервиÑÑ‹", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "При попытке выполнить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° аутентификацию произошли ошибки. ПожалуйÑта, попробуйте выйти из ÑиÑтемы и вернутьÑÑ Ð½Ð°Ð·Ð°Ð´, еÑли Ñта ошибка повторÑетÑÑ.", 48 "infobar.authRequestFailed": "При попытке выполнить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° аутентификацию произошли ошибки. ПожалуйÑта, попробуйте выйти из ÑиÑтемы и вернутьÑÑ Ð½Ð°Ð·Ð°Ð´, еÑли Ñта ошибка повторÑетÑÑ.",
50 "infobar.buttonChangelog": "Что новенького?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "ПерезапуÑтить и уÑтановить обновлениÑ", 50 "infobar.buttonInstallUpdate": "ПерезапуÑтить и уÑтановить обновлениÑ",
52 "infobar.buttonReloadServices": "Перезагрузить ÑервиÑÑ‹", 51 "infobar.buttonReloadServices": "Перезагрузить ÑервиÑÑ‹",
53 "infobar.hide": "Скрыть", 52 "infobar.hide": "Скрыть",
@@ -75,7 +74,7 @@
75 "login.email.label": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты", 74 "login.email.label": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты",
76 "login.headline": "Вход", 75 "login.headline": "Вход",
77 "login.invalidCredentials": "Ðеправильный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты или пароль", 76 "login.invalidCredentials": "Ðеправильный Ð°Ð´Ñ€ÐµÑ Ñлектронной почты или пароль",
78 "login.link.password": "ВоÑÑтановить пароль", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Создать беÑплатный аккаунт", 78 "login.link.signup": "Создать беÑплатный аккаунт",
80 "login.password.label": "Пароль", 79 "login.password.label": "Пароль",
81 "login.serverLogout": "СеÑÑÐ¸Ñ ÑƒÑтарела, пожалуйÑта, войдите Ñнова.", 80 "login.serverLogout": "СеÑÑÐ¸Ñ ÑƒÑтарела, пожалуйÑта, войдите Ñнова.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Поддержка", 116 "menu.help.support": "Поддержка",
118 "menu.help.tos": "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ÑпользованиÑ", 117 "menu.help.tos": "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¸ÑпользованиÑ",
119 "menu.services": "СервиÑ", 118 "menu.services": "СервиÑ",
120 "menu.services.activatePreviousService": "Ðктивировать предыдущий Ñервич", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Домой", 121 "menu.services.goHome": "Домой",
123 "menu.services.setNextServiceActive": "Ðктивировать Ñледующий ÑервиÑ", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Задачи", 123 "menu.todos": "Задачи",
125 "menu.todos.enableTodos": "Включить задачи", 124 "menu.todos.enableTodos": "Включить задачи",
126 "menu.view": "Вид", 125 "menu.view": "Вид",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Ð’Ñе ÑервиÑÑ‹", 147 "menu.workspaces.defaultWorkspace": "Ð’Ñе ÑервиÑÑ‹",
149 "menu.workspaces.openWorkspaceDrawer": "Открыть меню окружений", 148 "menu.workspaces.openWorkspaceDrawer": "Открыть меню окружений",
150 "password.email.label": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты", 149 "password.email.label": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты",
151 "password.headline": "ВоÑÑтановить пароль", 150 "password.headline": "Reset password",
152 "password.link.login": "Вход", 151 "password.link.login": "Вход",
153 "password.link.signup": "Создать беÑплатный аккаунт", 152 "password.link.signup": "Создать беÑплатный аккаунт",
154 "password.noUser": "Ðе найдено Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом Ñлектронной почты", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Проверьте вашу Ñлектронную почту", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Добавить пользовательÑкие веб-Ñайты",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "ПрокÑи ÑервиÑа",
162 "pricing.features.spellchecker": "Поддержка Spellchecker",
163 "pricing.features.teamManagement": "Команда управлениÑ",
164 "pricing.features.thirdPartyServices": "УÑтановить Ñторонние ÑервиÑÑ‹",
165 "pricing.features.unlimitedServices": "Добавить неограниченные ÑервиÑÑ‹",
166 "pricing.features.workspaces": "Окружение",
167 "service.crashHandler.action": "Перезагрузить {name}", 155 "service.crashHandler.action": "Перезагрузить {name}",
168 "service.crashHandler.autoReload": "ПытаюÑÑŒ автоматичеÑки воÑÑтановить {name} в течение {seconds} Ñекунд", 156 "service.crashHandler.autoReload": "ПытаюÑÑŒ автоматичеÑки воÑÑтановить {name} в течение {seconds} Ñекунд",
169 "service.crashHandler.headline": "О, нет!", 157 "service.crashHandler.headline": "О, нет!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Добро пожаловать во Ferdi", 171 "services.welcome": "Добро пожаловать во Ferdi",
184 "settings.account.account.editButton": "Редактировать аккаунт", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Обновить профиль", 175 "settings.account.buttonSave": "Обновить профиль",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Вам выÑлано пиÑьмо Ñ ÑÑылкой Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚Ð°. ПоÑле Ñтого ваш аккаунт и данные не Ñмогут быть воÑÑтановлены!", 177 "settings.account.deleteEmailSent": "Вам выÑлано пиÑьмо Ñ ÑÑылкой Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚Ð°. ПоÑле Ñтого ваш аккаунт и данные не Ñмогут быть воÑÑтановлены!",
190 "settings.account.deleteInfo": "ЕÑли вам больше не нужна ваша ÑƒÑ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ в Ferdi, вы можете удалить аккаунт и вÑÑŽ ÑвÑзанную Ñ Ð½ÐµÐ¹ информацию.", 178 "settings.account.deleteInfo": "ЕÑли вам больше не нужна ваша ÑƒÑ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ в Ferdi, вы можете удалить аккаунт и вÑÑŽ ÑвÑзанную Ñ Ð½ÐµÐ¹ информацию.",
191 "settings.account.headline": "Ðккаунт", 179 "settings.account.headline": "Ðккаунт",
192 "settings.account.headlineAccount": "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚Ð°", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Ð—Ð°Ð¿Ñ€ÐµÑ‚Ð½Ð°Ñ Ð—Ð¾Ð½Ð°", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Счета", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Сменить пароль", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Обновить профиль", 184 "settings.account.headlineProfile": "Обновить профиль",
197 "settings.account.successInfo": "Ваши Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¸ Ñохранены", 185 "settings.account.successInfo": "Ваши Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð¸ Ñохранены",
198 "settings.account.tryReloadServices": "Попробовать Ñнова", 186 "settings.account.tryReloadServices": "Попробовать Ñнова",
199 "settings.account.tryReloadUserInfoRequest": "Попробовать Ñнова", 187 "settings.account.tryReloadUserInfoRequest": "Попробовать Ñнова",
200 "settings.account.userInfoRequestFailed": "Ðевозможно загрузить информацию пользователÑ", 188 "settings.account.userInfoRequestFailed": "Ðевозможно загрузить информацию пользователÑ",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "ОчиÑтить кÑш", 191 "settings.app.buttonClearAllCache": "ОчиÑтить кÑш",
204 "settings.app.buttonInstallUpdate": "ПерезапуÑтить и уÑтановить обновлениÑ", 192 "settings.app.buttonInstallUpdate": "ПерезапуÑтить и уÑтановить обновлениÑ",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Включить Тёмный режим",
224 "settings.app.form.enableGPUAcceleration": "Включить уÑкорение GPU", 212 "settings.app.form.enableGPUAcceleration": "Включить уÑкорение GPU",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Включить проверку правопиÑаниÑ", 215 "settings.app.form.enableSpellchecking": "Включить проверку правопиÑаниÑ",
228 "settings.app.form.enableSystemTray": "Показывать Ferdi в ÑиÑтемном трее", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Показывать вкладки отключённых Ñлужб", 239 "settings.app.form.showDisabledServices": "Показывать вкладки отключённых Ñлужб",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Показывать значок непрочитанного ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ отключённых уведомлениÑÑ…", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Показывать значок непрочитанного ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ отключённых уведомлениÑÑ…",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "ЗапуÑкать Ñвернутым", 243 "settings.app.form.startMinimized": "ЗапуÑкать Ñвернутым",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes", 283 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes",
295 "settings.recipes.customService.headline.customRecipes": "Custom 3rd Party Recipes", 284 "settings.recipes.customService.headline.customRecipes": "Custom 3rd Party Recipes",
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "Чтобы добавить пользовательÑкий ÑервиÑ, Ñкопируйте файлы ÑервиÑа:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ разработчиков", 287 "settings.recipes.customService.openDevDocs": "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ разработчиков",
299 "settings.recipes.customService.openFolder": "Открыть папку", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "ДоÑтупные ÑервиÑÑ‹", 289 "settings.recipes.headline": "ДоÑтупные ÑервиÑÑ‹",
301 "settings.recipes.missingService": "Ðе можете найти ÑервиÑ?", 290 "settings.recipes.missingService": "Ðе можете найти ÑервиÑ?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Удалить ÑервиÑ", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Редактирование {name}", 305 "settings.service.form.editServiceHeadline": "Редактирование {name}",
317 "settings.service.form.enableAudio": "Включить звук", 306 "settings.service.form.enableAudio": "Включить звук",
318 "settings.service.form.enableBadge": "Показывать иконку непрочитанных Ñообщений", 307 "settings.service.form.enableBadge": "Показывать иконку непрочитанных Ñообщений",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Когда включено, Ñлужба будет отключена по иÑтечении времени, чтобы Ñохранить ÑиÑтемные реÑурÑÑ‹.", 321 "settings.service.form.isHibernatedEnabledInfo": "Когда включено, Ñлужба будет отключена по иÑтечении времени, чтобы Ñохранить ÑиÑтемные реÑурÑÑ‹.",
333 "settings.service.form.isMutedInfo": "Когда выключено, вÑе звуковые ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ отключены", 322 "settings.service.form.isMutedInfo": "Когда выключено, вÑе звуковые ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð±ÑƒÐ´ÑƒÑ‚ отключены",
334 "settings.service.form.name": "ИмÑ", 323 "settings.service.form.name": "ИмÑ",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Открыть user.css", 326 "settings.service.form.openUserCss": "Открыть user.css",
337 "settings.service.form.openUserJs": "Открыть user.js", 327 "settings.service.form.openUserJs": "Открыть user.js",
338 "settings.service.form.proxy.headline": "ÐаÑтройки ПрокÑи HTTP/HTTPS", 328 "settings.service.form.proxy.headline": "ÐаÑтройки ПрокÑи HTTP/HTTPS",
339 "settings.service.form.proxy.host": "ПрокÑи Host/IP", 329 "settings.service.form.proxy.host": "ПрокÑи Host/IP",
340 "settings.service.form.proxy.info": "ÐаÑтройки прокÑи не будут Ñинхронизированны Ñ Ñерверами Ferdi", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "ИÑпользовать прокÑи", 331 "settings.service.form.proxy.isEnabled": "ИÑпользовать прокÑи",
342 "settings.service.form.proxy.password": "Пароль (опционально)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Порт", 333 "settings.service.form.proxy.port": "Порт",
344 "settings.service.form.proxy.restartInfo": "ПожалуйÑта перезапуÑтите Ferdi поÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ð°Ñтроек прокÑи.", 334 "settings.service.form.proxy.restartInfo": "ПожалуйÑта перезапуÑтите Ferdi поÑле Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ð°Ñтроек прокÑи.",
345 "settings.service.form.proxy.user": "Пользователь (опционально)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Ваши пользовательÑкие файлы будут вÑтавлены на веб-Ñтраницу, чтобы вы могли наÑтроить ÑервиÑÑ‹ в любом удобном вам виде. Файлы пользователей хранÑÑ‚ÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ локально и не передаютÑÑ Ð½Ð° другие компьютеры, иÑпользующие ту же учетную запиÑÑŒ.", 336 "settings.service.form.recipeFileInfo": "Ваши пользовательÑкие файлы будут вÑтавлены на веб-Ñтраницу, чтобы вы могли наÑтроить ÑервиÑÑ‹ в любом удобном вам виде. Файлы пользователей хранÑÑ‚ÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ локально и не передаютÑÑ Ð½Ð° другие компьютеры, иÑпользующие ту же учетную запиÑÑŒ.",
347 "settings.service.form.saveButton": "Сохранить ÑервиÑ", 337 "settings.service.form.saveButton": "Сохранить ÑервиÑ",
348 "settings.service.form.tabHosted": "Размещено", 338 "settings.service.form.tabHosted": "Размещено",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Ðайти ÑервиÑÑ‹", 344 "settings.services.discoverServices": "Ðайти ÑервиÑÑ‹",
355 "settings.services.headline": "Ваши ÑервиÑÑ‹", 345 "settings.services.headline": "Ваши ÑервиÑÑ‹",
356 "settings.services.noServicesAdded": "Ðачните Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑервиÑа.", 346 "settings.services.noServicesAdded": "Ðачните Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑервиÑа.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Ошибка загрузки ÑервиÑов", 348 "settings.services.servicesRequestFailed": "Ошибка загрузки ÑервиÑов",
358 "settings.services.tooltip.isDisabled": "Ð¡ÐµÑ€Ð²Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½", 349 "settings.services.tooltip.isDisabled": "Ð¡ÐµÑ€Ð²Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½",
359 "settings.services.tooltip.isMuted": "Ð’Ñе звуки отключены", 350 "settings.services.tooltip.isMuted": "Ð’Ñе звуки отключены",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ферди ÑвлÑетÑÑ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸ÐµÐ¼ Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом и разрабатываетÑÑ ÑообщеÑтвом.</p><p>СпаÑибо людÑм, которые делают Ñто возможным:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ферди ÑвлÑетÑÑ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸ÐµÐ¼ Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ñ‹Ð¼ иÑходным кодом и разрабатываетÑÑ ÑообщеÑтвом.</p><p>СпаÑибо людÑм, которые делают Ñто возможным:</p>",
363 "settings.supportFerdi.bannerText": "Вы хотите помочь нам улучшить Ферди?", 354 "settings.supportFerdi.bannerText": "Вы хотите помочь нам улучшить Ферди?",
364 "settings.supportFerdi.headline": "О Ferdi", 355 "settings.supportFerdi.headline": "О Ferdi",
365 "settings.supportFerdi.openSurvey": "Открыть опроÑ", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "ЕÑли вы хотите поддержать развитие Ферди Ñ Ð¿Ð¾Ð¶ÐµÑ€Ñ‚Ð²Ð¾Ð²Ð°Ð½Ð¸ÐµÐ¼, вы можете Ñделать Ñто Ð´Ð²ÑƒÐ¼Ñ ÑпоÑобами,", 357 "settings.supportFerdi.textDonation": "ЕÑли вы хотите поддержать развитие Ферди Ñ Ð¿Ð¾Ð¶ÐµÑ€Ñ‚Ð²Ð¾Ð²Ð°Ð½Ð¸ÐµÐ¼, вы можете Ñделать Ñто Ð´Ð²ÑƒÐ¼Ñ ÑпоÑобами,",
367 "settings.supportFerdi.textDonationAnd": "и", 358 "settings.supportFerdi.textDonationAnd": "и",
368 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our", 359 "settings.supportFerdi.textExpenses": "While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our",
369 "settings.supportFerdi.textGitHubSponsors": "СпонÑоры на Github", 360 "settings.supportFerdi.textGitHubSponsors": "СпонÑоры на Github",
370 "settings.supportFerdi.textListContributors": "Полный ÑпиÑок учаÑтников", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "here", 362 "settings.supportFerdi.textListContributorsHere": "here",
372 "settings.supportFerdi.textOpenCollective": "Open Collective", 363 "settings.supportFerdi.textOpenCollective": "Open Collective",
373 "settings.supportFerdi.textSupportWelcome": "Support is always welcome. You can find a list of the help we need", 364 "settings.supportFerdi.textSupportWelcome": "Support is always welcome. You can find a list of the help we need",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "ÐекоммерчеÑкий", 378 "settings.user.form.accountType.non-profit": "ÐекоммерчеÑкий",
388 "settings.user.form.currentPassword": "Текущий пароль", 379 "settings.user.form.currentPassword": "Текущий пароль",
389 "settings.user.form.email": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты", 380 "settings.user.form.email": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты",
390 "settings.user.form.firstname": "ИмÑ", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "ФамилиÑ", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Ðовый пароль", 383 "settings.user.form.newPassword": "Ðовый пароль",
393 "settings.workspace.add.form.name": "ИмÑ", 384 "settings.workspace.add.form.name": "ИмÑ",
394 "settings.workspace.add.form.submitButton": "Создать окружение", 385 "settings.workspace.add.form.submitButton": "Создать окружение",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Включить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸ звук", 411 "sidebar.unmuteApp": "Включить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸ звук",
421 "signup.email.label": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты", 412 "signup.email.label": "ÐÐ´Ñ€ÐµÑ Ñлектронной почты",
422 "signup.emailDuplicate": "Пользователь Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом Ñлектронной почты уже ÑущеÑтвует", 413 "signup.emailDuplicate": "Пользователь Ñ Ñ‚Ð°ÐºÐ¸Ð¼ адреÑом Ñлектронной почты уже ÑущеÑтвует",
423 "signup.firstname.label": "ИмÑ", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "РегиÑтрациÑ", 415 "signup.headline": "РегиÑтрациÑ",
425 "signup.lastname.label": "ФамилиÑ", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Ð¡Ð¾Ð·Ð´Ð°Ð²Ð°Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚ Ferdi, вы принимаете", 417 "signup.legal.info": "Ð¡Ð¾Ð·Ð´Ð°Ð²Ð°Ñ Ð°ÐºÐºÐ°ÑƒÐ½Ñ‚ Ferdi, вы принимаете",
427 "signup.legal.privacy": "Политика конфиденциальноÑти", 418 "signup.legal.privacy": "Политика конфиденциальноÑти",
428 "signup.legal.terms": "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¾Ð±ÑлуживаниÑ", 419 "signup.legal.terms": "УÑÐ»Ð¾Ð²Ð¸Ñ Ð¾Ð±ÑлуживаниÑ",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Пароль", 421 "signup.password.label": "Пароль",
431 "signup.submit.label": "Создать аккаунт", 422 "signup.submit.label": "Создать аккаунт",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Удалить ÑервиÑ", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Отключить звук", 425 "tabs.item.disableAudio": "Отключить звук",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Отключить уведомлениÑ", 427 "tabs.item.disableNotifications": "Отключить уведомлениÑ",
437 "tabs.item.disableService": "Отключить ÑервиÑ", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Включить звук", 429 "tabs.item.enableAudio": "Включить звук",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Включить уведомлениÑ", 431 "tabs.item.enableNotification": "Включить уведомлениÑ",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Перезагрузить", 434 "tabs.item.reload": "Перезагрузить",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} недейÑтвительно", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} должно быть не менее {length} Ñимволов", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} обÑзательно", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} ÑвлÑетÑÑ Ð½ÐµÐ´ÐµÐ¹Ñтвительной ÑÑылкой", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Ðазад", 441 "webControls.back": "Ðазад",
451 "webControls.forward": "ПереÑлать", 442 "webControls.forward": "ПереÑлать",
452 "webControls.goHome": "Домой", 443 "webControls.goHome": "Домой",
diff --git a/src/i18n/locales/sk.json b/src/i18n/locales/sk.json
index 7e84088d1..02d325afd 100644
--- a/src/i18n/locales/sk.json
+++ b/src/i18n/locales/sk.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Obnoviť", 2 "app.errorHandler.action": "Obnoviť",
3 "app.errorHandler.headline": "NieÄo sa pokazilo", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Vlastný server", 4 "changeserver.customServerLabel": "Vlastný server",
5 "changeserver.headline": "Zmeniť server", 5 "changeserver.headline": "Zmeniť server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "ÄŒo sa stalo?", 10 "connectionLostBanner.informationLink": "ÄŒo sa stalo?",
11 "connectionLostBanner.message": "Oh nie! Ferdi stratil pripojenie k {name}.", 11 "connectionLostBanner.message": "Oh nie! Ferdi stratil pripojenie k {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Zverejniť informácie ladenia",
14 "feature.nightlyBuilds.activate": "Aktivovať", 13 "feature.nightlyBuilds.activate": "Aktivovať",
15 "feature.nightlyBuilds.info": "Tzv. \"noÄné verzie\" sú vysoko experimentálne verzie Ferdi, ktoré môžu obsahovaÅ¥ nedoladená alebo nedokonÄené funkcie. Tieto verzie sú používané predovÅ¡etkým vývojármi, aby otestovali novo-vyvíjané funkcie a spôsob, akým sa budú správaÅ¥ vo finálnej verzii. Ak neviete Äo robíte, navrhujeme neaktivovaÅ¥ tieto experimentálne verzie.", 14 "feature.nightlyBuilds.info": "Tzv. \"noÄné verzie\" sú vysoko experimentálne verzie Ferdi, ktoré môžu obsahovaÅ¥ nedoladená alebo nedokonÄené funkcie. Tieto verzie sú používané predovÅ¡etkým vývojármi, aby otestovali novo-vyvíjané funkcie a spôsob, akým sa budú správaÅ¥ vo finálnej verzii. Ak neviete Äo robíte, navrhujeme neaktivovaÅ¥ tieto experimentálne verzie.",
16 "feature.nightlyBuilds.title": "Vývojárske verzie", 15 "feature.nightlyBuilds.title": "Vývojárske verzie",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Hľadať...", 24 "feature.quickSwitch.search": "Hľadať...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Nedá sa pripojiť k online službám Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Zrušiť", 27 "global.cancel": "Cancel",
29 "global.edit": "Upraviť", 28 "global.edit": "Upraviť",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Nie ste pripojení k internetu.", 30 "global.notConnectedToTheInternet": "Nie ste pripojení k internetu.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Nastavenia", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Použiť predvolené nastavenie systému ({default})", 36 "global.spellchecker.useDefault": "Použiť predvolené nastavenie systému ({default})",
38 "global.spellchecking.autodetect": "Automaticky rozpoznať jazyk", 37 "global.spellchecking.autodetect": "Automaticky rozpoznať jazyk",
39 "global.spellchecking.autodetect.short": "Automatický", 38 "global.spellchecking.autodetect.short": "Automatický",
40 "global.spellchecking.language": "Jazyk kontroly pravopisu", 39 "global.spellchecking.language": "Jazyk kontroly pravopisu",
41 "global.submit": "Odoslať", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importovať vaše služby z Ferdi 4", 44 "import.headline": "Importovať vaše služby z Ferdi 4",
46 "import.notSupportedHeadline": "Služby zatiaľ nie sú podporované vo verzii Ferdi 5", 45 "import.notSupportedHeadline": "Služby zatiaľ nie sú podporované vo verzii Ferdi 5",
47 "import.skip.label": "Chcem pridaÅ¥ služby ruÄne", 46 "import.skip.label": "Chcem pridaÅ¥ služby ruÄne",
48 "import.submit.label": "Importovať služby", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Čo je nového?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Reštartovať a nainštalovať aktualizáciu", 50 "infobar.buttonInstallUpdate": "Reštartovať a nainštalovať aktualizáciu",
52 "infobar.buttonReloadServices": "Obnoviť služby", 51 "infobar.buttonReloadServices": "Obnoviť služby",
53 "infobar.hide": "Skryť", 52 "infobar.hide": "Skryť",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-mailová adresa", 74 "login.email.label": "E-mailová adresa",
76 "login.headline": "Prihlásiť sa", 75 "login.headline": "Prihlásiť sa",
77 "login.invalidCredentials": "E-mail alebo heslo nesúhlasia", 76 "login.invalidCredentials": "E-mail alebo heslo nesúhlasia",
78 "login.link.password": "Obnoviť heslo", 77 "login.link.password": "Reset password",
79 "login.link.signup": "VytvoriÅ¥ používateľský úÄet zdarma", 78 "login.link.signup": "VytvoriÅ¥ používateľský úÄet zdarma",
80 "login.password.label": "Heslo", 79 "login.password.label": "Heslo",
81 "login.serverLogout": "Vaša relácia vypršala, prihláste sa prosím znovu.", 80 "login.serverLogout": "Vaša relácia vypršala, prihláste sa prosím znovu.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Podpora", 116 "menu.help.support": "Podpora",
118 "menu.help.tos": "Podmienky použitia", 117 "menu.help.tos": "Podmienky použitia",
119 "menu.services": "Služby", 118 "menu.services": "Služby",
120 "menu.services.activatePreviousService": "Aktivovať predchádzajúcu službu", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Úvod", 121 "menu.services.goHome": "Úvod",
123 "menu.services.setNextServiceActive": "Aktivujte ÄalÅ¡iu službu", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Enable Todos", 124 "menu.todos.enableTodos": "Enable Todos",
126 "menu.view": "Zobraziť", 125 "menu.view": "Zobraziť",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Všetky služby", 147 "menu.workspaces.defaultWorkspace": "Všetky služby",
149 "menu.workspaces.openWorkspaceDrawer": "Otvoriť workspace záložku", 148 "menu.workspaces.openWorkspaceDrawer": "Otvoriť workspace záložku",
150 "password.email.label": "E-mailová adresa", 149 "password.email.label": "E-mailová adresa",
151 "password.headline": "Obnoviť heslo", 150 "password.headline": "Reset password",
152 "password.link.login": "PrihlásiÅ¥ sa do vášho úÄtu", 151 "password.link.login": "PrihlásiÅ¥ sa do vášho úÄtu",
153 "password.link.signup": "VytvoriÅ¥ používateľský úÄet zdarma", 152 "password.link.signup": "VytvoriÅ¥ používateľský úÄet zdarma",
154 "password.noUser": "Používateľ s touto e-mailovou adresou nebol nájdený", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Skontrolujte prosím váš e-mail", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Synchronizácia úÄtu",
157 "pricing.features.customWebsites": "Pridať vlastnú webstránku",
158 "pricing.features.desktopNotifications": "Upozornenie na ploche",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Proxy servery",
162 "pricing.features.spellchecker": "Podpora kontroly pravopisu",
163 "pricing.features.teamManagement": "Manažment tímu",
164 "pricing.features.thirdPartyServices": "Inštalovať inú službu",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Pracovný priestor",
167 "service.crashHandler.action": "Znovu naÄítaÅ¥ {name}", 155 "service.crashHandler.action": "Znovu naÄítaÅ¥ {name}",
168 "service.crashHandler.autoReload": "Najbližší pokus o automatické obnovenie {name} o {seconds} sekúnd", 156 "service.crashHandler.autoReload": "Najbližší pokus o automatické obnovenie {name} o {seconds} sekúnd",
169 "service.crashHandler.headline": "Ale nie!", 157 "service.crashHandler.headline": "Ale nie!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Vítajte v aplikácii Ferdi", 171 "services.welcome": "Vítajte v aplikácii Ferdi",
184 "settings.account.account.editButton": "UpraviÅ¥ úÄet", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Aktualizovať profil", 175 "settings.account.buttonSave": "Aktualizovať profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Bol vám odoslaný e-mail s odkazom pre potvrdenie odstránenia vášho úÄtu. Váš úÄet a údaje sa nebudú daÅ¥ obnoviÅ¥!", 177 "settings.account.deleteEmailSent": "Bol vám odoslaný e-mail s odkazom pre potvrdenie odstránenia vášho úÄtu. Váš úÄet a údaje sa nebudú daÅ¥ obnoviÅ¥!",
190 "settings.account.deleteInfo": "Ak už nepotrebujete váš Ferdi úÄet, tu ho môžete zmazaÅ¥ spolu so vÅ¡etkými prislúchajúcimi údajmi.", 178 "settings.account.deleteInfo": "Ak už nepotrebujete váš Ferdi úÄet, tu ho môžete zmazaÅ¥ spolu so vÅ¡etkými prislúchajúcimi údajmi.",
191 "settings.account.headline": "ÚÄet", 179 "settings.account.headline": "ÚÄet",
192 "settings.account.headlineAccount": "Informácie o úÄte", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "NebezpeÄná zóna", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Faktúry", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Zmeniť heslo", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Aktualizovať profil", 184 "settings.account.headlineProfile": "Aktualizovať profil",
197 "settings.account.successInfo": "Vaše zmeny boli uložené", 185 "settings.account.successInfo": "Vaše zmeny boli uložené",
198 "settings.account.tryReloadServices": "Skúsiť znova", 186 "settings.account.tryReloadServices": "Skúsiť znova",
199 "settings.account.tryReloadUserInfoRequest": "Skúsiť znova", 187 "settings.account.tryReloadUserInfoRequest": "Skúsiť znova",
200 "settings.account.userInfoRequestFailed": "Nebolo možné naÄítaÅ¥ informácie o používateľovi", 188 "settings.account.userInfoRequestFailed": "Nebolo možné naÄítaÅ¥ informácie o používateľovi",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "VyÄistiÅ¥ vyrovnávaciu pamäť", 191 "settings.app.buttonClearAllCache": "VyÄistiÅ¥ vyrovnávaciu pamäť",
204 "settings.app.buttonInstallUpdate": "Reštartovať a nainštalovať aktualizáciu", 192 "settings.app.buttonInstallUpdate": "Reštartovať a nainštalovať aktualizáciu",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Zapnúť Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Zapnúť GPU zrýchlenie", 212 "settings.app.form.enableGPUAcceleration": "Zapnúť GPU zrýchlenie",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Zapnúť kontrolu pravopisu", 215 "settings.app.form.enableSpellchecking": "Zapnúť kontrolu pravopisu",
228 "settings.app.form.enableSystemTray": "Zobrazovať Ferdi v systémovej lište", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Zobraziť záložky vypnutých služieb", 239 "settings.app.form.showDisabledServices": "Zobraziť záložky vypnutých služieb",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "ZobraziÅ¥ symbol pre nepreÄítané správy, keÄ sú vypnuté upozornenia", 241 "settings.app.form.showMessagesBadgesWhenMuted": "ZobraziÅ¥ symbol pre nepreÄítané správy, keÄ sú vypnuté upozornenia",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -296,7 +285,7 @@
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Developer Documentation", 287 "settings.recipes.customService.openDevDocs": "Developer Documentation",
299 "settings.recipes.customService.openFolder": "OtvoriÅ¥ prieÄinok", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Dostupné služby", 289 "settings.recipes.headline": "Dostupné služby",
301 "settings.recipes.missingService": "Chýba vám služba?", 290 "settings.recipes.missingService": "Chýba vám služba?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Odstrániť službu", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Upraviť {name}", 305 "settings.service.form.editServiceHeadline": "Upraviť {name}",
317 "settings.service.form.enableAudio": "Zapnúť zvuk", 306 "settings.service.form.enableAudio": "Zapnúť zvuk",
318 "settings.service.form.enableBadge": "ZobraziÅ¥ symboly nepreÄítaných správ", 307 "settings.service.form.enableBadge": "ZobraziÅ¥ symboly nepreÄítaných správ",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Ak je vypnuté, všetky zvuky oznámení a iné prehrávania budú stíšené", 322 "settings.service.form.isMutedInfo": "Ak je vypnuté, všetky zvuky oznámení a iné prehrávania budú stíšené",
334 "settings.service.form.name": "Meno", 323 "settings.service.form.name": "Meno",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Nastavenia servera proxy sa nebudú synchronizovať so servermi Ferdi.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Použiť Proxy", 331 "settings.service.form.proxy.isEnabled": "Použiť Proxy",
342 "settings.service.form.proxy.password": "Heslo (voliteľné)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Po zmene nastavení servera proxy reštartujte Ferdi.", 334 "settings.service.form.proxy.restartInfo": "Po zmene nastavení servera proxy reštartujte Ferdi.",
345 "settings.service.form.proxy.user": "Používateľ (voliteľné)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Uložiť službu", 337 "settings.service.form.saveButton": "Uložiť službu",
348 "settings.service.form.tabHosted": "Hostované", 338 "settings.service.form.tabHosted": "Hostované",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Preskúmať služby", 344 "settings.services.discoverServices": "Preskúmať služby",
355 "settings.services.headline": "Vaše služby", 345 "settings.services.headline": "Vaše služby",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Nepodarilo sa naÄítaÅ¥ vaÅ¡e služby", 348 "settings.services.servicesRequestFailed": "Nepodarilo sa naÄítaÅ¥ vaÅ¡e služby",
358 "settings.services.tooltip.isDisabled": "Služba je vypnutá", 349 "settings.services.tooltip.isDisabled": "Služba je vypnutá",
359 "settings.services.tooltip.isMuted": "Všetky zvuky sú stíšené", 350 "settings.services.tooltip.isMuted": "Všetky zvuky sú stíšené",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Nezisková organizácia", 378 "settings.user.form.accountType.non-profit": "Nezisková organizácia",
388 "settings.user.form.currentPassword": "SúÄasné heslo", 379 "settings.user.form.currentPassword": "SúÄasné heslo",
389 "settings.user.form.email": "E-mail", 380 "settings.user.form.email": "E-mail",
390 "settings.user.form.firstname": "Krstné meno", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Priezvisko", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nové heslo", 383 "settings.user.form.newPassword": "Nové heslo",
393 "settings.workspace.add.form.name": "Meno", 384 "settings.workspace.add.form.name": "Meno",
394 "settings.workspace.add.form.submitButton": "Vytvoriť pracovný priestor", 385 "settings.workspace.add.form.submitButton": "Vytvoriť pracovný priestor",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Skúsiť znova", 396 "settings.workspaces.tryReloadWorkspaces": "Skúsiť znova",
406 "settings.workspaces.updatedInfo": "Vaše zmeny boli uložené", 397 "settings.workspaces.updatedInfo": "Vaše zmeny boli uložené",
407 "settings.workspaces.workspaceFeatureHeadline": "Menej je viac: Predstavenie Ferdi Pracovné priestory", 398 "settings.workspaces.workspaceFeatureHeadline": "Menej je viac: Predstavenie Ferdi Pracovné priestory",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspace vám umožňujú sústrediÅ¥ sa na to, Äo je práve dôležité. Nastavte si rozliÄné skupiny služieb a jednoducho medzi nimi kedykoľvek prepínajte. Vy rozhodujete ktoré služby, kedy a kde potrebujete, a my vám potom vieme pomôcÅ¥ sústrediÅ¥ sa na prácu - alebo jednoducho prepnúť z práce na Äokoľvek iné.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Nebolo možné naÄítaÅ¥ vaÅ¡e workspace", 400 "settings.workspaces.workspacesRequestFailed": "Nebolo možné naÄítaÅ¥ vaÅ¡e workspace",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Povoliť oznámenia a zvuky", 411 "sidebar.unmuteApp": "Povoliť oznámenia a zvuky",
421 "signup.email.label": "E-mailová adresa", 412 "signup.email.label": "E-mailová adresa",
422 "signup.emailDuplicate": "Používateľ s touto e-mailovou adresou už jestvuje", 413 "signup.emailDuplicate": "Používateľ s touto e-mailovou adresou už jestvuje",
423 "signup.firstname.label": "Krstné meno", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Prihlásiť sa", 415 "signup.headline": "Prihlásiť sa",
425 "signup.lastname.label": "Priezvisko", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Vytvorením úÄtu Ferdi súhlasíte s", 417 "signup.legal.info": "Vytvorením úÄtu Ferdi súhlasíte s",
427 "signup.legal.privacy": "Vyhlásenie o ochrane súkromia", 418 "signup.legal.privacy": "Vyhlásenie o ochrane súkromia",
428 "signup.legal.terms": "Podmienky služby", 419 "signup.legal.terms": "Podmienky služby",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Heslo", 421 "signup.password.label": "Heslo",
431 "signup.submit.label": "VytvoriÅ¥ úÄet", 422 "signup.submit.label": "VytvoriÅ¥ úÄet",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Odstrániť službu", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Vypnúť zvuk", 425 "tabs.item.disableAudio": "Vypnúť zvuk",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Zakázať oznámenia", 427 "tabs.item.disableNotifications": "Zakázať oznámenia",
437 "tabs.item.disableService": "Vypnúť službu", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Zapnúť zvuk", 429 "tabs.item.enableAudio": "Zapnúť zvuk",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Povoliť oznámenia", 431 "tabs.item.enableNotification": "Povoliť oznámenia",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Obnoviť", 434 "tabs.item.reload": "Obnoviť",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} je neplatný", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} by malo byť dlhé aspoň {length} znakov", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Je nutné zadať aspoň jeden", 438 "validation.oneRequired": "Je nutné zadať aspoň jeden",
448 "validation.required": "{field} je povinné", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} nie je platné URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Naspäť", 441 "webControls.back": "Naspäť",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Úvod", 443 "webControls.goHome": "Úvod",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Obnoviť", 445 "webControls.reload": "Obnoviť",
455 "welcome.loginButton": "PrihlásiÅ¥ sa do vášho úÄtu", 446 "welcome.loginButton": "PrihlásiÅ¥ sa do vášho úÄtu",
456 "welcome.signupButton": "VytvoriÅ¥ používateľský úÄet zdarma", 447 "welcome.signupButton": "VytvoriÅ¥ používateľský úÄet zdarma",
457 "workspaceDrawer.addNewWorkspaceLabel": "Pridať nový workspace", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Všetky služby", 449 "workspaceDrawer.allServices": "Všetky služby",
459 "workspaceDrawer.headline": "Pracovný priestor", 450 "workspaceDrawer.headline": "Pracovný priestor",
460 "workspaceDrawer.item.contextMenuEdit": "Upraviť", 451 "workspaceDrawer.item.contextMenuEdit": "Upraviť",
461 "workspaceDrawer.item.noServicesAddedYet": "Zatiaľ žiadne služby", 452 "workspaceDrawer.item.noServicesAddedYet": "Zatiaľ žiadne služby",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspace vám umožňujú sústrediÅ¥ sa na to, Äo je práve dôležité. Nastavte si rozliÄné skupiny služieb a jednoducho medzi nimi kedykoľvek prepínajte.</p><p>Vy rozhodujete ktoré služby, kedy a kde potrebujete, a my vám potom vieme pomôcÅ¥ sústrediÅ¥ sa na prácu - alebo jednoducho prepnúť z práce na Äokoľvek iné. </p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Upraviť nastavenia workspace", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Prepínanie na" 455 "workspaces.switchingIndicator.switchingTo": "Prepínanie na"
465} 456}
diff --git a/src/i18n/locales/sl.json b/src/i18n/locales/sl.json
index 2c145d6f4..041b02632 100644
--- a/src/i18n/locales/sl.json
+++ b/src/i18n/locales/sl.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/sr.json b/src/i18n/locales/sr.json
index 8ee9417f6..85068ee5c 100644
--- a/src/i18n/locales/sr.json
+++ b/src/i18n/locales/sr.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Ponovno uÄitavanje", 2 "app.errorHandler.action": "Ponovno uÄitavanje",
3 "app.errorHandler.headline": "Дошло је до грешке", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Prilagođen server", 4 "changeserver.customServerLabel": "Prilagođen server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Сервер", 6 "changeserver.label": "Сервер",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Шта Ñе деÑило?", 10 "connectionLostBanner.informationLink": "Шта Ñе деÑило?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Ðктивирај", 13 "feature.nightlyBuilds.activate": "Ðктивирај",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "Search...", 24 "feature.quickSwitch.search": "Search...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Nije moguće pristupiti Ferdi-ovim on-line servisima. ", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Odustani", 27 "global.cancel": "Cancel",
29 "global.edit": "Uredi", 28 "global.edit": "Uredi",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Niste povezani sa serverom.", 30 "global.notConnectedToTheInternet": "Niste povezani sa serverom.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Postavke", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Use System Default ({default})", 36 "global.spellchecker.useDefault": "Use System Default ({default})",
38 "global.spellchecking.autodetect": "Detect language automatically", 37 "global.spellchecking.autodetect": "Detect language automatically",
39 "global.spellchecking.autodetect.short": "ÐутоматÑки", 38 "global.spellchecking.autodetect.short": "ÐутоматÑки",
40 "global.spellchecking.language": "Spell checking language", 39 "global.spellchecking.language": "Spell checking language",
41 "global.submit": "Pošalji", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Uvezite svoje Ferdi 4 servise", 44 "import.headline": "Uvezite svoje Ferdi 4 servise",
46 "import.notSupportedHeadline": "Servis trenutno nije podržan u Ferdi 5", 45 "import.notSupportedHeadline": "Servis trenutno nije podržan u Ferdi 5",
47 "import.skip.label": "Желим да додам уÑлуге ручно", 46 "import.skip.label": "Желим да додам уÑлуге ручно",
48 "import.submit.label": "Uvezi servise", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Å ta je novo? ", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje ", 50 "infobar.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje ",
52 "infobar.buttonReloadServices": "Ponovo uÄitaj servise ", 51 "infobar.buttonReloadServices": "Ponovo uÄitaj servise ",
53 "infobar.hide": "Sakrij", 52 "infobar.hide": "Sakrij",
@@ -75,7 +74,7 @@
75 "login.email.label": "Vaša e-adresa", 74 "login.email.label": "Vaša e-adresa",
76 "login.headline": "Prijavite se", 75 "login.headline": "Prijavite se",
77 "login.invalidCredentials": "E-mail ili lozinka nisu toÄni", 76 "login.invalidCredentials": "E-mail ili lozinka nisu toÄni",
78 "login.link.password": "Stvaranje nove lozinke", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Stvorite besplatan raÄun", 78 "login.link.signup": "Stvorite besplatan raÄun",
80 "login.password.label": "Лозинка", 79 "login.password.label": "Лозинка",
81 "login.serverLogout": "Vaša sesija je istekla, prijavite se ponovo.", 80 "login.serverLogout": "Vaša sesija je istekla, prijavite se ponovo.",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "УÑлови коришћења уÑлуге", 117 "menu.help.tos": "УÑлови коришћења уÑлуге",
119 "menu.services": "Usluge", 118 "menu.services": "Usluge",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Sve usluge", 147 "menu.workspaces.defaultWorkspace": "Sve usluge",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "Vaša e-adresa", 149 "password.email.label": "Vaša e-adresa",
151 "password.headline": "Stvaranje nove lozinke", 150 "password.headline": "Reset password",
152 "password.link.login": "Prijavite se na VaÅ¡ raÄun", 151 "password.link.login": "Prijavite se na VaÅ¡ raÄun",
153 "password.link.signup": "Stvorite besplatan raÄun", 152 "password.link.signup": "Stvorite besplatan raÄun",
154 "password.noUser": "Ne postoji ni jedan korisnik s tom e-mail adresom", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Molimo Vas da provjerite vašu e-mail adresu", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Osvježi {name}", 155 "service.crashHandler.action": "Osvježi {name}",
168 "service.crashHandler.autoReload": "Pokušaću automatski povratiti {name} u {seconds} sekundi", 156 "service.crashHandler.autoReload": "Pokušaću automatski povratiti {name} u {seconds} sekundi",
169 "service.crashHandler.headline": "O, ne! ", 157 "service.crashHandler.headline": "O, ne! ",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "Dobrodošli u Ferdi", 171 "services.welcome": "Dobrodošli u Ferdi",
184 "settings.account.account.editButton": "Uredi raÄun", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Account is unavailable", 173 "settings.account.accountUnavailable": "Account is unavailable",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Ažuriraj profil", 175 "settings.account.buttonSave": "Ažuriraj profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Добили Ñте имејл Ñа линком путем којег потврђујете бриÑање Ñвог налога. Ваш налог и подаци не могу бити повраћени!", 177 "settings.account.deleteEmailSent": "Добили Ñте имејл Ñа линком путем којег потврђујете бриÑање Ñвог налога. Ваш налог и подаци не могу бити повраћени!",
190 "settings.account.deleteInfo": "Уколико Вам више није потребан Франз налог, овде можете обриÑати Ñвој налог и Ñве податке везане за иÑти.", 178 "settings.account.deleteInfo": "Уколико Вам више није потребан Франз налог, овде можете обриÑати Ñвој налог и Ñве податке везане за иÑти.",
191 "settings.account.headline": "KorisniÄki nalog", 179 "settings.account.headline": "KorisniÄki nalog",
192 "settings.account.headlineAccount": "Podaci o nalogu", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Зона опреза", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Fakture", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Promijenite lozinku", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Ažuriraj profil", 184 "settings.account.headlineProfile": "Ažuriraj profil",
197 "settings.account.successInfo": "Vaše promjene su spremljene", 185 "settings.account.successInfo": "Vaše promjene su spremljene",
198 "settings.account.tryReloadServices": "Pokušajte ponovno", 186 "settings.account.tryReloadServices": "Pokušajte ponovno",
199 "settings.account.tryReloadUserInfoRequest": "Pokušajte ponovno", 187 "settings.account.tryReloadUserInfoRequest": "Pokušajte ponovno",
200 "settings.account.userInfoRequestFailed": "Nije moguće uÄitati informacije o korisniku", 188 "settings.account.userInfoRequestFailed": "Nije moguće uÄitati informacije o korisniku",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "ОчиÑти кеш", 191 "settings.app.buttonClearAllCache": "ОчиÑти кеш",
204 "settings.app.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje ", 192 "settings.app.buttonInstallUpdate": "Ponovo pokreni i instaliraj ažuriranje ",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Омогући убрзање графичке јединице", 212 "settings.app.form.enableGPUAcceleration": "Омогући убрзање графичке јединице",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Omogući provjeru pravopisa", 215 "settings.app.form.enableSpellchecking": "Omogući provjeru pravopisa",
228 "settings.app.form.enableSystemTray": "Prikaži aplikaciju u sustavskoj traci", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Prikaži ploÄe s onemogućenim servisima", 239 "settings.app.form.showDisabledServices": "Prikaži ploÄe s onemogućenim servisima",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Покажи беџ за непрочитане поруке када Ñу обавештења онемогућена", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Покажи беџ за непрочитане поруке када Ñу обавештења онемогућена",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Izbriši uslugu", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Uredite {name}", 305 "settings.service.form.editServiceHeadline": "Uredite {name}",
317 "settings.service.form.enableAudio": "Omogućite zvuk", 306 "settings.service.form.enableAudio": "Omogućite zvuk",
318 "settings.service.form.enableBadge": "Покажи беџеве за непрочитане поруке", 307 "settings.service.form.enableBadge": "Покажи беџеве за непрочитане поруке",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Kada je onemogućeno, sve obavijesti, svi zvukovi i sva pozadinska podrÅ¡ka će biti neÄujna.", 322 "settings.service.form.isMutedInfo": "Kada je onemogućeno, sve obavijesti, svi zvukovi i sva pozadinska podrÅ¡ka će biti neÄujna.",
334 "settings.service.form.name": "Ime", 323 "settings.service.form.name": "Ime",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Pronađite usluge", 344 "settings.services.discoverServices": "Pronađite usluge",
355 "settings.services.headline": "Vaše usluge", 345 "settings.services.headline": "Vaše usluge",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Usluga je onemogućena.", 349 "settings.services.tooltip.isDisabled": "Usluga je onemogućena.",
359 "settings.services.tooltip.isMuted": "Svi zvukovi su onemogućeni.", 350 "settings.services.tooltip.isMuted": "Svi zvukovi su onemogućeni.",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Neprofitno", 378 "settings.user.form.accountType.non-profit": "Neprofitno",
388 "settings.user.form.currentPassword": "Trenutna lozinka", 379 "settings.user.form.currentPassword": "Trenutna lozinka",
389 "settings.user.form.email": "E-pošta", 380 "settings.user.form.email": "E-pošta",
390 "settings.user.form.firstname": "Ime", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Prezime", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nova lozinka", 383 "settings.user.form.newPassword": "Nova lozinka",
393 "settings.workspace.add.form.name": "Ime", 384 "settings.workspace.add.form.name": "Ime",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "ИÑкључи обавештења и звукове", 411 "sidebar.unmuteApp": "ИÑкључи обавештења и звукове",
421 "signup.email.label": "Vaša e-adresa", 412 "signup.email.label": "Vaša e-adresa",
422 "signup.emailDuplicate": "Već postoji korisnik s tom e-mail adresom", 413 "signup.emailDuplicate": "Već postoji korisnik s tom e-mail adresom",
423 "signup.firstname.label": "Ime", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Prijava", 415 "signup.headline": "Prijava",
425 "signup.lastname.label": "Prezime", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Prilikom stvaranja Ferdi raÄuna, slažete se sa sljedećim stavkama", 417 "signup.legal.info": "Prilikom stvaranja Ferdi raÄuna, slažete se sa sljedećim stavkama",
427 "signup.legal.privacy": "Izjava o privatnosti", 418 "signup.legal.privacy": "Izjava o privatnosti",
428 "signup.legal.terms": "Uvjeti korištenja", 419 "signup.legal.terms": "Uvjeti korištenja",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Лозинка", 421 "signup.password.label": "Лозинка",
431 "signup.submit.label": "Napravite novi raÄun", 422 "signup.submit.label": "Napravite novi raÄun",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Izbriši uslugu", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Onemogući zvuk", 425 "tabs.item.disableAudio": "Onemogući zvuk",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Onemogući obavijesti", 427 "tabs.item.disableNotifications": "Onemogući obavijesti",
437 "tabs.item.disableService": "Onemogući servis", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Omogućite zvuk", 429 "tabs.item.enableAudio": "Omogućite zvuk",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Omogućite obavijesti", 431 "tabs.item.enableNotification": "Omogućite obavijesti",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Ponovno uÄitavanje", 434 "tabs.item.reload": "Ponovno uÄitavanje",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} није валидно", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} треба да буде најмање {length} карактера дугачко", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} је неопходно", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} није валидан УРЛ", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Back", 441 "webControls.back": "Back",
451 "webControls.forward": "Forward", 442 "webControls.forward": "Forward",
452 "webControls.goHome": "Home", 443 "webControls.goHome": "Home",
diff --git a/src/i18n/locales/sv.json b/src/i18n/locales/sv.json
index 87b92e398..ef254fc5d 100644
--- a/src/i18n/locales/sv.json
+++ b/src/i18n/locales/sv.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Ladda om", 2 "app.errorHandler.action": "Ladda om",
3 "app.errorHandler.headline": "NÃ¥gonting gick snett", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Anpassad server", 4 "changeserver.customServerLabel": "Anpassad server",
5 "changeserver.headline": "Byt server", 5 "changeserver.headline": "Byt server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Vad hände?", 10 "connectionLostBanner.informationLink": "Vad hände?",
11 "connectionLostBanner.message": "Åh nej! Ferdi förlorade anslutningen till {name}.", 11 "connectionLostBanner.message": "Åh nej! Ferdi förlorade anslutningen till {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Skicka felsökningsinformation",
14 "feature.nightlyBuilds.activate": "Aktivera", 13 "feature.nightlyBuilds.activate": "Aktivera",
15 "feature.nightlyBuilds.info": "Nattliga kompileringar är väldigt experimentella versioner av Ferdi som kan innehålla ofärdiga och ännu ej testade funktioner. Nattliga kompilering är i första hand tänkt för utvecklare för att kunna testa hur nya funktioner fungerar och presterar. Är du osäker på vad detta innebär rekommenderas du att inte aktivera nattliga kompileringar.", 14 "feature.nightlyBuilds.info": "Nattliga kompileringar är väldigt experimentella versioner av Ferdi som kan innehålla ofärdiga och ännu ej testade funktioner. Nattliga kompilering är i första hand tänkt för utvecklare för att kunna testa hur nya funktioner fungerar och presterar. Är du osäker på vad detta innebär rekommenderas du att inte aktivera nattliga kompileringar.",
16 "feature.nightlyBuilds.title": "Nattlig kompilering", 15 "feature.nightlyBuilds.title": "Nattlig kompilering",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Välj en tjänst med TAB, ↑ and ↓. Öppna en tjänst med ENTER.", 23 "feature.quickSwitch.info": "Välj en tjänst med TAB, ↑ and ↓. Öppna en tjänst med ENTER.",
25 "feature.quickSwitch.search": "Sök...", 24 "feature.quickSwitch.search": "Sök...",
26 "feature.quickSwitch.title": "Snabbväxling", 25 "feature.quickSwitch.title": "Snabbväxling",
27 "global.api.unhealthy": "Kan inte ansluta till Ferdis onlinetjänster", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Avbryt", 27 "global.cancel": "Cancel",
29 "global.edit": "Redigera", 28 "global.edit": "Redigera",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Du är inte ansluten till Internet.", 30 "global.notConnectedToTheInternet": "Du är inte ansluten till Internet.",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Inställningar", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Använd systemstandard ({default})", 36 "global.spellchecker.useDefault": "Använd systemstandard ({default})",
38 "global.spellchecking.autodetect": "Identifiera språk automatiskt", 37 "global.spellchecking.autodetect": "Identifiera språk automatiskt",
39 "global.spellchecking.autodetect.short": "Automatisk", 38 "global.spellchecking.autodetect.short": "Automatisk",
40 "global.spellchecking.language": "Rättstavningsspråk", 39 "global.spellchecking.language": "Rättstavningsspråk",
41 "global.submit": "Skicka", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Importera dina Ferdi 4-tjänster", 44 "import.headline": "Importera dina Ferdi 4-tjänster",
46 "import.notSupportedHeadline": "Tjänster som ännu inte stöds i Ferdi 5", 45 "import.notSupportedHeadline": "Tjänster som ännu inte stöds i Ferdi 5",
47 "import.skip.label": "Jag vill lägga till tjänster manuellt", 46 "import.skip.label": "Jag vill lägga till tjänster manuellt",
48 "import.submit.label": "Importera tjänster", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Det uppstod fel vid försök då en autentiserad begäran utfördes. Prova att logga ut och in igen om felet kvarstår.", 48 "infobar.authRequestFailed": "Det uppstod fel vid försök då en autentiserad begäran utfördes. Prova att logga ut och in igen om felet kvarstår.",
50 "infobar.buttonChangelog": "Vad nytt har hänt?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Starta om & installera uppdatering", 50 "infobar.buttonInstallUpdate": "Starta om & installera uppdatering",
52 "infobar.buttonReloadServices": "Ladda om tjänster", 51 "infobar.buttonReloadServices": "Ladda om tjänster",
53 "infobar.hide": "Dölj", 52 "infobar.hide": "Dölj",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-postadress", 74 "login.email.label": "E-postadress",
76 "login.headline": "Logga in", 75 "login.headline": "Logga in",
77 "login.invalidCredentials": "E-post eller lösenord är felaktigt", 76 "login.invalidCredentials": "E-post eller lösenord är felaktigt",
78 "login.link.password": "Återställ lösenord", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Skapa ett gratis konto", 78 "login.link.signup": "Skapa ett gratis konto",
80 "login.password.label": "Lösenord", 79 "login.password.label": "Lösenord",
81 "login.serverLogout": "Din session har gått ut. Vänligen logga in på nytt.", 80 "login.serverLogout": "Din session har gått ut. Vänligen logga in på nytt.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Support", 116 "menu.help.support": "Support",
118 "menu.help.tos": "Användarvillkor", 117 "menu.help.tos": "Användarvillkor",
119 "menu.services": "Tjänster", 118 "menu.services": "Tjänster",
120 "menu.services.activatePreviousService": "Aktivera föregående tjänst", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Lägg till ny tjänst", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Hem", 121 "menu.services.goHome": "Hem",
123 "menu.services.setNextServiceActive": "Aktivera nästa tjänst", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
125 "menu.todos.enableTodos": "Aktivera Todos", 124 "menu.todos.enableTodos": "Aktivera Todos",
126 "menu.view": "Visa", 125 "menu.view": "Visa",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Alla tjänster", 147 "menu.workspaces.defaultWorkspace": "Alla tjänster",
149 "menu.workspaces.openWorkspaceDrawer": "Öppna arbetsytan", 148 "menu.workspaces.openWorkspaceDrawer": "Öppna arbetsytan",
150 "password.email.label": "E-postadress", 149 "password.email.label": "E-postadress",
151 "password.headline": "Återställ lösenord", 150 "password.headline": "Reset password",
152 "password.link.login": "Logga in på ditt konto", 151 "password.link.login": "Logga in på ditt konto",
153 "password.link.signup": "Skapa ett gratis konto", 152 "password.link.signup": "Skapa ett gratis konto",
154 "password.noUser": "Ingen användare med den e-postadressen hittades", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Vänligen kontrollera din e-post", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Synkronisering av konto",
157 "pricing.features.customWebsites": "Lägg till egna webbplatser",
158 "pricing.features.desktopNotifications": "Skrivbordsaviseringar",
159 "pricing.features.onPremise": "Lokala tjänster och andra värdtjänster",
160 "pricing.features.recipes": "Välj mellan fler än 70 tjänster",
161 "pricing.features.serviceProxies": "Tjänstens proxies",
162 "pricing.features.spellchecker": "Stöd för stavningskontroll",
163 "pricing.features.teamManagement": "Hantera grupp",
164 "pricing.features.thirdPartyServices": "Installera tjänster från tredje part",
165 "pricing.features.unlimitedServices": "Lägg till obegränsat antal tjänster",
166 "pricing.features.workspaces": "Arbetsytor",
167 "service.crashHandler.action": "Ladda om {name}", 155 "service.crashHandler.action": "Ladda om {name}",
168 "service.crashHandler.autoReload": "Försöker automatiskt återställa {name} om {seconds} sekunder", 156 "service.crashHandler.autoReload": "Försöker automatiskt återställa {name} om {seconds} sekunder",
169 "service.crashHandler.headline": "Ã…h nej!", 157 "service.crashHandler.headline": "Ã…h nej!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Använd Ferdi utan ett konto", 170 "services.serverless": "Använd Ferdi utan ett konto",
183 "services.welcome": "Välkommen till Ferdi", 171 "services.welcome": "Välkommen till Ferdi",
184 "settings.account.account.editButton": "Redigera konto", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Kontot är inte tillgängligt", 173 "settings.account.accountUnavailable": "Kontot är inte tillgängligt",
186 "settings.account.accountUnavailableInfo": "Du använder Ferdi utan ett konto. Om du vill använda Ferdi med ett konto och hålla dina tjänster synkroniserade mellan installationer, välj en server i fliken Inställningar och logga in.", 174 "settings.account.accountUnavailableInfo": "Du använder Ferdi utan ett konto. Om du vill använda Ferdi med ett konto och hålla dina tjänster synkroniserade mellan installationer, välj en server i fliken Inställningar och logga in.",
187 "settings.account.buttonSave": "Uppdatera profil", 175 "settings.account.buttonSave": "Uppdatera profil",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Du har fått ett e-postmeddelande med en länk för att bekräfta raderingen av ditt konto. Ditt konto och data kan inte återställas!", 177 "settings.account.deleteEmailSent": "Du har fått ett e-postmeddelande med en länk för att bekräfta raderingen av ditt konto. Ditt konto och data kan inte återställas!",
190 "settings.account.deleteInfo": "Om du inte behöver ditt Ferdi-konto längre, kan du ta bort ditt konto och all anknuten information här.", 178 "settings.account.deleteInfo": "Om du inte behöver ditt Ferdi-konto längre, kan du ta bort ditt konto och all anknuten information här.",
191 "settings.account.headline": "Konto", 179 "settings.account.headline": "Konto",
192 "settings.account.headlineAccount": "Kontoinformation", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Högrisksområde", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Fakturor", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Ändra lösenord", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Uppdatera profil", 184 "settings.account.headlineProfile": "Uppdatera profil",
197 "settings.account.successInfo": "Dina ändringar har sparats", 185 "settings.account.successInfo": "Dina ändringar har sparats",
198 "settings.account.tryReloadServices": "Försök igen", 186 "settings.account.tryReloadServices": "Försök igen",
199 "settings.account.tryReloadUserInfoRequest": "Försök igen", 187 "settings.account.tryReloadUserInfoRequest": "Försök igen",
200 "settings.account.userInfoRequestFailed": "Kunde inte ladda användarinformation", 188 "settings.account.userInfoRequestFailed": "Kunde inte ladda användarinformation",
201 "settings.account.yourLicense": "Din Ferdi-licens", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Rensa cache", 191 "settings.app.buttonClearAllCache": "Rensa cache",
204 "settings.app.buttonInstallUpdate": "Starta om & installera uppdatering", 192 "settings.app.buttonInstallUpdate": "Starta om & installera uppdatering",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events", 207 "settings.app.form.clipboardNotifications": "Don't show notifications for clipboard events",
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Anpassad Todo-server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Aktivera mörkt läge", 211 "settings.app.form.darkMode": "Aktivera mörkt läge",
224 "settings.app.form.enableGPUAcceleration": "Aktivera GPU-hårdvaruacceleration", 212 "settings.app.form.enableGPUAcceleration": "Aktivera GPU-hårdvaruacceleration",
225 "settings.app.form.enableLock": "Aktivera lösenordslås", 213 "settings.app.form.enableLock": "Aktivera lösenordslås",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Aktivera stavningskontroll", 215 "settings.app.form.enableSpellchecking": "Aktivera stavningskontroll",
228 "settings.app.form.enableSystemTray": "Visa Ferdi i systemfältet", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Aktivera Ferdi Todos", 217 "settings.app.form.enableTodos": "Aktivera Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Strategi för vila", 219 "settings.app.form.hibernationStrategy": "Strategi för vila",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Visa flikar för inaktiverade tjänster", 239 "settings.app.form.showDisabledServices": "Visa flikar för inaktiverade tjänster",
252 "settings.app.form.showDragArea": "Visa dragbart område i fönstret", 240 "settings.app.form.showDragArea": "Visa dragbart område i fönstret",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Visa antal olästa meddelanden när aviseringar är inaktiverade", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Visa antal olästa meddelanden när aviseringar är inaktiverade",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Starta i minimerat läge", 243 "settings.app.form.startMinimized": "Starta i minimerat läge",
255 "settings.app.form.universalDarkMode": "Aktivera globalt mörkt läge", 244 "settings.app.form.universalDarkMode": "Aktivera globalt mörkt läge",
256 "settings.app.form.useTouchIdToUnlock": "Tillåt att TouchID används för att låsa upp Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Avancerat", 248 "settings.app.headlineAdvanced": "Avancerat",
@@ -267,7 +256,7 @@
267 "settings.app.languageDisclaimer": "Engelska och tyska är officella översättningar. Övriga språk har översatts av gemenskapen.", 256 "settings.app.languageDisclaimer": "Engelska och tyska är officella översättningar. Övriga språk har översatts av gemenskapen.",
268 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Lösenord", 258 "settings.app.lockedPassword": "Lösenord",
270 "settings.app.lockedPasswordInfo": "Se till att du anger ett lösenord du kommer att komma ihåg.\nOm du tappar bort detta lösenord måste du installera om Ferdi.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Ändringar kräver omstart", 260 "settings.app.restartRequired": "Ändringar kräver omstart",
272 "settings.app.scheduledDNDInfo": "Schemalagd \"Stör ej\" låter dig definiera en tidsperiod inom vilken du inte vill få meddelanden från Ferdi.", 261 "settings.app.scheduledDNDInfo": "Schemalagd \"Stör ej\" låter dig definiera en tidsperiod inom vilken du inte vill få meddelanden från Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Tid i 24-timmarsformat. Sluttid kan vara före starttid (t.ex. start 17:00, slut 09:00) för att aktivera \"Stör ej\" över natten.", 262 "settings.app.scheduledDNDTimeInfo": "Tid i 24-timmarsformat. Sluttid kan vara före starttid (t.ex. start 17:00, slut 09:00) för att aktivera \"Stör ej\" över natten.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi uses your Mac's build-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi uses your Mac's build-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.",
276 "settings.app.subheadlineCache": "Cache", 265 "settings.app.subheadlineCache": "Cache",
277 "settings.app.subheadlineFerdiProfile": "Ferdi Profile", 266 "settings.app.subheadlineFerdiProfile": "Ferdi Profile",
278 "settings.app.todoServerInfo": "Denna server kommer att användas för \"Ferdi Todo\"-funktionen.", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Hjälp oss att översätta Ferdi till ditt språk.", 268 "settings.app.translationHelp": "Hjälp oss att översätta Ferdi till ditt språk.",
280 "settings.app.universalDarkModeInfo": "Globalt mörkt läge försöker att dynamiskt generera en mörk stil för tjänster som ännu inte stöds.", 269 "settings.app.universalDarkModeInfo": "Globalt mörkt läge försöker att dynamiskt generera en mörk stil för tjänster som ännu inte stöds.",
281 "settings.app.updateStatusAvailable": "Uppdatering tillgänglig, laddar ner...", 270 "settings.app.updateStatusAvailable": "Uppdatering tillgänglig, laddar ner...",
@@ -294,9 +283,9 @@
294 "settings.recipes.customService.headline.communityRecipes": "Tredjepartsrecept från gemenskapen", 283 "settings.recipes.customService.headline.communityRecipes": "Tredjepartsrecept från gemenskapen",
295 "settings.recipes.customService.headline.customRecipes": "Egna tredjepartsrecept", 284 "settings.recipes.customService.headline.customRecipes": "Egna tredjepartsrecept",
296 "settings.recipes.customService.headline.devRecipes": "Dina recept för utvecklingsservice", 285 "settings.recipes.customService.headline.devRecipes": "Dina recept för utvecklingsservice",
297 "settings.recipes.customService.intro": "För att lägga till en anpassad tjänst, kopiera receptet för tjänsten till:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Dokumentation för utvecklare", 287 "settings.recipes.customService.openDevDocs": "Dokumentation för utvecklare",
299 "settings.recipes.customService.openFolder": "Öppna mapp", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Tillgängliga tjänster", 289 "settings.recipes.headline": "Tillgängliga tjänster",
301 "settings.recipes.missingService": "Saknar du en tjänst?", 290 "settings.recipes.missingService": "Saknar du en tjänst?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Ta bort tjänst", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Redigera {name}", 305 "settings.service.form.editServiceHeadline": "Redigera {name}",
317 "settings.service.form.enableAudio": "Aktivera ljud", 306 "settings.service.form.enableAudio": "Aktivera ljud",
318 "settings.service.form.enableBadge": "Visa olästa meddelandemärken", 307 "settings.service.form.enableBadge": "Visa olästa meddelandemärken",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Om inaktiverad kommer alla aviseringsljud och ljuduppspelning att tystas", 322 "settings.service.form.isMutedInfo": "Om inaktiverad kommer alla aviseringsljud och ljuduppspelning att tystas",
334 "settings.service.form.name": "Namn", 323 "settings.service.form.name": "Namn",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Öppna darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Öppna darkmode.css",
336 "settings.service.form.openUserCss": "Öppna user.css", 326 "settings.service.form.openUserCss": "Öppna user.css",
337 "settings.service.form.openUserJs": "Öppna user.js", 327 "settings.service.form.openUserJs": "Öppna user.js",
338 "settings.service.form.proxy.headline": "Inställningar för HTTP/HTTPS-proxy", 328 "settings.service.form.proxy.headline": "Inställningar för HTTP/HTTPS-proxy",
339 "settings.service.form.proxy.host": "Proxy-värd/IP", 329 "settings.service.form.proxy.host": "Proxy-värd/IP",
340 "settings.service.form.proxy.info": "Proxyinställningar kommer inte att synkroniseras med Ferdi-servrarna.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Använd proxy", 331 "settings.service.form.proxy.isEnabled": "Använd proxy",
342 "settings.service.form.proxy.password": "Lösenord (frivilligt)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Vänligen starta om Ferdi efter att du ändrat proxyinställningar.", 334 "settings.service.form.proxy.restartInfo": "Vänligen starta om Ferdi efter att du ändrat proxyinställningar.",
345 "settings.service.form.proxy.user": "Användare (valfritt)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Dina användarfiler kommer att infogas i webbsidan så att du kan anpassa tjänsterna hur du vill. Användarfiler lagras endast lokalt och överförs inte till andra datorer som använer samma konto.", 336 "settings.service.form.recipeFileInfo": "Dina användarfiler kommer att infogas i webbsidan så att du kan anpassa tjänsterna hur du vill. Användarfiler lagras endast lokalt och överförs inte till andra datorer som använer samma konto.",
347 "settings.service.form.saveButton": "Spara tjänst", 337 "settings.service.form.saveButton": "Spara tjänst",
348 "settings.service.form.tabHosted": "Värd", 338 "settings.service.form.tabHosted": "Värd",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Upptäck tjänster", 344 "settings.services.discoverServices": "Upptäck tjänster",
355 "settings.services.headline": "Dina tjänster", 345 "settings.services.headline": "Dina tjänster",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Kunde inte ladda dina tjänster", 348 "settings.services.servicesRequestFailed": "Kunde inte ladda dina tjänster",
358 "settings.services.tooltip.isDisabled": "Tjänsten är inaktiverad", 349 "settings.services.tooltip.isDisabled": "Tjänsten är inaktiverad",
359 "settings.services.tooltip.isMuted": "Alla ljud är avstängda", 350 "settings.services.tooltip.isMuted": "Alla ljud är avstängda",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Ideell organisation", 378 "settings.user.form.accountType.non-profit": "Ideell organisation",
388 "settings.user.form.currentPassword": "Nuvarande lösenord", 379 "settings.user.form.currentPassword": "Nuvarande lösenord",
389 "settings.user.form.email": "E-post", 380 "settings.user.form.email": "E-post",
390 "settings.user.form.firstname": "Förnamn", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Efternamn", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Nytt lösenord", 383 "settings.user.form.newPassword": "Nytt lösenord",
393 "settings.workspace.add.form.name": "Namn", 384 "settings.workspace.add.form.name": "Namn",
394 "settings.workspace.add.form.submitButton": "Skapa arbetsyta", 385 "settings.workspace.add.form.submitButton": "Skapa arbetsyta",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Försök igen", 396 "settings.workspaces.tryReloadWorkspaces": "Försök igen",
406 "settings.workspaces.updatedInfo": "Dina ändringar har sparats", 397 "settings.workspaces.updatedInfo": "Dina ändringar har sparats",
407 "settings.workspaces.workspaceFeatureHeadline": "\"Less is more\": Vi presenterar Ferdi-arbetsytor", 398 "settings.workspaces.workspaceFeatureHeadline": "\"Less is more\": Vi presenterar Ferdi-arbetsytor",
408 "settings.workspaces.workspaceFeatureInfo": "Ferdi-arbetsytor låter dig fokusera på det som är viktigt just nu. Konfigurera olika uppsättningar av tjänster och växla enkelt mellan dem när som helst. Du bestämmer vilka tjänster du behöver när och var, så att vi kan hjälpa dig att hålla koll på läget - eller enkelt koppla bort från jobbet när du vill.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Kunde inte ladda dina arbetsytor", 400 "settings.workspaces.workspacesRequestFailed": "Kunde inte ladda dina arbetsytor",
410 "setupAssistant.headline": "Let's get started", 401 "setupAssistant.headline": "Let's get started",
411 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.", 402 "setupAssistant.subheadline": "Choose from our most used services and get back on top of your messaging now.",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Aktivera aviseringar och ljud", 411 "sidebar.unmuteApp": "Aktivera aviseringar och ljud",
421 "signup.email.label": "E-postadress", 412 "signup.email.label": "E-postadress",
422 "signup.emailDuplicate": "En användare med den e-postadressen finns redan", 413 "signup.emailDuplicate": "En användare med den e-postadressen finns redan",
423 "signup.firstname.label": "Förnamn", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Registrera dig", 415 "signup.headline": "Registrera dig",
425 "signup.lastname.label": "Efternamn", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Genom att skapa ett Ferdi konto accepterar du", 417 "signup.legal.info": "Genom att skapa ett Ferdi konto accepterar du",
427 "signup.legal.privacy": "Integritetspolicy", 418 "signup.legal.privacy": "Integritetspolicy",
428 "signup.legal.terms": "Användarvillkor", 419 "signup.legal.terms": "Användarvillkor",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Lösenord", 421 "signup.password.label": "Lösenord",
431 "signup.submit.label": "Skapa konto", 422 "signup.submit.label": "Skapa konto",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Ta bort tjänst", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Inaktivera ljud", 425 "tabs.item.disableAudio": "Inaktivera ljud",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Inaktivera aviseringar", 427 "tabs.item.disableNotifications": "Inaktivera aviseringar",
437 "tabs.item.disableService": "Inaktivera tjänst", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Aktivera ljud", 429 "tabs.item.enableAudio": "Aktivera ljud",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Aktivera aviseringar", 431 "tabs.item.enableNotification": "Aktivera aviseringar",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Ladda om", 434 "tabs.item.reload": "Ladda om",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} är felaktig", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} bör vara minst {length} tecken lång", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Minst en krävs", 438 "validation.oneRequired": "Minst en krävs",
448 "validation.required": "{field} är obligatoriskt", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} är inte en giltig URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Tillbaka", 441 "webControls.back": "Tillbaka",
451 "webControls.forward": "Framåt", 442 "webControls.forward": "Framåt",
452 "webControls.goHome": "Hem", 443 "webControls.goHome": "Hem",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Ladda om", 445 "webControls.reload": "Ladda om",
455 "welcome.loginButton": "Logga in på ditt konto", 446 "welcome.loginButton": "Logga in på ditt konto",
456 "welcome.signupButton": "Skapa ett gratis konto", 447 "welcome.signupButton": "Skapa ett gratis konto",
457 "workspaceDrawer.addNewWorkspaceLabel": "Skapa ny arbetsyta", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Alla tjänster", 449 "workspaceDrawer.allServices": "Alla tjänster",
459 "workspaceDrawer.headline": "Arbetsytor", 450 "workspaceDrawer.headline": "Arbetsytor",
460 "workspaceDrawer.item.contextMenuEdit": "redigera", 451 "workspaceDrawer.item.contextMenuEdit": "redigera",
461 "workspaceDrawer.item.noServicesAddedYet": "Inga tjänster har lagts till", 452 "workspaceDrawer.item.noServicesAddedYet": "Inga tjänster har lagts till",
462 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi-arbetsytor låter dig fokusera på det som är viktigt just nu. Konfigurera olika uppsättningar av tjänster och växla enkelt mellan dem när som helst.</p><p>Du bestämmer vilka tjänster du behöver när och var, så att vi kan hjälpa dig att hålla koll på läget - eller enkelt koppla bort från jobbet när du vill.</p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Redigera inställningar för arbetsytor", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Byter till" 455 "workspaces.switchingIndicator.switchingTo": "Byter till"
465} 456}
diff --git a/src/i18n/locales/te.json b/src/i18n/locales/te.json
index be9bbb961..812ec8c4c 100644
--- a/src/i18n/locales/te.json
+++ b/src/i18n/locales/te.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Reload", 2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "Server", 6 "changeserver.label": "Server",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Publish debugging information",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -45,7 +44,7 @@
45 "import.headline": "Import your Ferdi 4 services", 44 "import.headline": "Import your Ferdi 4 services",
46 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5", 45 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
47 "import.skip.label": "I want to add services manually", 46 "import.skip.label": "I want to add services manually",
48 "import.submit.label": "Import services", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "What is new?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Restart & install update", 50 "infobar.buttonInstallUpdate": "Restart & install update",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "Terms of Service", 117 "menu.help.tos": "Terms of Service",
119 "menu.services": "Services", 118 "menu.services": "Services",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Home", 121 "menu.services.goHome": "Home",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "Restart & install update", 192 "settings.app.buttonInstallUpdate": "Restart & install update",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "Name", 323 "settings.service.form.name": "Name",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/locales/tr.json b/src/i18n/locales/tr.json
index 3b91dfad0..b0368a18a 100644
--- a/src/i18n/locales/tr.json
+++ b/src/i18n/locales/tr.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Yenile", 2 "app.errorHandler.action": "Yenile",
3 "app.errorHandler.headline": "Bir terslik çıktı", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Özel sunucu", 4 "changeserver.customServerLabel": "Özel sunucu",
5 "changeserver.headline": "Sunucuyu deÄŸiÅŸtir", 5 "changeserver.headline": "Sunucuyu deÄŸiÅŸtir",
6 "changeserver.label": "Sunucu", 6 "changeserver.label": "Sunucu",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Ne oldu?", 10 "connectionLostBanner.informationLink": "Ne oldu?",
11 "connectionLostBanner.message": "Nayır, nolamaz! Ferdi {name} ile bağlantısını yitirdi.", 11 "connectionLostBanner.message": "Nayır, nolamaz! Ferdi {name} ile bağlantısını yitirdi.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Hata ayıklama bilgisini yayımla",
14 "feature.nightlyBuilds.activate": "EtkinleÅŸtir", 13 "feature.nightlyBuilds.activate": "EtkinleÅŸtir",
15 "feature.nightlyBuilds.info": "Nightly yapılar Ferdi'nin deneysel sürümleri olup tamamlanmamış özellikler içerebilir. Bu nightly yapılar genellikle geliştiriciler tarafından yeni özellikleri deneyip geliştirmek için kullanılır. Ne yaptığınızı bilmiyorsanız nightly yapıları etkinleştirmeyin.", 14 "feature.nightlyBuilds.info": "Nightly yapılar Ferdi'nin deneysel sürümleri olup tamamlanmamış özellikler içerebilir. Bu nightly yapılar genellikle geliştiriciler tarafından yeni özellikleri deneyip geliştirmek için kullanılır. Ne yaptığınızı bilmiyorsanız nightly yapıları etkinleştirmeyin.",
16 "feature.nightlyBuilds.title": "Nightly Yapılar", 15 "feature.nightlyBuilds.title": "Nightly Yapılar",
@@ -24,30 +23,30 @@
24 "feature.quickSwitch.info": "TAB, ↑ ve ↓ ile bir servis seç. ENTER ile bir servisi aç.", 23 "feature.quickSwitch.info": "TAB, ↑ ve ↓ ile bir servis seç. ENTER ile bir servisi aç.",
25 "feature.quickSwitch.search": "Ara...", 24 "feature.quickSwitch.search": "Ara...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "Ferdi hizmetlerine ÅŸu anda eriÅŸilemiyor", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Ä°ptal", 27 "global.cancel": "Cancel",
29 "global.edit": "Düzenle", 28 "global.edit": "Düzenle",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "İnternete bağlı değilsiniz.", 30 "global.notConnectedToTheInternet": "İnternete bağlı değilsiniz.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Çık", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Ayarlar", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Sistem Dilini Kullan ({default})", 36 "global.spellchecker.useDefault": "Sistem Dilini Kullan ({default})",
38 "global.spellchecking.autodetect": "Dili otomatik tespit et", 37 "global.spellchecking.autodetect": "Dili otomatik tespit et",
39 "global.spellchecking.autodetect.short": "Otomatik", 38 "global.spellchecking.autodetect.short": "Otomatik",
40 "global.spellchecking.language": "Ä°mla kontrol dili", 39 "global.spellchecking.language": "Ä°mla kontrol dili",
41 "global.submit": "Gönder", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Ferdi 4 servislerinizi içeri aktarın", 44 "import.headline": "Ferdi 4 servislerinizi içeri aktarın",
46 "import.notSupportedHeadline": "Henüz Ferdi 5'te desteklenmeyen servisler", 45 "import.notSupportedHeadline": "Henüz Ferdi 5'te desteklenmeyen servisler",
47 "import.skip.label": "Servisleri kendim eklemek istiyorum", 46 "import.skip.label": "Servisleri kendim eklemek istiyorum",
48 "import.submit.label": "Servisleri içe aktar", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Yetkili bir işlem yapılmaya çalışırken hatalar ortaya çıktı. Lütfen bu hata tekrarlarsa çıkış yapıp tekrar girmeyi dene.", 48 "infobar.authRequestFailed": "Yetkili bir işlem yapılmaya çalışırken hatalar ortaya çıktı. Lütfen bu hata tekrarlarsa çıkış yapıp tekrar girmeyi dene.",
50 "infobar.buttonChangelog": "Yeni ne var?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Yeniden Başlat ve Güncelleştirmeleri Kur", 50 "infobar.buttonInstallUpdate": "Yeniden Başlat ve Güncelleştirmeleri Kur",
52 "infobar.buttonReloadServices": "Hizmetleri yeniden yükle", 51 "infobar.buttonReloadServices": "Hizmetleri yeniden yükle",
53 "infobar.hide": "Gizle", 52 "infobar.hide": "Gizle",
@@ -75,7 +74,7 @@
75 "login.email.label": "E-posta adresi", 74 "login.email.label": "E-posta adresi",
76 "login.headline": "Oturum Aç", 75 "login.headline": "Oturum Aç",
77 "login.invalidCredentials": "Yanlış parola ya da e-posta adresi", 76 "login.invalidCredentials": "Yanlış parola ya da e-posta adresi",
78 "login.link.password": "Parola sıfırla", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Ãœcretsiz hesap oluÅŸtur", 78 "login.link.signup": "Ãœcretsiz hesap oluÅŸtur",
80 "login.password.label": "Åžifre", 79 "login.password.label": "Åžifre",
81 "login.serverLogout": "Oturum süreniz dolmuş, lütfen tekrar giriş yapın.", 80 "login.serverLogout": "Oturum süreniz dolmuş, lütfen tekrar giriş yapın.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Destek", 116 "menu.help.support": "Destek",
118 "menu.help.tos": "Kullanım Şartları", 117 "menu.help.tos": "Kullanım Şartları",
119 "menu.services": "Hizmetler", 118 "menu.services": "Hizmetler",
120 "menu.services.activatePreviousService": "Bir önceki servisi aktive et", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Yeni Servis Ekle", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Ana Sayfa", 121 "menu.services.goHome": "Ana Sayfa",
123 "menu.services.setNextServiceActive": "Bir sonraki servisi aktive et", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Yapılacaklar", 123 "menu.todos": "Yapılacaklar",
125 "menu.todos.enableTodos": "Yapılacaklar Listesi'ni Aç", 124 "menu.todos.enableTodos": "Yapılacaklar Listesi'ni Aç",
126 "menu.view": "Görünüm", 125 "menu.view": "Görünüm",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Tüm servisler", 147 "menu.workspaces.defaultWorkspace": "Tüm servisler",
149 "menu.workspaces.openWorkspaceDrawer": "Çalışma alanı çekmecesini aç", 148 "menu.workspaces.openWorkspaceDrawer": "Çalışma alanı çekmecesini aç",
150 "password.email.label": "E-posta adresi", 149 "password.email.label": "E-posta adresi",
151 "password.headline": "Parola sıfırla", 150 "password.headline": "Reset password",
152 "password.link.login": "Hesabına giriş yap", 151 "password.link.login": "Hesabına giriş yap",
153 "password.link.signup": "Ãœcretsiz hesap oluÅŸtur", 152 "password.link.signup": "Ãœcretsiz hesap oluÅŸtur",
154 "password.noUser": "Bu e-posta adresinde bir kullanıcı bulunamadı", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "E-postanızı kontrol ediniz", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Hesap EÅŸitleme",
157 "pricing.features.customWebsites": "Özel Siteler Ekle",
158 "pricing.features.desktopNotifications": "Masaüstü Bildirimleri",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Servis proxy'leri",
162 "pricing.features.spellchecker": "Yazım denetimi desteği",
163 "pricing.features.teamManagement": "Takım yönetimi",
164 "pricing.features.thirdPartyServices": "3. parti servisleri yükleme",
165 "pricing.features.unlimitedServices": "Sınırsız servis ekleme",
166 "pricing.features.workspaces": "Çalışma Alanları",
167 "service.crashHandler.action": "{name} yeniden yükle", 155 "service.crashHandler.action": "{name} yeniden yükle",
168 "service.crashHandler.autoReload": "{name}'i {seconds} saniye içerisinde otomatik onarmayı deniyoruz", 156 "service.crashHandler.autoReload": "{name}'i {seconds} saniye içerisinde otomatik onarmayı deniyoruz",
169 "service.crashHandler.headline": "Olamaz!", 157 "service.crashHandler.headline": "Olamaz!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Ferdi'yi bir hesap olmadan kullan", 170 "services.serverless": "Ferdi'yi bir hesap olmadan kullan",
183 "services.welcome": "Ferdi'a HoÅŸgeldiniz", 171 "services.welcome": "Ferdi'a HoÅŸgeldiniz",
184 "settings.account.account.editButton": "Hesabı düzenle", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Hesap kullanılamıyor", 173 "settings.account.accountUnavailable": "Hesap kullanılamıyor",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Profili güncelle", 175 "settings.account.buttonSave": "Profili güncelle",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Hesabınızın silinmesini onaylamanız için e-posta adresinize gönderilen bağlantıya tıklayınız. Bu işlem sonrasında hesabınız ve bilgileriniz geri getirilemez!", 177 "settings.account.deleteEmailSent": "Hesabınızın silinmesini onaylamanız için e-posta adresinize gönderilen bağlantıya tıklayınız. Bu işlem sonrasında hesabınız ve bilgileriniz geri getirilemez!",
190 "settings.account.deleteInfo": "Ferdi hesabınıza artık ihtiyaç duymuyorsanız, hesabınızı ve buradaki bütün bağlantılı bilgilerinizi silebilirsiniz.", 178 "settings.account.deleteInfo": "Ferdi hesabınıza artık ihtiyaç duymuyorsanız, hesabınızı ve buradaki bütün bağlantılı bilgilerinizi silebilirsiniz.",
191 "settings.account.headline": "Hesap", 179 "settings.account.headline": "Hesap",
192 "settings.account.headlineAccount": "Hesap bilgileri", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Tehlike Bölgesi", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Faturalar", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Parolayı değiştir", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Profili güncelle", 184 "settings.account.headlineProfile": "Profili güncelle",
197 "settings.account.successInfo": "DeÄŸiÅŸikliklerin kaydedildi", 185 "settings.account.successInfo": "DeÄŸiÅŸikliklerin kaydedildi",
198 "settings.account.tryReloadServices": "Tekrar deneyin", 186 "settings.account.tryReloadServices": "Tekrar deneyin",
199 "settings.account.tryReloadUserInfoRequest": "Tekrar deneyin", 187 "settings.account.tryReloadUserInfoRequest": "Tekrar deneyin",
200 "settings.account.userInfoRequestFailed": "Kullanıcı bilgisi yüklenemedi", 188 "settings.account.userInfoRequestFailed": "Kullanıcı bilgisi yüklenemedi",
201 "settings.account.yourLicense": "Ferdi Lisansınız", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Önbelleği temizle", 191 "settings.app.buttonClearAllCache": "Önbelleği temizle",
204 "settings.app.buttonInstallUpdate": "Yeniden Başlat ve Güncelleştirmeleri Kur", 192 "settings.app.buttonInstallUpdate": "Yeniden Başlat ve Güncelleştirmeleri Kur",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Karanlık modu aç",
224 "settings.app.form.enableGPUAcceleration": "Grafik İşlemci Ünitesi (GPU) Hızlandırıcısını Aktif et", 212 "settings.app.form.enableGPUAcceleration": "Grafik İşlemci Ünitesi (GPU) Hızlandırıcısını Aktif et",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Yazım denetimini etkinleştir", 215 "settings.app.form.enableSpellchecking": "Yazım denetimini etkinleştir",
228 "settings.app.form.enableSystemTray": "Ferdi'ı sistem tepsisinde göster", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Devre dışı bırakılan servis sekmelerini göster", 239 "settings.app.form.showDisabledServices": "Devre dışı bırakılan servis sekmelerini göster",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Bildirimler kapalı iken okunmamış mesaj sayısını göster", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Bildirimler kapalı iken okunmamış mesaj sayısını göster",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -296,7 +285,7 @@
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Developer Documentation", 287 "settings.recipes.customService.openDevDocs": "Developer Documentation",
299 "settings.recipes.customService.openFolder": "Klasör aç", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Mevcut servisler", 289 "settings.recipes.headline": "Mevcut servisler",
301 "settings.recipes.missingService": "Aradığın servisi bulamadın mı?", 290 "settings.recipes.missingService": "Aradığın servisi bulamadın mı?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Servisi sil", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "{name} düzenle", 305 "settings.service.form.editServiceHeadline": "{name} düzenle",
317 "settings.service.form.enableAudio": "Sesi etkinleÅŸtirin", 306 "settings.service.form.enableAudio": "Sesi etkinleÅŸtirin",
318 "settings.service.form.enableBadge": "Okunmamış mesajları göster", 307 "settings.service.form.enableBadge": "Okunmamış mesajları göster",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Devre dışı bırakıldığında, tüm bildirim sesleri sessize alınır", 322 "settings.service.form.isMutedInfo": "Devre dışı bırakıldığında, tüm bildirim sesleri sessize alınır",
334 "settings.service.form.name": "Ad", 323 "settings.service.form.name": "Ad",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Ayarları", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Ayarları",
339 "settings.service.form.proxy.host": "Proxy Sunucusu/IP", 329 "settings.service.form.proxy.host": "Proxy Sunucusu/IP",
340 "settings.service.form.proxy.info": "Proxy ayarları Ferdi serverlarına yüklenmeyecektir.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Proxy Kullan", 331 "settings.service.form.proxy.isEnabled": "Proxy Kullan",
342 "settings.service.form.proxy.password": "Parola (opsiyonel)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
344 "settings.service.form.proxy.restartInfo": "Proxy ayarlarını değiştirdikten sonra Ferdi'ı yeniden başlatınız.", 334 "settings.service.form.proxy.restartInfo": "Proxy ayarlarını değiştirdikten sonra Ferdi'ı yeniden başlatınız.",
345 "settings.service.form.proxy.user": "Kullanıcı (opsiyonel)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Servisi kaydet", 337 "settings.service.form.saveButton": "Servisi kaydet",
348 "settings.service.form.tabHosted": "Barındırılan", 338 "settings.service.form.tabHosted": "Barındırılan",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Servisleri keÅŸfet", 344 "settings.services.discoverServices": "Servisleri keÅŸfet",
355 "settings.services.headline": "Servislerin", 345 "settings.services.headline": "Servislerin",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Hizmetiniz yüklenemedi", 348 "settings.services.servicesRequestFailed": "Hizmetiniz yüklenemedi",
358 "settings.services.tooltip.isDisabled": "Servis devre dışı", 349 "settings.services.tooltip.isDisabled": "Servis devre dışı",
359 "settings.services.tooltip.isMuted": "Tüm sesler kapalı", 350 "settings.services.tooltip.isMuted": "Tüm sesler kapalı",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Kar amacı gütmeyen", 378 "settings.user.form.accountType.non-profit": "Kar amacı gütmeyen",
388 "settings.user.form.currentPassword": "Mevcut ÅŸifre", 379 "settings.user.form.currentPassword": "Mevcut ÅŸifre",
389 "settings.user.form.email": "E-posta", 380 "settings.user.form.email": "E-posta",
390 "settings.user.form.firstname": "Ad", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Soyad", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Yeni ÅŸifre", 383 "settings.user.form.newPassword": "Yeni ÅŸifre",
393 "settings.workspace.add.form.name": "Ad", 384 "settings.workspace.add.form.name": "Ad",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Bildirimleri ve sesli uyarıları etkinleştir", 411 "sidebar.unmuteApp": "Bildirimleri ve sesli uyarıları etkinleştir",
421 "signup.email.label": "E-posta adresi", 412 "signup.email.label": "E-posta adresi",
422 "signup.emailDuplicate": "Bu email adresine sahip bir kullanıcı zaten mevcut", 413 "signup.emailDuplicate": "Bu email adresine sahip bir kullanıcı zaten mevcut",
423 "signup.firstname.label": "Ad", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Hesap oluÅŸtur", 415 "signup.headline": "Hesap oluÅŸtur",
425 "signup.lastname.label": "Soyad", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Ferdi'ı hesabı oluşturark kabul ediyorsun", 417 "signup.legal.info": "Ferdi'ı hesabı oluşturark kabul ediyorsun",
427 "signup.legal.privacy": "Gizlilik Sözleşmesi", 418 "signup.legal.privacy": "Gizlilik Sözleşmesi",
428 "signup.legal.terms": "Kullanım Koşulları", 419 "signup.legal.terms": "Kullanım Koşulları",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Åžifre", 421 "signup.password.label": "Åžifre",
431 "signup.submit.label": "Hesap oluÅŸtur", 422 "signup.submit.label": "Hesap oluÅŸtur",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Servisi sil", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Sesi kapat", 425 "tabs.item.disableAudio": "Sesi kapat",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Bildirimleri devre dışı bırak", 427 "tabs.item.disableNotifications": "Bildirimleri devre dışı bırak",
437 "tabs.item.disableService": "Servisi devre dışı bırak", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Sesi etkinleÅŸtirin", 429 "tabs.item.enableAudio": "Sesi etkinleÅŸtirin",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Bildirimleri etkinleÅŸtir", 431 "tabs.item.enableNotification": "Bildirimleri etkinleÅŸtir",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Yenile", 434 "tabs.item.reload": "Yenile",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} geçerli değil", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} en az {length} karakter uzunluğunda olmalı", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} gereklidir", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} geçerli bir URL değil", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Geri", 441 "webControls.back": "Geri",
451 "webControls.forward": "Ä°leri", 442 "webControls.forward": "Ä°leri",
452 "webControls.goHome": "Ana Sayfa", 443 "webControls.goHome": "Ana Sayfa",
diff --git a/src/i18n/locales/uk.json b/src/i18n/locales/uk.json
index b4f1fb66c..b03bf9072 100644
--- a/src/i18n/locales/uk.json
+++ b/src/i18n/locales/uk.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Перезавантажити", 2 "app.errorHandler.action": "Перезавантажити",
3 "app.errorHandler.headline": "ЩоÑÑŒ пішло не так", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "КориÑтувацький Ñервер", 4 "changeserver.customServerLabel": "КориÑтувацький Ñервер",
5 "changeserver.headline": "Змінити Ñервер", 5 "changeserver.headline": "Змінити Ñервер",
6 "changeserver.label": "Сервер", 6 "changeserver.label": "Сервер",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Що трапилоÑÑŒ?", 10 "connectionLostBanner.informationLink": "Що трапилоÑÑŒ?",
11 "connectionLostBanner.message": "О ні! Ферді втратив з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· {name}.", 11 "connectionLostBanner.message": "О ні! Ферді втратив з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Опублікувати інформацію Ð´Ð»Ñ Ð½Ð°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ",
14 "feature.nightlyBuilds.activate": "Ðктивувати", 13 "feature.nightlyBuilds.activate": "Ðктивувати",
15 "feature.nightlyBuilds.info": "Ðічні збірки - це виÑокоекÑпериментальні верÑÑ–Ñ— Ferdi, що можуть міÑтити \"неполіровані\" або незавершені функції. Ðічні збірки в оÑновному викориÑтовуютьÑÑ Ñ€Ð¾Ð·Ñ€Ð¾Ð±Ð½Ð¸ÐºÐ°Ð¼Ð¸, щоб перевірити Ñвої нові функції та те, Ñк вони будуть працювати в фінальній верÑÑ–Ñ—. Якщо ви не знаєте, що ви робите, то радимо не активувати нічні збірки.", 14 "feature.nightlyBuilds.info": "Ðічні збірки - це виÑокоекÑпериментальні верÑÑ–Ñ— Ferdi, що можуть міÑтити \"неполіровані\" або незавершені функції. Ðічні збірки в оÑновному викориÑтовуютьÑÑ Ñ€Ð¾Ð·Ñ€Ð¾Ð±Ð½Ð¸ÐºÐ°Ð¼Ð¸, щоб перевірити Ñвої нові функції та те, Ñк вони будуть працювати в фінальній верÑÑ–Ñ—. Якщо ви не знаєте, що ви робите, то радимо не активувати нічні збірки.",
16 "feature.nightlyBuilds.title": "Ðічні збірки", 15 "feature.nightlyBuilds.title": "Ðічні збірки",
@@ -24,30 +23,30 @@
24 "feature.quickSwitch.info": "Виберіть ÑÐµÑ€Ð²Ñ–Ñ Ð·Ð° допомогою TAB, Ñтрілок ↑ та ↓. ÐатиÑніть ENTER, щоб відкрити.", 23 "feature.quickSwitch.info": "Виберіть ÑÐµÑ€Ð²Ñ–Ñ Ð·Ð° допомогою TAB, Ñтрілок ↑ та ↓. ÐатиÑніть ENTER, щоб відкрити.",
25 "feature.quickSwitch.search": "Пошук...", 24 "feature.quickSwitch.search": "Пошук...",
26 "feature.quickSwitch.title": "Швидке перемиканнÑ", 25 "feature.quickSwitch.title": "Швидке перемиканнÑ",
27 "global.api.unhealthy": "Ðе можливо підключитиÑÑŒ до онлайн ÑервіÑів Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Відмінити", 27 "global.cancel": "Cancel",
29 "global.edit": "Редагувати", 28 "global.edit": "Редагувати",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Ви не підключені до Інтернету.", 30 "global.notConnectedToTheInternet": "Ви не підключені до Інтернету.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Вийти", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "ÐалаштуваннÑ", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "ВикориÑтовувати ÑиÑтемні параметри за змовчуваннÑм ({default})", 36 "global.spellchecker.useDefault": "ВикориÑтовувати ÑиÑтемні параметри за змовчуваннÑм ({default})",
38 "global.spellchecking.autodetect": "Ðвтоматично визначати мову", 37 "global.spellchecking.autodetect": "Ðвтоматично визначати мову",
39 "global.spellchecking.autodetect.short": "Ðвтоматично", 38 "global.spellchecking.autodetect.short": "Ðвтоматично",
40 "global.spellchecking.language": "Мова перевірки правопиÑу", 39 "global.spellchecking.language": "Мова перевірки правопиÑу",
41 "global.submit": "Подати", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "Ідентифікатор браузера", 42 "global.userAgentPref": "Ідентифікатор браузера",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Імпортувати ваші ÑервіÑи з Ferdi 4", 44 "import.headline": "Імпортувати ваші ÑервіÑи з Ferdi 4",
46 "import.notSupportedHeadline": "Ðаразі ÑервіÑи не підтримуютьÑÑ Ñƒ Ferdi 5", 45 "import.notSupportedHeadline": "Ðаразі ÑервіÑи не підтримуютьÑÑ Ñƒ Ferdi 5",
47 "import.skip.label": "Я бажаю додати ÑÐµÑ€Ð²Ñ–Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ", 46 "import.skip.label": "Я бажаю додати ÑÐµÑ€Ð²Ñ–Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ",
48 "import.submit.label": "Імпортувати ÑервіÑи", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "Що нового?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Перезавантажити Ñ– вÑтановити оновленнÑ", 50 "infobar.buttonInstallUpdate": "Перезавантажити Ñ– вÑтановити оновленнÑ",
52 "infobar.buttonReloadServices": "Перезавантажити ÑервіÑи", 51 "infobar.buttonReloadServices": "Перезавантажити ÑервіÑи",
53 "infobar.hide": "Приховати", 52 "infobar.hide": "Приховати",
@@ -75,7 +74,7 @@
75 "login.email.label": "Email адреÑа", 74 "login.email.label": "Email адреÑа",
76 "login.headline": "Увійти", 75 "login.headline": "Увійти",
77 "login.invalidCredentials": "Email або пароль некоректні", 76 "login.invalidCredentials": "Email або пароль некоректні",
78 "login.link.password": "Скинути пароль", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Створити безплатний акаунт", 78 "login.link.signup": "Створити безплатний акаунт",
80 "login.password.label": "Пароль", 79 "login.password.label": "Пароль",
81 "login.serverLogout": "Ваша ÑеÑÑ–Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡Ð¸Ð»Ð°ÑÑŒ, будь лаÑка, увійдіть знову.", 80 "login.serverLogout": "Ваша ÑеÑÑ–Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡Ð¸Ð»Ð°ÑÑŒ, будь лаÑка, увійдіть знову.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Підтримка", 116 "menu.help.support": "Підтримка",
118 "menu.help.tos": "Умови викориÑтаннÑ", 117 "menu.help.tos": "Умови викориÑтаннÑ",
119 "menu.services": "Служби", 118 "menu.services": "Служби",
120 "menu.services.activatePreviousService": "Ðктивувати попередню Ñлужбу", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Додати новий ÑервіÑ", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Головна", 121 "menu.services.goHome": "Головна",
123 "menu.services.setNextServiceActive": "Ðктивувати наÑтупний ÑервіÑ", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "ЗавданнÑ", 123 "menu.todos": "ЗавданнÑ",
125 "menu.todos.enableTodos": "Увімкнути ЗавданнÑ", 124 "menu.todos.enableTodos": "Увімкнути ЗавданнÑ",
126 "menu.view": "ВиглÑд", 125 "menu.view": "ВиглÑд",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "УÑÑ– ÑервіÑи", 147 "menu.workspaces.defaultWorkspace": "УÑÑ– ÑервіÑи",
149 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", 148 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
150 "password.email.label": "Email адреÑа", 149 "password.email.label": "Email адреÑа",
151 "password.headline": "Скинути пароль", 150 "password.headline": "Reset password",
152 "password.link.login": "Увійти до вашого акаунту", 151 "password.link.login": "Увійти до вашого акаунту",
153 "password.link.signup": "Створити безплатний акаунт", 152 "password.link.signup": "Створити безплатний акаунт",
154 "password.noUser": "Ðе знайдено жодного кориÑтувача з цією email адреÑою", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Будь лаÑка, перевірте ваш email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Перезавантажити {name}", 155 "service.crashHandler.action": "Перезавантажити {name}",
168 "service.crashHandler.autoReload": "Спробую автоматично відновити {name} через {seconds} Ñ", 156 "service.crashHandler.autoReload": "Спробую автоматично відновити {name} через {seconds} Ñ",
169 "service.crashHandler.headline": "О, ні!", 157 "service.crashHandler.headline": "О, ні!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "ЛаÑкаво проÑимо в Ferdi", 171 "services.welcome": "ЛаÑкаво проÑимо в Ferdi",
184 "settings.account.account.editButton": "Редагувати акаунт", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½ÐµÐ´Ð¾Ñтупний", 173 "settings.account.accountUnavailable": "Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½ÐµÐ´Ð¾Ñтупний",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "Оновити профіль", 175 "settings.account.buttonSave": "Оновити профіль",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Ви отримали електронного лиÑта з поÑиланнÑм, щоб підтвердити Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу. Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ñ– дані не можна буде відновити!", 177 "settings.account.deleteEmailSent": "Ви отримали електронного лиÑта з поÑиланнÑм, щоб підтвердити Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу. Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ñ– дані не можна буде відновити!",
190 "settings.account.deleteInfo": "Якщо Вам більше не потрібний обліковий Ð·Ð°Ð¿Ð¸Ñ Ferdi, Ви можете його видалити Ñ– вÑÑ– Ñуміжні дані.", 178 "settings.account.deleteInfo": "Якщо Вам більше не потрібний обліковий Ð·Ð°Ð¿Ð¸Ñ Ferdi, Ви можете його видалити Ñ– вÑÑ– Ñуміжні дані.",
191 "settings.account.headline": "Ðкаунт", 179 "settings.account.headline": "Ðкаунт",
192 "settings.account.headlineAccount": "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ акаунт", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Ðа Ñвій Ñтрах Ñ– ризик", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "ІнвойÑи", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Змінити пароль", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Оновити профіль", 184 "settings.account.headlineProfile": "Оновити профіль",
197 "settings.account.successInfo": "Ваші зміни були збережені", 185 "settings.account.successInfo": "Ваші зміни були збережені",
198 "settings.account.tryReloadServices": "Спробуйте ще раз", 186 "settings.account.tryReloadServices": "Спробуйте ще раз",
199 "settings.account.tryReloadUserInfoRequest": "Спробуйте ще раз", 187 "settings.account.tryReloadUserInfoRequest": "Спробуйте ще раз",
200 "settings.account.userInfoRequestFailed": "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ інформацію кориÑтувача", 188 "settings.account.userInfoRequestFailed": "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ інформацію кориÑтувача",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "ОчиÑтити кеш", 191 "settings.app.buttonClearAllCache": "ОчиÑтити кеш",
204 "settings.app.buttonInstallUpdate": "Перезавантажити Ñ– вÑтановити оновленнÑ", 192 "settings.app.buttonInstallUpdate": "Перезавантажити Ñ– вÑтановити оновленнÑ",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Переходь на Темну Сторону",
224 "settings.app.form.enableGPUAcceleration": "Ввімкнути приÑÐºÐ¾Ñ€ÐµÐ½Ð½Ñ GPU", 212 "settings.app.form.enableGPUAcceleration": "Ввімкнути приÑÐºÐ¾Ñ€ÐµÐ½Ð½Ñ GPU",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Увімкнути перевірку орфографії", 215 "settings.app.form.enableSpellchecking": "Увімкнути перевірку орфографії",
228 "settings.app.form.enableSystemTray": "Показувати Ferdi у ÑиÑтемному лотку", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Показати вкладку вимкнених ÑервіÑів", 239 "settings.app.form.showDisabledServices": "Показати вкладку вимкнених ÑервіÑів",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Показувати значок непрочитаних повідомлень коли ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ñ–", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Показувати значок непрочитаних повідомлень коли ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ñ–",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "ЗапуÑкати згорнутим", 243 "settings.app.form.startMinimized": "ЗапуÑкати згорнутим",
255 "settings.app.form.universalDarkMode": "Увімкнути універÑальний темний режим", 244 "settings.app.form.universalDarkMode": "Увімкнути універÑальний темний режим",
256 "settings.app.form.useTouchIdToUnlock": "Дозволити викориÑÑ‚Ð°Ð½Ð½Ñ TouchID Ð´Ð»Ñ Ñ€Ð¾Ð·Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Use horizontal style", 246 "settings.app.form.useVerticalStyle": "Use horizontal style",
258 "settings.app.form.wakeUpStrategy": "Wake up strategy", 247 "settings.app.form.wakeUpStrategy": "Wake up strategy",
259 "settings.app.headlineAdvanced": "Додаткові налаштуваннÑ", 248 "settings.app.headlineAdvanced": "Додаткові налаштуваннÑ",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "Видалити ÑервіÑ", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Редагувати {name}", 305 "settings.service.form.editServiceHeadline": "Редагувати {name}",
317 "settings.service.form.enableAudio": "Увімкнути звук", 306 "settings.service.form.enableAudio": "Увімкнути звук",
318 "settings.service.form.enableBadge": "Показувати непрочитані повідомленнÑ", 307 "settings.service.form.enableBadge": "Показувати непрочитані повідомленнÑ",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "Коли вимкнено, вÑÑ– ÑÐ¿Ð¾Ð²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ñ‚Ð° Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ–Ð³Ð½Ð¾Ñ€ÑƒÑŽÑ‚ÑŒÑÑ", 322 "settings.service.form.isMutedInfo": "Коли вимкнено, вÑÑ– ÑÐ¿Ð¾Ð²Ð¸Ñ‰ÐµÐ½Ð½Ñ Ñ‚Ð° Ð²Ñ–Ð´Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ–Ð³Ð½Ð¾Ñ€ÑƒÑŽÑ‚ÑŒÑÑ",
334 "settings.service.form.name": "Ім'Ñ", 323 "settings.service.form.name": "Ім'Ñ",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Відкрити user.css", 326 "settings.service.form.openUserCss": "Відкрити user.css",
337 "settings.service.form.openUserJs": "Відкрити user.js", 327 "settings.service.form.openUserJs": "Відкрити user.js",
338 "settings.service.form.proxy.headline": "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ HTTP/HTTPS прокÑÑ– ", 328 "settings.service.form.proxy.headline": "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ HTTP/HTTPS прокÑÑ– ",
339 "settings.service.form.proxy.host": "ПрокÑÑ– Host/IP", 329 "settings.service.form.proxy.host": "ПрокÑÑ– Host/IP",
340 "settings.service.form.proxy.info": "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐºÑÑ– не будуть Ñинхронізовані із Ñерверами Ferdi", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "ВикориÑтовувати прокÑÑ–", 331 "settings.service.form.proxy.isEnabled": "ВикориÑтовувати прокÑÑ–",
342 "settings.service.form.proxy.password": "Пароль (опційно)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Порт", 333 "settings.service.form.proxy.port": "Порт",
344 "settings.service.form.proxy.restartInfo": "Будь лаÑка, перезапуÑÑ‚Ñ–Ñ‚ÑŒ Ferdi піÑÐ»Ñ Ð·Ð¼Ñ–Ð½Ð¸ налуштувань прокÑÑ–", 334 "settings.service.form.proxy.restartInfo": "Будь лаÑка, перезапуÑÑ‚Ñ–Ñ‚ÑŒ Ferdi піÑÐ»Ñ Ð·Ð¼Ñ–Ð½Ð¸ налуштувань прокÑÑ–",
345 "settings.service.form.proxy.user": "КориÑтувач (опційно)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "Зберегти ÑервіÑ", 337 "settings.service.form.saveButton": "Зберегти ÑервіÑ",
348 "settings.service.form.tabHosted": "Розміщений", 338 "settings.service.form.tabHosted": "Розміщений",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Відкрийте Ð´Ð»Ñ Ñебе ÑервіÑи", 344 "settings.services.discoverServices": "Відкрийте Ð´Ð»Ñ Ñебе ÑервіÑи",
355 "settings.services.headline": "Ваші ÑервіÑи", 345 "settings.services.headline": "Ваші ÑервіÑи",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Ð¡ÐµÑ€Ð²Ñ–Ñ Ð²Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ð¹", 349 "settings.services.tooltip.isDisabled": "Ð¡ÐµÑ€Ð²Ñ–Ñ Ð²Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ð¹",
359 "settings.services.tooltip.isMuted": "Ð’ÑÑ– звуки вимкнено", 350 "settings.services.tooltip.isMuted": "Ð’ÑÑ– звуки вимкнено",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Ðекомерційний", 378 "settings.user.form.accountType.non-profit": "Ðекомерційний",
388 "settings.user.form.currentPassword": "Поточний пароль", 379 "settings.user.form.currentPassword": "Поточний пароль",
389 "settings.user.form.email": "Ел. пошта", 380 "settings.user.form.email": "Ел. пошта",
390 "settings.user.form.firstname": "Ім`Ñ", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Прізвище", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Ðовий пароль", 383 "settings.user.form.newPassword": "Ðовий пароль",
393 "settings.workspace.add.form.name": "Ім'Ñ", 384 "settings.workspace.add.form.name": "Ім'Ñ",
394 "settings.workspace.add.form.submitButton": "Create workspace", 385 "settings.workspace.add.form.submitButton": "Create workspace",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Увімкнути ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ‚Ð° звуки", 411 "sidebar.unmuteApp": "Увімкнути ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ‚Ð° звуки",
421 "signup.email.label": "Email адреÑа", 412 "signup.email.label": "Email адреÑа",
422 "signup.emailDuplicate": "КориÑтувач із цією email адреÑою вже Ñ–Ñнує", 413 "signup.emailDuplicate": "КориÑтувач із цією email адреÑою вже Ñ–Ñнує",
423 "signup.firstname.label": "Ім`Ñ", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Увійти", 415 "signup.headline": "Увійти",
425 "signup.lastname.label": "Прізвище", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "СтвореннÑм акаунту Ferdi ви приймаєте", 417 "signup.legal.info": "СтвореннÑм акаунту Ferdi ви приймаєте",
427 "signup.legal.privacy": "ЗаÑва про конфіденційніÑÑ‚ÑŒ", 418 "signup.legal.privacy": "ЗаÑва про конфіденційніÑÑ‚ÑŒ",
428 "signup.legal.terms": "Умови викориÑтаннÑ", 419 "signup.legal.terms": "Умови викориÑтаннÑ",
@@ -430,11 +421,11 @@
430 "signup.password.label": "Пароль", 421 "signup.password.label": "Пароль",
431 "signup.submit.label": "Створити акаунт", 422 "signup.submit.label": "Створити акаунт",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "Видалити ÑервіÑ", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "відключити звук", 425 "tabs.item.disableAudio": "відключити звук",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "Вимкнути ÑповіщеннÑ", 427 "tabs.item.disableNotifications": "Вимкнути ÑповіщеннÑ",
437 "tabs.item.disableService": "Вимкнути ÑервіÑ", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Увімкнути звук", 429 "tabs.item.enableAudio": "Увімкнути звук",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "Увімкнути ÑповіщеннÑ", 431 "tabs.item.enableNotification": "Увімкнути ÑповіщеннÑ",
@@ -442,11 +433,11 @@
442 "tabs.item.hibernateService": "Hibernate service", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Перезавантажити", 434 "tabs.item.reload": "Перезавантажити",
444 "tabs.item.wakeUpService": "Wake up service", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} не валідне", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "КількіÑÑ‚ÑŒ Ñимволів в {field} повина бути не меньше {length} ", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "At least one is required", 438 "validation.oneRequired": "At least one is required",
448 "validation.required": "{field} обов'Ñзвоке", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} не валідний URL", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Ðазад", 441 "webControls.back": "Ðазад",
451 "webControls.forward": "Вперед", 442 "webControls.forward": "Вперед",
452 "webControls.goHome": "Головна", 443 "webControls.goHome": "Головна",
diff --git a/src/i18n/locales/vi.json b/src/i18n/locales/vi.json
index 0bf52bf1d..668b75127 100644
--- a/src/i18n/locales/vi.json
+++ b/src/i18n/locales/vi.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "Tải lại", 2 "app.errorHandler.action": "Tải lại",
3 "app.errorHandler.headline": "Äã xảy ra lá»—i", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Máy chủ tùy chỉnh", 4 "changeserver.customServerLabel": "Máy chủ tùy chỉnh",
5 "changeserver.headline": "Thay đổi máy chủ", 5 "changeserver.headline": "Thay đổi máy chủ",
6 "changeserver.label": "Máy chủ", 6 "changeserver.label": "Máy chủ",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "Äiá»u gì đã xảy ra?", 10 "connectionLostBanner.informationLink": "Äiá»u gì đã xảy ra?",
11 "connectionLostBanner.message": "Mất kết nối tới {name}.", 11 "connectionLostBanner.message": "Mất kết nối tới {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "Gửi thông tin gỡ lỗi",
14 "feature.nightlyBuilds.activate": "Kích hoạt", 13 "feature.nightlyBuilds.activate": "Kích hoạt",
15 "feature.nightlyBuilds.info": "Các bản Nightly là các phiên bản Ferdi mang tính thử nghiệm có thể chứa các tính năng chưa được hoàn thiện. Các bản Nightly chủ yếu được các nhà phát triển sử dụng để kiểm tra các tính năng mới được phát triển của hỠvà cách chúng sẽ hoạt động trong bản dựng cuối cùng. Nếu bạn không biết mình đang làm gì, chúng tôi khuyên bạn không nên kích hoạt các bản dựng hàng đêm.", 14 "feature.nightlyBuilds.info": "Các bản Nightly là các phiên bản Ferdi mang tính thử nghiệm có thể chứa các tính năng chưa được hoàn thiện. Các bản Nightly chủ yếu được các nhà phát triển sử dụng để kiểm tra các tính năng mới được phát triển của hỠvà cách chúng sẽ hoạt động trong bản dựng cuối cùng. Nếu bạn không biết mình đang làm gì, chúng tôi khuyên bạn không nên kích hoạt các bản dựng hàng đêm.",
16 "feature.nightlyBuilds.title": "Phiên bản Nightly", 15 "feature.nightlyBuilds.title": "Phiên bản Nightly",
@@ -24,30 +23,30 @@
24 "feature.quickSwitch.info": "Chá»n má»™t dịch vụ vá»›i TAB, ↑ và ↓. Mở má»™t dịch vụ bằng ENTER.", 23 "feature.quickSwitch.info": "Chá»n má»™t dịch vụ vá»›i TAB, ↑ và ↓. Mở má»™t dịch vụ bằng ENTER.",
25 "feature.quickSwitch.search": "Tìm kiếm...", 24 "feature.quickSwitch.search": "Tìm kiếm...",
26 "feature.quickSwitch.title": "Chuyển đổi nhanh", 25 "feature.quickSwitch.title": "Chuyển đổi nhanh",
27 "global.api.unhealthy": "Không thể kết nối đến máy chủ trực tuyến của Ferdi", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "Hủy", 27 "global.cancel": "Cancel",
29 "global.edit": "Chỉnh sửa", 28 "global.edit": "Chỉnh sửa",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "Bạn không kết nối với Internet.", 30 "global.notConnectedToTheInternet": "Bạn không kết nối với Internet.",
32 "global.ok": "Ok", 31 "global.ok": "Ok",
33 "global.quit": "Thoát", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "Các thiết lập", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "Dùng mặc định hệ thống ({default})", 36 "global.spellchecker.useDefault": "Dùng mặc định hệ thống ({default})",
38 "global.spellchecking.autodetect": "Tự động phát hiện ngôn ngữ", 37 "global.spellchecking.autodetect": "Tự động phát hiện ngôn ngữ",
39 "global.spellchecking.autodetect.short": "Tá»± Ä‘á»™ng", 38 "global.spellchecking.autodetect.short": "Tá»± Ä‘á»™ng",
40 "global.spellchecking.language": "Ngôn ngữ kiểm tra chính tả", 39 "global.spellchecking.language": "Ngôn ngữ kiểm tra chính tả",
41 "global.submit": "Gá»­i", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Sá»­ dụng 'https://whatmyuseragent.com/' (để khám phá) hoặc 'https://developers.whatismybrowser.com/useragents/explore/' (để chá»n) tác nhân ngÆ°á»i dùng mong muốn của bạn và sao chép-dán nó vào đây.", 41 "global.userAgentHelp": "Sá»­ dụng 'https://whatmyuseragent.com/' (để khám phá) hoặc 'https://developers.whatismybrowser.com/useragents/explore/' (để chá»n) tác nhân ngÆ°á»i dùng mong muốn của bạn và sao chép-dán nó vào đây.",
43 "global.userAgentPref": "Tác nhân NgÆ°á»i dùng", 42 "global.userAgentPref": "Tác nhân NgÆ°á»i dùng",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "Nhập các dịch vụ Ferdi 4 của bạn", 44 "import.headline": "Nhập các dịch vụ Ferdi 4 của bạn",
46 "import.notSupportedHeadline": "Các dịch vụ chưa được hỗ trợ trong Ferdi 5", 45 "import.notSupportedHeadline": "Các dịch vụ chưa được hỗ trợ trong Ferdi 5",
47 "import.skip.label": "Tôi muốn thêm dịch vụ theo cách thủ công", 46 "import.skip.label": "Tôi muốn thêm dịch vụ theo cách thủ công",
48 "import.submit.label": "Nhập Dịch vụ", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "Äã xảy ra lá»—i khi cố gắng thá»±c hiện má»™t yêu cầu đã xác thá»±c. Vui lòng thá»­ đăng xuất và đăng nhập lại nếu lá»—i này vẫn tiếp diá»…n.", 48 "infobar.authRequestFailed": "Äã xảy ra lá»—i khi cố gắng thá»±c hiện má»™t yêu cầu đã xác thá»±c. Vui lòng thá»­ đăng xuất và đăng nhập lại nếu lá»—i này vẫn tiếp diá»…n.",
50 "infobar.buttonChangelog": "Có gì mới?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "Khởi động lại và cài đặt bản cập nhật", 50 "infobar.buttonInstallUpdate": "Khởi động lại và cài đặt bản cập nhật",
52 "infobar.buttonReloadServices": "Tải lại dịch vụ", 51 "infobar.buttonReloadServices": "Tải lại dịch vụ",
53 "infobar.hide": "Ẩn", 52 "infobar.hide": "Ẩn",
@@ -75,7 +74,7 @@
75 "login.email.label": "Äịa chỉ E-mail", 74 "login.email.label": "Äịa chỉ E-mail",
76 "login.headline": "Äăng nhập", 75 "login.headline": "Äăng nhập",
77 "login.invalidCredentials": "Email hoặc mật khẩu chưa chính xác", 76 "login.invalidCredentials": "Email hoặc mật khẩu chưa chính xác",
78 "login.link.password": "Äặt lại mật khẩu", 77 "login.link.password": "Reset password",
79 "login.link.signup": "Tạo tài khoản miễn phí", 78 "login.link.signup": "Tạo tài khoản miễn phí",
80 "login.password.label": "Mật khẩu", 79 "login.password.label": "Mật khẩu",
81 "login.serverLogout": "Phiên làm việc của bạn bị quá hạn, hãy đăng nhập lại.", 80 "login.serverLogout": "Phiên làm việc của bạn bị quá hạn, hãy đăng nhập lại.",
@@ -117,10 +116,10 @@
117 "menu.help.support": "Hỗ trợ", 116 "menu.help.support": "Hỗ trợ",
118 "menu.help.tos": "Äiá»u khoản Dịch vụ", 117 "menu.help.tos": "Äiá»u khoản Dịch vụ",
119 "menu.services": "Dịch vụ", 118 "menu.services": "Dịch vụ",
120 "menu.services.activatePreviousService": "Kích hoạt dịch vụ trước đó", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Thêm Dịch vụ mới", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "Trang chủ", 121 "menu.services.goHome": "Trang chủ",
123 "menu.services.setNextServiceActive": "Kích hoạt dịch vụ tiếp theo", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Danh sách cần làm", 123 "menu.todos": "Danh sách cần làm",
125 "menu.todos.enableTodos": "Mở danh sách cần làm", 124 "menu.todos.enableTodos": "Mở danh sách cần làm",
126 "menu.view": "Hiển thị", 125 "menu.view": "Hiển thị",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "Tất cả Dịch vụ", 147 "menu.workspaces.defaultWorkspace": "Tất cả Dịch vụ",
149 "menu.workspaces.openWorkspaceDrawer": "Mở không gian làm việc", 148 "menu.workspaces.openWorkspaceDrawer": "Mở không gian làm việc",
150 "password.email.label": "Äịa chỉ E-mail", 149 "password.email.label": "Äịa chỉ E-mail",
151 "password.headline": "Äặt lại mật khẩu", 150 "password.headline": "Reset password",
152 "password.link.login": "Äăng nhập Tài khoản", 151 "password.link.login": "Äăng nhập Tài khoản",
153 "password.link.signup": "Tạo tài khoản miễn phí", 152 "password.link.signup": "Tạo tài khoản miễn phí",
154 "password.noUser": "Không tìm thấy ngÆ°á»i dùng được đăng ký vá»›i địa chỉ e-mail này", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Vui lòng kiểm tra hộp thư của bạn", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Äồng bá»™ hóa Tài khoản",
157 "pricing.features.customWebsites": "Thêm Trang web tùy chỉnh",
158 "pricing.features.desktopNotifications": "Thông báo",
159 "pricing.features.onPremise": "Tại chỗ & các dịch vụ được lưu trữ khác",
160 "pricing.features.recipes": "Chá»n từ hÆ¡n 70 Dịch vụ",
161 "pricing.features.serviceProxies": "Các Proxy Dịch vụ",
162 "pricing.features.spellchecker": "Hỗ trợ Công cụ kiểm tra chính tả",
163 "pricing.features.teamManagement": "Quản lý nhóm",
164 "pricing.features.thirdPartyServices": "Cài đặt dịch vụ của bên thứ 3",
165 "pricing.features.unlimitedServices": "Thêm dịch vụ không giới hạn",
166 "pricing.features.workspaces": "Không gian làm việc",
167 "service.crashHandler.action": "Tải lại {name}", 155 "service.crashHandler.action": "Tải lại {name}",
168 "service.crashHandler.autoReload": "Äang cố gắng tá»± Ä‘á»™ng khôi phục {name} sau {seconds} giây", 156 "service.crashHandler.autoReload": "Äang cố gắng tá»± Ä‘á»™ng khôi phục {name} sau {seconds} giây",
169 "service.crashHandler.headline": "Ồ không!", 157 "service.crashHandler.headline": "Ồ không!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Theo tùy chá»n, bạn có thể thay đổi máy chủ Ferdi của mình bằng cách nhấp vào bánh răng ở góc dÆ°á»›i cùng bên trái. Nếu bạn Ä‘ang chuyển qua (từ má»™t trong các máy chủ được lÆ°u trữ) sang sá»­ dụng Ferdi mà không có tài khoản, vui lòng thông báo rằng bạn có thể xuất dữ liệu của mình từ máy chủ đó và sau đó nhập dữ liệu đó bằng menu Trợ giúp để phục hồi tất cả không gian làm việc và dịch vụ đã định cấu hình của bạn!", 169 "services.serverInfo": "Theo tùy chá»n, bạn có thể thay đổi máy chủ Ferdi của mình bằng cách nhấp vào bánh răng ở góc dÆ°á»›i cùng bên trái. Nếu bạn Ä‘ang chuyển qua (từ má»™t trong các máy chủ được lÆ°u trữ) sang sá»­ dụng Ferdi mà không có tài khoản, vui lòng thông báo rằng bạn có thể xuất dữ liệu của mình từ máy chủ đó và sau đó nhập dữ liệu đó bằng menu Trợ giúp để phục hồi tất cả không gian làm việc và dịch vụ đã định cấu hình của bạn!",
182 "services.serverless": "Sá»­ dụng Ferdi không cần Äăng nhập Tài khoản", 170 "services.serverless": "Sá»­ dụng Ferdi không cần Äăng nhập Tài khoản",
183 "services.welcome": "Chào mừng bạn đến với Ferdi", 171 "services.welcome": "Chào mừng bạn đến với Ferdi",
184 "settings.account.account.editButton": "Chỉnh sửa Tài khoản", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "Tài khoản không hợp lệ", 173 "settings.account.accountUnavailable": "Tài khoản không hợp lệ",
186 "settings.account.accountUnavailableInfo": "Bạn Ä‘ang sá»­ dụng Ferdi mà không có tài khoản. Nếu bạn muốn sá»­ dụng Ferdi vá»›i má»™t tài khoản và giữ cho các dịch vụ của mình được đồng bá»™ hóa giữa các bản cài đặt, vui lòng chá»n má»™t máy chủ trong tab Cài đặt rồi đăng nhập.", 174 "settings.account.accountUnavailableInfo": "Bạn Ä‘ang sá»­ dụng Ferdi mà không có tài khoản. Nếu bạn muốn sá»­ dụng Ferdi vá»›i má»™t tài khoản và giữ cho các dịch vụ của mình được đồng bá»™ hóa giữa các bản cài đặt, vui lòng chá»n má»™t máy chủ trong tab Cài đặt rồi đăng nhập.",
187 "settings.account.buttonSave": "Cập nhật Hồ sơ", 175 "settings.account.buttonSave": "Cập nhật Hồ sơ",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "Bạn đã nhận được một email có liên kết để xác nhận việc xóa tài khoản của bạn. Tài khoản và dữ liệu của bạn không thể được khôi phục!", 177 "settings.account.deleteEmailSent": "Bạn đã nhận được một email có liên kết để xác nhận việc xóa tài khoản của bạn. Tài khoản và dữ liệu của bạn không thể được khôi phục!",
190 "settings.account.deleteInfo": "Nếu bạn không cần tài khoản Ferdi nữa, bạn có thể xóa tài khoản của mình và tất cả dữ liệu liên quan tại đây.", 178 "settings.account.deleteInfo": "Nếu bạn không cần tài khoản Ferdi nữa, bạn có thể xóa tài khoản của mình và tất cả dữ liệu liên quan tại đây.",
191 "settings.account.headline": "Tài khoản", 179 "settings.account.headline": "Tài khoản",
192 "settings.account.headlineAccount": "Thông tin Tài khoản", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "Vùng Nguy hiểm", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "Thanh toán", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "Thay đổi Mật khẩu", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "Cập nhật Hồ sơ", 184 "settings.account.headlineProfile": "Cập nhật Hồ sơ",
197 "settings.account.successInfo": "Má»i thay đổi đã được lÆ°u lại", 185 "settings.account.successInfo": "Má»i thay đổi đã được lÆ°u lại",
198 "settings.account.tryReloadServices": "Thử lại", 186 "settings.account.tryReloadServices": "Thử lại",
199 "settings.account.tryReloadUserInfoRequest": "Thử lại", 187 "settings.account.tryReloadUserInfoRequest": "Thử lại",
200 "settings.account.userInfoRequestFailed": "Không thể tải được thông tin ngÆ°á»i dùng", 188 "settings.account.userInfoRequestFailed": "Không thể tải được thông tin ngÆ°á»i dùng",
201 "settings.account.yourLicense": "Giấy phép Ferdi của bạn", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Viết màu nhấn của bạn ở định dạng tương thích với CSS. (Mặc định: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Viết màu nhấn của bạn ở định dạng tương thích với CSS. (Mặc định: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Xóa bộ nhớ cache", 191 "settings.app.buttonClearAllCache": "Xóa bộ nhớ cache",
204 "settings.app.buttonInstallUpdate": "Khởi động lại và cài đặt bản cập nhật", 192 "settings.app.buttonInstallUpdate": "Khởi động lại và cài đặt bản cập nhật",
@@ -219,13 +207,13 @@
219 "settings.app.form.clipboardNotifications": "Không hiển thị thông báo cho các sự kiện khay nhớ tạm", 207 "settings.app.form.clipboardNotifications": "Không hiển thị thông báo cho các sự kiện khay nhớ tạm",
220 "settings.app.form.closeToSystemTray": "Thu nhỠFerdi xuống khay hệ thống", 208 "settings.app.form.closeToSystemTray": "Thu nhỠFerdi xuống khay hệ thống",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Tùy chỉnh Server Todo", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Cho phép Chế Ä‘á»™ ná»n tối", 211 "settings.app.form.darkMode": "Cho phép chế Ä‘á»™ ná»n tối",
224 "settings.app.form.enableGPUAcceleration": "Bật Tăng tốc GPU", 212 "settings.app.form.enableGPUAcceleration": "Bật Tăng tốc GPU",
225 "settings.app.form.enableLock": "Cho phép khóa bằng mật khẩu", 213 "settings.app.form.enableLock": "Cho phép khóa bằng mật khẩu",
226 "settings.app.form.enableMenuBar": "Luôn hiển thị Ferdi trong Menu Bar", 214 "settings.app.form.enableMenuBar": "Luôn hiển thị Ferdi trong Menu Bar",
227 "settings.app.form.enableSpellchecking": "Kích hoạt tính năng kiểm tra chính tả", 215 "settings.app.form.enableSpellchecking": "Kích hoạt tính năng kiểm tra chính tả",
228 "settings.app.form.enableSystemTray": "Hiển thị Ferdi trong khay hệ thống", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Cho phép Ferdi Todos", 217 "settings.app.form.enableTodos": "Cho phép Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Giữ các dịch vụ ở chế độ ngủ đông khi khởi động", 218 "settings.app.form.hibernateOnStartup": "Giữ các dịch vụ ở chế độ ngủ đông khi khởi động",
231 "settings.app.form.hibernationStrategy": "Chiến lược ngủ đông", 219 "settings.app.form.hibernationStrategy": "Chiến lược ngủ đông",
@@ -251,9 +239,10 @@
251 "settings.app.form.showDisabledServices": "Hiển thị các tab dịch vụ bị vô hiệu hóa", 239 "settings.app.form.showDisabledServices": "Hiển thị các tab dịch vụ bị vô hiệu hóa",
252 "settings.app.form.showDragArea": "Hiển thị khu vực có thể kéo trên cửa sổ", 240 "settings.app.form.showDragArea": "Hiển thị khu vực có thể kéo trên cửa sổ",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Hiển thị huy hiệu tin nhắn chÆ°a Ä‘á»c khi tắt thông báo", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Hiển thị huy hiệu tin nhắn chÆ°a Ä‘á»c khi tắt thông báo",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Bắt đầu thu nhá»", 243 "settings.app.form.startMinimized": "Bắt đầu thu nhá»",
255 "settings.app.form.universalDarkMode": "Bật Chế độ tối chung", 244 "settings.app.form.universalDarkMode": "Bật Chế độ tối chung",
256 "settings.app.form.useTouchIdToUnlock": "Cho phép sử dụng TouchID để mở khóa Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
257 "settings.app.form.useVerticalStyle": "Sử dụng kiểu ngang", 246 "settings.app.form.useVerticalStyle": "Sử dụng kiểu ngang",
258 "settings.app.form.wakeUpStrategy": "Chiến lược đánh thức", 247 "settings.app.form.wakeUpStrategy": "Chiến lược đánh thức",
259 "settings.app.headlineAdvanced": "Nâng cao", 248 "settings.app.headlineAdvanced": "Nâng cao",
@@ -265,9 +254,9 @@
265 "settings.app.hibernateInfo": "Theo mặc định, Ferdi sẽ giữ cho tất cả các dịch vụ của bạn luôn mở và được tải ở chế Ä‘á»™ ná»n để chúng luôn sẵn sàng khi bạn muốn sá»­ dụng. Service Hibernation sẽ dỡ bá» các dịch vụ của bạn sau má»™t khoảng thá»i gian cụ thể. Äiá»u này rất hữu ích để tiết kiệm RAM hoặc giữ cho các dịch vụ không làm chậm máy tính của bạn.", 254 "settings.app.hibernateInfo": "Theo mặc định, Ferdi sẽ giữ cho tất cả các dịch vụ của bạn luôn mở và được tải ở chế Ä‘á»™ ná»n để chúng luôn sẵn sàng khi bạn muốn sá»­ dụng. Service Hibernation sẽ dỡ bá» các dịch vụ của bạn sau má»™t khoảng thá»i gian cụ thể. Äiá»u này rất hữu ích để tiết kiệm RAM hoặc giữ cho các dịch vụ không làm chậm máy tính của bạn.",
266 "settings.app.inactivityLockInfo": "Vài phút không hoạt động, sau đó Ferdi sẽ tự động khóa. Sử dụng 0 để tắt", 255 "settings.app.inactivityLockInfo": "Vài phút không hoạt động, sau đó Ferdi sẽ tự động khóa. Sử dụng 0 để tắt",
267 "settings.app.languageDisclaimer": "Bản dịch chính thức là tiếng Anh và tiếng Äức. Tất cả các ngôn ngữ khác là bản dịch dá»±a trên cá»™ng đồng.", 256 "settings.app.languageDisclaimer": "Bản dịch chính thức là tiếng Anh và tiếng Äức. Tất cả các ngôn ngữ khác là bản dịch dá»±a trên cá»™ng đồng.",
268 "settings.app.lockInfo": "Khóa mật khẩu cho phép bạn bảo vệ tin nhắn của mình.\nSử dụng Khóa mật khẩu, bạn sẽ được nhắc nhập mật khẩu của mình mỗi khi khởi động Ferdi hoặc tự khóa Ferdi bằng biểu tượng ổ khóa ở góc dưới cùng bên trái hoặc phím tắt {lockShortcut}.", 257 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
269 "settings.app.lockedPassword": "Mật khẩu", 258 "settings.app.lockedPassword": "Mật khẩu",
270 "settings.app.lockedPasswordInfo": "Hãy chắc chắn rằng bạn đã đặt mật khẩu mà bạn sẽ nhớ.\nNếu bạn mất mật khẩu này, bạn sẽ phải cài đặt lại Ferdi.", 259 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
271 "settings.app.restartRequired": "Các thay đổi yêu cầu khởi động lại", 260 "settings.app.restartRequired": "Các thay đổi yêu cầu khởi động lại",
272 "settings.app.scheduledDNDInfo": "Theo lịch trình Không làm phiá»n cho phép bạn xác định khoảng thá»i gian mà bạn không muốn nhận Thông báo từ Ferdi.", 261 "settings.app.scheduledDNDInfo": "Theo lịch trình Không làm phiá»n cho phép bạn xác định khoảng thá»i gian mà bạn không muốn nhận Thông báo từ Ferdi.",
273 "settings.app.scheduledDNDTimeInfo": "Thá»i gian ở định dạng 24 giá». Thá»i gian kết thúc có thể trÆ°á»›c thá»i gian bắt đầu (ví dụ: bắt đầu từ 17:00, kết thúc lúc 09:00) để bật chế Ä‘á»™ Không làm phiá»n qua đêm.", 262 "settings.app.scheduledDNDTimeInfo": "Thá»i gian ở định dạng 24 giá». Thá»i gian kết thúc có thể trÆ°á»›c thá»i gian bắt đầu (ví dụ: bắt đầu từ 17:00, kết thúc lúc 09:00) để bật chế Ä‘á»™ Không làm phiá»n qua đêm.",
@@ -275,7 +264,7 @@
275 "settings.app.spellCheckerLanguageInfo": "Ferdi sá»­ dụng trình kiểm tra chính tả tích hợp trên máy Mac của bạn để kiểm tra lá»—i chính tả. Nếu bạn muốn thay đổi ngôn ngữ mà trình kiểm tra chính tả kiểm tra, bạn có thể làm nhÆ° vậy trong Tùy chá»n hệ thống của máy Mac.", 264 "settings.app.spellCheckerLanguageInfo": "Ferdi sá»­ dụng trình kiểm tra chính tả tích hợp trên máy Mac của bạn để kiểm tra lá»—i chính tả. Nếu bạn muốn thay đổi ngôn ngữ mà trình kiểm tra chính tả kiểm tra, bạn có thể làm nhÆ° vậy trong Tùy chá»n hệ thống của máy Mac.",
276 "settings.app.subheadlineCache": "Bộ nhớ đệm", 265 "settings.app.subheadlineCache": "Bộ nhớ đệm",
277 "settings.app.subheadlineFerdiProfile": "Hồ sơ Ferdi", 266 "settings.app.subheadlineFerdiProfile": "Hồ sơ Ferdi",
278 "settings.app.todoServerInfo": "Máy chủ này sẽ được sử dụng cho tính năng \"Ferdi Todo\".", 267 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature.",
279 "settings.app.translationHelp": "Giúp chúng tôi dịch Ferdi sang ngôn ngữ của bạn.", 268 "settings.app.translationHelp": "Giúp chúng tôi dịch Ferdi sang ngôn ngữ của bạn.",
280 "settings.app.universalDarkModeInfo": "Chế độ tối chung cố gắng tạo động các kiểu chế độ tối cho các dịch vụ hiện không được hỗ trợ.", 269 "settings.app.universalDarkModeInfo": "Chế độ tối chung cố gắng tạo động các kiểu chế độ tối cho các dịch vụ hiện không được hỗ trợ.",
281 "settings.app.updateStatusAvailable": "Bản cập nhật phù hợp, đang tải...", 270 "settings.app.updateStatusAvailable": "Bản cập nhật phù hợp, đang tải...",
@@ -294,12 +283,12 @@
294 "settings.recipes.customService.headline.communityRecipes": "Công thức của cộng đồng bên thứ 3", 283 "settings.recipes.customService.headline.communityRecipes": "Công thức của cộng đồng bên thứ 3",
295 "settings.recipes.customService.headline.customRecipes": "Công thức của tùy chỉnh bên thứ 3", 284 "settings.recipes.customService.headline.customRecipes": "Công thức của tùy chỉnh bên thứ 3",
296 "settings.recipes.customService.headline.devRecipes": "Công thức dịch vụ phát triển của bạn", 285 "settings.recipes.customService.headline.devRecipes": "Công thức dịch vụ phát triển của bạn",
297 "settings.recipes.customService.intro": "Äể thêm má»™t dịch vụ tùy chỉnh, hãy sao chép công thức dịch vụ vào:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Tài liệu dành cho nhà phát triển", 287 "settings.recipes.customService.openDevDocs": "Tài liệu dành cho nhà phát triển",
299 "settings.recipes.customService.openFolder": "Mở thư mục", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "Các dịch vụ có sẵn", 289 "settings.recipes.headline": "Các dịch vụ có sẵn",
301 "settings.recipes.missingService": "Thiếu một dịch vụ?", 290 "settings.recipes.missingService": "Thiếu một dịch vụ?",
302 "settings.recipes.nothingFound": "Xin lá»—i, không có dịch vụ nào phù hợp vá»›i cụm từ tìm kiếm của bạn - nhÆ°ng bạn vẫn có thể thêm nó bằng cách sá»­ dụng tùy chá»n \"Trang web tùy chỉnh\". Xin lÆ°u ý rằng trang web có thể hiển thị nhiá»u dịch vụ hÆ¡n đã được thêm vào Ferdi kể từ phiên bản bạn Ä‘ang sá»­ dụng. Äể nhận các dịch vụ má»›i đó, vui lòng xem xét nâng cấp lên phiên bản Ferdi má»›i hÆ¡n.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
303 "settings.recipes.servicesSuccessfulAddedInfo": "Äã thêm dịch vụ thành công", 292 "settings.recipes.servicesSuccessfulAddedInfo": "Äã thêm dịch vụ thành công",
304 "settings.searchService": "Tìm kiếm dịch vụ", 293 "settings.searchService": "Tìm kiếm dịch vụ",
305 "settings.service.error.goBack": "Quay lại dịch vụ", 294 "settings.service.error.goBack": "Quay lại dịch vụ",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Äá»™ sáng trình Ä‘á»c tối", 301 "settings.service.form.darkReaderBrightness": "Äá»™ sáng trình Ä‘á»c tối",
313 "settings.service.form.darkReaderContrast": "Äá»™ tÆ°Æ¡ng phản trình Ä‘á»c tối", 302 "settings.service.form.darkReaderContrast": "Äá»™ tÆ°Æ¡ng phản trình Ä‘á»c tối",
314 "settings.service.form.darkReaderSepia": "Màu nâu Ä‘á» của trình Ä‘á»c tối", 303 "settings.service.form.darkReaderSepia": "Màu nâu Ä‘á» của trình Ä‘á»c tối",
315 "settings.service.form.deleteButton": "Xóa dịch vụ", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "Chỉnh sửa {name}", 305 "settings.service.form.editServiceHeadline": "Chỉnh sửa {name}",
317 "settings.service.form.enableAudio": "Cho phép âm thanh", 306 "settings.service.form.enableAudio": "Cho phép âm thanh",
318 "settings.service.form.enableBadge": "Hiển thị huy hiệu tin nhắn chÆ°a Ä‘á»c", 307 "settings.service.form.enableBadge": "Hiển thị huy hiệu tin nhắn chÆ°a Ä‘á»c",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "Khi được kích hoạt, má»™t dịch vụ sẽ bị tắt sau má»™t khoảng thá»i gian để tiết kiệm tài nguyên hệ thống.", 321 "settings.service.form.isHibernatedEnabledInfo": "Khi được kích hoạt, má»™t dịch vụ sẽ bị tắt sau má»™t khoảng thá»i gian để tiết kiệm tài nguyên hệ thống.",
333 "settings.service.form.isMutedInfo": "Khi bị vô hiệu hóa, tất cả âm thanh thông báo và phát lại âm thanh sẽ bị tắt tiếng", 322 "settings.service.form.isMutedInfo": "Khi bị vô hiệu hóa, tất cả âm thanh thông báo và phát lại âm thanh sẽ bị tắt tiếng",
334 "settings.service.form.name": "Tên", 323 "settings.service.form.name": "Tên",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Mở darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Mở darkmode.css",
336 "settings.service.form.openUserCss": "Mở user.css", 326 "settings.service.form.openUserCss": "Mở user.css",
337 "settings.service.form.openUserJs": "Mở user.js", 327 "settings.service.form.openUserJs": "Mở user.js",
338 "settings.service.form.proxy.headline": "Cài đặt Proxy HTTP / HTTPS", 328 "settings.service.form.proxy.headline": "Cài đặt Proxy HTTP / HTTPS",
339 "settings.service.form.proxy.host": "Máy chủ Proxy/IP", 329 "settings.service.form.proxy.host": "Máy chủ Proxy/IP",
340 "settings.service.form.proxy.info": "Cài đặt proxy sẽ không được đồng bộ hóa với máy chủ Ferdi.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Sử dụng Proxy", 331 "settings.service.form.proxy.isEnabled": "Sử dụng Proxy",
342 "settings.service.form.proxy.password": "Mật khẩu (tùy chá»n)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Cổng", 333 "settings.service.form.proxy.port": "Cổng",
344 "settings.service.form.proxy.restartInfo": "Vui lòng khởi động lại Ferdi sau khi thay đổi Cài đặt proxy.", 334 "settings.service.form.proxy.restartInfo": "Vui lòng khởi động lại Ferdi sau khi thay đổi Cài đặt proxy.",
345 "settings.service.form.proxy.user": "NgÆ°á»i dùng (tùy chá»n)", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Các tệp ngÆ°á»i dùng của bạn sẽ được chèn vào trang web để bạn có thể tùy chỉnh các dịch vụ theo bất kỳ cách nào bạn muốn. Các tệp ngÆ°á»i dùng chỉ được lÆ°u trữ cục bá»™ và không được chuyển sang các máy tính khác sá»­ dụng cùng má»™t tài khoản.", 336 "settings.service.form.recipeFileInfo": "Các tệp ngÆ°á»i dùng của bạn sẽ được chèn vào trang web để bạn có thể tùy chỉnh các dịch vụ theo bất kỳ cách nào bạn muốn. Các tệp ngÆ°á»i dùng chỉ được lÆ°u trữ cục bá»™ và không được chuyển sang các máy tính khác sá»­ dụng cùng má»™t tài khoản.",
347 "settings.service.form.saveButton": "Lưu dịch vụ", 337 "settings.service.form.saveButton": "Lưu dịch vụ",
348 "settings.service.form.tabHosted": "Trở thành host", 338 "settings.service.form.tabHosted": "Trở thành host",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Khám phá các dịch vụ", 344 "settings.services.discoverServices": "Khám phá các dịch vụ",
355 "settings.services.headline": "Dịch vụ của bạn", 345 "settings.services.headline": "Dịch vụ của bạn",
356 "settings.services.noServicesAdded": "Bắt đầu bằng cách thêm một dịch vụ.", 346 "settings.services.noServicesAdded": "Bắt đầu bằng cách thêm một dịch vụ.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Không thể tải các dịch vụ của bạn", 348 "settings.services.servicesRequestFailed": "Không thể tải các dịch vụ của bạn",
358 "settings.services.tooltip.isDisabled": "Dịch vụ bị vô hiệu hóa", 349 "settings.services.tooltip.isDisabled": "Dịch vụ bị vô hiệu hóa",
359 "settings.services.tooltip.isMuted": "Tất cả âm thanh Ä‘á»u bị tắt tiếng", 350 "settings.services.tooltip.isMuted": "Tất cả âm thanh Ä‘á»u bị tắt tiếng",
@@ -362,12 +353,12 @@
362 "settings.supportFerdi.aboutIntro": "<p>Ferdi là má»™t ứng dụng mã nguồn mở và dẫn dắt cá»™ng đồng.</p><p>Cảm Æ¡n những ngÆ°á»i tạo nên sá»± khả thi này:</p>", 353 "settings.supportFerdi.aboutIntro": "<p>Ferdi là má»™t ứng dụng mã nguồn mở và dẫn dắt cá»™ng đồng.</p><p>Cảm Æ¡n những ngÆ°á»i tạo nên sá»± khả thi này:</p>",
363 "settings.supportFerdi.bannerText": "Bạn có muốn giúp chúng tôi cải thiện Ferdi không?", 354 "settings.supportFerdi.bannerText": "Bạn có muốn giúp chúng tôi cải thiện Ferdi không?",
364 "settings.supportFerdi.headline": "Giá»›i thiệu vá» phần má»m Ferdi", 355 "settings.supportFerdi.headline": "Giá»›i thiệu vá» phần má»m Ferdi",
365 "settings.supportFerdi.openSurvey": "Mở khảo sát", 356 "settings.supportFerdi.openSurvey": "Open survey",
366 "settings.supportFerdi.textDonation": "Nếu bạn cảm thấy muốn hỗ trợ sự phát triển của Ferdi bằng một khoản đóng góp, bạn có thể làm như vậy trên cả hai,", 357 "settings.supportFerdi.textDonation": "Nếu bạn cảm thấy muốn hỗ trợ sự phát triển của Ferdi bằng một khoản đóng góp, bạn có thể làm như vậy trên cả hai,",
367 "settings.supportFerdi.textDonationAnd": "và", 358 "settings.supportFerdi.textDonationAnd": "và",
368 "settings.supportFerdi.textExpenses": "Trong khi các tình nguyện viên thá»±c hiện hầu hết công việc, chúng tôi vẫn cần trả tiá»n cho các máy chủ và chứng chỉ. Là má»™t cá»™ng đồng, chúng tôi hoàn toàn minh bạch vá» các khoản tiá»n mà chúng tôi thu thập và chi tiêu - hãy xem", 359 "settings.supportFerdi.textExpenses": "Trong khi các tình nguyện viên thá»±c hiện hầu hết công việc, chúng tôi vẫn cần trả tiá»n cho các máy chủ và chứng chỉ. Là má»™t cá»™ng đồng, chúng tôi hoàn toàn minh bạch vá» các khoản tiá»n mà chúng tôi thu thập và chi tiêu - hãy xem",
369 "settings.supportFerdi.textGitHubSponsors": "Tài trợ bởi GitHub", 360 "settings.supportFerdi.textGitHubSponsors": "Tài trợ bởi GitHub",
370 "settings.supportFerdi.textListContributors": "Toàn danh sách ngÆ°á»i đóng góp", 361 "settings.supportFerdi.textListContributors": "Full list of contributors",
371 "settings.supportFerdi.textListContributorsHere": "tại đây", 362 "settings.supportFerdi.textListContributorsHere": "tại đây",
372 "settings.supportFerdi.textOpenCollective": "Mở Cộng đồng", 363 "settings.supportFerdi.textOpenCollective": "Mở Cộng đồng",
373 "settings.supportFerdi.textSupportWelcome": "Hỗ trợ luôn được chào đón. Bạn có thể tìm thấy danh sách trợ giúp mà chúng tôi cần", 364 "settings.supportFerdi.textSupportWelcome": "Hỗ trợ luôn được chào đón. Bạn có thể tìm thấy danh sách trợ giúp mà chúng tôi cần",
@@ -377,7 +368,7 @@
377 "settings.team.contentHeadline": "Quản lý nhóm Franz", 368 "settings.team.contentHeadline": "Quản lý nhóm Franz",
378 "settings.team.copy": "Quản lý nhóm của Franz cho phép bạn quản lý Äăng ký Franz cho nhiá»u ngÆ°á»i dùng. Xin lÆ°u ý rằng việc đăng ký Franz Premium sẽ không mang lại lợi ích gì cho bạn khi sá»­ dụng Ferdi: Lý do duy nhất bạn vẫn có quyá»n truy cập vào Quản lý nhóm là để bạn có thể quản lý Nhóm Franz cÅ© của mình và để bạn không mất bất kỳ chức năng nào trong việc quản lý tài khoản của bạn.", 369 "settings.team.copy": "Quản lý nhóm của Franz cho phép bạn quản lý Äăng ký Franz cho nhiá»u ngÆ°á»i dùng. Xin lÆ°u ý rằng việc đăng ký Franz Premium sẽ không mang lại lợi ích gì cho bạn khi sá»­ dụng Ferdi: Lý do duy nhất bạn vẫn có quyá»n truy cập vào Quản lý nhóm là để bạn có thể quản lý Nhóm Franz cÅ© của mình và để bạn không mất bất kỳ chức năng nào trong việc quản lý tài khoản của bạn.",
379 "settings.team.headline": "Nhóm", 370 "settings.team.headline": "Nhóm",
380 "settings.team.intro": "Bạn hiện Ä‘ang sá»­ dụng Máy chủ Franz, đó là lý do bạn có quyá»n truy cập vào Quản lý nhóm.", 371 "settings.team.intro": "You are currently using Franz Servers, which is why you have access to Team Management.",
381 "settings.team.manageAction": "Quản lý Nhóm của bạn trên meetfranz.com", 372 "settings.team.manageAction": "Quản lý Nhóm của bạn trên meetfranz.com",
382 "settings.team.teamsUnavailable": "Các đội không có sẵn", 373 "settings.team.teamsUnavailable": "Các đội không có sẵn",
383 "settings.team.teamsUnavailableInfo": "Nhóm hiện chỉ khả dụng khi sử dụng Máy chủ Franz và sau khi thanh toán cho Franz Professional. Vui lòng thay đổi máy chủ của bạn thành https://api.franzinfra.com để sử dụng nhóm.", 374 "settings.team.teamsUnavailableInfo": "Nhóm hiện chỉ khả dụng khi sử dụng Máy chủ Franz và sau khi thanh toán cho Franz Professional. Vui lòng thay đổi máy chủ của bạn thành https://api.franzinfra.com để sử dụng nhóm.",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "Phi lợi nhuận", 378 "settings.user.form.accountType.non-profit": "Phi lợi nhuận",
388 "settings.user.form.currentPassword": "Mật khẩu hiện tại", 379 "settings.user.form.currentPassword": "Mật khẩu hiện tại",
389 "settings.user.form.email": "E-mail", 380 "settings.user.form.email": "E-mail",
390 "settings.user.form.firstname": "Tên", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "Há», tên đệm", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "Mật khẩu mới", 383 "settings.user.form.newPassword": "Mật khẩu mới",
393 "settings.workspace.add.form.name": "Tên", 384 "settings.workspace.add.form.name": "Tên",
394 "settings.workspace.add.form.submitButton": "Tạo không gian làm việc", 385 "settings.workspace.add.form.submitButton": "Tạo không gian làm việc",
@@ -405,7 +396,7 @@
405 "settings.workspaces.tryReloadWorkspaces": "Thử lại", 396 "settings.workspaces.tryReloadWorkspaces": "Thử lại",
406 "settings.workspaces.updatedInfo": "Má»i thay đổi đã được lÆ°u lại", 397 "settings.workspaces.updatedInfo": "Má»i thay đổi đã được lÆ°u lại",
407 "settings.workspaces.workspaceFeatureHeadline": "Ãt hÆ¡n là Nhiá»u hÆ¡n: Giá»›i thiệu Không gian làm việc Ferdi", 398 "settings.workspaces.workspaceFeatureHeadline": "Ãt hÆ¡n là Nhiá»u hÆ¡n: Giá»›i thiệu Không gian làm việc Ferdi",
408 "settings.workspaces.workspaceFeatureInfo": "Không gian làm việc Ferdi cho phép bạn tập trung vào những gì quan trá»ng ngay bây giá». Thiết lập các nhóm dịch vụ khác nhau và dá»… dàng chuyển đổi giữa chúng bất kỳ lúc nào. Bạn quyết định dịch vụ nào bạn cần khi nào và ở đâu, vì vậy chúng tôi có thể giúp bạn luôn cập nhật trò chÆ¡i của mình - hoặc dá»… dàng tắt công việc bất cứ khi nào bạn muốn.", 399 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
409 "settings.workspaces.workspacesRequestFailed": "Không thể tải không gian làm việc của bạn", 400 "settings.workspaces.workspacesRequestFailed": "Không thể tải không gian làm việc của bạn",
410 "setupAssistant.headline": "Bắt đầu nào", 401 "setupAssistant.headline": "Bắt đầu nào",
411 "setupAssistant.subheadline": "Chá»n từ các dịch vụ được sá»­ dụng nhiá»u nhất của chúng tôi và nhận lại tin nhắn của bạn ngay bây giá».", 402 "setupAssistant.subheadline": "Chá»n từ các dịch vụ được sá»­ dụng nhiá»u nhất của chúng tôi và nhận lại tin nhắn của bạn ngay bây giá».",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "Bật thông báo và âm thanh", 411 "sidebar.unmuteApp": "Bật thông báo và âm thanh",
421 "signup.email.label": "Äịa chỉ E-mail", 412 "signup.email.label": "Äịa chỉ E-mail",
422 "signup.emailDuplicate": "Má»™t ngÆ°á»i dùng vá»›i địa chỉ email đó đã tồn tại", 413 "signup.emailDuplicate": "Má»™t ngÆ°á»i dùng vá»›i địa chỉ email đó đã tồn tại",
423 "signup.firstname.label": "Tên", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "Äăng ký", 415 "signup.headline": "Äăng ký",
425 "signup.lastname.label": "Há», tên đệm", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "Bằng cách tạo tài khoản Ferdi, bạn chấp nhận", 417 "signup.legal.info": "Bằng cách tạo tài khoản Ferdi, bạn chấp nhận",
427 "signup.legal.privacy": "Cam kết Bảo mật", 418 "signup.legal.privacy": "Cam kết Bảo mật",
428 "signup.legal.terms": "Äiá»u khoản dịch vụ", 419 "signup.legal.terms": "Äiá»u khoản dịch vụ",
@@ -430,23 +421,23 @@
430 "signup.password.label": "Mật khẩu", 421 "signup.password.label": "Mật khẩu",
431 "signup.submit.label": "Tạo Tài khoản", 422 "signup.submit.label": "Tạo Tài khoản",
432 "tabs.item.confirmDeleteService": "Bạn có thực sự muốn xóa dịch vụ {serviceName} không?", 423 "tabs.item.confirmDeleteService": "Bạn có thực sự muốn xóa dịch vụ {serviceName} không?",
433 "tabs.item.deleteService": "Xóa dịch vụ", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "Vô hiệu hóa âm thanh", 425 "tabs.item.disableAudio": "Vô hiệu hóa âm thanh",
435 "tabs.item.disableDarkMode": "Vô hiệu hóa chế độ tối", 426 "tabs.item.disableDarkMode": "Vô hiệu hóa chế độ tối",
436 "tabs.item.disableNotifications": "Vô hiệu hóa thông báo", 427 "tabs.item.disableNotifications": "Vô hiệu hóa thông báo",
437 "tabs.item.disableService": "Vô hiệu hóa dịch vụ", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "Cho phép âm thanh", 429 "tabs.item.enableAudio": "Cho phép âm thanh",
439 "tabs.item.enableDarkMode": "Kích hoạt chế độ tối", 430 "tabs.item.enableDarkMode": "Kích hoạt chế độ tối",
440 "tabs.item.enableNotification": "Kích hoạt thông báo", 431 "tabs.item.enableNotification": "Kích hoạt thông báo",
441 "tabs.item.enableService": "Kích hoạt dịch vụ", 432 "tabs.item.enableService": "Kích hoạt dịch vụ",
442 "tabs.item.hibernateService": "ÄÆ°a dịch vụ vào trạng thái ngủ đông", 433 "tabs.item.hibernateService": "Hibernate service",
443 "tabs.item.reload": "Tải lại", 434 "tabs.item.reload": "Tải lại",
444 "tabs.item.wakeUpService": "Äánh thức dịch vụ", 435 "tabs.item.wakeUpService": "Wake up service",
445 "validation.email": "{field} không hợp lệ", 436 "validation.email": "{field} is not valid",
446 "validation.minLength": "{field} phải dài ít nhất {length} ký tự", 437 "validation.minLength": "{field} should be at least {length} characters long",
447 "validation.oneRequired": "Ãt nhất má»™t cái được yêu cầu", 438 "validation.oneRequired": "Ãt nhất má»™t cái được yêu cầu",
448 "validation.required": "{field} là bắt buộc", 439 "validation.required": "{field} is required",
449 "validation.url": "{field} không phải là URL hợp lệ", 440 "validation.url": "{field} is not a valid URL",
450 "webControls.back": "Quay lại", 441 "webControls.back": "Quay lại",
451 "webControls.forward": "Tá»›i trÆ°á»›c", 442 "webControls.forward": "Tá»›i trÆ°á»›c",
452 "webControls.goHome": "Trang chủ", 443 "webControls.goHome": "Trang chủ",
@@ -454,12 +445,12 @@
454 "webControls.reload": "Tải lại", 445 "webControls.reload": "Tải lại",
455 "welcome.loginButton": "Äăng nhập vào tài khoản của bạn", 446 "welcome.loginButton": "Äăng nhập vào tài khoản của bạn",
456 "welcome.signupButton": "Tạo tài khoản miễn phí", 447 "welcome.signupButton": "Tạo tài khoản miễn phí",
457 "workspaceDrawer.addNewWorkspaceLabel": "Thêm Không gian làm việc mới", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "Tất cả Dịch vụ", 449 "workspaceDrawer.allServices": "Tất cả Dịch vụ",
459 "workspaceDrawer.headline": "Không gian làm việc", 450 "workspaceDrawer.headline": "Không gian làm việc",
460 "workspaceDrawer.item.contextMenuEdit": "chỉnh sửa", 451 "workspaceDrawer.item.contextMenuEdit": "chỉnh sửa",
461 "workspaceDrawer.item.noServicesAddedYet": "Không có dịch vụ bổ sung", 452 "workspaceDrawer.item.noServicesAddedYet": "Không có dịch vụ bổ sung",
462 "workspaceDrawer.workspaceFeatureInfo": "<p> Ferdi Workspaces cho phép bạn tập trung vào những gì quan trá»ng ngay bây giá». Thiết lập các nhóm dịch vụ khác nhau và dá»… dàng chuyển đổi giữa chúng bất kỳ lúc nào. </p> <p> Bạn quyết định dịch vụ nào bạn cần khi nào và ở đâu, vì vậy chúng tôi có thể giúp bạn luôn cập nhật trò chÆ¡i của mình - hoặc dá»… dàng tắt khá»i công việc bất cứ khi nào bạn muốn. </p>", 453 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
463 "workspaceDrawer.workspacesSettingsTooltip": "Chỉnh sửa cài đặt không gian làm việc", 454 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
464 "workspaces.switchingIndicator.switchingTo": "Chuyển sang" 455 "workspaces.switchingIndicator.switchingTo": "Chuyển sang"
465} 456}
diff --git a/src/i18n/locales/zh-CN.json b/src/i18n/locales/zh-CN.json
deleted file mode 100644
index 632127f4d..000000000
--- a/src/i18n/locales/zh-CN.json
+++ /dev/null
@@ -1,413 +0,0 @@
1{
2 "app.errorHandler.action": "Reload",
3 "app.errorHandler.headline": "Something went wrong",
4 "feature.announcements.changelog.headline": "Changes in Ferdi {version}",
5 "feature.debugger.title": "Publish debugging information",
6 "feature.publishDebugInfo.error": "There was an error while trying to publish the debug information. Please try again later or view the console for more information.",
7 "feature.publishDebugInfo.info": "Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service",
8 "feature.publishDebugInfo.privacy": "Privacy policy",
9 "feature.publishDebugInfo.publish": "Accept and publish",
10 "feature.publishDebugInfo.published": "Your debug log was published and is now availible at",
11 "feature.publishDebugInfo.terms": "Terms of service",
12 "feature.publishDebugInfo.title": "Publish debug information",
13 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
14 "feature.quickSwitch.search": "Search...",
15 "feature.quickSwitch.title": "QuickSwitch",
16 "feature.shareFranz.action.email": "Send as email",
17 "feature.shareFranz.action.facebook": "Share on Facebook",
18 "feature.shareFranz.action.twitter": "Share on Twitter",
19 "feature.shareFranz.headline": "Ferdi is better together!",
20 "feature.shareFranz.shareText.email": "I've added {count} services to Ferdi! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.getferdi.com",
21 "feature.shareFranz.shareText.twitter": "I've added {count} services to Ferdi! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.getferdi.com /cc @FerdiMessenger",
22 "feature.shareFranz.text": "Tell your friends and colleagues how awesome Ferdi is and help us to spread the word.",
23 "global.api.unhealthy": "Can't connect to Ferdi online services",
24 "global.edit": "Edit",
25 "global.franzProRequired": "Ferdi Professional Required",
26 "global.notConnectedToTheInternet": "You are not connected to the internet.",
27 "global.quit": "Quit",
28 "global.settings": "Settings",
29 "global.spellchecker.useDefault": "Use System Default ({default})",
30 "global.spellchecking.autodetect": "Detect language automatically",
31 "global.spellchecking.autodetect.short": "Automatic",
32 "global.spellchecking.language": "Spell checking language",
33 "global.submit": "Submit",
34 "import.headline": "Import your Ferdi 4 services",
35 "import.notSupportedHeadline": "Services not yet supported in Ferdi 5",
36 "import.skip.label": "I want to add services manually",
37 "import.submit.label": "Import services",
38 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
39 "infobar.buttonChangelog": "What is new?",
40 "infobar.buttonInstallUpdate": "Restart & install update",
41 "infobar.buttonReloadServices": "Reload services",
42 "infobar.requiredRequestsFailed": "Could not load services and user information",
43 "infobar.servicesUpdated": "Your services have been updated.",
44 "infobar.updateAvailable": "A new update for Ferdi is available.",
45 "invite.email.label": "Email address",
46 "invite.headline.friends": "Invite 3 of your friends or colleagues",
47 "invite.name.label": "Name",
48 "invite.skip.label": "I want to do this later",
49 "invite.submit.label": "Send invites",
50 "invite.successInfo": "Invitations sent successfully",
51 "locked.headline": "Locked",
52 "locked.info": "Ferdi is currently locked. Please unlock Ferdi with your password to see your messages.",
53 "locked.invalidCredentials": "Password invalid",
54 "locked.password.label": "Password",
55 "locked.submit.label": "Unlock",
56 "login.changeServer": "Change server",
57 "login.customServerQuestion": "Using a custom Ferdi server?",
58 "login.customServerSuggestion": "Try importing your Franz account",
59 "login.email.label": "Email address",
60 "login.headline": "Sign in",
61 "login.invalidCredentials": "Email or password not valid",
62 "login.link.password": "Reset password",
63 "login.link.signup": "Create a free account",
64 "login.password.label": "Password",
65 "login.serverLogout": "Your session expired, please login again.",
66 "login.submit.label": "Sign in",
67 "login.tokenExpired": "Your session expired, please login again.",
68 "menu.Todoss.closeTodosDrawer": "Close Todos drawer",
69 "menu.Todoss.openTodosDrawer": "Open Todos drawer",
70 "menu.app.about": "About Ferdi",
71 "menu.app.announcement": "What's new?",
72 "menu.app.autohideMenuBar": "Auto-hide menu bar",
73 "menu.app.checkForUpdates": "Check for updates",
74 "menu.app.hide": "Hide",
75 "menu.app.hideOthers": "Hide Others",
76 "menu.app.unhide": "Unhide",
77 "menu.edit": "Edit",
78 "menu.edit.copy": "Copy",
79 "menu.edit.cut": "Cut",
80 "menu.edit.delete": "Delete",
81 "menu.edit.emojiSymbols": "Emoji & Symbols",
82 "menu.edit.paste": "Paste",
83 "menu.edit.pasteAndMatchStyle": "Paste And Match Style",
84 "menu.edit.redo": "Redo",
85 "menu.edit.selectAll": "Select All",
86 "menu.edit.speech": "Speech",
87 "menu.edit.startDictation": "Start Dictation",
88 "menu.edit.startSpeaking": "Start Speaking",
89 "menu.edit.stopSpeaking": "Stop Speaking",
90 "menu.edit.undo": "Undo",
91 "menu.file": "File",
92 "menu.help": "Help",
93 "menu.help.changelog": "Changelog",
94 "menu.help.debugInfo": "Copy Debug Information",
95 "menu.help.debugInfoCopiedBody": "Your Debug Information has been copied to your clipboard.",
96 "menu.help.debugInfoCopiedHeadline": "Ferdi Debug Information",
97 "menu.help.learnMore": "Learn More",
98 "menu.help.privacy": "Privacy Statement",
99 "menu.help.publishDebugInfo": "Publish Debug Information",
100 "menu.help.support": "Support",
101 "menu.help.tos": "Terms of Service",
102 "menu.services": "Services",
103 "menu.services.activatePreviousService": "Activate previous service",
104 "menu.services.addNewService": "Add New Service...",
105 "menu.services.goHome": "Home",
106 "menu.services.setNextServiceActive": "Activate next service",
107 "menu.todos": "Todos",
108 "menu.todos.enableTodos": "Enable Todos",
109 "menu.view": "View",
110 "menu.view.back": "Back",
111 "menu.view.forward": "Forward",
112 "menu.view.lockFerdi": "Lock Ferdi",
113 "menu.view.openQuickSwitch": "Open Quick Switch",
114 "menu.view.reloadFerdi": "Reload Ferdi",
115 "menu.view.reloadService": "Reload Service",
116 "menu.view.resetZoom": "Actual Size",
117 "menu.view.toggleDevTools": "Toggle Developer Tools",
118 "menu.view.toggleFullScreen": "Toggle Full Screen",
119 "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools",
120 "menu.view.toggleTodosDevTools": "Toggle Todos Developer Tools",
121 "menu.view.zoomIn": "Zoom In",
122 "menu.view.zoomOut": "Zoom Out",
123 "menu.window": "Window",
124 "menu.window.close": "Close",
125 "menu.window.minimize": "Minimize",
126 "menu.workspaces": "Workspaces",
127 "menu.workspaces.addNewWorkspace": "Add New Workspace...",
128 "menu.workspaces.closeWorkspaceDrawer": "Close workspace drawer",
129 "menu.workspaces.defaultWorkspace": "All services",
130 "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer",
131 "password.email.label": "Email address",
132 "password.headline": "Reset password",
133 "password.link.login": "Sign in to your account",
134 "password.link.signup": "Create a free account",
135 "password.noUser": "No user with that email address was found",
136 "password.successInfo": "Please check your email",
137 "premiumFeature.button.upgradeAccount": "Upgrade account",
138 "pricing.features.accountSync": "Account Synchronisation",
139 "pricing.features.adFree": "Forever ad-free",
140 "pricing.features.appDelays": "No Waiting Screens",
141 "pricing.features.customWebsites": "Add Custom Websites",
142 "pricing.features.desktopNotifications": "Desktop Notifications",
143 "pricing.features.onPremise": "On-premise & other Hosted Services",
144 "pricing.features.recipes": "Choose from more than 70 Services",
145 "pricing.features.serviceProxies": "Service Proxies",
146 "pricing.features.spellchecker": "Spellchecker support",
147 "pricing.features.teamManagement": "Team Management",
148 "pricing.features.thirdPartyServices": "Install 3rd party services",
149 "pricing.features.unlimitedServices": "Add unlimited services",
150 "pricing.features.upToSixServices": "Add up to 6 services",
151 "pricing.features.upToThreeServices": "Add up to 3 services",
152 "pricing.features.workspaces": "Workspaces",
153 "service.crashHandler.action": "Reload {name}",
154 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
155 "service.crashHandler.headline": "Oh no!",
156 "service.crashHandler.text": "{name} has caused an error.",
157 "service.disabledHandler.action": "Enable {name}",
158 "service.disabledHandler.headline": "{name} is disabled",
159 "service.errorHandler.action": "Reload {name}",
160 "service.errorHandler.editAction": "Edit {name}",
161 "service.errorHandler.headline": "Oh no!",
162 "service.errorHandler.message": "Error",
163 "service.errorHandler.text": "{name} has failed to load.",
164 "service.webviewLoader.loading": "Loading {service}",
165 "services.getStarted": "Get started",
166 "services.login": "Please login to use Ferdi.",
167 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
168 "services.serverless": "Use Ferdi without an Account",
169 "services.welcome": "Welcome to Ferdi",
170 "settings.account.account.editButton": "Edit account",
171 "settings.account.accountType.basic": "Basic Account",
172 "settings.account.accountType.premium": "Premium Supporter Account",
173 "settings.account.accountUnavailable": "Account is unavailable",
174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
175 "settings.account.buttonSave": "Update profile",
176 "settings.account.deleteAccount": "Delete account",
177 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
178 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
179 "settings.account.headline": "Account",
180 "settings.account.headlineAccount": "Account information",
181 "settings.account.headlineDangerZone": "Danger Zone",
182 "settings.account.headlineInvoices": "Invoices",
183 "settings.account.headlinePassword": "Change password",
184 "settings.account.headlineProfile": "Update profile",
185 "settings.account.successInfo": "Your changes have been saved",
186 "settings.account.tryReloadServices": "Try again",
187 "settings.account.tryReloadUserInfoRequest": "Try again",
188 "settings.account.userInfoRequestFailed": "Could not load user information",
189 "settings.account.yourLicense": "Your Ferdi License",
190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
191 "settings.app.buttonClearAllCache": "Clear cache",
192 "settings.app.buttonInstallUpdate": "Restart & install update",
193 "settings.app.buttonSearchForUpdate": "Check for updates",
194 "settings.app.cacheInfo": "Ferdi cache is currently using {size} of disk space.",
195 "settings.app.currentVersion": "Current version:",
196 "settings.app.form.accentColor": "Accent color",
197 "settings.app.form.adaptableDarkMode": "Synchronize dark mode with my OS's dark mode setting",
198 "settings.app.form.autoLaunchInBackground": "Open in background",
199 "settings.app.form.autoLaunchOnStart": "Launch Ferdi on start",
200 "settings.app.form.beta": "Include beta versions",
201 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
202 "settings.app.form.darkMode": "Enable dark mode",
203 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
204 "settings.app.form.enableLock": "Enable Password Lock",
205 "settings.app.form.enableSpellchecking": "Enable spell checking",
206 "settings.app.form.enableSystemTray": "Show Ferdi in system tray",
207 "settings.app.form.enableTodos": "Enable Ferdi Todos",
208 "settings.app.form.hibernationStrategy": "Hibernation strategy",
209 "settings.app.form.iconSize": "Service icon size",
210 "settings.app.form.inactivityLock": "Lock after inactivity",
211 "settings.app.form.keepAllWorkspacesLoaded": "Keep all workspaces loaded",
212 "settings.app.form.language": "Language",
213 "settings.app.form.lockPassword": "Password",
214 "settings.app.form.minimizeToSystemTray": "Minimize Ferdi to system tray",
215 "settings.app.form.noUpdates": "Disable updates",
216 "settings.app.form.privateNotifications": "Don't show message content in notifications",
217 "settings.app.form.runInBackground": "Keep Ferdi in background when closing the window",
218 "settings.app.form.scheduledDNDEnabled": "Enable scheduled Do-not-Disturb",
219 "settings.app.form.scheduledDNDEnd": "To",
220 "settings.app.form.scheduledDNDStart": "From",
221 "settings.app.form.sentry": "Send telemetry data",
222 "settings.app.form.server": "Server",
223 "settings.app.form.serviceRibbonWidth": "Sidebar width",
224 "settings.app.form.showDisabledServices": "Display disabled services tabs",
225 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
226 "settings.app.form.showServiceNavigationBar": "Always show service navigation bar",
227 "settings.app.form.startMinimized": "Start minimized in tray",
228 "settings.app.form.todoServer": "Todo Server",
229 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
230 "settings.app.headlineAdvanced": "Advanced",
231 "settings.app.headlineAppearance": "Appearance",
232 "settings.app.headlineGeneral": "General",
233 "settings.app.headlineLanguage": "Language",
234 "settings.app.headlineUpdates": "Updates",
235 "settings.app.hibernateInfo": "By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.",
236 "settings.app.inactivityLockInfo": "Minutes of inactivity, after which Ferdi should automatically lock. Use 0 to disable",
237 "settings.app.languageDisclaimer": "Official translations are English & German. All other languages are community based translations.",
238 "settings.app.lockInfo": "Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
239 "settings.app.lockedPassword": "Password",
240 "settings.app.lockedPasswordInfo": "Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
241 "settings.app.restartRequired": "Changes require restart",
242 "settings.app.scheduledDNDInfo": "Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.",
243 "settings.app.scheduledDNDTimeInfo": "Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
244 "settings.app.sentryInfo": "Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!",
245 "settings.app.serverInfo": "We advice you to logout after changing your server as your settings might not be saved otherwise.",
246 "settings.app.serverMoneyInfo": "You are using the official Franz Server for Ferdi.\nWe know that Ferdi allows you to use all its features for free but you are still using Franz's server resources - which Franz's creator has to pay for.\nPlease still consider [Link 1]paying for a Franz account[/Link] or [Link 2]using a self-hosted ferdi-server[/Link] (if you have the knowledge and resources to do so). \nBy using Ferdi, you still profit greatly from Franz's recipe store, server resources and its development.",
247 "settings.app.subheadlineCache": "Cache",
248 "settings.app.todoServerInfo": "This server will be used for the \"Ferdi Todo\" feature. (default: https://app.franztodos.com)",
249 "settings.app.translationHelp": "Help us to translate Ferdi into your language.",
250 "settings.app.universalDarkModeInfo": "Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.",
251 "settings.app.updateStatusAvailable": "Update available, downloading...",
252 "settings.app.updateStatusSearching": "Is searching for update",
253 "settings.app.updateStatusUpToDate": "You are using the latest version of Ferdi",
254 "settings.invite.headline": "Invite Friends",
255 "settings.navigation.account": "Account",
256 "settings.navigation.availableServices": "Available services",
257 "settings.navigation.logout": "Logout",
258 "settings.navigation.supportFerdi": "Support Ferdi",
259 "settings.navigation.team": "Manage Team",
260 "settings.navigation.yourServices": "Your services",
261 "settings.navigation.yourWorkspaces": "Your workspaces",
262 "settings.recipes.all": "All services",
263 "settings.recipes.custom": "Custom Services",
264 "settings.recipes.customService.headline.communityRecipes": "Community 3rd Party Recipes",
265 "settings.recipes.customService.headline.customRecipes": "Custom 3rd Party Recipes",
266 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
267 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
268 "settings.recipes.customService.openDevDocs": "Developer Documentation",
269 "settings.recipes.customService.openFolder": "Open folder",
270 "settings.recipes.headline": "Available services",
271 "settings.recipes.missingService": "Missing a service?",
272 "settings.recipes.nothingFound": "Sorry, but no service matched your search term. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
273 "settings.recipes.servicesSuccessfulAddedInfo": "Service successfully added",
274 "settings.searchService": "Search service",
275 "settings.service.error.goBack": "Back to services",
276 "settings.service.error.headline": "Error",
277 "settings.service.error.message": "Could not load service recipe.",
278 "settings.service.form.addServiceHeadline": "Add {name}",
279 "settings.service.form.availableServices": "Available services",
280 "settings.service.form.customUrl": "Custom server",
281 "settings.service.form.customUrlPremiumInfo": "To add self hosted services, you need a Ferdi Premium Supporter Account.",
282 "settings.service.form.customUrlUpgradeAccount": "Upgrade your account",
283 "settings.service.form.customUrlValidationError": "Could not validate custom {name} server.",
284 "settings.service.form.deleteButton": "Delete service",
285 "settings.service.form.editServiceHeadline": "Edit {name}",
286 "settings.service.form.enableAudio": "Enable audio",
287 "settings.service.form.enableBadge": "Show unread message badges",
288 "settings.service.form.enableDarkMode": "Enable Dark Mode",
289 "settings.service.form.enableNotification": "Enable notifications",
290 "settings.service.form.enableService": "Enable service",
291 "settings.service.form.headlineBadges": "Unread message badges",
292 "settings.service.form.headlineGeneral": "General",
293 "settings.service.form.headlineNotifications": "Notifications",
294 "settings.service.form.icon": "Custom icon",
295 "settings.service.form.iconDelete": "Delete",
296 "settings.service.form.iconUpload": "Drop your image, or click here",
297 "settings.service.form.indirectMessageInfo": "You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
298 "settings.service.form.indirectMessages": "Show message badge for all new messages",
299 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
300 "settings.service.form.name": "Name",
301 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
302 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
303 "settings.service.form.proxy.host": "Proxy Host/IP",
304 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.",
305 "settings.service.form.proxy.isEnabled": "Use Proxy",
306 "settings.service.form.proxy.password": "Password (optional)",
307 "settings.service.form.proxy.port": "Port",
308 "settings.service.form.proxy.restartInfo": "Please restart Ferdi after changing proxy Settings.",
309 "settings.service.form.proxy.user": "User (optional)",
310 "settings.service.form.saveButton": "Save service",
311 "settings.service.form.tabHosted": "Hosted",
312 "settings.service.form.tabOnPremise": "Self hosted â­ï¸",
313 "settings.service.form.team": "Team",
314 "settings.service.form.useHostedService": "Use the hosted {name} service.",
315 "settings.service.form.yourServices": "Your services",
316 "settings.services.deletedInfo": "Service has been deleted",
317 "settings.services.discoverServices": "Discover services",
318 "settings.services.headline": "Your services",
319 "settings.services.noServicesAdded": "You haven't added any services yet.",
320 "settings.services.servicesRequestFailed": "Could not load your services",
321 "settings.services.tooltip.isDisabled": "Service is disabled",
322 "settings.services.tooltip.isMuted": "All sounds are muted",
323 "settings.services.tooltip.notificationsDisabled": "Notifications are disabled",
324 "settings.services.updatedInfo": "Your changes have been saved",
325 "settings.supportFerdi.github": "Star on GitHub",
326 "settings.supportFerdi.headline": "Support Ferdi",
327 "settings.supportFerdi.openCollective": "Support our Open Collective",
328 "settings.supportFerdi.share": "Tell your Friends",
329 "settings.supportFerdi.title": "Do you like Ferdi? Spread the love!",
330 "settings.team.contentHeadline": "Ferdi for Teams",
331 "settings.team.copy": "Ferdi for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!",
332 "settings.team.headline": "Team",
333 "settings.team.intro": "You and your team use Ferdi? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.",
334 "settings.team.manageAction": "Manage your Team on getferdi.com",
335 "settings.team.teamsUnavailable": "Teams are unavailable",
336 "settings.team.teamsUnavailableInfo": "Teams are currently only available when using the Franz Server and after paying for Franz Professional. Please change your server to https://api.franzinfra.com to use teams.",
337 "settings.team.upgradeAction": "Upgrade your Account",
338 "settings.user.form.accountType.company": "Company",
339 "settings.user.form.accountType.individual": "Individual",
340 "settings.user.form.accountType.label": "Account type",
341 "settings.user.form.accountType.non-profit": "Non-Profit",
342 "settings.user.form.currentPassword": "Current password",
343 "settings.user.form.email": "Email",
344 "settings.user.form.firstname": "First Name",
345 "settings.user.form.lastname": "Last Name",
346 "settings.user.form.newPassword": "New password",
347 "settings.workspace.add.form.name": "Name",
348 "settings.workspace.add.form.submitButton": "Create workspace",
349 "settings.workspace.form.buttonDelete": "Delete workspace",
350 "settings.workspace.form.buttonSave": "Save workspace",
351 "settings.workspace.form.keepLoaded": "Keep this workspace loaded*",
352 "settings.workspace.form.keepLoadedInfo": "*This option will be overwritten by the global \"Keep all workspaces loaded\" option.",
353 "settings.workspace.form.name": "Name",
354 "settings.workspace.form.servicesInWorkspaceHeadline": "Services in this Workspace",
355 "settings.workspace.form.yourWorkspaces": "Your workspaces",
356 "settings.workspaces.deletedInfo": "Workspace has been deleted",
357 "settings.workspaces.headline": "Your workspaces",
358 "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.",
359 "settings.workspaces.tryReloadWorkspaces": "Try again",
360 "settings.workspaces.updatedInfo": "Your changes have been saved",
361 "settings.workspaces.workspaceFeatureHeadline": "Less is More: Introducing Ferdi Workspaces",
362 "settings.workspaces.workspaceFeatureInfo": "Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.",
363 "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces",
364 "sidebar.addNewService": "Add new service",
365 "sidebar.closeTodosDrawer": "Close Ferdi Todos",
366 "sidebar.closeWorkspaceDrawer": "Close workspace drawer",
367 "sidebar.lockFerdi": "Lock Ferdi",
368 "sidebar.muteApp": "Disable notifications & audio",
369 "sidebar.openTodosDrawer": "Open Ferdi Todos",
370 "sidebar.openWorkspaceDrawer": "Open workspace drawer",
371 "sidebar.unmuteApp": "Enable notifications & audio",
372 "signup.email.label": "Email address",
373 "signup.emailDuplicate": "A user with that email address already exists",
374 "signup.firstname.label": "First Name",
375 "signup.headline": "Sign up",
376 "signup.lastname.label": "Last Name",
377 "signup.legal.info": "By creating a Ferdi account you accept the",
378 "signup.legal.privacy": "Privacy Statement",
379 "signup.legal.terms": "Terms of service",
380 "signup.link.login": "Already have an account, sign in?",
381 "signup.password.label": "Password",
382 "signup.submit.label": "Create account",
383 "tabs.item.deleteService": "Delete service",
384 "tabs.item.disableAudio": "Disable audio",
385 "tabs.item.disableNotifications": "Disable notifications",
386 "tabs.item.disableService": "Disable service",
387 "tabs.item.enableAudio": "Enable audio",
388 "tabs.item.enableNotification": "Enable notifications",
389 "tabs.item.enableService": "Enable service",
390 "tabs.item.reload": "Reload",
391 "validation.email": "{field} is not valid",
392 "validation.minLength": "{field} should be at least {length} characters long",
393 "validation.oneRequired": "At least one is required",
394 "validation.required": "{field} is required",
395 "validation.url": "{field} is not a valid URL",
396 "webControls.back": "Back",
397 "webControls.forward": "Forward",
398 "webControls.goHome": "Home",
399 "webControls.openInBrowser": "Open in Browser",
400 "webControls.reload": "Reload",
401 "welcome.loginButton": "Login to your account",
402 "welcome.signupButton": "Create a free account",
403 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
404 "workspaceDrawer.allServices": "All services",
405 "workspaceDrawer.headline": "Workspaces",
406 "workspaceDrawer.item.contextMenuEdit": "edit",
407 "workspaceDrawer.item.noServicesAddedYet": "No services added yet",
408 "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace",
409 "workspaceDrawer.reactivatePremiumAccountLabel": "Reactivate premium account",
410 "workspaceDrawer.workspaceFeatureInfo": "<p>Ferdi Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>",
411 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
412 "workspaces.switchingIndicator.switchingTo": "Switching to"
413}
diff --git a/src/i18n/locales/zh-HANT.json b/src/i18n/locales/zh-HANT.json
index 22a0b6771..ec6d9085b 100644
--- a/src/i18n/locales/zh-HANT.json
+++ b/src/i18n/locales/zh-HANT.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "é‡æ–°åŠ è¼‰", 2 "app.errorHandler.action": "é‡æ–°åŠ è¼‰",
3 "app.errorHandler.headline": "出ç¾éŒ¯èª¤", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "切æ›æœå‹™å™¨", 5 "changeserver.headline": "切æ›æœå‹™å™¨",
6 "changeserver.label": "伺æœå™¨", 6 "changeserver.label": "伺æœå™¨",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "What happened?", 10 "connectionLostBanner.informationLink": "What happened?",
11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.", 11 "connectionLostBanner.message": "Oh no! Ferdi lost the connection to {name}.",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "發布除錯訊æ¯",
14 "feature.nightlyBuilds.activate": "Activate", 13 "feature.nightlyBuilds.activate": "Activate",
15 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.", 14 "feature.nightlyBuilds.info": "Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
16 "feature.nightlyBuilds.title": "Nightly Builds", 15 "feature.nightlyBuilds.title": "Nightly Builds",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.", 23 "feature.quickSwitch.info": "Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
25 "feature.quickSwitch.search": "æœå°‹...", 24 "feature.quickSwitch.search": "æœå°‹...",
26 "feature.quickSwitch.title": "QuickSwitch", 25 "feature.quickSwitch.title": "QuickSwitch",
27 "global.api.unhealthy": "無法連接到Ferdi網路æœå‹™", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "å–消", 27 "global.cancel": "Cancel",
29 "global.edit": "編輯", 28 "global.edit": "編輯",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "您未連上網際網路", 30 "global.notConnectedToTheInternet": "您未連上網際網路",
@@ -33,21 +32,21 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "設置", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "使用系統é è¨­å€¼({default})", 36 "global.spellchecker.useDefault": "使用系統é è¨­å€¼({default})",
38 "global.spellchecking.autodetect": "自動檢測語言", 37 "global.spellchecking.autodetect": "自動檢測語言",
39 "global.spellchecking.autodetect.short": "自動", 38 "global.spellchecking.autodetect.short": "自動",
40 "global.spellchecking.language": "拼字檢查語言", 39 "global.spellchecking.language": "拼字檢查語言",
41 "global.submit": "é€å‡º", 40 "global.submit": "Submit",
42 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.", 41 "global.userAgentHelp": "Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
43 "global.userAgentPref": "User Agent", 42 "global.userAgentPref": "User Agent",
44 "global.yes": "Yes", 43 "global.yes": "Yes",
45 "import.headline": "匯入您的 Ferdi 4 æœå‹™", 44 "import.headline": "匯入您的 Ferdi 4 æœå‹™",
46 "import.notSupportedHeadline": "æ­¤æœå‹™ä¸è¢« Ferdi 5 支æŒ", 45 "import.notSupportedHeadline": "æ­¤æœå‹™ä¸è¢« Ferdi 5 支æŒ",
47 "import.skip.label": "我想手動匯入", 46 "import.skip.label": "我想手動匯入",
48 "import.submit.label": "匯入æœå‹™", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.", 48 "infobar.authRequestFailed": "There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
50 "infobar.buttonChangelog": "最新消æ¯!", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "é‡æ–°å•Ÿå‹•ä¸¦ä¸”æ›´æ–°", 50 "infobar.buttonInstallUpdate": "é‡æ–°å•Ÿå‹•ä¸¦ä¸”æ›´æ–°",
52 "infobar.buttonReloadServices": "é‡æ–°è¼‰å…¥", 51 "infobar.buttonReloadServices": "é‡æ–°è¼‰å…¥",
53 "infobar.hide": "éš±è—", 52 "infobar.hide": "éš±è—",
@@ -75,7 +74,7 @@
75 "login.email.label": "é›»å­éƒµä»¶ä¿¡ç®±", 74 "login.email.label": "é›»å­éƒµä»¶ä¿¡ç®±",
76 "login.headline": "登入", 75 "login.headline": "登入",
77 "login.invalidCredentials": "é›»å­éƒµä»¶å¸³æˆ¶æˆ–密碼有誤", 76 "login.invalidCredentials": "é›»å­éƒµä»¶å¸³æˆ¶æˆ–密碼有誤",
78 "login.link.password": "密碼é‡è¨­", 77 "login.link.password": "Reset password",
79 "login.link.signup": "建立一個å…費帳戶", 78 "login.link.signup": "建立一個å…費帳戶",
80 "login.password.label": "密碼", 79 "login.password.label": "密碼",
81 "login.serverLogout": "登入狀態éŽæœŸï¼Œè«‹é‡æ–°ç™»å…¥", 80 "login.serverLogout": "登入狀態éŽæœŸï¼Œè«‹é‡æ–°ç™»å…¥",
@@ -118,7 +117,7 @@
118 "menu.help.tos": "æœå‹™æ¢æ¬¾", 117 "menu.help.tos": "æœå‹™æ¢æ¬¾",
119 "menu.services": "æœå‹™", 118 "menu.services": "æœå‹™",
120 "menu.services.activatePreviousService": "Activate previous service", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "主é ", 121 "menu.services.goHome": "主é ",
123 "menu.services.setNextServiceActive": "Activate next service", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "Todos", 123 "menu.todos": "Todos",
@@ -148,22 +147,11 @@
148 "menu.workspaces.defaultWorkspace": "所有æœå‹™", 147 "menu.workspaces.defaultWorkspace": "所有æœå‹™",
149 "menu.workspaces.openWorkspaceDrawer": "打開工作å€", 148 "menu.workspaces.openWorkspaceDrawer": "打開工作å€",
150 "password.email.label": "é›»å­éƒµä»¶ä¿¡ç®±", 149 "password.email.label": "é›»å­éƒµä»¶ä¿¡ç®±",
151 "password.headline": "密碼é‡è¨­", 150 "password.headline": "Reset password",
152 "password.link.login": "登入您的帳戶", 151 "password.link.login": "登入您的帳戶",
153 "password.link.signup": "建立一個å…費帳戶", 152 "password.link.signup": "建立一個å…費帳戶",
154 "password.noUser": "此電å­éƒµä»¶å¸³æˆ¶ä¸å­˜åœ¨", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "è«‹é‡æ–°ç¢ºèªæ‚¨çš„é›»å­éƒµä»¶ä¿¡ç®±", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "帳號åŒæ­¥",
157 "pricing.features.customWebsites": "添加自訂網站",
158 "pricing.features.desktopNotifications": "æ¡Œé¢é€šçŸ¥",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "工作å€",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "唉呀 糟糕!", 157 "service.crashHandler.headline": "唉呀 糟糕!",
@@ -181,7 +169,7 @@
181 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!", 169 "services.serverInfo": "Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
182 "services.serverless": "Use Ferdi without an Account", 170 "services.serverless": "Use Ferdi without an Account",
183 "services.welcome": "歡迎使用 Ferdi", 171 "services.welcome": "歡迎使用 Ferdi",
184 "settings.account.account.editButton": "更改帳戶資訊", 172 "settings.account.account.editButton": "Edit account",
185 "settings.account.accountUnavailable": "帳號無法使用", 173 "settings.account.accountUnavailable": "帳號無法使用",
186 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.", 174 "settings.account.accountUnavailableInfo": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
187 "settings.account.buttonSave": "更新帳戶資訊", 175 "settings.account.buttonSave": "更新帳戶資訊",
@@ -189,16 +177,16 @@
189 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", 177 "settings.account.deleteEmailSent": "You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
190 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.", 178 "settings.account.deleteInfo": "If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
191 "settings.account.headline": "帳戶", 179 "settings.account.headline": "帳戶",
192 "settings.account.headlineAccount": "帳戶資訊", 180 "settings.account.headlineAccount": "Account information",
193 "settings.account.headlineDangerZone": "å±éšªæ“作å€", 181 "settings.account.headlineDangerZone": "Danger Zone",
194 "settings.account.headlineInvoices": "å‘票", 182 "settings.account.headlineInvoices": "Invoices",
195 "settings.account.headlinePassword": "更改密碼", 183 "settings.account.headlinePassword": "Change password",
196 "settings.account.headlineProfile": "更新帳戶資訊", 184 "settings.account.headlineProfile": "更新帳戶資訊",
197 "settings.account.successInfo": "您的更改已經儲存", 185 "settings.account.successInfo": "您的更改已經儲存",
198 "settings.account.tryReloadServices": "å†è©¦ä¸€æ¬¡", 186 "settings.account.tryReloadServices": "å†è©¦ä¸€æ¬¡",
199 "settings.account.tryReloadUserInfoRequest": "å†è©¦ä¸€æ¬¡", 187 "settings.account.tryReloadUserInfoRequest": "å†è©¦ä¸€æ¬¡",
200 "settings.account.userInfoRequestFailed": "無法載入帳戶資訊", 188 "settings.account.userInfoRequestFailed": "無法載入帳戶資訊",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "清除緩存", 191 "settings.app.buttonClearAllCache": "清除緩存",
204 "settings.app.buttonInstallUpdate": "é‡æ–°å•Ÿå‹•ä¸¦ä¸”æ›´æ–°", 192 "settings.app.buttonInstallUpdate": "é‡æ–°å•Ÿå‹•ä¸¦ä¸”æ›´æ–°",
@@ -225,7 +213,7 @@
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "在系統匣上顯示", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -296,7 +285,7 @@
296 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes", 285 "settings.recipes.customService.headline.devRecipes": "Your Development Service Recipes",
297 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:", 286 "settings.recipes.customService.intro": "To add a custom service, copy the service recipe to:",
298 "settings.recipes.customService.openDevDocs": "Developer Documentation", 287 "settings.recipes.customService.openDevDocs": "Developer Documentation",
299 "settings.recipes.customService.openFolder": "開啟資料夾", 288 "settings.recipes.customService.openFolder": "Open folder",
300 "settings.recipes.headline": "å¯ç”¨æœå‹™", 289 "settings.recipes.headline": "å¯ç”¨æœå‹™",
301 "settings.recipes.missingService": "Missing a service?", 290 "settings.recipes.missingService": "Missing a service?",
302 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.", 291 "settings.recipes.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
@@ -312,7 +301,7 @@
312 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness", 301 "settings.service.form.darkReaderBrightness": "Dark Reader Brightness",
313 "settings.service.form.darkReaderContrast": "Dark Reader Contrast", 302 "settings.service.form.darkReaderContrast": "Dark Reader Contrast",
314 "settings.service.form.darkReaderSepia": "Dark Reader Sepia", 303 "settings.service.form.darkReaderSepia": "Dark Reader Sepia",
315 "settings.service.form.deleteButton": "刪除", 304 "settings.service.form.deleteButton": "Delete service",
316 "settings.service.form.editServiceHeadline": "編輯 {name}", 305 "settings.service.form.editServiceHeadline": "編輯 {name}",
317 "settings.service.form.enableAudio": "啟用音效", 306 "settings.service.form.enableAudio": "啟用音效",
318 "settings.service.form.enableBadge": "Show unread message badges", 307 "settings.service.form.enableBadge": "Show unread message badges",
@@ -332,17 +321,18 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "åå­", 323 "settings.service.form.name": "åå­",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "使用代ç†", 331 "settings.service.form.proxy.isEnabled": "使用代ç†",
342 "settings.service.form.proxy.password": "密碼(å¯é¸æ“‡ï¼‰", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "連接埠", 333 "settings.service.form.proxy.port": "連接埠",
344 "settings.service.form.proxy.restartInfo": "Please restart Ferdi after changing proxy Settings.", 334 "settings.service.form.proxy.restartInfo": "Please restart Ferdi after changing proxy Settings.",
345 "settings.service.form.proxy.user": "用戶(å¯é¸æ“‡ï¼‰", 335 "settings.service.form.proxy.user": "User (optional)",
346 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.", 336 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
347 "settings.service.form.saveButton": "儲存", 337 "settings.service.form.saveButton": "儲存",
348 "settings.service.form.tabHosted": "Hosted", 338 "settings.service.form.tabHosted": "Hosted",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "æœå‹™åˆ—表", 344 "settings.services.discoverServices": "æœå‹™åˆ—表",
355 "settings.services.headline": "您的æœå‹™", 345 "settings.services.headline": "您的æœå‹™",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "å·²åœç”¨æœå‹™", 349 "settings.services.tooltip.isDisabled": "å·²åœç”¨æœå‹™",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
@@ -387,8 +378,8 @@
387 "settings.user.form.accountType.non-profit": "éžç‡Ÿåˆ©", 378 "settings.user.form.accountType.non-profit": "éžç‡Ÿåˆ©",
388 "settings.user.form.currentPassword": "舊密碼", 379 "settings.user.form.currentPassword": "舊密碼",
389 "settings.user.form.email": "é›»å­éƒµä»¶ä¿¡ç®±", 380 "settings.user.form.email": "é›»å­éƒµä»¶ä¿¡ç®±",
390 "settings.user.form.firstname": "åå­", 381 "settings.user.form.firstname": "First Name",
391 "settings.user.form.lastname": "姓æ°", 382 "settings.user.form.lastname": "Last Name",
392 "settings.user.form.newPassword": "新密碼", 383 "settings.user.form.newPassword": "新密碼",
393 "settings.workspace.add.form.name": "åå­", 384 "settings.workspace.add.form.name": "åå­",
394 "settings.workspace.add.form.submitButton": "建立工作å€", 385 "settings.workspace.add.form.submitButton": "建立工作å€",
@@ -420,9 +411,9 @@
420 "sidebar.unmuteApp": "啟用通知", 411 "sidebar.unmuteApp": "啟用通知",
421 "signup.email.label": "é›»å­éƒµä»¶ä¿¡ç®±", 412 "signup.email.label": "é›»å­éƒµä»¶ä¿¡ç®±",
422 "signup.emailDuplicate": "此電å­éƒµä»¶ä¿¡ç®±å·²è¢«è¨»å†Š", 413 "signup.emailDuplicate": "此電å­éƒµä»¶ä¿¡ç®±å·²è¢«è¨»å†Š",
423 "signup.firstname.label": "åå­", 414 "signup.firstname.label": "First Name",
424 "signup.headline": "註冊", 415 "signup.headline": "註冊",
425 "signup.lastname.label": "姓æ°", 416 "signup.lastname.label": "Last Name",
426 "signup.legal.info": "在建立帳戶åŒæ™‚,您åŒæ„:", 417 "signup.legal.info": "在建立帳戶åŒæ™‚,您åŒæ„:",
427 "signup.legal.privacy": "éš±ç§è²æ˜Ž", 418 "signup.legal.privacy": "éš±ç§è²æ˜Ž",
428 "signup.legal.terms": "æœå‹™æ¢æ¬¾", 419 "signup.legal.terms": "æœå‹™æ¢æ¬¾",
@@ -430,11 +421,11 @@
430 "signup.password.label": "密碼", 421 "signup.password.label": "密碼",
431 "signup.submit.label": "建立帳戶", 422 "signup.submit.label": "建立帳戶",
432 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?", 423 "tabs.item.confirmDeleteService": "Do you really want to delete the {serviceName} service?",
433 "tabs.item.deleteService": "刪除", 424 "tabs.item.deleteService": "Delete service",
434 "tabs.item.disableAudio": "åœç”¨éŸ³æ•ˆ", 425 "tabs.item.disableAudio": "åœç”¨éŸ³æ•ˆ",
435 "tabs.item.disableDarkMode": "Disable Dark mode", 426 "tabs.item.disableDarkMode": "Disable Dark mode",
436 "tabs.item.disableNotifications": "åœç”¨é€šçŸ¥", 427 "tabs.item.disableNotifications": "åœç”¨é€šçŸ¥",
437 "tabs.item.disableService": "åœç”¨æœå‹™", 428 "tabs.item.disableService": "Disable service",
438 "tabs.item.enableAudio": "啟用音效", 429 "tabs.item.enableAudio": "啟用音效",
439 "tabs.item.enableDarkMode": "Enable Dark mode", 430 "tabs.item.enableDarkMode": "Enable Dark mode",
440 "tabs.item.enableNotification": "啟用通知", 431 "tabs.item.enableNotification": "啟用通知",
@@ -454,7 +445,7 @@
454 "webControls.reload": "é‡æ–°åŠ è¼‰", 445 "webControls.reload": "é‡æ–°åŠ è¼‰",
455 "welcome.loginButton": "登入", 446 "welcome.loginButton": "登入",
456 "welcome.signupButton": "建立一個å…費帳戶", 447 "welcome.signupButton": "建立一個å…費帳戶",
457 "workspaceDrawer.addNewWorkspaceLabel": "新增工作å€", 448 "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace",
458 "workspaceDrawer.allServices": "所有æœå‹™", 449 "workspaceDrawer.allServices": "所有æœå‹™",
459 "workspaceDrawer.headline": "工作å€", 450 "workspaceDrawer.headline": "工作å€",
460 "workspaceDrawer.item.contextMenuEdit": "編輯", 451 "workspaceDrawer.item.contextMenuEdit": "編輯",
diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json
index fa30d636a..648d75a6d 100644
--- a/src/i18n/locales/zh.json
+++ b/src/i18n/locales/zh.json
@@ -1,6 +1,6 @@
1{ 1{
2 "app.errorHandler.action": "é‡æ–°åŠ è½½", 2 "app.errorHandler.action": "é‡æ–°åŠ è½½",
3 "app.errorHandler.headline": "出了些问题", 3 "app.errorHandler.headline": "Something went wrong.",
4 "changeserver.customServerLabel": "Custom server", 4 "changeserver.customServerLabel": "Custom server",
5 "changeserver.headline": "Change server", 5 "changeserver.headline": "Change server",
6 "changeserver.label": "æœåŠ¡å™¨ï¼š", 6 "changeserver.label": "æœåŠ¡å™¨ï¼š",
@@ -10,7 +10,6 @@
10 "connectionLostBanner.informationLink": "å‘生了什么?", 10 "connectionLostBanner.informationLink": "å‘生了什么?",
11 "connectionLostBanner.message": "哦ä¸ï¼Ferdi失去了与 {name} 的连接。", 11 "connectionLostBanner.message": "哦ä¸ï¼Ferdi失去了与 {name} 的连接。",
12 "feature.basicAuth.signIn": "Sign In", 12 "feature.basicAuth.signIn": "Sign In",
13 "feature.debugger.title": "å‘布调试信æ¯",
14 "feature.nightlyBuilds.activate": "激活", 13 "feature.nightlyBuilds.activate": "激活",
15 "feature.nightlyBuilds.info": "æ¯å¤œç‰ˆ(Nightly builds) 是Ferdi的实验性版本,å¯èƒ½åŒ…å«æœªå®Œå–„或未完æˆçš„功能。这些æ¯å¤œç‰ˆä¸»è¦ç”±å¼€å‘人员æ¥æµ‹è¯•ä»–们新开å‘的功能åŠå®ƒä»¬åœ¨æœ€ç»ˆç‰ˆæœ¬çš„的表现。如果您ä¸çŸ¥é“自己在åšä»€ä¹ˆï¼Œæˆ‘们建议您ä¸è¦æ¿€æ´»æ¯å¤œç‰ˆã€‚", 14 "feature.nightlyBuilds.info": "æ¯å¤œç‰ˆ(Nightly builds) 是Ferdi的实验性版本,å¯èƒ½åŒ…å«æœªå®Œå–„或未完æˆçš„功能。这些æ¯å¤œç‰ˆä¸»è¦ç”±å¼€å‘人员æ¥æµ‹è¯•ä»–们新开å‘的功能åŠå®ƒä»¬åœ¨æœ€ç»ˆç‰ˆæœ¬çš„的表现。如果您ä¸çŸ¥é“自己在åšä»€ä¹ˆï¼Œæˆ‘们建议您ä¸è¦æ¿€æ´»æ¯å¤œç‰ˆã€‚",
16 "feature.nightlyBuilds.title": "æ¯å¤œç‰ˆ", 15 "feature.nightlyBuilds.title": "æ¯å¤œç‰ˆ",
@@ -24,8 +23,8 @@
24 "feature.quickSwitch.info": "使用 TAB ,↑ å’Œ ↓ 选择æœåŠ¡ã€‚使用回车键(ENTER)打开æœåŠ¡", 23 "feature.quickSwitch.info": "使用 TAB ,↑ å’Œ ↓ 选择æœåŠ¡ã€‚使用回车键(ENTER)打开æœåŠ¡",
25 "feature.quickSwitch.search": "æœç´¢...", 24 "feature.quickSwitch.search": "æœç´¢...",
26 "feature.quickSwitch.title": "快速切æ¢", 25 "feature.quickSwitch.title": "快速切æ¢",
27 "global.api.unhealthy": "无法链接到 Ferdi 在线æœåŠ¡", 26 "global.api.unhealthy": "Can't connect to Ferdi online services",
28 "global.cancel": "å–消", 27 "global.cancel": "Cancel",
29 "global.edit": "编辑", 28 "global.edit": "编辑",
30 "global.no": "No", 29 "global.no": "No",
31 "global.notConnectedToTheInternet": "您没有连接到互è”网。", 30 "global.notConnectedToTheInternet": "您没有连接到互è”网。",
@@ -33,7 +32,7 @@
33 "global.quit": "Quit", 32 "global.quit": "Quit",
34 "global.quitConfirmation": "Do you really want to quit Ferdi?", 33 "global.quitConfirmation": "Do you really want to quit Ferdi?",
35 "global.save": "Save", 34 "global.save": "Save",
36 "global.settings": "设置", 35 "global.settings": "Settings",
37 "global.spellchecker.useDefault": "使用系统默认值 ({default})", 36 "global.spellchecker.useDefault": "使用系统默认值 ({default})",
38 "global.spellchecking.autodetect": "自动检测语言", 37 "global.spellchecking.autodetect": "自动检测语言",
39 "global.spellchecking.autodetect.short": "自动", 38 "global.spellchecking.autodetect.short": "自动",
@@ -45,9 +44,9 @@
45 "import.headline": "导入你的 Ferdi 4 æœåŠ¡", 44 "import.headline": "导入你的 Ferdi 4 æœåŠ¡",
46 "import.notSupportedHeadline": "Ferdi 5尚未支æŒçš„æœåŠ¡", 45 "import.notSupportedHeadline": "Ferdi 5尚未支æŒçš„æœåŠ¡",
47 "import.skip.label": "我想手动添加æœåŠ¡", 46 "import.skip.label": "我想手动添加æœåŠ¡",
48 "import.submit.label": "导入æœåŠ¡", 47 "import.submit.label": "Import {count} services",
49 "infobar.authRequestFailed": "å°è¯•è¿›è¡Œèº«ä»½éªŒè¯æ—¶å‡ºé”™ã€‚如果此错误ä»å­˜åœ¨ï¼Œè¯·å°è¯•æ³¨é”€å¹¶é‡æ–°ç™»å½•ã€‚", 48 "infobar.authRequestFailed": "å°è¯•è¿›è¡Œèº«ä»½éªŒè¯æ—¶å‡ºé”™ã€‚如果此错误ä»å­˜åœ¨ï¼Œè¯·å°è¯•æ³¨é”€å¹¶é‡æ–°ç™»å½•ã€‚",
50 "infobar.buttonChangelog": "有什么新鲜事?", 49 "infobar.buttonChangelog": "What is new?",
51 "infobar.buttonInstallUpdate": "é‡å¯å¹¶å®‰è£…æ›´æ–°", 50 "infobar.buttonInstallUpdate": "é‡å¯å¹¶å®‰è£…æ›´æ–°",
52 "infobar.buttonReloadServices": "é‡è½½æœåŠ¡", 51 "infobar.buttonReloadServices": "é‡è½½æœåŠ¡",
53 "infobar.hide": "éšè—", 52 "infobar.hide": "éšè—",
@@ -117,10 +116,10 @@
117 "menu.help.support": "支æŒ", 116 "menu.help.support": "支æŒ",
118 "menu.help.tos": "æœåŠ¡æ¡æ¬¾", 117 "menu.help.tos": "æœåŠ¡æ¡æ¬¾",
119 "menu.services": "æœåŠ¡", 118 "menu.services": "æœåŠ¡",
120 "menu.services.activatePreviousService": "激活以å‰çš„æœåŠ¡", 119 "menu.services.activatePreviousService": "Activate previous service",
121 "menu.services.addNewService": "Add New Service", 120 "menu.services.addNewService": "Add New Service...",
122 "menu.services.goHome": "主页", 121 "menu.services.goHome": "主页",
123 "menu.services.setNextServiceActive": "激活下一个æœåŠ¡", 122 "menu.services.setNextServiceActive": "Activate next service",
124 "menu.todos": "待办事项", 123 "menu.todos": "待办事项",
125 "menu.todos.enableTodos": "å¯ç”¨å¾…办事项", 124 "menu.todos.enableTodos": "å¯ç”¨å¾…办事项",
126 "menu.view": "查看", 125 "menu.view": "查看",
@@ -152,18 +151,7 @@
152 "password.link.login": "Sign in to your account", 151 "password.link.login": "Sign in to your account",
153 "password.link.signup": "Create a free account", 152 "password.link.signup": "Create a free account",
154 "password.noUser": "No user with that email address was found", 153 "password.noUser": "No user with that email address was found",
155 "password.successInfo": "Please check your email", 154 "password.successInfo": "Your new password was sent to your email address",
156 "pricing.features.accountSync": "Account Synchronisation",
157 "pricing.features.customWebsites": "Add Custom Websites",
158 "pricing.features.desktopNotifications": "Desktop Notifications",
159 "pricing.features.onPremise": "On-premise & other Hosted Services",
160 "pricing.features.recipes": "Choose from more than 70 Services",
161 "pricing.features.serviceProxies": "Service Proxies",
162 "pricing.features.spellchecker": "Spellchecker support",
163 "pricing.features.teamManagement": "Team Management",
164 "pricing.features.thirdPartyServices": "Install 3rd party services",
165 "pricing.features.unlimitedServices": "Add unlimited services",
166 "pricing.features.workspaces": "Workspaces",
167 "service.crashHandler.action": "Reload {name}", 155 "service.crashHandler.action": "Reload {name}",
168 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 156 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
169 "service.crashHandler.headline": "Oh no!", 157 "service.crashHandler.headline": "Oh no!",
@@ -198,7 +186,7 @@
198 "settings.account.tryReloadServices": "Try again", 186 "settings.account.tryReloadServices": "Try again",
199 "settings.account.tryReloadUserInfoRequest": "Try again", 187 "settings.account.tryReloadUserInfoRequest": "Try again",
200 "settings.account.userInfoRequestFailed": "Could not load user information", 188 "settings.account.userInfoRequestFailed": "Could not load user information",
201 "settings.account.yourLicense": "Your Ferdi License", 189 "settings.account.yourLicense": "Your Ferdi License:",
202 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})", 190 "settings.app.accentColorInfo": "Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
203 "settings.app.buttonClearAllCache": "Clear cache", 191 "settings.app.buttonClearAllCache": "Clear cache",
204 "settings.app.buttonInstallUpdate": "é‡å¯å¹¶å®‰è£…æ›´æ–°", 192 "settings.app.buttonInstallUpdate": "é‡å¯å¹¶å®‰è£…æ›´æ–°",
@@ -220,12 +208,12 @@
220 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray", 208 "settings.app.form.closeToSystemTray": "Close Ferdi to system tray",
221 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi", 209 "settings.app.form.confirmOnQuit": "Confirm when quitting Ferdi",
222 "settings.app.form.customTodoServer": "Custom Todo Server", 210 "settings.app.form.customTodoServer": "Custom Todo Server",
223 "settings.app.form.darkMode": "Enable dark mode", 211 "settings.app.form.darkMode": "Enable Dark Mode",
224 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration", 212 "settings.app.form.enableGPUAcceleration": "Enable GPU Acceleration",
225 "settings.app.form.enableLock": "Enable Password Lock", 213 "settings.app.form.enableLock": "Enable Password Lock",
226 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar", 214 "settings.app.form.enableMenuBar": "Always show Ferdi in Menu Bar",
227 "settings.app.form.enableSpellchecking": "Enable spell checking", 215 "settings.app.form.enableSpellchecking": "Enable spell checking",
228 "settings.app.form.enableSystemTray": "Show Ferdi in system tray", 216 "settings.app.form.enableSystemTray": "Always show Ferdi in System Tray",
229 "settings.app.form.enableTodos": "Enable Ferdi Todos", 217 "settings.app.form.enableTodos": "Enable Ferdi Todos",
230 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup", 218 "settings.app.form.hibernateOnStartup": "Keep services in hibernation on startup",
231 "settings.app.form.hibernationStrategy": "Hibernation strategy", 219 "settings.app.form.hibernationStrategy": "Hibernation strategy",
@@ -251,6 +239,7 @@
251 "settings.app.form.showDisabledServices": "Display disabled services tabs", 239 "settings.app.form.showDisabledServices": "Display disabled services tabs",
252 "settings.app.form.showDragArea": "Show draggable area on window", 240 "settings.app.form.showDragArea": "Show draggable area on window",
253 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 241 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
242 "settings.app.form.splitMode": "Enable Split View Mode",
254 "settings.app.form.startMinimized": "Start minimized", 243 "settings.app.form.startMinimized": "Start minimized",
255 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 244 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
256 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi", 245 "settings.app.form.useTouchIdToUnlock": "Allow using TouchID to unlock Ferdi",
@@ -332,12 +321,13 @@
332 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.", 321 "settings.service.form.isHibernatedEnabledInfo": "When enabled, a service will be shut down after a period of time to save system resources.",
333 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 322 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
334 "settings.service.form.name": "å称", 323 "settings.service.form.name": "å称",
324 "settings.service.form.onlyShowFavoritesInUnreadCount": "Only show Favorites in unread count",
335 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 325 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
336 "settings.service.form.openUserCss": "Open user.css", 326 "settings.service.form.openUserCss": "Open user.css",
337 "settings.service.form.openUserJs": "Open user.js", 327 "settings.service.form.openUserJs": "Open user.js",
338 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 328 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
339 "settings.service.form.proxy.host": "Proxy Host/IP", 329 "settings.service.form.proxy.host": "Proxy Host/IP",
340 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 330 "settings.service.form.proxy.info": "Proxy settings will not be synchronized with the Ferdi servers.",
341 "settings.service.form.proxy.isEnabled": "Use Proxy", 331 "settings.service.form.proxy.isEnabled": "Use Proxy",
342 "settings.service.form.proxy.password": "Password (optional)", 332 "settings.service.form.proxy.password": "Password (optional)",
343 "settings.service.form.proxy.port": "Port", 333 "settings.service.form.proxy.port": "Port",
@@ -354,6 +344,7 @@
354 "settings.services.discoverServices": "Discover services", 344 "settings.services.discoverServices": "Discover services",
355 "settings.services.headline": "Your services", 345 "settings.services.headline": "Your services",
356 "settings.services.noServicesAdded": "Start by adding a service.", 346 "settings.services.noServicesAdded": "Start by adding a service.",
347 "settings.services.nothingFound": "Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
357 "settings.services.servicesRequestFailed": "Could not load your services", 348 "settings.services.servicesRequestFailed": "Could not load your services",
358 "settings.services.tooltip.isDisabled": "Service is disabled", 349 "settings.services.tooltip.isDisabled": "Service is disabled",
359 "settings.services.tooltip.isMuted": "All sounds are muted", 350 "settings.services.tooltip.isMuted": "All sounds are muted",
diff --git a/src/i18n/manage-translations.js b/src/i18n/manage-translations.js
deleted file mode 100644
index ee64c9c09..000000000
--- a/src/i18n/manage-translations.js
+++ /dev/null
@@ -1,9 +0,0 @@
1require('@babel/register');
2const manageTranslations = require('react-intl-translations-manager').default;
3
4manageTranslations({
5 messagesDirectory: 'src/i18n/messages',
6 translationsDirectory: 'src/i18n/locales',
7 singleMessagesFile: true,
8 languages: ['en-US'],
9});
diff --git a/src/i18n/messages/src/components/AppUpdateInfoBar.json b/src/i18n/messages/src/components/AppUpdateInfoBar.json
deleted file mode 100644
index b99eaff67..000000000
--- a/src/i18n/messages/src/components/AppUpdateInfoBar.json
+++ /dev/null
@@ -1,41 +0,0 @@
1[
2 {
3 "id": "infobar.updateAvailable",
4 "defaultMessage": "!!!A new update for Ferdi is available.",
5 "file": "src/components/AppUpdateInfoBar.js",
6 "start": {
7 "line": 10,
8 "column": 19
9 },
10 "end": {
11 "line": 13,
12 "column": 3
13 }
14 },
15 {
16 "id": "infobar.buttonChangelog",
17 "defaultMessage": "!!!Changelog",
18 "file": "src/components/AppUpdateInfoBar.js",
19 "start": {
20 "line": 14,
21 "column": 13
22 },
23 "end": {
24 "line": 17,
25 "column": 3
26 }
27 },
28 {
29 "id": "infobar.buttonInstallUpdate",
30 "defaultMessage": "!!!Restart & install update",
31 "file": "src/components/AppUpdateInfoBar.js",
32 "start": {
33 "line": 18,
34 "column": 23
35 },
36 "end": {
37 "line": 21,
38 "column": 3
39 }
40 }
41] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/ChangeServer.json b/src/i18n/messages/src/components/auth/ChangeServer.json
deleted file mode 100644
index 87e0b5857..000000000
--- a/src/i18n/messages/src/components/auth/ChangeServer.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "changeserver.headline",
4 "defaultMessage": "!!!Change server",
5 "file": "src/components/auth/ChangeServer.js",
6 "start": {
7 "line": 15,
8 "column": 12
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "changeserver.label",
17 "defaultMessage": "!!!Server",
18 "file": "src/components/auth/ChangeServer.js",
19 "start": {
20 "line": 19,
21 "column": 9
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "changeserver.warning",
30 "defaultMessage": "!!!Extra settings offered by Ferdi will not be saved",
31 "file": "src/components/auth/ChangeServer.js",
32 "start": {
33 "line": 23,
34 "column": 11
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "changeserver.customServerLabel",
43 "defaultMessage": "!!!Custom server",
44 "file": "src/components/auth/ChangeServer.js",
45 "start": {
46 "line": 27,
47 "column": 21
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "changeserver.urlError",
56 "defaultMessage": "!!!Enter a valid URL",
57 "file": "src/components/auth/ChangeServer.js",
58 "start": {
59 "line": 31,
60 "column": 12
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Import.json b/src/i18n/messages/src/components/auth/Import.json
deleted file mode 100644
index 98ae2e61f..000000000
--- a/src/i18n/messages/src/components/auth/Import.json
+++ /dev/null
@@ -1,54 +0,0 @@
1[
2 {
3 "id": "import.headline",
4 "defaultMessage": "!!!Import your Ferdi 4 services",
5 "file": "src/components/auth/Import.js",
6 "start": {
7 "line": 13,
8 "column": 12
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "import.notSupportedHeadline",
17 "defaultMessage": "!!!Services not yet supported in Ferdi 5",
18 "file": "src/components/auth/Import.js",
19 "start": {
20 "line": 17,
21 "column": 24
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "import.submit.label",
30 "defaultMessage": "!!!Import {count} services",
31 "file": "src/components/auth/Import.js",
32 "start": {
33 "line": 21,
34 "column": 21
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 },
41 {
42 "id": "import.skip.label",
43 "defaultMessage": "!!!I want to add services manually",
44 "file": "src/components/auth/Import.js",
45 "start": {
46 "line": 25,
47 "column": 19
48 },
49 "end": {
50 "line": 28,
51 "column": 3
52 }
53 }
54] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Invite.json b/src/i18n/messages/src/components/auth/Invite.json
deleted file mode 100644
index 57c9bddcf..000000000
--- a/src/i18n/messages/src/components/auth/Invite.json
+++ /dev/null
@@ -1,93 +0,0 @@
1[
2 {
3 "id": "settings.invite.headline",
4 "defaultMessage": "!!!Invite Friends",
5 "file": "src/components/auth/Invite.js",
6 "start": {
7 "line": 16,
8 "column": 20
9 },
10 "end": {
11 "line": 19,
12 "column": 3
13 }
14 },
15 {
16 "id": "invite.headline.friends",
17 "defaultMessage": "!!!Invite 3 of your friends or colleagues",
18 "file": "src/components/auth/Invite.js",
19 "start": {
20 "line": 20,
21 "column": 12
22 },
23 "end": {
24 "line": 23,
25 "column": 3
26 }
27 },
28 {
29 "id": "invite.name.label",
30 "defaultMessage": "!!!Name",
31 "file": "src/components/auth/Invite.js",
32 "start": {
33 "line": 24,
34 "column": 13
35 },
36 "end": {
37 "line": 27,
38 "column": 3
39 }
40 },
41 {
42 "id": "invite.email.label",
43 "defaultMessage": "!!!Email address",
44 "file": "src/components/auth/Invite.js",
45 "start": {
46 "line": 28,
47 "column": 14
48 },
49 "end": {
50 "line": 31,
51 "column": 3
52 }
53 },
54 {
55 "id": "invite.submit.label",
56 "defaultMessage": "!!!Send invites",
57 "file": "src/components/auth/Invite.js",
58 "start": {
59 "line": 32,
60 "column": 21
61 },
62 "end": {
63 "line": 35,
64 "column": 3
65 }
66 },
67 {
68 "id": "invite.skip.label",
69 "defaultMessage": "!!!I want to do this later",
70 "file": "src/components/auth/Invite.js",
71 "start": {
72 "line": 36,
73 "column": 19
74 },
75 "end": {
76 "line": 39,
77 "column": 3
78 }
79 },
80 {
81 "id": "invite.successInfo",
82 "defaultMessage": "!!!Invitations sent successfully",
83 "file": "src/components/auth/Invite.js",
84 "start": {
85 "line": 40,
86 "column": 21
87 },
88 "end": {
89 "line": 43,
90 "column": 3
91 }
92 }
93] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Locked.json b/src/i18n/messages/src/components/auth/Locked.json
deleted file mode 100644
index a871d6fc8..000000000
--- a/src/i18n/messages/src/components/auth/Locked.json
+++ /dev/null
@@ -1,106 +0,0 @@
1[
2 {
3 "id": "locked.headline",
4 "defaultMessage": "!!!Locked",
5 "file": "src/components/auth/Locked.js",
6 "start": {
7 "line": 16,
8 "column": 12
9 },
10 "end": {
11 "line": 19,
12 "column": 3
13 }
14 },
15 {
16 "id": "locked.info",
17 "defaultMessage": "!!!Ferdi is currently locked. Please unlock Ferdi with your password to see your messages.",
18 "file": "src/components/auth/Locked.js",
19 "start": {
20 "line": 20,
21 "column": 8
22 },
23 "end": {
24 "line": 23,
25 "column": 3
26 }
27 },
28 {
29 "id": "locked.touchId",
30 "defaultMessage": "!!!Unlock with Touch ID",
31 "file": "src/components/auth/Locked.js",
32 "start": {
33 "line": 24,
34 "column": 11
35 },
36 "end": {
37 "line": 27,
38 "column": 3
39 }
40 },
41 {
42 "id": "locked.touchIdPrompt",
43 "defaultMessage": "!!!unlock via Touch ID",
44 "file": "src/components/auth/Locked.js",
45 "start": {
46 "line": 28,
47 "column": 17
48 },
49 "end": {
50 "line": 31,
51 "column": 3
52 }
53 },
54 {
55 "id": "locked.password.label",
56 "defaultMessage": "!!!Password",
57 "file": "src/components/auth/Locked.js",
58 "start": {
59 "line": 32,
60 "column": 17
61 },
62 "end": {
63 "line": 35,
64 "column": 3
65 }
66 },
67 {
68 "id": "locked.submit.label",
69 "defaultMessage": "!!!Unlock",
70 "file": "src/components/auth/Locked.js",
71 "start": {
72 "line": 36,
73 "column": 21
74 },
75 "end": {
76 "line": 39,
77 "column": 3
78 }
79 },
80 {
81 "id": "locked.unlockWithPassword",
82 "defaultMessage": "!!!Unlock with Password",
83 "file": "src/components/auth/Locked.js",
84 "start": {
85 "line": 40,
86 "column": 22
87 },
88 "end": {
89 "line": 43,
90 "column": 3
91 }
92 },
93 {
94 "id": "locked.invalidCredentials",
95 "defaultMessage": "!!!Password invalid",
96 "file": "src/components/auth/Locked.js",
97 "start": {
98 "line": 44,
99 "column": 22
100 },
101 "end": {
102 "line": 47,
103 "column": 3
104 }
105 }
106] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Login.json b/src/i18n/messages/src/components/auth/Login.json
deleted file mode 100644
index 275b04478..000000000
--- a/src/i18n/messages/src/components/auth/Login.json
+++ /dev/null
@@ -1,171 +0,0 @@
1[
2 {
3 "id": "login.headline",
4 "defaultMessage": "!!!Sign in",
5 "file": "src/components/auth/Login.js",
6 "start": {
7 "line": 20,
8 "column": 12
9 },
10 "end": {
11 "line": 23,
12 "column": 3
13 }
14 },
15 {
16 "id": "login.email.label",
17 "defaultMessage": "!!!Email address",
18 "file": "src/components/auth/Login.js",
19 "start": {
20 "line": 24,
21 "column": 14
22 },
23 "end": {
24 "line": 27,
25 "column": 3
26 }
27 },
28 {
29 "id": "login.password.label",
30 "defaultMessage": "!!!Password",
31 "file": "src/components/auth/Login.js",
32 "start": {
33 "line": 28,
34 "column": 17
35 },
36 "end": {
37 "line": 31,
38 "column": 3
39 }
40 },
41 {
42 "id": "login.submit.label",
43 "defaultMessage": "!!!Sign in",
44 "file": "src/components/auth/Login.js",
45 "start": {
46 "line": 32,
47 "column": 21
48 },
49 "end": {
50 "line": 35,
51 "column": 3
52 }
53 },
54 {
55 "id": "login.invalidCredentials",
56 "defaultMessage": "!!!Email or password not valid",
57 "file": "src/components/auth/Login.js",
58 "start": {
59 "line": 36,
60 "column": 22
61 },
62 "end": {
63 "line": 39,
64 "column": 3
65 }
66 },
67 {
68 "id": "login.customServerQuestion",
69 "defaultMessage": "!!!Using a Franz account to log in?",
70 "file": "src/components/auth/Login.js",
71 "start": {
72 "line": 40,
73 "column": 24
74 },
75 "end": {
76 "line": 43,
77 "column": 3
78 }
79 },
80 {
81 "id": "login.customServerSuggestion",
82 "defaultMessage": "!!!Try importing your Franz account into Ferdi",
83 "file": "src/components/auth/Login.js",
84 "start": {
85 "line": 44,
86 "column": 26
87 },
88 "end": {
89 "line": 47,
90 "column": 3
91 }
92 },
93 {
94 "id": "login.tokenExpired",
95 "defaultMessage": "!!!Your session expired, please login again.",
96 "file": "src/components/auth/Login.js",
97 "start": {
98 "line": 48,
99 "column": 16
100 },
101 "end": {
102 "line": 51,
103 "column": 3
104 }
105 },
106 {
107 "id": "login.serverLogout",
108 "defaultMessage": "!!!Your session expired, please login again.",
109 "file": "src/components/auth/Login.js",
110 "start": {
111 "line": 52,
112 "column": 16
113 },
114 "end": {
115 "line": 55,
116 "column": 3
117 }
118 },
119 {
120 "id": "login.link.signup",
121 "defaultMessage": "!!!Create a free account",
122 "file": "src/components/auth/Login.js",
123 "start": {
124 "line": 56,
125 "column": 14
126 },
127 "end": {
128 "line": 59,
129 "column": 3
130 }
131 },
132 {
133 "id": "login.changeServer",
134 "defaultMessage": "!!!Change server",
135 "file": "src/components/auth/Login.js",
136 "start": {
137 "line": 60,
138 "column": 16
139 },
140 "end": {
141 "line": 63,
142 "column": 3
143 }
144 },
145 {
146 "id": "services.serverless",
147 "defaultMessage": "!!!Use Ferdi without an Account",
148 "file": "src/components/auth/Login.js",
149 "start": {
150 "line": 64,
151 "column": 14
152 },
153 "end": {
154 "line": 67,
155 "column": 3
156 }
157 },
158 {
159 "id": "login.link.password",
160 "defaultMessage": "!!!Forgot password",
161 "file": "src/components/auth/Login.js",
162 "start": {
163 "line": 68,
164 "column": 16
165 },
166 "end": {
167 "line": 71,
168 "column": 3
169 }
170 }
171] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Password.json b/src/i18n/messages/src/components/auth/Password.json
deleted file mode 100644
index 336ba42ef..000000000
--- a/src/i18n/messages/src/components/auth/Password.json
+++ /dev/null
@@ -1,80 +0,0 @@
1[
2 {
3 "id": "password.headline",
4 "defaultMessage": "!!!Forgot password",
5 "file": "src/components/auth/Password.js",
6 "start": {
7 "line": 15,
8 "column": 12
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "password.email.label",
17 "defaultMessage": "!!!Email address",
18 "file": "src/components/auth/Password.js",
19 "start": {
20 "line": 19,
21 "column": 14
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "password.successInfo",
30 "defaultMessage": "!!!Your new password was sent to your email address",
31 "file": "src/components/auth/Password.js",
32 "start": {
33 "line": 23,
34 "column": 15
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "password.noUser",
43 "defaultMessage": "!!!No user affiliated with that email address",
44 "file": "src/components/auth/Password.js",
45 "start": {
46 "line": 27,
47 "column": 10
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "password.link.signup",
56 "defaultMessage": "!!!Create a free account",
57 "file": "src/components/auth/Password.js",
58 "start": {
59 "line": 31,
60 "column": 14
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 },
67 {
68 "id": "password.link.login",
69 "defaultMessage": "!!!Sign in to your account",
70 "file": "src/components/auth/Password.js",
71 "start": {
72 "line": 35,
73 "column": 13
74 },
75 "end": {
76 "line": 38,
77 "column": 3
78 }
79 }
80] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/ServiceAssistant.json b/src/i18n/messages/src/components/auth/ServiceAssistant.json
deleted file mode 100644
index 9170fc183..000000000
--- a/src/i18n/messages/src/components/auth/ServiceAssistant.json
+++ /dev/null
@@ -1,93 +0,0 @@
1[
2 {
3 "id": "settings.invite.headline",
4 "defaultMessage": "!!!Invite Friends",
5 "file": "src/components/auth/ServiceAssistant.js",
6 "start": {
7 "line": 16,
8 "column": 20
9 },
10 "end": {
11 "line": 19,
12 "column": 3
13 }
14 },
15 {
16 "id": "invite.headline.friends",
17 "defaultMessage": "!!!Invite 3 of your friends or colleagues",
18 "file": "src/components/auth/ServiceAssistant.js",
19 "start": {
20 "line": 20,
21 "column": 12
22 },
23 "end": {
24 "line": 23,
25 "column": 3
26 }
27 },
28 {
29 "id": "invite.name.label",
30 "defaultMessage": "!!!Name",
31 "file": "src/components/auth/ServiceAssistant.js",
32 "start": {
33 "line": 24,
34 "column": 13
35 },
36 "end": {
37 "line": 27,
38 "column": 3
39 }
40 },
41 {
42 "id": "invite.email.label",
43 "defaultMessage": "!!!Email address",
44 "file": "src/components/auth/ServiceAssistant.js",
45 "start": {
46 "line": 28,
47 "column": 14
48 },
49 "end": {
50 "line": 31,
51 "column": 3
52 }
53 },
54 {
55 "id": "invite.submit.label",
56 "defaultMessage": "!!!Send invites",
57 "file": "src/components/auth/ServiceAssistant.js",
58 "start": {
59 "line": 32,
60 "column": 21
61 },
62 "end": {
63 "line": 35,
64 "column": 3
65 }
66 },
67 {
68 "id": "invite.skip.label",
69 "defaultMessage": "!!!I want to do this later",
70 "file": "src/components/auth/ServiceAssistant.js",
71 "start": {
72 "line": 36,
73 "column": 19
74 },
75 "end": {
76 "line": 39,
77 "column": 3
78 }
79 },
80 {
81 "id": "invite.successInfo",
82 "defaultMessage": "!!!Invitations sent successfully",
83 "file": "src/components/auth/ServiceAssistant.js",
84 "start": {
85 "line": 40,
86 "column": 21
87 },
88 "end": {
89 "line": 43,
90 "column": 3
91 }
92 }
93] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/SetupAssistant.json b/src/i18n/messages/src/components/auth/SetupAssistant.json
deleted file mode 100644
index 108adab26..000000000
--- a/src/i18n/messages/src/components/auth/SetupAssistant.json
+++ /dev/null
@@ -1,54 +0,0 @@
1[
2 {
3 "id": "setupAssistant.headline",
4 "defaultMessage": "!!!Let's get started",
5 "file": "src/components/auth/SetupAssistant.js",
6 "start": {
7 "line": 20,
8 "column": 12
9 },
10 "end": {
11 "line": 23,
12 "column": 3
13 }
14 },
15 {
16 "id": "setupAssistant.subheadline",
17 "defaultMessage": "!!!Choose from our most used services and get back on top of your messaging now.",
18 "file": "src/components/auth/SetupAssistant.js",
19 "start": {
20 "line": 24,
21 "column": 15
22 },
23 "end": {
24 "line": 28,
25 "column": 3
26 }
27 },
28 {
29 "id": "setupAssistant.submit.label",
30 "defaultMessage": "!!!Let's go",
31 "file": "src/components/auth/SetupAssistant.js",
32 "start": {
33 "line": 29,
34 "column": 21
35 },
36 "end": {
37 "line": 32,
38 "column": 3
39 }
40 },
41 {
42 "id": "invite.successInfo",
43 "defaultMessage": "!!!Invitations sent successfully",
44 "file": "src/components/auth/SetupAssistant.js",
45 "start": {
46 "line": 33,
47 "column": 21
48 },
49 "end": {
50 "line": 36,
51 "column": 3
52 }
53 }
54] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Signup.json b/src/i18n/messages/src/components/auth/Signup.json
deleted file mode 100644
index 4a32628ef..000000000
--- a/src/i18n/messages/src/components/auth/Signup.json
+++ /dev/null
@@ -1,171 +0,0 @@
1[
2 {
3 "id": "signup.headline",
4 "defaultMessage": "!!!Sign up",
5 "file": "src/components/auth/Signup.js",
6 "start": {
7 "line": 20,
8 "column": 12
9 },
10 "end": {
11 "line": 23,
12 "column": 3
13 }
14 },
15 {
16 "id": "signup.firstname.label",
17 "defaultMessage": "!!!Firstname",
18 "file": "src/components/auth/Signup.js",
19 "start": {
20 "line": 24,
21 "column": 18
22 },
23 "end": {
24 "line": 27,
25 "column": 3
26 }
27 },
28 {
29 "id": "signup.lastname.label",
30 "defaultMessage": "!!!Lastname",
31 "file": "src/components/auth/Signup.js",
32 "start": {
33 "line": 28,
34 "column": 17
35 },
36 "end": {
37 "line": 31,
38 "column": 3
39 }
40 },
41 {
42 "id": "signup.email.label",
43 "defaultMessage": "!!!Email address",
44 "file": "src/components/auth/Signup.js",
45 "start": {
46 "line": 32,
47 "column": 14
48 },
49 "end": {
50 "line": 35,
51 "column": 3
52 }
53 },
54 {
55 "id": "signup.password.label",
56 "defaultMessage": "!!!Password",
57 "file": "src/components/auth/Signup.js",
58 "start": {
59 "line": 40,
60 "column": 17
61 },
62 "end": {
63 "line": 43,
64 "column": 3
65 }
66 },
67 {
68 "id": "signup.legal.info",
69 "defaultMessage": "!!!By creating a Ferdi account you accept the",
70 "file": "src/components/auth/Signup.js",
71 "start": {
72 "line": 44,
73 "column": 13
74 },
75 "end": {
76 "line": 47,
77 "column": 3
78 }
79 },
80 {
81 "id": "signup.legal.terms",
82 "defaultMessage": "!!!Terms of service",
83 "file": "src/components/auth/Signup.js",
84 "start": {
85 "line": 48,
86 "column": 9
87 },
88 "end": {
89 "line": 51,
90 "column": 3
91 }
92 },
93 {
94 "id": "signup.legal.privacy",
95 "defaultMessage": "!!!Privacy Statement",
96 "file": "src/components/auth/Signup.js",
97 "start": {
98 "line": 52,
99 "column": 11
100 },
101 "end": {
102 "line": 55,
103 "column": 3
104 }
105 },
106 {
107 "id": "signup.submit.label",
108 "defaultMessage": "!!!Create account",
109 "file": "src/components/auth/Signup.js",
110 "start": {
111 "line": 56,
112 "column": 21
113 },
114 "end": {
115 "line": 59,
116 "column": 3
117 }
118 },
119 {
120 "id": "signup.link.login",
121 "defaultMessage": "!!!Already have an account, sign in?",
122 "file": "src/components/auth/Signup.js",
123 "start": {
124 "line": 60,
125 "column": 13
126 },
127 "end": {
128 "line": 63,
129 "column": 3
130 }
131 },
132 {
133 "id": "login.changeServer",
134 "defaultMessage": "!!!Change server",
135 "file": "src/components/auth/Signup.js",
136 "start": {
137 "line": 64,
138 "column": 16
139 },
140 "end": {
141 "line": 67,
142 "column": 3
143 }
144 },
145 {
146 "id": "services.serverless",
147 "defaultMessage": "!!!Use Ferdi without an Account",
148 "file": "src/components/auth/Signup.js",
149 "start": {
150 "line": 68,
151 "column": 14
152 },
153 "end": {
154 "line": 71,
155 "column": 3
156 }
157 },
158 {
159 "id": "signup.emailDuplicate",
160 "defaultMessage": "!!!A user with that email address already exists",
161 "file": "src/components/auth/Signup.js",
162 "start": {
163 "line": 72,
164 "column": 18
165 },
166 "end": {
167 "line": 75,
168 "column": 3
169 }
170 }
171] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/auth/Welcome.json b/src/i18n/messages/src/components/auth/Welcome.json
deleted file mode 100644
index 3f0c1e5c2..000000000
--- a/src/i18n/messages/src/components/auth/Welcome.json
+++ /dev/null
@@ -1,41 +0,0 @@
1[
2 {
3 "id": "welcome.signupButton",
4 "defaultMessage": "!!!Create a free account",
5 "file": "src/components/auth/Welcome.js",
6 "start": {
7 "line": 11,
8 "column": 16
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 },
15 {
16 "id": "welcome.loginButton",
17 "defaultMessage": "!!!Login to your account",
18 "file": "src/components/auth/Welcome.js",
19 "start": {
20 "line": 15,
21 "column": 15
22 },
23 "end": {
24 "line": 18,
25 "column": 3
26 }
27 },
28 {
29 "id": "services.serverless",
30 "defaultMessage": "!!!Use Ferdi without an Account",
31 "file": "src/components/auth/Welcome.js",
32 "start": {
33 "line": 19,
34 "column": 14
35 },
36 "end": {
37 "line": 22,
38 "column": 3
39 }
40 }
41] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/layout/AppLayout.json b/src/i18n/messages/src/components/layout/AppLayout.json
deleted file mode 100644
index 807490a4f..000000000
--- a/src/i18n/messages/src/components/layout/AppLayout.json
+++ /dev/null
@@ -1,54 +0,0 @@
1[
2 {
3 "id": "infobar.servicesUpdated",
4 "defaultMessage": "!!!Your services have been updated.",
5 "file": "src/components/layout/AppLayout.js",
6 "start": {
7 "line": 28,
8 "column": 19
9 },
10 "end": {
11 "line": 31,
12 "column": 3
13 }
14 },
15 {
16 "id": "infobar.buttonReloadServices",
17 "defaultMessage": "!!!Reload services",
18 "file": "src/components/layout/AppLayout.js",
19 "start": {
20 "line": 32,
21 "column": 24
22 },
23 "end": {
24 "line": 35,
25 "column": 3
26 }
27 },
28 {
29 "id": "infobar.requiredRequestsFailed",
30 "defaultMessage": "!!!Could not load services and user information",
31 "file": "src/components/layout/AppLayout.js",
32 "start": {
33 "line": 36,
34 "column": 26
35 },
36 "end": {
37 "line": 39,
38 "column": 3
39 }
40 },
41 {
42 "id": "infobar.authRequestFailed",
43 "defaultMessage": "!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.",
44 "file": "src/components/layout/AppLayout.js",
45 "start": {
46 "line": 40,
47 "column": 21
48 },
49 "end": {
50 "line": 44,
51 "column": 3
52 }
53 }
54] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/layout/Sidebar.json b/src/i18n/messages/src/components/layout/Sidebar.json
deleted file mode 100644
index 9bc435f12..000000000
--- a/src/i18n/messages/src/components/layout/Sidebar.json
+++ /dev/null
@@ -1,106 +0,0 @@
1[
2 {
3 "id": "sidebar.addNewService",
4 "defaultMessage": "!!!Add new service",
5 "file": "src/components/layout/Sidebar.js",
6 "start": {
7 "line": 18,
8 "column": 17
9 },
10 "end": {
11 "line": 21,
12 "column": 3
13 }
14 },
15 {
16 "id": "sidebar.muteApp",
17 "defaultMessage": "!!!Disable notifications & audio",
18 "file": "src/components/layout/Sidebar.js",
19 "start": {
20 "line": 22,
21 "column": 8
22 },
23 "end": {
24 "line": 25,
25 "column": 3
26 }
27 },
28 {
29 "id": "sidebar.unmuteApp",
30 "defaultMessage": "!!!Enable notifications & audio",
31 "file": "src/components/layout/Sidebar.js",
32 "start": {
33 "line": 26,
34 "column": 10
35 },
36 "end": {
37 "line": 29,
38 "column": 3
39 }
40 },
41 {
42 "id": "sidebar.openWorkspaceDrawer",
43 "defaultMessage": "!!!Open workspace drawer",
44 "file": "src/components/layout/Sidebar.js",
45 "start": {
46 "line": 30,
47 "column": 23
48 },
49 "end": {
50 "line": 33,
51 "column": 3
52 }
53 },
54 {
55 "id": "sidebar.closeWorkspaceDrawer",
56 "defaultMessage": "!!!Close workspace drawer",
57 "file": "src/components/layout/Sidebar.js",
58 "start": {
59 "line": 34,
60 "column": 24
61 },
62 "end": {
63 "line": 37,
64 "column": 3
65 }
66 },
67 {
68 "id": "sidebar.openTodosDrawer",
69 "defaultMessage": "!!!Open Ferdi Todos",
70 "file": "src/components/layout/Sidebar.js",
71 "start": {
72 "line": 38,
73 "column": 19
74 },
75 "end": {
76 "line": 41,
77 "column": 3
78 }
79 },
80 {
81 "id": "sidebar.closeTodosDrawer",
82 "defaultMessage": "!!!Close Ferdi Todos",
83 "file": "src/components/layout/Sidebar.js",
84 "start": {
85 "line": 42,
86 "column": 20
87 },
88 "end": {
89 "line": 45,
90 "column": 3
91 }
92 },
93 {
94 "id": "sidebar.lockFerdi",
95 "defaultMessage": "!!!Lock Ferdi",
96 "file": "src/components/layout/Sidebar.js",
97 "start": {
98 "line": 46,
99 "column": 13
100 },
101 "end": {
102 "line": 49,
103 "column": 3
104 }
105 }
106] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/ConnectionBanner.json b/src/i18n/messages/src/components/services/content/ConnectionBanner.json
deleted file mode 100644
index 1047c28b5..000000000
--- a/src/i18n/messages/src/components/services/content/ConnectionBanner.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "webControls.goHome",
4 "defaultMessage": "!!!Home",
5 "file": "src/components/services/content/ConnectionBanner.js",
6 "start": {
7 "line": 13,
8 "column": 10
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "webControls.openInBrowser",
17 "defaultMessage": "!!!Open in Browser",
18 "file": "src/components/services/content/ConnectionBanner.js",
19 "start": {
20 "line": 17,
21 "column": 17
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "webControls.back",
30 "defaultMessage": "!!!Back",
31 "file": "src/components/services/content/ConnectionBanner.js",
32 "start": {
33 "line": 21,
34 "column": 8
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 },
41 {
42 "id": "webControls.forward",
43 "defaultMessage": "!!!Forward",
44 "file": "src/components/services/content/ConnectionBanner.js",
45 "start": {
46 "line": 25,
47 "column": 11
48 },
49 "end": {
50 "line": 28,
51 "column": 3
52 }
53 },
54 {
55 "id": "webControls.reload",
56 "defaultMessage": "!!!Reload",
57 "file": "src/components/services/content/ConnectionBanner.js",
58 "start": {
59 "line": 29,
60 "column": 10
61 },
62 "end": {
63 "line": 32,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/ConnectionLost.json b/src/i18n/messages/src/components/services/content/ConnectionLost.json
deleted file mode 100644
index ee3f7a4ba..000000000
--- a/src/i18n/messages/src/components/services/content/ConnectionLost.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "webControls.goHome",
4 "defaultMessage": "!!!Home",
5 "file": "src/components/services/content/ConnectionLost.js",
6 "start": {
7 "line": 13,
8 "column": 10
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "webControls.openInBrowser",
17 "defaultMessage": "!!!Open in Browser",
18 "file": "src/components/services/content/ConnectionLost.js",
19 "start": {
20 "line": 17,
21 "column": 17
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "webControls.back",
30 "defaultMessage": "!!!Back",
31 "file": "src/components/services/content/ConnectionLost.js",
32 "start": {
33 "line": 21,
34 "column": 8
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 },
41 {
42 "id": "webControls.forward",
43 "defaultMessage": "!!!Forward",
44 "file": "src/components/services/content/ConnectionLost.js",
45 "start": {
46 "line": 25,
47 "column": 11
48 },
49 "end": {
50 "line": 28,
51 "column": 3
52 }
53 },
54 {
55 "id": "webControls.reload",
56 "defaultMessage": "!!!Reload",
57 "file": "src/components/services/content/ConnectionLost.js",
58 "start": {
59 "line": 29,
60 "column": 10
61 },
62 "end": {
63 "line": 32,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/ConnectionLostBanner.json b/src/i18n/messages/src/components/services/content/ConnectionLostBanner.json
deleted file mode 100644
index 6805b4d67..000000000
--- a/src/i18n/messages/src/components/services/content/ConnectionLostBanner.json
+++ /dev/null
@@ -1,41 +0,0 @@
1[
2 {
3 "id": "connectionLostBanner.message",
4 "defaultMessage": "!!!Oh no! Ferdi lost the connection to {name}.",
5 "file": "src/components/services/content/ConnectionLostBanner.js",
6 "start": {
7 "line": 13,
8 "column": 8
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "connectionLostBanner.informationLink",
17 "defaultMessage": "!!!What happened?",
18 "file": "src/components/services/content/ConnectionLostBanner.js",
19 "start": {
20 "line": 17,
21 "column": 19
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "connectionLostBanner.cta",
30 "defaultMessage": "!!!Reload Service",
31 "file": "src/components/services/content/ConnectionLostBanner.js",
32 "start": {
33 "line": 21,
34 "column": 7
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 }
41] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/ErrorHandlers/WebviewErrorHandler.json b/src/i18n/messages/src/components/services/content/ErrorHandlers/WebviewErrorHandler.json
deleted file mode 100644
index c8fe802df..000000000
--- a/src/i18n/messages/src/components/services/content/ErrorHandlers/WebviewErrorHandler.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "service.errorHandler.headline",
4 "defaultMessage": "!!!Oh no!",
5 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
6 "start": {
7 "line": 12,
8 "column": 12
9 },
10 "end": {
11 "line": 15,
12 "column": 3
13 }
14 },
15 {
16 "id": "service.errorHandler.text",
17 "defaultMessage": "!!!{name} has failed to load.",
18 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
19 "start": {
20 "line": 16,
21 "column": 8
22 },
23 "end": {
24 "line": 19,
25 "column": 3
26 }
27 },
28 {
29 "id": "service.errorHandler.action",
30 "defaultMessage": "!!!Reload {name}",
31 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
32 "start": {
33 "line": 20,
34 "column": 10
35 },
36 "end": {
37 "line": 23,
38 "column": 3
39 }
40 },
41 {
42 "id": "service.errorHandler.editAction",
43 "defaultMessage": "!!!Edit {name}",
44 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
45 "start": {
46 "line": 24,
47 "column": 14
48 },
49 "end": {
50 "line": 27,
51 "column": 3
52 }
53 },
54 {
55 "id": "service.errorHandler.message",
56 "defaultMessage": "!!!Error:",
57 "file": "src/components/services/content/ErrorHandlers/WebviewErrorHandler.js",
58 "start": {
59 "line": 28,
60 "column": 16
61 },
62 "end": {
63 "line": 31,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/ServiceDisabled.json b/src/i18n/messages/src/components/services/content/ServiceDisabled.json
deleted file mode 100644
index 8bfad28c7..000000000
--- a/src/i18n/messages/src/components/services/content/ServiceDisabled.json
+++ /dev/null
@@ -1,28 +0,0 @@
1[
2 {
3 "id": "service.disabledHandler.headline",
4 "defaultMessage": "!!!{name} is disabled",
5 "file": "src/components/services/content/ServiceDisabled.js",
6 "start": {
7 "line": 9,
8 "column": 12
9 },
10 "end": {
11 "line": 12,
12 "column": 3
13 }
14 },
15 {
16 "id": "service.disabledHandler.action",
17 "defaultMessage": "!!!Enable {name}",
18 "file": "src/components/services/content/ServiceDisabled.js",
19 "start": {
20 "line": 13,
21 "column": 10
22 },
23 "end": {
24 "line": 16,
25 "column": 3
26 }
27 }
28] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/Services.json b/src/i18n/messages/src/components/services/content/Services.json
deleted file mode 100644
index 304c93f3c..000000000
--- a/src/i18n/messages/src/components/services/content/Services.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "services.welcome",
4 "defaultMessage": "!!!Welcome to Ferdi",
5 "file": "src/components/services/content/Services.js",
6 "start": {
7 "line": 15,
8 "column": 11
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "services.getStarted",
17 "defaultMessage": "!!!Get started",
18 "file": "src/components/services/content/Services.js",
19 "start": {
20 "line": 19,
21 "column": 14
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "services.login",
30 "defaultMessage": "!!!Please login to use Ferdi.",
31 "file": "src/components/services/content/Services.js",
32 "start": {
33 "line": 23,
34 "column": 9
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "services.serverless",
43 "defaultMessage": "!!!Use Ferdi without an Account",
44 "file": "src/components/services/content/Services.js",
45 "start": {
46 "line": 27,
47 "column": 14
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "services.serverInfo",
56 "defaultMessage": "!!!Optionally, you can change your Ferdi server by clicking the cog in the bottom left corner. If you are switching over (from one of the hosted servers) to using Ferdi without an account, please be informed that you can export your data from that server and subsequently import it using the Help menu to resurrect all your workspaces and configured services!",
57 "file": "src/components/services/content/Services.js",
58 "start": {
59 "line": 31,
60 "column": 14
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/WebControls.json b/src/i18n/messages/src/components/services/content/WebControls.json
deleted file mode 100644
index 5af5143d0..000000000
--- a/src/i18n/messages/src/components/services/content/WebControls.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "webControls.goHome",
4 "defaultMessage": "!!!Home",
5 "file": "src/components/services/content/WebControls.js",
6 "start": {
7 "line": 13,
8 "column": 10
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "webControls.openInBrowser",
17 "defaultMessage": "!!!Open in Browser",
18 "file": "src/components/services/content/WebControls.js",
19 "start": {
20 "line": 17,
21 "column": 17
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "webControls.back",
30 "defaultMessage": "!!!Back",
31 "file": "src/components/services/content/WebControls.js",
32 "start": {
33 "line": 21,
34 "column": 8
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 },
41 {
42 "id": "webControls.forward",
43 "defaultMessage": "!!!Forward",
44 "file": "src/components/services/content/WebControls.js",
45 "start": {
46 "line": 25,
47 "column": 11
48 },
49 "end": {
50 "line": 28,
51 "column": 3
52 }
53 },
54 {
55 "id": "webControls.reload",
56 "defaultMessage": "!!!Reload",
57 "file": "src/components/services/content/WebControls.js",
58 "start": {
59 "line": 29,
60 "column": 10
61 },
62 "end": {
63 "line": 32,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/content/WebviewCrashHandler.json b/src/i18n/messages/src/components/services/content/WebviewCrashHandler.json
deleted file mode 100644
index c3d6c41a5..000000000
--- a/src/i18n/messages/src/components/services/content/WebviewCrashHandler.json
+++ /dev/null
@@ -1,54 +0,0 @@
1[
2 {
3 "id": "service.crashHandler.headline",
4 "defaultMessage": "!!!Oh no!",
5 "file": "src/components/services/content/WebviewCrashHandler.js",
6 "start": {
7 "line": 10,
8 "column": 12
9 },
10 "end": {
11 "line": 13,
12 "column": 3
13 }
14 },
15 {
16 "id": "service.crashHandler.text",
17 "defaultMessage": "!!!{name} has caused an error.",
18 "file": "src/components/services/content/WebviewCrashHandler.js",
19 "start": {
20 "line": 14,
21 "column": 8
22 },
23 "end": {
24 "line": 17,
25 "column": 3
26 }
27 },
28 {
29 "id": "service.crashHandler.action",
30 "defaultMessage": "!!!Reload {name}",
31 "file": "src/components/services/content/WebviewCrashHandler.js",
32 "start": {
33 "line": 18,
34 "column": 10
35 },
36 "end": {
37 "line": 21,
38 "column": 3
39 }
40 },
41 {
42 "id": "service.crashHandler.autoReload",
43 "defaultMessage": "!!!Trying to automatically restore {name} in {seconds} seconds",
44 "file": "src/components/services/content/WebviewCrashHandler.js",
45 "start": {
46 "line": 22,
47 "column": 14
48 },
49 "end": {
50 "line": 25,
51 "column": 3
52 }
53 }
54] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/services/tabs/TabItem.json b/src/i18n/messages/src/components/services/tabs/TabItem.json
deleted file mode 100644
index de854f1e1..000000000
--- a/src/i18n/messages/src/components/services/tabs/TabItem.json
+++ /dev/null
@@ -1,171 +0,0 @@
1[
2 {
3 "id": "tabs.item.reload",
4 "defaultMessage": "!!!Reload",
5 "file": "src/components/services/tabs/TabItem.js",
6 "start": {
7 "line": 21,
8 "column": 10
9 },
10 "end": {
11 "line": 24,
12 "column": 3
13 }
14 },
15 {
16 "id": "tabs.item.disableNotifications",
17 "defaultMessage": "!!!Disable notifications",
18 "file": "src/components/services/tabs/TabItem.js",
19 "start": {
20 "line": 25,
21 "column": 24
22 },
23 "end": {
24 "line": 28,
25 "column": 3
26 }
27 },
28 {
29 "id": "tabs.item.enableNotification",
30 "defaultMessage": "!!!Enable notifications",
31 "file": "src/components/services/tabs/TabItem.js",
32 "start": {
33 "line": 29,
34 "column": 23
35 },
36 "end": {
37 "line": 32,
38 "column": 3
39 }
40 },
41 {
42 "id": "tabs.item.disableAudio",
43 "defaultMessage": "!!!Disable audio",
44 "file": "src/components/services/tabs/TabItem.js",
45 "start": {
46 "line": 33,
47 "column": 16
48 },
49 "end": {
50 "line": 36,
51 "column": 3
52 }
53 },
54 {
55 "id": "tabs.item.enableAudio",
56 "defaultMessage": "!!!Enable audio",
57 "file": "src/components/services/tabs/TabItem.js",
58 "start": {
59 "line": 37,
60 "column": 15
61 },
62 "end": {
63 "line": 40,
64 "column": 3
65 }
66 },
67 {
68 "id": "tabs.item.enableDarkMode",
69 "defaultMessage": "!!!Enable Dark mode",
70 "file": "src/components/services/tabs/TabItem.js",
71 "start": {
72 "line": 41,
73 "column": 18
74 },
75 "end": {
76 "line": 44,
77 "column": 3
78 }
79 },
80 {
81 "id": "tabs.item.disableDarkMode",
82 "defaultMessage": "!!!Disable Dark mode",
83 "file": "src/components/services/tabs/TabItem.js",
84 "start": {
85 "line": 45,
86 "column": 19
87 },
88 "end": {
89 "line": 48,
90 "column": 3
91 }
92 },
93 {
94 "id": "tabs.item.disableService",
95 "defaultMessage": "!!!Disable Service",
96 "file": "src/components/services/tabs/TabItem.js",
97 "start": {
98 "line": 49,
99 "column": 18
100 },
101 "end": {
102 "line": 52,
103 "column": 3
104 }
105 },
106 {
107 "id": "tabs.item.enableService",
108 "defaultMessage": "!!!Enable Service",
109 "file": "src/components/services/tabs/TabItem.js",
110 "start": {
111 "line": 53,
112 "column": 17
113 },
114 "end": {
115 "line": 56,
116 "column": 3
117 }
118 },
119 {
120 "id": "tabs.item.hibernateService",
121 "defaultMessage": "!!!Hibernate Service",
122 "file": "src/components/services/tabs/TabItem.js",
123 "start": {
124 "line": 57,
125 "column": 20
126 },
127 "end": {
128 "line": 60,
129 "column": 3
130 }
131 },
132 {
133 "id": "tabs.item.wakeUpService",
134 "defaultMessage": "!!!Wake Up Service",
135 "file": "src/components/services/tabs/TabItem.js",
136 "start": {
137 "line": 61,
138 "column": 17
139 },
140 "end": {
141 "line": 64,
142 "column": 3
143 }
144 },
145 {
146 "id": "tabs.item.deleteService",
147 "defaultMessage": "!!!Delete Service",
148 "file": "src/components/services/tabs/TabItem.js",
149 "start": {
150 "line": 65,
151 "column": 17
152 },
153 "end": {
154 "line": 68,
155 "column": 3
156 }
157 },
158 {
159 "id": "tabs.item.confirmDeleteService",
160 "defaultMessage": "!!!Do you really want to delete the {serviceName} service?",
161 "file": "src/components/services/tabs/TabItem.js",
162 "start": {
163 "line": 69,
164 "column": 24
165 },
166 "end": {
167 "line": 73,
168 "column": 3
169 }
170 }
171] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/SettingsLayout.json b/src/i18n/messages/src/components/settings/SettingsLayout.json
deleted file mode 100644
index 99337a315..000000000
--- a/src/i18n/messages/src/components/settings/SettingsLayout.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "settings.app.closeSettings",
4 "defaultMessage": "!!!Close settings",
5 "file": "src/components/settings/SettingsLayout.js",
6 "start": {
7 "line": 11,
8 "column": 17
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/account/AccountDashboard.json b/src/i18n/messages/src/components/settings/account/AccountDashboard.json
deleted file mode 100644
index b0cc2dcc7..000000000
--- a/src/i18n/messages/src/components/settings/account/AccountDashboard.json
+++ /dev/null
@@ -1,158 +0,0 @@
1[
2 {
3 "id": "settings.account.headline",
4 "defaultMessage": "!!!Account",
5 "file": "src/components/settings/account/AccountDashboard.js",
6 "start": {
7 "line": 14,
8 "column": 12
9 },
10 "end": {
11 "line": 17,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.account.headlineDangerZone",
17 "defaultMessage": "!!Danger Zone",
18 "file": "src/components/settings/account/AccountDashboard.js",
19 "start": {
20 "line": 18,
21 "column": 22
22 },
23 "end": {
24 "line": 21,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.account.account.editButton",
30 "defaultMessage": "!!!Edit Account",
31 "file": "src/components/settings/account/AccountDashboard.js",
32 "start": {
33 "line": 22,
34 "column": 21
35 },
36 "end": {
37 "line": 25,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.account.headlineInvoices",
43 "defaultMessage": "!!Invoices",
44 "file": "src/components/settings/account/AccountDashboard.js",
45 "start": {
46 "line": 26,
47 "column": 18
48 },
49 "end": {
50 "line": 29,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.account.userInfoRequestFailed",
56 "defaultMessage": "!!!Could not load user information",
57 "file": "src/components/settings/account/AccountDashboard.js",
58 "start": {
59 "line": 30,
60 "column": 25
61 },
62 "end": {
63 "line": 33,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.account.tryReloadUserInfoRequest",
69 "defaultMessage": "!!!Try again",
70 "file": "src/components/settings/account/AccountDashboard.js",
71 "start": {
72 "line": 34,
73 "column": 28
74 },
75 "end": {
76 "line": 37,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.account.deleteAccount",
82 "defaultMessage": "!!!Delete account",
83 "file": "src/components/settings/account/AccountDashboard.js",
84 "start": {
85 "line": 38,
86 "column": 17
87 },
88 "end": {
89 "line": 41,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.account.deleteInfo",
95 "defaultMessage": "!!!If you don't need your Ferdi account any longer, you can delete your account and all related data here.",
96 "file": "src/components/settings/account/AccountDashboard.js",
97 "start": {
98 "line": 42,
99 "column": 14
100 },
101 "end": {
102 "line": 46,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.account.deleteEmailSent",
108 "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!",
109 "file": "src/components/settings/account/AccountDashboard.js",
110 "start": {
111 "line": 47,
112 "column": 19
113 },
114 "end": {
115 "line": 51,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.account.yourLicense",
121 "defaultMessage": "!!!Your Franz License:",
122 "file": "src/components/settings/account/AccountDashboard.js",
123 "start": {
124 "line": 52,
125 "column": 15
126 },
127 "end": {
128 "line": 55,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.account.accountUnavailable",
134 "defaultMessage": "Account is unavailable",
135 "file": "src/components/settings/account/AccountDashboard.js",
136 "start": {
137 "line": 56,
138 "column": 22
139 },
140 "end": {
141 "line": 59,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.account.accountUnavailableInfo",
147 "defaultMessage": "You are using Ferdi without an account. If you want to use Ferdi with an account and keep your services synchronized across installations, please select a server in the Settings tab then login.",
148 "file": "src/components/settings/account/AccountDashboard.js",
149 "start": {
150 "line": 60,
151 "column": 26
152 },
153 "end": {
154 "line": 63,
155 "column": 3
156 }
157 }
158] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json
deleted file mode 100644
index 2029ad7af..000000000
--- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json
+++ /dev/null
@@ -1,93 +0,0 @@
1[
2 {
3 "id": "settings.navigation.availableServices",
4 "defaultMessage": "!!!Available services",
5 "file": "src/components/settings/navigation/SettingsNavigation.js",
6 "start": {
7 "line": 16,
8 "column": 21
9 },
10 "end": {
11 "line": 19,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.navigation.yourServices",
17 "defaultMessage": "!!!Your services",
18 "file": "src/components/settings/navigation/SettingsNavigation.js",
19 "start": {
20 "line": 20,
21 "column": 16
22 },
23 "end": {
24 "line": 23,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.navigation.yourWorkspaces",
30 "defaultMessage": "!!!Your workspaces",
31 "file": "src/components/settings/navigation/SettingsNavigation.js",
32 "start": {
33 "line": 24,
34 "column": 18
35 },
36 "end": {
37 "line": 27,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.navigation.account",
43 "defaultMessage": "!!!Account",
44 "file": "src/components/settings/navigation/SettingsNavigation.js",
45 "start": {
46 "line": 28,
47 "column": 11
48 },
49 "end": {
50 "line": 31,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.navigation.team",
56 "defaultMessage": "!!!Manage Team",
57 "file": "src/components/settings/navigation/SettingsNavigation.js",
58 "start": {
59 "line": 32,
60 "column": 8
61 },
62 "end": {
63 "line": 35,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.navigation.supportFerdi",
69 "defaultMessage": "!!!About Ferdi",
70 "file": "src/components/settings/navigation/SettingsNavigation.js",
71 "start": {
72 "line": 36,
73 "column": 16
74 },
75 "end": {
76 "line": 39,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.navigation.logout",
82 "defaultMessage": "!!!Logout",
83 "file": "src/components/settings/navigation/SettingsNavigation.js",
84 "start": {
85 "line": 40,
86 "column": 10
87 },
88 "end": {
89 "line": 43,
90 "column": 3
91 }
92 }
93] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json
deleted file mode 100644
index 7ab2916f5..000000000
--- a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json
+++ /dev/null
@@ -1,171 +0,0 @@
1[
2 {
3 "id": "settings.recipes.headline",
4 "defaultMessage": "!!!Available Services",
5 "file": "src/components/settings/recipes/RecipesDashboard.js",
6 "start": {
7 "line": 19,
8 "column": 12
9 },
10 "end": {
11 "line": 22,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.searchService",
17 "defaultMessage": "!!!Search service",
18 "file": "src/components/settings/recipes/RecipesDashboard.js",
19 "start": {
20 "line": 23,
21 "column": 17
22 },
23 "end": {
24 "line": 26,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.recipes.all",
30 "defaultMessage": "!!!All services",
31 "file": "src/components/settings/recipes/RecipesDashboard.js",
32 "start": {
33 "line": 27,
34 "column": 14
35 },
36 "end": {
37 "line": 30,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.recipes.custom",
43 "defaultMessage": "!!!Custom Services",
44 "file": "src/components/settings/recipes/RecipesDashboard.js",
45 "start": {
46 "line": 31,
47 "column": 17
48 },
49 "end": {
50 "line": 34,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.recipes.nothingFound",
56 "defaultMessage": "!!!Sorry, but no service matched your search term - but you can still probably add it using the \"Custom Website\" option. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
57 "file": "src/components/settings/recipes/RecipesDashboard.js",
58 "start": {
59 "line": 35,
60 "column": 16
61 },
62 "end": {
63 "line": 38,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.recipes.servicesSuccessfulAddedInfo",
69 "defaultMessage": "!!!Service successfully added",
70 "file": "src/components/settings/recipes/RecipesDashboard.js",
71 "start": {
72 "line": 39,
73 "column": 31
74 },
75 "end": {
76 "line": 42,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.recipes.missingService",
82 "defaultMessage": "!!!Missing a service?",
83 "file": "src/components/settings/recipes/RecipesDashboard.js",
84 "start": {
85 "line": 43,
86 "column": 18
87 },
88 "end": {
89 "line": 46,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.recipes.customService.intro",
95 "defaultMessage": "!!!To add a custom service, copy the recipe folder into:",
96 "file": "src/components/settings/recipes/RecipesDashboard.js",
97 "start": {
98 "line": 47,
99 "column": 21
100 },
101 "end": {
102 "line": 50,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.recipes.customService.openFolder",
108 "defaultMessage": "!!!Open directory",
109 "file": "src/components/settings/recipes/RecipesDashboard.js",
110 "start": {
111 "line": 51,
112 "column": 14
113 },
114 "end": {
115 "line": 54,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.recipes.customService.openDevDocs",
121 "defaultMessage": "!!!Developer Documentation",
122 "file": "src/components/settings/recipes/RecipesDashboard.js",
123 "start": {
124 "line": 55,
125 "column": 15
126 },
127 "end": {
128 "line": 58,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.recipes.customService.headline.customRecipes",
134 "defaultMessage": "!!!Custom 3rd Party Recipes",
135 "file": "src/components/settings/recipes/RecipesDashboard.js",
136 "start": {
137 "line": 59,
138 "column": 25
139 },
140 "end": {
141 "line": 62,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.recipes.customService.headline.communityRecipes",
147 "defaultMessage": "!!!Community 3rd Party Recipes",
148 "file": "src/components/settings/recipes/RecipesDashboard.js",
149 "start": {
150 "line": 63,
151 "column": 28
152 },
153 "end": {
154 "line": 66,
155 "column": 3
156 }
157 },
158 {
159 "id": "settings.recipes.customService.headline.devRecipes",
160 "defaultMessage": "!!!Your Development Service Recipes",
161 "file": "src/components/settings/recipes/RecipesDashboard.js",
162 "start": {
163 "line": 67,
164 "column": 22
165 },
166 "end": {
167 "line": 70,
168 "column": 3
169 }
170 }
171] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/services/EditServiceForm.json b/src/i18n/messages/src/components/settings/services/EditServiceForm.json
deleted file mode 100644
index d7830f198..000000000
--- a/src/i18n/messages/src/components/settings/services/EditServiceForm.json
+++ /dev/null
@@ -1,340 +0,0 @@
1[
2 {
3 "id": "settings.service.form.saveButton",
4 "defaultMessage": "!!!Save service",
5 "file": "src/components/settings/services/EditServiceForm.js",
6 "start": {
7 "line": 23,
8 "column": 15
9 },
10 "end": {
11 "line": 26,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.service.form.deleteButton",
17 "defaultMessage": "!!!Delete Service",
18 "file": "src/components/settings/services/EditServiceForm.js",
19 "start": {
20 "line": 27,
21 "column": 17
22 },
23 "end": {
24 "line": 30,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.service.form.openDarkmodeCss",
30 "defaultMessage": "!!!Open darkmode.css",
31 "file": "src/components/settings/services/EditServiceForm.js",
32 "start": {
33 "line": 31,
34 "column": 19
35 },
36 "end": {
37 "line": 34,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.service.form.openUserCss",
43 "defaultMessage": "!!!Open user.css",
44 "file": "src/components/settings/services/EditServiceForm.js",
45 "start": {
46 "line": 35,
47 "column": 15
48 },
49 "end": {
50 "line": 38,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.service.form.openUserJs",
56 "defaultMessage": "!!!Open user.js",
57 "file": "src/components/settings/services/EditServiceForm.js",
58 "start": {
59 "line": 39,
60 "column": 14
61 },
62 "end": {
63 "line": 42,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.service.form.recipeFileInfo",
69 "defaultMessage": "!!!Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
70 "file": "src/components/settings/services/EditServiceForm.js",
71 "start": {
72 "line": 43,
73 "column": 18
74 },
75 "end": {
76 "line": 46,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.service.form.availableServices",
82 "defaultMessage": "!!!Available services",
83 "file": "src/components/settings/services/EditServiceForm.js",
84 "start": {
85 "line": 47,
86 "column": 21
87 },
88 "end": {
89 "line": 50,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.service.form.yourServices",
95 "defaultMessage": "!!!Your services",
96 "file": "src/components/settings/services/EditServiceForm.js",
97 "start": {
98 "line": 51,
99 "column": 16
100 },
101 "end": {
102 "line": 54,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.service.form.addServiceHeadline",
108 "defaultMessage": "!!!Add {name}",
109 "file": "src/components/settings/services/EditServiceForm.js",
110 "start": {
111 "line": 55,
112 "column": 22
113 },
114 "end": {
115 "line": 58,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.service.form.editServiceHeadline",
121 "defaultMessage": "!!!Edit {name}",
122 "file": "src/components/settings/services/EditServiceForm.js",
123 "start": {
124 "line": 59,
125 "column": 23
126 },
127 "end": {
128 "line": 62,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.service.form.tabHosted",
134 "defaultMessage": "!!!Hosted",
135 "file": "src/components/settings/services/EditServiceForm.js",
136 "start": {
137 "line": 63,
138 "column": 13
139 },
140 "end": {
141 "line": 66,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.service.form.tabOnPremise",
147 "defaultMessage": "!!!Self hosted â­ï¸",
148 "file": "src/components/settings/services/EditServiceForm.js",
149 "start": {
150 "line": 67,
151 "column": 16
152 },
153 "end": {
154 "line": 70,
155 "column": 3
156 }
157 },
158 {
159 "id": "settings.service.form.useHostedService",
160 "defaultMessage": "!!!Use the hosted {name} service.",
161 "file": "src/components/settings/services/EditServiceForm.js",
162 "start": {
163 "line": 71,
164 "column": 20
165 },
166 "end": {
167 "line": 74,
168 "column": 3
169 }
170 },
171 {
172 "id": "settings.service.form.customUrlValidationError",
173 "defaultMessage": "!!!Could not validate custom {name} server.",
174 "file": "src/components/settings/services/EditServiceForm.js",
175 "start": {
176 "line": 75,
177 "column": 28
178 },
179 "end": {
180 "line": 78,
181 "column": 3
182 }
183 },
184 {
185 "id": "settings.service.form.indirectMessageInfo",
186 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
187 "file": "src/components/settings/services/EditServiceForm.js",
188 "start": {
189 "line": 79,
190 "column": 23
191 },
192 "end": {
193 "line": 82,
194 "column": 3
195 }
196 },
197 {
198 "id": "settings.service.form.isMutedInfo",
199 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted",
200 "file": "src/components/settings/services/EditServiceForm.js",
201 "start": {
202 "line": 83,
203 "column": 15
204 },
205 "end": {
206 "line": 86,
207 "column": 3
208 }
209 },
210 {
211 "id": "settings.service.form.isHibernatedEnabledInfo",
212 "defaultMessage": "!!!When enabled, a service will be shut down after a period of time to save system resources.",
213 "file": "src/components/settings/services/EditServiceForm.js",
214 "start": {
215 "line": 87,
216 "column": 28
217 },
218 "end": {
219 "line": 90,
220 "column": 3
221 }
222 },
223 {
224 "id": "settings.service.form.headlineNotifications",
225 "defaultMessage": "!!!Notifications",
226 "file": "src/components/settings/services/EditServiceForm.js",
227 "start": {
228 "line": 91,
229 "column": 25
230 },
231 "end": {
232 "line": 94,
233 "column": 3
234 }
235 },
236 {
237 "id": "settings.service.form.headlineBadges",
238 "defaultMessage": "!!!Unread message badges",
239 "file": "src/components/settings/services/EditServiceForm.js",
240 "start": {
241 "line": 95,
242 "column": 18
243 },
244 "end": {
245 "line": 98,
246 "column": 3
247 }
248 },
249 {
250 "id": "settings.service.form.headlineGeneral",
251 "defaultMessage": "!!!General",
252 "file": "src/components/settings/services/EditServiceForm.js",
253 "start": {
254 "line": 99,
255 "column": 19
256 },
257 "end": {
258 "line": 102,
259 "column": 3
260 }
261 },
262 {
263 "id": "settings.service.form.headlineDarkReaderSettings",
264 "defaultMessage": "!!!Dark Reader Settings",
265 "file": "src/components/settings/services/EditServiceForm.js",
266 "start": {
267 "line": 103,
268 "column": 30
269 },
270 "end": {
271 "line": 106,
272 "column": 3
273 }
274 },
275 {
276 "id": "settings.service.form.iconDelete",
277 "defaultMessage": "!!!Delete",
278 "file": "src/components/settings/services/EditServiceForm.js",
279 "start": {
280 "line": 107,
281 "column": 14
282 },
283 "end": {
284 "line": 110,
285 "column": 3
286 }
287 },
288 {
289 "id": "settings.service.form.iconUpload",
290 "defaultMessage": "!!!Drop your image, or click here",
291 "file": "src/components/settings/services/EditServiceForm.js",
292 "start": {
293 "line": 111,
294 "column": 14
295 },
296 "end": {
297 "line": 114,
298 "column": 3
299 }
300 },
301 {
302 "id": "settings.service.form.proxy.headline",
303 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings",
304 "file": "src/components/settings/services/EditServiceForm.js",
305 "start": {
306 "line": 115,
307 "column": 17
308 },
309 "end": {
310 "line": 118,
311 "column": 3
312 }
313 },
314 {
315 "id": "settings.service.form.proxy.restartInfo",
316 "defaultMessage": "!!!Please restart Ferdi after changing proxy Settings.",
317 "file": "src/components/settings/services/EditServiceForm.js",
318 "start": {
319 "line": 119,
320 "column": 20
321 },
322 "end": {
323 "line": 122,
324 "column": 3
325 }
326 },
327 {
328 "id": "settings.service.form.proxy.info",
329 "defaultMessage": "!!!Proxy settings will not be synchronized with the Ferdi servers.",
330 "file": "src/components/settings/services/EditServiceForm.js",
331 "start": {
332 "line": 123,
333 "column": 13
334 },
335 "end": {
336 "line": 126,
337 "column": 3
338 }
339 }
340] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/services/ServiceError.json b/src/i18n/messages/src/components/settings/services/ServiceError.json
deleted file mode 100644
index 648fc5b3e..000000000
--- a/src/i18n/messages/src/components/settings/services/ServiceError.json
+++ /dev/null
@@ -1,54 +0,0 @@
1[
2 {
3 "id": "settings.service.error.headline",
4 "defaultMessage": "!!!Error",
5 "file": "src/components/settings/services/ServiceError.js",
6 "start": {
7 "line": 10,
8 "column": 12
9 },
10 "end": {
11 "line": 13,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.service.error.goBack",
17 "defaultMessage": "!!!Back to services",
18 "file": "src/components/settings/services/ServiceError.js",
19 "start": {
20 "line": 14,
21 "column": 10
22 },
23 "end": {
24 "line": 17,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.service.form.availableServices",
30 "defaultMessage": "!!!Available services",
31 "file": "src/components/settings/services/ServiceError.js",
32 "start": {
33 "line": 18,
34 "column": 21
35 },
36 "end": {
37 "line": 21,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.service.error.message",
43 "defaultMessage": "!!!Could not load service recipe.",
44 "file": "src/components/settings/services/ServiceError.js",
45 "start": {
46 "line": 22,
47 "column": 16
48 },
49 "end": {
50 "line": 25,
51 "column": 3
52 }
53 }
54] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/services/ServiceItem.json b/src/i18n/messages/src/components/settings/services/ServiceItem.json
deleted file mode 100644
index ffea8b9e1..000000000
--- a/src/i18n/messages/src/components/settings/services/ServiceItem.json
+++ /dev/null
@@ -1,41 +0,0 @@
1[
2 {
3 "id": "settings.services.tooltip.isDisabled",
4 "defaultMessage": "!!!Service is disabled",
5 "file": "src/components/settings/services/ServiceItem.js",
6 "start": {
7 "line": 11,
8 "column": 21
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.services.tooltip.notificationsDisabled",
17 "defaultMessage": "!!!Notifications are disabled",
18 "file": "src/components/settings/services/ServiceItem.js",
19 "start": {
20 "line": 15,
21 "column": 32
22 },
23 "end": {
24 "line": 18,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.services.tooltip.isMuted",
30 "defaultMessage": "!!!All sounds are muted",
31 "file": "src/components/settings/services/ServiceItem.js",
32 "start": {
33 "line": 19,
34 "column": 18
35 },
36 "end": {
37 "line": 22,
38 "column": 3
39 }
40 }
41] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/services/ServicesDashboard.json b/src/i18n/messages/src/components/settings/services/ServicesDashboard.json
deleted file mode 100644
index 7e7c5d67e..000000000
--- a/src/i18n/messages/src/components/settings/services/ServicesDashboard.json
+++ /dev/null
@@ -1,119 +0,0 @@
1[
2 {
3 "id": "settings.services.headline",
4 "defaultMessage": "!!!Your services",
5 "file": "src/components/settings/services/ServicesDashboard.js",
6 "start": {
7 "line": 15,
8 "column": 12
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.searchService",
17 "defaultMessage": "!!!Search service",
18 "file": "src/components/settings/services/ServicesDashboard.js",
19 "start": {
20 "line": 19,
21 "column": 17
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.services.noServicesAdded",
30 "defaultMessage": "!!!Start by adding a service.",
31 "file": "src/components/settings/services/ServicesDashboard.js",
32 "start": {
33 "line": 23,
34 "column": 19
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.recipes.nothingFound",
43 "defaultMessage": "!!!Sorry, but no service matched your search term. Please note that the website might show more services that have been added to Ferdi since the version that you are currently on. To get those new services, please consider upgrading to a newer version of Ferdi.",
44 "file": "src/components/settings/services/ServicesDashboard.js",
45 "start": {
46 "line": 27,
47 "column": 18
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.services.discoverServices",
56 "defaultMessage": "!!!Discover services",
57 "file": "src/components/settings/services/ServicesDashboard.js",
58 "start": {
59 "line": 31,
60 "column": 20
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.services.servicesRequestFailed",
69 "defaultMessage": "!!!Could not load your services",
70 "file": "src/components/settings/services/ServicesDashboard.js",
71 "start": {
72 "line": 35,
73 "column": 25
74 },
75 "end": {
76 "line": 38,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.account.tryReloadServices",
82 "defaultMessage": "!!!Try again",
83 "file": "src/components/settings/services/ServicesDashboard.js",
84 "start": {
85 "line": 39,
86 "column": 21
87 },
88 "end": {
89 "line": 42,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.services.updatedInfo",
95 "defaultMessage": "!!!Your changes have been saved",
96 "file": "src/components/settings/services/ServicesDashboard.js",
97 "start": {
98 "line": 43,
99 "column": 15
100 },
101 "end": {
102 "line": 46,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.services.deletedInfo",
108 "defaultMessage": "!!!Service has been deleted",
109 "file": "src/components/settings/services/ServicesDashboard.js",
110 "start": {
111 "line": 47,
112 "column": 15
113 },
114 "end": {
115 "line": 50,
116 "column": 3
117 }
118 }
119] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json b/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json
deleted file mode 100644
index c281ebff3..000000000
--- a/src/i18n/messages/src/components/settings/settings/EditSettingsForm.json
+++ /dev/null
@@ -1,444 +0,0 @@
1[
2 {
3 "id": "settings.app.headlineGeneral",
4 "defaultMessage": "!!!General",
5 "file": "src/components/settings/settings/EditSettingsForm.js",
6 "start": {
7 "line": 21,
8 "column": 19
9 },
10 "end": {
11 "line": 24,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.app.sentryInfo",
17 "defaultMessage": "!!!Sending telemetry data allows us to find errors in Ferdi - we will not send any personal information like your message data!",
18 "file": "src/components/settings/settings/EditSettingsForm.js",
19 "start": {
20 "line": 25,
21 "column": 14
22 },
23 "end": {
24 "line": 28,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.app.hibernateInfo",
30 "defaultMessage": "!!!By default, Ferdi will keep all your services open and loaded in the background so they are ready when you want to use them. Service Hibernation will unload your services after a specified amount. This is useful to save RAM or keeping services from slowing down your computer.",
31 "file": "src/components/settings/settings/EditSettingsForm.js",
32 "start": {
33 "line": 29,
34 "column": 17
35 },
36 "end": {
37 "line": 32,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.app.inactivityLockInfo",
43 "defaultMessage": "!!!Minutes of inactivity, after which Ferdi should automatically lock. Use 0 to disable",
44 "file": "src/components/settings/settings/EditSettingsForm.js",
45 "start": {
46 "line": 33,
47 "column": 22
48 },
49 "end": {
50 "line": 36,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.app.todoServerInfo",
56 "defaultMessage": "!!!This server will be used for the \"Franz Todo\" feature. (default: https://app.franztodos.com)",
57 "file": "src/components/settings/settings/EditSettingsForm.js",
58 "start": {
59 "line": 37,
60 "column": 18
61 },
62 "end": {
63 "line": 40,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.app.lockedPassword",
69 "defaultMessage": "!!!Password",
70 "file": "src/components/settings/settings/EditSettingsForm.js",
71 "start": {
72 "line": 41,
73 "column": 18
74 },
75 "end": {
76 "line": 44,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.app.lockedPasswordInfo",
82 "defaultMessage": "!!!Please make sure to set a password you'll remember.\nIf you loose this password, you will have to reinstall Ferdi.",
83 "file": "src/components/settings/settings/EditSettingsForm.js",
84 "start": {
85 "line": 45,
86 "column": 22
87 },
88 "end": {
89 "line": 48,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.app.lockInfo",
95 "defaultMessage": "!!!Password Lock allows you to keep your messages protected.\nUsing Password Lock, you will be prompted to enter your password everytime you start Ferdi or lock Ferdi yourself using the lock symbol in the bottom left corner or the shortcut {lockShortcut}.",
96 "file": "src/components/settings/settings/EditSettingsForm.js",
97 "start": {
98 "line": 49,
99 "column": 12
100 },
101 "end": {
102 "line": 52,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.app.scheduledDNDTimeInfo",
108 "defaultMessage": "!!!Times in 24-Hour-Format. End time can be before start time (e.g. start 17:00, end 09:00) to enable Do-not-Disturb overnight.",
109 "file": "src/components/settings/settings/EditSettingsForm.js",
110 "start": {
111 "line": 53,
112 "column": 24
113 },
114 "end": {
115 "line": 56,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.app.scheduledDNDInfo",
121 "defaultMessage": "!!!Scheduled Do-not-Disturb allows you to define a period of time in which you do not want to get Notifications from Ferdi.",
122 "file": "src/components/settings/settings/EditSettingsForm.js",
123 "start": {
124 "line": 57,
125 "column": 20
126 },
127 "end": {
128 "line": 60,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.app.headlineLanguage",
134 "defaultMessage": "!!!Language",
135 "file": "src/components/settings/settings/EditSettingsForm.js",
136 "start": {
137 "line": 61,
138 "column": 20
139 },
140 "end": {
141 "line": 64,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.app.headlineUpdates",
147 "defaultMessage": "!!!Updates",
148 "file": "src/components/settings/settings/EditSettingsForm.js",
149 "start": {
150 "line": 65,
151 "column": 19
152 },
153 "end": {
154 "line": 68,
155 "column": 3
156 }
157 },
158 {
159 "id": "settings.app.headlineAppearance",
160 "defaultMessage": "!!!Appearance",
161 "file": "src/components/settings/settings/EditSettingsForm.js",
162 "start": {
163 "line": 69,
164 "column": 22
165 },
166 "end": {
167 "line": 72,
168 "column": 3
169 }
170 },
171 {
172 "id": "settings.app.universalDarkModeInfo",
173 "defaultMessage": "!!!Universal Dark Mode tries to dynamically generate dark mode styles for services that are otherwise not currently supported.",
174 "file": "src/components/settings/settings/EditSettingsForm.js",
175 "start": {
176 "line": 73,
177 "column": 25
178 },
179 "end": {
180 "line": 76,
181 "column": 3
182 }
183 },
184 {
185 "id": "settings.app.accentColorInfo",
186 "defaultMessage": "!!!Write your accent color in a CSS-compatible format. (Default: {defaultAccentColor})",
187 "file": "src/components/settings/settings/EditSettingsForm.js",
188 "start": {
189 "line": 77,
190 "column": 19
191 },
192 "end": {
193 "line": 80,
194 "column": 3
195 }
196 },
197 {
198 "id": "settings.app.headlinePrivacy",
199 "defaultMessage": "!!!Privacy",
200 "file": "src/components/settings/settings/EditSettingsForm.js",
201 "start": {
202 "line": 81,
203 "column": 19
204 },
205 "end": {
206 "line": 84,
207 "column": 3
208 }
209 },
210 {
211 "id": "settings.app.headlineAdvanced",
212 "defaultMessage": "!!!Advanced",
213 "file": "src/components/settings/settings/EditSettingsForm.js",
214 "start": {
215 "line": 85,
216 "column": 20
217 },
218 "end": {
219 "line": 88,
220 "column": 3
221 }
222 },
223 {
224 "id": "settings.app.translationHelp",
225 "defaultMessage": "!!!Help us to translate Ferdi into your language.",
226 "file": "src/components/settings/settings/EditSettingsForm.js",
227 "start": {
228 "line": 89,
229 "column": 19
230 },
231 "end": {
232 "line": 92,
233 "column": 3
234 }
235 },
236 {
237 "id": "settings.app.spellCheckerLanguageInfo",
238 "defaultMessage": "!!!Ferdi uses your Mac's build-in spellchecker to check for typos. If you want to change the languages the spellchecker checks for, you can do so in your Mac's System Preferences.",
239 "file": "src/components/settings/settings/EditSettingsForm.js",
240 "start": {
241 "line": 93,
242 "column": 28
243 },
244 "end": {
245 "line": 96,
246 "column": 3
247 }
248 },
249 {
250 "id": "settings.app.subheadlineCache",
251 "defaultMessage": "!!!Cache",
252 "file": "src/components/settings/settings/EditSettingsForm.js",
253 "start": {
254 "line": 97,
255 "column": 20
256 },
257 "end": {
258 "line": 100,
259 "column": 3
260 }
261 },
262 {
263 "id": "settings.app.cacheInfo",
264 "defaultMessage": "!!!Ferdi cache is currently using {size} of disk space.",
265 "file": "src/components/settings/settings/EditSettingsForm.js",
266 "start": {
267 "line": 101,
268 "column": 13
269 },
270 "end": {
271 "line": 104,
272 "column": 3
273 }
274 },
275 {
276 "id": "settings.app.cacheNotCleared",
277 "defaultMessage": "!!!Couldn't clear all cache",
278 "file": "src/components/settings/settings/EditSettingsForm.js",
279 "start": {
280 "line": 105,
281 "column": 19
282 },
283 "end": {
284 "line": 108,
285 "column": 3
286 }
287 },
288 {
289 "id": "settings.app.buttonClearAllCache",
290 "defaultMessage": "!!!Clear cache",
291 "file": "src/components/settings/settings/EditSettingsForm.js",
292 "start": {
293 "line": 109,
294 "column": 23
295 },
296 "end": {
297 "line": 112,
298 "column": 3
299 }
300 },
301 {
302 "id": "settings.app.subheadlineFerdiProfile",
303 "defaultMessage": "!!!Ferdi Profile",
304 "file": "src/components/settings/settings/EditSettingsForm.js",
305 "start": {
306 "line": 113,
307 "column": 27
308 },
309 "end": {
310 "line": 116,
311 "column": 3
312 }
313 },
314 {
315 "id": "settings.app.buttonOpenFerdiProfileFolder",
316 "defaultMessage": "!!!Open Profile folder",
317 "file": "src/components/settings/settings/EditSettingsForm.js",
318 "start": {
319 "line": 117,
320 "column": 32
321 },
322 "end": {
323 "line": 120,
324 "column": 3
325 }
326 },
327 {
328 "id": "settings.app.buttonOpenFerdiServiceRecipesFolder",
329 "defaultMessage": "!!!Open Service Recipes folder",
330 "file": "src/components/settings/settings/EditSettingsForm.js",
331 "start": {
332 "line": 121,
333 "column": 39
334 },
335 "end": {
336 "line": 124,
337 "column": 3
338 }
339 },
340 {
341 "id": "settings.app.buttonSearchForUpdate",
342 "defaultMessage": "!!!Check for updates",
343 "file": "src/components/settings/settings/EditSettingsForm.js",
344 "start": {
345 "line": 125,
346 "column": 25
347 },
348 "end": {
349 "line": 128,
350 "column": 3
351 }
352 },
353 {
354 "id": "settings.app.buttonInstallUpdate",
355 "defaultMessage": "!!!Restart & install update",
356 "file": "src/components/settings/settings/EditSettingsForm.js",
357 "start": {
358 "line": 129,
359 "column": 23
360 },
361 "end": {
362 "line": 132,
363 "column": 3
364 }
365 },
366 {
367 "id": "settings.app.updateStatusSearching",
368 "defaultMessage": "!!!Is searching for update",
369 "file": "src/components/settings/settings/EditSettingsForm.js",
370 "start": {
371 "line": 133,
372 "column": 25
373 },
374 "end": {
375 "line": 136,
376 "column": 3
377 }
378 },
379 {
380 "id": "settings.app.updateStatusAvailable",
381 "defaultMessage": "!!!Update available, downloading...",
382 "file": "src/components/settings/settings/EditSettingsForm.js",
383 "start": {
384 "line": 137,
385 "column": 25
386 },
387 "end": {
388 "line": 140,
389 "column": 3
390 }
391 },
392 {
393 "id": "settings.app.updateStatusUpToDate",
394 "defaultMessage": "!!!You are using the latest version of Ferdi",
395 "file": "src/components/settings/settings/EditSettingsForm.js",
396 "start": {
397 "line": 141,
398 "column": 24
399 },
400 "end": {
401 "line": 144,
402 "column": 3
403 }
404 },
405 {
406 "id": "settings.app.currentVersion",
407 "defaultMessage": "!!!Current version:",
408 "file": "src/components/settings/settings/EditSettingsForm.js",
409 "start": {
410 "line": 145,
411 "column": 18
412 },
413 "end": {
414 "line": 148,
415 "column": 3
416 }
417 },
418 {
419 "id": "settings.app.restartRequired",
420 "defaultMessage": "!!!Changes require restart",
421 "file": "src/components/settings/settings/EditSettingsForm.js",
422 "start": {
423 "line": 149,
424 "column": 22
425 },
426 "end": {
427 "line": 152,
428 "column": 3
429 }
430 },
431 {
432 "id": "settings.app.languageDisclaimer",
433 "defaultMessage": "!!!Official translations are English & German. All other languages are community based translations.",
434 "file": "src/components/settings/settings/EditSettingsForm.js",
435 "start": {
436 "line": 153,
437 "column": 22
438 },
439 "end": {
440 "line": 156,
441 "column": 3
442 }
443 }
444] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/supportFerdi/SupportFerdiDashboard.json b/src/i18n/messages/src/components/settings/supportFerdi/SupportFerdiDashboard.json
deleted file mode 100644
index e63c2801f..000000000
--- a/src/i18n/messages/src/components/settings/supportFerdi/SupportFerdiDashboard.json
+++ /dev/null
@@ -1,197 +0,0 @@
1[
2 {
3 "id": "settings.supportFerdi.headline",
4 "defaultMessage": "!!!About Ferdi",
5 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
6 "start": {
7 "line": 7,
8 "column": 12
9 },
10 "end": {
11 "line": 10,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.supportFerdi.title",
17 "defaultMessage": "!!!Do you like Ferdi?",
18 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
19 "start": {
20 "line": 11,
21 "column": 9
22 },
23 "end": {
24 "line": 14,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.supportFerdi.aboutIntro",
30 "defaultMessage": "!!!<p>Ferdi is an open-source and a community-lead application.</p><p>Thanks to the people who make this possbile:</p>",
31 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
32 "start": {
33 "line": 15,
34 "column": 14
35 },
36 "end": {
37 "line": 18,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.supportFerdi.textListContributors",
43 "defaultMessage": "!!!Full list of contributor",
44 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
45 "start": {
46 "line": 19,
47 "column": 24
48 },
49 "end": {
50 "line": 22,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.supportFerdi.textListContributorsHere",
56 "defaultMessage": "!!!here",
57 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
58 "start": {
59 "line": 23,
60 "column": 28
61 },
62 "end": {
63 "line": 26,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.supportFerdi.textVolunteers",
69 "defaultMessage": "!!!The development of Ferdi is done by volunteers. People who use Ferdi like you. They maintain, fix, and improve Ferdi in their spare time.",
70 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
71 "start": {
72 "line": 27,
73 "column": 18
74 },
75 "end": {
76 "line": 30,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.supportFerdi.textSupportWelcome",
82 "defaultMessage": "!!!Support is always welcome. You can find a list of the help we need",
83 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
84 "start": {
85 "line": 31,
86 "column": 22
87 },
88 "end": {
89 "line": 34,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.supportFerdi.textSupportWelcomeHere",
95 "defaultMessage": "!!!here",
96 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
97 "start": {
98 "line": 35,
99 "column": 26
100 },
101 "end": {
102 "line": 38,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.supportFerdi.textExpenses",
108 "defaultMessage": "!!!While volunteers do most of the work, we still need to pay for servers and certificates. As a community, we are fully transparent on funds we collect and spend - see our",
109 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
110 "start": {
111 "line": 39,
112 "column": 16
113 },
114 "end": {
115 "line": 42,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.supportFerdi.textOpenCollective",
121 "defaultMessage": "!!!Open Collective",
122 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
123 "start": {
124 "line": 43,
125 "column": 22
126 },
127 "end": {
128 "line": 46,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.supportFerdi.textDonation",
134 "defaultMessage": "!!!If you feel like supporting Ferdi development with a donation, you can do so on both,",
135 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
136 "start": {
137 "line": 47,
138 "column": 16
139 },
140 "end": {
141 "line": 50,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.supportFerdi.textDonationAnd",
147 "defaultMessage": "!!!and",
148 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
149 "start": {
150 "line": 51,
151 "column": 19
152 },
153 "end": {
154 "line": 54,
155 "column": 3
156 }
157 },
158 {
159 "id": "settings.supportFerdi.textGitHubSponsors",
160 "defaultMessage": "!!!GitHub Sponsors",
161 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
162 "start": {
163 "line": 55,
164 "column": 22
165 },
166 "end": {
167 "line": 58,
168 "column": 3
169 }
170 },
171 {
172 "id": "settings.supportFerdi.openSurvey",
173 "defaultMessage": "!!!Open Survey",
174 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
175 "start": {
176 "line": 59,
177 "column": 14
178 },
179 "end": {
180 "line": 62,
181 "column": 3
182 }
183 },
184 {
185 "id": "settings.supportFerdi.bannerText",
186 "defaultMessage": "!!!Do you want to help us improve Ferdi?",
187 "file": "src/components/settings/supportFerdi/SupportFerdiDashboard.js",
188 "start": {
189 "line": 63,
190 "column": 14
191 },
192 "end": {
193 "line": 66,
194 "column": 3
195 }
196 }
197] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/team/TeamDashboard.json b/src/i18n/messages/src/components/settings/team/TeamDashboard.json
deleted file mode 100644
index ac42ad98a..000000000
--- a/src/i18n/messages/src/components/settings/team/TeamDashboard.json
+++ /dev/null
@@ -1,93 +0,0 @@
1[
2 {
3 "id": "settings.team.headline",
4 "defaultMessage": "!!!Team",
5 "file": "src/components/settings/team/TeamDashboard.js",
6 "start": {
7 "line": 15,
8 "column": 12
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.team.contentHeadline",
17 "defaultMessage": "!!!Franz Team Management",
18 "file": "src/components/settings/team/TeamDashboard.js",
19 "start": {
20 "line": 19,
21 "column": 19
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.team.intro",
30 "defaultMessage": "!!!Your are currently using Franz Servers, which is why you have access to Team Management.",
31 "file": "src/components/settings/team/TeamDashboard.js",
32 "start": {
33 "line": 23,
34 "column": 9
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.team.copy",
43 "defaultMessage": "!!!Franz's Team Management allows you to manage Franz Subscriptions for multiple users. Please keep in mind that having a Franz Premium subscription will give you no advantages in using Ferdi: The only reason you still have access to Team Management is so you can manage your legacy Franz Teams and so that you don't loose any functionality in managing your account.",
44 "file": "src/components/settings/team/TeamDashboard.js",
45 "start": {
46 "line": 27,
47 "column": 8
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.team.manageAction",
56 "defaultMessage": "!!!Manage your Team on meetfranz.com",
57 "file": "src/components/settings/team/TeamDashboard.js",
58 "start": {
59 "line": 31,
60 "column": 16
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.team.teamsUnavailable",
69 "defaultMessage": "!!!Teams are unavailable",
70 "file": "src/components/settings/team/TeamDashboard.js",
71 "start": {
72 "line": 35,
73 "column": 20
74 },
75 "end": {
76 "line": 38,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.team.teamsUnavailableInfo",
82 "defaultMessage": "!!!Teams are currently only available when using the Franz Server and after paying for Franz Professional. Please change your server to https://api.franzinfra.com to use teams.",
83 "file": "src/components/settings/team/TeamDashboard.js",
84 "start": {
85 "line": 39,
86 "column": 24
87 },
88 "end": {
89 "line": 42,
90 "column": 3
91 }
92 }
93] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/settings/user/EditUserForm.json b/src/i18n/messages/src/components/settings/user/EditUserForm.json
deleted file mode 100644
index 3a59f8681..000000000
--- a/src/i18n/messages/src/components/settings/user/EditUserForm.json
+++ /dev/null
@@ -1,80 +0,0 @@
1[
2 {
3 "id": "settings.account.headline",
4 "defaultMessage": "!!!Account",
5 "file": "src/components/settings/user/EditUserForm.js",
6 "start": {
7 "line": 15,
8 "column": 12
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.account.headlineProfile",
17 "defaultMessage": "!!!Update Profile",
18 "file": "src/components/settings/user/EditUserForm.js",
19 "start": {
20 "line": 19,
21 "column": 19
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.account.headlineAccount",
30 "defaultMessage": "!!!Account Information",
31 "file": "src/components/settings/user/EditUserForm.js",
32 "start": {
33 "line": 23,
34 "column": 19
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.account.headlinePassword",
43 "defaultMessage": "!!!Change Password",
44 "file": "src/components/settings/user/EditUserForm.js",
45 "start": {
46 "line": 27,
47 "column": 20
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.account.successInfo",
56 "defaultMessage": "!!!Your changes have been saved",
57 "file": "src/components/settings/user/EditUserForm.js",
58 "start": {
59 "line": 31,
60 "column": 15
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.account.buttonSave",
69 "defaultMessage": "!!!Update profile",
70 "file": "src/components/settings/user/EditUserForm.js",
71 "start": {
72 "line": 35,
73 "column": 14
74 },
75 "end": {
76 "line": 38,
77 "column": 3
78 }
79 }
80] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/FeatureList.json b/src/i18n/messages/src/components/ui/FeatureList.json
deleted file mode 100644
index eb4bc483b..000000000
--- a/src/i18n/messages/src/components/ui/FeatureList.json
+++ /dev/null
@@ -1,145 +0,0 @@
1[
2 {
3 "id": "pricing.features.recipes",
4 "defaultMessage": "!!!Choose from more than 70 Services",
5 "file": "src/components/ui/FeatureList.js",
6 "start": {
7 "line": 8,
8 "column": 20
9 },
10 "end": {
11 "line": 11,
12 "column": 3
13 }
14 },
15 {
16 "id": "pricing.features.accountSync",
17 "defaultMessage": "!!!Account Synchronisation",
18 "file": "src/components/ui/FeatureList.js",
19 "start": {
20 "line": 12,
21 "column": 15
22 },
23 "end": {
24 "line": 15,
25 "column": 3
26 }
27 },
28 {
29 "id": "pricing.features.desktopNotifications",
30 "defaultMessage": "!!!Desktop Notifications",
31 "file": "src/components/ui/FeatureList.js",
32 "start": {
33 "line": 16,
34 "column": 24
35 },
36 "end": {
37 "line": 19,
38 "column": 3
39 }
40 },
41 {
42 "id": "pricing.features.unlimitedServices",
43 "defaultMessage": "!!!Add unlimited services",
44 "file": "src/components/ui/FeatureList.js",
45 "start": {
46 "line": 20,
47 "column": 21
48 },
49 "end": {
50 "line": 23,
51 "column": 3
52 }
53 },
54 {
55 "id": "pricing.features.spellchecker",
56 "defaultMessage": "!!!Spellchecker support",
57 "file": "src/components/ui/FeatureList.js",
58 "start": {
59 "line": 24,
60 "column": 16
61 },
62 "end": {
63 "line": 27,
64 "column": 3
65 }
66 },
67 {
68 "id": "pricing.features.workspaces",
69 "defaultMessage": "!!!Workspaces",
70 "file": "src/components/ui/FeatureList.js",
71 "start": {
72 "line": 28,
73 "column": 14
74 },
75 "end": {
76 "line": 31,
77 "column": 3
78 }
79 },
80 {
81 "id": "pricing.features.customWebsites",
82 "defaultMessage": "!!!Add Custom Websites",
83 "file": "src/components/ui/FeatureList.js",
84 "start": {
85 "line": 32,
86 "column": 18
87 },
88 "end": {
89 "line": 35,
90 "column": 3
91 }
92 },
93 {
94 "id": "pricing.features.onPremise",
95 "defaultMessage": "!!!On-premise & other Hosted Services",
96 "file": "src/components/ui/FeatureList.js",
97 "start": {
98 "line": 36,
99 "column": 13
100 },
101 "end": {
102 "line": 39,
103 "column": 3
104 }
105 },
106 {
107 "id": "pricing.features.thirdPartyServices",
108 "defaultMessage": "!!!Install 3rd party services",
109 "file": "src/components/ui/FeatureList.js",
110 "start": {
111 "line": 40,
112 "column": 22
113 },
114 "end": {
115 "line": 43,
116 "column": 3
117 }
118 },
119 {
120 "id": "pricing.features.serviceProxies",
121 "defaultMessage": "!!!Service Proxies",
122 "file": "src/components/ui/FeatureList.js",
123 "start": {
124 "line": 44,
125 "column": 18
126 },
127 "end": {
128 "line": 47,
129 "column": 3
130 }
131 },
132 {
133 "id": "pricing.features.teamManagement",
134 "defaultMessage": "!!!Team Management",
135 "file": "src/components/ui/FeatureList.js",
136 "start": {
137 "line": 48,
138 "column": 18
139 },
140 "end": {
141 "line": 51,
142 "column": 3
143 }
144 }
145] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/InfoBar.json b/src/i18n/messages/src/components/ui/InfoBar.json
deleted file mode 100644
index a6a629c71..000000000
--- a/src/i18n/messages/src/components/ui/InfoBar.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "infobar.hide",
4 "defaultMessage": "!!!Hide",
5 "file": "src/components/ui/InfoBar.js",
6 "start": {
7 "line": 12,
8 "column": 8
9 },
10 "end": {
11 "line": 15,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/Infobox.json b/src/i18n/messages/src/components/ui/Infobox.json
deleted file mode 100644
index 296c2ad3e..000000000
--- a/src/i18n/messages/src/components/ui/Infobox.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "infobox.dismiss",
4 "defaultMessage": "!!!Dismiss",
5 "file": "src/components/ui/Infobox.js",
6 "start": {
7 "line": 9,
8 "column": 11
9 },
10 "end": {
11 "line": 12,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/Input.json b/src/i18n/messages/src/components/ui/Input.json
deleted file mode 100644
index 6240badfb..000000000
--- a/src/i18n/messages/src/components/ui/Input.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "settings.app.form.passwordToggle",
4 "defaultMessage": "!!!Password toggle",
5 "file": "src/components/ui/Input.js",
6 "start": {
7 "line": 11,
8 "column": 18
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/WebviewLoader/index.json b/src/i18n/messages/src/components/ui/WebviewLoader/index.json
deleted file mode 100644
index 9caabef25..000000000
--- a/src/i18n/messages/src/components/ui/WebviewLoader/index.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "service.webviewLoader.loading",
4 "defaultMessage": "!!!Loading {service}",
5 "file": "src/components/ui/WebviewLoader/index.js",
6 "start": {
7 "line": 11,
8 "column": 11
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/util/ErrorBoundary/index.json b/src/i18n/messages/src/components/util/ErrorBoundary/index.json
deleted file mode 100644
index 43c323031..000000000
--- a/src/i18n/messages/src/components/util/ErrorBoundary/index.json
+++ /dev/null
@@ -1,28 +0,0 @@
1[
2 {
3 "id": "app.errorHandler.headline",
4 "defaultMessage": "!!!Something went wrong.",
5 "file": "src/components/util/ErrorBoundary/index.js",
6 "start": {
7 "line": 11,
8 "column": 12
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 },
15 {
16 "id": "app.errorHandler.action",
17 "defaultMessage": "!!!Reload",
18 "file": "src/components/util/ErrorBoundary/index.js",
19 "start": {
20 "line": 15,
21 "column": 10
22 },
23 "end": {
24 "line": 18,
25 "column": 3
26 }
27 }
28] \ No newline at end of file
diff --git a/src/i18n/messages/src/containers/settings/EditServiceScreen.json b/src/i18n/messages/src/containers/settings/EditServiceScreen.json
deleted file mode 100644
index 6744a9ff3..000000000
--- a/src/i18n/messages/src/containers/settings/EditServiceScreen.json
+++ /dev/null
@@ -1,249 +0,0 @@
1[
2 {
3 "id": "settings.service.form.name",
4 "defaultMessage": "!!!Name",
5 "file": "src/containers/settings/EditServiceScreen.js",
6 "start": {
7 "line": 28,
8 "column": 8
9 },
10 "end": {
11 "line": 31,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.service.form.enableService",
17 "defaultMessage": "!!!Enable service",
18 "file": "src/containers/settings/EditServiceScreen.js",
19 "start": {
20 "line": 32,
21 "column": 17
22 },
23 "end": {
24 "line": 35,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.service.form.enableHibernation",
30 "defaultMessage": "!!!Enable hibernation",
31 "file": "src/containers/settings/EditServiceScreen.js",
32 "start": {
33 "line": 36,
34 "column": 21
35 },
36 "end": {
37 "line": 39,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.service.form.enableNotification",
43 "defaultMessage": "!!!Enable Notifications",
44 "file": "src/containers/settings/EditServiceScreen.js",
45 "start": {
46 "line": 40,
47 "column": 22
48 },
49 "end": {
50 "line": 43,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.service.form.enableBadge",
56 "defaultMessage": "!!!Show unread message badges",
57 "file": "src/containers/settings/EditServiceScreen.js",
58 "start": {
59 "line": 44,
60 "column": 15
61 },
62 "end": {
63 "line": 47,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.service.form.enableAudio",
69 "defaultMessage": "!!!Enable audio",
70 "file": "src/containers/settings/EditServiceScreen.js",
71 "start": {
72 "line": 48,
73 "column": 15
74 },
75 "end": {
76 "line": 51,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.service.form.team",
82 "defaultMessage": "!!!Team",
83 "file": "src/containers/settings/EditServiceScreen.js",
84 "start": {
85 "line": 52,
86 "column": 8
87 },
88 "end": {
89 "line": 55,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.service.form.customUrl",
95 "defaultMessage": "!!!Service URL",
96 "file": "src/containers/settings/EditServiceScreen.js",
97 "start": {
98 "line": 56,
99 "column": 13
100 },
101 "end": {
102 "line": 59,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.service.form.indirectMessages",
108 "defaultMessage": "!!!Show message badge for all new messages",
109 "file": "src/containers/settings/EditServiceScreen.js",
110 "start": {
111 "line": 60,
112 "column": 20
113 },
114 "end": {
115 "line": 63,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.service.form.icon",
121 "defaultMessage": "!!!Custom icon",
122 "file": "src/containers/settings/EditServiceScreen.js",
123 "start": {
124 "line": 64,
125 "column": 8
126 },
127 "end": {
128 "line": 67,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.service.form.enableDarkMode",
134 "defaultMessage": "!!!Enable Dark Mode",
135 "file": "src/containers/settings/EditServiceScreen.js",
136 "start": {
137 "line": 68,
138 "column": 18
139 },
140 "end": {
141 "line": 71,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.service.form.darkReaderBrightness",
147 "defaultMessage": "!!!Dark Reader Brightness",
148 "file": "src/containers/settings/EditServiceScreen.js",
149 "start": {
150 "line": 72,
151 "column": 24
152 },
153 "end": {
154 "line": 75,
155 "column": 3
156 }
157 },
158 {
159 "id": "settings.service.form.darkReaderContrast",
160 "defaultMessage": "!!!Dark Reader Contrast",
161 "file": "src/containers/settings/EditServiceScreen.js",
162 "start": {
163 "line": 76,
164 "column": 22
165 },
166 "end": {
167 "line": 79,
168 "column": 3
169 }
170 },
171 {
172 "id": "settings.service.form.darkReaderSepia",
173 "defaultMessage": "!!!Dark Reader Sepia",
174 "file": "src/containers/settings/EditServiceScreen.js",
175 "start": {
176 "line": 80,
177 "column": 19
178 },
179 "end": {
180 "line": 83,
181 "column": 3
182 }
183 },
184 {
185 "id": "settings.service.form.proxy.isEnabled",
186 "defaultMessage": "!!!Use Proxy",
187 "file": "src/containers/settings/EditServiceScreen.js",
188 "start": {
189 "line": 84,
190 "column": 15
191 },
192 "end": {
193 "line": 87,
194 "column": 3
195 }
196 },
197 {
198 "id": "settings.service.form.proxy.host",
199 "defaultMessage": "!!!Proxy Host/IP",
200 "file": "src/containers/settings/EditServiceScreen.js",
201 "start": {
202 "line": 88,
203 "column": 13
204 },
205 "end": {
206 "line": 91,
207 "column": 3
208 }
209 },
210 {
211 "id": "settings.service.form.proxy.port",
212 "defaultMessage": "!!!Port",
213 "file": "src/containers/settings/EditServiceScreen.js",
214 "start": {
215 "line": 92,
216 "column": 13
217 },
218 "end": {
219 "line": 95,
220 "column": 3
221 }
222 },
223 {
224 "id": "settings.service.form.proxy.user",
225 "defaultMessage": "!!!User",
226 "file": "src/containers/settings/EditServiceScreen.js",
227 "start": {
228 "line": 96,
229 "column": 13
230 },
231 "end": {
232 "line": 99,
233 "column": 3
234 }
235 },
236 {
237 "id": "settings.service.form.proxy.password",
238 "defaultMessage": "!!!Password",
239 "file": "src/containers/settings/EditServiceScreen.js",
240 "start": {
241 "line": 100,
242 "column": 17
243 },
244 "end": {
245 "line": 103,
246 "column": 3
247 }
248 }
249] \ No newline at end of file
diff --git a/src/i18n/messages/src/containers/settings/EditSettingsScreen.json b/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
deleted file mode 100644
index b0087e5dd..000000000
--- a/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
+++ /dev/null
@@ -1,600 +0,0 @@
1[
2 {
3 "id": "settings.app.form.autoLaunchOnStart",
4 "defaultMessage": "!!!Launch Ferdi on start",
5 "file": "src/containers/settings/EditSettingsScreen.js",
6 "start": {
7 "line": 32,
8 "column": 21
9 },
10 "end": {
11 "line": 35,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.app.form.autoLaunchInBackground",
17 "defaultMessage": "!!!Open in background",
18 "file": "src/containers/settings/EditSettingsScreen.js",
19 "start": {
20 "line": 36,
21 "column": 26
22 },
23 "end": {
24 "line": 39,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.app.form.runInBackground",
30 "defaultMessage": "!!!Keep Ferdi in background when closing the window",
31 "file": "src/containers/settings/EditSettingsScreen.js",
32 "start": {
33 "line": 40,
34 "column": 19
35 },
36 "end": {
37 "line": 43,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.app.form.startMinimized",
43 "defaultMessage": "!!!Start minimized",
44 "file": "src/containers/settings/EditSettingsScreen.js",
45 "start": {
46 "line": 44,
47 "column": 18
48 },
49 "end": {
50 "line": 47,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.app.form.confirmOnQuit",
56 "defaultMessage": "!!!Confirm when quitting Ferdi",
57 "file": "src/containers/settings/EditSettingsScreen.js",
58 "start": {
59 "line": 48,
60 "column": 17
61 },
62 "end": {
63 "line": 51,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.app.form.enableSystemTray",
69 "defaultMessage": "!!!Always show Ferdi in System Tray",
70 "file": "src/containers/settings/EditSettingsScreen.js",
71 "start": {
72 "line": 52,
73 "column": 20
74 },
75 "end": {
76 "line": 55,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.app.form.enableMenuBar",
82 "defaultMessage": "!!!Always show Ferdi in Menu Bar",
83 "file": "src/containers/settings/EditSettingsScreen.js",
84 "start": {
85 "line": 56,
86 "column": 17
87 },
88 "end": {
89 "line": 59,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.app.form.reloadAfterResume",
95 "defaultMessage": "!!!Reload Ferdi after system resume",
96 "file": "src/containers/settings/EditSettingsScreen.js",
97 "start": {
98 "line": 60,
99 "column": 21
100 },
101 "end": {
102 "line": 63,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.app.form.minimizeToSystemTray",
108 "defaultMessage": "!!!Minimize Ferdi to system tray",
109 "file": "src/containers/settings/EditSettingsScreen.js",
110 "start": {
111 "line": 64,
112 "column": 24
113 },
114 "end": {
115 "line": 67,
116 "column": 3
117 }
118 },
119 {
120 "id": "settings.app.form.closeToSystemTray",
121 "defaultMessage": "!!!Close Ferdi to system tray",
122 "file": "src/containers/settings/EditSettingsScreen.js",
123 "start": {
124 "line": 68,
125 "column": 21
126 },
127 "end": {
128 "line": 71,
129 "column": 3
130 }
131 },
132 {
133 "id": "settings.app.form.privateNotifications",
134 "defaultMessage": "!!!Don't show message content in notifications",
135 "file": "src/containers/settings/EditSettingsScreen.js",
136 "start": {
137 "line": 72,
138 "column": 24
139 },
140 "end": {
141 "line": 75,
142 "column": 3
143 }
144 },
145 {
146 "id": "settings.app.form.clipboardNotifications",
147 "defaultMessage": "!!!Don't show notifications for clipboard events",
148 "file": "src/containers/settings/EditSettingsScreen.js",
149 "start": {
150 "line": 76,
151 "column": 26
152 },
153 "end": {
154 "line": 79,
155 "column": 3
156 }
157 },
158 {
159 "id": "settings.app.form.notifyTaskBarOnMessage",
160 "defaultMessage": "!!!Notify TaskBar/Dock on new message",
161 "file": "src/containers/settings/EditSettingsScreen.js",
162 "start": {
163 "line": 80,
164 "column": 26
165 },
166 "end": {
167 "line": 83,
168 "column": 3
169 }
170 },
171 {
172 "id": "settings.app.form.navigationBarBehaviour",
173 "defaultMessage": "!!!Navigation bar behaviour",
174 "file": "src/containers/settings/EditSettingsScreen.js",
175 "start": {
176 "line": 84,
177 "column": 26
178 },
179 "end": {
180 "line": 87,
181 "column": 3
182 }
183 },
184 {
185 "id": "settings.app.form.searchEngine",
186 "defaultMessage": "!!!Search engine",
187 "file": "src/containers/settings/EditSettingsScreen.js",
188 "start": {
189 "line": 88,
190 "column": 16
191 },
192 "end": {
193 "line": 91,
194 "column": 3
195 }
196 },
197 {
198 "id": "settings.app.form.sentry",
199 "defaultMessage": "!!!Send telemetry data",
200 "file": "src/containers/settings/EditSettingsScreen.js",
201 "start": {
202 "line": 92,
203 "column": 10
204 },
205 "end": {
206 "line": 95,
207 "column": 3
208 }
209 },
210 {
211 "id": "settings.app.form.hibernateOnStartup",
212 "defaultMessage": "!!!Keep services in hibernation on startup",
213 "file": "src/containers/settings/EditSettingsScreen.js",
214 "start": {
215 "line": 96,
216 "column": 22
217 },
218 "end": {
219 "line": 99,
220 "column": 3
221 }
222 },
223 {
224 "id": "settings.app.form.hibernationStrategy",
225 "defaultMessage": "!!!Hibernation strategy",
226 "file": "src/containers/settings/EditSettingsScreen.js",
227 "start": {
228 "line": 100,
229 "column": 23
230 },
231 "end": {
232 "line": 103,
233 "column": 3
234 }
235 },
236 {
237 "id": "settings.app.form.wakeUpStrategy",
238 "defaultMessage": "!!!Wake up strategy",
239 "file": "src/containers/settings/EditSettingsScreen.js",
240 "start": {
241 "line": 104,
242 "column": 18
243 },
244 "end": {
245 "line": 107,
246 "column": 3
247 }
248 },
249 {
250 "id": "settings.app.form.predefinedTodoServer",
251 "defaultMessage": "!!!Todo Server",
252 "file": "src/containers/settings/EditSettingsScreen.js",
253 "start": {
254 "line": 108,
255 "column": 24
256 },
257 "end": {
258 "line": 111,
259 "column": 3
260 }
261 },
262 {
263 "id": "settings.app.form.customTodoServer",
264 "defaultMessage": "!!!Custom TodoServer",
265 "file": "src/containers/settings/EditSettingsScreen.js",
266 "start": {
267 "line": 112,
268 "column": 20
269 },
270 "end": {
271 "line": 115,
272 "column": 3
273 }
274 },
275 {
276 "id": "settings.app.form.enableLock",
277 "defaultMessage": "!!!Enable Password Lock",
278 "file": "src/containers/settings/EditSettingsScreen.js",
279 "start": {
280 "line": 116,
281 "column": 14
282 },
283 "end": {
284 "line": 119,
285 "column": 3
286 }
287 },
288 {
289 "id": "settings.app.form.lockPassword",
290 "defaultMessage": "!!!Password",
291 "file": "src/containers/settings/EditSettingsScreen.js",
292 "start": {
293 "line": 120,
294 "column": 16
295 },
296 "end": {
297 "line": 123,
298 "column": 3
299 }
300 },
301 {
302 "id": "settings.app.form.useTouchIdToUnlock",
303 "defaultMessage": "!!!Allow using Touch ID to unlock",
304 "file": "src/containers/settings/EditSettingsScreen.js",
305 "start": {
306 "line": 124,
307 "column": 22
308 },
309 "end": {
310 "line": 127,
311 "column": 3
312 }
313 },
314 {
315 "id": "settings.app.form.inactivityLock",
316 "defaultMessage": "!!!Lock after inactivity",
317 "file": "src/containers/settings/EditSettingsScreen.js",
318 "start": {
319 "line": 128,
320 "column": 18
321 },
322 "end": {
323 "line": 131,
324 "column": 3
325 }
326 },
327 {
328 "id": "settings.app.form.scheduledDNDEnabled",
329 "defaultMessage": "!!!Enable scheduled Do-not-Disturb",
330 "file": "src/containers/settings/EditSettingsScreen.js",
331 "start": {
332 "line": 132,
333 "column": 23
334 },
335 "end": {
336 "line": 135,
337 "column": 3
338 }
339 },
340 {
341 "id": "settings.app.form.scheduledDNDStart",
342 "defaultMessage": "!!!From",
343 "file": "src/containers/settings/EditSettingsScreen.js",
344 "start": {
345 "line": 136,
346 "column": 21
347 },
348 "end": {
349 "line": 139,
350 "column": 3
351 }
352 },
353 {
354 "id": "settings.app.form.scheduledDNDEnd",
355 "defaultMessage": "!!!To",
356 "file": "src/containers/settings/EditSettingsScreen.js",
357 "start": {
358 "line": 140,
359 "column": 19
360 },
361 "end": {
362 "line": 143,
363 "column": 3
364 }
365 },
366 {
367 "id": "settings.app.form.language",
368 "defaultMessage": "!!!Language",
369 "file": "src/containers/settings/EditSettingsScreen.js",
370 "start": {
371 "line": 144,
372 "column": 12
373 },
374 "end": {
375 "line": 147,
376 "column": 3
377 }
378 },
379 {
380 "id": "settings.app.form.darkMode",
381 "defaultMessage": "!!!Dark Mode",
382 "file": "src/containers/settings/EditSettingsScreen.js",
383 "start": {
384 "line": 148,
385 "column": 12
386 },
387 "end": {
388 "line": 151,
389 "column": 3
390 }
391 },
392 {
393 "id": "settings.app.form.adaptableDarkMode",
394 "defaultMessage": "!!!Synchronize dark mode with my OS's dark mode setting",
395 "file": "src/containers/settings/EditSettingsScreen.js",
396 "start": {
397 "line": 152,
398 "column": 21
399 },
400 "end": {
401 "line": 155,
402 "column": 3
403 }
404 },
405 {
406 "id": "settings.app.form.universalDarkMode",
407 "defaultMessage": "!!!Enable universal Dark Mode",
408 "file": "src/containers/settings/EditSettingsScreen.js",
409 "start": {
410 "line": 156,
411 "column": 21
412 },
413 "end": {
414 "line": 159,
415 "column": 3
416 }
417 },
418 {
419 "id": "settings.app.form.serviceRibbonWidth",
420 "defaultMessage": "!!!Sidebar width",
421 "file": "src/containers/settings/EditSettingsScreen.js",
422 "start": {
423 "line": 160,
424 "column": 22
425 },
426 "end": {
427 "line": 163,
428 "column": 3
429 }
430 },
431 {
432 "id": "settings.app.form.iconSize",
433 "defaultMessage": "!!!Service icon size",
434 "file": "src/containers/settings/EditSettingsScreen.js",
435 "start": {
436 "line": 164,
437 "column": 12
438 },
439 "end": {
440 "line": 167,
441 "column": 3
442 }
443 },
444 {
445 "id": "settings.app.form.useVerticalStyle",
446 "defaultMessage": "!!!Use horizontal style",
447 "file": "src/containers/settings/EditSettingsScreen.js",
448 "start": {
449 "line": 168,
450 "column": 20
451 },
452 "end": {
453 "line": 171,
454 "column": 3
455 }
456 },
457 {
458 "id": "settings.app.form.alwaysShowWorkspaces",
459 "defaultMessage": "!!!Always show workspace drawer",
460 "file": "src/containers/settings/EditSettingsScreen.js",
461 "start": {
462 "line": 172,
463 "column": 24
464 },
465 "end": {
466 "line": 175,
467 "column": 3
468 }
469 },
470 {
471 "id": "settings.app.form.accentColor",
472 "defaultMessage": "!!!Accent color",
473 "file": "src/containers/settings/EditSettingsScreen.js",
474 "start": {
475 "line": 176,
476 "column": 15
477 },
478 "end": {
479 "line": 179,
480 "column": 3
481 }
482 },
483 {
484 "id": "settings.app.form.showDisabledServices",
485 "defaultMessage": "!!!Display disabled services tabs",
486 "file": "src/containers/settings/EditSettingsScreen.js",
487 "start": {
488 "line": 180,
489 "column": 24
490 },
491 "end": {
492 "line": 183,
493 "column": 3
494 }
495 },
496 {
497 "id": "settings.app.form.showMessagesBadgesWhenMuted",
498 "defaultMessage": "!!!Show unread message badge when notifications are disabled",
499 "file": "src/containers/settings/EditSettingsScreen.js",
500 "start": {
501 "line": 184,
502 "column": 29
503 },
504 "end": {
505 "line": 187,
506 "column": 3
507 }
508 },
509 {
510 "id": "settings.app.form.showDragArea",
511 "defaultMessage": "!!!Show draggable area on window",
512 "file": "src/containers/settings/EditSettingsScreen.js",
513 "start": {
514 "line": 188,
515 "column": 16
516 },
517 "end": {
518 "line": 191,
519 "column": 3
520 }
521 },
522 {
523 "id": "settings.app.form.enableSpellchecking",
524 "defaultMessage": "!!!Enable spell checking",
525 "file": "src/containers/settings/EditSettingsScreen.js",
526 "start": {
527 "line": 192,
528 "column": 23
529 },
530 "end": {
531 "line": 195,
532 "column": 3
533 }
534 },
535 {
536 "id": "settings.app.form.enableGPUAcceleration",
537 "defaultMessage": "!!!Enable GPU Acceleration",
538 "file": "src/containers/settings/EditSettingsScreen.js",
539 "start": {
540 "line": 196,
541 "column": 25
542 },
543 "end": {
544 "line": 199,
545 "column": 3
546 }
547 },
548 {
549 "id": "settings.app.form.beta",
550 "defaultMessage": "!!!Include beta versions",
551 "file": "src/containers/settings/EditSettingsScreen.js",
552 "start": {
553 "line": 200,
554 "column": 8
555 },
556 "end": {
557 "line": 203,
558 "column": 3
559 }
560 },
561 {
562 "id": "settings.app.form.automaticUpdates",
563 "defaultMessage": "!!!Enable updates",
564 "file": "src/containers/settings/EditSettingsScreen.js",
565 "start": {
566 "line": 204,
567 "column": 20
568 },
569 "end": {
570 "line": 207,
571 "column": 3
572 }
573 },
574 {
575 "id": "settings.app.form.enableTodos",
576 "defaultMessage": "!!!Enable Franz Todos",
577 "file": "src/containers/settings/EditSettingsScreen.js",
578 "start": {
579 "line": 208,
580 "column": 15
581 },
582 "end": {
583 "line": 211,
584 "column": 3
585 }
586 },
587 {
588 "id": "settings.app.form.keepAllWorkspacesLoaded",
589 "defaultMessage": "!!!Keep all workspaces loaded",
590 "file": "src/containers/settings/EditSettingsScreen.js",
591 "start": {
592 "line": 212,
593 "column": 27
594 },
595 "end": {
596 "line": 215,
597 "column": 3
598 }
599 }
600] \ No newline at end of file
diff --git a/src/i18n/messages/src/containers/settings/EditUserScreen.json b/src/i18n/messages/src/containers/settings/EditUserScreen.json
deleted file mode 100644
index 70ff29945..000000000
--- a/src/i18n/messages/src/containers/settings/EditUserScreen.json
+++ /dev/null
@@ -1,119 +0,0 @@
1[
2 {
3 "id": "settings.user.form.firstname",
4 "defaultMessage": "!!!Firstname",
5 "file": "src/containers/settings/EditUserScreen.js",
6 "start": {
7 "line": 14,
8 "column": 13
9 },
10 "end": {
11 "line": 17,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.user.form.lastname",
17 "defaultMessage": "!!!Lastname",
18 "file": "src/containers/settings/EditUserScreen.js",
19 "start": {
20 "line": 18,
21 "column": 12
22 },
23 "end": {
24 "line": 21,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.user.form.email",
30 "defaultMessage": "!!!Email",
31 "file": "src/containers/settings/EditUserScreen.js",
32 "start": {
33 "line": 22,
34 "column": 9
35 },
36 "end": {
37 "line": 25,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.user.form.accountType.label",
43 "defaultMessage": "!!!Account type",
44 "file": "src/containers/settings/EditUserScreen.js",
45 "start": {
46 "line": 26,
47 "column": 20
48 },
49 "end": {
50 "line": 29,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.user.form.accountType.individual",
56 "defaultMessage": "!!!Individual",
57 "file": "src/containers/settings/EditUserScreen.js",
58 "start": {
59 "line": 30,
60 "column": 25
61 },
62 "end": {
63 "line": 33,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.user.form.accountType.non-profit",
69 "defaultMessage": "!!!Non-Profit",
70 "file": "src/containers/settings/EditUserScreen.js",
71 "start": {
72 "line": 34,
73 "column": 24
74 },
75 "end": {
76 "line": 37,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.user.form.accountType.company",
82 "defaultMessage": "!!!Company",
83 "file": "src/containers/settings/EditUserScreen.js",
84 "start": {
85 "line": 38,
86 "column": 22
87 },
88 "end": {
89 "line": 41,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.user.form.currentPassword",
95 "defaultMessage": "!!!Current password",
96 "file": "src/containers/settings/EditUserScreen.js",
97 "start": {
98 "line": 42,
99 "column": 19
100 },
101 "end": {
102 "line": 45,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.user.form.newPassword",
108 "defaultMessage": "!!!New password",
109 "file": "src/containers/settings/EditUserScreen.js",
110 "start": {
111 "line": 46,
112 "column": 15
113 },
114 "end": {
115 "line": 49,
116 "column": 3
117 }
118 }
119] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/basicAuth/Component.json b/src/i18n/messages/src/features/basicAuth/Component.json
deleted file mode 100644
index fea1b0838..000000000
--- a/src/i18n/messages/src/features/basicAuth/Component.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "feature.basicAuth.signIn",
4 "defaultMessage": "!!!Sign In",
5 "file": "src/features/basicAuth/Component.js",
6 "start": {
7 "line": 24,
8 "column": 10
9 },
10 "end": {
11 "line": 27,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/debugger/Component.json b/src/i18n/messages/src/features/debugger/Component.json
deleted file mode 100644
index 86a5a05f4..000000000
--- a/src/i18n/messages/src/features/debugger/Component.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "feature.debugger.title",
4 "defaultMessage": "!!!Publish debugging information",
5 "file": "src/features/debugger/Component.js",
6 "start": {
7 "line": 16,
8 "column": 9
9 },
10 "end": {
11 "line": 19,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/nightlyBuilds/Component.json b/src/i18n/messages/src/features/nightlyBuilds/Component.json
deleted file mode 100644
index 0b2eab354..000000000
--- a/src/i18n/messages/src/features/nightlyBuilds/Component.json
+++ /dev/null
@@ -1,41 +0,0 @@
1[
2 {
3 "id": "feature.nightlyBuilds.title",
4 "defaultMessage": "!!!Nightly Builds",
5 "file": "src/features/nightlyBuilds/Component.js",
6 "start": {
7 "line": 17,
8 "column": 9
9 },
10 "end": {
11 "line": 20,
12 "column": 3
13 }
14 },
15 {
16 "id": "feature.nightlyBuilds.info",
17 "defaultMessage": "!!!Nightly builds are highly experimental versions of Ferdi that may contain unpolished or uncompleted features. These nightly builds are mainly used by developers to test their newly developed features and how they will perform in the final build. If you don't know what you are doing, we suggest not activating nightly builds.",
18 "file": "src/features/nightlyBuilds/Component.js",
19 "start": {
20 "line": 21,
21 "column": 8
22 },
23 "end": {
24 "line": 24,
25 "column": 3
26 }
27 },
28 {
29 "id": "feature.nightlyBuilds.activate",
30 "defaultMessage": "!!!Activate",
31 "file": "src/features/nightlyBuilds/Component.js",
32 "start": {
33 "line": 25,
34 "column": 12
35 },
36 "end": {
37 "line": 28,
38 "column": 3
39 }
40 }
41] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/publishDebugInfo/Component.json b/src/i18n/messages/src/features/publishDebugInfo/Component.json
deleted file mode 100644
index 4d07a4794..000000000
--- a/src/i18n/messages/src/features/publishDebugInfo/Component.json
+++ /dev/null
@@ -1,93 +0,0 @@
1[
2 {
3 "id": "feature.publishDebugInfo.title",
4 "defaultMessage": "!!!Publish debug information",
5 "file": "src/features/publishDebugInfo/Component.js",
6 "start": {
7 "line": 19,
8 "column": 9
9 },
10 "end": {
11 "line": 22,
12 "column": 3
13 }
14 },
15 {
16 "id": "feature.publishDebugInfo.info",
17 "defaultMessage": "!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service",
18 "file": "src/features/publishDebugInfo/Component.js",
19 "start": {
20 "line": 23,
21 "column": 8
22 },
23 "end": {
24 "line": 26,
25 "column": 3
26 }
27 },
28 {
29 "id": "feature.publishDebugInfo.error",
30 "defaultMessage": "!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.",
31 "file": "src/features/publishDebugInfo/Component.js",
32 "start": {
33 "line": 27,
34 "column": 9
35 },
36 "end": {
37 "line": 30,
38 "column": 3
39 }
40 },
41 {
42 "id": "feature.publishDebugInfo.privacy",
43 "defaultMessage": "!!!Privacy policy",
44 "file": "src/features/publishDebugInfo/Component.js",
45 "start": {
46 "line": 31,
47 "column": 11
48 },
49 "end": {
50 "line": 34,
51 "column": 3
52 }
53 },
54 {
55 "id": "feature.publishDebugInfo.terms",
56 "defaultMessage": "!!!Terms of service",
57 "file": "src/features/publishDebugInfo/Component.js",
58 "start": {
59 "line": 35,
60 "column": 9
61 },
62 "end": {
63 "line": 38,
64 "column": 3
65 }
66 },
67 {
68 "id": "feature.publishDebugInfo.publish",
69 "defaultMessage": "!!!Accept and publish",
70 "file": "src/features/publishDebugInfo/Component.js",
71 "start": {
72 "line": 39,
73 "column": 11
74 },
75 "end": {
76 "line": 42,
77 "column": 3
78 }
79 },
80 {
81 "id": "feature.publishDebugInfo.published",
82 "defaultMessage": "!!!Your debug log was published and is now availible at",
83 "file": "src/features/publishDebugInfo/Component.js",
84 "start": {
85 "line": 43,
86 "column": 13
87 },
88 "end": {
89 "line": 46,
90 "column": 3
91 }
92 }
93] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/quickSwitch/Component.json b/src/i18n/messages/src/features/quickSwitch/Component.json
deleted file mode 100644
index e112bedc1..000000000
--- a/src/i18n/messages/src/features/quickSwitch/Component.json
+++ /dev/null
@@ -1,41 +0,0 @@
1[
2 {
3 "id": "feature.quickSwitch.title",
4 "defaultMessage": "!!!QuickSwitch",
5 "file": "src/features/quickSwitch/Component.js",
6 "start": {
7 "line": 17,
8 "column": 9
9 },
10 "end": {
11 "line": 20,
12 "column": 3
13 }
14 },
15 {
16 "id": "feature.quickSwitch.search",
17 "defaultMessage": "!!!Search...",
18 "file": "src/features/quickSwitch/Component.js",
19 "start": {
20 "line": 21,
21 "column": 10
22 },
23 "end": {
24 "line": 24,
25 "column": 3
26 }
27 },
28 {
29 "id": "feature.quickSwitch.info",
30 "defaultMessage": "!!!Select a service with TAB, ↑ and ↓. Open a service with ENTER.",
31 "file": "src/features/quickSwitch/Component.js",
32 "start": {
33 "line": 25,
34 "column": 8
35 },
36 "end": {
37 "line": 28,
38 "column": 3
39 }
40 }
41] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/recipeConnectionLost/components/WebControls.json b/src/i18n/messages/src/features/recipeConnectionLost/components/WebControls.json
deleted file mode 100644
index f3bcaf345..000000000
--- a/src/i18n/messages/src/features/recipeConnectionLost/components/WebControls.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "webControls.goHome",
4 "defaultMessage": "!!!Home",
5 "file": "src/features/recipeConnectionLost/components/WebControls.js",
6 "start": {
7 "line": 13,
8 "column": 10
9 },
10 "end": {
11 "line": 16,
12 "column": 3
13 }
14 },
15 {
16 "id": "webControls.openInBrowser",
17 "defaultMessage": "!!!Open in Browser",
18 "file": "src/features/recipeConnectionLost/components/WebControls.js",
19 "start": {
20 "line": 17,
21 "column": 17
22 },
23 "end": {
24 "line": 20,
25 "column": 3
26 }
27 },
28 {
29 "id": "webControls.back",
30 "defaultMessage": "!!!Back",
31 "file": "src/features/recipeConnectionLost/components/WebControls.js",
32 "start": {
33 "line": 21,
34 "column": 8
35 },
36 "end": {
37 "line": 24,
38 "column": 3
39 }
40 },
41 {
42 "id": "webControls.forward",
43 "defaultMessage": "!!!Forward",
44 "file": "src/features/recipeConnectionLost/components/WebControls.js",
45 "start": {
46 "line": 25,
47 "column": 11
48 },
49 "end": {
50 "line": 28,
51 "column": 3
52 }
53 },
54 {
55 "id": "webControls.reload",
56 "defaultMessage": "!!!Reload",
57 "file": "src/features/recipeConnectionLost/components/WebControls.js",
58 "start": {
59 "line": 29,
60 "column": 10
61 },
62 "end": {
63 "line": 32,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/webControls/components/WebControls.json b/src/i18n/messages/src/features/webControls/components/WebControls.json
deleted file mode 100644
index 7676ec0b1..000000000
--- a/src/i18n/messages/src/features/webControls/components/WebControls.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "webControls.goHome",
4 "defaultMessage": "!!!Home",
5 "file": "src/features/webControls/components/WebControls.js",
6 "start": {
7 "line": 17,
8 "column": 10
9 },
10 "end": {
11 "line": 20,
12 "column": 3
13 }
14 },
15 {
16 "id": "webControls.openInBrowser",
17 "defaultMessage": "!!!Open in Browser",
18 "file": "src/features/webControls/components/WebControls.js",
19 "start": {
20 "line": 21,
21 "column": 17
22 },
23 "end": {
24 "line": 24,
25 "column": 3
26 }
27 },
28 {
29 "id": "webControls.back",
30 "defaultMessage": "!!!Back",
31 "file": "src/features/webControls/components/WebControls.js",
32 "start": {
33 "line": 25,
34 "column": 8
35 },
36 "end": {
37 "line": 28,
38 "column": 3
39 }
40 },
41 {
42 "id": "webControls.forward",
43 "defaultMessage": "!!!Forward",
44 "file": "src/features/webControls/components/WebControls.js",
45 "start": {
46 "line": 29,
47 "column": 11
48 },
49 "end": {
50 "line": 32,
51 "column": 3
52 }
53 },
54 {
55 "id": "webControls.reload",
56 "defaultMessage": "!!!Reload",
57 "file": "src/features/webControls/components/WebControls.js",
58 "start": {
59 "line": 33,
60 "column": 10
61 },
62 "end": {
63 "line": 36,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json
deleted file mode 100644
index 1aabfb520..000000000
--- a/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json
+++ /dev/null
@@ -1,28 +0,0 @@
1[
2 {
3 "id": "settings.workspace.add.form.submitButton",
4 "defaultMessage": "!!!Create workspace",
5 "file": "src/features/workspaces/components/CreateWorkspaceForm.js",
6 "start": {
7 "line": 12,
8 "column": 16
9 },
10 "end": {
11 "line": 15,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.workspace.add.form.name",
17 "defaultMessage": "!!!Name",
18 "file": "src/features/workspaces/components/CreateWorkspaceForm.js",
19 "start": {
20 "line": 16,
21 "column": 8
22 },
23 "end": {
24 "line": 19,
25 "column": 3
26 }
27 }
28] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json
deleted file mode 100644
index 804e30070..000000000
--- a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json
+++ /dev/null
@@ -1,119 +0,0 @@
1[
2 {
3 "id": "settings.workspace.form.buttonDelete",
4 "defaultMessage": "!!!Delete workspace",
5 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
6 "start": {
7 "line": 21,
8 "column": 16
9 },
10 "end": {
11 "line": 24,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.workspace.form.buttonSave",
17 "defaultMessage": "!!!Save workspace",
18 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
19 "start": {
20 "line": 25,
21 "column": 14
22 },
23 "end": {
24 "line": 28,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.workspace.form.name",
30 "defaultMessage": "!!!Name",
31 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
32 "start": {
33 "line": 29,
34 "column": 8
35 },
36 "end": {
37 "line": 32,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.workspace.form.yourWorkspaces",
43 "defaultMessage": "!!!Your workspaces",
44 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
45 "start": {
46 "line": 33,
47 "column": 18
48 },
49 "end": {
50 "line": 36,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.workspace.form.keepLoaded",
56 "defaultMessage": "!!!Keep this workspace loaded*",
57 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
58 "start": {
59 "line": 37,
60 "column": 14
61 },
62 "end": {
63 "line": 40,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.workspace.form.keepLoadedInfo",
69 "defaultMessage": "!!!*This option will be overwritten by the global \"Keep all workspaces loaded\" option.",
70 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
71 "start": {
72 "line": 41,
73 "column": 18
74 },
75 "end": {
76 "line": 45,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.workspace.form.servicesInWorkspaceHeadline",
82 "defaultMessage": "!!!Services in this Workspace",
83 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
84 "start": {
85 "line": 46,
86 "column": 31
87 },
88 "end": {
89 "line": 49,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.services.noServicesAdded",
95 "defaultMessage": "!!!Start by adding a service.",
96 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
97 "start": {
98 "line": 50,
99 "column": 19
100 },
101 "end": {
102 "line": 53,
103 "column": 3
104 }
105 },
106 {
107 "id": "settings.services.discoverServices",
108 "defaultMessage": "!!!Discover services",
109 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
110 "start": {
111 "line": 54,
112 "column": 20
113 },
114 "end": {
115 "line": 57,
116 "column": 3
117 }
118 }
119] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json
deleted file mode 100644
index 431f12710..000000000
--- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "workspaceDrawer.headline",
4 "defaultMessage": "!!!Workspaces",
5 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
6 "start": {
7 "line": 15,
8 "column": 12
9 },
10 "end": {
11 "line": 18,
12 "column": 3
13 }
14 },
15 {
16 "id": "workspaceDrawer.allServices",
17 "defaultMessage": "!!!All services",
18 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
19 "start": {
20 "line": 19,
21 "column": 15
22 },
23 "end": {
24 "line": 22,
25 "column": 3
26 }
27 },
28 {
29 "id": "workspaceDrawer.workspacesSettingsTooltip",
30 "defaultMessage": "!!!Workspaces settings",
31 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
32 "start": {
33 "line": 23,
34 "column": 29
35 },
36 "end": {
37 "line": 26,
38 "column": 3
39 }
40 },
41 {
42 "id": "workspaceDrawer.workspaceFeatureInfo",
43 "defaultMessage": "!!!Info about workspace feature",
44 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
45 "start": {
46 "line": 27,
47 "column": 24
48 },
49 "end": {
50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "workspaceDrawer.addNewWorkspaceLabel",
56 "defaultMessage": "!!!add new workspace",
57 "file": "src/features/workspaces/components/WorkspaceDrawer.js",
58 "start": {
59 "line": 31,
60 "column": 24
61 },
62 "end": {
63 "line": 34,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json
deleted file mode 100644
index 737dee59b..000000000
--- a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json
+++ /dev/null
@@ -1,28 +0,0 @@
1[
2 {
3 "id": "workspaceDrawer.item.noServicesAddedYet",
4 "defaultMessage": "!!!No services added yet",
5 "file": "src/features/workspaces/components/WorkspaceDrawerItem.js",
6 "start": {
7 "line": 11,
8 "column": 22
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 },
15 {
16 "id": "workspaceDrawer.item.contextMenuEdit",
17 "defaultMessage": "!!!edit",
18 "file": "src/features/workspaces/components/WorkspaceDrawerItem.js",
19 "start": {
20 "line": 15,
21 "column": 19
22 },
23 "end": {
24 "line": 18,
25 "column": 3
26 }
27 }
28] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json
deleted file mode 100644
index 4f3e6d55c..000000000
--- a/src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json
+++ /dev/null
@@ -1,15 +0,0 @@
1[
2 {
3 "id": "workspaces.switchingIndicator.switchingTo",
4 "defaultMessage": "!!!Switching to",
5 "file": "src/features/workspaces/components/WorkspaceSwitchingIndicator.js",
6 "start": {
7 "line": 12,
8 "column": 15
9 },
10 "end": {
11 "line": 15,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json
deleted file mode 100644
index 39c9c30fb..000000000
--- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json
+++ /dev/null
@@ -1,106 +0,0 @@
1[
2 {
3 "id": "settings.workspaces.headline",
4 "defaultMessage": "!!!Your workspaces",
5 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
6 "start": {
7 "line": 17,
8 "column": 12
9 },
10 "end": {
11 "line": 20,
12 "column": 3
13 }
14 },
15 {
16 "id": "settings.workspaces.noWorkspacesAdded",
17 "defaultMessage": "!!!You haven't created any workspaces yet.",
18 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
19 "start": {
20 "line": 21,
21 "column": 19
22 },
23 "end": {
24 "line": 24,
25 "column": 3
26 }
27 },
28 {
29 "id": "settings.workspaces.workspacesRequestFailed",
30 "defaultMessage": "!!!Could not load your workspaces",
31 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
32 "start": {
33 "line": 25,
34 "column": 27
35 },
36 "end": {
37 "line": 28,
38 "column": 3
39 }
40 },
41 {
42 "id": "settings.workspaces.tryReloadWorkspaces",
43 "defaultMessage": "!!!Try again",
44 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
45 "start": {
46 "line": 29,
47 "column": 23
48 },
49 "end": {
50 "line": 32,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.workspaces.updatedInfo",
56 "defaultMessage": "!!!Your changes have been saved",
57 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
58 "start": {
59 "line": 33,
60 "column": 15
61 },
62 "end": {
63 "line": 36,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.workspaces.deletedInfo",
69 "defaultMessage": "!!!Workspace has been deleted",
70 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
71 "start": {
72 "line": 37,
73 "column": 15
74 },
75 "end": {
76 "line": 40,
77 "column": 3
78 }
79 },
80 {
81 "id": "settings.workspaces.workspaceFeatureInfo",
82 "defaultMessage": "!!!Info about workspace feature",
83 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
84 "start": {
85 "line": 41,
86 "column": 24
87 },
88 "end": {
89 "line": 44,
90 "column": 3
91 }
92 },
93 {
94 "id": "settings.workspaces.workspaceFeatureHeadline",
95 "defaultMessage": "!!!Less is More: Introducing Ferdi Workspaces",
96 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
97 "start": {
98 "line": 45,
99 "column": 28
100 },
101 "end": {
102 "line": 48,
103 "column": 3
104 }
105 }
106] \ No newline at end of file
diff --git a/src/i18n/messages/src/helpers/validation-helpers.json b/src/i18n/messages/src/helpers/validation-helpers.json
deleted file mode 100644
index 6be1d33e9..000000000
--- a/src/i18n/messages/src/helpers/validation-helpers.json
+++ /dev/null
@@ -1,67 +0,0 @@
1[
2 {
3 "id": "validation.required",
4 "defaultMessage": "!!!Field is required",
5 "file": "src/helpers/validation-helpers.js",
6 "start": {
7 "line": 5,
8 "column": 12
9 },
10 "end": {
11 "line": 8,
12 "column": 3
13 }
14 },
15 {
16 "id": "validation.email",
17 "defaultMessage": "!!!Email not valid",
18 "file": "src/helpers/validation-helpers.js",
19 "start": {
20 "line": 9,
21 "column": 9
22 },
23 "end": {
24 "line": 12,
25 "column": 3
26 }
27 },
28 {
29 "id": "validation.url",
30 "defaultMessage": "!!!Not a valid URL",
31 "file": "src/helpers/validation-helpers.js",
32 "start": {
33 "line": 13,
34 "column": 7
35 },
36 "end": {
37 "line": 16,
38 "column": 3
39 }
40 },
41 {
42 "id": "validation.minLength",
43 "defaultMessage": "!!!Too few characters",
44 "file": "src/helpers/validation-helpers.js",
45 "start": {
46 "line": 17,
47 "column": 13
48 },
49 "end": {
50 "line": 20,
51 "column": 3
52 }
53 },
54 {
55 "id": "validation.oneRequired",
56 "defaultMessage": "!!!At least one is required",
57 "file": "src/helpers/validation-helpers.js",
58 "start": {
59 "line": 21,
60 "column": 15
61 },
62 "end": {
63 "line": 24,
64 "column": 3
65 }
66 }
67] \ No newline at end of file
diff --git a/src/i18n/messages/src/i18n/globalMessages.json b/src/i18n/messages/src/i18n/globalMessages.json
deleted file mode 100644
index bc1ec7397..000000000
--- a/src/i18n/messages/src/i18n/globalMessages.json
+++ /dev/null
@@ -1,236 +0,0 @@
1[
2 {
3 "id": "global.api.unhealthy",
4 "defaultMessage": "!!!Can't connect to Ferdi Online Services",
5 "file": "src/i18n/globalMessages.js",
6 "start": {
7 "line": 4,
8 "column": 16
9 },
10 "end": {
11 "line": 7,
12 "column": 3
13 }
14 },
15 {
16 "id": "global.notConnectedToTheInternet",
17 "defaultMessage": "!!!You are not connected to the internet.",
18 "file": "src/i18n/globalMessages.js",
19 "start": {
20 "line": 8,
21 "column": 29
22 },
23 "end": {
24 "line": 11,
25 "column": 3
26 }
27 },
28 {
29 "id": "global.spellchecking.language",
30 "defaultMessage": "!!!Spell checking language",
31 "file": "src/i18n/globalMessages.js",
32 "start": {
33 "line": 12,
34 "column": 24
35 },
36 "end": {
37 "line": 15,
38 "column": 3
39 }
40 },
41 {
42 "id": "global.spellchecker.useDefault",
43 "defaultMessage": "!!!Use System Default ({default})",
44 "file": "src/i18n/globalMessages.js",
45 "start": {
46 "line": 16,
47 "column": 29
48 },
49 "end": {
50 "line": 19,
51 "column": 3
52 }
53 },
54 {
55 "id": "global.spellchecking.autodetect",
56 "defaultMessage": "!!!Detect language automatically",
57 "file": "src/i18n/globalMessages.js",
58 "start": {
59 "line": 20,
60 "column": 34
61 },
62 "end": {
63 "line": 23,
64 "column": 3
65 }
66 },
67 {
68 "id": "global.spellchecking.autodetect.short",
69 "defaultMessage": "!!!Automatic",
70 "file": "src/i18n/globalMessages.js",
71 "start": {
72 "line": 24,
73 "column": 39
74 },
75 "end": {
76 "line": 27,
77 "column": 3
78 }
79 },
80 {
81 "id": "global.userAgentPref",
82 "defaultMessage": "!!!User Agent",
83 "file": "src/i18n/globalMessages.js",
84 "start": {
85 "line": 28,
86 "column": 17
87 },
88 "end": {
89 "line": 31,
90 "column": 3
91 }
92 },
93 {
94 "id": "global.userAgentHelp",
95 "defaultMessage": "!!!Use 'https://whatmyuseragent.com/' (to discover) or 'https://developers.whatismybrowser.com/useragents/explore/' (to choose) your desired user agent and copy-paste it here.",
96 "file": "src/i18n/globalMessages.js",
97 "start": {
98 "line": 32,
99 "column": 17
100 },
101 "end": {
102 "line": 35,
103 "column": 3
104 }
105 },
106 {
107 "id": "global.yes",
108 "defaultMessage": "!!!Yes",
109 "file": "src/i18n/globalMessages.js",
110 "start": {
111 "line": 36,
112 "column": 7
113 },
114 "end": {
115 "line": 39,
116 "column": 3
117 }
118 },
119 {
120 "id": "global.no",
121 "defaultMessage": "!!!No",
122 "file": "src/i18n/globalMessages.js",
123 "start": {
124 "line": 40,
125 "column": 6
126 },
127 "end": {
128 "line": 43,
129 "column": 3
130 }
131 },
132 {
133 "id": "global.ok",
134 "defaultMessage": "!!!Ok",
135 "file": "src/i18n/globalMessages.js",
136 "start": {
137 "line": 44,
138 "column": 6
139 },
140 "end": {
141 "line": 47,
142 "column": 3
143 }
144 },
145 {
146 "id": "global.cancel",
147 "defaultMessage": "!!!Cancel",
148 "file": "src/i18n/globalMessages.js",
149 "start": {
150 "line": 48,
151 "column": 10
152 },
153 "end": {
154 "line": 51,
155 "column": 3
156 }
157 },
158 {
159 "id": "global.save",
160 "defaultMessage": "!!!Save",
161 "file": "src/i18n/globalMessages.js",
162 "start": {
163 "line": 52,
164 "column": 8
165 },
166 "end": {
167 "line": 55,
168 "column": 3
169 }
170 },
171 {
172 "id": "global.submit",
173 "defaultMessage": "!!!Submit",
174 "file": "src/i18n/globalMessages.js",
175 "start": {
176 "line": 56,
177 "column": 10
178 },
179 "end": {
180 "line": 59,
181 "column": 3
182 }
183 },
184 {
185 "id": "global.quit",
186 "defaultMessage": "!!!Quit",
187 "file": "src/i18n/globalMessages.js",
188 "start": {
189 "line": 60,
190 "column": 8
191 },
192 "end": {
193 "line": 63,
194 "column": 3
195 }
196 },
197 {
198 "id": "global.quitConfirmation",
199 "defaultMessage": "!!!Do you really want to quit Ferdi?",
200 "file": "src/i18n/globalMessages.js",
201 "start": {
202 "line": 64,
203 "column": 20
204 },
205 "end": {
206 "line": 68,
207 "column": 3
208 }
209 },
210 {
211 "id": "global.settings",
212 "defaultMessage": "!!!Settings",
213 "file": "src/i18n/globalMessages.js",
214 "start": {
215 "line": 69,
216 "column": 12
217 },
218 "end": {
219 "line": 72,
220 "column": 3
221 }
222 },
223 {
224 "id": "global.edit",
225 "defaultMessage": "!!!Edit",
226 "file": "src/i18n/globalMessages.js",
227 "start": {
228 "line": 73,
229 "column": 8
230 },
231 "end": {
232 "line": 76,
233 "column": 3
234 }
235 }
236] \ No newline at end of file
diff --git a/src/i18n/messages/src/lib/Menu.json b/src/i18n/messages/src/lib/Menu.json
deleted file mode 100644
index 35f2e3b7b..000000000
--- a/src/i18n/messages/src/lib/Menu.json
+++ /dev/null
@@ -1,912 +0,0 @@
1[
2 {
3 "id": "menu.edit",
4 "defaultMessage": "!!!Edit",
5 "file": "src/lib/Menu.js",
6 "start": {
7 "line": 32,
8 "column": 8
9 },
10 "end": {
11 "line": 35,
12 "column": 3
13 }
14 },
15 {
16 "id": "menu.edit.undo",
17 "defaultMessage": "!!!Undo",
18 "file": "src/lib/Menu.js",
19 "start": {
20 "line": 36,
21 "column": 8
22 },
23 "end": {
24 "line": 39,
25 "column": 3
26 }
27 },
28 {
29 "id": "menu.edit.redo",
30 "defaultMessage": "!!!Redo",
31 "file": "src/lib/Menu.js",
32 "start": {
33 "line": 40,
34 "column": 8
35 },
36 "end": {
37 "line": 43,
38 "column": 3
39 }
40 },
41 {
42 "id": "menu.edit.cut",
43 "defaultMessage": "!!!Cut",
44 "file": "src/lib/Menu.js",
45 "start": {
46 "line": 44,
47 "column": 7
48 },
49 "end": {
50 "line": 47,
51 "column": 3
52 }
53 },
54 {
55 "id": "menu.edit.copy",
56 "defaultMessage": "!!!Copy",
57 "file": "src/lib/Menu.js",
58 "start": {
59 "line": 48,
60 "column": 8
61 },
62 "end": {
63 "line": 51,
64 "column": 3
65 }
66 },
67 {
68 "id": "menu.edit.paste",
69 "defaultMessage": "!!!Paste",
70 "file": "src/lib/Menu.js",
71 "start": {
72 "line": 52,
73 "column": 9
74 },
75 "end": {
76 "line": 55,
77 "column": 3
78 }
79 },
80 {
81 "id": "menu.edit.pasteAndMatchStyle",
82 "defaultMessage": "!!!Paste And Match Style",
83 "file": "src/lib/Menu.js",
84 "start": {
85 "line": 56,
86 "column": 22
87 },
88 "end": {
89 "line": 59,
90 "column": 3
91 }
92 },
93 {
94 "id": "menu.edit.delete",
95 "defaultMessage": "!!!Delete",
96 "file": "src/lib/Menu.js",
97 "start": {
98 "line": 60,
99 "column": 10
100 },
101 "end": {
102 "line": 63,
103 "column": 3
104 }
105 },
106 {
107 "id": "menu.edit.selectAll",
108 "defaultMessage": "!!!Select All",
109 "file": "src/lib/Menu.js",
110 "start": {
111 "line": 64,
112 "column": 13
113 },
114 "end": {
115 "line": 67,
116 "column": 3
117 }
118 },
119 {
120 "id": "menu.edit.findInPage",
121 "defaultMessage": "!!!Find in Page",
122 "file": "src/lib/Menu.js",
123 "start": {
124 "line": 68,
125 "column": 14
126 },
127 "end": {
128 "line": 71,
129 "column": 3
130 }
131 },
132 {
133 "id": "menu.edit.speech",
134 "defaultMessage": "!!!Speech",
135 "file": "src/lib/Menu.js",
136 "start": {
137 "line": 72,
138 "column": 10
139 },
140 "end": {
141 "line": 75,
142 "column": 3
143 }
144 },
145 {
146 "id": "menu.edit.startSpeaking",
147 "defaultMessage": "!!!Start Speaking",
148 "file": "src/lib/Menu.js",
149 "start": {
150 "line": 76,
151 "column": 17
152 },
153 "end": {
154 "line": 79,
155 "column": 3
156 }
157 },
158 {
159 "id": "menu.edit.stopSpeaking",
160 "defaultMessage": "!!!Stop Speaking",
161 "file": "src/lib/Menu.js",
162 "start": {
163 "line": 80,
164 "column": 16
165 },
166 "end": {
167 "line": 83,
168 "column": 3
169 }
170 },
171 {
172 "id": "menu.edit.startDictation",
173 "defaultMessage": "!!!Start Dictation",
174 "file": "src/lib/Menu.js",
175 "start": {
176 "line": 84,
177 "column": 18
178 },
179 "end": {
180 "line": 87,
181 "column": 3
182 }
183 },
184 {
185 "id": "menu.edit.emojiSymbols",
186 "defaultMessage": "!!!Emoji & Symbols",
187 "file": "src/lib/Menu.js",
188 "start": {
189 "line": 88,
190 "column": 16
191 },
192 "end": {
193 "line": 91,
194 "column": 3
195 }
196 },
197 {
198 "id": "menu.view.openQuickSwitch",
199 "defaultMessage": "!!!Open Quick Switch",
200 "file": "src/lib/Menu.js",
201 "start": {
202 "line": 92,
203 "column": 19
204 },
205 "end": {
206 "line": 95,
207 "column": 3
208 }
209 },
210 {
211 "id": "menu.view.back",
212 "defaultMessage": "!!!Back",
213 "file": "src/lib/Menu.js",
214 "start": {
215 "line": 96,
216 "column": 8
217 },
218 "end": {
219 "line": 99,
220 "column": 3
221 }
222 },
223 {
224 "id": "menu.view.forward",
225 "defaultMessage": "!!!Forward",
226 "file": "src/lib/Menu.js",
227 "start": {
228 "line": 100,
229 "column": 11
230 },
231 "end": {
232 "line": 103,
233 "column": 3
234 }
235 },
236 {
237 "id": "menu.view.resetZoom",
238 "defaultMessage": "!!!Actual Size",
239 "file": "src/lib/Menu.js",
240 "start": {
241 "line": 104,
242 "column": 13
243 },
244 "end": {
245 "line": 107,
246 "column": 3
247 }
248 },
249 {
250 "id": "menu.view.zoomIn",
251 "defaultMessage": "!!!Zoom In",
252 "file": "src/lib/Menu.js",
253 "start": {
254 "line": 108,
255 "column": 10
256 },
257 "end": {
258 "line": 111,
259 "column": 3
260 }
261 },
262 {
263 "id": "menu.view.zoomOut",
264 "defaultMessage": "!!!Zoom Out",
265 "file": "src/lib/Menu.js",
266 "start": {
267 "line": 112,
268 "column": 11
269 },
270 "end": {
271 "line": 115,
272 "column": 3
273 }
274 },
275 {
276 "id": "menu.view.toggleFullScreen",
277 "defaultMessage": "!!!Toggle Full Screen",
278 "file": "src/lib/Menu.js",
279 "start": {
280 "line": 116,
281 "column": 20
282 },
283 "end": {
284 "line": 119,
285 "column": 3
286 }
287 },
288 {
289 "id": "menu.view.toggleDarkMode",
290 "defaultMessage": "!!!Toggle Dark Mode",
291 "file": "src/lib/Menu.js",
292 "start": {
293 "line": 120,
294 "column": 18
295 },
296 "end": {
297 "line": 123,
298 "column": 3
299 }
300 },
301 {
302 "id": "menu.view.toggleDevTools",
303 "defaultMessage": "!!!Toggle Developer Tools",
304 "file": "src/lib/Menu.js",
305 "start": {
306 "line": 124,
307 "column": 18
308 },
309 "end": {
310 "line": 127,
311 "column": 3
312 }
313 },
314 {
315 "id": "menu.view.toggleTodosDevTools",
316 "defaultMessage": "!!!Toggle Todos Developer Tools",
317 "file": "src/lib/Menu.js",
318 "start": {
319 "line": 128,
320 "column": 23
321 },
322 "end": {
323 "line": 131,
324 "column": 3
325 }
326 },
327 {
328 "id": "menu.view.toggleServiceDevTools",
329 "defaultMessage": "!!!Toggle Service Developer Tools",
330 "file": "src/lib/Menu.js",
331 "start": {
332 "line": 132,
333 "column": 25
334 },
335 "end": {
336 "line": 135,
337 "column": 3
338 }
339 },
340 {
341 "id": "menu.view.reloadService",
342 "defaultMessage": "!!!Reload Service",
343 "file": "src/lib/Menu.js",
344 "start": {
345 "line": 136,
346 "column": 17
347 },
348 "end": {
349 "line": 139,
350 "column": 3
351 }
352 },
353 {
354 "id": "menu.view.reloadFerdi",
355 "defaultMessage": "!!!Reload Ferdi",
356 "file": "src/lib/Menu.js",
357 "start": {
358 "line": 140,
359 "column": 15
360 },
361 "end": {
362 "line": 143,
363 "column": 3
364 }
365 },
366 {
367 "id": "menu.view.lockFerdi",
368 "defaultMessage": "!!!Lock Ferdi",
369 "file": "src/lib/Menu.js",
370 "start": {
371 "line": 144,
372 "column": 13
373 },
374 "end": {
375 "line": 147,
376 "column": 3
377 }
378 },
379 {
380 "id": "menu.view.reloadTodos",
381 "defaultMessage": "!!!Reload ToDos",
382 "file": "src/lib/Menu.js",
383 "start": {
384 "line": 148,
385 "column": 15
386 },
387 "end": {
388 "line": 151,
389 "column": 3
390 }
391 },
392 {
393 "id": "menu.window.minimize",
394 "defaultMessage": "!!!Minimize",
395 "file": "src/lib/Menu.js",
396 "start": {
397 "line": 152,
398 "column": 12
399 },
400 "end": {
401 "line": 155,
402 "column": 3
403 }
404 },
405 {
406 "id": "menu.window.close",
407 "defaultMessage": "!!!Close",
408 "file": "src/lib/Menu.js",
409 "start": {
410 "line": 156,
411 "column": 9
412 },
413 "end": {
414 "line": 159,
415 "column": 3
416 }
417 },
418 {
419 "id": "menu.help.learnMore",
420 "defaultMessage": "!!!Learn More",
421 "file": "src/lib/Menu.js",
422 "start": {
423 "line": 160,
424 "column": 13
425 },
426 "end": {
427 "line": 163,
428 "column": 3
429 }
430 },
431 {
432 "id": "menu.help.changelog",
433 "defaultMessage": "!!!Changelog",
434 "file": "src/lib/Menu.js",
435 "start": {
436 "line": 164,
437 "column": 13
438 },
439 "end": {
440 "line": 167,
441 "column": 3
442 }
443 },
444 {
445 "id": "menu.help.importExportData",
446 "defaultMessage": "!!!Import/Export Configuration Data",
447 "file": "src/lib/Menu.js",
448 "start": {
449 "line": 168,
450 "column": 20
451 },
452 "end": {
453 "line": 171,
454 "column": 3
455 }
456 },
457 {
458 "id": "menu.help.support",
459 "defaultMessage": "!!!Support",
460 "file": "src/lib/Menu.js",
461 "start": {
462 "line": 172,
463 "column": 11
464 },
465 "end": {
466 "line": 175,
467 "column": 3
468 }
469 },
470 {
471 "id": "menu.help.debugInfo",
472 "defaultMessage": "!!!Copy Debug Information",
473 "file": "src/lib/Menu.js",
474 "start": {
475 "line": 176,
476 "column": 13
477 },
478 "end": {
479 "line": 179,
480 "column": 3
481 }
482 },
483 {
484 "id": "menu.help.publishDebugInfo",
485 "defaultMessage": "!!!Publish Debug Information",
486 "file": "src/lib/Menu.js",
487 "start": {
488 "line": 180,
489 "column": 20
490 },
491 "end": {
492 "line": 183,
493 "column": 3
494 }
495 },
496 {
497 "id": "menu.help.debugInfoCopiedHeadline",
498 "defaultMessage": "!!!Ferdi Debug Information",
499 "file": "src/lib/Menu.js",
500 "start": {
501 "line": 184,
502 "column": 27
503 },
504 "end": {
505 "line": 187,
506 "column": 3
507 }
508 },
509 {
510 "id": "menu.help.debugInfoCopiedBody",
511 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.",
512 "file": "src/lib/Menu.js",
513 "start": {
514 "line": 188,
515 "column": 23
516 },
517 "end": {
518 "line": 192,
519 "column": 3
520 }
521 },
522 {
523 "id": "locked.touchId",
524 "defaultMessage": "!!!Unlock with Touch ID",
525 "file": "src/lib/Menu.js",
526 "start": {
527 "line": 193,
528 "column": 11
529 },
530 "end": {
531 "line": 196,
532 "column": 3
533 }
534 },
535 {
536 "id": "locked.touchIdPrompt",
537 "defaultMessage": "!!!unlock via Touch ID",
538 "file": "src/lib/Menu.js",
539 "start": {
540 "line": 197,
541 "column": 17
542 },
543 "end": {
544 "line": 200,
545 "column": 3
546 }
547 },
548 {
549 "id": "menu.help.tos",
550 "defaultMessage": "!!!Terms of Service",
551 "file": "src/lib/Menu.js",
552 "start": {
553 "line": 201,
554 "column": 7
555 },
556 "end": {
557 "line": 204,
558 "column": 3
559 }
560 },
561 {
562 "id": "menu.help.privacy",
563 "defaultMessage": "!!!Privacy Statement",
564 "file": "src/lib/Menu.js",
565 "start": {
566 "line": 205,
567 "column": 11
568 },
569 "end": {
570 "line": 208,
571 "column": 3
572 }
573 },
574 {
575 "id": "menu.file",
576 "defaultMessage": "!!!File",
577 "file": "src/lib/Menu.js",
578 "start": {
579 "line": 209,
580 "column": 8
581 },
582 "end": {
583 "line": 212,
584 "column": 3
585 }
586 },
587 {
588 "id": "menu.view",
589 "defaultMessage": "!!!View",
590 "file": "src/lib/Menu.js",
591 "start": {
592 "line": 213,
593 "column": 8
594 },
595 "end": {
596 "line": 216,
597 "column": 3
598 }
599 },
600 {
601 "id": "menu.services",
602 "defaultMessage": "!!!Services",
603 "file": "src/lib/Menu.js",
604 "start": {
605 "line": 217,
606 "column": 12
607 },
608 "end": {
609 "line": 220,
610 "column": 3
611 }
612 },
613 {
614 "id": "menu.window",
615 "defaultMessage": "!!!Window",
616 "file": "src/lib/Menu.js",
617 "start": {
618 "line": 221,
619 "column": 10
620 },
621 "end": {
622 "line": 224,
623 "column": 3
624 }
625 },
626 {
627 "id": "menu.help",
628 "defaultMessage": "!!!Help",
629 "file": "src/lib/Menu.js",
630 "start": {
631 "line": 225,
632 "column": 8
633 },
634 "end": {
635 "line": 228,
636 "column": 3
637 }
638 },
639 {
640 "id": "menu.app.about",
641 "defaultMessage": "!!!About Ferdi",
642 "file": "src/lib/Menu.js",
643 "start": {
644 "line": 229,
645 "column": 9
646 },
647 "end": {
648 "line": 232,
649 "column": 3
650 }
651 },
652 {
653 "id": "menu.app.checkForUpdates",
654 "defaultMessage": "!!!Check for updates",
655 "file": "src/lib/Menu.js",
656 "start": {
657 "line": 233,
658 "column": 19
659 },
660 "end": {
661 "line": 236,
662 "column": 3
663 }
664 },
665 {
666 "id": "menu.app.hide",
667 "defaultMessage": "!!!Hide",
668 "file": "src/lib/Menu.js",
669 "start": {
670 "line": 237,
671 "column": 8
672 },
673 "end": {
674 "line": 240,
675 "column": 3
676 }
677 },
678 {
679 "id": "menu.app.hideOthers",
680 "defaultMessage": "!!!Hide Others",
681 "file": "src/lib/Menu.js",
682 "start": {
683 "line": 241,
684 "column": 14
685 },
686 "end": {
687 "line": 244,
688 "column": 3
689 }
690 },
691 {
692 "id": "menu.app.unhide",
693 "defaultMessage": "!!!Unhide",
694 "file": "src/lib/Menu.js",
695 "start": {
696 "line": 245,
697 "column": 10
698 },
699 "end": {
700 "line": 248,
701 "column": 3
702 }
703 },
704 {
705 "id": "menu.app.autohideMenuBar",
706 "defaultMessage": "!!!Auto-hide menu bar",
707 "file": "src/lib/Menu.js",
708 "start": {
709 "line": 249,
710 "column": 19
711 },
712 "end": {
713 "line": 252,
714 "column": 3
715 }
716 },
717 {
718 "id": "menu.services.addNewService",
719 "defaultMessage": "!!!Add New Service...",
720 "file": "src/lib/Menu.js",
721 "start": {
722 "line": 253,
723 "column": 17
724 },
725 "end": {
726 "line": 256,
727 "column": 3
728 }
729 },
730 {
731 "id": "menu.workspaces.addNewWorkspace",
732 "defaultMessage": "!!!Add New Workspace...",
733 "file": "src/lib/Menu.js",
734 "start": {
735 "line": 257,
736 "column": 19
737 },
738 "end": {
739 "line": 260,
740 "column": 3
741 }
742 },
743 {
744 "id": "menu.workspaces.openWorkspaceDrawer",
745 "defaultMessage": "!!!Open workspace drawer",
746 "file": "src/lib/Menu.js",
747 "start": {
748 "line": 261,
749 "column": 23
750 },
751 "end": {
752 "line": 264,
753 "column": 3
754 }
755 },
756 {
757 "id": "menu.workspaces.closeWorkspaceDrawer",
758 "defaultMessage": "!!!Close workspace drawer",
759 "file": "src/lib/Menu.js",
760 "start": {
761 "line": 265,
762 "column": 24
763 },
764 "end": {
765 "line": 268,
766 "column": 3
767 }
768 },
769 {
770 "id": "menu.services.setNextServiceActive",
771 "defaultMessage": "!!!Activate next service...",
772 "file": "src/lib/Menu.js",
773 "start": {
774 "line": 269,
775 "column": 23
776 },
777 "end": {
778 "line": 272,
779 "column": 3
780 }
781 },
782 {
783 "id": "menu.services.activatePreviousService",
784 "defaultMessage": "!!!Activate previous service...",
785 "file": "src/lib/Menu.js",
786 "start": {
787 "line": 273,
788 "column": 27
789 },
790 "end": {
791 "line": 276,
792 "column": 3
793 }
794 },
795 {
796 "id": "sidebar.muteApp",
797 "defaultMessage": "!!!Disable notifications & audio",
798 "file": "src/lib/Menu.js",
799 "start": {
800 "line": 277,
801 "column": 11
802 },
803 "end": {
804 "line": 280,
805 "column": 3
806 }
807 },
808 {
809 "id": "sidebar.unmuteApp",
810 "defaultMessage": "!!!Enable notifications & audio",
811 "file": "src/lib/Menu.js",
812 "start": {
813 "line": 281,
814 "column": 13
815 },
816 "end": {
817 "line": 284,
818 "column": 3
819 }
820 },
821 {
822 "id": "menu.workspaces",
823 "defaultMessage": "!!!Workspaces",
824 "file": "src/lib/Menu.js",
825 "start": {
826 "line": 285,
827 "column": 14
828 },
829 "end": {
830 "line": 288,
831 "column": 3
832 }
833 },
834 {
835 "id": "menu.workspaces.defaultWorkspace",
836 "defaultMessage": "!!!Default",
837 "file": "src/lib/Menu.js",
838 "start": {
839 "line": 289,
840 "column": 20
841 },
842 "end": {
843 "line": 292,
844 "column": 3
845 }
846 },
847 {
848 "id": "menu.todos",
849 "defaultMessage": "!!!Todos",
850 "file": "src/lib/Menu.js",
851 "start": {
852 "line": 293,
853 "column": 9
854 },
855 "end": {
856 "line": 296,
857 "column": 3
858 }
859 },
860 {
861 "id": "menu.Todoss.openTodosDrawer",
862 "defaultMessage": "!!!Open Todos drawer",
863 "file": "src/lib/Menu.js",
864 "start": {
865 "line": 297,
866 "column": 19
867 },
868 "end": {
869 "line": 300,
870 "column": 3
871 }
872 },
873 {
874 "id": "menu.Todoss.closeTodosDrawer",
875 "defaultMessage": "!!!Close Todos drawer",
876 "file": "src/lib/Menu.js",
877 "start": {
878 "line": 301,
879 "column": 20
880 },
881 "end": {
882 "line": 304,
883 "column": 3
884 }
885 },
886 {
887 "id": "menu.todos.enableTodos",
888 "defaultMessage": "!!!Enable Todos",
889 "file": "src/lib/Menu.js",
890 "start": {
891 "line": 305,
892 "column": 15
893 },
894 "end": {
895 "line": 308,
896 "column": 3
897 }
898 },
899 {
900 "id": "menu.services.goHome",
901 "defaultMessage": "!!!Home",
902 "file": "src/lib/Menu.js",
903 "start": {
904 "line": 309,
905 "column": 17
906 },
907 "end": {
908 "line": 312,
909 "column": 3
910 }
911 }
912] \ No newline at end of file
diff --git a/src/i18n/translations.js b/src/i18n/translations.js
deleted file mode 100644
index 161a172ba..000000000
--- a/src/i18n/translations.js
+++ /dev/null
@@ -1,13 +0,0 @@
1import { APP_LOCALES } from './languages';
2
3const translations = [];
4Object.keys(APP_LOCALES).forEach((key) => {
5 try {
6 const translation = require(`./locales/${key}.json`); // eslint-disable-line
7 translations[key] = translation;
8 } catch (err) {
9 console.warn(`Can't find translations for ${key}`);
10 }
11});
12
13module.exports = translations;
diff --git a/src/i18n/translations.ts b/src/i18n/translations.ts
new file mode 100644
index 000000000..9a7dc7453
--- /dev/null
+++ b/src/i18n/translations.ts
@@ -0,0 +1,15 @@
1/* eslint-disable global-require */
2import { APP_LOCALES } from './languages';
3
4const translations = [];
5for (const key of Object.keys(APP_LOCALES)) {
6 try {
7 // eslint-disable-next-line import/no-dynamic-require
8 const translation = require(`./locales/${key}.json`);
9 translations[key] = translation;
10 } catch {
11 console.warn(`Can't find translations for ${key}`);
12 }
13}
14
15module.exports = translations;
diff --git a/src/index.html b/src/index.html
index 929aec3ad..fea2ec387 100644
--- a/src/index.html
+++ b/src/index.html
@@ -26,7 +26,7 @@
26 ); 26 );
27 27
28 require('./sentry'); 28 require('./sentry');
29 const { isDevMode } = require('./environment'); 29 const { isDevMode } = require('./environment-remote');
30 if (isDevMode) { 30 if (isDevMode) {
31 const debugging = require('debug'); 31 const debugging = require('debug');
32 debugging.enable(process.env.DEBUG); 32 debugging.enable(process.env.DEBUG);
diff --git a/src/index.js b/src/index.js
index 1f3510361..9f384f5fa 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,31 +1,30 @@
1/* eslint-disable import/first */ 1/* eslint-disable import/first */
2 2
3import { app, BrowserWindow, ipcMain, session, dialog } from 'electron'; 3import { app, BrowserWindow, globalShortcut, ipcMain, session, dialog } from 'electron';
4 4
5import { emptyDirSync, ensureFileSync } from 'fs-extra'; 5import { emptyDirSync, ensureFileSync } from 'fs-extra';
6import { join } from 'path'; 6import { join } from 'path';
7import windowStateKeeper from 'electron-window-state'; 7import windowStateKeeper from 'electron-window-state';
8import { enforceMacOSAppLocation } from 'electron-util';
9import ms from 'ms'; 8import ms from 'ms';
9import { initializeRemote } from './electron-util';
10import { enforceMacOSAppLocation } from './enforce-macos-app-location';
10 11
11require('@electron/remote/main').initialize(); 12initializeRemote();
12 13
13import osName from 'os-name'; 14import { DEFAULT_APP_SETTINGS, DEFAULT_WINDOW_OPTIONS } from './config';
14import { DEFAULT_WINDOW_OPTIONS } from './config';
15 15
16import { 16import {
17 DEFAULT_APP_SETTINGS,
18 isDevMode,
19 isMac, 17 isMac,
20 isWindows, 18 isWindows,
21 isLinux, 19 isLinux,
20 altKey,
21} from './environment';
22import {
23 isDevMode,
24 aboutAppDetails,
22 userDataRecipesPath, 25 userDataRecipesPath,
23 userDataPath, 26 userDataPath,
24 ferdiVersion, 27} from './environment-remote';
25 electronVersion,
26 chromeVersion,
27 nodeVersion,
28} from './environment';
29import { ifUndefinedBoolean } from './jsUtils'; 28import { ifUndefinedBoolean } from './jsUtils';
30 29
31import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; 30import { mainIpcHandler as basicAuthHandler } from './features/basicAuth';
@@ -41,15 +40,9 @@ import './electron/exception';
41import { asarPath } from './helpers/asar-helpers'; 40import { asarPath } from './helpers/asar-helpers';
42import { openExternalUrl } from './helpers/url-helpers'; 41import { openExternalUrl } from './helpers/url-helpers';
43import userAgent from './helpers/userAgent-helpers'; 42import userAgent from './helpers/userAgent-helpers';
44import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved
45 43
46const debug = require('debug')('Ferdi:App'); 44const debug = require('debug')('Ferdi:App');
47 45
48// From Electron 9 onwards, app.allowRendererProcessReuse = true by default. This causes the app to crash on Windows due to the
49// Electron Windows Notification API crashing. Setting this to false fixes the issue until the electron team fixes the notification bug
50// More Info - https://github.com/electron/electron/issues/18397
51app.allowRendererProcessReuse = false;
52
53// Globally set useragent to fix user agent override in service workers 46// Globally set useragent to fix user agent override in service workers
54debug('Set userAgent to ', userAgent()); 47debug('Set userAgent to ', userAgent());
55app.userAgentFallback = userAgent(); 48app.userAgentFallback = userAgent();
@@ -83,14 +76,18 @@ if (isWindows) {
83const settings = new Settings('app', DEFAULT_APP_SETTINGS); 76const settings = new Settings('app', DEFAULT_APP_SETTINGS);
84const proxySettings = new Settings('proxy'); 77const proxySettings = new Settings('proxy');
85 78
86const retrieveSettingValue = (key, defaultValue = true) => ifUndefinedBoolean(settings.get(key), defaultValue); 79const retrieveSettingValue = (key, defaultValue = true) =>
80 ifUndefinedBoolean(settings.get(key), defaultValue);
87 81
88if (retrieveSettingValue('sentry')) { 82if (retrieveSettingValue('sentry')) {
89 // eslint-disable-next-line global-require 83 // eslint-disable-next-line global-require
90 require('./sentry'); 84 require('./sentry');
91} 85}
92 86
93const liftSingleInstanceLock = retrieveSettingValue('liftSingleInstanceLock', false); 87const liftSingleInstanceLock = retrieveSettingValue(
88 'liftSingleInstanceLock',
89 false,
90);
94 91
95// Force single window 92// Force single window
96const gotTheLock = liftSingleInstanceLock 93const gotTheLock = liftSingleInstanceLock
@@ -148,7 +145,7 @@ if (!gotTheLock) {
148// https://github.com/electron/electron/issues/9046 145// https://github.com/electron/electron/issues/9046
149if ( 146if (
150 isLinux && 147 isLinux &&
151 ['Pantheon', 'Unity:Unity7'].indexOf(process.env.XDG_CURRENT_DESKTOP) !== -1 148 ['Pantheon', 'Unity:Unity7'].includes(process.env.XDG_CURRENT_DESKTOP)
152) { 149) {
153 process.env.XDG_CURRENT_DESKTOP = 'Unity'; 150 process.env.XDG_CURRENT_DESKTOP = 'Unity';
154} 151}
@@ -160,17 +157,7 @@ if (!retrieveSettingValue('enableGPUAcceleration', false)) {
160} 157}
161 158
162app.setAboutPanelOptions({ 159app.setAboutPanelOptions({
163 applicationVersion: [ 160 applicationVersion: aboutAppDetails(),
164 `Version: ${ferdiVersion}`,
165 `Electron: ${electronVersion}`,
166 `Chrome: ${chromeVersion}`,
167 `Node.js: ${nodeVersion}`,
168 `Platform: ${osName()}`,
169 `Arch: ${process.arch}`,
170 `Build date: ${new Date(Number(buildInfo.timestamp))}`,
171 `Git SHA: ${buildInfo.gitHashShort}`,
172 `Git branch: ${buildInfo.gitBranch}`,
173 ].join('\n'),
174 version: '', 161 version: '',
175}); 162});
176 163
@@ -205,11 +192,11 @@ const createWindow = () => {
205 minWidth: 600, 192 minWidth: 600,
206 minHeight: 500, 193 minHeight: 500,
207 show: false, 194 show: false,
208 titleBarStyle: isMac ? 'hidden' : '', 195 titleBarStyle: isMac ? 'hidden' : 'default',
209 frame: isLinux, 196 frame: isLinux,
210 spellcheck: retrieveSettingValue('enableSpellchecking'),
211 backgroundColor, 197 backgroundColor,
212 webPreferences: { 198 webPreferences: {
199 spellcheck: retrieveSettingValue('enableSpellchecking'),
213 nodeIntegration: true, 200 nodeIntegration: true,
214 contextIsolation: false, 201 contextIsolation: false,
215 webviewTag: true, 202 webviewTag: true,
@@ -283,10 +270,7 @@ const createWindow = () => {
283 // Dereference the window object, usually you would store windows 270 // Dereference the window object, usually you would store windows
284 // in an array if your app supports multi windows, this is the time 271 // in an array if your app supports multi windows, this is the time
285 // when you should delete the corresponding element. 272 // when you should delete the corresponding element.
286 if ( 273 if (!willQuitApp && retrieveSettingValue('runInBackground')) {
287 !willQuitApp &&
288 retrieveSettingValue('runInBackground')
289 ) {
290 e.preventDefault(); 274 e.preventDefault();
291 if (isWindows) { 275 if (isWindows) {
292 debug('Window: minimize'); 276 debug('Window: minimize');
@@ -372,6 +356,13 @@ const createWindow = () => {
372 } else { 356 } else {
373 mainWindow.show(); 357 mainWindow.show();
374 } 358 }
359
360 app.whenReady().then(() => {
361 // Toggle the window on 'Alt+X'
362 globalShortcut.register(`${altKey()}+X`, () => {
363 trayIcon.trayMenuTemplate[0].click();
364 });
365 });
375}; 366};
376 367
377// Allow passing command line parameters/switches to electron 368// Allow passing command line parameters/switches to electron
@@ -415,31 +406,36 @@ app.on('ready', () => {
415 } 406 }
416 407
417 if (isWindows) { 408 if (isWindows) {
418 app.setUserTasks([ 409 const extraArgs = isDevMode ? `${__dirname} ` : '';
419 { 410 const iconPath = asarPath(
420 program: process.execPath,
421 arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`,
422 iconPath: asarPath(
423 join( 411 join(
424 isDevMode ? `${__dirname}../src/` : __dirname, 412 isDevMode ? `${__dirname}../src/` : __dirname,
425 'assets/images/taskbar/win32/display.ico', 413 'assets/images/taskbar/win32/display.ico',
426 ), 414 ),
427 ), 415 );
416 app.setUserTasks([
417 {
418 program: process.execPath,
419 arguments: `${extraArgs}--reset-window`,
420 iconPath,
428 iconIndex: 0, 421 iconIndex: 0,
429 title: 'Move Ferdi to Current Display', 422 title: 'Move Ferdi to Current Display',
430 description: 'Restore the position and size of Ferdi', 423 description: 'Restore the position and size of Ferdi',
431 }, 424 },
432 { 425 {
433 program: process.execPath, 426 program: process.execPath,
434 arguments: `${isDevMode ? `${__dirname} ` : ''}--quit`, 427 arguments: `${extraArgs}--quit`,
428 iconPath,
435 iconIndex: 0, 429 iconIndex: 0,
436 iconPath: null,
437 title: 'Quit Ferdi', 430 title: 'Quit Ferdi',
438 description: null, 431 description: null,
439 }, 432 },
440 ]); 433 ]);
441 } 434 }
442 435
436 // eslint-disable-next-line global-require
437 require('electron-react-titlebar/main').initialize();
438
443 createWindow(); 439 createWindow();
444}); 440});
445 441
@@ -486,8 +482,10 @@ ipcMain.on('open-browser-window', (e, { url, serviceId }) => {
486ipcMain.on( 482ipcMain.on(
487 'modifyRequestHeaders', 483 'modifyRequestHeaders',
488 (e, { modifiedRequestHeaders, serviceId }) => { 484 (e, { modifiedRequestHeaders, serviceId }) => {
489 debug(`Received modifyRequestHeaders ${modifiedRequestHeaders} for serviceId ${serviceId}`); 485 debug(
490 modifiedRequestHeaders.forEach(headerFilterSet => { 486 `Received modifyRequestHeaders ${modifiedRequestHeaders} for serviceId ${serviceId}`,
487 );
488 for (const headerFilterSet of modifiedRequestHeaders) {
491 const { headers, requestFilters } = headerFilterSet; 489 const { headers, requestFilters } = headerFilterSet;
492 session 490 session
493 .fromPartition(`persist:service-${serviceId}`) 491 .fromPartition(`persist:service-${serviceId}`)
@@ -500,27 +498,26 @@ ipcMain.on(
500 } 498 }
501 callback({ requestHeaders: details.requestHeaders }); 499 callback({ requestHeaders: details.requestHeaders });
502 }); 500 });
503 }); 501 }
504 }, 502 },
505); 503);
506 504
507ipcMain.on( 505ipcMain.on('knownCertificateHosts', (e, { knownHosts, serviceId }) => {
508 'knownCertificateHosts', 506 debug(
509 (e, { knownHosts, serviceId }) => { 507 `Received knownCertificateHosts ${knownHosts} for serviceId ${serviceId}`,
510 debug(`Received knownCertificateHosts ${knownHosts} for serviceId ${serviceId}`); 508 );
511 session 509 session
512 .fromPartition(`persist:service-${serviceId}`) 510 .fromPartition(`persist:service-${serviceId}`)
513 .setCertificateVerifyProc((request, callback) => { 511 .setCertificateVerifyProc((request, callback) => {
514 // To know more about these callbacks: https://www.electronjs.org/docs/api/session#sessetcertificateverifyprocproc 512 // To know more about these callbacks: https://www.electronjs.org/docs/api/session#sessetcertificateverifyprocproc
515 const { hostname } = request; 513 const { hostname } = request;
516 if (knownHosts.find(item => item.includes(hostname)).length > 0) { 514 if (knownHosts.find(item => item.includes(hostname)).length > 0) {
517 callback(0); 515 callback(0);
518 } else { 516 } else {
519 callback(-2); 517 callback(-2);
520 } 518 }
521 }); 519 });
522 }, 520});
523);
524 521
525ipcMain.on('feature-basic-auth-cancel', () => { 522ipcMain.on('feature-basic-auth-cancel', () => {
526 debug('Cancel basic auth'); 523 debug('Cancel basic auth');
@@ -563,6 +560,20 @@ ipcMain.on('stop-find-in-page', (e, action) => {
563 e.returnValue = null; 560 e.returnValue = null;
564}); 561});
565 562
563ipcMain.on('set-spellchecker-locales', (e, { locale, serviceId }) => {
564 if (serviceId === undefined) {
565 return;
566 }
567
568 const serviceSession = session.fromPartition(`persist:service-${serviceId}`);
569 const [defaultLocale] = serviceSession.getSpellCheckerLanguages();
570 debug(`Spellchecker default locale is: ${defaultLocale}`);
571
572 const locales = [locale, defaultLocale, DEFAULT_APP_SETTINGS.fallbackLocale];
573 debug(`Setting spellchecker locales to: ${locales}`);
574 serviceSession.setSpellCheckerLanguages(locales);
575});
576
566// Quit when all windows are closed. 577// Quit when all windows are closed.
567app.on('window-all-closed', () => { 578app.on('window-all-closed', () => {
568 // On OS X it is common for applications and their menu bar 579 // On OS X it is common for applications and their menu bar
@@ -575,7 +586,7 @@ app.on('window-all-closed', () => {
575 } 586 }
576}); 587});
577 588
578app.on('before-quit', (event) => { 589app.on('before-quit', event => {
579 const yesButtonIndex = 0; 590 const yesButtonIndex = 0;
580 let selection = yesButtonIndex; 591 let selection = yesButtonIndex;
581 if (retrieveSettingValue('confirmOnQuit')) { 592 if (retrieveSettingValue('confirmOnQuit')) {
@@ -583,10 +594,7 @@ app.on('before-quit', (event) => {
583 type: 'question', 594 type: 'question',
584 message: 'Quit', 595 message: 'Quit',
585 detail: 'Do you really want to quit Ferdi?', 596 detail: 'Do you really want to quit Ferdi?',
586 buttons: [ 597 buttons: ['Yes', 'No'],
587 'Yes',
588 'No',
589 ],
590 }); 598 });
591 } 599 }
592 if (selection === yesButtonIndex) { 600 if (selection === yesButtonIndex) {
diff --git a/src/internal-server/app/Controllers/Http/RecipeController.js b/src/internal-server/app/Controllers/Http/RecipeController.js
index 1a7595a9d..d44839db1 100644
--- a/src/internal-server/app/Controllers/Http/RecipeController.js
+++ b/src/internal-server/app/Controllers/Http/RecipeController.js
@@ -1,22 +1,18 @@
1const Recipe = use('App/Models/Recipe'); 1const Recipe = use('App/Models/Recipe');
2const Drive = use('Drive'); 2const Drive = use('Drive');
3const { 3const { validateAll } = use('Validator');
4 validateAll,
5} = use('Validator');
6const Env = use('Env'); 4const Env = use('Env');
7 5
8const fetch = require('node-fetch'); 6const fetch = require('node-fetch');
9const debug = require('debug')('Ferdi:internalServer:RecipeController'); 7const debug = require('debug')('Ferdi:internalServer:RecipeController');
10const { LIVE_FERDI_API } = require('../../../../config'); 8const { LIVE_FERDI_API } = require('../../../../config');
11const { API_VERSION } = require('../../../../environment'); 9const { API_VERSION } = require('../../../../environment-remote');
12 10
13const RECIPES_URL = `${LIVE_FERDI_API}/${API_VERSION}/recipes`; 11const RECIPES_URL = `${LIVE_FERDI_API}/${API_VERSION}/recipes`;
14 12
15class RecipeController { 13class RecipeController {
16 // List official and custom recipes 14 // List official and custom recipes
17 async list({ 15 async list({ response }) {
18 response,
19 }) {
20 const officialRecipes = JSON.parse(await (await fetch(RECIPES_URL)).text()); 16 const officialRecipes = JSON.parse(await (await fetch(RECIPES_URL)).text());
21 const customRecipesArray = (await Recipe.all()).rows; 17 const customRecipesArray = (await Recipe.all()).rows;
22 const customRecipes = customRecipesArray.map(recipe => ({ 18 const customRecipes = customRecipesArray.map(recipe => ({
@@ -25,19 +21,13 @@ class RecipeController {
25 ...JSON.parse(recipe.data), 21 ...JSON.parse(recipe.data),
26 })); 22 }));
27 23
28 const recipes = [ 24 const recipes = [...officialRecipes, ...customRecipes];
29 ...officialRecipes,
30 ...customRecipes,
31 ];
32 25
33 return response.send(recipes); 26 return response.send(recipes);
34 } 27 }
35 28
36 // Search official and custom recipes 29 // Search official and custom recipes
37 async search({ 30 async search({ request, response }) {
38 request,
39 response,
40 }) {
41 // Validate user input 31 // Validate user input
42 const validation = await validateAll(request.all(), { 32 const validation = await validateAll(request.all(), {
43 needle: 'required', 33 needle: 'required',
@@ -64,13 +54,23 @@ class RecipeController {
64 })); 54 }));
65 } else { 55 } else {
66 let remoteResults = []; 56 let remoteResults = [];
67 if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq 57 // eslint-disable-next-line eqeqeq
68 remoteResults = JSON.parse(await (await fetch(`${RECIPES_URL}/search?needle=${encodeURIComponent(needle)}`)).text()); 58 if (Env.get('CONNECT_WITH_FRANZ') == 'true') {
59 // eslint-disable-line eqeqeq
60 remoteResults = JSON.parse(
61 await (
62 await fetch(
63 `${RECIPES_URL}/search?needle=${encodeURIComponent(needle)}`,
64 )
65 ).text(),
66 );
69 } 67 }
70 68
71 debug('remoteResults:', remoteResults); 69 debug('remoteResults:', remoteResults);
72 70
73 const localResultsArray = (await Recipe.query().where('name', 'LIKE', `%${needle}%`).fetch()).toJSON(); 71 const localResultsArray = (
72 await Recipe.query().where('name', 'LIKE', `%${needle}%`).fetch()
73 ).toJSON();
74 const localResults = localResultsArray.map(recipe => ({ 74 const localResults = localResultsArray.map(recipe => ({
75 id: recipe.recipeId, 75 id: recipe.recipeId,
76 name: recipe.name, 76 name: recipe.name,
@@ -79,20 +79,14 @@ class RecipeController {
79 79
80 debug('localResults:', localResults); 80 debug('localResults:', localResults);
81 81
82 results = [ 82 results = [...localResults, ...(remoteResults || [])];
83 ...localResults,
84 ...remoteResults || [],
85 ];
86 } 83 }
87 84
88 return response.send(results); 85 return response.send(results);
89 } 86 }
90 87
91 // Download a recipe 88 // Download a recipe
92 async download({ 89 async download({ response, params }) {
93 response,
94 params,
95 }) {
96 // Validate user input 90 // Validate user input
97 const validation = await validateAll(params, { 91 const validation = await validateAll(params, {
98 recipe: 'required|accepted', 92 recipe: 'required|accepted',
@@ -108,14 +102,17 @@ class RecipeController {
108 const service = params.recipe; 102 const service = params.recipe;
109 103
110 // Check for invalid characters 104 // Check for invalid characters
111 if (/\.{1,}/.test(service) || /\/{1,}/.test(service)) { 105 if (/\.+/.test(service) || /\/+/.test(service)) {
112 return response.send('Invalid recipe name'); 106 return response.send('Invalid recipe name');
113 } 107 }
114 108
115 // Check if recipe exists in recipes folder 109 // Check if recipe exists in recipes folder
116 if (await Drive.exists(`${service}.tar.gz`)) { 110 if (await Drive.exists(`${service}.tar.gz`)) {
117 return response.send(await Drive.get(`${service}.tar.gz`)); 111 return response.send(await Drive.get(`${service}.tar.gz`));
118 } if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq 112 }
113 // eslint-disable-next-line eqeqeq
114 if (Env.get('CONNECT_WITH_FRANZ') == 'true') {
115 // eslint-disable-line eqeqeq
119 return response.redirect(`${RECIPES_URL}/download/${service}`); 116 return response.redirect(`${RECIPES_URL}/download/${service}`);
120 } 117 }
121 return response.status(400).send({ 118 return response.status(400).send({
diff --git a/src/internal-server/app/Controllers/Http/ServiceController.js b/src/internal-server/app/Controllers/Http/ServiceController.js
index f2af9d411..133473b68 100644
--- a/src/internal-server/app/Controllers/Http/ServiceController.js
+++ b/src/internal-server/app/Controllers/Http/ServiceController.js
@@ -2,7 +2,7 @@ const Service = use('App/Models/Service');
2const { validateAll } = use('Validator'); 2const { validateAll } = use('Validator');
3const Env = use('Env'); 3const Env = use('Env');
4 4
5const uuid = require('uuid/v4'); 5const { v4: uuid } = require('uuid');
6const path = require('path'); 6const path = require('path');
7const fs = require('fs-extra'); 7const fs = require('fs-extra');
8const { LOCAL_HOSTNAME, DEFAULT_SERVICE_ORDER } = require('../../../../config'); 8const { LOCAL_HOSTNAME, DEFAULT_SERVICE_ORDER } = require('../../../../config');
@@ -135,13 +135,11 @@ class ServiceController {
135 135
136 const newSettings = { 136 const newSettings = {
137 ...settings, 137 ...settings,
138 ...{ 138 iconId,
139 iconId, 139 customIconVersion:
140 customIconVersion: 140 settings && settings.customIconVersion
141 settings && settings.customIconVersion 141 ? settings.customIconVersion + 1
142 ? settings.customIconVersion + 1 142 : 1,
143 : 1,
144 },
145 }; 143 };
146 144
147 // Update data in database 145 // Update data in database
@@ -157,9 +155,7 @@ class ServiceController {
157 id, 155 id,
158 name: service.name, 156 name: service.name,
159 ...newSettings, 157 ...newSettings,
160 iconUrl: `http://${hostname}:${port}/${API_VERSION}/icon/${ 158 iconUrl: `http://${hostname}:${port}/${API_VERSION}/icon/${newSettings.iconId}`,
161 newSettings.iconId
162 }`,
163 userId: 1, 159 userId: 1,
164 }, 160 },
165 status: ['updated'], 161 status: ['updated'],
diff --git a/src/internal-server/app/Controllers/Http/UserController.js b/src/internal-server/app/Controllers/Http/UserController.js
index 994dcc0dc..25b5277bd 100644
--- a/src/internal-server/app/Controllers/Http/UserController.js
+++ b/src/internal-server/app/Controllers/Http/UserController.js
@@ -1,34 +1,35 @@
1const User = use('App/Models/User'); 1const User = use('App/Models/User');
2const Service = use('App/Models/Service'); 2const Service = use('App/Models/Service');
3const Workspace = use('App/Models/Workspace'); 3const Workspace = use('App/Models/Workspace');
4const { 4const { validateAll } = use('Validator');
5 validateAll,
6} = use('Validator');
7 5
8const btoa = require('btoa'); 6const btoa = require('btoa');
9const fetch = require('node-fetch'); 7const fetch = require('node-fetch');
10const uuid = require('uuid/v4'); 8const { v4: uuid } = require('uuid');
11const crypto = require('crypto'); 9const crypto = require('crypto');
12const { DEFAULT_APP_SETTINGS, API_VERSION } = require('../../../../environment'); 10const { DEFAULT_APP_SETTINGS } = require('../../../../config');
11const { API_VERSION } = require('../../../../environment-remote');
13const { default: userAgent } = require('../../../../helpers/userAgent-helpers'); 12const { default: userAgent } = require('../../../../helpers/userAgent-helpers');
14 13
15const apiRequest = (url, route, method, auth) => new Promise((resolve, reject) => { 14const apiRequest = (url, route, method, auth) =>
16 try { 15 new Promise((resolve, reject) => {
17 fetch(`${url}/${API_VERSION}/${route}`, { 16 try {
18 method, 17 fetch(`${url}/${API_VERSION}/${route}`, {
19 headers: { 18 method,
20 Authorization: `Bearer ${auth}`, 19 headers: {
21 'User-Agent': userAgent(), 20 Authorization: `Bearer ${auth}`,
22 }, 21 'User-Agent': userAgent(),
23 }) 22 },
24 .then(data => data.json()) 23 })
25 .then(json => resolve(json)); 24 .then(data => data.json())
26 } catch (e) { 25 .then(json => resolve(json));
27 reject(); 26 } catch {
28 } 27 reject();
29}); 28 }
29 });
30 30
31const LOGIN_SUCCESS_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJGZXJkaSBJbnRlcm5hbCBTZXJ2ZXIiLCJpYXQiOjE1NzEwNDAyMTUsImV4cCI6MjUzMzk1NDE3ODQ0LCJhdWQiOiJnZXRmZXJkaS5jb20iLCJzdWIiOiJmZXJkaUBsb2NhbGhvc3QiLCJ1c2VySWQiOiIxIn0.9_TWFGp6HROv8Yg82Rt6i1-95jqWym40a-HmgrdMC6M'; 31const LOGIN_SUCCESS_TOKEN =
32 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJGZXJkaSBJbnRlcm5hbCBTZXJ2ZXIiLCJpYXQiOjE1NzEwNDAyMTUsImV4cCI6MjUzMzk1NDE3ODQ0LCJhdWQiOiJnZXRmZXJkaS5jb20iLCJzdWIiOiJmZXJkaUBsb2NhbGhvc3QiLCJ1c2VySWQiOiIxIn0.9_TWFGp6HROv8Yg82Rt6i1-95jqWym40a-HmgrdMC6M';
32 33
33const DEFAULT_USER_DATA = { 34const DEFAULT_USER_DATA = {
34 accountType: 'individual', 35 accountType: 'individual',
@@ -45,10 +46,7 @@ const DEFAULT_USER_DATA = {
45 46
46class UserController { 47class UserController {
47 // Register a new user 48 // Register a new user
48 async signup({ 49 async signup({ request, response }) {
49 request,
50 response,
51 }) {
52 // Validate user input 50 // Validate user input
53 const validation = await validateAll(request.all(), { 51 const validation = await validateAll(request.all(), {
54 firstname: 'required', 52 firstname: 'required',
@@ -70,10 +68,7 @@ class UserController {
70 } 68 }
71 69
72 // Login using an existing user 70 // Login using an existing user
73 async login({ 71 async login({ request, response }) {
74 request,
75 response,
76 }) {
77 if (!request.header('Authorization')) { 72 if (!request.header('Authorization')) {
78 return response.status(401).send({ 73 return response.status(401).send({
79 message: 'Please provide authorization', 74 message: 'Please provide authorization',
@@ -88,23 +83,21 @@ class UserController {
88 } 83 }
89 84
90 // Return information about the current user 85 // Return information about the current user
91 async me({ 86 async me({ response }) {
92 response,
93 }) {
94 const user = await User.find(1); 87 const user = await User.find(1);
95 88
96 const settings = typeof user.settings === 'string' ? JSON.parse(user.settings) : user.settings; 89 const settings =
90 typeof user.settings === 'string'
91 ? JSON.parse(user.settings)
92 : user.settings;
97 93
98 return response.send({ 94 return response.send({
99 ...DEFAULT_USER_DATA, 95 ...DEFAULT_USER_DATA,
100 ...settings || {}, 96 ...settings,
101 }); 97 });
102 } 98 }
103 99
104 async updateMe({ 100 async updateMe({ request, response }) {
105 request,
106 response,
107 }) {
108 const user = await User.find(1); 101 const user = await User.find(1);
109 102
110 let settings = user.settings || {}; 103 let settings = user.settings || {};
@@ -125,16 +118,11 @@ class UserController {
125 ...DEFAULT_USER_DATA, 118 ...DEFAULT_USER_DATA,
126 ...newSettings, 119 ...newSettings,
127 }, 120 },
128 status: [ 121 status: ['data-updated'],
129 'data-updated',
130 ],
131 }); 122 });
132 } 123 }
133 124
134 async import({ 125 async import({ request, response }) {
135 request,
136 response,
137 }) {
138 // Validate user input 126 // Validate user input
139 const validation = await validateAll(request.all(), { 127 const validation = await validateAll(request.all(), {
140 email: 'required|email', 128 email: 'required|email',
@@ -142,7 +130,8 @@ class UserController {
142 server: 'required', 130 server: 'required',
143 }); 131 });
144 if (validation.fails()) { 132 if (validation.fails()) {
145 let errorMessage = 'There was an error while trying to import your account:\n'; 133 let errorMessage =
134 'There was an error while trying to import your account:\n';
146 for (const message of validation.messages()) { 135 for (const message of validation.messages()) {
147 if (message.validation === 'required') { 136 if (message.validation === 'required') {
148 errorMessage += `- Please make sure to supply your ${message.field}\n`; 137 errorMessage += `- Please make sure to supply your ${message.field}\n`;
@@ -155,13 +144,12 @@ class UserController {
155 return response.status(401).send(errorMessage); 144 return response.status(401).send(errorMessage);
156 } 145 }
157 146
158 const { 147 const { email, password, server } = request.all();
159 email,
160 password,
161 server,
162 } = request.all();
163 148
164 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); 149 const hashedPassword = crypto
150 .createHash('sha256')
151 .update(password)
152 .digest('base64');
165 153
166 // Try to get an authentication token 154 // Try to get an authentication token
167 let token; 155 let token;
@@ -178,16 +166,17 @@ class UserController {
178 const content = await rawResponse.json(); 166 const content = await rawResponse.json();
179 167
180 if (!content.message || content.message !== 'Successfully logged in') { 168 if (!content.message || content.message !== 'Successfully logged in') {
181 const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again'; 169 const errorMessage =
170 'Could not login into Franz with your supplied credentials. Please check and try again';
182 return response.status(401).send(errorMessage); 171 return response.status(401).send(errorMessage);
183 } 172 }
184 173
185 // eslint-disable-next-line prefer-destructuring 174 // eslint-disable-next-line prefer-destructuring
186 token = content.token; 175 token = content.token;
187 } catch (e) { 176 } catch (error) {
188 return response.status(401).send({ 177 return response.status(401).send({
189 message: 'Cannot login to Franz', 178 message: 'Cannot login to Franz',
190 error: e, 179 error,
191 }); 180 });
192 } 181 }
193 182
@@ -195,12 +184,13 @@ class UserController {
195 let userInf = false; 184 let userInf = false;
196 try { 185 try {
197 userInf = await apiRequest(server, 'me', 'GET', token); 186 userInf = await apiRequest(server, 'me', 'GET', token);
198 } catch (e) { 187 } catch (error) {
199 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${e}`; 188 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${error}`;
200 return response.status(401).send(errorMessage); 189 return response.status(401).send(errorMessage);
201 } 190 }
202 if (!userInf) { 191 if (!userInf) {
203 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later'; 192 const errorMessage =
193 'Could not get your user info from Franz. Please check your credentials or try again later';
204 return response.status(401).send(errorMessage); 194 return response.status(401).send(errorMessage);
205 } 195 }
206 196
@@ -213,8 +203,8 @@ class UserController {
213 for (const service of services) { 203 for (const service of services) {
214 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop 204 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop
215 } 205 }
216 } catch (e) { 206 } catch (error) {
217 const errorMessage = `Could not import your services into our system.\nError: ${e}`; 207 const errorMessage = `Could not import your services into our system.\nError: ${error}`;
218 return response.status(401).send(errorMessage); 208 return response.status(401).send(errorMessage);
219 } 209 }
220 210
@@ -225,12 +215,14 @@ class UserController {
225 for (const workspace of workspaces) { 215 for (const workspace of workspaces) {
226 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop 216 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop
227 } 217 }
228 } catch (e) { 218 } catch (error) {
229 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; 219 const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`;
230 return response.status(401).send(errorMessage); 220 return response.status(401).send(errorMessage);
231 } 221 }
232 222
233 return response.send('Your account has been imported. You can now use your Franz account in Ferdi.'); 223 return response.send(
224 'Your account has been imported. You can now use your Franz account in Ferdi.',
225 );
234 } 226 }
235 227
236 // Account import/export 228 // Account import/export
@@ -255,10 +247,7 @@ class UserController {
255 .send(exportData); 247 .send(exportData);
256 } 248 }
257 249
258 async importFerdi({ 250 async importFerdi({ request, response }) {
259 request,
260 response,
261 }) {
262 const validation = await validateAll(request.all(), { 251 const validation = await validateAll(request.all(), {
263 file: 'required', 252 file: 'required',
264 }); 253 });
@@ -269,8 +258,10 @@ class UserController {
269 let file; 258 let file;
270 try { 259 try {
271 file = JSON.parse(request.input('file')); 260 file = JSON.parse(request.input('file'));
272 } catch (e) { 261 } catch {
273 return response.send('Could not import: Invalid file, could not read file'); 262 return response.send(
263 'Could not import: Invalid file, could not read file',
264 );
274 } 265 }
275 266
276 if (!file || !file.services || !file.workspaces) { 267 if (!file || !file.services || !file.workspaces) {
@@ -284,8 +275,8 @@ class UserController {
284 for (const service of file.services) { 275 for (const service of file.services) {
285 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop 276 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop
286 } 277 }
287 } catch (e) { 278 } catch (error) {
288 const errorMessage = `Could not import your services into our system.\nError: ${e}`; 279 const errorMessage = `Could not import your services into our system.\nError: ${error}`;
289 return response.send(errorMessage); 280 return response.send(errorMessage);
290 } 281 }
291 282
@@ -294,8 +285,8 @@ class UserController {
294 for (const workspace of file.workspaces) { 285 for (const workspace of file.workspaces) {
295 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop 286 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop
296 } 287 }
297 } catch (e) { 288 } catch (error) {
298 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; 289 const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`;
299 return response.status(401).send(errorMessage); 290 return response.status(401).send(errorMessage);
300 } 291 }
301 292
@@ -306,15 +297,29 @@ class UserController {
306 let newWorkspaceId; 297 let newWorkspaceId;
307 do { 298 do {
308 newWorkspaceId = uuid(); 299 newWorkspaceId = uuid();
309 } while ((await Workspace.query().where('workspaceId', newWorkspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 300 } while (
310 301 (await Workspace.query().where('workspaceId', newWorkspaceId).fetch())
311 if (workspace.services && typeof (workspace.services) === 'string' && workspace.services.length > 0) { 302 .rows.length > 0
303 ); // eslint-disable-line no-await-in-loop
304
305 if (
306 workspace.services &&
307 typeof workspace.services === 'string' &&
308 workspace.services.length > 0
309 ) {
312 workspace.services = JSON.parse(workspace.services); 310 workspace.services = JSON.parse(workspace.services);
313 } 311 }
314 const services = (workspace.services && typeof (workspace.services) === 'object') ? 312 const services =
315 workspace.services.map(oldServiceId => serviceIdTranslation[oldServiceId]) : 313 workspace.services && typeof workspace.services === 'object'
316 []; 314 ? workspace.services.map(
317 if (workspace.data && typeof (workspace.data) === 'string' && workspace.data.length > 0) { 315 oldServiceId => serviceIdTranslation[oldServiceId],
316 )
317 : [];
318 if (
319 workspace.data &&
320 typeof workspace.data === 'string' &&
321 workspace.data.length > 0
322 ) {
318 workspace.data = JSON.parse(workspace.data); 323 workspace.data = JSON.parse(workspace.data);
319 } 324 }
320 325
@@ -332,12 +337,19 @@ class UserController {
332 let newServiceId; 337 let newServiceId;
333 do { 338 do {
334 newServiceId = uuid(); 339 newServiceId = uuid();
335 } while ((await Service.query().where('serviceId', newServiceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 340 } while (
341 (await Service.query().where('serviceId', newServiceId).fetch()).rows
342 .length > 0
343 ); // eslint-disable-line no-await-in-loop
336 344
337 // store the old serviceId as the key for future lookup 345 // store the old serviceId as the key for future lookup
338 serviceIdTranslation[service.serviceId] = newServiceId; 346 serviceIdTranslation[service.serviceId] = newServiceId;
339 347
340 if (service.settings && typeof (service.settings) === 'string' && service.settings.length > 0) { 348 if (
349 service.settings &&
350 typeof service.settings === 'string' &&
351 service.settings.length > 0
352 ) {
341 service.settings = JSON.parse(service.settings); 353 service.settings = JSON.parse(service.settings);
342 } 354 }
343 355
diff --git a/src/internal-server/app/Controllers/Http/WorkspaceController.js b/src/internal-server/app/Controllers/Http/WorkspaceController.js
index 773312a0b..9d461135e 100644
--- a/src/internal-server/app/Controllers/Http/WorkspaceController.js
+++ b/src/internal-server/app/Controllers/Http/WorkspaceController.js
@@ -1,16 +1,11 @@
1const Workspace = use('App/Models/Workspace'); 1const Workspace = use('App/Models/Workspace');
2const { 2const { validateAll } = use('Validator');
3 validateAll,
4} = use('Validator');
5 3
6const uuid = require('uuid/v4'); 4const { v4: uuid } = require('uuid');
7 5
8class WorkspaceController { 6class WorkspaceController {
9 // Create a new workspace for user 7 // Create a new workspace for user
10 async create({ 8 async create({ request, response }) {
11 request,
12 response,
13 }) {
14 // Validate user input 9 // Validate user input
15 const validation = await validateAll(request.all(), { 10 const validation = await validateAll(request.all(), {
16 name: 'required', 11 name: 'required',
@@ -29,10 +24,13 @@ class WorkspaceController {
29 let workspaceId; 24 let workspaceId;
30 do { 25 do {
31 workspaceId = uuid(); 26 workspaceId = uuid();
32 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 27 } while (
28 (await Workspace.query().where('workspaceId', workspaceId).fetch()).rows
29 .length > 0
30 ); // eslint-disable-line no-await-in-loop
33 31
34 const order = (await Workspace.all()).rows.length; 32 const order = (await Workspace.all()).rows.length;
35 const name = data.name; 33 const { name } = data;
36 delete data.name; 34 delete data.name;
37 35
38 await Workspace.create({ 36 await Workspace.create({
@@ -52,11 +50,7 @@ class WorkspaceController {
52 }); 50 });
53 } 51 }
54 52
55 async edit({ 53 async edit({ request, response, params }) {
56 request,
57 response,
58 params,
59 }) {
60 // Validate user input 54 // Validate user input
61 const validation = await validateAll(request.all(), { 55 const validation = await validateAll(request.all(), {
62 name: 'required', 56 name: 'required',
@@ -71,20 +65,19 @@ class WorkspaceController {
71 } 65 }
72 66
73 const data = request.all(); 67 const data = request.all();
74 const { 68 const { id } = params;
75 id,
76 } = params;
77 69
78 // Update data in database 70 // Update data in database
79 await (Workspace.query() 71 await Workspace.query()
80 .where('workspaceId', id)).update({ 72 .where('workspaceId', id)
81 name: data.name, 73 .update({
82 services: JSON.stringify(data.services), 74 name: data.name,
83 }); 75 services: JSON.stringify(data.services),
76 });
84 77
85 // Get updated row 78 // Get updated row
86 const workspace = (await Workspace.query() 79 const workspace = (await Workspace.query().where('workspaceId', id).fetch())
87 .where('workspaceId', id).fetch()).rows[0]; 80 .rows[0];
88 81
89 return response.send({ 82 return response.send({
90 id: workspace.workspaceId, 83 id: workspace.workspaceId,
@@ -113,13 +106,10 @@ class WorkspaceController {
113 }); 106 });
114 } 107 }
115 108
116 const { 109 const { id } = params;
117 id,
118 } = params;
119 110
120 // Update data in database 111 // Update data in database
121 await (Workspace.query() 112 await Workspace.query().where('workspaceId', id).delete();
122 .where('workspaceId', id)).delete();
123 113
124 return response.send({ 114 return response.send({
125 message: 'Successfully deleted workspace', 115 message: 'Successfully deleted workspace',
@@ -127,9 +117,7 @@ class WorkspaceController {
127 } 117 }
128 118
129 // List all workspaces a user has created 119 // List all workspaces a user has created
130 async list({ 120 async list({ response }) {
131 response,
132 }) {
133 const workspaces = (await Workspace.all()).rows; 121 const workspaces = (await Workspace.all()).rows;
134 // Convert to array with all data Franz wants 122 // Convert to array with all data Franz wants
135 let workspacesArray = []; 123 let workspacesArray = [];
@@ -138,7 +126,10 @@ class WorkspaceController {
138 id: workspace.workspaceId, 126 id: workspace.workspaceId,
139 name: workspace.name, 127 name: workspace.name,
140 order: workspace.order, 128 order: workspace.order,
141 services: typeof workspace.services === 'string' ? JSON.parse(workspace.services) : workspace.services, 129 services:
130 typeof workspace.services === 'string'
131 ? JSON.parse(workspace.services)
132 : workspace.services,
142 userId: 1, 133 userId: 1,
143 })); 134 }));
144 } 135 }
diff --git a/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js b/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js
index 87f1f6c25..9591cdc41 100644
--- a/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js
+++ b/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js
@@ -1,6 +1,6 @@
1class ConvertEmptyStringsToNull { 1class ConvertEmptyStringsToNull {
2 async handle({ request }, next) { 2 async handle({ request }, next) {
3 if (Object.keys(request.body).length) { 3 if (Object.keys(request.body).length > 0) {
4 request.body = Object.assign( 4 request.body = Object.assign(
5 ...Object.keys(request.body).map(key => ({ 5 ...Object.keys(request.body).map(key => ({
6 [key]: request.body[key] !== '' ? request.body[key] : null, 6 [key]: request.body[key] !== '' ? request.body[key] : null,
diff --git a/src/internal-server/app/Models/Recipe.js b/src/internal-server/app/Models/Recipe.js
index bd9741114..f9370e206 100644
--- a/src/internal-server/app/Models/Recipe.js
+++ b/src/internal-server/app/Models/Recipe.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Recipe extends Model { 4class Recipe extends Model {}
5}
6 5
7module.exports = Recipe; 6module.exports = Recipe;
diff --git a/src/internal-server/app/Models/Service.js b/src/internal-server/app/Models/Service.js
index a2e5c981e..95321686c 100644
--- a/src/internal-server/app/Models/Service.js
+++ b/src/internal-server/app/Models/Service.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Service extends Model { 4class Service extends Model {}
5}
6 5
7module.exports = Service; 6module.exports = Service;
diff --git a/src/internal-server/app/Models/Token.js b/src/internal-server/app/Models/Token.js
index 83e989117..1388b94ad 100644
--- a/src/internal-server/app/Models/Token.js
+++ b/src/internal-server/app/Models/Token.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Token extends Model { 4class Token extends Model {}
5}
6 5
7module.exports = Token; 6module.exports = Token;
diff --git a/src/internal-server/app/Models/User.js b/src/internal-server/app/Models/User.js
index 907710d8d..f17f04c3e 100644
--- a/src/internal-server/app/Models/User.js
+++ b/src/internal-server/app/Models/User.js
@@ -2,7 +2,6 @@
2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
3const Model = use('Model'); 3const Model = use('Model');
4 4
5class User extends Model { 5class User extends Model {}
6}
7 6
8module.exports = User; 7module.exports = User;
diff --git a/src/internal-server/app/Models/Workspace.js b/src/internal-server/app/Models/Workspace.js
index dcf39ac75..c47c02e37 100644
--- a/src/internal-server/app/Models/Workspace.js
+++ b/src/internal-server/app/Models/Workspace.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Workspace extends Model { 4class Workspace extends Model {}
5}
6 5
7module.exports = Workspace; 6module.exports = Workspace;
diff --git a/src/internal-server/config/shield.js b/src/internal-server/config/shield.js
index 76f430e91..4ff22c3f9 100644
--- a/src/internal-server/config/shield.js
+++ b/src/internal-server/config/shield.js
@@ -25,8 +25,7 @@ module.exports = {
25 | } 25 | }
26 | 26 |
27 */ 27 */
28 directives: { 28 directives: {},
29 },
30 /* 29 /*
31 |-------------------------------------------------------------------------- 30 |--------------------------------------------------------------------------
32 | Report only 31 | Report only
diff --git a/src/internal-server/public/js/transfer.js b/src/internal-server/public/js/transfer.js
index 8382bba02..36fdbd61a 100644
--- a/src/internal-server/public/js/transfer.js
+++ b/src/internal-server/public/js/transfer.js
@@ -1,13 +1,17 @@
1const submitBtn = document.getElementById('submit'); 1const submitBtn = document.querySelector('#submit');
2const fileInput = document.getElementById('file'); 2const fileInput = document.querySelector('#file');
3const fileOutput = document.getElementById('fileoutput'); 3const fileOutput = document.querySelector('#fileoutput');
4 4
5fileInput.addEventListener('change', () => { 5fileInput?.addEventListener('change', () => {
6 const reader = new FileReader(); 6 const reader = new FileReader();
7 reader.onload = () => { 7 reader.addEventListener('load', () => {
8 const text = reader.result; 8 const text = reader.result;
9 fileOutput.value = text; 9 if (fileOutput) {
10 submitBtn.disabled = false; 10 fileOutput.value = text;
11 }; 11 }
12 if (submitBtn) {
13 submitBtn.disabled = false;
14 }
15 });
12 reader.readAsText(fileInput.files[0]); 16 reader.readAsText(fileInput.files[0]);
13}); 17});
diff --git a/src/internal-server/start.js b/src/internal-server/start.ts
index 5ccc1330e..392f7cf41 100644
--- a/src/internal-server/start.js
+++ b/src/internal-server/start.ts
@@ -15,16 +15,16 @@
15| Make sure to pass a relative path from the project root. 15| Make sure to pass a relative path from the project root.
16*/ 16*/
17 17
18const fold = require('@adonisjs/fold'); 18import fold from '@adonisjs/fold';
19const { Ignitor } = require('@adonisjs/ignitor'); 19import { Ignitor } from '@adonisjs/ignitor';
20const fs = require('fs-extra'); 20import fs from 'fs-extra';
21const path = require('path'); 21import path from 'path';
22const { LOCAL_HOSTNAME } = require('../config'); 22import { LOCAL_HOSTNAME } from '../config';
23const { isWindows } = require('../environment'); 23import { isWindows } from '../environment';
24 24
25process.env.ENV_PATH = path.join(__dirname, 'env.ini'); 25process.env.ENV_PATH = path.join(__dirname, 'env.ini');
26 26
27module.exports = async (userPath, port) => { 27export const server = async (userPath: string, port: number) => {
28 const dbPath = path.join(userPath, 'server.sqlite'); 28 const dbPath = path.join(userPath, 'server.sqlite');
29 const dbTemplatePath = path.join(__dirname, 'database', 'template.sqlite'); 29 const dbTemplatePath = path.join(__dirname, 'database', 'template.sqlite');
30 30
@@ -45,7 +45,7 @@ module.exports = async (userPath, port) => {
45 process.env.DB_PATH = dbPath; 45 process.env.DB_PATH = dbPath;
46 process.env.USER_PATH = userPath; 46 process.env.USER_PATH = userPath;
47 process.env.HOST = LOCAL_HOSTNAME; 47 process.env.HOST = LOCAL_HOSTNAME;
48 process.env.PORT = port; 48 process.env.PORT = port.toString();
49 49
50 new Ignitor(fold).appRoot(__dirname).fireHttpServer().catch(console.error); // eslint-disable-line no-console 50 new Ignitor(fold).appRoot(__dirname).fireHttpServer().catch(console.error);
51}; 51};
diff --git a/src/internal-server/start/kernel.js b/src/internal-server/start/kernel.js
index 7b540f829..f72e445f2 100644
--- a/src/internal-server/start/kernel.js
+++ b/src/internal-server/start/kernel.js
@@ -32,8 +32,7 @@ const globalMiddleware = [
32| Route.get().middleware('auth') 32| Route.get().middleware('auth')
33| 33|
34*/ 34*/
35const namedMiddleware = { 35const namedMiddleware = {};
36};
37 36
38/* 37/*
39|-------------------------------------------------------------------------- 38|--------------------------------------------------------------------------
@@ -45,11 +44,8 @@ const namedMiddleware = {
45| control over request lifecycle. 44| control over request lifecycle.
46| 45|
47*/ 46*/
48const serverMiddleware = [ 47const serverMiddleware = ['Adonis/Middleware/Static'];
49 'Adonis/Middleware/Static',
50];
51 48
52Server 49Server.registerGlobal(globalMiddleware)
53 .registerGlobal(globalMiddleware)
54 .registerNamed(namedMiddleware) 50 .registerNamed(namedMiddleware)
55 .use(serverMiddleware); 51 .use(serverMiddleware);
diff --git a/src/internal-server/start/migrate.js b/src/internal-server/start/migrate.js
index c27e07bc5..97cefcc54 100644
--- a/src/internal-server/start/migrate.js
+++ b/src/internal-server/start/migrate.js
@@ -1,4 +1,4 @@
1const { ferdiVersion } = require('../../environment'); 1const { ferdiVersion } = require('../../environment-remote');
2 2
3/** 3/**
4 * Migrate server database to work with current Ferdi version 4 * Migrate server database to work with current Ferdi version
@@ -6,29 +6,39 @@ const { ferdiVersion } = require('../../environment');
6const Database = use('Database'); 6const Database = use('Database');
7const User = use('App/Models/User'); 7const User = use('App/Models/User');
8 8
9const migrateLog = (text) => { 9const migrateLog = text => {
10 console.log('\x1b[36m%s\x1b[0m', 'Ferdi Migration:', '\x1b[0m', text); 10 console.log('\u001B[36m%s\u001B[0m', 'Ferdi Migration:', '\u001B[0m', text);
11}; 11};
12 12
13module.exports = async () => { 13module.exports = async () => {
14 migrateLog('🧙†Running database migration wizard'); 14 migrateLog('🧙†Running database migration wizard');
15 15
16 // Make sure user table exists 16 // Make sure user table exists
17 await Database.raw('CREATE TABLE IF NOT EXISTS `users` (`id` integer not null primary key autoincrement, `settings` text, `created_at` datetime, `updated_at` datetime);'); 17 await Database.raw(
18 'CREATE TABLE IF NOT EXISTS `users` (`id` integer not null primary key autoincrement, `settings` text, `created_at` datetime, `updated_at` datetime);',
19 );
18 20
19 const user = await User.find(1); 21 const user = await User.find(1);
20 let settings; 22 let settings;
21 if (!user) { 23 if (!user) {
22 migrateLog('🎩 Migrating from old Ferdi version as user doesn\'t exist'); 24 migrateLog("🎩 Migrating from old Ferdi version as user doesn't exist");
23 25
24 // Create new user 26 // Create new user
25 await Database.raw('INSERT INTO "users" ("id") VALUES (\'1\');'); 27 await Database.raw('INSERT INTO "users" ("id") VALUES (\'1\');');
26 } else { 28 } else {
27 settings = typeof user.settings === 'string' ? JSON.parse(user.settings) : user.settings; 29 settings =
30 typeof user.settings === 'string'
31 ? JSON.parse(user.settings)
32 : user.settings;
28 } 33 }
29 34
30 if (!settings || !settings.db_version || settings.db_version !== ferdiVersion) { 35 if (
31 const srcVersion = settings && settings.db_version ? settings.db_version : '5.4.0-beta.2'; 36 !settings ||
37 !settings.db_version ||
38 settings.db_version !== ferdiVersion
39 ) {
40 const srcVersion =
41 settings && settings.db_version ? settings.db_version : '5.4.0-beta.2';
32 migrateLog(`🔮 Migrating table from ${srcVersion} to ${ferdiVersion}`); 42 migrateLog(`🔮 Migrating table from ${srcVersion} to ${ferdiVersion}`);
33 43
34 // Migrate database to current Ferdi version 44 // Migrate database to current Ferdi version
diff --git a/src/internal-server/start/routes.js b/src/internal-server/start/routes.js
index e75380ccd..db74479c9 100644
--- a/src/internal-server/start/routes.js
+++ b/src/internal-server/start/routes.js
@@ -8,7 +8,7 @@
8/** @type {typeof import('@adonisjs/framework/src/Route/Manager')} */ 8/** @type {typeof import('@adonisjs/framework/src/Route/Manager')} */
9const Route = use('Route'); 9const Route = use('Route');
10 10
11const { API_VERSION } = require('../../environment'); 11const { API_VERSION } = require('../../environment-remote');
12// Run latest database migration 12// Run latest database migration
13const migrate = require('./migrate'); 13const migrate = require('./migrate');
14 14
diff --git a/src/internal-server/test.js b/src/internal-server/test.js
deleted file mode 100644
index 8d4807d06..000000000
--- a/src/internal-server/test.js
+++ /dev/null
@@ -1,9 +0,0 @@
1const path = require('path');
2const fs = require('fs-extra');
3const server = require('./start');
4
5const dummyUserFolder = path.join(__dirname, 'user_data');
6
7fs.ensureDirSync(dummyUserFolder);
8
9server(dummyUserFolder, 45568);
diff --git a/src/internal-server/test.ts b/src/internal-server/test.ts
new file mode 100644
index 000000000..437a2813b
--- /dev/null
+++ b/src/internal-server/test.ts
@@ -0,0 +1,9 @@
1import path from 'path';
2import fs from 'fs-extra';
3import { server } from './start';
4
5const dummyUserFolder = path.join(__dirname, 'user_data');
6
7fs.ensureDirSync(dummyUserFolder);
8
9server(dummyUserFolder, 45_568);
diff --git a/src/lib/DBus.js b/src/lib/DBus.ts
index 9baaea014..b1febc2d1 100644
--- a/src/lib/DBus.js
+++ b/src/lib/DBus.ts
@@ -1,10 +1,12 @@
1import { sessionBus } from 'dbus-next'; 1import { MessageBus, sessionBus } from 'dbus-next';
2import { isLinux } from '../environment'; 2import { isLinux } from '../environment';
3 3
4export default class DBus { 4export default class DBus {
5 bus = null; 5 bus: MessageBus | null = null;
6 6
7 constructor(trayIcon) { 7 trayIcon: any;
8
9 constructor(trayIcon: any) {
8 this.trayIcon = trayIcon; 10 this.trayIcon = trayIcon;
9 } 11 }
10 12
@@ -19,15 +21,23 @@ export default class DBus {
19 } 21 }
20 22
21 // HACK Hook onto the MessageBus to track StatusNotifierWatchers 23 // HACK Hook onto the MessageBus to track StatusNotifierWatchers
22 this.bus._addMatch("type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',path='/org/freedesktop/DBus',member='NameOwnerChanged'"); 24 // @ts-expect-error Property '_addMatch' does not exist on type 'MessageBus'.
25 this.bus._addMatch(
26 "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',path='/org/freedesktop/DBus',member='NameOwnerChanged'",
27 );
23 const mangled = JSON.stringify({ 28 const mangled = JSON.stringify({
24 path: '/org/freedesktop/DBus', 29 path: '/org/freedesktop/DBus',
25 interface: 'org.freedesktop.DBus', 30 interface: 'org.freedesktop.DBus',
26 member: 'NameOwnerChanged', 31 member: 'NameOwnerChanged',
27 }); 32 });
28 this.bus._signals.on(mangled, (msg) => { 33 // @ts-expect-error Property '_signals' does not exist on type 'MessageBus'.
34 this.bus._signals.on(mangled, (msg: { body: [any, any, any] }) => {
29 const [name, oldOwner, newOwner] = msg.body; 35 const [name, oldOwner, newOwner] = msg.body;
30 if (name === 'org.kde.StatusNotifierWatcher' && oldOwner !== newOwner && newOwner !== '') { 36 if (
37 name === 'org.kde.StatusNotifierWatcher' &&
38 oldOwner !== newOwner &&
39 newOwner !== ''
40 ) {
31 // Leave ample time for the StatusNotifierWatcher to be initialized 41 // Leave ample time for the StatusNotifierWatcher to be initialized
32 setTimeout(() => { 42 setTimeout(() => {
33 this.trayIcon.recreateIfVisible(); 43 this.trayIcon.recreateIfVisible();
diff --git a/src/lib/Form.js b/src/lib/Form.ts
index 9b8321948..9b8321948 100644
--- a/src/lib/Form.js
+++ b/src/lib/Form.ts
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index 5dae56544..cd86f1669 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -1,5 +1,5 @@
1import { clipboard } from 'electron'; 1import { clipboard } from 'electron';
2import { app, Menu, systemPreferences } from '@electron/remote'; 2import { app, Menu, dialog, systemPreferences } from '@electron/remote';
3import { autorun, observable } from 'mobx'; 3import { autorun, observable } from 'mobx';
4import { defineMessages } from 'react-intl'; 4import { defineMessages } from 'react-intl';
5import { 5import {
@@ -20,6 +20,7 @@ import {
20 addNewServiceShortcutKey, 20 addNewServiceShortcutKey,
21 muteFerdiShortcutKey, 21 muteFerdiShortcutKey,
22} from '../environment'; 22} from '../environment';
23import { aboutAppDetails } from '../environment-remote';
23import { todosStore } from '../features/todos'; 24import { todosStore } from '../features/todos';
24import { todoActions } from '../features/todos/actions'; 25import { todoActions } from '../features/todos/actions';
25import { workspaceActions } from '../features/workspaces/actions'; 26import { workspaceActions } from '../features/workspaces/actions';
@@ -31,284 +32,283 @@ import globalMessages from '../i18n/globalMessages';
31const menuItems = defineMessages({ 32const menuItems = defineMessages({
32 edit: { 33 edit: {
33 id: 'menu.edit', 34 id: 'menu.edit',
34 defaultMessage: '!!!Edit', 35 defaultMessage: 'Edit',
35 }, 36 },
36 undo: { 37 undo: {
37 id: 'menu.edit.undo', 38 id: 'menu.edit.undo',
38 defaultMessage: '!!!Undo', 39 defaultMessage: 'Undo',
39 }, 40 },
40 redo: { 41 redo: {
41 id: 'menu.edit.redo', 42 id: 'menu.edit.redo',
42 defaultMessage: '!!!Redo', 43 defaultMessage: 'Redo',
43 }, 44 },
44 cut: { 45 cut: {
45 id: 'menu.edit.cut', 46 id: 'menu.edit.cut',
46 defaultMessage: '!!!Cut', 47 defaultMessage: 'Cut',
47 }, 48 },
48 copy: { 49 copy: {
49 id: 'menu.edit.copy', 50 id: 'menu.edit.copy',
50 defaultMessage: '!!!Copy', 51 defaultMessage: 'Copy',
51 }, 52 },
52 paste: { 53 paste: {
53 id: 'menu.edit.paste', 54 id: 'menu.edit.paste',
54 defaultMessage: '!!!Paste', 55 defaultMessage: 'Paste',
55 }, 56 },
56 pasteAndMatchStyle: { 57 pasteAndMatchStyle: {
57 id: 'menu.edit.pasteAndMatchStyle', 58 id: 'menu.edit.pasteAndMatchStyle',
58 defaultMessage: '!!!Paste And Match Style', 59 defaultMessage: 'Paste And Match Style',
59 }, 60 },
60 delete: { 61 delete: {
61 id: 'menu.edit.delete', 62 id: 'menu.edit.delete',
62 defaultMessage: '!!!Delete', 63 defaultMessage: 'Delete',
63 }, 64 },
64 selectAll: { 65 selectAll: {
65 id: 'menu.edit.selectAll', 66 id: 'menu.edit.selectAll',
66 defaultMessage: '!!!Select All', 67 defaultMessage: 'Select All',
67 }, 68 },
68 findInPage: { 69 findInPage: {
69 id: 'menu.edit.findInPage', 70 id: 'menu.edit.findInPage',
70 defaultMessage: '!!!Find in Page', 71 defaultMessage: 'Find in Page',
71 }, 72 },
72 speech: { 73 speech: {
73 id: 'menu.edit.speech', 74 id: 'menu.edit.speech',
74 defaultMessage: '!!!Speech', 75 defaultMessage: 'Speech',
75 }, 76 },
76 startSpeaking: { 77 startSpeaking: {
77 id: 'menu.edit.startSpeaking', 78 id: 'menu.edit.startSpeaking',
78 defaultMessage: '!!!Start Speaking', 79 defaultMessage: 'Start Speaking',
79 }, 80 },
80 stopSpeaking: { 81 stopSpeaking: {
81 id: 'menu.edit.stopSpeaking', 82 id: 'menu.edit.stopSpeaking',
82 defaultMessage: '!!!Stop Speaking', 83 defaultMessage: 'Stop Speaking',
83 }, 84 },
84 startDictation: { 85 startDictation: {
85 id: 'menu.edit.startDictation', 86 id: 'menu.edit.startDictation',
86 defaultMessage: '!!!Start Dictation', 87 defaultMessage: 'Start Dictation',
87 }, 88 },
88 emojiSymbols: { 89 emojiSymbols: {
89 id: 'menu.edit.emojiSymbols', 90 id: 'menu.edit.emojiSymbols',
90 defaultMessage: '!!!Emoji & Symbols', 91 defaultMessage: 'Emoji & Symbols',
91 }, 92 },
92 openQuickSwitch: { 93 openQuickSwitch: {
93 id: 'menu.view.openQuickSwitch', 94 id: 'menu.view.openQuickSwitch',
94 defaultMessage: '!!!Open Quick Switch', 95 defaultMessage: 'Open Quick Switch',
95 }, 96 },
96 back: { 97 back: {
97 id: 'menu.view.back', 98 id: 'menu.view.back',
98 defaultMessage: '!!!Back', 99 defaultMessage: 'Back',
99 }, 100 },
100 forward: { 101 forward: {
101 id: 'menu.view.forward', 102 id: 'menu.view.forward',
102 defaultMessage: '!!!Forward', 103 defaultMessage: 'Forward',
103 }, 104 },
104 resetZoom: { 105 resetZoom: {
105 id: 'menu.view.resetZoom', 106 id: 'menu.view.resetZoom',
106 defaultMessage: '!!!Actual Size', 107 defaultMessage: 'Actual Size',
107 }, 108 },
108 zoomIn: { 109 zoomIn: {
109 id: 'menu.view.zoomIn', 110 id: 'menu.view.zoomIn',
110 defaultMessage: '!!!Zoom In', 111 defaultMessage: 'Zoom In',
111 }, 112 },
112 zoomOut: { 113 zoomOut: {
113 id: 'menu.view.zoomOut', 114 id: 'menu.view.zoomOut',
114 defaultMessage: '!!!Zoom Out', 115 defaultMessage: 'Zoom Out',
115 }, 116 },
116 toggleFullScreen: { 117 toggleFullScreen: {
117 id: 'menu.view.toggleFullScreen', 118 id: 'menu.view.toggleFullScreen',
118 defaultMessage: '!!!Toggle Full Screen', 119 defaultMessage: 'Toggle Full Screen',
119 }, 120 },
120 toggleDarkMode: { 121 toggleDarkMode: {
121 id: 'menu.view.toggleDarkMode', 122 id: 'menu.view.toggleDarkMode',
122 defaultMessage: '!!!Toggle Dark Mode', 123 defaultMessage: 'Toggle Dark Mode',
123 }, 124 },
124 toggleDevTools: { 125 toggleDevTools: {
125 id: 'menu.view.toggleDevTools', 126 id: 'menu.view.toggleDevTools',
126 defaultMessage: '!!!Toggle Developer Tools', 127 defaultMessage: 'Toggle Developer Tools',
127 }, 128 },
128 toggleTodosDevTools: { 129 toggleTodosDevTools: {
129 id: 'menu.view.toggleTodosDevTools', 130 id: 'menu.view.toggleTodosDevTools',
130 defaultMessage: '!!!Toggle Todos Developer Tools', 131 defaultMessage: 'Toggle Todos Developer Tools',
131 }, 132 },
132 toggleServiceDevTools: { 133 toggleServiceDevTools: {
133 id: 'menu.view.toggleServiceDevTools', 134 id: 'menu.view.toggleServiceDevTools',
134 defaultMessage: '!!!Toggle Service Developer Tools', 135 defaultMessage: 'Toggle Service Developer Tools',
135 }, 136 },
136 reloadService: { 137 reloadService: {
137 id: 'menu.view.reloadService', 138 id: 'menu.view.reloadService',
138 defaultMessage: '!!!Reload Service', 139 defaultMessage: 'Reload Service',
139 }, 140 },
140 reloadFerdi: { 141 reloadFerdi: {
141 id: 'menu.view.reloadFerdi', 142 id: 'menu.view.reloadFerdi',
142 defaultMessage: '!!!Reload Ferdi', 143 defaultMessage: 'Reload Ferdi',
143 }, 144 },
144 lockFerdi: { 145 lockFerdi: {
145 id: 'menu.view.lockFerdi', 146 id: 'menu.view.lockFerdi',
146 defaultMessage: '!!!Lock Ferdi', 147 defaultMessage: 'Lock Ferdi',
147 }, 148 },
148 reloadTodos: { 149 reloadTodos: {
149 id: 'menu.view.reloadTodos', 150 id: 'menu.view.reloadTodos',
150 defaultMessage: '!!!Reload ToDos', 151 defaultMessage: 'Reload ToDos',
151 }, 152 },
152 minimize: { 153 minimize: {
153 id: 'menu.window.minimize', 154 id: 'menu.window.minimize',
154 defaultMessage: '!!!Minimize', 155 defaultMessage: 'Minimize',
155 }, 156 },
156 close: { 157 close: {
157 id: 'menu.window.close', 158 id: 'menu.window.close',
158 defaultMessage: '!!!Close', 159 defaultMessage: 'Close',
159 }, 160 },
160 learnMore: { 161 learnMore: {
161 id: 'menu.help.learnMore', 162 id: 'menu.help.learnMore',
162 defaultMessage: '!!!Learn More', 163 defaultMessage: 'Learn More',
163 }, 164 },
164 changelog: { 165 changelog: {
165 id: 'menu.help.changelog', 166 id: 'menu.help.changelog',
166 defaultMessage: '!!!Changelog', 167 defaultMessage: 'Changelog',
167 }, 168 },
168 importExportData: { 169 importExportData: {
169 id: 'menu.help.importExportData', 170 id: 'menu.help.importExportData',
170 defaultMessage: '!!!Import/Export Configuration Data', 171 defaultMessage: 'Import/Export Configuration Data',
171 }, 172 },
172 support: { 173 support: {
173 id: 'menu.help.support', 174 id: 'menu.help.support',
174 defaultMessage: '!!!Support', 175 defaultMessage: 'Support',
175 }, 176 },
176 debugInfo: { 177 debugInfo: {
177 id: 'menu.help.debugInfo', 178 id: 'menu.help.debugInfo',
178 defaultMessage: '!!!Copy Debug Information', 179 defaultMessage: 'Copy Debug Information',
179 }, 180 },
180 publishDebugInfo: { 181 publishDebugInfo: {
181 id: 'menu.help.publishDebugInfo', 182 id: 'menu.help.publishDebugInfo',
182 defaultMessage: '!!!Publish Debug Information', 183 defaultMessage: 'Publish Debug Information',
183 }, 184 },
184 debugInfoCopiedHeadline: { 185 debugInfoCopiedHeadline: {
185 id: 'menu.help.debugInfoCopiedHeadline', 186 id: 'menu.help.debugInfoCopiedHeadline',
186 defaultMessage: '!!!Ferdi Debug Information', 187 defaultMessage: 'Ferdi Debug Information',
187 }, 188 },
188 debugInfoCopiedBody: { 189 debugInfoCopiedBody: {
189 id: 'menu.help.debugInfoCopiedBody', 190 id: 'menu.help.debugInfoCopiedBody',
190 defaultMessage: 191 defaultMessage: 'Your Debug Information has been copied to your clipboard.',
191 '!!!Your Debug Information has been copied to your clipboard.',
192 }, 192 },
193 touchId: { 193 touchId: {
194 id: 'locked.touchId', 194 id: 'locked.touchId',
195 defaultMessage: '!!!Unlock with Touch ID', 195 defaultMessage: 'Unlock with Touch ID',
196 }, 196 },
197 touchIdPrompt: { 197 touchIdPrompt: {
198 id: 'locked.touchIdPrompt', 198 id: 'locked.touchIdPrompt',
199 defaultMessage: '!!!unlock via Touch ID', 199 defaultMessage: 'unlock via Touch ID',
200 }, 200 },
201 tos: { 201 tos: {
202 id: 'menu.help.tos', 202 id: 'menu.help.tos',
203 defaultMessage: '!!!Terms of Service', 203 defaultMessage: 'Terms of Service',
204 }, 204 },
205 privacy: { 205 privacy: {
206 id: 'menu.help.privacy', 206 id: 'menu.help.privacy',
207 defaultMessage: '!!!Privacy Statement', 207 defaultMessage: 'Privacy Statement',
208 }, 208 },
209 file: { 209 file: {
210 id: 'menu.file', 210 id: 'menu.file',
211 defaultMessage: '!!!File', 211 defaultMessage: 'File',
212 }, 212 },
213 view: { 213 view: {
214 id: 'menu.view', 214 id: 'menu.view',
215 defaultMessage: '!!!View', 215 defaultMessage: 'View',
216 }, 216 },
217 services: { 217 services: {
218 id: 'menu.services', 218 id: 'menu.services',
219 defaultMessage: '!!!Services', 219 defaultMessage: 'Services',
220 }, 220 },
221 window: { 221 window: {
222 id: 'menu.window', 222 id: 'menu.window',
223 defaultMessage: '!!!Window', 223 defaultMessage: 'Window',
224 }, 224 },
225 help: { 225 help: {
226 id: 'menu.help', 226 id: 'menu.help',
227 defaultMessage: '!!!Help', 227 defaultMessage: 'Help',
228 }, 228 },
229 about: { 229 about: {
230 id: 'menu.app.about', 230 id: 'menu.app.about',
231 defaultMessage: '!!!About Ferdi', 231 defaultMessage: 'About Ferdi',
232 }, 232 },
233 checkForUpdates: { 233 checkForUpdates: {
234 id: 'menu.app.checkForUpdates', 234 id: 'menu.app.checkForUpdates',
235 defaultMessage: '!!!Check for updates', 235 defaultMessage: 'Check for updates',
236 }, 236 },
237 hide: { 237 hide: {
238 id: 'menu.app.hide', 238 id: 'menu.app.hide',
239 defaultMessage: '!!!Hide', 239 defaultMessage: 'Hide',
240 }, 240 },
241 hideOthers: { 241 hideOthers: {
242 id: 'menu.app.hideOthers', 242 id: 'menu.app.hideOthers',
243 defaultMessage: '!!!Hide Others', 243 defaultMessage: 'Hide Others',
244 }, 244 },
245 unhide: { 245 unhide: {
246 id: 'menu.app.unhide', 246 id: 'menu.app.unhide',
247 defaultMessage: '!!!Unhide', 247 defaultMessage: 'Unhide',
248 }, 248 },
249 autohideMenuBar: { 249 autohideMenuBar: {
250 id: 'menu.app.autohideMenuBar', 250 id: 'menu.app.autohideMenuBar',
251 defaultMessage: '!!!Auto-hide menu bar', 251 defaultMessage: 'Auto-hide menu bar',
252 }, 252 },
253 addNewService: { 253 addNewService: {
254 id: 'menu.services.addNewService', 254 id: 'menu.services.addNewService',
255 defaultMessage: '!!!Add New Service...', 255 defaultMessage: 'Add New Service...',
256 }, 256 },
257 addNewWorkspace: { 257 addNewWorkspace: {
258 id: 'menu.workspaces.addNewWorkspace', 258 id: 'menu.workspaces.addNewWorkspace',
259 defaultMessage: '!!!Add New Workspace...', 259 defaultMessage: 'Add New Workspace...',
260 }, 260 },
261 openWorkspaceDrawer: { 261 openWorkspaceDrawer: {
262 id: 'menu.workspaces.openWorkspaceDrawer', 262 id: 'menu.workspaces.openWorkspaceDrawer',
263 defaultMessage: '!!!Open workspace drawer', 263 defaultMessage: 'Open workspace drawer',
264 }, 264 },
265 closeWorkspaceDrawer: { 265 closeWorkspaceDrawer: {
266 id: 'menu.workspaces.closeWorkspaceDrawer', 266 id: 'menu.workspaces.closeWorkspaceDrawer',
267 defaultMessage: '!!!Close workspace drawer', 267 defaultMessage: 'Close workspace drawer',
268 }, 268 },
269 activateNextService: { 269 activateNextService: {
270 id: 'menu.services.setNextServiceActive', 270 id: 'menu.services.setNextServiceActive',
271 defaultMessage: '!!!Activate next service...', 271 defaultMessage: 'Activate next service',
272 }, 272 },
273 activatePreviousService: { 273 activatePreviousService: {
274 id: 'menu.services.activatePreviousService', 274 id: 'menu.services.activatePreviousService',
275 defaultMessage: '!!!Activate previous service...', 275 defaultMessage: 'Activate previous service',
276 }, 276 },
277 muteApp: { 277 muteApp: {
278 id: 'sidebar.muteApp', 278 id: 'sidebar.muteApp',
279 defaultMessage: '!!!Disable notifications & audio', 279 defaultMessage: 'Disable notifications & audio',
280 }, 280 },
281 unmuteApp: { 281 unmuteApp: {
282 id: 'sidebar.unmuteApp', 282 id: 'sidebar.unmuteApp',
283 defaultMessage: '!!!Enable notifications & audio', 283 defaultMessage: 'Enable notifications & audio',
284 }, 284 },
285 workspaces: { 285 workspaces: {
286 id: 'menu.workspaces', 286 id: 'menu.workspaces',
287 defaultMessage: '!!!Workspaces', 287 defaultMessage: 'Workspaces',
288 }, 288 },
289 defaultWorkspace: { 289 defaultWorkspace: {
290 id: 'menu.workspaces.defaultWorkspace', 290 id: 'menu.workspaces.defaultWorkspace',
291 defaultMessage: '!!!Default', 291 defaultMessage: 'All services',
292 }, 292 },
293 todos: { 293 todos: {
294 id: 'menu.todos', 294 id: 'menu.todos',
295 defaultMessage: '!!!Todos', 295 defaultMessage: 'Todos',
296 }, 296 },
297 openTodosDrawer: { 297 openTodosDrawer: {
298 id: 'menu.Todoss.openTodosDrawer', 298 id: 'menu.Todoss.openTodosDrawer',
299 defaultMessage: '!!!Open Todos drawer', 299 defaultMessage: 'Open Todos drawer',
300 }, 300 },
301 closeTodosDrawer: { 301 closeTodosDrawer: {
302 id: 'menu.Todoss.closeTodosDrawer', 302 id: 'menu.Todoss.closeTodosDrawer',
303 defaultMessage: '!!!Close Todos drawer', 303 defaultMessage: 'Close Todos drawer',
304 }, 304 },
305 enableTodos: { 305 enableTodos: {
306 id: 'menu.todos.enableTodos', 306 id: 'menu.todos.enableTodos',
307 defaultMessage: '!!!Enable Todos', 307 defaultMessage: 'Enable Todos',
308 }, 308 },
309 serviceGoHome: { 309 serviceGoHome: {
310 id: 'menu.services.goHome', 310 id: 'menu.services.goHome',
311 defaultMessage: '!!!Home', 311 defaultMessage: 'Home',
312 }, 312 },
313}); 313});
314 314
@@ -404,14 +404,14 @@ const _titleBarTemplateFactory = (intl, locked) => [
404 }, 404 },
405 { 405 {
406 label: intl.formatMessage(menuItems.back), 406 label: intl.formatMessage(menuItems.back),
407 accelerator: `${cmdOrCtrlShortcutKey()}+Left`, 407 accelerator: `${!isMac ? altKey() : cmdOrCtrlShortcutKey()}+Left`,
408 click() { 408 click() {
409 getActiveService().webview.goBack(); 409 getActiveService().webview.goBack();
410 }, 410 },
411 }, 411 },
412 { 412 {
413 label: intl.formatMessage(menuItems.forward), 413 label: intl.formatMessage(menuItems.forward),
414 accelerator: `${cmdOrCtrlShortcutKey()}+Right`, 414 accelerator: `${!isMac ? altKey() : cmdOrCtrlShortcutKey()}+Right`,
415 click() { 415 click() {
416 getActiveService().webview.goForward(); 416 getActiveService().webview.goForward();
417 }, 417 },
@@ -433,8 +433,7 @@ const _titleBarTemplateFactory = (intl, locked) => [
433 const activeService = getActiveService().webview; 433 const activeService = getActiveService().webview;
434 const level = activeService.getZoomLevel(); 434 const level = activeService.getZoomLevel();
435 435
436 // level 9 =~ +300% and setZoomLevel wouldnt zoom in further 436 activeService.setZoomLevel(level + 0.5);
437 if (level < 9) activeService.setZoomLevel(level + 1);
438 }, 437 },
439 }, 438 },
440 { 439 {
@@ -444,8 +443,7 @@ const _titleBarTemplateFactory = (intl, locked) => [
444 const activeService = getActiveService().webview; 443 const activeService = getActiveService().webview;
445 const level = activeService.getZoomLevel(); 444 const level = activeService.getZoomLevel();
446 445
447 // level -9 =~ -50% and setZoomLevel wouldnt zoom out further 446 activeService.setZoomLevel(level - 0.5);
448 if (level > -9) activeService.setZoomLevel(level - 1);
449 }, 447 },
450 }, 448 },
451 { 449 {
@@ -557,7 +555,7 @@ const _titleBarTemplateFactory = (intl, locked) => [
557 }, 555 },
558]; 556];
559 557
560export default class FranzMenu { 558class FranzMenu {
561 @observable currentTemplate = []; 559 @observable currentTemplate = [];
562 560
563 constructor(stores, actions) { 561 constructor(stores, actions) {
@@ -632,7 +630,7 @@ export default class FranzMenu {
632 }, 630 },
633 ); 631 );
634 632
635 if (this.stores.features.features.isTodosEnabled) { 633 if (this.stores.todos.isFeatureEnabledByUser) {
636 tpl[1].submenu.push({ 634 tpl[1].submenu.push({
637 label: intl.formatMessage(menuItems.toggleTodosDevTools), 635 label: intl.formatMessage(menuItems.toggleTodosDevTools),
638 accelerator: `${cmdOrCtrlShortcutKey()}+${shiftKey()}+${altKey()}+O`, 636 accelerator: `${cmdOrCtrlShortcutKey()}+${shiftKey()}+${altKey()}+O`,
@@ -805,7 +803,12 @@ export default class FranzMenu {
805 const about = { 803 const about = {
806 label: intl.formatMessage(menuItems.about), 804 label: intl.formatMessage(menuItems.about),
807 click: () => { 805 click: () => {
808 app.showAboutPanel(); 806 dialog.showMessageBox({
807 type: 'info',
808 title: 'Franz Ferdinand',
809 message: 'Ferdi',
810 detail: aboutAppDetails(),
811 });
809 }, 812 },
810 }; 813 };
811 814
@@ -947,7 +950,7 @@ export default class FranzMenu {
947 }, 950 },
948 ); 951 );
949 952
950 services.allDisplayed.forEach((service, i) => 953 for (const [i, service] of services.allDisplayed.entries()) {
951 menu.push({ 954 menu.push({
952 label: this._getServiceName(service), 955 label: this._getServiceName(service),
953 accelerator: i < 9 ? `${cmdOrCtrlShortcutKey()}+${i + 1}` : null, 956 accelerator: i < 9 ? `${cmdOrCtrlShortcutKey()}+${i + 1}` : null,
@@ -960,8 +963,8 @@ export default class FranzMenu {
960 app.mainWindow.restore(); 963 app.mainWindow.restore();
961 } 964 }
962 }, 965 },
963 }), 966 });
964 ); 967 }
965 968
966 if ( 969 if (
967 services.active && 970 services.active &&
@@ -1013,23 +1016,23 @@ export default class FranzMenu {
1013 }); 1016 });
1014 } 1017 }
1015 1018
1016 menu.push({ 1019 menu.push(
1017 type: 'separator', 1020 {
1018 }); 1021 type: 'separator',
1019
1020 // Default workspace
1021 menu.push({
1022 label: intl.formatMessage(menuItems.defaultWorkspace),
1023 accelerator: `${cmdOrCtrlShortcutKey()}+${altKey()}+0`,
1024 type: 'radio',
1025 checked: !activeWorkspace,
1026 click: () => {
1027 workspaceActions.deactivate();
1028 }, 1022 },
1029 }); 1023 {
1024 label: intl.formatMessage(menuItems.defaultWorkspace),
1025 accelerator: `${cmdOrCtrlShortcutKey()}+${altKey()}+0`,
1026 type: 'radio',
1027 checked: !activeWorkspace,
1028 click: () => {
1029 workspaceActions.deactivate();
1030 },
1031 },
1032 );
1030 1033
1031 // Workspace items 1034 // Workspace items
1032 workspaces.forEach((workspace, i) => 1035 for (const [i, workspace] of workspaces.entries()) {
1033 menu.push({ 1036 menu.push({
1034 label: workspace.name, 1037 label: workspace.name,
1035 accelerator: 1038 accelerator:
@@ -1039,8 +1042,8 @@ export default class FranzMenu {
1039 click: () => { 1042 click: () => {
1040 workspaceActions.activate({ workspace }); 1043 workspaceActions.activate({ workspace });
1041 }, 1044 },
1042 }), 1045 });
1043 ); 1046 }
1044 1047
1045 return menu; 1048 return menu;
1046 } 1049 }
@@ -1126,3 +1129,5 @@ export default class FranzMenu {
1126 return name; 1129 return name;
1127 } 1130 }
1128} 1131}
1132
1133export default FranzMenu;
diff --git a/src/lib/TouchBar.js b/src/lib/TouchBar.ts
index 3397afdb2..417e20411 100644
--- a/src/lib/TouchBar.js
+++ b/src/lib/TouchBar.ts
@@ -5,7 +5,13 @@ import { autorun } from 'mobx';
5import { isMac, osRelease } from '../environment'; 5import { isMac, osRelease } from '../environment';
6 6
7export default class FranzTouchBar { 7export default class FranzTouchBar {
8 constructor(stores, actions) { 8 stores: any;
9
10 actions: any;
11
12 build: any;
13
14 constructor(stores: any, actions: any) {
9 this.stores = stores; 15 this.stores = stores;
10 this.actions = actions; 16 this.actions = actions;
11 17
@@ -15,8 +21,8 @@ export default class FranzTouchBar {
15 if (isMac && semver.gt(osRelease, '16.6.0')) { 21 if (isMac && semver.gt(osRelease, '16.6.0')) {
16 this.build = autorun(this._build.bind(this)); 22 this.build = autorun(this._build.bind(this));
17 } 23 }
18 } catch (err) { 24 } catch (error) {
19 console.error(err); 25 console.error(error);
20 } 26 }
21 } 27 }
22 28
@@ -26,19 +32,26 @@ export default class FranzTouchBar {
26 if (this.stores.user.isLoggedIn) { 32 if (this.stores.user.isLoggedIn) {
27 const { TouchBarButton, TouchBarSpacer } = TouchBar; 33 const { TouchBarButton, TouchBarSpacer } = TouchBar;
28 34
29 const buttons = []; 35 const buttons: any[] = [];
30 this.stores.services.allDisplayed.forEach(((service) => { 36 for (const service of this.stores.services.allDisplayed) {
31 buttons.push(new TouchBarButton({ 37 buttons.push(
32 label: `${service.name}${service.unreadDirectMessageCount > 0 38 new TouchBarButton({
33 ? ' 🔴' : ''} ${service.unreadDirectMessageCount === 0 39 label: `${service.name}${
34 && service.unreadIndirectMessageCount > 0 40 service.unreadDirectMessageCount > 0 ? ' 🔴' : ''
35 ? ' ⚪ï¸' : ''}`, 41 } ${
36 backgroundColor: service.isActive ? '#3498DB' : null, 42 service.unreadDirectMessageCount === 0 &&
37 click: () => { 43 service.unreadIndirectMessageCount > 0
38 this.actions.service.setActive({ serviceId: service.id }); 44 ? ' ⚪ï¸'
39 }, 45 : ''
40 }), new TouchBarSpacer({ size: 'small' })); 46 }`,
41 })); 47 backgroundColor: service.isActive && '#3498DB',
48 click: () => {
49 this.actions.service.setActive({ serviceId: service.id });
50 },
51 }),
52 new TouchBarSpacer({ size: 'small' }),
53 );
54 }
42 55
43 const touchBar = new TouchBar({ items: buttons }); 56 const touchBar = new TouchBar({ items: buttons });
44 currentWindow.setTouchBar(touchBar); 57 currentWindow.setTouchBar(touchBar);
diff --git a/src/models/News.ts b/src/models/News.ts
index a6ff86dda..4fc21f590 100644
--- a/src/models/News.ts
+++ b/src/models/News.ts
@@ -1,5 +1,3 @@
1// @flow
2
3import { ifUndefinedString, ifUndefinedBoolean } from '../jsUtils'; 1import { ifUndefinedString, ifUndefinedBoolean } from '../jsUtils';
4 2
5interface INews { 3interface INews {
@@ -20,11 +18,11 @@ export default class News {
20 18
21 constructor(data: INews) { 19 constructor(data: INews) {
22 if (!data) { 20 if (!data) {
23 throw Error('News config not valid'); 21 throw new Error('News config not valid');
24 } 22 }
25 23
26 if (!data.id) { 24 if (!data.id) {
27 throw Error('News requires Id'); 25 throw new Error('News requires Id');
28 } 26 }
29 27
30 this.id = data.id; 28 this.id = data.id;
diff --git a/src/models/Recipe.ts b/src/models/Recipe.ts
index 0a93fbc5a..859c75df0 100644
--- a/src/models/Recipe.ts
+++ b/src/models/Recipe.ts
@@ -1,6 +1,10 @@
1import semver from 'semver'; 1import semver from 'semver';
2import { pathExistsSync } from 'fs-extra'; 2import { pathExistsSync } from 'fs-extra';
3import { join } from 'path'; 3import { join } from 'path';
4import {
5 ifUndefinedString,
6 ifUndefinedBoolean,
7} from '../jsUtils';
4 8
5interface IRecipe { 9interface IRecipe {
6 id: string; 10 id: string;
@@ -22,11 +26,25 @@ interface IRecipe {
22 autoHibernate?: boolean; 26 autoHibernate?: boolean;
23 partition?: string; 27 partition?: string;
24 message?: string; 28 message?: string;
29 allowFavoritesDelineationInUnreadCount?: boolean;
25 }; 30 };
26} 31}
27 32
33// Note: Do NOT change these default values. If they change, then the corresponding changes in the recipes needs to be done
34// TODO: Need to reconcile other properties
35const DEFAULT_RECIPE_SETTINGS = {
36 hasDirectMessages: true,
37 hasIndirectMessages: false,
38 hasNotificationSound: false,
39 hasTeamId: false,
40 hasCustomUrl: false,
41 hasHostedOption: false,
42 allowFavoritesDelineationInUnreadCount: false,
43 disablewebsecurity: false,
44 autoHibernate: false,
45};
46
28export default class Recipe { 47export default class Recipe {
29 // Note: Do NOT change these default values. If they change, then the corresponding changes in the recipes needs to be done
30 id: string = ''; 48 id: string = '';
31 49
32 name: string = ''; 50 name: string = '';
@@ -37,21 +55,19 @@ export default class Recipe {
37 55
38 aliases: string[] = []; 56 aliases: string[] = [];
39 57
40 path: string = '';
41
42 serviceURL: string = ''; 58 serviceURL: string = '';
43 59
44 hasDirectMessages: boolean = true; 60 hasDirectMessages: boolean = DEFAULT_RECIPE_SETTINGS.hasDirectMessages;
45 61
46 hasIndirectMessages: boolean = false; 62 hasIndirectMessages: boolean = DEFAULT_RECIPE_SETTINGS.hasIndirectMessages;
47 63
48 hasNotificationSound: boolean = false; 64 hasNotificationSound: boolean = DEFAULT_RECIPE_SETTINGS.hasNotificationSound;
49 65
50 hasTeamId: boolean = false; 66 hasTeamId: boolean = DEFAULT_RECIPE_SETTINGS.hasTeamId;
51 67
52 hasCustomUrl: boolean = false; 68 hasCustomUrl: boolean = DEFAULT_RECIPE_SETTINGS.hasCustomUrl;
53 69
54 hasHostedOption: boolean = false; 70 hasHostedOption: boolean = DEFAULT_RECIPE_SETTINGS.hasHostedOption;
55 71
56 urlInputPrefix: string = ''; 72 urlInputPrefix: string = '';
57 73
@@ -59,52 +75,54 @@ export default class Recipe {
59 75
60 message: string = ''; 76 message: string = '';
61 77
62 disablewebsecurity: boolean = false; 78 allowFavoritesDelineationInUnreadCount: boolean = DEFAULT_RECIPE_SETTINGS.allowFavoritesDelineationInUnreadCount;
79
80 disablewebsecurity: boolean = DEFAULT_RECIPE_SETTINGS.disablewebsecurity;
63 81
64 autoHibernate: boolean = false; 82 // TODO: Is this even used?
83 autoHibernate: boolean = DEFAULT_RECIPE_SETTINGS.autoHibernate;
84
85 path: string = '';
65 86
66 partition: string = ''; 87 partition: string = '';
67 88
68 // TODO: Need to reconcile which of these are optional/mandatory 89 // TODO: Need to reconcile which of these are optional/mandatory
69 constructor(data: IRecipe) { 90 constructor(data: IRecipe) {
70 if (!data) { 91 if (!data) {
71 throw Error('Recipe config not valid'); 92 throw new Error('Recipe config not valid');
72 } 93 }
73 94
74 if (!data.id) { 95 if (!data.id) {
75 // Ferdi 4 recipes do not have an Id 96 // Ferdi 4 recipes do not have an Id
76 throw Error(`Recipe '${data.name}' requires Id`); 97 throw new Error(`Recipe '${data.name}' requires Id`);
77 } 98 }
78 99
79 if (!semver.valid(data.version)) { 100 if (!semver.valid(data.version)) {
80 throw Error(`Version ${data.version} of recipe '${data.name}' is not a valid semver version`); 101 throw new Error(`Version ${data.version} of recipe '${data.name}' is not a valid semver version`);
81 } 102 }
82 103
83 this.id = data.id || this.id; 104 // from the recipe
84 this.name = data.name || this.name; 105 this.id = ifUndefinedString(data.id, this.id);
85 this.version = data.version || this.version; 106 this.name = ifUndefinedString(data.name, this.name);
107 this.version = ifUndefinedString(data.version, this.version);
86 this.aliases = data.aliases || this.aliases; 108 this.aliases = data.aliases || this.aliases;
109 this.serviceURL = ifUndefinedString(data.config.serviceURL, this.serviceURL);
110 this.hasDirectMessages = ifUndefinedBoolean(data.config.hasDirectMessages, this.hasDirectMessages);
111 this.hasIndirectMessages = ifUndefinedBoolean(data.config.hasIndirectMessages, this.hasIndirectMessages);
112 this.hasNotificationSound = ifUndefinedBoolean(data.config.hasNotificationSound, this.hasNotificationSound);
113 this.hasTeamId = ifUndefinedBoolean(data.config.hasTeamId, this.hasTeamId);
114 this.hasCustomUrl = ifUndefinedBoolean(data.config.hasCustomUrl, this.hasCustomUrl);
115 this.hasHostedOption = ifUndefinedBoolean(data.config.hasHostedOption, this.hasHostedOption);
116 this.urlInputPrefix = ifUndefinedString(data.config.urlInputPrefix, this.urlInputPrefix);
117 this.urlInputSuffix = ifUndefinedString(data.config.urlInputSuffix, this.urlInputSuffix);
118 this.disablewebsecurity = ifUndefinedBoolean(data.config.disablewebsecurity, this.disablewebsecurity);
119 this.autoHibernate = ifUndefinedBoolean(data.config.autoHibernate, this.autoHibernate);
120 this.message = ifUndefinedString(data.config.message, this.message);
121 this.allowFavoritesDelineationInUnreadCount = ifUndefinedBoolean(data.config.allowFavoritesDelineationInUnreadCount, this.allowFavoritesDelineationInUnreadCount);
122
123 // computed
87 this.path = data.path; 124 this.path = data.path;
88 125 this.partition = ifUndefinedString(data.config.partition, this.partition);
89 this.serviceURL = data.config.serviceURL || this.serviceURL;
90
91 this.hasDirectMessages = data.config.hasDirectMessages || this.hasDirectMessages;
92 this.hasIndirectMessages = data.config.hasIndirectMessages || this.hasIndirectMessages;
93 this.hasNotificationSound = data.config.hasNotificationSound || this.hasNotificationSound;
94 this.hasTeamId = data.config.hasTeamId || this.hasTeamId;
95 this.hasCustomUrl = data.config.hasCustomUrl || this.hasCustomUrl;
96 this.hasHostedOption = data.config.hasHostedOption || this.hasHostedOption;
97
98 this.urlInputPrefix = data.config.urlInputPrefix || this.urlInputPrefix;
99 this.urlInputSuffix = data.config.urlInputSuffix || this.urlInputSuffix;
100
101 this.disablewebsecurity = data.config.disablewebsecurity || this.disablewebsecurity;
102
103 this.autoHibernate = data.config.autoHibernate || this.autoHibernate;
104
105 this.partition = data.config.partition || this.partition;
106
107 this.message = data.config.message || this.message;
108 } 126 }
109 127
110 // TODO: Need to remove this if its not used anywhere 128 // TODO: Need to remove this if its not used anywhere
diff --git a/src/models/RecipePreview.ts b/src/models/RecipePreview.ts
index 4d2cc8450..fb8cb3e3e 100644
--- a/src/models/RecipePreview.ts
+++ b/src/models/RecipePreview.ts
@@ -1,5 +1,3 @@
1// @flow
2
3interface IRecipePreview { 1interface IRecipePreview {
4 id: string; 2 id: string;
5 name: string; 3 name: string;
@@ -21,11 +19,11 @@ export default class RecipePreview {
21 19
22 constructor(data: IRecipePreview) { 20 constructor(data: IRecipePreview) {
23 if (!data) { 21 if (!data) {
24 throw Error('RecipePreview config not valid'); 22 throw new Error('RecipePreview config not valid');
25 } 23 }
26 24
27 if (!data.id) { 25 if (!data.id) {
28 throw Error(`RecipePreview '${data.name}' requires Id`); 26 throw new Error(`RecipePreview '${data.name}' requires Id`);
29 } 27 }
30 28
31 Object.assign(this, data); 29 Object.assign(this, data);
diff --git a/src/models/Service.js b/src/models/Service.js
index 4ee054b2b..75dfde027 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -8,7 +8,11 @@ import { todosStore } from '../features/todos';
8import { isValidExternalURL } from '../helpers/url-helpers'; 8import { isValidExternalURL } from '../helpers/url-helpers';
9import UserAgent from './UserAgent'; 9import UserAgent from './UserAgent';
10import { DEFAULT_SERVICE_ORDER } from '../config'; 10import { DEFAULT_SERVICE_ORDER } from '../config';
11import { ifUndefinedString, ifUndefinedBoolean, ifUndefinedNumber } from '../jsUtils'; 11import {
12 ifUndefinedString,
13 ifUndefinedBoolean,
14 ifUndefinedNumber,
15} from '../jsUtils';
12 16
13const debug = require('debug')('Ferdi:Service'); 17const debug = require('debug')('Ferdi:Service');
14 18
@@ -79,6 +83,8 @@ export default class Service {
79 83
80 @observable isHibernationRequested = false; 84 @observable isHibernationRequested = false;
81 85
86 @observable onlyShowFavoritesInUnreadCount = false;
87
82 @observable lastUsed = Date.now(); // timestamp 88 @observable lastUsed = Date.now(); // timestamp
83 89
84 @observable lastHibernated = null; // timestamp 90 @observable lastHibernated = null; // timestamp
@@ -95,11 +101,11 @@ export default class Service {
95 101
96 constructor(data, recipe) { 102 constructor(data, recipe) {
97 if (!data) { 103 if (!data) {
98 throw Error('Service config not valid'); 104 throw new Error('Service config not valid');
99 } 105 }
100 106
101 if (!recipe) { 107 if (!recipe) {
102 throw Error('Service recipe not valid'); 108 throw new Error('Service recipe not valid');
103 } 109 }
104 110
105 this.recipe = recipe; 111 this.recipe = recipe;
@@ -115,22 +121,55 @@ export default class Service {
115 121
116 this.order = ifUndefinedNumber(data.order, this.order); 122 this.order = ifUndefinedNumber(data.order, this.order);
117 this.isEnabled = ifUndefinedBoolean(data.isEnabled, this.isEnabled); 123 this.isEnabled = ifUndefinedBoolean(data.isEnabled, this.isEnabled);
118 this.isNotificationEnabled = ifUndefinedBoolean(data.isNotificationEnabled, this.isNotificationEnabled); 124 this.isNotificationEnabled = ifUndefinedBoolean(
119 this.isBadgeEnabled = ifUndefinedBoolean(data.isBadgeEnabled, this.isBadgeEnabled); 125 data.isNotificationEnabled,
120 this.isIndirectMessageBadgeEnabled = ifUndefinedBoolean(data.isIndirectMessageBadgeEnabled, this.isIndirectMessageBadgeEnabled); 126 this.isNotificationEnabled,
127 );
128 this.isBadgeEnabled = ifUndefinedBoolean(
129 data.isBadgeEnabled,
130 this.isBadgeEnabled,
131 );
132 this.isIndirectMessageBadgeEnabled = ifUndefinedBoolean(
133 data.isIndirectMessageBadgeEnabled,
134 this.isIndirectMessageBadgeEnabled,
135 );
121 this.isMuted = ifUndefinedBoolean(data.isMuted, this.isMuted); 136 this.isMuted = ifUndefinedBoolean(data.isMuted, this.isMuted);
122 this.isDarkModeEnabled = ifUndefinedBoolean(data.isDarkModeEnabled, this.isDarkModeEnabled); 137 this.isDarkModeEnabled = ifUndefinedBoolean(
123 this.darkReaderSettings = ifUndefinedString(data.darkReaderSettings, this.darkReaderSettings); 138 data.isDarkModeEnabled,
124 this.hasCustomUploadedIcon = ifUndefinedBoolean(data.hasCustomIcon, this.hasCustomUploadedIcon); 139 this.isDarkModeEnabled,
140 );
141 this.darkReaderSettings = ifUndefinedString(
142 data.darkReaderSettings,
143 this.darkReaderSettings,
144 );
145 this.hasCustomUploadedIcon = ifUndefinedBoolean(
146 data.hasCustomIcon,
147 this.hasCustomUploadedIcon,
148 );
149 this.onlyShowFavoritesInUnreadCount = ifUndefinedBoolean(
150 data.onlyShowFavoritesInUnreadCount,
151 this.onlyShowFavoritesInUnreadCount,
152 );
125 this.proxy = ifUndefinedString(data.proxy, this.proxy); 153 this.proxy = ifUndefinedString(data.proxy, this.proxy);
126 this.spellcheckerLanguage = ifUndefinedString(data.spellcheckerLanguage, this.spellcheckerLanguage); 154 this.spellcheckerLanguage = ifUndefinedString(
127 this.userAgentPref = ifUndefinedString(data.userAgentPref, this.userAgentPref); 155 data.spellcheckerLanguage,
128 this.isHibernationEnabled = ifUndefinedBoolean(data.isHibernationEnabled, this.isHibernationEnabled); 156 this.spellcheckerLanguage,
157 );
158 this.userAgentPref = ifUndefinedString(
159 data.userAgentPref,
160 this.userAgentPref,
161 );
162 this.isHibernationEnabled = ifUndefinedBoolean(
163 data.isHibernationEnabled,
164 this.isHibernationEnabled,
165 );
129 166
130 // Check if "Hibernate on Startup" is enabled and hibernate all services except active one 167 // Check if "Hibernate on Startup" is enabled and hibernate all services except active one
131 const { hibernateOnStartup } = window.ferdi.stores.settings.app; 168 const { hibernateOnStartup } = window.ferdi.stores.settings.app;
132 // The service store is probably not loaded yet so we need to use localStorage data to get active service 169 // The service store is probably not loaded yet so we need to use localStorage data to get active service
133 const isActive = window.localStorage.service && JSON.parse(window.localStorage.service).activeService === this.id; 170 const isActive =
171 window.localStorage.service &&
172 JSON.parse(window.localStorage.service).activeService === this.id;
134 if (hibernateOnStartup && !isActive) { 173 if (hibernateOnStartup && !isActive) {
135 this.isHibernationRequested = true; 174 this.isHibernationRequested = true;
136 } 175 }
@@ -158,6 +197,7 @@ export default class Service {
158 team: this.team, 197 team: this.team,
159 url: this.url, 198 url: this.url,
160 hasCustomIcon: this.hasCustomIcon, 199 hasCustomIcon: this.hasCustomIcon,
200 onlyShowFavoritesInUnreadCount: this.onlyShowFavoritesInUnreadCount,
161 }; 201 };
162 } 202 }
163 203
@@ -189,9 +229,14 @@ export default class Service {
189 if (this.recipe.hasCustomUrl && this.customUrl) { 229 if (this.recipe.hasCustomUrl && this.customUrl) {
190 let url; 230 let url;
191 try { 231 try {
192 url = normalizeUrl(this.customUrl, { stripWWW: false, removeTrailingSlash: false }); 232 url = normalizeUrl(this.customUrl, {
193 } catch (err) { 233 stripWWW: false,
194 console.error(`Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`); 234 removeTrailingSlash: false,
235 });
236 } catch {
237 console.error(
238 `Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`,
239 );
195 } 240 }
196 241
197 if (typeof this.recipe.buildUrl === 'function') { 242 if (typeof this.recipe.buildUrl === 'function') {
@@ -241,7 +286,9 @@ export default class Service {
241 } 286 }
242 287
243 initializeWebViewEvents({ handleIPCMessage, openWindow, stores }) { 288 initializeWebViewEvents({ handleIPCMessage, openWindow, stores }) {
244 const webviewWebContents = webContents.fromId(this.webview.getWebContentsId()); 289 const webviewWebContents = webContents.fromId(
290 this.webview.getWebContentsId(),
291 );
245 292
246 this.userAgentModel.setWebviewReference(this.webview); 293 this.userAgentModel.setWebviewReference(this.webview);
247 294
@@ -270,9 +317,15 @@ export default class Service {
270 debug(this.name, 'knownCertificateHosts is not defined in the recipe'); 317 debug(this.name, 'knownCertificateHosts is not defined in the recipe');
271 } 318 }
272 319
273 this.webview.addEventListener('ipc-message', async (e) => { 320 this.webview.addEventListener('ipc-message', async e => {
274 if (e.channel === 'inject-js-unsafe') { 321 if (e.channel === 'inject-js-unsafe') {
275 await Promise.all(e.args.map((script) => this.webview.executeJavaScript(`"use strict"; (() => { ${script} })();`))); 322 await Promise.all(
323 e.args.map(script =>
324 this.webview.executeJavaScript(
325 `"use strict"; (() => { ${script} })();`,
326 ),
327 ),
328 );
276 } else { 329 } else {
277 handleIPCMessage({ 330 handleIPCMessage({
278 serviceId: this.id, 331 serviceId: this.id,
@@ -282,27 +335,33 @@ export default class Service {
282 } 335 }
283 }); 336 });
284 337
285 this.webview.addEventListener('new-window', (event, url, frameName, options) => { 338 this.webview.addEventListener(
286 debug('new-window', event, url, frameName, options); 339 'new-window',
287 if (!isValidExternalURL(event.url)) { 340 (event, url, frameName, options) => {
288 return; 341 debug('new-window', event, url, frameName, options);
289 } 342 if (!isValidExternalURL(event.url)) {
290 if (event.disposition === 'foreground-tab' || event.disposition === 'background-tab') { 343 return;
291 openWindow({ 344 }
292 event, 345 if (
293 url, 346 event.disposition === 'foreground-tab' ||
294 frameName, 347 event.disposition === 'background-tab'
295 options, 348 ) {
296 }); 349 openWindow({
297 } else { 350 event,
298 ipcRenderer.send('open-browser-window', { 351 url,
299 url: event.url, 352 frameName,
300 serviceId: this.id, 353 options,
301 }); 354 });
302 } 355 } else {
303 }); 356 ipcRenderer.send('open-browser-window', {
357 url: event.url,
358 serviceId: this.id,
359 });
360 }
361 },
362 );
304 363
305 this.webview.addEventListener('did-start-loading', (event) => { 364 this.webview.addEventListener('did-start-loading', event => {
306 debug('Did start load', this.name, event); 365 debug('Did start load', this.name, event);
307 366
308 this.hasCrashed = false; 367 this.hasCrashed = false;
@@ -321,9 +380,13 @@ export default class Service {
321 this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this)); 380 this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this));
322 this.webview.addEventListener('did-navigate', didLoad.bind(this)); 381 this.webview.addEventListener('did-navigate', didLoad.bind(this));
323 382
324 this.webview.addEventListener('did-fail-load', (event) => { 383 this.webview.addEventListener('did-fail-load', event => {
325 debug('Service failed to load', this.name, event); 384 debug('Service failed to load', this.name, event);
326 if (event.isMainFrame && event.errorCode !== -21 && event.errorCode !== -3) { 385 if (
386 event.isMainFrame &&
387 event.errorCode !== -21 &&
388 event.errorCode !== -3
389 ) {
327 this.isError = true; 390 this.isError = true;
328 this.errorMessage = event.errorDescription; 391 this.errorMessage = event.errorDescription;
329 this.isLoading = false; 392 this.isLoading = false;
@@ -365,12 +428,12 @@ export default class Service {
365 428
366 initializeWebViewListener() { 429 initializeWebViewListener() {
367 if (this.webview && this.recipe.events) { 430 if (this.webview && this.recipe.events) {
368 Object.keys(this.recipe.events).forEach((eventName) => { 431 for (const eventName of Object.keys(this.recipe.events)) {
369 const eventHandler = this.recipe[this.recipe.events[eventName]]; 432 const eventHandler = this.recipe[this.recipe.events[eventName]];
370 if (typeof eventHandler === 'function') { 433 if (typeof eventHandler === 'function') {
371 this.webview.addEventListener(eventName, eventHandler); 434 this.webview.addEventListener(eventName, eventHandler);
372 } 435 }
373 }); 436 }
374 } 437 }
375 } 438 }
376 439
diff --git a/src/models/User.ts b/src/models/User.ts
index 54a6838df..a04d46d3c 100644
--- a/src/models/User.ts
+++ b/src/models/User.ts
@@ -43,11 +43,11 @@ export default class User {
43 43
44 constructor(data: IUser) { 44 constructor(data: IUser) {
45 if (!data) { 45 if (!data) {
46 throw Error('User config not valid'); 46 throw new Error('User config not valid');
47 } 47 }
48 48
49 if (!data.id) { 49 if (!data.id) {
50 throw Error('User requires Id'); 50 throw new Error('User requires Id');
51 } 51 }
52 52
53 this.id = data.id; 53 this.id = data.id;
diff --git a/src/models/UserAgent.js b/src/models/UserAgent.js
index 930ae19ef..33bf9d072 100644
--- a/src/models/UserAgent.js
+++ b/src/models/UserAgent.js
@@ -1,9 +1,4 @@
1import { 1import { action, computed, observe, observable } from 'mobx';
2 action,
3 computed,
4 observe,
5 observable,
6} from 'mobx';
7 2
8import defaultUserAgent from '../helpers/userAgent-helpers'; 3import defaultUserAgent from '../helpers/userAgent-helpers';
9 4
@@ -27,7 +22,7 @@ export default class UserAgent {
27 this.getUserAgent = overrideUserAgent; 22 this.getUserAgent = overrideUserAgent;
28 } 23 }
29 24
30 observe(this, 'webview', (change) => { 25 observe(this, 'webview', change => {
31 const { oldValue, newValue } = change; 26 const { oldValue, newValue } = change;
32 if (oldValue !== null) { 27 if (oldValue !== null) {
33 this._removeWebviewEvents(oldValue); 28 this._removeWebviewEvents(oldValue);
@@ -52,23 +47,24 @@ export default class UserAgent {
52 return defaultUserAgent(); 47 return defaultUserAgent();
53 } 48 }
54 49
55 @computed get userAgentWithChromeVersion() { 50 @computed get serviceUserAgentPref() {
56 if (typeof this.userAgentPref === 'string') { 51 if (typeof this.userAgentPref === 'string') {
57 const trimmed = this.userAgentPref.trim(); 52 const trimmed = this.userAgentPref.trim();
58 if (trimmed !== '') { 53 if (trimmed !== '') {
59 return trimmed; 54 return trimmed;
60 } 55 }
61 } 56 }
62 return this.defaultUserAgent; 57 return null;
63 } 58 }
64 59
65 @computed get userAgentWithoutChromeVersion() { 60 @computed get userAgentWithoutChromeVersion() {
66 const withChrome = this.userAgentWithChromeVersion; 61 const withChrome = this.defaultUserAgent;
67 return withChrome.replace(/Chrome\/[0-9.]+/, 'Chrome'); 62 return withChrome.replace(/Chrome\/[\d.]+/, 'Chrome');
68 } 63 }
69 64
70 @computed get userAgent() { 65 @computed get userAgent() {
71 return this.chromelessUserAgent ? this.userAgentWithoutChromeVersion : this.userAgentWithChromeVersion; 66 return this.serviceUserAgentPref
67 || (this.chromelessUserAgent ? this.userAgentWithoutChromeVersion : this.defaultUserAgent);
72 } 68 }
73 69
74 @action setWebviewReference(webview) { 70 @action setWebviewReference(webview) {
@@ -95,10 +91,10 @@ export default class UserAgent {
95 _addWebviewEvents(webview) { 91 _addWebviewEvents(webview) {
96 debug('Adding event handlers'); 92 debug('Adding event handlers');
97 93
98 this._willNavigateListener = (event) => this._handleNavigate(event.url, true); 94 this._willNavigateListener = event => this._handleNavigate(event.url, true);
99 webview.addEventListener('will-navigate', this._willNavigateListener); 95 webview.addEventListener('will-navigate', this._willNavigateListener);
100 96
101 this._didNavigateListener = (event) => this._handleNavigate(event.url); 97 this._didNavigateListener = event => this._handleNavigate(event.url);
102 webview.addEventListener('did-navigate', this._didNavigateListener); 98 webview.addEventListener('did-navigate', this._didNavigateListener);
103 } 99 }
104 100
diff --git a/src/prop-types.ts b/src/prop-types.ts
index 459b9a7b9..07607f105 100644
--- a/src/prop-types.ts
+++ b/src/prop-types.ts
@@ -1,6 +1,5 @@
1import PropTypes from 'prop-types'; 1import PropTypes from 'prop-types';
2 2
3// eslint-disable-next-line
4export const oneOrManyChildElements = PropTypes.oneOfType([ 3export const oneOrManyChildElements = PropTypes.oneOfType([
5 PropTypes.arrayOf(PropTypes.element), 4 PropTypes.arrayOf(PropTypes.element),
6 PropTypes.element, 5 PropTypes.element,
diff --git a/src/routes.js b/src/routes.js
index 4d32a59e0..502ea86f5 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -30,7 +30,6 @@ import { WORKSPACES_ROUTES } from './features/workspaces/constants';
30 30
31import SettingsStore from './stores/SettingsStore'; 31import SettingsStore from './stores/SettingsStore';
32 32
33export default
34@inject('stores', 'actions') 33@inject('stores', 'actions')
35@observer 34@observer
36class Routes extends Component { 35class Routes extends Component {
@@ -95,3 +94,5 @@ Routes.wrappedComponent.propTypes = {
95 }).isRequired, 94 }).isRequired,
96 history: PropTypes.any.isRequired, 95 history: PropTypes.any.isRequired,
97}; 96};
97
98export default Routes;
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index 469e7519e..3d9d2b551 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -16,16 +16,17 @@ import { readJsonSync } from 'fs-extra';
16 16
17import Store from './lib/Store'; 17import Store from './lib/Store';
18import Request from './lib/Request'; 18import Request from './lib/Request';
19import { CHECK_INTERVAL } from '../config'; 19import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config';
20import { 20import {
21 DEFAULT_APP_SETTINGS,
22 isMac, 21 isMac,
23 ferdiVersion,
24 electronVersion, 22 electronVersion,
25 osRelease, 23 osRelease,
24} from '../environment';
25import {
26 ferdiVersion,
26 userDataPath, 27 userDataPath,
27 ferdiLocale, 28 ferdiLocale,
28} from '../environment'; 29} from '../environment-remote';
29import locales from '../i18n/translations'; 30import locales from '../i18n/translations';
30import { getLocale } from '../helpers/i18n-helpers'; 31import { getLocale } from '../helpers/i18n-helpers';
31 32
@@ -251,16 +252,14 @@ export default class AppStore extends Store {
251 // macOS catalina notifications hack 252 // macOS catalina notifications hack
252 // notifications got stuck after upgrade but forcing a notification 253 // notifications got stuck after upgrade but forcing a notification
253 // via `new Notification` triggered the permission request 254 // via `new Notification` triggered the permission request
254 if (isMac) { 255 if (isMac && !localStorage.getItem(CATALINA_NOTIFICATION_HACK_KEY)) {
255 if (!localStorage.getItem(CATALINA_NOTIFICATION_HACK_KEY)) { 256 debug('Triggering macOS Catalina notification permission trigger');
256 debug('Triggering macOS Catalina notification permission trigger'); 257 // eslint-disable-next-line no-new
257 // eslint-disable-next-line no-new 258 new window.Notification('Welcome to Ferdi 5', {
258 new window.Notification('Welcome to Ferdi 5', { 259 body: 'Have a wonderful day & happy messaging.',
259 body: 'Have a wonderful day & happy messaging.', 260 });
260 });
261 261
262 localStorage.setItem(CATALINA_NOTIFICATION_HACK_KEY, true); 262 localStorage.setItem(CATALINA_NOTIFICATION_HACK_KEY, 'true');
263 }
264 } 263 }
265 } 264 }
266 265
@@ -325,7 +324,7 @@ export default class AppStore extends Store {
325 324
326 debug('New notification', title, options); 325 debug('New notification', title, options);
327 326
328 notification.onclick = () => { 327 notification.addEventListener('click', () => {
329 if (serviceId) { 328 if (serviceId) {
330 this.actions.service.sendIPCMessage({ 329 this.actions.service.sendIPCMessage({
331 channel: `notification-onclick:${notificationId}`, 330 channel: `notification-onclick:${notificationId}`,
@@ -346,7 +345,7 @@ export default class AppStore extends Store {
346 345
347 debug('Notification click handler'); 346 debug('Notification click handler');
348 } 347 }
349 }; 348 });
350 } 349 }
351 350
352 @action _setBadge({ unreadDirectMessageCount, unreadIndirectMessageCount }) { 351 @action _setBadge({ unreadDirectMessageCount, unreadIndirectMessageCount }) {
@@ -360,7 +359,7 @@ export default class AppStore extends Store {
360 ) { 359 ) {
361 indicator = 0; 360 indicator = 0;
362 } else { 361 } else {
363 indicator = parseInt(indicator, 10); 362 indicator = Number.parseInt(indicator, 10);
364 } 363 }
365 364
366 ipcRenderer.send('updateAppIndicator', { 365 ipcRenderer.send('updateAppIndicator', {
@@ -379,8 +378,8 @@ export default class AppStore extends Store {
379 debug('disabling launch on startup'); 378 debug('disabling launch on startup');
380 autoLauncher.disable(); 379 autoLauncher.disable();
381 } 380 }
382 } catch (err) { 381 } catch (error) {
383 console.warn(err); 382 console.warn(error);
384 } 383 }
385 } 384 }
386 385
@@ -438,7 +437,7 @@ export default class AppStore extends Store {
438 const allServiceIds = await getServiceIdsFromPartitions(); 437 const allServiceIds = await getServiceIdsFromPartitions();
439 const allOrphanedServiceIds = allServiceIds.filter( 438 const allOrphanedServiceIds = allServiceIds.filter(
440 id => 439 id =>
441 !this.stores.services.all.find( 440 !this.stores.services.all.some(
442 s => id.replace('service-', '') === s.id, 441 s => id.replace('service-', '') === s.id,
443 ), 442 ),
444 ); 443 );
@@ -447,8 +446,8 @@ export default class AppStore extends Store {
447 await Promise.all( 446 await Promise.all(
448 allOrphanedServiceIds.map(id => removeServicePartitionDirectory(id)), 447 allOrphanedServiceIds.map(id => removeServicePartitionDirectory(id)),
449 ); 448 );
450 } catch (ex) { 449 } catch (error) {
451 console.log('Error while deleting service partition directory - ', ex); 450 console.log('Error while deleting service partition directory -', error);
452 } 451 }
453 await Promise.all( 452 await Promise.all(
454 this.stores.services.all.map(s => 453 this.stores.services.all.map(s =>
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js
index 1d50dd714..8e0134d7f 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -51,7 +51,9 @@ export default class FeaturesStore extends Store {
51 let requestResult = {}; 51 let requestResult = {};
52 try { 52 try {
53 requestResult = this.featuresRequest.execute().result; 53 requestResult = this.featuresRequest.execute().result;
54 } catch (e) {} // eslint-disable-line no-empty 54 } catch (error) {
55 console.error(error);
56 }
55 Object.assign(features, requestResult); 57 Object.assign(features, requestResult);
56 } 58 }
57 runInAction('FeaturesStore::_updateFeatures', () => { 59 runInAction('FeaturesStore::_updateFeatures', () => {
@@ -69,15 +71,15 @@ export default class FeaturesStore extends Store {
69 } 71 }
70 72
71 _setupFeatures() { 73 _setupFeatures() {
72 serviceProxy(this.stores, this.actions); 74 serviceProxy(this.stores);
73 basicAuth(this.stores, this.actions); 75 basicAuth();
74 workspaces(this.stores, this.actions); 76 workspaces(this.stores, this.actions);
75 quickSwitch(this.stores, this.actions); 77 quickSwitch();
76 nightlyBuilds(this.stores, this.actions); 78 nightlyBuilds();
77 publishDebugInfo(this.stores, this.actions); 79 publishDebugInfo();
78 settingsWS(this.stores, this.actions); 80 settingsWS(this.stores, this.actions);
79 communityRecipes(this.stores, this.actions); 81 communityRecipes(this.stores, this.actions);
80 todos(this.stores, this.actions); 82 todos(this.stores, this.actions);
81 appearance(this.stores, this.actions); 83 appearance(this.stores);
82 } 84 }
83} 85}
diff --git a/src/stores/GlobalErrorStore.js b/src/stores/GlobalErrorStore.js
index aacaa247f..7cbfdc608 100644
--- a/src/stores/GlobalErrorStore.js
+++ b/src/stores/GlobalErrorStore.js
@@ -12,9 +12,9 @@ export default class GlobalErrorStore extends Store {
12 constructor(...args) { 12 constructor(...args) {
13 super(...args); 13 super(...args);
14 14
15 window.onerror = (...errorArgs) => { 15 window.addEventListener('error', (...errorArgs) => {
16 this._handleConsoleError.call(this, ['error', ...errorArgs]); 16 this._handleConsoleError.call(this, ['error', ...errorArgs]);
17 }; 17 });
18 18
19 const origConsoleError = console.error; 19 const origConsoleError = console.error;
20 window.console.error = (...errorArgs) => { 20 window.console.error = (...errorArgs) => {
@@ -38,7 +38,7 @@ export default class GlobalErrorStore extends Store {
38 } 38 }
39 39
40 _handleConsoleError(type, error, url, line) { 40 _handleConsoleError(type, error, url, line) {
41 if (typeof type === 'object' && type.length && type.length >= 1) { 41 if (typeof type === 'object' && type.length > 0) {
42 this.messages.push({ 42 this.messages.push({
43 type: type[0], 43 type: type[0],
44 info: type, 44 info: type,
@@ -53,14 +53,14 @@ export default class GlobalErrorStore extends Store {
53 } 53 }
54 } 54 }
55 55
56 _handleRequests = action(async (request) => { 56 _handleRequests = action(async request => {
57 if (request.isError) { 57 if (request.isError) {
58 this.error = request.error; 58 this.error = request.error;
59 59
60 if (request.error.json) { 60 if (request.error.json) {
61 try { 61 try {
62 this.response = await request.error.json(); 62 this.response = await request.error.json();
63 } catch (error) { 63 } catch {
64 this.response = {}; 64 this.response = {};
65 } 65 }
66 if (this.error.status === 401) { 66 if (this.error.status === 401) {
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js
index d2acebb75..95d662e79 100644
--- a/src/stores/RecipesStore.js
+++ b/src/stores/RecipesStore.js
@@ -6,7 +6,7 @@ import Store from './lib/Store';
6import CachedRequest from './lib/CachedRequest'; 6import CachedRequest from './lib/CachedRequest';
7import Request from './lib/Request'; 7import Request from './lib/Request';
8import { matchRoute } from '../helpers/routing-helpers'; 8import { matchRoute } from '../helpers/routing-helpers';
9import { asarRecipesPath } from '../environment'; 9import { asarRecipesPath } from '../helpers/asar-helpers';
10 10
11const debug = require('debug')('Ferdi:RecipeStore'); 11const debug = require('debug')('Ferdi:RecipeStore');
12 12
@@ -25,9 +25,7 @@ export default class RecipesStore extends Store {
25 this.actions.recipe.update.listen(this._update.bind(this)); 25 this.actions.recipe.update.listen(this._update.bind(this));
26 26
27 // Reactions 27 // Reactions
28 this.registerReactions([ 28 this.registerReactions([this._checkIfRecipeIsInstalled.bind(this)]);
29 this._checkIfRecipeIsInstalled.bind(this),
30 ]);
31 } 29 }
32 30
33 setup() { 31 setup() {
@@ -39,7 +37,10 @@ export default class RecipesStore extends Store {
39 } 37 }
40 38
41 @computed get active() { 39 @computed get active() {
42 const match = matchRoute('/settings/services/add/:id', this.stores.router.location.pathname); 40 const match = matchRoute(
41 '/settings/services/add/:id',
42 this.stores.router.location.pathname,
43 );
43 if (match) { 44 if (match) {
44 const activeRecipe = this.one(match.id); 45 const activeRecipe = this.one(match.id);
45 if (activeRecipe) { 46 if (activeRecipe) {
@@ -53,11 +54,11 @@ export default class RecipesStore extends Store {
53 } 54 }
54 55
55 @computed get recipeIdForServices() { 56 @computed get recipeIdForServices() {
56 return this.stores.services.all.map((s) => s.recipe.id); 57 return this.stores.services.all.map(s => s.recipe.id);
57 } 58 }
58 59
59 one(id) { 60 one(id) {
60 return this.all.find((recipe) => recipe.id === id); 61 return this.all.find(recipe => recipe.id === id);
61 } 62 }
62 63
63 isInstalled(id) { 64 isInstalled(id) {
@@ -77,41 +78,43 @@ export default class RecipesStore extends Store {
77 const recipes = {}; 78 const recipes = {};
78 79
79 // Hackfix, reference this.all to fetch services 80 // Hackfix, reference this.all to fetch services
80 debug(`Check Recipe updates for ${this.all.map((recipe) => recipe.id)}`); 81 debug(`Check Recipe updates for ${this.all.map(recipe => recipe.id)}`);
81 82
82 recipeIds.forEach((r) => { 83 for (const r of recipeIds) {
83 const recipe = this.one(r); 84 const recipe = this.one(r);
84 recipes[r] = recipe.version; 85 recipes[r] = recipe.version;
85 }); 86 }
86 87
87 if (Object.keys(recipes).length === 0) return; 88 if (Object.keys(recipes).length === 0) return;
88 89
89 const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise; 90 const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)
91 ._promise;
90 92
91 // Check for local updates 93 // Check for local updates
92 const allJsonFile = asarRecipesPath('all.json'); 94 const allJsonFile = asarRecipesPath('all.json');
93 const allJson = readJSONSync(allJsonFile); 95 const allJson = readJSONSync(allJsonFile);
94 const localUpdates = []; 96 const localUpdates = [];
95 97
96 Object.keys(recipes).forEach((recipe) => { 98 for (const recipe of Object.keys(recipes)) {
97 const version = recipes[recipe]; 99 const version = recipes[recipe];
98 100
99 // Find recipe in local recipe repository 101 // Find recipe in local recipe repository
100 const localRecipe = allJson.find((r) => r.id === recipe); 102 const localRecipe = allJson.find(r => r.id === recipe);
101 103
102 if (localRecipe && semver.lt(version, localRecipe.version)) { 104 if (localRecipe && semver.lt(version, localRecipe.version)) {
103 localUpdates.push(recipe); 105 localUpdates.push(recipe);
104 } 106 }
105 }); 107 }
106 108
107 const updates = [ 109 const updates = [...remoteUpdates, ...localUpdates];
108 ...remoteUpdates, 110 debug(
109 ...localUpdates, 111 'Got update information (local, remote):',
110 ]; 112 localUpdates,
111 debug('Got update information (local, remote):', localUpdates, remoteUpdates); 113 remoteUpdates,
114 );
112 115
113 const length = updates.length - 1; 116 const length = updates.length - 1;
114 const syncUpdate = async (i) => { 117 const syncUpdate = async i => {
115 const update = updates[i]; 118 const update = updates[i];
116 119
117 this.actions.recipe.install({ recipeId: update }); 120 this.actions.recipe.install({ recipeId: update });
@@ -134,7 +137,9 @@ export default class RecipesStore extends Store {
134 async _checkIfRecipeIsInstalled() { 137 async _checkIfRecipeIsInstalled() {
135 const { router } = this.stores; 138 const { router } = this.stores;
136 139
137 const match = router.location && matchRoute('/settings/services/add/:id', router.location.pathname); 140 const match =
141 router.location &&
142 matchRoute('/settings/services/add/:id', router.location.pathname);
138 if (match) { 143 if (match) {
139 const recipeId = match.id; 144 const recipeId = match.id;
140 145
@@ -142,9 +147,11 @@ export default class RecipesStore extends Store {
142 router.push('/settings/recipes'); 147 router.push('/settings/recipes');
143 debug(`Recipe ${recipeId} is not installed, trying to install it`); 148 debug(`Recipe ${recipeId} is not installed, trying to install it`);
144 149
145 const recipe = await this.installRecipeRequest.execute(recipeId)._promise; 150 const recipe = await this.installRecipeRequest.execute(recipeId)
151 ._promise;
146 if (recipe) { 152 if (recipe) {
147 await this.allRecipesRequest.invalidate({ immediately: true })._promise; 153 await this.allRecipesRequest.invalidate({ immediately: true })
154 ._promise;
148 router.push(`/settings/services/add/${recipeId}`); 155 router.push(`/settings/services/add/${recipeId}`);
149 } else { 156 } else {
150 router.push('/settings/recipes'); 157 router.push('/settings/recipes');
diff --git a/src/stores/RequestStore.js b/src/stores/RequestStore.js
index a92f4c685..6d2f2ef91 100644
--- a/src/stores/RequestStore.js
+++ b/src/stores/RequestStore.js
@@ -13,7 +13,7 @@ export default class RequestStore extends Store {
13 13
14 @observable showRequiredRequestsError = false; 14 @observable showRequiredRequestsError = false;
15 15
16 @observable localServerPort = 45569; 16 @observable localServerPort = 45_569;
17 17
18 retries = 0; 18 retries = 0;
19 19
@@ -22,11 +22,11 @@ export default class RequestStore extends Store {
22 constructor(...args) { 22 constructor(...args) {
23 super(...args); 23 super(...args);
24 24
25 this.actions.requests.retryRequiredRequests.listen(this._retryRequiredRequests.bind(this)); 25 this.actions.requests.retryRequiredRequests.listen(
26 this._retryRequiredRequests.bind(this),
27 );
26 28
27 this.registerReactions([ 29 this.registerReactions([this._autoRetry.bind(this)]);
28 this._autoRetry.bind(this),
29 ]);
30 } 30 }
31 31
32 setup() { 32 setup() {
@@ -41,13 +41,11 @@ export default class RequestStore extends Store {
41 } 41 }
42 42
43 @computed get areRequiredRequestsSuccessful() { 43 @computed get areRequiredRequestsSuccessful() {
44 return !this.userInfoRequest.isError 44 return !this.userInfoRequest.isError && !this.servicesRequest.isError;
45 && !this.servicesRequest.isError;
46 } 45 }
47 46
48 @computed get areRequiredRequestsLoading() { 47 @computed get areRequiredRequestsLoading() {
49 return this.userInfoRequest.isExecuting 48 return this.userInfoRequest.isExecuting || this.servicesRequest.isExecuting;
50 || this.servicesRequest.isExecuting;
51 } 49 }
52 50
53 @action _retryRequiredRequests() { 51 @action _retryRequiredRequests() {
@@ -67,7 +65,7 @@ export default class RequestStore extends Store {
67 } 65 }
68 66
69 this._autoRetry(); 67 this._autoRetry();
70 debug(`Retry required requests delayed in ${(delay) / 1000}s`); 68 debug(`Retry required requests delayed in ${delay / 1000}s`);
71 }, delay); 69 }, delay);
72 } 70 }
73 } 71 }
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index 75bc71388..ce6675866 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -10,11 +10,14 @@ import Request from './lib/Request';
10import CachedRequest from './lib/CachedRequest'; 10import CachedRequest from './lib/CachedRequest';
11import { matchRoute } from '../helpers/routing-helpers'; 11import { matchRoute } from '../helpers/routing-helpers';
12import { isInTimeframe } from '../helpers/schedule-helpers'; 12import { isInTimeframe } from '../helpers/schedule-helpers';
13import { getRecipeDirectory, getDevRecipeDirectory } from '../helpers/recipe-helpers'; 13import {
14 getRecipeDirectory,
15 getDevRecipeDirectory,
16} from '../helpers/recipe-helpers';
14import { workspaceStore } from '../features/workspaces'; 17import { workspaceStore } from '../features/workspaces';
15import { KEEP_WS_LOADED_USID } from '../config'; 18import { KEEP_WS_LOADED_USID } from '../config';
16import { SPELLCHECKER_LOCALES } from '../i18n/languages'; 19import { SPELLCHECKER_LOCALES } from '../i18n/languages';
17import { ferdiVersion } from '../environment'; 20import { ferdiVersion } from '../environment-remote';
18 21
19const debug = require('debug')('Ferdi:ServiceStore'); 22const debug = require('debug')('Ferdi:ServiceStore');
20 23
@@ -125,63 +128,56 @@ export default class ServicesStore extends Store {
125 setup() { 128 setup() {
126 // Single key reactions for the sake of your CPU 129 // Single key reactions for the sake of your CPU
127 reaction( 130 reaction(
128 () => ( 131 () => this.stores.settings.app.enableSpellchecking,
129 this.stores.settings.app.enableSpellchecking
130 ),
131 () => { 132 () => {
132 this._shareSettingsWithServiceProcess(); 133 this._shareSettingsWithServiceProcess();
133 }, 134 },
134 ); 135 );
135 136
136 reaction( 137 reaction(
137 () => ( 138 () => this.stores.settings.app.spellcheckerLanguage,
138 this.stores.settings.app.spellcheckerLanguage
139 ),
140 () => { 139 () => {
141 this._shareSettingsWithServiceProcess(); 140 this._shareSettingsWithServiceProcess();
142 }, 141 },
143 ); 142 );
144 143
145 reaction( 144 reaction(
146 () => ( 145 () => this.stores.settings.app.darkMode,
147 this.stores.settings.app.darkMode
148 ),
149 () => { 146 () => {
150 this._shareSettingsWithServiceProcess(); 147 this._shareSettingsWithServiceProcess();
151 }, 148 },
152 ); 149 );
153 150
154 reaction( 151 reaction(
155 () => ( 152 () => this.stores.settings.app.adaptableDarkMode,
156 this.stores.settings.app.adaptableDarkMode
157 ),
158 () => { 153 () => {
159 this._shareSettingsWithServiceProcess(); 154 this._shareSettingsWithServiceProcess();
160 }, 155 },
161 ); 156 );
162 157
163 reaction( 158 reaction(
164 () => ( 159 () => this.stores.settings.app.universalDarkMode,
165 this.stores.settings.app.universalDarkMode
166 ),
167 () => { 160 () => {
168 this._shareSettingsWithServiceProcess(); 161 this._shareSettingsWithServiceProcess();
169 }, 162 },
170 ); 163 );
171 164
172 reaction( 165 reaction(
173 () => ( 166 () => this.stores.settings.app.splitMode,
174 this.stores.settings.app.searchEngine
175 ),
176 () => { 167 () => {
177 this._shareSettingsWithServiceProcess(); 168 this._shareSettingsWithServiceProcess();
178 }, 169 },
179 ); 170 );
180 171
181 reaction( 172 reaction(
182 () => ( 173 () => this.stores.settings.app.searchEngine,
183 this.stores.settings.app.clipboardNotifications 174 () => {
184 ), 175 this._shareSettingsWithServiceProcess();
176 },
177 );
178
179 reaction(
180 () => this.stores.settings.app.clipboardNotifications,
185 () => { 181 () => {
186 this._shareSettingsWithServiceProcess(); 182 this._shareSettingsWithServiceProcess();
187 }, 183 },
@@ -215,12 +211,12 @@ export default class ServicesStore extends Store {
215 * Run various maintenance tasks on services 211 * Run various maintenance tasks on services
216 */ 212 */
217 _serviceMaintenance() { 213 _serviceMaintenance() {
218 this.enabled.forEach(service => { 214 for (const service of this.enabled) {
219 // Defines which services should be hibernated or woken up 215 // Defines which services should be hibernated or woken up
220 if (!service.isActive) { 216 if (!service.isActive) {
221 if ( 217 if (
222 !service.lastHibernated && 218 !service.lastHibernated &&
223 (Date.now() - service.lastUsed) > 219 Date.now() - service.lastUsed >
224 ms(`${this.stores.settings.all.app.hibernationStrategy}s`) 220 ms(`${this.stores.settings.all.app.hibernationStrategy}s`)
225 ) { 221 ) {
226 // If service is stale, hibernate it. 222 // If service is stale, hibernate it.
@@ -230,8 +226,8 @@ export default class ServicesStore extends Store {
230 if ( 226 if (
231 service.lastHibernated && 227 service.lastHibernated &&
232 Number(this.stores.settings.all.app.wakeUpStrategy) > 0 && 228 Number(this.stores.settings.all.app.wakeUpStrategy) > 0 &&
233 (Date.now() - service.lastHibernated) > 229 Date.now() - service.lastHibernated >
234 ms(`${this.stores.settings.all.app.wakeUpStrategy}s`) 230 ms(`${this.stores.settings.all.app.wakeUpStrategy}s`)
235 ) { 231 ) {
236 // If service is in hibernation and the wakeup time has elapsed, wake it. 232 // If service is in hibernation and the wakeup time has elapsed, wake it.
237 this._awake({ serviceId: service.id }); 233 this._awake({ serviceId: service.id });
@@ -240,7 +236,7 @@ export default class ServicesStore extends Store {
240 236
241 if ( 237 if (
242 service.lastPoll && 238 service.lastPoll &&
243 (service.lastPoll - service.lastPollAnswer) > ms('1m') 239 service.lastPoll - service.lastPollAnswer > ms('1m')
244 ) { 240 ) {
245 // If service did not reply for more than 1m try to reload. 241 // If service did not reply for more than 1m try to reload.
246 if (!service.isActive) { 242 if (!service.isActive) {
@@ -261,7 +257,7 @@ export default class ServicesStore extends Store {
261 service.lostRecipeConnection = false; 257 service.lostRecipeConnection = false;
262 service.lostRecipeReloadAttempt = 0; 258 service.lostRecipeReloadAttempt = 0;
263 } 259 }
264 }); 260 }
265 } 261 }
266 262
267 // Computed props 263 // Computed props
@@ -270,8 +266,7 @@ export default class ServicesStore extends Store {
270 const services = this.allServicesRequest.execute().result; 266 const services = this.allServicesRequest.execute().result;
271 if (services) { 267 if (services) {
272 return observable( 268 return observable(
273 services 269 [...services]
274 .slice()
275 .slice() 270 .slice()
276 .sort((a, b) => a.order - b.order) 271 .sort((a, b) => a.order - b.order)
277 .map((s, index) => { 272 .map((s, index) => {
@@ -318,11 +313,11 @@ export default class ServicesStore extends Store {
318 // Check if workspace needs to be kept loaded 313 // Check if workspace needs to be kept loaded
319 if (workspace.services.includes(KEEP_WS_LOADED_USID)) { 314 if (workspace.services.includes(KEEP_WS_LOADED_USID)) {
320 // Get services for workspace 315 // Get services for workspace
321 const serviceIDs = workspace.services.filter( 316 const serviceIDs = new Set(
322 i => i !== KEEP_WS_LOADED_USID, 317 workspace.services.filter(i => i !== KEEP_WS_LOADED_USID),
323 ); 318 );
324 const wsServices = filteredServices.filter(service => 319 const wsServices = filteredServices.filter(service =>
325 serviceIDs.includes(service.id), 320 serviceIDs.has(service.id),
326 ); 321 );
327 322
328 displayedServices = [...displayedServices, ...wsServices]; 323 displayedServices = [...displayedServices, ...wsServices];
@@ -410,12 +405,14 @@ export default class ServicesStore extends Store {
410 customIcon: false, 405 customIcon: false,
411 isDarkModeEnabled: false, 406 isDarkModeEnabled: false,
412 spellcheckerLanguage: 407 spellcheckerLanguage:
413 SPELLCHECKER_LOCALES[this.stores.settings.app.spellcheckerLanguage], 408 SPELLCHECKER_LOCALES[this.stores.settings.app.spellcheckerLanguage],
414 userAgentPref: '', 409 userAgentPref: '',
415 ...serviceData, 410 ...serviceData,
416 }; 411 };
417 412
418 const data = skipCleanup ? serviceData : this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); 413 const data = skipCleanup
414 ? serviceData
415 : this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData);
419 416
420 const response = await this.createServiceRequest.execute(recipeId, data) 417 const response = await this.createServiceRequest.execute(recipeId, data)
421 ._promise; 418 ._promise;
@@ -562,7 +559,8 @@ export default class ServicesStore extends Store {
562 // Write your scripts here 559 // Write your scripts here
563 console.log("Hello, World!", config); 560 console.log("Hello, World!", config);
564}; 561};
565`); 562`,
563 );
566 } 564 }
567 } else { 565 } else {
568 ensureFileSync(filePath); 566 ensureFileSync(filePath);
@@ -580,9 +578,9 @@ export default class ServicesStore extends Store {
580 if (!keepActiveRoute) this.stores.router.push('/'); 578 if (!keepActiveRoute) this.stores.router.push('/');
581 const service = this.one(serviceId); 579 const service = this.one(serviceId);
582 580
583 this.all.forEach(s => { 581 for (const s of this.all) {
584 s.isActive = false; 582 s.isActive = false;
585 }); 583 }
586 service.isActive = true; 584 service.isActive = true;
587 this._awake({ serviceId: service.id }); 585 this._awake({ serviceId: service.id });
588 586
@@ -618,10 +616,12 @@ export default class ServicesStore extends Store {
618 this.allDisplayed.length, 616 this.allDisplayed.length,
619 ); 617 );
620 618
621 this.all.forEach(s => { 619 for (const s of this.all) {
622 s.isActive = false; 620 s.isActive = false;
623 }); 621 }
624 this.allDisplayed[nextIndex].isActive = true; 622 this.allDisplayed[nextIndex].isActive = true;
623
624 this._focusActiveService();
625 } 625 }
626 626
627 @action _setActivePrev() { 627 @action _setActivePrev() {
@@ -631,10 +631,12 @@ export default class ServicesStore extends Store {
631 this.allDisplayed.length, 631 this.allDisplayed.length,
632 ); 632 );
633 633
634 this.all.forEach(s => { 634 for (const s of this.all) {
635 s.isActive = false; 635 s.isActive = false;
636 }); 636 }
637 this.allDisplayed[prevIndex].isActive = true; 637 this.allDisplayed[prevIndex].isActive = true;
638
639 this._focusActiveService();
638 } 640 }
639 641
640 @action _setUnreadMessageCount({ serviceId, count }) { 642 @action _setUnreadMessageCount({ serviceId, count }) {
@@ -676,12 +678,23 @@ export default class ServicesStore extends Store {
676 } 678 }
677 } 679 }
678 680
679 @action _focusActiveService() { 681 @action _focusActiveService(focusEvent = null) {
680 if (this.stores.user.isLoggedIn) { 682 if (this.stores.user.isLoggedIn) {
681 // TODO: add checks to not focus service when router path is /settings or /auth 683 // TODO: add checks to not focus service when router path is /settings or /auth
682 const service = this.active; 684 const service = this.active;
683 if (service) { 685 if (service) {
684 this._focusService({ serviceId: service.id }); 686 this._focusService({ serviceId: service.id });
687 if (this.stores.settings.app.splitMode && !focusEvent) {
688 setTimeout(() => {
689 document
690 .querySelector('.services__webview-wrapper.is-active')
691 .scrollIntoView({
692 behavior: 'smooth',
693 block: 'end',
694 inline: 'nearest',
695 });
696 }, 10);
697 }
685 } else { 698 } else {
686 debug('No service is active'); 699 debug('No service is active');
687 } 700 }
@@ -699,101 +712,128 @@ export default class ServicesStore extends Store {
699 @action _handleIPCMessage({ serviceId, channel, args }) { 712 @action _handleIPCMessage({ serviceId, channel, args }) {
700 const service = this.one(serviceId); 713 const service = this.one(serviceId);
701 714
702 if (channel === 'hello') { 715 // eslint-disable-next-line default-case
703 debug('Received hello event from', serviceId); 716 switch (channel) {
717 case 'hello': {
718 debug('Received hello event from', serviceId);
704 719
705 this._initRecipePolling(service.id); 720 this._initRecipePolling(service.id);
706 this._initializeServiceRecipeInWebview(serviceId); 721 this._initializeServiceRecipeInWebview(serviceId);
707 this._shareSettingsWithServiceProcess(); 722 this._shareSettingsWithServiceProcess();
708 } else if (channel === 'alive') {
709 service.lastPollAnswer = Date.now();
710 } else if (channel === 'message-counts') {
711 debug(`Received unread message info from '${serviceId}'`, args[0]);
712
713 this.actions.service.setUnreadMessageCount({
714 serviceId,
715 count: {
716 direct: args[0].direct,
717 indirect: args[0].indirect,
718 },
719 });
720 } else if (channel === 'notification') {
721 const { options } = args[0];
722 723
723 // Check if we are in scheduled Do-not-Disturb time 724 break;
724 const { scheduledDNDEnabled, scheduledDNDStart, scheduledDNDEnd } = 725 }
725 this.stores.settings.all.app; 726 case 'alive': {
727 service.lastPollAnswer = Date.now();
726 728
727 if ( 729 break;
728 scheduledDNDEnabled &&
729 isInTimeframe(scheduledDNDStart, scheduledDNDEnd)
730 ) {
731 return;
732 } 730 }
731 case 'message-counts': {
732 debug(`Received unread message info from '${serviceId}'`, args[0]);
733 733
734 if ( 734 this.actions.service.setUnreadMessageCount({
735 service.recipe.hasNotificationSound || 735 serviceId,
736 service.isMuted || 736 count: {
737 this.stores.settings.all.app.isAppMuted 737 direct: args[0].direct,
738 ) { 738 indirect: args[0].indirect,
739 Object.assign(options, { 739 },
740 silent: true,
741 }); 740 });
741
742 break;
742 } 743 }
744 case 'notification': {
745 const { options } = args[0];
743 746
744 if (service.isNotificationEnabled) { 747 // Check if we are in scheduled Do-not-Disturb time
745 let title = `Notification from ${service.name}`; 748 const { scheduledDNDEnabled, scheduledDNDStart, scheduledDNDEnd } =
746 if (!this.stores.settings.all.app.privateNotifications) { 749 this.stores.settings.all.app;
747 options.body = typeof options.body === 'string' ? options.body : ''; 750
748 title = 751 if (
749 typeof args[0].title === 'string' ? args[0].title : service.name; 752 scheduledDNDEnabled &&
750 } else { 753 isInTimeframe(scheduledDNDStart, scheduledDNDEnd)
751 // Remove message data from notification in private mode 754 ) {
752 options.body = ''; 755 return;
753 options.icon = '/assets/img/notification-badge.gif';
754 } 756 }
755 757
756 console.log(title, options); 758 if (
759 service.recipe.hasNotificationSound ||
760 service.isMuted ||
761 this.stores.settings.all.app.isAppMuted
762 ) {
763 Object.assign(options, {
764 silent: true,
765 });
766 }
757 767
758 this.actions.app.notify({ 768 if (service.isNotificationEnabled) {
759 notificationId: args[0].notificationId, 769 let title = `Notification from ${service.name}`;
760 title, 770 if (!this.stores.settings.all.app.privateNotifications) {
761 options, 771 options.body = typeof options.body === 'string' ? options.body : '';
762 serviceId, 772 title =
763 }); 773 typeof args[0].title === 'string' ? args[0].title : service.name;
774 } else {
775 // Remove message data from notification in private mode
776 options.body = '';
777 options.icon = '/assets/img/notification-badge.gif';
778 }
779
780 console.log(title, options);
781
782 this.actions.app.notify({
783 notificationId: args[0].notificationId,
784 title,
785 options,
786 serviceId,
787 });
788 }
789
790 break;
764 } 791 }
765 } else if (channel === 'avatar') { 792 case 'avatar': {
766 const url = args[0]; 793 const url = args[0];
767 if (service.iconUrl !== url && !service.hasCustomUploadedIcon) { 794 if (service.iconUrl !== url && !service.hasCustomUploadedIcon) {
768 service.customIconUrl = url; 795 service.customIconUrl = url;
796
797 this.actions.service.updateService({
798 serviceId,
799 serviceData: {
800 customIconUrl: url,
801 },
802 redirect: false,
803 });
804 }
769 805
770 this.actions.service.updateService({ 806 break;
771 serviceId,
772 serviceData: {
773 customIconUrl: url,
774 },
775 redirect: false,
776 });
777 } 807 }
778 } else if (channel === 'new-window') { 808 case 'new-window': {
779 const url = args[0]; 809 const url = args[0];
780 810
781 this.actions.app.openExternalUrl({ url }); 811 this.actions.app.openExternalUrl({ url });
782 } else if (channel === 'set-service-spellchecker-language') { 812
783 if (!args) { 813 break;
784 console.warn('Did not receive locale'); 814 }
785 } else { 815 case 'set-service-spellchecker-language': {
786 this.actions.service.updateService({ 816 if (!args) {
787 serviceId, 817 console.warn('Did not receive locale');
788 serviceData: { 818 } else {
789 spellcheckerLanguage: args[0] === 'reset' ? '' : args[0], 819 this.actions.service.updateService({
790 }, 820 serviceId,
791 redirect: false, 821 serviceData: {
792 }); 822 spellcheckerLanguage: args[0] === 'reset' ? '' : args[0],
823 },
824 redirect: false,
825 });
826 }
827
828 break;
793 } 829 }
794 } else if (channel === 'feature:todos') { 830 case 'feature:todos': {
795 Object.assign(args[0].data, { serviceId }); 831 Object.assign(args[0].data, { serviceId });
796 this.actions.todos.handleHostMessage(args[0]); 832 this.actions.todos.handleHostMessage(args[0]);
833
834 break;
835 }
836 // No default
797 } 837 }
798 } 838 }
799 839
@@ -809,13 +849,13 @@ export default class ServicesStore extends Store {
809 } 849 }
810 850
811 @action _sendIPCMessageToAllServices({ channel, args }) { 851 @action _sendIPCMessageToAllServices({ channel, args }) {
812 this.all.forEach(s => 852 for (const s of this.all) {
813 this.actions.service.sendIPCMessage({ 853 this.actions.service.sendIPCMessage({
814 serviceId: s.id, 854 serviceId: s.id,
815 channel, 855 channel,
816 args, 856 args,
817 }), 857 });
818 ); 858 }
819 } 859 }
820 860
821 @action _openWindow({ event }) { 861 @action _openWindow({ event }) {
@@ -863,11 +903,11 @@ export default class ServicesStore extends Store {
863 } 903 }
864 904
865 @action _reloadAll() { 905 @action _reloadAll() {
866 this.enabled.forEach(s => 906 for (const s of this.enabled) {
867 this._reload({ 907 this._reload({
868 serviceId: s.id, 908 serviceId: s.id,
869 }), 909 });
870 ); 910 }
871 } 911 }
872 912
873 @action _reloadUpdatedServices() { 913 @action _reloadUpdatedServices() {
@@ -901,17 +941,17 @@ export default class ServicesStore extends Store {
901 941
902 const services = {}; 942 const services = {};
903 // TODO: simplify this 943 // TODO: simplify this
904 this.all.forEach((s, index) => { 944 for (const [index] of this.all.entries()) {
905 services[this.all[index].id] = index; 945 services[this.all[index].id] = index;
906 }); 946 }
907 947
908 this.reorderServicesRequest.execute(services); 948 this.reorderServicesRequest.execute(services);
909 this.allServicesRequest.patch(data => { 949 this.allServicesRequest.patch(data => {
910 data.forEach(s => { 950 for (const s of data) {
911 const service = s; 951 const service = s;
912 952
913 service.order = services[s.id]; 953 service.order = services[s.id];
914 }); 954 }
915 }); 955 });
916 } 956 }
917 957
@@ -1001,13 +1041,14 @@ export default class ServicesStore extends Store {
1001 }`, 1041 }`,
1002 ); 1042 );
1003 1043
1044 // eslint-disable-next-line unicorn/consistent-function-scoping
1004 const resetTimer = service => { 1045 const resetTimer = service => {
1005 service.lastPollAnswer = Date.now(); 1046 service.lastPollAnswer = Date.now();
1006 service.lastPoll = Date.now(); 1047 service.lastPoll = Date.now();
1007 }; 1048 };
1008 1049
1009 if (!serviceId) { 1050 if (!serviceId) {
1010 this.allDisplayed.forEach(service => resetTimer(service)); 1051 for (const service of this.allDisplayed) resetTimer(service);
1011 } else { 1052 } else {
1012 const service = this.one(serviceId); 1053 const service = this.one(serviceId);
1013 if (service) { 1054 if (service) {
@@ -1043,7 +1084,7 @@ export default class ServicesStore extends Store {
1043 1084
1044 _mapActiveServiceToServiceModelReaction() { 1085 _mapActiveServiceToServiceModelReaction() {
1045 const { activeService } = this.stores.settings.all.service; 1086 const { activeService } = this.stores.settings.all.service;
1046 if (this.allDisplayed.length) { 1087 if (this.allDisplayed.length > 0) {
1047 this.allDisplayed.map(service => 1088 this.allDisplayed.map(service =>
1048 Object.assign(service, { 1089 Object.assign(service, {
1049 isActive: activeService 1090 isActive: activeService
@@ -1102,14 +1143,14 @@ export default class ServicesStore extends Store {
1102 const { enabled } = this; 1143 const { enabled } = this;
1103 const { isAppMuted } = this.stores.settings.app; 1144 const { isAppMuted } = this.stores.settings.app;
1104 1145
1105 enabled.forEach(service => { 1146 for (const service of enabled) {
1106 const { isAttached } = service; 1147 const { isAttached } = service;
1107 const isMuted = isAppMuted || service.isMuted; 1148 const isMuted = isAppMuted || service.isMuted;
1108 1149
1109 if (isAttached) { 1150 if (isAttached) {
1110 service.webview.audioMuted = isMuted; 1151 service.webview.audioMuted = isMuted;
1111 } 1152 }
1112 }); 1153 }
1113 } 1154 }
1114 1155
1115 _shareSettingsWithServiceProcess() { 1156 _shareSettingsWithServiceProcess() {
@@ -1151,7 +1192,7 @@ export default class ServicesStore extends Store {
1151 1192
1152 if ( 1193 if (
1153 this.allDisplayed.findIndex(service => service.isActive) === -1 && 1194 this.allDisplayed.findIndex(service => service.isActive) === -1 &&
1154 this.allDisplayed.length !== 0 1195 this.allDisplayed.length > 0
1155 ) { 1196 ) {
1156 debug('No active service found, setting active service to index 0'); 1197 debug('No active service found, setting active service to index 0');
1157 1198
diff --git a/src/stores/SettingsStore.js b/src/stores/SettingsStore.js
index 9aade974c..ec80fee7c 100644
--- a/src/stores/SettingsStore.js
+++ b/src/stores/SettingsStore.js
@@ -1,23 +1,19 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import { getCurrentWindow } from '@electron/remote'; 2import { getCurrentWindow } from '@electron/remote';
3import { 3import { action, computed, observable, reaction } from 'mobx';
4 action, computed, observable, reaction,
5} from 'mobx';
6import localStorage from 'mobx-localstorage'; 4import localStorage from 'mobx-localstorage';
7import { 5import { DEFAULT_APP_SETTINGS, FILE_SYSTEM_SETTINGS_TYPES, LOCAL_SERVER } from '../config';
8 FILE_SYSTEM_SETTINGS_TYPES, LOCAL_SERVER, SEARCH_ENGINE_DDG,
9} from '../config';
10import { API, DEFAULT_APP_SETTINGS } from '../environment';
11import { getLocale } from '../helpers/i18n-helpers';
12import { hash } from '../helpers/password-helpers'; 6import { hash } from '../helpers/password-helpers';
13import { SPELLCHECKER_LOCALES } from '../i18n/languages';
14import Request from './lib/Request'; 7import Request from './lib/Request';
15import Store from './lib/Store'; 8import Store from './lib/Store';
16 9
17const debug = require('debug')('Ferdi:SettingsStore'); 10const debug = require('debug')('Ferdi:SettingsStore');
18 11
19export default class SettingsStore extends Store { 12export default class SettingsStore extends Store {
20 @observable updateAppSettingsRequest = new Request(this.api.local, 'updateAppSettings'); 13 @observable updateAppSettingsRequest = new Request(
14 this.api.local,
15 'updateAppSettings',
16 );
21 17
22 startup = true; 18 startup = true;
23 19
@@ -40,9 +36,7 @@ export default class SettingsStore extends Store {
40 await this._migrate(); 36 await this._migrate();
41 37
42 reaction( 38 reaction(
43 () => ( 39 () => this.all.app.autohideMenuBar,
44 this.all.app.autohideMenuBar
45 ),
46 () => { 40 () => {
47 const currentWindow = getCurrentWindow(); 41 const currentWindow = getCurrentWindow();
48 currentWindow.setMenuBarVisibility(!this.all.app.autohideMenuBar); 42 currentWindow.setMenuBarVisibility(!this.all.app.autohideMenuBar);
@@ -51,10 +45,8 @@ export default class SettingsStore extends Store {
51 ); 45 );
52 46
53 reaction( 47 reaction(
54 () => ( 48 () => this.all.app.server,
55 this.all.app.server 49 server => {
56 ),
57 (server) => {
58 if (server === LOCAL_SERVER) { 50 if (server === LOCAL_SERVER) {
59 ipcRenderer.send('startLocalServer'); 51 ipcRenderer.send('startLocalServer');
60 } 52 }
@@ -65,7 +57,10 @@ export default class SettingsStore extends Store {
65 // Inactivity lock timer 57 // Inactivity lock timer
66 let inactivityTimer; 58 let inactivityTimer;
67 getCurrentWindow().on('blur', () => { 59 getCurrentWindow().on('blur', () => {
68 if (this.all.app.lockingFeatureEnabled && this.all.app.inactivityLock !== 0) { 60 if (
61 this.all.app.lockingFeatureEnabled &&
62 this.all.app.inactivityLock !== 0
63 ) {
69 inactivityTimer = setTimeout(() => { 64 inactivityTimer = setTimeout(() => {
70 this.actions.settings.update({ 65 this.actions.settings.update({
71 type: 'app', 66 type: 'app',
@@ -84,7 +79,11 @@ export default class SettingsStore extends Store {
84 79
85 ipcRenderer.on('appSettings', (event, resp) => { 80 ipcRenderer.on('appSettings', (event, resp) => {
86 // Lock on startup if enabled in settings 81 // Lock on startup if enabled in settings
87 if (this.startup && resp.type === 'app' && resp.data.lockingFeatureEnabled) { 82 if (
83 this.startup &&
84 resp.type === 'app' &&
85 resp.data.lockingFeatureEnabled
86 ) {
88 this.startup = false; 87 this.startup = false;
89 process.nextTick(() => { 88 process.nextTick(() => {
90 if (!this.all.app.locked) { 89 if (!this.all.app.locked) {
@@ -97,9 +96,9 @@ export default class SettingsStore extends Store {
97 ipcRenderer.send('initialAppSettings', resp); 96 ipcRenderer.send('initialAppSettings', resp);
98 }); 97 });
99 98
100 this.fileSystemSettingsTypes.forEach((type) => { 99 for (const type of this.fileSystemSettingsTypes) {
101 ipcRenderer.send('getAppSettings', type); 100 ipcRenderer.send('getAppSettings', type);
102 }); 101 }
103 } 102 }
104 103
105 @computed get app() { 104 @computed get app() {
@@ -111,15 +110,19 @@ export default class SettingsStore extends Store {
111 } 110 }
112 111
113 @computed get service() { 112 @computed get service() {
114 return localStorage.getItem('service') || { 113 return (
115 activeService: '', 114 localStorage.getItem('service') || {
116 }; 115 activeService: '',
116 }
117 );
117 } 118 }
118 119
119 @computed get stats() { 120 @computed get stats() {
120 return localStorage.getItem('stats') || { 121 return (
121 activeService: '', 122 localStorage.getItem('stats') || {
122 }; 123 activeService: '',
124 }
125 );
123 } 126 }
124 127
125 @computed get migration() { 128 @computed get migration() {
@@ -183,78 +186,6 @@ export default class SettingsStore extends Store {
183 async _migrate() { 186 async _migrate() {
184 const legacySettings = localStorage.getItem('app') || {}; 187 const legacySettings = localStorage.getItem('app') || {};
185 188
186 this._ensureMigrationAndMarkDone('5.0.0-beta.17-settings', () => {
187 this.actions.settings.update({
188 type: 'app',
189 data: {
190 autoLaunchInBackground: legacySettings.autoLaunchInBackground,
191 runInBackground: legacySettings.runInBackground,
192 enableSystemTray: legacySettings.enableSystemTray,
193 minimizeToSystemTray: legacySettings.minimizeToSystemTray,
194 closeToSystemTray: legacySettings.closeToSystemTray,
195 server: API,
196 isAppMuted: legacySettings.isAppMuted,
197 enableGPUAcceleration: legacySettings.enableGPUAcceleration,
198 showMessageBadgeWhenMuted: legacySettings.showMessageBadgeWhenMuted,
199 showDisabledServices: legacySettings.showDisabledServices,
200 enableSpellchecking: legacySettings.enableSpellchecking,
201 },
202 });
203
204 this.actions.settings.update({
205 type: 'service',
206 data: {
207 activeService: legacySettings.activeService,
208 },
209 });
210
211 localStorage.removeItem('app');
212
213 debug('Migrated settings to split stores');
214 });
215
216 this._ensureMigrationAndMarkDone('5.0.0-beta.19-settings', () => {
217 const spellcheckerLanguage = getLocale({
218 locale: this.stores.settings.app.locale,
219 locales: SPELLCHECKER_LOCALES,
220 defaultLocale: DEFAULT_APP_SETTINGS.spellcheckerLanguage,
221 fallbackLocale: DEFAULT_APP_SETTINGS.spellcheckerLanguage,
222 });
223
224 this.actions.settings.update({
225 type: 'app',
226 data: {
227 spellcheckerLanguage,
228 },
229 });
230 });
231
232 this._ensureMigrationAndMarkDone('5.4.4-beta.2-settings', () => {
233 const {
234 showServiceNavigationBar,
235 } = this.all.app;
236
237 this.actions.settings.update({
238 type: 'app',
239 data: {
240 navigationBarBehaviour: showServiceNavigationBar ? 'custom' : 'never',
241 },
242 });
243 });
244
245 this._ensureMigrationAndMarkDone('5.4.4-beta.4-settings', () => {
246 this.actions.settings.update({
247 type: 'app',
248 data: {
249 todoServer: 'isUsingCustomTodoService',
250 customTodoServer: legacySettings.todoServer,
251 automaticUpdates: !(legacySettings.noUpdates),
252 },
253 });
254
255 debug('Migrated old todo setting to new custom todo setting');
256 });
257
258 this._ensureMigrationAndMarkDone('password-hashing', () => { 189 this._ensureMigrationAndMarkDone('password-hashing', () => {
259 if (this.stores.settings.app.lockedPassword !== '') { 190 if (this.stores.settings.app.lockedPassword !== '') {
260 this.actions.settings.update({ 191 this.actions.settings.update({
@@ -272,7 +203,7 @@ export default class SettingsStore extends Store {
272 this.actions.settings.update({ 203 this.actions.settings.update({
273 type: 'app', 204 type: 'app',
274 data: { 205 data: {
275 searchEngine: SEARCH_ENGINE_DDG, 206 searchEngine: DEFAULT_APP_SETTINGS.searchEngine,
276 }, 207 },
277 }); 208 });
278 }); 209 });
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.ts
index be675d5ed..6ab63c2ee 100644
--- a/src/stores/UIStore.js
+++ b/src/stores/UIStore.ts
@@ -1,13 +1,15 @@
1import { 1import { action, observable, computed, reaction } from 'mobx';
2 action, observable, computed, reaction, 2import { theme, ThemeType } from '@meetfranz/theme';
3} from 'mobx';
4import { theme } from '@meetfranz/theme';
5import { nativeTheme, systemPreferences } from '@electron/remote'; 3import { nativeTheme, systemPreferences } from '@electron/remote';
6 4
7import Store from './lib/Store'; 5import Store from './lib/Store';
8import { isMac, isWindows } from '../environment'; 6import { isMac, isWindows } from '../environment';
9 7
10export default class UIStore extends Store { 8export default class UIStore extends Store {
9 actions: any;
10
11 stores: any;
12
11 @observable showServicesUpdatedInfoBar = false; 13 @observable showServicesUpdatedInfoBar = false;
12 14
13 @observable isOsDarkThemeActive = nativeTheme.shouldUseDarkColors; 15 @observable isOsDarkThemeActive = nativeTheme.shouldUseDarkColors;
@@ -43,38 +45,54 @@ export default class UIStore extends Store {
43 45
44 setup() { 46 setup() {
45 reaction( 47 reaction(
46 () => ( 48 () => this.isDarkThemeActive,
47 this.isDarkThemeActive
48 ),
49 () => { 49 () => {
50 this._setupThemeInDOM(); 50 this._setupThemeInDOM();
51 }, 51 },
52 { fireImmediately: true }, 52 { fireImmediately: true },
53 ); 53 );
54 reaction(
55 () => this.isSplitModeActive,
56 () => {
57 this._setupModeInDOM();
58 },
59 { fireImmediately: true },
60 );
54 } 61 }
55 62
56 @computed get showMessageBadgesEvenWhenMuted() { 63 @computed get showMessageBadgesEvenWhenMuted() {
57 const settings = this.stores.settings.all; 64 const settings = this.stores.settings.all;
58 65
59 return ( 66 return (
60 (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) 67 (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) ||
61 || !settings.app.isAppMuted 68 !settings.app.isAppMuted
62 ); 69 );
63 } 70 }
64 71
65 @computed get isDarkThemeActive() { 72 @computed get isDarkThemeActive() {
66 const isWithAdaptableInDarkMode = this.stores.settings.all.app.adaptableDarkMode 73 const isWithAdaptableInDarkMode =
67 && this.isOsDarkThemeActive; 74 this.stores.settings.all.app.adaptableDarkMode &&
68 const isWithoutAdaptableInDarkMode = this.stores.settings.all.app.darkMode 75 this.isOsDarkThemeActive;
69 && !this.stores.settings.all.app.adaptableDarkMode; 76 const isWithoutAdaptableInDarkMode =
77 this.stores.settings.all.app.darkMode &&
78 !this.stores.settings.all.app.adaptableDarkMode;
70 const isInDarkMode = this.stores.settings.all.app.darkMode; 79 const isInDarkMode = this.stores.settings.all.app.darkMode;
71 return !!(isWithAdaptableInDarkMode 80 return !!(
72 || isWithoutAdaptableInDarkMode 81 isWithAdaptableInDarkMode ||
73 || isInDarkMode); 82 isWithoutAdaptableInDarkMode ||
83 isInDarkMode
84 );
85 }
86
87 @computed get isSplitModeActive() {
88 return this.stores.settings.app.splitMode;
74 } 89 }
75 90
76 @computed get theme() { 91 @computed get theme() {
77 const themeId = (this.isDarkThemeActive || this.stores.settings.app.darkMode) ? 'dark' : 'default'; 92 const themeId =
93 this.isDarkThemeActive || this.stores.settings.app.darkMode
94 ? ThemeType.dark
95 : ThemeType.default;
78 const { accentColor } = this.stores.settings.app; 96 const { accentColor } = this.stores.settings.app;
79 return theme(themeId, accentColor); 97 return theme(themeId, accentColor);
80 } 98 }
@@ -102,9 +120,19 @@ export default class UIStore extends Store {
102 const body = document.querySelector('body'); 120 const body = document.querySelector('body');
103 121
104 if (!this.isDarkThemeActive) { 122 if (!this.isDarkThemeActive) {
105 body.classList.remove('theme__dark'); 123 body?.classList.remove('theme__dark');
124 } else {
125 body?.classList.add('theme__dark');
126 }
127 }
128
129 _setupModeInDOM() {
130 const body = document.querySelector('body');
131
132 if (!this.isSplitModeActive) {
133 body?.classList.remove('mode__split');
106 } else { 134 } else {
107 body.classList.add('theme__dark'); 135 body?.classList.add('mode__split');
108 } 136 }
109 } 137 }
110} 138}
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js
index 2e009893a..9f222d2d3 100644
--- a/src/stores/UserStore.js
+++ b/src/stores/UserStore.js
@@ -2,13 +2,13 @@ import { observable, computed, action } from 'mobx';
2import moment from 'moment'; 2import moment from 'moment';
3import jwt from 'jsonwebtoken'; 3import jwt from 'jsonwebtoken';
4import localStorage from 'mobx-localstorage'; 4import localStorage from 'mobx-localstorage';
5import { session } from '@electron/remote'; 5import { ipcRenderer } from 'electron';
6 6
7import { isDevMode } from '../environment'; 7import { TODOS_PARTITION_ID } from '../config';
8import { isDevMode } from '../environment-remote';
8import Store from './lib/Store'; 9import Store from './lib/Store';
9import Request from './lib/Request'; 10import Request from './lib/Request';
10import CachedRequest from './lib/CachedRequest'; 11import CachedRequest from './lib/CachedRequest';
11import { TODOS_PARTITION_ID } from '../config';
12 12
13const debug = require('debug')('Ferdi:UserStore'); 13const debug = require('debug')('Ferdi:UserStore');
14 14
@@ -46,7 +46,10 @@ export default class UserStore extends Store {
46 46
47 @observable updateUserInfoRequest = new Request(this.api.user, 'updateInfo'); 47 @observable updateUserInfoRequest = new Request(this.api.user, 'updateInfo');
48 48
49 @observable getLegacyServicesRequest = new CachedRequest(this.api.user, 'getLegacyServices'); 49 @observable getLegacyServicesRequest = new CachedRequest(
50 this.api.user,
51 'getLegacyServices',
52 );
50 53
51 @observable deleteAccountRequest = new CachedRequest(this.api.user, 'delete'); 54 @observable deleteAccountRequest = new CachedRequest(this.api.user, 'delete');
52 55
@@ -81,13 +84,17 @@ export default class UserStore extends Store {
81 84
82 // Register action handlers 85 // Register action handlers
83 this.actions.user.login.listen(this._login.bind(this)); 86 this.actions.user.login.listen(this._login.bind(this));
84 this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); 87 this.actions.user.retrievePassword.listen(
88 this._retrievePassword.bind(this),
89 );
85 this.actions.user.logout.listen(this._logout.bind(this)); 90 this.actions.user.logout.listen(this._logout.bind(this));
86 this.actions.user.signup.listen(this._signup.bind(this)); 91 this.actions.user.signup.listen(this._signup.bind(this));
87 this.actions.user.invite.listen(this._invite.bind(this)); 92 this.actions.user.invite.listen(this._invite.bind(this));
88 this.actions.user.update.listen(this._update.bind(this)); 93 this.actions.user.update.listen(this._update.bind(this));
89 this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); 94 this.actions.user.resetStatus.listen(this._resetStatus.bind(this));
90 this.actions.user.importLegacyServices.listen(this._importLegacyServices.bind(this)); 95 this.actions.user.importLegacyServices.listen(
96 this._importLegacyServices.bind(this),
97 );
91 this.actions.user.delete.listen(this._delete.bind(this)); 98 this.actions.user.delete.listen(this._delete.bind(this));
92 99
93 // Reactions 100 // Reactions
@@ -176,7 +183,14 @@ export default class UserStore extends Store {
176 } 183 }
177 184
178 @action async _signup({ 185 @action async _signup({
179 firstname, lastname, email, password, accountType, company, plan, currency, 186 firstname,
187 lastname,
188 email,
189 password,
190 accountType,
191 company,
192 plan,
193 currency,
180 }) { 194 }) {
181 const authToken = await this.signupRequest.execute({ 195 const authToken = await this.signupRequest.execute({
182 firstname, 196 firstname,
@@ -205,7 +219,7 @@ export default class UserStore extends Store {
205 } 219 }
206 220
207 @action async _invite({ invites }) { 221 @action async _invite({ invites }) {
208 const data = invites.filter((invite) => invite.email !== ''); 222 const data = invites.filter(invite => invite.email !== '');
209 223
210 const response = await this.inviteRequest.execute(data)._promise; 224 const response = await this.inviteRequest.execute(data)._promise;
211 225
@@ -220,7 +234,8 @@ export default class UserStore extends Store {
220 @action async _update({ userData }) { 234 @action async _update({ userData }) {
221 if (!this.isLoggedIn) return; 235 if (!this.isLoggedIn) return;
222 236
223 const response = await this.updateUserInfoRequest.execute(userData)._promise; 237 const response = await this.updateUserInfoRequest.execute(userData)
238 ._promise;
224 239
225 this.getUserInfoRequest.patch(() => response.data); 240 this.getUserInfoRequest.patch(() => response.data);
226 this.actionStatus = response.status || []; 241 this.actionStatus = response.status || [];
@@ -241,8 +256,7 @@ export default class UserStore extends Store {
241 this.stores.services.allServicesRequest.invalidate().reset(); 256 this.stores.services.allServicesRequest.invalidate().reset();
242 257
243 if (this.stores.todos.isTodosEnabled) { 258 if (this.stores.todos.isTodosEnabled) {
244 const sess = session.fromPartition(TODOS_PARTITION_ID); 259 ipcRenderer.send('clear-storage-data', { sessionId: TODOS_PARTITION_ID });
245 sess.clearStorageData();
246 } 260 }
247 } 261 }
248 262
@@ -250,19 +264,27 @@ export default class UserStore extends Store {
250 this.isImportLegacyServicesExecuting = true; 264 this.isImportLegacyServicesExecuting = true;
251 265
252 // Reduces recipe duplicates 266 // Reduces recipe duplicates
253 const recipes = services.filter((obj, pos, arr) => arr.map((mapObj) => mapObj.recipe.id).indexOf(obj.recipe.id) === pos).map((s) => s.recipe.id); 267 const recipes = services
268 .filter(
269 (obj, pos, arr) =>
270 arr.map(mapObj => mapObj.recipe.id).indexOf(obj.recipe.id) === pos,
271 )
272 .map(s => s.recipe.id);
254 273
255 // Install recipes 274 // Install recipes
256 for (const recipe of recipes) { // eslint-disable-line no-unused-vars 275 for (const recipe of recipes) {
257 // eslint-disable-next-line 276 // eslint-disable-line no-unused-vars
277 // eslint-disable-next-line no-await-in-loop
258 await this.stores.recipes._install({ recipeId: recipe }); 278 await this.stores.recipes._install({ recipeId: recipe });
259 } 279 }
260 280
261 for (const service of services) { // eslint-disable-line no-unused-vars 281 for (const service of services) {
282 // eslint-disable-line no-unused-vars
262 this.actions.service.createFromLegacyService({ 283 this.actions.service.createFromLegacyService({
263 data: service, 284 data: service,
264 }); 285 });
265 await this.stores.services.createServiceRequest._promise; // eslint-disable-line 286 // eslint-disable-next-line no-await-in-loop
287 await this.stores.services.createServiceRequest._promise;
266 } 288 }
267 289
268 this.isImportLegacyServicesExecuting = false; 290 this.isImportLegacyServicesExecuting = false;
@@ -281,8 +303,7 @@ export default class UserStore extends Store {
281 303
282 const { router } = this.stores; 304 const { router } = this.stores;
283 const currentRoute = window.location.hash; 305 const currentRoute = window.location.hash;
284 if (!this.isLoggedIn 306 if (!this.isLoggedIn && currentRoute.includes('token=')) {
285 && currentRoute.includes('token=')) {
286 router.push(this.WELCOME_ROUTE); 307 router.push(this.WELCOME_ROUTE);
287 const token = currentRoute.split('=')[1]; 308 const token = currentRoute.split('=')[1];
288 309
@@ -293,20 +314,18 @@ export default class UserStore extends Store {
293 this._tokenLogin(token); 314 this._tokenLogin(token);
294 }, 1000); 315 }, 1000);
295 } 316 }
296 } else if (!this.isLoggedIn 317 } else if (!this.isLoggedIn && !currentRoute.includes(this.BASE_ROUTE)) {
297 && !currentRoute.includes(this.BASE_ROUTE)) {
298 router.push(this.WELCOME_ROUTE); 318 router.push(this.WELCOME_ROUTE);
299 } else if (this.isLoggedIn 319 } else if (this.isLoggedIn && currentRoute === this.LOGOUT_ROUTE) {
300 && currentRoute === this.LOGOUT_ROUTE) {
301 this.actions.user.logout(); 320 this.actions.user.logout();
302 router.push(this.LOGIN_ROUTE); 321 router.push(this.LOGIN_ROUTE);
303 } else if (this.isLoggedIn 322 } else if (
304 && currentRoute.includes(this.BASE_ROUTE) 323 this.isLoggedIn &&
305 && (this.hasCompletedSignup 324 currentRoute.includes(this.BASE_ROUTE) &&
306 || this.hasCompletedSignup === null)) { 325 (this.hasCompletedSignup || this.hasCompletedSignup === null) &&
307 if (!isDevMode) { 326 !isDevMode
308 this.stores.router.push('/'); 327 ) {
309 } 328 this.stores.router.push('/');
310 } 329 }
311 }; 330 };
312 331
@@ -316,7 +335,7 @@ export default class UserStore extends Store {
316 let data; 335 let data;
317 try { 336 try {
318 data = await this.getUserInfoRequest.execute()._promise; 337 data = await this.getUserInfoRequest.execute()._promise;
319 } catch (e) { 338 } catch {
320 return false; 339 return false;
321 } 340 }
322 341
@@ -336,12 +355,12 @@ export default class UserStore extends Store {
336 try { 355 try {
337 const decoded = jwt.decode(authToken); 356 const decoded = jwt.decode(authToken);
338 357
339 return ({ 358 return {
340 id: decoded.userId, 359 id: decoded.userId,
341 tokenExpiry: moment.unix(decoded.exp).toISOString(), 360 tokenExpiry: moment.unix(decoded.exp).toISOString(),
342 authToken, 361 authToken,
343 }); 362 };
344 } catch (err) { 363 } catch {
345 this._logout(); 364 this._logout();
346 return false; 365 return false;
347 } 366 }
@@ -372,7 +391,7 @@ export default class UserStore extends Store {
372 async _migrateUserLocale() { 391 async _migrateUserLocale() {
373 try { 392 try {
374 await this.getUserInfoRequest._promise; 393 await this.getUserInfoRequest._promise;
375 } catch (e) { 394 } catch {
376 return false; 395 return false;
377 } 396 }
378 397
diff --git a/src/stores/index.ts b/src/stores/index.ts
index 4cd4e92ea..1760ddfa2 100644
--- a/src/stores/index.ts
+++ b/src/stores/index.ts
@@ -34,10 +34,10 @@ export default (api, actions, router) => {
34 }); 34 });
35 35
36 // Initialize all stores 36 // Initialize all stores
37 Object.keys(stores).forEach(name => { 37 for (const name of Object.keys(stores)) {
38 if (stores[name] && stores[name].initialize) { 38 if (stores[name] && stores[name].initialize) {
39 stores[name].initialize(); 39 stores[name].initialize();
40 } 40 }
41 }); 41 }
42 return stores; 42 return stores;
43}; 43};
diff --git a/src/stores/lib/CachedRequest.js b/src/stores/lib/CachedRequest.js
index 94f615144..a6dd47f7d 100644
--- a/src/stores/lib/CachedRequest.js
+++ b/src/stores/lib/CachedRequest.js
@@ -1,4 +1,3 @@
1// @flow
2import { action } from 'mobx'; 1import { action } from 'mobx';
3import { isEqual, remove } from 'lodash'; 2import { isEqual, remove } from 'lodash';
4import Request from './Request'; 3import Request from './Request';
@@ -30,48 +29,60 @@ export default class CachedRequest extends Request {
30 29
31 // This timeout is necessary to avoid warnings from mobx 30 // This timeout is necessary to avoid warnings from mobx
32 // regarding triggering actions as side-effect of getters 31 // regarding triggering actions as side-effect of getters
33 setTimeout(action(() => { 32 setTimeout(
34 this.isExecuting = true; 33 action(() => {
35 // Apply the previous result from this call immediately (cached) 34 this.isExecuting = true;
36 if (existingApiCall) { 35 // Apply the previous result from this call immediately (cached)
37 this.result = existingApiCall.result; 36 if (existingApiCall) {
38 } 37 this.result = existingApiCall.result;
39 }), 0); 38 }
39 }),
40 0,
41 );
40 42
41 // Issue api call & save it as promise that is handled to update the results of the operation 43 // Issue api call & save it as promise that is handled to update the results of the operation
42 this._promise = new Promise((resolve) => { 44 this._promise = new Promise(resolve => {
43 this._api[this._method](...callArgs) 45 this._api[this._method](...callArgs)
44 .then((result) => { 46 .then(result => {
45 setTimeout(action(() => { 47 setTimeout(
46 this.result = result; 48 action(() => {
47 if (this._currentApiCall) this._currentApiCall.result = result; 49 this.result = result;
48 this.isExecuting = false; 50 if (this._currentApiCall) this._currentApiCall.result = result;
49 this.isError = false; 51 this.isExecuting = false;
50 this.wasExecuted = true; 52 this.isError = false;
51 this._isInvalidated = false; 53 this.wasExecuted = true;
52 this._isWaitingForResponse = false; 54 this._isInvalidated = false;
53 this._triggerHooks(); 55 this._isWaitingForResponse = false;
54 resolve(result); 56 this._triggerHooks();
55 }), 1); 57 resolve(result);
58 }),
59 1,
60 );
56 return result; 61 return result;
57 }) 62 })
58 .catch(action((error) => { 63 .catch(
59 setTimeout(action(() => { 64 action(error => {
60 this.error = error; 65 setTimeout(
61 this.isExecuting = false; 66 action(() => {
62 this.isError = true; 67 this.error = error;
63 this.wasExecuted = true; 68 this.isExecuting = false;
64 this._isWaitingForResponse = false; 69 this.isError = true;
65 this._triggerHooks(); 70 this.wasExecuted = true;
66 // reject(error); 71 this._isWaitingForResponse = false;
67 }), 1); 72 this._triggerHooks();
68 })); 73 // reject(error);
74 }),
75 1,
76 );
77 }),
78 );
69 }); 79 });
70 80
71 this._isWaitingForResponse = true; 81 this._isWaitingForResponse = true;
72 return this; 82 return this;
73 } 83 }
74 84
85 // eslint-disable-next-line unicorn/no-object-as-default-parameter
75 invalidate(options = { immediately: false }) { 86 invalidate(options = { immediately: false }) {
76 this._isInvalidated = true; 87 this._isInvalidated = true;
77 if (options.immediately && this._currentApiCall) { 88 if (options.immediately && this._currentApiCall) {
@@ -81,18 +92,21 @@ export default class CachedRequest extends Request {
81 } 92 }
82 93
83 patch(modify) { 94 patch(modify) {
84 return new Promise((resolve) => { 95 return new Promise(resolve => {
85 setTimeout(action(() => { 96 setTimeout(
86 const override = modify(this.result); 97 action(() => {
87 if (override !== undefined) this.result = override; 98 const override = modify(this.result);
88 if (this._currentApiCall) this._currentApiCall.result = this.result; 99 if (override !== undefined) this.result = override;
89 resolve(this); 100 if (this._currentApiCall) this._currentApiCall.result = this.result;
90 }), 0); 101 resolve(this);
102 }),
103 0,
104 );
91 }); 105 });
92 } 106 }
93 107
94 removeCacheForCallWith(...args) { 108 removeCacheForCallWith(...args) {
95 remove(this._apiCalls, (c) => isEqual(c.args, args)); 109 remove(this._apiCalls, c => isEqual(c.args, args));
96 } 110 }
97 111
98 _addApiCall(args) { 112 _addApiCall(args) {
@@ -102,6 +116,6 @@ export default class CachedRequest extends Request {
102 } 116 }
103 117
104 _findApiCall(args) { 118 _findApiCall(args) {
105 return this._apiCalls.find((c) => isEqual(c.args, args)); 119 return this._apiCalls.find(c => isEqual(c.args, args));
106 } 120 }
107} 121}
diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js
index 32ffe4367..39f32729a 100644
--- a/src/stores/lib/Request.js
+++ b/src/stores/lib/Request.js
@@ -107,7 +107,7 @@ export default class Request {
107 } 107 }
108 108
109 _triggerHooks() { 109 _triggerHooks() {
110 Request._hooks.forEach((hook) => hook(this)); 110 for (const hook of Request._hooks) hook(this);
111 } 111 }
112 112
113 reset = () => { 113 reset = () => {
diff --git a/src/stores/lib/Store.js b/src/stores/lib/Store.js
index b03a7e725..b39070ce8 100644
--- a/src/stores/lib/Store.js
+++ b/src/stores/lib/Store.js
@@ -28,18 +28,18 @@ export default class Store {
28 } 28 }
29 29
30 registerReactions(reactions) { 30 registerReactions(reactions) {
31 reactions.forEach((reaction) => this._reactions.push(new Reaction(reaction))); 31 for (const reaction of reactions) this._reactions.push(new Reaction(reaction));
32 } 32 }
33 33
34 setup() {} 34 setup() {}
35 35
36 initialize() { 36 initialize() {
37 this.setup(); 37 this.setup();
38 this._reactions.forEach((reaction) => reaction.start()); 38 for (const reaction of this._reactions) reaction.start();
39 } 39 }
40 40
41 teardown() { 41 teardown() {
42 this._reactions.forEach((reaction) => reaction.stop()); 42 for (const reaction of this._reactions) reaction.stop();
43 } 43 }
44 44
45 resetStatus() { 45 resetStatus() {
diff --git a/src/styles/layout.scss b/src/styles/layout.scss
index 49e041022..b5d4d86d0 100644
--- a/src/styles/layout.scss
+++ b/src/styles/layout.scss
@@ -82,6 +82,10 @@ body.win32:not(.isFullScreen) .app .app__content {
82 height: calc(100% - 28px); 82 height: calc(100% - 28px);
83} 83}
84 84
85.mode__split .app .app__service {
86 overflow-x: auto;
87}
88
85.app { 89.app {
86 .app__content { 90 .app__content {
87 display: flex; 91 display: flex;
diff --git a/src/styles/services.scss b/src/styles/services.scss
index 8b8c27e10..dd053e93d 100644
--- a/src/styles/services.scss
+++ b/src/styles/services.scss
@@ -18,6 +18,24 @@
18 } 18 }
19} 19}
20 20
21.mode__split .services {
22 display: flex;
23 overflow: visible;
24
25 .services__webview {
26 position: relative;
27 flex: 1 0 50%;
28
29 @media (min-width: 1280px) {
30 flex-basis: 33.33%;
31 }
32
33 @media (min-width: 2048px) {
34 flex-basis: 25%;
35 }
36 }
37}
38
21.services { 39.services {
22 background: #FFF; 40 background: #FFF;
23 flex: 1; 41 flex: 1;
@@ -71,7 +89,7 @@
71 } 89 }
72 90
73 .services__info-layer { 91 .services__info-layer {
74 position: absolut; 92 position: absolute;
75 z-index: 110; 93 z-index: 110;
76 } 94 }
77 95
diff --git a/src/styles/tabs.scss b/src/styles/tabs.scss
index df10da77c..16318b9f6 100644
--- a/src/styles/tabs.scss
+++ b/src/styles/tabs.scss
@@ -120,6 +120,19 @@
120 } 120 }
121 } 121 }
122 122
123 .tab-item__shortcut-index {
124 align-items: center;
125 background: $theme-gray-light;
126 bottom: 8px;
127 color: #fff;
128 display: flex;
129 font-size: 11px;
130 min-height: 17px;
131 padding: 0px 5px;
132 position: absolute;
133 left: 8px;
134 }
135
123 &.is-reordering { 136 &.is-reordering {
124 z-index: 99999; 137 z-index: 99999;
125 } 138 }
diff --git a/src/webview/badge.ts b/src/webview/badge.ts
index 753e90fef..8e8b66c0c 100644
--- a/src/webview/badge.ts
+++ b/src/webview/badge.ts
@@ -21,22 +21,22 @@ export class BadgeHandler {
21 // Parse number to integer 21 // Parse number to integer
22 // This will correct errors that recipes may introduce, e.g. 22 // This will correct errors that recipes may introduce, e.g.
23 // by sending a String instead of an integer 23 // by sending a String instead of an integer
24 const parsedNumber = parseInt(text.toString(), 10); 24 const parsedNumber = Number.parseInt(text.toString(), 10);
25 const adjustedNumber = Number.isNaN(parsedNumber) ? 0 : parsedNumber; 25 const adjustedNumber = Number.isNaN(parsedNumber) ? 0 : parsedNumber;
26 return Math.max(adjustedNumber, 0); 26 return Math.max(adjustedNumber, 0);
27 } 27 }
28 28
29 setBadge(direct: string | number, indirect: string | number) { 29 setBadge(direct: string | number | undefined | null, indirect: string | number | undefined | null) {
30 if (this.countCache.direct.toString() === direct.toString()
31 && this.countCache.indirect.toString() === indirect.toString()) {
32 return;
33 }
34
35 const count = { 30 const count = {
36 direct: this.safeParseInt(direct), 31 direct: this.safeParseInt(direct),
37 indirect: this.safeParseInt(indirect), 32 indirect: this.safeParseInt(indirect),
38 }; 33 };
39 34
35 if (this.countCache.direct.toString() === count.direct.toString()
36 && this.countCache.indirect.toString() === count.indirect.toString()) {
37 return;
38 }
39
40 debug('Sending badge count to host', count); 40 debug('Sending badge count to host', count);
41 ipcRenderer.sendToHost('message-counts', count); 41 ipcRenderer.sendToHost('message-counts', count);
42 42
diff --git a/src/webview/contextMenuBuilder.js b/src/webview/contextMenuBuilder.js
index 8c39e6d04..938eade1e 100644
--- a/src/webview/contextMenuBuilder.js
+++ b/src/webview/contextMenuBuilder.js
@@ -6,7 +6,8 @@
6 * 6 *
7 * Source: https://github.com/electron-userland/electron-spellchecker/blob/master/src/context-menu-builder.js 7 * Source: https://github.com/electron-userland/electron-spellchecker/blob/master/src/context-menu-builder.js
8 */ 8 */
9import { clipboard, ipcRenderer, nativeImage } from 'electron'; 9// eslint-disable-next-line no-unused-vars
10import { clipboard, ipcRenderer, nativeImage, WebContents } from 'electron';
10import { Menu, MenuItem } from '@electron/remote'; 11import { Menu, MenuItem } from '@electron/remote';
11import { cmdOrCtrlShortcutKey, isMac } from '../environment'; 12import { cmdOrCtrlShortcutKey, isMac } from '../environment';
12 13
@@ -16,7 +17,8 @@ import { openExternalUrl } from '../helpers/url-helpers';
16const { URL } = require('url'); 17const { URL } = require('url');
17 18
18function matchesWord(string) { 19function matchesWord(string) {
19 const regex = /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]+/g; 20 const regex =
21 /[A-Za-z\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]+/g;
20 22
21 return string.match(regex); 23 return string.match(regex);
22} 24}
@@ -56,12 +58,12 @@ module.exports = class ContextMenuBuilder {
56 /** 58 /**
57 * Creates an instance of ContextMenuBuilder 59 * Creates an instance of ContextMenuBuilder
58 * 60 *
59 * @param {webContents} webContents Current webContents 61 * @param {WebContents} webContents Current webContents
60 * @param {Boolean} debugMode If true, display the "Inspect Element" menu item. 62 * @param {Boolean} debugMode If true, display the "Inspect Element" menu item.
61 * @param {function} processMenu If passed, this method will be passed the menu to change 63 * @param {function} processMenu If passed, this method will be passed the menu to change
62 * it prior to display. Signature: (menu, info) => menu 64 * it prior to display. Signature: (menu, info) => menu
63 */ 65 */
64 constructor(webContents, debugMode = false, processMenu = (m) => m) { 66 constructor(webContents, debugMode = false, processMenu = m => m) {
65 this.debugMode = debugMode; 67 this.debugMode = debugMode;
66 this.processMenu = processMenu; 68 this.processMenu = processMenu;
67 this.menu = null; 69 this.menu = null;
@@ -96,7 +98,7 @@ module.exports = class ContextMenuBuilder {
96 async showPopupMenu(contextInfo) { 98 async showPopupMenu(contextInfo) {
97 const menu = await this.buildMenuForElement(contextInfo); 99 const menu = await this.buildMenuForElement(contextInfo);
98 if (!menu) return; 100 if (!menu) return;
99 menu.popup({}); 101 menu.popup();
100 } 102 }
101 103
102 /** 104 /**
@@ -115,7 +117,10 @@ module.exports = class ContextMenuBuilder {
115 return this.buildMenuForImage(info); 117 return this.buildMenuForImage(info);
116 } 118 }
117 119
118 if (info.isEditable || (info.inputFieldType && info.inputFieldType !== 'none')) { 120 if (
121 info.isEditable ||
122 (info.inputFieldType && info.inputFieldType !== 'none')
123 ) {
119 return this.buildMenuForTextInput(info); 124 return this.buildMenuForTextInput(info);
120 } 125 }
121 126
@@ -157,12 +162,17 @@ module.exports = class ContextMenuBuilder {
157 const isEmailAddress = menuInfo.linkURL.startsWith('mailto:'); 162 const isEmailAddress = menuInfo.linkURL.startsWith('mailto:');
158 163
159 const copyLink = new MenuItem({ 164 const copyLink = new MenuItem({
160 label: isEmailAddress ? this.stringTable.copyMail() : this.stringTable.copyLinkUrl(), 165 label: isEmailAddress
166 ? this.stringTable.copyMail()
167 : this.stringTable.copyLinkUrl(),
161 click: () => { 168 click: () => {
162 // Omit the mailto: portion of the link; we just want the address 169 // Omit the mailto: portion of the link; we just want the address
163 const url = isEmailAddress ? menuInfo.linkText : menuInfo.linkURL; 170 const url = isEmailAddress ? menuInfo.linkText : menuInfo.linkURL;
164 clipboard.writeText(url); 171 clipboard.writeText(url);
165 this._sendNotificationOnClipboardEvent(menuInfo.clipboardNotifications, () => `Link URL copied: ${url}`); 172 this._sendNotificationOnClipboardEvent(
173 menuInfo.clipboardNotifications,
174 () => `Link URL copied: ${url}`,
175 );
166 }, 176 },
167 }); 177 });
168 178
@@ -250,11 +260,13 @@ module.exports = class ContextMenuBuilder {
250 const webContents = this.getWebContents(); 260 const webContents = this.getWebContents();
251 // Add each spelling suggestion 261 // Add each spelling suggestion
252 for (const suggestion of menuInfo.dictionarySuggestions) { 262 for (const suggestion of menuInfo.dictionarySuggestions) {
253 menu.append(new MenuItem({ 263 menu.append(
254 label: suggestion, 264 new MenuItem({
255 // eslint-disable-next-line no-loop-func 265 label: suggestion,
256 click: () => webContents.replaceMisspelling(suggestion), 266 // eslint-disable-next-line no-loop-func
257 })); 267 click: () => webContents.replaceMisspelling(suggestion),
268 }),
269 );
258 } 270 }
259 271
260 // Allow users to add the misspelled word to the dictionary 272 // Allow users to add the misspelled word to the dictionary
@@ -262,7 +274,10 @@ module.exports = class ContextMenuBuilder {
262 menu.append( 274 menu.append(
263 new MenuItem({ 275 new MenuItem({
264 label: this.stringTable.addToDictionary(), 276 label: this.stringTable.addToDictionary(),
265 click: () => webContents.session.addWordToSpellCheckerDictionary(menuInfo.misspelledWord), 277 click: () =>
278 webContents.session.addWordToSpellCheckerDictionary(
279 menuInfo.misspelledWord,
280 ),
266 }), 281 }),
267 ); 282 );
268 } 283 }
@@ -274,7 +289,7 @@ module.exports = class ContextMenuBuilder {
274 * Adds search-related menu items. 289 * Adds search-related menu items.
275 */ 290 */
276 addSearchItems(menu, menuInfo) { 291 addSearchItems(menu, menuInfo) {
277 if (!menuInfo.selectionText || menuInfo.selectionText.length < 1) { 292 if (!menuInfo.selectionText || menuInfo.selectionText.length === 0) {
278 return menu; 293 return menu;
279 } 294 }
280 295
@@ -287,7 +302,9 @@ module.exports = class ContextMenuBuilder {
287 const webContents = this.getWebContents(); 302 const webContents = this.getWebContents();
288 303
289 const lookUpDefinition = new MenuItem({ 304 const lookUpDefinition = new MenuItem({
290 label: this.stringTable.lookUpDefinition({ word: menuInfo.selectionText.trim() }), 305 label: this.stringTable.lookUpDefinition({
306 word: menuInfo.selectionText.trim(),
307 }),
291 click: () => webContents.showDefinitionForSelection(), 308 click: () => webContents.showDefinitionForSelection(),
292 }); 309 });
293 310
@@ -295,9 +312,13 @@ module.exports = class ContextMenuBuilder {
295 } 312 }
296 313
297 const search = new MenuItem({ 314 const search = new MenuItem({
298 label: this.stringTable.searchWith({ searchEngine: SEARCH_ENGINE_NAMES[menuInfo.searchEngine] }), 315 label: this.stringTable.searchWith({
316 searchEngine: SEARCH_ENGINE_NAMES[menuInfo.searchEngine],
317 }),
299 click: () => { 318 click: () => {
300 const url = SEARCH_ENGINE_URLS[menuInfo.searchEngine]({ searchTerm: encodeURIComponent(menuInfo.selectionText) }); 319 const url = SEARCH_ENGINE_URLS[menuInfo.searchEngine]({
320 searchTerm: encodeURIComponent(menuInfo.selectionText),
321 });
301 openExternalUrl(url, true); 322 openExternalUrl(url, true);
302 }, 323 },
303 }); 324 });
@@ -319,10 +340,14 @@ module.exports = class ContextMenuBuilder {
319 const copyImage = new MenuItem({ 340 const copyImage = new MenuItem({
320 label: this.stringTable.copyImage(), 341 label: this.stringTable.copyImage(),
321 click: () => { 342 click: () => {
322 const result = this.convertImageToBase64(menuInfo.srcURL, 343 const result = this.convertImageToBase64(menuInfo.srcURL, dataURL =>
323 (dataURL) => clipboard.writeImage(nativeImage.createFromDataURL(dataURL))); 344 clipboard.writeImage(nativeImage.createFromDataURL(dataURL)),
324 345 );
325 this._sendNotificationOnClipboardEvent(menuInfo.clipboardNotifications, () => `Image copied from URL: ${menuInfo.srcURL}`); 346
347 this._sendNotificationOnClipboardEvent(
348 menuInfo.clipboardNotifications,
349 () => `Image copied from URL: ${menuInfo.srcURL}`,
350 );
326 return result; 351 return result;
327 }, 352 },
328 }); 353 });
@@ -333,7 +358,10 @@ module.exports = class ContextMenuBuilder {
333 label: this.stringTable.copyImageUrl(), 358 label: this.stringTable.copyImageUrl(),
334 click: () => { 359 click: () => {
335 const result = clipboard.writeText(menuInfo.srcURL); 360 const result = clipboard.writeText(menuInfo.srcURL);
336 this._sendNotificationOnClipboardEvent(menuInfo.clipboardNotifications, () => `Image URL copied: ${menuInfo.srcURL}`); 361 this._sendNotificationOnClipboardEvent(
362 menuInfo.clipboardNotifications,
363 () => `Image URL copied: ${menuInfo.srcURL}`,
364 );
337 return result; 365 return result;
338 }, 366 },
339 }); 367 });
@@ -345,20 +373,22 @@ module.exports = class ContextMenuBuilder {
345 const downloadImage = new MenuItem({ 373 const downloadImage = new MenuItem({
346 label: this.stringTable.downloadImage(), 374 label: this.stringTable.downloadImage(),
347 click: () => { 375 click: () => {
348 const urlWithoutBlob = menuInfo.srcURL.substr(5); 376 const urlWithoutBlob = menuInfo.srcURL.slice(5);
349 this.convertImageToBase64(menuInfo.srcURL, 377 this.convertImageToBase64(menuInfo.srcURL, dataURL => {
350 (dataURL) => { 378 const url = new window.URL(urlWithoutBlob);
351 const url = new window.URL(urlWithoutBlob); 379 const fileName = url.pathname.slice(1);
352 const fileName = url.pathname.substr(1); 380 ipcRenderer.send('download-file', {
353 ipcRenderer.send('download-file', { 381 content: dataURL,
354 content: dataURL, 382 fileOptions: {
355 fileOptions: { 383 name: fileName,
356 name: fileName, 384 mime: 'image/png',
357 mime: 'image/png', 385 },
358 },
359 });
360 }); 386 });
361 this._sendNotificationOnClipboardEvent(menuInfo.clipboardNotifications, () => `Image downloaded: ${urlWithoutBlob}`); 387 });
388 this._sendNotificationOnClipboardEvent(
389 menuInfo.clipboardNotifications,
390 () => `Image downloaded: ${urlWithoutBlob}`,
391 );
362 }, 392 },
363 }); 393 });
364 394
@@ -373,12 +403,14 @@ module.exports = class ContextMenuBuilder {
373 */ 403 */
374 addCut(menu, menuInfo) { 404 addCut(menu, menuInfo) {
375 const webContents = this.getWebContents(); 405 const webContents = this.getWebContents();
376 menu.append(new MenuItem({ 406 menu.append(
377 label: this.stringTable.cut(), 407 new MenuItem({
378 accelerator: `${cmdOrCtrlShortcutKey()}+X`, 408 label: this.stringTable.cut(),
379 enabled: menuInfo.editFlags.canCut, 409 accelerator: `${cmdOrCtrlShortcutKey()}+X`,
380 click: () => webContents.cut(), 410 enabled: menuInfo.editFlags.canCut,
381 })); 411 click: () => webContents.cut(),
412 }),
413 );
382 414
383 return menu; 415 return menu;
384 } 416 }
@@ -388,12 +420,14 @@ module.exports = class ContextMenuBuilder {
388 */ 420 */
389 addCopy(menu, menuInfo) { 421 addCopy(menu, menuInfo) {
390 const webContents = this.getWebContents(); 422 const webContents = this.getWebContents();
391 menu.append(new MenuItem({ 423 menu.append(
392 label: this.stringTable.copy(), 424 new MenuItem({
393 accelerator: `${cmdOrCtrlShortcutKey()}+C`, 425 label: this.stringTable.copy(),
394 enabled: menuInfo.editFlags.canCopy, 426 accelerator: `${cmdOrCtrlShortcutKey()}+C`,
395 click: () => webContents.copy(), 427 enabled: menuInfo.editFlags.canCopy,
396 })); 428 click: () => webContents.copy(),
429 }),
430 );
397 431
398 return menu; 432 return menu;
399 } 433 }
@@ -403,21 +437,23 @@ module.exports = class ContextMenuBuilder {
403 */ 437 */
404 addPaste(menu, menuInfo) { 438 addPaste(menu, menuInfo) {
405 const webContents = this.getWebContents(); 439 const webContents = this.getWebContents();
406 menu.append(new MenuItem({ 440 menu.append(
407 label: this.stringTable.paste(), 441 new MenuItem({
408 accelerator: `${cmdOrCtrlShortcutKey()}+V`, 442 label: this.stringTable.paste(),
409 enabled: menuInfo.editFlags.canPaste, 443 accelerator: `${cmdOrCtrlShortcutKey()}+V`,
410 click: () => webContents.paste(), 444 enabled: menuInfo.editFlags.canPaste,
411 })); 445 click: () => webContents.paste(),
446 }),
447 );
412 448
413 return menu; 449 return menu;
414 } 450 }
415 451
416 addPastePlain(menu, menuInfo) { 452 addPastePlain(menu, menuInfo) {
417 if ( 453 if (
418 menuInfo.editFlags.canPaste 454 menuInfo.editFlags.canPaste &&
419 && !menuInfo.linkText 455 !menuInfo.linkText &&
420 && !menuInfo.hasImageContents 456 !menuInfo.hasImageContents
421 ) { 457 ) {
422 const webContents = this.getWebContents(); 458 const webContents = this.getWebContents();
423 menu.append( 459 menu.append(
@@ -463,21 +499,21 @@ module.exports = class ContextMenuBuilder {
463 * @param {String} outputFormat The image format to use, defaults to 'image/png' 499 * @param {String} outputFormat The image format to use, defaults to 'image/png'
464 */ 500 */
465 convertImageToBase64(url, callback, outputFormat = 'image/png') { 501 convertImageToBase64(url, callback, outputFormat = 'image/png') {
466 let canvas = document.createElement('CANVAS'); 502 let canvas = document.createElement('canvas');
467 const ctx = canvas.getContext('2d'); 503 const ctx = canvas.getContext('2d');
468 // eslint-disable-next-line no-undef 504 // eslint-disable-next-line no-undef
469 const img = new Image(); 505 const img = new Image();
470 img.crossOrigin = 'Anonymous'; 506 img.crossOrigin = 'Anonymous';
471 507
472 img.onload = () => { 508 img.addEventListener('load', () => {
473 canvas.height = img.height; 509 canvas.height = img.height;
474 canvas.width = img.width; 510 canvas.width = img.width;
475 ctx.drawImage(img, 0, 0); 511 ctx?.drawImage(img, 0, 0);
476 512
477 const dataURL = canvas.toDataURL(outputFormat); 513 const dataURL = canvas.toDataURL(outputFormat);
478 canvas = null; 514 canvas = null;
479 callback(dataURL); 515 callback(dataURL);
480 }; 516 });
481 517
482 img.src = url; 518 img.src = url;
483 } 519 }
@@ -487,12 +523,14 @@ module.exports = class ContextMenuBuilder {
487 */ 523 */
488 goBack(menu) { 524 goBack(menu) {
489 const webContents = this.getWebContents(); 525 const webContents = this.getWebContents();
490 menu.append(new MenuItem({ 526 menu.append(
491 label: this.stringTable.goBack(), 527 new MenuItem({
492 accelerator: `${cmdOrCtrlShortcutKey()}+left`, 528 label: this.stringTable.goBack(),
493 enabled: webContents.canGoBack(), 529 accelerator: `${cmdOrCtrlShortcutKey()}+left`,
494 click: () => webContents.goBack(), 530 enabled: webContents.canGoBack(),
495 })); 531 click: () => webContents.goBack(),
532 }),
533 );
496 534
497 return menu; 535 return menu;
498 } 536 }
@@ -502,12 +540,14 @@ module.exports = class ContextMenuBuilder {
502 */ 540 */
503 goForward(menu) { 541 goForward(menu) {
504 const webContents = this.getWebContents(); 542 const webContents = this.getWebContents();
505 menu.append(new MenuItem({ 543 menu.append(
506 label: this.stringTable.goForward(), 544 new MenuItem({
507 accelerator: `${cmdOrCtrlShortcutKey()}+right`, 545 label: this.stringTable.goForward(),
508 enabled: webContents.canGoForward(), 546 accelerator: `${cmdOrCtrlShortcutKey()}+right`,
509 click: () => webContents.goForward(), 547 enabled: webContents.canGoForward(),
510 })); 548 click: () => webContents.goForward(),
549 }),
550 );
511 551
512 return menu; 552 return menu;
513 } 553 }
@@ -516,14 +556,19 @@ module.exports = class ContextMenuBuilder {
516 * Adds the 'copy page url' menu item. 556 * Adds the 'copy page url' menu item.
517 */ 557 */
518 copyPageUrl(menu, menuInfo) { 558 copyPageUrl(menu, menuInfo) {
519 menu.append(new MenuItem({ 559 menu.append(
520 label: this.stringTable.copyPageUrl(), 560 new MenuItem({
521 enabled: true, 561 label: this.stringTable.copyPageUrl(),
522 click: () => { 562 enabled: true,
523 clipboard.writeText(window.location.href); 563 click: () => {
524 this._sendNotificationOnClipboardEvent(menuInfo.clipboardNotifications, () => `Page URL copied: ${window.location.href}`); 564 clipboard.writeText(window.location.href);
525 }, 565 this._sendNotificationOnClipboardEvent(
526 })); 566 menuInfo.clipboardNotifications,
567 () => `Page URL copied: ${window.location.href}`,
568 );
569 },
570 }),
571 );
527 572
528 return menu; 573 return menu;
529 } 574 }
@@ -533,15 +578,17 @@ module.exports = class ContextMenuBuilder {
533 */ 578 */
534 goToHomePage(menu, menuInfo) { 579 goToHomePage(menu, menuInfo) {
535 const baseURL = new URL(menuInfo.pageURL); 580 const baseURL = new URL(menuInfo.pageURL);
536 menu.append(new MenuItem({ 581 menu.append(
537 label: this.stringTable.goToHomePage(), 582 new MenuItem({
538 accelerator: `${cmdOrCtrlShortcutKey()}+Home`, 583 label: this.stringTable.goToHomePage(),
539 enabled: true, 584 accelerator: `${cmdOrCtrlShortcutKey()}+Home`,
540 click: () => { 585 enabled: true,
541 // webContents.loadURL(baseURL.origin); 586 click: () => {
542 window.location.href = baseURL.origin; 587 // webContents.loadURL(baseURL.origin);
543 }, 588 window.location.href = baseURL.origin;
544 })); 589 },
590 }),
591 );
545 592
546 return menu; 593 return menu;
547 } 594 }
@@ -550,13 +597,15 @@ module.exports = class ContextMenuBuilder {
550 * Adds the 'open in browser' menu item. 597 * Adds the 'open in browser' menu item.
551 */ 598 */
552 openInBrowser(menu, menuInfo) { 599 openInBrowser(menu, menuInfo) {
553 menu.append(new MenuItem({ 600 menu.append(
554 label: this.stringTable.openInBrowser(), 601 new MenuItem({
555 enabled: true, 602 label: this.stringTable.openInBrowser(),
556 click: () => { 603 enabled: true,
557 openExternalUrl(menuInfo.pageURL, true); 604 click: () => {
558 }, 605 openExternalUrl(menuInfo.pageURL, true);
559 })); 606 },
607 }),
608 );
560 609
561 return menu; 610 return menu;
562 } 611 }
@@ -566,9 +615,8 @@ module.exports = class ContextMenuBuilder {
566 return; 615 return;
567 } 616 }
568 // eslint-disable-next-line no-new 617 // eslint-disable-next-line no-new
569 new window.Notification('Data copied into Clipboard', 618 new window.Notification('Data copied into Clipboard', {
570 { 619 body: notificationText(),
571 body: notificationText(), 620 });
572 });
573 } 621 }
574}; 622};
diff --git a/src/webview/darkmode.ts b/src/webview/darkmode.ts
index e06c22f11..7b9407049 100644
--- a/src/webview/darkmode.ts
+++ b/src/webview/darkmode.ts
@@ -1,5 +1,3 @@
1/* eslint no-bitwise: ["error", { "int32Hint": true }] */
2
3import { join } from 'path'; 1import { join } from 'path';
4import { pathExistsSync, readFileSync } from 'fs-extra'; 2import { pathExistsSync, readFileSync } from 'fs-extra';
5 3
@@ -7,7 +5,9 @@ const debug = require('debug')('Ferdi:DarkMode');
7 5
8const chars = [...'abcdefghijklmnopqrstuvwxyz']; 6const chars = [...'abcdefghijklmnopqrstuvwxyz'];
9 7
10const ID = [...Array(20)].map(() => chars[Math.random() * chars.length | 0]).join(''); 8const ID = [...Array.from({ length: 20 })]
9 .map(() => chars[Math.trunc(Math.random() * chars.length)])
10 .join('');
11 11
12export function injectDarkModeStyle(recipePath: string) { 12export function injectDarkModeStyle(recipePath: string) {
13 const darkModeStyle = join(recipePath, 'darkmode.css'); 13 const darkModeStyle = join(recipePath, 'darkmode.css');
diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js
index 2bd6bad8d..f1d493e7c 100644
--- a/src/webview/lib/RecipeWebview.js
+++ b/src/webview/lib/RecipeWebview.js
@@ -1,12 +1,14 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import { exists, pathExistsSync, readFileSync } from 'fs-extra'; 2import { BrowserWindow } from '@electron/remote';
3import { pathExistsSync, readFileSync, existsSync } from 'fs-extra';
3 4
4const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); 5const debug = require('debug')('Ferdi:Plugin:RecipeWebview');
5 6
6class RecipeWebview { 7class RecipeWebview {
7 constructor(badgeHandler, notificationsHandler) { 8 constructor(badgeHandler, notificationsHandler, sessionHandler) {
8 this.badgeHandler = badgeHandler; 9 this.badgeHandler = badgeHandler;
9 this.notificationsHandler = notificationsHandler; 10 this.notificationsHandler = notificationsHandler;
11 this.sessionHandler = sessionHandler;
10 12
11 ipcRenderer.on('poll', () => { 13 ipcRenderer.on('poll', () => {
12 this.loopFunc(); 14 this.loopFunc();
@@ -23,6 +25,16 @@ class RecipeWebview {
23 25
24 darkModeHandler = false; 26 darkModeHandler = false;
25 27
28 // TODO Remove this once we implement a proper wrapper.
29 get ipcRenderer() {
30 return ipcRenderer;
31 }
32
33 // TODO Remove this once we implement a proper wrapper.
34 get BrowserWindow() {
35 return BrowserWindow;
36 }
37
26 /** 38 /**
27 * Initialize the loop 39 * Initialize the loop
28 * 40 *
@@ -35,12 +47,12 @@ class RecipeWebview {
35 /** 47 /**
36 * Set the unread message badge 48 * Set the unread message badge
37 * 49 *
38 * @param {int} direct Set the count of direct messages 50 * @param {string | number | undefined | null} direct Set the count of direct messages
39 * eg. Slack direct mentions, or a 51 * eg. Slack direct mentions, or a
40 * message to @channel 52 * message to @channel
41 * @param {int} indirect Set a badge that defines there are 53 * @param {string | number | undefined | null} indirect Set a badge that defines there are
42 * new messages but they do not involve 54 * new messages but they do not involve
43 * me directly to me eg. in a channel 55 * me directly to me eg. in a channel
44 */ 56 */
45 setBadge(direct = 0, indirect = 0) { 57 setBadge(direct = 0, indirect = 0) {
46 this.badgeHandler.setBadge(direct, indirect); 58 this.badgeHandler.setBadge(direct, indirect);
@@ -62,12 +74,13 @@ class RecipeWebview {
62 * be an absolute path to the file 74 * be an absolute path to the file
63 */ 75 */
64 injectCSS(...files) { 76 injectCSS(...files) {
65 files.forEach(async (file) => { 77 // eslint-disable-next-line unicorn/no-array-for-each
78 files.forEach(file => {
66 if (pathExistsSync(file)) { 79 if (pathExistsSync(file)) {
67 const styles = document.createElement('style'); 80 const styles = document.createElement('style');
68 styles.innerHTML = readFileSync(file, 'utf8'); 81 styles.innerHTML = readFileSync(file, 'utf8');
69 82
70 document.querySelector('head').appendChild(styles); 83 document.querySelector('head').append(styles);
71 84
72 debug('Append styles', styles); 85 debug('Append styles', styles);
73 } 86 }
@@ -75,14 +88,16 @@ class RecipeWebview {
75 } 88 }
76 89
77 injectJSUnsafe(...files) { 90 injectJSUnsafe(...files) {
78 Promise.all(files.map(async (file) => { 91 Promise.all(
79 if (await exists(file)) { 92 files.map(file => {
80 return readFileSync(file, 'utf8'); 93 if (existsSync(file)) {
81 } 94 return readFileSync(file, 'utf8');
82 debug('Script not found', file); 95 }
83 return null; 96 debug('Script not found', file);
84 })).then(async (scripts) => { 97 return null;
85 const scriptsFound = scripts.filter((script) => script !== null); 98 }),
99 ).then(scripts => {
100 const scriptsFound = scripts.filter(script => script !== null);
86 if (scriptsFound.length > 0) { 101 if (scriptsFound.length > 0) {
87 debug('Inject scripts to main world', scriptsFound); 102 debug('Inject scripts to main world', scriptsFound);
88 ipcRenderer.sendToHost('inject-js-unsafe', ...scriptsFound); 103 ipcRenderer.sendToHost('inject-js-unsafe', ...scriptsFound);
@@ -110,6 +125,22 @@ class RecipeWebview {
110 fn(); 125 fn();
111 } 126 }
112 } 127 }
128
129 clearStorageData(serviceId, targetsToClear) {
130 ipcRenderer.send('clear-storage-data', { serviceId, targetsToClear });
131 }
132
133 releaseServiceWorkers() {
134 this.sessionHandler.releaseServiceWorkers();
135 }
136
137 setAvatarImage(avatarUrl) {
138 ipcRenderer.sendToHost('avatar', avatarUrl);
139 }
140
141 openNewWindow(url) {
142 ipcRenderer.sendToHost('new-window', url);
143 }
113} 144}
114 145
115export default RecipeWebview; 146export default RecipeWebview;
diff --git a/src/webview/lib/Userscript.js b/src/webview/lib/Userscript.js
index 2043d9fff..bed2b1ff8 100644
--- a/src/webview/lib/Userscript.js
+++ b/src/webview/lib/Userscript.js
@@ -28,7 +28,7 @@ export default class Userscript {
28 * 28 *
29 * @param {*} settings 29 * @param {*} settings
30 */ 30 */
31 // eslint-disable-next-line 31 // eslint-disable-next-line camelcase
32 internal_setSettings(settings) { 32 internal_setSettings(settings) {
33 // This is needed to get a clean JS object from the settings itself to provide better accessibility 33 // This is needed to get a clean JS object from the settings itself to provide better accessibility
34 // Otherwise this will be a mobX instance 34 // Otherwise this will be a mobX instance
@@ -95,9 +95,7 @@ export default class Userscript {
95 * @param {*} value 95 * @param {*} value
96 */ 96 */
97 set(key, value) { 97 set(key, value) {
98 window.localStorage.setItem( 98 window.localStorage.setItem(`ferdi-user-${key}`, JSON.stringify(value));
99 `ferdi-user-${key}`, JSON.stringify(value),
100 );
101 } 99 }
102 100
103 /** 101 /**
@@ -107,9 +105,7 @@ export default class Userscript {
107 * @return Value of the key 105 * @return Value of the key
108 */ 106 */
109 get(key) { 107 get(key) {
110 return JSON.parse(window.localStorage.getItem( 108 return JSON.parse(window.localStorage.getItem(`ferdi-user-${key}`));
111 `ferdi-user-${key}`,
112 ));
113 } 109 }
114 110
115 /** 111 /**
diff --git a/src/webview/notifications.js b/src/webview/notifications.js
index 205a3220c..22960d818 100644
--- a/src/webview/notifications.js
+++ b/src/webview/notifications.js
@@ -1,22 +1,26 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import uuidV1 from 'uuid/v1'; 2
3import { v1 as uuidV1 } from 'uuid';
3 4
4const debug = require('debug')('Ferdi:Notifications'); 5const debug = require('debug')('Ferdi:Notifications');
5 6
6export class NotificationsHandler { 7export class NotificationsHandler {
7 onNotify = (data) => data; 8 onNotify = data => data;
8 9
9 displayNotification(title, options) { 10 displayNotification(title, options) {
10 return new Promise((resolve) => { 11 return new Promise(resolve => {
11 debug('New notification', title, options); 12 debug('New notification', title, options);
12 13
13 const notificationId = uuidV1(); 14 const notificationId = uuidV1();
14 15
15 ipcRenderer.sendToHost('notification', this.onNotify({ 16 ipcRenderer.sendToHost(
16 title, 17 'notification',
17 options, 18 this.onNotify({
18 notificationId, 19 title,
19 })); 20 options,
21 notificationId,
22 }),
23 );
20 24
21 ipcRenderer.once(`notification-onclick:${notificationId}`, () => { 25 ipcRenderer.once(`notification-onclick:${notificationId}`, () => {
22 resolve(); 26 resolve();
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index a3ae4513f..5cab28c09 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -1,6 +1,6 @@
1/* eslint-disable global-require */
1/* eslint-disable import/first */ 2/* eslint-disable import/first */
2import { contextBridge, desktopCapturer, ipcRenderer } from 'electron'; 3import { contextBridge, ipcRenderer } from 'electron';
3import { BrowserWindow, getCurrentWebContents } from '@electron/remote';
4import { join } from 'path'; 4import { join } from 'path';
5import { autorun, computed, observable } from 'mobx'; 5import { autorun, computed, observable } from 'mobx';
6import { pathExistsSync, readFileSync } from 'fs-extra'; 6import { pathExistsSync, readFileSync } from 'fs-extra';
@@ -45,7 +45,7 @@ import {
45 getSpellcheckerLocaleByFuzzyIdentifier, 45 getSpellcheckerLocaleByFuzzyIdentifier,
46} from './spellchecker'; 46} from './spellchecker';
47 47
48import { DEFAULT_APP_SETTINGS } from '../environment'; 48import { DEFAULT_APP_SETTINGS } from '../config';
49 49
50const debug = require('debug')('Ferdi:Plugin'); 50const debug = require('debug')('Ferdi:Plugin');
51 51
@@ -100,26 +100,15 @@ window.open = (url, frameName, features) => {
100 } 100 }
101}; 101};
102 102
103// We can't override APIs here, so we first expose functions via window.ferdi, 103// We can't override APIs here, so we first expose functions via 'window.ferdi',
104// then overwrite the corresponding field of the window object by injected JS. 104// then overwrite the corresponding field of the window object by injected JS.
105contextBridge.exposeInMainWorld('ferdi', { 105contextBridge.exposeInMainWorld('ferdi', {
106 open: window.open, 106 open: window.open,
107 setBadge: (direct, indirect) => 107 setBadge: (direct, indirect) => badgeHandler.setBadge(direct, indirect),
108 badgeHandler.setBadge(direct, indirect), 108 safeParseInt: text => badgeHandler.safeParseInt(text),
109 safeParseInt: (text) =>
110 badgeHandler.safeParseInt(text),
111 displayNotification: (title, options) => 109 displayNotification: (title, options) =>
112 notificationsHandler.displayNotification(title, options), 110 notificationsHandler.displayNotification(title, options),
113 clearStorageData: (storageLocations) =>
114 sessionHandler.clearStorageData(storageLocations),
115 releaseServiceWorkers: () =>
116 sessionHandler.releaseServiceWorkers(),
117 getDisplayMediaSelector, 111 getDisplayMediaSelector,
118 getCurrentWebContents,
119 BrowserWindow,
120 ipcRenderer,
121 // TODO: When the discord recipe is changed to use the screenshare.js, this can be removed
122 desktopCapturer,
123}); 112});
124 113
125ipcRenderer.sendToHost( 114ipcRenderer.sendToHost(
@@ -173,12 +162,12 @@ class RecipeController {
173 findInPage = null; 162 findInPage = null;
174 163
175 async initialize() { 164 async initialize() {
176 Object.keys(this.ipcEvents).forEach(channel => { 165 for (const channel of Object.keys(this.ipcEvents)) {
177 ipcRenderer.on(channel, (...args) => { 166 ipcRenderer.on(channel, (...args) => {
178 debug('Received IPC event for channel', channel, 'with', ...args); 167 debug('Received IPC event for channel', channel, 'with', ...args);
179 this[this.ipcEvents[channel]](...args); 168 this[this.ipcEvents[channel]](...args);
180 }); 169 });
181 }); 170 }
182 171
183 debug('Send "hello" to host'); 172 debug('Send "hello" to host');
184 setTimeout(() => ipcRenderer.sendToHost('hello'), 100); 173 setTimeout(() => ipcRenderer.sendToHost('hello'), 100);
@@ -209,8 +198,12 @@ class RecipeController {
209 // Delete module from cache 198 // Delete module from cache
210 delete require.cache[require.resolve(modulePath)]; 199 delete require.cache[require.resolve(modulePath)];
211 try { 200 try {
212 this.recipe = new RecipeWebview(badgeHandler, notificationsHandler); 201 this.recipe = new RecipeWebview(
213 // eslint-disable-next-line 202 badgeHandler,
203 notificationsHandler,
204 sessionHandler,
205 );
206 // eslint-disable-next-line import/no-dynamic-require
214 require(modulePath)(this.recipe, { ...config, recipe }); 207 require(modulePath)(this.recipe, { ...config, recipe });
215 debug('Initialize Recipe', config, recipe); 208 debug('Initialize Recipe', config, recipe);
216 209
@@ -218,8 +211,8 @@ class RecipeController {
218 211
219 // Make sure to update the WebView, otherwise the custom darkmode handler may not be used 212 // Make sure to update the WebView, otherwise the custom darkmode handler may not be used
220 this.update(); 213 this.update();
221 } catch (err) { 214 } catch (error) {
222 console.error('Recipe initialization failed', err); 215 console.error('Recipe initialization failed', error);
223 } 216 }
224 217
225 this.loadUserFiles(recipe, config); 218 this.loadUserFiles(recipe, config);
@@ -234,12 +227,12 @@ class RecipeController {
234 const data = readFileSync(userCss); 227 const data = readFileSync(userCss);
235 styles.innerHTML += data.toString(); 228 styles.innerHTML += data.toString();
236 } 229 }
237 document.querySelector('head').appendChild(styles); 230 document.querySelector('head').append(styles);
238 231
239 const userJs = join(recipe.path, 'user.js'); 232 const userJs = join(recipe.path, 'user.js');
240 if (pathExistsSync(userJs)) { 233 if (pathExistsSync(userJs)) {
241 const loadUserJs = () => { 234 const loadUserJs = () => {
242 // eslint-disable-next-line 235 // eslint-disable-next-line import/no-dynamic-require
243 const userJsModule = require(userJs); 236 const userJsModule = require(userJs);
244 237
245 if (typeof userJsModule === 'function') { 238 if (typeof userJsModule === 'function') {
@@ -281,8 +274,8 @@ class RecipeController {
281 } 274 }
282 275
283 if (this.settings.app.enableSpellchecking) { 276 if (this.settings.app.enableSpellchecking) {
284 debug('Setting spellchecker language to', this.spellcheckerLanguage);
285 let { spellcheckerLanguage } = this; 277 let { spellcheckerLanguage } = this;
278 debug(`Setting spellchecker language to ${spellcheckerLanguage}`);
286 if (spellcheckerLanguage.includes('automatic')) { 279 if (spellcheckerLanguage.includes('automatic')) {
287 this.automaticLanguageDetection(); 280 this.automaticLanguageDetection();
288 debug( 281 debug(
@@ -291,7 +284,7 @@ class RecipeController {
291 ); 284 );
292 spellcheckerLanguage = this.settings.app.locale; 285 spellcheckerLanguage = this.settings.app.locale;
293 } 286 }
294 switchDict(spellcheckerLanguage); 287 switchDict(spellcheckerLanguage, this.settings.service.id);
295 } else { 288 } else {
296 debug('Disable spellchecker'); 289 debug('Disable spellchecker');
297 } 290 }
@@ -392,15 +385,14 @@ class RecipeController {
392 } 385 }
393 386
394 // Remove dark reader if (universal) dark mode was just disabled 387 // Remove dark reader if (universal) dark mode was just disabled
395 if (this.universalDarkModeInjected) { 388 if (
396 if ( 389 this.universalDarkModeInjected &&
397 !this.settings.app.darkMode || 390 (!this.settings.app.darkMode ||
398 !this.settings.service.isDarkModeEnabled || 391 !this.settings.service.isDarkModeEnabled ||
399 !this.settings.app.universalDarkMode 392 !this.settings.app.universalDarkMode)
400 ) { 393 ) {
401 disableDarkMode(); 394 disableDarkMode();
402 this.universalDarkModeInjected = false; 395 this.universalDarkModeInjected = false;
403 }
404 } 396 }
405 } 397 }
406 398
@@ -447,7 +439,7 @@ class RecipeController {
447 spellcheckerLocale, 439 spellcheckerLocale,
448 ); 440 );
449 if (spellcheckerLocale) { 441 if (spellcheckerLocale) {
450 switchDict(spellcheckerLocale); 442 switchDict(spellcheckerLocale, this.settings.service.id);
451 } 443 }
452 }, 225), 444 }, 225),
453 ); 445 );
diff --git a/src/webview/sessionHandler.ts b/src/webview/sessionHandler.ts
index 6a7e62ac5..0c6d23f23 100644
--- a/src/webview/sessionHandler.ts
+++ b/src/webview/sessionHandler.ts
@@ -1,28 +1,16 @@
1import { getCurrentWebContents } from '@electron/remote';
2
3const debug = require('debug')('Ferdi:Plugin:SessionHandler'); 1const debug = require('debug')('Ferdi:Plugin:SessionHandler');
4 2
5export class SessionHandler { 3export class SessionHandler {
6 clearStorageData(storageLocations: string[]) {
7 try {
8 debug('Clearing storageLocations:', storageLocations);
9 const { session } = getCurrentWebContents();
10 session.flushStorageData();
11 session.clearStorageData({ storages: storageLocations });
12 } catch (err) {
13 debug(err);
14 }
15 }
16
17 async releaseServiceWorkers() { 4 async releaseServiceWorkers() {
18 try { 5 try {
19 const registrations = await window.navigator.serviceWorker.getRegistrations(); 6 const registrations =
20 registrations.forEach(r => { 7 await window.navigator.serviceWorker.getRegistrations();
21 r.unregister(); 8 for (const registration of registrations) {
9 registration.unregister();
22 debug('ServiceWorker unregistered'); 10 debug('ServiceWorker unregistered');
23 }); 11 }
24 } catch (err) { 12 } catch (error) {
25 debug(err); 13 debug(error);
26 } 14 }
27 } 15 }
28} 16}
diff --git a/src/webview/spellchecker.ts b/src/webview/spellchecker.ts
index 30b4ef075..468a1b4ae 100644
--- a/src/webview/spellchecker.ts
+++ b/src/webview/spellchecker.ts
@@ -1,35 +1,25 @@
1import { getCurrentWebContents } from '@electron/remote'; 1import { ipcRenderer } from 'electron';
2import { SPELLCHECKER_LOCALES } from '../i18n/languages'; 2import { SPELLCHECKER_LOCALES } from '../i18n/languages';
3import { DEFAULT_APP_SETTINGS, isMac } from '../environment'; 3import { isMac } from '../environment';
4 4
5const debug = require('debug')('Ferdi:spellchecker'); 5const debug = require('debug')('Ferdi:spellchecker');
6 6
7const { session } = getCurrentWebContents();
8const [defaultLocale] = session.getSpellCheckerLanguages();
9debug('Spellchecker default locale is', defaultLocale);
10
11export function getSpellcheckerLocaleByFuzzyIdentifier(identifier: string) { 7export function getSpellcheckerLocaleByFuzzyIdentifier(identifier: string) {
12 const locales = Object.keys(SPELLCHECKER_LOCALES).filter((key) => key.toLocaleLowerCase() === identifier.toLowerCase() || key.split('-')[0] === identifier.toLowerCase()); 8 const locales = Object.keys(SPELLCHECKER_LOCALES).filter((key) => key.toLocaleLowerCase() === identifier.toLowerCase() || key.split('-')[0] === identifier.toLowerCase());
13 9
14 return locales.length >= 1 ? locales[0] : null; 10 return locales.length > 0 ? locales[0] : null;
15} 11}
16 12
17export function switchDict(locale: string) { 13export function switchDict(fuzzyLocale: string, serviceId: string) {
18 if (isMac) { 14 if (isMac) {
19 debug('Ignoring dictionary changes on macOS'); 15 debug('Ignoring dictionary changes on macOS');
20 return; 16 return;
21 } 17 }
22 18
23 debug('Setting spellchecker locale to', locale); 19 debug(`Setting spellchecker locale from: ${fuzzyLocale}`);
24 20 const locale = getSpellcheckerLocaleByFuzzyIdentifier(fuzzyLocale);
25 const locales: string[] = []; 21 if (locale) {
26 22 debug(`Sending spellcheck locales to host: ${locale}`);
27 const foundLocale = getSpellcheckerLocaleByFuzzyIdentifier(locale); 23 ipcRenderer.send('set-spellchecker-locales', { locale, serviceId });
28 if (foundLocale) {
29 locales.push(foundLocale);
30 } 24 }
31
32 locales.push(defaultLocale, DEFAULT_APP_SETTINGS.fallbackLocale);
33
34 session.setSpellCheckerLanguages(locales);
35} 25}
diff --git a/tsconfig.json b/tsconfig.json
index 2676f392d..2d9889286 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,34 @@
1{ 1{
2 "extends": "./tsconfig.settings.json",
3 "compilerOptions": { 2 "compilerOptions": {
4 "outDir": ".tmp", 3 "outDir": ".tmp",
5 "rootDir": "./" 4 "rootDir": "./",
5 "baseUrl": ".",
6 "strict": true,
7 "target": "esnext",
8 "lib": ["esnext", "dom"],
9 "module": "commonjs",
10 "jsx": "react",
11 "typeRoots": ["@types", "node_modules/@types"],
12 "moduleResolution": "node",
13 "types": ["node", "mocha"],
14 "sourceMap": true,
15 "skipLibCheck": true,
16 "noImplicitAny": false, // TODO: Need to switch
17 "allowSyntheticDefaultImports": true,
18 "experimentalDecorators": true,
19 "composite": true,
20 "esModuleInterop": true,
21 "importHelpers": true,
22 "removeComments": true,
23 "allowUnreachableCode": false,
24 "allowUnusedLabels": false,
25 "noUnusedLocals": true,
26 "noUnusedParameters": true,
27 "noImplicitReturns": true,
28 "noImplicitThis": true,
29 "preserveConstEnums": true,
30 "strictNullChecks": true,
31 "resolveJsonModule": true,
32 "forceConsistentCasingInFileNames": true
6 } 33 }
7} 34}
diff --git a/tsconfig.settings.json b/tsconfig.settings.json
deleted file mode 100644
index bd4669e01..000000000
--- a/tsconfig.settings.json
+++ /dev/null
@@ -1,28 +0,0 @@
1{
2 "extends": "@tsconfig/node14/tsconfig.json",
3 "compilerOptions": {
4 "baseUrl": ".",
5 "target": "esnext",
6 "lib": ["es2015", "es2017", "dom"],
7 "jsx": "react",
8 "typeRoots": ["node_modules/@types"],
9 "moduleResolution": "node",
10 "types": ["node"],
11 "sourceMap": true,
12 "noImplicitAny": false, // TODO: Need to switch
13 "allowSyntheticDefaultImports": true,
14 "experimentalDecorators": true,
15 "composite": true,
16 "esModuleInterop": true,
17 "importHelpers": true,
18 "removeComments": true,
19 "allowUnreachableCode": false,
20 "allowUnusedLabels": false,
21 "noUnusedLocals": true,
22 "noUnusedParameters": true,
23 "noImplicitReturns": true,
24 "noImplicitThis": true,
25 "preserveConstEnums": true,
26 "strictNullChecks": true,
27 }
28}
diff --git a/uidev/src/index.tsx b/uidev/src/index.tsx
index 99658b184..5aa3979c8 100644
--- a/uidev/src/index.tsx
+++ b/uidev/src/index.tsx
@@ -6,4 +6,4 @@ const app = () => (
6 <App /> 6 <App />
7); 7);
8 8
9render(app(), document.getElementById('root')); 9render(app(), document.querySelector('#root'));
diff --git a/uidev/src/stories/input.stories.tsx b/uidev/src/stories/input.stories.tsx
index 889539266..c92ebb36a 100644
--- a/uidev/src/stories/input.stories.tsx
+++ b/uidev/src/stories/input.stories.tsx
@@ -1,7 +1,7 @@
1import React from 'react'; 1import React from 'react';
2import uuid from 'uuid/v4';
3 2
4import { Input } from '@meetfranz/forms'; 3import { Input } from '@meetfranz/forms';
4import { v4 as uuid } from 'uuid';
5import { storiesOf } from '../stores/stories'; 5import { storiesOf } from '../stores/stories';
6 6
7const defaultProps = () => { 7const defaultProps = () => {
@@ -10,7 +10,8 @@ const defaultProps = () => {
10 label: 'Label', 10 label: 'Label',
11 id: `test-${id}`, 11 id: `test-${id}`,
12 name: `test-${id}`, 12 name: `test-${id}`,
13 onChange: (e: React.ChangeEvent<HTMLInputElement>) => console.log('changed event', e), 13 onChange: (e: React.ChangeEvent<HTMLInputElement>) =>
14 console.log('changed event', e),
14 }; 15 };
15}; 16};
16 17
@@ -21,44 +22,23 @@ const defaultPasswordProps = () => {
21 id: `test-${id}`, 22 id: `test-${id}`,
22 name: `test-${id}`, 23 name: `test-${id}`,
23 type: 'password', 24 type: 'password',
24 onChange: (e: React.ChangeEvent<HTMLInputElement>) => console.log('changed event', e), 25 onChange: (e: React.ChangeEvent<HTMLInputElement>) =>
26 console.log('changed event', e),
25 }; 27 };
26}; 28};
27 29
28storiesOf('Input') 30storiesOf('Input')
29 .add('Basic', () => ( 31 .add('Basic', () => (
30 <Input 32 <Input {...defaultProps()} placeholder="Placeholder text" />
31 {...defaultProps()}
32 placeholder="Placeholder text"
33 />
34 ))
35 .add('Without Label', () => (
36 <Input
37 {...defaultProps()}
38 showLabel={false}
39 />
40 ))
41 .add('Disabled', () => (
42 <Input {...defaultProps()} disabled />
43 ))
44 .add('With prefix', () => (
45 <Input
46 {...defaultProps()}
47 prefix="https://"
48 />
49 )) 33 ))
34 .add('Without Label', () => <Input {...defaultProps()} showLabel={false} />)
35 .add('Disabled', () => <Input {...defaultProps()} disabled />)
36 .add('With prefix', () => <Input {...defaultProps()} prefix="https://" />)
50 .add('With suffix', () => ( 37 .add('With suffix', () => (
51 <Input 38 <Input {...defaultProps()} suffix=".meetfranz.com" />
52 {...defaultProps()}
53 suffix=".meetfranz.com"
54 />
55 )) 39 ))
56 .add('With pre-suffix', () => ( 40 .add('With pre-suffix', () => (
57 <Input 41 <Input {...defaultProps()} prefix="https://" suffix=".meetfranz.com" />
58 {...defaultProps()}
59 prefix="https://"
60 suffix=".meetfranz.com"
61 />
62 )) 42 ))
63 .add('With error', () => ( 43 .add('With error', () => (
64 <Input 44 <Input
@@ -68,32 +48,16 @@ storiesOf('Input')
68 /> 48 />
69 )) 49 ))
70 .add('Type number with min & max', () => ( 50 .add('Type number with min & max', () => (
71 <Input 51 <Input {...defaultProps()} type="number" min={1} max={10} />
72 {...defaultProps()}
73 type="number"
74 min={1}
75 max={10}
76 />
77 )); 52 ));
78 53
79storiesOf('Password') 54storiesOf('Password')
80 .add('Basic', () => ( 55 .add('Basic', () => <Input {...defaultPasswordProps()} />)
81 <Input
82 {...defaultPasswordProps()}
83 />
84 ))
85 .add('Show password toggle', () => ( 56 .add('Show password toggle', () => (
86 <Input 57 <Input {...defaultPasswordProps()} showPasswordToggle />
87 {...defaultPasswordProps()}
88 showPasswordToggle
89 />
90 )) 58 ))
91 .add('Score password', () => ( 59 .add('Score password', () => (
92 <Input 60 <Input {...defaultPasswordProps()} showPasswordToggle scorePassword />
93 {...defaultPasswordProps()}
94 showPasswordToggle
95 scorePassword
96 />
97 )) 61 ))
98 .add('Score password with error', () => ( 62 .add('Score password with error', () => (
99 <Input 63 <Input
diff --git a/uidev/src/stories/select.stories.tsx b/uidev/src/stories/select.stories.tsx
index 51ec6ed88..93e072cd9 100644
--- a/uidev/src/stories/select.stories.tsx
+++ b/uidev/src/stories/select.stories.tsx
@@ -1,5 +1,5 @@
1import React from 'react'; 1import React from 'react';
2import uuid from 'uuid/v4'; 2import { v4 as uuid } from 'uuid';
3 3
4import { Select } from '@meetfranz/forms'; 4import { Select } from '@meetfranz/forms';
5import { storiesOf } from '../stores/stories'; 5import { storiesOf } from '../stores/stories';
@@ -282,35 +282,18 @@ const defaultProps = () => {
282 }, 282 },
283 actionText: 'Select country', 283 actionText: 'Select country',
284 // defaultValue: 'AT', 284 // defaultValue: 'AT',
285 onChange: (e: React.ChangeEvent<HTMLInputElement>) => console.log('changed event', e), 285 onChange: (e: React.ChangeEvent<HTMLInputElement>) =>
286 console.log('changed event', e),
286 }; 287 };
287}; 288};
288 289
289storiesOf('Select') 290storiesOf('Select')
290 .add('Basic', () => ( 291 .add('Basic', () => <Select {...defaultProps()} />)
291 <Select
292 {...defaultProps()}
293 />
294 ))
295 .add('With preselection', () => ( 292 .add('With preselection', () => (
296 <Select 293 <Select {...defaultProps()} defaultValue="AT" />
297 {...defaultProps()}
298 defaultValue="AT"
299 />
300 ))
301 .add('With search', () => (
302 <Select
303 {...defaultProps()}
304 showSearch
305 />
306 ))
307 .add('Disabled', () => (
308 <Select
309 {...defaultProps()}
310 showSearch
311 disabled
312 />
313 )) 294 ))
295 .add('With search', () => <Select {...defaultProps()} showSearch />)
296 .add('Disabled', () => <Select {...defaultProps()} showSearch disabled />)
314 .add('With error', () => ( 297 .add('With error', () => (
315 <Select 298 <Select
316 {...defaultProps()} 299 {...defaultProps()}
diff --git a/uidev/src/stories/textarea.stories.tsx b/uidev/src/stories/textarea.stories.tsx
index 1ab21820b..09b9fef70 100644
--- a/uidev/src/stories/textarea.stories.tsx
+++ b/uidev/src/stories/textarea.stories.tsx
@@ -1,5 +1,5 @@
1import React from 'react'; 1import React from 'react';
2import uuid from 'uuid/v4'; 2import { v4 as uuid } from 'uuid';
3 3
4import { Textarea } from '@meetfranz/forms'; 4import { Textarea } from '@meetfranz/forms';
5import { storiesOf } from '../stores/stories'; 5import { storiesOf } from '../stores/stories';
@@ -11,7 +11,8 @@ const defaultProps = () => {
11 id: `test-${id}`, 11 id: `test-${id}`,
12 name: `test-${id}`, 12 name: `test-${id}`,
13 rows: 5, 13 rows: 5,
14 onChange: (e: React.ChangeEvent<HTMLInputElement>) => console.log('changed event', e), 14 onChange: (e: React.ChangeEvent<HTMLInputElement>) =>
15 console.log('changed event', e),
15 }; 16 };
16}; 17};
17 18
@@ -22,22 +23,8 @@ storiesOf('Textarea')
22 // placeholder="Placeholder text" 23 // placeholder="Placeholder text"
23 /> 24 />
24 )) 25 ))
25 .add('10 rows', () => ( 26 .add('10 rows', () => <Textarea {...defaultProps()} rows={10} />)
26 <Textarea
27 {...defaultProps()}
28 rows={10}
29 />
30 ))
31 .add('With error', () => ( 27 .add('With error', () => (
32 <Textarea 28 <Textarea {...defaultProps()} error="This is a generic error message." />
33 {...defaultProps()}
34 error="This is a generic error message."
35 />
36 )) 29 ))
37 .add('Disabled', () => ( 30 .add('Disabled', () => <Textarea {...defaultProps()} rows={2} disabled />);
38 <Textarea
39 {...defaultProps()}
40 rows={2}
41 disabled
42 />
43 ));
diff --git a/uidev/src/stories/toggle.stories.tsx b/uidev/src/stories/toggle.stories.tsx
index af6b282bc..f54e67596 100644
--- a/uidev/src/stories/toggle.stories.tsx
+++ b/uidev/src/stories/toggle.stories.tsx
@@ -1,7 +1,7 @@
1import { observable } from 'mobx'; 1import { observable } from 'mobx';
2import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
3import React from 'react'; 3import React from 'react';
4import uuid from 'uuid/v4'; 4import { v4 as uuid } from 'uuid';
5 5
6import { Toggle } from '@meetfranz/forms'; 6import { Toggle } from '@meetfranz/forms';
7import { storiesOf } from '../stores/stories'; 7import { storiesOf } from '../stores/stories';
@@ -16,14 +16,17 @@ interface IStoreArgs {
16 error?: string; 16 error?: string;
17} 17}
18 18
19const createStore = (args?: IStoreArgs) => observable({ id: `element-${uuid()}`, 19const createStore = (args?: IStoreArgs) =>
20 observable({
21 id: `element-${uuid()}`,
20 name: 'toggle', 22 name: 'toggle',
21 label: 'Label', 23 label: 'Label',
22 value: true, 24 value: true,
23 checked: false, 25 checked: false,
24 disabled: false, 26 disabled: false,
25 error: '', 27 error: '',
26...args }); 28 ...args,
29 });
27 30
28const WithStoreToggle = observer(({ store }: { store: any }) => ( 31const WithStoreToggle = observer(({ store }: { store: any }) => (
29 <> 32 <>
@@ -35,37 +38,40 @@ const WithStoreToggle = observer(({ store }: { store: any }) => (
35 name={store.name} 38 name={store.name}
36 disabled={store.disabled} 39 disabled={store.disabled}
37 error={store.error} 40 error={store.error}
38 onChange={() => store.checked = !store.checked} 41 onChange={() => (store.checked = !store.checked)}
39 /> 42 />
40 </> 43 </>
41)); 44));
42 45
43storiesOf('Toggle') 46storiesOf('Toggle')
44 .add('Basic', () => ( 47 .add('Basic', () => <WithStoreToggle store={createStore()} />)
45 <WithStoreToggle store={createStore()} />
46 ))
47 .add('Checked', () => ( 48 .add('Checked', () => (
48 <WithStoreToggle store={createStore({ 49 <WithStoreToggle
49 checked: true, 50 store={createStore({
50 })} 51 checked: true,
52 })}
51 /> 53 />
52 )) 54 ))
53 .add('Disabled', () => ( 55 .add('Disabled', () => (
54 <WithStoreToggle store={createStore({ 56 <WithStoreToggle
55 checked: true, 57 store={createStore({
56 disabled: true, 58 checked: true,
57 })} 59 disabled: true,
60 })}
58 /> 61 />
59 )) 62 ))
60 .add('Long label', () => ( 63 .add('Long label', () => (
61 <WithStoreToggle store={createStore({ 64 <WithStoreToggle
62 label: 'Hello world, this is an insanely long label for this toggle. We need to make sure that it will be displayed correctly.', 65 store={createStore({
63 })} 66 label:
67 'Hello world, this is an insanely long label for this toggle. We need to make sure that it will be displayed correctly.',
68 })}
64 /> 69 />
65 )) 70 ))
66 .add('With error', () => ( 71 .add('With error', () => (
67 <WithStoreToggle store={createStore({ 72 <WithStoreToggle
68 error: 'Something went wrong', 73 store={createStore({
69 })} 74 error: 'Something went wrong',
75 })}
70 /> 76 />
71 )); 77 ));
diff --git a/uidev/tsconfig.json b/uidev/tsconfig.json
index fb57639c8..60459d69e 100644
--- a/uidev/tsconfig.json
+++ b/uidev/tsconfig.json
@@ -1,14 +1,16 @@
1{ 1{
2 "extends": "../tsconfig.settings.json", 2 "extends": "../tsconfig.json",
3 "compilerOptions": { 3 "compilerOptions": {
4 "baseUrl": "..", 4 "baseUrl": "..",
5 "outDir": "lib", 5 "outDir": "lib",
6 "rootDir": "src", 6 "rootDir": "src"
7 }, 7 },
8 "references": [{ 8 "references": [
9 "path": "../packages/theme" 9 {
10 }, 10 "path": "../packages/theme"
11 { 11 },
12 "path": "../packages/forms" 12 {
13 }] 13 "path": "../packages/forms"
14 }
15 ]
14} 16}