Merge pull request #1281 from dbgate/feature/translation4

Feature/translation4
This commit is contained in:
Jan Prochazka
2025-12-02 14:11:51 +01:00
committed by GitHub
66 changed files with 469 additions and 434 deletions

View File

@@ -53,14 +53,15 @@
import InputTextModal from '../modals/InputTextModal.svelte'; import InputTextModal from '../modals/InputTextModal.svelte';
import ConfirmModal from '../modals/ConfirmModal.svelte'; import ConfirmModal from '../modals/ConfirmModal.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
export let data; export let data;
const handleRename = () => { const handleRename = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: data.fileName, value: data.fileName,
label: 'New file name', label: _t('appFile.newFileName', { defaultMessage: 'New file name' }),
header: 'Rename file', header: _t('appFile.renameFile', { defaultMessage: 'Rename file' }),
onConfirm: newFile => { onConfirm: newFile => {
apiCall('apps/rename-file', { apiCall('apps/rename-file', {
file: data.fileName, file: data.fileName,
@@ -74,7 +75,7 @@
const handleDelete = () => { const handleDelete = () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete file ${data.fileName}?`, message: _t('appFile.deleteFileConfirm', { defaultMessage: 'Really delete file {fileName}?', values: { fileName: data.fileName } }),
onConfirm: () => { onConfirm: () => {
apiCall('apps/delete-file', { apiCall('apps/delete-file', {
file: data.fileName, file: data.fileName,
@@ -101,10 +102,10 @@
function createMenu() { function createMenu() {
return [ return [
{ text: 'Delete', onClick: handleDelete }, { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
{ text: 'Rename', onClick: handleRename }, { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
data.fileType.endsWith('.sql') && { text: 'Open SQL', onClick: handleOpenSqlFile }, data.fileType.endsWith('.sql') && { text: _t('common.openSql', { defaultMessage: 'Open SQL' }), onClick: handleOpenSqlFile },
data.fileType.endsWith('.json') && { text: 'Open JSON', onClick: handleOpenJsonFile }, data.fileType.endsWith('.json') && { text: _t('common.openJson', { defaultMessage: 'Open JSON' }), onClick: handleOpenJsonFile },
// data.fileType.endsWith('.yaml') && { text: 'Open YAML', onClick: handleOpenYamlFile }, // data.fileType.endsWith('.yaml') && { text: 'Open YAML', onClick: handleOpenYamlFile },
]; ];

View File

@@ -15,6 +15,7 @@
import InputTextModal from '../modals/InputTextModal.svelte'; import InputTextModal from '../modals/InputTextModal.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { useConnectionList } from '../utility/metadataLoaders'; import { useConnectionList } from '../utility/metadataLoaders';
import { _t } from '../translations';
export let data; export let data;
@@ -34,8 +35,8 @@
showModal(InputTextModal, { showModal(InputTextModal, {
value: name, value: name,
label: 'New application name', label: _t('appFolder.newApplicationName', { defaultMessage: 'New application name' }),
header: 'Rename application', header: _t('appFolder.renameApplication', { defaultMessage: 'Rename application' }),
onConfirm: async newFolder => { onConfirm: async newFolder => {
await apiCall('apps/rename-folder', { await apiCall('apps/rename-folder', {
folder: data.name, folder: data.name,
@@ -60,16 +61,16 @@
function createMenu() { function createMenu() {
return [ return [
{ text: 'Delete', onClick: handleDelete }, { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
{ text: 'Rename', onClick: handleRename }, { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
$currentDatabase && [ $currentDatabase && [
!isOnCurrentDb($currentDatabase, $connections) && { !isOnCurrentDb($currentDatabase, $connections) && {
text: 'Enable on current database', text: _t('appFolder.enableOnCurrentDatabase', { defaultMessage: 'Enable on current database' }),
onClick: () => setOnCurrentDb(true), onClick: () => setOnCurrentDb(true),
}, },
isOnCurrentDb($currentDatabase, $connections) && { isOnCurrentDb($currentDatabase, $connections) && {
text: 'Disable on current database', text: _t('appFolder.disableOnCurrentDatabase', { defaultMessage: 'Disable on current database' }),
onClick: () => setOnCurrentDb(false), onClick: () => setOnCurrentDb(false),
}, },
], ],
@@ -90,7 +91,7 @@
title={data.name} title={data.name}
icon={'img app'} icon={'img app'}
statusIcon={isOnCurrentDb($currentDatabase, $connections) ? 'icon check' : null} statusIcon={isOnCurrentDb($currentDatabase, $connections) ? 'icon check' : null}
statusTitle={`Application ${data.name} is used for database ${$currentDatabase?.name}`} statusTitle={_t('appFolder.applicationUsedForDatabase', { defaultMessage: 'Application {application} is used for database {database}', values: { application: data.name, database: $currentDatabase?.name } })}
isBold={data.name == $currentApplication} isBold={data.name == $currentApplication}
on:click={() => ($currentApplication = data.name)} on:click={() => ($currentApplication = data.name)}
menu={createMenu} menu={createMenu}

View File

@@ -82,6 +82,7 @@
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { openImportExportTab } from '../utility/importExportTools'; import { openImportExportTab } from '../utility/importExportTools';
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import { _t } from '../translations';
export let data; export let data;
$: isZipped = data.folderName?.endsWith('.zip'); $: isZipped = data.folderName?.endsWith('.zip');
@@ -89,8 +90,8 @@
const handleRename = () => { const handleRename = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: data.fileName, value: data.fileName,
label: 'New file name', label: _t('archiveFile.newFileName', { defaultMessage: 'New file name' }),
header: 'Rename file', header: _t('archiveFile.renameFile', { defaultMessage: 'Rename file' }),
onConfirm: newFile => { onConfirm: newFile => {
apiCall('archive/rename-file', { apiCall('archive/rename-file', {
file: data.fileName, file: data.fileName,
@@ -104,7 +105,7 @@
const handleDelete = () => { const handleDelete = () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete file ${data.fileName}?`, message: _t('archiveFile.deleteFileConfirm', { defaultMessage: 'Really delete file {fileName}?', values: { fileName: data.fileName } }),
onConfirm: () => { onConfirm: () => {
apiCall('archive/delete-file', { apiCall('archive/delete-file', {
file: data.fileName, file: data.fileName,
@@ -147,10 +148,10 @@
} }
return [ return [
data.fileType == 'jsonl' && { text: 'Open', onClick: handleOpenArchive }, data.fileType == 'jsonl' && { text: _t('common.open', { defaultMessage: 'Open' }), onClick: handleOpenArchive },
data.fileType == 'jsonl' && { text: 'Open in text editor', onClick: handleOpenJsonLinesText }, data.fileType == 'jsonl' && { text: _t('common.openInTextEditor', { defaultMessage: 'Open in text editor' }), onClick: handleOpenJsonLinesText },
!isZipped && { text: 'Delete', onClick: handleDelete }, !isZipped && { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
!isZipped && { text: 'Rename', onClick: handleRename }, !isZipped && { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
data.fileType == 'jsonl' && data.fileType == 'jsonl' &&
createQuickExportMenu( createQuickExportMenu(
fmt => async () => { fmt => async () => {
@@ -185,19 +186,19 @@
}, },
} }
), ),
data.fileType.endsWith('.sql') && { text: 'Open SQL', onClick: handleOpenSqlFile }, data.fileType.endsWith('.sql') && { text: _t('common.openSql', { defaultMessage: 'Open SQL' }), onClick: handleOpenSqlFile },
data.fileType.endsWith('.yaml') && { text: 'Open YAML', onClick: handleOpenYamlFile }, data.fileType.endsWith('.yaml') && { text: _t('common.openYaml', { defaultMessage: 'Open YAML' }), onClick: handleOpenYamlFile },
!isZipped && !isZipped &&
isProApp() && isProApp() &&
data.fileType == 'jsonl' && { data.fileType == 'jsonl' && {
text: 'Open in profiler', text: _t('common.openInProfiler', { defaultMessage: 'Open in profiler' }),
submenu: getExtensions() submenu: getExtensions()
.drivers.filter(eng => eng.profilerFormatterFunction) .drivers.filter(eng => eng.profilerFormatterFunction)
.map(eng => ({ .map(eng => ({
text: eng.title, text: eng.title,
onClick: () => { onClick: () => {
openNewTab({ openNewTab({
title: 'Profiler', title: _t('common.profiler', { defaultMessage: 'Profiler' }),
icon: 'img profiler', icon: 'img profiler',
tabComponent: 'ProfilerTab', tabComponent: 'ProfilerTab',
props: { props: {

View File

@@ -21,14 +21,15 @@
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import { extractShellConnection } from '../impexp/createImpExpScript'; import { extractShellConnection } from '../impexp/createImpExpScript';
import { saveFileToDisk } from '../utility/exportFileTools'; import { saveFileToDisk } from '../utility/exportFileTools';
import { _t } from '../translations';
export let data; export let data;
const handleDelete = () => { const handleDelete = () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: data.name.endsWith('.link') message: data.name.endsWith('.link')
? `Really delete link to folder ${data.name}? Folder content remains untouched.` ? _t('archiveFolder.deleteLinkConfirm', { defaultMessage: 'Really delete link to folder {folderName}? Folder content remains untouched.', values: { folderName: data.name } })
: `Really delete folder ${data.name}?`, : _t('archiveFolder.deleteFolderConfirm', { defaultMessage: 'Really delete folder {folderName}?', values: { folderName: data.name } }),
onConfirm: () => { onConfirm: () => {
apiCall('archive/delete-folder', { folder: data.name }); apiCall('archive/delete-folder', { folder: data.name });
}, },
@@ -42,8 +43,8 @@
showModal(InputTextModal, { showModal(InputTextModal, {
value: name, value: name,
label: 'New folder name', label: _t('archiveFolder.newFolderName', { defaultMessage: 'New folder name' }),
header: 'Rename folder', header: _t('archiveFolder.renameFolder', { defaultMessage: 'Rename folder' }),
onConfirm: async newFolder => { onConfirm: async newFolder => {
await apiCall('archive/rename-folder', { await apiCall('archive/rename-folder', {
folder: data.name, folder: data.name,
@@ -95,7 +96,7 @@ await dbgateApi.deployDb(${JSON.stringify(
const handleCompareWithCurrentDb = () => { const handleCompareWithCurrentDb = () => {
openNewTab( openNewTab(
{ {
title: 'Compare', title: _t('common.compare', { defaultMessage: 'Compare' }),
icon: 'img compare', icon: 'img compare',
tabComponent: 'CompareModelTab', tabComponent: 'CompareModelTab',
props: { props: {
@@ -153,7 +154,7 @@ await dbgateApi.deployDb(${JSON.stringify(
}); });
}, },
{ {
formatLabel: 'ZIP files', formatLabel: _t('common.zipFiles', { defaultMessage: 'ZIP files' }),
formatExtension: 'zip', formatExtension: 'zip',
defaultFileName: data.name?.endsWith('.zip') ? data.name : data.name + '.zip', defaultFileName: data.name?.endsWith('.zip') ? data.name : data.name + '.zip',
} }
@@ -162,28 +163,28 @@ await dbgateApi.deployDb(${JSON.stringify(
function createMenu() { function createMenu() {
return [ return [
data.name != 'default' && { text: 'Delete', onClick: handleDelete }, data.name != 'default' && { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
data.name != 'default' && { text: 'Rename', onClick: handleRename }, data.name != 'default' && { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
isProApp() && { text: 'Data deployer', onClick: handleOpenDataDeployTab }, isProApp() && { text: _t('common.dataDeployer', { defaultMessage: 'Data deployer' }), onClick: handleOpenDataDeployTab },
$currentDatabase && [ $currentDatabase && [
{ text: 'Generate deploy DB SQL', onClick: handleGenerateDeploySql }, { text: _t('archiveFolder.generateDeployDbSql', { defaultMessage: 'Generate deploy DB SQL' }), onClick: handleGenerateDeploySql },
hasPermission(`run-shell-script`) && { text: 'Shell: Deploy DB', onClick: handleGenerateDeployScript }, hasPermission(`run-shell-script`) && { text: _t('archiveFolder.shellDeployDb', { defaultMessage: 'Shell: Deploy DB' }), onClick: handleGenerateDeployScript },
], ],
data.name != 'default' && data.name != 'default' &&
isProApp() && isProApp() &&
data.name.endsWith('.zip') && { text: 'Unpack ZIP', onClick: () => handleZipUnzip('archive/unzip') }, data.name.endsWith('.zip') && { text: _t('archiveFolder.unpackZip', { defaultMessage: 'Unpack ZIP' }), onClick: () => handleZipUnzip('archive/unzip') },
data.name != 'default' && data.name != 'default' &&
isProApp() && isProApp() &&
!data.name.endsWith('.zip') && { text: 'Pack (create ZIP)', onClick: () => handleZipUnzip('archive/zip') }, !data.name.endsWith('.zip') && { text: _t('archiveFolder.packZip', { defaultMessage: 'Pack (create ZIP)' }), onClick: () => handleZipUnzip('archive/zip') },
isProApp() && { text: 'Download ZIP', onClick: handleDownloadZip }, isProApp() && { text: _t('archiveFolder.downloadZip', { defaultMessage: 'Download ZIP' }), onClick: handleDownloadZip },
data.name != 'default' && data.name != 'default' &&
hasPermission('dbops/model/compare') && hasPermission('dbops/model/compare') &&
isProApp() && isProApp() &&
_.get($currentDatabase, 'connection._id') && { _.get($currentDatabase, 'connection._id') && {
onClick: handleCompareWithCurrentDb, onClick: handleCompareWithCurrentDb,
text: `Compare with ${_.get($currentDatabase, 'name')}`, text: _t('archiveFolder.compareWithCurrentDb', { defaultMessage: 'Compare with {name}', values: { name: _.get($currentDatabase, 'name') } }),
}, },
]; ];
} }

View File

@@ -407,8 +407,8 @@ await dbgateApi.executeQuery(${JSON.stringify(
const handleCreateNewApp = () => { const handleCreateNewApp = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
header: 'New application', header: _t('database.newApplication', { defaultMessage: 'New application' }),
label: 'Application name', label: _t('database.applicationName', { defaultMessage: 'Application name' }),
value: _.startCase(name), value: _.startCase(name),
onConfirm: async appName => { onConfirm: async appName => {
const newAppId = await apiCall('apps/create-app-from-db', { const newAppId = await apiCall('apps/create-app-from-db', {

View File

@@ -199,12 +199,12 @@
divider: true, divider: true,
}, },
hasPermission('dbops/export') && { hasPermission('dbops/export') && {
label: 'Export', label: _t('common.export', { defaultMessage: 'Export' }),
functionName: 'tableReader', functionName: 'tableReader',
isExport: true, isExport: true,
}, },
hasPermission('dbops/import') && { hasPermission('dbops/import') && {
label: 'Import', label: _t('common.import', { defaultMessage: 'Import' }),
isImport: true, isImport: true,
requiresWriteAccess: true, requiresWriteAccess: true,
}, },
@@ -260,7 +260,7 @@
divider: true, divider: true,
}, },
{ {
label: 'Export', label: _t('common.export', { defaultMessage: 'Export' }),
isExport: true, isExport: true,
functionName: 'tableReader', functionName: 'tableReader',
}, },
@@ -310,7 +310,7 @@
divider: true, divider: true,
}, },
{ {
label: 'Export', label: _t('common.export', { defaultMessage: 'Export' }),
isExport: true, isExport: true,
functionName: 'tableReader', functionName: 'tableReader',
}, },
@@ -402,7 +402,7 @@
icon: 'img perspective', icon: 'img perspective',
}, },
hasPermission('dbops/export') && { hasPermission('dbops/export') && {
label: 'Export', label: _t('common.export', { defaultMessage: 'Export' }),
isExport: true, isExport: true,
functionName: 'tableReader', functionName: 'tableReader',
}, },

View File

@@ -193,6 +193,7 @@
import { saveFileToDisk } from '../utility/exportFileTools'; import { saveFileToDisk } from '../utility/exportFileTools';
import { getConnectionInfo } from '../utility/metadataLoaders'; import { getConnectionInfo } from '../utility/metadataLoaders';
import { showSnackbarError } from '../utility/snackbar'; import { showSnackbarError } from '../utility/snackbar';
import { _t } from '../translations';
export let data; export let data;
@@ -214,27 +215,26 @@
function createMenu() { function createMenu() {
return [ return [
handler?.tabComponent && { text: 'Open', onClick: openTab }, handler?.tabComponent && { text: _t('common.open', { defaultMessage: 'Open' }), onClick: openTab },
!data.teamFileId && hasPermission(`files/${data.folder}/write`) && { text: 'Rename', onClick: handleRename }, !data.teamFileId && hasPermission(`files/${data.folder}/write`) && { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
!data.teamFileId && hasPermission(`files/${data.folder}/write`) && { text: 'Create copy', onClick: handleCopy }, !data.teamFileId && hasPermission(`files/${data.folder}/write`) && { text: _t('common.createCopy', { defaultMessage: 'Create copy' }), onClick: handleCopy },
!data.teamFileId && hasPermission(`files/${data.folder}/write`) && { text: 'Delete', onClick: handleDelete }, !data.teamFileId && hasPermission(`files/${data.folder}/write`) && { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
data.teamFileId && data.allowWrite && { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
data.teamFileId && data.allowWrite && { text: 'Rename', onClick: handleRename },
data.teamFileId && data.teamFileId &&
data.allowRead && data.allowRead &&
hasPermission('all-team-files/create') && { text: 'Create copy', onClick: handleCopy }, hasPermission('all-team-files/create') && { text: _t('common.createCopy', { defaultMessage: 'Create copy' }), onClick: handleCopy },
data.teamFileId && data.allowWrite && { text: 'Delete', onClick: handleDelete }, data.teamFileId && data.allowWrite && { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
folder == 'markdown' && { text: 'Show page', onClick: showMarkdownPage }, folder == 'markdown' && { text: _t('common.showPage', { defaultMessage: 'Show page' }), onClick: showMarkdownPage },
!data.teamFileId && { text: 'Download', onClick: handleDownload }, !data.teamFileId && { text: _t('common.download', { defaultMessage: 'Download' }), onClick: handleDownload },
data.teamFileId && data.allowRead && { text: 'Download', onClick: handleDownload }, data.teamFileId && data.allowRead && { text: _t('common.download', { defaultMessage: 'Download' }), onClick: handleDownload },
]; ];
} }
const handleDelete = () => { const handleDelete = () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete file ${data.file}?`, message: _t('common.reallyDeleteFile', { defaultMessage: 'Really delete file {file}?', values: { file: data.file } }),
onConfirm: () => { onConfirm: () => {
if (data.teamFileId) { if (data.teamFileId) {
apiCall('team-files/delete', { teamFileId: data.teamFileId }); apiCall('team-files/delete', { teamFileId: data.teamFileId });
@@ -253,8 +253,8 @@
const handleRename = () => { const handleRename = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: data.file, value: data.file,
label: 'New file name', label: _t('common.newFileName', { defaultMessage: 'New file name' }),
header: 'Rename file', header: _t('common.renameFile', { defaultMessage: 'Rename file' }),
onConfirm: newFile => { onConfirm: newFile => {
if (data.teamFileId) { if (data.teamFileId) {
apiCall('team-files/update', { teamFileId: data.teamFileId, name: newFile }); apiCall('team-files/update', { teamFileId: data.teamFileId, name: newFile });
@@ -274,8 +274,8 @@
const handleCopy = () => { const handleCopy = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: data.file, value: data.file,
label: 'New file name', label: _t('savedFile.newFileName', { defaultMessage: 'New file name' }),
header: 'Copy file', header: _t('savedFile.copyFile', { defaultMessage: 'Copy file' }),
onConfirm: newFile => { onConfirm: newFile => {
if (data.teamFileId) { if (data.teamFileId) {
apiCall('team-files/copy', { teamFileId: data.teamFileId, newName: newFile }); apiCall('team-files/copy', { teamFileId: data.teamFileId, newName: newFile });
@@ -323,12 +323,12 @@
if (data.teamFileId) { if (data.teamFileId) {
if (data?.metadata?.autoExecute) { if (data?.metadata?.autoExecute) {
if (!data.allowUse) { if (!data.allowUse) {
showSnackbarError('You do not have permission to use this team file'); showSnackbarError(_t('savedFile.noPermissionUseTeamFile', { defaultMessage: 'You do not have permission to use this team file' }));
return; return;
} }
} else { } else {
if (!data.allowRead) { if (!data.allowRead) {
showSnackbarError('You do not have permission to read this team file'); showSnackbarError(_t('savedFile.noPermissionReadTeamFile', { defaultMessage: 'You do not have permission to read this team file' }));
return; return;
} }
} }

View File

@@ -81,7 +81,7 @@
import { getLocalStorage } from '../utility/storageCache'; import { getLocalStorage } from '../utility/storageCache';
import registerCommand from './registerCommand'; import registerCommand from './registerCommand';
import { formatKeyText, switchCurrentDatabase } from '../utility/common'; import { formatKeyText, switchCurrentDatabase } from '../utility/common';
import { _tval, __t } from '../translations'; import { _tval, __t, _t } from '../translations';
let domInput; let domInput;
let filter = ''; let filter = '';
@@ -181,7 +181,7 @@
domInput.focus(); domInput.focus();
}} }}
> >
<FontIcon icon="icon menu" /> Commands <FontIcon icon="icon menu" /> {_t('commandPalette.commands', { defaultMessage: 'Commands' })}
</div> </div>
<div <div
class="page" class="page"
@@ -191,7 +191,7 @@
domInput.focus(); domInput.focus();
}} }}
> >
<FontIcon icon="icon database" /> Database <FontIcon icon="icon database" /> {_t('common.database', { defaultMessage: 'Database' })}
</div> </div>
</div> </div>
<div class="mainInner"> <div class="mainInner">
@@ -201,8 +201,8 @@
bind:this={domInput} bind:this={domInput}
bind:value={filter} bind:value={filter}
on:keydown={handleKeyDown} on:keydown={handleKeyDown}
placeholder={parentCommand?.text || placeholder={_tval(parentCommand?.text) ||
($visibleCommandPalette == 'database' ? 'Search in database' : 'Search in commands')} ($visibleCommandPalette == 'database' ? _t('commandPalette.searchInDatabase', { defaultMessage: 'Search in database' }) : _t('commandPalette.searchInCommands', { defaultMessage: 'Search in commands' }))}
/> />
</div> </div>
<div class="content"> <div class="content">

View File

@@ -1,5 +1,5 @@
<script context="module" lang="ts"> <script context="module" lang="ts">
import { __t } from '../translations' import { __t, _t } from '../translations'
const getCurrentEditor = () => getActiveComponent('SqlDataGridCore'); const getCurrentEditor = () => getActiveComponent('SqlDataGridCore');
registerCommand({ registerCommand({
@@ -127,7 +127,7 @@
export function openQuery(sql?) { export function openQuery(sql?) {
openNewTab( openNewTab(
{ {
title: 'Query #', title: _t('common.queryNumber', { defaultMessage: 'Query #' }),
icon: 'img sql-file', icon: 'img sql-file',
tabComponent: 'QueryTab', tabComponent: 'QueryTab',
focused: true, focused: true,

View File

@@ -67,7 +67,7 @@
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import dragScroll from '../utility/dragScroll'; import dragScroll from '../utility/dragScroll';
import FormStyledButton from '../buttons/FormStyledButton.svelte'; import FormStyledButton from '../buttons/FormStyledButton.svelte';
import { __t } from '../translations'; import { __t, _t } from '../translations';
export let value; export let value;
export let onChange; export let onChange;
@@ -849,45 +849,45 @@
settings?.customizeStyle && [ settings?.customizeStyle && [
{ divider: true }, { divider: true },
isProApp() && { isProApp() && {
text: 'Column properties', text: _t('designer.columnProperties', { defaultMessage: 'Column properties' }),
submenu: [ submenu: [
{ {
text: `Nullability: ${value?.style?.showNullability ? 'YES' : 'NO'}`, text: _t('designer.nullabilityYesNo', { defaultMessage: 'Nullability: {show}', values: { show: value?.style?.showNullability ? 'YES' : 'NO' } }),
onClick: changeStyleFunc('showNullability', !value?.style?.showNullability), onClick: changeStyleFunc('showNullability', !value?.style?.showNullability),
}, },
{ {
text: `Data type: ${value?.style?.showDataType ? 'YES' : 'NO'}`, text: _t('designer.dataTypeYesNo', { defaultMessage: 'Data type: {show}', values: { show: value?.style?.showDataType ? 'YES' : 'NO' } }),
onClick: changeStyleFunc('showDataType', !value?.style?.showDataType), onClick: changeStyleFunc('showDataType', !value?.style?.showDataType),
}, },
], ],
}, },
isProApp() && { isProApp() && {
text: `Columns - ${_.startCase(value?.style?.filterColumns || 'all')}`, text: _t('designer.columns', { defaultMessage: 'Columns - { filterColumns }', values: { filterColumns: _.startCase(value?.style?.filterColumns || 'all') } }),
submenu: [ submenu: [
{ {
text: 'All', text: _t('designer.all', { defaultMessage: 'All' }),
onClick: changeStyleFunc('filterColumns', ''), onClick: changeStyleFunc('filterColumns', ''),
}, },
{ {
text: 'Primary Key', text: _t('designer.primaryKey', { defaultMessage: 'Primary Key' }),
onClick: changeStyleFunc('filterColumns', 'primaryKey'), onClick: changeStyleFunc('filterColumns', 'primaryKey'),
}, },
{ {
text: 'All Keys', text: _t('designer.allKeys', { defaultMessage: 'All Keys' }),
onClick: changeStyleFunc('filterColumns', 'allKeys'), onClick: changeStyleFunc('filterColumns', 'allKeys'),
}, },
{ {
text: 'Not Null', text: _t('designer.notNull', { defaultMessage: 'Not Null' }),
onClick: changeStyleFunc('filterColumns', 'notNull'), onClick: changeStyleFunc('filterColumns', 'notNull'),
}, },
{ {
text: 'Keys And Not Null', text: _t('designer.keysAndNotNull', { defaultMessage: 'Keys And Not Null' }),
onClick: changeStyleFunc('filterColumns', 'keysAndNotNull'), onClick: changeStyleFunc('filterColumns', 'keysAndNotNull'),
}, },
], ],
}, },
{ {
text: `Zoom - ${(value?.style?.zoomKoef || 1) * 100}%`, text: _t('designer.zoom', { defaultMessage: 'Zoom - {zoom}%', values: { zoom: ((value?.style?.zoomKoef || 1) * 100) } }),
submenu: DIAGRAM_ZOOMS.map(koef => ({ submenu: DIAGRAM_ZOOMS.map(koef => ({
text: `${koef * 100} %`, text: `${koef * 100} %`,
onClick: changeStyleFunc('zoomKoef', koef.toString()), onClick: changeStyleFunc('zoomKoef', koef.toString()),
@@ -1016,11 +1016,11 @@
use:dragScroll={handleDragScroll} use:dragScroll={handleDragScroll}
> >
{#if !(tables?.length > 0)} {#if !(tables?.length > 0)}
<div class="empty">Drag &amp; drop tables or views from left panel here</div> <div class="empty">{_t('designer.dragDropTables', { defaultMessage: 'Drag & drop tables or views from left panel here' })}</div>
{#if allowAddTablesButton} {#if allowAddTablesButton}
<div class="addAllTables"> <div class="addAllTables">
<FormStyledButton value="Add all tables" on:click={handleAddAllTables} /> <FormStyledButton value={_t('designer.addAllTables', { defaultMessage: 'Add all tables' })} on:click={handleAddAllTables} />
</div> </div>
{/if} {/if}
{/if} {/if}
@@ -1119,7 +1119,7 @@
<div class="panel"> <div class="panel">
<DragColumnMemory {settings} {sourceDragColumn$} {targetDragColumn$} /> <DragColumnMemory {settings} {sourceDragColumn$} {targetDragColumn$} />
<div class="searchbox"> <div class="searchbox">
<SearchInput bind:value={columnFilter} placeholder="Filter columns" /> <SearchInput bind:value={columnFilter} placeholder={_t('designer.filterColumns', { defaultMessage: 'Filter columns' })} />
<CloseSearchButton bind:filter={columnFilter} /> <CloseSearchButton bind:filter={columnFilter} />
</div> </div>
</div> </div>

View File

@@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import _ from 'lodash'; import _ from 'lodash';
import DropDownButton from '../buttons/DropDownButton.svelte'; import DropDownButton from '../buttons/DropDownButton.svelte';
import { _tval } from '../translations';
interface TabDef { interface TabDef {
label: string; label: string;
@@ -46,7 +47,7 @@
data-testid={tab.testid} data-testid={tab.testid}
> >
<span class="ml-2 noselect"> <span class="ml-2 noselect">
{tab.label} {_tval(tab.label)}
</span> </span>
</div> </div>
{/each} {/each}

View File

@@ -8,6 +8,7 @@
import { getFormContext } from './FormProviderCore.svelte'; import { getFormContext } from './FormProviderCore.svelte';
import FormSelectField from './FormSelectField.svelte'; import FormSelectField from './FormSelectField.svelte';
import { _t } from '../translations';
export let additionalFolders = []; export let additionalFolders = [];
export let name; export let name;
@@ -35,7 +36,7 @@
label: folder, label: folder,
})), })),
allowCreateNew && { allowCreateNew && {
label: '(Create new)', label: _t('archiveFolder.createNew', { defaultMessage: '(Create new)' }),
value: '@create', value: '@create',
}, },
]; ];
@@ -48,8 +49,8 @@
function handleChange(e) { function handleChange(e) {
if (e.detail == '@create') { if (e.detail == '@create') {
showModal(InputTextModal, { showModal(InputTextModal, {
header: 'Archive', header: _t('archiveFolder.archive', { defaultMessage: 'Archive' }),
label: 'Name of new archive folder', label: _t('archiveFolder.nameOfNewArchiveFolder', { defaultMessage: 'Name of new archive folder' }),
onConfirm: createOption, onConfirm: createOption,
}); });
} }

View File

@@ -11,6 +11,7 @@
import { showModal } from '../modals/modalTools'; import { showModal } from '../modals/modalTools';
import InputTextModal from '../modals/InputTextModal.svelte'; import InputTextModal from '../modals/InputTextModal.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
export let value = ''; export let value = '';
export let conid; export let conid;
@@ -33,8 +34,8 @@
async function handleAddNewApplication() { async function handleAddNewApplication() {
showModal(InputTextModal, { showModal(InputTextModal, {
header: 'New application', header: _t('database.newApplication', { defaultMessage: 'New application' }),
label: 'Application name', label: _t('database.applicationName', { defaultMessage: 'Application name' }),
value: _.startCase(database), value: _.startCase(database),
onConfirm: async appName => { onConfirm: async appName => {
const newAppId = await apiCall('apps/create-app-from-db', { const newAppId = await apiCall('apps/create-app-from-db', {

View File

@@ -310,21 +310,21 @@
}, },
}); });
}} }}
>{columnCount > 0 ? `(${columnCount} columns)` : '(copy from source)'} >{columnCount > 0 ? _t('importExport.columnsCount', { defaultMessage: '({columnCount} columns)', values: { columnCount } }) : _t('importExport.copyFromSource', { defaultMessage: '(copy from source)' })}
</Link> </Link>
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="3" let:row> <svelte:fragment slot="3" let:row>
{#if progressHolder[row]?.status == 'running' && isRunning} {#if progressHolder[row]?.status == 'running' && isRunning}
<FontIcon icon="icon loading" /> <FontIcon icon="icon loading" />
{#if progressHolder[row]?.writtenRowCount} {#if progressHolder[row]?.writtenRowCount}
{progressHolder[row]?.writtenRowCount} rows writtem {progressHolder[row]?.writtenRowCount} {_t('importExport.rowsWritten', { defaultMessage: 'rows written' })}
{:else if progressHolder[row]?.readRowCount} {:else if progressHolder[row]?.readRowCount}
{progressHolder[row]?.readRowCount} rows read {progressHolder[row]?.readRowCount} {_t('importExport.rowsRead', { defaultMessage: 'rows read' })}
{:else} {:else}
Running {_t('importExport.running', { defaultMessage: 'Running' })}
{/if} {/if}
{:else if progressHolder[row]?.status == 'error'} {:else if progressHolder[row]?.status == 'error'}
<FontIcon icon="img error" /> Error <FontIcon icon="img error" /> {_t('common.error', { defaultMessage: 'Error' })}
{#if progressHolder[row]?.errorMessage} {#if progressHolder[row]?.errorMessage}
<FontIcon <FontIcon
icon="img info" icon="img info"
@@ -337,20 +337,20 @@
{:else if progressHolder[row]?.status == 'done'} {:else if progressHolder[row]?.status == 'done'}
<FontIcon icon="img ok" /> <FontIcon icon="img ok" />
{#if progressHolder[row]?.writtenRowCount} {#if progressHolder[row]?.writtenRowCount}
{progressHolder[row]?.writtenRowCount} rows written {progressHolder[row]?.writtenRowCount} {_t('importExport.rowsWritten', { defaultMessage: 'rows written' })}
{:else if progressHolder[row]?.readRowCount} {:else if progressHolder[row]?.readRowCount}
{progressHolder[row]?.readRowCount} rows written {progressHolder[row]?.readRowCount} {_t('importExport.rowsWritten', { defaultMessage: 'rows written' })}
{:else} {:else}
Done {_t('common.done', { defaultMessage: 'Done' })}
{/if} {/if}
{:else} {:else}
<FontIcon icon="icon wait" /> <FontIcon icon="icon wait" />
{#if progressHolder[row]?.writtenRowCount} {#if progressHolder[row]?.writtenRowCount}
{progressHolder[row]?.writtenRowCount} rows writtem {progressHolder[row]?.writtenRowCount} {_t('importExport.rowsWritten', { defaultMessage: 'rows written' })}
{:else if progressHolder[row]?.readRowCount} {:else if progressHolder[row]?.readRowCount}
{progressHolder[row]?.readRowCount} rows read {progressHolder[row]?.readRowCount} {_t('importExport.rowsRead', { defaultMessage: 'rows read' })}
{:else} {:else}
Queued {_t('importExport.queued', { defaultMessage: 'Queued' })}
{/if} {/if}
{/if} {/if}
</svelte:fragment> </svelte:fragment>

View File

@@ -114,8 +114,8 @@
value={_t('importExport.newArchive', { defaultMessage: "New archive" })} value={_t('importExport.newArchive', { defaultMessage: "New archive" })}
on:click={() => { on:click={() => {
showModal(InputTextModal, { showModal(InputTextModal, {
header: 'Archive', header: _t('importExport.archive', { defaultMessage: 'Archive' }),
label: 'Name of new archive folder', label: _t('importExport.nameOfNewArchiveFolder', { defaultMessage: 'Name of new archive folder' }),
value: `import-${moment().format('YYYY-MM-DD-hh-mm-ss')}`, value: `import-${moment().format('YYYY-MM-DD-hh-mm-ss')}`,
onConfirm: value => { onConfirm: value => {
values.update(x => ({ values.update(x => ({

View File

@@ -8,6 +8,7 @@
import Link from '../elements/Link.svelte'; import Link from '../elements/Link.svelte';
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import { _t } from '../translations';
const config = useConfig(); const config = useConfig();
$: version = $config?.version; $: version = $config?.version;
@@ -15,18 +16,18 @@
</script> </script>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">About DbGate</svelte:fragment> <svelte:fragment slot="header">{_t('aboutModal.aboutDbGate', { defaultMessage: 'About DbGate' })}</svelte:fragment>
<div class="flex"> <div class="flex">
<img src="logo192.png" /> <img src="logo192.png" />
<div class="ml-4"> <div class="ml-4">
<div> <div>
Version: <span>{version}</span> {_t('aboutModal.version', { defaultMessage: 'Version' })}: <span>{version}</span>
</div> </div>
<div> <div>
Build date: <span>{moment(buildTime).format('YYYY-MM-DD')}</span> {_t('aboutModal.buildDate', { defaultMessage: 'Build date' })}: <span>{moment(buildTime).format('YYYY-MM-DD')}</span>
</div> </div>
<div> <div>
License type: <span {_t('aboutModal.licenseType', { defaultMessage: 'License type' })}: <span
>{$config?.checkedLicense && $config?.checkedLicense?.type != 'community' >{$config?.checkedLicense && $config?.checkedLicense?.type != 'community'
? ($config?.checkedLicense?.licenseTypeObj?.name ?? 'Unknown') ? ($config?.checkedLicense?.licenseTypeObj?.name ?? 'Unknown')
: 'Community'}</span : 'Community'}</span
@@ -34,16 +35,16 @@
</div> </div>
{#if $config?.checkedLicense?.users} {#if $config?.checkedLicense?.users}
<div> <div>
User count: <span>{$config?.checkedLicense?.users}</span> {_t('aboutModal.userCount', { defaultMessage: 'User count' })}: <span>{$config?.checkedLicense?.users}</span>
</div> </div>
{/if} {/if}
<div class="mt-2"> <div class="mt-2">
<FontIcon icon="mdi mdi-web color-icon-blue" /> Web: <Link href="https://www.dbgate.io">dbgate.io</Link> <FontIcon icon="mdi mdi-web color-icon-blue" /> {_t('aboutModal.web', { defaultMessage: 'Web' })}: <Link href="https://www.dbgate.io">dbgate.io</Link>
</div> </div>
{#if isProApp()} {#if isProApp()}
<div> <div>
<FontIcon icon="mdi mdi-email color-icon-red" /> Support: <Link href="mailto:support@dbgate.io" <FontIcon icon="mdi mdi-email color-icon-red" /> {_t('aboutModal.support', { defaultMessage: 'Support' })}: <Link href="mailto:support@dbgate.io"
>support@dbgate.io</Link >support@dbgate.io</Link
> >
</div> </div>
@@ -55,10 +56,10 @@
</div> --> </div> -->
<div class="mt-2"> <div class="mt-2">
Source codes: <Link href="https://github.com/dbgate/dbgate/">GitHub</Link> {_t('aboutModal.sourceCodes', { defaultMessage: 'Source codes' })}: <Link href="https://github.com/dbgate/dbgate/">GitHub</Link>
</div> </div>
<div> <div>
Docker container: <Link {_t('aboutModal.dockerContainer', { defaultMessage: 'Docker container' })}: <Link
href={isProApp() href={isProApp()
? 'https://hub.docker.com/r/dbgate/dbgate-premium' ? 'https://hub.docker.com/r/dbgate/dbgate-premium'
: 'https://hub.docker.com/r/dbgate/dbgate'}>Docker Hub</Link : 'https://hub.docker.com/r/dbgate/dbgate'}>Docker Hub</Link
@@ -69,13 +70,13 @@
</div> --> </div> -->
<div class="mt-2"> <div class="mt-2">
Produced by: <span>Sprinx System a.s.</span> {_t('aboutModal.producedBy', { defaultMessage: 'Produced by' })}: <span>Sprinx System a.s.</span>
</div> </div>
</div> </div>
</div> </div>
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormStyledButton value="Close" on:click={closeCurrentModal} /> <FormStyledButton value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -8,6 +8,7 @@
import TextField from '../forms/TextField.svelte'; import TextField from '../forms/TextField.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let conid; export let conid;
export let database; export let database;
@@ -26,10 +27,10 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Add key</svelte:fragment> <svelte:fragment slot="header">{_t('addDbKeyModal.addKey', { defaultMessage: 'Add key' })}</svelte:fragment>
<div class="container"> <div class="container">
<FormFieldTemplateLarge label="Key" type="text" noMargin> <FormFieldTemplateLarge label={_t('addDbKeyModal.key', { defaultMessage: 'Key' })} type="text" noMargin>
<TextField <TextField
value={keyName} value={keyName}
on:change={e => { on:change={e => {
@@ -41,7 +42,7 @@
<div class="m-3" /> <div class="m-3" />
<FormFieldTemplateLarge label="Type" type="combo" noMargin> <FormFieldTemplateLarge label={_t('addDbKeyModal.type', { defaultMessage: 'Type' })} type="combo" noMargin>
<SelectField <SelectField
options={driver.supportedKeyTypes.map(t => ({ value: t.name, label: t.label }))} options={driver.supportedKeyTypes.map(t => ({ value: t.name, label: t.label }))}
value={type} value={type}
@@ -62,8 +63,8 @@
</div> </div>
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormStyledButton value="OK" on:click={e => handleSubmit()} /> <FormStyledButton value={_t('common.ok', { defaultMessage: 'OK' })} on:click={e => handleSubmit()} />
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -6,6 +6,7 @@
import FormTextField from '../forms/FormTextField.svelte'; import FormTextField from '../forms/FormTextField.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let onConfirm; export let onConfirm;
export let url; export let url;
@@ -18,13 +19,13 @@
<FormProvider initialValues={{ url }}> <FormProvider initialValues={{ url }}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Download imported file from web</svelte:fragment> <svelte:fragment slot="header">{_t('changeDownloadUrlModal.header', { defaultMessage: 'Download imported file from web' })}</svelte:fragment>
<FormTextField label="URL" name="url" style={{ width: '30vw' }} focused /> <FormTextField label={_t('changeDownloadUrlModal.urlLabel', { defaultMessage: 'URL' })} name="url" style={{ width: '30vw' }} focused />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit value="OK" on:click={handleSubmit} /> <FormSubmit value={_t('common.ok', { defaultMessage: 'OK' })} on:click={handleSubmit} />
<FormStyledButton value="Cancel" on:click={closeCurrentModal} /> <FormStyledButton value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -6,6 +6,7 @@
import FormSubmit from '../forms/FormSubmit.svelte'; import FormSubmit from '../forms/FormSubmit.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let message = ''; export let message = '';
export let onConfirm; export let onConfirm;
@@ -13,21 +14,21 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Choose archive folder</svelte:fragment> <svelte:fragment slot="header">{_t('archiveFolderModal.chooseArchiveFolder', { defaultMessage: 'Choose archive folder' })}</svelte:fragment>
<div>{message}</div> <div>{message}</div>
<FormArchiveFolderSelect label="Archive folder" name="archiveFolder" isNative allowCreateNew /> <FormArchiveFolderSelect label={_t('archiveFolderModal.archiveFolder', { defaultMessage: 'Archive folder' })} name="archiveFolder" isNative allowCreateNew />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={e => { on:click={e => {
closeCurrentModal(); closeCurrentModal();
onConfirm(e.detail.archiveFolder); onConfirm(e.detail.archiveFolder);
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -7,6 +7,7 @@
import { useCloudContentList } from '../utility/metadataLoaders'; import { useCloudContentList } from '../utility/metadataLoaders';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let message = ''; export let message = '';
export let onConfirm; export let onConfirm;
@@ -18,22 +19,21 @@
{#if $cloudContentList} {#if $cloudContentList}
<FormProvider initialValues={{ cloudFolder: $cloudContentList?.find(x => x.isPrivate)?.folid }}> <FormProvider initialValues={{ cloudFolder: $cloudContentList?.find(x => x.isPrivate)?.folid }}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Choose cloud folder</svelte:fragment> <svelte:fragment slot="header">{_t('cloudFolderModal.chooseCloudFolder', { defaultMessage: 'Choose cloud folder' })}</svelte:fragment>
<div>{message}</div> <div>{message}</div>
<FormCloudFolderSelect label="Cloud folder" name="cloudFolder" isNative {requiredRoleVariants} /> <FormCloudFolderSelect label={_t('cloudFolderModal.cloudFolder', { defaultMessage: 'Cloud folder' })} name="cloudFolder" isNative {requiredRoleVariants} />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={e => { on:click={e => {
closeCurrentModal(); closeCurrentModal();
console.log('onConfirm', e.detail); console.log('onConfirm', e.detail);
onConfirm(e.detail.cloudFolder); onConfirm(e.detail.cloudFolder);
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -11,8 +11,9 @@
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import _ from 'lodash'; import _ from 'lodash';
import { _t } from '../translations';
export let header = 'Configure columns'; export let header = _t('columnMapModal.configureColumns', { defaultMessage: 'Configure columns' });
export let onConfirm; export let onConfirm;
export let sourceTableInfo; export let sourceTableInfo;
@@ -69,7 +70,7 @@
if (!value) return; if (!value) return;
if (value.length == 0) return; if (value.length == 0) return;
if (value.some(x => !x.src || !x.dst)) { if (value.some(x => !x.src || !x.dst)) {
validationError = 'Source and target columns must be defined'; validationError = _t('columnMapModal.sourceAndTargetColumnsMustBeDefined', { defaultMessage: 'Source and target columns must be defined' });
return; return;
} }
const duplicates = _.chain(value.map(x => x.dst)) const duplicates = _.chain(value.map(x => x.dst))
@@ -78,7 +79,7 @@
.keys() .keys()
.value(); .value();
if (duplicates.length > 0) { if (duplicates.length > 0) {
validationError = 'Target columns must be unique, duplicates found: ' + duplicates.join(', '); validationError = _t('columnMapModal.targetColumnsMustBeUnique', { defaultMessage: 'Target columns must be unique, duplicates found: ' }) + duplicates.join(', ');
return; return;
} }
} }
@@ -95,19 +96,19 @@
{#if resetValue.length == 0} {#if resetValue.length == 0}
<div class="m-3"> <div class="m-3">
When no columns are defined in this mapping, source row is copied to target without any modifications {_t('columnMapModal.noColumnsDefined', { defaultMessage: 'When no columns are defined in this mapping, source row is copied to target without any modifications' })}
</div> </div>
{/if} {/if}
<TableControl <TableControl
columns={[ columns={[
{ fieldName: 'use', header: 'Use', slot: 4 }, { fieldName: 'use', header: _t('columnMapModal.use', { defaultMessage: 'Use' }), slot: 4 },
{ fieldName: 'src', header: 'Source column', slot: 1 }, { fieldName: 'src', header: _t('columnMapModal.sourceColumn', { defaultMessage: 'Source column' }), slot: 1 },
{ fieldName: 'dst', header: 'Target column', slot: 2 }, { fieldName: 'dst', header: _t('columnMapModal.targetColumn', { defaultMessage: 'Target column' }), slot: 2 },
{ fieldName: 'actions', header: '', slot: 3 }, { fieldName: 'actions', header: '', slot: 3 },
]} ]}
rows={value || []} rows={value || []}
emptyMessage="No transform defined" emptyMessage={_t('columnMapModal.noTransformDefined', { defaultMessage: 'No transform defined' })}
> >
<svelte:fragment slot="4" let:row let:index> <svelte:fragment slot="4" let:row let:index>
<CheckboxField <CheckboxField
@@ -136,7 +137,7 @@
<Link <Link
onClick={() => { onClick={() => {
value = value.filter((x, i) => i != index); value = value.filter((x, i) => i != index);
}}>Remove</Link }}>{_t('common.Remove', { defaultMessage: 'Remove' })}</Link
> >
</svelte:fragment> </svelte:fragment>
</TableControl> </TableControl>
@@ -160,14 +161,14 @@
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Add column" value={_t('columnMapModal.addColumn', { defaultMessage: 'Add column' })}
on:click={() => { on:click={() => {
value = [...(value || []), {}]; value = [...(value || []), {}];
}} }}
/> />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Reset" value={_t('columnMapModal.reset', { defaultMessage: 'Reset' })}
disabled={!differentFromReset} disabled={!differentFromReset}
on:click={() => { on:click={() => {
value = resetValue; value = resetValue;

View File

@@ -5,17 +5,18 @@
import FormSubmit from '../forms/FormSubmit.svelte'; import FormSubmit from '../forms/FormSubmit.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let message; export let message;
export let onConfirm; export let onConfirm;
export let confirmLabel = 'OK'; export let confirmLabel = _t('common.ok', { defaultMessage: 'OK' });
export let header = null; export let header = null;
</script> </script>
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header"> <svelte:fragment slot="header">
{header || 'Confirm'} {header || _t('common.confirm', { defaultMessage: 'Confirm' })}
</svelte:fragment> </svelte:fragment>
{message} {message}
@@ -31,7 +32,7 @@
/> />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Close" value={_t('common.close', { defaultMessage: 'Close' })}
on:click={closeCurrentModal} on:click={closeCurrentModal}
data-testid="ConfirmModal_closeButton" data-testid="ConfirmModal_closeButton"
/> />

View File

@@ -9,6 +9,7 @@
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let script; export let script;
export let onConfirm; export let onConfirm;
@@ -19,7 +20,7 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<div slot="header">Save changes</div> <div slot="header">{_t('common.saveChanges', { defaultMessage: 'Save changes' })}</div>
<div class="editor"> <div class="editor">
<AceEditor mode="javascript" readOnly value={script} /> <AceEditor mode="javascript" readOnly value={script} />
@@ -28,7 +29,7 @@
{#if skipConfirmSettingKey} {#if skipConfirmSettingKey}
<div class="mt-2"> <div class="mt-2">
<TemplatedCheckboxField <TemplatedCheckboxField
label="Don't ask again" label={_t('common.dontAskAgain', { defaultMessage: "Don't ask again" })}
templateProps={{ noMargin: true }} templateProps={{ noMargin: true }}
checked={dontAskAgain} checked={dontAskAgain}
on:change={e => { on:change={e => {
@@ -41,16 +42,16 @@
<div slot="footer"> <div slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onConfirm(); onConfirm();
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Open script" value={_t('common.openScript', { defaultMessage: 'Open script' })}
on:click={() => { on:click={() => {
newQuery({ newQuery({
initialData: script, initialData: script,

View File

@@ -54,6 +54,7 @@
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal, showModal } from './modalTools'; import { closeCurrentModal, showModal } from './modalTools';
import { _t } from '../translations';
export let sql; export let sql;
export let onConfirm; export let onConfirm;
@@ -81,7 +82,7 @@
<FormProviderCore {values}> <FormProviderCore {values}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<div slot="header">Save changes</div> <div slot="header">{_t('common.saveChanges', { defaultMessage: 'Save changes' })}</div>
<div class="editor"> <div class="editor">
<SqlEditor {engine} value={currentScript} readOnly /> <SqlEditor {engine} value={currentScript} readOnly />
@@ -91,7 +92,7 @@
<div class="mt-2"> <div class="mt-2">
<FormCheckboxField <FormCheckboxField
templateProps={{ noMargin: true }} templateProps={{ noMargin: true }}
label="Delete references CASCADE" label={_t('sqlModal.deleteReferencesCascade', { defaultMessage: 'Delete references CASCADE' })}
name="deleteReferencesCascade" name="deleteReferencesCascade"
data-testid="ConfirmSqlModal_deleteReferencesCascade" data-testid="ConfirmSqlModal_deleteReferencesCascade"
/> />
@@ -101,13 +102,13 @@
{#if $values.deleteReferencesCascade} {#if $values.deleteReferencesCascade}
<div class="form-margin flex"> <div class="form-margin flex">
<FormStyledButton <FormStyledButton
value="Check all" value={_t('common.checkAll', { defaultMessage: 'Check all' })}
on:click={() => { on:click={() => {
$values = _.omitBy($values, (v, k) => k.startsWith('deleteReferencesFor_')); $values = _.omitBy($values, (v, k) => k.startsWith('deleteReferencesFor_'));
}} }}
/> />
<FormStyledButton <FormStyledButton
value="Uncheck all" value={_t('common.uncheckAll', { defaultMessage: 'Uncheck all' })}
on:click={() => { on:click={() => {
const newValues = { ...$values }; const newValues = { ...$values };
for (const item of deleteCascadesScripts) { for (const item of deleteCascadesScripts) {
@@ -135,12 +136,11 @@
{#if isRecreated} {#if isRecreated}
<div class="form-margin"> <div class="form-margin">
<div> <div>
<FontIcon icon="img warn" /> This operation is not directly supported by SQL engine. DbGate can emulate it, but <FontIcon icon="img warn" /> {_t('sqlModal.recreateWarning', { defaultMessage: "This operation is not directly supported by SQL engine. DbGate can emulate it, but please check the generated SQL script." })}
please check the generated SQL script.
</div> </div>
<FormCheckboxField <FormCheckboxField
templateProps={{ noMargin: true }} templateProps={{ noMargin: true }}
label="Allow recreate (don't use on production databases)" label={_t('sqlModal.allowRecreate', { defaultMessage: "Allow recreate (don't use on production databases)" })}
name="allowRecreate" name="allowRecreate"
/> />
</div> </div>
@@ -149,7 +149,7 @@
{#if skipConfirmSettingKey} {#if skipConfirmSettingKey}
<div class="mt-2"> <div class="mt-2">
<TemplatedCheckboxField <TemplatedCheckboxField
label="Don't ask again" label={_t('common.dontAskAgain', { defaultMessage: "Don't ask again" })}
templateProps={{ noMargin: true }} templateProps={{ noMargin: true }}
checked={dontAskAgain} checked={dontAskAgain}
on:change={e => { on:change={e => {
@@ -162,7 +162,7 @@
<div slot="footer"> <div slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
disabled={isRecreated && !$values.allowRecreate} disabled={isRecreated && !$values.allowRecreate}
on:click={e => { on:click={e => {
closeCurrentModal(); closeCurrentModal();
@@ -172,13 +172,13 @@
/> />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Close" value={_t('common.close', { defaultMessage: 'Close' })}
on:click={closeCurrentModal} on:click={closeCurrentModal}
data-testid="ConfirmSqlModal_closeButton" data-testid="ConfirmSqlModal_closeButton"
/> />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Open script" value={_t('common.openScript', { defaultMessage: 'Open script' })}
on:click={() => { on:click={() => {
newQuery({ newQuery({
initialData: currentScript, initialData: currentScript,

View File

@@ -28,6 +28,7 @@
import { callServerPing } from '../utility/connectionsPinger'; import { callServerPing } from '../utility/connectionsPinger';
import { getConnectionLabel } from 'dbgate-tools'; import { getConnectionLabel } from 'dbgate-tools';
import { openedConnections } from '../stores'; import { openedConnections } from '../stores';
import { _t } from '../translations';
export let conid; export let conid;
export let passwordMode; export let passwordMode;
@@ -125,11 +126,11 @@
<FormProviderCore {values}> <FormProviderCore {values}>
<ModalBase {...$$restProps} simple> <ModalBase {...$$restProps} simple>
<svelte:fragment slot="header">Database Log In ({engineTitle})</svelte:fragment> <svelte:fragment slot="header">{_t('databaseLoginModal.header', { defaultMessage: 'Database Log In ({engineTitle})', values: {engineTitle} })}</svelte:fragment>
<FormTextField label="Connection" name="connectionLabel" disabled /> <FormTextField label={_t('databaseLoginModal.connection', { defaultMessage: 'Connection' })} name="connectionLabel" disabled />
<FormTextField <FormTextField
label="Username" label={_t('databaseLoginModal.username', { defaultMessage: 'Username' })}
name="user" name="user"
autocomplete="username" autocomplete="username"
disabled={usedPasswordMode == 'askPassword'} disabled={usedPasswordMode == 'askPassword'}
@@ -138,7 +139,7 @@
data-testid="DatabaseLoginModal_username" data-testid="DatabaseLoginModal_username"
/> />
<FormPasswordField <FormPasswordField
label="Password" label={_t('databaseLoginModal.password', { defaultMessage: 'Password' })}
name="password" name="password"
autocomplete="current-password" autocomplete="current-password"
focused={usedPasswordMode == 'askPassword'} focused={usedPasswordMode == 'askPassword'}
@@ -148,34 +149,34 @@
{#if isTesting} {#if isTesting}
<div> <div>
<FontIcon icon="icon loading" /> Testing connection <FontIcon icon="icon loading" /> {_t('databaseLoginModal.testingConnection', { defaultMessage: 'Testing connection' })}
</div> </div>
{/if} {/if}
{#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'error'} {#if !isTesting && sqlConnectResult && sqlConnectResult.msgtype == 'error'}
<div class="error-result"> <div class="error-result">
Connect failed: <FontIcon icon="img error" /> {_t('databaseLoginModal.connectFailed', { defaultMessage: 'Connect failed:' })} <FontIcon icon="img error" />
{sqlConnectResult.error} {sqlConnectResult.error}
<Link <Link
onClick={() => onClick={() =>
showModal(ErrorMessageModal, { showModal(ErrorMessageModal, {
message: sqlConnectResult.detail, message: sqlConnectResult.detail,
showAsCode: true, showAsCode: true,
title: 'Database connection error', title: _t('databaseLoginModal.connectionError', { defaultMessage: 'Database connection error' }),
})} })}
> >
Show detail {_t('databaseLoginModal.showDetail', { defaultMessage: 'Show detail' })}
</Link> </Link>
</div> </div>
{/if} {/if}
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
{#if isTesting} {#if isTesting}
<FormStyledButton value="Stop connecting" on:click={handleCancelTest} data-testid="DatabaseLoginModal_stop" /> <FormStyledButton value={_t('databaseLoginModal.stopConnecting', { defaultMessage: 'Stop connecting' })} on:click={handleCancelTest} data-testid="DatabaseLoginModal_stop" />
{:else} {:else}
<FormSubmit value="Connect" on:click={handleSubmit} data-testid="DatabaseLoginModal_connect" /> <FormSubmit value={_t('databaseLoginModal.connect', { defaultMessage: 'Connect' })} on:click={handleSubmit} data-testid="DatabaseLoginModal_connect" />
{/if} {/if}
<FormStyledButton value="Close" on:click={closeCurrentModal} data-testid="DatabaseLoginModal_close" /> <FormStyledButton value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} data-testid="DatabaseLoginModal_close" />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProviderCore> </FormProviderCore>

View File

@@ -5,6 +5,7 @@
import FormProvider from '../forms/FormProvider.svelte'; import FormProvider from '../forms/FormProvider.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let keyInfo; export let keyInfo;
export let label; export let label;
@@ -21,7 +22,7 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Add item</svelte:fragment> <svelte:fragment slot="header">{_t('dbKeyAddItemModal.header', { defaultMessage: 'Add item' })}</svelte:fragment>
<div class="container"> <div class="container">
<DbKeyItemDetail <DbKeyItemDetail
@@ -34,8 +35,8 @@
</div> </div>
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormStyledButton value="OK" on:click={e => handleSubmit()} /> <FormStyledButton value={_t('common.ok', { defaultMessage: 'OK' })} on:click={e => handleSubmit()} />
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -21,6 +21,7 @@
import { currentDatabase } from '../stores'; import { currentDatabase } from '../stores';
import { filterAppsForDatabase } from '../utility/appTools'; import { filterAppsForDatabase } from '../utility/appTools';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
export let conid; export let conid;
export let database; export let database;
@@ -52,10 +53,10 @@
<FormProviderCore {values}> <FormProviderCore {values}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Define description</svelte:fragment> <svelte:fragment slot="header">{_t('defineDictionaryDescriptionModal.header', { defaultMessage: 'Define description' })}</svelte:fragment>
<FormSelectField <FormSelectField
label="Target application (mandatory)" label={_t('defineDictionaryDescriptionModal.targetApplication', { defaultMessage: 'Target application (mandatory)' })}
name="targetApplication" name="targetApplication"
disableInitialize disableInitialize
selectFieldComponent={TargetApplicationSelect} selectFieldComponent={TargetApplicationSelect}
@@ -68,8 +69,8 @@
rows={$tableInfo?.columns || []} rows={$tableInfo?.columns || []}
columns={[ columns={[
{ fieldName: 'checked', header: '', slot: 1 }, { fieldName: 'checked', header: '', slot: 1 },
{ fieldName: 'columnName', header: 'Column' }, { fieldName: 'columnName', header: _t('defineDictionaryDescriptionModal.column', { defaultMessage: 'Column' }) },
{ fieldName: 'dataType', header: 'Data type' }, { fieldName: 'dataType', header: _t('defineDictionaryDescriptionModal.dataType', { defaultMessage: 'Data type' }) },
]} ]}
> >
<input <input
@@ -88,15 +89,15 @@
</TableControl> </TableControl>
</div> </div>
<FormTextField name="columns" label="Show columns" /> <FormTextField name="columns" label={_t('defineDictionaryDescriptionModal.showColumns', { defaultMessage: 'Show columns' })} />
<FormTextField name="delimiter" label="Delimiter" /> <FormTextField name="delimiter" label={_t('defineDictionaryDescriptionModal.delimiter', { defaultMessage: 'Delimiter' })} />
<!-- <FormCheckboxField name="useForAllDatabases" label="Use for all databases" /> --> <!-- <FormCheckboxField name="useForAllDatabases" label="Use for all databases" /> -->
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
disabled={!checkDescriptionExpression($values?.columns, $tableInfo) || !$values.targetApplication} disabled={!checkDescriptionExpression($values?.columns, $tableInfo) || !$values.targetApplication}
on:click={async () => { on:click={async () => {
closeCurrentModal(); closeCurrentModal();
@@ -122,7 +123,7 @@
onConfirm?.(); onConfirm?.();
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProviderCore> </FormProviderCore>

View File

@@ -15,6 +15,7 @@
import FormTextField from '../forms/FormTextField.svelte'; import FormTextField from '../forms/FormTextField.svelte';
import _ from 'lodash'; import _ from 'lodash';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
export let onConfirm; export let onConfirm;
export let conid; export let conid;
@@ -126,15 +127,15 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Lookup from {pureName}</svelte:fragment> <svelte:fragment slot="header">{_t('dictionaryLookupModal.header', { defaultMessage: 'Lookup from {pureName}', values: {pureName} })}</svelte:fragment>
<!-- <FormTextField name="search" label='Search' placeholder="Search" bind:value={search} /> --> <!-- <FormTextField name="search" label='Search' placeholder="Search" bind:value={search} /> -->
<div class="largeFormMarker"> <div class="largeFormMarker">
<SearchInput placeholder="Search" bind:value={search} isDebounced /> <SearchInput placeholder={_t("common.search", { defaultMessage: "Search" })} bind:value={search} isDebounced />
</div> </div>
{#if isLoading} {#if isLoading}
<LoadingInfo message="Loading data" /> <LoadingInfo message={_t('dictionaryLookupModal.loadingData', { defaultMessage: "Loading data" })} />
{/if} {/if}
{#if !isLoading && tableInfo && description && rows && tableInfo?.primaryKey?.columns?.length == 1} {#if !isLoading && tableInfo && description && rows && tableInfo?.primaryKey?.columns?.length == 1}
@@ -161,13 +162,13 @@
}, },
{ {
fieldName: 'value', fieldName: 'value',
header: 'Value', header: _t('dictionaryLookupModal.value', { defaultMessage: 'Value' }),
formatter: row => row[tableInfo.primaryKey.columns[0].columnName], formatter: row => row[tableInfo.primaryKey.columns[0].columnName],
width: '100px', width: '100px',
}, },
{ {
fieldName: 'description', fieldName: 'description',
header: 'Description', header: _t('dictionaryLookupModal.description', { defaultMessage: 'Description' }),
formatter: row => description.columns.map(col => row[col]).join(description.delimiter || ' '), formatter: row => description.columns.map(col => row[col]).join(description.delimiter || ' '),
}, },
]} ]}
@@ -194,15 +195,15 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
{#if multiselect} {#if multiselect}
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onConfirm(checkedKeys); onConfirm(checkedKeys);
}} }}
/> />
{/if} {/if}
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
<FormStyledButton type="button" value="Customize" on:click={defineDescription} /> <FormStyledButton type="button" value={_t('dictionaryLookupModal.customize', { defaultMessage: 'Customize' })} on:click={defineDescription} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -66,7 +66,7 @@
<div slot="footer" class="footer"> <div slot="footer" class="footer">
<div> <div>
<FormStyledButton <FormStyledButton
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
title="Ctrl+Enter" title="Ctrl+Enter"
on:click={() => { on:click={() => {
onSave(parseCellValue(textValue, dataEditorTypesBehaviour)); onSave(parseCellValue(textValue, dataEditorTypesBehaviour));

View File

@@ -30,11 +30,10 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<div slot="header">Edit JSON value</div> <div slot="header">{_t('editJsonModal.header', { defaultMessage: 'Edit JSON value' })}</div>
{#if showPasteInfo} {#if showPasteInfo}
<div class="m-2"> <div class="m-2">
Edit JSON object or array. You can paste JSON array or object directly into data grid, new row(s) will be added {_t('editJsonModal.pasteInfo', { defaultMessage: "Edit JSON object or array. You can paste JSON array or object directly into data grid, new row(s) will be added to recordset." })}
to recordset.
</div> </div>
{/if} {/if}

View File

@@ -168,11 +168,11 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps} fullScreen> <ModalBase {...$$restProps} fullScreen>
<div slot="header"> <div slot="header">
{mode == 'export' ? 'Export' : 'Import'} connections &amp; settings {mode == 'export' ? 'Export' : 'Import'} {_t('importExport.connectionsSettings', { defaultMessage: 'connections & settings' })}
<span class="check-uncheck"> <span class="check-uncheck">
<Link onClick={() => handleCheckAll(true)}>Check all</Link> <Link onClick={() => handleCheckAll(true)}>{_t('common.checkAll', { defaultMessage: 'Check all' })}</Link>
| |
<Link onClick={() => handleCheckAll(false)}>Uncheck all</Link> <Link onClick={() => handleCheckAll(false)}>{_t('common.uncheckAll', { defaultMessage: 'Uncheck all' })}</Link>
</span> </span>
</div> </div>
@@ -180,16 +180,16 @@
<TabControl <TabControl
tabs={_.compact([ tabs={_.compact([
connections?.length && { connections?.length && {
label: `Connections (${checkedConnections?.length}/${connections?.length})`, label: _t('importExport.connectionsNum', { defaultMessage:'Connections ({checkedConnections}/{connections})', values: { checkedConnections: checkedConnections?.length, connections: connections?.length } }),
slot: 1, slot: 1,
}, },
users?.length && { label: `Users (${checkedUsers?.length}/${users?.length})`, slot: 2 }, users?.length && { label: _t('importExport.usersNum', { defaultMessage:'Users ({checkedUsers}/{users})', values: { checkedUsers: checkedUsers?.length, users: users?.length } }), slot: 2 },
roles?.length && { label: `Roles (${checkedRoles?.length}/${roles?.length})`, slot: 3 }, roles?.length && { label: _t('importExport.rolesNum', { defaultMessage:'Roles ({checkedRoles}/{roles})', values: { checkedRoles: checkedRoles?.length, roles: roles?.length } }), slot: 3 },
authMethods?.length && { authMethods?.length && {
label: `Auth methods (${checkedAuthMethods?.length}/${authMethods?.length})`, label: _t('importExport.authMethodsNum', { defaultMessage:'Auth methods ({checkedAuthMethods}/{authMethods})', values: { checkedAuthMethods: checkedAuthMethods?.length, authMethods: authMethods?.length } }),
slot: 4, slot: 4,
}, },
config?.length && { label: `Config (${checkedConfig?.length}/${config?.length})`, slot: 5 }, config?.length && { label: _t('importExport.configNum', { defaultMessage:'Config ({checkedConfig}/{config})', values: { checkedConfig: checkedConfig?.length, config: config?.length } }), slot: 5 },
])} ])}
> >
<svelte:fragment slot="1"> <svelte:fragment slot="1">
@@ -199,10 +199,10 @@
stickyHeader stickyHeader
columns={[ columns={[
{ header: 'ID', fieldName: 'id', sortable: true, filterable: true }, { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
{ header: 'Display name', fieldName: 'displayName', sortable: true, filterable: true }, { header: _t('importExport.displayName', { defaultMessage: 'Display name' }), fieldName: 'displayName', sortable: true, filterable: true },
{ header: 'Engine', fieldName: 'engine', sortable: true, filterable: true }, { header: _t('importExport.engine', { defaultMessage: 'Engine' }), fieldName: 'engine', sortable: true, filterable: true },
{ header: 'Server', fieldName: 'server', sortable: true, filterable: true }, { header: _t('importExport.server', { defaultMessage: 'Server' }), fieldName: 'server', sortable: true, filterable: true },
{ header: 'User', fieldName: 'user', sortable: true, filterable: true }, { header: _t('importExport.user', { defaultMessage: 'User' }), fieldName: 'user', sortable: true, filterable: true },
]} ]}
clickable clickable
rows={connections} rows={connections}
@@ -225,8 +225,8 @@
stickyHeader stickyHeader
columns={[ columns={[
{ header: 'ID', fieldName: 'id', sortable: true, filterable: true }, { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
{ header: 'Login', fieldName: 'login', sortable: true, filterable: true }, { header: _t('importExport.login', { defaultMessage: 'Login' }), fieldName: 'login', sortable: true, filterable: true },
{ header: 'E-mail', fieldName: 'email', sortable: true, filterable: true }, { header: _t('importExport.email', { defaultMessage: 'E-mail' }), fieldName: 'email', sortable: true, filterable: true },
]} ]}
clickable clickable
rows={users} rows={users}
@@ -249,7 +249,7 @@
stickyHeader stickyHeader
columns={[ columns={[
{ header: 'ID', fieldName: 'id', sortable: true, filterable: true }, { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
{ header: 'Name', fieldName: 'name', sortable: true, filterable: true }, { header: _t('importExport.name', { defaultMessage: 'Name' }), fieldName: 'name', sortable: true, filterable: true },
]} ]}
clickable clickable
rows={roles} rows={roles}
@@ -272,8 +272,8 @@
stickyHeader stickyHeader
columns={[ columns={[
{ header: 'ID', fieldName: 'id', sortable: true, filterable: true }, { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
{ header: 'Name', fieldName: 'name', sortable: true, filterable: true }, { header: _t('importExport.name', { defaultMessage: 'Name' }), fieldName: 'name', sortable: true, filterable: true },
{ header: 'Type', fieldName: 'type', sortable: true, filterable: true }, { header: _t('importExport.type', { defaultMessage: 'Type' }), fieldName: 'type', sortable: true, filterable: true },
]} ]}
clickable clickable
rows={authMethods} rows={authMethods}
@@ -296,9 +296,9 @@
stickyHeader stickyHeader
columns={[ columns={[
{ header: 'ID', fieldName: 'id', sortable: true, filterable: true }, { header: 'ID', fieldName: 'id', sortable: true, filterable: true },
{ header: 'Group', fieldName: 'group', sortable: true, filterable: true }, { header: _t('importExport.group', { defaultMessage: 'Group' }), fieldName: 'group', sortable: true, filterable: true },
{ header: 'Key', fieldName: 'key', sortable: true, filterable: true }, { header: _t('importExport.key', { defaultMessage: 'Key' }), fieldName: 'key', sortable: true, filterable: true },
{ header: 'Value', fieldName: 'value', sortable: true, filterable: true }, { header: _t('importExport.value', { defaultMessage: 'Value' }), fieldName: 'value', sortable: true, filterable: true },
]} ]}
clickable clickable
rows={config} rows={config}
@@ -340,7 +340,7 @@
> >
{/if} {/if}
<LargeButton icon="icon close" on:click={closeCurrentModal} data-testid="EditJsonModal_closeButton" <LargeButton icon="icon close" on:click={closeCurrentModal} data-testid="EditJsonModal_closeButton"
>Close</LargeButton >{_t('common.close', { defaultMessage: 'Close' })}</LargeButton
> >
</div> </div>
</div> </div>

View File

@@ -16,6 +16,7 @@
import FormSubmit from '../forms/FormSubmit.svelte'; import FormSubmit from '../forms/FormSubmit.svelte';
import FormButton from '../forms/FormButton.svelte'; import FormButton from '../forms/FormButton.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
export let editingData; export let editingData;
export let savingTab; export let savingTab;
@@ -113,28 +114,28 @@
<FormProvider {initialValues}> <FormProvider {initialValues}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">{editingData ? 'Edit favorite' : 'Share / add to favorites'}</svelte:fragment> <svelte:fragment slot="header">{editingData ? _t('favorite.editFavorite', { defaultMessage: 'Edit favorite' }) : _t('favorite.shareAddToFavorites', { defaultMessage: 'Share / add to favorites' })}</svelte:fragment>
<FormTextField label="Title" name="title" focused /> <FormTextField label={_t('favorite.title', { defaultMessage: 'Title' })} name="title" focused />
<FormTextField label="Icon" name="icon" /> <FormTextField label={_t('favorite.icon', { defaultMessage: 'Icon' })} name="icon" />
<FormTextField label="URL path" name="urlPath" /> <FormTextField label={_t('favorite.urlPath', { defaultMessage: 'URL path' })} name="urlPath" />
{#if !!savingTab && !electron && canWriteFavorite} {#if !!savingTab && !electron && canWriteFavorite}
<FormCheckboxField label="Share as link" name="shareAsLink" /> <FormCheckboxField label={_t('favorite.shareAsLink', { defaultMessage: 'Share as link' })} name="shareAsLink" />
{/if} {/if}
<FormValues let:values> <FormValues let:values>
{#if !values.shareAsLink && canWriteFavorite} {#if !values.shareAsLink && canWriteFavorite}
<FormCheckboxField label="Show in toolbar" name="showInToolbar" /> <FormCheckboxField label={_t('favorite.showInToolbar', { defaultMessage: 'Show in toolbar' })} name="showInToolbar" />
<FormCheckboxField label="Open on startup" name="openOnStartup" /> <FormCheckboxField label={_t('favorite.openOnStartup', { defaultMessage: 'Open on startup' })} name="openOnStartup" />
{/if} {/if}
</FormValues> </FormValues>
{#if !!savingTab && !!savedFile} {#if !!savingTab && !!savedFile}
<FormSelectField <FormSelectField
label="What to save" label={_t('favorite.whatToSave', { defaultMessage: 'What to save' })}
name="whatToSave" name="whatToSave"
options={[ options={[
{ label: 'Link to file', value: 'fileName' }, { label: _t('favorite.linkToFile', { defaultMessage: 'Link to file' }), value: 'fileName' },
{ label: 'Content', value: 'content' }, { label: _t('favorite.content', { defaultMessage: 'Content' }), value: 'content' },
]} ]}
/> />
{/if} {/if}
@@ -142,12 +143,12 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormValues let:values> <FormValues let:values>
{#if !values.shareAsLink && canWriteFavorite} {#if !values.shareAsLink && canWriteFavorite}
<FormSubmit value="OK" on:click={handleSubmit} /> <FormSubmit value={_t('common.ok', { defaultMessage: 'OK' })} on:click={handleSubmit} />
{/if} {/if}
{#if values.shareAsLink || !canWriteFavorite} {#if values.shareAsLink || !canWriteFavorite}
<FormButton value="Copy link" on:click={handleCopyLink} /> <FormButton value={_t('common.copyLink', { defaultMessage: 'Copy link' })} on:click={handleCopyLink} />
{/if} {/if}
<FormButton value="Cancel" on:click={closeCurrentModal} /> <FormButton value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</FormValues> </FormValues>
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -3,6 +3,7 @@
import FormStyledButton from '../buttons/FormStyledButton.svelte'; import FormStyledButton from '../buttons/FormStyledButton.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let onFilter; export let onFilter;
@@ -16,35 +17,35 @@
</script> </script>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<div slot="header">Filter multiple values</div> <div slot="header">{_t('filterMultipleValues.filterMultipleValues', { defaultMessage: 'Filter multiple values' })}</div>
<div class="flex"> <div class="flex">
<TextAreaField rows={10} bind:value focused /> <TextAreaField rows={10} bind:value focused />
<div> <div>
<div> <div>
<input type="radio" bind:group value="is" id="__is" /> <input type="radio" bind:group value="is" id="__is" />
<label for="__is">Is one of line</label>' <label for="__is">{_t('filterMultipleValues.isOneOfLine', { defaultMessage: 'Is one of line' })}</label>'
</div> </div>
<div> <div>
<input type="radio" bind:group value="is_not" id="__is_not" /> <input type="radio" bind:group value="is_not" id="__is_not" />
<label for="__is_not">Is not one of line</label>' <label for="__is_not">{_t('filterMultipleValues.isNotOneOfLine', { defaultMessage: 'Is not one of line' })}</label>'
</div> </div>
<div> <div>
<input type="radio" bind:group value="contains" id="__contains" /> <input type="radio" bind:group value="contains" id="__contains" />
<label for="__contains">Contains</label>' <label for="__contains">{_t('filterMultipleValues.contains', { defaultMessage: 'Contains' })}</label>'
</div> </div>
<div> <div>
<input type="radio" bind:group value="begins" id="__begins" /> <input type="radio" bind:group value="begins" id="__begins" />
<label for="__begins">Begins</label>' <label for="__begins">{_t('filterMultipleValues.begins', { defaultMessage: 'Begins' })}</label>'
</div> </div>
<div> <div>
<input type="radio" bind:group value="ends" id="__ends" /> <input type="radio" bind:group value="ends" id="__ends" />
<label for="__ends">Ends</label>' <label for="__ends">{_t('filterMultipleValues.ends', { defaultMessage: 'Ends' })}</label>'
</div> </div>
</div> </div>
</div> </div>
<div slot="footer"> <div slot="footer">
<FormStyledButton value="OK" on:click={handleOk} /> <FormStyledButton value={_t('common.ok', { defaultMessage: 'OK' })} on:click={handleOk} />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</div> </div>
</ModalBase> </ModalBase>

View File

@@ -9,6 +9,7 @@
import newQuery from '../query/newQuery'; import newQuery from '../query/newQuery';
import SqlEditor from '../query/SqlEditor.svelte'; import SqlEditor from '../query/SqlEditor.svelte';
import keycodes from '../utility/keycodes'; import keycodes from '../utility/keycodes';
import { _t } from '../translations';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
@@ -77,24 +78,23 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Generate SQL from data</svelte:fragment> <svelte:fragment slot="header">{_t('generateSqlFromData.generateSqlFromData', { defaultMessage: 'Generate SQL from data' })}</svelte:fragment>
<div class="flex mb-3"> <div class="flex mb-3">
<div class="m-1 col-4"> <div class="m-1 col-4">
<div class="m-1">Choose query type</div> <div class="m-1">{_t('generateSqlFromData.chooseQueryType', { defaultMessage: 'Choose query type' })}</div>
<TableControl <TableControl
rows={QUERY_TYPES.map(name => ({ name }))} rows={QUERY_TYPES.map(name => ({ name }))}
bind:selectedIndex={queryTypeIndex} bind:selectedIndex={queryTypeIndex}
bind:domTable={domQueryType} bind:domTable={domQueryType}
focusOnCreate focusOnCreate
selectable selectable
columns={[{ fieldName: 'name', header: 'Query type' }]} columns={[{ fieldName: 'name', header: _t('generateSqlFromData.queryType', { defaultMessage: 'Query type' }) }]}
/> />
</div> </div>
<div class="m-1 col-4"> <div class="m-1 col-4">
<div class="m-1">Value columns</div> <div class="m-1">{_t('generateSqlFromData.valueColumns', { defaultMessage: 'Value columns' })}</div>
<CheckableColumnList <CheckableColumnList
{allColumns} {allColumns}
@@ -120,13 +120,13 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={() => { on:click={() => {
newQuery({ initialData: sqlPreview }); newQuery({ initialData: sqlPreview });
closeCurrentModal(); closeCurrentModal();
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -29,7 +29,7 @@
<FormTextField {label} name="value" focused data-testid="InputTextModal_value" /> <FormTextField {label} name="value" focused data-testid="InputTextModal_value" />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit value="OK" on:click={e => handleSubmit(e.detail)} data-testid="InputTextModal_ok" /> <FormSubmit value={_t('common.ok', { defaultMessage: 'OK' })} on:click={e => handleSubmit(e.detail)} data-testid="InputTextModal_ok" />
<FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} data-testid="InputTextModal_cancel" /> <FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} data-testid="InputTextModal_cancel" />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -9,6 +9,8 @@
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
import _ from 'lodash';
export let sql; export let sql;
export let onInsert; export let onInsert;
@@ -104,12 +106,11 @@
</script> </script>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Insert join</svelte:fragment> <svelte:fragment slot="header">{_t('insertJoin.insertJoin', { defaultMessage: 'Insert join' })}</svelte:fragment>
<div class="flex mb-3"> <div class="flex mb-3">
<div class="m-1 col-3"> <div class="m-1 col-3">
<div class="m-1">Existing table</div> <div class="m-1">{_t('insertJoin.existingTable', { defaultMessage: 'Existing table' })}</div>
<TableControl <TableControl
rows={sources} rows={sources}
focusOnCreate focusOnCreate
@@ -118,14 +119,14 @@
selectable selectable
on:keydown={sourceKeyDown} on:keydown={sourceKeyDown}
columns={[ columns={[
{ fieldName: 'alias', header: 'Alias' }, { fieldName: 'alias', header: _t('insertJoin.alias', { defaultMessage: 'Alias' }) },
{ fieldName: 'name', header: 'Name' }, { fieldName: 'name', header: _t('insertJoin.name', { defaultMessage: 'Name' }) },
]} ]}
/> />
</div> </div>
<div class="m-1 col-6"> <div class="m-1 col-6">
<div class="m-1">New table</div> <div class="m-1">{_t('insertJoin.newTable', { defaultMessage: 'New table' })}</div>
<TableControl <TableControl
rows={targets} rows={targets}
@@ -134,15 +135,15 @@
selectable selectable
on:keydown={targetKeyDown} on:keydown={targetKeyDown}
columns={[ columns={[
{ fieldName: 'baseColumns', header: 'Column from' }, { fieldName: 'baseColumns', header: _t('insertJoin.columnFrom', { defaultMessage: 'Column from' }) },
{ fieldName: 'refTable', header: 'Table to' }, { fieldName: 'refTable', header: _t('insertJoin.tableTo', { defaultMessage: 'Table to' }) },
{ fieldName: 'refColumns', header: 'Column to' }, { fieldName: 'refColumns', header: _t('insertJoin.columnTo', { defaultMessage: 'Column to' }) },
]} ]}
/> />
</div> </div>
<div class="m-1 col-3"> <div class="m-1 col-3">
<div class="m-1">Join</div> <div class="m-1">{_t('insertJoin.join', { defaultMessage: 'Join' })}</div>
<TableControl <TableControl
rows={JOIN_TYPES.map(name => ({ name }))} rows={JOIN_TYPES.map(name => ({ name }))}
@@ -150,10 +151,10 @@
bind:domTable={domJoin} bind:domTable={domJoin}
selectable selectable
on:keydown={joinKeyDown} on:keydown={joinKeyDown}
columns={[{ fieldName: 'name', header: 'Join type' }]} columns={[{ fieldName: 'name', header: _t('insertJoin.joinType', { defaultMessage: 'Join type' }) }]}
/> />
<div class="m-1">Alias</div> <div class="m-1">{_t('insertJoin.alias', { defaultMessage: 'Alias' })}</div>
<TextField <TextField
value={alias} value={alias}
on:input={e => { on:input={e => {
@@ -171,13 +172,13 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormStyledButton <FormStyledButton
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onInsert(sqlPreview); onInsert(sqlPreview);
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -5,6 +5,7 @@
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import { openWebLink } from '../utility/simpleTools'; import { openWebLink } from '../utility/simpleTools';
import { _t } from '../translations';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
@@ -15,7 +16,7 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<div slot="header">License limit error</div> <div slot="header">{_t('licenseLimit.licenseLimitError', { defaultMessage: 'License limit error' })}</div>
<div class="wrapper"> <div class="wrapper">
<div class="icon"> <div class="icon">
@@ -23,15 +24,15 @@
</div> </div>
<div data-testid="LicenseLimitMessageModal_message"> <div data-testid="LicenseLimitMessageModal_message">
<p> <p>
Cloud operation ended with error:<br /> {_t('licenseLimit.cloudOperationEndedWithError', { defaultMessage: 'Cloud operation ended with error:' })}<br />
{message} {message}
</p> </p>
<p> <p>
This is a limitation of the free version of DbGate. To continue using cloud operations, please {#if !isProApp()}download {_t('licenseLimit.limitationMessage', { defaultMessage: 'This is a limitation of the free version of DbGate. To continue using cloud operations, please' })} {#if !isProApp()} {_t('licenseLimit.download', { defaultMessage: 'download and' })}
and{/if} purchase DbGate Premium. {/if} {_t('licenseLimit.purchase', { defaultMessage: 'purchase DbGate Premium.' })}
</p> </p>
<p>Free version limit:</p> <p>{_t('licenseLimit.freeVersionLimit', { defaultMessage: 'Free version limit:' })}</p>
<ul> <ul>
{#each licenseLimits || [] as limit} {#each licenseLimits || [] as limit}
<li>{limit}</li> <li>{limit}</li>
@@ -41,16 +42,16 @@
</div> </div>
<div slot="footer"> <div slot="footer">
<FormSubmit value="Close" on:click={closeCurrentModal} data-testid="LicenseLimitMessageModal_closeButton" /> <FormSubmit value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} data-testid="LicenseLimitMessageModal_closeButton" />
{#if !isProApp()} {#if !isProApp()}
<FormStyledButton <FormStyledButton
value="Download DbGate Premium" value={_t('licenseLimit.downloadDbGatePremium', { defaultMessage: 'Download DbGate Premium' })}
on:click={() => openWebLink('https://www.dbgate.io/download/')} on:click={() => openWebLink('https://www.dbgate.io/download/')}
skipWidth skipWidth
/> />
{/if} {/if}
<FormStyledButton <FormStyledButton
value="Purchase DbGate Premium" value={_t('licenseLimit.purchaseDbGatePremium', { defaultMessage: 'Purchase DbGate Premium' })}
on:click={() => openWebLink('https://www.dbgate.io/purchase/premium/')} on:click={() => openWebLink('https://www.dbgate.io/purchase/premium/')}
skipWidth skipWidth
/> />

View File

@@ -30,9 +30,9 @@
const { errorMessage } = resp || {}; const { errorMessage } = resp || {};
if (errorMessage) { if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when executing operation', message: errorMessage }); showModal(ErrorMessageModal, { title: _t('error.executingOperation', { defaultMessage: 'Error when executing operation' }), message: errorMessage });
} else { } else {
showSnackbarSuccess('Saved to database'); showSnackbarSuccess(_t('common.savedToDatabase', { defaultMessage: 'Saved to database' }));
apiCall('database-connections/sync-model', dbid); apiCall('database-connections/sync-model', dbid);
closeCurrentModal(); closeCurrentModal();
} }
@@ -51,7 +51,7 @@
<FormArgumentList args={driver?.newCollectionFormParams} /> <FormArgumentList args={driver?.newCollectionFormParams} />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit value="OK" on:click={e => handleSubmit(e.detail)} disabled={isSaving} /> <FormSubmit value={_t('common.ok', { defaultMessage: 'OK' })} on:click={e => handleSubmit(e.detail)} disabled={isSaving} />
<FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -102,7 +102,7 @@
{ {
icon: 'icon compare', icon: 'icon compare',
colorClass: 'color-icon-red', colorClass: 'color-icon-red',
title: _t('common.compare', { defaultMessage: 'Compare database' }), title: _t('common.compareDatabase', { defaultMessage: 'Compare database' }),
description: _t('newObject.compareDescription', { defaultMessage: 'Compare database schemas' }), description: _t('newObject.compareDescription', { defaultMessage: 'Compare database schemas' }),
command: 'database.compare', command: 'database.compare',
testid: 'NewObjectModal_databaseCompare', testid: 'NewObjectModal_databaseCompare',

View File

@@ -5,6 +5,7 @@
import FormSubmit from '../forms/FormSubmit.svelte'; import FormSubmit from '../forms/FormSubmit.svelte';
import FormTextField from '../forms/FormTextField.svelte'; import FormTextField from '../forms/FormTextField.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
import getElectron from '../utility/getElectron'; import getElectron from '../utility/getElectron';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
@@ -26,7 +27,7 @@
<FormProvider initialValues={parameterValues}> <FormProvider initialValues={parameterValues}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Edit query parameters</svelte:fragment> <svelte:fragment slot="header">{_t('queryParameters.editQueryParameters', { defaultMessage: 'Edit query parameters' })}</svelte:fragment>
<div class="params"> <div class="params">
{#each parameterNames as parameterName, index} {#each parameterNames as parameterName, index}
@@ -34,11 +35,11 @@
{/each} {/each}
</div> </div>
<div>String values must be 'quoted'. You can use valid SQL expressions.</div> <div>{_t('queryParameters.stringValuesMustBeQuoted', { defaultMessage: "String values must be 'quoted'. You can use valid SQL expressions." })}</div>
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit value="Run query" on:click={handleSubmit} /> <FormSubmit value={_t('queryParameters.runQuery', { defaultMessage: 'Run query' })} on:click={handleSubmit} />
<FormStyledButton value="Close" on:click={handleClose} /> <FormStyledButton value={_t('common.close', { defaultMessage: 'Close' })} on:click={handleClose} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -6,6 +6,7 @@
import FormTextField from '../forms/FormTextField.svelte'; import FormTextField from '../forms/FormTextField.svelte';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let value; export let value;
export let onConfirm; export let onConfirm;
@@ -18,24 +19,24 @@
<FormProvider initialValues={{ value }}> <FormProvider initialValues={{ value }}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Rows limit</svelte:fragment> <svelte:fragment slot="header">{_t('query.rowsLimit', { defaultMessage: 'Rows limit' })}</svelte:fragment>
<FormTextField <FormTextField
label="Return only N rows from query" label={_t('query.returnOnlyNRows', { defaultMessage: 'Return only N rows from query' })}
name="value" name="value"
focused focused
data-testid="RowsLimitModal_value" data-testid="RowsLimitModal_value"
placeholder="(No rows limit)" placeholder={_t('query.noRowsLimit', { defaultMessage: '(No rows limit)' })}
/> />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={e => handleSubmit(parseInt(e.detail.value) || null)} on:click={e => handleSubmit(parseInt(e.detail.value) || null)}
data-testid="RowsLimitModal_setLimit" data-testid="RowsLimitModal_setLimit"
/> />
<FormStyledButton value="Set no limit" on:click={e => handleSubmit(null)} data-testid="RowsLimitModal_setNoLimit" /> <FormStyledButton value={_t('common.setNoLimit', { defaultMessage: 'Set no limit' })} on:click={e => handleSubmit(null)} data-testid="RowsLimitModal_setNoLimit" />
<FormStyledButton type="button" value="Cancel" on:click={closeCurrentModal} data-testid="RowsLimitModal_cancel" /> <FormStyledButton type="button" value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} data-testid="RowsLimitModal_cancel" />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -10,6 +10,7 @@
import { showSnackbarError } from '../utility/snackbar'; import { showSnackbarError } from '../utility/snackbar';
import ModalBase from './ModalBase.svelte'; import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools'; import { closeCurrentModal } from './modalTools';
import { _t } from '../translations';
export let script; export let script;
export let header; export let header;
@@ -77,14 +78,14 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
{#if isRunning} {#if isRunning}
<FormStyledButton value="Stop" on:click={handleStop} data-testid="RunScriptModal_stop" /> <FormStyledButton value={_t('script.stop', { defaultMessage: 'Stop' })} on:click={handleStop} data-testid="RunScriptModal_stop" />
{:else} {:else}
<FormStyledButton value="Close" on:click={handleClose} data-testid="RunScriptModal_close" /> <FormStyledButton value={_t('common.close', { defaultMessage: 'Close' })} on:click={handleClose} data-testid="RunScriptModal_close" />
{/if} {/if}
{#if onOpenResult && !isRunning} {#if onOpenResult && !isRunning}
<FormStyledButton <FormStyledButton
value={openResultLabel || 'Open result'} value={openResultLabel || _t('script.openResult', { defaultMessage: 'Open result' })}
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onOpenResult(); onOpenResult();

View File

@@ -24,10 +24,10 @@
<FormProvider initialValues={{ file, folder }}> <FormProvider initialValues={{ file, folder }}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Save to archive</svelte:fragment> <svelte:fragment slot="header">{_t('archive.saveToArchive', { defaultMessage: 'Save to archive' })}</svelte:fragment>
<FormArchiveFolderSelect label="Folder" name="folder" isNative allowCreateNew skipZipFiles /> <FormArchiveFolderSelect label={_t('archive.folder', { defaultMessage: 'Folder' })} name="folder" isNative allowCreateNew skipZipFiles />
<FormTextField label="File name" name="file" disabled={fileIsReadOnly} /> <FormTextField label={_t('archive.fileName', { defaultMessage: 'File name' })} name="file" disabled={fileIsReadOnly} />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit value={_t('common.save', { defaultMessage: 'Save' })} on:click={handleSubmit} /> <FormSubmit value={_t('common.save', { defaultMessage: 'Save' })} on:click={handleSubmit} />

View File

@@ -125,7 +125,7 @@
<FormTextField label="File name" name="name" focused /> <FormTextField label="File name" name="name" focused />
{#if $cloudSigninTokenHolder && !$values['saveToTeamFolder']} {#if $cloudSigninTokenHolder && !$values['saveToTeamFolder']}
<FormCloudFolderSelect <FormCloudFolderSelect
label="Choose cloud folder" label={_t('cloud.chooseCloudFolder', { defaultMessage: "Choose cloud folder" })}
name="cloudFolder" name="cloudFolder"
isNative isNative
requiredRoleVariants={['write', 'admin']} requiredRoleVariants={['write', 'admin']}
@@ -134,13 +134,13 @@
: [ : [
{ {
folid: '__local', folid: '__local',
name: "Local folder (don't store on cloud)", name: _t('cloud.localFolder', { defaultMessage: "Local folder (don't store on cloud)" }),
}, },
]} ]}
/> />
{/if} {/if}
{#if $configValue?.storageDatabase} {#if $configValue?.storageDatabase}
<FormCheckboxField label="Save to team folder" name="saveToTeamFolder" /> <FormCheckboxField label={_t('cloud.saveToTeamFolder', { defaultMessage: "Save to team folder" })} name="saveToTeamFolder" />
{/if} {/if}
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
@@ -148,12 +148,12 @@
{#if electron} {#if electron}
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Save to disk" value={_t('common.saveToDisk', { defaultMessage: 'Save to disk' })}
on:click={async () => { on:click={async () => {
const file = await electron.showSaveDialog({ const file = await electron.showSaveDialog({
filters: [ filters: [
{ name: `${fileExtension.toUpperCase()} files`, extensions: [fileExtension] }, { name: _t('common.fileType', { defaultMessage: '{extension} files', values: {extension: fileExtension.toUpperCase()} }), extensions: [fileExtension] },
{ name: `All files`, extensions: ['*'] }, { name: _t('common.allFiles', { defaultMessage: 'All files' }), extensions: ['*'] },
], ],
defaultPath: filePath || `${name}.${fileExtension}`, defaultPath: filePath || `${name}.${fileExtension}`,
properties: ['showOverwriteConfirmation'], properties: ['showOverwriteConfirmation'],

View File

@@ -84,7 +84,7 @@
</div> </div>
<div slot="footer"> <div slot="footer">
<FormSubmit value="OK" on:click={handleOk} /> <FormSubmit value={_t('common.ok', {defaultMessage: "OK"})} on:click={handleOk} />
<FormButton type="button" value={_t('common.close', {defaultMessage: 'Close'})} on:click={closeCurrentModal} /> <FormButton type="button" value={_t('common.close', {defaultMessage: 'Close'})} on:click={closeCurrentModal} />
</div> </div>
</ModalBase> </ModalBase>

View File

@@ -14,7 +14,7 @@
</script> </script>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<div slot="header">SQL Script</div> <div slot="header">{_t('script.sqlScript', { defaultMessage: 'SQL Script' })}</div>
<div class="editor"> <div class="editor">
<SqlEditor {engine} value={sql} readOnly /> <SqlEditor {engine} value={sql} readOnly />
@@ -29,7 +29,7 @@
/> />
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Open script" value={_t('common.openScript', { defaultMessage: "Open script" })}
on:click={() => { on:click={() => {
newQuery({ newQuery({
initialData: sql, initialData: sql,

View File

@@ -32,6 +32,7 @@
import LoadingInfo from '../elements/LoadingInfo.svelte'; import LoadingInfo from '../elements/LoadingInfo.svelte';
import { getObjectTypeFieldLabel } from '../utility/common'; import { getObjectTypeFieldLabel } from '../utility/common';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
export let conid; export let conid;
export let database; export let database;
@@ -113,7 +114,7 @@
function editSql() { function editSql() {
openNewTab( openNewTab(
{ {
title: 'Query #', title: _t('query.queryNumber', { defaultMessage: 'Query #' }),
icon: 'img sql-file', icon: 'img sql-file',
tabComponent: 'QueryTab', tabComponent: 'QueryTab',
focused: true, focused: true,
@@ -133,7 +134,7 @@
<FormProviderCore values={valuesStore} template={FormFieldTemplateTiny}> <FormProviderCore values={valuesStore} template={FormFieldTemplateTiny}>
<ModalBase {...$$restProps} fullScreen> <ModalBase {...$$restProps} fullScreen>
<svelte:fragment slot="header"> <svelte:fragment slot="header">
SQL Generator {_t('sqlGenerator.sqlGenerator', { defaultMessage: 'SQL Generator' })}
<span class="dbname"> <span class="dbname">
<FontIcon icon="icon database" /> <FontIcon icon="icon database" />
{database} {database}
@@ -146,9 +147,9 @@
<HorizontalSplitter initialValue="300px" bind:size={managerSize}> <HorizontalSplitter initialValue="300px" bind:size={managerSize}>
<svelte:fragment slot="1"> <svelte:fragment slot="1">
<div class="flexcol flex1"> <div class="flexcol flex1">
<WidgetTitle>Choose objects</WidgetTitle> <WidgetTitle>{_t('sqlGenerator.chooseObjects', { defaultMessage: 'Choose objects' })}</WidgetTitle>
<SearchBoxWrapper> <SearchBoxWrapper>
<SearchInput placeholder="Search tables or objects" bind:value={objectsFilter} /> <SearchInput placeholder={_t('sqlGenerator.searchTablesOrObjects', { defaultMessage: 'Search tables or objects' })} bind:value={objectsFilter} />
</SearchBoxWrapper> </SearchBoxWrapper>
<WidgetsInnerContainer> <WidgetsInnerContainer>
@@ -174,54 +175,53 @@
{:else} {:else}
<div class="flexcol flex1"> <div class="flexcol flex1">
{#if truncated} {#if truncated}
<ErrorInfo icon="img warn" message="SQL truncated, file size limit exceed" /> <ErrorInfo icon="img warn" message={_t('sqlGenerator.sqlTruncated', { defaultMessage: 'SQL truncated, file size limit exceed' })} />
{/if} {/if}
<div class="relative flex1"> <div class="relative flex1">
<SqlEditor readOnly value={sqlPreview} /> <SqlEditor readOnly value={sqlPreview} />
</div> </div>
</div> </div>
{#if busy} {#if busy}
<LoadingInfo wrapper message="Loading SQL preview" /> <LoadingInfo wrapper message={_t('sqlGenerator.loadingSqlPreview', { defaultMessage: "Loading SQL preview" })} />
{/if} {/if}
{/if} {/if}
</svelte:fragment> </svelte:fragment>
<svelte:fragment slot="2"> <svelte:fragment slot="2">
<div class="flexcol flex1"> <div class="flexcol flex1">
<WidgetTitle>Generator settings</WidgetTitle> <WidgetTitle>{_t('sqlGenerator.generatorSettings', { defaultMessage: 'Generator settings' })}</WidgetTitle>
<WidgetsInnerContainer> <WidgetsInnerContainer>
<FormValues let:values> <FormValues let:values>
<div class="obj-heading">Tables</div> <div class="obj-heading">{_t('sqlGenerator.tables', { defaultMessage: 'Tables' })}</div>
<FormCheckboxField label="Drop tables" name="dropTables" /> <FormCheckboxField label={_t('sqlGenerator.dropTables', { defaultMessage: 'Drop tables' })} name="dropTables" />
{#if values.dropTables} {#if values.dropTables}
<div class="ml-2"> <div class="ml-2">
<FormCheckboxField label="Test if exists" name="checkIfTableExists" /> <FormCheckboxField label={_t('sqlGenerator.testIfExists', { defaultMessage: 'Test if exists' })} name="checkIfTableExists" />
</div> </div>
{/if} {/if}
<FormCheckboxField label="Drop references" name="dropReferences" /> <FormCheckboxField label={_t('sqlGenerator.dropReferences', { defaultMessage: 'Drop references' })} name="dropReferences" />
<FormCheckboxField label="Create tables" name="createTables" /> <FormCheckboxField label={_t('sqlGenerator.createTables', { defaultMessage: 'Create tables' })} name="createTables" />
<FormCheckboxField label="Create references" name="createReferences" /> <FormCheckboxField label={_t('sqlGenerator.createReferences', { defaultMessage: 'Create references' })} name="createReferences" />
<FormCheckboxField label="Create foreign keys" name="createForeignKeys" /> <FormCheckboxField label={_t('sqlGenerator.createForeignKeys', { defaultMessage: 'Create foreign keys' })} name="createForeignKeys" />
<FormCheckboxField label="Create indexes" name="createIndexes" /> <FormCheckboxField label={_t('sqlGenerator.createIndexes', { defaultMessage: 'Create indexes' })} name="createIndexes" />
<FormCheckboxField label="Insert" name="insert" /> <FormCheckboxField label={_t('sqlGenerator.insert', { defaultMessage: 'Insert' })} name="insert" />
{#if values.insert} {#if values.insert}
<div class="ml-2"> <div class="ml-2">
<FormCheckboxField label="Skip autoincrement column" name="skipAutoincrementColumn" /> <FormCheckboxField label={_t('sqlGenerator.skipAutoincrementColumn', { defaultMessage: 'Skip autoincrement column' })} name="skipAutoincrementColumn" />
<FormCheckboxField label="Disable constraints" name="disableConstraints" /> <FormCheckboxField label={_t('sqlGenerator.disableConstraints', { defaultMessage: 'Disable constraints' })} name="disableConstraints" />
<FormCheckboxField label="Omit NULL values" name="omitNulls" /> <FormCheckboxField label={_t('sqlGenerator.omitNulls', { defaultMessage: 'Omit NULL values' })} name="omitNulls" />
</div> </div>
{/if} {/if}
<FormCheckboxField label="Truncate tables (delete all rows)" name="truncate" /> <FormCheckboxField label={_t('sqlGenerator.truncate', { defaultMessage: 'Truncate tables (delete all rows)' })} name="truncate" />
{#each ['View', 'Matview', 'Procedure', 'Function', 'Trigger', 'SchedulerEvent'] as objtype} {#each ['View', 'Matview', 'Procedure', 'Function', 'Trigger', 'SchedulerEvent'] as objtype}
<div class="obj-heading">{getObjectTypeFieldLabel(objtype + 's')}</div> <div class="obj-heading">{getObjectTypeFieldLabel(objtype + 's')}</div>
<FormCheckboxField label="Create" name={`create${objtype}s`} /> <FormCheckboxField label={_t('sqlGenerator.create', { defaultMessage: 'Create {objtype}s', values: {objtype} })} name={`create${objtype}s`} />
<FormCheckboxField label="Drop" name={`drop${objtype}s`} /> <FormCheckboxField label={_t('sqlGenerator.drop', { defaultMessage: `Drop ${objtype}s` })} name={`drop${objtype}s`} />
{#if values[`drop${objtype}s`]} {#if values[`drop${objtype}s`]}
<div class="ml-2"> <div class="ml-2">
<FormCheckboxField label="Check if exists" name={`checkIf${objtype}Exists`} /> <FormCheckboxField label={_t('sqlGenerator.checkIfExists', { defaultMessage: 'Check if exists' })} name={`checkIf${objtype}Exists`} />
</div> </div>
{/if} {/if}
{/each} {/each}
@@ -241,8 +241,8 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<div class="flex m-2"> <div class="flex m-2">
<LargeButton on:click={editSql} icon="icon sql-file">Edit SQL</LargeButton> <LargeButton on:click={editSql} icon="icon sql-file">{_t('sqlGenerator.editSql', { defaultMessage: 'Edit SQL' })}</LargeButton>
<LargeButton on:click={closeCurrentModal} icon="icon close">Close</LargeButton> <LargeButton on:click={closeCurrentModal} icon="icon close">{_t('common.close', { defaultMessage: 'Close' })}</LargeButton>
</div> </div>
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -19,6 +19,7 @@
import FormConnectionSelect from '../impexp/FormConnectionSelect.svelte'; import FormConnectionSelect from '../impexp/FormConnectionSelect.svelte';
import FormDatabaseSelect from '../impexp/FormDatabaseSelect.svelte'; import FormDatabaseSelect from '../impexp/FormDatabaseSelect.svelte';
import { changeTab } from '../utility/common'; import { changeTab } from '../utility/common';
import { _t } from '../translations';
export let editingData; export let editingData;
export let callingTab; export let callingTab;
@@ -46,15 +47,15 @@
<FormProvider {initialValues}> <FormProvider {initialValues}>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Switch database</svelte:fragment> <svelte:fragment slot="header">{_t('switchDatabase.switchDatabase', { defaultMessage: 'Switch database' })}</svelte:fragment>
<FormConnectionSelect name="conid" label="Server" direction="source" isNative /> <FormConnectionSelect name="conid" label={_t('switchDatabase.server', { defaultMessage: 'Server' })} direction="source" isNative />
<FormDatabaseSelect conidName="conid" name="database" label="Database" isNative /> <FormDatabaseSelect conidName="conid" name="database" label={_t('common.database', { defaultMessage: 'Database' })} isNative />
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormValues let:values> <FormValues let:values>
<FormSubmit value="OK" on:click={handleSubmit} /> <FormSubmit value={_t('common.ok', { defaultMessage: 'OK' })} on:click={handleSubmit} />
<FormButton value="Cancel" on:click={closeCurrentModal} /> <FormButton value={_t('common.cancel', { defaultMessage: 'Cancel' })} on:click={closeCurrentModal} />
</FormValues> </FormValues>
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>

View File

@@ -141,7 +141,7 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
{#if multiselect} {#if multiselect}
<FormSubmit <FormSubmit
value="OK" value={_t('common.ok', { defaultMessage: 'OK' })}
on:click={() => { on:click={() => {
closeCurrentModal(); closeCurrentModal();
onConfirm(checkedKeys); onConfirm(checkedKeys);

View File

@@ -20,6 +20,7 @@
import type { ChangePerspectiveConfigFunc, PerspectiveConfig, PerspectiveCustomJoinConfig } from 'dbgate-datalib'; import type { ChangePerspectiveConfigFunc, PerspectiveConfig, PerspectiveCustomJoinConfig } from 'dbgate-datalib';
import uuidv1 from 'uuid/v1'; import uuidv1 from 'uuid/v1';
import TextField from '../forms/TextField.svelte'; import TextField from '../forms/TextField.svelte';
import { _t } from '../translations';
export let conid; export let conid;
export let database; export let database;
@@ -90,7 +91,7 @@
$: connections = useConnectionList(); $: connections = useConnectionList();
$: connectionOptions = [ $: connectionOptions = [
{ value: null, label: 'The same as root' }, { value: null, label: _t('customJoin.theSameAsRoot', { defaultMessage: 'The same as root' }) },
..._.sortBy( ..._.sortBy(
($connections || []) ($connections || [])
// .filter(x => !x.unsaved) // .filter(x => !x.unsaved)
@@ -107,7 +108,7 @@
$: databases = useDatabaseList({ conid: conidOverride || conid }); $: databases = useDatabaseList({ conid: conidOverride || conid });
$: databaseOptions = [ $: databaseOptions = [
{ value: null, label: 'The same as root' }, { value: null, label: _t('customJoin.theSameAsRoot', { defaultMessage: 'The same as root' }) },
..._.sortBy( ..._.sortBy(
($databases || []).map(db => ({ ($databases || []).map(db => ({
value: db.name, value: db.name,
@@ -147,11 +148,11 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Define custom join</svelte:fragment> <svelte:fragment slot="header">{_t('customJoin.defineCustomJoin', { defaultMessage: 'Define custom join' })}</svelte:fragment>
<div class="largeFormMarker"> <div class="largeFormMarker">
<div class="row"> <div class="row">
<div class="label col-3">Join name</div> <div class="label col-3">{_t('customJoin.joinName', { defaultMessage: 'Join name' })}</div>
<div class="col-9"> <div class="col-9">
<TextField <TextField
value={joinName} value={joinName}
@@ -164,7 +165,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="label col-3">Base table</div> <div class="label col-3">{_t('customJoin.baseTable', { defaultMessage: 'Base table' })}</div>
<div class="col-9"> <div class="col-9">
<SelectField <SelectField
value={fromDesignerId} value={fromDesignerId}
@@ -181,7 +182,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="label col-3">Connection</div> <div class="label col-3">{_t('customJoin.connection', { defaultMessage: 'Connection' })}</div>
<div class="col-9"> <div class="col-9">
<SelectField <SelectField
value={conidOverride} value={conidOverride}
@@ -195,7 +196,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="label col-3">Database</div> <div class="label col-3">{_t('customJoin.database', { defaultMessage: 'Database' })}</div>
<div class="col-9"> <div class="col-9">
<SelectField <SelectField
value={databaseOverride} value={databaseOverride}
@@ -212,7 +213,7 @@
<FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} label="Database" /> --> <FormDatabaseSelect conidName={connectionIdField} name={databaseNameField} label="Database" /> -->
<div class="row"> <div class="row">
<div class="label col-3">Referenced table</div> <div class="label col-3">{_t('customJoin.referencedTable', { defaultMessage: 'Referenced table' })}</div>
<div class="col-9"> <div class="col-9">
<SelectField <SelectField
value={fullNameToString({ pureName: refTableName, schemaName: refSchemaName })} value={fullNameToString({ pureName: refTableName, schemaName: refSchemaName })}
@@ -239,10 +240,10 @@
<div class="row"> <div class="row">
<div class="col-5 mr-1"> <div class="col-5 mr-1">
Base column - {fromTableInfo?.pureName} {_t('customJoin.baseColumn', { defaultMessage: 'Base column' })} - {fromTableInfo?.pureName}
</div> </div>
<div class="col-5 ml-1"> <div class="col-5 ml-1">
Ref column - {refTableName || '(table not set)'} {_t('customJoin.refColumn', { defaultMessage: 'Ref column' })} - {refTableName || _t('customJoin.tableNotSet', { defaultMessage: '(table not set)' })}
</div> </div>
</div> </div>
@@ -286,7 +287,7 @@
</div> </div>
<div class="col-2 button"> <div class="col-2 button">
<FormStyledButton <FormStyledButton
value="Delete" value={_t('common.delete', { defaultMessage: 'Delete' })}
on:click={e => { on:click={e => {
const x = [...columns]; const x = [...columns];
x.splice(index, 1); x.splice(index, 1);
@@ -299,7 +300,7 @@
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Add column" value={_t('customJoin.addColumn', { defaultMessage: 'Add column' })}
on:click={() => { on:click={() => {
columns = [ columns = [
...columns, ...columns,
@@ -314,7 +315,7 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value={'Save'} value={_t('common.save', { defaultMessage: 'Save' })}
on:click={() => { on:click={() => {
setConfig(cfg => { setConfig(cfg => {
const newNode = createPerspectiveNodeConfig({ pureName: refTableName, schemaName: refSchemaName }); const newNode = createPerspectiveNodeConfig({ pureName: refTableName, schemaName: refSchemaName });
@@ -361,7 +362,7 @@
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -6,6 +6,7 @@
import { filterName } from 'dbgate-tools'; import { filterName } from 'dbgate-tools';
import InlineButton from '../buttons/InlineButton.svelte'; import InlineButton from '../buttons/InlineButton.svelte';
import FontIcon from '../icons/FontIcon.svelte'; import FontIcon from '../icons/FontIcon.svelte';
import { _t } from '../translations';
export let items: any[]; export let items: any[];
export let showProcedure = false; export let showProcedure = false;
@@ -49,49 +50,49 @@
}} }}
> >
<FontIcon icon="icon delete" padRight /> <FontIcon icon="icon delete" padRight />
Clear {_t('messageView.clear', { defaultMessage: "Clear" })}
</InlineButton> </InlineButton>
{/if} {/if}
<RowsFilterSwitcher <RowsFilterSwitcher
icon="img debug" icon="img debug"
label="Debug" label={_t('messageView.debug', { defaultMessage: "Debug" })}
{values} {values}
field="hideDebug" field="hideDebug"
count={items.filter(x => x.severity == 'debug').length} count={items.filter(x => x.severity == 'debug').length}
/> />
<RowsFilterSwitcher <RowsFilterSwitcher
icon="img info" icon="img info"
label="Info" label={_t('messageView.info', { defaultMessage: "Info" })}
{values} {values}
field="hideInfo" field="hideInfo"
count={items.filter(x => x.severity == 'info').length} count={items.filter(x => x.severity == 'info').length}
/> />
<RowsFilterSwitcher <RowsFilterSwitcher
icon="img error" icon="img error"
label="Error" label={_t('messageView.error', { defaultMessage: "Error" })}
{values} {values}
field="hideError" field="hideError"
count={items.filter(x => x.severity == 'error').length} count={items.filter(x => x.severity == 'error').length}
/> />
<SearchInput placeholder="Filter log messages" bind:value={filter} /> <SearchInput placeholder={_t('messageView.filterLogMessages', { defaultMessage: "Filter log messages" })} bind:value={filter} />
</div> </div>
<div class="tablewrap"> <div class="tablewrap">
<table> <table>
<thead> <thead>
<tr> <tr>
<td class="header">Number</td> <td class="header">{_t('messageView.number', { defaultMessage: 'Number' })}</td>
<td class="header">Message</td> <td class="header">{_t('messageView.message', { defaultMessage: 'Message' })}</td>
<td class="header">Time</td> <td class="header">{_t('messageView.time', { defaultMessage: 'Time' })}</td>
<td class="header">Delta</td> <td class="header">{_t('messageView.delta', { defaultMessage: 'Delta' })}</td>
<td class="header">Duration</td> <td class="header">{_t('messageView.duration', { defaultMessage: 'Duration' })}</td>
{#if showProcedure} {#if showProcedure}
<td class="header">Procedure</td> <td class="header">{_t('messageView.procedure', { defaultMessage: 'Procedure' })}</td>
{/if} {/if}
{#if showLine} {#if showLine}
<td class="header">Line</td> <td class="header">{_t('messageView.line', { defaultMessage: 'Line' })}</td>
{/if} {/if}
{#if showCaller} {#if showCaller}
<td class="header">Caller</td> <td class="header">{_t('messageView.caller', { defaultMessage: 'Caller' })}</td>
{/if} {/if}
</tr> </tr>
</thead> </thead>

View File

@@ -11,6 +11,7 @@
import AllResultsTab from './AllResultsTab.svelte'; import AllResultsTab from './AllResultsTab.svelte';
import JslChart from '../charts/JslChart.svelte'; import JslChart from '../charts/JslChart.svelte';
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import { __t, _t } from '../translations';
export let tabs = []; export let tabs = [];
export let sessionId; export let sessionId;
@@ -68,7 +69,7 @@
...(oneTab && resultInfos.length > 0 ...(oneTab && resultInfos.length > 0
? [ ? [
{ {
label: 'Results', label: _t('resultTabs.results', { defaultMessage: 'Results' }),
isResult: true, isResult: true,
component: AllResultsTab, component: AllResultsTab,
props: { props: {
@@ -77,14 +78,14 @@
}, },
] ]
: resultInfos.map((info, index) => ({ : resultInfos.map((info, index) => ({
label: `Result ${index + 1}`, label: _t('resultTabs.resultNumber', { defaultMessage: 'Result {number}', values: { number: index + 1 } }),
isResult: true, isResult: true,
component: JslDataGrid, component: JslDataGrid,
resultIndex: info.resultIndex, resultIndex: info.resultIndex,
props: { jslid: info.jslid, driver, onOpenChart: () => handleOpenChart(info.resultIndex) }, props: { jslid: info.jslid, driver, onOpenChart: () => handleOpenChart(info.resultIndex) },
}))), }))),
...charts.map((info, index) => ({ ...charts.map((info, index) => ({
label: `Chart ${info.resultIndex + 1}`, label: _t('resultTabs.chartNumber', { defaultMessage: 'Chart {number}', values: { number: info.resultIndex + 1 } }),
isChart: true, isChart: true,
resultIndex: info.resultIndex, resultIndex: info.resultIndex,
component: JslChart, component: JslChart,
@@ -174,8 +175,8 @@
tabs={allTabs} tabs={allTabs}
menu={resultInfos.length > 0 && [ menu={resultInfos.length > 0 && [
oneTab oneTab
? { text: 'Every result in single tab', onClick: () => setOneTabValue(false) } ? { text: _t('resultTabs.everyResultInSingleTab', { defaultMessage: 'Every result in single tab' }), onClick: () => setOneTabValue(false) }
: { text: 'All results in one tab', onClick: () => setOneTabValue(true) }, : { text: _t('resultTabs.allResultsInOneTab', { defaultMessage: 'All results in one tab' }), onClick: () => setOneTabValue(true) },
]} ]}
onUserChange={value => { onUserChange={value => {
if (allTabs[value].isChart) { if (allTabs[value].isChart) {

View File

@@ -8,6 +8,7 @@
import { downloadFromApi } from '../utility/exportFileTools'; import { downloadFromApi } from '../utility/exportFileTools';
import useEffect from '../utility/useEffect'; import useEffect from '../utility/useEffect';
import Link from '../elements/Link.svelte'; import Link from '../elements/Link.svelte';
import { _t } from '../translations';
export let runnerId; export let runnerId;
export let executeNumber; export let executeNumber;
@@ -40,28 +41,28 @@
</script> </script>
{#if !files || files.length == 0} {#if !files || files.length == 0}
<ErrorInfo message="No output files" icon="img alert" /> <ErrorInfo message={_t('query.NoOutputFiles', { defaultMessage: 'No output files' })} icon="img alert" />
{:else} {:else}
<div class="flex1 scroll"> <div class="flex1 scroll">
<TableControl <TableControl
rows={files} rows={files}
stickyHeader stickyHeader
columns={[ columns={[
{ fieldName: 'name', header: 'Name' }, { fieldName: 'name', header: _t('query.Name', { defaultMessage: 'Name' }) },
{ fieldName: 'size', header: 'Size', formatter: row => formatFileSize(row.size) }, { fieldName: 'size', header: _t('query.Size', { defaultMessage: 'Size' }), formatter: row => formatFileSize(row.size) },
!electron && { !electron && {
fieldName: 'download', fieldName: 'download',
header: 'Download', header: _t('query.Download', { defaultMessage: 'Download' }),
slot: 0, slot: 0,
}, },
electron && { electron && {
fieldName: 'copy', fieldName: 'copy',
header: 'Copy', header: _t('query.Copy', { defaultMessage: 'Copy' }),
slot: 1, slot: 1,
}, },
electron && { electron && {
fieldName: 'show', fieldName: 'show',
header: 'Show', header: _t('query.Show', { defaultMessage: 'Show' }),
slot: 2, slot: 2,
}, },
]} ]}
@@ -72,7 +73,7 @@
downloadFromApi(`runners/data/${runnerId}/${row.name}`, row.name); downloadFromApi(`runners/data/${runnerId}/${row.name}`, row.name);
}} }}
> >
download {_t('query.download', { defaultMessage: 'download' })}
</Link> </Link>
</svelte:fragment> </svelte:fragment>
@@ -86,7 +87,7 @@
} }
}} }}
> >
save {_t('query.save', { defaultMessage: 'save' })}
</Link> </Link>
</svelte:fragment> </svelte:fragment>
@@ -96,7 +97,7 @@
electron.showItemInFolder(row.path); electron.showItemInFolder(row.path);
}} }}
> >
show {_t('query.show', { defaultMessage: 'show' })}
</Link> </Link>
</svelte:fragment> </svelte:fragment>
</TableControl> </TableControl>

View File

@@ -3,6 +3,7 @@
import WidgetTitle from '../widgets/WidgetTitle.svelte'; import WidgetTitle from '../widgets/WidgetTitle.svelte';
import RunnerOutputFiles from './RunnerOutputFiles.svelte'; import RunnerOutputFiles from './RunnerOutputFiles.svelte';
import SocketMessageView from './SocketMessageView.svelte'; import SocketMessageView from './SocketMessageView.svelte';
import { _t } from '../translations';
export let runnerId; export let runnerId;
export let executeNumber; export let executeNumber;
@@ -10,7 +11,7 @@
<HorizontalSplitter> <HorizontalSplitter>
<div class="container" slot="1"> <div class="container" slot="1">
<WidgetTitle>Messages</WidgetTitle> <WidgetTitle>{_t('query.Messages', { defaultMessage: 'Messages' })}</WidgetTitle>
<SocketMessageView <SocketMessageView
eventName={runnerId ? `runner-info-${runnerId}` : null} eventName={runnerId ? `runner-info-${runnerId}` : null}
{executeNumber} {executeNumber}
@@ -19,7 +20,7 @@
/> />
</div> </div>
<div class="container" slot="2"> <div class="container" slot="2">
<WidgetTitle>Output files</WidgetTitle> <WidgetTitle>{_t('query.OutputFiles', { defaultMessage: 'Output files' })}</WidgetTitle>
<RunnerOutputFiles {runnerId} {executeNumber} /> <RunnerOutputFiles {runnerId} {executeNumber} />
</div> </div>
</HorizontalSplitter> </HorizontalSplitter>

View File

@@ -3,6 +3,7 @@
import ErrorInfo from '../elements/ErrorInfo.svelte'; import ErrorInfo from '../elements/ErrorInfo.svelte';
import { apiOff, apiOn } from '../utility/api'; import { apiOff, apiOn } from '../utility/api';
import createRef from '../utility/createRef'; import createRef from '../utility/createRef';
import { _t } from '../translations';
import useEffect from '../utility/useEffect'; import useEffect from '../utility/useEffect';
@@ -75,7 +76,7 @@
</script> </script>
{#if showNoMessagesAlert && (!displayedMessages || displayedMessages.length == 0)} {#if showNoMessagesAlert && (!displayedMessages || displayedMessages.length == 0)}
<ErrorInfo message="No messages" icon="img alert" /> <ErrorInfo message={_t('message.NoMessages', { defaultMessage: 'No messages' })} icon="img alert" />
{:else} {:else}
<MessageView <MessageView
items={displayedMessages} items={displayedMessages}

View File

@@ -10,7 +10,7 @@
<div class="wrapper"> <div class="wrapper">
<FormValues let:values> <FormValues let:values>
<div class="heading">{_t('settings.defaultActions', { defaultMessage: 'Default actions' })}</div> <div class="heading">{_t('settings.defaultActions', { defaultMessage: 'Default Actions' })}</div>
<FormSelectField <FormSelectField
label={_t('settings.defaultActions.connectionClick', { defaultMessage: 'Connection click' })} label={_t('settings.defaultActions.connectionClick', { defaultMessage: 'Connection click' })}

View File

@@ -4,7 +4,7 @@
</script> </script>
<div class="wrapper"> <div class="wrapper">
<div class="heading">{_t('settings.externalTools', { defaultMessage: 'External tools' })}</div> <div class="heading">{_t('settings.externalTools', { defaultMessage: 'External Tools' })}</div>
<FormTextField <FormTextField
name="externalTools.mysqldump" name="externalTools.mysqldump"
label={_t('settings.other.externalTools.mysqldump', { label={_t('settings.other.externalTools.mysqldump', {

View File

@@ -188,7 +188,7 @@
<ObjectListControl <ObjectListControl
collection={columns?.map((x, index) => ({ ...x, ordinal: index + 1 }))} collection={columns?.map((x, index) => ({ ...x, ordinal: index + 1 }))}
title={_t('tableEditor.columns', { title={_t('tableEditor.columnsCount', {
defaultMessage: 'Columns ({columnCount})', defaultMessage: 'Columns ({columnCount})',
values: { columnCount: columns?.length || 0 }, values: { columnCount: columns?.length || 0 },
})} })}

View File

@@ -12,6 +12,7 @@
import { onMount, tick } from 'svelte'; import { onMount, tick } from 'svelte';
import TargetApplicationSelect from '../forms/TargetApplicationSelect.svelte'; import TargetApplicationSelect from '../forms/TargetApplicationSelect.svelte';
import { apiCall } from '../utility/api'; import { apiCall } from '../utility/api';
import { _t } from '../translations';
// import { apiCall } from '../utility/api'; // import { apiCall } from '../utility/api';
// import { saveDbToApp } from '../utility/appTools'; // import { saveDbToApp } from '../utility/appTools';
@@ -70,11 +71,11 @@
<FormProvider> <FormProvider>
<ModalBase {...$$restProps}> <ModalBase {...$$restProps}>
<svelte:fragment slot="header">Virtual foreign key</svelte:fragment> <svelte:fragment slot="header">{_t('virtualForeignKey.virtualForeignKey', { defaultMessage: 'Virtual foreign key' })}</svelte:fragment>
<div class="largeFormMarker"> <div class="largeFormMarker">
<div class="row"> <div class="row">
<div class="label col-3">Referenced table</div> <div class="label col-3">{_t('virtualForeignKey.referencedTable', { defaultMessage: 'Referenced table' })}</div>
<div class="col-9"> <div class="col-9">
<SelectField <SelectField
value={fullNameToString({ pureName: refTableName, schemaName: refSchemaName })} value={fullNameToString({ pureName: refTableName, schemaName: refSchemaName })}
@@ -105,10 +106,10 @@
<div class="row"> <div class="row">
<div class="col-5 mr-1"> <div class="col-5 mr-1">
Base column - {$tableInfo?.pureName} {_t('virtualForeignKey.baseColumn', { defaultMessage: 'Base column' })} - {$tableInfo?.pureName}
</div> </div>
<div class="col-5 ml-1"> <div class="col-5 ml-1">
Ref column - {refTableName || '(table not set)'} {_t('virtualForeignKey.refColumn', { defaultMessage: 'Ref column' })} - {refTableName || _t('virtualForeignKey.tableNotSet', { defaultMessage: '(table not set)' })}
</div> </div>
</div> </div>
@@ -152,7 +153,7 @@
</div> </div>
<div class="col-2 button"> <div class="col-2 button">
<FormStyledButton <FormStyledButton
value="Delete" value={_t('common.delete', { defaultMessage: 'Delete' })}
on:click={e => { on:click={e => {
const x = [...columns]; const x = [...columns];
x.splice(index, 1); x.splice(index, 1);
@@ -165,14 +166,14 @@
<FormStyledButton <FormStyledButton
type="button" type="button"
value="Add column" value={_t('virtualForeignKey.addColumn', { defaultMessage: 'Add column' })}
on:click={() => { on:click={() => {
columns = [...columns, {}]; columns = [...columns, {}];
}} }}
/> />
<div class="row"> <div class="row">
<div class="label col-3">Target application</div> <div class="label col-3">{_t('virtualForeignKey.targetApplication', { defaultMessage: 'Target application' })}</div>
<div class="col-9"> <div class="col-9">
<TargetApplicationSelect bind:value={dstApp} {conid} {database} /> <TargetApplicationSelect bind:value={dstApp} {conid} {database} />
</div> </div>
@@ -181,7 +182,7 @@
<svelte:fragment slot="footer"> <svelte:fragment slot="footer">
<FormSubmit <FormSubmit
value={'Save'} value={_t('common.save', { defaultMessage: 'Save' })}
disabled={!dstApp} disabled={!dstApp}
on:click={async () => { on:click={async () => {
await apiCall('apps/save-virtual-reference', { await apiCall('apps/save-virtual-reference', {
@@ -196,7 +197,7 @@
}} }}
/> />
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} /> <FormStyledButton type="button" value={_t('common.close', { defaultMessage: 'Close' })} on:click={closeCurrentModal} />
</svelte:fragment> </svelte:fragment>
</ModalBase> </ModalBase>
</FormProvider> </FormProvider>

View File

@@ -169,6 +169,7 @@
import hasPermission from '../utility/hasPermission'; import hasPermission from '../utility/hasPermission';
import QueryAiAssistant from '../ai/QueryAiAssistant.svelte'; import QueryAiAssistant from '../ai/QueryAiAssistant.svelte';
import { getCurrentSettings } from '../stores'; import { getCurrentSettings } from '../stores';
import { Messages } from 'openai/resources/chat/completions';
export let tabid; export let tabid;
export let conid; export let conid;
@@ -765,7 +766,7 @@
<svelte:fragment slot="2"> <svelte:fragment slot="2">
<ResultTabs <ResultTabs
bind:this={domResultTabs} bind:this={domResultTabs}
tabs={[{ label: 'Messages', slot: 0 }]} tabs={[{ label: _t('query.Messages', { defaultMessage: 'Messages' }), slot: 0 }]}
{sessionId} {sessionId}
{executeNumber} {executeNumber}
bind:resultCount bind:resultCount

View File

@@ -172,11 +172,11 @@
const resp = await apiCall('database-connections/run-script', { conid, database, sql, useTransaction: true }); const resp = await apiCall('database-connections/run-script', { conid, database, sql, useTransaction: true });
const { errorMessage } = resp || {}; const { errorMessage } = resp || {};
if (errorMessage) { if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage }); showModal(ErrorMessageModal, { title: _t('tableData.errorWhenSaving', { defaultMessage: 'Error when saving' }), message: errorMessage });
} else { } else {
dispatchChangeSet({ type: 'reset', value: createChangeSet() }); dispatchChangeSet({ type: 'reset', value: createChangeSet() });
cache.update(reloadDataCacheFunc); cache.update(reloadDataCacheFunc);
showSnackbarSuccess('Saved to database'); showSnackbarSuccess(_t('tableData.savedToDatabase', { defaultMessage: 'Saved to database' }));
} }
} }
@@ -192,11 +192,11 @@
}); });
const { errorMessage } = resp || {}; const { errorMessage } = resp || {};
if (errorMessage) { if (errorMessage) {
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage }); showModal(ErrorMessageModal, { title: _t('tableData.errorWhenSaving', { defaultMessage: 'Error when saving' }), message: errorMessage });
} else { } else {
dispatchChangeSet({ type: 'reset', value: createChangeSet() }); dispatchChangeSet({ type: 'reset', value: createChangeSet() });
cache.update(reloadDataCacheFunc); cache.update(reloadDataCacheFunc);
showSnackbarSuccess('Saved to database'); showSnackbarSuccess(_t('tableData.savedToDatabase', { defaultMessage: 'Saved to database' }));
} }
} else { } else {
const script = driver.createSaveChangeSetScript($changeSetStore?.value, $dbinfo, () => const script = driver.createSaveChangeSetScript($changeSetStore?.value, $dbinfo, () =>
@@ -360,13 +360,13 @@
> >
<ToolStripCommandSplitButton <ToolStripCommandSplitButton
buttonLabel={autoRefreshStarted ? `Refresh (every ${autoRefreshInterval}s)` : null} buttonLabel={autoRefreshStarted ? _t('tableData.refreshEvery', { defaultMessage: 'Refresh (every {autoRefreshInterval}s)', values: { autoRefreshInterval } }) : null}
commands={['dataGrid.refresh', ...createAutoRefreshMenu()]} commands={['dataGrid.refresh', ...createAutoRefreshMenu()]}
hideDisabled hideDisabled
data-testid="TableDataTab_refreshGrid" data-testid="TableDataTab_refreshGrid"
/> />
<ToolStripCommandSplitButton <ToolStripCommandSplitButton
buttonLabel={autoRefreshStarted ? `Refresh (every ${autoRefreshInterval}s)` : null} buttonLabel={autoRefreshStarted ? _t('tableData.refreshEvery', { defaultMessage: 'Refresh (every {autoRefreshInterval}s)', values: { autoRefreshInterval } }) : null}
commands={['dataForm.refresh', ...createAutoRefreshMenu()]} commands={['dataForm.refresh', ...createAutoRefreshMenu()]}
hideDisabled hideDisabled
data-testid="TableDataTab_refreshForm" data-testid="TableDataTab_refreshForm"

View File

@@ -6,6 +6,7 @@ import { getExtensions } from '../stores';
import { getConnectionInfo, getDatabaseInfo } from './metadataLoaders'; import { getConnectionInfo, getDatabaseInfo } from './metadataLoaders';
import ConfirmSqlModal, { saveScriptToDatabase } from '../modals/ConfirmSqlModal.svelte'; import ConfirmSqlModal, { saveScriptToDatabase } from '../modals/ConfirmSqlModal.svelte';
import { apiCall } from './api'; import { apiCall } from './api';
import { _t } from '../translations';
export async function alterDatabaseDialog(conid, database, updateFunc) { export async function alterDatabaseDialog(conid, database, updateFunc) {
const conn = await getConnectionInfo({ conid }); const conn = await getConnectionInfo({ conid });
@@ -30,8 +31,8 @@ export async function alterDatabaseDialog(conid, database, updateFunc) {
export async function renameDatabaseObjectDialog(conid, database, oldName, updateFunc) { export async function renameDatabaseObjectDialog(conid, database, oldName, updateFunc) {
showModal(InputTextModal, { showModal(InputTextModal, {
value: oldName, value: oldName,
label: 'New name', label: _t('renameDatabaseObject.newName', { defaultMessage: 'New name' }),
header: 'Rename object', header: _t('renameDatabaseObject.header', { defaultMessage: 'Rename object' }),
onConfirm: newName => { onConfirm: newName => {
alterDatabaseDialog(conid, database, db => updateFunc(db, newName)); alterDatabaseDialog(conid, database, db => updateFunc(db, newName));
}, },

View File

@@ -161,8 +161,8 @@
const handleRename = () => { const handleRename = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: folder, value: folder,
label: 'New folder name', label: _t('connection.newFolderName', { defaultMessage: 'New folder name' }),
header: 'Rename folder', header: _t('connection.renameFolder', { defaultMessage: 'Rename folder' }),
onConfirm: async newFolder => { onConfirm: async newFolder => {
emptyConnectionGroupNames.update(folders => _.uniq(folders.map(fld => (fld == folder ? newFolder : fld)))); emptyConnectionGroupNames.update(folders => _.uniq(folders.map(fld => (fld == folder ? newFolder : fld))));
apiCall('connections/batch-change-folder', { apiCall('connections/batch-change-folder', {
@@ -175,7 +175,7 @@
const handleDelete = () => { const handleDelete = () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete folder ${folder}? Connections in folder will be moved into root folder.`, message: _t('connection.deleteFolderConfirm', { defaultMessage: 'Really delete folder {folder}? Connections in folder will be moved into root folder.', values: { folder } }),
onConfirm: () => { onConfirm: () => {
emptyConnectionGroupNames.update(folders => folders.filter(fld => fld != folder)); emptyConnectionGroupNames.update(folders => folders.filter(fld => fld != folder));
apiCall('connections/batch-change-folder', { apiCall('connections/batch-change-folder', {
@@ -187,8 +187,8 @@
}; };
return [ return [
{ text: 'Rename', onClick: handleRename }, { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
{ text: 'Delete', onClick: handleDelete }, { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
]; ];
} }

View File

@@ -19,6 +19,7 @@
import _ from 'lodash'; import _ from 'lodash';
import openNewTab from '../utility/openNewTab'; import openNewTab from '../utility/openNewTab';
import { showSnackbarError } from '../utility/snackbar'; import { showSnackbarError } from '../utility/snackbar';
import { _t } from '../translations';
import DbKeysSubTree from './DbKeysSubTree.svelte'; import DbKeysSubTree from './DbKeysSubTree.svelte';
@@ -43,10 +44,10 @@
return [ return [
item.key != null && item.key != null &&
!connection?.isReadOnly && { !connection?.isReadOnly && {
label: 'Delete key', label: _t('dbKeysTreeNode.deleteKey', { defaultMessage: 'Delete key' }),
onClick: () => { onClick: () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete key ${item.key}?`, message: _t('dbKeysTreeNode.deleteKeyConfirm', { defaultMessage: 'Really delete key {key}?', values: { key: item.key } }),
onConfirm: async () => { onConfirm: async () => {
await apiCall('database-connections/call-method', { await apiCall('database-connections/call-method', {
conid, conid,
@@ -62,12 +63,12 @@
}, },
item.key != null && item.key != null &&
!connection?.isReadOnly && { !connection?.isReadOnly && {
label: 'Rename key', label: _t('dbKeysTreeNode.renameKey', { defaultMessage: 'Rename key' }),
onClick: () => { onClick: () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: item.key, value: item.key,
label: 'New name', label: _t('dbKeysTreeNode.newName', { defaultMessage: 'New name' }),
header: 'Rename key', header: _t('dbKeysTreeNode.renameKey', { defaultMessage: 'Rename key' }),
onConfirm: async newName => { onConfirm: async newName => {
await apiCall('database-connections/call-method', { await apiCall('database-connections/call-method', {
conid, conid,
@@ -90,11 +91,11 @@
// }, // },
item.type == 'dir' && item.type == 'dir' &&
!connection?.isReadOnly && { !connection?.isReadOnly && {
label: 'Delete branch', label: _t('dbKeysTreeNode.deleteBranch', { defaultMessage: 'Delete branch' }),
onClick: () => { onClick: () => {
const branch = `${item.key}:*`; const branch = `${item.key}:*`;
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete branch ${branch} with all keys?`, message: _t('dbKeysTreeNode.deleteBranchConfirm', { defaultMessage: 'Really delete branch {branch} with all keys?', values: { branch } }),
onConfirm: async () => { onConfirm: async () => {
await apiCall('database-connections/call-method', { await apiCall('database-connections/call-method', {
conid, conid,
@@ -110,7 +111,7 @@
}, },
, ,
{ {
label: 'Generate script', label: _t('dbKeysTreeNode.generateScript', { defaultMessage: 'Generate script' }),
onClick: async () => { onClick: async () => {
const data = await apiCall('database-connections/export-keys', { const data = await apiCall('database-connections/export-keys', {
conid, conid,
@@ -126,7 +127,7 @@
} }
newQuery({ newQuery({
title: 'Export #', title: _t('dbKeysTreeNode.exportTitle', { defaultMessage: 'Export #' }),
initialData: data, initialData: data,
}); });
}, },
@@ -137,7 +138,7 @@
<AppObjectCore <AppObjectCore
icon={getIconForRedisType(item.type)} icon={getIconForRedisType(item.type)}
title={item.text || '(no name)'} title={item.text || _t('dbKeysTreeNode.noName', { defaultMessage: '(no name)' })}
expandIcon={item.type == 'dir' ? plusExpandIcon(isExpanded) : 'icon invisible-box'} expandIcon={item.type == 'dir' ? plusExpandIcon(isExpanded) : 'icon invisible-box'}
on:expand={() => { on:expand={() => {
if (item.type == 'dir') { if (item.type == 'dir') {
@@ -150,7 +151,7 @@
} else { } else {
openNewTab({ openNewTab({
tabComponent: 'DbKeyDetailTab', tabComponent: 'DbKeyDetailTab',
title: item.text || '(no name)', title: item.text || _t('dbKeysTreeNode.noName', { defaultMessage: '(no name)' }),
icon: 'img keydb', icon: 'img keydb',
props: { props: {
isDefaultBrowser: true, isDefaultBrowser: true,

View File

@@ -115,7 +115,7 @@
command: 'new.connectionOnCloud', command: 'new.connectionOnCloud',
}, },
{ {
text: 'New SQL script', text: _t('privateCloudWidget.newSqlScript', { defaultMessage: 'New SQL script' }),
onClick: () => { onClick: () => {
const data = ''; const data = '';
showModal(SaveFileModal, { showModal(SaveFileModal, {
@@ -145,11 +145,11 @@
function createAddFolderMenu() { function createAddFolderMenu() {
return [ return [
isProApp() && { isProApp() && {
text: 'Create shared folder', text: _t('privateCloudWidget.createSharedFolder', { defaultMessage: 'Create shared folder' }),
onClick: () => { onClick: () => {
showModal(InputTextModal, { showModal(InputTextModal, {
label: 'New folder name', label: _t('privateCloudWidget.newFolderName', { defaultMessage: 'New folder name' }),
header: 'New shared folder', header: _t('privateCloudWidget.newSharedFolder', { defaultMessage: 'New shared folder' }),
onConfirm: async newFolder => { onConfirm: async newFolder => {
apiCall('cloud/create-folder', { apiCall('cloud/create-folder', {
name: newFolder, name: newFolder,
@@ -159,11 +159,11 @@
}, },
}, },
{ {
text: 'Add existing folder (from link)', text: _t('privateCloudWidget.addExistingFolder', { defaultMessage: 'Add existing folder (from link)' }),
onClick: () => { onClick: () => {
showModal(InputTextModal, { showModal(InputTextModal, {
label: 'Your invite link (in form dbgate://folder/xxx)', label: _t('privateCloudWidget.yourInviteLink', { defaultMessage: 'Your invite link (in form dbgate://folder/xxx)' }),
header: 'Add existing shared folder', header: _t('privateCloudWidget.addExistingSharedFolder', { defaultMessage: 'Add existing shared folder' }),
onConfirm: async newFolder => { onConfirm: async newFolder => {
apiCall('cloud/grant-folder', { apiCall('cloud/grant-folder', {
inviteLink: newFolder, inviteLink: newFolder,
@@ -179,8 +179,8 @@
const handleRename = () => { const handleRename = () => {
showModal(InputTextModal, { showModal(InputTextModal, {
value: contentGroupMap[folder]?.name, value: contentGroupMap[folder]?.name,
label: 'New folder name', label: _t('privateCloudWidget.newFolderName', { defaultMessage: 'New folder name' }),
header: 'Rename folder', header: _t('privateCloudWidget.renameFolder', { defaultMessage: 'Rename folder' }),
onConfirm: async name => { onConfirm: async name => {
apiCall('cloud/rename-folder', { apiCall('cloud/rename-folder', {
folid: folder, folid: folder,
@@ -192,8 +192,8 @@
const handleDelete = () => { const handleDelete = () => {
showModal(ConfirmModal, { showModal(ConfirmModal, {
message: `Really delete folder ${contentGroupMap[folder]?.name}? All folder content will be deleted!`, message: _t('privateCloudWidget.deleteFolderConfirm', { defaultMessage: 'Really delete folder {folder}? All folder content will be deleted!', values: { folder: contentGroupMap[folder]?.name } }),
header: 'Delete folder', header: _t('privateCloudWidget.deleteFolder', { defaultMessage: 'Delete folder' }),
onConfirm: () => { onConfirm: () => {
apiCall('cloud/delete-folder', { apiCall('cloud/delete-folder', {
folid: folder, folid: folder,
@@ -204,13 +204,13 @@
return [ return [
contentGroupMap[folder]?.role == 'admin' && [ contentGroupMap[folder]?.role == 'admin' && [
{ text: 'Rename', onClick: handleRename }, { text: _t('common.rename', { defaultMessage: 'Rename' }), onClick: handleRename },
{ text: 'Delete', onClick: handleDelete }, { text: _t('common.delete', { defaultMessage: 'Delete' }), onClick: handleDelete },
], ],
isProApp() && isProApp() &&
contentGroupMap[folder]?.role == 'admin' && contentGroupMap[folder]?.role == 'admin' &&
!contentGroupMap[folder]?.isPrivate && { !contentGroupMap[folder]?.isPrivate && {
text: 'Administrate access', text: _t('privateCloudWidget.administrateAccess', { defaultMessage: 'Administrate access' }),
onClick: () => { onClick: () => {
showModal(ConfigureSharedFolderModal, { showModal(ConfigureSharedFolderModal, {
folid: folder, folid: folder,
@@ -249,13 +249,13 @@
skip={!$cloudSigninTokenHolder} skip={!$cloudSigninTokenHolder}
> >
<SearchBoxWrapper> <SearchBoxWrapper>
<SearchInput placeholder="Search cloud connections and files" bind:value={filter} /> <SearchInput placeholder={_t('privateCloudWidget.searchPlaceholder', { defaultMessage: 'Search cloud connections and files' })} bind:value={filter} />
<CloseSearchButton bind:filter /> <CloseSearchButton bind:filter />
<DropDownButton icon="icon plus-thick" menu={createAddItemMenu} title="Add new connection or file" /> <DropDownButton icon="icon plus-thick" menu={createAddItemMenu} title={_t('privateCloudWidget.addNewConnectionOrFile', { defaultMessage: 'Add new connection or file' })} />
<DropDownButton icon="icon add-folder" menu={createAddFolderMenu} title="Add new folder" /> <DropDownButton icon="icon add-folder" menu={createAddFolderMenu} title={_t('privateCloudWidget.addNewFolder', { defaultMessage: 'Add new folder' })} />
<InlineButton <InlineButton
on:click={handleRefreshContent} on:click={handleRefreshContent}
title="Refresh files" title={_t('privateCloudWidget.refreshFiles', { defaultMessage: 'Refresh files' })}
data-testid="CloudItemsWidget_buttonRefreshContent" data-testid="CloudItemsWidget_buttonRefreshContent"
> >
<FontIcon icon="icon refresh" /> <FontIcon icon="icon refresh" />
@@ -289,11 +289,11 @@
/> />
{#if !cloudContentFlat?.length} {#if !cloudContentFlat?.length}
<ErrorInfo message="You have no content on DbGate cloud" icon="img info" /> <ErrorInfo message={_t('privateCloudWidget.noContent', { defaultMessage: 'You have no content on DbGate cloud' })} icon="img info" />
<div class="error-info"> <div class="error-info">
<div class="m-1"></div> <div class="m-1"></div>
<FormStyledButton <FormStyledButton
value="Create connection on DbGate Cloud" value={_t('privateCloudWidget.createConnection', { defaultMessage: 'Create connection on DbGate Cloud' })}
skipWidth skipWidth
on:click={() => { on:click={() => {
runCommand('new.connectionOnCloud'); runCommand('new.connectionOnCloud');

View File

@@ -27,7 +27,7 @@
</script> </script>
<WidgetColumnBar> <WidgetColumnBar>
<WidgetColumnBarItem title="Public Knowledge Base" name="publicCloud" storageName="publicCloudItems"> <WidgetColumnBarItem title={_t('publicCloudWidget.publicKnowledgeBase', { defaultMessage: "Public Knowledge Base" })} name="publicCloud" storageName="publicCloudItems">
<WidgetsInnerContainer> <WidgetsInnerContainer>
<SearchBoxWrapper> <SearchBoxWrapper>
<SearchInput placeholder={_t('publicCloudWidget.searchPublicFiles', { defaultMessage: "Search public files" })} bind:value={filter} /> <SearchInput placeholder={_t('publicCloudWidget.searchPublicFiles', { defaultMessage: "Search public files" })} bind:value={filter} />
@@ -49,7 +49,7 @@
/> />
{#if !$publicFiles?.length} {#if !$publicFiles?.length}
<ErrorInfo message="No files found for your configuration" /> <ErrorInfo message={_t('publicCloudWidget.noFilesFound', { defaultMessage: "No files found for your configuration" })} />
<div class="error-info"> <div class="error-info">
<div class="m-1"> <div class="m-1">
{_t('publicCloudWidget.onlyRelevantFilesListed', { defaultMessage: "Only files relevant for your connections, platform and DbGate edition are listed. Please define connections at first." })} {_t('publicCloudWidget.onlyRelevantFilesListed', { defaultMessage: "Only files relevant for your connections, platform and DbGate edition are listed. Please define connections at first." })}