You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LanguageSelectDropdown.web.js 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import DropdownMenu, {
  2. DropdownItem,
  3. DropdownItemGroup
  4. } from '@atlaskit/dropdown-menu';
  5. import PropTypes from 'prop-types';
  6. import React, { Component } from 'react';
  7. import { DEFAULT_LANGUAGE, LANGUAGES, translate } from '../../base/i18n';
  8. /**
  9. * Implements a React {@link Component} which displays a dropdown for changing
  10. * application text to another language.
  11. *
  12. * @extends Component
  13. */
  14. class LanguageSelectDropdown extends Component {
  15. /**
  16. * {@code LanguageSelectDropdown} component's property types.
  17. *
  18. * @static
  19. */
  20. static propTypes = {
  21. /**
  22. * The translation service.
  23. */
  24. i18n: PropTypes.object,
  25. /**
  26. * Invoked to obtain translated strings.
  27. */
  28. t: PropTypes.func
  29. };
  30. /**
  31. * {@code LanguageSelectDropdown} component's local state.
  32. *
  33. * @type {Object}
  34. * @property {string|null} currentLanguage - The currently selected language
  35. * the application should be displayed in.
  36. * @property {boolean} isLanguageSelectOpen - Whether or not the dropdown
  37. * should be displayed as open.
  38. */
  39. state = {
  40. currentLanguage: null,
  41. isLanguageSelectOpen: false
  42. };
  43. /**
  44. * Initializes a new {@code LanguageSelectDropdown} instance.
  45. *
  46. * @param {Object} props - The read-only properties with which the new
  47. * instance is to be initialized.
  48. */
  49. constructor(props) {
  50. super(props);
  51. this.state.currentLanguage
  52. = this.props.i18n.language || DEFAULT_LANGUAGE;
  53. // Bind event handlers so they are only bound once for every instance.
  54. this._onLanguageSelected = this._onLanguageSelected.bind(this);
  55. this._onSetDropdownOpen = this._onSetDropdownOpen.bind(this);
  56. this._setCurrentLanguage = this._setCurrentLanguage.bind(this);
  57. }
  58. /**
  59. * Sets a listener to update the currently selected language if it is
  60. * changed from somewhere else.
  61. *
  62. * @inheritdoc
  63. * @returns {void}
  64. */
  65. componentDidMount() {
  66. this.props.i18n.on('languageChanged', this._setCurrentLanguage);
  67. }
  68. /**
  69. * Removes all listeners.
  70. *
  71. * @inheritdoc
  72. * @returns {void}
  73. */
  74. componentWillUnmount() {
  75. this.props.i18n.off('languageChanged', this._setCurrentLanguage);
  76. }
  77. /**
  78. * Implements React's {@link Component#render()}.
  79. *
  80. * @inheritdoc
  81. * @returns {ReactElement}
  82. */
  83. render() {
  84. const { t } = this.props;
  85. const { currentLanguage } = this.state;
  86. const languageItems = LANGUAGES.map(language =>
  87. // eslint-disable-next-line react/jsx-wrap-multilines
  88. <DropdownItem
  89. key = { language }
  90. // eslint-disable-next-line react/jsx-no-bind
  91. onClick = { () => this._onLanguageSelected(language) }>
  92. { t(`languages:${language}`) }
  93. </DropdownItem>
  94. );
  95. return (
  96. <div>
  97. <DropdownMenu
  98. isOpen = { this.state.isLanguageSelectOpen }
  99. onOpenChange = { this._onSetDropdownOpen }
  100. shouldFitContainer = { true }
  101. trigger = { currentLanguage
  102. ? t(`languages:${currentLanguage}`)
  103. : '' }
  104. triggerButtonProps = {{
  105. appearance: 'primary',
  106. shouldFitContainer: true
  107. }}
  108. triggerType = 'button'>
  109. <DropdownItemGroup>
  110. { languageItems }
  111. </DropdownItemGroup>
  112. </DropdownMenu>
  113. </div>
  114. );
  115. }
  116. /**
  117. * Updates the application's currently displayed language.
  118. *
  119. * @param {string} language - The language code for the language to display.
  120. * @private
  121. * @returns {void}
  122. */
  123. _onLanguageSelected(language) {
  124. const previousLanguage = this.state.currentLanguage;
  125. this.setState({
  126. currentLanguage: language,
  127. isLanguageSelectOpen: false
  128. });
  129. this.props.i18n.changeLanguage(language, error => {
  130. if (error) {
  131. this._setCurrentLanguage(previousLanguage);
  132. }
  133. });
  134. }
  135. /**
  136. * Set whether or not the dropdown should be open.
  137. *
  138. * @param {Object} dropdownEvent - The event returned from requesting the
  139. * open state of the dropdown be changed.
  140. * @private
  141. * @returns {void}
  142. */
  143. _onSetDropdownOpen(dropdownEvent) {
  144. this.setState({
  145. isLanguageSelectOpen: dropdownEvent.isOpen
  146. });
  147. }
  148. /**
  149. * Updates the known current language of the application.
  150. *
  151. * @param {string} currentLanguage - The language code for the current
  152. * language.
  153. * @private
  154. * @returns {void}
  155. */
  156. _setCurrentLanguage(currentLanguage) {
  157. this.setState({ currentLanguage });
  158. }
  159. }
  160. export default translate(LanguageSelectDropdown);