diff --git a/backend/locales/en.json b/backend/locales/en.json
index 09d1461554..d0287fd335 100644
--- a/backend/locales/en.json
+++ b/backend/locales/en.json
@@ -60,6 +60,7 @@
"admin.api.revokedHint": "This key has been revoked and can no longer be used.",
"admin.api.subtitle": "Manage keys to access the API",
"admin.api.title": "API Access",
+ "admin.api.switchStateFailed": "Failed to switch API state.",
"admin.api.toggleStateDisabledSuccess": "API has been disabled successfully.",
"admin.api.toggleStateEnabledSuccess": "API has been enabled successfully.",
"admin.approval.title": "Approvals",
@@ -109,12 +110,16 @@
"admin.auth.strategyStateLocked": "and cannot be disabled.",
"admin.auth.subtitle": "Configure the authentication settings of your wiki",
"admin.auth.title": "Authentication",
+ "admin.auth.deleteStrategy": "Delete Strategy",
+ "admin.auth.saveFailed": "Failed to save authentication configuration.",
"admin.auth.vendor": "Vendor",
"admin.auth.vendorWebsite": "Website",
"admin.blocks.add": "Add Block",
"admin.blocks.builtin": "Built-in",
"admin.blocks.custom": "Custom",
+ "admin.blocks.fetchFailed": "Failed to fetch blocks state.",
"admin.blocks.isEnabled": "Enabled",
+ "admin.blocks.saveFailed": "Failed to save blocks state.",
"admin.blocks.saveSuccess": "Blocks state saved successfully.",
"admin.blocks.subtitle": "Manage dynamic components available for use inside pages.",
"admin.blocks.title": "Content Blocks",
@@ -182,6 +187,9 @@
"admin.editors.markdownName": "Markdown Editor",
"admin.editors.redirectDescription": "Create redirections to other pages / external links.",
"admin.editors.redirectName": "Redirection",
+ "admin.editors.fetchFailed": "Failed to fetch editors state.",
+ "admin.editors.invalidConfigCall": "Invalid call to config:",
+ "admin.editors.saveFailed": "Failed to save editors state.",
"admin.editors.saveSuccess": "Editors state saved successfully.",
"admin.editors.subtitle": "Manage editors and their configuration",
"admin.editors.title": "Editors",
@@ -209,6 +217,8 @@
"admin.flags.experimental.label": "Experimental Features",
"admin.flags.getTokenHint": "Copy your current authentication token for use in GraphQL API testing.",
"admin.flags.getTokenLabel": "Get Current Token",
+ "admin.flags.tokenCopyFailed": "Failed to copy current token to clipboard.",
+ "admin.flags.tokenCopySuccess": "Current token copied to clipboard.",
"admin.flags.saveSuccess": "Flags have been updated successfully.",
"admin.flags.sqlLog.hint": "Log all queries made to the database to console.",
"admin.flags.sqlLog.label": "SQL Query Logging",
@@ -251,6 +261,7 @@
"admin.general.displaySiteTitleHint": "Should the site title be displayed next to the logo? If your logo isn't square and contain your brand name, turn this option off.",
"admin.general.favicon": "Favicon",
"admin.general.faviconHint": "Favicon image file, in SVG, PNG, JPG, WEBP or GIF format. Must be a square image.",
+ "admin.general.faviconUploadFailed": "Failed to upload site favicon.",
"admin.general.faviconUploadSuccess": "Site Favicon uploaded successfully.",
"admin.general.features": "Features",
"admin.general.footerCopyright": "Footer / Copyright",
@@ -260,6 +271,7 @@
"admin.general.logo": "Logo",
"admin.general.logoUpl": "Site Logo",
"admin.general.logoUplHint": "Logo image file, in SVG, PNG, JPG, WEBP or GIF format.",
+ "admin.general.logoUploadFailed": "Failed to upload site logo.",
"admin.general.logoUploadSuccess": "Site logo uploaded successfully.",
"admin.general.pageCasing": "Case Sensitive Paths",
"admin.general.pageCasingHint": "Treat paths with different casing as distinct pages.",
@@ -273,6 +285,7 @@
"admin.general.reasonForChangeOff": "Off",
"admin.general.reasonForChangeOptional": "Optional",
"admin.general.reasonForChangeRequired": "Required",
+ "admin.general.saveFailed": "Failed to save general configuration.",
"admin.general.saveSuccess": "Site configuration saved successfully.",
"admin.general.searchAllowFollow": "Allow Search Engines to Follow Links",
"admin.general.searchAllowFollowHint": "This sets the meta-robots property to follow or nofollow.",
@@ -319,8 +332,11 @@
"admin.groups.exportRules": "Export Rules",
"admin.groups.exportRulesNoneError": "This group has no rule to export!",
"admin.groups.filterUsers": "Filter...",
+ "admin.groups.fetchDetailsFailed": "Failed to fetch group details.",
+ "admin.groups.fetchUsersFailed": "Failed to fetch group users.",
"admin.groups.general": "General",
"admin.groups.importFailed": "Something went wrong while importing this file. Making sure it is a valid rules JSON file.",
+ "admin.groups.invalidRulesFormat": "Invalid rules format.",
"admin.groups.importModeAdd": "Add to Existing",
"admin.groups.importModeReplace": "Replace All",
"admin.groups.importModeText": "Do you want to replace all existing rules with these ones or add these rules to the existing ones?",
@@ -328,6 +344,7 @@
"admin.groups.importRules": "Import Rules",
"admin.groups.importSuccess": "Rules imported successfully!",
"admin.groups.info": "Group Info",
+ "admin.groups.newRule": "New Rule",
"admin.groups.name": "Group Name",
"admin.groups.nameHint": "Name of the group",
"admin.groups.overview": "Overview",
@@ -338,7 +355,45 @@
"admin.groups.redirectOnLoginHint": "The path / URL where the user will be redirected upon successful login. Leave empty to use the site-defined value.",
"admin.groups.redirectOnLogout": "Redirect on Logout",
"admin.groups.redirectOnLogoutHint": "The path / URL where the user will be redirected upon logout. Leave empty to use the site-defined value.",
+ "admin.groups.loadFailed": "Failed to load groups state.",
"admin.groups.refreshSuccess": "Groups refreshed successfully.",
+ "admin.groups.permissions.accessAdminHint": "Can access the administration area.",
+ "admin.groups.permissions.manageUsersHint": "Can create and manage users, except users with administrative permissions.",
+ "admin.groups.permissions.manageGroupsHint": "Can create and manage groups, assign permissions, and manage page rules, except manage:system.",
+ "admin.groups.permissions.manageNavigationHint": "Can manage site navigation.",
+ "admin.groups.permissions.manageThemeHint": "Can modify site theme settings.",
+ "admin.groups.permissions.manageSitesHint": "Can create and manage sites.",
+ "admin.groups.permissions.manageSystemHint": "Can manage and access everything. Root administrator.",
+ "admin.groups.permissions.readPagesTitle": "Read Pages",
+ "admin.groups.permissions.readPagesHint": "Can view and search pages.",
+ "admin.groups.permissions.writePagesTitle": "Write Pages",
+ "admin.groups.permissions.writePagesHint": "Can create and edit pages.",
+ "admin.groups.permissions.reviewPagesTitle": "Review Pages",
+ "admin.groups.permissions.reviewPagesHint": "Can review and approve edits submitted by users.",
+ "admin.groups.permissions.managePagesTitle": "Manage Pages",
+ "admin.groups.permissions.managePagesHint": "Can move existing pages to other locations the user has write access to.",
+ "admin.groups.permissions.deletePagesTitle": "Delete Pages",
+ "admin.groups.permissions.deletePagesHint": "Can delete existing pages.",
+ "admin.groups.permissions.useCssTitle": "Use CSS",
+ "admin.groups.permissions.useCssHint": "Can insert CSS styles in pages.",
+ "admin.groups.permissions.useJavaScriptTitle": "Use JavaScript",
+ "admin.groups.permissions.useJavaScriptHint": "Can insert JavaScript in pages.",
+ "admin.groups.permissions.viewPageSourceTitle": "View Page Source",
+ "admin.groups.permissions.viewPageSourceHint": "Can view page source.",
+ "admin.groups.permissions.viewPageHistoryTitle": "View Page History",
+ "admin.groups.permissions.viewPageHistoryHint": "Can view previous versions of pages.",
+ "admin.groups.permissions.viewAssetsTitle": "View Assets",
+ "admin.groups.permissions.viewAssetsHint": "Can view and use assets, such as images and files, in pages.",
+ "admin.groups.permissions.uploadAssetsTitle": "Upload Assets",
+ "admin.groups.permissions.uploadAssetsHint": "Can upload new assets, such as images and files.",
+ "admin.groups.permissions.manageAssetsTitle": "Manage Assets",
+ "admin.groups.permissions.manageAssetsHint": "Can edit and delete existing assets, such as images and files.",
+ "admin.groups.permissions.readCommentsTitle": "Read Comments",
+ "admin.groups.permissions.readCommentsHint": "Can view page comments.",
+ "admin.groups.permissions.writeCommentsTitle": "Write Comments",
+ "admin.groups.permissions.writeCommentsHint": "Can post new comments on pages.",
+ "admin.groups.permissions.manageCommentsTitle": "Manage Comments",
+ "admin.groups.permissions.manageCommentsHint": "Can edit and delete existing page comments.",
"admin.groups.ruleAllow": "Allow",
"admin.groups.ruleDeny": "Deny",
"admin.groups.ruleForceAllow": "Force Allow",
@@ -371,9 +426,11 @@
"admin.instances.activeListeners": "Active Listeners",
"admin.instances.firstSeen": "First Seen",
"admin.instances.lastSeen": "Last Seen",
+ "admin.instances.loadFailed": "Failed to load instances list.",
"admin.instances.subtitle": "View a list of active instances",
"admin.instances.title": "Instances",
"admin.locale.active": "Active Locales",
+ "admin.locale.activeHint": "The list of locale packs currently enabled for this site.",
"admin.locale.activeNamespaces": "Active Namespaces",
"admin.locale.autoUpdate.hint": "Automatically download updates to this locale as they become available.",
"admin.locale.autoUpdate.hintWithNS": "Automatically download updates to all namespaced locales enabled below.",
@@ -401,11 +458,13 @@
"admin.locale.settings": "Locale Settings",
"admin.locale.sideload": "Sideload Locale Package",
"admin.locale.sideloadHelp": "If you are not connected to the internet or cannot download locale files using the method above, you can instead sideload packages manually by uploading them below.",
+ "admin.locale.saveSuccess": "Locale settings saved successfully.",
"admin.locale.subtitle": "Set localization options for your wiki",
"admin.locale.title": "Locale",
"admin.logging.title": "Logging",
"admin.login.background": "Background Image",
"admin.login.backgroundHint": "Specify an image to use as the login background. PNG and JPG are supported, 1920x1080 recommended. Leave empty for default.",
+ "admin.login.bgUploadFailed": "Failed to upload login background image.",
"admin.login.bgUploadSuccess": "Login background image uploaded successfully.",
"admin.login.bypassScreen": "Bypass Login Screen",
"admin.login.bypassScreenHint": "Should the user be redirected automatically to the first authentication provider. Has no effect if the first provider is a username/password provider type.",
@@ -418,6 +477,7 @@
"admin.login.logoutRedirectHint": "Optionally redirect the user to a specific page when he/she logouts. This can be overridden at the group level.",
"admin.login.providers": "Login Providers",
"admin.login.providersVisbleWarning": "Note that you can always temporarily show all hidden providers by adding ?all=1 to the url. This is useful to login as local admin while hiding it from normal users.",
+ "admin.login.saveFailed": "Failed to save login configuration.",
"admin.login.saveSuccess": "Login configuration saved successfully.",
"admin.login.subtitle": "Configure the login user experience of your wiki site",
"admin.login.title": "Login",
@@ -435,6 +495,7 @@
"admin.mail.dkimPrivateKeyHint": "Private key for the selector in PEM format",
"admin.mail.dkimUse": "Use DKIM",
"admin.mail.dkimUseHint": "Should DKIM be used when sending emails.",
+ "admin.mail.fetchConfigFailed": "Failed to fetch mail configuration.",
"admin.mail.saveSuccess": "Configuration saved successfully.",
"admin.mail.sendTestSuccess": "A test email was sent successfully.",
"admin.mail.sender": "Sender",
@@ -472,6 +533,7 @@
"admin.metrics.endpoint": "The metrics endpoint can be scraped at {endpoint}",
"admin.metrics.endpointWarning": "Note that this override any page at this path.",
"admin.metrics.refreshSuccess": "Metrics endpoint state has been refreshed.",
+ "admin.metrics.switchStateFailed": "Failed to switch metrics endpoint state.",
"admin.metrics.subtitle": "Manage the Prometheus metrics endpoint",
"admin.metrics.title": "Metrics",
"admin.metrics.toggleStateDisabledSuccess": "Metrics endpoint disabled successfully.",
@@ -506,6 +568,7 @@
"admin.navigation.navType.searchQuery": "Search Query",
"admin.navigation.noItemsText": "Click the Add button to add your first navigation item.",
"admin.navigation.noSelectionText": "Select a navigation item on the left.",
+ "admin.navigation.refreshSuccess": "Navigation has been refreshed.",
"admin.navigation.saveSuccess": "Navigation saved successfully.",
"admin.navigation.selectPageButton": "Select Page...",
"admin.navigation.sourceLocale": "Source Locale",
@@ -517,7 +580,25 @@
"admin.navigation.untitled": "Untitled {kind}",
"admin.navigation.visibilityMode.all": "Visible to everyone",
"admin.navigation.visibilityMode.restricted": "Visible to select groups...",
+ "admin.pages.locale": "Locale",
+ "admin.pages.localeAll": "All Locales",
+ "admin.pages.none": "No pages to display.",
+ "admin.pages.publishState": "Publish State",
+ "admin.pages.publishStateAll": "All Publishing States",
+ "admin.pages.publishStatePublished": "Published",
+ "admin.pages.publishStateUnpublished": "Not Published",
+ "admin.pages.recycleBin": "Recycle Bin",
+ "admin.pages.refreshSuccess": "Page list has been refreshed.",
+ "admin.pages.searchPlaceholder": "Search Pages...",
+ "admin.pages.subtitle": "Manage pages",
"admin.pages.title": "Pages",
+ "admin.pages.visualize": "Visualize",
+ "admin.pages.visualizeEmpty": "Looks like there's no data yet to graph!",
+ "admin.pages.visualizeModeHierarchicalRadial": "Hierarchical Radial",
+ "admin.pages.visualizeModeRelationalRadial": "Relational Radial",
+ "admin.pages.visualizeModeTree": "Hierarchical Tree",
+ "admin.pages.visualizeSubtitle": "Dendrogram representation of your pages",
+ "admin.pages.visualizeTitle": "Visualize Pages",
"admin.rendering.subtitle": "Configure the content rendering pipeline",
"admin.rendering.title": "Rendering",
"admin.scheduler.active": "Active",
@@ -535,9 +616,12 @@
"admin.scheduler.failed": "Failed",
"admin.scheduler.failedNone": "There are no recently failed job to display.",
"admin.scheduler.interrupted": "Interrupted",
+ "admin.scheduler.loadFailed": "Failed to load scheduler jobs.",
"admin.scheduler.pending": "Pending",
"admin.scheduler.result": "Result",
"admin.scheduler.retryJob": "Retry Job",
+ "admin.scheduler.cancelJobFailed": "Failed to cancel job.",
+ "admin.scheduler.retryJobFailed": "Failed to retry job.",
"admin.scheduler.retryJobSuccess": "Job has been rescheduled and will execute shortly.",
"admin.scheduler.schedule": "Schedule",
"admin.scheduler.scheduled": "Scheduled",
@@ -560,9 +644,12 @@
"admin.search.highlighting": "Enable Term Highlighting",
"admin.search.highlightingHint": "Whether to show the highlighted terms in search results. There is a slight performance impact when enabled.",
"admin.search.indexRebuildSuccess": "Index rebuilt successfully.",
+ "admin.search.loadFailed": "Failed to load search engine state.",
"admin.search.listRefreshSuccess": "List of search engines has been refreshed.",
"admin.search.rebuildIndex": "Rebuild Index",
+ "admin.search.rebuildFailed": "Failed to rebuild search index.",
"admin.search.rebuildInitSuccess": "A search index rebuild has been initiated and will start shortly.",
+ "admin.search.saveFailed": "Failed to save search engine configuration.",
"admin.search.saveSuccess": "Search engine configuration saved successfully",
"admin.search.searchEngine": "Search Engine",
"admin.search.subtitle": "Configure the search capabilities of your wiki",
@@ -602,6 +689,7 @@
"admin.security.maxUploadSize": "Max Upload Size",
"admin.security.maxUploadSizeHint": "The maximum size for a single file. Final value in base 2.",
"admin.security.maxUploadSizeSuffix": "bytes",
+ "admin.security.saveFailed": "Failed to save security configuration.",
"admin.security.saveSuccess": "Security configuration updated successfully.",
"admin.security.scanSVG": "Scan and Sanitize SVG Uploads",
"admin.security.scanSVGHint": "Should SVG uploads be scanned for vulnerabilities and stripped of any potentially unsafe content.",
@@ -689,6 +777,7 @@
"admin.storage.contentTypeLargeFilesThreshold": "Size Threshold",
"admin.storage.contentTypeOthers": "Others",
"admin.storage.contentTypeOthersHint": "Any other file types that don't match the other categories.",
+ "admin.storage.loadFailed": "Failed to load storage targets.",
"admin.storage.contentTypePages": "Pages",
"admin.storage.contentTypePagesHint": "Page content source, in Markdown, HTML or JSON format depending on the editor.",
"admin.storage.contentTypes": "Content Types",
@@ -786,6 +875,9 @@
"admin.system.checkUpdate": "Check / Upgrade",
"admin.system.checkingForUpdates": "Checking for Updates...",
"admin.system.client": "Client",
+ "admin.system.copyInfoFailed": "Failed to copy system info.",
+ "admin.system.copyInfoSuccess": "System info copied successfully.",
+ "admin.system.copySystemInfo": "Copy System Info",
"admin.system.clientCookies": "Cookies Support",
"admin.system.clientCookiesHint": "Whether cookies are enabled on this browser.",
"admin.system.clientLanguage": "Primary Language",
@@ -883,6 +975,7 @@
"admin.theme.fonts": "Fonts",
"admin.theme.headHtmlInjection": "Head HTML Injection",
"admin.theme.headHtmlInjectionHint": "HTML code to be injected just before the closing head tag. Usually for script tags.",
+ "admin.theme.fetchFailed": "Failed to fetch theme configuration.",
"admin.theme.headerColor": "Header Color",
"admin.theme.headerColorHint": "The background color for the site top header. Does not apply to the administration area.",
"admin.theme.iconset": "Icon Set",
@@ -894,6 +987,7 @@
"admin.theme.reduceMotion": "Reduce Motion",
"admin.theme.reduceMotionHint": "Disable most site animations. This setting is automatically enforced when the reduced motion flag is enabled on the user OS.",
"admin.theme.resetDefaults": "Reset Defaults",
+ "admin.theme.saveFailed": "Failed to save theme configuration.",
"admin.theme.saveSuccess": "Theme configuration saved successfully!",
"admin.theme.secondaryColor": "Secondary Color",
"admin.theme.secondaryColorHint": "The alternate color for secondary action buttons and for some other elements.",
@@ -937,6 +1031,8 @@
"admin.users.dateFormat": "Date Format",
"admin.users.dateFormatHint": "How dates should be formatted when displayed to the user.",
"admin.users.defaults": "Manage User Defaults",
+ "admin.users.defaultsLoadFailed": "Failed to load user defaults.",
+ "admin.users.defaultsSaveFailed": "Failed to save user defaults.",
"admin.users.defaultsSaveSuccess": "User defaults saved successfully.",
"admin.users.delete": "Delete User",
"admin.users.deleteConfirmForeignNotice": "Note that you cannot delete a user that already created content. You must instead either deactivate the user or delete all content that was created by that user.",
@@ -951,6 +1047,7 @@
"admin.users.emailInvalid": "Email address is invalid.",
"admin.users.emailMissing": "Email address is missing.",
"admin.users.extendedMetadata": "Extended Metadata",
+ "admin.users.fetchDetailsFailed": "Failed to fetch user details.",
"admin.users.groupAlreadyAssigned": "User is already assigned to this group.",
"admin.users.groupAssign": "Assign",
"admin.users.groupAssignNotice": "Note that you cannot assign users to the Administrators or Guests groups from this panel.",
@@ -1054,6 +1151,7 @@
"admin.utilities.contentSubtitle": "Various tools for pages",
"admin.utilities.contentTitle": "Content",
"admin.utilities.disconnectWS": "Disconnect WebSocket Sessions",
+ "admin.utilities.disconnectWSFailed": "Failed to disconnect WS connections.",
"admin.utilities.disconnectWSHint": "Force all active websocket connections to be closed.",
"admin.utilities.disconnectWSSuccess": "All active websocket connections have been terminated.",
"admin.utilities.export": "Export",
@@ -1092,6 +1190,7 @@
"admin.webhooks.deleteConfirmWarn": "This action cannot be undone!",
"admin.webhooks.deleteSuccess": "Webhook deleted successfully.",
"admin.webhooks.edit": "Edit Webhook",
+ "admin.webhooks.fetchConfigFailed": "Failed to fetch webhook configuration.",
"admin.webhooks.eventCreatePage": "Create a new page",
"admin.webhooks.eventDeleteAsset": "Delete an asset",
"admin.webhooks.eventDeleteComment": "Delete a comment",
@@ -1164,6 +1263,7 @@
"auth.errors.passwordTooShort": "Password is too short.",
"auth.errors.passwordsNotMatch": "Passwords do not match.",
"auth.errors.register": "One or more fields are invalid.",
+ "auth.errors.unexpectedResponse": "Unexpected authentication response.",
"auth.errors.tfaMissing": "Missing or incomplete security code.",
"auth.errors.tooManyAttempts": "Too many attempts!",
"auth.errors.tooManyAttemptsMsg": "You've made too many failed attempts in a short period of time, please try again {time}.",
@@ -1178,6 +1278,7 @@
"auth.forgotPasswordLink": "Forgot Password",
"auth.forgotPasswordLoading": "Requesting password reset...",
"auth.forgotPasswordSubtitle": "Enter your email address to receive the instructions to reset your password:",
+ "auth.forgotPasswordUnavailable": "Forgot password is not implemented yet.",
"auth.forgotPasswordSuccess": "Check your emails for password reset instructions!",
"auth.forgotPasswordTitle": "Forgot your password",
"auth.genericError": "Authentication is unavailable.",
@@ -1236,6 +1337,7 @@
"common.actions.discardChanges": "Discard Changes",
"common.actions.download": "Download",
"common.actions.duplicate": "Duplicate",
+ "common.actions.email": "Email",
"common.actions.edit": "Edit",
"common.actions.exit": "Exit",
"common.actions.fetch": "Fetch",
@@ -1244,6 +1346,8 @@
"common.actions.goback": "Go Back",
"common.actions.howItWorks": "How it works",
"common.actions.insert": "Insert",
+ "common.actions.pick": "Pick...",
+ "common.actions.viewAll": "View All",
"common.actions.login": "Login",
"common.actions.manage": "Manage",
"common.actions.move": "Move",
@@ -1306,6 +1410,7 @@
"common.duration.years": "Year(s)",
"common.error.generic.hint": "Oops, something went wrong...",
"common.error.generic.title": "Unexpected Error",
+ "common.error.notImplemented": "Not implemented yet.",
"common.error.notfound.hint": "That page doesn't exist or is not available.",
"common.error.notfound.title": "Not Found",
"common.error.title": "Error",
@@ -1314,10 +1419,15 @@
"common.error.unexpected": "An unexpected error occurred.",
"common.error.unknownsite.hint": "There's no wiki site at this host.",
"common.error.unknownsite.title": "Unknown Site",
+ "common.field.basic": "Basic",
"common.field.createdOn": "Created On",
+ "common.field.created": "Created",
"common.field.id": "ID",
+ "common.field.json": "JSON",
"common.field.lastUpdated": "Last Updated",
"common.field.name": "Name",
+ "common.field.none": "None",
+ "common.field.path": "Path",
"common.field.task": "Task",
"common.field.title": "Title",
"common.footerCopyright": "© {year} {company}. All rights reserved.",
@@ -1332,6 +1442,7 @@
"common.header.delete": "Delete",
"common.header.duplicate": "Duplicate",
"common.header.edit": "Edit",
+ "common.header.editNavigation": "Edit Navigation",
"common.header.history": "History",
"common.header.home": "Home",
"common.header.imagesFiles": "Images & Files",
@@ -1343,6 +1454,8 @@
"common.header.newPage": "New Page",
"common.header.pageActions": "Page Actions",
"common.header.profile": "Profile",
+ "common.header.bookmarks": "Bookmarks",
+ "common.header.browse": "Browse",
"common.header.search": "Search...",
"common.header.searchClose": "Close",
"common.header.searchCopyLink": "Copy Search Link",
@@ -1352,8 +1465,10 @@
"common.header.searchNoResult": "No pages matching your query.",
"common.header.searchResultsCount": "Found {total} results",
"common.header.siteMap": "Site Map",
+ "common.header.switchLocale": "Switch Locale",
"common.header.view": "View",
"common.header.viewSource": "View Source",
+ "common.locale.loadFailed": "Failed to load locale strings for {locale}.",
"common.license.alr": "All Rights Reserved",
"common.license.cc0": "Public Domain",
"common.license.ccby": " Creative Commons Attribution License",
@@ -1381,10 +1496,14 @@
"common.page.global": "Global",
"common.page.id": "ID {id}",
"common.page.lastEditedBy": "Last edited by",
+ "common.page.lastModifiedOn": "Last modified on",
"common.page.loading": "Loading Page...",
+ "common.page.noEditorSpecified": "No editor specified.",
+ "common.page.print": "Print",
"common.page.printFormat": "Print Format",
"common.page.private": "Private",
"common.page.published": "Published",
+ "common.page.rate": "Rate this page",
"common.page.returnNormalView": "Return to Normal View",
"common.page.share": "Share",
"common.page.tags": "Tags",
@@ -1392,6 +1511,7 @@
"common.page.toc": "Table of Contents",
"common.page.unpublished": "Unpublished",
"common.page.unpublishedWarning": "This page is not published.",
+ "common.page.watch": "Watch Page",
"common.page.versionId": "Version ID {id}",
"common.page.viewingSource": "Viewing source of page {path}",
"common.page.viewingSourceVersion": "Viewing source as of {date} of page {path}",
@@ -1494,7 +1614,16 @@
"editor.markup.header": "Header",
"editor.markup.headerLevel": "Header {level}",
"editor.markup.heading": "Heading {level}",
+ "editor.markup.increaseHeaderLevel": "Increase Header Level",
"editor.markup.inlineCode": "Inline Code",
+ "editor.markup.fromClipboard": "From Clipboard...",
+ "editor.markup.fromFileManager": "From File Manager...",
+ "editor.markup.fromRemoteURL": "From Remote URL...",
+ "editor.markup.clipboardError": "Unable to read from clipboard.",
+ "editor.markup.clipboardReadDenied": "Not allowed to read clipboard.",
+ "editor.markup.clipboardUnsupported": "No supported content found in the clipboard.",
+ "editor.markup.fetchConfigFailed": "Failed to fetch markdown editor configuration.",
+ "editor.markup.fetchUserSettingsFailed": "Failed to fetch markdown editor settings.",
"editor.markup.insertAssets": "Insert Assets",
"editor.markup.insertBlock": "Insert Block",
"editor.markup.insertCodeBlock": "Insert Code Block",
@@ -1509,9 +1638,11 @@
"editor.markup.insertVideoAudio": "Insert Video / Audio",
"editor.markup.italic": "Italic",
"editor.markup.keyboardKey": "Keyboard Key",
+ "editor.markup.markdown": "Markdown",
"editor.markup.markdownFormattingHelp": "Markdown Formatting Help",
"editor.markup.noSelectionError": "Text must be selected first!",
"editor.markup.orderedList": "Ordered List",
+ "editor.markup.decreaseHeaderLevel": "Decrease Header Level",
"editor.markup.strikethrough": "Strikethrough",
"editor.markup.subscript": "Subscript",
"editor.markup.superscript": "Superscript",
@@ -1519,8 +1650,12 @@
"editor.markup.taskList": "Task List",
"editor.markup.taskListChecked": "Checked List Item",
"editor.markup.taskListUnchecked": "Unchecked List Item",
+ "editor.markup.toggleBold": "Toggle Bold",
+ "editor.markup.toggleItalic": "Toggle Italic",
"editor.markup.togglePreviewPane": "Hide / Show Preview Pane",
"editor.markup.toggleSpellcheck": "Toggle Spellcheck",
+ "editor.markup.saveConfigFailed": "Failed to save markdown editor configuration.",
+ "editor.markup.saveUserSettingsFailed": "Failed to save markdown editor settings.",
"editor.markup.unorderedList": "Unordered List",
"editor.page": "Page",
"editor.pageData.data": "Data",
@@ -1548,8 +1683,13 @@
"editor.pageData.templateStructure": "Structure",
"editor.pageData.templateTitle": "Template Title",
"editor.pageData.templateUntitled": "Untitled Template",
+ "editor.pageData.attributeBoolean": "Attribute Boolean",
+ "editor.pageData.attributeNumber": "Attribute Number",
+ "editor.pageData.attributeText": "Attribute Text",
"editor.pageData.title": "Page Data",
+ "editor.pageData.visual": "Visual",
"editor.pageData.uniqueKey": "Unique Key",
+ "editor.pageData.yaml": "YAML",
"editor.pageRel.button": "Button Appearance",
"editor.pageRel.caption": "Caption (optional)",
"editor.pageRel.center": "Center",
@@ -1671,6 +1811,9 @@
"fileman.epsFileType": "EPS Image",
"fileman.exeFileType": "Windows Executable",
"fileman.flacFileType": "FLAC Audio File",
+ "fileman.fetchAssetDataFailed": "Failed to fetch asset data.",
+ "fileman.fetchFolderDataFailed": "Failed to fetch folder data.",
+ "fileman.fetchingFolderContents": "Fetching folder contents...",
"fileman.folderChildrenCount": "Empty folder | 1 child | {count} children",
"fileman.folderCreate": "New Folder",
"fileman.folderFileName": "Path Name",
@@ -1709,7 +1852,12 @@
"fileman.renameAssetSuccess": "Asset renamed successfully",
"fileman.renameFolderInvalidData": "One or more fields are invalid.",
"fileman.renameFolderSuccess": "Folder renamed successfully.",
+ "fileman.browseUsing": "Browse using...",
+ "fileman.compactList": "Compact List",
+ "fileman.copyURLFailed": "Failed to copy URL to clipboard.",
+ "fileman.loadTreeFailed": "Failed to load folder tree.",
"fileman.searchFolder": "Search folder...",
+ "fileman.showFolders": "Show Folders",
"fileman.svgFileType": "Scalable Vector Graphic",
"fileman.tarFileType": "TAR Archive",
"fileman.tgzFileType": "Gzipped TAR Archive",
@@ -1718,6 +1866,7 @@
"fileman.ttfFileType": "TrueType Font File",
"fileman.txtFileType": "Text Document",
"fileman.unknownFileType": "{type} file",
+ "fileman.uploadFailed": "Failed to upload file.",
"fileman.uploadSuccess": "File(s) uploaded successfully.",
"fileman.viewOptions": "View Options",
"fileman.wavFileType": "WAV Audio File",
@@ -1733,10 +1882,25 @@
"folderDeleteDialog.deleteSuccess": "Folder has been deleted successfully.",
"folderDeleteDialog.folderId": "Folder ID {id}",
"folderDeleteDialog.title": "Confirm Delete Folder",
+ "headerSearch.operatorExact": "\"foo bar\" matches the exact phrase foo bar.",
+ "headerSearch.operatorExclude": "!foo or -bar excludes foo and bar.",
+ "headerSearch.operatorOr": "foo,bar or foo|bar searches for foo OR bar.",
+ "headerSearch.operatorStartsWith": "bana* matches any term starting with bana, such as banana.",
+ "headerSearch.operators": "Search Operators",
+ "headerSearch.placeholder": "Search...",
+ "headerSearch.popularTags": "Popular Tags",
+ "headerSearch.pressEnter": "Press Enter",
"history.restore.confirmButton": "Restore",
"history.restore.confirmText": "Are you sure you want to restore this page content as it was on {date}? This version will be copied on top of the current history. As such, newer versions will still be preserved.",
"history.restore.confirmTitle": "Restore page version?",
"history.restore.success": "Page version restored succesfully!",
+ "iconPicker.docsHint": "Learn how to use icons in the {docsLink}.",
+ "iconPicker.iconTab": "Icon",
+ "iconPicker.imageTab": "Image",
+ "iconPicker.iconName": "Icon Name",
+ "iconPicker.referenceHint": "View the {referenceLink} for all possible options.",
+ "iconPicker.referenceLink": "Icon Pack reference",
+ "iconPicker.useIconsLink": "the documentation",
"navEdit.clearItems": "Clear All Items",
"navEdit.editMenuItems": "Edit Menu Items",
"navEdit.emptyMenuText": "Click the Add button to add your first menu item.",
@@ -1746,6 +1910,20 @@
"navEdit.label": "Label",
"navEdit.labelHint": "Text to display on the menu item.",
"navEdit.link": "Link",
+ "navEdit.mode.hide.hint": "Completely hide the left sidebar navigation.",
+ "navEdit.mode.hide.label": "Hide",
+ "navEdit.mode.hideCurrent.hint": "Completely hide the left sidebar navigation only for this path.",
+ "navEdit.mode.hideCurrent.label": "Hide Current Only",
+ "navEdit.mode.hideDescendants.hint": "Completely hide the left sidebar navigation for this path and all descendants.",
+ "navEdit.mode.hideDescendants.label": "Hide Current + Descendants",
+ "navEdit.mode.inherit.hint": "Use the menu items and settings from the parent path.",
+ "navEdit.mode.inherit.label": "Inherit",
+ "navEdit.mode.override.hint": "Set menu items and settings for this path and all descendants.",
+ "navEdit.mode.override.label": "Override Current + Descendants",
+ "navEdit.mode.overrideExact.hint": "Set menu items and settings only for this path.",
+ "navEdit.mode.overrideExact.label": "Override Current Only",
+ "navEdit.mode.show.hint": "Show the left sidebar navigation menu items.",
+ "navEdit.mode.show.label": "Show",
"navEdit.nestItem": "Nest Item",
"navEdit.nestingWarn": "The previous menu item must be a normal link or another nested link. Invalid nested items will be shown in red.",
"navEdit.noSelection": "Select a menu item from the left to start editing.",
@@ -1767,10 +1945,38 @@
"pageDeleteDialog.deleteSuccess": "Page deleted successfully.",
"pageDeleteDialog.pageId": "Page ID {id}",
"pageDeleteDialog.title": "Confirm Page Deletion",
+ "page.notify.createFailed": "Failed to create page.",
+ "page.notify.createHomeFailed": "Failed to create homepage.",
+ "page.notify.createHomeSuccess": "Homepage created successfully.",
+ "page.notify.moveSuccess": "Page moved successfully.",
+ "page.notify.reloadFailed": "Failed to reload page state.",
+ "page.notify.renameSuccess": "Page renamed successfully.",
+ "page.notify.reverted": "Page has been reverted to the last saved state.",
+ "page.notify.saveFailed": "Failed to save page changes.",
+ "page.notify.saveSuccess": "Page saved successfully.",
+ "pageActions.convertPage": "Convert Page",
+ "pageActions.duplicatePage": "Duplicate Page",
+ "pageActions.noPendingAssetUploads": "There are no assets pending uploads.",
+ "pageActions.pendingAssetUploads": "Pending Asset Uploads",
+ "pageActions.pendingAssetUploadsHint": "Assets pasted or dropped onto this page will be kept here until the page is saved.",
+ "pageActions.renameMovePage": "Rename / Move Page",
+ "pageActions.viewBacklinks": "View Backlinks",
"pageDuplicateDialog.title": "Duplicate and Save As...",
+ "pageNewMenu.newApiDocumentation": "New API Documentation",
+ "pageNewMenu.newAsciiDocPage": "New AsciiDoc Page",
+ "pageNewMenu.newBlogPage": "New Blog Page",
+ "pageNewMenu.newDiscussionSpace": "New Discussion Space",
+ "pageNewMenu.newFolder": "New Folder",
+ "pageNewMenu.newMarkdownPage": "New Markdown Page",
+ "pageNewMenu.newPage": "New Page",
+ "pageNewMenu.newRedirection": "New Redirection",
+ "pageNewMenu.uploadMediaAsset": "Upload Media Asset",
"pageRenameDialog.title": "Rename / Move to...",
"pageSaveDialog.displayModePath": "Browse Using Paths",
"pageSaveDialog.displayModeTitle": "Browse Using Titles",
+ "pageSaveDialog.displayOptions": "Display Options",
+ "pageSaveDialog.loadTreeFailed": "Failed to load folder tree.",
+ "pageSaveDialog.pathName": "Path Name",
"pageSaveDialog.title": "Save As...",
"profile.accessibility": "Accessibility",
"profile.activity": "Activity",
@@ -1866,6 +2072,7 @@
"renderPageDialog.success": "Page rerendered successfully.",
"search.editorAny": "Any editor",
"search.emptyQuery": "Enter a query in the search field above and press Enter.",
+ "search.failedQuery": "Failed to perform search query.",
"search.filterEditor": "Editor",
"search.filterLocale": "Locale(s)",
"search.filterLocaleDisplay": "Any locale | {n} locale only | {count} locales selected",
@@ -1907,5 +2114,8 @@
"welcome.homeDefault.description": "Welcome to my wiki!",
"welcome.homeDefault.title": "Home",
"welcome.subtitle": "Let's get started...",
- "welcome.title": "Welcome to Wiki.js!"
+ "welcome.title": "Welcome to Wiki.js!",
+ "welcome.usingAsciiDocEditor": "Using the AsciiDoc Editor",
+ "welcome.usingMarkdownEditor": "Using the Markdown Editor",
+ "welcome.usingVisualEditor": "Using the Visual Editor"
}
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
index 504d0a7790..7520a85562 100644
--- a/frontend/src/App.vue
+++ b/frontend/src/App.vue
@@ -65,7 +65,7 @@ async function applyLocale (locale) {
} catch (err) {
$q.notify({
type: 'negative',
- message: `Failed to load ${locale} locale strings.`,
+ message: i18n.t('common.locale.loadFailed', { locale }),
caption: err.message
})
}
diff --git a/frontend/src/components/ApiKeyCreateDialog.vue b/frontend/src/components/ApiKeyCreateDialog.vue
index ccc331bcae..8d108565bf 100644
--- a/frontend/src/components/ApiKeyCreateDialog.vue
+++ b/frontend/src/components/ApiKeyCreateDialog.vue
@@ -236,7 +236,7 @@ async function create () {
onDialogOK()
})
} else {
- throw new Error(resp?.data?.createApiKey?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.createApiKey?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/ApiKeyRevokeDialog.vue b/frontend/src/components/ApiKeyRevokeDialog.vue
index 77e6144d80..11c640dc72 100644
--- a/frontend/src/components/ApiKeyRevokeDialog.vue
+++ b/frontend/src/components/ApiKeyRevokeDialog.vue
@@ -91,7 +91,7 @@ async function confirm () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.revokeApiKey?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.revokeApiKey?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/AssetDeleteDialog.vue b/frontend/src/components/AssetDeleteDialog.vue
index 974cddb5b4..dd88ea961b 100644
--- a/frontend/src/components/AssetDeleteDialog.vue
+++ b/frontend/src/components/AssetDeleteDialog.vue
@@ -96,7 +96,7 @@ async function confirm () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.deleteAsset?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.deleteAsset?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/AssetRenameDialog.vue b/frontend/src/components/AssetRenameDialog.vue
index 95b71603dc..4675aee619 100644
--- a/frontend/src/components/AssetRenameDialog.vue
+++ b/frontend/src/components/AssetRenameDialog.vue
@@ -115,7 +115,7 @@ async function rename () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.renameAsset?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.renameAsset?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
@@ -150,7 +150,7 @@ onMounted(async () => {
}
})
if (resp?.data?.assetById?.id !== props.assetId) {
- throw new Error('Failed to fetch asset data.')
+ throw new Error(t('fileman.fetchAssetDataFailed'))
}
state.path = resp.data.assetById.fileName
} catch (err) {
diff --git a/frontend/src/components/AuthLoginPanel.vue b/frontend/src/components/AuthLoginPanel.vue
index 773103eb85..6414600c5a 100644
--- a/frontend/src/components/AuthLoginPanel.vue
+++ b/frontend/src/components/AuthLoginPanel.vue
@@ -510,7 +510,7 @@ function switchTo (screen) {
break
}
default: {
- throw new Error('Invalid Screen')
+ throw new Error(t('common.error.unexpected'))
}
}
}
@@ -576,7 +576,7 @@ async function handleLoginResponse (resp) {
$q.loading.hide()
$q.notify({
type: 'negative',
- message: 'Unexpected Authentication Response'
+ message: t('auth.errors.unexpectedResponse')
})
}
}
@@ -705,7 +705,7 @@ async function forgotPassword () {
// TODO: Implement forgot password
$q.notify({
type: 'negative',
- message: 'Not implemented yet.'
+ message: t('auth.forgotPasswordUnavailable')
})
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/ChangePwdDialog.vue b/frontend/src/components/ChangePwdDialog.vue
index 784f8b0a34..f0e8893df8 100644
--- a/frontend/src/components/ChangePwdDialog.vue
+++ b/frontend/src/components/ChangePwdDialog.vue
@@ -48,7 +48,7 @@ q-dialog(ref='dialogRef', @hide='onDialogHide')
@click='randomizePassword'
)
q-icon(name='las la-dice-d6')
- .q-pl-xs.text-caption: strong Generate
+ .q-pl-xs.text-caption: strong {{ t('common.actions.generate') }}
q-item
blueprint-icon(icon='good-pincode')
q-item-section
@@ -235,7 +235,7 @@ async function save () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.changePassword?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.changePassword?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/CheckUpdateDialog.vue b/frontend/src/components/CheckUpdateDialog.vue
index 085c2de56b..e7a31e6881 100644
--- a/frontend/src/components/CheckUpdateDialog.vue
+++ b/frontend/src/components/CheckUpdateDialog.vue
@@ -94,7 +94,7 @@ async function check () {
state.latest = resp.latest
state.latestDate = DateTime.fromISO(resp.latestDate).toFormat(userStore.preferredDateFormat)
} else {
- throw new Error(resp?.message || 'An unexpected error occured.')
+ throw new Error(resp?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/EditorMarkdown.vue b/frontend/src/components/EditorMarkdown.vue
index cbb7e6b87a..dd2ccd3379 100644
--- a/frontend/src/components/EditorMarkdown.vue
+++ b/frontend/src/components/EditorMarkdown.vue
@@ -26,7 +26,7 @@
q-item-section(side)
q-icon(name='las la-folder-open', color='positive')
q-item-section
- q-item-label From File Manager...
+ q-item-label {{ t('editor.markup.fromFileManager') }}
q-item(
clickable
@click='getAssetFromClipboard'
@@ -35,7 +35,7 @@
q-item-section(side)
q-icon(name='las la-clipboard', color='brown')
q-item-section
- q-item-label From Clipboard...
+ q-item-label {{ t('editor.markup.fromClipboard') }}
q-item(
clickable
@click='notImplemented'
@@ -44,7 +44,7 @@
q-item-section(side)
q-icon(name='las la-cloud-download-alt', color='blue')
q-item-section
- q-item-label From Remote URL...
+ q-item-label {{ t('editor.markup.fromRemoteURL') }}
q-tooltip(anchor='center right' self='center left') {{ t('editor.markup.insertAssets') }}
q-btn(
icon='mdi-code-json'
@@ -103,7 +103,7 @@
)
q-tooltip(anchor='center right' self='center left') {{ t('editor.markup.insertHorizontalBar') }}
q-space
- span.editor-markdown-type Markdown
+ span.editor-markdown-type {{ t('editor.markup.markdown') }}
.editor-markdown-mid
//--------------------------------------------------------
//- TOP TOOLBAR
@@ -506,7 +506,7 @@ async function getAssetFromClipboard () {
name: 'clipboard-read'
})
if (permission.state === 'denied') {
- throw new Error('Not allowed to read clipboard.')
+ throw new Error(t('editor.markup.clipboardReadDenied'))
}
const clipboardContents = await navigator.clipboard.read()
let hasValidItem = false
@@ -522,12 +522,12 @@ async function getAssetFromClipboard () {
}
}
if (!hasValidItem) {
- throw new Error('No supported content found in the Clipboard.')
+ throw new Error(t('editor.markup.clipboardUnsupported'))
}
} catch (err) {
return $q.notify({
type: 'negative',
- message: 'Unable to copy from Clipboard',
+ message: t('editor.markup.clipboardError'),
caption: err.message
})
}
@@ -592,7 +592,7 @@ onMounted(async () => {
contextMenuOrder: 0,
id: 'markdown.extension.editing.toggleBold',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyB],
- label: 'Toggle bold',
+ label: t('editor.markup.toggleBold'),
precondition: '',
run (ed) {
toggleMarkup({ start: '**' })
@@ -604,7 +604,7 @@ onMounted(async () => {
contextMenuOrder: 0,
id: 'markdown.extension.editing.toggleItalic',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI],
- label: 'Toggle italic',
+ label: t('editor.markup.toggleItalic'),
precondition: '',
run (ed) {
toggleMarkup({ start: '*' })
@@ -614,7 +614,7 @@ onMounted(async () => {
editor.addAction({
id: 'markdown.extension.editing.increaseHeaderLevel',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.RightArrow],
- label: 'Increase Header Level',
+ label: t('editor.markup.increaseHeaderLevel'),
precondition: '',
run (ed) {
let lvl = getHeaderLevel()
@@ -625,7 +625,7 @@ onMounted(async () => {
editor.addAction({
id: 'markdown.extension.editing.decreaseHeaderLevel',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyMod.Alt | monaco.KeyCode.LeftArrow],
- label: 'Decrease Header Level',
+ label: t('editor.markup.decreaseHeaderLevel'),
precondition: '',
run (ed) {
let lvl = getHeaderLevel()
@@ -637,7 +637,7 @@ onMounted(async () => {
editor.addAction({
id: 'save',
keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
- label: 'Save',
+ label: t('common.actions.save'),
precondition: '',
run (ed) {
}
@@ -754,7 +754,7 @@ onBeforeUnmount(() => {
function notImplemented () {
$q.notify({
type: 'negative',
- message: 'Not implemented'
+ message: t('common.error.notImplemented')
})
}
diff --git a/frontend/src/components/EditorMarkdownConfigOverlay.vue b/frontend/src/components/EditorMarkdownConfigOverlay.vue
index 320d6ede03..4a970d0212 100644
--- a/frontend/src/components/EditorMarkdownConfigOverlay.vue
+++ b/frontend/src/components/EditorMarkdownConfigOverlay.vue
@@ -353,7 +353,7 @@ async function load () {
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to fetch markdown editor configuration.'
+ message: t('editor.markup.fetchConfigFailed')
})
}
$q.loading.hide()
@@ -398,12 +398,12 @@ async function save () {
editorStore.$patch({ configIsLoaded: false })
close()
} else {
- throw new Error(respRaw?.data?.updateSite?.operation?.message || 'An unexpected error occured.')
+ throw new Error(respRaw?.data?.updateSite?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to save Markdown editor config',
+ message: t('editor.markup.saveConfigFailed'),
caption: err.message
})
}
diff --git a/frontend/src/components/EditorMarkdownUserSettingsOverlay.vue b/frontend/src/components/EditorMarkdownUserSettingsOverlay.vue
index 67215948ae..7a93ca108a 100644
--- a/frontend/src/components/EditorMarkdownUserSettingsOverlay.vue
+++ b/frontend/src/components/EditorMarkdownUserSettingsOverlay.vue
@@ -141,7 +141,7 @@ async function load () {
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to fetch Markdown editor settings.'
+ message: t('editor.markup.fetchUserSettingsFailed')
})
}
$q.loading.hide()
@@ -179,12 +179,12 @@ async function save () {
})
close()
} else {
- throw new Error(respRaw?.data?.saveUserEditorSettings?.operation?.message || 'An unexpected error occured.')
+ throw new Error(respRaw?.data?.saveUserEditorSettings?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to save Markdown editor settings.',
+ message: t('editor.markup.saveUserSettingsFailed'),
caption: err.message
})
}
diff --git a/frontend/src/components/FileManager.vue b/frontend/src/components/FileManager.vue
index eaa2c11a15..e873a71b39 100644
--- a/frontend/src/components/FileManager.vue
+++ b/frontend/src/components/FileManager.vue
@@ -134,7 +134,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
q-item(clickable)
q-item-section(side)
q-icon(name='las la-list', color='grey', size='xs')
- q-item-section.q-pr-sm Browse using...
+ q-item-section.q-pr-sm {{ t('fileman.browseUsing') }}
q-item-section(side)
q-icon(name='las la-angle-right', color='grey', size='xs')
q-menu(
@@ -149,7 +149,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
:color='state.displayMode === `path` ? `positive` : `grey`'
size='xs'
)
- q-item-section.q-pr-sm Browse Using Paths
+ q-item-section.q-pr-sm {{ t('pageSaveDialog.displayModePath') }}
q-item(clickable, @click='state.displayMode = `title`')
q-item-section(side)
q-icon(
@@ -157,7 +157,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
:color='state.displayMode === `title` ? `positive` : `grey`'
size='xs'
)
- q-item-section.q-pr-sm Browse Using Titles
+ q-item-section.q-pr-sm {{ t('pageSaveDialog.displayModeTitle') }}
q-item(clickable, @click='state.isCompact = !state.isCompact')
q-item-section(side)
q-icon(
@@ -165,7 +165,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
:color='state.isCompact ? `positive` : `grey`'
size='xs'
)
- q-item-section.q-pr-sm Compact List
+ q-item-section.q-pr-sm {{ t('fileman.compactList') }}
q-item(clickable, @click='state.shouldShowFolders = !state.shouldShowFolders')
q-item-section(side)
q-icon(
@@ -173,7 +173,7 @@ q-layout.fileman(view='hHh lpR lFr', container)
:color='state.shouldShowFolders ? `positive` : `grey`'
size='xs'
)
- q-item-section.q-pr-sm Show Folders
+ q-item-section.q-pr-sm {{ t('fileman.showFolders') }}
q-btn.q-mr-sm(
flat
dense
@@ -221,10 +221,10 @@ q-layout.fileman(view='hHh lpR lFr', container)
)
.fileman-loadinglist(v-if='state.fileListLoading')
q-spinner.q-mr-sm(color='primary', size='64px', :thickness='1')
- span.text-primary Fetching folder contents...
+ span.text-primary {{ t('fileman.fetchingFolderContents') }}
.fileman-emptylist(v-else-if='files.length < 1')
img(src='/_assets/icons/carbon-copy-empty-box.svg')
- span This folder is empty.
+ span {{ t('common.pageSelector.folderEmptyWarning') }}
q-list.fileman-filelist(
v-else
:class='state.isCompact && `is-compact`'
@@ -689,7 +689,7 @@ async function loadTree ({ parentId = null, parentPath = null, types, initLoad =
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to load folder tree.',
+ message: t('fileman.loadTreeFailed'),
caption: err.message
})
}
@@ -900,7 +900,7 @@ async function uploadNewFiles () {
}
})
if (!resp?.data?.uploadAssets?.operation?.succeeded) {
- throw new Error(resp?.data?.uploadAssets?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.uploadAssets?.operation?.message || t('common.error.unexpected'))
}
}
state.uploadPercentage = 100
@@ -912,7 +912,7 @@ async function uploadNewFiles () {
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to upload file.',
+ message: t('fileman.uploadFailed'),
caption: err.message
})
}
@@ -995,7 +995,7 @@ async function copyItemURL (item) {
} catch (err) {
$q.notify({
type: 'negative',
- message: 'Failed to copy URL to clipboard.',
+ message: t('fileman.copyURLFailed'),
caption: err.message
})
}
diff --git a/frontend/src/components/FolderCreateDialog.vue b/frontend/src/components/FolderCreateDialog.vue
index 332af16160..fb63ffdc31 100644
--- a/frontend/src/components/FolderCreateDialog.vue
+++ b/frontend/src/components/FolderCreateDialog.vue
@@ -177,7 +177,7 @@ async function create () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.createFolder?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.createFolder?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/FolderDeleteDialog.vue b/frontend/src/components/FolderDeleteDialog.vue
index 9428289267..d3f8a5a429 100644
--- a/frontend/src/components/FolderDeleteDialog.vue
+++ b/frontend/src/components/FolderDeleteDialog.vue
@@ -96,7 +96,7 @@ async function confirm () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.deleteFolder?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.deleteFolder?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/FolderRenameDialog.vue b/frontend/src/components/FolderRenameDialog.vue
index e07d9c1147..8c51c6d5e0 100644
--- a/frontend/src/components/FolderRenameDialog.vue
+++ b/frontend/src/components/FolderRenameDialog.vue
@@ -173,7 +173,7 @@ async function rename () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.renameFolder?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.renameFolder?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
@@ -210,7 +210,7 @@ onMounted(async () => {
}
})
if (resp?.data?.folderById?.id !== props.folderId) {
- throw new Error('Failed to fetch folder data.')
+ throw new Error(t('fileman.fetchFolderDataFailed'))
}
state.path = resp.data.folderById.fileName
state.title = resp.data.folderById.title
diff --git a/frontend/src/components/GroupCreateDialog.vue b/frontend/src/components/GroupCreateDialog.vue
index 6d9f52429e..6a83a7adc4 100644
--- a/frontend/src/components/GroupCreateDialog.vue
+++ b/frontend/src/components/GroupCreateDialog.vue
@@ -112,7 +112,7 @@ async function create () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.createGroup?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.createGroup?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/GroupDeleteDialog.vue b/frontend/src/components/GroupDeleteDialog.vue
index c13e73e005..03b5ff0fc6 100644
--- a/frontend/src/components/GroupDeleteDialog.vue
+++ b/frontend/src/components/GroupDeleteDialog.vue
@@ -84,7 +84,7 @@ async function confirm () {
})
onDialogOK()
} else {
- throw new Error(resp?.data?.deleteGroup?.operation?.message || 'An unexpected error occured.')
+ throw new Error(resp?.data?.deleteGroup?.operation?.message || t('common.error.unexpected'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/GroupEditOverlay.vue b/frontend/src/components/GroupEditOverlay.vue
index 9b004d0ce1..49f66b02d9 100644
--- a/frontend/src/components/GroupEditOverlay.vue
+++ b/frontend/src/components/GroupEditOverlay.vue
@@ -174,7 +174,7 @@ q-layout(view='hHh lpR fFf', container)
unelevated
color='primary'
icon='las la-plus'
- label='New Rule'
+ :label='t(`admin.groups.newRule`)'
@click='newRule'
)
q-separator
@@ -597,49 +597,49 @@ const usersHeaders = [
const permissions = [
{
permission: 'access:admin',
- hint: 'Can access the administration area.',
+ hint: t('admin.groups.permissions.accessAdminHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:users',
- hint: 'Can create / manage users (but not users with administrative permissions)',
+ hint: t('admin.groups.permissions.manageUsersHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:groups',
- hint: 'Can create / manage groups and assign permissions (but not manage:system) / page rules',
+ hint: t('admin.groups.permissions.manageGroupsHint'),
warning: true,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:navigation',
- hint: 'Can manage site navigation',
+ hint: t('admin.groups.permissions.manageNavigationHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:theme',
- hint: 'Can modify site theme settings',
+ hint: t('admin.groups.permissions.manageThemeHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:sites',
- hint: 'Can create / manage sites',
+ hint: t('admin.groups.permissions.manageSitesHint'),
warning: true,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:system',
- hint: 'Can manage and access everything. Root administrator.',
+ hint: t('admin.groups.permissions.manageSystemHint'),
warning: true,
restrictedForSystem: true,
disabled: true
@@ -649,120 +649,120 @@ const permissions = [
const rules = [
{
permission: 'read:pages',
- title: 'Read Pages',
- hint: 'Can view and search pages.',
+ title: t('admin.groups.permissions.readPagesTitle'),
+ hint: t('admin.groups.permissions.readPagesHint'),
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'write:pages',
- title: 'Write Pages',
- hint: 'Can create and edit pages.',
+ title: t('admin.groups.permissions.writePagesTitle'),
+ hint: t('admin.groups.permissions.writePagesHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'review:pages',
- title: 'Review Pages',
- hint: 'Can review and approve edits submitted by users.',
+ title: t('admin.groups.permissions.reviewPagesTitle'),
+ hint: t('admin.groups.permissions.reviewPagesHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:pages',
- title: 'Manage Pages',
- hint: 'Can move existing pages to other locations the user has write access to.',
+ title: t('admin.groups.permissions.managePagesTitle'),
+ hint: t('admin.groups.permissions.managePagesHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'delete:pages',
- title: 'Delete Pages',
- hint: 'Can delete existing pages.',
+ title: t('admin.groups.permissions.deletePagesTitle'),
+ hint: t('admin.groups.permissions.deletePagesHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'write:styles',
- title: 'Use CSS',
- hint: 'Can insert CSS styles in pages.',
+ title: t('admin.groups.permissions.useCssTitle'),
+ hint: t('admin.groups.permissions.useCssHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'write:scripts',
- title: 'Use JavaScript',
- hint: 'Can insert JavaScript in pages.',
+ title: t('admin.groups.permissions.useJavaScriptTitle'),
+ hint: t('admin.groups.permissions.useJavaScriptHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'read:source',
- title: 'View Page Source',
- hint: 'Can view pages source.',
+ title: t('admin.groups.permissions.viewPageSourceTitle'),
+ hint: t('admin.groups.permissions.viewPageSourceHint'),
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'read:history',
- title: 'View Page History',
- hint: 'Can view previous versions of pages.',
+ title: t('admin.groups.permissions.viewPageHistoryTitle'),
+ hint: t('admin.groups.permissions.viewPageHistoryHint'),
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'read:assets',
- title: 'View Assets',
- hint: 'Can view / use assets (such as images and files) in pages.',
+ title: t('admin.groups.permissions.viewAssetsTitle'),
+ hint: t('admin.groups.permissions.viewAssetsHint'),
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'write:assets',
- title: 'Upload Assets',
- hint: 'Can upload new assets (such as images and files).',
+ title: t('admin.groups.permissions.uploadAssetsTitle'),
+ hint: t('admin.groups.permissions.uploadAssetsHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'manage:assets',
- title: 'Manage Assets',
- hint: 'Can edit and delete existing assets (such as images and files).',
+ title: t('admin.groups.permissions.manageAssetsTitle'),
+ hint: t('admin.groups.permissions.manageAssetsHint'),
warning: false,
restrictedForSystem: true,
disabled: false
},
{
permission: 'read:comments',
- title: 'Read Comments',
- hint: 'Can view page comments.',
+ title: t('admin.groups.permissions.readCommentsTitle'),
+ hint: t('admin.groups.permissions.readCommentsHint'),
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'write:comments',
- title: 'Write Comments',
- hint: 'Can post new comments on pages.',
+ title: t('admin.groups.permissions.writeCommentsTitle'),
+ hint: t('admin.groups.permissions.writeCommentsHint'),
warning: false,
restrictedForSystem: false,
disabled: false
},
{
permission: 'manage:comments',
- title: 'Manage Comments',
- hint: 'Can edit and delete existing page comments.',
+ title: t('admin.groups.permissions.manageCommentsTitle'),
+ hint: t('admin.groups.permissions.manageCommentsHint'),
warning: false,
restrictedForSystem: true,
disabled: false
@@ -902,7 +902,7 @@ async function fetchGroup () {
state.group = cloneDeep(resp.data.groupById)
state.usersTotal = state.group.userCount ?? 0
} else {
- throw new Error('An unexpected error occured while fetching group details.')
+ throw new Error(t('admin.groups.fetchDetailsFailed'))
}
} catch (err) {
$q.notify({
@@ -952,7 +952,7 @@ async function importRules () {
const rulesRaw = await blob.text()
const rules = JSON.parse(rulesRaw)
if (!Array.isArray(rules) || rules.length < 1) {
- throw new Error('Invalid Rules Format')
+ throw new Error(t('admin.groups.invalidRulesFormat'))
}
$q.dialog({
title: t('admin.groups.importModeTitle'),
@@ -1040,7 +1040,7 @@ async function refreshUsers () {
state.usersTotal = resp.data.groupById.userCount ?? 0
state.users = cloneDeep(resp.data.groupById.users)
} else {
- throw new Error('An unexpected error occured while fetching group users.')
+ throw new Error(t('admin.groups.fetchUsersFailed'))
}
} catch (err) {
$q.notify({
diff --git a/frontend/src/components/HeaderNav.vue b/frontend/src/components/HeaderNav.vue
index 22e9951fe2..819f2b3d7a 100644
--- a/frontend/src/components/HeaderNav.vue
+++ b/frontend/src/components/HeaderNav.vue
@@ -43,9 +43,9 @@ q-header.bg-header.text-white.site-header(
dense
icon='las la-plus-circle'
color='blue-4'
- aria-label='Create New Page'
+ :aria-label='t(`common.header.newPage`)'
)
- q-tooltip Create New Page
+ q-tooltip {{ t('common.header.newPage') }}
new-menu
q-btn.q-ml-md(
v-if='userStore.can(`browse:fileman`)'
@@ -54,10 +54,10 @@ q-header.bg-header.text-white.site-header(
dense
icon='las la-folder-open'
color='positive'
- aria-label='File Manager'
+ :aria-label='t(`fileman.title`)'
@click='openFileManager'
)
- q-tooltip File Manager
+ q-tooltip {{ t('fileman.title') }}
q-btn.q-ml-md(
v-if='userStore.can(`access:admin`)'
flat
diff --git a/frontend/src/components/HeaderSearch.vue b/frontend/src/components/HeaderSearch.vue
index f45073fb32..e515eda94e 100644
--- a/frontend/src/components/HeaderSearch.vue
+++ b/frontend/src/components/HeaderSearch.vue
@@ -12,7 +12,7 @@ q-toolbar(
rounded
ref='searchField'
style='width: 100%;'
- label='Search...'
+ :label='t(`headerSearch.placeholder`)'
@keyup.enter='onSearchEnter'
@focus='state.searchIsFocused = true'
@blur='checkSearchFocus'
@@ -37,7 +37,7 @@ q-toolbar(
)
q-badge.q-mr-sm(
v-else-if='siteStore.search && siteStore.search !== siteStore.searchLastQuery'
- label='Press Enter'
+ :label='t(`headerSearch.pressEnter`)'
color='grey-7'
outline
@click='searchField.focus()'
@@ -55,11 +55,11 @@ q-toolbar(
)
template(v-if='siteStore.tagsLoaded && siteStore.tags.length > 0')
.searchpanel-header
- span Popular Tags
+ span {{ t('headerSearch.popularTags') }}
q-space
q-btn.acrylic-btn(
flat
- label='View All'
+ :label='t(`common.actions.viewAll`)'
rounded
size='xs'
)
@@ -75,11 +75,11 @@ q-toolbar(
clickable
@click='addTag(tag)'
) {{ tag }}
- .searchpanel-header Search Operators
- .searchpanel-tip #[code !foo] or #[code -bar] to exclude "foo" and "bar".
- .searchpanel-tip #[code bana*] for to match any term starting with "bana" (e.g. banana).
- .searchpanel-tip #[code foo,bar] or #[code foo|bar] to search for "foo" OR "bar".
- .searchpanel-tip #[code "foo bar"] to match exactly the phrase "foo bar".
+ .searchpanel-header {{ t('headerSearch.operators') }}
+ .searchpanel-tip {{ t('headerSearch.operatorExclude') }}
+ .searchpanel-tip {{ t('headerSearch.operatorStartsWith') }}
+ .searchpanel-tip {{ t('headerSearch.operatorOr') }}
+ .searchpanel-tip {{ t('headerSearch.operatorExact') }}
diff --git a/frontend/src/components/PageDataDialog.vue b/frontend/src/components/PageDataDialog.vue
index e644cb7055..fd9249c94f 100644
--- a/frontend/src/components/PageDataDialog.vue
+++ b/frontend/src/components/PageDataDialog.vue
@@ -41,11 +41,11 @@ q-card.page-data-dialog(style='width: 750px;')
)
q-tab(
name='visual'
- label='Visual'
+ :label='t(`editor.pageData.visual`)'
)
q-tab(
name='code'
- label='YAML'
+ :label='t(`editor.pageData.yaml`)'
)
q-scroll-area(
:thumb-style='siteStore.thumbStyle'
@@ -55,14 +55,14 @@ q-card.page-data-dialog(style='width: 750px;')
q-card-section(v-if='state.mode === `visual`')
.q-gutter-sm
q-input(
- label='Attribute Text'
+ :label='t(`editor.pageData.attributeText`)'
dense
outlined
)
template(v-slot:before)
q-icon(name='las la-font', color='primary')
q-input(
- label='Attribute Number'
+ :label='t(`editor.pageData.attributeNumber`)'
dense
outlined
type='number'
@@ -71,7 +71,7 @@ q-card.page-data-dialog(style='width: 750px;')
q-icon(name='las la-infinity', color='primary')
.q-py-xs
q-checkbox(
- label='Attribute Boolean'
+ :label='t(`editor.pageData.attributeBoolean`)'
color='primary'
dense
size='lg'
@@ -92,7 +92,7 @@ q-card.page-data-dialog(style='width: 750px;')
diff --git a/frontend/src/components/PageNewMenu.vue b/frontend/src/components/PageNewMenu.vue
index 969d80c40c..04046645a3 100644
--- a/frontend/src/components/PageNewMenu.vue
+++ b/frontend/src/components/PageNewMenu.vue
@@ -11,14 +11,14 @@ q-menu.translucent-menu(
v-if='siteStore.editors.wysiwyg && flagsStore.experimental'
)
blueprint-icon(icon='google-presentation')
- q-item-section.q-pr-sm New Page
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newPage') }}
q-item(
clickable
@click='create(`markdown`)'
v-if='siteStore.editors.markdown'
)
blueprint-icon(icon='markdown')
- q-item-section.q-pr-sm New Markdown Page
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newMarkdownPage') }}
template(v-if='flagsStore.experimental')
q-item(
clickable
@@ -26,31 +26,31 @@ q-menu.translucent-menu(
v-if='siteStore.editors.asciidoc'
)
blueprint-icon(icon='asciidoc')
- q-item-section.q-pr-sm New AsciiDoc Page
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newAsciiDocPage') }}
q-item(
clickable
@click='create(`channel`)'
)
blueprint-icon(icon='chat')
- q-item-section.q-pr-sm New Discussion Space
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newDiscussionSpace') }}
q-item(
clickable
@click='create(`blog`)'
)
blueprint-icon(icon='typewriter-with-paper')
- q-item-section.q-pr-sm New Blog Page
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newBlogPage') }}
q-item(
clickable
@click='create(`api`)'
)
blueprint-icon(icon='api')
- q-item-section.q-pr-sm New API Documentation
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newApiDocumentation') }}
q-item(
clickable
@click='create(`redirect`)'
)
blueprint-icon(icon='advance')
- q-item-section.q-pr-sm New Redirection
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newRedirection') }}
template(v-if='props.hideAssetBtn === false')
q-separator.q-my-sm(inset)
q-item(
@@ -58,7 +58,7 @@ q-menu.translucent-menu(
@click='openFileManager'
)
blueprint-icon(icon='add-image')
- q-item-section.q-pr-sm Upload Media Asset
+ q-item-section.q-pr-sm {{ t('pageNewMenu.uploadMediaAsset') }}
template(v-if='props.showNewFolder')
q-separator.q-my-sm(inset)
q-item(
@@ -66,7 +66,7 @@ q-menu.translucent-menu(
@click='newFolder'
)
blueprint-icon(icon='add-folder')
- q-item-section.q-pr-sm New Folder
+ q-item-section.q-pr-sm {{ t('pageNewMenu.newFolder') }}