diff --git a/README.md b/README.md index 16f9581c..36e2ce2e 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,17 @@ and pass an object with the key defined in curly brackets and the dynamic value ```` +Use ``getCurrentLanguage()`` to retrieve the current language +````javascript +// Example: CandidatesContainer.js +// --------------------------------------------- +// 1. import getCurrentLanguage from utils/helper +import { getCurrentLanguage } from 'utils/helper' +// 2. call getCurrentLanguage() to retrieve the current language +const currentLanguage = getCurrentLanguage() +// possible currentLanguage value: en or zh (default) +```` + ## Reference [立場區議會選舉專頁 - 2015](https://dce2015.thestandnews.com) diff --git a/web/src/App.js b/web/src/App.js index f16b569f..b4790f56 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -65,7 +65,7 @@ const Wrapper = styled(Box)` const LangSwitch = props => { const { path, url } = useRouteMatch() if (url !== '/') { - i18n.changeLanguage(url.replace('/', '')) + i18n.changeLanguage(url.replace(/\//g, '')) } return ( diff --git a/web/src/components/containers/CandidatesContainer.js b/web/src/components/containers/CandidatesContainer.js index 14444c83..bfe8b8b1 100644 --- a/web/src/components/containers/CandidatesContainer.js +++ b/web/src/components/containers/CandidatesContainer.js @@ -14,6 +14,7 @@ import { getColorFromCamp, getConstituencyTagsByCandidateCamps, withLanguage, + getCurrentLanguage, } from 'utils/helper' import { COLORS } from 'ui/theme' @@ -104,6 +105,8 @@ const CandidatesContainer = props => { data.dcd_candidates && data.dcd_candidates.filter(c => c.election_type === 'ordinary') + const currentLanguage = getCurrentLanguage() + const tags = getConstituencyTagsByCandidateCamps(candidates) return ( <> @@ -136,8 +139,8 @@ const CandidatesContainer = props => { } > diff --git a/web/src/components/district/Councillor.js b/web/src/components/district/Councillor.js index 1f17dcb2..85036f15 100644 --- a/web/src/components/district/Councillor.js +++ b/web/src/components/district/Councillor.js @@ -12,6 +12,7 @@ import { useTranslation } from 'react-i18next' import { getColorFromPoliticalAffiliation, getElectionResults, + getCurrentLanguage, } from 'utils/helper' import moment from 'moment' @@ -67,6 +68,7 @@ class Councillor extends Component { const tags = [] // ['競逐連任'] //getTagsForPerson(councillor.person) const { t } = useTranslation() + const currentLanguage = getCurrentLanguage() return ( @@ -80,7 +82,7 @@ class Councillor extends Component { {councillors.map(councillor => ( diff --git a/web/src/components/molecules/SearchBoxOption.js b/web/src/components/molecules/SearchBoxOption.js index 54cf36a8..3f874619 100644 --- a/web/src/components/molecules/SearchBoxOption.js +++ b/web/src/components/molecules/SearchBoxOption.js @@ -7,7 +7,7 @@ import Columns from 'components/atoms/Columns' import { withRouter } from 'react-router-dom' import ContextStore from 'ContextStore' import { DRAWER_CLOSE } from 'reducers/drawer' -import { getProfilePath } from 'utils/helper' +import { getProfilePath, getCurrentLanguage } from 'utils/helper' // import { fireEvent } from 'utils/ga_fireevent' const AddressOption = props => { @@ -96,7 +96,8 @@ export default withRouter(props => { } = React.useContext(ContextStore) function handleAddressSelected({ year, code }) { - props.history.push(`/district/${year}/${code}`) + const currentLanguage = getCurrentLanguage() + props.history.push(`/${currentLanguage}/district/${year}/${code}`) dispatch({ type: DRAWER_CLOSE }) } diff --git a/web/src/components/molecules/candidate/CandidatesTableContent.js b/web/src/components/molecules/candidate/CandidatesTableContent.js index 8de239e6..12860cd6 100644 --- a/web/src/components/molecules/candidate/CandidatesTableContent.js +++ b/web/src/components/molecules/candidate/CandidatesTableContent.js @@ -3,7 +3,11 @@ import { PeopleAvatar } from 'components/atoms/Avatar' import { withRouter } from 'react-router-dom' import { Box, Grid } from '@material-ui/core' import styled from 'styled-components' -import { getColorFromCamp } from 'utils/helper' +import { + getColorFromCamp, + getCurrentLanguage, + withLanguage, +} from 'utils/helper' import { COLORS } from 'ui/theme' import TableRow from '@material-ui/core/TableRow' import TableCell from '@material-ui/core/TableCell' @@ -93,7 +97,7 @@ const CandidateGrid = props => { /> - {candidate.person.name_zh || candidate.person.name_en} + {withLanguage(candidate.person.name_en, candidate.person.name_zh)} {candidate.tags.findIndex( tag => tag.type === 'camp' && tag.tag === '有爭議' ) > -1 && ( @@ -148,6 +152,7 @@ class CandidatesTableContent extends Component { render() { const { props, matchCamp } = this const { candidates, showEstablishment, showDemocracy, showOthers } = props + const currentLanguage = getCurrentLanguage() return ( <> {candidates @@ -159,7 +164,7 @@ class CandidatesTableContent extends Component { key={candidate.person.id} onClick={() => { props.history.push( - `/profile/${candidate.person.name_zh || + `/${currentLanguage}/profile/${candidate.person.name_zh || candidate.person.name_en}/${candidate.person.uuid}` ) }} diff --git a/web/src/components/molecules/constituency/ConstituencyTableContent.js b/web/src/components/molecules/constituency/ConstituencyTableContent.js index 544694c0..da8da217 100644 --- a/web/src/components/molecules/constituency/ConstituencyTableContent.js +++ b/web/src/components/molecules/constituency/ConstituencyTableContent.js @@ -3,7 +3,11 @@ import styled from 'styled-components' import { withRouter } from 'react-router-dom' import CandidatesTableContent from 'components/molecules/candidate/CandidatesTableContent' import { TableRow, TableCell, Box, Typography } from '@material-ui/core' -import { getConstituencyTagsByCandidateCamps, withLanguage } from 'utils/helper' +import { + getConstituencyTagsByCandidateCamps, + withLanguage, + getCurrentLanguage, +} from 'utils/helper' import { SecondaryTag } from 'components/atoms/Tag' import { SeperatedColumns } from 'components/atoms/Columns' @@ -34,12 +38,15 @@ const ConstituencyTableContent = props => { showOthers, } = props const tags = getConstituencyTagsByCandidateCamps(constituency.candidates) + const currentLanguage = getCurrentLanguage() return ( <> { - props.history.push(`/district/${year}/${constituency.code}`) + props.history.push( + `/${currentLanguage}/district/${year}/${constituency.code}` + ) }} > diff --git a/web/src/components/molecules/district/DistrictTableContent.js b/web/src/components/molecules/district/DistrictTableContent.js index 39a3fd0d..3bb6f6f0 100644 --- a/web/src/components/molecules/district/DistrictTableContent.js +++ b/web/src/components/molecules/district/DistrictTableContent.js @@ -6,7 +6,7 @@ import TableCell from '@material-ui/core/TableCell' import { Typography } from '@material-ui/core' import TableRow from '@material-ui/core/TableRow' import { useTranslation } from 'react-i18next' -import { withLanguage } from 'utils/helper' +import { withLanguage, getCurrentLanguage } from 'utils/helper' const DistrictNameTableRow = styled(TableRow)` && { @@ -25,11 +25,14 @@ const DistrictTableContent = props => { } = props const { t } = useTranslation() + const currentLanguage = getCurrentLanguage() return ( <> { - props.history.push(`/district/${year}/${district.dc_code}`) + props.history.push( + `/${currentLanguage}/district/${year}/${district.dc_code}` + ) }} > diff --git a/web/src/components/organisms/ConstituencyCard.js b/web/src/components/organisms/ConstituencyCard.js index 626e95e9..0cfd5281 100644 --- a/web/src/components/organisms/ConstituencyCard.js +++ b/web/src/components/organisms/ConstituencyCard.js @@ -5,7 +5,7 @@ import { withRouter } from 'react-router-dom' import { SecondaryTag } from 'components/atoms/Tag' import Box from '@material-ui/core/Box' import Columns from 'components/atoms/Columns' -import { getDistrictListUriFromTag } from 'utils/helper' +import { getDistrictListUriFromTag, getCurrentLanguage } from 'utils/helper' import CandidatesContainer from 'components/containers/CandidatesContainer' const StyledCard = styled(Card)` @@ -29,11 +29,13 @@ const ConstituencyCard = props => { const sortedTags = tags.sort((a, b) => a.type === 'boundary' ? -1 : a.type === b.type ? 0 : 1 ) - + const currentLanguage = getCurrentLanguage() return ( { - props.history.push(`/district/2019/${constituency.code}`) + props.history.push( + `/${currentLanguage}/district/2019/${constituency.code}` + ) }} > diff --git a/web/src/components/organisms/Footer.js b/web/src/components/organisms/Footer.js index 152a8113..87302e3d 100644 --- a/web/src/components/organisms/Footer.js +++ b/web/src/components/organisms/Footer.js @@ -7,6 +7,7 @@ import Columns from 'components/atoms/Columns' import { withRouter } from 'react-router-dom' import { Disclaimer } from 'components/templates/Disclaimer' import { useTranslation } from 'react-i18next' +import { getCurrentLanguage } from 'utils/helper' const StyledFooter = styled(Box)` && { @@ -39,6 +40,7 @@ const LinkBox = styled(Box)` function Footer(props) { const { t } = useTranslation() + const currentLanguage = getCurrentLanguage() return ( <> @@ -49,7 +51,7 @@ function Footer(props) { props.history.push(`/about-us`) + () => props.history.push(`/${currentLanguage}/about-us`) // console.log(props) } > @@ -68,7 +70,7 @@ function Footer(props) { props.history.push(`/disclaimer`) + () => props.history.push(`/${currentLanguage}/disclaimer`) // console.log(props) } > diff --git a/web/src/components/organisms/SearchTab.js b/web/src/components/organisms/SearchTab.js index 7caaab04..e66a6916 100644 --- a/web/src/components/organisms/SearchTab.js +++ b/web/src/components/organisms/SearchTab.js @@ -7,6 +7,7 @@ import { withRouter } from 'react-router-dom' import ContextStore from 'ContextStore' import { DRAWER_CLOSE } from 'reducers/drawer' import DistrictSelector from 'components/molecules/DistrictSelector' +import { getCurrentLanguage } from 'utils/helper' const Container = styled(Paper)` && { @@ -51,8 +52,10 @@ function SearchTab(props) { When user select click previous button in district page, the CACODE should follow follow the above result */ - - props.history.push(`/district/${result.year}/${result.code}`) + const currentLanguage = getCurrentLanguage() + props.history.push( + `/${currentLanguage}/district/${result.year}/${result.code}` + ) dispatch({ type: DRAWER_CLOSE }) } diff --git a/web/src/components/pages/battleground/index.js b/web/src/components/pages/battleground/index.js index 49f45415..d554a71b 100644 --- a/web/src/components/pages/battleground/index.js +++ b/web/src/components/pages/battleground/index.js @@ -23,6 +23,7 @@ import { getDistrictOverviewUriFromTag, getParameterByName, withLanguage, + getCurrentLanguage, } from 'utils/helper' import { getCentroidFromYearAndCode, @@ -90,7 +91,8 @@ class BattleGroundPage extends Component { (selectedYear == null && selectedCode == null) || (year !== selectedYear || code !== selectedCode) ) { - this.props.history.push(`/district/${year}/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push(`/${currentLanguage}/district/${year}/${code}`) } } @@ -137,7 +139,8 @@ class BattleGroundPage extends Component { params: { code }, }, } = this.props - this.props.history.push(`/district/2015/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push(`/${currentLanguage}/district/2015/${code}`) } onNextElection() { @@ -146,7 +149,10 @@ class BattleGroundPage extends Component { params: { year, code }, }, } = this.props - this.props.history.push(`/district/${parseInt(year, 10) + 4}/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push( + `/${currentLanguage}/district/${parseInt(year, 10) + 4}/${code}` + ) } render() { @@ -185,7 +191,7 @@ class BattleGroundPage extends Component { const DCCAStatus = district.tags && district.tags.find(tag => tag.type === 'boundary') - + console.log(district) return ( <> @@ -195,7 +201,10 @@ class BattleGroundPage extends Component { > { - this.props.history.push(`/district/2019`) + const currentLanguage = getCurrentLanguage() + this.props.history.push( + `/${currentLanguage}/district/2019` + ) }} > {year} diff --git a/web/src/components/pages/disclaimer/index.js b/web/src/components/pages/disclaimer/index.js index dad861a8..2db84c88 100644 --- a/web/src/components/pages/disclaimer/index.js +++ b/web/src/components/pages/disclaimer/index.js @@ -47,10 +47,10 @@ const DisclaimerPage = props => {

{/* 本屆區議會選舉的候選人政治陣營取自 */} - {t('disclaimer.paragraph2.segment1')} + {t('disclaimer.paragraph2.segment1')}{' '} {/* 選區事實處 */} - {t('thirdParty.dfo')} + {t('thirdParty.dfo')}{' '} {/* ,該網站收集大眾意見,並跟據以下資料綜合判斷: */} {t('disclaimer.paragraph2.segment2')} diff --git a/web/src/components/pages/district/index.js b/web/src/components/pages/district/index.js index a337f742..e49f26bd 100644 --- a/web/src/components/pages/district/index.js +++ b/web/src/components/pages/district/index.js @@ -7,6 +7,7 @@ import MainAreas from 'components/district/MainAreas' import Metrics from 'components/district/Metrics' import styled from 'styled-components' import { bps } from 'ui/responsive' +import { getCurrentLanguage } from 'utils/helper' import { QUERY_CONSTITUENCIES } from 'queries/gql' @@ -65,14 +66,18 @@ class DistrictPage extends Component { } handleCandidateSelected = person => { + const currentLanguage = getCurrentLanguage() this.props.history.push( - `/profile/${person.name_zh || person.name_en}/${person.uuid}` + `/${currentLanguage}/profile/${person.name_zh || person.name_en}/${ + person.uuid + }` ) } handleChangeDistrict = (year, code) => { if (!year || !code) return - this.props.history.push(`/district/${year}/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push(`/${currentLanguage}/district/${year}/${code}`) } onPrevElection() { @@ -81,7 +86,10 @@ class DistrictPage extends Component { params: { year, code }, }, } = this.props - this.props.history.push(`/district/${parseInt(year, 10) - 4}/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push( + `/${currentLanguage}/district/${parseInt(year, 10) - 4}/${code}` + ) } onNextElection() { @@ -90,7 +98,10 @@ class DistrictPage extends Component { params: { year, code }, }, } = this.props - this.props.history.push(`/district/${parseInt(year, 10) + 4}/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push( + `/${currentLanguage}/district/${parseInt(year, 10) + 4}/${code}` + ) } render() { diff --git a/web/src/components/pages/profile/index.js b/web/src/components/pages/profile/index.js index d10d543c..95119281 100644 --- a/web/src/components/pages/profile/index.js +++ b/web/src/components/pages/profile/index.js @@ -21,6 +21,7 @@ import { withTranslation } from 'react-i18next' import { getDistrictOverviewUriFromTag, getConstituencyUriFromTag, + getCurrentLanguage, } from 'utils/helper' // TODO: add age, camp & related_organization @@ -229,7 +230,8 @@ class ProfilePage extends Component { async componentDidMount() {} handleElectionDetailButton = (year, code) => { - this.props.history.push(`/district/${year}/${code}`) + const currentLanguage = getCurrentLanguage() + this.props.history.push(`/${currentLanguage}/district/${year}/${code}`) } renderFacebook = person => { @@ -452,7 +454,10 @@ class ProfilePage extends Component { > { - this.props.history.push(`/district/2019`) + const currentLanguage = getCurrentLanguage() + this.props.history.push( + `/${currentLanguage}/district/2019` + ) }} > diff --git a/web/src/components/templates/Councillor.js b/web/src/components/templates/Councillor.js index 4f7708ee..839632ff 100644 --- a/web/src/components/templates/Councillor.js +++ b/web/src/components/templates/Councillor.js @@ -10,6 +10,8 @@ import { getColorFromPoliticalAffiliation, getCouncillorMeta, formatNumber, + withLanguage, + getCurrentLanguage, } from 'utils/helper' const Councillor = props => { @@ -25,13 +27,13 @@ const Councillor = props => { const meta = getCouncillorMeta(councillor) const { t } = useTranslation() const [imageLoadError, setImageLoadError] = useState(true) + const currentLanguage = getCurrentLanguage() return ( @@ -70,7 +72,10 @@ const Councillor = props => { - {councillor.person.name_zh} + {withLanguage( + councillor.person.name_en, + councillor.person.name_zh + )} @@ -89,8 +94,7 @@ const Councillor = props => { - {meta.lastParticipated.year} - {/* 選舉結果 */} + {meta.lastParticipated.year} {/* 選舉結果 */} {t('electionResults')} diff --git a/web/src/components/templates/DCCAElectionHistories.js b/web/src/components/templates/DCCAElectionHistories.js index 67d6e7e7..57db43bb 100644 --- a/web/src/components/templates/DCCAElectionHistories.js +++ b/web/src/components/templates/DCCAElectionHistories.js @@ -36,6 +36,7 @@ class DCCAElectionHistories extends Component { name_zh candidates(where: { year: { _eq: $year${year} }, cacode: { _eq: $code${code} } }) { person { + name_en name_zh uuid } diff --git a/web/src/components/templates/DCCAElectionResult.js b/web/src/components/templates/DCCAElectionResult.js index 61994a15..ff29985c 100644 --- a/web/src/components/templates/DCCAElectionResult.js +++ b/web/src/components/templates/DCCAElectionResult.js @@ -9,7 +9,12 @@ import LinearProgress from '@material-ui/core/LinearProgress' import { COLORS } from 'ui/theme' import { UnstyledNavLink } from 'components/atoms/Link' -import { formatNumber, getColorFromCamp } from 'utils/helper' +import { + formatNumber, + getColorFromCamp, + withLanguage, + getCurrentLanguage, +} from 'utils/helper' const Container = styled.div` && { @@ -89,6 +94,7 @@ const DCCAElectionResult = props => { ) const [imageLoadError, setImageLoadError] = useState(true) + const currentLanguage = getCurrentLanguage() return ( @@ -101,10 +107,11 @@ const DCCAElectionResult = props => { (candidate.votes / electionResult.vote_sum) * 100 ).toFixed(1) + return ( @@ -138,7 +145,10 @@ const DCCAElectionResult = props => { - {candidate.person.name_zh} + {withLanguage( + candidate.person.name_en, + candidate.person.name_zh + )} diff --git a/web/src/components/templates/PersonElectionHistories.js b/web/src/components/templates/PersonElectionHistories.js index d3a11df1..f29db44e 100644 --- a/web/src/components/templates/PersonElectionHistories.js +++ b/web/src/components/templates/PersonElectionHistories.js @@ -7,7 +7,7 @@ import { Box, Grid } from '@material-ui/core' import { SuccessText, FailureText } from '../atoms/Text' import { UnstyledNavLink } from '../atoms/Link' import NavigateNextIcon from '@material-ui/icons/NavigateNext' -import { formatNumber } from 'utils/helper' +import { formatNumber, getCurrentLanguage } from 'utils/helper' import { useTranslation } from 'react-i18next' import { getCentroidFromYearAndCode, @@ -23,7 +23,8 @@ const PersonElectionHistoriesTitle = styled.div` ` const createQueryStringToBattlegroundPage = election => { - let targetPath = `/district/2019/${election.constituency.code}` + const currentLanguage = getCurrentLanguage() + let targetPath = `/${currentLanguage}/district/2019/${election.constituency.code}` switch (election.year) { case 2019: return targetPath @@ -40,7 +41,7 @@ const createQueryStringToBattlegroundPage = election => { lat: coordinates[1], } const dccaHistories = getAllFeaturesFromPoint(point) - targetPath = `/district/2019/${ + targetPath = `/${currentLanguage}/district/2019/${ dccaHistories.find(history => history.year === '2019').CACODE }` return targetPath + `?year=${election.year}` diff --git a/web/src/utils/helper.js b/web/src/utils/helper.js index ac110c0c..19a3c0bf 100644 --- a/web/src/utils/helper.js +++ b/web/src/utils/helper.js @@ -1,11 +1,21 @@ import { DCREGION } from 'constants/dcregion' import _ from 'lodash' +import i18n from 'i18n' -export const getDistrictListUriFromTag = tag => `/district/2019/tags/${tag}` +export const getDistrictListUriFromTag = tag => { + const currentLanguage = getCurrentLanguage() + return `/${currentLanguage}/district/2019/tags/${tag}` +} -export const getDistrictOverviewUriFromTag = code => `/district/2019/${code}` +export const getDistrictOverviewUriFromTag = code => { + const currentLanguage = getCurrentLanguage() + return `/${currentLanguage}/district/2019/${code}` +} -export const getConstituencyUriFromTag = code => `/district/2019/${code}` +export const getConstituencyUriFromTag = code => { + const currentLanguage = getCurrentLanguage() + return `/${currentLanguage}/district/2019/${code}` +} export const getCodeFromDistrictName = name => { let code = 'A' @@ -157,7 +167,8 @@ export const getColorFromPoliticalAffiliation = pa => { export const getProfilePath = person => { const { name_en, name_zh, uuid } = person - return `/profile/${name_zh || name_en}/${uuid}` + const currentLanguage = getCurrentLanguage() + return `/${currentLanguage}/profile/${name_zh || name_en}/${uuid}` } export const formatNumber = num => @@ -205,7 +216,11 @@ export const getConstituencyTagsByCandidateCamps = candidates => { } export const withLanguage = (name_en, name_zh) => { - var lang = window.location.href.match(/(en|zh)$/) - lang = lang ? lang[0] : 'zh' + var lang = window.location.pathname.match(/^\/([\w]{2})\//) + lang = lang ? lang[1] : 'zh' return lang === 'en' && name_en ? name_en : name_zh } + +export const getCurrentLanguage = () => { + return i18n.language || window.localStorage.i18nextLng || 'zh' +}