Skip to content

Commit

Permalink
Merge pull request #1640 from Sefaria/feature/sc-20316/inform-users-t…
Browse files Browse the repository at this point in the history
…hey-can-choose-alternative

feat: [sc-20316] Inform users they can choose alternative translations
  • Loading branch information
nsantacruz committed Sep 19, 2023
2 parents 50d943c + 971c3de commit ef374c0
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 72 deletions.
22 changes: 21 additions & 1 deletion static/css/s2.css
Original file line number Diff line number Diff line change
Expand Up @@ -1854,7 +1854,8 @@ div.interfaceLinks-row a {
color: inherit;
cursor: pointer;
}
.navSidebar a.inTextLink {
.navSidebar a.inTextLink,
.translationsDesc a.inTextLink {
color: inherit;
text-decoration: underline;
margin-inline-start: 5px;
Expand Down Expand Up @@ -8413,6 +8414,25 @@ h3.aboutSheetHeader {
border-width: 1px;
}

.translationsHeader {
margin-bottom: 35px;
}

.translationsHeader h3 {
text-transform: none;
color: var(--dark-grey);
font-size: var(--sans-serif-h3-font-size);
--english-font: var(--english-sans-serif-font-family);
--hebrew-font: var(--hebrew-sans-serif-font-family);
margin-bottom: 12px;
margin-top: 0;
}

.translationsHeader .translationsDesc {
font-size: var(--sans-serif-body-font-size);
color: var(--dark-grey);
}

.aboutSheetPanel hr {
height: 0px;
border: 1px solid var(--light-grey);
Expand Down
4 changes: 2 additions & 2 deletions static/js/ReaderApp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2072,7 +2072,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) {
var updateSearchFilter = this.updateSearchFilter.bind(null, i);
var updateSearchOptionField = this.updateSearchOptionField.bind(null, i);
var updateSearchOptionSort = this.updateSearchOptionSort.bind(null, i);
var onOpenConnectionsClick = this.openTextListAt.bind(null, i+1);
var openConnectionsPanel = this.openTextListAt.bind(null, i+1);
var setTextListHighlight = this.setTextListHighlight.bind(null, i);
var setSelectedWords = this.setSelectedWords.bind(null, i);
var clearSelectedWords = this.clearSelectedWords.bind(null, i);
Expand Down Expand Up @@ -2111,7 +2111,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) {
onSearchResultClick={onSearchResultClick}
onSidebarSearchClick={onSidebarSearchClick}
onNavigationClick={this.handleNavigationClick}
onOpenConnectionsClick={onOpenConnectionsClick}
openConnectionsPanel={openConnectionsPanel}
openComparePanel={openComparePanel}
setTextListHighlight={setTextListHighlight}
setConnectionsFilter={setConnectionsFilter}
Expand Down
72 changes: 14 additions & 58 deletions static/js/ReaderPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import UserStats from './UserStats';
import ModeratorToolsPanel from './ModeratorToolsPanel';
import PublicCollectionsPage from './PublicCollectionsPage';
import TranslationsPage from './TranslationsPage';
import { TextColumnBannerChooser } from './TextColumnBanner';
import {
CloseButton,
MenuButton,
Expand Down Expand Up @@ -1111,7 +1112,7 @@ class ReaderPanel extends Component {
openDisplaySettings={this.openDisplaySettings}
currentLayout={this.currentLayout}
onError={this.onError}
openSidePanel={this.openSidePanel}
openConnectionsPanel={this.props.openConnectionsPanel}
connectionsMode={this.state.filter.length && this.state.connectionsMode === "Connections" ? "Connection Text" : this.state.connectionsMode}
connectionsCategory={this.state.connectionsCategory}
closePanel={this.props.closePanel}
Expand Down Expand Up @@ -1259,6 +1260,9 @@ class ReaderControls extends Component {
}
});
}
openTranslations() {
this.props.openConnectionsPanel([this.props.currentRef], null, {"connectionsMode": "Translations"});
}
componentDidMount() {
const title = this.props.currentRef;
if (title) {
Expand Down Expand Up @@ -1388,7 +1392,14 @@ class ReaderControls extends Component {
/>
<DisplaySettingsButton onClick={this.props.openDisplaySettings} />
</div>);
let transLangPrefSuggBann = hideHeader || connectionsHeader ? null : <TranslationLanguagePreferenceSuggestionBanner setTranslationLanguagePreference={this.props.setTranslationLanguagePreference} />;
const openTransBannerApplies = () => Sefaria.openTransBannerApplies(this.props.currentBook(), this.props.settings.language);
let banner = (hideHeader || connectionsHeader) ? null : (
<TextColumnBannerChooser
setTranslationLanguagePreference={this.props.setTranslationLanguagePreference}
openTranslations={this.openTranslations}
openTransBannerApplies={openTransBannerApplies}
/>
);
const classes = classNames({
readerControls: 1,
connectionsHeader: mode == "Connections",
Expand All @@ -1408,7 +1419,7 @@ class ReaderControls extends Component {
<div>
{connectionsHeader ? null : <CategoryColorLine category={this.props.currentCategory()} />}
{readerControls}
{transLangPrefSuggBann}
{banner}
</div>
);
}
Expand Down Expand Up @@ -1443,61 +1454,6 @@ ReaderControls.propTypes = {
};


const TranslationLanguagePreferenceSuggestionBanner = ({ setTranslationLanguagePreference }) => {
const [accepted, setAccepted] = useState(false);
const [closed, setClosed] = useState(false);

const cookie = Sefaria._inBrowser ? $.cookie : Sefaria.util.cookie;
const { translation_language_preference_suggestion } = Sefaria;
if (closed || (!accepted && cookie("translation_language_preference_suggested")) || !translation_language_preference_suggestion) {
return null;
}
const closeBanner = () => {
setClosed(true);
cookie("translation_language_preference_suggested", JSON.stringify(1), {path: "/"});
Sefaria.editProfileAPI({settings: {translation_language_preference_suggested: true}});
}
const accept = () => {
setAccepted(true);
setTranslationLanguagePreference(translation_language_preference_suggestion);
}
const lang = Sefaria.translateISOLanguageCode(translation_language_preference_suggestion);

return (
<div className="readerControls transLangPrefSuggBann">
<div className="readerControlsInner transLangPrefSuggBannInner sans-serif">
{
accepted ? (
<div className="transLangPrefCentered">
<InterfaceText>
<EnglishText> Thanks! We'll show you {lang} translations first when we have them. </EnglishText>
<HebrewText>תודה! כשנוכל, נציג לכם תרגומים בשפה ה<span className="bold">{Sefaria._(lang)}</span> כאשר אלו יהיו זמינים. </HebrewText>
</InterfaceText>
</div>
) : (
<div className="transLangPrefCentered">
<InterfaceText>
<EnglishText> Prefer to see <span className="bold"> {lang} </span> translations when available? </EnglishText>
<HebrewText>האם תעדיפו לראות תרגומים בשפה ה<span className="bold">{Sefaria._(lang)}</span> כאשר הם זמינים?</HebrewText>
</InterfaceText>
<div className="yesNoGroup">
<a className="yesNoButton" onClick={accept}>
<InterfaceText>Yes</InterfaceText>
</a>
<a className="yesNoButton" onClick={closeBanner}>
<InterfaceText>No</InterfaceText>
</a>
</div>
</div>
)
}
<CloseButton onClick={closeBanner} />
</div>
</div>
);
}


class ReaderDisplayOptionsMenu extends Component {
renderAliyotToggle() {
let torah = ["Genesis", "Exodus", "Leviticus", "Numbers", "Deuteronomy", "Onkelos Genesis", "Onkelos Exodus", "Onkelos Leviticus", "Onkelos Numbers", "Onkelos Deuteronomy"];
Expand Down
154 changes: 154 additions & 0 deletions static/js/TextColumnBanner.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import React, {useState} from "react";
import Sefaria from './sefaria/sefaria';
import $ from './sefaria/sefariaJquery';
import {
CloseButton, InterfaceText, EnglishText, HebrewText
} from './Misc';

const cookie = Sefaria._inBrowser ? $.cookie : Sefaria.util.cookie;
const { translation_language_preference_suggestion } = Sefaria;

export const TextColumnBannerChooser = ({ setTranslationLanguagePreference, openTranslations, openTransBannerApplies }) => {
const [transLangPrefAccepted, setTransLangPrefAccepted] = useState(false);
const shouldTransPrefBannerRender = () => {
// we haven't suggested yet and we have a suggestion
return transLangPrefAccepted || (!cookie("translation_language_preference_suggested") && translation_language_preference_suggestion);
};
const shouldOpenTransBannerRender = () => {
return openTransBannerApplies() && !cookie("open_trans_banner_shown"); // && textMode in (bilingual, english) && category in (Tanakh, Mishnah, Bavli)
}

if (shouldTransPrefBannerRender()) {
return (
<TransLangPrefBanner
accepted={transLangPrefAccepted}
setAccepted={setTransLangPrefAccepted}
setTranslationLanguagePreference={setTranslationLanguagePreference}
/>
);
}
else if (shouldOpenTransBannerRender()) {
return <OpenTransBanner openTranslations={openTranslations} />;
}
return null;
};


const TransLangPrefBanner = ({accepted, setAccepted, setTranslationLanguagePreference}) => {
if (accepted) {
return <TransLangPrefAcceptedBanner />;
}

return (
<TransLangPrefAskBanner
setAccepted={setAccepted}
setTranslationLanguagePreference={setTranslationLanguagePreference}
/>
);
}


const TransLangPrefAcceptedBanner = () => {
const lang = Sefaria.translateISOLanguageCode(translation_language_preference_suggestion);
return (
<TextColumnBanner>
<InterfaceText>
<EnglishText> Thanks! We'll show you {lang} translations first when we have them. </EnglishText>
<HebrewText>תודה! כשנוכל, נציג לכם תרגומים בשפה ה<span className="bold">{Sefaria._(lang)}</span> כאשר אלו יהיו זמינים. </HebrewText>
</InterfaceText>
</TextColumnBanner>
);
}


const TransLangPrefAskBanner = ({ setAccepted, setTranslationLanguagePreference }) => {
const reject = () => {
cookie("translation_language_preference_suggested", JSON.stringify(1), {path: "/"});
Sefaria.editProfileAPI({settings: {translation_language_preference_suggested: true}});
}
const accept = () => {
setAccepted(true);
setTranslationLanguagePreference(translation_language_preference_suggestion);
}
const lang = Sefaria.translateISOLanguageCode(translation_language_preference_suggestion);
const buttons = [{text: "Yes", onClick: accept}, {text: "No", onClick: reject, sideEffect: "close" }];

return (
<TextColumnBanner buttons={buttons} onClose={reject}>
<InterfaceText>
<EnglishText> Prefer to see <span className="bold"> {lang} </span> translations when available? </EnglishText>
<HebrewText>האם תעדיפו לראות תרגומים בשפה ה<span className="bold">{Sefaria._(lang)}</span> כאשר הם זמינים?</HebrewText>
</InterfaceText>
</TextColumnBanner>
);
}


/**
*
* @param openTranslations: function with no parameters that opens translations in the resources panel
* @returns {JSX.Element}
* @constructor
*/
const OpenTransBanner = ({ openTranslations }) => {
const buttons = [{
text: "Go to translations",
onClick: () => { openTranslations(); },
sideEffect: "close",
}];
const onClose = () => {
cookie("open_trans_banner_shown", JSON.stringify(1), {path: "/"});
};
return (
<TextColumnBanner buttons={buttons} onClose={onClose}>
<InterfaceText>
<EnglishText> Want to <span className="bold">change</span> the translation?</EnglishText>
<HebrewText> מעוניינים בתרגום אחר?</HebrewText>
</InterfaceText>
</TextColumnBanner>
);
};



/**
* Banner which appears right above text column and informs a user of an action they can take
* @param children: React element to display the call-to-action text.
* @param buttons: List of objects. Each object should have keys "text" and "onClick". Can optionally have key "sideEffect" whose value can be "close" if the button should close the banner.
* @param onClose: Optional callback that gets called when the banner is closed.
* @returns {JSX.Element|null}
* @constructor
*/
const TextColumnBanner = ({ children, buttons, onClose }) => {
const [closed, setClosed] = useState(false);
const closeBanner = () => {
setClosed(true);
onClose?.();
};
if (closed) { return null; }
return (
<div className="readerControls transLangPrefSuggBann">
<div className="readerControlsInner transLangPrefSuggBannInner sans-serif">
<div className="transLangPrefCentered">
{ children }
<div className="yesNoGroup">
{ buttons?.map(button => <TextColumnBannerButton key={button.text} button={button} closeBanner={closeBanner}/>) }
</div>
</div>
<CloseButton onClick={closeBanner} />
</div>
</div>
);
}

const TextColumnBannerButton = ({ button, closeBanner }) => {
const onClick = () => {
button.onClick();
if (button.sideEffect === "close") { closeBanner(true); }
}
return (
<a className="yesNoButton" onClick={onClick}>
<InterfaceText>{button.text}</InterfaceText>
</a>
);
}
46 changes: 35 additions & 11 deletions static/js/TranslationsBox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import Sefaria from './sefaria/sefaria';
import {VersionsBlocksList} from './VersionBlock';
import Component from 'react-class';
import {LoadingMessage} from "./Misc";
import {EnglishText, HebrewText, InterfaceText, LoadingMessage} from "./Misc";
import {RecentFilterSet} from "./ConnectionFilters";
import TextRange from "./TextRange";
import {AddConnectionToSheetButton, ConnectionButtons, OpenConnectionTabButton} from "./TextList";
Expand Down Expand Up @@ -78,16 +78,19 @@ class TranslationsBox extends Component {
);
}
return (
<VersionsBlocksList
versionsByLanguages={this.state.versionLangMap}
currObjectVersions={this.props.currObjectVersions}
sortPrioritizeLanugage={"en"}
currentRef={this.props.srefs[0]}
openVersionInReader={this.props.openVersionInReader}
openVersionInSidebar={this.openVersionInSidebar}
viewExtendedNotes={this.props.viewExtendedNotes}
inTranslationBox={true}
/>
<>
<TranslationsHeader />
<VersionsBlocksList
versionsByLanguages={this.state.versionLangMap}
currObjectVersions={this.props.currObjectVersions}
sortPrioritizeLanugage={"en"}
currentRef={this.props.srefs[0]}
openVersionInReader={this.props.openVersionInReader}
openVersionInSidebar={this.openVersionInSidebar}
viewExtendedNotes={this.props.viewExtendedNotes}
inTranslationBox={true}
/>
</>
);
}
}
Expand All @@ -109,6 +112,27 @@ TranslationsBox.propTypes = {
};


const TranslationsHeader = () => (
<div className="translationsHeader">
<h3>
<InterfaceText>Translations</InterfaceText>
</h3>
<div className="translationsDesc sans-serif">
<InterfaceText>
<EnglishText>Sefaria acquires translations to enrich your learning experience. Preview or choose a different translation below.</EnglishText>
<HebrewText>ספריא עושה מאמצים להוסיף תרגומים שונים לספרים כדי להעשיר את חווית הלמידה שלכם. כאן ניתן להחליף לתרגום אחר או לראות תצוגה מקדימה שלו לצד הטקסט הנוכחי.</HebrewText>
</InterfaceText>
<a href="/sheets/511573" target="_blank" className="inTextLink">
<InterfaceText>
<EnglishText>Learn more ›</EnglishText>
<HebrewText>למידע נוסף ›</HebrewText>
</InterfaceText>
</a>
</div>
</div>
);


class VersionsTextList extends Component {
constructor(props) {
super(props);
Expand Down

0 comments on commit ef374c0

Please sign in to comment.