From 629637a599ac7c36a8676e28945901296893b844 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 11 Nov 2024 16:52:48 +0100 Subject: [PATCH] [Enhancement #553] Allow selecting content language when creating file. --- .../multilingual/EditLanguageSelector.tsx | 29 ++-------------- .../resource/file/CreateFileMetadata.tsx | 26 ++++++++++++++- .../resource/file/LanguageSelector.tsx | 33 +++++++++++++++++++ src/i18n/cs.ts | 1 + src/i18n/en.ts | 1 + src/util/IntlUtil.ts | 28 ++++++++++++++++ 6 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 src/component/resource/file/LanguageSelector.tsx diff --git a/src/component/multilingual/EditLanguageSelector.tsx b/src/component/multilingual/EditLanguageSelector.tsx index fd743a9e..dcc7d3ba 100644 --- a/src/component/multilingual/EditLanguageSelector.tsx +++ b/src/component/multilingual/EditLanguageSelector.tsx @@ -1,10 +1,8 @@ import * as React from "react"; -import ISO6391 from "iso-639-1"; import classNames from "classnames"; // @ts-ignore import { IntelligentTreeSelect } from "intelligent-tree-select"; -import Constants from "../../util/Constants"; -import { getShortLocale } from "../../util/IntlUtil"; +import { getLanguageOptions, Language } from "../../util/IntlUtil"; import { renderLanguages } from "./LanguageSelector"; import { Nav, NavItem, NavLink } from "reactstrap"; import { FaPlusCircle } from "react-icons/fa"; @@ -18,29 +16,6 @@ interface EditLanguageSelectorProps { onRemove: (lang: string) => void; } -interface Language { - code: string; - name: string; - nativeName: string; -} - -function prioritizeLanguages(options: Language[], languages: string[]) { - languages.forEach((lang) => { - const ind = options.findIndex((v) => v.code === lang); - const option = options[ind]; - options.splice(ind, 1); - options.unshift(option); - }); - return options; -} - -const OPTIONS = prioritizeLanguages( - ISO6391.getLanguages(ISO6391.getAllCodes()), - Object.getOwnPropertyNames(Constants.LANG).map((lang) => - getShortLocale(Constants.LANG[lang].locale) - ) -); - const EditLanguageSelector: React.FC = (props) => { const { language, existingLanguages, onSelect, onRemove } = props; const { i18n, formatMessage } = useI18n(); @@ -51,7 +26,7 @@ const EditLanguageSelector: React.FC = (props) => { if (existingLanguages.indexOf(language) === -1) { existingLanguages.push(language); } - const options = OPTIONS.slice(); + const options = getLanguageOptions().slice(); for (const existing of existingLanguages) { const toRemove = options.findIndex((o) => o.code === existing); options.splice(toRemove, 1); diff --git a/src/component/resource/file/CreateFileMetadata.tsx b/src/component/resource/file/CreateFileMetadata.tsx index 07433906..daf7de26 100644 --- a/src/component/resource/file/CreateFileMetadata.tsx +++ b/src/component/resource/file/CreateFileMetadata.tsx @@ -1,9 +1,20 @@ import React from "react"; -import { Button, ButtonToolbar, Col, Form, Row } from "reactstrap"; +import { + Button, + ButtonToolbar, + Col, + Form, + FormGroup, + Label, + Row, +} from "reactstrap"; import UploadFile from "./UploadFile"; import TermItFile from "../../../model/File"; import CustomInput from "../../misc/CustomInput"; import { useI18n } from "../../hook/useI18n"; +import { useSelector } from "react-redux"; +import TermItState from "../../../model/TermItState"; +import LanguageSelector from "./LanguageSelector"; interface CreateFileMetadataProps { onCreate: (termItFile: TermItFile, file: File) => any; @@ -17,6 +28,10 @@ const CreateFileMetadata: React.FC = ({ const { i18n } = useI18n(); const [label, setLabel] = React.useState(""); const [file, setFile] = React.useState(); + const lang = useSelector( + (state: TermItState) => state.configuration.language + ); + const [language, setLanguage] = React.useState(lang); const onFileSelected = (file: File) => { setFile(file); @@ -28,6 +43,7 @@ const CreateFileMetadata: React.FC = ({ new TermItFile({ iri: "", label, + language, }), file ); @@ -51,6 +67,14 @@ const CreateFileMetadata: React.FC = ({ /> + + + + + + + + diff --git a/src/component/resource/file/LanguageSelector.tsx b/src/component/resource/file/LanguageSelector.tsx new file mode 100644 index 00000000..ea46c853 --- /dev/null +++ b/src/component/resource/file/LanguageSelector.tsx @@ -0,0 +1,33 @@ +import React from "react"; +// @ts-ignore +import { IntelligentTreeSelect } from "intelligent-tree-select"; +import { getLanguageOptions, Language } from "../../../util/IntlUtil"; +import { useI18n } from "../../hook/useI18n"; + +const LanguageSelector: React.FC<{ + onChange: (lang: string) => void; + value: string; +}> = ({ onChange, value }) => { + const options = getLanguageOptions(); + const { i18n } = useI18n(); + return ( + onChange(item.code)} + options={options} + maxHeight={200} + multi={false} + labelKey="nativeName" + valueKey="code" + classNamePrefix="react-select" + simpleTreeData={true} + renderAsTree={false} + showSettings={false} + isClearable={false} + placeholder="" + noResultsText={i18n("search.no-results")} + value={options.find((o) => o.code === value)} + /> + ); +}; + +export default LanguageSelector; diff --git a/src/i18n/cs.ts b/src/i18n/cs.ts index ebeb3399..3268bfbd 100644 --- a/src/i18n/cs.ts +++ b/src/i18n/cs.ts @@ -622,6 +622,7 @@ const cs = { "file.upload.hint": "Maximální velikost souboru: {maxUploadFileSize}. Má-li být soubor použit pro extrakci pojmů do slovníku, musí být ve formátu UTF-8, nebo validní MS Excel.", "file.upload.size.exceeded": "Soubor je příliš velký.", + "file.language": "Jazyk obsahu souboru", "dataset.license": "Licence", "dataset.format": "Formát", diff --git a/src/i18n/en.ts b/src/i18n/en.ts index ea573359..3f375228 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -613,6 +613,7 @@ const en = { "file.upload.hint": "Maximum file size: {maxUploadFileSize}. To use the file for term extraction, it must be in UTF-8 or a valid MS Excel file.", "file.upload.size.exceeded": "File is too large.", + "file.language": "File content language", "dataset.license": "License", "dataset.format": "Format", diff --git a/src/util/IntlUtil.ts b/src/util/IntlUtil.ts index 3c5631dd..56f9acc2 100644 --- a/src/util/IntlUtil.ts +++ b/src/util/IntlUtil.ts @@ -2,6 +2,7 @@ import Constants from "./Constants"; import IntlData from "../model/IntlData"; import BrowserStorage from "./BrowserStorage"; import Utils from "./Utils"; +import ISO6391 from "iso-639-1"; export function loadInitialLocalizationData(): IntlData { const prefLang = BrowserStorage.get(Constants.STORAGE_LANG_KEY); @@ -88,3 +89,30 @@ export function removeTranslation( } }); } + +export interface Language { + code: string; + name: string; + nativeName: string; +} + +function prioritizeLanguages(options: Language[], languages: string[]) { + languages.forEach((lang) => { + const ind = options.findIndex((v) => v.code === lang); + const option = options[ind]; + options.splice(ind, 1); + options.unshift(option); + }); + return options; +} + +const LANGUAGE_OPTIONS = prioritizeLanguages( + ISO6391.getLanguages(ISO6391.getAllCodes()), + Object.getOwnPropertyNames(Constants.LANG).map((lang) => + getShortLocale(Constants.LANG[lang].locale) + ) +); + +export function getLanguageOptions(): Language[] { + return LANGUAGE_OPTIONS; +}