fix(translation) translation button visibility for users, add missing languages

This commit is contained in:
tamasdomokos 2022-09-29 14:44:59 +03:00 committed by GitHub
parent 69e0a37529
commit 8162ae4dbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 179 additions and 37 deletions

View File

@ -375,6 +375,14 @@ var config = {
// // Whether the feature should be enabled or not. // // Whether the feature should be enabled or not.
// enabled: false, // enabled: false,
// // Translation languages.
// // Available languages can be found in
// // ./src/react/features/transcribing/translation-languages.json.
// translationLanguages: ['en', 'es', 'fr', 'ro'],
// // Important languages to show on the top of the language list.
// translationLanguagesHead: ['en'],
// // If true transcriber will use the application language. // // If true transcriber will use the application language.
// // The application language is either explicitly set by participants in their settings or automatically // // The application language is either explicitly set by participants in their settings or automatically
// // detected based on the environment, e.g. if the app is opened in a chrome instance which // // detected based on the environment, e.g. if the app is opened in a chrome instance which
@ -1349,6 +1357,8 @@ var config = {
*/ */
mouseMoveCallbackInterval: 1000, mouseMoveCallbackInterval: 1000,
hiddenDomain: 'tdomokos.jitsi.net',
/** /**
Use this array to configure which notifications will be shown to the user Use this array to configure which notifications will be shown to the user
The items correspond to the title or description key of that notification The items correspond to the title or description key of that notification

View File

@ -0,0 +1,111 @@
{
"af": "Afrikaans",
"am": "Amharic",
"ar": "Arabic",
"az": "Azerbaijani",
"be": "Belarusian",
"bg": "Bulgarian",
"bn": "Bengali",
"bs": "Bosnian",
"ca": "Catalan",
"ceb": "Cebuano",
"co": "Corsican",
"cs": "Czech",
"cy": "Welsh",
"da": "Danish",
"de": "German",
"el": "Greek",
"en": "English",
"eo": "Esperanto",
"es": "Spanish",
"et": "Estonian",
"eu": "Basque",
"fa": "Persian",
"fi": "Finnish",
"fr": "French",
"fy": "Frisian",
"ga": "Irish",
"gd": "Scots Gaelic",
"gl": "Galician",
"gu": "Gujarati",
"ha": "Hausa",
"haw": "Hawaiian",
"he": "Hebrew",
"hi": "Hindi",
"hmn": "Hmong",
"hr": "Croatian",
"ht": "Haitian Creole",
"hu": "Hungarian",
"hy": "Armenian",
"id": "Indonesian",
"ig": "Igbo",
"is": "Icelandic",
"it": "Italian",
"ja": "Japanese",
"jv": "Javanese",
"ka": "Georgian",
"kk": "Kazakh",
"km": "Khmer",
"kn": "Kannada",
"ko": "Korean",
"ku": "Kurdish",
"ky": "Kyrgyz",
"la": "Latin",
"lb": "Luxembourgish",
"lo": "Lao",
"lt": "Lithuanian",
"lv": "Latvian",
"mg": "Malagasy",
"mi": "Maori",
"mk": "Macedonian",
"ml": "Malayalam",
"mn": "Mongolian",
"mr": "Marathi",
"ms": "Malay",
"mt": "Maltese",
"my": "Myanmar (Burmese)",
"ne": "Nepali",
"nl": "Dutch",
"no": "Norwegian",
"ny": "Nyanja (Chichewa)",
"or": "Odia (Oriya)",
"pa": "Punjabi",
"pl": "Polish",
"ps": "Pashto",
"pt": "Portuguese (Portugal, Brazil)",
"ro": "Romanian",
"ru": "Russian",
"rw": "Kinyarwanda",
"sd": "Sindhi",
"si": "Sinhala (Sinhalese)",
"sk": "Slovak",
"sl": "Slovenian",
"sm": "Samoan",
"sn": "Shona",
"so": "Somali",
"sq": "Albanian",
"sr": "Serbian",
"st": "Sesotho",
"su": "Sundanese",
"sv": "Swedish",
"sw": "Swahili",
"ta": "Tamil",
"te": "Telugu",
"tg": "Tajik",
"th": "Thai",
"tk": "Turkmen",
"tl": "Tagalog (Filipino)",
"tr": "Turkish",
"tt": "Tatar",
"ug": "Uyghur",
"uk": "Ukrainian",
"ur": "Urdu",
"uz": "Uzbek",
"vi": "Vietnamese",
"xh": "Xhosa",
"yi": "Yiddish",
"yo": "Yoruba",
"zh-CN": "Chinese (Simplified)",
"zh-TW": "Chinese (Traditional)",
"zu": "Zulu"
}

View File

@ -464,6 +464,8 @@ export interface IConfig {
disableStartForAll?: boolean; disableStartForAll?: boolean;
enabled?: boolean; enabled?: boolean;
preferredLanguage?: string; preferredLanguage?: string;
translationLanguages?: Array<string>;
translationLanguagesHead?: Array<string>;
useAppLanguage?: boolean; useAppLanguage?: boolean;
}; };
useHostPageLocalStorage?: boolean; useHostPageLocalStorage?: boolean;

View File

@ -7,6 +7,7 @@ import _ from 'lodash';
import LANGUAGES_RESOURCES from '../../../../lang/languages.json'; import LANGUAGES_RESOURCES from '../../../../lang/languages.json';
import MAIN_RESOURCES from '../../../../lang/main.json'; import MAIN_RESOURCES from '../../../../lang/main.json';
import TRANSLATION_LANGUAGES_RESOURCES from '../../../../lang/translation-languages.json';
import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes'; import { I18NEXT_INITIALIZED, LANGUAGE_CHANGED } from './actionTypes';
// eslint-disable-next-line lines-around-comment // eslint-disable-next-line lines-around-comment
@ -36,22 +37,21 @@ const COUNTRIES = _.merge({}, COUNTRIES_RESOURCES, COUNTRIES_RESOURCES_OVERRIDES
export const LANGUAGES: Array<string> = Object.keys(LANGUAGES_RESOURCES); export const LANGUAGES: Array<string> = Object.keys(LANGUAGES_RESOURCES);
/** /**
* The languages for the top section of the translation language list. * The available/supported translation languages.
*
* @public
* @type {Array<string>}
*/
export const TRANSLATION_LANGUAGES: Array<string> = Object.keys(TRANSLATION_LANGUAGES_RESOURCES);
/**
* The available/supported translation languages head. (Languages displayed on the top ).
* *
* @public * @public
* @type {Array<string>} * @type {Array<string>}
*/ */
export const TRANSLATION_LANGUAGES_HEAD: Array<string> = [ 'en' ]; export const TRANSLATION_LANGUAGES_HEAD: Array<string> = [ 'en' ];
/**
* The languages to explude from the translation language list.
*
* @public
* @type {Array<string>}
*/
export const TRANSLATION_LANGUAGES_EXCLUDE: Array<string>
= [ 'enGB', 'esUS', 'frCA', 'hsb', 'kab', 'ptBR', 'zhCN', 'zhTW' ];
/** /**
* The default language. * The default language.
* *
@ -77,7 +77,7 @@ const options = {
escapeValue: false // not needed for react as it escapes by default escapeValue: false // not needed for react as it escapes by default
}, },
load: 'languageOnly', load: 'languageOnly',
ns: [ 'main', 'languages', 'countries' ], ns: [ 'main', 'languages', 'countries', 'translation-languages' ],
react: { react: {
// re-render when a new resource bundle is added // re-render when a new resource bundle is added
bindI18nStore: 'added', bindI18nStore: 'added',
@ -109,6 +109,12 @@ i18next.addResourceBundle(
LANGUAGES_RESOURCES, LANGUAGES_RESOURCES,
/* deep */ true, /* deep */ true,
/* overwrite */ true); /* overwrite */ true);
i18next.addResourceBundle(
DEFAULT_LANGUAGE,
'translation-languages',
TRANSLATION_LANGUAGES_RESOURCES,
/* deep */ true,
/* overwrite */ true);
i18next.addResourceBundle( i18next.addResourceBundle(
DEFAULT_LANGUAGE, DEFAULT_LANGUAGE,
'main', 'main',

View File

@ -4,4 +4,4 @@ export * from './functions';
// TODO Eventually (e.g. when the non-React Web app is rewritten into React), it // TODO Eventually (e.g. when the non-React Web app is rewritten into React), it
// should not be necessary to export i18next. // should not be necessary to export i18next.
export { default as i18next, DEFAULT_LANGUAGE, export { default as i18next, DEFAULT_LANGUAGE,
LANGUAGES, TRANSLATION_LANGUAGES_HEAD, TRANSLATION_LANGUAGES_EXCLUDE } from './i18next'; LANGUAGES, TRANSLATION_LANGUAGES, TRANSLATION_LANGUAGES_HEAD, i18n } from './i18next';

View File

@ -11,7 +11,7 @@ export * from './actions.any';
* type: UPDATE_TRANSLATION_LANGUAGE * type: UPDATE_TRANSLATION_LANGUAGE
* }} * }}
*/ */
export function toggleLangugeSelectorDialog() { export function toggleLanguageSelectorDialog() {
return function(dispatch: (Object) => Object) { return function(dispatch: (Object) => Object) {
dispatch(toggleDialog(LanguageSelectorDialogWeb)); dispatch(toggleDialog(LanguageSelectorDialogWeb));
}; };

View File

@ -3,7 +3,7 @@
import { translate } from '../../base/i18n'; import { translate } from '../../base/i18n';
import { IconClosedCaption } from '../../base/icons'; import { IconClosedCaption } from '../../base/icons';
import { connect } from '../../base/redux'; import { connect } from '../../base/redux';
import { toggleLangugeSelectorDialog } from '../actions'; import { toggleLanguageSelectorDialog } from '../actions';
import { import {
AbstractClosedCaptionButton, AbstractClosedCaptionButton,
@ -20,7 +20,9 @@ class ClosedCaptionButton
tooltip = 'transcribing.ccButtonTooltip'; tooltip = 'transcribing.ccButtonTooltip';
label = 'toolbar.startSubtitles'; label = 'toolbar.startSubtitles';
labelProps = { labelProps = {
language: this.props.t(this.props._language) language: this.props.t(this.props._language),
languages: this.props.t(this.props.languages),
languagesHead: this.props.t(this.props.languagesHead)
}; };
/** /**
@ -31,7 +33,7 @@ class ClosedCaptionButton
_handleClickOpenLanguageSelector() { _handleClickOpenLanguageSelector() {
const { dispatch } = this.props; const { dispatch } = this.props;
dispatch(toggleLangugeSelectorDialog()); dispatch(toggleLanguageSelectorDialog());
} }
} }

View File

@ -31,7 +31,11 @@ const useStyles = makeStyles()((theme: Theme) => {
display: 'flex', display: 'flex',
color: theme.palette.text01, color: theme.palette.text01,
alignItems: 'center', alignItems: 'center',
fontSize: '14px' fontSize: '14px',
cursor: 'pointer',
'&:hover': {
backgroundColor: theme.palette.ui04
}
}, },
iconWrapper: { iconWrapper: {
margin: '4px 10px', margin: '4px 10px',

View File

@ -6,15 +6,17 @@ import { IState } from '../../app/types';
// @ts-ignore // @ts-ignore
import { Dialog } from '../../base/dialog'; import { Dialog } from '../../base/dialog';
// @ts-ignore // @ts-ignore
import { LANGUAGES, TRANSLATION_LANGUAGES_EXCLUDE, TRANSLATION_LANGUAGES_HEAD } from '../../base/i18n'; import { TRANSLATION_LANGUAGES, TRANSLATION_LANGUAGES_HEAD } from '../../base/i18n';
import { connect } from '../../base/redux/functions'; import { connect } from '../../base/redux/functions';
// @ts-ignore // @ts-ignore
import { setRequestingSubtitles, toggleLangugeSelectorDialog, updateTranslationLanguage } from '../actions'; import { setRequestingSubtitles, toggleLanguageSelectorDialog, updateTranslationLanguage } from '../actions';
import LanguageList from './LanguageList'; import LanguageList from './LanguageList';
interface ILanguageSelectorDialogProps { interface ILanguageSelectorDialogProps {
_language: string; _language: string;
_translationLanguages: Array<string>;
_translationLanguagesHead: Array<string>;
t: Function; t: Function;
} }
@ -23,18 +25,21 @@ interface ILanguageSelectorDialogProps {
* *
* @returns {React$Element<any>} * @returns {React$Element<any>}
*/ */
const LanguageSelectorDialog = ({ _language }: ILanguageSelectorDialogProps) => { const LanguageSelectorDialog = ({ _language, _translationLanguages, _translationLanguagesHead }:
ILanguageSelectorDialogProps) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const off = 'transcribing.subtitlesOff'; const off = 'transcribing.subtitlesOff';
const [ language, setLanguage ] = useState(off); const [ language, setLanguage ] = useState(off);
const importantLanguages = TRANSLATION_LANGUAGES_HEAD.map((lang: string) => `languages:${lang}`); const languagesHead = _translationLanguagesHead.map((lang: string) => `translation-languages:${lang}`);
const fixedItems = [ off, ...importantLanguages ]; // The off and the head languages are always on the top of the list. But once you are selecting
// a language from the translationLanguages, that language is moved under the fixedItems list,
const languages = LANGUAGES // until a new languages is selected. FixedItems keep their positions.
.filter((lang: string) => !TRANSLATION_LANGUAGES_EXCLUDE.includes(lang)) const fixedItems = [ off, ...languagesHead ];
.map((lang: string) => `languages:${lang}`) const languages = _translationLanguages
.filter((lang: string) => !(lang === language || importantLanguages.includes(lang))); .map((lang: string) => `translation-languages:${lang}`)
.filter((lang: string) => !(lang === language || languagesHead.includes(lang)));
const listItems = (fixedItems.includes(language) const listItems = (fixedItems.includes(language)
? [ ...fixedItems, ...languages ] ? [ ...fixedItems, ...languages ]
@ -55,7 +60,7 @@ const LanguageSelectorDialog = ({ _language }: ILanguageSelectorDialogProps) =>
setLanguage(e); setLanguage(e);
dispatch(updateTranslationLanguage(e)); dispatch(updateTranslationLanguage(e));
dispatch(setRequestingSubtitles(e !== off)); dispatch(setRequestingSubtitles(e !== off));
dispatch(toggleLangugeSelectorDialog()); dispatch(toggleLanguageSelectorDialog());
}, [ _language ]); }, [ _language ]);
return ( return (
@ -81,17 +86,18 @@ const LanguageSelectorDialog = ({ _language }: ILanguageSelectorDialogProps) =>
* @returns {Props} * @returns {Props}
*/ */
function mapStateToProps(state: IState) { function mapStateToProps(state: IState) {
const { const { conference } = state['features/base/conference'];
conference const { _language } = state['features/subtitles'];
} = state['features/base/conference']; const { transcription } = state['features/base/config'];
const { const languages = transcription?.translationLanguages ?? TRANSLATION_LANGUAGES;
_language const languagesHead = transcription?.translationLanguagesHead ?? TRANSLATION_LANGUAGES_HEAD;
} = state['features/subtitles'];
return { return {
_conference: conference, _conference: conference,
_language _language,
_translationLanguages: languages,
_translationLanguagesHead: languagesHead
}; };
} }

View File

@ -1,4 +1,5 @@
// @flow // @flow
import i18next from 'i18next';
import { MiddlewareRegistry } from '../base/redux'; import { MiddlewareRegistry } from '../base/redux';
@ -115,7 +116,7 @@ function _endpointMessageReceived({ dispatch, getState }, next, action) {
newTranscriptMessage)); newTranscriptMessage));
} else if (json.type === JSON_TYPE_TRANSCRIPTION_RESULT } else if (json.type === JSON_TYPE_TRANSCRIPTION_RESULT
&& !translationLanguage) { && i18next.language === translationLanguage) {
// Displays interim and final results without any translation if // Displays interim and final results without any translation if
// translations are disabled. // translations are disabled.
@ -186,7 +187,7 @@ function _requestingSubtitlesChange({ getState }) {
if (requestingSubtitles) { if (requestingSubtitles) {
conference.setLocalParticipantProperty( conference.setLocalParticipantProperty(
P_NAME_TRANSLATION_LANGUAGE, P_NAME_TRANSLATION_LANGUAGE,
_language.replace('languages:', '')); _language.replace('translation-languages:', ''));
} }
} }