This commit is contained in:
calvados1 2026-05-24 22:54:40 +05:00 committed by GitHub
commit b4fd0f8788
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 712 additions and 232 deletions

View file

@ -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);

211
src/i18n/en.ts Normal file
View file

@ -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;

28
src/i18n/index.ts Normal file
View file

@ -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<string, Translations> = {
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, string>): 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;
}

211
src/i18n/zh.ts Normal file
View file

@ -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;

View file

@ -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<void> {
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();

View file

@ -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 () => {

View file

@ -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<void> {
@ -16,32 +17,32 @@ export async function renderExcludeFolders(settingsTab: SettingsTab): Promise<vo
const manageExcluded = new Setting(containerEl)
.setHeading()
.setClass('fn-excluded-folder-heading')
.setName('Manage excluded folders');
.setName(t('manageExcludedFolders'));
const desc3 = document.createDocumentFragment();
desc3.append(
'Add {regex} at the beginning of the folder name to use a regex pattern.',
t('manageExcludedFoldersDesc1'),
desc3.createEl('br'),
'Use * before and after to exclude folders that include the name between the *s.',
t('manageExcludedFoldersDesc2'),
desc3.createEl('br'),
'Use * before the folder name to exclude folders that end with the folder name.',
t('manageExcludedFoldersDesc3'),
desc3.createEl('br'),
'Use * after the folder name to exclude folders that start with the folder name.',
t('manageExcludedFoldersDesc4'),
);
manageExcluded.setDesc(desc3);
// eslint-disable-next-line max-len
manageExcluded.infoEl.appendText('The regexes and wildcards are only for the folder name, not the path.');
manageExcluded.infoEl.appendText(t('excludedFoldersInfo1'));
manageExcluded.infoEl.createEl('br');
// eslint-disable-next-line max-len
manageExcluded.infoEl.appendText('If you want to switch to a folder path delete the pattern first.');
manageExcluded.infoEl.appendText(t('excludedFoldersInfo2'));
// eslint-disable-next-line max-len
manageExcluded.infoEl.style.color = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
new Setting(containerEl)
.setName('Whitelisted folders')
.setDesc('Folders that override the excluded folders/patterns')
.setName(t('whitelistedFolders'))
.setDesc(t('whitelistedFoldersDesc'))
.addButton((cb) => {
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<vo
});
new Setting(containerEl)
.setName('Exclude folder default settings')
.setName(t('excludeFolderDefaultSettings'))
.addButton((cb) => {
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<vo
});
new Setting(containerEl)
.setName('Exclude pattern default settings')
.setName(t('excludePatternDefaultSettings'))
.addButton((cb) => {
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<vo
new Setting(containerEl)
.setName('Add excluded folder')
.setName(t('addExcludedFolder'))
.setClass('add-exclude-folder-item')
.addButton((cb) => {
cb.setIcon('plus');
cb.setClass('add-exclude-folder');
cb.setTooltip('Add excluded folder');
cb.setTooltip(t('addExcludedFolder'));
cb.onClick(() => {
const excludedFolder = new ExcludedFolder(
'',

View file

@ -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<void> {
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<void
);
const setting2 = new Setting(containerEl)
.setName('Disable click-to-open folder note on mobile')
.setDesc('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.')
.setName(t('disableClickToOpenOnMobile'))
.setDesc(t('disableClickToOpenOnMobileDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.disableOpenFolderNoteOnClick)
@ -34,13 +36,13 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
}),
);
setting2.infoEl.appendText('Requires a restart to take effect');
setting2.infoEl.appendText(t('requiresRestart'));
const setting2AccentColor = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
setting2.infoEl.style.color = setting2AccentColor;
new Setting(containerEl)
.setName('Open folder notes by only clicking directly on the folder name')
.setDesc('Only allow folder notes to open when clicking directly on the folder name in the file explorer')
.setName(t('openByClickingFolderNameOnly'))
.setDesc(t('openByClickingFolderNameOnlyDesc'))
.addToggle((toggle) =>
toggle
.setValue(!settingsTab.plugin.settings.stopWhitespaceCollapsing)
@ -56,8 +58,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
);
const disableSetting = new Setting(containerEl);
disableSetting.setName('Disable folder collapsing');
disableSetting.setDesc('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.');
disableSetting.setName(t('disableFolderCollapsing'));
disableSetting.setDesc(t('disableFolderCollapsingDesc'));
disableSetting.addToggle((toggle) =>
toggle
.setValue(!settingsTab.plugin.settings.enableCollapsing)
@ -66,13 +68,13 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
await settingsTab.plugin.saveSettings();
}),
);
disableSetting.infoEl.appendText('Requires a restart to take effect');
disableSetting.infoEl.appendText(t('requiresRestart'));
const accentColor = settingsTab.app.vault.getConfig('accentColor') as string || '#7d5bed';
disableSetting.infoEl.style.color = accentColor;
new Setting(containerEl)
.setName('Use submenus')
.setDesc('Use submenus for file/folder commands')
.setName(t('useSubmenus'))
.setDesc(t('useSubmenusDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.useSubmenus)
@ -85,8 +87,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
if (settingsTab.plugin.settings.frontMatterTitle.enabled) {
new Setting(containerEl)
.setName('Auto update folder name in the file explorer (front matter title plugin only)')
.setDesc('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.')
.setName(t('autoUpdateFolderNameInExplorer'))
.setDesc(t('autoUpdateFolderNameInExplorerDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.frontMatterTitle.explorer)
@ -108,11 +110,11 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
);
}
settingsTab.settingsPage.createEl('h3', { text: 'Style settings' });
settingsTab.settingsPage.createEl('h3', { text: t('styleSettings') });
new Setting(containerEl)
.setName('Highlight folder in the file explorer')
.setDesc('Highlight the folder in the file explorer when it has a folder note and the folder note is open in the editor')
.setName(t('highlightFolder'))
.setDesc(t('highlightFolderDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.highlightFolder)
@ -128,8 +130,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
);
new Setting(containerEl)
.setName('Hide collapse icon')
.setDesc('Hide the collapse icon in the file explorer next to the name of a folder when a folder only contains a folder note')
.setName(t('hideCollapseIcon'))
.setDesc(t('hideCollapseIconDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.hideCollapsingIcon)
@ -146,8 +148,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
);
new Setting(containerEl)
.setName('Hide collapse icon for every empty folder')
.setDesc('Hide the collapse icon in the file explorer next to the name of a folder when a folder is empty')
.setName(t('hideCollapseIconForEmptyFolders'))
.setDesc(t('hideCollapseIconForEmptyFoldersDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.hideCollapsingIconForEmptyFolders)
@ -165,7 +167,7 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
if (settingsTab.plugin.settings.hideCollapsingIcon) {
new Setting(containerEl)
.setName('Hide collapse icon also when only the attachment folder is in the same folder')
.setName(t('hideCollapseIconForAttachmentFolder'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.ignoreAttachmentFolder)
@ -182,8 +184,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
}
new Setting(containerEl)
.setName('Underline the name of folder notes')
.setDesc('Add an underline to folders that have a folder note in the file explorer')
.setName(t('underlineFolderNote'))
.setDesc(t('underlineFolderNoteDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.underlineFolder)
@ -199,8 +201,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
);
new Setting(containerEl)
.setName('Bold the name of folder notes')
.setDesc('Make the folder name bold in the file explorer when it has a folder note')
.setName(t('boldFolderNote'))
.setDesc(t('boldFolderNoteDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.boldName)
@ -216,8 +218,8 @@ export async function renderFileExplorer(settingsTab: SettingsTab): Promise<void
);
new Setting(containerEl)
.setName('Cursive the name of folder notes')
.setDesc('Make the folder name cursive in the file explorer when it has a folder note')
.setName(t('cursiveFolderNote'))
.setDesc(t('cursiveFolderNoteDesc'))
.addToggle((toggle) =>
toggle
.setValue(settingsTab.plugin.settings.cursiveName)

View file

@ -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<void> {
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<vo
}),
);
containerEl.createEl('h3', { text: 'Overviews default settings' });
containerEl.createEl('h3', { text: t('overviewDefaultSettings') });
const pEl = containerEl.createEl('p', {
text: 'Edit the default settings for new folder overviews, ',
text: t('overviewDefaultSettingsDesc'),
cls: 'setting-item-description',
});
const span = createSpan({ text: "this won't apply to already existing overviews.", cls: '' });
const span = createSpan({ text: t('overviewDefaultSettingsSpan'), cls: '' });
const accentColor = (settingsTab.app.vault.getConfig('accentColor') as string) || '#7d5bed';
span.setAttr('style', `color: ${accentColor};`);
pEl.appendChild(span);

View file

@ -9,15 +9,33 @@ import { TemplateSuggest } from '../suggesters/TemplateSuggester';
import { refreshAllFolderStyles } from '../functions/styleFunctions';
import BackupWarningModal from './modals/BackupWarning';
import RenameFolderNotesModal from './modals/RenameFns';
import { t, setLanguage } from '../i18n';
let debounceTimer: NodeJS.Timeout;
// eslint-disable-next-line complexity
export async function renderGeneral(settingsTab: SettingsTab): Promise<void> {
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 folders name. Existing notes wont 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<void> {
)
.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<void> {
}
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<void> {
});
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<void> {
{ 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<void> {
} 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<void> {
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<void> {
}
});
});
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<void> {
)
.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<void> {
}
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<void> {
),
);
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<void> {
);
}
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<void> {
});
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<void> {
});
}
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<void> {
);
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<void> {
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<void> {
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<void> {
}
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<void> {
}),
);
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<void> {
if (settingsTab.plugin.settings.autoCreate) {
new Setting(containerEl)
.setName('Auto-open after creation')
.setDesc('Open the folder note immediately after its 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<void> {
);
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<void> {
}
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<void> {
}),
);
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<void> {
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<void> {
);
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)

View file

@ -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<void> {
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<void> {
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<void> {
);
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<void> {
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<void> {
);
}
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<void> {
);
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<void> {
);
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<void> {
);
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)

View file

@ -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 {