diff options
165 files changed, 3237 insertions, 1064 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml index 1c60cbdb3..7c6da9d57 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -5,12 +5,14 @@ env: browser: true node: true es6: true + jest: true parser: babel-eslint plugins: - react - jsx-a11y +- import parserOptions: sourceType: module @@ -21,8 +23,14 @@ parserOptions: modules: true spread: true -rules: +settings: + import/extensions: + - .js + import/ignore: + - node_modules + - \\.(css|scss|json)$ +rules: brace-style: warn comma-dangle: - error @@ -125,3 +133,17 @@ rules: jsx-a11y/role-supports-aria-props: off jsx-a11y/scope: warn jsx-a11y/tabindex-no-positive: warn + + import/extensions: + - error + - always + - js: never + import/newline-after-import: error + import/no-extraneous-dependencies: + - error + - devDependencies: + - "config/webpack/**" + - "app/javascript/mastodon/test_setup.js" + - "app/javascript/**/__tests__/**" + import/no-unresolved: error + import/no-webpack-loader-syntax: error diff --git a/.travis.yml b/.travis.yml index 52ff15c01..5c2c2c889 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,5 +53,5 @@ before_script: script: - travis_retry bundle exec parallel_test spec/ --group-by filesize --type rspec - - npm test - - bundle exec i18n-tasks unused + - yarn test + - bundle exec i18n-tasks check-normalized && bundle exec i18n-tasks unused diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index 207c7b324..069026715 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -39,6 +39,7 @@ class Settings::PreferencesController < ApplicationController :setting_boost_modal, :setting_delete_modal, :setting_auto_play_gif, + :setting_reduce_motion, :setting_system_font_ui, :setting_noindex, :setting_theme, diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 14776b354..abce85812 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -27,6 +27,7 @@ module SettingsHelper pt: 'Português', 'pt-BR': 'Português do Brasil', ru: 'Русский', + sv: 'Svenska', th: 'ภาษาไทย', tr: 'Türkçe', uk: 'Українська', diff --git a/app/javascript/glitch/components/account/header.js b/app/javascript/glitch/components/account/header.js index 6359c1775..f4a413aa3 100644 --- a/app/javascript/glitch/components/account/header.js +++ b/app/javascript/glitch/components/account/header.js @@ -48,7 +48,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; // Mastodon imports // -import emojify from 'mastodon/features/emoji/emoji'; +import emojify from '../../../mastodon/features/emoji/emoji'; import IconButton from '../../../mastodon/components/icon_button'; import Avatar from '../../../mastodon/components/avatar'; diff --git a/app/javascript/glitch/components/local_settings/container.js b/app/javascript/glitch/components/local_settings/container.js index 6c202a4e7..4569db99f 100644 --- a/app/javascript/glitch/components/local_settings/container.js +++ b/app/javascript/glitch/components/local_settings/container.js @@ -2,10 +2,10 @@ import { connect } from 'react-redux'; // Mastodon imports // -import { closeModal } from 'mastodon/actions/modal'; +import { closeModal } from '../../../mastodon/actions/modal'; // Our imports // -import { changeLocalSetting } from 'glitch/actions/local_settings'; +import { changeLocalSetting } from '../../../glitch/actions/local_settings'; import LocalSettings from '.'; const mapStateToProps = state => ({ diff --git a/app/javascript/glitch/components/local_settings/index.js b/app/javascript/glitch/components/local_settings/index.js index 7f7b93de4..ef711229a 100644 --- a/app/javascript/glitch/components/local_settings/index.js +++ b/app/javascript/glitch/components/local_settings/index.js @@ -8,7 +8,7 @@ import LocalSettingsPage from './page'; import LocalSettingsNavigation from './navigation'; // Stylesheet imports -import './style'; +import './style.scss'; export default class LocalSettings extends React.PureComponent { diff --git a/app/javascript/glitch/components/local_settings/navigation/index.js b/app/javascript/glitch/components/local_settings/navigation/index.js index 1f72cc824..fa35e83c7 100644 --- a/app/javascript/glitch/components/local_settings/navigation/index.js +++ b/app/javascript/glitch/components/local_settings/navigation/index.js @@ -7,7 +7,7 @@ import { injectIntl, defineMessages } from 'react-intl'; import LocalSettingsNavigationItem from './item'; // Stylesheet imports -import './style'; +import './style.scss'; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/app/javascript/glitch/components/local_settings/navigation/item/index.js b/app/javascript/glitch/components/local_settings/navigation/item/index.js index 1676aa404..a352d5fb2 100644 --- a/app/javascript/glitch/components/local_settings/navigation/item/index.js +++ b/app/javascript/glitch/components/local_settings/navigation/item/index.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; // Stylesheet imports -import './style'; +import './style.scss'; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/app/javascript/glitch/components/local_settings/navigation/item/style.scss b/app/javascript/glitch/components/local_settings/navigation/item/style.scss index 33d7d3744..7f7371993 100644 --- a/app/javascript/glitch/components/local_settings/navigation/item/style.scss +++ b/app/javascript/glitch/components/local_settings/navigation/item/style.scss @@ -1,4 +1,4 @@ -@import 'styles/variables'; +@import 'styles/mastodon/variables'; .glitch.local-settings__navigation__item { display: block; diff --git a/app/javascript/glitch/components/local_settings/navigation/style.scss b/app/javascript/glitch/components/local_settings/navigation/style.scss index a610a1212..0336f943b 100644 --- a/app/javascript/glitch/components/local_settings/navigation/style.scss +++ b/app/javascript/glitch/components/local_settings/navigation/style.scss @@ -1,4 +1,4 @@ -@import 'styles/variables'; +@import 'styles/mastodon/variables'; .glitch.local-settings__navigation { background: $primary-text-color; diff --git a/app/javascript/glitch/components/local_settings/page/index.js b/app/javascript/glitch/components/local_settings/page/index.js index 338d86333..366c113c0 100644 --- a/app/javascript/glitch/components/local_settings/page/index.js +++ b/app/javascript/glitch/components/local_settings/page/index.js @@ -8,7 +8,7 @@ import { defineMessages, FormattedMessage, injectIntl } from 'react-intl'; import LocalSettingsPageItem from './item'; // Stylesheet imports -import './style'; +import './style.scss'; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/app/javascript/glitch/components/local_settings/page/item/index.js b/app/javascript/glitch/components/local_settings/page/item/index.js index 326c7eeb0..37e28c084 100644 --- a/app/javascript/glitch/components/local_settings/page/item/index.js +++ b/app/javascript/glitch/components/local_settings/page/item/index.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; // Stylesheet imports -import './style'; +import './style.scss'; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * diff --git a/app/javascript/glitch/components/local_settings/page/item/style.scss b/app/javascript/glitch/components/local_settings/page/item/style.scss index da1941b99..b2d8f7185 100644 --- a/app/javascript/glitch/components/local_settings/page/item/style.scss +++ b/app/javascript/glitch/components/local_settings/page/item/style.scss @@ -1,4 +1,4 @@ -@import 'styles/variables'; +@import 'styles/mastodon/variables'; .glitch.local-settings__page__item { select { diff --git a/app/javascript/glitch/components/local_settings/page/style.scss b/app/javascript/glitch/components/local_settings/page/style.scss index 53c95ea40..e9eedcad0 100644 --- a/app/javascript/glitch/components/local_settings/page/style.scss +++ b/app/javascript/glitch/components/local_settings/page/style.scss @@ -1,4 +1,4 @@ -@import 'styles/variables'; +@import 'styles/mastodon/variables'; .glitch.local-settings__page { display: block; diff --git a/app/javascript/glitch/components/local_settings/style.scss b/app/javascript/glitch/components/local_settings/style.scss index 54fec47bd..765294607 100644 --- a/app/javascript/glitch/components/local_settings/style.scss +++ b/app/javascript/glitch/components/local_settings/style.scss @@ -1,4 +1,4 @@ -@import 'styles/variables'; +@import 'styles/mastodon/variables'; .glitch.local-settings { position: relative; diff --git a/app/javascript/mastodon/base_polyfills.js b/app/javascript/mastodon/base_polyfills.js index 266a0020c..7856b26f9 100644 --- a/app/javascript/mastodon/base_polyfills.js +++ b/app/javascript/mastodon/base_polyfills.js @@ -1,5 +1,5 @@ import 'intl'; -import 'intl/locale-data/jsonp/en.js'; +import 'intl/locale-data/jsonp/en'; import 'es6-symbol/implement'; import includes from 'array-includes'; import assign from 'object-assign'; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap new file mode 100644 index 000000000..4005c860f --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar-test.js.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<Avatar /> Autoplay renders a animated avatar 1`] = ` +<div + className="account__avatar" + data-avatar-of="@alice" + onMouseEnter={[Function]} + onMouseLeave={[Function]} + style={ + Object { + "backgroundImage": "url(/animated/alice.gif)", + "backgroundSize": "100px 100px", + "height": "100px", + "width": "100px", + } + } +/> +`; + +exports[`<Avatar /> Still renders a still avatar 1`] = ` +<div + className="account__avatar" + data-avatar-of="@alice" + onMouseEnter={[Function]} + onMouseLeave={[Function]} + style={ + Object { + "backgroundImage": "url(/static/alice.jpg)", + "backgroundSize": "100px 100px", + "height": "100px", + "width": "100px", + } + } +/> +`; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap new file mode 100644 index 000000000..d9e5e5252 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/avatar_overlay-test.js.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<AvatarOverlay renders a overlay avatar 1`] = ` +<div + className="account__avatar-overlay" +> + <div + className="account__avatar-overlay-base" + data-avatar-of="@alice" + style={ + Object { + "backgroundImage": "url(/static/alice.jpg)", + } + } + /> + <div + className="account__avatar-overlay-overlay" + data-avatar-of="@eve@blackhat.lair" + style={ + Object { + "backgroundImage": "url(/static/eve.jpg)", + } + } + /> +</div> +`; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap new file mode 100644 index 000000000..c3f018d90 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/button-test.js.snap @@ -0,0 +1,114 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<Button /> adds class "button-secondary" if props.secondary given 1`] = ` +<button + className="button button-secondary" + disabled={undefined} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +/> +`; + +exports[`<Button /> renders a button element 1`] = ` +<button + className="button" + disabled={undefined} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +/> +`; + +exports[`<Button /> renders a disabled attribute if props.disabled given 1`] = ` +<button + className="button" + disabled={true} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +/> +`; + +exports[`<Button /> renders class="button--block" if props.block given 1`] = ` +<button + className="button button--block" + disabled={undefined} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +/> +`; + +exports[`<Button /> renders the children 1`] = ` +<button + className="button" + disabled={undefined} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +> + <p> + children + </p> +</button> +`; + +exports[`<Button /> renders the given text 1`] = ` +<button + className="button" + disabled={undefined} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +> + foo +</button> +`; + +exports[`<Button /> renders the props.text instead of children 1`] = ` +<button + className="button" + disabled={undefined} + onClick={[Function]} + style={ + Object { + "height": "36px", + "lineHeight": "36px", + "padding": "0 16px", + } + } +> + foo +</button> +`; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap new file mode 100644 index 000000000..533359ffe --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/display_name-test.js.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<DisplayName /> renders display name + account name 1`] = ` +<span + className="display-name" +> + <strong + className="display-name__html" + dangerouslySetInnerHTML={ + Object { + "__html": "<p>Foo</p>", + } + } + /> + + <span + className="display-name__account" + > + @ + bar@baz + </span> +</span> +`; diff --git a/app/javascript/mastodon/components/__tests__/avatar-test.js b/app/javascript/mastodon/components/__tests__/avatar-test.js new file mode 100644 index 000000000..dd3f7b7d2 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/avatar-test.js @@ -0,0 +1,36 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { fromJS } from 'immutable'; +import Avatar from '../avatar'; + +describe('<Avatar />', () => { + const account = fromJS({ + username: 'alice', + acct: 'alice', + display_name: 'Alice', + avatar: '/animated/alice.gif', + avatar_static: '/static/alice.jpg', + }); + + const size = 100; + + describe('Autoplay', () => { + it('renders a animated avatar', () => { + const component = renderer.create(<Avatar account={account} animate size={size} />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + }); + + describe('Still', () => { + it('renders a still avatar', () => { + const component = renderer.create(<Avatar account={account} size={size} />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + }); + + // TODO add autoplay test if possible +}); diff --git a/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js b/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js new file mode 100644 index 000000000..44addea83 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/avatar_overlay-test.js @@ -0,0 +1,29 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { fromJS } from 'immutable'; +import AvatarOverlay from '../avatar_overlay'; + +describe('<AvatarOverlay', () => { + const account = fromJS({ + username: 'alice', + acct: 'alice', + display_name: 'Alice', + avatar: '/animated/alice.gif', + avatar_static: '/static/alice.jpg', + }); + + const friend = fromJS({ + username: 'eve', + acct: 'eve@blackhat.lair', + display_name: 'Evelyn', + avatar: '/animated/eve.gif', + avatar_static: '/static/eve.jpg', + }); + + it('renders a overlay avatar', () => { + const component = renderer.create(<AvatarOverlay account={account} friend={friend} />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/app/javascript/mastodon/components/__tests__/button-test.js b/app/javascript/mastodon/components/__tests__/button-test.js new file mode 100644 index 000000000..160cd3cbc --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/button-test.js @@ -0,0 +1,75 @@ +import { shallow } from 'enzyme'; +import React from 'react'; +import renderer from 'react-test-renderer'; +import Button from '../button'; + +describe('<Button />', () => { + it('renders a button element', () => { + const component = renderer.create(<Button />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders the given text', () => { + const text = 'foo'; + const component = renderer.create(<Button text={text} />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('handles click events using the given handler', () => { + const handler = jest.fn(); + const button = shallow(<Button onClick={handler} />); + button.find('button').simulate('click'); + + expect(handler.mock.calls.length).toEqual(1); + }); + + it('does not handle click events if props.disabled given', () => { + const handler = jest.fn(); + const button = shallow(<Button onClick={handler} disabled />); + button.find('button').simulate('click'); + + expect(handler.mock.calls.length).toEqual(0); + }); + + it('renders a disabled attribute if props.disabled given', () => { + const component = renderer.create(<Button disabled />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders the children', () => { + const children = <p>children</p>; + const component = renderer.create(<Button>{children}</Button>); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders the props.text instead of children', () => { + const text = 'foo'; + const children = <p>children</p>; + const component = renderer.create(<Button text={text}>{children}</Button>); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders class="button--block" if props.block given', () => { + const component = renderer.create(<Button block />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('adds class "button-secondary" if props.secondary given', () => { + const component = renderer.create(<Button secondary />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/app/javascript/mastodon/components/__tests__/display_name-test.js b/app/javascript/mastodon/components/__tests__/display_name-test.js new file mode 100644 index 000000000..0d040c4cd --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/display_name-test.js @@ -0,0 +1,18 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { fromJS } from 'immutable'; +import DisplayName from '../display_name'; + +describe('<DisplayName />', () => { + it('renders display name + account name', () => { + const account = fromJS({ + username: 'bar', + acct: 'bar@baz', + display_name_html: '<p>Foo</p>', + }); + const component = renderer.create(<DisplayName account={account} />); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/app/javascript/mastodon/components/collapsable.js b/app/javascript/mastodon/components/collapsable.js index ad1453589..42ea37ec2 100644 --- a/app/javascript/mastodon/components/collapsable.js +++ b/app/javascript/mastodon/components/collapsable.js @@ -1,5 +1,5 @@ import React from 'react'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../features/ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import PropTypes from 'prop-types'; diff --git a/app/javascript/mastodon/components/dropdown_menu.js b/app/javascript/mastodon/components/dropdown_menu.js index 73ad46bb7..3a3ebf487 100644 --- a/app/javascript/mastodon/components/dropdown_menu.js +++ b/app/javascript/mastodon/components/dropdown_menu.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import IconButton from './icon_button'; import Overlay from 'react-overlays/lib/Overlay'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../features/ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import detectPassiveEvents from 'detect-passive-events'; diff --git a/app/javascript/mastodon/components/icon_button.js b/app/javascript/mastodon/components/icon_button.js index 6fb191c6b..76b0da12f 100644 --- a/app/javascript/mastodon/components/icon_button.js +++ b/app/javascript/mastodon/components/icon_button.js @@ -1,7 +1,8 @@ import React from 'react'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../features/ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; export default class IconButton extends React.PureComponent { @@ -56,27 +57,26 @@ export default class IconButton extends React.PureComponent { style.textAlign = 'left'; } - const classes = ['icon-button']; - - if (this.props.active) { - classes.push('active'); - } - - if (this.props.disabled) { - classes.push('disabled'); - } - - if (this.props.inverted) { - classes.push('inverted'); - } - - if (this.props.overlay) { - classes.push('overlayed'); - } - - if (this.props.className) { - classes.push(this.props.className); - } + const { + active, + animate, + className, + disabled, + expanded, + icon, + inverted, + overlay, + pressed, + tabIndex, + title, + } = this.props; + + const classes = classNames(className, 'icon-button', { + active, + disabled, + inverted, + overlayed: overlay, + }); const flipDeg = this.props.flip ? -180 : -360; const rotateDeg = this.props.active ? flipDeg : 0; @@ -90,23 +90,23 @@ export default class IconButton extends React.PureComponent { damping: 7, }; const motionStyle = { - rotate: this.props.animate ? spring(rotateDeg, springOpts) : 0, + rotate: animate ? spring(rotateDeg, springOpts) : 0, }; return ( <Motion defaultStyle={motionDefaultStyle} style={motionStyle}> {({ rotate }) => <button - aria-label={this.props.title} - aria-pressed={this.props.pressed} - aria-expanded={this.props.expanded} - title={this.props.title} - className={classes.join(' ')} + aria-label={title} + aria-pressed={pressed} + aria-expanded={expanded} + title={title} + className={classes} onClick={this.handleClick} style={style} - tabIndex={this.props.tabIndex} + tabIndex={tabIndex} > - <i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${this.props.icon}`} aria-hidden='true' /> + <i style={{ transform: `rotate(${rotate}deg)` }} className={`fa fa-fw fa-${icon}`} aria-hidden='true' /> {this.props.label} </button> } diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js index cf9c8fb53..af152cc32 100644 --- a/app/javascript/mastodon/components/status_action_bar.js +++ b/app/javascript/mastodon/components/status_action_bar.js @@ -16,6 +16,7 @@ const messages = defineMessages({ block: { id: 'account.block', defaultMessage: 'Block @{name}' }, reply: { id: 'status.reply', defaultMessage: 'Reply' }, share: { id: 'status.share', defaultMessage: 'Share' }, + more: { id: 'status.more', defaultMessage: 'More' }, replyAll: { id: 'status.replyAll', defaultMessage: 'Reply to thread' }, reblog: { id: 'status.reblog', defaultMessage: 'Boost' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, @@ -182,7 +183,7 @@ export default class StatusActionBar extends ImmutablePureComponent { {shareButton} <div className='status__action-bar-dropdown'> - <DropdownMenuContainer disabled={anonymousAccess} status={status} items={menu} icon='ellipsis-h' size={18} direction='right' ariaLabel='More' /> + <DropdownMenuContainer disabled={anonymousAccess} status={status} items={menu} icon='ellipsis-h' size={18} direction='right' ariaLabel={intl.formatMessage(messages.more)} /> </div> </div> ); diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index 8ad60b9d6..0f7f15dfc 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -125,6 +125,7 @@ export default class StatusContent extends React.PureComponent { const directionStyle = { direction: 'ltr' }; const classNames = classnames('status__content', { 'status__content--with-action': this.props.onClick && this.context.router, + 'status__content--with-spoiler': status.get('spoiler_text').length > 0, }); if (isRtl(status.get('search_index'))) { @@ -156,7 +157,7 @@ export default class StatusContent extends React.PureComponent { {mentionsPlaceholder} - <div tabIndex={!hidden && 0} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} style={directionStyle} dangerouslySetInnerHTML={content} /> + <div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} style={directionStyle} dangerouslySetInnerHTML={content} /> </div> ); } else if (this.props.onClick) { diff --git a/app/javascript/mastodon/containers/mastodon.js b/app/javascript/mastodon/containers/mastodon.js index 6beffca1c..a7138e62d 100644 --- a/app/javascript/mastodon/containers/mastodon.js +++ b/app/javascript/mastodon/containers/mastodon.js @@ -10,6 +10,7 @@ import { hydrateStore } from '../actions/store'; import { connectUserStream } from '../actions/streaming'; import { IntlProvider, addLocaleData } from 'react-intl'; import { getLocale } from '../locales'; + const { localeData, messages } = getLocale(); addLocaleData(localeData); diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js index 5402d6753..57678d162 100644 --- a/app/javascript/mastodon/features/account/components/header.js +++ b/app/javascript/mastodon/features/account/components/header.js @@ -6,7 +6,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import IconButton from '../../../components/icon_button'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import { connect } from 'react-redux'; import ImmutablePureComponent from 'react-immutable-pure-component'; diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js index 5b06cef7c..17f5bde4b 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.js +++ b/app/javascript/mastodon/features/compose/components/compose_form.js @@ -58,7 +58,6 @@ export default class ComposeForm extends ImmutablePureComponent { onPickEmoji: PropTypes.func.isRequired, showSearch: PropTypes.bool, settings : ImmutablePropTypes.map.isRequired, - filesAttached : PropTypes.bool, }; static defaultProps = { @@ -156,13 +155,12 @@ export default class ComposeForm extends ImmutablePureComponent { } render () { - const { intl, onPaste, showSearch, filesAttached } = this.props; + const { intl, onPaste, showSearch } = this.props; const disabled = this.props.is_submitting; const maybeEye = (this.props.advanced_options && this.props.advanced_options.do_not_federate) ? ' 👁️' : ''; const text = [this.props.spoiler_text, countableText(this.props.text), maybeEye].join(''); const secondaryVisibility = this.props.settings.get('side_arm'); - const isWideView = this.props.settings.get('stretch'); let showSideArm = secondaryVisibility !== 'none'; let publishText = ''; @@ -182,14 +180,9 @@ export default class ComposeForm extends ImmutablePureComponent { { <i className={`fa fa-${privacyIcons[this.props.privacy]}`} - style={{ - paddingRight: (filesAttached || !isWideView) ? '0' : '5px', - }} + style={{ paddingRight: '5px' }} /> - }{ - (filesAttached || !isWideView) ? '' : - intl.formatMessage(messages.publish) - } + }{intl.formatMessage(messages.publish)} </span> ); @@ -247,36 +240,33 @@ export default class ComposeForm extends ImmutablePureComponent { <UploadFormContainer /> </div> - <div className='compose-form__buttons-wrapper'> - <div className='compose-form__buttons'> - <UploadButtonContainer /> - <DoodleButtonContainer /> - <PrivacyDropdownContainer /> - <ComposeAdvancedOptionsContainer /> - <SensitiveButtonContainer /> - <SpoilerButtonContainer /> - </div> + <div className='compose-form__buttons'> + <UploadButtonContainer /> + <DoodleButtonContainer /> + <PrivacyDropdownContainer /> + <ComposeAdvancedOptionsContainer /> + <SensitiveButtonContainer /> + <SpoilerButtonContainer /> + </div> - <div className='compose-form__publish'> - <div className='character-counter__wrapper'><CharacterCounter max={500} text={text} /></div> - <div className='compose-form__publish-button-wrapper'> - { - showSideArm ? - <Button - className='compose-form__publish__side-arm' - text={publishText2} - onClick={this.handleSubmit2} - disabled={submitDisabled} - /> : '' - } - <Button - className='compose-form__publish__primary' - text={publishText} - onClick={this.handleSubmit} - disabled={submitDisabled} - block - /> - </div> + <div className='compose-form__publish'> + <div className='character-counter__wrapper'><CharacterCounter max={500} text={text} /></div> + <div className='compose-form__publish-button-wrapper'> + { + showSideArm ? + <Button + className='compose-form__publish__side-arm' + text={publishText2} + onClick={this.handleSubmit2} + disabled={submitDisabled} + /> : '' + } + <Button + className='compose-form__publish__primary' + text={publishText} + onClick={this.handleSubmit} + disabled={submitDisabled} + /> </div> </div> </div> diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js index e38ed38c1..c1e85aee3 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.js +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { injectIntl, defineMessages } from 'react-intl'; import IconButton from '../../../components/icon_button'; import Overlay from 'react-overlays/lib/Overlay'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import detectPassiveEvents from 'detect-passive-events'; import classNames from 'classnames'; diff --git a/app/javascript/mastodon/features/compose/components/search.js b/app/javascript/mastodon/features/compose/components/search.js index f57d54618..398fc44ce 100644 --- a/app/javascript/mastodon/features/compose/components/search.js +++ b/app/javascript/mastodon/features/compose/components/search.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import Overlay from 'react-overlays/lib/Overlay'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; const messages = defineMessages({ diff --git a/app/javascript/mastodon/features/compose/components/upload.js b/app/javascript/mastodon/features/compose/components/upload.js index cd9e08360..5d8d66cf7 100644 --- a/app/javascript/mastodon/features/compose/components/upload.js +++ b/app/javascript/mastodon/features/compose/components/upload.js @@ -2,7 +2,7 @@ import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import PropTypes from 'prop-types'; import IconButton from '../../../components/icon_button'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { defineMessages, injectIntl } from 'react-intl'; diff --git a/app/javascript/mastodon/features/compose/components/upload_progress.js b/app/javascript/mastodon/features/compose/components/upload_progress.js index 3e49098c7..d5e6f19cd 100644 --- a/app/javascript/mastodon/features/compose/components/upload_progress.js +++ b/app/javascript/mastodon/features/compose/components/upload_progress.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import { FormattedMessage } from 'react-intl'; diff --git a/app/javascript/mastodon/features/compose/components/warning.js b/app/javascript/mastodon/features/compose/components/warning.js index a0814e984..803b7f86a 100644 --- a/app/javascript/mastodon/features/compose/components/warning.js +++ b/app/javascript/mastodon/features/compose/components/warning.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; export default class Warning extends React.PureComponent { diff --git a/app/javascript/mastodon/features/compose/containers/autosuggest_status_container.js b/app/javascript/mastodon/features/compose/containers/autosuggest_status_container.js deleted file mode 100644 index a9e3a9edf..000000000 --- a/app/javascript/mastodon/features/compose/containers/autosuggest_status_container.js +++ /dev/null @@ -1,15 +0,0 @@ -import { connect } from 'react-redux'; -import AutosuggestStatus from '../components/autosuggest_status'; -import { makeGetStatus } from '../../../selectors'; - -const makeMapStateToProps = () => { - const getStatus = makeGetStatus(); - - const mapStateToProps = (state, { id }) => ({ - status: getStatus(state, id), - }); - - return mapStateToProps; -}; - -export default connect(makeMapStateToProps)(AutosuggestStatus); diff --git a/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js b/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js index 8624849f3..e4bd5a743 100644 --- a/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js +++ b/app/javascript/mastodon/features/compose/containers/sensitive_button_container.js @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import IconButton from '../../../components/icon_button'; import { changeComposeSensitivity } from '../../../actions/compose'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import { injectIntl, defineMessages } from 'react-intl'; diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js index 9068648bd..41a97d550 100644 --- a/app/javascript/mastodon/features/compose/index.js +++ b/app/javascript/mastodon/features/compose/index.js @@ -10,7 +10,7 @@ import { changeLocalSetting } from '../../../glitch/actions/local_settings'; import { Link } from 'react-router-dom'; import { injectIntl, defineMessages } from 'react-intl'; import SearchContainer from './containers/search_container'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import SearchResultsContainer from './containers/search_results_container'; import { changeComposing } from '../../actions/compose'; diff --git a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js new file mode 100644 index 000000000..636402172 --- /dev/null +++ b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js @@ -0,0 +1,61 @@ +import emojify from '../emoji'; + +describe('emoji', () => { + describe('.emojify', () => { + it('ignores unknown shortcodes', () => { + expect(emojify(':foobarbazfake:')).toEqual(':foobarbazfake:'); + }); + + it('ignores shortcodes inside of tags', () => { + expect(emojify('<p data-foo=":smile:"></p>')).toEqual('<p data-foo=":smile:"></p>'); + }); + + it('works with unclosed tags', () => { + expect(emojify('hello>')).toEqual('hello>'); + expect(emojify('<hello')).toEqual('<hello'); + }); + + it('works with unclosed shortcodes', () => { + expect(emojify('smile:')).toEqual('smile:'); + expect(emojify(':smile')).toEqual(':smile'); + }); + + it('does unicode', () => { + expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).toEqual( + '<img draggable="false" class="emojione" alt="👩👩👦👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg" />'); + expect(emojify('👨👩👧👧')).toEqual( + '<img draggable="false" class="emojione" alt="👨👩👧👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg" />'); + expect(emojify('👩👩👦')).toEqual('<img draggable="false" class="emojione" alt="👩👩👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg" />'); + expect(emojify('\u2757')).toEqual( + '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); + }); + + it('does multiple unicode', () => { + expect(emojify('\u2757 #\uFE0F\u20E3')).toEqual( + '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); + expect(emojify('\u2757#\uFE0F\u20E3')).toEqual( + '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); + expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).toEqual( + '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); + expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).toEqual( + 'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> bar'); + }); + + it('ignores unicode inside of tags', () => { + expect(emojify('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>')).toEqual('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>'); + }); + + it('does multiple emoji properly (issue 5188)', () => { + expect(emojify('👌🌈💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); + expect(emojify('👌 🌈 💕')).toEqual('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); + }); + + it('does an emoji that has no shortcode', () => { + expect(emojify('🕉️')).toEqual('<img draggable="false" class="emojione" alt="🕉️" title="" src="/emoji/1f549.svg" />'); + }); + + it('does an emoji whose filename is irregular', () => { + expect(emojify('↙️')).toEqual('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg" />'); + }); + }); +}); diff --git a/app/javascript/mastodon/features/emoji/__tests__/emoji_index-test.js b/app/javascript/mastodon/features/emoji/__tests__/emoji_index-test.js new file mode 100644 index 000000000..53efa5743 --- /dev/null +++ b/app/javascript/mastodon/features/emoji/__tests__/emoji_index-test.js @@ -0,0 +1,130 @@ +import { pick } from 'lodash'; +import { emojiIndex } from 'emoji-mart'; +import { search } from '../emoji_mart_search_light'; + +const trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']); + +describe('emoji_index', () => { + it('should give same result for emoji_index_light and emoji-mart', () => { + const expected = [ + { + id: 'pineapple', + unified: '1f34d', + native: '🍍', + }, + ]; + expect(search('pineapple').map(trimEmojis)).toEqual(expected); + expect(emojiIndex.search('pineapple').map(trimEmojis)).toEqual(expected); + }); + + it('orders search results correctly', () => { + const expected = [ + { + id: 'apple', + unified: '1f34e', + native: '🍎', + }, + { + id: 'pineapple', + unified: '1f34d', + native: '🍍', + }, + { + id: 'green_apple', + unified: '1f34f', + native: '🍏', + }, + { + id: 'iphone', + unified: '1f4f1', + native: '📱', + }, + ]; + expect(search('apple').map(trimEmojis)).toEqual(expected); + expect(emojiIndex.search('apple').map(trimEmojis)).toEqual(expected); + }); + + it('handles custom emoji', () => { + const custom = [ + { + id: 'mastodon', + name: 'mastodon', + short_names: ['mastodon'], + text: '', + emoticons: [], + keywords: ['mastodon'], + imageUrl: 'http://example.com', + custom: true, + }, + ]; + search('', { custom }); + emojiIndex.search('', { custom }); + const expected = [ + { + id: 'mastodon', + custom: true, + }, + ]; + expect(search('masto').map(trimEmojis)).toEqual(expected); + expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected); + }); + + it('should filter only emojis we care about, exclude pineapple', () => { + const emojisToShowFilter = unified => unified !== '1F34D'; + expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id)) + .not.toContain('pineapple'); + expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id)) + .not.toContain('pineapple'); + }); + + it('can include/exclude categories', () => { + expect(search('flag', { include: ['people'] })).toEqual([]); + expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([]); + }); + + it('does an emoji whose unified name is irregular', () => { + const expected = [ + { + 'id': 'water_polo', + 'unified': '1f93d', + 'native': '🤽', + }, + { + 'id': 'man-playing-water-polo', + 'unified': '1f93d-200d-2642-fe0f', + 'native': '🤽♂️', + }, + { + 'id': 'woman-playing-water-polo', + 'unified': '1f93d-200d-2640-fe0f', + 'native': '🤽♀️', + }, + ]; + expect(search('polo').map(trimEmojis)).toEqual(expected); + expect(emojiIndex.search('polo').map(trimEmojis)).toEqual(expected); + }); + + it('can search for thinking_face', () => { + const expected = [ + { + id: 'thinking_face', + unified: '1f914', + native: '🤔', + }, + ]; + expect(search('thinking_fac').map(trimEmojis)).toEqual(expected); + expect(emojiIndex.search('thinking_fac').map(trimEmojis)).toEqual(expected); + }); + + it('can search for woman-facepalming', () => { + const expected = [ + { + id: 'woman-facepalming', + unified: '1f926-200d-2640-fe0f', + native: '🤦♀️', + }, + ]; + expect(search('woman-facep').map(trimEmojis)).toEqual(expected); + expect(emojiIndex.search('woman-facep').map(trimEmojis)).toEqual(expected); + }); +}); diff --git a/app/javascript/mastodon/features/emoji/emoji_compressed.js b/app/javascript/mastodon/features/emoji/emoji_compressed.js index 3bd89cf3b..c0cba952a 100644 --- a/app/javascript/mastodon/features/emoji/emoji_compressed.js +++ b/app/javascript/mastodon/features/emoji/emoji_compressed.js @@ -9,7 +9,8 @@ const { unicodeToFilename } = require('./unicode_to_filename'); const { unicodeToUnifiedName } = require('./unicode_to_unified_name'); const emojiMap = require('./emoji_map.json'); const { emojiIndex } = require('emoji-mart'); -const emojiMartData = require('emoji-mart/dist/data').default; +const { default: emojiMartData } = require('emoji-mart/dist/data'); + const excluded = ['®', '©', '™']; const skins = ['🏻', '🏼', '🏽', '🏾', '🏿']; const shortcodeMap = {}; diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 816f83e45..d8547db36 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -48,6 +48,8 @@ export default class DetailedStatus extends ImmutablePureComponent { let media = ''; let mediaIcon = null; let applicationLink = ''; + let reblogLink = ''; + let reblogIcon = 'retweet'; if (status.get('media_attachments').size > 0) { if (status.get('media_attachments').some(item => item.get('type') === 'unknown')) { @@ -85,6 +87,23 @@ export default class DetailedStatus extends ImmutablePureComponent { applicationLink = <span> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener'>{status.getIn(['application', 'name'])}</a></span>; } + if (status.get('visibility') === 'direct') { + reblogIcon = 'envelope'; + } else if (status.get('visibility') === 'private') { + reblogIcon = 'lock'; + } + + if (status.get('visibility') === 'private') { + reblogLink = <i className={`fa fa-${reblogIcon}`} />; + } else { + reblogLink = (<Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'> + <i className={`fa fa-${reblogIcon}`} /> + <span className='detailed-status__reblogs'> + <FormattedNumber value={status.get('reblogs_count')} /> + </span> + </Link>); + } + return ( <div className='detailed-status'> <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'> @@ -101,12 +120,7 @@ export default class DetailedStatus extends ImmutablePureComponent { <div className='detailed-status__meta'> <a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener'> <FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' /> - </a>{applicationLink} · <Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'> - <i className='fa fa-retweet' /> - <span className='detailed-status__reblogs'> - <FormattedNumber value={status.get('reblogs_count')} /> - </span> - </Link> · <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'> + </a>{applicationLink} · {reblogLink} · <Link to={`/statuses/${status.get('id')}/favourites`} className='detailed-status__link'> <i className='fa fa-star' /> <span className='detailed-status__favorites'> <FormattedNumber value={status.get('favourites_count')} /> diff --git a/spec/javascript/components/features/ui/components/column.test.js b/app/javascript/mastodon/features/ui/components/__tests__/column-test.js index 4491d6e19..1e5e1d8dc 100644 --- a/spec/javascript/components/features/ui/components/column.test.js +++ b/app/javascript/mastodon/features/ui/components/__tests__/column-test.js @@ -1,14 +1,18 @@ -import { expect } from 'chai'; -import { mount } from 'enzyme'; -import sinon from 'sinon'; import React from 'react'; -import Column from '../../../../../../app/javascript/mastodon/features/ui/components/column'; -import ColumnHeader from '../../../../../../app/javascript/mastodon/features/ui/components/column_header'; +import { mount } from 'enzyme'; +import Column from '../column'; +import ColumnHeader from '../column_header'; describe('<Column />', () => { describe('<ColumnHeader /> click handler', () => { + const originalRaf = global.requestAnimationFrame; + beforeEach(() => { - global.requestAnimationFrame = sinon.spy(); + global.requestAnimationFrame = jest.fn(); + }); + + afterAll(() => { + global.requestAnimationFrame = originalRaf; }); it('runs the scroll animation if the column contains scrollable content', () => { @@ -18,13 +22,13 @@ describe('<Column />', () => { </Column> ); wrapper.find(ColumnHeader).simulate('click'); - expect(global.requestAnimationFrame.called).to.equal(true); + expect(global.requestAnimationFrame.mock.calls.length).toEqual(1); }); it('does not try to scroll if there is no scrollable content', () => { const wrapper = mount(<Column heading='notifications' />); wrapper.find(ColumnHeader).simulate('click'); - expect(global.requestAnimationFrame.called).to.equal(false); + expect(global.requestAnimationFrame.mock.calls.length).toEqual(0); }); }); }); diff --git a/app/javascript/mastodon/features/ui/components/upload_area.js b/app/javascript/mastodon/features/ui/components/upload_area.js index dda28feeb..c19065be6 100644 --- a/app/javascript/mastodon/features/ui/components/upload_area.js +++ b/app/javascript/mastodon/features/ui/components/upload_area.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import Motion from 'react-motion/lib/Motion'; +import Motion from '../../ui/util/optional_motion'; import spring from 'react-motion/lib/spring'; import { FormattedMessage } from 'react-intl'; diff --git a/app/javascript/mastodon/features/ui/util/optional_motion.js b/app/javascript/mastodon/features/ui/util/optional_motion.js new file mode 100644 index 000000000..af6368738 --- /dev/null +++ b/app/javascript/mastodon/features/ui/util/optional_motion.js @@ -0,0 +1,56 @@ +// Like react-motion's Motion, but checks to see if the user prefers +// reduced motion and uses a cross-fade in those cases. + +import React from 'react'; +import Motion from 'react-motion/lib/Motion'; +import PropTypes from 'prop-types'; + +const stylesToKeep = ['opacity', 'backgroundOpacity']; + +let reduceMotion; + +const extractValue = (value) => { + // This is either an object with a "val" property or it's a number + return (typeof value === 'object' && value && 'val' in value) ? value.val : value; +}; + +class OptionalMotion extends React.Component { + + static propTypes = { + defaultStyle: PropTypes.object, + style: PropTypes.object, + children: PropTypes.func, + } + + render() { + + const { style, defaultStyle, children } = this.props; + + if (typeof reduceMotion !== 'boolean') { + // This never changes without a page reload, so we can just grab it + // once from the body classes as opposed to using Redux's connect(), + // which would unnecessarily update every state change + reduceMotion = document.body.classList.contains('reduce-motion'); + } + if (reduceMotion) { + Object.keys(style).forEach(key => { + if (stylesToKeep.includes(key)) { + return; + } + // If it's setting an x or height or scale or some other value, we need + // to preserve the end-state value without actually animating it + style[key] = defaultStyle[key] = extractValue(style[key]); + }); + } + + return ( + <Motion style={style} defaultStyle={defaultStyle}> + {children} + </Motion> + ); + } + +} + + +export default OptionalMotion; diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index 799819c7c..7cc8ea237 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -82,7 +82,6 @@ "empty_column.community": "الخط الزمني المحلي فارغ. اكتب شيئا ما للعامة كبداية.", "empty_column.hashtag": "ليس هناك بعدُ أي محتوى ذو علاقة بهذا الوسم.", "empty_column.home": "إنك لا تتبع بعد أي شخص إلى حد الآن. زر {public} أو استخدام حقل البحث لكي تبدأ على التعرف على مستخدمين آخرين.", - "empty_column.home.inactivity": "صفحتك فارغة. لقد كنت غائبا لفترة طويلة عن الشبكة. سوف تملأ تلقائيا في وقت قريب.", "empty_column.home.public_timeline": "الخيط العام", "empty_column.notifications": "لم تتلق أي إشعار بعدُ. تفاعل مع المستخدمين الآخرين لإنشاء محادثة.", "empty_column.public": "لا يوجد شيء هنا ! قم بتحرير شيء ما بشكل عام، أو اتبع مستخدمين آخرين في الخوادم المثيلة الأخرى لملء خيط المحادثات العام.", @@ -160,6 +159,11 @@ "privacy.public.short": "للعامة", "privacy.unlisted.long": "لا تقم بإدراجه على الخيوط العامة", "privacy.unlisted.short": "غير مدرج", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "إلغاء", "report.placeholder": "تعليقات إضافية", "report.submit": "إرسال", @@ -179,6 +183,7 @@ "status.load_more": "حمّل المزيد", "status.media_hidden": "الصورة مستترة", "status.mention": "أذكُر @{name}", + "status.more": "More", "status.mute_conversation": "كتم المحادثة", "status.open": "وسع هذه المشاركة", "status.pin": "تدبيس على الملف الشخصي", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index eeded31b7..da2372cff 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -82,7 +82,6 @@ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not show in public timelines", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Отказ", "report.placeholder": "Additional comments", "report.submit": "Submit", @@ -179,6 +183,7 @@ "status.load_more": "Load more", "status.media_hidden": "Media hidden", "status.mention": "Споменаване", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expand this status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index fe2433591..af732921d 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -82,7 +82,6 @@ "empty_column.community": "La línia de temps local és buida. Escriu alguna cosa públicament per fer rodar la pilota!", "empty_column.hashtag": "Encara no hi ha res amb aquesta etiqueta.", "empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.", - "empty_column.home.inactivity": "La línia Inici és buida. si has estat inactiu durant un temps es regenerarà aviat.", "empty_column.home.public_timeline": "la línia de temps pública", "empty_column.notifications": "Encara no tens notificacions. Interactua amb altres per iniciar la conversa.", "empty_column.public": "No hi ha res aquí! Escriu alguna cosa públicament o segueix manualment usuaris d'altres instàncies per omplir-ho", @@ -160,11 +159,11 @@ "privacy.public.short": "Públic", "privacy.unlisted.long": "No publicar en línies de temps públiques", "privacy.unlisted.short": "No llistat", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", - "relative_time.just_now": "now", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "relative_time.days": "fa {number} jorns", + "relative_time.hours": "fa {number} hores", + "relative_time.just_now": "ara", + "relative_time.minutes": "fa {number} minutes", + "relative_time.seconds": "fa {number} segondes", "reply_indicator.cancel": "Cancel·lar", "report.placeholder": "Comentaris addicionals", "report.submit": "Enviar", @@ -184,6 +183,7 @@ "status.load_more": "Carrega més", "status.media_hidden": "Multimèdia amagat", "status.mention": "Esmentar @{name}", + "status.more": "Més", "status.mute_conversation": "Silenciar conversació", "status.open": "Ampliar aquest estat", "status.pin": "Fixat en el perfil", diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 9d9853236..283a2946f 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -82,7 +82,6 @@ "empty_column.community": "Die lokale Zeitleiste ist leer. Schreibe einen öffentlichen Beitrag, um den Ball ins Rollen zu bringen!", "empty_column.hashtag": "Unter diesem Hashtag gibt es noch nichts.", "empty_column.home": "Deine Startseite ist leer! Besuche {public} oder nutze die Suche, um loszulegen und andere Leute zu finden.", - "empty_column.home.inactivity": "Deine Zeitleiste ist leer. Falls du eine längere Zeit inaktiv warst, wird sie für dich so schnell wie möglich neu erstellt.", "empty_column.home.public_timeline": "die öffentliche Zeitleiste", "empty_column.notifications": "Du hast noch keine Mitteilungen. Interagiere mit anderen, um ins Gespräch zu kommen.", "empty_column.public": "Hier ist nichts zu sehen! Schreibe etwas öffentlich oder folge Profilen von anderen Instanzen, um die Zeitleiste aufzufüllen", @@ -160,6 +159,11 @@ "privacy.public.short": "Öffentlich", "privacy.unlisted.long": "Nicht in öffentlichen Zeitleisten anzeigen", "privacy.unlisted.short": "Nicht gelistet", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Abbrechen", "report.placeholder": "Zusätzliche Kommentare", "report.submit": "Absenden", @@ -179,6 +183,7 @@ "status.load_more": "Weitere laden", "status.media_hidden": "Medien versteckt", "status.mention": "@{name} erwähnen", + "status.more": "Mehr", "status.mute_conversation": "Thread stummschalten", "status.open": "Diesen Beitrag öffnen", "status.pin": "Im Profil anheften", diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index 99ff3b35b..f400b283f 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -184,6 +184,10 @@ "id": "status.share" }, { + "defaultMessage": "More", + "id": "status.more" + }, + { "defaultMessage": "Reply to thread", "id": "status.replyAll" }, @@ -908,10 +912,6 @@ "id": "column.home" }, { - "defaultMessage": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", - "id": "empty_column.home.inactivity" - }, - { "defaultMessage": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "id": "empty_column.home" }, @@ -1408,4 +1408,4 @@ ], "path": "app/javascript/mastodon/features/video/index.json" } -] +] \ No newline at end of file diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 12efe0e0c..1d0bbcee5 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -82,7 +82,6 @@ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not post to public timelines", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancel", "report.placeholder": "Additional comments", "report.submit": "Submit", @@ -179,6 +183,7 @@ "status.load_more": "Load more", "status.media_hidden": "Media hidden", "status.mention": "Mention @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expand this status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 8f90bdf78..22639f6f9 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -82,7 +82,6 @@ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not show in public timelines", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Rezigni", "report.placeholder": "Additional comments", "report.submit": "Submit", @@ -179,6 +183,7 @@ "status.load_more": "Load more", "status.media_hidden": "Media hidden", "status.mention": "Mencii @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expand this status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index f6bfbb04d..6e8e94700 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -82,7 +82,6 @@ "empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!", "empty_column.hashtag": "No hay nada en este hashtag aún.", "empty_column.home": "No estás siguiendo a nadie aún. Visita {public} o haz búsquedas para empezar y conocer gente nueva.", - "empty_column.home.inactivity": "Tus notificaciones están vacías. Si has estado inactivo por un tiempo, se regenerará para ti pronto.", "empty_column.home.public_timeline": "la línea de tiempo pública", "empty_column.notifications": "No tienes ninguna notificación aún. Interactúa con otros para empezar una conversación.", "empty_column.public": "¡No hay nada aquí! Escribe algo públicamente, o sigue usuarios de otras instancias manualmente para llenarlo.", @@ -160,6 +159,11 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "No mostrar en la historia federada", "privacy.unlisted.short": "Sin federar", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "ahora", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancelar", "report.placeholder": "Comentarios adicionales", "report.submit": "Publicar", @@ -179,6 +183,7 @@ "status.load_more": "Cargar más", "status.media_hidden": "Contenido multimedia oculto", "status.mention": "Mencionar", + "status.more": "Más", "status.mute_conversation": "Silenciar conversación", "status.open": "Expandir estado", "status.pin": "Fijar", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 9df0dec42..995d1b5ae 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -82,7 +82,6 @@ "empty_column.community": "فهرست نوشتههای محلی خالی است. چیزی بنویسید تا چرخش بچرخد!", "empty_column.hashtag": "هنوز هیچ چیزی با این هشتگ نیست.", "empty_column.home": "شما هنوز پیگیر کسی نیستید. {public} را ببینید یا چیزی را جستجو کنید تا کاربران دیگر را ببینید.", - "empty_column.home.inactivity": "فهرست پیگیریهای شما خالی است. اگر مدتی است که غیرفعال بودید، این فهرست به زودی برایتان پر میشود.", "empty_column.home.public_timeline": "فهرست نوشتههای همهجا", "empty_column.notifications": "هنوز هیچ اعلانی ندارید. به نوشتههای دیگران واکنش نشان دهید تا گفتگو آغاز شود.", "empty_column.public": "اینجا هنوز چیزی نیست! خودتان چیزی بنویسید یا کاربران دیگر را پی بگیرید تا اینجا پر شود", @@ -160,6 +159,11 @@ "privacy.public.short": "عمومی", "privacy.unlisted.long": "عمومی، ولی فهرست نکن", "privacy.unlisted.short": "فهرستنشده", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "لغو", "report.placeholder": "توضیح اضافه", "report.submit": "بفرست", @@ -179,6 +183,7 @@ "status.load_more": "بیشتر نشان بده", "status.media_hidden": "تصویر پنهان شده", "status.mention": "نامبردن از @{name}", + "status.more": "More", "status.mute_conversation": "بیصداکردن گفتگو", "status.open": "این نوشته را باز کن", "status.pin": "نوشتهٔ ثابت نمایه", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 0f6554595..af08be5d1 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -82,7 +82,6 @@ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not show in public timelines", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Peruuta", "report.placeholder": "Additional comments", "report.submit": "Submit", @@ -179,6 +183,7 @@ "status.load_more": "Load more", "status.media_hidden": "Media hidden", "status.mention": "Mainitse @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expand this status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 145b683f3..219bf4da1 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -63,7 +63,7 @@ "confirmations.mute.message": "Confirmez-vous le masquage de {name} ?", "confirmations.unfollow.confirm": "Ne plus suivre", "confirmations.unfollow.message": "Voulez-vous arrêter de suivre {name} ?", - "embed.instructions": "Intégrez ce statut à votre site en copiant ce code ci-dessous.", + "embed.instructions": "Intégrez ce statut à votre site en copiant le code ci-dessous.", "embed.preview": "Il apparaîtra comme cela : ", "emoji_button.activity": "Activités", "emoji_button.custom": "Personnalisés", @@ -82,7 +82,6 @@ "empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !", "empty_column.hashtag": "Il n’y a encore aucun contenu associé à ce hashtag", "empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateur⋅ice⋅s.", - "empty_column.home.inactivity": "Votre accueil est vide. Si vous ne vous êtes pas connecté⋅e depuis un moment, il se remplira automatiquement très bientôt.", "empty_column.home.public_timeline": "le fil public", "empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres utilisateur⋅ice⋅s pour débuter la conversation.", "empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateur⋅ice⋅s d’autres instances pour remplir le fil public.", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Ne pas afficher dans les fils publics", "privacy.unlisted.short": "Non-listé", + "relative_time.days": "{number} j", + "relative_time.hours": "{number} h", + "relative_time.just_now": "à l’instant", + "relative_time.minutes": "{number} min", + "relative_time.seconds": "{number} s", "reply_indicator.cancel": "Annuler", "report.placeholder": "Commentaires additionnels", "report.submit": "Envoyer", @@ -179,6 +183,7 @@ "status.load_more": "Charger plus", "status.media_hidden": "Média caché", "status.mention": "Mentionner", + "status.more": "Plus", "status.mute_conversation": "Masquer la conversation", "status.open": "Déplier ce statut", "status.pin": "Épingler sur le profil", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index beaa4fd3a..a260f0968 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -82,7 +82,6 @@ "empty_column.community": "טור הסביבה ריק. יש לפרסם משהו כדי שדברים יתרחילו להתגלגל!", "empty_column.hashtag": "אין כלום בהאשתג הזה עדיין.", "empty_column.home": "אף אחד לא במעקב עדיין. אפשר לבקר ב{public} או להשתמש בחיפוש כדי להתחיל ולהכיר חצוצרנים אחרים.", - "empty_column.home.inactivity": "ציר זמן הבית שלך ריק. אם לא הייתה פעילות מצידך לאחרונה, הוא יתמלא מחדש בקרוב.", "empty_column.home.public_timeline": "ציר זמן בין-קהילתי", "empty_column.notifications": "אין התראות עדיין. יאללה, הגיע הזמן להתחיל להתערבב!", "empty_column.public": "אין פה כלום! כדי למלא את הטור הזה אפשר לכתוב משהו, או להתחיל לעקוב אחרי אנשים מקהילות אחרות.", @@ -160,6 +159,11 @@ "privacy.public.short": "פומבי", "privacy.unlisted.long": "לא יופיע בפידים הציבוריים המשותפים", "privacy.unlisted.short": "לא לפיד הכללי", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "ביטול", "report.placeholder": "הערות נוספות", "report.submit": "שליחה", @@ -179,6 +183,7 @@ "status.load_more": "עוד", "status.media_hidden": "מדיה מוסתרת", "status.mention": "פניה אל @{name}", + "status.more": "More", "status.mute_conversation": "השתקת שיחה", "status.open": "הרחבת הודעה", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index cef61f15e..6ac7fc3b4 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -82,7 +82,6 @@ "empty_column.community": "Lokalni timeline je prazan. Napiši nešto javno kako bi pokrenuo stvari!", "empty_column.hashtag": "Još ne postoji ništa s ovim hashtagom.", "empty_column.home": "Još ne slijediš nikoga. Posjeti {public} ili koristi tražilicu kako bi počeo i upoznao druge korisnike.", - "empty_column.home.inactivity": "Tvoj home feed je prazan. Ako si neko vrijeme bio neaktivan, uskoro ćese regenerirati.", "empty_column.home.public_timeline": "javni timeline", "empty_column.notifications": "Još nemaš notifikacija. Komuniciraj sa drugima kako bi započeo razgovor.", "empty_column.public": "Ovdje nema ništa! Napiši nešto javno, ili ručno slijedi korisnike sa drugih instanci kako bi popunio", @@ -160,6 +159,11 @@ "privacy.public.short": "Javno", "privacy.unlisted.long": "Ne prikazuj u javnim timelineovima", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Otkaži", "report.placeholder": "Dodatni komentari", "report.submit": "Pošalji", @@ -179,6 +183,7 @@ "status.load_more": "Učitaj više", "status.media_hidden": "Sakriven media sadržaj", "status.mention": "Spomeni @{name}", + "status.more": "More", "status.mute_conversation": "Utišaj razgovor", "status.open": "Proširi ovaj status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 2296ea71e..5892e606e 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -82,7 +82,6 @@ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not show in public timelines", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Mégsem", "report.placeholder": "Additional comments", "report.submit": "Submit", @@ -179,6 +183,7 @@ "status.load_more": "Load more", "status.media_hidden": "Media hidden", "status.mention": "Említés", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expand this status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index cc48aa996..f73ef0e19 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -82,7 +82,6 @@ "empty_column.community": "Linimasa lokal masih kosong. Tulis sesuatu secara publik dan buat roda berputar!", "empty_column.hashtag": "Tidak ada apapun dalam hashtag ini.", "empty_column.home": "Anda sedang tidak mengikuti siapapun. Kunjungi {public} atau gunakan pencarian untuk memulai dan bertemu pengguna lain.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "linimasa publik", "empty_column.notifications": "Anda tidak memiliki notifikasi apapun. Berinteraksi dengan orang lain untuk memulai percakapan.", "empty_column.public": "Tidak ada apapun disini! Tulis sesuatu, atau ikuti pengguna lain dari server lain untuk mengisinya secara manual", @@ -160,6 +159,11 @@ "privacy.public.short": "Publik", "privacy.unlisted.long": "Tidak ditampilkan di linimasa publik", "privacy.unlisted.short": "Tak Terdaftar", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Batal", "report.placeholder": "Komentar tambahan", "report.submit": "Kirim", @@ -179,6 +183,7 @@ "status.load_more": "Tampilkan semua", "status.media_hidden": "Media disembunyikan", "status.mention": "Balasan @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Tampilkan status ini", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index b484bebc7..53371bece 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -82,7 +82,6 @@ "empty_column.community": "La lokala tempolineo esas vakua. Skribez ulo publike por iniciar la agiveso!", "empty_column.hashtag": "Esas ankore nulo en ta gretovorto.", "empty_column.home": "Tu sequas ankore nulu. Vizitez {public} od uzez la serchilo por komencar e renkontrar altra uzeri.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "la publika tempolineo", "empty_column.notifications": "Tu havas ankore nula savigo. Komunikez kun altri por debutar la konverso.", "empty_column.public": "Esas nulo hike! Skribez ulo publike, o manuale sequez uzeri de altra instaluri por plenigar ol.", @@ -160,6 +159,11 @@ "privacy.public.short": "Publike", "privacy.unlisted.long": "Ne montrar en publika tempolinei", "privacy.unlisted.short": "Ne enlistigota", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Nihiligar", "report.placeholder": "Plusa komenti", "report.submit": "Sendar", @@ -179,6 +183,7 @@ "status.load_more": "Kargar pluse", "status.media_hidden": "Kontenajo celita", "status.mention": "Mencionar @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Detaligar ca mesajo", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 4d73fbea8..3873d797e 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -82,7 +82,6 @@ "empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!", "empty_column.hashtag": "Non c'è ancora nessun post con questo hashtag.", "empty_column.home": "Non stai ancora seguendo nessuno. Visita {public} o usa la ricerca per incontrare nuove persone.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "la timeline pubblica", "empty_column.notifications": "Non hai ancora nessuna notifica. Interagisci con altri per iniziare conversazioni.", "empty_column.public": "Qui non c'è nulla! Scrivi qualcosa pubblicamente, o aggiungi utenti da altri server per riempire questo spazio.", @@ -160,6 +159,11 @@ "privacy.public.short": "Pubblico", "privacy.unlisted.long": "Non mostrare sulla timeline pubblica", "privacy.unlisted.short": "Non elencato", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Annulla", "report.placeholder": "Commenti aggiuntivi", "report.submit": "Invia", @@ -179,6 +183,7 @@ "status.load_more": "Mostra di più", "status.media_hidden": "Allegato nascosto", "status.mention": "Nomina @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Espandi questo post", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index ce797a7c7..fb6d11ebe 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -82,7 +82,6 @@ "empty_column.community": "ローカルタイムラインはまだ使われていません。何か書いてみましょう!", "empty_column.hashtag": "このハッシュタグはまだ使われていません。", "empty_column.home": "まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。", - "empty_column.home.inactivity": "あなたのホームフィードにはなにもありません。あなたがしばらくの間アクティブではなかった場合はすぐ元通りになります。", "empty_column.home.public_timeline": "連合タイムライン", "empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。", "empty_column.public": "ここにはまだ何もありません!公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう!", @@ -184,6 +183,7 @@ "status.load_more": "もっと見る", "status.media_hidden": "非表示のメディア", "status.mention": "返信", + "status.more": "もっと見る", "status.mute_conversation": "会話をミュート", "status.open": "詳細を表示", "status.pin": "プロフィールに固定表示", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index c1768cf8f..d99dacd59 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -18,7 +18,7 @@ "account.unblock_domain": "{domain} 숨김 해제", "account.unfollow": "팔로우 해제", "account.unmute": "뮤트 해제", - "account.view_full_profile": "View full profile", + "account.view_full_profile": "전체 프로필 보기", "boost_modal.combo": "다음부터 {combo}를 누르면 이 과정을 건너뛸 수 있습니다.", "bundle_column_error.body": "Something went wrong while loading this component.", "bundle_column_error.retry": "Try again", @@ -33,7 +33,7 @@ "column.home": "홈", "column.mutes": "뮤트 중인 사용자", "column.notifications": "알림", - "column.pins": "고정된 Toot", + "column.pins": "고정된 툿", "column.public": "연합 타임라인", "column_back_button.label": "돌아가기", "column_header.hide_settings": "Hide settings", @@ -47,7 +47,7 @@ "compose_form.lock_disclaimer": "이 계정은 {locked}로 설정 되어 있지 않습니다. 누구나 이 계정을 팔로우 할 수 있으며, 팔로워 공개의 포스팅을 볼 수 있습니다.", "compose_form.lock_disclaimer.lock": "비공개", "compose_form.placeholder": "지금 무엇을 하고 있나요?", - "compose_form.publish": "Toot", + "compose_form.publish": "툿", "compose_form.publish_loud": "{publish}!", "compose_form.sensitive": "이 미디어를 민감한 미디어로 취급", "compose_form.spoiler": "텍스트 숨기기", @@ -63,8 +63,8 @@ "confirmations.mute.message": "정말로 {name}를 뮤트하시겠습니까?", "confirmations.unfollow.confirm": "Unfollow", "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "embed.instructions": "아래의 코드를 복사하여 대화를 원하는 곳으로 퍼가세요.", + "embed.preview": "다음과 같이 표시됩니다:", "emoji_button.activity": "활동", "emoji_button.custom": "Custom", "emoji_button.flags": "국기", @@ -82,7 +82,6 @@ "empty_column.community": "로컬 타임라인에 아무 것도 없습니다. 아무거나 적어 보세요!", "empty_column.hashtag": "이 해시태그는 아직 사용되지 않았습니다.", "empty_column.home": "아직 아무도 팔로우 하고 있지 않습니다. {public}를 보러 가거나, 검색하여 다른 사용자를 찾아 보세요.", - "empty_column.home.inactivity": "홈 피드에 아무 것도 없습니다. 한동안 활동하지 않은 경우 곧 원래대로 돌아올 것입니다.", "empty_column.home.public_timeline": "연합 타임라인", "empty_column.notifications": "아직 알림이 없습니다. 다른 사람과 대화를 시작해 보세요!", "empty_column.public": "여기엔 아직 아무 것도 없습니다! 공개적으로 무언가 포스팅하거나, 다른 인스턴스 유저를 팔로우 해서 가득 채워보세요!", @@ -113,7 +112,7 @@ "navigation_bar.info": "이 인스턴스에 대해서", "navigation_bar.logout": "로그아웃", "navigation_bar.mutes": "뮤트 중인 사용자", - "navigation_bar.pins": "고정된 Toot", + "navigation_bar.pins": "고정된 툿", "navigation_bar.preferences": "사용자 설정", "navigation_bar.public_timeline": "연합 타임라인", "notification.favourite": "{name}님이 즐겨찾기 했습니다", @@ -159,29 +158,35 @@ "privacy.public.long": "공개 타임라인에 표시", "privacy.public.short": "공개", "privacy.unlisted.long": "공개 타임라인에 표시하지 않음", - "privacy.unlisted.short": "Unlisted", + "privacy.unlisted.short": "타임라인에 비표시", + "relative_time.days": "{number}일 전", + "relative_time.hours": "{number}시간 전", + "relative_time.just_now": "방금", + "relative_time.minutes": "{number}분 전", + "relative_time.seconds": "{number}초 전", "reply_indicator.cancel": "취소", "report.placeholder": "코멘트", "report.submit": "신고하기", "report.target": "문제가 된 사용자", "search.placeholder": "검색", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", + "search_popout.search_format": "고급 검색 방법", + "search_popout.tips.hashtag": "해시태그", + "search_popout.tips.status": "툿", + "search_popout.tips.text": "단순한 텍스트 검색은 관계된 프로필 이름, 유저 이름 그리고 해시태그를 표시합니다", + "search_popout.tips.user": "유저", "search_results.total": "{count, number}건의 결과", "standalone.public_title": "A look inside...", "status.cannot_reblog": "이 포스트는 부스트 할 수 없습니다", "status.delete": "삭제", - "status.embed": "Embed", + "status.embed": "공유하기", "status.favourite": "즐겨찾기", "status.load_more": "더 보기", "status.media_hidden": "미디어 숨겨짐", "status.mention": "답장", + "status.more": "More", "status.mute_conversation": "이 대화를 뮤트", "status.open": "상세 정보 표시", - "status.pin": "Pin on profile", + "status.pin": "고정", "status.reblog": "부스트", "status.reblogged_by": "{name}님이 부스트 했습니다", "status.reply": "답장", @@ -193,7 +198,7 @@ "status.show_less": "숨기기", "status.show_more": "더 보기", "status.unmute_conversation": "이 대화의 뮤트 해제하기", - "status.unpin": "Unpin from profile", + "status.unpin": "고정 해제", "tabs_bar.compose": "포스트", "tabs_bar.federated_timeline": "연합", "tabs_bar.home": "홈", diff --git a/app/javascript/mastodon/locales/nl.json b/app/javascript/mastodon/locales/nl.json index 04b88da34..d0727a24d 100644 --- a/app/javascript/mastodon/locales/nl.json +++ b/app/javascript/mastodon/locales/nl.json @@ -82,7 +82,6 @@ "empty_column.community": "De lokale tijdlijn is nog leeg. Toot iets in het openbaar om de bal aan het rollen te krijgen!", "empty_column.hashtag": "Er is nog niks te vinden onder deze hashtag.", "empty_column.home": "Jij volgt nog niemand. Bezoek {public} of gebruik het zoekvenster om andere mensen te ontmoeten.", - "empty_column.home.inactivity": "Deze tijdlijn is leeg. Wanneer je een tijdje inactief bent geweest wordt deze snel opnieuw aangemaakt.", "empty_column.home.public_timeline": "de globale tijdlijn", "empty_column.notifications": "Je hebt nog geen meldingen. Heb interactie met andere mensen om het gesprek aan te gaan.", "empty_column.public": "Er is hier helemaal niks! Toot iets in het openbaar of volg mensen van andere Mastodon-servers om het te vullen.", @@ -160,6 +159,11 @@ "privacy.public.short": "Openbaar", "privacy.unlisted.long": "Niet op openbare tijdlijnen tonen", "privacy.unlisted.short": "Minder openbaar", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Annuleren", "report.placeholder": "Extra opmerkingen", "report.submit": "Verzenden", @@ -179,6 +183,7 @@ "status.load_more": "Meer laden", "status.media_hidden": "Media verborgen", "status.mention": "Vermeld @{name}", + "status.more": "Meer", "status.mute_conversation": "Negeer conversatie", "status.open": "Toot volledig tonen", "status.pin": "Aan profielpagina vastmaken", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 26556b290..d74ae0091 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -82,7 +82,6 @@ "empty_column.community": "Den lokale tidslinjen er tom. Skriv noe offentlig for å få snøballen til å rulle!", "empty_column.hashtag": "Det er ingenting i denne hashtagen ennå.", "empty_column.home": "Du har ikke fulgt noen ennå. Besøk {publlic} eller bruk søk for å komme i gang og møte andre brukere.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "en offentlig tidslinje", "empty_column.notifications": "Du har ingen varsler ennå. Kommuniser med andre for å begynne samtalen.", "empty_column.public": "Det er ingenting her! Skriv noe offentlig, eller følg brukere manuelt fra andre instanser for å fylle den opp", @@ -160,6 +159,11 @@ "privacy.public.short": "Offentlig", "privacy.unlisted.long": "Ikke vis i offentlige tidslinjer", "privacy.unlisted.short": "Uoppført", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Avbryt", "report.placeholder": "Tilleggskommentarer", "report.submit": "Send inn", @@ -179,6 +183,7 @@ "status.load_more": "Last mer", "status.media_hidden": "Media skjult", "status.mention": "Nevn @{name}", + "status.more": "More", "status.mute_conversation": "Demp samtale", "status.open": "Utvid denne statusen", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index 4715f60ef..1e0849d95 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -82,7 +82,6 @@ "empty_column.community": "Lo flux public local es void. Escrivètz quicòm per lo garnir !", "empty_column.hashtag": "I a pas encara de contengut ligat a aqueste hashtag", "empty_column.home": "Vòstre flux d’acuèlh es void. Visitatz {public} o utilizatz la recèrca per vos connectar a d’autras personas.", - "empty_column.home.inactivity": "Vòstra pagina d’acuèlh es voida. Se sètz estat inactiu per un moment, serà tornada generar per vos dins una estona.", "empty_column.home.public_timeline": "lo flux public", "empty_column.notifications": "Avètz pas encara de notificacions. Respondètz a qualqu’un per començar una conversacion.", "empty_column.public": "I a pas res aquí ! Escrivètz quicòm de public, o seguètz de personas d’autras instàncias per garnir lo flux public.", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Mostrar pas dins los fluxes publics", "privacy.unlisted.short": "Pas-listat", + "relative_time.days": "fa {number}j", + "relative_time.hours": "fa {number}h", + "relative_time.just_now": "ara", + "relative_time.minutes": "fa {number} minutas", + "relative_time.seconds": "fa {number} segondas", "reply_indicator.cancel": "Anullar", "report.placeholder": "Comentaris addicionals", "report.submit": "Mandar", @@ -179,6 +183,7 @@ "status.load_more": "Cargar mai", "status.media_hidden": "Mèdia rescondut", "status.mention": "Mencionar", + "status.more": "Mai", "status.mute_conversation": "Rescondre la conversacion", "status.open": "Desplegar aqueste estatut", "status.pin": "Penjar al perfil", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index c8228c0cb..c0776dfc9 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -82,7 +82,6 @@ "empty_column.community": "Lokalna oś czasu jest pusta. Napisz coś publicznie, aby zagaić!", "empty_column.hashtag": "Nie ma wpisów oznaczonych tym hashtagiem. Możesz napisać pierwszy!", "empty_column.home": "Nie śledzisz nikogo. Odwiedź publiczną oś czasu lub użyj wyszukiwarki, aby znaleźć interesujące Cię profile.", - "empty_column.home.inactivity": "Strumień jest pusty. Jeżeli nie było Cię tu ostatnio, zostanie on wypełniony wkrótce.", "empty_column.home.public_timeline": "publiczna oś czasu", "empty_column.notifications": "Nie masz żadnych powiadomień. Rozpocznij interakcje z innymi użytkownikami.", "empty_column.public": "Tu nic nie ma! Napisz coś publicznie, lub dodaj ludzi z innych instancji, aby to wyświetlić.", @@ -160,6 +159,11 @@ "privacy.public.short": "Publiczny", "privacy.unlisted.long": "Niewidoczny na publicznych osiach czasu", "privacy.unlisted.short": "Niewidoczny", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Anuluj", "report.placeholder": "Dodatkowe komentarze", "report.submit": "Wyślij", @@ -179,6 +183,7 @@ "status.load_more": "Załaduj więcej", "status.media_hidden": "Zawartość multimedialna ukryta", "status.mention": "Wspomnij o @{name}", + "status.more": "Więcej", "status.mute_conversation": "Wycisz konwersację", "status.open": "Rozszerz ten wpis", "status.pin": "Przypnij do profilu", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 2c79a7509..ddb8b83f5 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -82,7 +82,6 @@ "empty_column.community": "A timeline local está vazia. Escreva algo publicamente para começar!", "empty_column.hashtag": "Ainda não há qualquer conteúdo com essa hashtag", "empty_column.home": "Você ainda não segue usuário algo. Visite a timeline {public} ou use o buscador para procurar e conhecer outros usuários.", - "empty_column.home.inactivity": "A sua página inicial está vazia. Se você esteve inativo por um tempo, ela irá se regenerar em alguns intantes.", "empty_column.home.public_timeline": "global", "empty_column.notifications": "Você ainda não possui notificações. Interaja com outros usuários para começar a conversar!", "empty_column.public": "Não há nada aqui! Escreva algo publicamente ou siga manualmente usuários de outras instâncias.", @@ -160,16 +159,21 @@ "privacy.public.short": "Pública", "privacy.unlisted.long": "Não publicar em feeds públicos", "privacy.unlisted.short": "Não listada", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancelar", "report.placeholder": "Comentários adicionais", "report.submit": "Enviar", "report.target": "Denunciar", "search.placeholder": "Pesquisar", -"search_popout.search_format": "Advanced search format", -"search_popout.tips.hashtag": "hashtag", -"search_popout.tips.status": "status", + "search_popout.search_format": "Formato de busca avançado", + "search_popout.tips.hashtag": "hashtag", + "search_popout.tips.status": "status", "search_popout.tips.text": "Texto simples retorna nomes de exibição, usuários e hashtags correspondentes", - "search_popout.tips.user": "user", + "search_popout.tips.user": "usuário", "search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}", "standalone.public_title": "Dê uma espiada...", "status.cannot_reblog": "Esta postagem não pode ser compartilhada", @@ -179,6 +183,7 @@ "status.load_more": "Carregar mais", "status.media_hidden": "Mídia escondida", "status.mention": "Mencionar @{name}", + "status.more": "More", "status.mute_conversation": "Silenciar conversa", "status.open": "Expandir", "status.pin": "Fixar no perfil", diff --git a/app/javascript/mastodon/locales/pt.json b/app/javascript/mastodon/locales/pt.json index ecd0689df..9ae140df9 100644 --- a/app/javascript/mastodon/locales/pt.json +++ b/app/javascript/mastodon/locales/pt.json @@ -82,7 +82,6 @@ "empty_column.community": "Ainda não existem conteúdo local para mostrar!", "empty_column.hashtag": "Ainda não existe qualquer conteúdo com essa hashtag", "empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "global", "empty_column.notifications": "Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.", "empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para ver aqui os conteúdos públicos.", @@ -160,6 +159,11 @@ "privacy.public.short": "Público", "privacy.unlisted.long": "Não publicar nos feeds públicos", "privacy.unlisted.short": "Não listar", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancelar", "report.placeholder": "Comentários adicionais", "report.submit": "Enviar", @@ -179,6 +183,7 @@ "status.load_more": "Carregar mais", "status.media_hidden": "Media escondida", "status.mention": "Mencionar @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expandir", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index bf32c820d..104b063f5 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -82,7 +82,6 @@ "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!", "empty_column.hashtag": "Статусов с таким хэштегом еще не существует.", "empty_column.home": "Пока Вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.", - "empty_column.home.inactivity": "Ваша домашняя лента пуста. Если Вы некоторое время были неактивны, она будет сгенерирована для Вас в ближайшее время.", "empty_column.home.public_timeline": "публичные ленты", "empty_column.notifications": "У Вас еще нет уведомлений. Заведите знакомство с другими пользователями, чтобы начать разговор.", "empty_column.public": "Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту.", @@ -160,6 +159,11 @@ "privacy.public.short": "Публичный", "privacy.unlisted.long": "Не показывать в лентах", "privacy.unlisted.short": "Скрытый", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Отмена", "report.placeholder": "Комментарий", "report.submit": "Отправить", @@ -179,6 +183,7 @@ "status.load_more": "Показать еще", "status.media_hidden": "Медиаконтент скрыт", "status.mention": "Упомянуть @{name}", + "status.more": "More", "status.mute_conversation": "Заглушить тред", "status.open": "Развернуть статус", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json new file mode 100644 index 000000000..70beb70f7 --- /dev/null +++ b/app/javascript/mastodon/locales/sv.json @@ -0,0 +1,217 @@ +{ + "account.block": "Blockera @{name}", + "account.block_domain": "Dölj allt från {domain}", + "account.disclaimer_full": "Informationen nedan kan spegla användarens profil ofullständigt.", + "account.edit_profile": "Redigera profil", + "account.follow": "Följ", + "account.followers": "Följare", + "account.follows": "Följer", + "account.follows_you": "Följer dig", + "account.media": "Media", + "account.mention": "Nämna @{name}", + "account.mute": "Tysta @{name}", + "account.posts": "Inlägg", + "account.report": "Rapportera @{name}", + "account.requested": "Inväntar godkännande. Klicka för att avbryta följförfrågan", + "account.share": "Dela @{name}'s profil", + "account.unblock": "Avblockera @{name}", + "account.unblock_domain": "Ta fram {domain}", + "account.unfollow": "Sluta följa", + "account.unmute": "Ta bort tystad @{name}", + "account.view_full_profile": "Visa hela profilen", + "boost_modal.combo": "Du kan trycka {combo} för att slippa denna nästa gång", + "bundle_column_error.body": "Något gick fel när du laddade denna komponent.", + "bundle_column_error.retry": "Försök igen", + "bundle_column_error.title": "Nätverksfel", + "bundle_modal_error.close": "Stäng", + "bundle_modal_error.message": "Något gick fel när du laddade denna komponent.", + "bundle_modal_error.retry": "Försök igen", + "column.blocks": "Blockerade användare", + "column.community": "Lokal tidslinje", + "column.favourites": "Favoriter", + "column.follow_requests": "Följ förfrågningar", + "column.home": "Hem", + "column.mutes": "Tystade användare", + "column.notifications": "Meddelanden", + "column.pins": "Nålade toots", + "column.public": "Förenad tidslinje", + "column_back_button.label": "Tillbaka", + "column_header.hide_settings": "Dölj inställningar", + "column_header.moveLeft_settings": "Flytta kolumnen till vänster", + "column_header.moveRight_settings": "Flytta kolumnen till höger", + "column_header.pin": "Fäst", + "column_header.show_settings": "Visa inställningar", + "column_header.unpin": "Ångra fäst", + "column_subheading.navigation": "Navigation", + "column_subheading.settings": "Inställningar", + "compose_form.lock_disclaimer": "Ditt konto är inte {locked}. Vemsomhelst kan följa dig och även se dina inlägg skrivna för endast dina följare.", + "compose_form.lock_disclaimer.lock": "låst", + "compose_form.placeholder": "Vad funderar du på?", + "compose_form.publish": "Toot", + "compose_form.publish_loud": "{publish}!", + "compose_form.sensitive": "Markera media som känslig", + "compose_form.spoiler": "Dölj text bakom varning", + "compose_form.spoiler_placeholder": "Skriv din varning här", + "confirmation_modal.cancel": "Ångra", + "confirmations.block.confirm": "Blockera", + "confirmations.block.message": "Är du säker att du vill blockera {name}?", + "confirmations.delete.confirm": "Ta bort", + "confirmations.delete.message": "Är du säker att du vill ta bort denna status?", + "confirmations.domain_block.confirm": "Blockera hela domänen", + "confirmations.domain_block.message": "Är du verkligen, verkligen säker på att du vill blockera hela {domain}? I de flesta fall är några riktade blockeringar eller nedtystade tillräckligt och föredras.", + "confirmations.mute.confirm": "Tysta", + "confirmations.mute.message": "Är du säker du vill tysta ner {name}?", + "confirmations.unfollow.confirm": "Sluta följa", + "confirmations.unfollow.message": "Är du säker på att du vill sluta följa {name}?", + "embed.instructions": "Bädda in den här statusen på din webbplats genom att kopiera koden nedan.", + "embed.preview": "Här ser du hur det kommer att se ut:", + "emoji_button.activity": "Aktivitet", + "emoji_button.custom": "Specialgjord", + "emoji_button.flags": "Flaggor", + "emoji_button.food": "Mat & Dryck", + "emoji_button.label": "Lägg till emoji", + "emoji_button.nature": "Natur", + "emoji_button.not_found": "Inga emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.objects": "Objekt", + "emoji_button.people": "Människor", + "emoji_button.recent": "Ofta använda", + "emoji_button.search": "Sök...", + "emoji_button.search_results": "Sökresultat", + "emoji_button.symbols": "Symboler", + "emoji_button.travel": "Resor & Platser", + "empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att få bollen att rulla!", + "empty_column.hashtag": "Det finns inget i denna hashtag ännu.", + "empty_column.home": "Din hemma-tidslinje är tom! Besök {public} eller använd sökning för att komma igång och träffa andra användare.", + "empty_column.home.inactivity": "Ditt hemmafeed är tomt. Om du har varit inaktiv ett tag kommer det att regenereras för dig snart.", + "empty_column.home.public_timeline": "den publika tidslinjen", + "empty_column.notifications": "Du har inga meddelanden än. Interagera med andra för att starta konversationen.", + "empty_column.public": "Det finns inget här! Skriv något offentligt, eller följ manuellt användarna från andra instanser för att fylla på det", + "follow_request.authorize": "Godkänn", + "follow_request.reject": "Avvisa", + "getting_started.appsshort": "Appar", + "getting_started.faq": "FAQ", + "getting_started.heading": "Kom igång", + "getting_started.open_source_notice": "Mastodon är programvara med öppen källkod. Du kan bidra eller rapportera problem på GitHub på {github}.", + "getting_started.userguide": "Användarguide", + "home.column_settings.advanced": "Avancerad", + "home.column_settings.basic": "Grundläggande", + "home.column_settings.filter_regex": "Filtrera ut med regelbundna uttryck", + "home.column_settings.show_reblogs": "Visa knuffar", + "home.column_settings.show_replies": "Visa svar", + "home.settings": "Kolumninställningar", + "lightbox.close": "Stäng", + "lightbox.next": "Nästa", + "lightbox.previous": "Tidigare", + "loading_indicator.label": "Laddar...", + "media_gallery.toggle_visible": "Växla synlighet", + "missing_indicator.label": "Hittades inte", + "navigation_bar.blocks": "Blockerade användare", + "navigation_bar.community_timeline": "Lokal tidslinje", + "navigation_bar.edit_profile": "Redigera profil", + "navigation_bar.favourites": "Favoriter", + "navigation_bar.follow_requests": "Följförfrågningar", + "navigation_bar.info": "Om denna instans", + "navigation_bar.logout": "Logga ut", + "navigation_bar.mutes": "Tystade användare", + "navigation_bar.pins": "Nålade inlägg (toots)", + + "navigation_bar.preferences": "Inställningar", + "navigation_bar.public_timeline": "Förenad tidslinje", + "notification.favourite": "{name} favoriserade din status", + "notification.follow": "{name} följer dig", + "notification.mention": "{name} nämnde dig", + "notification.reblog": "{name} knuffade din status", + "notifications.clear": "Rensa meddelanden", + "notifications.clear_confirmation": "Är du säker på att du vill radera alla dina meddelanden permanent?", + "notifications.column_settings.alert": "Skrivbordsmeddelanden", + "notifications.column_settings.favourite": "Favoriter:", + "notifications.column_settings.follow": "Nya följare:", + "notifications.column_settings.mention": "Omnämningar:", + "notifications.column_settings.push": "Push meddelanden", + "notifications.column_settings.push_meta": "Denna anordning", + "notifications.column_settings.reblog": "Knuffar:", + "notifications.column_settings.show": "Visa i kolumnen", + "notifications.column_settings.sound": "Spela upp ljud", + "onboarding.done": "Klart", + "onboarding.next": "Nästa", + "onboarding.page_five.public_timelines": "Den lokala tidslinjen visar offentliga inlägg från alla på {domain}. Den förenade tidslinjen visar offentliga inlägg från alla personer på {domain} som följer. Dom här offentliga tidslinjerna är ett bra sätt att upptäcka nya människor.", + "onboarding.page_four.home": "Hemmatidslinjen visar inlägg från personer du följer.", + "onboarding.page_four.notifications": "Meddelandekolumnen visar när någon interagerar med dig.", + "onboarding.page_one.federation": "Mastodon är ett nätverk av oberoende servrar som ansluter för att skapa ett större socialt nätverk. Vi kallar dessa servrar instanser.", + "onboarding.page_one.handle": "Du är på {domain}, så din fulla hantering är {handle}", + "onboarding.page_one.welcome": "Välkommen till Mastodon!", + "onboarding.page_six.admin": "Din instansadmin är {admin}.", + "onboarding.page_six.almost_done": "Snart klart...", + "onboarding.page_six.appetoot": "Bon Appetoot!", + "onboarding.page_six.apps_available": "Det finns {apps} tillgängligt för iOS, Android och andra plattformar.", + "onboarding.page_six.github": "Mastodon är fri programvara med öppen källkod. Du kan rapportera fel, efterfråga funktioner eller bidra till koden på {github}.", + "onboarding.page_six.guidelines": "gemenskapsriktlinjer", + "onboarding.page_six.read_guidelines": "Vänligen läs {domain}'s {guidelines}!", + "onboarding.page_six.various_app": "mobilappar", + "onboarding.page_three.profile": "Redigera din profil för att ändra ditt avatar, bio och visningsnamn. Där hittar du även andra inställningar.", + "onboarding.page_three.search": "Använd sökfältet för att hitta personer och titta på hashtags, till exempel {illustration} och {introductions}. För att leta efter en person som inte befinner sig i detta fall använd deras fulla handhavande.", + "onboarding.page_two.compose": "Skriv inlägg från skrivkolumnen. Du kan ladda upp bilder, ändra integritetsinställningar och lägga till varningar med ikonerna nedan.", + "onboarding.skip": "Hoppa över", + "privacy.change": "Justera status sekretess", + "privacy.direct.long": "Skicka endast till nämnda användare", + "privacy.direct.short": "Direkt", + "privacy.private.long": "Skicka endast till följare", + "privacy.private.short": "Endast följare", + "privacy.public.long": "Skicka till publik tidslinje", + "privacy.public.short": "Publik", + "privacy.unlisted.long": "Skicka inte till publik tidslinje", + "privacy.unlisted.short": "Olistad", + "reply_indicator.cancel": "Ångra", + "report.placeholder": "Ytterligare kommentarer", + "report.submit": "Skicka", + "report.target": "Rapporterar {target}", + "search.placeholder": "Sök", + "search_popout.search_format": "Avancerat sökformat", + "search_popout.tips.hashtag": "hashtag", + "search_popout.tips.status": "status", + "search_popout.tips.text": "Enkel text returnerar matchande visningsnamn, användarnamn och hashtags", + "search_popout.tips.user": "användare", + "search_results.total": "{count, number} {count, plural, ett {result} andra {results}}", + "standalone.public_title": "En titt inuti...", + "status.cannot_reblog": "Detta inlägg kan inte knuffas", + "status.delete": "Ta bort", + "status.embed": "Bädda in", + "status.favourite": "Favorit", + "status.load_more": "Ladda fler", + "status.media_hidden": "Media dold", + "status.mention": "Omnämn @{name}", + "status.mute_conversation": "Tysta konversation", + "status.open": "Utvidga denna status", + "status.pin": "Fäst i profil", + "status.reblog": "Knuff", + "status.reblogged_by": "{name} knuffade", + "status.reply": "Svara", + "status.replyAll": "Svara på tråden", + "status.report": "Rapportera @{name}", + "status.sensitive_toggle": "Klicka för att se", + "status.sensitive_warning": "Känsligt innehåll", + "status.share": "Dela", + "status.show_less": "Visa mindre", + "status.show_more": "Visa mer", + "status.unmute_conversation": "Öppna konversation", + "status.unpin": "Ångra fäst i profil", + "tabs_bar.compose": "Skriv", + "tabs_bar.federated_timeline": "Förenad", + "tabs_bar.home": "Hem", + "tabs_bar.local_timeline": "Lokal", + "tabs_bar.notifications": "Meddelanden", + "upload_area.title": "Dra & släpp för att ladda upp", + "upload_button.label": "Lägg till media", + "upload_form.description": "Beskriv för synskadade", + "upload_form.undo": "Ångra", + "upload_progress.label": "Laddar upp...", + "video.close": "Stäng video", + "video.exit_fullscreen": "Stäng helskärm", + "video.expand": "Expandera video", + "video.fullscreen": "Helskärm", + "video.hide": "Dölj video", + "video.mute": "Tysta ljud", + "video.pause": "Pause", + "video.play": "Spela upp", + "video.unmute": "Spela upp ljud" +} diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 4339d1497..db3f3dd0d 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -82,7 +82,6 @@ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "the public timeline", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", @@ -160,6 +159,11 @@ "privacy.public.short": "Public", "privacy.unlisted.long": "Do not post to public timelines", "privacy.unlisted.short": "Unlisted", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Cancel", "report.placeholder": "Additional comments", "report.submit": "Submit", @@ -179,6 +183,7 @@ "status.load_more": "Load more", "status.media_hidden": "Media hidden", "status.mention": "Mention @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Expand this status", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index afc6383b4..cdd3581da 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -82,7 +82,6 @@ "empty_column.community": "Yerel zaman tüneliniz boş. Daha fazla eğlence için herkese açık bir gönderi paylaşın.", "empty_column.hashtag": "Henüz bu hashtag’e sahip hiçbir gönderi yok.", "empty_column.home": "Henüz kimseyi takip etmiyorsunuz. {public} ziyaret edebilir veya arama kısmını kullanarak diğer kullanıcılarla iletişime geçebilirsiniz.", - "empty_column.home.inactivity": "Your home feed is empty. If you have been inactive for a while, it will be regenerated for you soon.", "empty_column.home.public_timeline": "herkese açık zaman tüneli", "empty_column.notifications": "Henüz hiçbir bildiriminiz yok. Diğer insanlarla sobhet edebilmek için etkileşime geçebilirsiniz.", "empty_column.public": "Burada hiçbir gönderi yok! Herkese açık bir şeyler yazın, veya diğer sunucudaki insanları takip ederek bu alanın dolmasını sağlayın", @@ -160,6 +159,11 @@ "privacy.public.short": "Herkese açık", "privacy.unlisted.long": "Herkese açık zaman tüneline gönderme", "privacy.unlisted.short": "Listelenmemiş", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "İptal", "report.placeholder": "Ek yorumlar", "report.submit": "Gönder", @@ -179,6 +183,7 @@ "status.load_more": "Daha fazla", "status.media_hidden": "Gizli görsel", "status.mention": "Bahset @{name}", + "status.more": "More", "status.mute_conversation": "Mute conversation", "status.open": "Bu gönderiyi genişlet", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index d0aae032b..930529f15 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -82,7 +82,6 @@ "empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!", "empty_column.hashtag": "Дописів з цим хештегом поки не існує.", "empty_column.home": "Ви поки ні на кого не підписані. Погортайте {public}, або скористуйтесь пошуком, щоб освоїтися та познайомитися з іншими користувачами.", - "empty_column.home.inactivity": "Ваша домашня стрічка пуста. Якщо ви були неактивні протягом деякого часу, вона скоро буде згенерована для Вас.", "empty_column.home.public_timeline": "публічні стрічки", "empty_column.notifications": "У вас ще немає сповіщень. Переписуйтесь з іншими користувачами, щоб почати розмову.", "empty_column.public": "Тут поки нічого немає! Опублікуйте щось, або вручну підпишіться на користувачів інших інстанцій, щоб заповнити стрічку.", @@ -160,6 +159,11 @@ "privacy.public.short": "Публічний", "privacy.unlisted.long": "Не показувати у публічних стрічках", "privacy.unlisted.short": "Прихований", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "Відмінити", "report.placeholder": "Додаткові коментарі", "report.submit": "Відправити", @@ -179,6 +183,7 @@ "status.load_more": "Завантажити більше", "status.media_hidden": "Медіаконтент приховано", "status.mention": "Згадати", + "status.more": "More", "status.mute_conversation": "Заглушити діалог", "status.open": "Розгорнути допис", "status.pin": "Pin on profile", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index e0ffc16df..827c815cf 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -82,7 +82,6 @@ "empty_column.community": "本站时间轴暂时未有内容,快嘟几个来抢头香啊!", "empty_column.hashtag": "这个标签暂时未有内容。", "empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。", - "empty_column.home.inactivity": "你的主页暂时没有内容。也许你太久没有来了?如果是这样,文章会慢慢出来,请稍后再看。", "empty_column.home.public_timeline": "公共时间轴", "empty_column.notifications": "你没有任何通知纪录,快向其他用户搭讪吧。", "empty_column.public": "跨站公共时间轴暂时没有内容!快写一些公共的嘟文,或者关注另一些服务器实例的用户吧!你和本站、友站的交流,将决定这里出现的内容。", @@ -160,6 +159,11 @@ "privacy.public.short": "公共", "privacy.unlisted.long": "公开,但不在公共时间轴显示", "privacy.unlisted.short": "公开", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "取消", "report.placeholder": "额外消息", "report.submit": "提交", @@ -179,6 +183,7 @@ "status.load_more": "加载更多", "status.media_hidden": "隐藏媒体内容", "status.mention": "提及 @{name}", + "status.more": "More", "status.mute_conversation": "静音对话", "status.open": "展开嘟文", "status.pin": "置顶到资料", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 053e971aa..f6f56fee1 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -82,7 +82,6 @@ "empty_column.community": "本站時間軸暫時未有內容,快文章來搶頭香啊!", "empty_column.hashtag": "這個標籤暫時未有內容。", "empty_column.home": "你還沒有關注任何用戶。快看看{public},向其他用戶搭訕吧。", - "empty_column.home.inactivity": "你的主頁暫時沒有內容。也許你太久沒有來?如果是這樣,文章會慢慢出來,請稍後再看。", "empty_column.home.public_timeline": "公共時間軸", "empty_column.notifications": "你沒有任何通知紀錄,快向其他用戶搭訕吧。", "empty_column.public": "跨站時間軸暫時沒有內容!快寫一些公共的文章,或者關注另一些服務站的用戶吧!你和本站、友站的交流,將決定這裏出現的內容。", @@ -160,6 +159,11 @@ "privacy.public.short": "公共", "privacy.unlisted.long": "公開,但不在公共時間軸顯示", "privacy.unlisted.short": "公開", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "取消", "report.placeholder": "額外訊息", "report.submit": "提交", @@ -179,6 +183,7 @@ "status.load_more": "載入更多", "status.media_hidden": "隱藏媒體內容", "status.mention": "提及 @{name}", + "status.more": "More", "status.mute_conversation": "靜音對話", "status.open": "展開文章", "status.pin": "置頂到資料頁", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index a22d66fa1..1f43c6a20 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -82,7 +82,6 @@ "empty_column.community": "本地時間軸是空的。公開寫點什麼吧!", "empty_column.hashtag": "這個主題標籤下什麼都沒有。", "empty_column.home": "你還沒關注任何人。造訪{public}或利用搜尋功能找到其他用者。", - "empty_column.home.inactivity": "你家的訊息摘要是空的。如果你很久沒活動了,很快它就會重新產生。", "empty_column.home.public_timeline": "公開時間軸", "empty_column.notifications": "還沒有任何通知。和別的使用者互動來開始對話。", "empty_column.public": "這裡什麼都沒有!公開寫些什麼,或是關注其他副本的使用者。", @@ -160,6 +159,11 @@ "privacy.public.short": "公開貼", "privacy.unlisted.long": "不要貼到公開時間軸", "privacy.unlisted.short": "不列出來", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "now", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", "reply_indicator.cancel": "取消", "report.placeholder": "更多訊息", "report.submit": "送出", @@ -179,6 +183,7 @@ "status.load_more": "載入更多", "status.media_hidden": "媒體已隱藏", "status.mention": "提到 @{name}", + "status.more": "More", "status.mute_conversation": "消音對話", "status.open": "展開這個狀態", "status.pin": "置頂到個人資訊頁", diff --git a/app/javascript/mastodon/main.js b/app/javascript/mastodon/main.js index c85cd5800..93d2eaf10 100644 --- a/app/javascript/mastodon/main.js +++ b/app/javascript/mastodon/main.js @@ -1,6 +1,5 @@ -import * as OfflinePluginRuntime from 'offline-plugin/runtime'; import * as WebPushSubscription from './web_push_subscription'; -import Mastodon from 'mastodon/containers/mastodon'; +import Mastodon from './containers/mastodon'; import React from 'react'; import ReactDOM from 'react-dom'; import ready from './ready'; @@ -25,7 +24,7 @@ function main() { ReactDOM.render(<Mastodon {...props} />, mountNode); if (process.env.NODE_ENV === 'production') { // avoid offline in dev mode because it's harder to debug - OfflinePluginRuntime.install(); + require('offline-plugin/runtime').install(); WebPushSubscription.register(); } perf.stop('main()'); diff --git a/app/javascript/mastodon/middleware/sounds.js b/app/javascript/mastodon/middleware/sounds.js index 372e7c835..3d1e3eaba 100644 --- a/app/javascript/mastodon/middleware/sounds.js +++ b/app/javascript/mastodon/middleware/sounds.js @@ -12,7 +12,11 @@ const createAudio = sources => { const play = audio => { if (!audio.paused) { audio.pause(); - audio.fastSeek(0); + if (typeof audio.fastSeek === 'function') { + audio.fastSeek(0); + } else { + audio.seek(0); + } } audio.play(); diff --git a/app/javascript/mastodon/reducers/timelines.js b/app/javascript/mastodon/reducers/timelines.js index b17d74ef3..bee4c4ef9 100644 --- a/app/javascript/mastodon/reducers/timelines.js +++ b/app/javascript/mastodon/reducers/timelines.js @@ -31,10 +31,10 @@ const initialTimeline = ImmutableMap({ }); const normalizeTimeline = (state, timeline, statuses, next) => { - const ids = ImmutableList(statuses.map(status => status.get('id'))); + const oldIds = state.getIn([timeline, 'items'], ImmutableList()); + const ids = ImmutableList(statuses.map(status => status.get('id'))).filter(newId => !oldIds.includes(newId)); const wasLoaded = state.getIn([timeline, 'loaded']); const hadNext = state.getIn([timeline, 'next']); - const oldIds = state.getIn([timeline, 'items'], ImmutableList()); return state.update(timeline, initialTimeline, map => map.withMutations(mMap => { mMap.set('loaded', true); @@ -45,8 +45,8 @@ const normalizeTimeline = (state, timeline, statuses, next) => { }; const appendNormalizedTimeline = (state, timeline, statuses, next) => { - const ids = ImmutableList(statuses.map(status => status.get('id'))); const oldIds = state.getIn([timeline, 'items'], ImmutableList()); + const ids = ImmutableList(statuses.map(status => status.get('id'))).filter(newId => !oldIds.includes(newId)); return state.update(timeline, initialTimeline, map => map.withMutations(mMap => { mMap.set('isLoading', false); @@ -75,15 +75,9 @@ const updateTimeline = (state, timeline, status, references) => { })); }; -const deleteStatus = (state, id, accountId, references, reblogOf) => { +const deleteStatus = (state, id, accountId, references) => { state.keySeq().forEach(timeline => { - state = state.updateIn([timeline, 'items'], list => { - if (reblogOf && !list.includes(reblogOf)) { - return list.map(item => item === id ? reblogOf : item); - } else { - return list.filterNot(item => item === id); - } - }); + state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id)); }); // Remove reblogs of deleted status diff --git a/app/javascript/mastodon/test_setup.js b/app/javascript/mastodon/test_setup.js new file mode 100644 index 000000000..80148379b --- /dev/null +++ b/app/javascript/mastodon/test_setup.js @@ -0,0 +1,5 @@ +import { configure } from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; + +const adapter = new Adapter(); +configure({ adapter }); diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index aa94006c6..d275c3bb0 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -2,7 +2,8 @@ import loadPolyfills from '../mastodon/load_polyfills'; // import default stylesheet with variables require('font-awesome/css/font-awesome.css'); -import 'styles/application'; + +import '../styles/application.scss'; require.context('../images/', true); diff --git a/app/javascript/packs/common.js b/app/javascript/packs/common.js index de0c68fa5..5ac6504d4 100644 --- a/app/javascript/packs/common.js +++ b/app/javascript/packs/common.js @@ -1,6 +1,9 @@ import { start } from 'rails-ujs'; +import 'font-awesome/css/font-awesome.css'; // import common styling require('../styles/common.scss'); +require.context('../images/', true); + start(); diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss index e35937be1..efd34393f 100644 --- a/app/javascript/styles/application.scss +++ b/app/javascript/styles/application.scss @@ -1,20 +1,23 @@ -@import 'mixins'; -@import 'variables'; +@import 'mastodon/mixins'; +@import 'mastodon/variables'; @import 'variables-glitch'; +@import 'fonts/roboto'; +@import 'fonts/roboto-mono'; +@import 'fonts/montserrat'; -@import 'reset'; -@import 'basics'; -@import 'containers'; -@import 'lists'; -@import 'footer'; -@import 'compact_header'; -@import 'landing_strip'; -@import 'forms'; -@import 'accounts'; -@import 'stream_entries'; -@import 'components'; -@import 'emoji_picker'; -@import 'about'; -@import 'tables'; -@import 'admin'; -@import 'rtl'; +@import 'mastodon/reset'; +@import 'mastodon/basics'; +@import 'mastodon/containers'; +@import 'mastodon/lists'; +@import 'mastodon/footer'; +@import 'mastodon/compact_header'; +@import 'mastodon/landing_strip'; +@import 'mastodon/forms'; +@import 'mastodon/accounts'; +@import 'mastodon/stream_entries'; +@import 'mastodon/components'; +@import 'mastodon/emoji_picker'; +@import 'mastodon/about'; +@import 'mastodon/tables'; +@import 'mastodon/admin'; +@import 'mastodon/rtl'; diff --git a/app/javascript/styles/_mixins.scss b/app/javascript/styles/mastodon/_mixins.scss index 7412991b8..7412991b8 100644 --- a/app/javascript/styles/_mixins.scss +++ b/app/javascript/styles/mastodon/_mixins.scss diff --git a/app/javascript/styles/about.scss b/app/javascript/styles/mastodon/about.scss index 4ec689427..4ec689427 100644 --- a/app/javascript/styles/about.scss +++ b/app/javascript/styles/mastodon/about.scss diff --git a/app/javascript/styles/accounts.scss b/app/javascript/styles/mastodon/accounts.scss index b00dd8c1e..b00dd8c1e 100644 --- a/app/javascript/styles/accounts.scss +++ b/app/javascript/styles/mastodon/accounts.scss diff --git a/app/javascript/styles/admin.scss b/app/javascript/styles/mastodon/admin.scss index 87bc710af..87bc710af 100644 --- a/app/javascript/styles/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss diff --git a/app/javascript/styles/basics.scss b/app/javascript/styles/mastodon/basics.scss index 43c32c8bc..b5d77ff63 100644 --- a/app/javascript/styles/basics.scss +++ b/app/javascript/styles/mastodon/basics.scss @@ -30,7 +30,7 @@ body { } &.app-body { - position: fixed; + position: absolute; width: 100%; height: 100%; padding: 0; diff --git a/app/javascript/styles/boost.scss b/app/javascript/styles/mastodon/boost.scss index b07b72f8e..b07b72f8e 100644 --- a/app/javascript/styles/boost.scss +++ b/app/javascript/styles/mastodon/boost.scss diff --git a/app/javascript/styles/compact_header.scss b/app/javascript/styles/mastodon/compact_header.scss index 90d98cc8c..90d98cc8c 100644 --- a/app/javascript/styles/compact_header.scss +++ b/app/javascript/styles/mastodon/compact_header.scss diff --git a/app/javascript/styles/components.scss b/app/javascript/styles/mastodon/components.scss index 7ef3dcc43..6fe179581 100644 --- a/app/javascript/styles/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -302,7 +302,6 @@ font-family: inherit; font-size: 14px; background: $simple-background-color; - border-radius: 0 0 4px; } .compose-form__buttons-wrapper { @@ -452,6 +451,7 @@ .compose-form__publish { display: flex; + justify-content: flex-end; min-width: 0; } @@ -468,7 +468,7 @@ .compose-form__publish__side-arm { padding: 0 !important; - width: 4em; + width: 36px; text-align: center; margin-right: 2px; } @@ -551,6 +551,14 @@ overflow: visible; white-space: pre-wrap; + &.status__content--with-spoiler { + white-space: normal; + + .status__content__text { + white-space: pre-wrap; + } + } + .emojione { width: 18px; height: 18px; diff --git a/app/javascript/styles/containers.scss b/app/javascript/styles/mastodon/containers.scss index af2589e23..af2589e23 100644 --- a/app/javascript/styles/containers.scss +++ b/app/javascript/styles/mastodon/containers.scss diff --git a/app/javascript/styles/emoji_picker.scss b/app/javascript/styles/mastodon/emoji_picker.scss index 2b46d30fc..2b46d30fc 100644 --- a/app/javascript/styles/emoji_picker.scss +++ b/app/javascript/styles/mastodon/emoji_picker.scss diff --git a/app/javascript/styles/footer.scss b/app/javascript/styles/mastodon/footer.scss index 2d953b34e..2d953b34e 100644 --- a/app/javascript/styles/footer.scss +++ b/app/javascript/styles/mastodon/footer.scss diff --git a/app/javascript/styles/forms.scss b/app/javascript/styles/mastodon/forms.scss index 61fcf286f..61fcf286f 100644 --- a/app/javascript/styles/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss diff --git a/app/javascript/styles/landing_strip.scss b/app/javascript/styles/mastodon/landing_strip.scss index 15ff84912..15ff84912 100644 --- a/app/javascript/styles/landing_strip.scss +++ b/app/javascript/styles/mastodon/landing_strip.scss diff --git a/app/javascript/styles/lists.scss b/app/javascript/styles/mastodon/lists.scss index 6019cd800..6019cd800 100644 --- a/app/javascript/styles/lists.scss +++ b/app/javascript/styles/mastodon/lists.scss diff --git a/app/javascript/styles/reset.scss b/app/javascript/styles/mastodon/reset.scss index cc5ba9d7c..cc5ba9d7c 100644 --- a/app/javascript/styles/reset.scss +++ b/app/javascript/styles/mastodon/reset.scss diff --git a/app/javascript/styles/rtl.scss b/app/javascript/styles/mastodon/rtl.scss index 67bfa8a38..67bfa8a38 100644 --- a/app/javascript/styles/rtl.scss +++ b/app/javascript/styles/mastodon/rtl.scss diff --git a/app/javascript/styles/stream_entries.scss b/app/javascript/styles/mastodon/stream_entries.scss index 453070b7c..453070b7c 100644 --- a/app/javascript/styles/stream_entries.scss +++ b/app/javascript/styles/mastodon/stream_entries.scss diff --git a/app/javascript/styles/tables.scss b/app/javascript/styles/mastodon/tables.scss index ad46f5f9f..ad46f5f9f 100644 --- a/app/javascript/styles/tables.scss +++ b/app/javascript/styles/mastodon/tables.scss diff --git a/app/javascript/styles/variables.scss b/app/javascript/styles/mastodon/variables.scss index 090706ff5..090706ff5 100644 --- a/app/javascript/styles/variables.scss +++ b/app/javascript/styles/mastodon/variables.scss diff --git a/app/javascript/themes/spin/pack.js b/app/javascript/themes/spin/pack.js index dab0e93a4..b11ac4802 100644 --- a/app/javascript/themes/spin/pack.js +++ b/app/javascript/themes/spin/pack.js @@ -1,2 +1,2 @@ -import 'packs/application'; -import 'themes/spin/style'; +import '../../packs/application'; +import './style.scss'; diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 9688f57a6..01144f595 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -67,9 +67,14 @@ class ActivityPub::Activity end def distribute(status) + crawl_links(status) + + # Only continue if the status is supposed to have + # arrived in real-time + return unless @options[:override_timestamps] + notify_about_reblog(status) if reblog_of_local_account?(status) notify_about_mentions(status) - crawl_links(status) distribute_to_followers(status) end diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 5a3af7206..39d3333da 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -56,7 +56,17 @@ class FeedManager falloff_rank = FeedManager::REBLOG_FALLOFF - 1 falloff_range = redis.zrevrange(timeline_key, falloff_rank, falloff_rank, with_scores: true) falloff_score = falloff_range&.first&.last&.to_i || 0 - redis.zremrangebyscore(reblog_key, 0, falloff_score) + + # Get any reblogs we might have to clean up after. + redis.zrangebyscore(reblog_key, 0, falloff_score).each do |reblogged_id| + # Remove it from the set of reblogs we're tracking *first* to avoid races. + redis.zrem(reblog_key, reblogged_id) + # Just drop any set we might have created to track additional reblogs. + # This means that if this reblog is deleted, we won't automatically insert + # another reblog, but also that any new reblog can be inserted into the + # feed. + redis.del(key(type, account_id, "reblogs:#{reblogged_id}")) + end end def push_update_required?(timeline_type, account_id) @@ -100,11 +110,24 @@ class FeedManager end def populate_feed(account) - prepopulate_limit = FeedManager::MAX_ITEMS / 4 - statuses = Status.as_home_timeline(account).order(account_id: :desc).limit(prepopulate_limit) - statuses.reverse_each do |status| - next if filter_from_home?(status, account) - add_to_feed(:home, account, status) + added = 0 + limit = FeedManager::MAX_ITEMS / 2 + max_id = nil + + loop do + statuses = Status.as_home_timeline(account) + .paginate_by_max_id(limit, max_id) + + break if statuses.empty? + + statuses.each do |status| + next if filter_from_home?(status, account) + added += 1 if add_to_feed(:home, account, status) + end + + break unless added.zero? + + max_id = statuses.last.id end end @@ -167,20 +190,31 @@ class FeedManager # either action is appropriate. def add_to_feed(timeline_type, account, status) timeline_key = key(timeline_type, account.id) - reblog_key = key(timeline_type, account.id, 'reblogs') + reblog_key = key(timeline_type, account.id, 'reblogs') if status.reblog? # If the original status or a reblog of it is within # REBLOG_FALLOFF statuses from the top, do not re-insert it into # the feed rank = redis.zrevrank(timeline_key, status.reblog_of_id) + return false if !rank.nil? && rank < FeedManager::REBLOG_FALLOFF reblog_rank = redis.zrevrank(reblog_key, status.reblog_of_id) - return false unless reblog_rank.nil? - - redis.zadd(timeline_key, status.id, status.id) - redis.zadd(reblog_key, status.id, status.reblog_of_id) + if reblog_rank.nil? + # This is not something we've already seen reblogged, so we + # can just add it to the feed (and note that we're + # reblogging it). + redis.zadd(timeline_key, status.id, status.id) + redis.zadd(reblog_key, status.id, status.reblog_of_id) + else + # Another reblog of the same status was already in the + # REBLOG_FALLOFF most recent statuses, so we note that this + # is an "extra" reblog, by storing it in reblog_set_key. + reblog_set_key = key(timeline_type, account.id, "reblogs:#{status.reblog_of_id}") + redis.sadd(reblog_set_key, status.id) + return false + end else redis.zadd(timeline_key, status.id, status.id) end @@ -194,22 +228,29 @@ class FeedManager # do so if appropriate. def remove_from_feed(timeline_type, account, status) timeline_key = key(timeline_type, account.id) - reblog_key = key(timeline_type, account.id, 'reblogs') if status.reblog? # 1. If the reblogging status is not in the feed, stop. status_rank = redis.zrevrank(timeline_key, status.id) return false if status_rank.nil? - # 2. Remove the reblogged status from the `:reblogs` zset. - redis.zrem(reblog_key, status.reblog_of_id) + # 2. Remove reblog from set of this status's reblogs. + reblog_set_key = key(timeline_type, account.id, "reblogs:#{status.reblog_of_id}") + + redis.srem(reblog_set_key, status.id) + # 3. Re-insert another reblog or original into the feed if one + # remains in the set. We could pick a random element, but this + # set should generally be small, and it seems ideal to show the + # oldest potential such reblog. + other_reblog = redis.smembers(reblog_set_key).map(&:to_i).sort.first - # 3. Add the reblogged status to the feed using the reblogging - # status' ID as its score, and the reblogged status' ID as its - # value. - redis.zadd(timeline_key, status.id, status.reblog_of_id) + redis.zadd(timeline_key, other_reblog, other_reblog) if other_reblog # 4. Remove the reblogging status from the feed (as normal) + # (outside conditional) + else + # If the original is getting deleted, no use for reblog references + redis.del(key(timeline_type, account.id, "reblogs:#{status.id}")) end redis.zrem(timeline_key, status.id) diff --git a/app/lib/ostatus/activity/creation.rb b/app/lib/ostatus/activity/creation.rb index a1ab522e2..3418e2420 100644 --- a/app/lib/ostatus/activity/creation.rb +++ b/app/lib/ostatus/activity/creation.rb @@ -56,7 +56,7 @@ class OStatus::Activity::Creation < OStatus::Activity::Base Rails.logger.debug "Queuing remote status #{status.id} (#{id}) for distribution" LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text? - DistributionWorker.perform_async(status.id) + DistributionWorker.perform_async(status.id) if @options[:override_timestamps] status end diff --git a/app/lib/user_settings_decorator.rb b/app/lib/user_settings_decorator.rb index 3b7a856ee..d86959c0b 100644 --- a/app/lib/user_settings_decorator.rb +++ b/app/lib/user_settings_decorator.rb @@ -23,6 +23,7 @@ class UserSettingsDecorator user.settings['boost_modal'] = boost_modal_preference if change?('setting_boost_modal') user.settings['delete_modal'] = delete_modal_preference if change?('setting_delete_modal') user.settings['auto_play_gif'] = auto_play_gif_preference if change?('setting_auto_play_gif') + user.settings['reduce_motion'] = reduce_motion_preference if change?('setting_reduce_motion') user.settings['system_font_ui'] = system_font_ui_preference if change?('setting_system_font_ui') user.settings['noindex'] = noindex_preference if change?('setting_noindex') user.settings['theme'] = theme_preference if change?('setting_theme') @@ -64,6 +65,10 @@ class UserSettingsDecorator boolean_cast_setting 'setting_auto_play_gif' end + def reduce_motion_preference + boolean_cast_setting 'setting_reduce_motion' + end + def noindex_preference boolean_cast_setting 'setting_noindex' end diff --git a/app/models/user.rb b/app/models/user.rb index 3bf069a31..325e27f44 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -102,6 +102,10 @@ class User < ApplicationRecord settings.auto_play_gif end + def setting_reduce_motion + settings.reduce_motion + end + def setting_system_font_ui settings.system_font_ui end diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index 0992771fc..1f5ee789a 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -25,6 +25,7 @@ class InitialStateSerializer < ActiveModel::Serializer store[:boost_modal] = object.current_account.user.setting_boost_modal store[:delete_modal] = object.current_account.user.setting_delete_modal store[:auto_play_gif] = object.current_account.user.setting_auto_play_gif + store[:reduce_motion] = object.current_account.user.setting_reduce_motion end store diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 7029c4d75..14c21b6cc 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -3,7 +3,7 @@ class FetchLinkCardService < BaseService URL_PATTERN = %r{ ( # $1 URL - (https?:\/\/)? # $2 Protocol (optional) + (https?:\/\/) # $2 Protocol (required) (#{Twitter::Regex[:valid_domain]}) # $3 Domain(s) (?::(#{Twitter::Regex[:valid_port_number]}))? # $4 Port number (optional) (/#{Twitter::Regex[:valid_url_path]}*)? # $5 URL Path and anchor diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 24b74c787..b1fd9ef40 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -29,6 +29,7 @@ = yield :header_tags - body_classes ||= @body_classes || '' + - body_classes += ' reduce-motion' if current_account&.user&.setting_reduce_motion - body_classes += ' system-font' if current_account&.user&.setting_system_font_ui %body{ class: add_rtl_body_class(body_classes) } diff --git a/app/views/settings/preferences/show.html.haml b/app/views/settings/preferences/show.html.haml index 7475e3fd2..69e26a7be 100644 --- a/app/views/settings/preferences/show.html.haml +++ b/app/views/settings/preferences/show.html.haml @@ -35,6 +35,7 @@ .fields-group = f.input :setting_auto_play_gif, as: :boolean, wrapper: :with_label + = f.input :setting_reduce_motion, as: :boolean, wrapper: :with_label = f.input :setting_system_font_ui, as: :boolean, wrapper: :with_label .actions diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml index a4eab16df..b488bd9ba 100644 --- a/app/views/stream_entries/_detailed_status.html.haml +++ b/app/views/stream_entries/_detailed_status.html.haml @@ -19,15 +19,14 @@ %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') .e-content{ lang: status.language, style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }< = Formatter.instance.format(status, custom_emojify: true) - - if !status.media_attachments.empty? - if status.media_attachments.first.video? - video = status.media_attachments.first - %div{ data: { component: 'Video', props: Oj.dump(src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive?, width: 670, height: 380) }}>< + %div{ data: { component: 'Video', props: Oj.dump(src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive?, width: 670, height: 380) }}< - else - %div{ data: { component: 'MediaGallery', props: Oj.dump(height: 380, sensitive: status.sensitive?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }) }}>< + %div{ data: { component: 'MediaGallery', props: Oj.dump(height: 380, sensitive: status.sensitive?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }) }}< - elsif status.preview_cards.first - %div{ data: { component: 'Card', props: Oj.dump('maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_cards.first, serializer: REST::PreviewCardSerializer).as_json) }}>< + %div{ data: { component: 'Card', props: Oj.dump('maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_cards.first, serializer: REST::PreviewCardSerializer).as_json) }}< .detailed-status__meta %data.dt-published{ value: status.created_at.to_time.iso8601 } @@ -40,9 +39,16 @@ - else = link_to status.application.name, status.application.website, class: 'detailed-status__application', target: '_blank', rel: 'noopener' · - %span< - = fa_icon('retweet') - %span= status.reblogs_count + - if status.direct_visibility? + %span< + = fa_icon('envelope') + - elsif status.private_visibility? + %span< + = fa_icon('lock') + - else + %span< + = fa_icon('retweet') + %span= status.reblogs_count · %span< = fa_icon('star') diff --git a/app/views/user_mailer/confirmation_instructions.sv.html.erb b/app/views/user_mailer/confirmation_instructions.sv.html.erb new file mode 100644 index 000000000..e0ad611a7 --- /dev/null +++ b/app/views/user_mailer/confirmation_instructions.sv.html.erb @@ -0,0 +1,15 @@ +<p>Välkommen <%= @resource.email %> !</p> + +<p>Du har precis startat upp ett konto på <%= @instance %>.</p> + +<p>För att bekräfta din inskrift, vänligen klicka på följande länk : <br> +<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p> + +<p>Om länken ovan inte fungerar, kopiera och klistra in den här webbadressen i adressfältet: <br> +<span><%= confirmation_url(@resource, confirmation_token: @token) %></span> + +<p>Vänligen kolla även våra <%= link_to 'terms and conditions', terms_url %>.</p> + +<p>Vänliga hälsningar,<p> + +<p>Teamet på <%= @instance %></p> diff --git a/app/views/user_mailer/confirmation_instructions.sv.text.erb b/app/views/user_mailer/confirmation_instructions.sv.text.erb new file mode 100644 index 000000000..64ffb9799 --- /dev/null +++ b/app/views/user_mailer/confirmation_instructions.sv.text.erb @@ -0,0 +1,12 @@ +Välkommen <%= @resource.email %> ! + +Du har precis skapat ett konto på <%= @instance %>. + +För att bekräfta din inskrift, vänligen klicka på följande länk : +<%= confirmation_url(@resource, confirmation_token: @token) %> + +Vänligen läs även våra användarvillkor <%= terms_url %> + +Vänliga hälsningar, + +Teamet på <%= @instance %> diff --git a/app/views/user_mailer/password_change.sv.html.erb b/app/views/user_mailer/password_change.sv.html.erb new file mode 100644 index 000000000..f6168c638 --- /dev/null +++ b/app/views/user_mailer/password_change.sv.html.erb @@ -0,0 +1,3 @@ +<p>Hej <%= @resource.email %>!</p> + +<p>Vi kontaktar dig för att meddela dig att ditt lösenord på <%= @instance %> har blivit ändrat.</p> diff --git a/app/views/user_mailer/password_change.sv.text.erb b/app/views/user_mailer/password_change.sv.text.erb new file mode 100644 index 000000000..b6df73226 --- /dev/null +++ b/app/views/user_mailer/password_change.sv.text.erb @@ -0,0 +1,3 @@ +Hej <%= @resource.email %>! + +Vi kontaktar dig för att meddela dig att ditt lösenord på <%= @instance %> har blivit ändrat. diff --git a/app/views/user_mailer/reset_password_instructions.sv.html.erb b/app/views/user_mailer/reset_password_instructions.sv.html.erb new file mode 100644 index 000000000..f38d2a39f --- /dev/null +++ b/app/views/user_mailer/reset_password_instructions.sv.html.erb @@ -0,0 +1,8 @@ +<p>Hej <%= @resource.email %>!</p> + +<p>SNågon har begärt en länk för att ändra ditt lösenord på <%= @instance %>. Du kan göra det genom länken nedan.</p> + +<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p> + +<p>Om du inte begärt detta, ignorerar du det här e-postmeddelandet.</p> +<p>Ditt lösenord ändras inte förrän du öppnar länken ovan och skapar en ny.</p> diff --git a/app/views/user_mailer/reset_password_instructions.sv.text.erb b/app/views/user_mailer/reset_password_instructions.sv.text.erb new file mode 100644 index 000000000..946426119 --- /dev/null +++ b/app/views/user_mailer/reset_password_instructions.sv.text.erb @@ -0,0 +1,8 @@ +Hej <%= @resource.email %>! + +Någon har begärt en länk för att ändra ditt lösenord på <%= @instance %>. Du kan göra det genom länken nedan. + +<%= edit_password_url(@resource, reset_password_token: @token) %> + +Om du inte begärt detta, ignorerar du det här e-postmeddelandet. +Ditt lösenord ändras inte förrän du öppnar länken ovan och skapar ett nytt. diff --git a/app/workers/scheduler/feed_cleanup_scheduler.rb b/app/workers/scheduler/feed_cleanup_scheduler.rb index dbebaa2c3..cfa2d31a4 100644 --- a/app/workers/scheduler/feed_cleanup_scheduler.rb +++ b/app/workers/scheduler/feed_cleanup_scheduler.rb @@ -5,17 +5,36 @@ class Scheduler::FeedCleanupScheduler include Sidekiq::Worker def perform + reblogged_id_sets = {} + feedmanager = FeedManager.instance + + redis.pipelined do + inactive_user_ids.each do |account_id| + redis.del(feedmanager.key(:home, account_id)) + reblog_key = feedmanager.key(:home, account_id, 'reblogs') + # We collect a future for this: we don't block while getting + # it, but we can iterate over it later. + reblogged_id_sets[account_id] = redis.zrange(reblog_key, 0, -1) + redis.del(reblog_key) + end + end + + # Remove all of the reblog tracking keys we just removed the + # references to. redis.pipelined do - inactive_users.pluck(:account_id).each do |account_id| - redis.del(FeedManager.instance.key(:home, account_id)) + reblogged_id_sets.each do |account_id, future| + future.value.each do |reblogged_id| + reblog_set_key = feedmanager.key(:home, account_id, "reblogs:#{reblogged_id}") + redis.del(reblog_set_key) + end end end end private - def inactive_users - User.confirmed.inactive + def inactive_user_ids + @inactive_user_ids ||= User.confirmed.inactive.pluck(:account_id) end def redis diff --git a/config/application.rb b/config/application.rb index 4e8a5875d..b54ea1c40 100644 --- a/config/application.rb +++ b/config/application.rb @@ -55,6 +55,7 @@ module Mastodon :pt, :'pt-BR', :ru, + :sv, :th, :tr, :uk, diff --git a/config/database.yml b/config/database.yml index f74635a36..82e560515 100644 --- a/config/database.yml +++ b/config/database.yml @@ -6,7 +6,7 @@ default: &default development: <<: *default - database: mastodon_development + database: <%= ENV['DB_NAME'] || 'mastodon_development' %> username: <%= ENV['DB_USER'] %> password: <%= ENV['DB_PASS'] %> host: <%= ENV['DB_HOST'] %> @@ -17,7 +17,7 @@ development: # Do not set this db to the same as development or production. test: <<: *default - database: mastodon_test<%= ENV['TEST_ENV_NUMBER'] %> + database: <%= ENV['DB_NAME'] || 'mastodon' %>_test<%= ENV['TEST_ENV_NUMBER'] %> username: <%= ENV['DB_USER'] %> password: <%= ENV['DB_PASS'] %> host: <%= ENV['DB_HOST'] %> diff --git a/config/locales/de.yml b/config/locales/de.yml index a54d9734f..169af50ff 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1,8 +1,8 @@ --- de: about: - about_mastodon_html: Mastodon ist ein soziales Netzwerk. Es basiert auf offenen Web-Protokollen und freier, quelloffener Software. Es ist dezentral (so wie E-Mail!). about_hashtag_html: Dies sind öffentliche Beiträge, die mit <strong>#%{hashtag}</strong> getaggt wurden. Wenn du ein Konto irgendwo im Fediversum besitzt, kannst du mit ihnen interagieren. + about_mastodon_html: Mastodon ist ein soziales Netzwerk. Es basiert auf offenen Web-Protokollen und freier, quelloffener Software. Es ist dezentral (so wie E-Mail!). about_this: Über diese Instanz closed_registrations: Die Registrierung auf dieser Instanz ist momentan geschlossen. Aber du kannst dein Konto auch auf einer anderen Instanz erstellen! Von dort hast du genauso Zugriff auf das Mastodon-Netzwerk. contact: Kontakt @@ -50,6 +50,13 @@ de: admin: Admin unfollow: Entfolgen admin: + account_moderation_notes: + account: Moderator*in + create: Erstellen + created_at: Datum + created_msg: Moderationsnotiz erfolgreich erstellt! + delete: Löschen + destroyed_msg: Moderationsnotiz erfolgreich gelöscht! accounts: are_you_sure: Bist du sicher? confirm: Bestätigen @@ -110,13 +117,6 @@ de: unsubscribe: Abbestellen username: Profilname web: Web - account_moderation_notes: - account: Moderator*in - created_at: Datum - create: Erstellen - created_msg: Moderationsnotiz erfolgreich erstellt! - delete: Löschen - destroyed_msg: Moderationsnotiz erfolgreich gelöscht! custom_emojis: copied_msg: Eine lokale Kopie des Emojis wurde erstellt copy: Kopieren diff --git a/config/locales/devise.sv.yml b/config/locales/devise.sv.yml new file mode 100644 index 000000000..3ac0c6d10 --- /dev/null +++ b/config/locales/devise.sv.yml @@ -0,0 +1,61 @@ +--- +sv: + devise: + confirmations: + confirmed: Din e-postadress har bekräftats. + send_instructions: Du kommer att få ett mail med instruktioner för hur du bekräftar din e-postadress om några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + send_paranoid_instructions: Om din e-postadress finns i vår databas får du ett mail med instruktioner för hur du bekräftar din e-postadress inom några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + failure: + already_authenticated: Du är redan inloggad. + inactive: Ditt konto är inte aktiverat än.. + invalid: Ogiltigt %{authentication_keys} eller lösenord. + last_attempt: Du har ytterligare ett försök innan ditt konto blir låst. + locked: Ditt konto är låst. + not_found_in_database: Ogiltigt %{authentication_keys} eller lösenord. + timeout: Din session löpte ut. Vänligen logga in igen för att fortsätta. + unauthenticated: Du måste logga in eller registrera dig innan du fortsätter. + unconfirmed: Du måste bekräfta din e-postadress innan du fortsätter. + mailer: + confirmation_instructions: + subject: 'Mastodon: Bekräftelsesinstruktioner för %{instance}' + password_change: + subject: 'Mastodon: Lösenord ändrat' + reset_password_instructions: + subject: 'Mastodon: Instruktioner för återställning av lösenord' + unlock_instructions: + subject: 'Mastodon: Lås upp instruktioner' + omniauth_callbacks: + failure: Det gick inte att autentisera dig från %{kind} för "%{reason}". + success: Autentiserad från %{kind} konto. + passwords: + no_token: Du kan inte komma åt den här sidan utan att komma från ett e-postmeddelande för lösenordsåterställning. Om du kommer från ett lösenordsåterställt e-postmeddelande, var vänlig och se till att du använde hela webbadressen. + send_instructions: Om din e-postadress finns i vår databas, får du en länk för återställning av lösenord på din e-postadress om några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + send_paranoid_instructions: Om din e-postadress finns i vår databas, får du en länk för återställning av lösenord på din e-postadress om några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + updated: Your password has been changed successfully. You are now signed in. + updated_not_active: Ditt lösenord har ändrats. Du är nu inloggad. + registrations: + destroyed: Adjö! Ditt konto har blivit nerstängt. Vi hoppas att vi ses snart igen. + signed_up: Välkommen! Du har nu registrerat dig. + signed_up_but_inactive: Du har nu registrerat dig. Vi kunde dock inte logga in dig eftersom ditt konto ännu inte är aktiverat. + signed_up_but_locked: Du har nu registrerat dig. Vi kunde dock inte logga in eftersom ditt konto är låst. + signed_up_but_unconfirmed: Ett meddelande med en bekräftelse länk har skickats till din e-postadress. Vänligen följ länken för att aktivera ditt konto. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + update_needs_confirmation: Du har uppdaterat ditt konto med framgång, men vi måste verifiera din nya e-postadress. Vänligen kolla din email och följ bekräfta länken för att bekräfta din nya e-postadress. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + updated: Ditt konto har uppdaterats utan problem. + sessions: + already_signed_out: Utloggad. + signed_in: Inloggad. + signed_out: Utloggad. + unlocks: + send_instructions: Du kommer att få ett mail med instruktioner om hur du låser upp ditt konto inom några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + send_paranoid_instructions: Om ditt konto finns, får du ett mail med instruktioner om hur du låser upp det på några minuter. Kontrollera din spammapp om du inte fick det här e-postmeddelandet. + unlocked: Ditt konto ha låsts upp. Vänligen logga in för att fortsätta. + errors: + messages: + already_confirmed: var redan bekräftad, var god försök att logga in + confirmation_period_expired: måste bekräftas inom %{period}, var god be om en ny + expired: har gått ut, vänligen be om en ny + not_found: hittades inte + not_locked: var inte låst + not_saved: + one: '1 fel förbjöd denna %{resource} att sparas:' + other: "%{count} fel förbjöd dessa %{resource} från att sparas:" diff --git a/config/locales/devise.tr.yml b/config/locales/devise.tr.yml index f00dd2a95..ade23769d 100644 --- a/config/locales/devise.tr.yml +++ b/config/locales/devise.tr.yml @@ -1,14 +1,13 @@ - --- tr: simple_form: hints: defaults: avatar: En fazla 2MB olacak şekilde PNG, GIF veya JPG formatında yükleyiniz. 120x120px büyüklüğüne indirgenecektir - display_name: '%{count} karakter kaldı' + display_name: "%{count} karakter kaldı" header: En fazla 2MB olacak şekilde PNG, GIF veya JPG formatında yükleyiniz. 700x335px büyüklüğüne indirgenecektir. locked: Takipçilerinizi manuel olarak kabul etmenizi ve gönderilerinizi varsayılan olarak sadece takipçilerinizin göreceği şekilde paylaşmanızı sağlar. - note: '%{count} karakter kaldı' + note: "%{count} karakter kaldı" imports: data: Diğer Mastodon sunucusundan dışarı aktardığınız CSV dosyası sessions: @@ -45,8 +44,8 @@ tr: follow_request: Biri bana takip isteği gönderdiğinde, bana e-posta gönder mention: Biri benden bahsettiğinde, bana e-posta gönder reblog: Biri durumumu paylaştığında, bana e-posta gönder - 'no': 'Hayır' + 'no': Hayır required: mark: "*" text: gerekli - 'yes': 'Evet' + 'yes': Evet diff --git a/config/locales/doorkeeper.sv.yml b/config/locales/doorkeeper.sv.yml new file mode 100644 index 000000000..19a457427 --- /dev/null +++ b/config/locales/doorkeeper.sv.yml @@ -0,0 +1,119 @@ +--- +sv: + activerecord: + attributes: + doorkeeper/application: + name: Applikationsnamn + redirect_uri: Omdirigera URI + scopes: Omfattning + website: Applikationswebbplats + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: kan inte innehålla ett fragment. + invalid_uri: måste vara en giltig URI. + relative_uri: måste vara en absolut URI. + secured_uri: måste vara en HTTPS/SSL URI. + doorkeeper: + applications: + buttons: + authorize: Godkänna + cancel: Ångra + destroy: Förstöra + edit: Redigera + submit: Skicka + confirmations: + destroy: Äre du säker? + edit: + title: Redigera applikation + form: + error: Hoppsan! Kontrollera i formuläret efter eventuella fel + help: + native_redirect_uri: Använd %{native_redirect_uri} för lokalt test + redirect_uri: Använd en per rad URI + scopes: Separera omfattningen med mellanslag. Lämna tomt för att använda standardomfattning. + index: + application: Applikation + callback_url: Callback URL + delete: Ta bort + name: Namn + new: Ny applikation + scopes: Omfattning + show: Visa + title: Dina applikationer + new: + title: Ny applikation + show: + actions: Handlingar + application_id: Klientnyckel + callback_urls: Callback URLs + scopes: Omfattning + secret: Kundhemlighet + title: 'Application: %{name}' + authorizations: + buttons: + authorize: Godkänna + deny: Neka + error: + title: Ett fel har uppstått + new: + able_to: Det kommer att kunna + prompt: Applikation %{client_name} begär tillgång till ditt konto + title: Godkännande krävs + show: + title: Kopiera denna behörighetskod och klistra in den i programmet. + authorized_applications: + buttons: + revoke: Återkalla + confirmations: + revoke: Är du säker? + index: + application: Applikation + created_at: Auktoriserad + date_format: "%Y-%m-%d %H:%M:%S" + scopes: Omfattning + title: Dina behöriga ansökningar + errors: + messages: + access_denied: Resursägaren eller behörighetsservern nekade begäran. + credential_flow_not_configured: Resurs Ägare Lösenord Credentials flöde misslyckades på grund av att Doorkeeper.configure.resource_owner_from_credentials är okonfigurerad. + invalid_client: Klientautentisering misslyckades på grund av okänd klient, ingen klientautentisering inkluderad eller icke godkänd autentiseringsmetod. + invalid_grant: Det beviljade godkännandetillskottet är ogiltigt, upphört, återkallat, matchar inte den omdirigering URI som användes i auktorisationsförfrågan eller har utfärdats till en annan klient. + invalid_redirect_uri: Den omdirigerade uri är inte giltig. + invalid_request: Förfrågan saknar en obligatorisk parameter, innehåller ett icke-stödt parametervärde eller är annars felaktigt. + invalid_resource_owner: De angivna resursägarnas referenser är inte giltiga, eller resursägare kan inte hittas + invalid_scope: Det begärda räckvidden är ogiltigt, okänt eller felaktigt. + invalid_token: + expired: The access token utgången + revoked: The access token är återkallad + unknown: The access token är ogiltig + resource_owner_authenticator_not_configured: Resursägaren hittade fel på grund av Doorkeeper.configure.resource_owner_authenticator är okonfigurerad. + server_error: Tillståndsservern stötte på ett oväntat villkor som hindrade det från att uppfylla förfrågan. + temporarily_unavailable: Autorisationsservern kan inte hantera begäran på grund av tillfällig överbelastning eller underhåll av servern. + unauthorized_client: Klienten är inte behörig att utföra denna förfrågan med den här metoden. + unsupported_grant_type: Typgodkännandet för godkännande beviljas inte av behörighetsservern. + unsupported_response_type: Autorisationsservern stöder inte den här svarstypen. + flash: + applications: + create: + notice: Applikation skapad. + destroy: + notice: Applikation borttagen. + update: + notice: Applikation uppdaterad. + authorized_applications: + destroy: + notice: Applikation återkallas. + layouts: + admin: + nav: + applications: Applikationer + oauth2_provider: OAuth2 Provider + application: + title: OAuth-behörighet krävs + scopes: + follow: följ, blockera, ta bort blockering och sluta följa konton + read: läs dina kontodata + write: posta på dina vägnar diff --git a/config/locales/en.yml b/config/locales/en.yml index 7d2596fc6..45929e97d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,8 +1,8 @@ --- en: about: - about_mastodon_html: Mastodon is a social network based on open web protocols and free, open-source software. It is decentralized like e-mail. about_hashtag_html: These are public toots tagged with <strong>#%{hashtag}</strong>. You can interact with them if you have an account anywhere in the fediverse. + about_mastodon_html: Mastodon is a social network based on open web protocols and free, open-source software. It is decentralized like e-mail. about_this: About closed_registrations: Registrations are currently closed on this instance. However! You can find a different instance to make an account on and get access to the very same network from there. contact: Contact @@ -50,6 +50,13 @@ en: admin: Admin unfollow: Unfollow admin: + account_moderation_notes: + account: Moderator + create: Create + created_at: Date + created_msg: Moderation note successfully created! + delete: Delete + destroyed_msg: Moderation note successfully destroyed! accounts: are_you_sure: Are you sure? confirm: Confirm @@ -110,15 +117,6 @@ en: unsubscribe: Unsubscribe username: Username web: Web - - account_moderation_notes: - account: Moderator - created_at: Date - create: Create - created_msg: Moderation note successfully created! - delete: Delete - destroyed_msg: Moderation note successfully destroyed! - custom_emojis: copied_msg: Successfully created local copy of the emoji copy: Copy diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 8cb84c7ae..24a2ddd51 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -1,8 +1,8 @@ --- fa: about: - about_mastodon_html: ماستدون (Mastodon) یک شبکهٔ اجتماعی است که بر اساس پروتکلهای آزاد وب و نرمافزارهای آزاد و کدباز ساخته شده است. این شبکه مانند ایمیل غیرمتمرکز است. about_hashtag_html: اینها نوشتههای عمومی هستند که برچسب (هشتگ) <strong>#%{hashtag}</strong> را دارند. اگر شما روی هر سروری حساب داشته باشید میتوانید به این نوشتهها واکنش نشان دهید. + about_mastodon_html: ماستدون (Mastodon) یک شبکهٔ اجتماعی است که بر اساس پروتکلهای آزاد وب و نرمافزارهای آزاد و کدباز ساخته شده است. این شبکه مانند ایمیل غیرمتمرکز است. about_this: درباره closed_registrations: ثبتنام روی این سرور هماینک فعال نیست. اما شما میتوانید سرور دیگری بیابید و با حسابی که آنجا میسازید دقیقاً به همین شبکه دسترسی داشته باشید. contact: تماس @@ -50,6 +50,13 @@ fa: admin: مدیر unfollow: پایان پیگیری admin: + account_moderation_notes: + account: مدیر + create: نوشتن + created_at: تاریخ + created_msg: یادداشت مدیر با موفقیت ساخته شد! + delete: پاک کردن + destroyed_msg: یادداشت مدیر با موفقیت پاک شد! accounts: are_you_sure: آیا مطمئن هستید؟ confirm: تأیید @@ -110,15 +117,6 @@ fa: unsubscribe: لغو اشتراک username: نام کاربری web: وب - - account_moderation_notes: - account: مدیر - created_at: تاریخ - create: نوشتن - created_msg: یادداشت مدیر با موفقیت ساخته شد! - delete: پاک کردن - destroyed_msg: یادداشت مدیر با موفقیت پاک شد! - custom_emojis: copied_msg: نسخهٔ محلی شکلک با موفقیت ساخته شد copy: نسخهبرداری diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 712724ffa..0d9c227f3 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1,8 +1,8 @@ --- fr: about: - about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé. about_hashtag_html: Figurent ci-dessous les pouets tagués avec <strong>#%{hashtag}</strong>. Vous pouvez interagir avec eux si vous avez un compte n’importe où dans le Fediverse. + about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé. about_this: À propos closed_registrations: Les inscriptions sont actuellement fermées sur cette instance. Cependant, vous pouvez trouver une autre instance sur laquelle vous créer un compte et à partir de laquelle vous pourrez accéder au même réseau. contact: Contact @@ -50,6 +50,13 @@ fr: admin: Admin unfollow: Ne plus suivre admin: + account_moderation_notes: + account: Modérateur·ice + create: Créer + created_at: Date + created_msg: Note de modération créée avec succès ! + delete: Supprimer + destroyed_msg: Note de modération supprimée avec succès ! accounts: are_you_sure: Êtes-vous certain⋅e ? confirm: Confirmer @@ -110,15 +117,6 @@ fr: unsubscribe: Se désabonner username: Nom d’utilisateur⋅ice web: Web - - account_moderation_notes: - account: Modérateur·ice - created_at: Date - create: Créer - created_msg: Note de modération créée avec succès ! - delete: Supprimer - destroyed_msg: Note de modération supprimée avec succès ! - custom_emojis: copied_msg: Copie locale de l’émoji créée avec succès ! copy: Copier @@ -523,7 +521,7 @@ fr: body_html: | <h2>Politique de confidentialité</h2> - <h3 id=\"collect\">Quelles données collectons-nous ?</h3> + <h3 id="collect">Quelles données collectons-nous ?</h3> <p>Nous collectons des données lorsque vous vous enregistrez sur notre site et les récoltons lorsque vous participez dans le forum en lisant, écrivant, et évaluant le contenu partagé ici.</p> @@ -531,7 +529,7 @@ fr: <p>Lors de l’inscription et de la publication de statuts, nous enregistrons l’adresse IP de laquelle les statuts proviennent. Nous pouvons également conserver des historiques serveurs qui contiendront l’adresse IP de chaque requête adressée à notre serveur.</p> - <h3 id=\"use\">Que faisons-nous avec vos données ?</h3> + <h3 id="use">Que faisons-nous avec vos données ?</h3> <p>Toute information que nous collectons pourra être utilisée d’une des manières suivantes :</p> @@ -542,11 +540,11 @@ fr: <li>Afin d’envoyer des courriels à intervalles réguliers — l’adresse électronique que vous renseignez peut être utilisée pour vous envoyer des données et notifications concernant des changements ou en réponse à votre nom d’utilisateur⋅ice, en réponse à vos demandes et/ou autres requêtes ou questions</li> </ul> - <h3 id=\"protect\">Comment protégeons-nous vos données ?</h3> + <h3 id="protect">Comment protégeons-nous vos données ?</h3> <p>Nous appliquons une multitude de mesures afin de maintenir la sécurité de vos données personnelles lorsque vous entrez, soumettez, ou accédez à ces dernières.</p> - <h3 id=\"data-retention\">Quelle est notre politique de conservation des données ?</h3> + <h3 id="data-retention">Quelle est notre politique de conservation des données ?</h3> <p>Nous nous efforçons de :</p> @@ -555,39 +553,39 @@ fr: <li>ne pas conserver les adresses IP associées aux utilisateur⋅trices et leur contenu plus de 5 ans.</li> </ul> - <h3 id=\"cookies\">Utilisons-nous des « cookies » ?</h3> + <h3 id="cookies">Utilisons-nous des « cookies » ?</h3> <p>Oui. Les cookies sont de petits fichiers qu’un site ou prestataires de services transfèrent sur le disque dur de votre ordinateur par le biais de votre navigateur Web (si ce dernier le permet). Ces cookies permettent au site de reconnaître votre navigateur et, si vous disposez d’un compte, de l’associer à celui-ci.</p> <p>Nous utilisons les cookies pour enregistrer vos préférences pour de futures visites, compiler des données agrégées à propos du trafic et des interactions effectuées sur le site afin de proposer une meilleure expérience dans le futur. Nous pouvons contracter les services de tiers afin de nous aider à mieux comprendre les visiteurs de notre site. Ces tiers ont l’autorisation d’utiliser ces données seulement à des fins d’améliorations.</p> - <h3 id=\"disclose\">Divulguons-nous des données à des tiers ?</h3> + <h3 id="disclose">Divulguons-nous des données à des tiers ?</h3> <p>Nous n’échangeons pas, ne vendons pas ni effectuons de quelconques transferts avec des tiers d’informations permettant de vous identifier personnellement. Cela n’inclut pas les tiers de confiance qui nous aident à gérer notre entreprise et à vous servir tant que ces tiers s’accordent à garder lesdites informations confidentielles. Nous pouvons être amenés à délivrer vos informations lorsque jugé adéquat afin de respecter la loi, d’appliquer la politique de notre site, ou afin de protéger nos droits, ceux des autres, notre propriété ou sécurité. Cependant, aucune information permettant l’identification de nos visiteur⋅euse⋅s ne sera divulguée à des fins publicitaires, commerciales ou tout autre usage.</p> - <h3 id=\"third-party\">Liens vers des tiers</h3> + <h3 id="third-party">Liens vers des tiers</h3> <p>Nous pouvons être amenés à inclure ou offrir les services ou produits de tiers sur notre site. Ces tiers possèdent leur propre politique de confidentialité. Nous ne sommes donc pas responsables du contenu ou activités desdits tiers. Néanmoins, nous cherchons à protéger l’intégrité de notre site et sommes ouverts à toute remarque concernant ces tiers.</p> - <h3 id=\"coppa\" lang=\"en\">Children's Online Privacy Protection Act</h3> + <h3 id="coppa" lang="en">Children's Online Privacy Protection Act</h3> - <p>Notre site, nos produits et services sont tous destinés à l’usage de personnes âgées de 13 ans ou plus. Si ce serveur est hébergé aux États-Unis et que vous êtes âgé⋅e de moins de 13 ans, au vu du COPPA (<a href=\"https://fr.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\"><i lang=\"en\">Children's Online Privacy Protection Act</i></a>) n’utilisez pas ce site.</p> + <p>Notre site, nos produits et services sont tous destinés à l’usage de personnes âgées de 13 ans ou plus. Si ce serveur est hébergé aux États-Unis et que vous êtes âgé⋅e de moins de 13 ans, au vu du COPPA (<a href="https://fr.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act"><i lang="en">Children's Online Privacy Protection Act</i></a>) n’utilisez pas ce site.</p> <h3 id="online">Politique de confidentialité en ligne</h3> <p>Cette politique de confidentialité en ligne s'applique uniquement aux informations collectées par le biais de notre site et non aux informations collectées hors ligne.</p> - <h3 id=\"consent\">Votre consentement</h3> + <h3 id="consent">Votre consentement</h3> <p>En utilisant notre site, vous consentez à la présente politique de confidentialité.</p> - <h3 id=\"changes\">Changements de notre politique de confidentialité</h3> + <h3 id="changes">Changements de notre politique de confidentialité</h3> <p>Si nous décidons d’apporter des changements à notre politique de confidentialité, nous les publierons sur cette page.</p> <p>Ce document est distribué sous licence CC-BY-SA. Il a été mis à jour pour la dernière fois le 31 mai 2013. Il a été traduit en français en juillet 2017.</p> - <p>Originellement adapté à partir de la politique de confidentialité de <a href=\"https://github.com/discourse/discourse\">Discourse</a>.</p> + <p>Originellement adapté à partir de la politique de confidentialité de <a href="https://github.com/discourse/discourse">Discourse</a>.</p> title: "%{instance} Conditions d’utilisations et politique de confidentialité" themes: default: Mastodon diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 35cec6b15..abf5f0ea4 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1,7 +1,7 @@ --- ko: about: - about_hashtag_html: <strong>#%{hashtag}</strong> 라는 해시태그가 붙은 공개 툿 입니다. 같은 연합에 속한 임의의 인스턴스에 계정을 생성하면 당신도 대화에 참여할 수 있습니다. + about_hashtag_html: "<strong>#%{hashtag}</strong> 라는 해시태그가 붙은 공개 툿 입니다. 같은 연합에 속한 임의의 인스턴스에 계정을 생성하면 당신도 대화에 참여할 수 있습니다." about_mastodon_html: Mastodon은 <em>오픈 소스 기반의</em> 소셜 네트워크 서비스 입니다. 상용 플랫폼의 대체로서 <em>분산형 구조</em>를 채택해, 여러분의 대화가 한 회사에 독점되는 것을 방지합니다. 신뢰할 수 있는 인스턴스를 선택하세요 — 어떤 인스턴스를 고르더라도, 누구와도 대화할 수 있습니다. 누구나 자신만의 Mastodon 인스턴스를 만들 수 있으며, 아주 매끄럽게 <em>소셜 네트워크</em>에 참가할 수 있습니다. about_this: 이 인스턴스에 대해서 closed_registrations: 현재 이 인스턴스에서는 신규 등록을 받고 있지 않습니다. diff --git a/config/locales/nl.yml b/config/locales/nl.yml index fa66d14ef..501ec013d 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1,8 +1,8 @@ --- nl: about: - about_mastodon_html: Mastodon is een <em>vrij, gratis en open-source</em> sociaal netwerk. Een <em>gedecentraliseerd</em> alternatief voor commerciële platforms. Het voorkomt de risico's van een enkel bedrijf dat jouw communicatie monopoliseert. Kies een server die je vertrouwt — welke je ook kiest, je kunt met elke andere server communiceren. Iedereen kan een eigen Mastodon-server draaien en naadloos deelnemen in het <em>sociale netwerk</em>. about_hashtag_html: Dit zijn openbare toots die getagged zijn met <strong>#%{hashtag}</strong>. Je kunt er op reageren of iets anders mee doen als je op Mastodon (of ergens anders in de fediverse) een account hebt. + about_mastodon_html: Mastodon is een <em>vrij, gratis en open-source</em> sociaal netwerk. Een <em>gedecentraliseerd</em> alternatief voor commerciële platforms. Het voorkomt de risico's van een enkel bedrijf dat jouw communicatie monopoliseert. Kies een server die je vertrouwt — welke je ook kiest, je kunt met elke andere server communiceren. Iedereen kan een eigen Mastodon-server draaien en naadloos deelnemen in het <em>sociale netwerk</em>. about_this: Over deze server closed_registrations: Registreren op deze server is momenteel uitgeschakeld. contact: Contact @@ -50,6 +50,13 @@ nl: admin: Beheerder unfollow: Ontvolgen admin: + account_moderation_notes: + account: Moderator + create: Aanmaken + created_at: Datum + created_msg: Aanmaken van opmerking voor moderatoren geslaagd! + delete: Verwijderen + destroyed_msg: Verwijderen van opmerking voor moderatoren geslaagd! accounts: are_you_sure: Weet je het zeker? confirm: Bevestigen @@ -110,15 +117,6 @@ nl: unsubscribe: Opzeggen username: Gebruikersnaam web: Webapp - - account_moderation_notes: - account: Moderator - created_at: Datum - create: Aanmaken - created_msg: Aanmaken van opmerking voor moderatoren geslaagd! - delete: Verwijderen - destroyed_msg: Verwijderen van opmerking voor moderatoren geslaagd! - custom_emojis: copied_msg: Lokale kopie van emoji maken geslaagd copy: Kopiëren diff --git a/config/locales/oc.yml b/config/locales/oc.yml index 2d72d247f..0d2a8c2f6 100644 --- a/config/locales/oc.yml +++ b/config/locales/oc.yml @@ -1,8 +1,8 @@ --- oc: about: - about_mastodon_html: Mastodon es un malhum social bastit amb de protocòls liures e gratuits. Es descentralizat coma los corrièls. about_hashtag_html: Vaquí los estatuts publics ligats a <strong>#%{hashtag}</strong>. Podètz interagir amb eles s’avètz un compte ont que siasque sul fediverse. + about_mastodon_html: Mastodon es un malhum social bastit amb de protocòls liures e gratuits. Es descentralizat coma los corrièls. about_this: A prepaus d’aquesta instància closed_registrations: Las inscripcions son clavadas pel moment sus aquesta instància. contact: Contacte @@ -50,6 +50,13 @@ oc: admin: Admin unfollow: Quitar de sègre admin: + account_moderation_notes: + account: Moderator + create: Crear + created_at: Data + created_msg: Nòta de moderacion ben creada ! + delete: Suprimir + destroyed_msg: Nòta de moderacion ben suprimida ! accounts: are_you_sure: Sètz segur ? confirm: Confirmar @@ -110,19 +117,10 @@ oc: unsubscribe: Se desabonar username: Nom d’utilizaire web: Web - - account_moderation_notes: - account: Moderator - created_at: Data - create: Crear - created_msg: Nòta de moderacion ben creada ! - delete: Suprimir - destroyed_msg: Nòta de moderacion ben suprimida ! - custom_emojis: - copied_msg: Còpia locale de l’emoji ben creada + copied_msg: Còpia locala de l’emoji ben creada copy: Copiar - copy_failed_msg: Fracàs de la còpia locale de l’emoji + copy_failed_msg: Fracàs de la còpia locala de l’emoji created_msg: Emoji ben creat ! delete: Suprimir destroyed_msg: Emojo ben suprimit ! @@ -171,15 +169,15 @@ oc: title: Blòc de domeni undo: Restablir email_domain_blocks: - add_new: Ajustar - created_msg: Blocatge del domeni de corrièl ben plaçat - delete: Suprimir - destroyed_msg: Blocatge del domeni de corrièl ben levat - domain: Domeni - new: - create: Crear un blocatge - title: Nòu blocatge de domeni de corrièl - title: Blocatge de domeni de corrièl + add_new: Ajustar + created_msg: Blocatge del domeni de corrièl ben plaçat + delete: Suprimir + destroyed_msg: Blocatge del domeni de corrièl ben levat + domain: Domeni + new: + create: Crear un blocatge + title: Nòu blocatge de domeni de corrièl + title: Blocatge de domeni de corrièl instances: account_count: Comptes coneguts domain_name: Domeni diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 8e2a9780c..c58c1c2f8 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -1,8 +1,8 @@ --- pl: about: - about_mastodon_html: Mastodon jest wolną i otwartą siecią społecznościową, zdecentralizowaną alternatywą dla zamkniętych, komercyjnych platform. about_hashtag_html: Znajdują się tu publiczne wpisy oznaczone hashtagiem <strong>#%{hashtag}</strong>. Możesz dołączyć do dyskusji, jeżeli posiadasz konto gdziekolwiek w Fediwersum. + about_mastodon_html: Mastodon jest wolną i otwartą siecią społecznościową, zdecentralizowaną alternatywą dla zamkniętych, komercyjnych platform. about_this: O tej instancji closed_registrations: Rejestracja na tej instancji jest obecnie zamknięta. Możesz jednak zarejestrować się na innej instancji, uzyskując dostęp do tej samej sieci. contact: Kontakt @@ -50,6 +50,13 @@ pl: admin: Administrator unfollow: Przestań śledzić admin: + account_moderation_notes: + account: Autor + create: Dodaj + created_at: Data + created_msg: Pomyślnie dodano notatkę moderacyjną! + delete: Usuń + destroyed_msg: Pomyślnie usunięto notatkę moderacyjną! accounts: are_you_sure: Jesteś tego pewien? confirm: Potwierdź @@ -110,13 +117,6 @@ pl: unsubscribe: Przestań subskrybować username: Nazwa użytkownika web: Sieć - account_moderation_notes: - account: Autor - created_at: Data - create: Dodaj - created_msg: Pomyślnie dodano notatkę moderacyjną! - delete: Usuń - destroyed_msg: Pomyślnie usunięto notatkę moderacyjną! custom_emojis: copied_msg: Pomyślnie utworzono lokalną kopię emoji copy: Kopiuj diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 060fd3112..4b9ea152f 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -1,8 +1,8 @@ --- pt-BR: about: - about_mastodon_html: Mastodon é uma rede social baseada em protocolos abertos e software gratuito e de código aberto. É descentralizada como e-mail. about_hashtag_html: Estes são toots públicos com a hashtag <strong>#%{hashtag}</strong>. Voce pode interagir com eles se tiver uma conta em qualquer lugar no fediverso. + about_mastodon_html: Mastodon é uma rede social baseada em protocolos abertos e software gratuito e de código aberto. É descentralizada como e-mail. about_this: Sobre closed_registrations: Cadastros estão atualmente fechados nesta instância. No entanto! Você pode procurar uma instância diferente na qual possa criar uma conta e acessar a mesma rede por lá. contact: Contato @@ -11,7 +11,7 @@ pt-BR: description_headline: O que é %{domain}? domain_count_after: outras instâncias domain_count_before: Conectado a - extended_description_html: + extended_description_html: | <h3>Um bom lugar para regras</h3> <p>A descrição da instância ainda não foi feita.</p> features: @@ -50,6 +50,13 @@ pt-BR: admin: Administrador unfollow: Deixar de seguir admin: + account_moderation_notes: + account: Moderador + create: Criar + created_at: Data + created_msg: Nota de moderação criada com sucesso! + delete: Excluir + destroyed_msg: Nota de moderação excluída com sucesso! accounts: are_you_sure: Você tem certeza? confirm: Confirmar @@ -110,15 +117,6 @@ pt-BR: unsubscribe: Desinscrever-se username: Nome de usuário web: Web - - account_moderation_notes: - account: Moderador - created_at: Data - create: Criar - created_msg: Nota de moderação criada com sucesso! - delete: Excluir - destroyed_msg: Nota de moderação excluída com sucesso! - custom_emojis: copied_msg: Cópia local do emoji criada com sucesso! copy: Copiar @@ -520,7 +518,7 @@ pt-BR: reblogged: compartilhado sensitive_content: Conteúdo sensível terms: - body_html: + body_html: | <h2>Política de privacidade</h2> <h3 id="collect">Que informações nós coletamos?</h3> diff --git a/config/locales/simple_form.de.yml b/config/locales/simple_form.de.yml index 4064aa5f2..9933093ca 100644 --- a/config/locales/simple_form.de.yml +++ b/config/locales/simple_form.de.yml @@ -44,6 +44,7 @@ de: setting_default_sensitive: Medien immer als heikel markieren setting_delete_modal: Bestätigungsdialog anzeigen, bevor ein Beitrag gelöscht wird setting_noindex: Suchmaschinen-Indexierung verhindern + setting_reduce_motion: Bewegung in Animationen verringern setting_system_font_ui: Standardschriftart des Systems verwenden setting_theme: Theme der Website setting_unfollow_modal: Bestätigungsdialog anzeigen, bevor jemand entfolgt wird diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 86c80290c..aafae48ce 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -44,6 +44,7 @@ en: setting_default_sensitive: Always mark media as sensitive setting_delete_modal: Show confirmation dialog before deleting a toot setting_noindex: Opt-out of search engine indexing + setting_reduce_motion: Reduce motion in animations setting_system_font_ui: Use system's default font setting_theme: Site theme setting_unfollow_modal: Show confirmation dialog before unfollowing someone diff --git a/config/locales/simple_form.fr.yml b/config/locales/simple_form.fr.yml index 40fed9675..06ab018a7 100644 --- a/config/locales/simple_form.fr.yml +++ b/config/locales/simple_form.fr.yml @@ -44,6 +44,7 @@ fr: setting_default_sensitive: Toujours marquer les médias comme sensibles setting_delete_modal: Afficher une fenêtre de confirmation avant de supprimer un pouet setting_noindex: Demander aux moteurs de recherche de ne pas indexer vos informations personnelles + setting_reduce_motion: Réduire la vitesse des animations setting_system_font_ui: Utiliser la police par défaut du système setting_theme: Thème du site setting_unfollow_modal: Afficher une fenêtre de confirmation avant de vous désabonner d’un compte diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index c889a882e..993eae706 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -40,6 +40,7 @@ ja: setting_default_sensitive: メディアを常に閲覧注意としてマークする setting_delete_modal: トゥートを削除する前に確認ダイアログを表示する setting_noindex: 検索エンジンによるインデックスを拒否する + setting_reduce_motion: アニメーションの動きを減らす setting_system_font_ui: システムのデフォルトフォントを使う setting_theme: サイトテーマ setting_unfollow_modal: フォロー解除する前に確認ダイアログを表示する diff --git a/config/locales/simple_form.nl.yml b/config/locales/simple_form.nl.yml index fabb5840a..5637bd848 100644 --- a/config/locales/simple_form.nl.yml +++ b/config/locales/simple_form.nl.yml @@ -4,13 +4,17 @@ nl: hints: defaults: avatar: PNG, GIF of JPG. Maximaal 2MB. Wordt teruggeschaald naar 120x120px - display_name: Maximaal 30 tekens + digest: Wordt na een lange periode van inactiviteit verzonden, met een samenvatting van vermeldingen tijdens je afwezigheid. + display_name: + one: <span class="name-counter">1</span> teken over + other: <span class="name-counter">%{count}</span> tekens over header: PNG, GIF of JPG. Maximaal 2MB. Wordt teruggeschaald naar 700x335px locked: Vereist dat je handmatig volgers moet accepteren en stelt de privacy van toots standaard in op alleen volgers note: one: <span class="note-counter">1</span> teken over other: <span class="note-counter">%{count}</span> tekens over setting_noindex: Heeft invloed op jouw openbare profiel en toots + setting_theme: Heeft invloed op hoe de webapp van Mastodon er uit ziet, op elk apparaat waarmee je inlogt. imports: data: CSV-bestand dat op een andere Mastodon-server werd geëxporteerd sessions: @@ -40,6 +44,7 @@ nl: setting_default_sensitive: Media altijd als gevoelig markeren setting_delete_modal: Vraag voor het verwijderen van een toot een bevestiging setting_noindex: Jouw toots niet door zoekmachines laten indexeren + setting_reduce_motion: Langzamere animaties setting_system_font_ui: Standaardlettertype van jouw systeem gebruiken setting_unfollow_modal: Vraag voor het ontvolgen van iemand een bevestiging type: Importtype diff --git a/config/locales/simple_form.oc.yml b/config/locales/simple_form.oc.yml index d45f98e66..d43c0d7eb 100644 --- a/config/locales/simple_form.oc.yml +++ b/config/locales/simple_form.oc.yml @@ -43,6 +43,7 @@ oc: setting_default_sensitive: Totjorn marcar los mèdias coma sensibles setting_delete_modal: Afichar una fenèstra de confirmacion abans de suprimir un estatut setting_noindex: Èsser pas indexat pels motors de recèrca + setting_reduce_motion: Reduire la velocitat de las animacions setting_system_font_ui: Utilizar la policia Font del sisèma setting_theme: Tèma del site setting_unfollow_modal: Afichar una confirmacion abans de quitar de sègre qualqu’un diff --git a/config/locales/simple_form.pl.yml b/config/locales/simple_form.pl.yml index e5d408973..68f84d109 100644 --- a/config/locales/simple_form.pl.yml +++ b/config/locales/simple_form.pl.yml @@ -48,6 +48,7 @@ pl: setting_default_sensitive: Zawsze oznaczaj zawartość multimedialną jako wrażliwą setting_delete_modal: Pytaj o potwierdzenie przed usunięciem wpisu setting_noindex: Nie indeksuj mojego profilu w wyszukiwarkach internetowych + setting_reduce_motion: Ogranicz ruch w animacjach setting_system_font_ui: Używaj domyślnej czcionki systemu setting_theme: Motyw strony setting_unfollow_modal: Pytaj o potwierdzenie przed cofnięciem śledzenia diff --git a/config/locales/simple_form.sv.yml b/config/locales/simple_form.sv.yml new file mode 100644 index 000000000..ca5771085 --- /dev/null +++ b/config/locales/simple_form.sv.yml @@ -0,0 +1,67 @@ +--- +sv: + simple_form: + hints: + defaults: + avatar: Högst 2 MB. Kommer nedskalas till 120x120px + digest: Skickas efter en lång period av inaktivitet med en sammanfattning av anmärkningar du har fått under din frånvaro + display_name: + one: <span class="name-counter">1</span> tecken kvar + other: <span class="name-counter">%{count}</span> tecken kvar + header: NG, GIF eller JPG. Högst 2 MB. Kommer nedskalas till 700x335px + locked: Kräver dig att manuellt godkänna följare + note: + one: <span class="note-counter">1</span> tecken kvar + other: <span class="note-counter">%{count}</span> tecken kvar + setting_noindex: Påverkar din offentliga profil och status sidor + setting_theme: Påverkar hur Mastodon ser ut när du är inloggad från vilken enhet som helst. + imports: + data: CSV-fil som exporteras från en annan Mastodon-instans + sessions: + otp: Ange tvåfaktorkoden från din telefon eller använd någon av dina återställningskoder. + user: + filtered_languages: Kontrollerade språk filtreras från offentliga tidslinjer för dig + labels: + defaults: + avatar: Avatar + confirm_new_password: Bekräfta nytt lösenord + confirm_password: Bekräfta lösenord + current_password: Nuvarande lösenord + data: Data + display_name: Visningsnamn + email: E-postadress + filtered_languages: Filtrerade språk + header: Rubrik + locale: Språk + locked: Lås konto + new_password: Nytt lösenord + note: Biografi + otp_attempt: Tvåfaktorkod + password: Lösenord + setting_auto_play_gif: Auto-play animerade GIF-filer + setting_boost_modal: Visa bekräftelsedialog innan du knuffar + setting_default_privacy: Postintegritet + setting_default_sensitive: Markera alltid media som känsligt + setting_delete_modal: Visa bekräftelse innan du raderar en toot + setting_noindex: Uteslutning av sökmotorindexering + setting_system_font_ui: Använd systemets standardfont + setting_theme: Sidans tema + setting_unfollow_modal: Visa bekräftelse innan du slutar följa någon + severity: Strikthet + type: Importtyp + username: Användarnamn + interactions: + must_be_follower: Blockera meddelanden från icke-följare + must_be_following: Blockera meddelanden från personer du inte följer + notification_emails: + digest: Skicka sammandrag via e-post + favourite: Skicka e-post när någon favoriterar din status + follow: Skicka e-post när någon följer dig + follow_request: Skicka e-post när någon begär att följa dig + mention: Skicka e-post när någon nämner dig + reblog: Skicka e-post när någon knuffar din status + 'no': Nej + required: + mark: "*" + text: obligatorisk + 'yes': Ja diff --git a/config/locales/sv.yml b/config/locales/sv.yml new file mode 100644 index 000000000..260b44666 --- /dev/null +++ b/config/locales/sv.yml @@ -0,0 +1,614 @@ +--- +sv: + about: + about_hashtag_html: Dessa är offentliga toots märkta med <strong>#%{hashtag}</strong>. Du kan interagera med dem om du har ett konto någonstans i federationen. + about_mastodon_html: Mastodon är ett socialt nätverk baserat på öppna webbprotokoll och gratis, öppen källkodsprogramvara. Det är decentraliserat som e-post + about_this: Om + closed_registrations: Registreringar är för närvarande stängda i denna instans. Dock så kan du hitta en annan instans för att skapa ett konto och få tillgång till samma nätverk från det. + contact: Kontakt + contact_missing: Inte inställd + contact_unavailable: N/A + description_headline: Vad är %{domain}? + domain_count_after: annan instans + domain_count_before: Uppkopplad mot + extended_description_html: | + <h3>En bra plats för regler</h3> + <p>Den utökade beskrivningen har inte konfigurerats ännu.</p> + features: + humane_approach_body: Mastodon, har lärt sig från tidigare misslyckanden i andra nätverk och syftar till att göra etiska designval i Mastodon för att bekämpa missbruk av sociala medier. + humane_approach_title: En mer human inställning + not_a_product_body: Mastodon är inte ett kommersiellt nätverk. Ingen reklam, ingen datautvinning, inga muromgärdade trädgårdar. Det finns ingen central myndighet. + not_a_product_title: Du är en person, inte en produkt + real_conversation_body: Med 500 tecken till ditt förfogande och stöd för granulärt innehåll och mediavarningar så kan du uttrycka dig själv, som du vill. + real_conversation_title: Byggd för riktiga konversationer + within_reach_body: Flera appar för iOS, Android och andra plattformar tack vare ett utvecklingsvänligt API-ekosystem gör att du kan hålla kontakten med dina vänner var som helst. + within_reach_title: Alltid inom räckhåll + find_another_instance: Hitta en annan instans + generic_description: "%{domain} är en server i nätverket" + hosted_on: Mastodon värd på %{domain} + learn_more: Lär dig mer + other_instances: Instanslista + source_code: Källkod + status_count_after: statusar + status_count_before: Vem författade + user_count_after: användare + user_count_before: Hem till + what_is_mastodon: Vad är Mastodon? + accounts: + follow: Följa + followers: Följare + following: Följer + media: Media + nothing_here: Det finns inget här! + people_followed_by: Personer som %{name} följer + people_who_follow: Personer som följer %{name} + posts: Toots + posts_with_replies: Toots med svar + remote_follow: Avlägsen följare + reserved_username: Användarnamnet är reserverat + roles: + admin: Admin + unfollow: Sluta följa + admin: + account_moderation_notes: + account: Moderator + create: Skapa + created_at: Datum + created_msg: Modereringsnotering skapad utan problem! + delete: Ta bort + destroyed_msg: Modereringsnotering borttagen utan problem! + accounts: + are_you_sure: Är du säker? + confirm: Bekräfta + confirmed: Bekräftad + disable_two_factor_authentication: Inaktivera 2FA + display_name: Visningsnamn + domain: Domän + edit: Redigera + email: E-post + feed_url: Feed URL + followers: Följare + followers_url: Följare URL + follows: Följs + inbox_url: Inbox URL + ip: IP + location: + all: Alla + local: Lokal + remote: Avlägsen + title: Plats + media_attachments: Media bifogade filer + moderation: + all: Alla + silenced: Tystas + suspended: Avstängd + title: Moderering + moderation_notes: Moderation anteckning + most_recent_activity: Senaste aktivitet + most_recent_ip: Senaste IP + not_subscribed: Inte prenumererat + order: + alphabetic: Alfabetiskt + most_recent: Senaste + title: Ordning + outbox_url: Utkorg URL + perform_full_suspension: Utför full avstängning + profile_url: Profil URL + protocol: Protokoll + public: Offentlig + push_subscription_expires: PuSH-prenumerationen löper ut + redownload: Uppdatera avatar + reset: Återställ + reset_password: Återställ lösenord + resubscribe: Starta en ny prenumeration + salmon_url: Lax URL + search: Sök + shared_inbox_url: Delad inkorg URL + show: + created_reports: Rapporter som skapats av det här kontot + report: rapport + targeted_reports: Rapporter gjorda om detta konto + silence: Tystnad + statuses: Status + subscribe: Prenumerera + title: Konton + undo_silenced: Ångra tystnad + undo_suspension: Ångra avstängning + unsubscribe: Säga upp + username: Användarnamn + web: Webb + custom_emojis: + copied_msg: Skapade en lokal kopia av emoji utan problem + copy: Kopia + copy_failed_msg: Kunde inte skapa en lokal kopia av den emoji + created_msg: Emoji skapades utan problem! + delete: Ta bort + destroyed_msg: Emojo borttagen utan problem! + disable: Inaktivera + disabled_msg: Inaktiverade emoji utan problem + emoji: Emoji + enable: Aktivera + enabled_msg: Aktiverade den emoji utan problem + image_hint: PNG upp till 50KB + new: + title: Lägg till ny egen emoji + shortcode: Kortkod + shortcode_hint: Minst 2 tecken, endast alfanumeriska tecken och understreck + title: Custom emojis + upload: Ladda upp + domain_blocks: + add_new: Lägg till ny + created_msg: Domänblocket behandlas nu + destroyed_msg: Domänblocket är ogjord + domain: Domän + new: + create: Skapa block + hint: Domänblocket hindrar inte skapandet av kontoposter i databasen, men kommer retroaktivt, automatiskt att tillämpa specifika modereringsmetoder på dessa konton. + severity: + desc_html: "<strong>Tystnad</strong> kommer att göra kontoinlägg osynliga för alla som inte följer dem. <strong>Suspendera</strong> tar bort allt kontons innehåll, media och profildata. Använd <strong>Ingen</strong> om du bara vill avvisa mediefiler." + noop: Ingen + silence: Tystnad + suspend: Suspendera + title: Nytt domänblock + reject_media: Avvisa mediafiler + reject_media_hint: Ta bort lokalt lagrade mediefiler och tar bort möjligheten att ladda ner något i framtiden. Irrelevant för suspensioner + severities: + noop: Ingen + silence: Tystnad + suspend: Suspendera + severity: Svårighet + show: + affected_accounts: + one: Ett konto i databasen drabbades + other: "%{count} konton i databasen drabbades" + retroactive: + silence: Ta bort tystnad från alla befintliga konton från den här domänen + suspend: Ta bort suspendering från alla befintliga konton i den här domänen + title: Ångra domänblockering för %{domain} + undo: Ångra + title: Domänblockering + undo: Ångra + email_domain_blocks: + add_new: Lägg till ny + created_msg: E-postdomänblocket har skapats + delete: Ta bort + destroyed_msg: E-postdomänblocket har tagits bort + domain: Domän + new: + create: Skapa block + title: Nytt E-postdomänblock + title: E-postdomänblock + instances: + account_count: Kända konton + domain_name: Domän + reset: Återställa + search: Sök + title: Kända instanser + reports: + action_taken_by: Åtgärder vidtagna av + are_you_sure: Är du säker? + comment: + label: Kommentar + none: Ingen + delete: Ta bort + id: ID + mark_as_resolved: Markera som löst + nsfw: + 'false': Visa bifogade mediafiler + 'true': Dölj bifogade mediafiler + report: 'Rapportera #%{id}' + report_contents: Innehåll + reported_account: Rapporterat konto + reported_by: Rapporterad av + resolved: Löst + silence_account: Tystat konto + status: Status + suspend_account: Suspenderat konto + target: Mål + title: Rapporter + unresolved: Olösta + view: Granska + settings: + bootstrap_timeline_accounts: + desc_html: Separera flera användarnamn med kommatecken. Endast lokala och olåsta konton kommer att fungera. Standard när det är tomt och alla är lokala administratörer. + title: Standard att följa för nya användare + contact_information: + email: Företag E-post + username: Kontakten användarnamn + registrations: + closed_message: + desc_html: Visas på framsidan när registreringen är stängd. Du kan använda HTML-taggar + title: Stängt registreringsmeddelande + deletion: + desc_html: Tillåt alla att ta bort sitt konto + title: Open account deletion + open: + desc_html: Tillåt alla att skapa ett konto + title: Öppen registrering + site_description: + desc_html: Inledande stycke på framsidan och i metataggar. Du kan använda HTML-taggar, i synnerhet <code><a></code> och <code><em></code>. + title: Instansbeskrivning + site_description_extended: + desc_html: Ett bra ställe för din uppförandekod, regler, riktlinjer och andra saker som stämmer med din instans. Du kan använda HTML-taggar + title: Custom utökad information + site_terms: + desc_html: Du kan skriva din egen integritetspolicy, användarvillkor eller andra regler. Du kan använda HTML-taggar + title: Custom Villkor för tjänster + site_title: Namn på instans + thumbnail: + desc_html: Används för förhandsgranskningar via OpenGraph och API. 1200x630px rekommenderas + title: Instans tumnagelbild + timeline_preview: + desc_html: Visa offentlig tidslinje på landingsidan + title: Förhandsgranska tidslinje + title: Sidans inställningar + statuses: + back_to_account: Tillbaka till kontosidan + batch: + delete: Ta bort + nsfw_off: NSFW AV + nsfw_on: NSFW PÅ + execute: Kör + failed_to_execute: Misslyckades att köra + media: + hide: Dölj media + show: Visa media + title: Media + no_media: Ingen media + title: Kontostatus + with_media: med media + subscriptions: + callback_url: Återanrop URL + confirmed: Bekräftad + expires_in: Går ut om + last_delivery: Sista leverans + title: WebSub + topic: Ämne + title: Administration + admin_mailer: + new_report: + body: "%{reporter} har rapporterat %{target}" + subject: Ny rapport för %{instance} (#%{id}) + application_mailer: + salutation: "%{name}," + settings: 'Change e-mail preferences: %{link}' + signature: Mastodon meddelande från %{instance} + view: 'Granska:' + applications: + created: Ansökan är framgångsrikt skapad + destroyed: Ansökan är framgångsrikt borttagen + invalid_url: Den angivna webbadressen är ogiltig + regenerate_token: Regenerera access token + token_regenerated: Access token lyckades regenereras + warning: Var mycket försiktig med denna data. Dela aldrig den med någon! + your_token: Din access token + auth: + agreement_html: Genom att registrera dig godkänner du <a href="%{rules_path}">våra användarvillkor</a> och <a href="%{terms_path}">sekretesspolicy</a>. + change_password: Säkerhet + delete_account: Ta bort konto + delete_account_html: Om du vill radera ditt konto kan du <a href="%{path}">fortsätta här</a>. Du kommer att bli ombedd att bekräfta. + didnt_get_confirmation: Fick inte instruktioner om bekräftelse? + forgot_password: Glömt ditt lösenord? + invalid_reset_password_token: Lösenordsåterställningstoken är ogiltig eller utgått. Vänligen be om en ny. + login: Logga in + logout: Logga ut + register: Registrera + resend_confirmation: Skicka instruktionerna om bekräftelse igen + reset_password: Återställ lösenord + set_new_password: Skriv in nytt lösenord + authorize_follow: + error: Tyvärr inträffade ett fel när vi kontrollerade fjärrkontot + follow: Följ + follow_request: 'Du har skickat en följaförfrågan till:' + following: 'Succé! Du följer nu:' + post_follow: + close: Eller så kan du stänga detta fönster. + return: Återgå till användarens profil + web: Gå till webb + title: Följ %{acct} + datetime: + distance_in_words: + about_x_hours: "%{count}tim" + about_x_months: "%{count}mån" + about_x_years: "%{count}år" + almost_x_years: "%{count}år" + half_a_minute: Just nu + less_than_x_minutes: "%{count}min" + less_than_x_seconds: Just nu + over_x_years: "%{count}år" + x_days: "%{count}d" + x_minutes: "%{count}min" + x_months: "%{count}mån" + x_seconds: "%{count}sek" + deletes: + bad_password_msg: Bra försök, hackare! Fel lösenord + confirm_password: Ange ditt lösenord för att verifiera din identitet + description_html: Detta vill <strong>permanent, irreversibelt</strong> ta bort innehåll från ditt konto och avaktivera det. Ditt användarnamn kommer att förbli reserverat för att förhindra framtida efterföljare. + proceed: Ta bort konto + success_msg: Ditt konto har tagits bort + warning_html: Endast borttagning av innehåll från denna speciella instans garanteras. Innehåll som har delats i stor utsträckning kommer sannolikt att lämna spår. Offline-servrar och servrar som har avstängt från dina uppdateringar uppdaterar inte sina databaser. + warning_title: Spridet innehåll och tillgänglighet + errors: + '403': Du har inte behörighet att visa den här sidan. + '404': Sidan du letade efter existerar inte. + '410': Sidan du letade efter existerar inte längre. + '422': + content: Säkerhetsverifiering misslyckades Blockerar du cookies? + title: Säkerhetsverifiering misslyckades + '429': Strypt + '500': + content: Vi är ledsna, men något gick fel från vårat håll. + title: Den här sidan är inte korrekt + noscript_html: För att använda Mastodon webbapplikationen, vänligen aktivera JavaScript. Alternativt kan du prova en av <a href="https://github.com/tootsuite/documentation/blob/master/Using-Mastodon/Apps.md">inhemska appar</a> för Mastodon för din plattform. + exports: + blocks: Du blockerar + csv: CSV + follows: Du följer + mutes: Du tystar + storage: Media lagring + followers: + domain: Domän + explanation_html: Om du vill se integriteten för dina statusar måste du vara medveten om vem som följer dig. <strong>Dina privata statusar levereras till alla instanser där du har följare</strong>. Du kanske vill granska dem och ta bort följare om du inte litar på att din integritet respekteras av staff eller programvaran i instanserna. + followers_count: Antal följare + lock_link: Lås ditt konto + purge: Ta bort från följare + success: + one: I processen med soft-blocking följare från en domän ... + other: I processen med soft-blocking följare från %{count} domäner... + true_privacy_html: Kom ihåg att <strong>sann integritet kan bara uppnås med end-to-end kryptering</strong>. + unlocked_warning_html: Vem som helst kan följa dig omedelbart se dina privata statusar. %{lock_link} för att kunna granska och avvisa följare. + unlocked_warning_title: Ditt konto är inte låst + generic: + changes_saved_msg: Ändringar sparades framgångsrikt! + powered_by: powered by %{link} + save_changes: Spara ändringar + validation_errors: + one: Något är inte riktigt rätt ännu! Kontrollera felet nedan + other: Något är inte riktigt rätt ännu! Kontrollera dom %{count} felen nedan + imports: + preface: Du kan importera data som du exporterat från en annan instans, till exempel en lista över personer du följer eller blockerar. + success: Dina uppgifter har laddats upp och kommer nu att behandlas snarast + types: + blocking: Blockering lista + following: Följare lista + muting: Tystade lista + upload: Ladda upp + landing_strip_html: "<strong>%{name}</strong> är en användare på %{link_to_root_path}. Du kan följa dem eller interagera med dem om du har ett konto någonstans i federationen." + landing_strip_signup_html: Om du inte gör det, så kan du <a href="%{sign_up_path}">registrera dig här</a>. + media_attachments: + validations: + images_and_video: Det går inte att bifoga en video till en status som redan innehåller bilder + too_many: Det går inte att bifoga mer än 4 filer + notification_mailer: + digest: + body: 'Här är en kort sammanfattning av vad du missat på %{instance} sedan ditt senaste besök på %{since}:' + mention: "%{name} nämnde dig i:" + new_followers_summary: + one: Du har förvärvat en ny följare! Jippie! + other: Du har fått %{count} nya följare! Otroligt! + subject: + one: "1 nytt meddelande sedan ditt senaste besök \U0001F418" + other: "%{count} nya meddelanden sedan ditt senaste besök \U0001F418" + favourite: + body: 'Din status favoriserades av %{name}:' + subject: "%{name} favoriserade din status" + follow: + body: "%{name} följer nu dig!" + subject: "%{name} följer nu dig" + follow_request: + body: "%{name} har begärt att följa dig" + subject: 'Pending follower: %{name}' + mention: + body: 'Du nämndes av %{name} in:' + subject: Du nämndes av %{name} + reblog: + body: 'Din status boostades av %{name}:' + subject: "%{name} boostade din status" + number: + human: + decimal_units: + format: "%n%u" + units: + billion: B + million: M + quadrillion: Q + thousand: K + trillion: T + unit: '' + pagination: + next: Nästa + prev: Tidigare + truncate: "…" + preferences: + languages: Språk + other: Annat + publishing: Publicering + web: Webb + push_notifications: + favourite: + title: "%{name} favoriserade din status" + follow: + title: "%{name} följer nu dig" + group: + title: "%{count} meddelanden" + mention: + action_boost: Boosta + action_expand: Visa mer + action_favourite: Favoriter + title: "%{name} nämnde dig" + reblog: + title: "%{name} boostade din status" + remote_follow: + acct: Ange ditt användarnamn@domän du vill följa från + missing_resource: Det gick inte att hitta den begärda omdirigeringsadressen för ditt konto + proceed: Fortsätt för att följa + prompt: 'Du kommer att följa:' + sessions: + activity: Senaste aktivitet + browser: Webbläsare + browsers: + alipay: Alipay + blackberry: Blackberry + chrome: Chrome + edge: Microsoft Edge + firefox: Firefox + generic: Okänd browser + ie: Internet Explorer + micro_messenger: MicroMessenger + nokia: Nokia S40 Ovi Browser + opera: Opera + phantom_js: PhantomJS + qq: QQ Browser + safari: Safari + uc_browser: UCBrowser + weibo: Weibo + current_session: Nuvarande session + description: "%{browser} på %{platform}" + explanation: Detta är inloggade webbläsare på Mastodon just nu + ip: IP + platforms: + adobe_air: Adobe Air + android: Android + blackberry: Blackberry + chrome_os: ChromeOS + firefox_os: Firefox OS + ios: iOS + linux: Linux + mac: Mac + other: okänd plattform + windows: Windows + windows_mobile: Windows Mobile + windows_phone: Windows Phone + revoke: Återkalla + revoke_success: Sessionen återkallas framgångsrikt + title: Sessioner + settings: + authorized_apps: Godkända appar + back: Tillbaka till Mastodon + delete: Konto radering + development: Utveckling + edit_profile: Redigera profil + export: Data export + followers: Auktoriserade följare + import: Import + notifications: Meddelanden + preferences: Inställningar + settings: Inställningar + two_factor_authentication: Två-faktor autentisering + your_apps: Dina applikationer + statuses: + open_in_web: Öppna på webben + over_character_limit: teckengräns på %{max} har överskridits + pin_errors: + limit: För många tootar fästa + ownership: Någon annans toot kan inte fästas + private: Icke-offentliga toot kan inte fästas + reblog: En boost kan inte fästas + show_more: Visa mer + visibilities: + private: Endast följare + private_long: Visa endast till följare + public: Offentlig + public_long: Alla kan se + unlisted: Olistade + unlisted_long: Alla kan se, men inte listade på offentliga tidslinjer + stream_entries: + click_to_show: Klicka för att visa + pinned: Fäst toot + reblogged: boostad + sensitive_content: Känsligt innehåll + terms: + body_html: | + <h2>Integritetspolicy</h2> + + <h3 id="collect">Vilken information samlar vi in</h3> + + <p>Vi samlar in information från dig när du registrerar dig på vår webbplats och samlar in data när du deltar i forumet genom att läsa, skriva och utvärdera innehållet som delas här.</p> + + <p>När du registrerar dig på vår webbplats kan du bli ombedd att ange ditt namn och din e-postadress. Du kan dock besöka vår webbplats utan att registrera dig. Din e-postadress kommer att verifieras med ett e-postmeddelande som innehåller en unik länk. Om den länken besöks vet vi att du kontrollerar e-postadressen.</p> + + <p>När vi registrerar och postar registrerar vi den IP-adress som posten härstammar från. Vi kan också behålla serverns loggar som innehåller IP-adress för varje begäran till vår server.</p> + + <h3 id="use">Vad använder vi din information för?</h3> + + <p>Vilken som helst information vi samlar in från dig kan användas på något av följande sätt:</p> + + <ul> + <li>För att personifiera din upplevelse & mdash; Din information hjälper oss att bättre svara på dina individuella behov.</li> + <li>För att förbättra vår webbplats & mdash; Vi strävar kontinuerligt efter att förbättra våra erbjudanden på webbplatsen baserat på information och feedback vi mottar från dig.</li> + <li>För att förbättra kundtjänst & mdash; Din information hjälper oss att effektivt svara på dina kundserviceförfrågningar och supportbehov.</li> + <li>För att skicka periodiska e-postmeddelanden & mdash; Den e-postadress du anger kan användas för att skicka information, meddelanden som du begär om ändringar i ämnen eller som svar på ditt användarnamn, svara på förfrågningar och / eller andra förfrågningar eller frågor.</li> + </ul> + + <h3 id="protect">Hur skyddar vi din information?</h3> + + <p>Vi genomför en rad säkerhetsåtgärder för att upprätthålla säkerheten för din personliga information när du anger, lämnar in eller har tillgång till din personliga information.</p> + + <h3 id="data-retention">Vad är policyn för lagring av data?</h3> + + <p>Vi kommer att göra en ansträngning för:</p> + + <ul> + <li>Behåll serverloggar som innehåller IP-adressen för alla förfrågningar till den här servern inte mer än 90 dagar.</li> + <li>Behåll IP-adresserna i samband med registrerade användare och deras inlägg inte längre än 5 år.</li> + </ul> + + <h3 id="cookies">Använder vi cookies?</h3> + + <p>Ja. Cookies är små filer som en webbplats eller tjänstleverantör överför till datorns hårddisk via din webbläsare (om du tillåter). Dessa cookies tillåter webbplatsen att känna igen din webbläsare och, om du har ett registrerat konto, associerar det med ditt registrerade konto.</p> + + <p>Vi använder cookies för att förstå och spara dina inställningar för framtida besök och sammanställa sammanlagda data om webbplatsstrafik och webbplatsinteraktion så att vi kan erbjuda bättre sajtupplevelser och verktyg i framtiden. Vi kan komma överens med tredje parts tjänsteleverantörer för att hjälpa oss att bättre förstå våra besökare. Dessa tjänsteleverantörer får inte använda den information som samlas in för vår räkning utom för att hjälpa oss att bedriva och förbättra vår verksamhet.</p> + + <h3 id="disclose">Avslöjar vi information till utomstående parter?</h3> + + <p>Vi säljer inte, handlar eller på annat sätt överför dina personuppgifter till utomstående parter. Det här omfattar inte betrodda tredje parter som hjälper oss att driva vår webbplats, bedriva vår verksamhet eller service dig, så länge dessa parter är överens om att hålla denna information konfidentiell. Vi kan också släppa din information när vi anser att utgåvan är lämplig för att följa lagen, tillämpa vår webbplatspolicy eller skydda vår eller andra rättigheter, egendom eller säkerhet. Däremot kan personuppgifter som inte identifieras personligen lämnas till andra parter för marknadsföring, reklam eller annan användning.</p> + + <h3 id="third-party">Tredjepartslänkar</h3> + + <p>Ibland kan vi, efter eget gottfinnande, inkludera eller erbjuda produkter från tredje part eller tjänster på vår webbplats. Dessa tredje parts webbplatser har separata och oberoende sekretesspolicyer. Vi har därför inget ansvar eller ansvar för innehållet och aktiviteterna för dessa länkade webbplatser. Ändå försöker vi skydda integriteten på vår webbplats och välkomna eventuella återkopplingar om dessa webbplatser.</p> + + <h3 id="coppa">Children's Online Privacy Protection Act Compliance</h3> + + <p>Vår webbplats, produkter och tjänster riktas alla till personer som är minst 13 år gamla. Om den här servern är i USA, och du är under 13 år, enligt kraven i COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) ska du inte använda denna sida.</p> + + <h3 id="online">Endast online sekretesspolicy</h3> + + <p>Denna online sekretesspolicy gäller endast information som samlas in via vår webbplats och inte till information som samlas in offline.</p> + + <h3 id="consent">Ditt samtycke</h3> + + <p>Genom att använda vår webbplats godkänner du vår hemsida sekretesspolicy.</p> + + <h3 id="changes">Ändringar i vår sekretesspolicy</h3> + + <p>Om vi bestämmer oss för att ändra vår integritetspolicy, lägger vi in de ändringar på den här sidan.</p> + + <p>This document is CC-BY-SA. It was last updated May 31, 2013.</p> + + <p>Ursprungligen anpassad från <a href="https://github.com/discourse/discourse">Discourse integritetspolicy</a>.</p> + title: "%{instance} Användarvillkor och Sekretesspolicy" + themes: + default: Mastodon + time: + formats: + default: "%b %d, %Y, %H:%M" + two_factor_authentication: + code_hint: Ange koden som genererats av din autentiseringsapp för att bekräfta + description_html: Om du aktiverar <strong>tvåfaktors autentisering</strong>, loggar in kommer att kräva att du är i besittning av din telefon, vilket kommer att generera tokens för dig att uppge. + disable: Avaktivera + enable: Aktivera + enabled: Tvåfaktorsautentisering är aktiverad + enabled_success: Tvåfaktors autentisering aktiverad + generate_recovery_codes: Generera återställningskoder + instructions_html: "<strong>Skanna den här QR-koden i Google Authenticator eller en liknande TOTP-app på din telefon </strong>. Från och med nu genererar den appen tokens som du måste ange när du loggar in." + lost_recovery_codes: Återställningskoder tillåter dig att få tillgång till ditt konto om du förlorar din telefon. Om du har förlorat dina återställningskoder kan du regenerera dem här. Dina gamla återställningskoder kommer att ogiltigförklaras. + manual_instructions: 'Om du inte kan skanna QR-koden och behöver skriva in den manuellt, här är den enkla texten:' + recovery_codes: Backup återställningskod + recovery_codes_regenerated: Återställningskoder regenererades framgångsrikt + recovery_instructions_html: Om du någonsin tappar åtkomst till din telefon kan du använda någon av återställningskoderna nedan för att återställa åtkomst till ditt konto. <strong> Håll återställningskoderna säkra </strong>. Du kan till exempel skriva ut dem och lagra dem med andra viktiga dokument. + setup: Ställ in + wrong_code: Den angivna koden var ogiltig! Är servertid och enhetstid korrekt? + users: + invalid_email: E-postadressen är ogiltig + invalid_otp_token: Ogiltig tvåfaktorkod + signed_in_as: 'Inloggad som:' diff --git a/config/settings.yml b/config/settings.yml index 3cd3307f4..c03d0b766 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -22,6 +22,7 @@ defaults: &defaults boost_modal: false delete_modal: true auto_play_gif: false + reduce_motion: false system_font_ui: false noindex: false theme: 'default' diff --git a/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb b/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb index 5d15817bd..c10aa2c4f 100644 --- a/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb +++ b/db/migrate/20170920024819_status_ids_to_timestamp_ids.rb @@ -26,7 +26,7 @@ class StatusIdsToTimestampIds < ActiveRecord::Migration[5.1] SELECT setval('statuses_id_seq', (SELECT MAX(id) FROM statuses)); ALTER TABLE statuses ALTER COLUMN id - SET DEFAULT nextval('statuses_id_seq');" + SET DEFAULT nextval('statuses_id_seq'); SQL end end diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..50bde57e6 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,25 @@ +module.exports = { + projects: [ + '<rootDir>/app/javascript/mastodon', + ], + testPathIgnorePatterns: [ + '<rootDir>/node_modules/', + '<rootDir>/vendor/', + '<rootDir>/config/', + '<rootDir>/log/', + '<rootDir>/public/', + '<rootDir>/tmp/', + ], + setupFiles: [ + 'raf/polyfill', + ], + setupTestFrameworkScriptFile: '<rootDir>/app/javascript/mastodon/test_setup.js', + collectCoverageFrom: [ + 'app/javascript/mastodon/**/*.js', + '!app/javascript/mastodon/features/emoji/emoji_compressed.js', + '!app/javascript/mastodon/locales/locale-data/*.js', + '!app/javascript/mastodon/service_worker/entry.js', + '!app/javascript/mastodon/test_setup.js', + ], + coverageDirectory: '<rootDir>/coverage', +}; diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index 0f2fc5ac6..f10ace13e 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -21,7 +21,7 @@ module Mastodon end def flags - 'rc2' + '' end def to_a diff --git a/package.json b/package.json index 5dc2a9144..5856b56db 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "build:production": "cross-env RAILS_ENV=production ./bin/webpack", "manage:translations": "node ./config/webpack/translationRunner.js", "start": "node ./streaming/index.js", - "test": "npm run test:lint && npm run test:mocha", + "test": "npm run test:lint && npm run test:jest", "test:lint": "eslint -c .eslintrc.yml --ext=js app/javascript/ config/webpack/ spec/javascript/ streaming/", - "test:mocha": "cross-env NODE_ENV=test mocha --require ./spec/javascript/setup.js --compilers js:babel-register ./spec/javascript/components/**/*.test.js", + "test:jest": "cross-env NODE_ENV=test jest --coverage", "postinstall": "npm rebuild node-sass" }, "repository": { @@ -58,6 +58,7 @@ "immutable": "^3.8.1", "intersection-observer": "^0.4.0", "intl": "^1.2.5", + "intl-messageformat": "^2.1.0", "intl-relativeformat": "^2.0.0", "is-nan": "^1.2.1", "js-yaml": "^3.9.0", @@ -119,22 +120,37 @@ }, "devDependencies": { "babel-eslint": "^7.2.3", - "chai": "^4.1.0", - "chai-enzyme": "^0.8.0", "enzyme": "^3.0.0", "enzyme-adapter-react-16": "^1.0.0", "eslint": "^3.19.0", + "eslint-plugin-import": "^2.7.0", "eslint-plugin-jsx-a11y": "^4.0.0", "eslint-plugin-react": "^6.10.3", - "jsdom": "^11.1.0", - "mocha": "^3.4.1", + "jest": "^21.2.1", + "raf": "^3.4.0", "react-intl-translations-manager": "^5.0.0", "react-test-renderer": "^16.0.0", - "sinon": "^2.3.7", "webpack-dev-server": "^2.6.1", "yargs": "^8.0.2" }, "optionalDependencies": { "fsevents": "*" + }, + "jest": { + "projects": [ + "<rootDir>/app/javascript/mastodon" + ], + "testPathIgnorePatterns": [ + "<rootDir>/node_modules/", + "<rootDir>/vendor/", + "<rootDir>/config/", + "<rootDir>/log/", + "<rootDir>/public/", + "<rootDir>/tmp/" + ], + "setupFiles": [ + "raf/polyfill" + ], + "setupTestFrameworkScriptFile": "<rootDir>/app/javascript/mastodon/test_setup.js" } } diff --git a/spec/javascript/.eslintrc.yml b/spec/javascript/.eslintrc.yml deleted file mode 100644 index 6db2a46c5..000000000 --- a/spec/javascript/.eslintrc.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -env: - mocha: true diff --git a/spec/javascript/components/avatar.test.js b/spec/javascript/components/avatar.test.js deleted file mode 100644 index 34949f2b5..000000000 --- a/spec/javascript/components/avatar.test.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import Avatar from '../../../app/javascript/mastodon/components/avatar'; - -import { expect } from 'chai'; -import { render } from 'enzyme'; -import { fromJS } from 'immutable'; - -describe('<Avatar />', () => { - const account = fromJS({ - username: 'alice', - acct: 'alice', - display_name: 'Alice', - avatar: '/animated/alice.gif', - avatar_static: '/static/alice.jpg', - }); - - const size = 100; - const animated = render(<Avatar account={account} animate size={size} />); - const still = render(<Avatar account={account} size={size} />); - - // Autoplay - xit('renders a div element with the given src as background', () => { - expect(animated.find('div')).to.have.style('background-image', `url(${account.get('avatar')})`); - }); - - xit('renders a div element of the given size', () => { - ['width', 'height'].map((attr) => { - expect(animated.find('div')).to.have.style(attr, `${size}px`); - }); - }); - - // Still - xit('renders a div element with the given static src as background if not autoplay', () => { - expect(still.find('div')).to.have.style('background-image', `url(${account.get('avatar_static')})`); - }); - - xit('renders a div element of the given size if not autoplay', () => { - ['width', 'height'].map((attr) => { - expect(still.find('div')).to.have.style(attr, `${size}px`); - }); - }); - - // TODO add autoplay test if possible -}); diff --git a/spec/javascript/components/avatar_overlay.test.js b/spec/javascript/components/avatar_overlay.test.js deleted file mode 100644 index fe1d3a012..000000000 --- a/spec/javascript/components/avatar_overlay.test.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import AvatarOverlay from '../../../app/javascript/mastodon/components/avatar_overlay'; - -import { expect } from 'chai'; -import { render } from 'enzyme'; -import { fromJS } from 'immutable'; - -describe('<Avatar />', () => { - const account = fromJS({ - username: 'alice', - acct: 'alice', - display_name: 'Alice', - avatar: '/animated/alice.gif', - avatar_static: '/static/alice.jpg', - }); - - const friend = fromJS({ - username: 'eve', - acct: 'eve@blackhat.lair', - display_name: 'Evelyn', - avatar: '/animated/eve.gif', - avatar_static: '/static/eve.jpg', - }); - - const overlay = render(<AvatarOverlay account={account} friend={friend} />); - - xit('renders account static src as base of overlay avatar', () => { - expect(overlay.find('.account__avatar-overlay-base')) - .to.have.style('background-image', `url(${account.get('avatar_static')})`); - }); - - xit('renders friend static src as overlay of overlay avatar', () => { - expect(overlay.find('.account__avatar-overlay-overlay')) - .to.have.style('background-image', `url(${friend.get('avatar_static')})`); - }); -}); diff --git a/spec/javascript/components/button.test.js b/spec/javascript/components/button.test.js deleted file mode 100644 index d2cd0b4e7..000000000 --- a/spec/javascript/components/button.test.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import Button from '../../../app/javascript/mastodon/components/button'; - -import { expect } from 'chai'; -import { shallow } from 'enzyme'; -import sinon from 'sinon'; - -describe('<Button />', () => { - xit('renders a button element', () => { - const wrapper = shallow(<Button />); - expect(wrapper).to.match('button'); - }); - - xit('renders the given text', () => { - const text = 'foo'; - const wrapper = shallow(<Button text={text} />); - expect(wrapper.find('button')).to.have.text(text); - }); - - it('handles click events using the given handler', () => { - const handler = sinon.spy(); - const wrapper = shallow(<Button onClick={handler} />); - wrapper.find('button').simulate('click'); - expect(handler.calledOnce).to.equal(true); - }); - - it('does not handle click events if props.disabled given', () => { - const handler = sinon.spy(); - const wrapper = shallow(<Button onClick={handler} disabled />); - wrapper.find('button').simulate('click'); - expect(handler.called).to.equal(false); - }); - - xit('renders a disabled attribute if props.disabled given', () => { - const wrapper = shallow(<Button disabled />); - expect(wrapper.find('button')).to.be.disabled(); - }); - - xit('renders the children', () => { - const children = <p>children</p>; - const wrapper = shallow(<Button>{children}</Button>); - expect(wrapper.find('button')).to.contain(children); - }); - - xit('renders the props.text instead of children', () => { - const text = 'foo'; - const children = <p>children</p>; - const wrapper = shallow(<Button text={text}>{children}</Button>); - expect(wrapper.find('button')).to.have.text(text); - expect(wrapper.find('button')).to.not.contain(children); - }); - - xit('renders style="display: block; width: 100%;" if props.block given', () => { - const wrapper = shallow(<Button block />); - expect(wrapper.find('button')).to.have.className('button--block'); - }); - - xit('renders style="display: inline-block; width: auto;" by default', () => { - const wrapper = shallow(<Button />); - expect(wrapper.find('button')).to.not.have.className('button--block'); - }); - - xit('adds class "button-secondary" if props.secondary given', () => { - const wrapper = shallow(<Button secondary />); - expect(wrapper.find('button')).to.have.className('button-secondary'); - }); - - xit('does not add class "button-secondary" by default', () => { - const wrapper = shallow(<Button />); - expect(wrapper.find('button')).to.not.have.className('button-secondary'); - }); -}); diff --git a/spec/javascript/components/display_name.test.js b/spec/javascript/components/display_name.test.js deleted file mode 100644 index 97a111894..000000000 --- a/spec/javascript/components/display_name.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; -import DisplayName from '../../../app/javascript/mastodon/components/display_name'; - -import { expect } from 'chai'; -import { render } from 'enzyme'; -import { fromJS } from 'immutable'; - -describe('<DisplayName />', () => { - xit('renders display name + account name', () => { - const account = fromJS({ - username: 'bar', - acct: 'bar@baz', - display_name_html: '<p>Foo</p>', - }); - const wrapper = render(<DisplayName account={account} />); - expect(wrapper).to.have.text('Foo @bar@baz'); - }); -}); diff --git a/spec/javascript/components/emoji_index.test.js b/spec/javascript/components/emoji_index.test.js deleted file mode 100644 index cdb50cb8c..000000000 --- a/spec/javascript/components/emoji_index.test.js +++ /dev/null @@ -1,111 +0,0 @@ -import { expect } from 'chai'; -import { search } from '../../../app/javascript/mastodon/features/emoji/emoji_mart_search_light'; -import { emojiIndex } from 'emoji-mart'; -import { pick } from 'lodash'; - -const trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']); - -// hack to fix https://github.com/chaijs/type-detect/issues/98 -// see: https://github.com/chaijs/type-detect/issues/98#issuecomment-325010785 -import jsdom from 'jsdom'; -global.window = new jsdom.JSDOM().window; -global.document = window.document; -global.HTMLElement = window.HTMLElement; - -describe('emoji_index', () => { - - it('should give same result for emoji_index_light and emoji-mart', () => { - let expected = [{ - id: 'pineapple', - unified: '1f34d', - native: '🍍', - }]; - expect(search('pineapple').map(trimEmojis)).to.deep.equal(expected); - expect(emojiIndex.search('pineapple').map(trimEmojis)).to.deep.equal(expected); - }); - - it('orders search results correctly', () => { - let expected = [{ - id: 'apple', - unified: '1f34e', - native: '🍎', - }, { - id: 'pineapple', - unified: '1f34d', - native: '🍍', - }, { - id: 'green_apple', - unified: '1f34f', - native: '🍏', - }, { - id: 'iphone', - unified: '1f4f1', - native: '📱', - }]; - expect(search('apple').map(trimEmojis)).to.deep.equal(expected); - expect(emojiIndex.search('apple').map(trimEmojis)).to.deep.equal(expected); - }); - - it('handles custom emoji', () => { - let custom = [{ - id: 'mastodon', - name: 'mastodon', - short_names: ['mastodon'], - text: '', - emoticons: [], - keywords: ['mastodon'], - imageUrl: 'http://example.com', - custom: true, - }]; - search('', { custom }); - emojiIndex.search('', { custom }); - let expected = [ { id: 'mastodon', custom: true } ]; - expect(search('masto').map(trimEmojis)).to.deep.equal(expected); - expect(emojiIndex.search('masto').map(trimEmojis)).to.deep.equal(expected); - }); - - it('should filter only emojis we care about, exclude pineapple', () => { - let emojisToShowFilter = (unified) => unified !== '1F34D'; - expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id)) - .not.to.contain('pineapple'); - expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id)) - .not.to.contain('pineapple'); - }); - - it('can include/exclude categories', () => { - expect(search('flag', { include: ['people'] })) - .to.deep.equal([]); - expect(emojiIndex.search('flag', { include: ['people'] })) - .to.deep.equal([]); - }); - - it('does an emoji whose unified name is irregular', () => { - let expected = [{ - 'id': 'water_polo', - 'unified': '1f93d', - 'native': '🤽', - }, { - 'id': 'man-playing-water-polo', - 'unified': '1f93d-200d-2642-fe0f', - 'native': '🤽♂️', - }, { - 'id': 'woman-playing-water-polo', - 'unified': '1f93d-200d-2640-fe0f', - 'native': '🤽♀️', - }]; - expect(search('polo').map(trimEmojis)).to.deep.equal(expected); - expect(emojiIndex.search('polo').map(trimEmojis)).to.deep.equal(expected); - }); - - it('can search for thinking_face', () => { - let expected = [ { id: 'thinking_face', unified: '1f914', native: '🤔' } ]; - expect(search('thinking_fac').map(trimEmojis)).to.deep.equal(expected); - expect(emojiIndex.search('thinking_fac').map(trimEmojis)).to.deep.equal(expected); - }); - - it('can search for woman-facepalming', () => { - let expected = [ { id: 'woman-facepalming', unified: '1f926-200d-2640-fe0f', native: '🤦♀️' } ]; - expect(search('woman-facep').map(trimEmojis)).to.deep.equal(expected); - expect(emojiIndex.search('woman-facep').map(trimEmojis)).deep.equal(expected); - }); -}); diff --git a/spec/javascript/components/emojify.test.js b/spec/javascript/components/emojify.test.js deleted file mode 100644 index 3105c8e3f..000000000 --- a/spec/javascript/components/emojify.test.js +++ /dev/null @@ -1,61 +0,0 @@ -import { expect } from 'chai'; -import emojify from '../../../app/javascript/mastodon/features/emoji/emoji'; - -describe('emojify', () => { - it('ignores unknown shortcodes', () => { - expect(emojify(':foobarbazfake:')).to.equal(':foobarbazfake:'); - }); - - it('ignores shortcodes inside of tags', () => { - expect(emojify('<p data-foo=":smile:"></p>')).to.equal('<p data-foo=":smile:"></p>'); - }); - - it('works with unclosed tags', () => { - expect(emojify('hello>')).to.equal('hello>'); - expect(emojify('<hello')).to.equal('<hello'); - }); - - it('works with unclosed shortcodes', () => { - expect(emojify('smile:')).to.equal('smile:'); - expect(emojify(':smile')).to.equal(':smile'); - }); - - it('does unicode', () => { - expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).to.equal( - '<img draggable="false" class="emojione" alt="👩👩👦👦" title=":woman-woman-boy-boy:" src="/emoji/1f469-200d-1f469-200d-1f466-200d-1f466.svg" />'); - expect(emojify('👨👩👧👧')).to.equal( - '<img draggable="false" class="emojione" alt="👨👩👧👧" title=":man-woman-girl-girl:" src="/emoji/1f468-200d-1f469-200d-1f467-200d-1f467.svg" />'); - expect(emojify('👩👩👦')).to.equal('<img draggable="false" class="emojione" alt="👩👩👦" title=":woman-woman-boy:" src="/emoji/1f469-200d-1f469-200d-1f466.svg" />'); - expect(emojify('\u2757')).to.equal( - '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); - }); - - it('does multiple unicode', () => { - expect(emojify('\u2757 #\uFE0F\u20E3')).to.equal( - '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); - expect(emojify('\u2757#\uFE0F\u20E3')).to.equal( - '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /><img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" />'); - expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).to.equal( - '<img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" />'); - expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).to.equal( - 'foo <img draggable="false" class="emojione" alt="❗" title=":exclamation:" src="/emoji/2757.svg" /> <img draggable="false" class="emojione" alt="#️⃣" title=":hash:" src="/emoji/23-20e3.svg" /> bar'); - }); - - it('ignores unicode inside of tags', () => { - expect(emojify('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>')).to.equal('<p data-foo="\uD83D\uDC69\uD83D\uDC69\uD83D\uDC66"></p>'); - }); - - it('does multiple emoji properly (issue 5188)', () => { - expect(emojify('👌🌈💕')).to.equal('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /><img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /><img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); - expect(emojify('👌 🌈 💕')).to.equal('<img draggable="false" class="emojione" alt="👌" title=":ok_hand:" src="/emoji/1f44c.svg" /> <img draggable="false" class="emojione" alt="🌈" title=":rainbow:" src="/emoji/1f308.svg" /> <img draggable="false" class="emojione" alt="💕" title=":two_hearts:" src="/emoji/1f495.svg" />'); - }); - - it('does an emoji that has no shortcode', () => { - expect(emojify('🕉️')).to.equal('<img draggable="false" class="emojione" alt="🕉️" title="" src="/emoji/1f549.svg" />'); - }); - - it('does an emoji whose filename is irregular', () => { - expect(emojify('↙️')).to.equal('<img draggable="false" class="emojione" alt="↙️" title=":arrow_lower_left:" src="/emoji/2199.svg" />'); - }); - -}); diff --git a/spec/javascript/setup.js b/spec/javascript/setup.js deleted file mode 100644 index ab8a36b95..000000000 --- a/spec/javascript/setup.js +++ /dev/null @@ -1,15 +0,0 @@ -import { JSDOM } from 'jsdom'; -import Enzyme from 'enzyme'; -import Adapter from 'enzyme-adapter-react-16'; - -Enzyme.configure({ adapter: new Adapter() }); - -const { window } = new JSDOM('', { - userAgent: 'node.js', -}); - -Object.keys(window).forEach(property => { - if (typeof global[property] === 'undefined') { - global[property] = window[property]; - } -}); diff --git a/spec/lib/feed_manager_spec.rb b/spec/lib/feed_manager_spec.rb index 923894ccb..0f97a579e 100644 --- a/spec/lib/feed_manager_spec.rb +++ b/spec/lib/feed_manager_spec.rb @@ -211,6 +211,22 @@ RSpec.describe FeedManager do expect(FeedManager.instance.push('type', account, reblogs.last)).to be false end + it 'does not save a new reblog of a multiply-reblogged-then-unreblogged status' do + account = Fabricate(:account) + reblogged = Fabricate(:status) + reblogs = 3.times.map { Fabricate(:status, reblog: reblogged) } + + # Accept the reblogs + FeedManager.instance.push('type', account, reblogs[0]) + FeedManager.instance.push('type', account, reblogs[1]) + + # Unreblog the first one + FeedManager.instance.unpush('type', account, reblogs[0]) + + # The last reblog should still be ignored + expect(FeedManager.instance.push('type', account, reblogs.last)).to be false + end + it 'saves a new reblog of a long-ago-reblogged status' do account = Fabricate(:account) reblogged = Fabricate(:status) @@ -230,34 +246,101 @@ RSpec.describe FeedManager do end end + describe '#trim' do + let(:receiver) { Fabricate(:account) } + + it 'cleans up reblog tracking keys' do + reblogged = Fabricate(:status) + status = Fabricate(:status, reblog: reblogged) + another_status = Fabricate(:status, reblog: reblogged) + reblogs_key = FeedManager.instance.key('type', receiver.id, 'reblogs') + reblog_set_key = FeedManager.instance.key('type', receiver.id, "reblogs:#{reblogged.id}") + + FeedManager.instance.push('type', receiver, status) + FeedManager.instance.push('type', receiver, another_status) + + # We should have a tracking set and an entry in reblogs. + expect(Redis.current.exists(reblog_set_key)).to be true + expect(Redis.current.zrange(reblogs_key, 0, -1)).to eq [reblogged.id.to_s] + + # Push everything off the end of the feed. + FeedManager::MAX_ITEMS.times do + FeedManager.instance.push('type', receiver, Fabricate(:status)) + end + + # `trim` should be called automatically, but do it anyway, as + # we're testing `trim`, not side effects of `push`. + FeedManager.instance.trim('type', receiver.id) + + # We should not have any reblog tracking data. + expect(Redis.current.exists(reblog_set_key)).to be false + expect(Redis.current.zrange(reblogs_key, 0, -1)).to be_empty + end + end + describe '#unpush' do - it 'leaves a reblogged status when deleting the reblog' do - account = Fabricate(:account) + let(:receiver) { Fabricate(:account) } + + it 'leaves a reblogged status if original was on feed' do reblogged = Fabricate(:status) - status = Fabricate(:status, reblog: reblogged) + status = Fabricate(:status, reblog: reblogged) - FeedManager.instance.push('type', account, status) + FeedManager.instance.push('type', receiver, reblogged) + FeedManager::REBLOG_FALLOFF.times { FeedManager.instance.push('type', receiver, Fabricate(:status)) } + FeedManager.instance.push('type', receiver, status) + + # The reblogging status should show up under normal conditions. + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to include(status.id.to_s) + + FeedManager.instance.unpush('type', receiver, status) + + # Restore original status + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to_not include(status.id.to_s) + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to include(reblogged.id.to_s) + end + + it 'removes a reblogged status if it was only reblogged once' do + reblogged = Fabricate(:status) + status = Fabricate(:status, reblog: reblogged) + + FeedManager.instance.push('type', receiver, status) # The reblogging status should show up under normal conditions. - expect(Redis.current.zrange("feed:type:#{account.id}", 0, -1)).to eq [status.id.to_s] + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to eq [status.id.to_s] - FeedManager.instance.unpush('type', account, status) + FeedManager.instance.unpush('type', receiver, status) - # Because we couldn't tell if the status showed up any other way, - # we had to stick the reblogged status in by itself. - expect(Redis.current.zrange("feed:type:#{account.id}", 0, -1)).to eq [reblogged.id.to_s] + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to be_empty + end + + it 'leaves a multiply-reblogged status if another reblog was in feed' do + reblogged = Fabricate(:status) + reblogs = 3.times.map { Fabricate(:status, reblog: reblogged) } + + reblogs.each do |reblog| + FeedManager.instance.push('type', receiver, reblog) + end + + # The reblogging status should show up under normal conditions. + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to eq [reblogs.first.id.to_s] + + reblogs[0...-1].each do |reblog| + FeedManager.instance.unpush('type', receiver, reblog) + end + + expect(Redis.current.zrange("feed:type:#{receiver.id}", 0, -1)).to eq [reblogs.last.id.to_s] end it 'sends push updates' do - account = Fabricate(:account) - status = Fabricate(:status) - FeedManager.instance.push('type', account, status) + status = Fabricate(:status) + + FeedManager.instance.push('type', receiver, status) allow(Redis.current).to receive_messages(publish: nil) - FeedManager.instance.unpush('type', account, status) + FeedManager.instance.unpush('type', receiver, status) deletion = Oj.dump(event: :delete, payload: status.id.to_s) - expect(Redis.current).to have_received(:publish).with("timeline:#{account.id}", deletion) + expect(Redis.current).to have_received(:publish).with("timeline:#{receiver.id}", deletion) end end end diff --git a/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb b/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb index b8487b03f..7fae680ba 100644 --- a/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb +++ b/spec/workers/scheduler/feed_cleanup_scheduler_spec.rb @@ -9,14 +9,18 @@ describe Scheduler::FeedCleanupScheduler do it 'clears feeds of inactives' do Redis.current.zadd(feed_key_for(inactive_user), 1, 1) Redis.current.zadd(feed_key_for(active_user), 1, 1) + Redis.current.zadd(feed_key_for(inactive_user, 'reblogs'), 2, 2) + Redis.current.sadd(feed_key_for(inactive_user, 'reblogs:2'), 3) subject.perform expect(Redis.current.zcard(feed_key_for(inactive_user))).to eq 0 expect(Redis.current.zcard(feed_key_for(active_user))).to eq 1 + expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs'))).to be false + expect(Redis.current.exists(feed_key_for(inactive_user, 'reblogs:2'))).to be false end - def feed_key_for(user) - FeedManager.instance.key(:home, user.account_id) + def feed_key_for(user, subtype = nil) + FeedManager.instance.key(:home, user.account_id, subtype) end end diff --git a/streaming/index.js b/streaming/index.js index 017073fa1..83903b89b 100644 --- a/streaming/index.js +++ b/streaming/index.js @@ -80,7 +80,7 @@ const startWorker = (workerId) => { development: { user: process.env.DB_USER || pg.defaults.user, password: process.env.DB_PASS || pg.defaults.password, - database: 'mastodon_development', + database: process.env.DB_NAME || 'mastodon_development', host: process.env.DB_HOST || pg.defaults.host, port: process.env.DB_PORT || pg.defaults.port, max: 10, diff --git a/yarn.lock b/yarn.lock index a1c29badd..aceff463b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,8 +3,8 @@ "@types/node@^6.0.46": - version "6.0.80" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.80.tgz#914a75799605b4609bd9a2918c865ba3c4141367" + version "6.0.89" + resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.89.tgz#154be0e6a823760cd6083aa8c48f952e2e63e0b0" abab@^1.0.3: version "1.0.3" @@ -114,6 +114,10 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" +ansi-escapes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" + ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" @@ -136,6 +140,12 @@ ansi-styles@^3.1.0: dependencies: color-convert "^1.0.0" +ansi-styles@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" + dependencies: + color-convert "^1.9.0" + any-promise@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-0.1.0.tgz#830b680aa7e56f33451d4b049f3bd8044498ee27" @@ -151,6 +161,12 @@ ap@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + aproba@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" @@ -228,7 +244,7 @@ array.prototype.find@^2.0.1: define-properties "^1.1.2" es-abstract "^1.7.0" -arrify@^1.0.0: +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -262,14 +278,14 @@ assert@^1.1.1, assert@^1.3.0: dependencies: util "0.10.3" -assertion-error@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" - ast-types-flow@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" @@ -282,11 +298,11 @@ async@0.2.x: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" -async@^1.5.2: +async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.2, async@^2.1.5: +async@^2.1.2, async@^2.1.4, async@^2.1.5: version "2.5.0" resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" dependencies: @@ -357,7 +373,7 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.25.0, babel-core@^6.26.0: +babel-core@^6.0.0, babel-core@^6.25.0, babel-core@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: @@ -390,7 +406,7 @@ babel-eslint@^7.2.3: babel-types "^6.23.0" babylon "^6.17.0" -babel-generator@^6.26.0: +babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" dependencies: @@ -512,6 +528,13 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" +babel-jest@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-21.2.0.tgz#2ce059519a9374a2c46f2455b6fbef5ad75d863e" + dependencies: + babel-plugin-istanbul "^4.0.0" + babel-preset-jest "^21.2.0" + babel-loader@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126" @@ -536,6 +559,18 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-istanbul@^4.0.0: + version "4.1.5" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" + dependencies: + find-up "^2.1.0" + istanbul-lib-instrument "^1.7.5" + test-exclude "^4.1.1" + +babel-plugin-jest-hoist@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" + babel-plugin-lodash@^3.2.11: version "3.2.11" resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.2.11.tgz#21c8fdec9fe1835efaa737873e3902bdd66d5701" @@ -595,7 +630,7 @@ babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" -babel-plugin-syntax-object-rest-spread@^6.8.0: +babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -927,6 +962,13 @@ babel-preset-flow@^6.23.0: dependencies: babel-plugin-transform-flow-strip-types "^6.22.0" +babel-preset-jest@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz#ff9d2bce08abd98e8a36d9a8a5189b9173b85638" + dependencies: + babel-plugin-jest-hoist "^21.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + babel-preset-react@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" @@ -964,6 +1006,16 @@ babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" +babel-template@^6.16.0, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + babel-template@^6.24.1, babel-template@^6.3.0: version "6.25.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071" @@ -974,14 +1026,18 @@ babel-template@^6.24.1, babel-template@^6.3.0: babylon "^6.17.2" lodash "^4.2.0" -babel-template@^6.26.0: +babel-traverse@^6.18.0, babel-traverse@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" babel-runtime "^6.26.0" - babel-traverse "^6.26.0" babel-types "^6.26.0" babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" lodash "^4.17.4" babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.25.0: @@ -998,19 +1054,14 @@ babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.25.0: invariant "^2.2.0" lodash "^4.2.0" -babel-traverse@^6.26.0: +babel-types@^6.18.0, babel-types@^6.26.0: version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" + esutils "^2.0.2" lodash "^4.17.4" + to-fast-properties "^1.0.3" babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.25.0: version "6.25.0" @@ -1021,15 +1072,6 @@ babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.25 lodash "^4.2.0" to-fast-properties "^1.0.1" -babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - babylon@^6.17.0, babylon@^6.17.2: version "6.17.4" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.4.tgz#3e8b7402b88d22c3423e137a1577883b15ff869a" @@ -1143,9 +1185,11 @@ brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" -browser-stdout@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" +browser-resolve@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.0.6" @@ -1219,6 +1263,12 @@ browserslist@^2.4.0: caniuse-lite "^1.0.30000718" electron-to-chromium "^1.3.18" +bser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" + dependencies: + node-int64 "^0.4.0" + buffer-indexof@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.0.tgz#f54f647c4f4e25228baa656a2e57e43d5f270982" @@ -1239,7 +1289,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -builtin-modules@^1.0.0: +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1265,6 +1315,10 @@ callsites@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + camelcase-css@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-1.0.1.tgz#157c4238265f5cf94a1dffde86446552cbf3f705" @@ -1324,24 +1378,6 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chai-enzyme@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/chai-enzyme/-/chai-enzyme-0.8.0.tgz#609c552a1dcdb091f435e1e281cc4f2149a33be1" - dependencies: - html "^1.0.0" - react-element-to-jsx-string "^5.0.0" - -chai@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" - dependencies: - assertion-error "^1.0.1" - check-error "^1.0.1" - deep-eql "^3.0.0" - get-func-name "^2.0.0" - pathval "^1.0.0" - type-detect "^4.0.0" - chain-function@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/chain-function/-/chain-function-1.0.0.tgz#0d4ab37e7e18ead0bdc47b920764118ce58733dc" @@ -1372,10 +1408,6 @@ chalk@^2.1.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" -check-error@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - cheerio@^1.0.0-rc.2: version "1.0.0-rc.2" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" @@ -1402,6 +1434,10 @@ chokidar@^1.6.0, chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" +ci-info@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.1.tgz#47b44df118c48d2597b56d342e7e25791060171a" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -1476,11 +1512,7 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -collapse-white-space@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.3.tgz#4b906f670e5a963a87b76b0e1689643341b6023c" - -color-convert@^1.0.0, color-convert@^1.3.0: +color-convert@^1.0.0, color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" dependencies: @@ -1526,12 +1558,6 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - dependencies: - graceful-readlink ">= 1.0.0" - commander@^2.8.1, commander@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" @@ -1575,7 +1601,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.7, concat-stream@^1.5.2: +concat-stream@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1601,6 +1627,10 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -1621,7 +1651,7 @@ convert-source-map@^0.3.3: version "0.3.5" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" -convert-source-map@^1.1.1, convert-source-map@^1.5.0: +convert-source-map@^1.1.1, convert-source-map@^1.4.0, convert-source-map@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" @@ -1934,7 +1964,7 @@ debug@2.6.8, debug@^2.1.1, debug@^2.2.0, debug@^2.4.5, debug@^2.6.6, debug@^2.6. dependencies: ms "2.0.0" -debug@2.6.9: +debug@2.6.9, debug@^2.6.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -1952,12 +1982,6 @@ decimal.js@7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-7.2.3.tgz#6434c3b8a8c375780062fc633d0d2bbdb264cc78" -deep-eql@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - dependencies: - type-detect "^4.0.0" - deep-equal@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -1970,6 +1994,12 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + defaults@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" @@ -2051,13 +2081,9 @@ detect-passive-events@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/detect-passive-events/-/detect-passive-events-1.0.4.tgz#6ed477e6e5bceb79079735dcd357789d37f9a91a" -diff@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" - -diff@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.0.tgz#056695150d7aa93237ca7e378ac3b1682b7963b9" +diff@^3.2.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" diffie-hellman@^5.0.0: version "5.0.2" @@ -2088,7 +2114,7 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -doctrine@^1.2.2: +doctrine@1.5.0, doctrine@^1.2.2: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: @@ -2163,10 +2189,6 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" -editions@^1.1.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.3.tgz#0907101bdda20fac3cbe334c27cbd0688dc99a5b" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2231,8 +2253,8 @@ entities@^1.1.1, entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" enzyme-adapter-react-16@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.0.tgz#e7edd5536743818dcbef336d40d7da59b3a7db8e" + version "1.0.1" + resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.0.1.tgz#066cb1735e65d8d95841a023f94dab3ce6109e17" dependencies: enzyme-adapter-utils "^1.0.0" lodash "^4.17.4" @@ -2241,16 +2263,16 @@ enzyme-adapter-react-16@^1.0.0: prop-types "^15.5.10" enzyme-adapter-utils@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.0.0.tgz#e94eee63da9a798d498adb1162a2102ed04fc638" + version "1.0.1" + resolved "https://registry.yarnpkg.com/enzyme-adapter-utils/-/enzyme-adapter-utils-1.0.1.tgz#fcd81223339a55a312f7552641e045c404084009" dependencies: lodash "^4.17.4" object.assign "^4.0.4" prop-types "^15.5.10" enzyme@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.0.0.tgz#94ce364254dc654c4e619b25eecc644bf6481de7" + version "3.1.0" + resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-3.1.0.tgz#d8ca84085790fbcec6ed40badd14478faee4c25a" dependencies: cheerio "^1.0.0-rc.2" function.prototype.name "^1.0.3" @@ -2261,9 +2283,9 @@ enzyme@^3.0.0: object.entries "^1.0.4" object.values "^1.0.4" raf "^3.3.2" - rst-selector-parser "^2.2.1" + rst-selector-parser "^2.2.2" -errno@^0.1.3: +errno@^0.1.3, errno@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" dependencies: @@ -2275,7 +2297,17 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.6.1, es-abstract@^1.7.0: +es-abstract@^1.6.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.1" + has "^1.0.1" + is-callable "^1.1.3" + is-regex "^1.0.4" + +es-abstract@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c" dependencies: @@ -2348,7 +2380,7 @@ escape-html@^1.0.3, escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2372,6 +2404,35 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-import-resolver-node@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz#4422574cde66a9a7b099938ee4d508a199e0e3cc" + dependencies: + debug "^2.6.8" + resolve "^1.2.0" + +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz#21de33380b9efb55f5ef6d2e210ec0e07e7fa69f" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + eslint-plugin-jsx-a11y@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-4.0.0.tgz#779bb0fe7b08da564a422624911de10061e048ee" @@ -2508,6 +2569,12 @@ evp_bytestokey@^1.0.0: dependencies: create-hash "^1.1.1" +exec-sh@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.1.tgz#163b98a6e89e6b65b47c2a28d215bc1f63989c38" + dependencies: + merge "^1.1.3" + execa@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/execa/-/execa-0.5.1.tgz#de3fb85cb8d6e91c85bcbceb164581785cb57b36" @@ -2536,6 +2603,17 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" +expect@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-21.2.1.tgz#003ac2ac7005c3c29e73b38a272d4afadd6d1d7b" + dependencies: + ansi-styles "^3.2.0" + jest-diff "^21.2.1" + jest-get-type "^21.2.0" + jest-matcher-utils "^21.2.1" + jest-message-util "^21.2.1" + jest-regex-util "^21.2.0" + express@^4.13.3: version "4.15.3" resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" @@ -2651,6 +2729,12 @@ faye-websocket@~0.11.0: dependencies: websocket-driver ">=0.5.1" +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + dependencies: + bser "^2.0.0" + fbjs@^0.8.14, fbjs@^0.8.16: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" @@ -2699,6 +2783,13 @@ filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + filesize@^3.5.9: version "3.5.10" resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" @@ -2817,12 +2908,6 @@ form-data@~2.1.1: combined-stream "^1.0.5" mime-types "^2.1.12" -formatio@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb" - dependencies: - samsam "1.x" - forwarded@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" @@ -2857,7 +2942,7 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@*, fsevents@^1.0.0: +fsevents@*, fsevents@^1.0.0, fsevents@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" dependencies: @@ -2881,9 +2966,9 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2, function-bind@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" +function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" function.prototype.name@^1.0.3: version "1.0.3" @@ -2930,10 +3015,6 @@ get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -2964,17 +3045,6 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.2" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" @@ -3025,17 +3095,13 @@ gonzales-pe@^4.0.3: dependencies: minimist "1.1.x" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - -growl@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" gzip-size@^3.0.0: version "3.0.0" @@ -3047,6 +3113,16 @@ handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" +handlebars@^4.0.3: + version "4.0.10" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" @@ -3104,10 +3180,6 @@ hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - history@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" @@ -3168,12 +3240,6 @@ html-entities@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" -html@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/html/-/html-1.0.0.tgz#a544fa9ea5492bfb3a2cca8210a10be7b5af1f61" - dependencies: - concat-stream "^1.4.7" - htmlparser2@^3.9.1: version "3.9.2" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" @@ -3430,6 +3496,12 @@ is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" +is-ci@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" + dependencies: + ci-info "^1.0.0" + is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" @@ -3553,16 +3625,12 @@ is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" -is-regex@^1.0.3: +is-regex@^1.0.3, is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" dependencies: has "^1.0.1" -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - is-resolvable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" @@ -3636,10 +3704,298 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +istanbul-api@^1.1.1: + version "1.1.14" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.14.tgz#25bc5701f7c680c0ffff913de46e3619a3a6e680" + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.1.1" + istanbul-lib-hook "^1.0.7" + istanbul-lib-instrument "^1.8.0" + istanbul-lib-report "^1.1.1" + istanbul-lib-source-maps "^1.2.1" + istanbul-reports "^1.1.2" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.0.1, istanbul-lib-coverage@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da" + +istanbul-lib-hook@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz#66f6c9421cc9ec4704f76f2db084ba9078a2b532" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.1.1" + semver "^5.3.0" + +istanbul-lib-report@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9" + dependencies: + istanbul-lib-coverage "^1.1.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.1.0, istanbul-lib-source-maps@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c" + dependencies: + debug "^2.6.3" + istanbul-lib-coverage "^1.1.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.2.tgz#0fb2e3f6aa9922bd3ce45d05d8ab4d5e8e07bd4f" + dependencies: + handlebars "^4.0.3" + javascript-natural-sort@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" +jest-changed-files@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-21.2.0.tgz#5dbeecad42f5d88b482334902ce1cba6d9798d29" + dependencies: + throat "^4.0.0" + +jest-cli@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-21.2.1.tgz#9c528b6629d651911138d228bdb033c157ec8c00" + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + glob "^7.1.2" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + istanbul-api "^1.1.1" + istanbul-lib-coverage "^1.0.1" + istanbul-lib-instrument "^1.4.2" + istanbul-lib-source-maps "^1.1.0" + jest-changed-files "^21.2.0" + jest-config "^21.2.1" + jest-environment-jsdom "^21.2.1" + jest-haste-map "^21.2.0" + jest-message-util "^21.2.1" + jest-regex-util "^21.2.0" + jest-resolve-dependencies "^21.2.0" + jest-runner "^21.2.1" + jest-runtime "^21.2.1" + jest-snapshot "^21.2.1" + jest-util "^21.2.1" + micromatch "^2.3.11" + node-notifier "^5.0.2" + pify "^3.0.0" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + worker-farm "^1.3.1" + yargs "^9.0.0" + +jest-config@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-21.2.1.tgz#c7586c79ead0bcc1f38c401e55f964f13bf2a480" + dependencies: + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^21.2.1" + jest-environment-node "^21.2.1" + jest-get-type "^21.2.0" + jest-jasmine2 "^21.2.1" + jest-regex-util "^21.2.0" + jest-resolve "^21.2.0" + jest-util "^21.2.1" + jest-validate "^21.2.1" + pretty-format "^21.2.1" + +jest-diff@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-21.2.1.tgz#46cccb6cab2d02ce98bc314011764bb95b065b4f" + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^21.2.0" + pretty-format "^21.2.1" + +jest-docblock@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + +jest-environment-jsdom@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-21.2.1.tgz#38d9980c8259b2a608ec232deee6289a60d9d5b4" + dependencies: + jest-mock "^21.2.0" + jest-util "^21.2.1" + jsdom "^9.12.0" + +jest-environment-node@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-21.2.1.tgz#98c67df5663c7fbe20f6e792ac2272c740d3b8c8" + dependencies: + jest-mock "^21.2.0" + jest-util "^21.2.1" + +jest-get-type@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23" + +jest-haste-map@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-21.2.0.tgz#1363f0a8bb4338f24f001806571eff7a4b2ff3d8" + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + jest-docblock "^21.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + worker-farm "^1.3.1" + +jest-jasmine2@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-21.2.1.tgz#9cc6fc108accfa97efebce10c4308548a4ea7592" + dependencies: + chalk "^2.0.1" + expect "^21.2.1" + graceful-fs "^4.1.11" + jest-diff "^21.2.1" + jest-matcher-utils "^21.2.1" + jest-message-util "^21.2.1" + jest-snapshot "^21.2.1" + p-cancelable "^0.3.0" + +jest-matcher-utils@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-21.2.1.tgz#72c826eaba41a093ac2b4565f865eb8475de0f64" + dependencies: + chalk "^2.0.1" + jest-get-type "^21.2.0" + pretty-format "^21.2.1" + +jest-message-util@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-21.2.1.tgz#bfe5d4692c84c827d1dcf41823795558f0a1acbe" + dependencies: + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + +jest-mock@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-21.2.0.tgz#7eb0770e7317968165f61ea2a7281131534b3c0f" + +jest-regex-util@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-21.2.0.tgz#1b1e33e63143babc3e0f2e6c9b5ba1eb34b2d530" + +jest-resolve-dependencies@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-21.2.0.tgz#9e231e371e1a736a1ad4e4b9a843bc72bfe03d09" + dependencies: + jest-regex-util "^21.2.0" + +jest-resolve@^21.2.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-21.2.0.tgz#068913ad2ba6a20218e5fd32471f3874005de3a6" + dependencies: + browser-resolve "^1.11.2" + chalk "^2.0.1" + is-builtin-module "^1.0.0" + +jest-runner@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-21.2.1.tgz#194732e3e518bfb3d7cbfc0fd5871246c7e1a467" + dependencies: + jest-config "^21.2.1" + jest-docblock "^21.2.0" + jest-haste-map "^21.2.0" + jest-jasmine2 "^21.2.1" + jest-message-util "^21.2.1" + jest-runtime "^21.2.1" + jest-util "^21.2.1" + pify "^3.0.0" + throat "^4.0.0" + worker-farm "^1.3.1" + +jest-runtime@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-21.2.1.tgz#99dce15309c670442eee2ebe1ff53a3cbdbbb73e" + dependencies: + babel-core "^6.0.0" + babel-jest "^21.2.0" + babel-plugin-istanbul "^4.0.0" + chalk "^2.0.1" + convert-source-map "^1.4.0" + graceful-fs "^4.1.11" + jest-config "^21.2.1" + jest-haste-map "^21.2.0" + jest-regex-util "^21.2.0" + jest-resolve "^21.2.0" + jest-util "^21.2.1" + json-stable-stringify "^1.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^9.0.0" + +jest-snapshot@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-21.2.1.tgz#29e49f16202416e47343e757e5eff948c07fd7b0" + dependencies: + chalk "^2.0.1" + jest-diff "^21.2.1" + jest-matcher-utils "^21.2.1" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^21.2.1" + +jest-util@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-21.2.1.tgz#a274b2f726b0897494d694a6c3d6a61ab819bb78" + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + jest-message-util "^21.2.1" + jest-mock "^21.2.0" + jest-validate "^21.2.1" + mkdirp "^0.5.1" + +jest-validate@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7" + dependencies: + chalk "^2.0.1" + jest-get-type "^21.2.0" + leven "^2.1.0" + pretty-format "^21.2.1" + +jest@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-21.2.1.tgz#c964e0b47383768a1438e3ccf3c3d470327604e1" + dependencies: + jest-cli "^21.2.1" + js-base64@^2.1.8, js-base64@^2.1.9: version "2.1.9" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" @@ -3659,7 +4015,7 @@ js-yaml@^3.4.3, js-yaml@^3.5.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.9.0: +js-yaml@^3.7.0, js-yaml@^3.9.0: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: @@ -3677,9 +4033,9 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" -jsdom@^11.1.0: - version "11.2.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.2.0.tgz#4f6b8736af3357c3af7227a3b54a5bda1c513fd6" +jsdom@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4" dependencies: abab "^1.0.3" acorn "^4.0.4" @@ -3690,17 +4046,15 @@ jsdom@^11.1.0: cssstyle ">= 0.2.37 < 0.3.0" escodegen "^1.6.1" html-encoding-sniffer "^1.0.1" - nwmatcher "^1.4.1" - parse5 "^3.0.2" - pn "^1.0.0" + nwmatcher ">= 1.3.9 < 2.0.0" + parse5 "^1.5.1" request "^2.79.0" - request-promise-native "^1.0.3" sax "^1.2.1" symbol-tree "^3.2.1" tough-cookie "^2.3.2" webidl-conversions "^4.0.0" whatwg-encoding "^1.0.1" - whatwg-url "^6.1.0" + whatwg-url "^4.3.0" xml-name-validator "^2.0.1" jsesc@^1.3.0: @@ -3733,7 +4087,7 @@ json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -json3@3.3.2, json3@^3.3.2: +json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" @@ -3810,6 +4164,10 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -3879,10 +4237,6 @@ lodash._basecopy@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" -lodash._basecreate@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" - lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" @@ -3923,13 +4277,9 @@ lodash.clonedeep@^4.3.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" -lodash.create@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" - dependencies: - lodash._baseassign "^3.0.0" - lodash._basecreate "^3.0.0" - lodash._isiterateecall "^3.0.0" +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" lodash.defaults@^3.1.2: version "3.1.2" @@ -3974,10 +4324,6 @@ lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - lodash.tail@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" @@ -3994,10 +4340,6 @@ loglevel@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.4.1.tgz#95b383f91a3c2756fd4ab093667e4309161f2bcd" -lolex@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" - longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" @@ -4032,6 +4374,12 @@ make-dir@^1.0.0: dependencies: pify "^2.3.0" +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + dependencies: + tmpl "1.0.x" + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -4096,6 +4444,10 @@ merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" +merge@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -4187,10 +4539,14 @@ minimist@1.1.x: version "1.1.3" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" -minimist@^1.1.3, minimist@^1.2.0: +minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minimist@~0.0.1: + version "0.0.10" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" + mixin-object@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" @@ -4198,29 +4554,12 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" -mocha@^3.4.1: - version "3.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" - dependencies: - browser-stdout "1.3.0" - commander "2.9.0" - debug "2.6.8" - diff "3.2.0" - escape-string-regexp "1.0.5" - glob "7.1.1" - growl "1.9.2" - he "1.1.1" - json3 "3.3.2" - lodash.create "3.1.1" - mkdirp "0.5.1" - supports-color "3.1.2" - mousetrap@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.1.tgz#2a085f5c751294c75e7e81f6ec2545b29cbf42d9" @@ -4248,10 +4587,6 @@ nan@^2.0.0, nan@^2.3.0, nan@^2.3.2: version "2.6.2" resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" -native-promise-only@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11" - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -4297,6 +4632,10 @@ node-gyp@^3.3.1: tar "^2.0.0" which "1" +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + node-libs-browser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" @@ -4325,6 +4664,15 @@ node-libs-browser@^2.0.0: util "^0.10.3" vm-browserify "0.0.4" +node-notifier@^5.0.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + dependencies: + growly "^1.3.0" + semver "^5.3.0" + shellwords "^0.1.0" + which "^1.2.12" + node-pre-gyp@^0.6.36, node-pre-gyp@^0.6.4: version "0.6.36" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" @@ -4448,9 +4796,9 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -nwmatcher@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.1.tgz#7ae9b07b0ea804db7e25f05cb5fe4097d4e4949f" +"nwmatcher@>= 1.3.9 < 2.0.0": + version "1.4.3" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" oauth-sign@~0.8.1: version "0.8.2" @@ -4537,7 +4885,7 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0, once@^1.3.3: +once@^1.3.0, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -4557,6 +4905,13 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -4607,6 +4962,10 @@ osenv@0, osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -4672,7 +5031,11 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" -parse5@^3.0.1, parse5@^3.0.2: +parse5@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" + +parse5@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510" dependencies: @@ -4744,10 +5107,6 @@ path-type@^2.0.0: dependencies: pify "^2.0.0" -pathval@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" - pbkdf2@^3.0.3: version "3.0.12" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2" @@ -4824,6 +5183,12 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" @@ -4834,10 +5199,6 @@ pluralize@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" -pn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" - portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" @@ -5352,6 +5713,13 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +pretty-format@^21.2.1: + version "21.2.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-21.2.1.tgz#ae5407f3cf21066cd011aa1ba5fce7b6a2eddb36" + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + private@^0.1.6, private@^0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" @@ -5484,12 +5852,18 @@ quote@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/quote/-/quote-0.4.0.tgz#10839217f6c1362b89194044d29b233fd7f32f01" -raf@^3.1.0, raf@^3.3.2: +raf@^3.1.0: version "3.3.2" resolved "https://registry.yarnpkg.com/raf/-/raf-3.3.2.tgz#0c13be0b5b49b46f76d6669248d527cf2b02fe27" dependencies: performance-now "^2.1.0" +raf@^3.3.2, raf@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" + dependencies: + performance-now "^2.1.0" + railroad-diagrams@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" @@ -5549,17 +5923,6 @@ react-dom@^16.0.0: object-assign "^4.1.1" prop-types "^15.6.0" -react-element-to-jsx-string@^5.0.0: - version "5.0.7" - resolved "https://registry.yarnpkg.com/react-element-to-jsx-string/-/react-element-to-jsx-string-5.0.7.tgz#c663a4800a9c712115c0d8519cb0215a46a1f0f2" - dependencies: - collapse-white-space "^1.0.0" - is-plain-object "^2.0.1" - lodash "^4.17.4" - sortobject "^1.0.0" - stringify-object "2.4.0" - traverse "^0.6.6" - react-event-listener@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.5.0.tgz#d82105135573e187e3d900d18150a5882304b8d1" @@ -5945,20 +6308,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request-promise-core@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" - dependencies: - lodash "^4.13.1" - -request-promise-native@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.4.tgz#86988ec8eee408e45579fce83bfd05b3adf9a155" - dependencies: - request-promise-core "1.1.1" - stealthy-require "^1.1.0" - tough-cookie ">=2.3.0" - request@2, request@^2.79.0, request@^2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -6043,12 +6392,22 @@ resolve-url@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" dependencies: path-parse "^1.0.5" +resolve@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + dependencies: + path-parse "^1.0.5" + restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" @@ -6100,7 +6459,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" -rst-selector-parser@^2.2.1: +rst-selector-parser@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.2.tgz#9927b619bd5af8dc23a76c64caef04edf90d2c65" dependencies: @@ -6125,9 +6484,19 @@ safe-buffer@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" -samsam@1.x, samsam@^1.1.3: - version "1.2.1" - resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.2.1.tgz#edd39093a3184370cb859243b2bdf255e7d8ea67" +sane@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.2.0.tgz#d6d2e2fcab00e3d283c93b912b7c3a20846f1d56" + dependencies: + anymatch "^1.3.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + minimatch "^3.0.2" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.1.1" sass-graph@^2.1.1: version "2.2.4" @@ -6313,23 +6682,14 @@ shelljs@^0.7.5: interpret "^1.0.0" rechoir "^0.6.2" -signal-exit@^3.0.0: +shellwords@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -sinon@^2.3.7: - version "2.4.1" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.4.1.tgz#021fd64b54cb77d9d2fb0d43cdedfae7629c3a36" - dependencies: - diff "^3.1.0" - formatio "1.2.0" - lolex "^1.6.0" - native-promise-only "^0.8.1" - path-to-regexp "^1.7.0" - samsam "^1.1.3" - text-encoding "0.6.4" - type-detect "^4.0.0" - slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -6368,12 +6728,6 @@ sort-keys@^1.0.0: dependencies: is-plain-obj "^1.0.0" -sortobject@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sortobject/-/sortobject-1.1.1.tgz#4f695d4d44ed0a4c06482c34c2582a2dcdc2ab34" - dependencies: - editions "^1.1.1" - source-list-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" @@ -6407,7 +6761,7 @@ source-map@^0.1.38: dependencies: amdefine ">=0.0.4" -source-map@^0.4.2: +source-map@^0.4.2, source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: @@ -6498,10 +6852,6 @@ stdout-stream@^1.4.0: dependencies: readable-stream "^2.0.1" -stealthy-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -6523,6 +6873,13 @@ strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -6548,13 +6905,6 @@ string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringify-object@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-2.4.0.tgz#c62d11023eb21fe2d9b087be039a26df3b22a09d" - dependencies: - is-plain-obj "^1.0.0" - is-regexp "^1.0.0" - stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -6575,16 +6925,16 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-bom@3.0.0, strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" dependencies: is-utf8 "^0.2.0" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -6616,17 +6966,11 @@ sugarss@^1.0.0: dependencies: postcss "^6.0.0" -supports-color@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" - dependencies: - has-flag "^1.0.0" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.2.3: +supports-color@^3.1.2, supports-color@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: @@ -6710,14 +7054,24 @@ tcomb@^2.5.0, tcomb@^2.5.1: version "2.7.0" resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-2.7.0.tgz#10d62958041669a5d53567b9a4ee8cde22b1c2b0" -text-encoding@0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19" +test-exclude@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + throng@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/throng/-/throng-4.0.0.tgz#983c6ba1993b58eae859998aa687ffe88df84c17" @@ -6746,6 +7100,10 @@ tiny-queue@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -6754,7 +7112,7 @@ to-fast-properties@^1.0.1, to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" -tough-cookie@>=2.3.0, tough-cookie@^2.3.2, tough-cookie@~2.3.0: +tough-cookie@^2.3.2, tough-cookie@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: @@ -6764,10 +7122,6 @@ tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" -traverse@^0.6.6: - version "0.6.6" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" - trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -6800,10 +7154,6 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea" - type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" @@ -6823,7 +7173,7 @@ ua-parser-js@^0.7.9: version "0.7.13" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.13.tgz#cd9dd2f86493b3f44dbeeef3780fda74c5ee14be" -uglify-js@^2.8.29: +uglify-js@^2.6, uglify-js@^2.8.29: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: @@ -6974,12 +7324,25 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + dependencies: + makeerror "1.0.x" + warning@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" dependencies: loose-envify "^1.0.0" +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + watchpack@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.4.0.tgz#4a1472bcbb952bd0a9bb4036801f954dfb39faac" @@ -6994,7 +7357,11 @@ wbuf@^1.1.0, wbuf@^1.7.2: dependencies: minimalistic-assert "^1.0.0" -webidl-conversions@^4.0.0, webidl-conversions@^4.0.1: +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + +webidl-conversions@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0" @@ -7132,13 +7499,12 @@ whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" -whatwg-url@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.1.0.tgz#5fc8279b93d75483b9ced8b26239854847a18578" +whatwg-url@^4.3.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0" dependencies: - lodash.sortby "^4.7.0" tr46 "~0.0.3" - webidl-conversions "^4.0.1" + webidl-conversions "^3.0.0" whet.extend@~0.9.9: version "0.9.9" @@ -7158,6 +7524,12 @@ which@1, which@^1.2.9: dependencies: isexe "^2.0.0" +which@^1.2.12: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -7172,10 +7544,21 @@ wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +worker-farm@^1.3.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.0.tgz#adfdf0cd40581465ed0a1f648f9735722afd5c8d" + dependencies: + errno "^0.1.4" + xtend "^4.0.1" + wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -7187,6 +7570,14 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" +write-file-atomic@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" @@ -7204,7 +7595,7 @@ xml-name-validator@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" -xtend@^4.0.0: +xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -7288,6 +7679,24 @@ yargs@^8.0.2: y18n "^3.2.1" yargs-parser "^7.0.0" +yargs@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" + dependencies: + camelcase "^4.1.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + read-pkg-up "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^7.0.0" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" |