From 15ad2ea91f375eaa75dcef8c58c2f084291ad573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 18 May 2024 15:47:36 +0200 Subject: [PATCH] Client-side language detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- package.json | 1 + src/actions/compose.ts | 18 +++++++-- .../compose/components/language-dropdown.tsx | 11 +++++- .../compose/editor/plugins/state-plugin.tsx | 38 ++++++++++++++++--- src/reducers/compose.ts | 5 +++ src/schemas/instance.ts | 4 -- src/utils/features.ts | 10 ++++- vite.config.ts | 6 +++ yarn.lock | 12 ++++++ 9 files changed, 89 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 292a83633..6f7283225 100644 --- a/package.json +++ b/package.json @@ -117,6 +117,7 @@ "escape-html": "^1.0.3", "eslint-plugin-formatjs": "^4.12.2", "exifr": "^7.1.3", + "fasttext.wasm.js": "^1.0.0", "fuzzysort": "^3.0.0", "graphemesplit": "^2.4.4", "html-react-parser": "^5.0.0", diff --git a/src/actions/compose.ts b/src/actions/compose.ts index ba736151e..2bc67c8e6 100644 --- a/src/actions/compose.ts +++ b/src/actions/compose.ts @@ -90,7 +90,8 @@ const COMPOSE_EDITOR_STATE_SET = 'COMPOSE_EDITOR_STATE_SET' as const; const COMPOSE_CHANGE_MEDIA_ORDER = 'COMPOSE_CHANGE_MEDIA_ORDER' as const; -const COMPOSE_ADD_SUGGESTED_QUOTE = 'COMPOSE_ADD_SUGGESTED_QUOTE' as const; +const COMPOSE_ADD_SUGGESTED_QUOTE = 'COMPOSE_ADD_SUGGESTED_QUOTE' as const; +const COMPOSE_ADD_SUGGESTED_LANGUAGE = 'COMPOSE_ADD_SUGGESTED_LANGUAGE' as const; const getAccount = makeGetAccount(); @@ -380,7 +381,7 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => content_type: contentType, poll: compose.poll, scheduled_at: compose.schedule, - language: compose.language, + language: compose.language || compose.suggested_language, to, }; @@ -875,7 +876,7 @@ const eventDiscussionCompose = (composeId: string, status: Status) => const setEditorState = (composeId: string, editorState: EditorState | string | null, text?: string) => ({ type: COMPOSE_EDITOR_STATE_SET, id: composeId, - editorState: editorState, + editorState, text, }); @@ -889,7 +890,13 @@ const changeMediaOrder = (composeId: string, a: string, b: string) => ({ const addSuggestedQuote = (composeId: string, quoteId: string) => ({ type: COMPOSE_ADD_SUGGESTED_QUOTE, id: composeId, - quoteId: quoteId, + quoteId, +}); + +const addSuggestedLanguage = (composeId: string, language: string) => ({ + type: COMPOSE_ADD_SUGGESTED_LANGUAGE, + id: composeId, + language, }); type ComposeAction = @@ -940,6 +947,7 @@ type ComposeAction = | ReturnType | ReturnType | ReturnType + | ReturnType export { COMPOSE_CHANGE, @@ -990,6 +998,7 @@ export { COMPOSE_EDITOR_STATE_SET, COMPOSE_CHANGE_MEDIA_ORDER, COMPOSE_ADD_SUGGESTED_QUOTE, + COMPOSE_ADD_SUGGESTED_LANGUAGE, setComposeToStatus, changeCompose, replyCompose, @@ -1047,5 +1056,6 @@ export { setEditorState, changeMediaOrder, addSuggestedQuote, + addSuggestedLanguage, type ComposeAction, }; diff --git a/src/features/compose/components/language-dropdown.tsx b/src/features/compose/components/language-dropdown.tsx index 99a157bd3..8ed307393 100644 --- a/src/features/compose/components/language-dropdown.tsx +++ b/src/features/compose/components/language-dropdown.tsx @@ -27,6 +27,7 @@ const languages = Object.entries(languagesObject) as Array<[Language, string]>; const messages = defineMessages({ languagePrompt: { id: 'compose.language_dropdown.prompt', defaultMessage: 'Select language' }, + languageSuggestion: { id: 'compose.language_dropdown.suggestion', defaultMessage: '{language} (detected)' }, search: { id: 'compose.language_dropdown.search', defaultMessage: 'Search language…' }, }); @@ -61,7 +62,7 @@ const LanguageDropdown: React.FC = ({ composeId }) => { ], }); - const language = useCompose(composeId).language; + const { language, suggested_language: suggestedLanguage } = useCompose(composeId); const handleClick: React.EventHandler< React.MouseEvent | React.KeyboardEvent @@ -253,12 +254,18 @@ const LanguageDropdown: React.FC = ({ composeId }) => { const isSearching = searchValue !== ''; const results = search(); + let buttonLabel = intl.formatMessage(messages.languagePrompt); + if (language) buttonLabel = languagesObject[language]; + else if (suggestedLanguage) buttonLabel = intl.formatMessage(messages.languageSuggestion, { + language: languagesObject[suggestedLanguage as Language] || suggestedLanguage, + }); + return ( <>