summaryrefslogtreecommitdiffstats
path: root/webapp/components
diff options
context:
space:
mode:
authorenahum <nahumhbl@gmail.com>2016-06-02 16:47:26 -0300
committerCorey Hulen <corey@hulen.com>2016-06-02 12:47:26 -0700
commit159953050a9c4fb700bbde79042ead4843b0bea5 (patch)
tree747a022c5cf579599402447b5e5d0f51dfee9f76 /webapp/components
parente44b8ec6d57fc55230a5c97ea105b7fd9ef59aca (diff)
downloadchat-159953050a9c4fb700bbde79042ead4843b0bea5.tar.gz
chat-159953050a9c4fb700bbde79042ead4843b0bea5.tar.bz2
chat-159953050a9c4fb700bbde79042ead4843b0bea5.zip
PLT-1800 Load server side locale from the config.json (#3202)
* PLT-1800 Load server side locale from the config.json * Add support for locales with country specifics * Fix localization on served locale file as plain/text * Remove github.com/cloudfoundry/jibber_jabber as vendor dependency * Fix get locale on login_controller
Diffstat (limited to 'webapp/components')
-rw-r--r--webapp/components/admin_console/admin_sidebar.jsx9
-rw-r--r--webapp/components/admin_console/localization_settings.jsx145
-rw-r--r--webapp/components/admin_console/multiselect_settings.jsx80
-rw-r--r--webapp/components/login/login_controller.jsx2
-rw-r--r--webapp/components/root.jsx8
-rw-r--r--webapp/components/user_settings/user_settings_display.jsx11
6 files changed, 251 insertions, 4 deletions
diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx
index 19a6316b6..d760e3db9 100644
--- a/webapp/components/admin_console/admin_sidebar.jsx
+++ b/webapp/components/admin_console/admin_sidebar.jsx
@@ -295,6 +295,15 @@ export default class AdminSidebar extends React.Component {
}
/>
<AdminSidebarSection
+ name='localization'
+ title={
+ <FormattedMessage
+ id='admin.sidebar.localization'
+ defaultMessage='Localization'
+ />
+ }
+ />
+ <AdminSidebarSection
name='users_and_teams'
title={
<FormattedMessage
diff --git a/webapp/components/admin_console/localization_settings.jsx b/webapp/components/admin_console/localization_settings.jsx
new file mode 100644
index 000000000..6876e0c36
--- /dev/null
+++ b/webapp/components/admin_console/localization_settings.jsx
@@ -0,0 +1,145 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+
+import * as I18n from 'i18n/i18n.jsx';
+
+import AdminSettings from './admin_settings.jsx';
+import {FormattedMessage} from 'react-intl';
+import SettingsGroup from './settings_group.jsx';
+import DropdownSetting from './dropdown_setting.jsx';
+import MultiSelectSetting from './multiselect_settings.jsx';
+
+export default class LocalizationSettings extends AdminSettings {
+ constructor(props) {
+ super(props);
+
+ this.getConfigFromState = this.getConfigFromState.bind(this);
+
+ this.renderSettings = this.renderSettings.bind(this);
+ this.canSave = this.canSave.bind(this);
+
+ const locales = I18n.getAllLanguages();
+
+ this.state = Object.assign(this.state, {
+ hasErrors: false,
+ defaultServerLocale: props.config.LocalizationSettings.DefaultServerLocale,
+ defaultClientLocale: props.config.LocalizationSettings.DefaultClientLocale,
+ availableLocales: props.config.LocalizationSettings.AvailableLocales.split(','),
+ languages: Object.keys(locales).map((l) => {
+ return {value: locales[l].value, text: locales[l].name};
+ })
+ });
+ }
+
+ canSave() {
+ return this.state.availableLocales.join(',').indexOf(this.state.defaultClientLocale) !== -1;
+ }
+
+ getConfigFromState(config) {
+ config.LocalizationSettings.DefaultServerLocale = this.state.defaultServerLocale;
+ config.LocalizationSettings.DefaultClientLocale = this.state.defaultClientLocale;
+ config.LocalizationSettings.AvailableLocales = this.state.availableLocales.join(',');
+
+ return config;
+ }
+
+ renderTitle() {
+ return (
+ <h3>
+ <FormattedMessage
+ id='admin.general.title'
+ defaultMessage='General Settings'
+ />
+ </h3>
+ );
+ }
+
+ renderSettings() {
+ return (
+ <SettingsGroup
+ header={
+ <FormattedMessage
+ id='admin.general.localization'
+ defaultMessage='Localization'
+ />
+ }
+ >
+ <DropdownSetting
+ id='defaultServerLocale'
+ values={this.state.languages}
+ label={
+ <FormattedMessage
+ id='admin.general.localization.serverLocaleTitle'
+ defaultMessage='Default Server Language:'
+ />
+ }
+ value={this.state.defaultServerLocale}
+ onChange={this.handleChange}
+ helpText={
+ <FormattedMessage
+ id='admin.general.localization.serverLocaleDescription'
+ defaultMessage='This setting sets the default language for the system messages and logs. (NEED SERVER RESTART)'
+ />
+ }
+ />
+ <DropdownSetting
+ id='defaultClientLocale'
+ values={this.state.languages}
+ label={
+ <FormattedMessage
+ id='admin.general.localization.clientLocaleTitle'
+ defaultMessage='Default Client Language:'
+ />
+ }
+ value={this.state.defaultClientLocale}
+ onChange={this.handleChange}
+ helpText={
+ <FormattedMessage
+ id='admin.general.localization.clientLocaleDescription'
+ defaultMessage="This setting sets the Default language for newly created users and for pages where the user hasn't loggged in."
+ />
+ }
+ />
+ <MultiSelectSetting
+ id='availableLocales'
+ values={this.state.languages}
+ label={
+ <FormattedMessage
+ id='admin.general.localization.availableLocalesTitle'
+ defaultMessage='Available Languages:'
+ />
+ }
+ selected={this.state.availableLocales}
+ mustBePresent={this.state.defaultClientLocale}
+ onChange={this.handleChange}
+ helpText={
+ <FormattedMessage
+ id='admin.general.localization.availableLocalesDescription'
+ defaultMessage='This setting determines the available languages that a user can set using the Account Settings.'
+ />
+ }
+ noResultText={
+ <FormattedMessage
+ id='admin.general.localization.availableLocalesNoResults'
+ defaultMessage='No results found'
+ />
+ }
+ errorText={
+ <FormattedMessage
+ id='admin.general.localization.availableLocalesError'
+ defaultMessage='There has to be at least one language available'
+ />
+ }
+ notPresent={
+ <FormattedMessage
+ id='admin.general.localization.availableLocalesNotPresent'
+ defaultMessage='The default client language must be included in the available list'
+ />
+ }
+ />
+ </SettingsGroup>
+ );
+ }
+} \ No newline at end of file
diff --git a/webapp/components/admin_console/multiselect_settings.jsx b/webapp/components/admin_console/multiselect_settings.jsx
new file mode 100644
index 000000000..deba983de
--- /dev/null
+++ b/webapp/components/admin_console/multiselect_settings.jsx
@@ -0,0 +1,80 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+import React from 'react';
+import ReactSelect from 'react-select';
+
+import Setting from './setting.jsx';
+import FormError from 'components/form_error.jsx';
+
+export default class MultiSelectSetting extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleChange = this.handleChange.bind(this);
+ this.state = {error: false};
+ }
+
+ handleChange(newValue) {
+ const values = newValue.map((n) => {
+ return n.value;
+ });
+
+ if (!newValue || newValue.length === 0) {
+ this.setState({error: this.props.errorText});
+ } else if (this.props.mustBePresent && values.join(',').indexOf(this.props.mustBePresent) === -1) {
+ this.setState({error: this.props.notPresent});
+ } else {
+ this.props.onChange(this.props.id, values);
+ this.setState({error: false});
+ }
+ }
+
+ componentWillReceiveProps(newProps) {
+ if (newProps.mustBePresent && newProps.selected.join(',').indexOf(newProps.mustBePresent) === -1) {
+ this.setState({error: this.props.notPresent});
+ } else {
+ this.setState({error: false});
+ }
+ }
+
+ render() {
+ return (
+ <Setting
+ label={this.props.label}
+ inputId={this.props.id}
+ helpText={this.props.helpText}
+ >
+ <ReactSelect
+ id={this.props.id}
+ multi={true}
+ labelKey='text'
+ options={this.props.values}
+ joinValues={true}
+ disabled={this.props.disabled}
+ noResultsText={this.props.noResultText}
+ onChange={this.handleChange}
+ value={this.props.selected}
+ />
+ <FormError error={this.state.error}/>
+ </Setting>
+ );
+ }
+}
+
+MultiSelectSetting.defaultProps = {
+ disabled: false
+};
+
+MultiSelectSetting.propTypes = {
+ id: React.PropTypes.string.isRequired,
+ values: React.PropTypes.array.isRequired,
+ label: React.PropTypes.node.isRequired,
+ selected: React.PropTypes.array.isRequired,
+ mustBePresent: React.PropTypes.string,
+ onChange: React.PropTypes.func.isRequired,
+ disabled: React.PropTypes.bool,
+ helpText: React.PropTypes.node,
+ noResultText: React.PropTypes.node,
+ errorText: React.PropTypes.node,
+ notPresent: React.PropTypes.node
+}; \ No newline at end of file
diff --git a/webapp/components/login/login_controller.jsx b/webapp/components/login/login_controller.jsx
index 1b1f65436..c1b7f8a74 100644
--- a/webapp/components/login/login_controller.jsx
+++ b/webapp/components/login/login_controller.jsx
@@ -118,7 +118,7 @@ export default class LoginController extends React.Component {
finishSignin() {
GlobalActions.emitInitialLoad(
() => {
- GlobalActions.loadBrowserLocale();
+ GlobalActions.loadDefaultLocale();
browserHistory.push('/select_team');
}
);
diff --git a/webapp/components/root.jsx b/webapp/components/root.jsx
index c96499392..abaa05bb5 100644
--- a/webapp/components/root.jsx
+++ b/webapp/components/root.jsx
@@ -6,6 +6,7 @@
import * as GlobalActions from 'actions/global_actions.jsx';
import LocalizationStore from 'stores/localization_store.jsx';
+import Client from 'utils/web_client.jsx';
import {IntlProvider} from 'react-intl';
@@ -41,7 +42,10 @@ export default class Root extends React.Component {
FastClick.attach(document.body);
}
localizationChanged() {
- this.setState({locale: LocalizationStore.getLocale(), translations: LocalizationStore.getTranslations()});
+ const locale = LocalizationStore.getLocale();
+
+ Client.setAcceptLanguage(locale);
+ this.setState({locale, translations: LocalizationStore.getTranslations()});
}
redirectIfNecessary(props) {
@@ -67,7 +71,7 @@ export default class Root extends React.Component {
LocalizationStore.addChangeListener(this.localizationChanged);
// Get our localizaiton
- GlobalActions.loadBrowserLocale();
+ GlobalActions.loadDefaultLocale();
}
componentWillUnmount() {
LocalizationStore.removeChangeListener(this.localizationChanged);
diff --git a/webapp/components/user_settings/user_settings_display.jsx b/webapp/components/user_settings/user_settings_display.jsx
index a7015d403..7036d7389 100644
--- a/webapp/components/user_settings/user_settings_display.jsx
+++ b/webapp/components/user_settings/user_settings_display.jsx
@@ -641,7 +641,11 @@ export default class UserSettingsDisplay extends React.Component {
);
}
+ const userLocale = this.props.user.locale;
if (this.props.activeSection === 'languages') {
+ if (!I18n.isLanguageAvailable(userLocale)) {
+ this.props.user.locale = global.window.mm_config.DefaultClientLocale;
+ }
languagesSection = (
<ManageLanguages
user={this.props.user}
@@ -652,7 +656,12 @@ export default class UserSettingsDisplay extends React.Component {
/>
);
} else {
- var locale = I18n.getLanguageInfo(this.props.user.locale).name;
+ let locale;
+ if (I18n.isLanguageAvailable(userLocale)) {
+ locale = I18n.getLanguageInfo(userLocale).name;
+ } else {
+ locale = I18n.getLanguageInfo(global.window.mm_config.DefaultClientLocale).name;
+ }
languagesSection = (
<SettingItemMin