diff --git a/Makefile b/Makefile index 0eb144d3d70..93e9683597a 100755 --- a/Makefile +++ b/Makefile @@ -78,13 +78,13 @@ locales: msgfmt -o modules/bvl_feedback/locale/ja/LC_MESSAGES/bvl_feedback.mo modules/bvl_feedback/locale/ja/LC_MESSAGES/bvl_feedback.po msgfmt -o modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.mo modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.po npx i18next-conv -l ja -s modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.po -t modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.json - msgfmt -o modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.mo modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po - npx i18next-conv -l hi -s modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po -t modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.json msgfmt -o modules/candidate_parameters/locale/ja/LC_MESSAGES/candidate_parameters.mo modules/candidate_parameters/locale/ja/LC_MESSAGES/candidate_parameters.po msgfmt -o modules/candidate_profile/locale/ja/LC_MESSAGES/candidate_profile.mo modules/candidate_profile/locale/ja/LC_MESSAGES/candidate_profile.po msgfmt -o modules/configuration/locale/ja/LC_MESSAGES/configuration.mo modules/configuration/locale/ja/LC_MESSAGES/configuration.po msgfmt -o modules/configuration/locale/ja/LC_MESSAGES/configuration.mo modules/configuration/locale/ja/LC_MESSAGES/configuration.po msgfmt -o modules/conflict_resolver/locale/ja/LC_MESSAGES/conflict_resolver.mo modules/conflict_resolver/locale/ja/LC_MESSAGES/conflict_resolver.po + msgfmt -o modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.mo modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po + npx i18next-conv -l hi -s modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po -t modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.json msgfmt -o modules/create_timepoint/locale/ja/LC_MESSAGES/create_timepoint.mo modules/create_timepoint/locale/ja/LC_MESSAGES/create_timepoint.po npx i18next-conv -l ja -s modules/create_timepoint/locale/ja/LC_MESSAGES/create_timepoint.po -t modules/create_timepoint/locale/ja/LC_MESSAGES/create_timepoint.json msgfmt -o modules/create_timepoint/locale/es/LC_MESSAGES/create_timepoint.mo modules/create_timepoint/locale/es/LC_MESSAGES/create_timepoint.po @@ -143,8 +143,9 @@ create_timepoint: target=data_release npm run compile data_release: modules/data_release/locale/hi/LC_MESSAGES/data_release.mo modules/data_release/locale/ja/LC_MESSAGES/data_release.mo - npx i18next-conv -l hi -s modules/data_release/locale/hi/LC_MESSAGES/data_release.po -t modules/data_release/locale/hi/LC_MESSAGES/data_release.json - npx i18next-conv -l ja -s modules/data_release/locale/ja/LC_MESSAGES/data_release.po -t modules/data_release/locale/ja/LC_MESSAGES/data_release.json + msgfmt -o modules/data_release/locale/hi/LC_MESSAGES/data_release.mo modules/data_release/locale/hi/LC_MESSAGES/data_release.po + npx i18next-conv -l hi -s modules/data_release/locale/hi/LC_MESSAGES/data_release.po -t modules/data_release/locale/hi/LC_MESSAGES/data_release.json + npx i18next-conv -l ja -s modules/data_release/locale/ja/LC_MESSAGES/data_release.po -t modules/data_release/locale/ja/LC_MESSAGES/data_release.json target=data_release npm run compile instrument_manager: modules/instrument_manager/locale/ja/LC_MESSAGES/instrument_manager.mo @@ -168,7 +169,6 @@ issue_tracker: modules/issue_tracker/locale/ja/LC_MESSAGES/issue_tracker.mo candidate_list: modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.mo modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.mo npx i18next-conv -l ja -s modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.po -t modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.json - npx i18next-conv -l hi -s modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po -t modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.json target=candidate_list npm run compile candidate_parameters: modules/candidate_parameters/locale/ja/LC_MESSAGES/candidate_parameters.mo @@ -184,4 +184,7 @@ server_processes_manager: modules/server_processes_manager/locale/ja/LC_MESSAGES target=server_processes_manager npm run compile conflict_resolver: + msgfmt -o modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.mo modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po + npx i18next-conv -l hi -s modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po -t modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.json target=conflict_resolver npm run compile + diff --git a/jsx/DataTable.js b/jsx/DataTable.js index 2826e82cb1c..20779d88fa6 100644 --- a/jsx/DataTable.js +++ b/jsx/DataTable.js @@ -563,6 +563,7 @@ class DataTable extends Component { ({this.props.t('Maximum rows per page:')} {rowsPerPageDropdown}) ; + let header = this.props.hide.rowsPerPage === true ? '' : (
@@ -601,7 +602,7 @@ class DataTable extends Component { className="btn btn-primary" onClick={this.downloadCSV.bind(null, filteredRowIndexes)} > - {this.props.t('Download Data as CSV')} + {this.props.t('Download Table as CSV')} ) } { const args = QueryString.get(); i18n.addResourceBundle('ja', 'candidate_list', jaStrings); - i18n.addResourceBundle('hi', 'candidate_list', hiStrings); - const CLIndex = withTranslation( ['candidate_list', 'loris'] diff --git a/modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po b/modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po index e3097cf1fa8..ef611f1bf71 100644 --- a/modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po +++ b/modules/candidate_list/locale/hi/LC_MESSAGES/candidate_list.po @@ -22,7 +22,6 @@ msgid "Access Profile" msgstr "प्रोफ़ाइल तक पहुँचें" - msgid "Visit Count" msgstr "आगंतुक गणना" @@ -30,4 +29,3 @@ msgid "Open Profile" msgstr "प्रोफ़ाइल खोलें" - diff --git a/modules/conflict_resolver/jsx/CandidateConflictsWidget.js b/modules/conflict_resolver/jsx/CandidateConflictsWidget.js index 36f1abf1a03..96d11874452 100644 --- a/modules/conflict_resolver/jsx/CandidateConflictsWidget.js +++ b/modules/conflict_resolver/jsx/CandidateConflictsWidget.js @@ -2,6 +2,7 @@ import '../../../node_modules/c3/c3.css'; import c3 from 'c3'; import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; +import {withTranslation} from 'react-i18next'; /** * Renders a representation of the candidate conflicts as a React @@ -11,6 +12,7 @@ import PropTypes from 'prop-types'; * @return {object} */ function CandidateConflictsWidget(props) { + const {t} = props; const visits = getVisits(props.Conflicts); const instruments = getInstruments(props.Conflicts); @@ -34,14 +36,14 @@ function CandidateConflictsWidget(props) { type: 'category', categories: visits, label: { - text: 'Visit', + text: t('Visit', {ns: 'conflict_resolver'}), position: 'outer-center', }, }, y: { label: { position: 'outer-middle', - text: 'Number of Conflicts', + text: t('Number of Conflicts', {ns: 'conflict_resolver'}), }, }, }, @@ -64,12 +66,14 @@ function CandidateConflictsWidget(props) {
  • - {'Click on instrument in legend to visit conflict resolver ' - + 'for that instrument across all visits.'} + {t('Click on instrument in legend to visit conflict resolver' + + ' for that instrument across all visits.', + {ns: 'conflict_resolver'})}
  • - {'Click on bar in graph to visit conflict resolver ' - + 'for that visit and instrument combination.'} + {t('Click on bar in graph to visit conflict resolver' + + ' for that visit and instrument combination.', + {ns: 'conflict_resolver'})}
; @@ -78,6 +82,7 @@ CandidateConflictsWidget.propTypes = { Conflicts: PropTypes.array, BaseURL: PropTypes.string, Candidate: PropTypes.object, + t: PropTypes.func, }; /** @@ -150,4 +155,5 @@ function getDataBreakdown(visits, instruments, conflicts) { return data; } -export default CandidateConflictsWidget; +export default withTranslation( + ['conflict_resolver', 'loris'])(CandidateConflictsWidget); diff --git a/modules/conflict_resolver/jsx/conflict_resolver.js b/modules/conflict_resolver/jsx/conflict_resolver.js index ce85d7050d2..46f45fbb097 100644 --- a/modules/conflict_resolver/jsx/conflict_resolver.js +++ b/modules/conflict_resolver/jsx/conflict_resolver.js @@ -3,9 +3,11 @@ import React, {Component} from 'react'; import {Tabs, TabPane} from 'Tabs'; import i18n from 'I18nSetup'; import {withTranslation} from 'react-i18next'; +import PropTypes from 'prop-types'; import UnresolvedFilterableDataTable from './unresolved_filterabledatatable'; import ResolvedFilterableDataTable from './resolved_filterabledatatable'; +import hiStrings from '../locale/hi/LC_MESSAGES/conflict_resolver.json'; /** * Conflict Resolver class. @@ -41,9 +43,10 @@ class ConflictResolver extends Component { * @return {JSX} */ render() { + const {t} = this.props; const tabs = [ - {id: 'unresolved', label: 'Unresolved'}, - {id: 'resolved', label: 'Resolved'}, + {id: 'unresolved', label: t('Unresolved', {ns: 'conflict_resolver'})}, + {id: 'resolved', label: t('Resolved', {ns: 'conflict_resolver'})}, ]; let filtertable; @@ -76,6 +79,7 @@ class ConflictResolver extends Component { window.addEventListener('load', () => { i18n.addResourceBundle('ja', 'conflict_resolver', {}); + i18n.addResourceBundle('hi', 'conflict_resolver', hiStrings); const Index = withTranslation( ['conflict_resolver', 'loris'] )(ConflictResolver); @@ -84,3 +88,10 @@ window.addEventListener('load', () => { ).render(); }); +ConflictResolver.propTypes = { + t: PropTypes.func, +}; + +export default withTranslation( + ['conflict_resolver', 'loris'])(ConflictResolver); + diff --git a/modules/conflict_resolver/jsx/fix_conflict_form.js b/modules/conflict_resolver/jsx/fix_conflict_form.js index ac3648544e2..e951e6f3489 100644 --- a/modules/conflict_resolver/jsx/fix_conflict_form.js +++ b/modules/conflict_resolver/jsx/fix_conflict_form.js @@ -5,6 +5,7 @@ import {Component} from 'react'; import PropTypes from 'prop-types'; import {SelectElement} from 'jsx/Form'; +import {withTranslation} from 'react-i18next'; /** * The fix FixConflictForm renders a
within a . The form as a select @@ -53,6 +54,7 @@ class FixConflictForm extends Component { * @param {string} value */ resolveConflict(name, value) { + const {t} = this.props; fetch(loris.BaseURL.concat('/conflict_resolver/unresolved'), { method: 'POST', credentials: 'same-origin', @@ -71,7 +73,7 @@ class FixConflictForm extends Component { this.setState({success: true, error: null, emptyOption: false, value}); }) .catch((error) => { - swal('Error!', error, 'error'); + swal(t('Error!', {ns: 'conflict_resolver'}), error, 'error'); this.setState({error, success: false, emptyOption: true}); }); } @@ -83,12 +85,11 @@ class FixConflictForm extends Component { */ render() { const {value, success, error, emptyOption} = this.state; - const color = { - backgroundColor: success ? '#d1ffcf' : '', - transition: 'background-color 1s', - }; return ( - + -

An error occured while loading the page.

+

{t('An error occured while loading the page.', + {ns: 'conflict_resolver'})}

{this.state.error.message}
); @@ -127,70 +130,80 @@ class ResolvedFilterableDataTable extends Component { const options = this.state.data.fieldOptions; const fields = [ - {label: 'Resolved ID', show: false}, - {label: 'Project', show: true, filter: { + {label: t('Resolved ID', + {ns: 'conflict_resolver'}), show: false}, + {label: t('Project', {ns: 'loris'}), show: true, filter: { name: 'Project', type: 'select', options: options.project, }}, - {label: 'Cohort', show: true, filter: { + {label: t('Cohort', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'Cohort', type: 'select', options: options.cohort, }}, - {label: 'Site', show: true, filter: { + {label: t('Site', {ns: 'loris'}), show: true, filter: { name: 'Site', type: 'select', options: options.site, }}, - {label: 'CandID', show: true, filter: { + {label: t('CandID', {ns: 'loris'}), show: true, filter: { name: 'candidateID', type: 'text', value: '300001', }}, - {label: 'PSCID', show: true, filter: { + {label: t('PSCID', {ns: 'loris'}), show: true, filter: { name: 'PSCID', type: 'text', }}, - {label: 'Visit Label', show: true, filter: { + {label: t('Visit Label', {ns: 'loris'}), show: true, filter: { name: 'visitLabel', type: 'select', options: options.visitLabel, }}, - {label: 'Instrument', show: true, filter: { + {label: t('Instrument', {ns: 'loris'}), show: true, filter: { name: 'instrument', type: 'select', options: options.instrument, }}, - {label: 'Question', show: true, filter: { + {label: t('Question', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'Question', type: 'text', }}, - {label: 'Description', show: true, filter: { + {label: t('Description', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'Description', type: 'text', }}, - {label: 'Incorrect Answer', show: true, filter: { + {label: t('Incorrect Answer', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'OldValue', type: 'text', }}, - {label: 'Correct Answer', show: true, filter: { + {label: t('Correct Answer', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'CorrectAnswer', type: 'text', }}, - {label: 'User 1', show: true, filter: { + {label: t('User 1', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'User1', type: 'text', }}, - {label: 'User 2', show: true, filter: { + {label: t('User 2', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'User2', type: 'text', }}, - {label: 'Resolver', show: true, filter: { + {label: t('Resolver', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'Resolver', type: 'text', }}, - {label: 'Resolution Timestamp', show: true, filter: { + {label: t('Resolution Timestamp', + {ns: 'conflict_resolver'}), show: true, filter: { name: 'ResolutionTimestamp', type: 'text', }}, @@ -207,6 +220,10 @@ class ResolvedFilterableDataTable extends Component { } } +ResolvedFilterableDataTable.propTypes = { + t: PropTypes.func.isRequired, +}; + export default withTranslation( ['conflict_resolver', 'loris'] )(ResolvedFilterableDataTable); diff --git a/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js b/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js index a296d290e8d..b1a2e3c2406 100644 --- a/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js +++ b/modules/conflict_resolver/jsx/unresolved_filterabledatatable.js @@ -3,6 +3,7 @@ import Loader from 'Loader'; import {withTranslation} from 'react-i18next'; import FilterableDataTable from 'FilterableDataTable'; import FixConflictForm from './fix_conflict_form'; +import PropTypes from 'prop-types'; /** * Filterable database for unresolved conflicts. @@ -47,7 +48,7 @@ class UnresolvedFilterableDataTable extends Component { */ formatColumn(column, cell, rowData, rowHeaders) { switch (column) { - case 'Correct Answer': + case this.props.t('Correct Answer', {ns: 'conflict_resolver'}): const options = { 1: rowData['Value 1'], 2: rowData['Value 2'], @@ -122,10 +123,12 @@ class UnresolvedFilterableDataTable extends Component { */ render() { // If error occurs, return a message. + const {t} = this.props; if (this.state.error) { return (
-

An error occured while loading the page.

+

{t('An error occured while loading the page.', + {ns: 'conflict_resolver'})}

{this.state.error.toString()}
); @@ -139,52 +142,52 @@ class UnresolvedFilterableDataTable extends Component { const options = this.state.data.fieldOptions; const fields = [ - {label: 'Conflict ID', show: false}, - {label: 'Project', show: true, filter: { + {label: t('Conflict ID', {ns: 'conflict_resolver'}), show: false}, + {label: t('Project', {ns: 'loris'}), show: true, filter: { name: 'Project', type: 'select', options: options.project, }}, - {label: 'Cohort', show: true, filter: { + {label: t('Cohort', {ns: 'conflict_resolver'}), show: true, filter: { name: 'cohort', type: 'select', options: options.cohort, }}, - {label: 'Site', show: true, filter: { + {label: t('Site', {ns: 'loris'}), show: true, filter: { name: 'Site', type: 'select', options: options.site, }}, - {label: 'CandID', show: true, filter: { + {label: t('CandID', {ns: 'loris'}), show: true, filter: { name: 'candidateID', type: 'text', value: '300001', }}, - {label: 'PSCID', show: true, filter: { + {label: t('PSCID', {ns: 'loris'}), show: true, filter: { name: 'PSCID', type: 'text', }}, - {label: 'Visit Label', show: true, filter: { + {label: t('Visit Label', {ns: 'loris'}), show: true, filter: { name: 'visitLabel', type: 'select', options: options.visitLabel, }}, - {label: 'Instrument', show: true, filter: { + {label: t('Instrument', {ns: 'loris'}), show: true, filter: { name: 'instrument', type: 'select', options: options.instrument, }}, - {label: 'Question', show: true, filter: { + {label: t('Question', {ns: 'conflict_resolver'}), show: true, filter: { name: 'Question', type: 'text', }}, - {label: 'Description', show: true, filter: { + {label: t('Description', {ns: 'conflict_resolver'}), show: true, filter: { name: 'Description', type: 'text', }}, - {label: 'Value 1', show: false}, - {label: 'Value 2', show: false}, - {label: 'Correct Answer', show: true}, + {label: t('Value 1', {ns: 'conflict_resolver'}), show: false}, + {label: t('Value 2', {ns: 'conflict_resolver'}), show: false}, + {label: t('Correct Answer', {ns: 'conflict_resolver'}), show: true}, ]; return ( @@ -198,6 +201,10 @@ class UnresolvedFilterableDataTable extends Component { } } +UnresolvedFilterableDataTable.propTypes = { + t: PropTypes.func.isRequired, +}; + export default withTranslation( ['conflict_resolver', 'loris'] )(UnresolvedFilterableDataTable); diff --git a/modules/conflict_resolver/locale/conflict_resolver.pot b/modules/conflict_resolver/locale/conflict_resolver.pot index aa626a59221..9b8f31eedb0 100644 --- a/modules/conflict_resolver/locale/conflict_resolver.pot +++ b/modules/conflict_resolver/locale/conflict_resolver.pot @@ -27,3 +27,68 @@ msgstr "" msgid "Unresolved Conflicts" msgstr "" +# --- Strings not in loris.pot, add below --- + +msgid "Unresolved" +msgstr "" + +msgid "Resolved" +msgstr "" + +msgid "An error occured while loading the page." +msgstr "" + +msgid "Correct Answer" +msgstr "" + +msgid "Conflict ID" +msgstr "" + +msgid "Cohort" +msgstr "" + +msgid "Question" +msgstr "" + +msgid "Description" +msgstr "" + +msgid "Value 1" +msgstr "" + +msgid "Value 2" +msgstr "" + +msgid "Resolved ID" +msgstr "" + +msgid "Incorrect Answer" +msgstr "" + +msgid "User 1" +msgstr "" + +msgid "User 2" +msgstr "" + +msgid "Resolver" +msgstr "" + +msgid "Resolution Timestamp" +msgstr "" + +msgid "Error!" +msgstr "" + +msgid "Visit" +msgstr "" + +msgid "Number of Conflicts" +msgstr "" + +msgid "Click on instrument in legend to visit conflict resolver for that instrument across all visits." +msgstr "" + +msgid "Click on bar in graph to visit conflict resolver for that visit and instrument combination." +msgstr "" + diff --git a/modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po b/modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po new file mode 100644 index 00000000000..04d45c92621 --- /dev/null +++ b/modules/conflict_resolver/locale/hi/LC_MESSAGES/conflict_resolver.po @@ -0,0 +1,94 @@ +# Default LORIS strings to be translated (English). +# Copy this to a language specific file and add translations to the +# new file. +# Copyright (C) 2025 +# This file is distributed under the same license as the LORIS package. +# Dave MacFarlane , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: LORIS 27\n" +"Report-Msgid-Bugs-To: https://github.com/aces/Loris/issues\n" +"POT-Creation-Date: 2025-04-08 14:37-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: hi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "Conflict Resolver" +msgstr "कॉन्फ्लिक्ट रेज़ोल्वर" + +msgid "Data entry conflict" +msgstr "डेटा प्रविष्टि टकराव" + +msgid "Unresolved Conflicts" +msgstr "असुलझे टकराव" + +# --- Strings not in loris.pot, add below --- + +msgid "Unresolved" +msgstr "असुलझा" + +msgid "Resolved" +msgstr "सुलझा हुआ" + +msgid "An error occured while loading the page." +msgstr "पृष्ठ लोड करते समय एक त्रुटि हुई।" + +msgid "Correct Answer" +msgstr "सही उत्तर" + +msgid "Conflict ID" +msgstr "टकराव आईडी" + +msgid "Cohort" +msgstr "समूह" + +msgid "Question" +msgstr "प्रश्न" + +msgid "Description" +msgstr "विवरण" + +msgid "Value 1" +msgstr "मान 1" + +msgid "Value 2" +msgstr "मान 2" + +msgid "Resolved ID" +msgstr "सुलझा हुआ आईडी" + +msgid "Incorrect Answer" +msgstr "गलत उत्तर" + +msgid "User 1" +msgstr "उपयोगकर्ता 1" + +msgid "User 2" +msgstr "उपयोगकर्ता 2" + +msgid "Resolver" +msgstr "सुलझाने वाला" + +msgid "Resolution Timestamp" +msgstr "संकल्प समय" + +msgid "Error!" +msgstr "त्रुटि!" + +msgid "Visit" +msgstr "विज़िट" + +msgid "Number of Conflicts" +msgstr "टकरावों की संख्या" + +msgid "Click on instrument in legend to visit conflict resolver for that instrument across all visits." +msgstr "सभी विज़िट्स में उस इंस्ट्रूमेंट के लिए कॉन्फ्लिक्ट रेज़ोल्वर देखने हेतु लीजेंड में इंस्ट्रूमेंट पर क्लिक करें।" + +msgid "Click on bar in graph to visit conflict resolver for that visit and instrument combination." +msgstr "ग्राफ़ में बार पर क्लिक करें ताकि उस विज़िट और इंस्ट्रूमेंट संयोजन के लिए कॉन्फ्लिक्ट रेज़ोल्वर देखें।" +