diff --git a/src/Commands.ts b/src/Commands.ts index c64830d..93191b2 100644 --- a/src/Commands.ts +++ b/src/Commands.ts @@ -30,6 +30,7 @@ import { hideFolderNoteInFileExplorer, showFolderNoteInFileExplorer, } from './functions/styleFunctions'; +import { t } from './i18n'; @@ -49,7 +50,7 @@ export class Commands { regularCommands(): void { this.plugin.addCommand({ id: 'turn-into-folder-note', - name: 'Use this file as the folder note for its parent folder', + name: t('cmdUseFolderNote'), checkCallback: (checking: boolean) => { const file = this.app.workspace.getActiveFile(); if (!(file instanceof TFile)) return false; @@ -66,7 +67,7 @@ export class Commands { this.plugin.addCommand({ id: 'create-folder-note', - name: 'Make a folder with this file as its folder note', + name: t('cmdMakeFolderWithNote'), callback: async () => { const file = this.app.workspace.getActiveFile(); if (!(file instanceof TFile)) return; @@ -75,7 +76,7 @@ export class Commands { newPath = file.basename; } if (this.plugin.app.vault.getAbstractFileByPath(newPath)) { - return new Notice('Folder already exists'); + return new Notice(t('noticeFolderAlreadyExists')); } const automaticallyCreateFolderNote = this.plugin.settings.autoCreate; @@ -92,7 +93,7 @@ export class Commands { this.plugin.addCommand({ id: 'create-folder-note-for-current-folder', - name: 'Create markdown folder note for this folder', + name: t('cmdCreateMarkdownFolderNote'), checkCallback: (checking) => { const file = this.app.workspace.getActiveFile(); if (!(file instanceof TFile)) return false; @@ -108,7 +109,7 @@ export class Commands { if (fileType === 'md') return; this.plugin.addCommand({ id: `create-${fileType}-folder-note-for-current-folder`, - name: `Create ${fileType} folder note for this folder`, + name: t('cmdCreateFileTypeFolderNote', { fileType }), checkCallback: (checking) => { const file = this.app.workspace.getActiveFile(); if (!(file instanceof TFile)) return false; @@ -124,7 +125,7 @@ export class Commands { const type = fileType === 'md' ? 'markdown' : fileType; this.plugin.addCommand({ id: `create-${type}-folder-note-for-active-file-explorer-folder`, - name: `Create ${type} folder note for current active folder in file explorer`, + name: t('cmdCreateFileTypeFolderNoteForActive', { type }), checkCallback: (checking: boolean) => { const folder = getFileExplorerActiveFolder(); if (!folder) return false; @@ -143,7 +144,7 @@ export class Commands { this.plugin.addCommand({ id: 'delete-folder-note-for-current-folder', - name: 'Delete this folder\'s linked note', + name: t('cmdDeleteFolderNote'), checkCallback: (checking) => { const file = this.app.workspace.getActiveFile(); if (!(file instanceof TFile)) return false; @@ -158,7 +159,7 @@ export class Commands { this.plugin.addCommand({ id: 'delete-folder-note-of-active-file-explorer-folder', - name: 'Delete folder note of current active folder in file explorer', + name: t('cmdDeleteFolderNoteActive'), checkCallback: (checking: boolean) => { const folder = getFileExplorerActiveFolder(); if (!folder) return false; @@ -173,7 +174,7 @@ export class Commands { }); this.plugin.addCommand({ id: 'open-folder-note-for-current-folder', - name: 'Open this folder\'s linked note', + name: t('cmdOpenFolderNote'), checkCallback: (checking) => { const file = this.app.workspace.getActiveFile(); if (!(file instanceof TFile)) return false; @@ -187,7 +188,7 @@ export class Commands { }); this.plugin.addCommand({ id: 'open-folder-note-of-active-file-explorer-folder', - name: 'Open folder note of current active folder in file explorer', + name: t('cmdOpenFolderNoteActive'), checkCallback: (checking: boolean) => { const folder = getFileExplorerActiveFolder(); if (!folder) return false; @@ -203,7 +204,7 @@ export class Commands { this.plugin.addCommand({ id: 'create-folder-note-from-selected-text', - name: 'Create folder note from selection', + name: t('cmdCreateFolderNoteFromSelection'), editorCheckCallback: (checking: boolean, editor: Editor, view: MarkdownView) => { const text = editor.getSelection().trim(); const { file } = view; @@ -214,12 +215,12 @@ export class Commands { for (const char of blacklist) { if (text.includes(char)) { // eslint-disable-next-line max-len - new Notice('File name cannot contain any of the following characters: * " \\ / < > : | ?'); + new Notice(t('noticeInvalidFileName')); return false; } } if (text.endsWith('.')) { - new Notice('File name cannot end with a dot'); + new Notice(t('noticeFileNameEndDot')); return; } let folder: TAbstractFile | null; @@ -227,7 +228,7 @@ export class Commands { if (folderPath === '') { folder = this.plugin.app.vault.getAbstractFileByPath(text); if (folder instanceof TFolder) { - new Notice('Folder note already exists'); + new Notice(t('noticeFolderNoteAlreadyExists')); return false; } this.plugin.app.vault.createFolder(text); @@ -237,7 +238,7 @@ export class Commands { const folderFullPath = folderPath + '/' + text; folder = this.plugin.app.vault.getAbstractFileByPath(folderFullPath); if (folder instanceof TFolder) { - new Notice('Folder note already exists'); + new Notice(t('noticeFolderNoteAlreadyExists')); return false; } if (this.plugin.settings.storageLocation === 'parentFolder') { @@ -246,7 +247,7 @@ export class Commands { folderPath + '/' + text + this.plugin.settings.folderNoteType, ) ) { - new Notice('File already exists'); + new Notice(t('noticeFileAlreadyExists')); return false; } } @@ -303,7 +304,7 @@ export class Commands { const addFolderNoteActions = (folderMenu: Menu): void => { if (file instanceof TFile) { folderMenu.addItem((item) => { - item.setTitle('Create folder note'); + item.setTitle(t('menuCreateFolderNote')); item.setIcon('edit'); item.onClick(async () => { if (!folder) return; @@ -312,7 +313,7 @@ export class Commands { newPath = file.basename; } if (this.plugin.app.vault.getAbstractFileByPath(newPath)) { - return new Notice('Folder already exists'); + return new Notice(t('noticeFolderAlreadyExists')); } const automaticallyCreateFolderNote = this.plugin.settings.autoCreate; @@ -342,7 +343,7 @@ export class Commands { if (folder.path === '' || folder.path === '/') return; folderMenu.addItem((item) => { - item.setTitle(`Turn into folder note for ${folder?.name}`); + item.setTitle(t('menuTurnIntoFolderNote', { folderName: folder?.name ?? '' })); item.setIcon('edit'); item.onClick(() => { if (!folder || !(folder instanceof TFolder)) return; @@ -372,7 +373,7 @@ export class Commands { // }); folderMenu.addItem((item) => { - item.setTitle('Remove folder from excluded folders'); + item.setTitle(t('menuRemoveFromExcluded')); item.setIcon('trash'); item.onClick(() => { this.plugin.settings.excludeFolders = @@ -381,7 +382,7 @@ export class Commands { (excluded.path !== file.path) || excluded.detached, ); this.plugin.saveSettings(true); - new Notice('Successfully removed folder from excluded folders'); + new Notice(t('noticeRemovedFromExcluded')); }); }); @@ -390,7 +391,7 @@ export class Commands { if (detachedExcludedFolder) { folderMenu.addItem((item) => { - item.setTitle('Remove folder from detached folders'); + item.setTitle(t('menuRemoveFromDetached')); item.setIcon('trash'); item.onClick(() => { deleteExcludedFolder(this.plugin, detachedExcludedFolder); @@ -401,7 +402,7 @@ export class Commands { if (detachedExcludedFolder) { return; } folderMenu.addItem((item) => { - item.setTitle('Exclude folder from folder notes'); + item.setTitle(t('menuExcludeFromFolderNotes')); item.setIcon('x-circle'); item.onClick(() => { const newExcludedFolder = new ExcludedFolder( @@ -412,7 +413,7 @@ export class Commands { ); this.plugin.settings.excludeFolders.push(newExcludedFolder); this.plugin.saveSettings(true); - new Notice('Successfully excluded folder from folder notes'); + new Notice(t('noticeExcluded')); }); }); @@ -422,7 +423,7 @@ export class Commands { if (folderNote instanceof TFile && !detachedExcludedFolder) { folderMenu.addItem((item) => { - item.setTitle('Delete folder note'); + item.setTitle(t('menuDeleteFolderNote')); item.setIcon('trash'); item.onClick(() => { deleteFolderNote(this.plugin, folderNote, true); @@ -430,7 +431,7 @@ export class Commands { }); folderMenu.addItem((item) => { - item.setTitle('Open folder note'); + item.setTitle(t('menuOpenFolderNote')); item.setIcon('chevron-right-square'); item.onClick(() => { openFolderNote(this.plugin, folderNote); @@ -438,7 +439,7 @@ export class Commands { }); folderMenu.addItem((item) => { - item.setTitle('Detach folder note'); + item.setTitle(t('menuDetachFolderNote')); item.setIcon('unlink'); item.onClick(() => { detachFolderNote(this.plugin, folderNote); @@ -446,7 +447,7 @@ export class Commands { }); folderMenu.addItem((item) => { - item.setTitle('Copy Obsidian URL'); + item.setTitle(t('menuCopyObsidianUrl')); item.setIcon('link'); item.onClick(() => { this.app.copyObsidianUrl(folderNote); @@ -456,7 +457,7 @@ export class Commands { if (this.plugin.settings.hideFolderNote) { if (excludedFolder?.showFolderNote) { folderMenu.addItem((item) => { - item.setTitle('Hide folder note in explorer'); + item.setTitle(t('menuHideFolderNoteInExplorer')); item.setIcon('eye-off'); item.onClick(() => { hideFolderNoteInFileExplorer(file.path, this.plugin); @@ -464,7 +465,7 @@ export class Commands { }); } else { folderMenu.addItem((item) => { - item.setTitle('Show folder note in explorer'); + item.setTitle(t('menuShowFolderNoteInExplorer')); item.setIcon('eye'); item.onClick(() => { showFolderNoteInFileExplorer(file.path, this.plugin); @@ -474,7 +475,7 @@ export class Commands { } } else { folderMenu.addItem((item) => { - item.setTitle('Create markdown folder note'); + item.setTitle(t('menuCreateMarkdownFolderNote')); item.setIcon('edit'); item.onClick(() => { createFolderNote(this.plugin, file.path, true, '.md'); @@ -484,7 +485,7 @@ export class Commands { this.plugin.settings.supportedFileTypes.forEach((fileType) => { if (fileType === 'md') return; folderMenu.addItem((item) => { - item.setTitle(`Create ${fileType} folder note`); + item.setTitle(t('menuCreateFileTypeFolderNote', { fileType })); item.setIcon('edit'); item.onClick(() => { createFolderNote(this.plugin, file.path, true, '.' + fileType); @@ -500,7 +501,7 @@ export class Commands { this.plugin.settings.useSubmenus ) { menu.addItem(async (item) => { - item.setTitle('Folder Note Commands').setIcon('folder-edit'); + item.setTitle(t('menuFolderNoteCommands')).setIcon('folder-edit'); let subMenu: Menu = item.setSubmenu() as Menu; addFolderNoteActions(subMenu); }); @@ -516,7 +517,7 @@ export class Commands { const text = editor.getSelection().trim(); if (!text || text.trim() === '') return; menu.addItem((item) => { - item.setTitle('Create folder note') + item.setTitle(t('menuCreateFolderNote')) .setIcon('edit') .onClick(() => { const { file } = view; @@ -525,12 +526,12 @@ export class Commands { for (const char of blacklist) { if (text.includes(char)) { // eslint-disable-next-line max-len - new Notice('File name cannot contain any of the following characters: * " \\ / < > : | ?'); + new Notice(t('noticeInvalidFileName')); return; } } if (text.endsWith('.')) { - new Notice('File name cannot end with a dot'); + new Notice(t('noticeFileNameEndDot')); return; } @@ -541,7 +542,7 @@ export class Commands { if (folderPath === '') { folder = this.plugin.app.vault.getAbstractFileByPath(text); if (folder instanceof TFolder) { - return new Notice('Folder note already exists'); + return new Notice(t('noticeFolderNoteAlreadyExists')); } this.plugin.app.vault.createFolder(text); createFolderNote(this.plugin, text, false); @@ -551,7 +552,7 @@ export class Commands { folderPath + '/' + text, ); if (folder instanceof TFolder) { - return new Notice('Folder note already exists'); + return new Notice(t('noticeFolderNoteAlreadyExists')); } if (this.plugin.settings.storageLocation === 'parentFolder') { if ( @@ -562,7 +563,7 @@ export class Commands { this.plugin.settings.folderNoteType, ) ) { - return new Notice('File already exists'); + return new Notice(t('noticeFileAlreadyExists')); } } this.plugin.app.vault.createFolder(folderPath + '/' + text); diff --git a/src/i18n/en.ts b/src/i18n/en.ts new file mode 100644 index 0000000..4b0a240 --- /dev/null +++ b/src/i18n/en.ts @@ -0,0 +1,211 @@ +export const en = { + // Tab names + tabGeneral: 'General', + tabFolderOverview: 'Folder overview', + tabExcludeFolders: 'Exclude folders', + tabFileExplorer: 'File explorer', + tabPath: 'Path', + + // Common + requiresRestart: 'Requires a restart to take effect', + styleSettings: 'Style settings', + manage: 'Manage', + + // Language selector + language: 'Language', + languageDesc: 'Select the language for the plugin interface', + langEnglish: 'English', + langChinese: '中文', + + // GeneralSettings + folderNoteNameTemplate: 'Folder note name template', + folderNoteNameTemplateDesc: 'All folder notes will use this name. Use {{folder_name}} to insert the folder\'s name. Existing notes won\'t update automatically; click on the button to apply the new name.', + renameExistingFolderNotes: 'Rename existing folder notes', + renameAllExistingFolderNotes: 'Rename all existing folder notes', + renameConfirmMsg: 'When you click on "Confirm" all existing folder notes will be renamed to the new folder note name.', + displayFolderNameInTabTitle: 'Display Folder Name in Tab Title', + displayFolderNameInTabTitleDesc: 'Use the actual folder name in the tab title instead of the custom folder note name (e.g., "Folder Note").', + defaultFileType: 'Default file type for new folder notes', + defaultFileTypeDesc: 'Choose the default file type (canvas, markdown, ...) used when creating new folder notes.', + askForFileType: 'ask for file type', + markdown: 'markdown', + supportedFileTypes: 'Supported file types', + supportedFileTypesDesc: 'Specify which file types are allowed as folder notes. Applies to both new and existing folders. Adding many types may affect performance.', + addCustomFileType: 'Add custom file type', + customExtension: 'Custom extension', + templatePath: 'Template path', + templatePathDesc: 'Can be used with templater/templates plugin. If you add the location of the templates there.', + templatePathPlaceholder: 'Template path', + storageLocation: 'Storage location', + storageLocationDesc: 'Choose where to store the folder notes', + insideFolder: 'Inside the folder', + inParentFolder: 'In the parent folder', + switchButton: 'Switch', + switchStorageLocationTitle: 'Switch storage location', + switchStorageLocationMsg: 'When you click on "Confirm" all folder notes will be moved to the new storage location.', + deleteFolderNotesOnFolderDelete: 'Delete folder notes when deleting the folder', + deleteFolderNotesOnFolderDeleteDesc: 'Delete the folder note when deleting the folder', + moveFolderNotesOnFolderMove: 'Move folder notes when moving the folder', + moveFolderNotesOnFolderMoveDesc: 'Move the folder note file along with the folder when it is moved', + keyboardShortcuts: 'Keyboard Shortcuts', + keyForCreatingFolderNote: 'Key for creating folder note', + keyForCreatingFolderNoteDesc: 'The key combination to create a folder note', + ctrlClick: 'Ctrl + Click', + altClick: 'Alt + Click', + cmdClick: 'Cmd + Click', + optionClick: 'Option + Click', + keyForOpeningFolderNote: 'Key for opening folder note', + keyForOpeningFolderNoteDesc: 'Select the combination to open a folder note', + mouseClick: 'Mouse Click', + folderNoteBehavior: 'Folder note behavior', + confirmFolderNoteDeletion: 'Confirm folder note deletion', + confirmFolderNoteDeletionDesc: 'Ask for confirmation before deleting a folder note', + deletedFolderNotes: 'Deleted folder notes', + deletedFolderNotesDesc: 'What happens to the folder note after you delete it', + moveToSystemTrash: 'Move to system trash', + moveToObsidianTrash: 'Move to Obsidian trash (.trash folder)', + deletePermanently: 'Delete permanently', + openInNewTab: 'Open folder note in a new tab by default', + openInNewTabDesc: 'Always open folder notes in a new tab unless the note is already open in the current tab.', + focusExistingTab: 'Focus existing tab instead of creating a new one', + focusExistingTabDesc: 'If a folder note is already open in a tab, focus that tab instead of creating a new one.', + syncFolderName: 'Sync folder name', + syncFolderNameDesc: 'Automatically rename the folder note when the folder name is changed', + automationSettings: 'Automation settings', + createFolderNotesForAllFolders: 'Create folder notes for all folders', + createFolderNotesForAllFoldersDesc: 'Generate folder notes for every folder in the vault.', + autoCreateOnFolderCreation: 'Auto-create on folder creation', + autoCreateOnFolderCreationDesc: 'Automatically create a folder note whenever a new folder is added.', + autoOpenAfterCreation: 'Auto-open after creation', + autoOpenAfterCreationDesc: 'Open the folder note immediately after it\'s created automatically.', + autoCreateForAttachmentFolders: 'Auto-create for attachment folders', + autoCreateForAttachmentFoldersDesc: 'Also automatically create folder notes for attachment folders (e.g., "Attachments", "Media", etc.).', + autoCreateWhenCreatingNotes: 'Auto-create when creating notes', + autoCreateWhenCreatingNotesDesc: 'Automatically create a folder note when a regular note is created inside a folder. Works for supported file types only.', + integrationCompatibility: 'Integration & Compatibility', + enableFmtpIntegration: 'Enable front matter title plugin integration', + enableFmtpIntegrationDesc: 'Allows you to use the {link} with folder notes. It allows you to set the folder name to some name you set in the front matter.', + frontMatterTitlePlugin: 'front matter title plugin', + sessionPersistence: 'Session & Persistence', + persistTabAfterRestart: 'Persist tab after restart', + persistTabAfterRestartDesc: 'Restore the same settings tab after restarting Obsidian.', + persistTabDuringSession: 'Persist tab during session only', + persistTabDuringSessionDesc: 'Keep the current settings tab open during the session, but reset it after a restart or reload.', + + // FileExplorerSettings + hideFolderNote: 'Hide folder note', + hideFolderNoteDesc: 'Hide the folder note file from appearing in the file explorer', + disableClickToOpenOnMobile: 'Disable click-to-open folder note on mobile', + disableClickToOpenOnMobileDesc: 'Prevents folder notes from opening when tapping the folder name or surrounding area on mobile devices. They can now only be opened via the context menu or a command.', + openByClickingFolderNameOnly: 'Open folder notes by only clicking directly on the folder name', + openByClickingFolderNameOnlyDesc: 'Only allow folder notes to open when clicking directly on the folder name in the file explorer', + disableFolderCollapsing: 'Disable folder collapsing', + disableFolderCollapsingDesc: 'When enabled, folders in the file explorer will only collapse when clicking the collapse icon next to the folder name, not when clicking near a folder name when it has a folder note.', + useSubmenus: 'Use submenus', + useSubmenusDesc: 'Use submenus for file/folder commands', + autoUpdateFolderNameInExplorer: 'Auto update folder name in the file explorer (front matter title plugin only)', + autoUpdateFolderNameInExplorerDesc: 'Automatically update the folder name in the file explorer when the front matter title plugin is enabled and the title for a folder note is changed in the front matter. This will not change the file name, only the displayed name in the file explorer.', + highlightFolder: 'Highlight folder in the file explorer', + highlightFolderDesc: 'Highlight the folder in the file explorer when it has a folder note and the folder note is open in the editor', + hideCollapseIcon: 'Hide collapse icon', + hideCollapseIconDesc: 'Hide the collapse icon in the file explorer next to the name of a folder when a folder only contains a folder note', + hideCollapseIconForEmptyFolders: 'Hide collapse icon for every empty folder', + hideCollapseIconForEmptyFoldersDesc: 'Hide the collapse icon in the file explorer next to the name of a folder when a folder is empty', + hideCollapseIconForAttachmentFolder: 'Hide collapse icon also when only the attachment folder is in the same folder', + underlineFolderNote: 'Underline the name of folder notes', + underlineFolderNoteDesc: 'Add an underline to folders that have a folder note in the file explorer', + boldFolderNote: 'Bold the name of folder notes', + boldFolderNoteDesc: 'Make the folder name bold in the file explorer when it has a folder note', + cursiveFolderNote: 'Cursive the name of folder notes', + cursiveFolderNoteDesc: 'Make the folder name cursive in the file explorer when it has a folder note', + + // PathSettings + openFolderNoteThroughPath: 'Open folder note through path', + openFolderNoteThroughPathDesc: 'Open a folder note when clicking on a folder name in the path if it is a folder note', + openSidebarMobile: 'Open sidebar when opening a folder note through path (Mobile only)', + openSidebarMobileDesc: 'Open the sidebar when opening a folder note through the path on mobile', + openSidebarDesktop: 'Open sidebar when opening a folder note through path (Desktop only)', + openSidebarDesktopDesc: 'Open the sidebar when opening a folder note through the path on desktop', + autoUpdateFolderNameInPath: 'Auto update folder name in the path (front matter title plugin only)', + autoUpdateFolderNameInPathDesc: 'Automatically update the folder name in the path when the front matter title plugin is enabled and the title for a folder note is changed in the front matter. This will not change the file name, only the displayed name in the path.', + underlineFoldersInPath: 'Underline folders in the path', + underlineFoldersInPathDesc: 'Add an underline to folders that have a folder note in the path above a note', + boldFoldersInPath: 'Bold folders in the path', + boldFoldersInPathDesc: 'Make the folder name bold in the path above a note when it has a folder note', + cursiveFoldersInPath: 'Cursive the name of folder notes in the path', + cursiveFoldersInPathDesc: 'Make the folder name cursive in the path above a note when it has a folder note', + hideFolderNoteNameInPath: 'Hide folder note name in the path', + hideFolderNoteNameInPathDesc: 'Only show the folder name in the path and hide the folder note name.', + + // ExcludedFoldersSettings + manageExcludedFolders: 'Manage excluded folders', + manageExcludedFoldersDesc1: 'Add {regex} at the beginning of the folder name to use a regex pattern.', + manageExcludedFoldersDesc2: 'Use * before and after to exclude folders that include the name between the *s.', + manageExcludedFoldersDesc3: 'Use * before the folder name to exclude folders that end with the folder name.', + manageExcludedFoldersDesc4: 'Use * after the folder name to exclude folders that start with the folder name.', + excludedFoldersInfo1: 'The regexes and wildcards are only for the folder name, not the path.', + excludedFoldersInfo2: 'If you want to switch to a folder path delete the pattern first.', + whitelistedFolders: 'Whitelisted folders', + whitelistedFoldersDesc: 'Folders that override the excluded folders/patterns', + excludeFolderDefaultSettings: 'Exclude folder default settings', + excludePatternDefaultSettings: 'Exclude pattern default settings', + addExcludedFolder: 'Add excluded folder', + + // FolderOverviewSettings + globalSettings: 'Global settings', + autoUpdateLinks: 'Auto-update links without opening the overview', + autoUpdateLinksDesc: 'If enabled, the links that appear in the graph view will be updated even when you don\'t have the overview open somewhere.', + overviewDefaultSettings: 'Overviews default settings', + overviewDefaultSettingsDesc: 'Edit the default settings for new folder overviews, ', + overviewDefaultSettingsSpan: 'this won\'t apply to already existing overviews.', + + // SettingsTab notices + startingUpdateFolderNotes: 'Starting to update folder notes...', + finishedUpdatingFolderNotes: 'Finished updating folder notes', + startingSwitchStorageLocation: 'Starting to switch storage location...', + finishedSwitchingStorageLocation: 'Finished switching storage location', + + // Commands + cmdUseFolderNote: 'Use this file as the folder note for its parent folder', + cmdMakeFolderWithNote: 'Make a folder with this file as its folder note', + cmdCreateMarkdownFolderNote: 'Create markdown folder note for this folder', + cmdCreateFileTypeFolderNote: 'Create {fileType} folder note for this folder', + cmdCreateFileTypeFolderNoteForActive: 'Create {type} folder note for current active folder in file explorer', + cmdDeleteFolderNote: 'Delete this folder\'s linked note', + cmdDeleteFolderNoteActive: 'Delete folder note of current active folder in file explorer', + cmdOpenFolderNote: 'Open this folder\'s linked note', + cmdOpenFolderNoteActive: 'Open folder note of current active folder in file explorer', + cmdCreateFolderNoteFromSelection: 'Create folder note from selection', + noticeFolderAlreadyExists: 'Folder already exists', + noticeInvalidFileName: 'File name cannot contain any of the following characters: * " \\ / < > : | ?', + noticeFileNameEndDot: 'File name cannot end with a dot', + noticeFolderNoteAlreadyExists: 'Folder note already exists', + noticeFileAlreadyExists: 'File already exists', + menuCreateFolderNote: 'Create folder note', + menuTurnIntoFolderNote: 'Turn into folder note for {folderName}', + menuRemoveFromExcluded: 'Remove folder from excluded folders', + noticeRemovedFromExcluded: 'Successfully removed folder from excluded folders', + menuRemoveFromDetached: 'Remove folder from detached folders', + menuExcludeFromFolderNotes: 'Exclude folder from folder notes', + noticeExcluded: 'Successfully excluded folder from folder notes', + menuDeleteFolderNote: 'Delete folder note', + menuOpenFolderNote: 'Open folder note', + menuDetachFolderNote: 'Detach folder note', + menuCopyObsidianUrl: 'Copy Obsidian URL', + menuHideFolderNoteInExplorer: 'Hide folder note in explorer', + menuShowFolderNoteInExplorer: 'Show folder note in explorer', + menuCreateMarkdownFolderNote: 'Create markdown folder note', + menuCreateFileTypeFolderNote: 'Create {fileType} folder note', + menuFolderNoteCommands: 'Folder Note Commands', + + // DeleteConfirmation modal + deleteFolderNoteTitle: 'Delete folder note', + deleteConfirmMsg: 'Are you sure you want to delete the folder note \'{fileName}\' ?', + willMoveToSystemTrash: 'It will be moved to your system trash.', + willMoveToObsidianTrash: 'It will be moved to your Obsidian trash, which is located in the ".trash" hidden folder in your vault.', + willBeDeleted: 'It will be permanently deleted.', + dontAskAgain: 'Don\'t ask again', + deleteAndDontAsk: 'Delete and don\'t ask again', + delete: 'Delete', + cancel: 'Cancel', +} as const; diff --git a/src/i18n/index.ts b/src/i18n/index.ts new file mode 100644 index 0000000..7b36987 --- /dev/null +++ b/src/i18n/index.ts @@ -0,0 +1,28 @@ +import { en } from './en'; +import { zh } from './zh'; + +export type TranslationKey = keyof typeof en; + +type Translations = { [K in TranslationKey]: string }; + +const translations: Record = { + en: en as Translations, + zh: zh as Translations, +}; + +let currentLang = 'en'; + +export function setLanguage(lang: string): void { + currentLang = lang; +} + +export function t(key: TranslationKey, vars?: Record): string { + const langMap = translations[currentLang] ?? translations['en']; + let str: string = langMap[key] ?? (translations['en'][key] as string) ?? key; + if (vars) { + for (const [k, v] of Object.entries(vars)) { + str = str.replace(`{${k}}`, v); + } + } + return str; +} diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts new file mode 100644 index 0000000..8348ebf --- /dev/null +++ b/src/i18n/zh.ts @@ -0,0 +1,211 @@ +export const zh = { + // Tab names + tabGeneral: '常规', + tabFolderOverview: '文件夹概览', + tabExcludeFolders: '排除文件夹', + tabFileExplorer: '文件资源管理器', + tabPath: '路径', + + // Common + requiresRestart: '需要重启才能生效', + styleSettings: '样式设置', + manage: '管理', + + // Language selector + language: '语言', + languageDesc: '选择插件界面语言', + langEnglish: 'English', + langChinese: '中文', + + // GeneralSettings + folderNoteNameTemplate: '文件夹笔记名称模板', + folderNoteNameTemplateDesc: '所有文件夹笔记将使用此名称。使用 {{folder_name}} 插入文件夹名称。现有笔记不会自动更新,请点击按钮应用新名称。', + renameExistingFolderNotes: '重命名现有文件夹笔记', + renameAllExistingFolderNotes: '重命名所有现有文件夹笔记', + renameConfirmMsg: '点击"确认"后,所有现有文件夹笔记将被重命名为新的文件夹笔记名称。', + displayFolderNameInTabTitle: '在标签页标题中显示文件夹名称', + displayFolderNameInTabTitleDesc: '在标签页标题中使用实际文件夹名称,而非自定义文件夹笔记名称(如"Folder Note")。', + defaultFileType: '新文件夹笔记的默认文件类型', + defaultFileTypeDesc: '选择创建新文件夹笔记时使用的默认文件类型(Canvas、Markdown 等)。', + askForFileType: '每次询问文件类型', + markdown: 'Markdown', + supportedFileTypes: '支持的文件类型', + supportedFileTypesDesc: '指定允许作为文件夹笔记的文件类型。适用于新建和现有文件夹。添加过多类型可能影响性能。', + addCustomFileType: '添加自定义文件类型', + customExtension: '自定义扩展名', + templatePath: '模板路径', + templatePathDesc: '可与 Templater/Templates 插件配合使用。在此处添加模板的位置。', + templatePathPlaceholder: '模板路径', + storageLocation: '存储位置', + storageLocationDesc: '选择文件夹笔记的存储位置', + insideFolder: '文件夹内部', + inParentFolder: '父文件夹中', + switchButton: '切换', + switchStorageLocationTitle: '切换存储位置', + switchStorageLocationMsg: '点击"确认"后,所有文件夹笔记将被移动到新的存储位置。', + deleteFolderNotesOnFolderDelete: '删除文件夹时同步删除文件夹笔记', + deleteFolderNotesOnFolderDeleteDesc: '删除文件夹时同时删除对应的文件夹笔记', + moveFolderNotesOnFolderMove: '移动文件夹时同步移动文件夹笔记', + moveFolderNotesOnFolderMoveDesc: '移动文件夹时同时移动对应的文件夹笔记文件', + keyboardShortcuts: '键盘快捷键', + keyForCreatingFolderNote: '创建文件夹笔记的快捷键', + keyForCreatingFolderNoteDesc: '创建文件夹笔记的按键组合', + ctrlClick: 'Ctrl + 单击', + altClick: 'Alt + 单击', + cmdClick: 'Cmd + 单击', + optionClick: 'Option + 单击', + keyForOpeningFolderNote: '打开文件夹笔记的快捷键', + keyForOpeningFolderNoteDesc: '选择打开文件夹笔记的按键组合', + mouseClick: '鼠标单击', + folderNoteBehavior: '文件夹笔记行为', + confirmFolderNoteDeletion: '确认文件夹笔记删除', + confirmFolderNoteDeletionDesc: '删除文件夹笔记前询问确认', + deletedFolderNotes: '已删除的文件夹笔记', + deletedFolderNotesDesc: '删除文件夹笔记后的处理方式', + moveToSystemTrash: '移至系统回收站', + moveToObsidianTrash: '移至 Obsidian 回收站(.trash 文件夹)', + deletePermanently: '永久删除', + openInNewTab: '默认在新标签页中打开文件夹笔记', + openInNewTabDesc: '始终在新标签页中打开文件夹笔记,除非该笔记已在当前标签页中打开。', + focusExistingTab: '聚焦已有标签页而非创建新标签页', + focusExistingTabDesc: '如果文件夹笔记已在某个标签页中打开,则聚焦该标签页而非创建新标签页。', + syncFolderName: '同步文件夹名称', + syncFolderNameDesc: '文件夹名称更改时自动重命名文件夹笔记', + automationSettings: '自动化设置', + createFolderNotesForAllFolders: '为所有文件夹创建文件夹笔记', + createFolderNotesForAllFoldersDesc: '为仓库中的每个文件夹生成文件夹笔记。', + autoCreateOnFolderCreation: '创建文件夹时自动创建笔记', + autoCreateOnFolderCreationDesc: '每次添加新文件夹时自动创建文件夹笔记。', + autoOpenAfterCreation: '创建后自动打开', + autoOpenAfterCreationDesc: '自动创建文件夹笔记后立即打开该笔记。', + autoCreateForAttachmentFolders: '为附件文件夹自动创建', + autoCreateForAttachmentFoldersDesc: '同时为附件文件夹(如"Attachments"、"Media"等)自动创建文件夹笔记。', + autoCreateWhenCreatingNotes: '创建笔记时自动创建文件夹笔记', + autoCreateWhenCreatingNotesDesc: '在文件夹内创建普通笔记时自动创建文件夹笔记。仅适用于支持的文件类型。', + integrationCompatibility: '集成与兼容', + enableFmtpIntegration: '启用 Front Matter Title 插件集成', + enableFmtpIntegrationDesc: '允许将 {link} 与文件夹笔记配合使用,可将文件夹名称设置为 Front Matter 中指定的名称。', + frontMatterTitlePlugin: 'Front Matter Title 插件', + sessionPersistence: '会话与持久化', + persistTabAfterRestart: '重启后保留标签页', + persistTabAfterRestartDesc: '重启 Obsidian 后恢复到相同的设置标签页。', + persistTabDuringSession: '仅在会话期间保留标签页', + persistTabDuringSessionDesc: '在会话期间保持当前设置标签页打开,但重启或重新加载后重置。', + + // FileExplorerSettings + hideFolderNote: '隐藏文件夹笔记', + hideFolderNoteDesc: '在文件资源管理器中隐藏文件夹笔记文件', + disableClickToOpenOnMobile: '在移动端禁用点击打开文件夹笔记', + disableClickToOpenOnMobileDesc: '防止在移动设备上通过点击文件夹名称或周围区域打开文件夹笔记。只能通过右键菜单或命令打开。', + openByClickingFolderNameOnly: '仅通过直接点击文件夹名称打开文件夹笔记', + openByClickingFolderNameOnlyDesc: '只允许在文件资源管理器中直接点击文件夹名称时打开文件夹笔记', + disableFolderCollapsing: '禁用文件夹折叠', + disableFolderCollapsingDesc: '启用后,文件资源管理器中的文件夹只有点击折叠图标时才会折叠,而不是在有文件夹笔记的情况下点击文件夹名称附近。', + useSubmenus: '使用子菜单', + useSubmenusDesc: '为文件/文件夹命令使用子菜单', + autoUpdateFolderNameInExplorer: '自动更新文件资源管理器中的文件夹名称(仅限 Front Matter Title 插件)', + autoUpdateFolderNameInExplorerDesc: '启用 Front Matter Title 插件后,当 Front Matter 中的文件夹笔记标题更改时,自动更新文件资源管理器中的文件夹名称。这不会更改文件名,只更改资源管理器中显示的名称。', + highlightFolder: '在文件资源管理器中高亮显示文件夹', + highlightFolderDesc: '当文件夹有文件夹笔记且该笔记在编辑器中打开时,在文件资源管理器中高亮显示该文件夹', + hideCollapseIcon: '隐藏折叠图标', + hideCollapseIconDesc: '当文件夹只包含文件夹笔记时,隐藏文件资源管理器中文件夹名称旁边的折叠图标', + hideCollapseIconForEmptyFolders: '为每个空文件夹隐藏折叠图标', + hideCollapseIconForEmptyFoldersDesc: '当文件夹为空时,隐藏文件资源管理器中文件夹名称旁边的折叠图标', + hideCollapseIconForAttachmentFolder: '当同文件夹中只有附件文件夹时也隐藏折叠图标', + underlineFolderNote: '为文件夹笔记名称添加下划线', + underlineFolderNoteDesc: '在文件资源管理器中为有文件夹笔记的文件夹添加下划线', + boldFolderNote: '加粗文件夹笔记名称', + boldFolderNoteDesc: '在文件资源管理器中有文件夹笔记时将文件夹名称加粗显示', + cursiveFolderNote: '斜体显示文件夹笔记名称', + cursiveFolderNoteDesc: '在文件资源管理器中有文件夹笔记时将文件夹名称斜体显示', + + // PathSettings + openFolderNoteThroughPath: '通过路径打开文件夹笔记', + openFolderNoteThroughPathDesc: '点击路径中的文件夹名称时,如果它是文件夹笔记则打开该笔记', + openSidebarMobile: '通过路径打开文件夹笔记时打开侧边栏(仅限移动端)', + openSidebarMobileDesc: '在移动端通过路径打开文件夹笔记时打开侧边栏', + openSidebarDesktop: '通过路径打开文件夹笔记时打开侧边栏(仅限桌面端)', + openSidebarDesktopDesc: '在桌面端通过路径打开文件夹笔记时打开侧边栏', + autoUpdateFolderNameInPath: '自动更新路径中的文件夹名称(仅限 Front Matter Title 插件)', + autoUpdateFolderNameInPathDesc: '启用 Front Matter Title 插件后,当 Front Matter 中的文件夹笔记标题更改时,自动更新路径中的文件夹名称。这不会更改文件名,只更改路径中显示的名称。', + underlineFoldersInPath: '为路径中的文件夹添加下划线', + underlineFoldersInPathDesc: '为笔记上方路径中有文件夹笔记的文件夹添加下划线', + boldFoldersInPath: '加粗路径中的文件夹', + boldFoldersInPathDesc: '笔记上方路径中有文件夹笔记时将文件夹名称加粗显示', + cursiveFoldersInPath: '斜体显示路径中的文件夹笔记名称', + cursiveFoldersInPathDesc: '笔记上方路径中有文件夹笔记时将文件夹名称斜体显示', + hideFolderNoteNameInPath: '在路径中隐藏文件夹笔记名称', + hideFolderNoteNameInPathDesc: '仅在路径中显示文件夹名称,隐藏文件夹笔记名称。', + + // ExcludedFoldersSettings + manageExcludedFolders: '管理排除的文件夹', + manageExcludedFoldersDesc1: '在文件夹名称开头添加 {regex} 以使用正则表达式模式。', + manageExcludedFoldersDesc2: '在名称前后使用 * 排除包含 * 之间名称的文件夹。', + manageExcludedFoldersDesc3: '在文件夹名称前使用 * 排除以该名称结尾的文件夹。', + manageExcludedFoldersDesc4: '在文件夹名称后使用 * 排除以该名称开头的文件夹。', + excludedFoldersInfo1: '正则表达式和通配符仅适用于文件夹名称,不适用于路径。', + excludedFoldersInfo2: '如需切换到文件夹路径,请先删除该模式。', + whitelistedFolders: '白名单文件夹', + whitelistedFoldersDesc: '可覆盖排除文件夹/模式的文件夹', + excludeFolderDefaultSettings: '排除文件夹默认设置', + excludePatternDefaultSettings: '排除模式默认设置', + addExcludedFolder: '添加排除文件夹', + + // FolderOverviewSettings + globalSettings: '全局设置', + autoUpdateLinks: '不打开概览也自动更新链接', + autoUpdateLinksDesc: '启用后,即使没有在任何地方打开概览,图谱视图中显示的链接也会自动更新。', + overviewDefaultSettings: '概览默认设置', + overviewDefaultSettingsDesc: '编辑新文件夹概览的默认设置,', + overviewDefaultSettingsSpan: '这不会应用到已有的概览。', + + // SettingsTab notices + startingUpdateFolderNotes: '开始更新文件夹笔记...', + finishedUpdatingFolderNotes: '文件夹笔记更新完成', + startingSwitchStorageLocation: '开始切换存储位置...', + finishedSwitchingStorageLocation: '存储位置切换完成', + + // Commands + cmdUseFolderNote: '将此文件用作父文件夹的文件夹笔记', + cmdMakeFolderWithNote: '以此文件为笔记创建文件夹', + cmdCreateMarkdownFolderNote: '为此文件夹创建 Markdown 文件夹笔记', + cmdCreateFileTypeFolderNote: '为此文件夹创建 {fileType} 文件夹笔记', + cmdCreateFileTypeFolderNoteForActive: '为文件资源管理器中当前活动文件夹创建 {type} 文件夹笔记', + cmdDeleteFolderNote: '删除此文件夹的关联笔记', + cmdDeleteFolderNoteActive: '删除文件资源管理器中当前活动文件夹的文件夹笔记', + cmdOpenFolderNote: '打开此文件夹的关联笔记', + cmdOpenFolderNoteActive: '打开文件资源管理器中当前活动文件夹的文件夹笔记', + cmdCreateFolderNoteFromSelection: '从选中文字创建文件夹笔记', + noticeFolderAlreadyExists: '文件夹已存在', + noticeInvalidFileName: '文件名不能包含以下字符:* " \\ / < > : | ?', + noticeFileNameEndDot: '文件名不能以点结尾', + noticeFolderNoteAlreadyExists: '文件夹笔记已存在', + noticeFileAlreadyExists: '文件已存在', + menuCreateFolderNote: '创建文件夹笔记', + menuTurnIntoFolderNote: '设为 {folderName} 的文件夹笔记', + menuRemoveFromExcluded: '从排除文件夹中移除', + noticeRemovedFromExcluded: '已成功从排除文件夹中移除', + menuRemoveFromDetached: '从分离文件夹中移除', + menuExcludeFromFolderNotes: '将文件夹排除出文件夹笔记', + noticeExcluded: '已成功将文件夹排除出文件夹笔记', + menuDeleteFolderNote: '删除文件夹笔记', + menuOpenFolderNote: '打开文件夹笔记', + menuDetachFolderNote: '分离文件夹笔记', + menuCopyObsidianUrl: '复制 Obsidian URL', + menuHideFolderNoteInExplorer: '在资源管理器中隐藏文件夹笔记', + menuShowFolderNoteInExplorer: '在资源管理器中显示文件夹笔记', + menuCreateMarkdownFolderNote: '创建 Markdown 文件夹笔记', + menuCreateFileTypeFolderNote: '创建 {fileType} 文件夹笔记', + menuFolderNoteCommands: '文件夹笔记命令', + + // DeleteConfirmation modal + deleteFolderNoteTitle: '删除文件夹笔记', + deleteConfirmMsg: '确定要删除文件夹笔记"{fileName}"吗?', + willMoveToSystemTrash: '它将被移至系统回收站。', + willMoveToObsidianTrash: '它将被移至 Obsidian 回收站(仓库中的".trash"隐藏文件夹)。', + willBeDeleted: '它将被永久删除。', + dontAskAgain: '不再询问', + deleteAndDontAsk: '删除且不再询问', + delete: '删除', + cancel: '取消', +} as const; diff --git a/src/main.ts b/src/main.ts index 4e4b23c..6f76ec0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,6 +9,7 @@ import { import { type FolderNotesSettings, DEFAULT_SETTINGS, SettingsTab, } from './settings/SettingsTab'; +import { setLanguage } from './i18n'; import { Commands } from './Commands'; import type { FileExplorerWorkspaceLeaf } from './globals'; import { @@ -53,6 +54,7 @@ export default class FolderNotesPlugin extends Plugin { async onload(): Promise { console.log('loading folder notes plugin'); await this.loadSettings(); + setLanguage(this.settings.language ?? 'en'); this.settingsTab = new SettingsTab(this.app, this); this.addSettingTab(this.settingsTab); this.saveSettings(); diff --git a/src/modals/DeleteConfirmation.ts b/src/modals/DeleteConfirmation.ts index ac857b6..5946293 100644 --- a/src/modals/DeleteConfirmation.ts +++ b/src/modals/DeleteConfirmation.ts @@ -1,6 +1,8 @@ import { Modal, Platform, type App, type TFile } from 'obsidian'; import type FolderNotesPlugin from '../main'; import { deleteFolderNote } from 'src/functions/folderNoteFunctions'; +import { t } from '../i18n'; + export default class DeleteConfirmationModal extends Modal { plugin: FolderNotesPlugin; app: App; @@ -15,20 +17,20 @@ export default class DeleteConfirmationModal extends Modal { const { contentEl, plugin } = this; const modalTitle = contentEl.createDiv({ cls: 'fn-modal-title' }); const modalContent = contentEl.createDiv({ cls: 'fn-modal-content' }); - modalTitle.createEl('h2', { text: 'Delete folder note' }); + modalTitle.createEl('h2', { text: t('deleteFolderNoteTitle') }); // eslint-disable-next-line max-len - modalContent.createEl('p', { text: `Are you sure you want to delete the folder note '${this.file.name}' ?` }); + modalContent.createEl('p', { text: t('deleteConfirmMsg', { fileName: this.file.name }) }); switch (plugin.settings.deleteFilesAction) { case 'trash': - modalContent.createEl('p', { text: 'It will be moved to your system trash.' }); + modalContent.createEl('p', { text: t('willMoveToSystemTrash') }); break; case 'obsidianTrash': // eslint-disable-next-line max-len - modalContent.createEl('p', { text: 'It will be moved to your Obsidian trash, which is located in the ".trash" hidden folder in your vault.' }); + modalContent.createEl('p', { text: t('willMoveToObsidianTrash') }); break; case 'delete': modalContent - .createEl('p', { text: 'It will be permanently deleted.' }) + .createEl('p', { text: t('willBeDeleted') }) .setCssStyles({ color: 'red' }); break; } @@ -39,7 +41,7 @@ export default class DeleteConfirmationModal extends Modal { const checkbox = buttonContainer.createEl('label', { cls: 'mod-checkbox' }); checkbox.tabIndex = -1; const input = checkbox.createEl('input', { type: 'checkbox' }); - checkbox.appendText('Don\'t ask again'); + checkbox.appendText(t('dontAskAgain')); input.addEventListener('change', (e) => { const target = e.target as HTMLInputElement; if (target.checked) { @@ -51,7 +53,7 @@ export default class DeleteConfirmationModal extends Modal { }); } else { const confirmButton = buttonContainer.createEl('button', { - text: 'Delete and don\'t ask again', + text: t('deleteAndDontAsk'), cls: 'mod-destructive', }); confirmButton.addEventListener('click', async () => { @@ -63,7 +65,7 @@ export default class DeleteConfirmationModal extends Modal { } const deleteButton = buttonContainer.createEl('button', { - text: 'Delete', + text: t('delete'), cls: 'mod-warning', }); deleteButton.addEventListener('click', async () => { @@ -73,7 +75,7 @@ export default class DeleteConfirmationModal extends Modal { deleteButton.focus(); const cancelButton = buttonContainer.createEl('button', { - text: 'Cancel', + text: t('cancel'), cls: 'mod-cancel', }); cancelButton.addEventListener('click', async () => { diff --git a/src/settings/ExcludedFoldersSettings.ts b/src/settings/ExcludedFoldersSettings.ts index 55e5c7e..fcd0251 100644 --- a/src/settings/ExcludedFoldersSettings.ts +++ b/src/settings/ExcludedFoldersSettings.ts @@ -9,6 +9,7 @@ import type { SettingsTab } from './SettingsTab'; import ExcludedFolderSettings from 'src/ExcludeFolders/modals/ExcludeFolderSettings'; import PatternSettings from 'src/ExcludeFolders/modals/PatternSettings'; import WhitelistedFoldersSettings from 'src/ExcludeFolders/modals/WhitelistedFoldersSettings'; +import { t } from '../i18n'; // import ExcludedFoldersWhitelist from 'src/ExcludeFolders/modals/WhitelistModal'; export async function renderExcludeFolders(settingsTab: SettingsTab): Promise { @@ -16,32 +17,32 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise { - cb.setButtonText('Manage'); + cb.setButtonText(t('manage')); cb.setCta(); cb.onClick(async () => { new WhitelistedFoldersSettings(settingsTab).open(); @@ -49,9 +50,9 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise { - cb.setButtonText('Manage'); + cb.setButtonText(t('manage')); cb.setCta(); cb.onClick(async () => { new ExcludedFolderSettings( @@ -63,9 +64,9 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise { - cb.setButtonText('Manage'); + cb.setButtonText(t('manage')); cb.setCta(); cb.onClick(async () => { new PatternSettings( @@ -78,12 +79,12 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise { cb.setIcon('plus'); cb.setClass('add-exclude-folder'); - cb.setTooltip('Add excluded folder'); + cb.setTooltip(t('addExcludedFolder')); cb.onClick(() => { const excludedFolder = new ExcludedFolder( '', diff --git a/src/settings/FileExplorerSettings.ts b/src/settings/FileExplorerSettings.ts index 906dcfa..ac6c12c 100644 --- a/src/settings/FileExplorerSettings.ts +++ b/src/settings/FileExplorerSettings.ts @@ -1,12 +1,14 @@ /* eslint-disable max-len */ import { Setting } from 'obsidian'; import type { SettingsTab } from './SettingsTab'; +import { t } from '../i18n'; + export async function renderFileExplorer(settingsTab: SettingsTab): Promise { const containerEl = settingsTab.settingsPage; new Setting(containerEl) - .setName('Hide folder note') - .setDesc('Hide the folder note file from appearing in the file explorer') + .setName(t('hideFolderNote')) + .setDesc(t('hideFolderNoteDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.hideFolderNote) @@ -23,8 +25,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.disableOpenFolderNoteOnClick) @@ -34,13 +36,13 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(!settingsTab.plugin.settings.stopWhitespaceCollapsing) @@ -56,8 +58,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(!settingsTab.plugin.settings.enableCollapsing) @@ -66,13 +68,13 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.useSubmenus) @@ -85,8 +87,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.frontMatterTitle.explorer) @@ -108,11 +110,11 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.highlightFolder) @@ -128,8 +130,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.hideCollapsingIcon) @@ -146,8 +148,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.hideCollapsingIconForEmptyFolders) @@ -165,7 +167,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.ignoreAttachmentFolder) @@ -182,8 +184,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.underlineFolder) @@ -199,8 +201,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.boldName) @@ -216,8 +218,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise toggle .setValue(settingsTab.plugin.settings.cursiveName) diff --git a/src/settings/FolderOverviewSettings.ts b/src/settings/FolderOverviewSettings.ts index de253e3..5b4febf 100644 --- a/src/settings/FolderOverviewSettings.ts +++ b/src/settings/FolderOverviewSettings.ts @@ -1,17 +1,18 @@ import { Setting } from 'obsidian'; import type { SettingsTab } from './SettingsTab'; import { createOverviewSettings } from 'src/obsidian-folder-overview/src/settings'; +import { t } from '../i18n'; export async function renderFolderOverview(settingsTab: SettingsTab): Promise { const { plugin } = settingsTab; const defaultOverviewSettings = plugin.settings.defaultOverview; const containerEl = settingsTab.settingsPage; - containerEl.createEl('h3', { text: 'Global settings' }); + containerEl.createEl('h3', { text: t('globalSettings') }); new Setting(containerEl) - .setName('Auto-update links without opening the overview') + .setName(t('autoUpdateLinks')) // eslint-disable-next-line max-len - .setDesc('If enabled, the links that appear in the graph view will be updated even when you don\'t have the overview open somewhere.') + .setDesc(t('autoUpdateLinksDesc')) .addToggle((toggle) => toggle .setValue(plugin.settings.fvGlobalSettings.autoUpdateLinks) @@ -26,12 +27,12 @@ export async function renderFolderOverview(settingsTab: SettingsTab): Promise { const containerEl = settingsTab.settingsPage; + + // Language selector + new Setting(containerEl) + .setName(t('language')) + .setDesc(t('languageDesc')) + .addDropdown((dropdown) => { + dropdown.addOption('en', t('langEnglish')); + dropdown.addOption('zh', t('langChinese')); + dropdown.setValue(settingsTab.plugin.settings.language ?? 'en'); + dropdown.onChange(async (value) => { + settingsTab.plugin.settings.language = value; + await settingsTab.plugin.saveSettings(); + setLanguage(value); + settingsTab.display(); + }); + }); + const nameSetting = new Setting(containerEl) - .setName('Folder note name template') - .setDesc('All folder notes will use this name. Use {{folder_name}} to insert the folder’s name. Existing notes won’t update automatically; click on the button to apply the new name.') + .setName(t('folderNoteNameTemplate')) + .setDesc(t('folderNoteNameTemplateDesc')) .addText((text) => text .setValue(settingsTab.plugin.settings.folderNoteName) @@ -45,25 +63,25 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ) .addButton((button) => button - .setButtonText('Rename existing folder notes') + .setButtonText(t('renameExistingFolderNotes')) .setCta() .onClick(async () => { new RenameFolderNotesModal( settingsTab.plugin, - 'Rename all existing folder notes', - 'When you click on "Confirm" all existing folder notes will be renamed to the new folder note name.', + t('renameAllExistingFolderNotes'), + t('renameConfirmMsg'), settingsTab.renameFolderNotes, []) .open(); }), ); - nameSetting.infoEl.appendText('Requires a restart to take effect'); + nameSetting.infoEl.appendText(t('requiresRestart')); nameSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; if (!settingsTab.plugin.settings.folderNoteName.includes('{{folder_name}}')) { new Setting(containerEl) - .setName('Display Folder Name in Tab Title') - .setDesc('Use the actual folder name in the tab title instead of the custom folder note name (e.g., "Folder Note").') + .setName(t('displayFolderNameInTabTitle')) + .setDesc(t('displayFolderNameInTabTitleDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.tabManagerEnabled) @@ -82,13 +100,13 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { } new Setting(containerEl) - .setName('Default file type for new folder notes') - .setDesc('Choose the default file type (canvas, markdown, ...) used when creating new folder notes.') + .setName(t('defaultFileType')) + .setDesc(t('defaultFileTypeDesc')) .addDropdown((dropdown) => { - dropdown.addOption('.ask', 'ask for file type'); + dropdown.addOption('.ask', t('askForFileType')); settingsTab.plugin.settings.supportedFileTypes.forEach((type) => { if (type === '.md' || type === 'md') { - dropdown.addOption('.md', 'markdown'); + dropdown.addOption('.md', t('markdown')); } else { dropdown.addOption('.' + type, type); } @@ -126,11 +144,9 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { }); const setting0 = new Setting(containerEl); - setting0.setName('Supported file types'); + setting0.setName(t('supportedFileTypes')); const desc0 = document.createDocumentFragment(); - desc0.append( - 'Specify which file types are allowed as folder notes. Applies to both new and existing folders. Adding many types may affect performance.', - ); + desc0.append(t('supportedFileTypesDesc')); setting0.setDesc(desc0); const list = new ListComponent( setting0.settingEl, @@ -154,7 +170,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { { value: 'canvas', label: 'Canvas' }, { value: 'base', label: 'Bases' }, { value: 'excalidraw', label: 'Excalidraw' }, - { value: 'custom', label: 'Custom extension' }, + { value: 'custom', label: t('customExtension') }, ]; options.forEach((option) => { @@ -181,7 +197,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { } else { setting0.addButton((button) => button - .setButtonText('Add custom file type') + .setButtonText(t('addCustomFileType')) .setCta() .onClick(async () => { new AddSupportedFileModal( @@ -196,11 +212,11 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { const templateSetting = new Setting(containerEl) - .setDesc('Can be used with templater/templates plugin. If you add the location of the templates there.') - .setName('Template path') + .setDesc(t('templatePathDesc')) + .setName(t('templatePath')) .addSearch((cb) => { new TemplateSuggest(cb.inputEl, settingsTab.plugin); - cb.setPlaceholder('Template path'); + cb.setPlaceholder(t('templatePathPlaceholder')); const templateFile = settingsTab.plugin.app.vault.getAbstractFileByPath( settingsTab.plugin.settings.templatePath, ); @@ -215,16 +231,16 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { } }); }); - templateSetting.infoEl.appendText('Requires a restart to take effect'); + templateSetting.infoEl.appendText(t('requiresRestart')); templateSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; const storageLocation = new Setting(containerEl) - .setName('Storage location') - .setDesc('Choose where to store the folder notes') + .setName(t('storageLocation')) + .setDesc(t('storageLocationDesc')) .addDropdown((dropdown) => dropdown - .addOption('insideFolder', 'Inside the folder') - .addOption('parentFolder', 'In the parent folder') + .addOption('insideFolder', t('insideFolder')) + .addOption('parentFolder', t('inParentFolder')) .setValue(settingsTab.plugin.settings.storageLocation) .onChange(async (value: 'insideFolder' | 'parentFolder' | 'vaultFolder') => { settingsTab.plugin.settings.storageLocation = value; @@ -235,7 +251,7 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ) .addButton((button) => button - .setButtonText('Switch') + .setButtonText(t('switchButton')) .setCta() .onClick(async () => { let oldStorageLocation = settingsTab.plugin.settings.storageLocation; @@ -246,20 +262,20 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { } new BackupWarningModal( settingsTab.plugin, - 'Switch storage location', - 'When you click on "Confirm" all folder notes will be moved to the new storage location.', + t('switchStorageLocationTitle'), + t('switchStorageLocationMsg'), settingsTab.switchStorageLocation, [oldStorageLocation], ).open(); }), ); - storageLocation.infoEl.appendText('Requires a restart to take effect'); + storageLocation.infoEl.appendText(t('requiresRestart')); storageLocation.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; if (settingsTab.plugin.settings.storageLocation === 'parentFolder') { new Setting(containerEl) - .setName('Delete folder notes when deleting the folder') - .setDesc('Delete the folder note when deleting the folder') + .setName(t('deleteFolderNotesOnFolderDelete')) + .setDesc(t('deleteFolderNotesOnFolderDeleteDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.syncDelete) @@ -270,8 +286,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ), ); new Setting(containerEl) - .setName('Move folder notes when moving the folder') - .setDesc('Move the folder note file along with the folder when it is moved') + .setName(t('moveFolderNotesOnFolderMove')) + .setDesc(t('moveFolderNotesOnFolderMoveDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.syncMove) @@ -282,18 +298,18 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ); } if (Platform.isDesktopApp) { - settingsTab.settingsPage.createEl('h3', { text: 'Keyboard Shortcuts' }); + settingsTab.settingsPage.createEl('h3', { text: t('keyboardShortcuts') }); new Setting(containerEl) - .setName('Key for creating folder note') - .setDesc('The key combination to create a folder note') + .setName(t('keyForCreatingFolderNote')) + .setDesc(t('keyForCreatingFolderNoteDesc')) .addDropdown((dropdown) => { if (!Platform.isMacOS) { - dropdown.addOption('ctrl', 'Ctrl + Click'); - dropdown.addOption('alt', 'Alt + Click'); + dropdown.addOption('ctrl', t('ctrlClick')); + dropdown.addOption('alt', t('altClick')); } else { - dropdown.addOption('ctrl', 'Cmd + Click'); - dropdown.addOption('alt', 'Option + Click'); + dropdown.addOption('ctrl', t('cmdClick')); + dropdown.addOption('alt', t('optionClick')); } dropdown.setValue(settingsTab.plugin.settings.ctrlKey ? 'ctrl' : 'alt'); dropdown.onChange(async (value) => { @@ -305,16 +321,16 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { }); new Setting(containerEl) - .setName('Key for opening folder note') - .setDesc('Select the combination to open a folder note') + .setName(t('keyForOpeningFolderNote')) + .setDesc(t('keyForOpeningFolderNoteDesc')) .addDropdown((dropdown) => { - dropdown.addOption('click', 'Mouse Click'); + dropdown.addOption('click', t('mouseClick')); if (!Platform.isMacOS) { - dropdown.addOption('ctrl', 'Ctrl + Click'); - dropdown.addOption('alt', 'Alt + Click'); + dropdown.addOption('ctrl', t('ctrlClick')); + dropdown.addOption('alt', t('altClick')); } else { - dropdown.addOption('ctrl', 'Cmd + Click'); - dropdown.addOption('alt', 'Option + Click'); + dropdown.addOption('ctrl', t('cmdClick')); + dropdown.addOption('alt', t('optionClick')); } if (settingsTab.plugin.settings.openByClick) { dropdown.setValue('click'); @@ -333,11 +349,11 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { }); } - settingsTab.settingsPage.createEl('h3', { text: 'Folder note behavior' }); + settingsTab.settingsPage.createEl('h3', { text: t('folderNoteBehavior') }); new Setting(containerEl) - .setName('Confirm folder note deletion') - .setDesc('Ask for confirmation before deleting a folder note') + .setName(t('confirmFolderNoteDeletion')) + .setDesc(t('confirmFolderNoteDeletionDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.showDeleteConfirmation) @@ -349,12 +365,12 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Deleted folder notes') - .setDesc('What happens to the folder note after you delete it') + .setName(t('deletedFolderNotes')) + .setDesc(t('deletedFolderNotesDesc')) .addDropdown((dropdown) => { - dropdown.addOption('trash', 'Move to system trash'); - dropdown.addOption('obsidianTrash', 'Move to Obsidian trash (.trash folder)'); - dropdown.addOption('delete', 'Delete permanently'); + dropdown.addOption('trash', t('moveToSystemTrash')); + dropdown.addOption('obsidianTrash', t('moveToObsidianTrash')); + dropdown.addOption('delete', t('deletePermanently')); dropdown.setValue(settingsTab.plugin.settings.deleteFilesAction); dropdown.onChange(async (value: 'trash' | 'delete' | 'obsidianTrash') => { settingsTab.plugin.settings.deleteFilesAction = value; @@ -365,8 +381,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { if (Platform.isDesktop) { const setting3 = new Setting(containerEl); - setting3.setName('Open folder note in a new tab by default'); - setting3.setDesc('Always open folder notes in a new tab unless the note is already open in the current tab.'); + setting3.setName(t('openInNewTab')); + setting3.setDesc(t('openInNewTabDesc')); setting3.addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.openInNewTab) @@ -376,14 +392,14 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { settingsTab.display(); }), ); - setting3.infoEl.appendText('Requires a restart to take effect'); + setting3.infoEl.appendText(t('requiresRestart')); setting3.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; } if (settingsTab.plugin.settings.openInNewTab) { new Setting(containerEl) - .setName('Focus existing tab instead of creating a new one') - .setDesc('If a folder note is already open in a tab, focus that tab instead of creating a new one.') + .setName(t('focusExistingTab')) + .setDesc(t('focusExistingTabDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.focusExistingTab) @@ -396,8 +412,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { } new Setting(containerEl) - .setName('Sync folder name') - .setDesc('Automatically rename the folder note when the folder name is changed') + .setName(t('syncFolderName')) + .setDesc(t('syncFolderNameDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.syncFolderName) @@ -408,22 +424,22 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { }), ); - settingsTab.settingsPage.createEl('h4', { text: 'Automation settings' }); + settingsTab.settingsPage.createEl('h4', { text: t('automationSettings') }); new Setting(containerEl) - .setName('Create folder notes for all folders') - .setDesc('Generate folder notes for every folder in the vault.') + .setName(t('createFolderNotesForAllFolders')) + .setDesc(t('createFolderNotesForAllFoldersDesc')) .addButton((cb) => { cb.setIcon('plus'); - cb.setTooltip('Create folder notes'); + cb.setTooltip(t('createFolderNotesForAllFolders')); cb.onClick(async () => { new ConfirmationModal(settingsTab.app, settingsTab.plugin).open(); }); }); new Setting(containerEl) - .setName('Auto-create on folder creation') - .setDesc('Automatically create a folder note whenever a new folder is added.') + .setName(t('autoCreateOnFolderCreation')) + .setDesc(t('autoCreateOnFolderCreationDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.autoCreate) @@ -436,8 +452,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { if (settingsTab.plugin.settings.autoCreate) { new Setting(containerEl) - .setName('Auto-open after creation') - .setDesc('Open the folder note immediately after it’s created automatically.') + .setName(t('autoOpenAfterCreation')) + .setDesc(t('autoOpenAfterCreationDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.autoCreateFocusFiles) @@ -449,8 +465,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Auto-create for attachment folders') - .setDesc('Also automatically create folder notes for attachment folders (e.g., "Attachments", "Media", etc.).') + .setName(t('autoCreateForAttachmentFolders')) + .setDesc(t('autoCreateForAttachmentFoldersDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.autoCreateForAttachmentFolder) @@ -463,8 +479,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { } new Setting(containerEl) - .setName('Auto-create when creating notes') - .setDesc('Automatically create a folder note when a regular note is created inside a folder. Works for supported file types only.') + .setName(t('autoCreateWhenCreatingNotes')) + .setDesc(t('autoCreateWhenCreatingNotesDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.autoCreateForFiles) @@ -475,23 +491,21 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { }), ); - settingsTab.settingsPage.createEl('h3', { text: 'Integration & Compatibility' }); + settingsTab.settingsPage.createEl('h3', { text: t('integrationCompatibility') }); const desc1 = document.createDocumentFragment(); - const link = document.createElement('a'); link.href = 'https://github.com/snezhig/obsidian-front-matter-title'; - link.textContent = 'front matter title plugin'; + link.textContent = t('frontMatterTitlePlugin'); link.target = '_blank'; - - desc1.append( - 'Allows you to use the ', - link, - ' with folder notes. It allows you to set the folder name to some name you set in the front matter.', - ); + const fmtpDescText = t('enableFmtpIntegrationDesc'); + const [before, after] = fmtpDescText.split('{link}'); + desc1.append(before ?? ''); + desc1.appendChild(link); + desc1.append(after ?? ''); const fmtpSetting = new Setting(containerEl) - .setName('Enable front matter title plugin integration') + .setName(t('enableFmtpIntegration')) .setDesc(desc1) .addToggle((toggle) => toggle @@ -524,14 +538,14 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { settingsTab.display(); }), ); - fmtpSetting.infoEl.appendText('Requires a restart to take effect'); + fmtpSetting.infoEl.appendText(t('requiresRestart')); fmtpSetting.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed'; - settingsTab.settingsPage.createEl('h3', { text: 'Session & Persistence' }); + settingsTab.settingsPage.createEl('h3', { text: t('sessionPersistence') }); new Setting(containerEl) - .setName('Persist tab after restart') - .setDesc('Restore the same settings tab after restarting Obsidian.') + .setName(t('persistTabAfterRestart')) + .setDesc(t('persistTabAfterRestartDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.persistentSettingsTab.afterRestart) @@ -543,8 +557,8 @@ export async function renderGeneral(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Persist tab during session only') - .setDesc('Keep the current settings tab open during the session, but reset it after a restart or reload.') + .setName(t('persistTabDuringSession')) + .setDesc(t('persistTabDuringSessionDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.persistentSettingsTab.afterChangingTab) diff --git a/src/settings/PathSettings.ts b/src/settings/PathSettings.ts index 3e7494c..58d383e 100644 --- a/src/settings/PathSettings.ts +++ b/src/settings/PathSettings.ts @@ -1,11 +1,13 @@ /* eslint-disable max-len */ import { Setting } from 'obsidian'; import type { SettingsTab } from './SettingsTab'; +import { t } from '../i18n'; + export async function renderPath(settingsTab: SettingsTab): Promise { const containerEl = settingsTab.settingsPage; new Setting(containerEl) - .setName('Open folder note through path') - .setDesc('Open a folder note when clicking on a folder name in the path if it is a folder note') + .setName(t('openFolderNoteThroughPath')) + .setDesc(t('openFolderNoteThroughPathDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.openFolderNoteOnClickInPath) @@ -18,8 +20,8 @@ export async function renderPath(settingsTab: SettingsTab): Promise { if (settingsTab.plugin.settings.openFolderNoteOnClickInPath) { new Setting(containerEl) - .setName('Open sidebar when opening a folder note through path (Mobile only)') - .setDesc('Open the sidebar when opening a folder note through the path on mobile') + .setName(t('openSidebarMobile')) + .setDesc(t('openSidebarMobileDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.openSidebar.mobile) @@ -30,8 +32,8 @@ export async function renderPath(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Open sidebar when opening a folder note through path (Desktop only)') - .setDesc('Open the sidebar when opening a folder note through the path on desktop') + .setName(t('openSidebarDesktop')) + .setDesc(t('openSidebarDesktopDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.openSidebar.desktop) @@ -44,8 +46,8 @@ export async function renderPath(settingsTab: SettingsTab): Promise { if (settingsTab.plugin.settings.frontMatterTitle.enabled) { new Setting(containerEl) - .setName('Auto update folder name in the path (front matter title plugin only)') - .setDesc('Automatically update the folder name in the path when the front matter title plugin is enabled and the title for a folder note is changed in the front matter. This will not change the file name, only the displayed name in the path.') + .setName(t('autoUpdateFolderNameInPath')) + .setDesc(t('autoUpdateFolderNameInPathDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.frontMatterTitle.path) @@ -61,11 +63,11 @@ export async function renderPath(settingsTab: SettingsTab): Promise { ); } - settingsTab.settingsPage.createEl('h3', { text: 'Style settings' }); + settingsTab.settingsPage.createEl('h3', { text: t('styleSettings') }); new Setting(containerEl) - .setName('Underline folders in the path') - .setDesc('Add an underline to folders that have a folder note in the path above a note') + .setName(t('underlineFoldersInPath')) + .setDesc(t('underlineFoldersInPathDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.underlineFolderInPath) @@ -81,8 +83,8 @@ export async function renderPath(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Bold folders in the path') - .setDesc('Make the folder name bold in the path above a note when it has a folder note') + .setName(t('boldFoldersInPath')) + .setDesc(t('boldFoldersInPathDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.boldNameInPath) @@ -98,8 +100,8 @@ export async function renderPath(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Cursive the name of folder notes in the path') - .setDesc('Make the folder name cursive in the path above a note when it has a folder note') + .setName(t('cursiveFoldersInPath')) + .setDesc(t('cursiveFoldersInPathDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.cursiveNameInPath) @@ -115,8 +117,8 @@ export async function renderPath(settingsTab: SettingsTab): Promise { ); new Setting(containerEl) - .setName('Hide folder note name in the path') - .setDesc('Only show the folder name in the path and hide the folder note name.') + .setName(t('hideFolderNoteNameInPath')) + .setDesc(t('hideFolderNoteNameInPathDesc')) .addToggle((toggle) => toggle .setValue(settingsTab.plugin.settings.hideFolderNoteNameInPath) diff --git a/src/settings/SettingsTab.ts b/src/settings/SettingsTab.ts index 80c98d0..48979c0 100644 --- a/src/settings/SettingsTab.ts +++ b/src/settings/SettingsTab.ts @@ -2,6 +2,7 @@ import { Notice, PluginSettingTab, TFile, TFolder, type App, type MarkdownPostProcessorContext, } from 'obsidian'; +import { t } from '../i18n'; import type FolderNotesPlugin from '../main'; import type { ExcludePattern } from 'src/ExcludeFolders/ExcludePattern'; import type { ExcludedFolder } from 'src/ExcludeFolders/ExcludeFolder'; @@ -83,6 +84,7 @@ export interface FolderNotesSettings { autoUpdateLinks: boolean; } hideFolderNoteNameInPath: boolean; + language: string; } export const DEFAULT_SETTINGS: FolderNotesSettings = { @@ -208,6 +210,7 @@ export const DEFAULT_SETTINGS: FolderNotesSettings = { autoUpdateLinks: false, }, hideFolderNoteNameInPath: false, + language: 'en', }; export class SettingsTab extends PluginSettingTab { @@ -219,28 +222,30 @@ export class SettingsTab extends PluginSettingTab { constructor(app: App, plugin: FolderNotesPlugin) { super(app, plugin); } - TABS = { - GENERAL: { - name: 'General', - id: 'general', - }, - FOLDER_OVERVIEW: { - name: 'Folder overview', - id: 'folder_overview', - }, - EXCLUDE_FOLDERS: { - name: 'Exclude folders', - id: 'exclude_folders', - }, - FILE_EXPLORER: { - name: 'File explorer', - id: 'file_explorer', - }, - PATH: { - name: 'Path', - id: 'path', - }, - }; + get TABS() { + return { + GENERAL: { + name: t('tabGeneral'), + id: 'general', + }, + FOLDER_OVERVIEW: { + name: t('tabFolderOverview'), + id: 'folder_overview', + }, + EXCLUDE_FOLDERS: { + name: t('tabExcludeFolders'), + id: 'exclude_folders', + }, + FILE_EXPLORER: { + name: t('tabFileExplorer'), + id: 'file_explorer', + }, + PATH: { + name: t('tabPath'), + id: 'path', + }, + }; + } renderSettingsPage(tabId: string): void { this.settingsPage.empty(); @@ -321,7 +326,7 @@ export class SettingsTab extends PluginSettingTab { } renameFolderNotes(): void { - new Notice('Starting to update folder notes...'); + new Notice(t('startingUpdateFolderNotes')); const oldTemplate = this.plugin.settings.oldFolderNoteName ?? '{{folder_name}}'; for (const folder of this.app.vault.getAllLoadedFiles()) { @@ -357,11 +362,11 @@ export class SettingsTab extends PluginSettingTab { this.plugin.settings.oldFolderNoteName = this.plugin.settings.folderNoteName; this.plugin.saveSettings(); - new Notice('Finished updating folder notes'); + new Notice(t('finishedUpdatingFolderNotes')); } switchStorageLocation(oldMethod: string): void { - new Notice('Starting to switch storage location...'); + new Notice(t('startingSwitchStorageLocation')); this.app.vault.getAllLoadedFiles().forEach((file) => { if (file instanceof TFolder) { const folderNote = getFolderNote(this.plugin, file.path, oldMethod); @@ -385,7 +390,7 @@ export class SettingsTab extends PluginSettingTab { } } }); - new Notice('Finished switching storage location'); + new Notice(t('finishedSwitchingStorageLocation')); } onClose(): void {