diff --git a/extend.php b/extend.php index 3de3ced..a26947b 100644 --- a/extend.php +++ b/extend.php @@ -35,5 +35,7 @@ return [ ->default('blomstra-search.search-discussion-subjects', true) ->default('blomstra-search.search-post-bodies', true) ->default('blomstra-search.min-search-length', Commands\BuildCommand::DEFAULT_MIN_SEARCH_LENGTH) - ->serializeToForum('blomstraSearchMinLength', 'blomstra-search.min-search-length', 'intval'), + ->default('blomstra-search.stem-exclusion', '') + ->serializeToForum('blomstraSearchMinLength', 'blomstra-search.min-search-length', 'intval') + ->serializeToForum('blomstraSearchPostBodies', 'blomstra-search.search-post-bodies', fn ($v) => (bool) $v, true), ]; diff --git a/js/src/admin/index.ts b/js/src/admin/index.ts index ff0f0f9..58b3256 100644 --- a/js/src/admin/index.ts +++ b/js/src/admin/index.ts @@ -4,7 +4,7 @@ import DashboardPage from 'flarum/admin/components/DashboardPage'; import DashboardWidget from 'flarum/admin/components/DashboardWidget'; import Alert from 'flarum/common/components/Alert'; -const REQUIRED_INDEX_COMPAT = 'v2'; +const REQUIRED_INDEX_COMPAT = 'v3'; class ReindexWarningWidget extends DashboardWidget { className() { @@ -35,46 +35,43 @@ app.initializers.add('blomstra-search', () => { }); } - const languages = new Map(); - [ - 'arabic', - 'armenian', - 'basque', - 'bengali', - 'brazilian', - 'bulgarian', - 'catalan', - 'cjk', - 'czech', - 'danish', - 'dutch', - 'english', - 'estonian', - 'finnish', - 'french', - 'galician', - 'german', - 'greek', - 'hindi', - 'hungarian', - 'indonesian', - 'irish', - 'italian', - 'latvian', - 'lithuanian', - 'norwegian', - 'persian', - 'portuguese', - 'romanian', - 'russian', - 'sorani', - 'spanish', - 'swedish', - 'turkish', - 'thai', - ].forEach((language) => { - languages.set(language, language); - }); + const languages: Record = { + arabic: 'Arabic', + armenian: 'Armenian', + basque: 'Basque', + bengali: 'Bengali', + brazilian: 'Brazilian Portuguese', + bulgarian: 'Bulgarian', + catalan: 'Catalan', + cjk: 'CJK (Chinese, Japanese, Korean)', + czech: 'Czech', + danish: 'Danish', + dutch: 'Dutch', + english: 'English', + estonian: 'Estonian', + finnish: 'Finnish', + french: 'French', + galician: 'Galician', + german: 'German', + greek: 'Greek', + hindi: 'Hindi', + hungarian: 'Hungarian', + indonesian: 'Indonesian', + irish: 'Irish', + italian: 'Italian', + latvian: 'Latvian', + lithuanian: 'Lithuanian', + norwegian: 'Norwegian', + persian: 'Persian', + portuguese: 'Portuguese', + romanian: 'Romanian', + russian: 'Russian', + sorani: 'Sorani (Kurdish)', + spanish: 'Spanish', + swedish: 'Swedish', + turkish: 'Turkish', + thai: 'Thai', + }; app.extensionData .for('blomstra-search') @@ -84,12 +81,10 @@ app.initializers.add('blomstra-search', () => { if (!activeIndex || !indexedAnalyzer) return null; const currentAnalyzer = this.setting('blomstra-search.analyzer-language')() || 'english'; - const currentMinLength = this.setting('blomstra-search.min-search-length')(); - const indexedMinLength = String( - app.data.settings['blomstra-search.indexed-min-search-length'] || app.data.settings['blomstra-search.min-search-length'] - ); + const currentStemExclusion = this.setting('blomstra-search.stem-exclusion')() || ''; + const indexedStemExclusion = app.data.settings['blomstra-search.indexed-stem-exclusion'] || ''; - if (currentAnalyzer === indexedAnalyzer && currentMinLength === indexedMinLength) return null; + if (currentAnalyzer === indexedAnalyzer && currentStemExclusion === indexedStemExclusion) return null; return m( Alert, @@ -118,14 +113,6 @@ app.initializers.add('blomstra-search', () => { default: 'flarum', type: 'input', }) - .registerSetting({ - setting: 'blomstra-search.analyzer-language', - label: app.translator.trans('blomstra-search.admin.analyzer.label'), - help: app.translator.trans('blomstra-search.admin.analyzer.help'), - type: 'select', - options: Object.fromEntries(languages.entries()), - default: 'english', - }) .registerSetting({ setting: 'blomstra-search.search-discussion-subjects', label: app.translator.trans('blomstra-search.admin.search-discussion-subjects'), @@ -137,11 +124,33 @@ app.initializers.add('blomstra-search', () => { type: 'switch', }) .registerSetting({ - setting: 'blomstra-search.min-search-length', - label: app.translator.trans('blomstra-search.admin.min-search-length.label'), - help: app.translator.trans('blomstra-search.admin.min-search-length.help'), + setting: 'blomstra-search.analyzer-language', + label: app.translator.trans('blomstra-search.admin.analyzer.label'), + help: app.translator.trans('blomstra-search.admin.analyzer.help'), type: 'select', - options: { '1': '1', '2': '2', '3': '3', '4': '4' }, - default: app.data.settings['blomstra-search.min-search-length'], + options: languages, + default: 'english', + }) + .registerSetting(function (this: any) { + const isCjk = (this.setting('blomstra-search.analyzer-language')() || 'english') === 'cjk'; + return this.buildSettingComponent({ + setting: 'blomstra-search.stem-exclusion', + type: 'textarea', + label: app.translator.trans('blomstra-search.admin.settings.stem-exclusion.label'), + help: app.translator.trans('blomstra-search.admin.settings.stem-exclusion.help'), + disabled: isCjk, + }); + }) + .registerSetting(function (this: any) { + const isCjk = (this.setting('blomstra-search.analyzer-language')() || 'english') === 'cjk'; + return this.buildSettingComponent({ + setting: 'blomstra-search.min-search-length', + label: app.translator.trans('blomstra-search.admin.min-search-length.label'), + help: app.translator.trans('blomstra-search.admin.min-search-length.help'), + type: 'select', + options: { '1': '1', '2': '2', '3': '3', '4': '4' }, + default: app.data.settings['blomstra-search.min-search-length'], + disabled: isCjk, + }); }); }); diff --git a/resources/locale/en.yml b/resources/locale/en.yml index ec08d82..5ce7f8e 100644 --- a/resources/locale/en.yml +++ b/resources/locale/en.yml @@ -17,9 +17,12 @@ blomstra-search: search-post-bodies: Search inside comments match-sentences: Match search term against full sentence match-words: Match search term against full words + settings: + stem-exclusion: + label: "Protected words (stem exclusion)" + help: "One word per line. These words will not be stemmed during search (e.g. brand names, proper nouns). Not applicable for CJK or Thai languages. Requires a full re-index to take effect." min-search-length: label: Minimum search query length help: | Minimum number of characters required before a search is triggered. Lower this to 1 or 2 for CJK (Chinese, Japanese, Korean) communities where single characters carry full meaning. - Changing this requires a full index rebuild to take effect.