From 0a480311a1c3ca1eadc8cdfb24d60c070186cc64 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Mon, 15 Sep 2025 19:14:51 +0200 Subject: [PATCH 1/3] Localize user-facing strings with `ITranslator` --- package.json | 1 + src/diff/nbdime.ts | 6 ++-- src/plugin.ts | 79 +++++++++++++++++++++++++++++++--------------- src/widget.ts | 14 ++++++-- yarn.lock | 1 + 5 files changed, 71 insertions(+), 30 deletions(-) diff --git a/package.json b/package.json index 6b8eacc..25c070b 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "@jupyterlab/coreutils": "^6.0.0", "@jupyterlab/notebook": "^4.0.0", "@jupyterlab/services": "^7.0.0", + "@jupyterlab/translation": "^4.0.0", "@jupyterlab/ui-components": "^4.0.0", "@lumino/widgets": "^2.0.0", "codemirror": "^6.0.2", diff --git a/src/diff/nbdime.ts b/src/diff/nbdime.ts index c068d55..900ae5c 100644 --- a/src/diff/nbdime.ts +++ b/src/diff/nbdime.ts @@ -48,12 +48,13 @@ export async function createNBDimeDiffWidget( originalSource, newSource, diffData, + trans, showActionButtons = true, openDiff = true } = options; if (!diffData || !diffData.diff) { - throw new Error('NBDime strategy requires diff data'); + throw new Error(trans.__('NBDime strategy requires diff data')); } const diff = createPatchStringDiffModel( @@ -68,7 +69,8 @@ export async function createNBDimeDiffWidget( originalSource, newSource, showActionButtons, - openDiff + openDiff, + trans }); diffWidget.addClass('jupyterlab-cell-diff'); diff --git a/src/plugin.ts b/src/plugin.ts index a4f2dd8..1b2926a 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -4,6 +4,7 @@ import { } from '@jupyterlab/application'; import { ICellModel } from '@jupyterlab/cells'; import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook'; +import { ITranslator, nullTranslator } from '@jupyterlab/translation'; import { ICellFooterTracker } from 'jupyterlab-cell-input-footer'; import { requestAPI } from './handler'; @@ -11,6 +12,11 @@ import { IDiffWidgetOptions } from './widget'; import { createNBDimeDiffWidget } from './diff/nbdime'; import { createCodeMirrorDiffWidget } from './diff/codemirror'; +/** + * The translation namespace for the plugin. + */ +const TRANSLATION_NAMESPACE = 'jupyterlab-cell-diff'; + /** * Find a notebook by path using the notebook tracker */ @@ -56,43 +62,50 @@ const codeMirrorPlugin: JupyterFrontEndPlugin = { id: 'jupyterlab-cell-diff:codemirror-plugin', description: 'Expose a command to show cell diffs using CodeMirror', requires: [ICellFooterTracker, INotebookTracker], + optional: [ITranslator], autoStart: true, activate: async ( app: JupyterFrontEnd, cellFooterTracker: ICellFooterTracker, - notebookTracker: INotebookTracker + notebookTracker: INotebookTracker, + translator: ITranslator | null ) => { const { commands } = app; + const trans = (translator ?? nullTranslator).load(TRANSLATION_NAMESPACE); commands.addCommand('jupyterlab-cell-diff:show-codemirror', { - label: 'Show Cell Diff (CodeMirror)', + label: trans.__('Show Cell Diff (CodeMirror)'), describedBy: { args: { type: 'object', properties: { cellId: { type: 'string', - description: 'ID of the cell to show diff for' + description: trans.__('ID of the cell to show diff for') }, originalSource: { type: 'string', - description: 'Original source code to compare against' + description: trans.__('Original source code to compare against') }, newSource: { type: 'string', - description: 'New source code to compare with' + description: trans.__('New source code to compare with') }, showActionButtons: { type: 'boolean', - description: 'Whether to show action buttons in the diff widget' + description: trans.__( + 'Whether to show action buttons in the diff widget' + ) }, notebookPath: { type: 'string', - description: 'Path to the notebook containing the cell' + description: trans.__('Path to the notebook containing the cell') }, openDiff: { type: 'boolean', - description: 'Whether to open the diff widget automatically' + description: trans.__( + 'Whether to open the diff widget automatically' + ) } } } @@ -115,14 +128,16 @@ const codeMirrorPlugin: JupyterFrontEndPlugin = { const cell = findCell(currentNotebook, cellId); if (!cell) { console.error( - 'Missing required arguments: cellId (or no active cell found)' + trans.__( + 'Missing required arguments: cellId (or no active cell found)' + ) ); return; } const footer = cellFooterTracker.getFooter(cell.id); if (!footer) { - console.error(`Footer not found for cell ${cell.id}`); + console.error(trans.__('Footer not found for cell %1', cell.id)); return; } @@ -133,12 +148,13 @@ const codeMirrorPlugin: JupyterFrontEndPlugin = { originalSource, newSource, showActionButtons, - openDiff + openDiff, + trans }; await createCodeMirrorDiffWidget(options); } catch (error) { - console.error('Failed to create diff widget:', error); + console.error(trans.__('Failed to create diff widget:'), error); } } }); @@ -152,43 +168,50 @@ const nbdimePlugin: JupyterFrontEndPlugin = { id: 'jupyterlab-cell-diff:nbdime-plugin', description: 'Expose a command to show cell diffs using NBDime', requires: [ICellFooterTracker, INotebookTracker], + optional: [ITranslator], autoStart: true, activate: async ( app: JupyterFrontEnd, cellFooterTracker: ICellFooterTracker, - notebookTracker: INotebookTracker + notebookTracker: INotebookTracker, + translator: ITranslator | null ) => { const { commands } = app; + const trans = (translator ?? nullTranslator).load(TRANSLATION_NAMESPACE); commands.addCommand('jupyterlab-cell-diff:show-nbdime', { - label: 'Show Cell Diff (NBDime)', + label: trans.__('Show Cell Diff (NBDime)'), describedBy: { args: { type: 'object', properties: { cellId: { type: 'string', - description: 'ID of the cell to show diff for' + description: trans.__('ID of the cell to show diff for') }, originalSource: { type: 'string', - description: 'Original source code to compare against' + description: trans.__('Original source code to compare against') }, newSource: { type: 'string', - description: 'New source code to compare with' + description: trans.__('New source code to compare with') }, showActionButtons: { type: 'boolean', - description: 'Whether to show action buttons in the diff widget' + description: trans.__( + 'Whether to show action buttons in the diff widget' + ) }, notebookPath: { type: 'string', - description: 'Path to the notebook containing the cell' + description: trans.__('Path to the notebook containing the cell') }, openDiff: { type: 'boolean', - description: 'Whether to open the diff widget automatically' + description: trans.__( + 'Whether to open the diff widget automatically' + ) } } } @@ -211,7 +234,9 @@ const nbdimePlugin: JupyterFrontEndPlugin = { const cell = findCell(currentNotebook, cellId); if (!cell) { console.error( - 'Missing required arguments: cellId (or no active cell found)' + trans.__( + 'Missing required arguments: cellId (or no active cell found)' + ) ); return; } @@ -228,12 +253,15 @@ const nbdimePlugin: JupyterFrontEndPlugin = { }); diffData = (response as any).diff; } catch (error) { - console.warn('Failed to fetch diff data from server:', error); + console.warn( + trans.__('Failed to fetch diff data from server:'), + error + ); } const footer = cellFooterTracker.getFooter(cell.id); if (!footer) { - console.error(`Footer not found for cell ${cell.id}`); + console.error(trans.__('Footer not found for cell %1', cell.id)); return; } @@ -246,12 +274,13 @@ const nbdimePlugin: JupyterFrontEndPlugin = { diffData: diffData ? { diff: diffData } : undefined, cellId: cell.id, showActionButtons, - openDiff + openDiff, + trans }; await createNBDimeDiffWidget(options); } catch (error) { - console.error('Failed to create diff widget:', error); + console.error(trans.__('Failed to create diff widget:'), error); } } }); diff --git a/src/widget.ts b/src/widget.ts index 710d12c..e074d0c 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -1,4 +1,5 @@ import { ICellModel } from '@jupyterlab/cells'; +import { nullTranslator, TranslationBundle } from '@jupyterlab/translation'; import { checkIcon, ToolbarButton, undoIcon } from '@jupyterlab/ui-components'; import { Widget } from '@lumino/widgets'; import { ICellFooterTracker } from 'jupyterlab-cell-input-footer'; @@ -27,6 +28,11 @@ export interface IDiffWidgetOptions { */ newSource: string; + /** + * The translation bundle + */ + trans: TranslationBundle; + /** * Additional diff data (for nbdime strategy) */ @@ -61,6 +67,7 @@ export abstract class BaseDiffWidget extends Widget { this._cellFooterTracker = options.cellFooterTracker; this._originalSource = options.originalSource; this._newSource = options.newSource || options.cell.sharedModel.getSource(); + this._trans = options.trans; this._showActionButtons = options.showActionButtons ?? true; this._openDiff = options.openDiff ?? true; } @@ -128,7 +135,7 @@ export abstract class BaseDiffWidget extends Widget { */ private _createButtons(footer: any): void { this._toggleButton = new ToolbarButton({ - label: 'Compare changes', + label: this._trans.__('Compare changes'), enabled: true, className: 'jp-DiffView-toggle', onClick: () => { @@ -141,7 +148,7 @@ export abstract class BaseDiffWidget extends Widget { if (this._showActionButtons) { const rejectButton = new ToolbarButton({ icon: undoIcon, - tooltip: 'Reject Changes', + tooltip: this._trans.__('Reject Changes'), enabled: true, className: 'jp-DiffView-reject', onClick: () => this.onRejectClick() @@ -149,7 +156,7 @@ export abstract class BaseDiffWidget extends Widget { const acceptButton = new ToolbarButton({ icon: checkIcon, - tooltip: 'Accept Changes', + tooltip: this._trans.__('Accept Changes'), enabled: true, className: 'jp-DiffView-accept', onClick: () => this.onAcceptClick() @@ -191,4 +198,5 @@ export abstract class BaseDiffWidget extends Widget { protected _showActionButtons: boolean; protected _openDiff: boolean; protected _toggleButton: ToolbarButton | null = null; + private _trans: TranslationBundle; } diff --git a/yarn.lock b/yarn.lock index 412a3b2..08b1bfa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3714,6 +3714,7 @@ __metadata: "@jupyterlab/coreutils": ^6.0.0 "@jupyterlab/notebook": ^4.0.0 "@jupyterlab/services": ^7.0.0 + "@jupyterlab/translation": ^4.0.0 "@jupyterlab/ui-components": ^4.0.0 "@lumino/widgets": ^2.0.0 "@types/json-schema": ^7.0.11 From 4af39c3930094020e60e083e37d42e20c50f777f Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Mon, 15 Sep 2025 19:21:50 +0200 Subject: [PATCH 2/3] fix build --- src/diff/codemirror.ts | 4 +++- src/widget.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/diff/codemirror.ts b/src/diff/codemirror.ts index d78e567..18231e1 100644 --- a/src/diff/codemirror.ts +++ b/src/diff/codemirror.ts @@ -91,6 +91,7 @@ export async function createCodeMirrorDiffWidget( cellFooterTracker, originalSource, newSource, + trans, showActionButtons = true, openDiff = true } = options; @@ -101,7 +102,8 @@ export async function createCodeMirrorDiffWidget( cell, cellFooterTracker, showActionButtons, - openDiff + openDiff, + trans }); diffWidget.addClass('jupyterlab-cell-diff'); diff --git a/src/widget.ts b/src/widget.ts index e074d0c..0caabfa 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -1,5 +1,5 @@ import { ICellModel } from '@jupyterlab/cells'; -import { nullTranslator, TranslationBundle } from '@jupyterlab/translation'; +import { TranslationBundle } from '@jupyterlab/translation'; import { checkIcon, ToolbarButton, undoIcon } from '@jupyterlab/ui-components'; import { Widget } from '@lumino/widgets'; import { ICellFooterTracker } from 'jupyterlab-cell-input-footer'; From b2c752a864491fd59c39e4b8e17e23b6b472e9a3 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Mon, 15 Sep 2025 21:22:00 +0200 Subject: [PATCH 3/3] fixes --- src/plugin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugin.ts b/src/plugin.ts index 1b2926a..89a5f0c 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -154,7 +154,7 @@ const codeMirrorPlugin: JupyterFrontEndPlugin = { await createCodeMirrorDiffWidget(options); } catch (error) { - console.error(trans.__('Failed to create diff widget:'), error); + console.error(trans.__('Failed to create diff widget: %1'), error); } } }); @@ -254,7 +254,7 @@ const nbdimePlugin: JupyterFrontEndPlugin = { diffData = (response as any).diff; } catch (error) { console.warn( - trans.__('Failed to fetch diff data from server:'), + trans.__('Failed to fetch diff data from server: %1'), error ); } @@ -280,7 +280,7 @@ const nbdimePlugin: JupyterFrontEndPlugin = { await createNBDimeDiffWidget(options); } catch (error) { - console.error(trans.__('Failed to create diff widget:'), error); + console.error(trans.__('Failed to create diff widget: %1'), error); } } });