Skip to content

Commit dec99ee

Browse files
author
Brian Vaughn
committed
JIT choose default docs language and persist user selections with localStorage
1 parent d5211dc commit dec99ee

File tree

6 files changed

+92
-20
lines changed

6 files changed

+92
-20
lines changed

plugins/gatsby-plugin-crowdin/onCreatePage.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ module.exports = ({page, boundActionCreators}, pluginOptions) => {
9797

9898
createRedirect({
9999
fromPath: nonLocalizedPath,
100-
toPath: path,
100+
toPath: `/docs-language-redirect/?${nonLocalizedPath}`,
101101
redirectInBrowser: true,
102102
Language: language,
103103
});

src/pages/docs-language-redirect.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
*
4+
* @emails react-core
5+
*/
6+
7+
import React from 'react';
8+
import PropTypes from 'prop-types';
9+
import {Redirect} from 'react-router-dom';
10+
import {getSelectedLanguage} from 'utils/languageUtils';
11+
12+
const DocsRedirect = ({location}) => {
13+
// Redirect the user to their most recent locale, or English as a fallback.
14+
const language = getSelectedLanguage();
15+
16+
return <Redirect to={`/${language}${location.search.substr(1)}`} />;
17+
};
18+
19+
DocsRedirect.propTypes = {
20+
location: PropTypes.object.isRequired,
21+
};
22+
23+
export default DocsRedirect;

src/pages/translations.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ import TitleAndMetaTags from 'components/TitleAndMetaTags';
1111
import Link from 'gatsby-link';
1212
import React from 'react';
1313
import {sharedStyles} from 'theme';
14-
15-
// $FlowFixMe This is a valid path
16-
import languages from '../../crowdin/languages.json';
14+
import {getTranslatedLanguages} from 'utils/languageUtils';
1715

1816
const Translations = () => (
1917
<Container>
@@ -27,7 +25,7 @@ const Translations = () => (
2725
languages:
2826
</p>
2927
<ul>
30-
{languages.map(language => (
28+
{getTranslatedLanguages().map(language => (
3129
<li key={language}>
3230
<Link to={`/${language}/docs/hello-world.html`}>
3331
{language}

src/templates/docs.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,26 @@ import PropTypes from 'prop-types';
99
import React from 'react';
1010
import {createLinkDocs} from 'utils/createLink';
1111
import {sectionListDocs} from 'utils/sectionList';
12+
import {setSelectedLanguage} from 'utils/languageUtils';
1213

13-
const Docs = ({data, location}) => (
14-
<MarkdownPage
15-
createLink={createLinkDocs}
16-
location={location}
17-
markdownRemark={data.markdownRemark}
18-
sectionList={sectionListDocs}
19-
titlePostfix=" - React"
20-
/>
21-
);
14+
const Docs = ({data, location}) => {
15+
// Store the user's most recent locale based on the current URL.
16+
// We'll restore this language when they visit a new (unlocalized) URL.
17+
const matches = location.pathname.substr(1).split('/');
18+
if (matches.length > 1) {
19+
setSelectedLanguage(matches[0]);
20+
}
21+
22+
return (
23+
<MarkdownPage
24+
createLink={createLinkDocs}
25+
location={location}
26+
markdownRemark={data.markdownRemark}
27+
sectionList={sectionListDocs}
28+
titlePostfix=" - React"
29+
/>
30+
);
31+
};
2232

2333
Docs.propTypes = {
2434
data: PropTypes.object.isRequired,

src/utils/createLink.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,13 @@ type CreateLinkBaseProps = {
2424

2525
const createLinkBlog = ({
2626
isActive,
27-
isLocalized,
2827
item,
2928
location,
3029
section,
3130
}: CreateLinkBaseProps): Node => {
3231
return (
3332
<Link
3433
css={[linkCss, isActive && activeLinkCss]}
35-
isLocalized={isLocalized}
3634
location={location}
3735
to={item.id}>
3836
{isActive && <span css={activeLinkBefore} />}
@@ -43,7 +41,6 @@ const createLinkBlog = ({
4341

4442
const createLinkCommunity = ({
4543
isActive,
46-
isLocalized,
4744
item,
4845
location,
4946
section,
@@ -65,7 +62,7 @@ const createLinkCommunity = ({
6562
}
6663
return createLinkDocs({
6764
isActive,
68-
isLocalized,
65+
isLocalized: false,
6966
item,
7067
location,
7168
section,
@@ -97,7 +94,6 @@ type CreateLinkTutorialProps = {
9794

9895
const createLinkTutorial = ({
9996
isActive,
100-
isLocalized,
10197
item,
10298
location,
10399
onLinkClick,
@@ -106,7 +102,6 @@ const createLinkTutorial = ({
106102
return (
107103
<Link
108104
css={[linkCss, isActive && activeLinkCss]}
109-
isLocalized={isLocalized}
110105
location={location}
111106
onClick={onLinkClick}
112107
to={item.href}>

src/utils/languageUtils.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* Copyright (c) 2013-present, Facebook, Inc.
3+
*
4+
* @emails react-core
5+
* @flow
6+
*/
7+
8+
// $FlowFixMe This is a valid path
9+
import languagesArray from '../../crowdin/languages.json';
10+
11+
const DEFAULT_LANGUAGE = 'en-US';
12+
13+
const languagesMap = languagesArray.reduce((map: Object, language: string) => {
14+
map[language] = true;
15+
return map;
16+
}, Object.create(null));
17+
18+
export function getTranslatedLanguages(): Array<string> {
19+
return languagesArray;
20+
}
21+
22+
export function getSelectedLanguage(): string {
23+
let language = localStorage.getItem('selectedLanguage');
24+
if (languagesMap[language]) {
25+
return ((language: any): string);
26+
} else {
27+
const {languages} = navigator;
28+
for (let i = 0; i < languages.length; i++) {
29+
language = languages[i];
30+
if (languagesMap[language]) {
31+
return language;
32+
}
33+
}
34+
}
35+
return DEFAULT_LANGUAGE;
36+
}
37+
38+
export function setSelectedLanguage(language: string): void {
39+
if (languagesMap[language]) {
40+
localStorage.setItem('selectedLanguage', language);
41+
} else if (process.env.NODE_ENV !== 'production') {
42+
console.warn(
43+
`Specified language "${language}" is not a valid translation.`,
44+
);
45+
}
46+
}

0 commit comments

Comments
 (0)