[MM-33112] Add support for multiple custom spellchecking languages (#1743)
* [MM-33112] Add support for multiple custom spellchecking languages * Styles and other formatting * Type and lint fixes * Update wording
This commit is contained in:
parent
c3963424f1
commit
6dc84b3e5d
493
package-lock.json
generated
493
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -73,6 +73,7 @@
|
||||||
"@types/react": "^17.0.11",
|
"@types/react": "^17.0.11",
|
||||||
"@types/react-beautiful-dnd": "^13.0.0",
|
"@types/react-beautiful-dnd": "^13.0.0",
|
||||||
"@types/react-dom": "^17.0.8",
|
"@types/react-dom": "^17.0.8",
|
||||||
|
"@types/react-select": "^4.0.17",
|
||||||
"@types/underscore": "^1.11.2",
|
"@types/underscore": "^1.11.2",
|
||||||
"@types/valid-url": "^1.0.3",
|
"@types/valid-url": "^1.0.3",
|
||||||
"@types/winreg": "^1.2.30",
|
"@types/winreg": "^1.2.30",
|
||||||
|
@ -138,6 +139,7 @@
|
||||||
"react-beautiful-dnd": "^13.1.0",
|
"react-beautiful-dnd": "^13.1.0",
|
||||||
"react-bootstrap": "^1.6.1",
|
"react-bootstrap": "^1.6.1",
|
||||||
"react-dom": "^16.14.0",
|
"react-dom": "^16.14.0",
|
||||||
|
"react-select": "4.3.1",
|
||||||
"react-transition-group": "^2.5.0",
|
"react-transition-group": "^2.5.0",
|
||||||
"sass": "^1.35.1",
|
"sass": "^1.35.1",
|
||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
|
|
|
@ -98,3 +98,5 @@ export const SEND_DROPDOWN_MENU_SIZE = 'send-dropdown-menu-size';
|
||||||
|
|
||||||
export const BROWSER_HISTORY_PUSH = 'browser-history-push';
|
export const BROWSER_HISTORY_PUSH = 'browser-history-push';
|
||||||
export const APP_LOGGED_IN = 'app-logged-in';
|
export const APP_LOGGED_IN = 'app-logged-in';
|
||||||
|
|
||||||
|
export const GET_AVAILABLE_SPELL_CHECKER_LANGUAGES = 'get-available-spell-checker-languages';
|
||||||
|
|
|
@ -31,7 +31,7 @@ const defaultPreferences: ConfigV3 = {
|
||||||
useSpellChecker: true,
|
useSpellChecker: true,
|
||||||
enableHardwareAcceleration: true,
|
enableHardwareAcceleration: true,
|
||||||
autostart: true,
|
autostart: true,
|
||||||
spellCheckerLocale: 'en-US',
|
spellCheckerLocales: [],
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
downloadLocation: getDefaultDownloadLocation(),
|
downloadLocation: getDefaultDownloadLocation(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -235,8 +235,8 @@ export default class Config extends EventEmitter {
|
||||||
return this.combinedData?.spellCheckerURL;
|
return this.combinedData?.spellCheckerURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
get spellCheckerLocale() {
|
get spellCheckerLocales() {
|
||||||
return this.combinedData?.spellCheckerLocale ?? defaultPreferences.spellCheckerLocale;
|
return this.combinedData?.spellCheckerLocales ?? defaultPreferences.spellCheckerLocales;
|
||||||
}
|
}
|
||||||
get showTrayIcon() {
|
get showTrayIcon() {
|
||||||
return this.combinedData?.showTrayIcon ?? defaultPreferences.showTrayIcon;
|
return this.combinedData?.showTrayIcon ?? defaultPreferences.showTrayIcon;
|
||||||
|
|
|
@ -43,6 +43,7 @@ function upgradeV2toV3(configV2: ConfigV2) {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
config.lastActiveTeam = 0;
|
config.lastActiveTeam = 0;
|
||||||
|
config.spellCheckerLocales = [];
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
/* eslint-disable quote-props */
|
||||||
|
|
||||||
export const PRODUCTION = 'production';
|
export const PRODUCTION = 'production';
|
||||||
export const DEVELOPMENT = 'development';
|
export const DEVELOPMENT = 'development';
|
||||||
|
@ -21,3 +22,234 @@ export const DEFAULT_WINDOW_WIDTH = 1000;
|
||||||
export const DEFAULT_WINDOW_HEIGHT = 700;
|
export const DEFAULT_WINDOW_HEIGHT = 700;
|
||||||
export const MINIMUM_WINDOW_WIDTH = 700;
|
export const MINIMUM_WINDOW_WIDTH = 700;
|
||||||
export const MINIMUM_WINDOW_HEIGHT = 240;
|
export const MINIMUM_WINDOW_HEIGHT = 240;
|
||||||
|
|
||||||
|
export const localeTranslations: Record<string, string> = {
|
||||||
|
'af': 'Afrikaans',
|
||||||
|
'af-ZA': 'Afrikaans (South Africa)',
|
||||||
|
'ar': 'Arabic',
|
||||||
|
'ar-AE': 'Arabic (U.A.E.)',
|
||||||
|
'ar-BH': 'Arabic (Bahrain)',
|
||||||
|
'ar-DZ': 'Arabic (Algeria)',
|
||||||
|
'ar-EG': 'Arabic (Egypt)',
|
||||||
|
'ar-IQ': 'Arabic (Iraq)',
|
||||||
|
'ar-JO': 'Arabic (Jordan)',
|
||||||
|
'ar-KW': 'Arabic (Kuwait)',
|
||||||
|
'ar-LB': 'Arabic (Lebanon)',
|
||||||
|
'ar-LY': 'Arabic (Libya)',
|
||||||
|
'ar-MA': 'Arabic (Morocco)',
|
||||||
|
'ar-OM': 'Arabic (Oman)',
|
||||||
|
'ar-QA': 'Arabic (Qatar)',
|
||||||
|
'ar-SA': 'Arabic (Saudi Arabia)',
|
||||||
|
'ar-SY': 'Arabic (Syria)',
|
||||||
|
'ar-TN': 'Arabic (Tunisia)',
|
||||||
|
'ar-YE': 'Arabic (Yemen)',
|
||||||
|
'az': 'Azeri (Latin)',
|
||||||
|
'az-AZ': 'Azeri (Azerbaijan)',
|
||||||
|
'be': 'Belarusian',
|
||||||
|
'be-BY': 'Belarusian (Belarus)',
|
||||||
|
'bg': 'Bulgarian',
|
||||||
|
'bg-BG': 'Bulgarian (Bulgaria)',
|
||||||
|
'bs-BA': 'Bosnian (Bosnia and Herzegovina)',
|
||||||
|
'ca': 'Catalan',
|
||||||
|
'ca-ES': 'Catalan (Spain)',
|
||||||
|
'cs': 'Czech',
|
||||||
|
'cs-CZ': 'Czech (Czech Republic)',
|
||||||
|
'cy': 'Welsh',
|
||||||
|
'cy-GB': 'Welsh (United Kingdom)',
|
||||||
|
'da': 'Danish',
|
||||||
|
'da-DK': 'Danish (Denmark)',
|
||||||
|
'de': 'German',
|
||||||
|
'de-AT': 'German (Austria)',
|
||||||
|
'de-CH': 'German (Switzerland)',
|
||||||
|
'de-DE': 'German (Germany)',
|
||||||
|
'de-LI': 'German (Liechtenstein)',
|
||||||
|
'de-LU': 'German (Luxembourg)',
|
||||||
|
'dv': 'Divehi',
|
||||||
|
'dv-MV': 'Divehi (Maldives)',
|
||||||
|
'el': 'Greek',
|
||||||
|
'el-GR': 'Greek (Greece)',
|
||||||
|
'en': 'English',
|
||||||
|
'en-AU': 'English (Australia)',
|
||||||
|
'en-BZ': 'English (Belize)',
|
||||||
|
'en-CA': 'English (Canada)',
|
||||||
|
'en-CB': 'English (Caribbean)',
|
||||||
|
'en-GB': 'English (United Kingdom)',
|
||||||
|
'en-IE': 'English (Ireland)',
|
||||||
|
'en-JM': 'English (Jamaica)',
|
||||||
|
'en-NZ': 'English (New Zealand)',
|
||||||
|
'en-PH': 'English (Republic of the Philippines)',
|
||||||
|
'en-TT': 'English (Trinidad and Tobago)',
|
||||||
|
'en-US': 'English (United States)',
|
||||||
|
'en-ZA': 'English (South Africa)',
|
||||||
|
'en-ZW': 'English (Zimbabwe)',
|
||||||
|
'eo': 'Esperanto',
|
||||||
|
'es': 'Spanish',
|
||||||
|
'es-AR': 'Spanish (Argentina)',
|
||||||
|
'es-BO': 'Spanish (Bolivia)',
|
||||||
|
'es-CL': 'Spanish (Chile)',
|
||||||
|
'es-CO': 'Spanish (Colombia)',
|
||||||
|
'es-CR': 'Spanish (Costa Rica)',
|
||||||
|
'es-DO': 'Spanish (Dominican Republic)',
|
||||||
|
'es-EC': 'Spanish (Ecuador)',
|
||||||
|
'es-ES': 'Spanish (Spain)',
|
||||||
|
'es-GT': 'Spanish (Guatemala)',
|
||||||
|
'es-HN': 'Spanish (Honduras)',
|
||||||
|
'es-MX': 'Spanish (Mexico)',
|
||||||
|
'es-NI': 'Spanish (Nicaragua)',
|
||||||
|
'es-PA': 'Spanish (Panama)',
|
||||||
|
'es-PE': 'Spanish (Peru)',
|
||||||
|
'es-PR': 'Spanish (Puerto Rico)',
|
||||||
|
'es-PY': 'Spanish (Paraguay)',
|
||||||
|
'es-SV': 'Spanish (El Salvador)',
|
||||||
|
'es-UY': 'Spanish (Uruguay)',
|
||||||
|
'es-VE': 'Spanish (Venezuela)',
|
||||||
|
'et': 'Estonian',
|
||||||
|
'et-EE': 'Estonian (Estonia)',
|
||||||
|
'eu': 'Basque',
|
||||||
|
'eu-ES': 'Basque (Spain)',
|
||||||
|
'fa': 'Farsi',
|
||||||
|
'fa-IR': 'Farsi (Iran)',
|
||||||
|
'fi': 'Finnish',
|
||||||
|
'fi-FI': 'Finnish (Finland)',
|
||||||
|
'fo': 'Faroese',
|
||||||
|
'fo-FO': 'Faroese (Faroe Islands)',
|
||||||
|
'fr': 'French',
|
||||||
|
'fr-BE': 'French (Belgium)',
|
||||||
|
'fr-CA': 'French (Canada)',
|
||||||
|
'fr-CH': 'French (Switzerland)',
|
||||||
|
'fr-FR': 'French (France)',
|
||||||
|
'fr-LU': 'French (Luxembourg)',
|
||||||
|
'fr-MC': 'French (Principality of Monaco)',
|
||||||
|
'gl': 'Galician',
|
||||||
|
'gl-ES': 'Galician (Spain)',
|
||||||
|
'gu': 'Gujarati',
|
||||||
|
'gu-IN': 'Gujarati (India)',
|
||||||
|
'he': 'Hebrew',
|
||||||
|
'he-IL': 'Hebrew (Israel)',
|
||||||
|
'hi': 'Hindi',
|
||||||
|
'hi-IN': 'Hindi (India)',
|
||||||
|
'hr': 'Croatian',
|
||||||
|
'hr-BA': 'Croatian (Bosnia and Herzegovina)',
|
||||||
|
'hr-HR': 'Croatian (Croatia)',
|
||||||
|
'hu': 'Hungarian',
|
||||||
|
'hu-HU': 'Hungarian (Hungary)',
|
||||||
|
'hy': 'Armenian',
|
||||||
|
'hy-AM': 'Armenian (Armenia)',
|
||||||
|
'id': 'Indonesian',
|
||||||
|
'id-ID': 'Indonesian (Indonesia)',
|
||||||
|
'is': 'Icelandic',
|
||||||
|
'is-IS': 'Icelandic (Iceland)',
|
||||||
|
'it': 'Italian',
|
||||||
|
'it-CH': 'Italian (Switzerland)',
|
||||||
|
'it-IT': 'Italian (Italy)',
|
||||||
|
'ja': 'Japanese',
|
||||||
|
'ja-JP': 'Japanese (Japan)',
|
||||||
|
'ka': 'Georgian',
|
||||||
|
'ka-GE': 'Georgian (Georgia)',
|
||||||
|
'kk': 'Kazakh',
|
||||||
|
'kk-KZ': 'Kazakh (Kazakhstan)',
|
||||||
|
'kn': 'Kannada',
|
||||||
|
'kn-IN': 'Kannada (India)',
|
||||||
|
'ko': 'Korean',
|
||||||
|
'ko-KR': 'Korean (Korea)',
|
||||||
|
'kok': 'Konkani',
|
||||||
|
'kok-IN': 'Konkani (India)',
|
||||||
|
'ky': 'Kyrgyz',
|
||||||
|
'ky-KG': 'Kyrgyz (Kyrgyzstan)',
|
||||||
|
'lt': 'Lithuanian',
|
||||||
|
'lt-LT': 'Lithuanian (Lithuania)',
|
||||||
|
'lv': 'Latvian',
|
||||||
|
'lv-LV': 'Latvian (Latvia)',
|
||||||
|
'mi': 'Maori',
|
||||||
|
'mi-NZ': 'Maori (New Zealand)',
|
||||||
|
'mk': 'FYRO Macedonian',
|
||||||
|
'mk-MK': 'FYRO Macedonian (Former Yugoslav Republic of Macedonia)',
|
||||||
|
'mn': 'Mongolian',
|
||||||
|
'mn-MN': 'Mongolian (Mongolia)',
|
||||||
|
'mr': 'Marathi',
|
||||||
|
'mr-IN': 'Marathi (India)',
|
||||||
|
'ms': 'Malay',
|
||||||
|
'ms-BN': 'Malay (Brunei Darussalam)',
|
||||||
|
'ms-MY': 'Malay (Malaysia)',
|
||||||
|
'mt': 'Maltese',
|
||||||
|
'mt-MT': 'Maltese (Malta)',
|
||||||
|
'nb': 'Norwegian (Bokm?l)',
|
||||||
|
'nb-NO': 'Norwegian (Bokm?l) (Norway)',
|
||||||
|
'nl': 'Dutch',
|
||||||
|
'nl-BE': 'Dutch (Belgium)',
|
||||||
|
'nl-NL': 'Dutch (Netherlands)',
|
||||||
|
'nn-NO': 'Norwegian (Nynorsk) (Norway)',
|
||||||
|
'ns': 'Northern Sotho',
|
||||||
|
'ns-ZA': 'Northern Sotho (South Africa)',
|
||||||
|
'pa': 'Punjabi',
|
||||||
|
'pa-IN': 'Punjabi (India)',
|
||||||
|
'pl': 'Polish',
|
||||||
|
'pl-PL': 'Polish (Poland)',
|
||||||
|
'ps': 'Pashto',
|
||||||
|
'ps-AR': 'Pashto (Afghanistan)',
|
||||||
|
'pt': 'Portuguese',
|
||||||
|
'pt-BR': 'Portuguese (Brazil)',
|
||||||
|
'pt-PT': 'Portuguese (Portugal)',
|
||||||
|
'qu': 'Quechua',
|
||||||
|
'qu-BO': 'Quechua (Bolivia)',
|
||||||
|
'qu-EC': 'Quechua (Ecuador)',
|
||||||
|
'qu-PE': 'Quechua (Peru)',
|
||||||
|
'ro': 'Romanian',
|
||||||
|
'ro-RO': 'Romanian (Romania)',
|
||||||
|
'ru': 'Russian',
|
||||||
|
'ru-RU': 'Russian (Russia)',
|
||||||
|
'sa': 'Sanskrit',
|
||||||
|
'sa-IN': 'Sanskrit (India)',
|
||||||
|
'se': 'Sami (Northern)',
|
||||||
|
'se-FI': 'Sami (Finland)',
|
||||||
|
'se-NO': 'Sami (Norway)',
|
||||||
|
'se-SE': 'Sami (Sweden)',
|
||||||
|
'sk': 'Slovak',
|
||||||
|
'sk-SK': 'Slovak (Slovakia)',
|
||||||
|
'sl': 'Slovenian',
|
||||||
|
'sl-SI': 'Slovenian (Slovenia)',
|
||||||
|
'sq': 'Albanian',
|
||||||
|
'sq-AL': 'Albanian (Albania)',
|
||||||
|
'sr-BA': 'Serbian (Bosnia and Herzegovina)',
|
||||||
|
'sr-SP': 'Serbian (Serbia and Montenegro)',
|
||||||
|
'sv': 'Swedish',
|
||||||
|
'sv-FI': 'Swedish (Finland)',
|
||||||
|
'sv-SE': 'Swedish (Sweden)',
|
||||||
|
'sw': 'Swahili',
|
||||||
|
'sw-KE': 'Swahili (Kenya)',
|
||||||
|
'syr': 'Syriac',
|
||||||
|
'syr-SY': 'Syriac (Syria)',
|
||||||
|
'ta': 'Tamil',
|
||||||
|
'ta-IN': 'Tamil (India)',
|
||||||
|
'te': 'Telugu',
|
||||||
|
'te-IN': 'Telugu (India)',
|
||||||
|
'th': 'Thai',
|
||||||
|
'th-TH': 'Thai (Thailand)',
|
||||||
|
'tl': 'Tagalog',
|
||||||
|
'tl-PH': 'Tagalog (Philippines)',
|
||||||
|
'tn': 'Tswana',
|
||||||
|
'tn-ZA': 'Tswana (South Africa)',
|
||||||
|
'tr': 'Turkish',
|
||||||
|
'tr-TR': 'Turkish (Turkey)',
|
||||||
|
'tt': 'Tatar',
|
||||||
|
'tt-RU': 'Tatar (Russia)',
|
||||||
|
'ts': 'Tsonga',
|
||||||
|
'uk': 'Ukrainian',
|
||||||
|
'uk-UA': 'Ukrainian (Ukraine)',
|
||||||
|
'ur': 'Urdu',
|
||||||
|
'ur-PK': 'Urdu (Islamic Republic of Pakistan)',
|
||||||
|
'uz': 'Uzbek (Latin)',
|
||||||
|
'uz-UZ': 'Uzbek (Uzbekistan)',
|
||||||
|
'vi': 'Vietnamese',
|
||||||
|
'vi-VN': 'Vietnamese (Viet Nam)',
|
||||||
|
'xh': 'Xhosa',
|
||||||
|
'xh-ZA': 'Xhosa (South Africa)',
|
||||||
|
'zh': 'Chinese',
|
||||||
|
'zh-CN': 'Chinese (S)',
|
||||||
|
'zh-HK': 'Chinese (Hong Kong)',
|
||||||
|
'zh-MO': 'Chinese (Macau)',
|
||||||
|
'zh-SG': 'Chinese (Singapore)',
|
||||||
|
'zh-TW': 'Chinese (T)',
|
||||||
|
'zu': 'Zulu',
|
||||||
|
'zu-ZA': 'Zulu (South Africa)',
|
||||||
|
};
|
||||||
|
|
|
@ -88,7 +88,7 @@ const configDataSchemaV2 = Joi.object<ConfigV2>({
|
||||||
useSpellChecker: Joi.boolean().default(true),
|
useSpellChecker: Joi.boolean().default(true),
|
||||||
enableHardwareAcceleration: Joi.boolean().default(true),
|
enableHardwareAcceleration: Joi.boolean().default(true),
|
||||||
autostart: Joi.boolean().default(true),
|
autostart: Joi.boolean().default(true),
|
||||||
spellCheckerLocale: Joi.string().regex(/^[a-z]{2}-[A-Z]{2}$/).default('en-US'),
|
spellCheckerLocale: Joi.string().default('en-US'),
|
||||||
spellCheckerURL: Joi.string().allow(null),
|
spellCheckerURL: Joi.string().allow(null),
|
||||||
darkMode: Joi.boolean().default(false),
|
darkMode: Joi.boolean().default(false),
|
||||||
downloadLocation: Joi.string(),
|
downloadLocation: Joi.string(),
|
||||||
|
@ -119,7 +119,7 @@ const configDataSchemaV3 = Joi.object<ConfigV3>({
|
||||||
useSpellChecker: Joi.boolean().default(true),
|
useSpellChecker: Joi.boolean().default(true),
|
||||||
enableHardwareAcceleration: Joi.boolean().default(true),
|
enableHardwareAcceleration: Joi.boolean().default(true),
|
||||||
autostart: Joi.boolean().default(true),
|
autostart: Joi.boolean().default(true),
|
||||||
spellCheckerLocale: Joi.string().regex(/^[a-z]{2}-[A-Z]{2}$/).default('en-US'),
|
spellCheckerLocales: Joi.array().items(Joi.string().regex(/^[a-z]{2}-[A-Z]{2}$/)).default([]),
|
||||||
spellCheckerURL: Joi.string().allow(null),
|
spellCheckerURL: Joi.string().allow(null),
|
||||||
darkMode: Joi.boolean().default(false),
|
darkMode: Joi.boolean().default(false),
|
||||||
downloadLocation: Joi.string(),
|
downloadLocation: Joi.string(),
|
||||||
|
|
|
@ -43,6 +43,7 @@ import {
|
||||||
UPDATE_SHORTCUT_MENU,
|
UPDATE_SHORTCUT_MENU,
|
||||||
OPEN_TEAMS_DROPDOWN,
|
OPEN_TEAMS_DROPDOWN,
|
||||||
UPDATE_LAST_ACTIVE,
|
UPDATE_LAST_ACTIVE,
|
||||||
|
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import {MattermostServer} from 'common/servers/MattermostServer';
|
import {MattermostServer} from 'common/servers/MattermostServer';
|
||||||
|
@ -265,6 +266,7 @@ function initializeInterCommunicationEventListeners() {
|
||||||
ipcMain.on(WINDOW_MINIMIZE, WindowManager.minimize);
|
ipcMain.on(WINDOW_MINIMIZE, WindowManager.minimize);
|
||||||
ipcMain.on(WINDOW_RESTORE, WindowManager.restore);
|
ipcMain.on(WINDOW_RESTORE, WindowManager.restore);
|
||||||
ipcMain.on(SHOW_SETTINGS_WINDOW, WindowManager.showSettingsWindow);
|
ipcMain.on(SHOW_SETTINGS_WINDOW, WindowManager.showSettingsWindow);
|
||||||
|
ipcMain.handle(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES, handleGetAvailableSpellCheckerLanguages);
|
||||||
ipcMain.handle(GET_DOWNLOAD_LOCATION, handleSelectDownload);
|
ipcMain.handle(GET_DOWNLOAD_LOCATION, handleSelectDownload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +291,7 @@ function handleConfigUpdate(newConfig: CombinedConfig) {
|
||||||
authManager.handleConfigUpdate(newConfig);
|
authManager.handleConfigUpdate(newConfig);
|
||||||
}
|
}
|
||||||
setUnreadBadgeSetting(newConfig && newConfig.showUnreadBadge);
|
setUnreadBadgeSetting(newConfig && newConfig.showUnreadBadge);
|
||||||
|
updateSpellCheckerLocales();
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.emit('update-menu', true, config);
|
ipcMain.emit('update-menu', true, config);
|
||||||
|
@ -639,6 +642,12 @@ function handleRemoveServerModal(e: IpcMainEvent, name: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSpellCheckerLocales() {
|
||||||
|
if (config.data?.spellCheckerLocales.length && app.isReady()) {
|
||||||
|
session.defaultSession.setSpellCheckerLanguages(config.data?.spellCheckerLocales);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initializeAfterAppReady() {
|
function initializeAfterAppReady() {
|
||||||
updateServerInfos(config.teams);
|
updateServerInfos(config.teams);
|
||||||
app.setAppUserModelId('Mattermost.Desktop'); // Use explicit AppUserModelID
|
app.setAppUserModelId('Mattermost.Desktop'); // Use explicit AppUserModelID
|
||||||
|
@ -662,6 +671,7 @@ function initializeAfterAppReady() {
|
||||||
log.info(`Dictionary definitions downloaded successfully for ${lang}`);
|
log.info(`Dictionary definitions downloaded successfully for ${lang}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
updateSpellCheckerLocales();
|
||||||
}
|
}
|
||||||
|
|
||||||
const appVersionJson = path.join(app.getPath('userData'), 'app-state.json');
|
const appVersionJson = path.join(app.getPath('userData'), 'app-state.json');
|
||||||
|
@ -975,3 +985,6 @@ function handleUpdateLastActive(event: IpcMainEvent, serverName: string, viewNam
|
||||||
config.set('lastActiveTeam', teams.find((team) => team.name === serverName)?.order || 0);
|
config.set('lastActiveTeam', teams.find((team) => team.name === serverName)?.order || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleGetAvailableSpellCheckerLanguages() {
|
||||||
|
return session.defaultSession.availableSpellCheckerLanguages;
|
||||||
|
}
|
||||||
|
|
|
@ -8,13 +8,23 @@ import 'renderer/css/settings.css';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button} from 'react-bootstrap';
|
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button} from 'react-bootstrap';
|
||||||
|
import ReactSelect, {ActionMeta, OptionsType} from 'react-select';
|
||||||
|
|
||||||
import {debounce} from 'underscore';
|
import {debounce} from 'underscore';
|
||||||
|
|
||||||
import {CombinedConfig, LocalConfiguration, Team} from 'types/config';
|
import {CombinedConfig, LocalConfiguration} from 'types/config';
|
||||||
import {DeepPartial} from 'types/utils';
|
import {DeepPartial} from 'types/utils';
|
||||||
|
|
||||||
import {GET_LOCAL_CONFIGURATION, UPDATE_CONFIGURATION, DOUBLE_CLICK_ON_WINDOW, GET_DOWNLOAD_LOCATION, ADD_SERVER, RELOAD_CONFIGURATION} from 'common/communication';
|
import {localeTranslations} from 'common/utils/constants';
|
||||||
|
|
||||||
|
import {
|
||||||
|
GET_LOCAL_CONFIGURATION,
|
||||||
|
UPDATE_CONFIGURATION,
|
||||||
|
DOUBLE_CLICK_ON_WINDOW,
|
||||||
|
GET_DOWNLOAD_LOCATION,
|
||||||
|
RELOAD_CONFIGURATION,
|
||||||
|
GET_AVAILABLE_SPELL_CHECKER_LANGUAGES,
|
||||||
|
} from 'common/communication';
|
||||||
|
|
||||||
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
|
import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';
|
||||||
|
|
||||||
|
@ -26,13 +36,11 @@ type ConfigType = typeof CONFIG_TYPE_SERVERS | typeof CONFIG_TYPE_APP_OPTIONS;
|
||||||
type State = DeepPartial<CombinedConfig> & {
|
type State = DeepPartial<CombinedConfig> & {
|
||||||
ready: boolean;
|
ready: boolean;
|
||||||
maximized?: boolean;
|
maximized?: boolean;
|
||||||
teams?: Team[];
|
|
||||||
showAddTeamForm: boolean;
|
|
||||||
trayWasVisible?: boolean;
|
trayWasVisible?: boolean;
|
||||||
firstRun?: boolean;
|
|
||||||
savingState: SavingStateItems;
|
savingState: SavingStateItems;
|
||||||
userOpenedDownloadDialog: boolean;
|
userOpenedDownloadDialog: boolean;
|
||||||
allowSaveSpellCheckerURL: boolean;
|
allowSaveSpellCheckerURL: boolean;
|
||||||
|
availableLanguages: Array<{label: string; value: string}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type SavingStateItems = {
|
type SavingStateItems = {
|
||||||
|
@ -61,18 +69,19 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
|
|
||||||
saveQueue: SaveQueueItem[];
|
saveQueue: SaveQueueItem[];
|
||||||
|
|
||||||
|
selectedSpellCheckerLocales: Array<{label: string; value: string}>;
|
||||||
|
|
||||||
constructor(props: Record<string, never>) {
|
constructor(props: Record<string, never>) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
ready: false,
|
ready: false,
|
||||||
teams: [],
|
|
||||||
showAddTeamForm: false,
|
|
||||||
savingState: {
|
savingState: {
|
||||||
appOptions: SavingState.SAVING_STATE_DONE,
|
appOptions: SavingState.SAVING_STATE_DONE,
|
||||||
servers: SavingState.SAVING_STATE_DONE,
|
servers: SavingState.SAVING_STATE_DONE,
|
||||||
},
|
},
|
||||||
userOpenedDownloadDialog: false,
|
userOpenedDownloadDialog: false,
|
||||||
allowSaveSpellCheckerURL: false,
|
allowSaveSpellCheckerURL: false,
|
||||||
|
availableLanguages: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getConfig();
|
this.getConfig();
|
||||||
|
@ -89,19 +98,20 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
this.spellCheckerURLRef = React.createRef();
|
this.spellCheckerURLRef = React.createRef();
|
||||||
|
|
||||||
this.saveQueue = [];
|
this.saveQueue = [];
|
||||||
|
this.selectedSpellCheckerLocales = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.ipcRenderer.on(ADD_SERVER, () => {
|
|
||||||
this.setState({
|
|
||||||
showAddTeamForm: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
window.ipcRenderer.on(RELOAD_CONFIGURATION, () => {
|
window.ipcRenderer.on(RELOAD_CONFIGURATION, () => {
|
||||||
this.updateSaveState();
|
this.updateSaveState();
|
||||||
this.getConfig();
|
this.getConfig();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.ipcRenderer.invoke(GET_AVAILABLE_SPELL_CHECKER_LANGUAGES).then((languages: string[]) => {
|
||||||
|
const availableLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
|
||||||
|
availableLanguages.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
|
this.setState({availableLanguages});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getConfig = () => {
|
getConfig = () => {
|
||||||
|
@ -112,16 +122,12 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
|
|
||||||
convertConfigDataToState = (configData: Partial<LocalConfiguration>, currentState: Partial<State> = {}) => {
|
convertConfigDataToState = (configData: Partial<LocalConfiguration>, currentState: Partial<State> = {}) => {
|
||||||
const newState = Object.assign({} as State, configData);
|
const newState = Object.assign({} as State, configData);
|
||||||
newState.showAddTeamForm = currentState.showAddTeamForm || false;
|
|
||||||
newState.trayWasVisible = currentState.trayWasVisible || false;
|
newState.trayWasVisible = currentState.trayWasVisible || false;
|
||||||
if (newState.teams?.length === 0 && currentState.firstRun !== false) {
|
|
||||||
newState.firstRun = false;
|
|
||||||
newState.showAddTeamForm = true;
|
|
||||||
}
|
|
||||||
newState.savingState = currentState.savingState || {
|
newState.savingState = currentState.savingState || {
|
||||||
appOptions: SavingState.SAVING_STATE_DONE,
|
appOptions: SavingState.SAVING_STATE_DONE,
|
||||||
servers: SavingState.SAVING_STATE_DONE,
|
servers: SavingState.SAVING_STATE_DONE,
|
||||||
};
|
};
|
||||||
|
this.selectedSpellCheckerLocales = configData.spellCheckerLocales?.map((language: string) => ({label: localeTranslations[language] || language, value: language})) || [];
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,17 +178,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
handleTeamsChange = (teams: Team[]) => {
|
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_SERVERS, {key: 'teams', data: teams});
|
|
||||||
this.setState({
|
|
||||||
showAddTeamForm: false,
|
|
||||||
teams,
|
|
||||||
});
|
|
||||||
if (teams.length === 0) {
|
|
||||||
this.setState({showAddTeamForm: true});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleChangeShowTrayIcon = () => {
|
handleChangeShowTrayIcon = () => {
|
||||||
const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
|
const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
|
||||||
|
@ -220,19 +215,6 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleShowTeamForm = () => {
|
|
||||||
this.setState({
|
|
||||||
showAddTeamForm: !this.state.showAddTeamForm,
|
|
||||||
});
|
|
||||||
(document.activeElement as HTMLElement).blur();
|
|
||||||
}
|
|
||||||
|
|
||||||
setShowTeamFormVisibility = (val: boolean) => {
|
|
||||||
this.setState({
|
|
||||||
showAddTeamForm: val,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFlashWindow = () => {
|
handleFlashWindow = () => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
|
||||||
key: 'notifications',
|
key: 'notifications',
|
||||||
|
@ -295,6 +277,22 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChangeSpellCheckerLocales = (value: OptionsType<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
|
||||||
|
switch (actionMeta.action) {
|
||||||
|
case 'select-option':
|
||||||
|
this.selectedSpellCheckerLocales = [...value];
|
||||||
|
break;
|
||||||
|
case 'remove-value':
|
||||||
|
this.selectedSpellCheckerLocales = this.selectedSpellCheckerLocales.filter((language) => language.value !== actionMeta.removedValue.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const values = this.selectedSpellCheckerLocales.map((language) => language.value);
|
||||||
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerLocales', data: values});
|
||||||
|
this.setState({
|
||||||
|
spellCheckerLocales: values,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
handleChangeEnableHardwareAcceleration = () => {
|
handleChangeEnableHardwareAcceleration = () => {
|
||||||
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
|
window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -426,21 +424,36 @@ export default class SettingsPage extends React.PureComponent<Record<string, nev
|
||||||
}
|
}
|
||||||
|
|
||||||
options.push(
|
options.push(
|
||||||
<FormCheck>
|
<>
|
||||||
<FormCheck.Input
|
<FormCheck>
|
||||||
type='checkbox'
|
<FormCheck.Input
|
||||||
key='inputSpellChecker'
|
type='checkbox'
|
||||||
id='inputSpellChecker'
|
key='inputSpellChecker'
|
||||||
ref={this.useSpellCheckerRef}
|
id='inputSpellChecker'
|
||||||
checked={this.state.useSpellChecker}
|
ref={this.useSpellCheckerRef}
|
||||||
onChange={this.handleChangeUseSpellChecker}
|
checked={this.state.useSpellChecker}
|
||||||
/>
|
onChange={this.handleChangeUseSpellChecker}
|
||||||
{'Check spelling'}
|
/>
|
||||||
<FormText>
|
{'Check spelling'}
|
||||||
{'Highlight misspelled words in your messages based on your system language configuration. '}
|
<FormText>
|
||||||
{'Setting takes effect after restarting the app.'}
|
{'Highlight misspelled words in your messages based on your system language or language preference. '}
|
||||||
</FormText>
|
{'Setting takes effect after restarting the app.'}
|
||||||
</FormCheck>);
|
</FormText>
|
||||||
|
</FormCheck>
|
||||||
|
{this.state.useSpellChecker &&
|
||||||
|
<ReactSelect
|
||||||
|
className='SettingsPage__spellCheckerLocalesDropdown'
|
||||||
|
classNamePrefix='SettingsPage__spellCheckerLocalesDropdown'
|
||||||
|
options={this.state.availableLanguages}
|
||||||
|
isMulti={true}
|
||||||
|
isClearable={false}
|
||||||
|
onChange={this.handleChangeSpellCheckerLocales}
|
||||||
|
value={this.selectedSpellCheckerLocales}
|
||||||
|
placeholder={'Select preferred language(s)'}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</>,
|
||||||
|
);
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
if (this.state.spellCheckerURL === null || typeof this.state.spellCheckerURL === 'undefined') {
|
if (this.state.spellCheckerURL === null || typeof this.state.spellCheckerURL === 'undefined') {
|
||||||
options.push(
|
options.push(
|
||||||
|
|
|
@ -3,3 +3,19 @@
|
||||||
.TeamListItem:hover {
|
.TeamListItem:hover {
|
||||||
background: #242a30;
|
background: #242a30;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SettingsPage__spellCheckerLocalesDropdown .SettingsPage__spellCheckerLocalesDropdown__control {
|
||||||
|
background: #242a30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SettingsPage__spellCheckerLocalesDropdown .SettingsPage__spellCheckerLocalesDropdown__menu {
|
||||||
|
background: #242a30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SettingsPage__spellCheckerLocalesDropdown .SettingsPage__spellCheckerLocalesDropdown__option {
|
||||||
|
background: #242a30;
|
||||||
|
}
|
||||||
|
|
||||||
|
.SettingsPage__spellCheckerLocalesDropdown .SettingsPage__spellCheckerLocalesDropdown__option:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.16);
|
||||||
|
}
|
||||||
|
|
|
@ -35,3 +35,9 @@ body {
|
||||||
background-color: #166de0;
|
background-color: #166de0;
|
||||||
border-color: #166de0;
|
border-color: #166de0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.SettingsPage__spellCheckerLocalesDropdown {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-left: 16px;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ export type ConfigV3 = {
|
||||||
useSpellChecker: boolean;
|
useSpellChecker: boolean;
|
||||||
enableHardwareAcceleration: boolean;
|
enableHardwareAcceleration: boolean;
|
||||||
autostart: boolean;
|
autostart: boolean;
|
||||||
spellCheckerLocale: string;
|
spellCheckerLocales: string[];
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
downloadLocation: string;
|
downloadLocation: string;
|
||||||
spellCheckerURL?: string;
|
spellCheckerURL?: string;
|
||||||
|
|
Loading…
Reference in a new issue