diff --git a/.eslintignore b/.eslintignore
index 1ee2668e7..e69de29bb 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1 +0,0 @@
-src/components/SurahInfo/htmls/*
diff --git a/karma.conf.js b/karma.conf.js
index d21d97f4a..ac9b1aa40 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -13,17 +13,19 @@ module.exports = function(config) {
'karma-sinon',
'karma-webpack',
'karma-chrome-launcher',
- 'karma-phantomjs-launcher'
+ 'karma-phantomjs-launcher',
+ 'karma-intl-shim'
],
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
- frameworks: ['mocha', 'chai-sinon', 'sinon'],
+ frameworks: ['mocha', 'chai-sinon', 'sinon', 'intl-shim'],
// list of files / patterns to load in the browser
files: [
'./node_modules/phantomjs-polyfill/bind-polyfill.js',
'./tests/polyfill/Event.js',
+ './node_modules/Intl/locale-data/jsonp/en-US.js',
{pattern: 'static/images/*', watched: false, included: false, served: true},
// Actual tests here
diff --git a/package.json b/package.json
index 6ffb5c67b..9c22ed569 100644
--- a/package.json
+++ b/package.json
@@ -113,6 +113,7 @@
"url-loader": "0.5.7",
"webpack": "2.1.0-beta.20",
"webpack-isomorphic-tools": "2.5.7",
+ "react-intl": "2.1.5",
"winston": "1.1.2",
"react-inlinesvg": "0.5.4"
},
@@ -135,6 +136,7 @@
"karma-chai": "0.1.0",
"karma-chai-sinon": "0.1.5",
"karma-chrome-launcher": "0.2.0",
+ "karma-intl-shim": "1.0.3",
"karma-junit-reporter": "0.3.4",
"karma-mocha": "0.2.0",
"karma-phantomjs-launcher": "~0.2.1",
diff --git a/src/client.js b/src/client.js
index 2be5baf31..92ccb4b3c 100644
--- a/src/client.js
+++ b/src/client.js
@@ -12,6 +12,7 @@ import applyRouterMiddleware from 'react-router/lib/applyRouterMiddleware';
import useScroll from 'react-router-scroll';
import { ReduxAsyncConnect } from 'redux-connect';
import { syncHistoryWithStore } from 'react-router-redux';
+import { IntlProvider } from 'react-intl';
import debug from 'debug';
@@ -19,6 +20,7 @@ import config from './config';
import ApiClient from './helpers/ApiClient';
import createStore from './redux/create';
import routes from './routes';
+import {getLocalMessages} from './helpers/setLocal';
const client = new ApiClient();
const store = createStore(browserHistory, client, window.reduxData);
@@ -38,6 +40,9 @@ window.clearCookies = () => {
reactCookie.remove('content');
reactCookie.remove('audio');
reactCookie.remove('isFirstTime');
+ reactCookie.remove('currentLocale');
+ reactCookie.remove('smartbanner-closed');
+ reactCookie.remove('smartbanner-installed');
};
match({ history, routes: routes(store) }, (error, redirectLocation, renderProps) => {
@@ -60,9 +65,11 @@ match({ history, routes: routes(store) }, (error, redirectLocation, renderProps)
debug('client', 'React Rendering');
ReactDOM.render(
-
+
+
{component}
- , mountNode, () => {
+
+ , mountNode, () => {
debug('client', 'React Rendered');
}
);
diff --git a/src/components/Audioplayer/RepeatDropdown/index.js b/src/components/Audioplayer/RepeatDropdown/index.js
index 3f222830f..ef90239ae 100644
--- a/src/components/Audioplayer/RepeatDropdown/index.js
+++ b/src/components/Audioplayer/RepeatDropdown/index.js
@@ -6,12 +6,14 @@ import NavItem from 'react-bootstrap/lib/NavItem';
import FormControl from 'react-bootstrap/lib/FormControl';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
+import { intlShape, injectIntl } from 'react-intl';
import SwitchToggle from 'components/SwitchToggle';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
const style = require('../style.scss');
-export default class RepeatButton extends Component {
+class RepeatButton extends Component {
static propTypes = {
surah: PropTypes.object.isRequired,
repeat: PropTypes.shape({
@@ -20,7 +22,8 @@ export default class RepeatButton extends Component {
times: PropTypes.number
}).isRequired,
setRepeat: PropTypes.func.isRequired,
- current: PropTypes.number.isRequired
+ current: PropTypes.number.isRequired,
+ intl: intlShape.isRequired
};
handleToggle = () => {
@@ -59,9 +62,13 @@ export default class RepeatButton extends Component {
return (
- From - To:
-
+ {' '}:
+
- -
-
+ {' '}:
+
- Ayah:
+ {' '}:
- Single
+
- Range
+
@@ -163,13 +184,16 @@ export default class RepeatButton extends Component {
}
renderTimes() {
- const { repeat, setRepeat } = this.props;
+ const { repeat, setRepeat, intl } = this.props;
const times = Array(10).join().split(',');
return (
- Times:
+ :
-
{
times.map((ayah, index) => (
@@ -204,7 +230,10 @@ export default class RepeatButton extends Component {
title={
- Toggle repeat{' '}
+ {' '}
{
setRepeat = sinon.stub();
- component = mount(
+ component = mountWithIntl(
{
/>
);
- overlay = mount(component.find('OverlayTrigger').first().props().overlay);
+ overlay = mountWithIntl(component.find('OverlayTrigger').first().props().overlay);
}
describe('', () => {
diff --git a/src/components/Audioplayer/ScrollButton/index.js b/src/components/Audioplayer/ScrollButton/index.js
index be57620d8..314212625 100644
--- a/src/components/Audioplayer/ScrollButton/index.js
+++ b/src/components/Audioplayer/ScrollButton/index.js
@@ -1,13 +1,17 @@
import React, { PropTypes } from 'react';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
const style = require('../style.scss');
const ScrollButton = ({ shouldScroll, onScrollToggle }) => {
const tooltip = (
- Automatically scrolls to the currently playing ayah on transitions...
+
);
diff --git a/src/components/Audioplayer/index.js b/src/components/Audioplayer/index.js
index 6ecea05dc..e5bc42620 100644
--- a/src/components/Audioplayer/index.js
+++ b/src/components/Audioplayer/index.js
@@ -11,6 +11,7 @@ import Track from './Track';
import Segments from './Segments';
import ScrollButton from './ScrollButton';
import RepeatDropdown from './RepeatDropdown';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
// Helpers
import debug from 'helpers/debug';
@@ -392,7 +393,12 @@ export class Audioplayer extends Component {
if (isLoading || !currentAyah) {
return (
-
-
Loading...
+
+
+
);
}
@@ -419,7 +425,10 @@ export class Audioplayer extends Component {
-
- Ayah: {currentAyah.split(':')[1]}
+ : {currentAyah.split(':')[1]}
-
{this.renderPreviousButton()}
diff --git a/src/components/Ayah/index.js b/src/components/Ayah/index.js
index e6f4125de..6a9d18fa2 100644
--- a/src/components/Ayah/index.js
+++ b/src/components/Ayah/index.js
@@ -3,6 +3,7 @@ import Link from 'react-router/lib/Link';
import { Element } from 'react-scroll';
import Copy from 'components/Copy';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
import debug from 'helpers/debug';
@@ -61,12 +62,12 @@ export default class Ayah extends Component {
}
handlePlay(ayah) {
- const { isPlaying, audioActions } = this.props;
+ const { isPlaying, audioActions, currentAyah } = this.props;
const { pause, setAyah, play } = audioActions;
+ const isPreviouslyPlaying = isPlaying;
- if (isPlaying) {
+ if (isPlaying)
pause();
- }
setAyah(ayah);
play();
}
@@ -100,9 +101,9 @@ export default class Ayah extends Component {
}
renderMedia() {
- const { ayah, mediaActions } = this.props;
+ const { ayah, mediaActions, isSearched } = this.props;
- if (!ayah.mediaContent) return false;
+ if (isSearched || !ayah.mediaContent) return false;
return (
@@ -122,7 +123,11 @@ export default class Ayah extends Component {
data-metrics-media-content-id={content.id}
data-metrics-media-content-ayah-key={ayah.ayahKey}
>
- Watch lecture by {content.resource.name}
+
@@ -134,7 +139,7 @@ export default class Ayah extends Component {
}
renderText() {
- const { ayah, audioActions, tooltip } = this.props;
+ const { ayah, audioActions, tooltip, isSearched } = this.props;
if (!ayah.words[0].code) {
return false;
@@ -163,7 +168,7 @@ export default class Ayah extends Component {
id={id}
rel="tooltip"
onClick={event =>
- audioActions.setCurrentWord && audioActions.setCurrentWord(event.target.dataset.key)
+ !isSearched && audioActions.setCurrentWord && audioActions.setCurrentWord(event.target.dataset.key)
}
data-key={`${word.ayahKey}:${position}`}
className={`${className}`}
@@ -172,13 +177,12 @@ export default class Ayah extends Component {
/>
);
}
-
const label = isLast ? { title: `Verse ${ayah.ayahNum}` } : {};
return (
- audioActions.setCurrentWord && audioActions.setCurrentWord(event.target.dataset.key)
+ !isSearched && audioActions.setCurrentWord && audioActions.setCurrentWord(event.target.dataset.key)
}
data-key={`${word.ayahKey}:${position}`}
rel="tooltip"
@@ -204,7 +208,8 @@ export default class Ayah extends Component {
}
renderPlayLink() {
- const { isSearched, ayah } = this.props;
+ const { isSearched, ayah, currentAyah, isPlaying } = this.props;
+ const playing = ayah.ayahKey == currentAyah && isPlaying;
if (!isSearched) {
return (
@@ -212,7 +217,11 @@ export default class Ayah extends Component {
onClick={() => this.handlePlay(ayah.ayahKey)}
className="text-muted"
>
- Play
+
+
);
}
@@ -233,9 +242,9 @@ export default class Ayah extends Component {
}
renderBookmark() {
- const { ayah, bookmarked, isAuthenticated, bookmarkActions } = this.props;
+ const { ayah, bookmarked, isAuthenticated, bookmarkActions, isSearched } = this.props;
- if (!isAuthenticated) return false;
+ if (isSearched || !isAuthenticated) return false;
if (bookmarked) {
return (
@@ -243,7 +252,12 @@ export default class Ayah extends Component {
onClick={() => bookmarkActions.removeBookmark(ayah.ayahKey)}
className="text-muted"
>
- Bookmarked
+
+
+
);
}
@@ -253,7 +267,11 @@ export default class Ayah extends Component {
onClick={() => bookmarkActions.addBookmark(ayah.ayahKey)}
className="text-muted"
>
- Bookmark
+
+
);
}
diff --git a/src/components/Ayah/style.scss b/src/components/Ayah/style.scss
index 57842c1d6..09bf14987 100644
--- a/src/components/Ayah/style.scss
+++ b/src/components/Ayah/style.scss
@@ -145,11 +145,6 @@
margin-top: 5px;
margin-bottom: 25px;
}
-
- .urdu, .punjabi{
- direction: rtl;
- font-family: 'Nafees';
- }
}
.word_font{
diff --git a/src/components/ContentDropdown/index.js b/src/components/ContentDropdown/index.js
index 190b2915c..3806ed6d7 100644
--- a/src/components/ContentDropdown/index.js
+++ b/src/components/ContentDropdown/index.js
@@ -1,6 +1,8 @@
import React, { Component, PropTypes } from 'react';
import MenuItem from 'react-bootstrap/lib/MenuItem';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+
const style = require('./style.scss');
@@ -524,18 +526,25 @@ export default class ContentDropdown extends Component {
aria-haspopup="true"
aria-expanded="false"
>
- Translations
+
+
{
content.length &&
-
+
}
-
+
{this.renderEnglishList()}
-
+
{this.renderLanguagesList()}
diff --git a/src/components/ContentDropdown/spec.js b/src/components/ContentDropdown/spec.js
index e3cb8537b..a97516e36 100644
--- a/src/components/ContentDropdown/spec.js
+++ b/src/components/ContentDropdown/spec.js
@@ -1,6 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import { shallow } from 'enzyme';
+import { mountWithIntl } from '../../../tests/helpers/intl-enzyme-test-helper.js';
import ContentDropdown, { slugs } from './index';
@@ -11,7 +11,7 @@ let defaultOption = 19
describe('', () => {
beforeEach(() => {
onOptionChange = sinon.stub();
- wrapper = shallow();
+ wrapper = mountWithIntl();
});
it('should render', () => {
diff --git a/src/components/Copy/index.js b/src/components/Copy/index.js
index ab407ccfa..eaefa42c9 100644
--- a/src/components/Copy/index.js
+++ b/src/components/Copy/index.js
@@ -1,5 +1,6 @@
import React, { Component, PropTypes } from 'react';
import copyToClipboard from 'copy-to-clipboard';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
export default class Copy extends Component {
static propTypes = {
@@ -26,7 +27,11 @@ export default class Copy extends Component {
className={!isCopied && 'text-muted'}
data-metrics-event-name="Ayah:Copy"
>
- {isCopied ? 'Copied!' : 'Copy'}
+
+
);
}
diff --git a/src/components/FontSizeDropdown/index.js b/src/components/FontSizeDropdown/index.js
index a17fc75a4..3da3d8ba6 100644
--- a/src/components/FontSizeDropdown/index.js
+++ b/src/components/FontSizeDropdown/index.js
@@ -5,6 +5,8 @@ import Popover from 'react-bootstrap/lib/Popover';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+
const style = require('./style.scss');
export default class FontSizeDropdown extends Component {
@@ -29,8 +31,10 @@ export default class FontSizeDropdown extends Component {
}
renderPopup() {
+ const title =
+
return (
-
+
this.handleOptionSelected('arabic', -1)} className="pointer">
@@ -38,7 +42,7 @@ export default class FontSizeDropdown extends Component {
- Arabic
+
this.handleOptionSelected('arabic', 1)} className="pointer">
@@ -54,7 +58,7 @@ export default class FontSizeDropdown extends Component {
- Translations
+
this.handleOptionSelected('translation', 1)} className="pointer">
@@ -74,7 +78,7 @@ export default class FontSizeDropdown extends Component {
className="text-color"
data-metrics-event-name="FontSizeDropdown"
>
- Font size
+
);
diff --git a/src/components/Footer/index.js b/src/components/Footer/index.js
index 6b7300302..eecfacf9c 100644
--- a/src/components/Footer/index.js
+++ b/src/components/Footer/index.js
@@ -5,6 +5,9 @@ import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+import LocaleSwitcher from 'components/LocaleSwitcher'
+
const styles = require('./style.scss');
const Footer = () => (
@@ -13,19 +16,42 @@ const Footer = () => (
- Navigate
+ Navigate
+
- Useful sites
+
+
+
+
- Other links
+
+
+
- Sitemap
-
@@ -61,13 +93,27 @@ const Footer = () => (
+
-
- Quran.com ( also known as The Noble Quran, Al Quran, Holy Quran, Koran ){' '}
- is a pro bono project.
+
+
- © QURAN.COM. ALL RIGHTS RESERVED 2016
+
+
+
+
+
+
+
+
© QURAN.COM. ALL RIGHTS RESERVED 2016
+
diff --git a/src/components/Footer/style.scss b/src/components/Footer/style.scss
index ea87437a2..beabe666b 100644
--- a/src/components/Footer/style.scss
+++ b/src/components/Footer/style.scss
@@ -8,6 +8,11 @@
padding-top: 30px;
text-transform: uppercase;
+ .header{
+ line-height: 30px;
+ color: #fff;
+ }
+
.list{
padding-left: 0px;
:global(li){
@@ -16,11 +21,6 @@
}
}
- p{
- line-height: 30px;
- color: #fff;
- }
-
a{
font-size: 13px;
color: rgba(#fff, 0.5);
@@ -38,13 +38,4 @@
-ms-transition: color .15s ease-in-out;
transition: color .15s ease-in-out;
}
-
- .links {
- &:last-child{
- p{
- color: rgba(#fff, 0.5);
- }
- }
- }
-
}
diff --git a/src/components/Home/QuickSurahs/index.js b/src/components/Home/QuickSurahs/index.js
index 8def0c064..bd7a996a9 100644
--- a/src/components/Home/QuickSurahs/index.js
+++ b/src/components/Home/QuickSurahs/index.js
@@ -2,6 +2,8 @@ import React from 'react';
import debug from 'helpers/debug';
import Link from 'react-router/lib/Link';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+
const styles = require('containers/Home/style.scss');
export default () => {
@@ -12,7 +14,7 @@ export default () => {
return (
- Quick links:
+
{
isFriday &&
diff --git a/src/components/Home/QuickSurahs/spec.js b/src/components/Home/QuickSurahs/spec.js
index fe352eaf8..375c0fb0d 100644
--- a/src/components/Home/QuickSurahs/spec.js
+++ b/src/components/Home/QuickSurahs/spec.js
@@ -2,18 +2,21 @@ import React from 'react';
import { mount } from 'enzyme';
import Link from 'react-router/lib/Link';
import QuickSurahs from './index.js';
+import { mountWithIntl } from '../../../../tests/helpers/intl-enzyme-test-helper.js';
+
describe("", () => {
const count = new Date().getDay() === 5 ? 5 : 4;
it("Should render QuickSurahs component", () => {
- let component = mount();
+ let component = mountWithIntl();
+
expect(component).to.be.ok;
expect(component.find('a').length).to.equal(count);
});
it("Should render QuickSurahs component with Surah Al-Kahf", () => {
- let component = mount();
+ let component = mountWithIntl();
expect(component).to.be.ok;
expect(component.find('a').length).to.equal(count);
})
diff --git a/src/components/IndexHeader/Nav/index.js b/src/components/IndexHeader/Nav/index.js
index 55396965c..1d683a34d 100644
--- a/src/components/IndexHeader/Nav/index.js
+++ b/src/components/IndexHeader/Nav/index.js
@@ -2,6 +2,8 @@ import React, { Component, PropTypes } from 'react';
import Link from 'react-router/lib/Link';
import { connect } from 'react-redux';
+import LocaleFormattedMessage from 'components/LocaleFormattedMessage';
+
export class IndexHeaderNav extends Component {
static propTypes = {
user: PropTypes.object
@@ -25,25 +27,42 @@ export class IndexHeaderNav extends Component {