Skip to content
This repository was archived by the owner on Jan 17, 2023. It is now read-only.

WIP Fix #1714 Switch localization from l20n to fluent-react for better react integration. #2611

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions flow-typed/fluent-react/compat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

declare module 'fluent-react/compat' {
declare function Localized(): Object;
}
3 changes: 3 additions & 0 deletions frontend/.flowconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
../node_modules/react/*.
../node_modules/html-react-parser/*.
../node_modules/moment/*.
../node_modules/fluent-react/*.

[libs]
../flow-typed


13 changes: 13 additions & 0 deletions frontend/src/app/actions/localizations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// @flow

import type {
Localizations,
SetLocalizationsAction
} from '../reducers/localizations.js';

export function setLocalizations(localizations: Localizations): SetLocalizationsAction {
return {
type: 'SET_LOCALIZATIONS',
payload: localizations
};
}
39 changes: 28 additions & 11 deletions frontend/src/app/components/EmailDialog.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow

import { Localized } from 'fluent-react/compat';
import React from 'react';

import NewsletterForm from './NewsletterForm';
import { subscribeToBasket } from '../lib/utils';

Expand Down Expand Up @@ -49,11 +50,15 @@ export default class EmailDialog extends React.Component {
return (
<div id="first-page" className="modal feedback-modal modal-bounce-in">
<header className="modal-header-wrapper">
<h3 className="modal-header" data-l10n-id="emailOptInDialogTitle">Welcome to Test Pilot!</h3>
<Localized id="emailOptInDialogTitle">
<h3 className="modal-header">Welcome to Test Pilot!</h3>
</Localized>
<div className="modal-cancel" onClick={e => this.skip(e)}/>
</header>
<div className="modal-content centered">
<p data-l10n-id="emailOptInMessage" className="">Find out about new experiments and see test results for experiments you&apos;ve tried.</p>
<Localized id="emailOptInMessage">
<p>Find out about new experiments and see test results for experiments you&apos;ve tried.</p>
</Localized>
<NewsletterForm {...{ email, privacy }}
isModal={true}
setEmail={newEmail => this.setState({ email: newEmail })}
Expand All @@ -68,15 +73,21 @@ export default class EmailDialog extends React.Component {
return (
<div id="second-page" className="modal">
<header className="modal-header-wrapper">
<h3 className="modal-header" data-l10n-id="newsletterFooterSuccessHeader">Thanks!</h3>
<Localized id="newsletterFooterSuccessHeader">
<h3 className="modal-header">Thanks!</h3>
</Localized>
<div className="modal-cancel" onClick={e => this.continue(e)} />
</header>
<div className="modal-content centered">
<div className="envelope" />
<p data-l10n-id="newsletterFooterSuccessBody" />
<Localized id="newsletterFooterSuccessBody">
<p>Thank you!</p>
</Localized>
</div>
<div className="modal-actions">
<button id="email-success-continue" onClick={e => this.continue(e)} className="button default large" data-l10n-id="emailOptInConfirmationClose">On to the experiments...</button>
<Localized id="emailOptInConfirmationClose">
<button id="email-success-continue" onClick={e => this.continue(e)} className="button default large">On to the experiments&hellip;</button>
</Localized>
</div>
</div>
);
Expand All @@ -86,17 +97,23 @@ export default class EmailDialog extends React.Component {
return (
<div id="second-page" className="modal">
<header className="modal-header-wrapper">
<h3 className="modal-header" data-l10n-id="emailOptInDialogErrorTitle">Oh no!</h3>
<Localized id="emailOptInDialogErrorTitle">
<h3 className="modal-header">Oh no!</h3>
</Localized>
<div className="modal-cancel" onClick={e => this.continue(e)} />
</header>
<div className="modal-content centered">
<div className="envelope" />
<p className="error" data-l10n-id="newsletterFooterError">
There was an error submitting your email address. Try again?
</p>
<Localized id="newsletterFooterError">
<p className="error">
There was an error submitting your email address. Try again?
</p>
</Localized>
</div>
<div className="modal-actions">
<button id="email-success-continue" onClick={e => this.reset(e)} className="button default large" data-l10n-id="newsletterFormSubmitButton">Sign Up Now</button>
<Localized id="newsletterFormSubmitButton">
<button id="email-success-continue" onClick={e => this.reset(e)} className="button default large">Sign Up Now</button>
</Localized>
</div>
</div>
);
Expand Down
32 changes: 18 additions & 14 deletions frontend/src/app/components/ExperimentDisableDialog.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @flow

import { Localized } from 'fluent-react/compat';
import React from 'react';

import Copter from './Copter';
Expand Down Expand Up @@ -27,25 +27,29 @@ export default class ExperimentDisableDialog extends React.Component {
<div className="modal-container">
<div id="disabled-feedback-modal" className="modal feedback-modal modal-bounce-in">
<header className="modal-header-wrapper">
<h3 className="modal-header"
data-l10n-id="feedbackUninstallTitle"
data-l10n-args={JSON.stringify({ title: experiment.title })} />
<Localized id="feedbackUninstallTitle" $title={ experiment.title }>
<h3 className="modal-header" />
</Localized>
<div className="modal-cancel" onClick={e => this.cancel(e)} />
</header>
<div className="modal-content">
<Copter small={true}/>
<p className="centered" data-l10n-id="feedbackUninstallCopy">
Your participation in Firefox Test Pilot means a lot!
Please check out our other experiments, and stay tuned for more to come!
</p>
<Localized id="feedbackUninstallCopy">
<p className="centered">
Your participation in Firefox Test Pilot means a lot!
Please check out our other experiments, and stay tuned for more to come!
</p>
</Localized>
</div>
<div className="modal-actions">
<a data-l10n-id="feedbackSubmitButton"
onClick={e => this.submit(e)} href={surveyURL}
target="_blank" rel="noopener noreferrer"
className="submit button default large quit">
Take a quick survey
</a>
<Localized id="feedbackSubmitButton">
<a
onClick={e => this.submit(e)} href={surveyURL}
target="_blank" rel="noopener noreferrer"
className="submit button default large quit">
Take a quick survey
</a>
</Localized>
</div>
</div>
</div>
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/app/components/ExperimentEolDialog.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @flow

import { Localized } from 'fluent-react/compat';
import React from 'react';

type ExperimentEolDialogProps = {
Expand All @@ -17,15 +18,21 @@ export default class ExperimentEolDialog extends React.Component {
<div className="modal-container">
<div id="retire-dialog-modal" className="modal feedback-modal modal-bounce-in">
<header className="modal-header-wrapper warning-modal">
<h3 className="title modal-header" data-l10n-id="disableHeader">Disable Experiment?</h3>
<Localized id="disableHeader">
<h3 className="title modal-header">Disable Experiment?</h3>
</Localized>
<div className="modal-cancel" onClick={e => this.cancel(e)}/>
</header>
<form>
<div className="modal-content">
<p data-l10n-id="eolDisableMessage" data-l10n-args={JSON.stringify({ title })} className="centered"></p>
<Localized id="eolDisableMessage" $title={title}>
<p className="centered"></p>
</Localized>
</div>
<div className="modal-actions">
<button onClick={e => this.proceed(e)} data-l10n-id="disableExperiment" data-l10n-args={JSON.stringify({ title })} className="submit button warning large"></button>
<Localized id="disableExperiment" $title={title}>
<button onClick={e => this.proceed(e)} className="submit button warning large"></button>
</Localized>
</div>
</form>
</div>
Expand Down
22 changes: 10 additions & 12 deletions frontend/src/app/components/ExperimentPreFeedbackDialog.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// @flow

import React from 'react';
import classnames from 'classnames';
import { Localized } from 'fluent-react/compat';
import parser from 'html-react-parser';
import React from 'react';

type ExperimentPreFeedbackDialogProps = {
experiment: Object,
Expand All @@ -17,18 +18,14 @@ export default class ExperimentPreFeedbackDialog extends React.Component {
render() {
const { experiment, surveyURL } = this.props;

const l10nArgs = JSON.stringify({
title: experiment.title
});

return (
<div className="modal-container">
<div className={classnames('modal', 'tour-modal')}>
<header className="modal-header-wrapper">
<h3 className="modal-header"
data-l10n-id="experimentPreFeedbackTitle"
data-l10n-args={l10nArgs}></h3>
<div className="modal-cancel" onClick={e => this.cancel(e)}/>
<Localized id="experimentPreFeedbackTitle" $title={experiment.title}>
<h3 className="modal-header"></h3>
</Localized>
<div className="modal-cancel" onClick={e => this.cancel(e)}/>
</header>
<div className="tour-content">
<div className="tour-image">
Expand All @@ -39,9 +36,10 @@ export default class ExperimentPreFeedbackDialog extends React.Component {
{parser(experiment.pre_feedback_copy)}
</div>
<div className="tour-text">
<a data-l10n-id="experimentPreFeedbackLinkCopy"
data-l10n-args={l10nArgs} onClick={e => this.feedback(e)}
href={surveyURL}></a>
<Localized id="experimentPreFeedbackLinkCopy" $title={experiment.title}>
<a onClick={e => this.feedback(e)}
href={surveyURL}></a>
</Localized>
</div>
</div>
</div>
Expand Down
63 changes: 44 additions & 19 deletions frontend/src/app/components/ExperimentRowCard.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// @flow

import React from 'react';
import classnames from 'classnames';
import { Localized } from 'fluent-react/compat';
import React from 'react';

import LocalizedHtml from '../components/LocalizedHtml';

import { buildSurveyURL, experimentL10nId } from '../lib/utils';

Expand Down Expand Up @@ -49,9 +52,15 @@ export default class ExperimentRowCard extends React.Component {
})}
>
<div className="experiment-actions">
{enabled && <div data-l10n-id="experimentListEnabledTab" className="tab enabled-tab"></div>}
{this.justLaunched() && <div data-l10n-id="experimentListJustLaunchedTab" className="tab just-launched-tab"></div>}
{this.justUpdated() && <div data-l10n-id="experimentListJustUpdatedTab" className="tab just-updated-tab"></div>}
{enabled && <Localized id="experimentListEnabledTab">
<div className="tab enabled-tab"></div>
</Localized>}
{this.justLaunched() && <Localized id="experimentListJustLaunchedTab">
<div className="tab just-launched-tab"></div>
</Localized>}
{this.justUpdated() && <Localized id="experimentListJustUpdatedTab">
<div className="tab just-updated-tab"></div>
</Localized>}
</div>
<div className={`experiment-icon-wrapper-${experiment.slug} experiment-icon-wrapper`}>
<div className={`experiment-icon-${experiment.slug} experiment-icon`}></div>
Expand All @@ -60,12 +69,16 @@ export default class ExperimentRowCard extends React.Component {
<header>
<div>
<h3>{title}</h3>
{subtitle && <h4 data-l10n-id={this.l10nId('subtitle')} className="subtitle">{subtitle}</h4>}
{subtitle && <Localized id={this.l10nId('subtitle')}>
<h4 className="subtitle">{subtitle}</h4>
</Localized>}
<h4>{this.statusMsg()}</h4>
</div>
{this.renderFeedbackButton()}
</header>
<p data-l10n-id={this.l10nId('description')}>{description}</p>
<Localized id={this.l10nId('description')}>
<p>{description}</p>
</Localized>
{ this.renderInstallationCount(installation_count, isCompleted) }
{ this.renderManageButton(enabled, hasAddon, isCompleted) }
</div>
Expand All @@ -80,9 +93,9 @@ export default class ExperimentRowCard extends React.Component {
renderInstallationCount(installation_count: number, isCompleted: Boolean) {
if (installation_count <= 100 || isCompleted) return '';
return (
<span className="participant-count"
data-l10n-id="participantCount"
data-l10n-args={JSON.stringify({ installation_count })}>{installation_count}</span>
<LocalizedHtml id="participantCount" $installation_count={installation_count}>
<span className="participant-count"><span>{installation_count}</span> participants</span>
</LocalizedHtml>
);
}

Expand All @@ -94,11 +107,13 @@ export default class ExperimentRowCard extends React.Component {
const surveyURL = buildSurveyURL('givefeedback', title, installed, clientUUID, survey_url);
return (
<div>
<a onClick={() => this.handleFeedback()}
href={surveyURL} target="_blank" rel="noopener noreferrer"
className="experiment-feedback" data-l10n-id="experimentCardFeedback">
Feedback
</a>
<Localized id="experimentCardFeedback">
<a onClick={() => this.handleFeedback()}
href={surveyURL} target="_blank" rel="noopener noreferrer"
className="experiment-feedback">
Feedback
</a>
</Localized>
</div>
);
}
Expand All @@ -115,15 +130,21 @@ export default class ExperimentRowCard extends React.Component {
renderManageButton(enabled: Boolean, hasAddon: Boolean, isCompleted: Boolean) {
if (enabled && hasAddon) {
return (
<div className="button card-control secondary" data-l10n-id="experimentCardManage">Manage</div>
<Localized id="experimentCardManage">
<div className="button card-control secondary">Manage</div>
</Localized>
);
} else if (isCompleted) {
return (
<div className="button card-control secondary" data-l10n-id="experimentCardLearnMore">Learn More</div>
<Localized id="experimentCardLearnMore">
<div className="button card-control secondary">Learn More</div>
</Localized>
);
}
return (
<div className="button card-control default" data-l10n-id="experimentCardGetStarted">Get Started</div>
<Localized id="experimentCardGetStarted">
<div className="button card-control default">Get Started</div>
</Localized>
);
}

Expand Down Expand Up @@ -171,9 +192,13 @@ export default class ExperimentRowCard extends React.Component {
if (delta < 0) {
return '';
} else if (delta < ONE_DAY) {
return <span className="eol-message" data-l10n-id="experimentListEndingTomorrow">Ending Tomorrow</span>;
return <Localized id="experimentListEndingTomorrow">
<span className="eol-message">Ending Tomorrow</span>
</Localized>;
} else if (delta < ONE_WEEK) {
return <span className="eol-message" data-l10n-id="experimentListEndingSoon">Ending Soon</span>;
return <Localized id="experimentListEndingSoon">
<span className="eol-message">Ending Soon</span>
</Localized>;
}
}
return '';
Expand Down
Loading