Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(i18n): add i18n support #951

Merged
merged 34 commits into from
Feb 28, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ca53310
feat(i18n): add i18n support
Feb 25, 2019
f4cdec4
feat(i18n): extending language files
Feb 25, 2019
d3d039b
feat(i18n): calendar-header
Feb 25, 2019
36aada3
Merge branch 'master' into feat/i18n
gergelyke Feb 25, 2019
42ad35f
docs(i18n): add cta
Feb 25, 2019
4c0d09e
feat(i18n): co-locate locale files
Feb 25, 2019
d8ef6b2
Merge branch 'master' into feat/i18n
gergelyke Feb 25, 2019
bdb6726
fix(i18n): remove unused import
Feb 25, 2019
f7ac2f3
feat(i18n): breadcrumb and accordion
Feb 25, 2019
03d1973
feat(i18n): buttongrup
Feb 25, 2019
2ba26bb
fix(i18n): breadcrumb prop
Feb 25, 2019
d72da0d
Merge branch 'master' into feat/i18n
gergelyke Feb 25, 2019
f541e2e
feat(i18n): file-uploader
Feb 25, 2019
635028d
feat(i18n): modal
Feb 25, 2019
b9ff5c9
feat(i18n): pagination
Feb 26, 2019
bf02490
feat(i18n): select
Feb 26, 2019
46d561c
feat(i18n): toast
Feb 26, 2019
4ef8859
Merge branch 'master' into feat/i18n
gergelyke Feb 26, 2019
41e1b78
Merge branch 'master' into feat/i18n
gergelyke Feb 26, 2019
029d327
Merge branch 'master' into feat/i18n
gergelyke Feb 26, 2019
cffbcb9
feat(i18n): fix ButtonGroup tests
tajo Feb 27, 2019
bd7fb02
Merge branch 'master' into feat/i18n
gergelyke Feb 27, 2019
f07ffcd
Merge branch 'master' into feat/i18n
gergelyke Feb 27, 2019
2f971f9
fix(i18n): breadcrumbs
Feb 27, 2019
083752e
fix(i18n): test coverage
Feb 27, 2019
6ef7e2e
fix(i18n): flow types
Feb 27, 2019
a040d5f
docs(i18n): add example
Feb 27, 2019
b2c2cff
fix(i18n): update snapshots
Feb 28, 2019
c21f011
Merge branch 'master' into feat/i18n
gergelyke Feb 28, 2019
6a0c288
Merge branch 'master' into feat/i18n
gergelyke Feb 28, 2019
c353798
fix(i18n): pagination
Feb 28, 2019
a2ab15d
docs(i18n): more docs
Feb 28, 2019
4ee5e45
Merge branch 'master' into feat/i18n
gergelyke Feb 28, 2019
290357f
Update src/button-group/button-group.js
chasestarr Feb 28, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions documentation-site/pages/getting-started/internationalization.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!--
Copyright (c) 2018 Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
-->

import Layout from '../../components/layout';

export default Layout;

# Internationalization

Base UI supports English as the default language. Following the instructions below, you
can use other languages too.

```javascript
import { LocaleProvider } from 'baseui';
import {huHU} from '{YOUR_PROJECT}/hu.json';
import App from '{YOUR_PROJECT}/app.js';

return (
<LocaleProvider locale={huHU}>
<App />
</LocaleProvider>
);
```


4 changes: 4 additions & 0 deletions documentation-site/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ const routes = [
text: 'Comparison with other component libraries',
path: '/getting-started/comparison',
},
{
text: 'Internationalization',
path: '/getting-started/internationalization',
},
],
},
{
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
"dependencies": {
"date-fns": "2.0.0-alpha.27",
"focus-trap": "^4.0.2",
"just-extend": "^4.0.2",
"memoize-one": "^5.0.0",
"popper.js": "^1.14.3",
"react-dropzone": "^9.0.0",
Expand Down
25 changes: 15 additions & 10 deletions src/datepicker/calendar-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ LICENSE file in the root directory of this source tree.
import * as React from 'react';
import {ArrowLeft, ArrowRight} from '../icon/index.js';
import {Select} from '../select/index.js';
import {LocaleContext} from '../locale/index.js';
import {
StyledCalendarHeader,
StyledPrevButton,
Expand Down Expand Up @@ -59,7 +60,7 @@ export default class CalendarHeader extends React.Component<HeaderPropsT> {
this.props.onMonthChange({date: subMonths(this.props.date, 1)});
};

renderPreviousMonthButton = () => {
renderPreviousMonthButton = ({locale}) => {
const {date, overrides = {}} = this.props;
const allPrevDaysDisabled = monthDisabledBefore(date, this.props);

Expand All @@ -81,7 +82,7 @@ export default class CalendarHeader extends React.Component<HeaderPropsT> {
}
return (
<PrevButton
aria-label="Previous month"
aria-label={locale.datepicker.previousMonth}
tabIndex={0}
onClick={clickHandler}
{...prevButtonProps}
Expand All @@ -98,7 +99,7 @@ export default class CalendarHeader extends React.Component<HeaderPropsT> {
);
};

renderNextMonthButton = () => {
renderNextMonthButton = ({locale}) => {
const {date, overrides = {}} = this.props;
const allNextDaysDisabled = monthDisabledAfter(date, this.props);

Expand Down Expand Up @@ -126,7 +127,7 @@ export default class CalendarHeader extends React.Component<HeaderPropsT> {
}
return (
<NextButton
aria-label="Next month"
aria-label={locale.datepicker.nextMonth}
tabIndex={0}
onClick={clickHandler}
{...nextButtonProps}
Expand Down Expand Up @@ -273,12 +274,16 @@ export default class CalendarHeader extends React.Component<HeaderPropsT> {
StyledCalendarHeader,
);
return (
<CalendarHeader {...calendarHeaderProps}>
{this.renderPreviousMonthButton()}
{this.renderMonthDropdown()}
{this.renderYearDropdown()}
{this.renderNextMonthButton()}
</CalendarHeader>
<LocaleContext.Consumer>
{locale => (
<CalendarHeader {...calendarHeaderProps}>
{this.renderPreviousMonthButton({locale})}
{this.renderMonthDropdown()}
{this.renderYearDropdown()}
{this.renderNextMonthButton({locale})}
</CalendarHeader>
)}
</LocaleContext.Consumer>
);
}
}
110 changes: 58 additions & 52 deletions src/datepicker/datepicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {Popover, PLACEMENT} from '../popover/index.js';
import Calendar from './calendar.js';
import {formatDate} from './utils/index.js';
import {getOverrides} from '../helpers/overrides.js';
import {LocaleContext} from '../locale/index.js';
import type {DatepickerPropsT} from './types.js';

export default class Datepicker extends React.Component<
Expand All @@ -23,7 +24,6 @@ export default class Datepicker extends React.Component<
},
> {
static defaultProps = {
'aria-label': 'Select a date',
'aria-labelledby': null,
'aria-describedby': 'datepicker--screenreader--message--input',
disabled: false,
Expand Down Expand Up @@ -138,58 +138,64 @@ export default class Datepicker extends React.Component<
overrides.Popover,
Popover,
);

return (
<React.Fragment>
<PopoverComponent
placement={PLACEMENT.bottom}
isOpen={this.state.isOpen}
onClickOutside={this.close}
onEsc={this.handleEsc}
content={
<Calendar
autoFocusCalendar={this.state.calendarFocused}
trapTabbing={true}
value={this.props.value}
{...this.props}
onChange={this.onChange}
/>
}
{...popoverProps}
>
<InputComponent
aria-disabled={this.props.disabled}
aria-label={this.props['aria-label']}
aria-labelledby={this.props['aria-labelledby']}
aria-describedby={this.props['aria-describedby']}
aria-required={this.props.required || null}
disabled={this.props.disabled}
value={this.formatDisplayValue(this.props.value)}
onFocus={this.open}
onBlur={this.handleInputBlur}
onKeyDown={this.handleKeyDown}
placeholder={this.props.placeholder}
required={this.props.required}
{...inputProps}
/>
</PopoverComponent>
<p
id="datepicker--screenreader--message--input"
style={{
position: 'absolute',
width: '1px',
height: '1px',
margin: '-1px',
border: '0px',
padding: '0px',
overflow: 'hidden',
clip: 'react(0px, 0px, 0px, 0px)',
clipPath: 'inset(100%)',
}}
>
Press the down arrow key to interact with the calendar and select a
date. Press the escape button to close the calendar.
</p>
</React.Fragment>
<LocaleContext.Consumer>
{locale => (
<React.Fragment>
<PopoverComponent
placement={PLACEMENT.bottom}
isOpen={this.state.isOpen}
onClickOutside={this.close}
onEsc={this.handleEsc}
content={
<Calendar
autoFocusCalendar={this.state.calendarFocused}
trapTabbing={true}
value={this.props.value}
{...this.props}
onChange={this.onChange}
/>
}
{...popoverProps}
>
<InputComponent
aria-disabled={this.props.disabled}
aria-label={
this.props['aria-label'] || locale.datepicker.ariaLabel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. I wanted to point this one out. 👍

}
aria-labelledby={this.props['aria-labelledby']}
aria-describedby={this.props['aria-describedby']}
aria-required={this.props.required || null}
disabled={this.props.disabled}
value={this.formatDisplayValue(this.props.value)}
onFocus={this.open}
onBlur={this.handleInputBlur}
onKeyDown={this.handleKeyDown}
placeholder={this.props.placeholder}
required={this.props.required}
{...inputProps}
/>
</PopoverComponent>
<p
id="datepicker--screenreader--message--input"
style={{
position: 'absolute',
width: '1px',
height: '1px',
margin: '-1px',
border: '0px',
padding: '0px',
overflow: 'hidden',
clip: 'react(0px, 0px, 0px, 0px)',
clipPath: 'inset(100%)',
}}
>
{locale.datepicker.screenReaderMessageInput}
</p>
</React.Fragment>
)}
</LocaleContext.Consumer>
);
}
}
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LICENSE file in the root directory of this source tree.
*/
// @flow
export {styled, ThemeProvider} from './styles/index.js';
import LocaleProvider from './locale/index.js';
export {LocaleProvider};
export {
createTheme,
lightThemePrimitives,
Expand Down
19 changes: 19 additions & 0 deletions src/locale/en_US.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
Copyright (c) 2018 Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
// @flow

const en_US = {
datepicker: {
chasestarr marked this conversation as resolved.
Show resolved Hide resolved
ariaLabel: 'Select a date',
previousMonth: 'Previous month',
nextMonth: 'Next month',
screenReaderMessageInput:
'Press the down arrow key to interact with the calendar and select a date. Press the escape button to close the calendar.',
},
};

export default en_US;
25 changes: 25 additions & 0 deletions src/locale/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
Copyright (c) 2018 Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
// @flow
import * as React from 'react';
import extend from 'just-extend';

import type {LocaleT} from './types.js';
import en_US from './en_US.js';

export const LocaleContext: React.Context<LocaleT> = React.createContext(en_US);

const LocaleProvider = (props: {locale: LocaleT, children: ?React.Node}) => {
const {locale, children} = props;
return (
<LocaleContext.Provider value={extend(en_US, locale)}>
{children}
</LocaleContext.Provider>
);
};

export default LocaleProvider;
18 changes: 18 additions & 0 deletions src/locale/types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright (c) 2018 Uber Technologies, Inc.

This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
// @flow

export type DatepickerLocaleT = {|
ariaLabel: string,
chasestarr marked this conversation as resolved.
Show resolved Hide resolved
nextMonth: string,
prevMonth: string,
screenReaderMessageInput: string,
|};

export type LocaleT = {|
datepicker: DatepickerLocaleT,
Copy link
Member

@tajo tajo Feb 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be overriding the English locale and keeping all LocaleT props optional?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean user can do that but it should be a deepMerge and seems nice to do it by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that makes perfect sense 👍

|};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8997,6 +8997,11 @@ junk@^1.0.1:
resolved "https://registry.yarnpkg.com/junk/-/junk-1.0.3.tgz#87be63488649cbdca6f53ab39bec9ccd2347f592"
integrity sha1-h75jSIZJy9ym9Tqzm+yczSNH9ZI=

just-extend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.0.2.tgz#f3f47f7dfca0f989c55410a7ebc8854b07108afc"
integrity sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==

kefir@^3.7.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/kefir/-/kefir-3.8.3.tgz#8e0ab10084ed8a01cbb5d4f7f18a0b859f7b9bd9"
Expand Down