Skip to content

Commit 626028f

Browse files
committed
add localization for integration management views
1 parent 110bbf1 commit 626028f

File tree

11 files changed

+288
-41
lines changed

11 files changed

+288
-41
lines changed

src/messageTypes.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,48 @@ export type LocalizedMessages = {
165165
dataframePageOf: string;
166166
dataframeCopyTable: string;
167167
dataframeExportTable: string;
168+
// Integration panel strings
169+
integrationsTitle: string;
170+
integrationsNoIntegrationsFound: string;
171+
integrationsConnected: string;
172+
integrationsNotConfigured: string;
173+
integrationsConfigure: string;
174+
integrationsReconfigure: string;
175+
integrationsReset: string;
176+
integrationsConfirmResetTitle: string;
177+
integrationsConfirmResetMessage: string;
178+
integrationsConfirmResetDetails: string;
179+
integrationsConfigureTitle: string;
180+
integrationsCancel: string;
181+
integrationsSave: string;
182+
// PostgreSQL form strings
183+
integrationsPostgresNameLabel: string;
184+
integrationsPostgresNamePlaceholder: string;
185+
integrationsPostgresHostLabel: string;
186+
integrationsPostgresHostPlaceholder: string;
187+
integrationsPostgresPortLabel: string;
188+
integrationsPostgresPortPlaceholder: string;
189+
integrationsPostgresDatabaseLabel: string;
190+
integrationsPostgresDatabasePlaceholder: string;
191+
integrationsPostgresUsernameLabel: string;
192+
integrationsPostgresUsernamePlaceholder: string;
193+
integrationsPostgresPasswordLabel: string;
194+
integrationsPostgresPasswordPlaceholder: string;
195+
integrationsPostgresSslLabel: string;
196+
integrationsPostgresUnnamedIntegration: string;
197+
// BigQuery form strings
198+
integrationsBigQueryNameLabel: string;
199+
integrationsBigQueryNamePlaceholder: string;
200+
integrationsBigQueryProjectIdLabel: string;
201+
integrationsBigQueryProjectIdPlaceholder: string;
202+
integrationsBigQueryCredentialsLabel: string;
203+
integrationsBigQueryCredentialsPlaceholder: string;
204+
integrationsBigQueryCredentialsRequired: string;
205+
integrationsBigQueryInvalidJson: string;
206+
integrationsBigQueryUnnamedIntegration: string;
207+
// Common form strings
208+
integrationsRequiredField: string;
209+
integrationsOptionalField: string;
168210
};
169211
// Map all messages to specific payloads
170212
export class IInteractiveWindowMapping {

src/notebooks/deepnote/integrations/integrationWebview.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { inject, injectable } from 'inversify';
22
import { Disposable, l10n, Uri, ViewColumn, WebviewPanel, window } from 'vscode';
33

44
import { IExtensionContext } from '../../../platform/common/types';
5+
import * as localize from '../../../platform/common/utils/localize';
56
import { logger } from '../../../platform/logging';
7+
import { LocalizedMessages, SharedMessages } from '../../../messageTypes';
68
import { IIntegrationStorage, IIntegrationWebviewProvider } from './types';
79
import { IntegrationConfig, IntegrationStatus, IntegrationWithStatus } from './integrationTypes';
810

@@ -82,6 +84,7 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
8284
this.disposables
8385
);
8486

87+
await this.sendLocStrings();
8588
await this.updateWebview();
8689

8790
// If a specific integration was requested, show its configuration form
@@ -90,6 +93,61 @@ export class IntegrationWebviewProvider implements IIntegrationWebviewProvider {
9093
}
9194
}
9295

96+
/**
97+
* Send localization strings to the webview
98+
*/
99+
private async sendLocStrings(): Promise<void> {
100+
if (!this.currentPanel) {
101+
return;
102+
}
103+
104+
const locStrings: Partial<LocalizedMessages> = {
105+
integrationsTitle: localize.Integrations.title,
106+
integrationsNoIntegrationsFound: localize.Integrations.noIntegrationsFound,
107+
integrationsConnected: localize.Integrations.connected,
108+
integrationsNotConfigured: localize.Integrations.notConfigured,
109+
integrationsConfigure: localize.Integrations.configure,
110+
integrationsReconfigure: localize.Integrations.reconfigure,
111+
integrationsReset: localize.Integrations.reset,
112+
integrationsConfirmResetTitle: localize.Integrations.confirmResetTitle,
113+
integrationsConfirmResetMessage: localize.Integrations.confirmResetMessage,
114+
integrationsConfirmResetDetails: localize.Integrations.confirmResetDetails,
115+
integrationsConfigureTitle: localize.Integrations.configureTitle,
116+
integrationsCancel: localize.Integrations.cancel,
117+
integrationsSave: localize.Integrations.save,
118+
integrationsRequiredField: localize.Integrations.requiredField,
119+
integrationsOptionalField: localize.Integrations.optionalField,
120+
integrationsPostgresNameLabel: localize.Integrations.postgresNameLabel,
121+
integrationsPostgresNamePlaceholder: localize.Integrations.postgresNamePlaceholder,
122+
integrationsPostgresHostLabel: localize.Integrations.postgresHostLabel,
123+
integrationsPostgresHostPlaceholder: localize.Integrations.postgresHostPlaceholder,
124+
integrationsPostgresPortLabel: localize.Integrations.postgresPortLabel,
125+
integrationsPostgresPortPlaceholder: localize.Integrations.postgresPortPlaceholder,
126+
integrationsPostgresDatabaseLabel: localize.Integrations.postgresDatabaseLabel,
127+
integrationsPostgresDatabasePlaceholder: localize.Integrations.postgresDatabasePlaceholder,
128+
integrationsPostgresUsernameLabel: localize.Integrations.postgresUsernameLabel,
129+
integrationsPostgresUsernamePlaceholder: localize.Integrations.postgresUsernamePlaceholder,
130+
integrationsPostgresPasswordLabel: localize.Integrations.postgresPasswordLabel,
131+
integrationsPostgresPasswordPlaceholder: localize.Integrations.postgresPasswordPlaceholder,
132+
integrationsPostgresSslLabel: localize.Integrations.postgresSslLabel,
133+
integrationsPostgresUnnamedIntegration: '', // Will be formatted on the client side
134+
integrationsBigQueryNameLabel: localize.Integrations.bigQueryNameLabel,
135+
integrationsBigQueryNamePlaceholder: localize.Integrations.bigQueryNamePlaceholder,
136+
integrationsBigQueryProjectIdLabel: localize.Integrations.bigQueryProjectIdLabel,
137+
integrationsBigQueryProjectIdPlaceholder: localize.Integrations.bigQueryProjectIdPlaceholder,
138+
integrationsBigQueryCredentialsLabel: localize.Integrations.bigQueryCredentialsLabel,
139+
integrationsBigQueryCredentialsPlaceholder: localize.Integrations.bigQueryCredentialsPlaceholder,
140+
integrationsBigQueryCredentialsRequired: localize.Integrations.bigQueryCredentialsRequired,
141+
integrationsBigQueryInvalidJson: '', // Will be formatted on the client side
142+
integrationsBigQueryUnnamedIntegration: '' // Will be formatted on the client side
143+
};
144+
145+
await this.currentPanel.webview.postMessage({
146+
type: SharedMessages.LocInit,
147+
locStrings: JSON.stringify(locStrings)
148+
});
149+
}
150+
93151
/**
94152
* Update the webview with current integration data
95153
*/

src/platform/common/utils/localize.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,51 @@ export namespace WebViews {
814814
export const dataframeExportTable = l10n.t('Export table');
815815
}
816816

817+
export namespace Integrations {
818+
export const title = l10n.t('Deepnote Integrations');
819+
export const noIntegrationsFound = l10n.t('No integrations found in this project.');
820+
export const connected = l10n.t('Connected');
821+
export const notConfigured = l10n.t('Not Configured');
822+
export const configure = l10n.t('Configure');
823+
export const reconfigure = l10n.t('Reconfigure');
824+
export const reset = l10n.t('Reset');
825+
export const confirmResetTitle = l10n.t('Confirm Reset');
826+
export const confirmResetMessage = l10n.t('Are you sure you want to reset this integration configuration?');
827+
export const confirmResetDetails = l10n.t('This will remove the stored credentials. You can reconfigure it later.');
828+
export const configureTitle = l10n.t('Configure Integration: {0}');
829+
export const cancel = l10n.t('Cancel');
830+
export const save = l10n.t('Save');
831+
export const requiredField = l10n.t('*');
832+
export const optionalField = l10n.t('(optional)');
833+
834+
// PostgreSQL form strings
835+
export const postgresNameLabel = l10n.t('Name (optional)');
836+
export const postgresNamePlaceholder = l10n.t('My PostgreSQL Database');
837+
export const postgresHostLabel = l10n.t('Host');
838+
export const postgresHostPlaceholder = l10n.t('localhost');
839+
export const postgresPortLabel = l10n.t('Port');
840+
export const postgresPortPlaceholder = l10n.t('5432');
841+
export const postgresDatabaseLabel = l10n.t('Database');
842+
export const postgresDatabasePlaceholder = l10n.t('mydb');
843+
export const postgresUsernameLabel = l10n.t('Username');
844+
export const postgresUsernamePlaceholder = l10n.t('postgres');
845+
export const postgresPasswordLabel = l10n.t('Password');
846+
export const postgresPasswordPlaceholder = l10n.t('••••••••');
847+
export const postgresSslLabel = l10n.t('Use SSL');
848+
export const postgresUnnamedIntegration = (id: string) => l10n.t('Unnamed PostgreSQL Integration ({0})', id);
849+
850+
// BigQuery form strings
851+
export const bigQueryNameLabel = l10n.t('Name (optional)');
852+
export const bigQueryNamePlaceholder = l10n.t('My BigQuery Project');
853+
export const bigQueryProjectIdLabel = l10n.t('Project ID');
854+
export const bigQueryProjectIdPlaceholder = l10n.t('my-project-id');
855+
export const bigQueryCredentialsLabel = l10n.t('Service Account Credentials (JSON)');
856+
export const bigQueryCredentialsPlaceholder = l10n.t('{"type": "service_account", ...}');
857+
export const bigQueryCredentialsRequired = l10n.t('Credentials are required');
858+
export const bigQueryInvalidJson = (message: string) => l10n.t('Invalid JSON: {0}', message);
859+
export const bigQueryUnnamedIntegration = (id: string) => l10n.t('Unnamed BigQuery Integration ({0})', id);
860+
}
861+
817862
export namespace Deprecated {
818863
export const SHOW_DEPRECATED_FEATURE_PROMPT_FORMAT_ON_SAVE = l10n.t({
819864
message: "The setting 'python.formatting.formatOnSave' is deprecated, please use 'editor.formatOnSave'.",

src/platform/webviews/webviewHost.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,46 @@ export abstract class WebviewHost<IMapping> implements IDisposable {
265265
dataframeNextPage: localize.WebViews.dataframeNextPage,
266266
dataframePageOf: localize.WebViews.dataframePageOf,
267267
dataframeCopyTable: localize.WebViews.dataframeCopyTable,
268-
dataframeExportTable: localize.WebViews.dataframeExportTable
268+
dataframeExportTable: localize.WebViews.dataframeExportTable,
269+
// Integration panel strings (not used in this webview, but required by type)
270+
integrationsTitle: '',
271+
integrationsNoIntegrationsFound: '',
272+
integrationsConnected: '',
273+
integrationsNotConfigured: '',
274+
integrationsConfigure: '',
275+
integrationsReconfigure: '',
276+
integrationsReset: '',
277+
integrationsConfirmResetTitle: '',
278+
integrationsConfirmResetMessage: '',
279+
integrationsConfirmResetDetails: '',
280+
integrationsConfigureTitle: '',
281+
integrationsCancel: '',
282+
integrationsSave: '',
283+
integrationsPostgresNameLabel: '',
284+
integrationsPostgresNamePlaceholder: '',
285+
integrationsPostgresHostLabel: '',
286+
integrationsPostgresHostPlaceholder: '',
287+
integrationsPostgresPortLabel: '',
288+
integrationsPostgresPortPlaceholder: '',
289+
integrationsPostgresDatabaseLabel: '',
290+
integrationsPostgresDatabasePlaceholder: '',
291+
integrationsPostgresUsernameLabel: '',
292+
integrationsPostgresUsernamePlaceholder: '',
293+
integrationsPostgresPasswordLabel: '',
294+
integrationsPostgresPasswordPlaceholder: '',
295+
integrationsPostgresSslLabel: '',
296+
integrationsPostgresUnnamedIntegration: '',
297+
integrationsBigQueryNameLabel: '',
298+
integrationsBigQueryNamePlaceholder: '',
299+
integrationsBigQueryProjectIdLabel: '',
300+
integrationsBigQueryProjectIdPlaceholder: '',
301+
integrationsBigQueryCredentialsLabel: '',
302+
integrationsBigQueryCredentialsPlaceholder: '',
303+
integrationsBigQueryCredentialsRequired: '',
304+
integrationsBigQueryInvalidJson: '',
305+
integrationsBigQueryUnnamedIntegration: '',
306+
integrationsRequiredField: '',
307+
integrationsOptionalField: ''
269308
};
270309
this.postMessageInternal(SharedMessages.LocInit, JSON.stringify(locStrings)).catch(noop);
271310
}

src/webviews/webview-side/integrations/BigQueryForm.tsx

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
2+
import { getLocString } from '../react-common/locReactSide';
33
import { BigQueryIntegrationConfig } from './types';
44

55
export interface IBigQueryFormProps {
@@ -27,7 +27,7 @@ export const BigQueryForm: React.FC<IBigQueryFormProps> = ({ integrationId, exis
2727

2828
const validateCredentials = (value: string): boolean => {
2929
if (!value.trim()) {
30-
setCredentialsError('Credentials are required');
30+
setCredentialsError(getLocString('integrationsBigQueryCredentialsRequired', 'Credentials are required'));
3131
return false;
3232
}
3333

@@ -37,7 +37,11 @@ export const BigQueryForm: React.FC<IBigQueryFormProps> = ({ integrationId, exis
3737
return true;
3838
} catch (error) {
3939
const errorMessage = error instanceof Error ? error.message : 'Invalid JSON format';
40-
setCredentialsError(`Invalid JSON: ${errorMessage}`);
40+
const invalidJsonMsg = getLocString('integrationsBigQueryInvalidJson', 'Invalid JSON: {0}').replace(
41+
'{0}',
42+
errorMessage
43+
);
44+
setCredentialsError(invalidJsonMsg);
4145
return false;
4246
}
4347
};
@@ -56,9 +60,14 @@ export const BigQueryForm: React.FC<IBigQueryFormProps> = ({ integrationId, exis
5660
return;
5761
}
5862

63+
const unnamedIntegration = getLocString(
64+
'integrationsBigQueryUnnamedIntegration',
65+
'Unnamed BigQuery Integration ({0})'
66+
).replace('{0}', integrationId);
67+
5968
const config: BigQueryIntegrationConfig = {
6069
id: integrationId,
61-
name: name || `Unnamed BigQuery Integration (${integrationId})`,
70+
name: name || unnamedIntegration,
6271
type: 'bigquery',
6372
projectId,
6473
credentials
@@ -70,41 +79,46 @@ export const BigQueryForm: React.FC<IBigQueryFormProps> = ({ integrationId, exis
7079
return (
7180
<form onSubmit={handleSubmit}>
7281
<div className="form-group">
73-
<label htmlFor="name">Name (optional)</label>
82+
<label htmlFor="name">{getLocString('integrationsBigQueryNameLabel', 'Name (optional)')}</label>
7483
<input
7584
type="text"
7685
id="name"
7786
value={name}
7887
onChange={(e) => setName(e.target.value)}
79-
placeholder="My BigQuery Project"
88+
placeholder={getLocString('integrationsBigQueryNamePlaceholder', 'My BigQuery Project')}
8089
autoComplete="off"
8190
/>
8291
</div>
8392

8493
<div className="form-group">
8594
<label htmlFor="projectId">
86-
Project ID <span className="required">*</span>
95+
{getLocString('integrationsBigQueryProjectIdLabel', 'Project ID')}{' '}
96+
<span className="required">{getLocString('integrationsRequiredField', '*')}</span>
8797
</label>
8898
<input
8999
type="text"
90100
id="projectId"
91101
value={projectId}
92102
onChange={(e) => setProjectId(e.target.value)}
93-
placeholder="my-project-id"
103+
placeholder={getLocString('integrationsBigQueryProjectIdPlaceholder', 'my-project-id')}
94104
autoComplete="off"
95105
required
96106
/>
97107
</div>
98108

99109
<div className="form-group">
100110
<label htmlFor="credentials">
101-
Service Account Credentials (JSON) <span className="required">*</span>
111+
{getLocString('integrationsBigQueryCredentialsLabel', 'Service Account Credentials (JSON)')}{' '}
112+
<span className="required">{getLocString('integrationsRequiredField', '*')}</span>
102113
</label>
103114
<textarea
104115
id="credentials"
105116
value={credentials}
106117
onChange={handleCredentialsChange}
107-
placeholder='{"type": "service_account", ...}'
118+
placeholder={getLocString(
119+
'integrationsBigQueryCredentialsPlaceholder',
120+
'{"type": "service_account", ...}'
121+
)}
108122
rows={10}
109123
autoComplete="off"
110124
spellCheck={false}
@@ -123,10 +137,10 @@ export const BigQueryForm: React.FC<IBigQueryFormProps> = ({ integrationId, exis
123137

124138
<div className="form-actions">
125139
<button type="submit" className="primary">
126-
Save
140+
{getLocString('integrationsSave', 'Save')}
127141
</button>
128142
<button type="button" className="secondary" onClick={onCancel}>
129-
Cancel
143+
{getLocString('integrationsCancel', 'Cancel')}
130144
</button>
131145
</div>
132146
</form>

src/webviews/webview-side/integrations/ConfigurationForm.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import { getLocString } from '../react-common/locReactSide';
23
import { PostgresForm } from './PostgresForm';
34
import { BigQueryForm } from './BigQueryForm';
45
import { IntegrationConfig } from './types';
@@ -34,11 +35,16 @@ export const ConfigurationForm: React.FC<IConfigurationFormProps> = ({
3435

3536
const integrationType = getIntegrationType();
3637

38+
const title = getLocString('integrationsConfigureTitle', 'Configure Integration: {0}').replace(
39+
'{0}',
40+
integrationId
41+
);
42+
3743
return (
3844
<div className="configuration-form-overlay">
3945
<div className="configuration-form-container">
4046
<div className="configuration-form-header">
41-
<h2>Configure Integration: {integrationId}</h2>
47+
<h2>{title}</h2>
4248
<button type="button" className="close-button" onClick={onCancel}>
4349
×
4450
</button>

src/webviews/webview-side/integrations/IntegrationItem.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import { getLocString } from '../react-common/locReactSide';
23
import { IntegrationWithStatus } from './types';
34

45
export interface IIntegrationItemProps {
@@ -9,8 +10,13 @@ export interface IIntegrationItemProps {
910

1011
export const IntegrationItem: React.FC<IIntegrationItemProps> = ({ integration, onConfigure, onDelete }) => {
1112
const statusClass = integration.status === 'connected' ? 'status-connected' : 'status-disconnected';
12-
const statusText = integration.status === 'connected' ? 'Connected' : 'Not Configured';
13-
const configureText = integration.config ? 'Reconfigure' : 'Configure';
13+
const statusText =
14+
integration.status === 'connected'
15+
? getLocString('integrationsConnected', 'Connected')
16+
: getLocString('integrationsNotConfigured', 'Not Configured');
17+
const configureText = integration.config
18+
? getLocString('integrationsReconfigure', 'Reconfigure')
19+
: getLocString('integrationsConfigure', 'Configure');
1420
const displayName = integration.config?.name || integration.id;
1521

1622
return (
@@ -25,7 +31,7 @@ export const IntegrationItem: React.FC<IIntegrationItemProps> = ({ integration,
2531
</button>
2632
{integration.config && (
2733
<button type="button" className="secondary" onClick={() => onDelete(integration.id)}>
28-
Reset
34+
{getLocString('integrationsReset', 'Reset')}
2935
</button>
3036
)}
3137
</div>

0 commit comments

Comments
 (0)