Browse Source

Add "Languages" page (#1691)

* Added language selector page

* PR nits

* Fix typo in variable name

* Added language icon. Show search icon in mobile.

* Tweaked header alignment

* Split languages into 3 categories based on progress:
complete, partially translated, and needs contributors

* Lower-cased pt-* language codes

* Re-added locale sort

* Renamed 'Partially Translated' header to 'In Progress'
main
Brian Vaughn 6 years ago
committed by Dan Abramov
parent
commit
07253c8209
  1. 133
      content/languages.yml
  2. 29
      src/components/LayoutHeader/DocSearch.js
  3. 77
      src/components/LayoutHeader/Header.js
  4. 159
      src/pages/languages.js
  5. 2
      src/site-constants.js

133
content/languages.yml

@ -0,0 +1,133 @@
# Status enums indicate what percentage of "core" content has been translated:
# 0: Incomplete (0–49%)
# 1: Partially complete (50–94%)
# 2: Complete (95–100%)
- name: English
translated_name: English
code: en
status: 2
- name: Arabic
translated_name: العربية
code: ar
status: 0
- name: Azerbaijani
translated_name: Azərbaycanca
code: az
status: 0
- name: Bulgarian
translated_name: Български
code: bg
status: 0
- name: Bengali
translated_name: বাংলা
code: bn
status: 0
- name: German
translated_name: Deutsch
code: de
status: 0
- name: Spanish
translated_name: Español
code: es
status: 2
- name: Persian
translated_name: فارسی
code: fa
status: 0
- name: French
translated_name: Français
code: fr
status: 0
- name: Hebrew
translated_name: עברית
code: he
status: 0
- name: Hindi
translated_name: हिन्दी
code: hi
status: 0
- name: Armenian
translated_name: Հայերեն
code: hy
status: 0
- name: Indonesian
translated_name: Bahasa Indonesia
code: id
status: 0
- name: Italian
translated_name: Italiano
code: it
status: 0
- name: Japanese
translated_name: 日本語
code: ja
status: 1
- name: Korean
translated_name: 한국어
code: ko
status: 0
- name: Malayalam
translated_name: മലയാളം
code: ml
status: 0
- name: Nepali
translated_name: नेपाली
code: ne
status: 0
- name: Dutch
translated_name: Nederlands
code: nl
status: 0
- name: Polish
translated_name: Polski
code: pl
status: 0
- name: Portuguese (Brazil)
translated_name: Português do Brasil
code: pt-br
status: 1
- name: Portuguese (Portugal)
translated_name: Português europeu
code: pt-pt
status: 0
- name: Romanian
translated_name: Română
code: ro
status: 0
- name: Russian
translated_name: Русский
code: ru
status: 0
- name: Sinhala
translated_name: සිංහල
code: si
status: 0
- name: Tamil
translated_name: தமிழ்
code: ta
status: 0
- name: Turkish
translated_name: Türkçe
code: tr
status: 0
- name: Ukrainian
translated_name: Українська
code: uk
status: 0
- name: Uzbek
translated_name: Oʻzbekcha
code: uz
status: 0
- name: Vietnamese
translated_name: Tiếng Việt
code: vi
status: 0
- name: Simplified Chinese
translated_name: 简体中文
code: zh-hans
status: 0
- name: Traditional Chinese
translated_name: 繁體中文
code: zh-hant
status: 0

29
src/components/LayoutHeader/DocSearch.js

@ -42,27 +42,23 @@ class DocSearch extends Component<{}, State> {
flex: '0 0 auto',
flexDirection: 'row',
alignItems: 'center',
paddingLeft: '0.5rem',
paddingRight: '0.5rem',
paddingLeft: '0.25rem',
paddingRight: '0.25rem',
[media.lessThan('small')]: {
justifyContent: 'flex-end',
},
[media.lessThan('large')]: {
justifyContent: 'flex-end',
marginRight: 10,
},
[media.between('small', 'medium')]: {
width: 'calc(100% / 3)',
},
[media.between('medium', 'xlarge')]: {
width: 'calc(100% / 6)',
//width: 'calc(100% / 6)',
},
[media.greaterThan('small')]: {
minWidth: 120,
[media.greaterThan('large')]: {
minWidth: 100,
},
}}>
<input
css={{
width: '100%',
appearance: 'none',
background: 'transparent',
border: 0,
@ -71,12 +67,12 @@ class DocSearch extends Component<{}, State> {
fontWeight: 300,
fontFamily: 'inherit',
position: 'relative',
padding: '5px 5px 5px 29px',
padding: '4px 4px 4px 29px',
backgroundImage: 'url(/search.svg)',
backgroundSize: '16px 16px',
backgroundRepeat: 'no-repeat',
backgroundPositionY: 'center',
backgroundPositionX: '5px',
backgroundPositionX: '4px',
':focus': {
outline: 0,
@ -86,11 +82,6 @@ class DocSearch extends Component<{}, State> {
[media.lessThan('large')]: {
fontSize: 16,
},
[media.greaterThan('small')]: {
width: '100%',
},
[media.lessThan('small')]: {
width: '16px',
transition: 'width 0.2s ease, padding 0.2s ease',
paddingLeft: '16px',
@ -104,7 +95,7 @@ class DocSearch extends Component<{}, State> {
}}
id="algolia-doc-search"
type="search"
placeholder="Search docs"
placeholder="Search"
aria-label="Search docs"
/>
</form>

77
src/components/LayoutHeader/Header.js

@ -92,6 +92,7 @@ const Header = ({location}: {location: Location}) => (
<nav
css={{
flex: '1',
display: 'flex',
flexDirection: 'row',
alignItems: 'stretch',
@ -99,7 +100,6 @@ const Header = ({location}: {location: Location}) => (
overflowY: 'hidden',
WebkitOverflowScrolling: 'touch',
height: '100%',
width: '60%',
[media.size('xsmall')]: {
flexGrow: '1',
@ -139,12 +139,17 @@ const Header = ({location}: {location: Location}) => (
<div
css={{
[media.lessThan('medium')]: {
display: 'none',
},
[media.greaterThan('large')]: {
width: 'calc(100% / 6)',
},
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
width: 'auto',
//[media.lessThan('medium')]: {
//width: 'auto',
//},
//[media.greaterThan('large')]: {
//width: 'calc(100% / 4)',
//},
}}>
<Link
css={{
@ -161,10 +166,45 @@ const Header = ({location}: {location: Location}) => (
backgroundColor: colors.lighter,
borderRadius: 15,
},
[media.lessThan('medium')]: {
display: 'none',
},
}}
to="/versions">
v{version}
</Link>
<Link
css={{
display: 'flex',
alignItems: 'center',
padding: '5px 10px',
whiteSpace: 'nowrap',
...fonts.small,
':hover': {
color: colors.brand,
},
':focus': {
outline: 0,
backgroundColor: colors.lighter,
borderRadius: 15,
},
}}
to="/languages">
<LanguagesIcon />{' '}
<span
css={{
marginLeft: '0.5rem',
[media.lessThan('medium')]: {
display: 'none',
},
}}>
Languages
</span>
</Link>
<a
css={{
padding: '5px 10px',
@ -181,6 +221,10 @@ const Header = ({location}: {location: Location}) => (
backgroundColor: colors.lighter,
borderRadius: 15,
},
[media.lessThan('large')]: {
display: 'none',
},
}}
href="https://github.com/facebook/react/"
target="_blank"
@ -200,4 +244,23 @@ const Header = ({location}: {location: Location}) => (
</header>
);
const LanguagesIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none" />
<path
css={{fill: 'currentColor'}}
d="
M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5
7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09
5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62
7l1.62-4.33L19.12 17h-3.24z
"
/>
</svg>
);
export default Header;

159
src/pages/languages.js

@ -0,0 +1,159 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* @emails react-core
* @flow
*/
import Layout from 'components/Layout';
import Container from 'components/Container';
import Header from 'components/Header';
import TitleAndMetaTags from 'components/TitleAndMetaTags';
import React from 'react';
import {media, sharedStyles} from 'theme';
// $FlowFixMe This is a valid path
import languages from '../../content/languages.yml';
// Status enums indicate what percentage of "core" content has been translated:
// 0: Incomplete (0–49%)
// 1: Partially complete (50–94%)
// 2: Complete (95–100%)
const {complete, incomplete, partial} = languages.reduce(
(reduced, language) => {
switch (language.status) {
case 0:
reduced.incomplete.push(language);
break;
case 1:
reduced.partial.push(language);
break;
case 2:
reduced.complete.push(language);
break;
}
return reduced;
},
{complete: [], incomplete: [], partial: []},
);
type Props = {
location: Location,
};
const Languages = ({location}: Props) => (
<Layout location={location}>
<Container>
<div css={sharedStyles.articleLayout.container}>
<div css={sharedStyles.articleLayout.content}>
<Header>Languages</Header>
<TitleAndMetaTags title="React - Languages" />
<div css={sharedStyles.markdown}>
<p>
The React documentation is available in the following languages:
</p>
<LanguagesGrid languages={complete} />
<h2>In Progress</h2>
<LanguagesGrid languages={partial} />
<h2>Needs Contributors</h2>
<LanguagesGrid languages={incomplete} />
<p>
Don't see your language above?{' '}
<a
href="https://github.com/reactjs/reactjs.org-translation#reactjsorg-translation"
target="_blank"
rel="noopener">
Let us know
</a>
.
</p>
</div>
</div>
</div>
</Container>
</Layout>
);
const LanguagesGrid = ({languages}) => (
<ul
css={{
display: 'flex',
flexWrap: 'wrap',
marginLeft: -20,
}}>
{languages
.sort((a, b) => a.code.localeCompare(b.code))
.map(({code, name, status, translated_name}) => (
<Language
key={code}
code={code}
name={name}
status={status}
translatedName={translated_name}
/>
))}
</ul>
);
const Language = ({code, name, status, translatedName}) => {
const prefix = code === 'en' ? '' : `${code}.`;
return (
<li
css={{
paddingLeft: 20,
paddingTop: 20,
borderTop: '1px dotted #ececec',
paddingBottom: 20,
width: '100%',
listStyle: 'none',
[media.size('small')]: {
width: '50%',
},
[media.size('medium')]: {
width: '33.33%',
},
[media.greaterThan('large')]: {
width: '25%',
},
}}
key={code}>
<div css={{}}>{name}</div>
<div
css={{
fontSize: 22,
fontWeight: 'bold',
marginBottom: 8,
marginTop: 8,
}}>
{status === 0 && translatedName}
{status > 0 && (
<a href={`https://${prefix}reactjs.org/`} rel="nofollow">
{translatedName}
</a>
)}
</div>
<div css={{marginTop: 10}}>
<a
css={{
fontSize: 12,
}}
href={`https://github.com/reactjs/${prefix}reactjs.org/`}
target="_blank"
rel="noopener">
Contribute
</a>
</div>
</li>
);
};
export default Languages;

2
src/site-constants.js

@ -11,4 +11,4 @@ const urlRoot = 'https://reactjs.org';
const version = '16.8.3';
const babelURL = 'https://unpkg.com/babel-standalone@6.26.0/babel.min.js';
export {urlRoot, version, babelURL};
export {babelURL, urlRoot, version};

Loading…
Cancel
Save