From 8345420fb531d562ca13be35e2e73ae94a5e4031 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 6 Dec 2024 01:06:23 -0800 Subject: [PATCH 1/3] Localize all views and messages --- src/common/errors/utils.ts | 9 +- src/common/localize.ts | 101 +++++++++++++++++++++ src/common/pickers/environments.ts | 14 +-- src/common/pickers/managers.ts | 8 +- src/common/pickers/packages.ts | 8 +- src/common/pickers/projects.ts | 5 +- src/extension.ts | 4 +- src/features/views/envManagersView.ts | 5 +- src/features/views/projectView.ts | 15 +-- src/features/views/revealHandler.ts | 4 +- src/managers/conda/condaEnvManager.ts | 9 +- src/managers/conda/condaPackageManager.ts | 30 +++--- src/managers/conda/condaUtils.ts | 41 +++++---- src/managers/sysPython/sysPythonManager.ts | 9 +- src/managers/sysPython/utils.ts | 18 +++- src/managers/sysPython/venvManager.ts | 9 +- src/managers/sysPython/venvUtils.ts | 57 ++++++------ 17 files changed, 229 insertions(+), 117 deletions(-) diff --git a/src/common/errors/utils.ts b/src/common/errors/utils.ts index d04f61e6..b7e7abd9 100644 --- a/src/common/errors/utils.ts +++ b/src/common/errors/utils.ts @@ -1,5 +1,6 @@ import * as stackTrace from 'stack-trace'; import { commands, LogOutputChannel, window } from 'vscode'; +import { Common } from '../localize'; export function parseStack(ex: Error) { if (ex.stack && Array.isArray(ex.stack)) { @@ -10,8 +11,8 @@ export function parseStack(ex: Error) { } export async function showErrorMessage(message: string, log?: LogOutputChannel) { - const result = await window.showErrorMessage(message, 'View Logs'); - if (result === 'View Logs') { + const result = await window.showErrorMessage(message, Common.viewLogs); + if (result === Common.viewLogs) { if (log) { log.show(); } else { @@ -21,8 +22,8 @@ export async function showErrorMessage(message: string, log?: LogOutputChannel) } export async function showWarningMessage(message: string, log?: LogOutputChannel) { - const result = await window.showWarningMessage(message, 'View Logs'); - if (result === 'View Logs') { + const result = await window.showWarningMessage(message, Common.viewLogs); + if (result === Common.viewLogs) { if (log) { log.show(); } else { diff --git a/src/common/localize.ts b/src/common/localize.ts index 17632a86..85402509 100644 --- a/src/common/localize.ts +++ b/src/common/localize.ts @@ -6,6 +6,11 @@ export namespace Common { export const uninstall = l10n.t('Uninstall'); export const openInBrowser = l10n.t('Open in Browser'); export const openInEditor = l10n.t('Open in Editor'); + export const browse = l10n.t('Browse'); + export const selectFolder = l10n.t('Select Folder'); + export const viewLogs = l10n.t('View Logs'); + export const yes = l10n.t('Yes'); + export const no = l10n.t('No'); } export namespace Interpreter { @@ -25,3 +30,99 @@ export namespace PackageManagement { export const enterPackagesPlaceHolder = l10n.t('Enter package names separated by space'); export const editArguments = l10n.t('Edit arguments'); } + +export namespace Pickers { + export namespace Environments { + export const selectExecutable = l10n.t('Select Python Executable'); + export const selectEnvironment = l10n.t('Select a Python Environment'); + } + + export namespace Packages { + export const selectOption = l10n.t('Select an option'); + export const installPackages = l10n.t('Install packages'); + export const uninstallPackages = l10n.t('Uninstall packages'); + } + + export namespace Managers { + export const selectEnvironmentManager = l10n.t('Select an environment manager'); + export const selectPackageManager = l10n.t('Select a package manager'); + export const selectProjectCreator = l10n.t('Select a project creator'); + } + + export namespace Project { + export const selectProject = l10n.t('Select a project, folder or script'); + export const selectProjects = l10n.t('Select one or more projects, folders or scripts'); + } +} + +export namespace ProjectViews { + export const noPackageManager = l10n.t('No package manager found'); + export const waitingForEnvManager = l10n.t('Waiting for environment managers to load'); + export const noEnvironmentManager = l10n.t('Environment manager not found'); + export const noEnvironmentManagerDescription = l10n.t( + 'Install an environment manager to get started. If you have installed then it might be loading or errored', + ); + export const noEnvironmentProvided = l10n.t('No environment provided by:'); + export const noPackages = l10n.t('No packages found'); +} + +export namespace VenvManagerStrings { + export const venvManagerDescription = l10n.t('Manages virtual environments created using `venv`'); + export const venvInitialize = l10n.t('Initializing virtual environments'); + export const venvRefreshing = l10n.t('Refreshing virtual environments'); + export const venvGlobalFolder = l10n.t('Select a folder to create a global virtual environment'); + export const venvGlobalFoldersSetting = l10n.t('Venv Folders Setting'); + + export const venvErrorNoBasePython = l10n.t('No base python found'); + export const venvErrorNoPython3 = l10n.t('Did not find any base python 3'); + + export const venvName = l10n.t('Enter a name for the virtual environment'); + export const venvNameErrorEmpty = l10n.t('Name cannot be empty'); + export const venvNameErrorExists = l10n.t('A folder with the same name already exists'); + + export const venvCreating = l10n.t('Creating virtual environment'); + export const venvCreateFailed = l10n.t('Failed to create virtual environment'); + + export const venvRemoving = l10n.t('Removing virtual environment'); + export const venvRemoveFailed = l10n.t('Failed to remove virtual environment'); + + export const installEditable = l10n.t('Install project as editable'); + export const searchingDependencies = l10n.t('Searching for dependencies'); +} + +export namespace SysManagerStrings { + export const sysManagerDescription = l10n.t('Manages Global python installs'); + export const sysManagerRefreshing = l10n.t('Refreshing Global Python interpreters'); + export const sysManagerDiscovering = l10n.t('Discovering Global Python interpreters'); + + export const selectInstall = l10n.t('Select packages to install'); + export const selectUninstall = l10n.t('Select packages to uninstall'); + + export const packageRefreshError = l10n.t('Error refreshing packages'); +} + +export namespace CondaStrings { + export const condaManager = l10n.t('Manages Conda environments'); + export const condaDiscovering = l10n.t('Discovering Conda environments'); + export const condaRefreshingEnvs = l10n.t('Refreshing Conda environments'); + + export const condaPackageMgr = l10n.t('Manages Conda packages'); + export const condaRefreshingPackages = l10n.t('Refreshing Conda packages'); + export const condaInstallingPackages = l10n.t('Installing Conda packages'); + export const condaInstallError = l10n.t('Error installing Conda packages'); + export const condaUninstallingPackages = l10n.t('Uninstalling Conda packages'); + export const condaUninstallError = l10n.t('Error uninstalling Conda packages'); + + export const condaNamed = l10n.t('Named'); + export const condaPrefix = l10n.t('Prefix'); + + export const condaNamedDescription = l10n.t('Create a named conda environment'); + export const condaPrefixDescription = l10n.t('Create environment in your workspace'); + export const condaSelectEnvType = l10n.t('Select the type of conda environment to create'); + + export const condaNamedInput = l10n.t('Enter the name of the conda environment to create'); + + export const condaCreateFailed = l10n.t('Failed to create conda environment'); + export const condaRemoveFailed = l10n.t('Failed to remove conda environment'); + export const condaExists = l10n.t('Environment already exists'); +} diff --git a/src/common/pickers/environments.ts b/src/common/pickers/environments.ts index 0cef6f2b..5a890f16 100644 --- a/src/common/pickers/environments.ts +++ b/src/common/pickers/environments.ts @@ -1,7 +1,7 @@ import { Uri, ThemeIcon, QuickPickItem, QuickPickItemKind, ProgressLocation, QuickInputButtons } from 'vscode'; import { IconPath, PythonEnvironment, PythonProject } from '../../api'; import { InternalEnvironmentManager } from '../../internal.api'; -import { Common, Interpreter } from '../localize'; +import { Common, Interpreter, Pickers } from '../localize'; import { showQuickPickWithButtons, showQuickPick, showOpenDialog, withProgress } from '../window.apis'; import { isWindows } from '../../managers/common/utils'; import { traceError } from '../logging'; @@ -18,14 +18,10 @@ type QuickPickIcon = | undefined; function getIconPath(i: IconPath | undefined): QuickPickIcon { - if (i === undefined || i instanceof ThemeIcon) { + if (i === undefined || i instanceof ThemeIcon || i instanceof Uri) { return i; } - if (i instanceof Uri) { - return i.fsPath.endsWith('__icon__.py') ? undefined : i; - } - if (typeof i === 'string') { return Uri.file(i); } @@ -51,7 +47,7 @@ async function browseForPython( canSelectFolders: false, canSelectMany: false, filters, - title: 'Select Python executable', + title: Pickers.Environments.selectExecutable, }); if (!uris || uris.length === 0) { return; @@ -103,7 +99,7 @@ async function pickEnvironmentImpl( options: EnvironmentPickOptions, ): Promise { const selected = await showQuickPickWithButtons(items, { - placeHolder: `Select a Python Environment`, + placeHolder: Pickers.Environments.selectEnvironment, ignoreFocusOut: true, showBackButton: options?.showBackButton, }); @@ -184,7 +180,7 @@ export async function pickEnvironmentFrom(environments: PythonEnvironment[]): Pr iconPath: getIconPath(e.iconPath), })); const selected = await showQuickPick(items, { - placeHolder: 'Select Python Environment', + placeHolder: Pickers.Environments.selectEnvironment, ignoreFocusOut: true, }); return (selected as { e: PythonEnvironment })?.e; diff --git a/src/common/pickers/managers.ts b/src/common/pickers/managers.ts index ed19b388..100f9ee9 100644 --- a/src/common/pickers/managers.ts +++ b/src/common/pickers/managers.ts @@ -1,7 +1,7 @@ import { QuickPickItem, QuickPickItemKind } from 'vscode'; import { PythonProjectCreator } from '../../api'; import { InternalEnvironmentManager, InternalPackageManager } from '../../internal.api'; -import { Common } from '../localize'; +import { Common, Pickers } from '../localize'; import { showQuickPickWithButtons, showQuickPick } from '../window.apis'; export async function pickEnvironmentManager( @@ -44,7 +44,7 @@ export async function pickEnvironmentManager( })), ); const item = await showQuickPickWithButtons(items, { - placeHolder: 'Select an environment manager', + placeHolder: Pickers.Managers.selectEnvironmentManager, ignoreFocusOut: true, }); return (item as QuickPickItem & { id: string })?.id; @@ -90,7 +90,7 @@ export async function pickPackageManager( })), ); const item = await showQuickPickWithButtons(items, { - placeHolder: 'Select an package manager', + placeHolder: Pickers.Managers.selectPackageManager, ignoreFocusOut: true, }); return (item as QuickPickItem & { id: string })?.id; @@ -111,7 +111,7 @@ export async function pickCreator(creators: PythonProjectCreator[]): Promise { const items = [ { label: Common.install, - description: 'Install packages', + description: Pickers.Packages.installPackages, }, { label: Common.uninstall, - description: 'Uninstall packages', + description: Pickers.Packages.uninstallPackages, }, ]; const selected = await showQuickPick(items, { - placeHolder: 'Select an option', + placeHolder: Pickers.Packages.selectOption, ignoreFocusOut: true, }); return selected?.label; diff --git a/src/common/pickers/projects.ts b/src/common/pickers/projects.ts index 708b0d7c..919943a4 100644 --- a/src/common/pickers/projects.ts +++ b/src/common/pickers/projects.ts @@ -2,6 +2,7 @@ import path from 'path'; import { QuickPickItem } from 'vscode'; import { PythonProject } from '../../api'; import { showQuickPick, showQuickPickWithButtons } from '../window.apis'; +import { Pickers } from '../localize'; interface ProjectQuickPickItem extends QuickPickItem { project: PythonProject; @@ -15,7 +16,7 @@ export async function pickProject(projects: ReadonlyArray): Promi project: pw, })); const item = await showQuickPick(items, { - placeHolder: 'Select a project, folder or script', + placeHolder: Pickers.Project.selectProject, ignoreFocusOut: true, }); if (item) { @@ -38,7 +39,7 @@ export async function pickProjectMany( project: pw, })); const item = await showQuickPickWithButtons(items, { - placeHolder: 'Select a project, folder or script', + placeHolder: Pickers.Project.selectProjects, ignoreFocusOut: true, canPickMany: true, showBackButton: showBackButton, diff --git a/src/extension.ts b/src/extension.ts index 38a6b0be..8af1d6f6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -35,7 +35,7 @@ import { registerAutoProjectProvider, registerExistingProjectProvider, } from './features/projectCreators'; -import { WorkspaceView } from './features/views/projectView'; +import { ProjectView } from './features/views/projectView'; import { registerCompletionProvider } from './features/settings/settingCompletions'; import { TerminalManager, TerminalManagerImpl } from './features/terminal/terminalManager'; import { @@ -93,7 +93,7 @@ export async function activate(context: ExtensionContext): Promise, Disposable { private treeView: TreeView; @@ -120,7 +121,7 @@ export class EnvManagerView implements TreeDataProvider, Disposable this.packageRoots.set(environment.envId.id, item); views.push(item); } else { - views.push(new EnvInfoTreeItem(parent, 'No package manager found')); + views.push(new EnvInfoTreeItem(parent, ProjectViews.noPackageManager)); } return views; @@ -137,7 +138,7 @@ export class EnvManagerView implements TreeDataProvider, Disposable if (packages) { views.push(...packages.map((p) => new PackageTreeItem(p, root, manager))); } else { - views.push(new PackageRootInfoTreeItem(root, 'No packages found')); + views.push(new PackageRootInfoTreeItem(root, ProjectViews.noPackages)); } return views; diff --git a/src/features/views/projectView.ts b/src/features/views/projectView.ts index dfd976bd..28fb653d 100644 --- a/src/features/views/projectView.ts +++ b/src/features/views/projectView.ts @@ -25,8 +25,9 @@ import { } from './treeViewItems'; import { onDidChangeConfiguration } from '../../common/workspace.apis'; import { createSimpleDebounce } from '../../common/utils/debounce'; +import { ProjectViews } from '../../common/localize'; -export class WorkspaceView implements TreeDataProvider { +export class ProjectView implements TreeDataProvider { private treeView: TreeView; private _treeDataChanged: EventEmitter = new EventEmitter< ProjectTreeItem | ProjectTreeItem[] | null | undefined @@ -149,7 +150,7 @@ export class WorkspaceView implements TreeDataProvider { new NoProjectEnvironment( projectItem.project, projectItem, - 'Waiting for environment managers to load', + ProjectViews.waitingForEnvManager, undefined, undefined, '$(loading~spin)', @@ -164,8 +165,8 @@ export class WorkspaceView implements TreeDataProvider { new NoProjectEnvironment( projectItem.project, projectItem, - 'Environment manager not found', - 'Install an environment manager to get started. If you have installed then it might be loading.', + ProjectViews.noEnvironmentManager, + ProjectViews.noEnvironmentManagerDescription, ), ]; } @@ -176,7 +177,7 @@ export class WorkspaceView implements TreeDataProvider { new NoProjectEnvironment( projectItem.project, projectItem, - `No environment provided by ${manager.displayName}`, + `${ProjectViews.noEnvironmentProvided} ${manager.displayName}`, ), ]; } @@ -199,7 +200,7 @@ export class WorkspaceView implements TreeDataProvider { this.packageRoots.set(uri ? uri.fsPath : 'global', item); views.push(item); } else { - views.push(new ProjectEnvironmentInfo(environmentItem, 'No package manager found')); + views.push(new ProjectEnvironmentInfo(environmentItem, ProjectViews.noPackageManager)); } return views; } @@ -214,7 +215,7 @@ export class WorkspaceView implements TreeDataProvider { if (packages) { return packages.map((p) => new ProjectPackage(root, p, manager)); } else { - views.push(new ProjectPackageRootInfoTreeItem(root, 'No packages found')); + views.push(new ProjectPackageRootInfoTreeItem(root, ProjectViews.noPackages)); } } diff --git a/src/features/views/revealHandler.ts b/src/features/views/revealHandler.ts index 2698d315..251a36f8 100644 --- a/src/features/views/revealHandler.ts +++ b/src/features/views/revealHandler.ts @@ -1,5 +1,5 @@ import { activeTextEditor } from '../../common/window.apis'; -import { WorkspaceView } from './projectView'; +import { ProjectView } from './projectView'; import { EnvManagerView } from './envManagersView'; import { PythonStatusBar } from './pythonStatusBar'; import { isPythonProjectFile } from '../../common/utils/fileNameUtils'; @@ -7,7 +7,7 @@ import { PythonEnvironmentApi } from '../../api'; export function updateViewsAndStatus( statusBar: PythonStatusBar, - workspaceView: WorkspaceView, + workspaceView: ProjectView, managerView: EnvManagerView, api: PythonEnvironmentApi, ) { diff --git a/src/managers/conda/condaEnvManager.ts b/src/managers/conda/condaEnvManager.ts index a6066f73..1834ad79 100644 --- a/src/managers/conda/condaEnvManager.ts +++ b/src/managers/conda/condaEnvManager.ts @@ -30,6 +30,7 @@ import { import { NativePythonFinder } from '../common/nativePythonFinder'; import { createDeferred, Deferred } from '../../common/utils/deferred'; import { withProgress } from '../../common/window.apis'; +import { CondaStrings } from '../../common/localize'; export class CondaEnvManager implements EnvironmentManager, Disposable { private collection: PythonEnvironment[] = []; @@ -51,8 +52,8 @@ export class CondaEnvManager implements EnvironmentManager, Disposable { this.name = 'conda'; this.displayName = 'Conda'; this.preferredPackageManagerId = 'ms-python.python:conda'; - this.description = 'Conda environment manager'; - this.tooltip = 'Conda environment manager'; + this.description = CondaStrings.condaManager; + this.tooltip = CondaStrings.condaManager; } name: string; @@ -77,7 +78,7 @@ export class CondaEnvManager implements EnvironmentManager, Disposable { await withProgress( { location: ProgressLocation.Window, - title: 'Discovering Conda environments', + title: CondaStrings.condaDiscovering, }, async () => { this.collection = await refreshCondaEnvs(false, this.nativeFinder, this.api, this.log, this); @@ -168,7 +169,7 @@ export class CondaEnvManager implements EnvironmentManager, Disposable { await withProgress( { location: ProgressLocation.Window, - title: 'Refreshing Conda Environments', + title: CondaStrings.condaRefreshingEnvs, }, async () => { this.log.info('Refreshing Conda Environments'); diff --git a/src/managers/conda/condaPackageManager.ts b/src/managers/conda/condaPackageManager.ts index cfa35448..ca48987b 100644 --- a/src/managers/conda/condaPackageManager.ts +++ b/src/managers/conda/condaPackageManager.ts @@ -6,7 +6,6 @@ import { LogOutputChannel, MarkdownString, ProgressLocation, - window, } from 'vscode'; import { DidChangePackagesEventArgs, @@ -19,6 +18,9 @@ import { PythonEnvironmentApi, } from '../../api'; import { installPackages, refreshPackages, uninstallPackages } from './condaUtils'; +import { withProgress } from '../../common/window.apis'; +import { showErrorMessage } from '../../common/errors/utils'; +import { CondaStrings } from '../../common/localize'; function getChanges(before: Package[], after: Package[]): { kind: PackageChangeKind; pkg: Package }[] { const changes: { kind: PackageChangeKind; pkg: Package }[] = []; @@ -40,8 +42,8 @@ export class CondaPackageManager implements PackageManager, Disposable { constructor(public readonly api: PythonEnvironmentApi, public readonly log: LogOutputChannel) { this.name = 'conda'; this.displayName = 'Conda'; - this.description = 'Conda package manager'; - this.tooltip = 'Conda package manager'; + this.description = CondaStrings.condaPackageMgr; + this.tooltip = CondaStrings.condaPackageMgr; } name: string; displayName?: string; @@ -50,10 +52,10 @@ export class CondaPackageManager implements PackageManager, Disposable { iconPath?: IconPath; async install(environment: PythonEnvironment, packages: string[], options: PackageInstallOptions): Promise { - await window.withProgress( + await withProgress( { location: ProgressLocation.Notification, - title: 'Installing packages', + title: CondaStrings.condaInstallingPackages, cancellable: true, }, async (_progress, token) => { @@ -70,10 +72,7 @@ export class CondaPackageManager implements PackageManager, Disposable { this.log.error('Error installing packages', e); setImmediate(async () => { - const result = await window.showErrorMessage('Error installing packages', 'View Output'); - if (result === 'View Output') { - this.log.show(); - } + await showErrorMessage(CondaStrings.condaInstallError, this.log); }); } }, @@ -81,10 +80,10 @@ export class CondaPackageManager implements PackageManager, Disposable { } async uninstall(environment: PythonEnvironment, packages: Package[] | string[]): Promise { - await window.withProgress( + await withProgress( { location: ProgressLocation.Notification, - title: 'Uninstalling packages', + title: CondaStrings.condaUninstallingPackages, cancellable: true, }, async (_progress, token) => { @@ -101,20 +100,17 @@ export class CondaPackageManager implements PackageManager, Disposable { this.log.error('Error uninstalling packages', e); setImmediate(async () => { - const result = await window.showErrorMessage('Error installing packages', 'View Output'); - if (result === 'View Output') { - this.log.show(); - } + await showErrorMessage(CondaStrings.condaUninstallError, this.log); }); } }, ); } async refresh(context: PythonEnvironment): Promise { - await window.withProgress( + await withProgress( { location: ProgressLocation.Window, - title: 'Refreshing packages', + title: CondaStrings.condaRefreshingPackages, }, async () => { this.packages.set(context.envId.id, await refreshPackages(context, this.api, this)); diff --git a/src/managers/conda/condaUtils.ts b/src/managers/conda/condaUtils.ts index bf2395c0..26121367 100644 --- a/src/managers/conda/condaUtils.ts +++ b/src/managers/conda/condaUtils.ts @@ -12,7 +12,7 @@ import { import * as path from 'path'; import * as os from 'os'; import * as fsapi from 'fs-extra'; -import { CancellationError, CancellationToken, LogOutputChannel, ProgressLocation, Uri, window } from 'vscode'; +import { CancellationError, CancellationToken, l10n, LogOutputChannel, ProgressLocation, Uri } from 'vscode'; import { ENVS_EXTENSION_ID } from '../../common/constants'; import { createDeferred } from '../../common/utils/deferred'; import { @@ -27,6 +27,9 @@ import { getGlobalPersistentState, getWorkspacePersistentState } from '../../com import which from 'which'; import { shortVersion, sortEnvironments } from '../common/utils'; import { pickProject } from '../../common/pickers/projects'; +import { CondaStrings } from '../../common/localize'; +import { showErrorMessage } from '../../common/errors/utils'; +import { showInputBox, showQuickPick, withProgress } from '../../common/window.apis'; export const CONDA_PATH_KEY = `${ENVS_EXTENSION_ID}:conda:CONDA_PATH`; export const CONDA_PREFIXES_KEY = `${ENVS_EXTENSION_ID}:conda:CONDA_PREFIXES`; @@ -398,20 +401,20 @@ export async function createCondaEnvironment( Array.isArray(uris) && uris.length > 1 ? 'Named' : ( - await window.showQuickPick( + await showQuickPick( [ - { label: 'Named', description: 'Create a named conda environment' }, - { label: 'Prefix', description: 'Create environment in your workspace' }, + { label: CondaStrings.condaNamed, description: CondaStrings.condaNamedDescription }, + { label: CondaStrings.condaPrefix, description: CondaStrings.condaPrefixDescription }, ], { - placeHolder: 'Select the type of conda environment to create', + placeHolder: CondaStrings.condaSelectEnvType, ignoreFocusOut: true, }, ) )?.label; if (envType) { - return envType === 'Named' + return envType === CondaStrings.condaNamed ? await createNamedCondaEnvironment(api, log, manager, getName(api, uris ?? [])) : await createPrefixCondaEnvironment(api, log, manager, await getLocation(api, uris ?? [])); } @@ -424,8 +427,8 @@ async function createNamedCondaEnvironment( manager: EnvironmentManager, name?: string, ): Promise { - name = await window.showInputBox({ - prompt: 'Enter the name of the conda environment to create', + name = await showInputBox({ + prompt: CondaStrings.condaNamedInput, value: name, ignoreFocusOut: true, }); @@ -435,10 +438,10 @@ async function createNamedCondaEnvironment( const envName: string = name; - return await window.withProgress( + return await withProgress( { location: ProgressLocation.Notification, - title: `Creating conda environment: ${envName}`, + title: l10n.t(`Creating conda environment: ${envName}`), }, async () => { try { @@ -479,8 +482,8 @@ async function createNamedCondaEnvironment( ); return environment; } catch (e) { - window.showErrorMessage('Failed to create conda environment'); log.error('Failed to create conda environment', e); + await showErrorMessage(CondaStrings.condaCreateFailed, log); } }, ); @@ -499,12 +502,12 @@ async function createPrefixCondaEnvironment( let name = `./.conda`; if (await fsapi.pathExists(path.join(fsPath, '.conda'))) { log.warn(`Environment "${path.join(fsPath, '.conda')}" already exists`); - const newName = await window.showInputBox({ - prompt: `Environment "${name}" already exists. Enter a different name`, + const newName = await showInputBox({ + prompt: l10n.t(`Environment "${name}" already exists. Enter a different name`), ignoreFocusOut: true, validateInput: (value) => { if (value === name) { - return 'Environment already exists'; + return CondaStrings.condaExists; } return undefined; }, @@ -517,7 +520,7 @@ async function createPrefixCondaEnvironment( const prefix: string = path.isAbsolute(name) ? name : path.join(fsPath, name); - return await window.withProgress( + return await withProgress( { location: ProgressLocation.Notification, title: `Creating conda environment: ${name}`, @@ -552,7 +555,7 @@ async function createPrefixCondaEnvironment( ); return environment; } catch (e) { - window.showErrorMessage('Failed to create conda environment'); + await showErrorMessage(CondaStrings.condaCreateFailed, log); log.error('Failed to create conda environment', e); } }, @@ -561,16 +564,16 @@ async function createPrefixCondaEnvironment( export async function deleteCondaEnvironment(environment: PythonEnvironment, log: LogOutputChannel): Promise { let args = ['env', 'remove', '--yes', '--prefix', environment.environmentPath.fsPath]; - return await window.withProgress( + return await withProgress( { location: ProgressLocation.Notification, - title: `Deleting conda environment: ${environment.environmentPath.fsPath}`, + title: l10n.t(`Deleting conda environment: ${environment.environmentPath.fsPath}`), }, async () => { try { await runConda(args); } catch (e) { - window.showErrorMessage('Failed to delete conda environment'); + await showErrorMessage(CondaStrings.condaRemoveFailed, log); log.error(`Failed to delete conda environment: ${e}`); return false; } diff --git a/src/managers/sysPython/sysPythonManager.ts b/src/managers/sysPython/sysPythonManager.ts index 685e9259..b44e6cc5 100644 --- a/src/managers/sysPython/sysPythonManager.ts +++ b/src/managers/sysPython/sysPythonManager.ts @@ -26,6 +26,7 @@ import { import { NativePythonFinder } from '../common/nativePythonFinder'; import { createDeferred, Deferred } from '../../common/utils/deferred'; import { getLatest } from '../common/utils'; +import { SysManagerStrings } from '../../common/localize'; export class SysPythonManager implements EnvironmentManager { private collection: PythonEnvironment[] = []; @@ -53,8 +54,8 @@ export class SysPythonManager implements EnvironmentManager { this.name = 'system'; this.displayName = 'Global'; this.preferredPackageManagerId = 'ms-python.python:pip'; - this.description = 'Manages Global python installs'; - this.tooltip = new MarkdownString('$(globe) Python Environment Manager', true); + this.description = SysManagerStrings.sysManagerDescription; + this.tooltip = new MarkdownString(SysManagerStrings.sysManagerDescription, true); this.iconPath = new ThemeIcon('globe'); } @@ -66,13 +67,13 @@ export class SysPythonManager implements EnvironmentManager { this._initialized = createDeferred(); - await this.internalRefresh(false, 'Discovering Python environments'); + await this.internalRefresh(false, SysManagerStrings.sysManagerDiscovering); this._initialized.resolve(); } refresh(_scope: RefreshEnvironmentsScope): Promise { - return this.internalRefresh(true, 'Refreshing Python environments'); + return this.internalRefresh(true, SysManagerStrings.sysManagerRefreshing); } private async internalRefresh(hardRefresh: boolean, title: string) { diff --git a/src/managers/sysPython/utils.ts b/src/managers/sysPython/utils.ts index 1b08b343..c423b9f2 100644 --- a/src/managers/sysPython/utils.ts +++ b/src/managers/sysPython/utils.ts @@ -1,4 +1,13 @@ -import { CancellationError, CancellationToken, LogOutputChannel, QuickPickItem, ThemeIcon, Uri, window } from 'vscode'; +import { + CancellationError, + CancellationToken, + l10n, + LogOutputChannel, + QuickPickItem, + ThemeIcon, + Uri, + window, +} from 'vscode'; import { EnvironmentManager, Package, @@ -22,6 +31,7 @@ import { getWorkspacePersistentState } from '../../common/persistentState'; import { shortVersion, sortEnvironments } from '../common/utils'; import { sendTelemetryEvent } from '../../common/telemetry/sender'; import { EventNames } from '../../common/telemetry/constants'; +import { SysManagerStrings } from '../../common/localize'; export const SYSTEM_WORKSPACE_KEY = `${ENVS_EXTENSION_ID}:system:WORKSPACE_SELECTED`; export const SYSTEM_GLOBAL_KEY = `${ENVS_EXTENSION_ID}:system:GLOBAL_SELECTED`; @@ -82,7 +92,7 @@ export async function pickPackages(uninstall: boolean, packages: string[] | Pack }); const result = await window.showQuickPick(items, { - placeHolder: uninstall ? 'Select packages to uninstall' : 'Select packages to install', + placeHolder: uninstall ? SysManagerStrings.selectUninstall : SysManagerStrings.selectInstall, canPickMany: true, ignoreFocusOut: true, }); @@ -280,7 +290,7 @@ export async function refreshPackages( ): Promise { if (!environment.execInfo) { manager.log?.error(`No executable found for python: ${environment.environmentPath.fsPath}`); - showErrorMessage(`No executable found for python: ${environment.environmentPath.fsPath}`, manager.log); + showErrorMessage(l10n.t(`No executable found for python: ${environment.environmentPath.fsPath}`), manager.log); return []; } @@ -298,7 +308,7 @@ export async function refreshPackages( } } catch (e) { manager.log?.error('Error refreshing packages', e); - showErrorMessage('Error refreshing packages', manager.log); + showErrorMessage(SysManagerStrings.packageRefreshError, manager.log); return []; } diff --git a/src/managers/sysPython/venvManager.ts b/src/managers/sysPython/venvManager.ts index 5bde9a98..fe77b41e 100644 --- a/src/managers/sysPython/venvManager.ts +++ b/src/managers/sysPython/venvManager.ts @@ -33,6 +33,7 @@ import { ENVS_EXTENSION_ID } from '../../common/constants'; import { createDeferred, Deferred } from '../../common/utils/deferred'; import { getLatest, sortEnvironments } from '../common/utils'; import { withProgress } from '../../common/window.apis'; +import { VenvManagerStrings } from '../../common/localize'; export class VenvManager implements EnvironmentManager { private collection: PythonEnvironment[] = []; @@ -60,8 +61,8 @@ export class VenvManager implements EnvironmentManager { ) { this.name = 'venv'; this.displayName = 'venv Environments'; - this.description = 'Manages virtual environments created using venv'; - this.tooltip = new MarkdownString('Manages virtual environments created using `venv`', true); + this.description = VenvManagerStrings.venvManagerDescription; + this.tooltip = new MarkdownString(VenvManagerStrings.venvManagerDescription, true); this.preferredPackageManagerId = 'ms-python.python:pip'; this.iconPath = new ThemeIcon('python'); } @@ -75,7 +76,7 @@ export class VenvManager implements EnvironmentManager { this._initialized = createDeferred(); try { - await this.internalRefresh(undefined, false, 'Initializing virtual environments'); + await this.internalRefresh(undefined, false, VenvManagerStrings.venvInitialize); } finally { this._initialized.resolve(); } @@ -141,7 +142,7 @@ export class VenvManager implements EnvironmentManager { } async refresh(scope: RefreshEnvironmentsScope): Promise { - return this.internalRefresh(scope, true, 'Refreshing virtual environments'); + return this.internalRefresh(scope, true, VenvManagerStrings.venvRefreshing); } private async internalRefresh(scope: RefreshEnvironmentsScope, hardRefresh: boolean, title: string): Promise { diff --git a/src/managers/sysPython/venvUtils.ts b/src/managers/sysPython/venvUtils.ts index 2987881d..6b96200f 100644 --- a/src/managers/sysPython/venvUtils.ts +++ b/src/managers/sysPython/venvUtils.ts @@ -1,4 +1,4 @@ -import { LogOutputChannel, ProgressLocation, QuickPickItem, QuickPickItemKind, ThemeIcon, Uri } from 'vscode'; +import { l10n, LogOutputChannel, ProgressLocation, QuickPickItem, QuickPickItemKind, ThemeIcon, Uri } from 'vscode'; import { EnvironmentManager, Installable, @@ -34,6 +34,7 @@ import { } from '../../common/window.apis'; import { showErrorMessage } from '../../common/errors/utils'; import { getPackagesToInstallFromInstallable } from '../../common/pickers/packages'; +import { Common, VenvManagerStrings } from '../../common/localize'; export const VENV_WORKSPACE_KEY = `${ENVS_EXTENSION_ID}:venv:WORKSPACE_SELECTED`; export const VENV_GLOBAL_KEY = `${ENVS_EXTENSION_ID}:venv:GLOBAL_SELECTED`; @@ -185,8 +186,8 @@ interface FolderQuickPickItem extends QuickPickItem { export async function getGlobalVenvLocation(): Promise { const items: FolderQuickPickItem[] = [ { - label: 'Browse', - description: 'Select a folder to create a global virtual environment', + label: Common.browse, + description: VenvManagerStrings.venvGlobalFolder, }, ]; @@ -194,7 +195,7 @@ export async function getGlobalVenvLocation(): Promise { if (venvPaths.length > 0) { items.push( { - label: 'Venv Folders Setting', + label: VenvManagerStrings.venvGlobalFoldersSetting, kind: QuickPickItemKind.Separator, }, ...venvPaths.map((p) => ({ @@ -208,11 +209,11 @@ export async function getGlobalVenvLocation(): Promise { if (process.env.WORKON_HOME) { items.push( { - label: 'Virtualenvwrapper', + label: 'virtualenvwrapper', kind: QuickPickItemKind.Separator, }, { - label: 'WORKON_HOME', + label: 'WORKON_HOME (env variable)', description: process.env.WORKON_HOME, uri: Uri.file(process.env.WORKON_HOME), }, @@ -220,17 +221,17 @@ export async function getGlobalVenvLocation(): Promise { } const selected = await showQuickPick(items, { - placeHolder: 'Select a folder to create a global virtual environment', + placeHolder: VenvManagerStrings.venvGlobalFolder, ignoreFocusOut: true, }); if (selected) { - if (selected.label === 'Browse') { + if (selected.label === Common.browse) { const result = await showOpenDialog({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, - openLabel: 'Select Folder', + openLabel: Common.selectFolder, }); if (result && result.length > 0) { return result[0]; @@ -252,14 +253,14 @@ export async function createPythonVenv( ): Promise { if (basePythons.length === 0) { log.error('No base python found'); - showErrorMessage('No base python found'); + showErrorMessage(VenvManagerStrings.venvErrorNoBasePython); return; } const filtered = basePythons.filter((e) => e.version.startsWith('3.')); if (filtered.length === 0) { log.error('Did not find any base python 3.*'); - showErrorMessage('Did not find any base python 3.*'); + showErrorMessage(VenvManagerStrings.venvErrorNoPython3); basePythons.forEach((e) => { log.error(`available base python: ${e.version}`); }); @@ -272,22 +273,16 @@ export async function createPythonVenv( return; } - if (basePython.version.startsWith('2.')) { - log.error('Python 2.* is not supported for virtual env creation'); - showErrorMessage('Python 2.* is not supported, use Python 3.*'); - return; - } - const name = await showInputBox({ - prompt: 'Enter name for virtual environment', + prompt: VenvManagerStrings.venvName, value: '.venv', ignoreFocusOut: true, validateInput: async (value) => { if (!value) { - return 'Name cannot be empty'; + return VenvManagerStrings.venvNameErrorEmpty; } if (await fsapi.pathExists(path.join(venvRoot.fsPath, value))) { - return 'Virtual environment already exists'; + return VenvManagerStrings.venvNameErrorExists; } }, }); @@ -315,7 +310,7 @@ export async function createPythonVenv( return await withProgress( { location: ProgressLocation.Notification, - title: 'Creating virtual environment', + title: VenvManagerStrings.venvCreating, }, async () => { try { @@ -349,7 +344,7 @@ export async function createPythonVenv( return env; } catch (e) { log.error(`Failed to create virtual environment: ${e}`); - showErrorMessage(`Failed to create virtual environment`); + showErrorMessage(VenvManagerStrings.venvCreateFailed); return; } }, @@ -363,12 +358,16 @@ export async function removeVenv(environment: PythonEnvironment, log: LogOutputC ? path.dirname(path.dirname(environment.environmentPath.fsPath)) : environment.environmentPath.fsPath; - const confirm = await showWarningMessage(`Are you sure you want to remove ${envPath}?`, 'Yes', 'No'); - if (confirm === 'Yes') { + const confirm = await showWarningMessage( + l10n.t(`Are you sure you want to remove ${envPath}?`), + Common.yes, + Common.no, + ); + if (confirm === Common.yes) { await withProgress( { location: ProgressLocation.Notification, - title: 'Removing virtual environment', + title: VenvManagerStrings.venvRemoving, }, async () => { try { @@ -376,6 +375,7 @@ export async function removeVenv(environment: PythonEnvironment, log: LogOutputC return true; } catch (e) { log.error(`Failed to remove virtual environment: ${e}`); + showErrorMessage(VenvManagerStrings.venvRemoveFailed); return false; } }, @@ -404,7 +404,7 @@ function getTomlInstallable(toml: tomljs.JsonMap, tomlPath: Uri): Installable[] if (isPipInstallableToml(toml)) { extras.push({ displayName: path.basename(tomlPath.fsPath), - description: 'Install project as editable', + description: VenvManagerStrings.installEditable, group: 'TOML', args: ['-e', path.dirname(tomlPath.fsPath)], uri: tomlPath, @@ -437,10 +437,9 @@ export async function getProjectInstallable( await withProgress( { location: ProgressLocation.Window, - title: 'Searching dependencies', + title: VenvManagerStrings.searchingDependencies, }, - async (progress, token) => { - progress.report({ message: 'Searching for Requirements and TOML files' }); + async (_progress, token) => { const results: Uri[] = ( await Promise.all([ findFiles('**/*requirements*.txt', exclude, undefined, token), From e36886ea762ac7712263b97d0f3bc99a5ea3e4b3 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 6 Dec 2024 01:14:13 -0800 Subject: [PATCH 2/3] Fix build --- src/managers/conda/condaUtils.ts | 18 ++++++++++++------ src/managers/sysPython/utils.ts | 5 ++++- src/managers/sysPython/venvUtils.ts | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/managers/conda/condaUtils.ts b/src/managers/conda/condaUtils.ts index 26121367..5bd00fd4 100644 --- a/src/managers/conda/condaUtils.ts +++ b/src/managers/conda/condaUtils.ts @@ -441,7 +441,7 @@ async function createNamedCondaEnvironment( return await withProgress( { location: ProgressLocation.Notification, - title: l10n.t(`Creating conda environment: ${envName}`), + title: l10n.t('Creating conda environment: {0}', envName), }, async () => { try { @@ -483,7 +483,9 @@ async function createNamedCondaEnvironment( return environment; } catch (e) { log.error('Failed to create conda environment', e); - await showErrorMessage(CondaStrings.condaCreateFailed, log); + setImmediate(async () => { + await showErrorMessage(CondaStrings.condaCreateFailed, log); + }); } }, ); @@ -503,7 +505,7 @@ async function createPrefixCondaEnvironment( if (await fsapi.pathExists(path.join(fsPath, '.conda'))) { log.warn(`Environment "${path.join(fsPath, '.conda')}" already exists`); const newName = await showInputBox({ - prompt: l10n.t(`Environment "${name}" already exists. Enter a different name`), + prompt: l10n.t('Environment "{0}" already exists. Enter a different name', name), ignoreFocusOut: true, validateInput: (value) => { if (value === name) { @@ -555,8 +557,10 @@ async function createPrefixCondaEnvironment( ); return environment; } catch (e) { - await showErrorMessage(CondaStrings.condaCreateFailed, log); log.error('Failed to create conda environment', e); + setImmediate(async () => { + await showErrorMessage(CondaStrings.condaCreateFailed, log); + }); } }, ); @@ -567,14 +571,16 @@ export async function deleteCondaEnvironment(environment: PythonEnvironment, log return await withProgress( { location: ProgressLocation.Notification, - title: l10n.t(`Deleting conda environment: ${environment.environmentPath.fsPath}`), + title: l10n.t('Deleting conda environment: {0}', environment.environmentPath.fsPath), }, async () => { try { await runConda(args); } catch (e) { - await showErrorMessage(CondaStrings.condaRemoveFailed, log); log.error(`Failed to delete conda environment: ${e}`); + setImmediate(async () => { + await showErrorMessage(CondaStrings.condaRemoveFailed, log); + }); return false; } return true; diff --git a/src/managers/sysPython/utils.ts b/src/managers/sysPython/utils.ts index c423b9f2..35a1f022 100644 --- a/src/managers/sysPython/utils.ts +++ b/src/managers/sysPython/utils.ts @@ -290,7 +290,10 @@ export async function refreshPackages( ): Promise { if (!environment.execInfo) { manager.log?.error(`No executable found for python: ${environment.environmentPath.fsPath}`); - showErrorMessage(l10n.t(`No executable found for python: ${environment.environmentPath.fsPath}`), manager.log); + showErrorMessage( + l10n.t('No executable found for python: {0}', environment.environmentPath.fsPath), + manager.log, + ); return []; } diff --git a/src/managers/sysPython/venvUtils.ts b/src/managers/sysPython/venvUtils.ts index 6b96200f..cb25df9e 100644 --- a/src/managers/sysPython/venvUtils.ts +++ b/src/managers/sysPython/venvUtils.ts @@ -359,7 +359,7 @@ export async function removeVenv(environment: PythonEnvironment, log: LogOutputC : environment.environmentPath.fsPath; const confirm = await showWarningMessage( - l10n.t(`Are you sure you want to remove ${envPath}?`), + l10n.t('Are you sure you want to remove {0}?', envPath), Common.yes, Common.no, ); From c980ef98b493a5b1900e022c5dfff21c7e0dab4e Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 6 Dec 2024 10:16:28 -0800 Subject: [PATCH 3/3] Address comments --- src/common/localize.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/localize.ts b/src/common/localize.ts index 85402509..a81f8042 100644 --- a/src/common/localize.ts +++ b/src/common/localize.ts @@ -73,8 +73,8 @@ export namespace VenvManagerStrings { export const venvGlobalFolder = l10n.t('Select a folder to create a global virtual environment'); export const venvGlobalFoldersSetting = l10n.t('Venv Folders Setting'); - export const venvErrorNoBasePython = l10n.t('No base python found'); - export const venvErrorNoPython3 = l10n.t('Did not find any base python 3'); + export const venvErrorNoBasePython = l10n.t('No base Python found'); + export const venvErrorNoPython3 = l10n.t('Did not find any base Python 3'); export const venvName = l10n.t('Enter a name for the virtual environment'); export const venvNameErrorEmpty = l10n.t('Name cannot be empty'); @@ -91,7 +91,7 @@ export namespace VenvManagerStrings { } export namespace SysManagerStrings { - export const sysManagerDescription = l10n.t('Manages Global python installs'); + export const sysManagerDescription = l10n.t('Manages Global Python installs'); export const sysManagerRefreshing = l10n.t('Refreshing Global Python interpreters'); export const sysManagerDiscovering = l10n.t('Discovering Global Python interpreters');