--- /dev/null
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+const CanonicalLinks = ({ base, lang, langs }) => {
+ const { i18n } = useTranslation();
+
+ const activeLang = lang || i18n.language;
+ const availableLangs = langs || ['de', 'en'];
+
+ return <Helmet>
+ <link
+ href={`https://alttp.localhorst.tv${base}?lng=${activeLang}`}
+ hrefLang={activeLang}
+ rel="canonical"
+ />
+ <link
+ href={`https://alttp.localhorst.tv${base}`}
+ hrefLang="x-default"
+ rel="alternate"
+ />
+ {availableLangs.filter(l => l !== activeLang).map(l =>
+ <link
+ key={l}
+ href={`https://alttp.localhorst.tv${base}?lng=${l}`}
+ hrefLang={l}
+ rel="alternate"
+ />
+ )}
+ </Helmet>;
+};
+
+CanonicalLinks.propTypes = {
+ base: PropTypes.string.isRequired,
+ lang: PropTypes.string,
+ langs: PropTypes.arrayOf(PropTypes.string),
+};
+
+export default CanonicalLinks;
import { Button, Col, Container, Image, Row } from 'react-bootstrap';
import { useNavigate } from 'react-router-dom';
+import CanonicalLinks from '../common/CanonicalLinks';
+
const Front = () => {
const navigate = useNavigate();
}, []);
return <Container className="mt-5">
+ <CanonicalLinks base="/" />
<Row>
<Col md={6}>
<Button
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
+import CanonicalLinks from '../common/CanonicalLinks';
import Buttons from '../map/Buttons';
import List from '../map/List';
import OpenSeadragon from '../map/OpenSeadragon';
<title>{t('map.heading')}</title>
<meta name="description" content={t('map.description')} />
</Helmet>
+ <CanonicalLinks base="/map" />
<OpenSeadragon ref={container}>
<div className="d-flex align-items-start justify-content-between">
<h1>{t('map.heading')}</h1>
import { withTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
+import CanonicalLinks from '../common/CanonicalLinks';
import ErrorBoundary from '../common/ErrorBoundary';
import ErrorMessage from '../common/ErrorMessage';
import Loading from '../common/Loading';
import NotFound from '../pages/NotFound';
import Detail from '../techniques/Detail';
-import { getLanguages, getTranslation } from '../../helpers/Technique';
+import { getLanguages, getMatchedLocale, getTranslation } from '../../helpers/Technique';
import i18n from '../../i18n';
const Technique = () => {
<Helmet>
<title>{getTranslation(technique, 'title', i18n.language)}</title>
<meta name="description" content={getTranslation(technique, 'short', i18n.language)} />
- <link
- href={`https://alttp.localhorst.tv/tech/${technique.name}`}
- hrefLang="x-default"
- rel="alternate"
- />
- {getLanguages(technique).map(l =>
- <link
- key={l}
- href={`https://alttp.localhorst.tv/tech/${technique.name}?lng=${l}`}
- hrefLang={l}
- rel="alternate"
- />
- )}
</Helmet>
+ <CanonicalLinks
+ base={`/tech/${technique.name}`}
+ lang={getMatchedLocale(technique, i18n.language)}
+ langs={getLanguages(technique)}
+ />
<Detail technique={technique} />
</ErrorBoundary>;
};
import { withTranslation } from 'react-i18next';
import NotFound from './NotFound';
+import CanonicalLinks from '../common/CanonicalLinks';
import ErrorBoundary from '../common/ErrorBoundary';
import ErrorMessage from '../common/ErrorMessage';
import Loading from '../common/Loading';
<title>{i18n.t(`${namespace}.heading`)}</title>
<meta name="description" content={i18n.t(`${namespace}.description`)} />
</Helmet>
+ <CanonicalLinks base="/tech" />
<Overview
filter={filter}
namespace={namespace}
import { Helmet } from 'react-helmet';
import { useParams } from 'react-router-dom';
+import CanonicalLinks from '../common/CanonicalLinks';
import ErrorBoundary from '../common/ErrorBoundary';
import ErrorMessage from '../common/ErrorMessage';
import Loading from '../common/Loading';
<Helmet>
<title>{tournament.title}</title>
</Helmet>
+ <CanonicalLinks base={`/tournaments/${tournament.id}`} />
<Detail addRound={addRound} tournament={tournament} />
</ErrorBoundary>;
};
import { Helmet } from 'react-helmet';
import { useParams } from 'react-router-dom';
+import CanonicalLinks from '../common/CanonicalLinks';
import ErrorBoundary from '../common/ErrorBoundary';
import ErrorMessage from '../common/ErrorMessage';
import Loading from '../common/Loading';
<Helmet>
<title>{user.nickname || user.username}</title>
</Helmet>
+ <CanonicalLinks base={`/users/${user.id}`} />
<Profile user={user} />
</ErrorBoundary>;
};
export const getLanguages = tech => ['en', ...tech.translations.map(t => t.locale)];
+export const getMatchedLocale = (tech, lang) => {
+ const direct = tech.translations.find(t => t.locale === lang);
+ if (direct) {
+ return direct.locale;
+ }
+ const sameLang = tech.translations.find(t => t.locale.substr(0, 2) === lang.substr(0, 2));
+ if (sameLang) {
+ return sameLang.locale;
+ }
+ return 'en';
+};
+
export const getTranslation = (tech, prop, lang) => {
const direct = tech.translations.find(t => t.locale === lang);
if (direct) {