diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index bef5e03f..c6fad772 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -28,6 +28,12 @@ "common.pin": "Pin", "common.unpin": "Unpin", "common.noResults": "No results", + "common.error": "Sorry, something went wrong.", + "common.yes": "yes", + "common.no": "no", + + "notifications.outputChannel.link": "output window", + "notifications.outputChannel.description": "Check the {0} for more details.", "settings.view.common": "Common", "settings.view.contentFolders": "Content folders", @@ -488,6 +494,40 @@ "commands.folders.get.notificationError.remove.action": "Remove folder", "commands.folders.get.notificationError.create.action": "Create folder", - "listeners.dashboard.settingsListener.triggerTemplate.notification": "Template files copied." + "commands.preview.panel.title": "Preview: {0}", + "commands.preview.askUserToPickFolder.title": "Select the folder of the article to preview", + "commands.project.initialize.success": "Project initialized successfully.", + "commands.project.switchProject.title": "To which project do you want to switch?", + "commands.project.createSampleTemplate.info": "Sample template created.", + + "commands.settings.create.input.prompt": "Insert the value of the {0} that you want to add to your configuration.", + "commands.settings.create.input.placeholder": "Name of the {0}", + "commands.settings.create.warning": "The provided {0} already exists.", + "commands.settings.create.quickPick.placeholder": "Do you want to add the new {0} to the page?", + "commands.settings.export.progress.title": "{0}: exporting tags and categories", + "commands.settings.export.progress.success": "Export completed. Tags: {0} - Categories: {1}.", + "commands.settings.remap.quickpick.title": "Remap", + "commands.settings.remap.quickpick.placeholder": "What do you want to remap?", + "commands.settings.remap.noTaxonomy.warning": "No {0} configured.", + "commands.settings.remap.selectTaxonomy.placeholder": "Select your {0} to insert.", + "commands.settings.remap.newOption.input.prompt": "Specify the value of the {0} with which you want to remap \"{1}\". Leave the input if you want to remove the {0} from all articles.", + "commands.settings.remap.newOption.input.placeholder": "Name of the {0}", + "commands.settings.remap.delete.placeholder": "Delete {0} {1}?", + + "commands.statusListener.verifyRequiredFields.diagnostic.emptyField": "The {0} field is required. Please define a value for the field.", + "commands.statusListener.verifyRequiredFields.notification.error": "The following fields are required to contain a value: {0}", + + "commands.template.generate.input.title": "Template title", + "commands.template.generate.input.prompt": "Which name would you like to give your template?", + "commands.template.generate.input.placeholder": "article", + "commands.template.generate.noTitle.warning": "You did not specify a template title.", + "commands.template.generate.keepContents.title": "Keep content", + "commands.template.generate.keepContents.placeholder": "Do you want to keep the contents for the template?", + "commands.template.generate.keepContents.noOption.warning": "You did not pick any of the options for keeping the template its content.", + "commands.template.generate.keepContents.success": "Template created and is now available in your {0} folder.", + "commands.template.getTemplates.warning": "No templates found.", + "commands.template.create.folderPath.warning": "Incorrect project folder path retrieved.", + + "listeners.dashboard.settingsListener.triggerTemplate.notification": "Template files copied." } \ No newline at end of file diff --git a/src/commands/Preview.ts b/src/commands/Preview.ts index 5b0c3834..0f28e902 100644 --- a/src/commands/Preview.ts +++ b/src/commands/Preview.ts @@ -24,6 +24,8 @@ import { WebviewHelper } from '@estruyf/vscode'; import { Folders } from './Folders'; import { ParsedFrontMatter } from '../parsers'; import { getLocalizationFile } from '../utils/getLocalizationFile'; +import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../localization'; export class Preview { public static filePath: string | undefined = undefined; @@ -71,7 +73,9 @@ export class Preview { // Create the preview webview const webView = window.createWebviewPanel( 'frontMatterPreview', - article?.data?.title ? `Preview: ${article?.data?.title}` : 'FrontMatter Preview', + article?.data?.title + ? l10n.t(LocalizationKey.commandsPreviewPanelTitle, article?.data.title) + : 'Front Matter Preview', { viewColumn: ViewColumn.Beside, preserveFocus: true @@ -393,7 +397,7 @@ export class Preview { const folderNames = crntFolders.map((folder) => folder.title); const selectedFolderName = await window.showQuickPick(folderNames, { canPickMany: false, - title: 'Select the folder of the article to preview' + title: l10n.t(LocalizationKey.commandsPreviewAskUserToPickFolderTitle) }); if (selectedFolderName) { diff --git a/src/commands/Project.ts b/src/commands/Project.ts index 2281ae63..0521a3f6 100644 --- a/src/commands/Project.ts +++ b/src/commands/Project.ts @@ -21,6 +21,8 @@ import { } from '../constants'; import { SettingsListener } from '../listeners/dashboard'; import { existsAsync, writeFileAsync } from '../utils'; +import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../localization'; export class Project { private static content = `--- @@ -66,7 +68,7 @@ categories: [] if (sampleTemplate !== undefined) { await Project.createSampleTemplate(); } else { - Notifications.info('Project initialized successfully.'); + Notifications.info(l10n.t(LocalizationKey.commandsProjectInitializeSuccess)); } // Initialize the media library @@ -89,10 +91,14 @@ categories: [] } catch (error: unknown) { const err = error as Error; Logger.error(`Project::init: ${err?.message || err}`); - Notifications.error(`Sorry, something went wrong - ${err?.message || err}`); + Notifications.errorWithOutput(l10n.t(LocalizationKey.commonError)); } } + /** + * Project switcher + * @returns + */ public static async switchProject() { const projects = Settings.getProjects(); const project = await window.showQuickPick( @@ -100,7 +106,7 @@ categories: [] { canPickMany: false, ignoreFocusOut: true, - title: 'Select a project to switch to' + title: l10n.t(LocalizationKey.commandsProjectSwitchProjectTitle) } ); @@ -136,7 +142,7 @@ categories: [] await writeFileAsync(article.fsPath, Project.content, { encoding: 'utf-8' }); - Notifications.info('Sample template created.'); + Notifications.info(l10n.t(LocalizationKey.commandsProjectCreateSampleTemplateInfo)); } } diff --git a/src/commands/Settings.ts b/src/commands/Settings.ts index 5190bd5c..f87f7460 100644 --- a/src/commands/Settings.ts +++ b/src/commands/Settings.ts @@ -5,6 +5,8 @@ import { EXTENSION_NAME } from '../constants'; import { ArticleHelper, FilesHelper } from '../helpers'; import { FrontMatterParser } from '../parsers'; import { Notifications } from '../helpers/Notifications'; +import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../localization'; export class Settings { /** @@ -13,11 +15,11 @@ export class Settings { * @param type */ public static async create(type: TaxonomyType) { + const taxonomy = type === TaxonomyType.Tag ? 'tag' : 'category'; + const newOption = await vscode.window.showInputBox({ - prompt: `Insert the value of the ${ - type === TaxonomyType.Tag ? 'tag' : 'category' - } that you want to add to your configuration.`, - placeHolder: `Name of the ${type === TaxonomyType.Tag ? 'tag' : 'category'}`, + prompt: l10n.t(LocalizationKey.commandsFoldersCreateInputPrompt, taxonomy), + placeHolder: l10n.t(LocalizationKey.commandsFoldersCreateInputPlaceholder, taxonomy), ignoreFocusOut: true }); @@ -25,9 +27,7 @@ export class Settings { let options = (await TaxonomyHelper.get(type)) || []; if (options.find((o) => o === newOption)) { - Notifications.info( - `The provided ${type === TaxonomyType.Tag ? 'tag' : 'category'} already exists.` - ); + Notifications.warning(l10n.t(LocalizationKey.commandsSettingsCreateWarning, taxonomy)); return; } @@ -35,15 +35,16 @@ export class Settings { TaxonomyHelper.update(type, options); // Ask if the new term needs to be added to the page - const addToPage = await vscode.window.showQuickPick(['yes', 'no'], { - canPickMany: false, - placeHolder: `Do you want to add the new ${ - type === TaxonomyType.Tag ? 'tag' : 'category' - } to the page?`, - ignoreFocusOut: true - }); + const addToPage = await vscode.window.showQuickPick( + [l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)], + { + canPickMany: false, + placeHolder: l10n.t(LocalizationKey.commandsSettingsCreateQuickPickPlaceholder, taxonomy), + ignoreFocusOut: true + } + ); - if (addToPage && addToPage === 'yes') { + if (addToPage && addToPage === l10n.t(LocalizationKey.commonYes)) { const editor = vscode.window.activeTextEditor; if (!editor) { return; @@ -54,7 +55,7 @@ export class Settings { return; } - const matterProp: string = type === TaxonomyType.Tag ? 'tags' : 'categories'; + const matterProp: string = taxonomy; // Add the selected options to the options array if (article.data[matterProp]) { const propData: string[] = article.data[matterProp]; @@ -83,7 +84,7 @@ export class Settings { vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, - title: `${EXTENSION_NAME}: exporting tags and categories`, + title: l10n.t(LocalizationKey.commandsSettingsExportProgressTitle, EXTENSION_NAME), cancellable: false }, async (progress) => { @@ -146,7 +147,11 @@ export class Settings { // Done Notifications.info( - `Export completed. Tags: ${crntTags.length} - Categories: ${crntCategories.length}.` + l10n.t( + LocalizationKey.commandsSettingsExportProgressSuccess, + crntTags.length, + crntCategories.length + ) ); } ); @@ -157,8 +162,8 @@ export class Settings { */ public static async remap() { const taxType = await vscode.window.showQuickPick(['Tag', 'Category'], { - title: `Remap`, - placeHolder: `What do you want to remap?`, + title: l10n.t(LocalizationKey.commandsSettingsRemapQuickpickTitle), + placeHolder: l10n.t(LocalizationKey.commandsSettingsRemapQuickpickPlaceholder), canPickMany: false, ignoreFocusOut: true }); @@ -168,15 +173,18 @@ export class Settings { } const type = taxType === 'Tag' ? TaxonomyType.Tag : TaxonomyType.Category; + const taxonomy = type === TaxonomyType.Tag ? 'tags' : 'categories'; const options = (await TaxonomyHelper.get(type)) || []; if (!options || options.length === 0) { - Notifications.info(`No ${type === TaxonomyType.Tag ? 'tags' : 'categories'} configured.`); + Notifications.warning( + l10n.t(LocalizationKey.commandsSettingsRemapNoTaxonomyWarning, taxonomy) + ); return; } const selectedOption = await vscode.window.showQuickPick(options, { - placeHolder: `Select your ${type === TaxonomyType.Tag ? 'tags' : 'categories'} to insert`, + placeHolder: l10n.t(LocalizationKey.commandsSettingsRemapSelectTaxonomyPlaceholder, taxonomy), canPickMany: false, ignoreFocusOut: true }); @@ -186,19 +194,23 @@ export class Settings { } const newOptionValue = await vscode.window.showInputBox({ - prompt: `Specify the value of the ${ - type === TaxonomyType.Tag ? 'tag' : 'category' - } with which you want to remap "${selectedOption}". Leave the input if you want to remove the ${ - type === TaxonomyType.Tag ? 'tag' : 'category' - } from all articles.`, - placeHolder: `Name of the ${type === TaxonomyType.Tag ? 'tag' : 'category'}`, + prompt: l10n.t( + LocalizationKey.commandsSettingsRemapNewOptionInputPrompt, + taxonomy, + selectedOption + ), + placeHolder: l10n.t(LocalizationKey.commandsSettingsRemapNewOptionInputPlaceholder, taxonomy), ignoreFocusOut: true }); if (!newOptionValue) { const deleteAnswer = await vscode.window.showQuickPick(['yes', 'no'], { canPickMany: false, - placeHolder: `Delete ${selectedOption} ${type === TaxonomyType.Tag ? 'tag' : 'category'}?`, + placeHolder: l10n.t( + LocalizationKey.commandsSettingsRemapDeletePlaceholder, + selectedOption, + taxonomy + ), ignoreFocusOut: true }); if (deleteAnswer === 'no') { diff --git a/src/commands/StatusListener.ts b/src/commands/StatusListener.ts index b2585957..c665eac6 100644 --- a/src/commands/StatusListener.ts +++ b/src/commands/StatusListener.ts @@ -1,6 +1,7 @@ import { ParsedFrontMatter } from './../parsers/FrontMatterParser'; import { CONTEXT, + EXTENSION_NAME, NOTIFICATION_TYPE, SETTING_SEO_DESCRIPTION_FIELD, SETTING_SEO_DESCRIPTION_LENGTH, @@ -16,6 +17,8 @@ import { DataListener } from '../listeners/panel'; import { commands } from 'vscode'; import { Field } from '../models'; import { Preview } from './Preview'; +import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../localization'; export class StatusListener { /** @@ -135,12 +138,13 @@ export class StatusListener { const diagnostic: vscode.Diagnostic = { code: '', - message: `This ${fields - .map((f) => f.name) - .join('/')} field is required to contain a value.`, + message: l10n.t( + LocalizationKey.commandsStatusListenerVerifyRequiredFieldsDiagnosticEmptyField, + fields.map((f) => f.name).join('/') + ), range: new vscode.Range(posStart, posEnd), severity: vscode.DiagnosticSeverity.Error, - source: 'Front Matter' + source: EXTENSION_NAME }; requiredDiagnostics.push(diagnostic); @@ -158,7 +162,10 @@ export class StatusListener { Notifications.showIfNotDisabled( NOTIFICATION_TYPE.requiredFieldValidation, 'ERROR_ONCE', - `The following fields are required to contain a value: ${fieldsToReport.join(', ')}` + l10n.t( + LocalizationKey.commandsStatusListenerVerifyRequiredFieldsNotificationError, + fieldsToReport.join(', ') + ) ); } } diff --git a/src/commands/Template.ts b/src/commands/Template.ts index a39e56c7..652fb4a8 100644 --- a/src/commands/Template.ts +++ b/src/commands/Template.ts @@ -16,6 +16,8 @@ import { PagesListener } from '../listeners/dashboard'; import { extname } from 'path'; import { Telemetry } from '../helpers/Telemetry'; import { writeFileAsync, copyFileAsync } from '../utils'; +import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../localization'; export class Template { /** @@ -31,27 +33,30 @@ export class Template { const clonedArticle = Object.assign({}, article); const titleValue = await vscode.window.showInputBox({ - title: `Template title`, - prompt: `What name would you like to give your template?`, - placeHolder: `article`, + title: l10n.t(LocalizationKey.commandsTemplateGenerateInputTitle), + prompt: l10n.t(LocalizationKey.commandsTemplateGenerateInputPrompt), + placeHolder: l10n.t(LocalizationKey.commandsTemplateGenerateInputPlaceholder), ignoreFocusOut: true }); if (!titleValue) { - Notifications.warning(`You did not specify a template title.`); + Notifications.warning(l10n.t(LocalizationKey.commandsTemplateGenerateNoTitleWarning)); return; } - const keepContents = await vscode.window.showQuickPick(['yes', 'no'], { - title: `Keep contents`, - canPickMany: false, - placeHolder: `Do you want to keep the contents for the template?`, - ignoreFocusOut: true - }); + const keepContents = await vscode.window.showQuickPick( + [l10n.t(LocalizationKey.commonYes), l10n.t(LocalizationKey.commonNo)], + { + title: l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsTitle), + placeHolder: l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsPlaceholder), + canPickMany: false, + ignoreFocusOut: true + } + ); if (!keepContents) { Notifications.warning( - `You did not pick any of the options for keeping the template its content.` + l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsNoOptionWarning) ); return; } @@ -60,14 +65,16 @@ export class Template { const templatePath = Project.templatePath(); if (templatePath) { const fileContents = ArticleHelper.stringifyFrontMatter( - keepContents === 'no' ? '' : clonedArticle.content, + keepContents === l10n.t(LocalizationKey.commonNo) ? '' : clonedArticle.content, clonedArticle.data ); const templateFile = path.join(templatePath.fsPath, `${titleValue}.${fileType}`); await writeFileAsync(templateFile, fileContents, { encoding: 'utf-8' }); - Notifications.info(`Template created and is now available in your ${folder} folder.`); + Notifications.info( + l10n.t(LocalizationKey.commandsTemplateGenerateKeepContentsSuccess, folder) + ); } } } @@ -79,7 +86,7 @@ export class Template { const folder = Settings.get(SETTING_TEMPLATES_FOLDER); if (!folder) { - Notifications.warning(`No templates found.`); + Notifications.warning(l10n.t(LocalizationKey.commandsTemplateGetTemplatesWarning)); return; } @@ -96,7 +103,7 @@ export class Template { const contentTypes = ContentType.getAll(); if (!folderPath) { - Notifications.warning(`Incorrect project folder path retrieved.`); + Notifications.warning(l10n.t(LocalizationKey.commandsTemplateCreateFolderPathWarning)); return; } diff --git a/src/helpers/Notifications.ts b/src/helpers/Notifications.ts index 62b07cf0..49b4fd74 100644 --- a/src/helpers/Notifications.ts +++ b/src/helpers/Notifications.ts @@ -1,8 +1,10 @@ import { SETTING_GLOBAL_NOTIFICATIONS_DISABLED } from './../constants/settings'; import { window } from 'vscode'; -import { EXTENSION_NAME, SETTING_GLOBAL_NOTIFICATIONS } from '../constants'; +import { COMMAND_NAME, EXTENSION_NAME, SETTING_GLOBAL_NOTIFICATIONS } from '../constants'; import { Logger } from './Logger'; import { Settings } from './SettingsHelper'; +import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../localization'; type NotificationType = 'INFO' | 'WARNING' | 'ERROR' | 'ERROR_ONCE'; @@ -57,6 +59,30 @@ export class Notifications { return Promise.resolve(undefined); } + /** + * Show an error notification to the user with a link to the output channel + * @param message + * @param items + * @returns + */ + public static errorWithOutput(message: string, ...items: any): Thenable { + Logger.info(`${EXTENSION_NAME}: ${message}`, 'ERROR'); + + if (this.shouldShow('ERROR')) { + return window.showErrorMessage( + `${EXTENSION_NAME}: ${message} ${l10n.t( + LocalizationKey.notificationsOutputChannelDescription, + `[${l10n.t(LocalizationKey.notificationsOutputChannelLink)}](command:${ + COMMAND_NAME.showOutputChannel + })` + )}`, + ...items + ); + } + + return Promise.resolve(undefined); + } + /** * Show an error notification to the user only once * @param message diff --git a/src/localization/localization.enum.ts b/src/localization/localization.enum.ts index 3f23a660..d89137a5 100644 --- a/src/localization/localization.enum.ts +++ b/src/localization/localization.enum.ts @@ -115,6 +115,26 @@ export enum LocalizationKey { * No results */ commonNoResults = 'common.noResults', + /** + * Sorry, something went wrong. + */ + commonError = 'common.error', + /** + * yes + */ + commonYes = 'common.yes', + /** + * no + */ + commonNo = 'common.no', + /** + * output window + */ + notificationsOutputChannelLink = 'notifications.outputChannel.link', + /** + * Check the {0} for more details. + */ + notificationsOutputChannelDescription = 'notifications.outputChannel.description', /** * Common */ @@ -1552,6 +1572,126 @@ export enum LocalizationKey { * Create folder */ commandsFoldersGetNotificationErrorCreateAction = 'commands.folders.get.notificationError.create.action', + /** + * Preview: {0} + */ + commandsPreviewPanelTitle = 'commands.preview.panel.title', + /** + * Select the folder of the article to preview + */ + commandsPreviewAskUserToPickFolderTitle = 'commands.preview.askUserToPickFolder.title', + /** + * Project initialized successfully. + */ + commandsProjectInitializeSuccess = 'commands.project.initialize.success', + /** + * To which project do you want to switch? + */ + commandsProjectSwitchProjectTitle = 'commands.project.switchProject.title', + /** + * Sample template created. + */ + commandsProjectCreateSampleTemplateInfo = 'commands.project.createSampleTemplate.info', + /** + * Insert the value of the {0} that you want to add to your configuration. + */ + commandsSettingsCreateInputPrompt = 'commands.settings.create.input.prompt', + /** + * Name of the {0} + */ + commandsSettingsCreateInputPlaceholder = 'commands.settings.create.input.placeholder', + /** + * The provided {0} already exists. + */ + commandsSettingsCreateWarning = 'commands.settings.create.warning', + /** + * Do you want to add the new {0} to the page? + */ + commandsSettingsCreateQuickPickPlaceholder = 'commands.settings.create.quickPick.placeholder', + /** + * {0}: exporting tags and categories + */ + commandsSettingsExportProgressTitle = 'commands.settings.export.progress.title', + /** + * Export completed. Tags: {0} - Categories: {1}. + */ + commandsSettingsExportProgressSuccess = 'commands.settings.export.progress.success', + /** + * Remap + */ + commandsSettingsRemapQuickpickTitle = 'commands.settings.remap.quickpick.title', + /** + * What do you want to remap? + */ + commandsSettingsRemapQuickpickPlaceholder = 'commands.settings.remap.quickpick.placeholder', + /** + * No {0} configured. + */ + commandsSettingsRemapNoTaxonomyWarning = 'commands.settings.remap.noTaxonomy.warning', + /** + * Select your {0} to insert. + */ + commandsSettingsRemapSelectTaxonomyPlaceholder = 'commands.settings.remap.selectTaxonomy.placeholder', + /** + * Specify the value of the {0} with which you want to remap "{1}". Leave the input if you want to remove the {0} from all articles. + */ + commandsSettingsRemapNewOptionInputPrompt = 'commands.settings.remap.newOption.input.prompt', + /** + * Name of the {0} + */ + commandsSettingsRemapNewOptionInputPlaceholder = 'commands.settings.remap.newOption.input.placeholder', + /** + * Delete {0} {1}? + */ + commandsSettingsRemapDeletePlaceholder = 'commands.settings.remap.delete.placeholder', + /** + * The {0} field is required. Please define a value for the field. + */ + commandsStatusListenerVerifyRequiredFieldsDiagnosticEmptyField = 'commands.statusListener.verifyRequiredFields.diagnostic.emptyField', + /** + * The following fields are required to contain a value: {0} + */ + commandsStatusListenerVerifyRequiredFieldsNotificationError = 'commands.statusListener.verifyRequiredFields.notification.error', + /** + * Template title + */ + commandsTemplateGenerateInputTitle = 'commands.template.generate.input.title', + /** + * Which name would you like to give your template? + */ + commandsTemplateGenerateInputPrompt = 'commands.template.generate.input.prompt', + /** + * article + */ + commandsTemplateGenerateInputPlaceholder = 'commands.template.generate.input.placeholder', + /** + * You did not specify a template title. + */ + commandsTemplateGenerateNoTitleWarning = 'commands.template.generate.noTitle.warning', + /** + * Keep content + */ + commandsTemplateGenerateKeepContentsTitle = 'commands.template.generate.keepContents.title', + /** + * Do you want to keep the contents for the template? + */ + commandsTemplateGenerateKeepContentsPlaceholder = 'commands.template.generate.keepContents.placeholder', + /** + * You did not pick any of the options for keeping the template its content. + */ + commandsTemplateGenerateKeepContentsNoOptionWarning = 'commands.template.generate.keepContents.noOption.warning', + /** + * Template created and is now available in your {0} folder. + */ + commandsTemplateGenerateKeepContentsSuccess = 'commands.template.generate.keepContents.success', + /** + * No templates found. + */ + commandsTemplateGetTemplatesWarning = 'commands.template.getTemplates.warning', + /** + * Incorrect project folder path retrieved. + */ + commandsTemplateCreateFolderPathWarning = 'commands.template.create.folderPath.warning', /** * Template files copied. */