From 2a26d857574f2160e3ee5538ad3a84ec47082f86 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Thu, 21 Jan 2016 12:14:17 -0500 Subject: Generalize analytics server functions and begin componentizing client analytics controls --- api/admin.go | 12 +- mattermost.go | 4 +- store/sql_channel_store.go | 16 +- store/sql_post_store.go | 52 ++-- store/sql_user_store.go | 27 ++ store/store.go | 1 + web/react/components/admin_console/analytics.jsx | 277 +++++++++++++++++++++ .../components/admin_console/team_analytics.jsx | 256 +++---------------- web/react/utils/client.jsx | 18 +- 9 files changed, 407 insertions(+), 256 deletions(-) create mode 100644 web/react/components/admin_console/analytics.jsx diff --git a/api/admin.go b/api/admin.go index 72a95ba6a..e19616986 100644 --- a/api/admin.go +++ b/api/admin.go @@ -27,6 +27,7 @@ func InitAdmin(r *mux.Router) { sr.Handle("/client_props", ApiAppHandler(getClientConfig)).Methods("GET") sr.Handle("/log_client", ApiAppHandler(logClient)).Methods("POST") sr.Handle("/analytics/{id:[A-Za-z0-9]+}/{name:[A-Za-z0-9_]+}", ApiAppHandler(getAnalytics)).Methods("GET") + sr.Handle("/analytics/{name:[A-Za-z0-9_]+}", ApiAppHandler(getAnalytics)).Methods("GET") } func getLogs(c *Context, w http.ResponseWriter, r *http.Request) { @@ -153,13 +154,15 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { name := params["name"] if name == "standard" { - var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 3) + var rows model.AnalyticsRows = make([]*model.AnalyticsRow, 4) rows[0] = &model.AnalyticsRow{"channel_open_count", 0} rows[1] = &model.AnalyticsRow{"channel_private_count", 0} rows[2] = &model.AnalyticsRow{"post_count", 0} + rows[3] = &model.AnalyticsRow{"unique_user_count", 0} openChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_OPEN) privateChan := Srv.Store.Channel().AnalyticsTypeCount(teamId, model.CHANNEL_PRIVATE) postChan := Srv.Store.Post().AnalyticsPostCount(teamId) + userChan := Srv.Store.User().AnalyticsUniqueUserCount(teamId) if r := <-openChan; r.Err != nil { c.Err = r.Err @@ -182,6 +185,13 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) { rows[2].Value = float64(r.Data.(int64)) } + if r := <-userChan; r.Err != nil { + c.Err = r.Err + return + } else { + rows[3].Value = float64(r.Data.(int64)) + } + w.Write([]byte(rows.ToJson())) } else if name == "post_counts_day" { if r := <-Srv.Store.Post().AnalyticsPostCountsByDay(teamId); r.Err != nil { diff --git a/mattermost.go b/mattermost.go index 9786a6abd..51a9591db 100644 --- a/mattermost.go +++ b/mattermost.go @@ -66,7 +66,9 @@ func main() { api.InitApi() web.InitWeb() - utils.LoadLicense() + if model.BuildEnterpriseReady == "true" { + utils.LoadLicense() + } if flagRunCmds { runCmds() diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index 4585647de..336398ae7 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -869,15 +869,13 @@ func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) S go func() { result := StoreResult{} - v, err := s.GetReplica().SelectInt( - `SELECT - COUNT(Id) AS Value - FROM - Channels - WHERE - TeamId = :TeamId - AND Type = :ChannelType`, - map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) + query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType" + + if len(teamId) > 0 { + query += " AND TeamId = :TeamId" + } + + v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.AnalyticsTypeCount", "We couldn't get channel type counts", err.Error()) } else { diff --git a/store/sql_post_store.go b/store/sql_post_store.go index 40dca9930..e332858e4 100644 --- a/store/sql_post_store.go +++ b/store/sql_post_store.go @@ -805,9 +805,13 @@ func (s SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) StoreChan FROM Posts, Channels WHERE - Posts.ChannelId = Channels.Id - AND Channels.TeamId = :TeamId - AND Posts.CreateAt <= :EndTime + Posts.ChannelId = Channels.Id` + + if len(teamId) > 0 { + query += " AND Channels.TeamId = :TeamId" + } + + query += ` AND Posts.CreateAt <= :EndTime ORDER BY Name DESC) AS t1 GROUP BY Name ORDER BY Name DESC @@ -824,9 +828,13 @@ func (s SqlPostStore) AnalyticsUserCountsWithPostsByDay(teamId string) StoreChan FROM Posts, Channels WHERE - Posts.ChannelId = Channels.Id - AND Channels.TeamId = :TeamId - AND Posts.CreateAt <= :EndTime + Posts.ChannelId = Channels.Id` + + if len(teamId) > 0 { + query += " AND Channels.TeamId = :TeamId" + } + + query += ` AND Posts.CreateAt <= :EndTime ORDER BY Name DESC) AS t1 GROUP BY Name ORDER BY Name DESC @@ -869,9 +877,13 @@ func (s SqlPostStore) AnalyticsPostCountsByDay(teamId string) StoreChannel { FROM Posts, Channels WHERE - Posts.ChannelId = Channels.Id - AND Channels.TeamId = :TeamId - AND Posts.CreateAt <= :EndTime + Posts.ChannelId = Channels.Id` + + if len(teamId) > 0 { + query += " AND Channels.TeamId = :TeamId" + } + + query += ` AND Posts.CreateAt <= :EndTime AND Posts.CreateAt >= :StartTime) AS t1 GROUP BY Name ORDER BY Name DESC @@ -888,9 +900,13 @@ func (s SqlPostStore) AnalyticsPostCountsByDay(teamId string) StoreChannel { FROM Posts, Channels WHERE - Posts.ChannelId = Channels.Id - AND Channels.TeamId = :TeamId - AND Posts.CreateAt <= :EndTime + Posts.ChannelId = Channels.Id` + + if len(teamId) > 0 { + query += " AND Channels.TeamId = :TeamId" + } + + query += ` AND Posts.CreateAt <= :EndTime AND Posts.CreateAt >= :StartTime) AS t1 GROUP BY Name ORDER BY Name DESC @@ -924,16 +940,20 @@ func (s SqlPostStore) AnalyticsPostCount(teamId string) StoreChannel { go func() { result := StoreResult{} - v, err := s.GetReplica().SelectInt( + query := `SELECT COUNT(Posts.Id) AS Value FROM Posts, Channels WHERE - Posts.ChannelId = Channels.Id - AND Channels.TeamId = :TeamId`, - map[string]interface{}{"TeamId": teamId}) + Posts.ChannelId = Channels.Id` + + if len(teamId) > 0 { + query += " AND Channels.TeamId = :TeamId" + } + + v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId}) if err != nil { result.Err = model.NewAppError("SqlPostStore.AnalyticsPostCount", "We couldn't get post counts", err.Error()) } else { diff --git a/store/sql_user_store.go b/store/sql_user_store.go index 0f73f73c3..efd8b7f33 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -600,3 +600,30 @@ func (us SqlUserStore) PermanentDelete(userId string) StoreChannel { return storeChannel } + +func (us SqlUserStore) AnalyticsUniqueUserCount(teamId string) StoreChannel { + + storeChannel := make(StoreChannel) + + go func() { + result := StoreResult{} + + query := "SELECT COUNT(DISTINCT Email) FROM Users" + + if len(teamId) > 0 { + query += " WHERE TeamId = :TeamId" + } + + v, err := us.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId}) + if err != nil { + result.Err = model.NewAppError("SqlUserStore.AnalyticsUniqueUserCount", "We couldn't get the unique user count", err.Error()) + } else { + result.Data = v + } + + storeChannel <- result + close(storeChannel) + }() + + return storeChannel +} diff --git a/store/store.go b/store/store.go index 179cfecd7..b91b08f27 100644 --- a/store/store.go +++ b/store/store.go @@ -125,6 +125,7 @@ type UserStore interface { GetTotalActiveUsersCount() StoreChannel GetSystemAdminProfiles() StoreChannel PermanentDelete(userId string) StoreChannel + AnalyticsUniqueUserCount(teamId string) StoreChannel } type SessionStore interface { diff --git a/web/react/components/admin_console/analytics.jsx b/web/react/components/admin_console/analytics.jsx new file mode 100644 index 000000000..4349719c1 --- /dev/null +++ b/web/react/components/admin_console/analytics.jsx @@ -0,0 +1,277 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import * as Utils from '../../utils/utils.jsx'; +import Constants from '../../utils/constants.jsx'; +import LineChart from './line_chart.jsx'; + +var Tooltip = ReactBootstrap.Tooltip; +var OverlayTrigger = ReactBootstrap.OverlayTrigger; + +export default class Analytics extends React.Component { + constructor(props) { + super(props); + + this.state = {}; + } + + render() { // in the future, break down these into smaller components + var serverError = ''; + if (this.props.serverError) { + serverError =
; + } + + var totalCount = ( +
+
+
{'Total Users'}
+
{this.props.uniqueUserCount == null ? 'Loading...' : this.props.uniqueUserCount}
+
+
+ ); + + var openChannelCount = ( +
+
+
{'Public Channels'}
+
{this.props.channelOpenCount == null ? 'Loading...' : this.props.channelOpenCount}
+
+
+ ); + + var openPrivateCount = ( +
+
+
{'Private Groups'}
+
{this.props.channelPrivateCount == null ? 'Loading...' : this.props.channelPrivateCount}
+
+
+ ); + + var postCount = ( +
+
+
{'Total Posts'}
+
{this.props.postCount == null ? 'Loading...' : this.props.postCount}
+
+
+ ); + + var postCountsByDay = ( +
+
+
{'Total Posts'}
+
{'Loading...'}
+
+
+ ); + + if (this.props.postCountsDay != null) { + let content; + if (this.props.postCountsDay.labels.length === 0) { + content = 'Not enough data for a meaningful representation.'; + } else { + content = ( + + ); + } + postCountsByDay = ( +
+
+
{'Total Posts'}
+
+ {content} +
+
+
+ ); + } + + var usersWithPostsByDay = ( +
+
+
{'Total Posts'}
+
{'Loading...'}
+
+
+ ); + + if (this.props.userCountsWithPostsDay != null) { + let content; + if (this.props.userCountsWithPostsDay.labels.length === 0) { + content = 'Not enough data for a meaningful representation.'; + } else { + content = ( + + ); + } + usersWithPostsByDay = ( +
+
+
{'Active Users With Posts'}
+
+ {content} +
+
+
+ ); + } + + var recentActiveUser = ( +
+
{'Recent Active Users'}
+
{'Loading...'}
+
+ ); + + if (this.props.recentActiveUsers != null) { + recentActiveUser = ( +
+
+
{'Recent Active Users'}
+
+ + + { + this.props.recentActiveUsers.map((user) => { + const tooltip = ( + + {user.email} + + ); + + return ( + + + + + ); + }) + } + +
+ + + + {Utils.displayDateTime(user.last_activity_at)}
+
+
+
+ ); + } + + var newUsers = ( +
+
{'Newly Created Users'}
+
{'Loading...'}
+
+ ); + + if (this.props.newlyCreatedUsers != null) { + newUsers = ( +
+
+
{'Newly Created Users'}
+
+ + + { + this.props.newlyCreatedUsers.map((user) => { + const tooltip = ( + + {user.email} + + ); + + return ( + + + + + ); + }) + } + +
+ + + + {Utils.displayDateTime(user.create_at)}
+
+
+
+ ); + } + + return ( +
+

{'Statistics for ' + this.props.title}

+
+ {totalCount} + {postCount} + {openChannelCount} + {openPrivateCount} +
+
+ {postCountsByDay} +
+
+ {usersWithPostsByDay} +
+
+ {recentActiveUser} + {newUsers} +
+
+ ); + } +} + + +Analytics.defaultProps = { + title: null, + users: null, + channelOpenCount: null, + channelPrivateCount: null, + postCount: null, + postCountsDay: null, + userCountsWithPostsDay: null, + recentActiveUsers: null, + newlyCreatedUsers: null, + uniqueUserCount: null, + serverError: null +}; + +Analytics.propTypes = { + title: React.PropTypes.string, + users: React.PropTypes.object, + channelOpenCount: React.PropTypes.number, + channelPrivateCount: React.PropTypes.number, + postCount: React.PropTypes.number, + postCountsDay: React.PropTypes.object, + userCountsWithPostsDay: React.PropTypes.object, + recentActiveUsers: React.PropTypes.array, + newlyCreatedUsers: React.PropTypes.array, + uniqueUserCount: React.PropTypes.number, + serverError: React.PropTypes.string +}; diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx index fe7230946..baa041bac 100644 --- a/web/react/components/admin_console/team_analytics.jsx +++ b/web/react/components/admin_console/team_analytics.jsx @@ -1,13 +1,8 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. +import Analytics from './analytics.jsx'; import * as Client from '../../utils/client.jsx'; -import * as Utils from '../../utils/utils.jsx'; -import Constants from '../../utils/constants.jsx'; -import LineChart from './line_chart.jsx'; - -var Tooltip = ReactBootstrap.Tooltip; -var OverlayTrigger = ReactBootstrap.OverlayTrigger; export default class TeamAnalytics extends React.Component { constructor(props) { @@ -15,7 +10,7 @@ export default class TeamAnalytics extends React.Component { this.getData = this.getData.bind(this); - this.state = { + this.state = { // most of this state should be from a store in the future users: null, serverError: null, channel_open_count: null, @@ -24,7 +19,8 @@ export default class TeamAnalytics extends React.Component { post_counts_day: null, user_counts_with_posts_day: null, recent_active_users: null, - newly_created_users: null + newly_created_users: null, + unique_user_count: null }; } @@ -32,8 +28,8 @@ export default class TeamAnalytics extends React.Component { this.getData(this.props.team.id); } - getData(teamId) { - Client.getAnalytics( + getData(teamId) { // should be moved to an action creator eventually + Client.getTeamAnalytics( teamId, 'standard', (data) => { @@ -49,6 +45,10 @@ export default class TeamAnalytics extends React.Component { if (data[index].name === 'post_count') { this.setState({post_count: data[index].value}); } + + if (data[index].name === 'unique_user_count') { + this.setState({unique_user_count: data[index].value}); + } } }, (err) => { @@ -56,7 +56,7 @@ export default class TeamAnalytics extends React.Component { } ); - Client.getAnalytics( + Client.getTeamAnalytics( teamId, 'post_counts_day', (data) => { @@ -91,7 +91,7 @@ export default class TeamAnalytics extends React.Component { } ); - Client.getAnalytics( + Client.getTeamAnalytics( teamId, 'user_counts_with_posts_day', (data) => { @@ -198,227 +198,29 @@ export default class TeamAnalytics extends React.Component { post_counts_day: null, user_counts_with_posts_day: null, recent_active_users: null, - newly_created_users: null + newly_created_users: null, + unique_user_count: null }); this.getData(newProps.team.id); } - componentWillUnmount() { - } - render() { - var serverError = ''; - if (this.state.serverError) { - serverError =
; - } - - var totalCount = ( -
-
-
{'Total Users'}
-
{this.state.users == null ? 'Loading...' : Object.keys(this.state.users).length}
-
-
- ); - - var openChannelCount = ( -
-
-
{'Public Channels'}
-
{this.state.channel_open_count == null ? 'Loading...' : this.state.channel_open_count}
-
-
- ); - - var openPrivateCount = ( -
-
-
{'Private Groups'}
-
{this.state.channel_private_count == null ? 'Loading...' : this.state.channel_private_count}
-
-
- ); - - var postCount = ( -
-
-
{'Total Posts'}
-
{this.state.post_count == null ? 'Loading...' : this.state.post_count}
-
-
- ); - - var postCountsByDay = ( -
-
-
{'Total Posts'}
-
{'Loading...'}
-
-
- ); - - if (this.state.post_counts_day != null) { - postCountsByDay = ( -
-
-
{'Total Posts'}
-
- -
-
-
- ); - } - - var usersWithPostsByDay = ( -
-
-
{'Total Posts'}
-
{'Loading...'}
-
-
- ); - - if (this.state.user_counts_with_posts_day != null) { - usersWithPostsByDay = ( -
-
-
{'Active Users With Posts'}
-
- -
-
-
- ); - } - - var recentActiveUser = ( -
-
{'Recent Active Users'}
-
{'Loading...'}
-
- ); - - if (this.state.recent_active_users != null) { - recentActiveUser = ( -
-
-
{'Recent Active Users'}
-
- - - { - this.state.recent_active_users.map((user) => { - const tooltip = ( - - {user.email} - - ); - - return ( - - - - - ); - }) - } - -
- - - - {Utils.displayDateTime(user.last_activity_at)}
-
-
-
- ); - } - - var newUsers = ( -
-
{'Newly Created Users'}
-
{'Loading...'}
-
- ); - - if (this.state.newly_created_users != null) { - newUsers = ( -
-
-
{'Newly Created Users'}
-
- - - { - this.state.newly_created_users.map((user) => { - const tooltip = ( - - {user.email} - - ); - - return ( - - - - - ); - }) - } - -
- - - - {Utils.displayDateTime(user.create_at)}
-
-
-
- ); - } - return ( -
-

{'Statistics for ' + this.props.team.name}

- {serverError} -
- {totalCount} - {postCount} - {openChannelCount} - {openPrivateCount} -
-
- {postCountsByDay} -
-
- {usersWithPostsByDay} -
-
- {recentActiveUser} - {newUsers} -
+
+
); } diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index d60fea872..8484f3cce 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -387,7 +387,7 @@ export function getConfig(success, error) { }); } -export function getAnalytics(teamId, name, success, error) { +export function getTeamAnalytics(teamId, name, success, error) { $.ajax({ url: '/api/v1/admin/analytics/' + teamId + '/' + name, dataType: 'json', @@ -395,7 +395,21 @@ export function getAnalytics(teamId, name, success, error) { type: 'GET', success, error: (xhr, status, err) => { - var e = handleError('getAnalytics', xhr, status, err); + var e = handleError('getTeamAnalytics', xhr, status, err); + error(e); + } + }); +} + +export function getServerAnalytics(name, success, error) { + $.ajax({ + url: '/api/v1/admin/analytics/' + name, + dataType: 'json', + contentType: 'application/json', + type: 'GET', + success, + error: (xhr, status, err) => { + var e = handleError('getServerAnalytics', xhr, status, err); error(e); } }); -- cgit v1.2.3-1-g7c22 From cefdad6d8c71ff6adf0ae919bd9f9139e02a6caa Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Thu, 21 Jan 2016 12:59:32 -0500 Subject: Add system analytics page --- .../components/admin_console/admin_controller.jsx | 5 +- .../components/admin_console/admin_sidebar.jsx | 19 +++ web/react/components/admin_console/analytics.jsx | 158 ++++++++++---------- .../components/admin_console/system_analytics.jsx | 161 +++++++++++++++++++++ web/react/utils/client.jsx | 4 +- 5 files changed, 266 insertions(+), 81 deletions(-) create mode 100644 web/react/components/admin_console/system_analytics.jsx diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index 0f85c238d..db98d8f35 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. import AdminSidebar from './admin_sidebar.jsx'; @@ -23,6 +23,7 @@ import TeamUsersTab from './team_users.jsx'; import TeamAnalyticsTab from './team_analytics.jsx'; import LdapSettingsTab from './ldap_settings.jsx'; import LicenseSettingsTab from './license_settings.jsx'; +import SystemAnalyticsTab from './system_analytics.jsx'; export default class AdminController extends React.Component { constructor(props) { @@ -165,6 +166,8 @@ export default class AdminController extends React.Component { if (this.state.teams) { tab = ; } + } else if (this.state.selected === 'system_analytics') { + tab = ; } } diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index 5a5eaa055..66f82c55b 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -192,6 +192,25 @@ export default class AdminSidebar extends React.Component {
  • +
      +
    • +

      + + {'SITE REPORTS'} +

      +
    • +
    +
    • diff --git a/web/react/components/admin_console/analytics.jsx b/web/react/components/admin_console/analytics.jsx index 4349719c1..8fdf538f8 100644 --- a/web/react/components/admin_console/analytics.jsx +++ b/web/react/components/admin_console/analytics.jsx @@ -94,8 +94,8 @@ export default class Analytics extends React.Component { var usersWithPostsByDay = (
      -
      {'Total Posts'}
      -
      {'Loading...'}
      +
      {'Active Users With Posts'}
      +
      {'Loading...'}
      ); @@ -125,98 +125,102 @@ export default class Analytics extends React.Component { ); } - var recentActiveUser = ( -
      -
      {'Recent Active Users'}
      -
      {'Loading...'}
      -
      - ); - + let recentActiveUser; if (this.props.recentActiveUsers != null) { + let content; + if (this.props.recentActiveUsers.length === 0) { + content = 'Loading...'; + } else { + content = ( + + + { + this.props.recentActiveUsers.map((user) => { + const tooltip = ( + + {user.email} + + ); + + return ( + + + + + ); + }) + } + +
      + + + + {Utils.displayDateTime(user.last_activity_at)}
      + ); + } recentActiveUser = (
      {'Recent Active Users'}
      - - - { - this.props.recentActiveUsers.map((user) => { - const tooltip = ( - - {user.email} - - ); - - return ( - - - - - ); - }) - } - -
      - - - - {Utils.displayDateTime(user.last_activity_at)}
      + {content}
      ); } - var newUsers = ( -
      -
      {'Newly Created Users'}
      -
      {'Loading...'}
      -
      - ); - + let newUsers; if (this.props.newlyCreatedUsers != null) { + let content; + if (this.props.newlyCreatedUsers.length === 0) { + content = 'Loading...'; + } else { + content = ( + + + { + this.props.newlyCreatedUsers.map((user) => { + const tooltip = ( + + {user.email} + + ); + + return ( + + + + + ); + }) + } + +
      + + + + {Utils.displayDateTime(user.create_at)}
      + ); + } newUsers = (
      {'Newly Created Users'}
      - - - { - this.props.newlyCreatedUsers.map((user) => { - const tooltip = ( - - {user.email} - - ); - - return ( - - - - - ); - }) - } - -
      - - - - {Utils.displayDateTime(user.create_at)}
      + {content}
      @@ -250,7 +254,6 @@ export default class Analytics extends React.Component { Analytics.defaultProps = { title: null, - users: null, channelOpenCount: null, channelPrivateCount: null, postCount: null, @@ -264,7 +267,6 @@ Analytics.defaultProps = { Analytics.propTypes = { title: React.PropTypes.string, - users: React.PropTypes.object, channelOpenCount: React.PropTypes.number, channelPrivateCount: React.PropTypes.number, postCount: React.PropTypes.number, diff --git a/web/react/components/admin_console/system_analytics.jsx b/web/react/components/admin_console/system_analytics.jsx new file mode 100644 index 000000000..640f17ff0 --- /dev/null +++ b/web/react/components/admin_console/system_analytics.jsx @@ -0,0 +1,161 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import Analytics from './analytics.jsx'; +import * as Client from '../../utils/client.jsx'; + +export default class SystemAnalytics extends React.Component { + constructor(props) { + super(props); + + this.getData = this.getData.bind(this); + + this.state = { // most of this state should be from a store in the future + users: null, + serverError: null, + channel_open_count: null, + channel_private_count: null, + post_count: null, + post_counts_day: null, + user_counts_with_posts_day: null, + recent_active_users: null, + newly_created_users: null, + unique_user_count: null + }; + } + + componentDidMount() { + this.getData(); + } + + getData() { // should be moved to an action creator eventually + Client.getSystemAnalytics( + 'standard', + (data) => { + for (var index in data) { + if (data[index].name === 'channel_open_count') { + this.setState({channel_open_count: data[index].value}); + } + + if (data[index].name === 'channel_private_count') { + this.setState({channel_private_count: data[index].value}); + } + + if (data[index].name === 'post_count') { + this.setState({post_count: data[index].value}); + } + + if (data[index].name === 'unique_user_count') { + this.setState({unique_user_count: data[index].value}); + } + } + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + + Client.getSystemAnalytics( + 'post_counts_day', + (data) => { + data.reverse(); + + var chartData = { + labels: [], + datasets: [{ + label: 'Total Posts', + fillColor: 'rgba(151,187,205,0.2)', + strokeColor: 'rgba(151,187,205,1)', + pointColor: 'rgba(151,187,205,1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(151,187,205,1)', + data: [] + }] + }; + + for (var index in data) { + if (data[index]) { + var row = data[index]; + chartData.labels.push(row.name); + chartData.datasets[0].data.push(row.value); + } + } + + this.setState({post_counts_day: chartData}); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + + Client.getSystemAnalytics( + 'user_counts_with_posts_day', + (data) => { + data.reverse(); + + var chartData = { + labels: [], + datasets: [{ + label: 'Active Users With Posts', + fillColor: 'rgba(151,187,205,0.2)', + strokeColor: 'rgba(151,187,205,1)', + pointColor: 'rgba(151,187,205,1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(151,187,205,1)', + data: [] + }] + }; + + for (var index in data) { + if (data[index]) { + var row = data[index]; + chartData.labels.push(row.name); + chartData.datasets[0].data.push(row.value); + } + } + + this.setState({user_counts_with_posts_day: chartData}); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + componentWillReceiveProps(newProps) { + this.setState({ + serverError: null, + channel_open_count: null, + channel_private_count: null, + post_count: null, + post_counts_day: null, + user_counts_with_posts_day: null, + unique_user_count: null + }); + + this.getData(); + } + + render() { + return ( +
      + +
      + ); + } +} + +SystemAnalytics.propTypes = { + team: React.PropTypes.object +}; diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index 8484f3cce..96fa342a3 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -401,7 +401,7 @@ export function getTeamAnalytics(teamId, name, success, error) { }); } -export function getServerAnalytics(name, success, error) { +export function getSystemAnalytics(name, success, error) { $.ajax({ url: '/api/v1/admin/analytics/' + name, dataType: 'json', @@ -409,7 +409,7 @@ export function getServerAnalytics(name, success, error) { type: 'GET', success, error: (xhr, status, err) => { - var e = handleError('getServerAnalytics', xhr, status, err); + var e = handleError('getSystemAnalytics', xhr, status, err); error(e); } }); -- cgit v1.2.3-1-g7c22 From c408e09a0418c77e1f1f0a91a1c85bf5f20145e7 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Wed, 20 Jan 2016 13:16:53 -0800 Subject: Fixed issue with enter key not working in delete post modal --- web/react/components/delete_post_modal.jsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/web/react/components/delete_post_modal.jsx b/web/react/components/delete_post_modal.jsx index 827654e1b..4cde5feed 100644 --- a/web/react/components/delete_post_modal.jsx +++ b/web/react/components/delete_post_modal.jsx @@ -23,7 +23,7 @@ export default class DeletePostModal extends React.Component { this.selectedList = null; this.state = { - show: true, + show: false, post: null, commentCount: 0, error: '' @@ -40,6 +40,14 @@ export default class DeletePostModal extends React.Component { ModalStore.removeModalListener(ActionTypes.TOGGLE_DELETE_POST_MODAL, this.handleToggle); } + componentDidUpdate(prevProps, prevState) { + if (this.state.show && !prevState.show) { + setTimeout(() => { + $(ReactDOM.findDOMNode(this.refs.deletePostBtn)).focus(); + }, 0); + } + } + handleDelete() { Client.deletePost( this.state.post.channel_id, @@ -149,10 +157,10 @@ export default class DeletePostModal extends React.Component { {'Cancel'} -- cgit v1.2.3-1-g7c22 From bbcf00f02e469bcf04a45c1cdf8a7932e30ccfc0 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 22 Jan 2016 09:53:17 -0500 Subject: Add create_at back to profile fields to fix analytics --- api/license.go | 13 +++++++++++++ model/user.go | 1 - utils/license.go | 3 ++- web/react/components/admin_console/system_analytics.jsx | 2 +- web/react/components/admin_console/team_analytics.jsx | 4 ++++ 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/api/license.go b/api/license.go index 5b3809651..fc2fd4384 100644 --- a/api/license.go +++ b/api/license.go @@ -5,6 +5,7 @@ package api import ( "bytes" + "fmt" l4g "github.com/alecthomas/log4go" "github.com/gorilla/mux" "github.com/mattermost/platform/model" @@ -63,6 +64,18 @@ func addLicense(c *Context, w http.ResponseWriter, r *http.Request) { if success, licenseStr := utils.ValidateLicense(data); success { license = model.LicenseFromJson(strings.NewReader(licenseStr)) + if result := <-Srv.Store.User().AnalyticsUniqueUserCount(""); result.Err != nil { + c.Err = model.NewAppError("addLicense", "Unable to count total unique users.", fmt.Sprintf("err=%v", result.Err.Error())) + return + } else { + uniqueUserCount := result.Data.(int64) + + if uniqueUserCount > int64(*license.Features.Users) { + c.Err = model.NewAppError("addLicense", fmt.Sprintf("This license only supports %d users, when your system has %d unique users. Unique users are counted distinctly by email address. You can see total user count under Site Reports -> View Statistics.", *license.Features.Users, uniqueUserCount), "") + return + } + } + if ok := utils.SetLicense(license); !ok { c.LogAudit("failed - expired or non-started license") c.Err = model.NewAppError("addLicense", "License is either expired or has not yet started.", "") diff --git a/model/user.go b/model/user.go index 7744b0073..44228d93f 100644 --- a/model/user.go +++ b/model/user.go @@ -236,7 +236,6 @@ func (u *User) Sanitize(options map[string]bool) { } func (u *User) ClearNonProfileFields() { - u.CreateAt = 0 u.UpdateAt = 0 u.Password = "" u.AuthData = "" diff --git a/utils/license.go b/utils/license.go index 7594e33af..4fba94d4d 100644 --- a/utils/license.go +++ b/utils/license.go @@ -55,6 +55,7 @@ func LoadLicense() { if success, licenseStr := ValidateLicense(buf.Bytes()); success { license := model.LicenseFromJson(strings.NewReader(licenseStr)) SetLicense(license) + return } l4g.Warn("No valid enterprise license found") @@ -105,7 +106,7 @@ func ValidateLicense(signed []byte) (bool, string) { } // remove null terminator - if decoded[len(decoded)-1] == byte(0) { + for decoded[len(decoded)-1] == byte(0) { decoded = decoded[:len(decoded)-1] } diff --git a/web/react/components/admin_console/system_analytics.jsx b/web/react/components/admin_console/system_analytics.jsx index 640f17ff0..fffe7cc53 100644 --- a/web/react/components/admin_console/system_analytics.jsx +++ b/web/react/components/admin_console/system_analytics.jsx @@ -142,7 +142,7 @@ export default class SystemAnalytics extends React.Component { return (
      19) { break; -- cgit v1.2.3-1-g7c22 From 0d239a1a9e82a1279685b8962920eaf5c1b8f571 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 22 Jan 2016 10:19:02 -0500 Subject: Added unit test and fixed errors --- api/admin_test.go | 70 +++++++++++++++++++--- model/client.go | 11 +++- web/react/components/admin_console/analytics.jsx | 4 +- .../components/admin_console/system_analytics.jsx | 2 +- 4 files changed, 76 insertions(+), 11 deletions(-) diff --git a/api/admin_test.go b/api/admin_test.go index f7b6a7eeb..c2f4e9c76 100644 --- a/api/admin_test.go +++ b/api/admin_test.go @@ -151,7 +151,7 @@ func TestEmailTest(t *testing.T) { } } -func TestGetAnalyticsStandard(t *testing.T) { +func TestGetTeamAnalyticsStandard(t *testing.T) { Setup() team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} @@ -169,7 +169,7 @@ func TestGetAnalyticsStandard(t *testing.T) { post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"} post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post) - if _, err := Client.GetAnalytics(team.Id, "standard"); err == nil { + if _, err := Client.GetTeamAnalytics(team.Id, "standard"); err == nil { t.Fatal("Shouldn't have permissions") } @@ -180,7 +180,7 @@ func TestGetAnalyticsStandard(t *testing.T) { Client.LoginByEmail(team.Name, user.Email, "pwd") - if result, err := Client.GetAnalytics(team.Id, "standard"); err != nil { + if result, err := Client.GetTeamAnalytics(team.Id, "standard"); err != nil { t.Fatal(err) } else { rows := result.Data.(model.AnalyticsRows) @@ -214,6 +214,62 @@ func TestGetAnalyticsStandard(t *testing.T) { t.Log(rows.ToJson()) t.Fatal() } + + if rows[3].Name != "unique_user_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[3].Value != 1 { + t.Log(rows.ToJson()) + t.Fatal() + } + } + + if result, err := Client.GetSystemAnalytics("standard"); err != nil { + t.Fatal(err) + } else { + rows := result.Data.(model.AnalyticsRows) + + if rows[0].Name != "channel_open_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[0].Value < 2 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[1].Name != "channel_private_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[1].Value == 0 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[2].Name != "post_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[2].Value == 0 { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[3].Name != "unique_user_count" { + t.Log(rows.ToJson()) + t.Fatal() + } + + if rows[3].Value == 0 { + t.Log(rows.ToJson()) + t.Fatal() + } } } @@ -239,7 +295,7 @@ func TestGetPostCount(t *testing.T) { Srv.Store.(*store.SqlStore).GetMaster().Exec("UPDATE Posts SET CreateAt = :CreateAt WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channel1.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())}) - if _, err := Client.GetAnalytics(team.Id, "post_counts_day"); err == nil { + if _, err := Client.GetTeamAnalytics(team.Id, "post_counts_day"); err == nil { t.Fatal("Shouldn't have permissions") } @@ -250,7 +306,7 @@ func TestGetPostCount(t *testing.T) { Client.LoginByEmail(team.Name, user.Email, "pwd") - if result, err := Client.GetAnalytics(team.Id, "post_counts_day"); err != nil { + if result, err := Client.GetTeamAnalytics(team.Id, "post_counts_day"); err != nil { t.Fatal(err) } else { rows := result.Data.(model.AnalyticsRows) @@ -284,7 +340,7 @@ func TestUserCountsWithPostsByDay(t *testing.T) { Srv.Store.(*store.SqlStore).GetMaster().Exec("UPDATE Posts SET CreateAt = :CreateAt WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channel1.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())}) - if _, err := Client.GetAnalytics(team.Id, "user_counts_with_posts_day"); err == nil { + if _, err := Client.GetTeamAnalytics(team.Id, "user_counts_with_posts_day"); err == nil { t.Fatal("Shouldn't have permissions") } @@ -295,7 +351,7 @@ func TestUserCountsWithPostsByDay(t *testing.T) { Client.LoginByEmail(team.Name, user.Email, "pwd") - if result, err := Client.GetAnalytics(team.Id, "user_counts_with_posts_day"); err != nil { + if result, err := Client.GetTeamAnalytics(team.Id, "user_counts_with_posts_day"); err != nil { t.Fatal(err) } else { rows := result.Data.(model.AnalyticsRows) diff --git a/model/client.go b/model/client.go index 75b93c971..b8e7c4894 100644 --- a/model/client.go +++ b/model/client.go @@ -434,7 +434,7 @@ func (c *Client) TestEmail(config *Config) (*Result, *AppError) { } } -func (c *Client) GetAnalytics(teamId, name string) (*Result, *AppError) { +func (c *Client) GetTeamAnalytics(teamId, name string) (*Result, *AppError) { if r, err := c.DoApiGet("/admin/analytics/"+teamId+"/"+name, "", ""); err != nil { return nil, err } else { @@ -443,6 +443,15 @@ func (c *Client) GetAnalytics(teamId, name string) (*Result, *AppError) { } } +func (c *Client) GetSystemAnalytics(name string) (*Result, *AppError) { + if r, err := c.DoApiGet("/admin/analytics/"+name, "", ""); err != nil { + return nil, err + } else { + return &Result{r.Header.Get(HEADER_REQUEST_ID), + r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil + } +} + func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) { if r, err := c.DoApiPost("/channels/create", channel.ToJson()); err != nil { return nil, err diff --git a/web/react/components/admin_console/analytics.jsx b/web/react/components/admin_console/analytics.jsx index 8fdf538f8..70ef1ecab 100644 --- a/web/react/components/admin_console/analytics.jsx +++ b/web/react/components/admin_console/analytics.jsx @@ -180,7 +180,7 @@ export default class Analytics extends React.Component { if (this.props.newlyCreatedUsers != null) { let content; if (this.props.newlyCreatedUsers.length === 0) { - content = 'Loading...'; + content = 'Loading...'; } else { content = ( @@ -230,6 +230,7 @@ export default class Analytics extends React.Component { return (

      {'Statistics for ' + this.props.title}

      + {serverError}
      {totalCount} {postCount} @@ -251,7 +252,6 @@ export default class Analytics extends React.Component { } } - Analytics.defaultProps = { title: null, channelOpenCount: null, diff --git a/web/react/components/admin_console/system_analytics.jsx b/web/react/components/admin_console/system_analytics.jsx index fffe7cc53..f54813a94 100644 --- a/web/react/components/admin_console/system_analytics.jsx +++ b/web/react/components/admin_console/system_analytics.jsx @@ -124,7 +124,7 @@ export default class SystemAnalytics extends React.Component { ); } - componentWillReceiveProps(newProps) { + componentWillReceiveProps() { this.setState({ serverError: null, channel_open_count: null, -- cgit v1.2.3-1-g7c22 From 60a73ebabba6798d2b45fa8c8ac0f2bfa6144689 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Fri, 22 Jan 2016 10:24:37 -0500 Subject: Change default system console page to statistics --- web/react/components/admin_console/admin_controller.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index db98d8f35..efd163017 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -46,7 +46,7 @@ export default class AdminController extends React.Component { config: AdminStore.getConfig(), teams: AdminStore.getAllTeams(), selectedTeams, - selected: props.tab || 'service_settings', + selected: props.tab || 'system_analytics', selectedTeam: props.teamId || null }; -- cgit v1.2.3-1-g7c22 From 329a2a12946e65f3ab095efdf76f95e1fc4c763a Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Fri, 22 Jan 2016 14:53:22 -0800 Subject: Fixed duplicate email team signup error --- web/react/components/team_signup_welcome_page.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/react/components/team_signup_welcome_page.jsx b/web/react/components/team_signup_welcome_page.jsx index aa91a1329..a374dd363 100644 --- a/web/react/components/team_signup_welcome_page.jsx +++ b/web/react/components/team_signup_welcome_page.jsx @@ -59,7 +59,13 @@ export default class TeamSignupWelcomePage extends React.Component { } }.bind(this), function error(err) { - this.setState({serverError: err.message}); + let errorMsg = err.message; + + if (err.detailed_error.indexOf('Invalid RCPT TO address provided') >= 0) { + errorMsg = 'Please enter a valid email address'; + } + + this.setState({emailError: '', serverError: errorMsg}); }.bind(this) ); } -- cgit v1.2.3-1-g7c22 From eb58e631e74d9a5ff0992a67cd9452b3a525c5e6 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sat, 23 Jan 2016 10:25:10 -0300 Subject: PLT-7: Refactoring api to use translations (chunk 3) - Add spanish translations - Not included tests and templates --- api/web_conn.go | 7 +- api/web_hub.go | 3 +- api/web_socket.go | 7 +- api/web_team_hub.go | 3 +- api/webhook.go | 24 +- i18n/en.json | 2732 ++++++++++++++++++++++++++------------------------- i18n/es.json | 76 ++ 7 files changed, 1504 insertions(+), 1348 deletions(-) diff --git a/api/web_conn.go b/api/web_conn.go index 2b0e29038..515a8ab31 100644 --- a/api/web_conn.go +++ b/api/web_conn.go @@ -8,6 +8,7 @@ import ( "github.com/gorilla/websocket" "github.com/mattermost/platform/model" "github.com/mattermost/platform/store" + "github.com/mattermost/platform/utils" "time" ) @@ -33,11 +34,11 @@ func NewWebConn(ws *websocket.Conn, teamId string, userId string, sessionId stri pchan := Srv.Store.User().UpdateLastPingAt(userId, model.GetMillis()) if result := <-achan; result.Err != nil { - l4g.Error("Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v", userId, sessionId, result.Err) + l4g.Error(utils.T("api.web_conn.new_web_conn.last_activity.error"), userId, sessionId, result.Err) } if result := <-pchan; result.Err != nil { - l4g.Error("Failed to updated LastPingAt for user_id=%v, err=%v", userId, result.Err) + l4g.Error(utils.T("api.web_conn.new_web_conn.last_ping.error"), userId, result.Err) } }() @@ -56,7 +57,7 @@ func (c *WebConn) readPump() { go func() { if result := <-Srv.Store.User().UpdateLastPingAt(c.UserId, model.GetMillis()); result.Err != nil { - l4g.Error("Failed to updated LastPingAt for user_id=%v, err=%v", c.UserId, result.Err) + l4g.Error(utils.T("api.web_conn.new_web_conn.last_ping.error"), c.UserId, result.Err) } }() diff --git a/api/web_hub.go b/api/web_hub.go index 4361d1035..5fe9d6ae8 100644 --- a/api/web_hub.go +++ b/api/web_hub.go @@ -6,6 +6,7 @@ package api import ( l4g "github.com/alecthomas/log4go" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" ) type Hub struct { @@ -86,7 +87,7 @@ func (h *Hub) Start() { nh.broadcast <- msg } case s := <-h.stop: - l4g.Debug("stopping %v connections", s) + l4g.Debug(utils.T("api.web_hub.start.stopping.debug"), s) for _, v := range h.teamHubs { v.Stop() } diff --git a/api/web_socket.go b/api/web_socket.go index 995e2a677..7590e6646 100644 --- a/api/web_socket.go +++ b/api/web_socket.go @@ -8,11 +8,12 @@ import ( "github.com/gorilla/mux" "github.com/gorilla/websocket" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" "net/http" ) func InitWebSocket(r *mux.Router) { - l4g.Debug("Initializing web socket api routes") + l4g.Debug(utils.T("api.web_socket.init.debug")) r.Handle("/websocket", ApiUserRequired(connect)).Methods("GET") hub.Start() } @@ -28,8 +29,8 @@ func connect(c *Context, w http.ResponseWriter, r *http.Request) { ws, err := upgrader.Upgrade(w, r, nil) if err != nil { - l4g.Error("websocket connect err: %v", err) - c.Err = model.NewAppError("connect", "Failed to upgrade websocket connection", "") + l4g.Error(utils.T("api.web_socket.connect.error"), err) + c.Err = model.NewLocAppError("connect", "api.web_socket.connect.upgrade.app_error", nil, "") return } diff --git a/api/web_team_hub.go b/api/web_team_hub.go index bb9ed9526..55300c828 100644 --- a/api/web_team_hub.go +++ b/api/web_team_hub.go @@ -6,6 +6,7 @@ package api import ( l4g "github.com/alecthomas/log4go" "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" ) type TeamHub struct { @@ -65,7 +66,7 @@ func (h *TeamHub) Start() { case s := <-h.stop: if s { - l4g.Debug("team hub stopping for teamId=%v", h.teamId) + l4g.Debug(utils.T("api.web_team_hun.start.debug"), h.teamId) for webCon := range h.connections { webCon.WebSocket.Close() diff --git a/api/webhook.go b/api/webhook.go index a9a88b7b8..1372fe335 100644 --- a/api/webhook.go +++ b/api/webhook.go @@ -12,7 +12,7 @@ import ( ) func InitWebhook(r *mux.Router) { - l4g.Debug("Initializing webhook api routes") + l4g.Debug(utils.T("api.webhook.init.debug")) sr := r.PathPrefix("/hooks").Subrouter() sr.Handle("/incoming/create", ApiUserRequired(createIncomingHook)).Methods("POST") @@ -27,7 +27,7 @@ func InitWebhook(r *mux.Router) { func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("createIncomingHook", "Incoming webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("createIncomingHook", "api.webhook.create_incoming.disabled.app_errror", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -74,7 +74,7 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("deleteIncomingHook", "Incoming webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("deleteIncomingHook", "api.webhook.delete_incoming.disabled.app_errror", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -95,7 +95,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { } else { if c.Session.UserId != result.Data.(*model.IncomingWebhook).UserId && !c.IsTeamAdmin() { c.LogAudit("fail - inappropriate permissions") - c.Err = model.NewAppError("deleteIncomingHook", "Inappropriate permissions to delete incoming webhook", "user_id="+c.Session.UserId) + c.Err = model.NewLocAppError("deleteIncomingHook", "api.webhook.delete_incoming.permissions.app_errror", nil, "user_id="+c.Session.UserId) return } } @@ -111,7 +111,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) { func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("getIncomingHooks", "Incoming webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("getIncomingHooks", "api.webhook.get_incoming.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -127,7 +127,7 @@ func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) { func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks { - c.Err = model.NewAppError("createOutgoingHook", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("createOutgoingHook", "api.webhook.create_outgoing.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -167,7 +167,7 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { } } } else if len(hook.TriggerWords) == 0 { - c.Err = model.NewAppError("createOutgoingHook", "Either trigger_words or channel_id must be set", "") + c.Err = model.NewLocAppError("createOutgoingHook", "api.webhook.create_outgoing.triggers.app_error", nil, "") return } @@ -183,7 +183,7 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks { - c.Err = model.NewAppError("getOutgoingHooks", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("getOutgoingHooks", "api.webhook.get_outgoing.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -199,7 +199,7 @@ func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) { func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("deleteOutgoingHook", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("deleteOutgoingHook", "api.webhook.delete_outgoing.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -220,7 +220,7 @@ func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { } else { if c.Session.UserId != result.Data.(*model.OutgoingWebhook).CreatorId && !c.IsTeamAdmin() { c.LogAudit("fail - inappropriate permissions") - c.Err = model.NewAppError("deleteOutgoingHook", "Inappropriate permissions to delete outcoming webhook", "user_id="+c.Session.UserId) + c.Err = model.NewLocAppError("deleteOutgoingHook", "api.webhook.delete_outgoing.permissions.app_error", nil, "user_id="+c.Session.UserId) return } } @@ -236,7 +236,7 @@ func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) { func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks { - c.Err = model.NewAppError("regenOutgoingHookToken", "Outgoing webhooks have been disabled by the system admin.", "") + c.Err = model.NewLocAppError("regenOutgoingHookToken", "api.webhook.regen_outgoing_token.disabled.app_error", nil, "") c.Err.StatusCode = http.StatusNotImplemented return } @@ -260,7 +260,7 @@ func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) if c.Session.UserId != hook.CreatorId && !c.IsTeamAdmin() { c.LogAudit("fail - inappropriate permissions") - c.Err = model.NewAppError("regenOutgoingHookToken", "Inappropriate permissions to regenerate outcoming webhook token", "user_id="+c.Session.UserId) + c.Err = model.NewLocAppError("regenOutgoingHookToken", "api.webhook.regen_outgoing_token.permissions.app_error", nil, "user_id="+c.Session.UserId) return } } diff --git a/i18n/en.json b/i18n/en.json index 4edc176d6..554840075 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,1330 +1,1406 @@ [ - { - "id": "api.admin.file_read_error", - "translation": "Error reading log file" - }, - { - "id": "api.admin.init.debug", - "translation": "Initializing admin api routes" - }, - { - "id": "api.admin.test_email.body", - "translation": "


      It appears your Mattermost email is setup correctly!" - }, - { - "id": "api.admin.test_email.subject", - "translation": "Mattermost - Testing Email Settings" - }, - { - "id": "api.api.init.parsing_templates.debug", - "translation": "Parsing server templates at %v" - }, - { - "id": "api.api.init.parsing_templates.error", - "translation": "Failed to parse server templates %v" - }, - { - "id": "api.api.render.error", - "translation": "Error rendering template %v err=%v" - }, - { - "id": "api.channel.add_member.added", - "translation": "%v added to the channel by %v" - }, - { - "id": "api.channel.add_member.find_channel.app_error", - "translation": "Failed to find channel" - }, - { - "id": "api.channel.add_member.find_user.app_error", - "translation": "Failed to find user to be added" - }, - { - "id": "api.channel.add_member.user_adding.app_error", - "translation": "Failed to find user doing the adding" - }, - { - "id": "api.channel.add_user.to.channel.failed.app_error", - "translation": "Failed to add user to channel" - }, - { - "id": "api.channel.add_user_to_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.add_user_to_channel.type.app_error", - "translation": "Can not add user to this channel type" - }, - { - "id": "api.channel.create_channel.direct_channel.app_error", - "translation": "Must use createDirectChannel api service for direct message channel creation" - }, - { - "id": "api.channel.create_channel.invalid_character.app_error", - "translation": "Invalid character '__' in channel name for non-direct channel" - }, - { - "id": "api.channel.create_default_channels.off_topic", - "translation": "Off-Topic" - }, - { - "id": "api.channel.create_default_channels.town_square", - "translation": "Town Square" - }, - { - "id": "api.channel.create_direct_channel.invalid_user.app_error", - "translation": "Invalid other user id " - }, - { - "id": "api.channel.delete_channel.archived", - "translation": "%v has archived the channel." - }, - { - "id": "api.channel.delete_channel.cannot.app_error", - "translation": "Cannot delete the default channel {{.Channel}}" - }, - { - "id": "api.channel.delete_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.delete_channel.failed_post.error", - "translation": "Failed to post archive message %v" - }, - { - "id": "api.channel.delete_channel.failed_send.app_error", - "translation": "Failed to send archive message" - }, - { - "id": "api.channel.delete_channel.incoming_webhook.error", - "translation": "Encountered error deleting incoming webhook, id=%v" - }, - { - "id": "api.channel.delete_channel.outgoing_webhook.error", - "translation": "Encountered error deleting outgoing webhook, id=%v" - }, - { - "id": "api.channel.delete_channel.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.channel.get_channel_counts.app_error", - "translation": "Unable to get channel counts from the database" - }, - { - "id": "api.channel.get_channel_extra_info.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.get_channel_extra_info.member_limit.app_error", - "translation": "Failed to parse member limit" - }, - { - "id": "api.channel.get_channels.error", - "translation": "Error in getting users profile for id=%v forcing logout" - }, - { - "id": "api.channel.init.debug", - "translation": "Initializing channel api routes" - }, - { - "id": "api.channel.join_channel.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.channel.join_channel.post_and_forget", - "translation": "%v has joined the channel." - }, - { - "id": "api.channel.leave.default.app_error", - "translation": "Cannot leave the default channel {{.Channel}}" - }, - { - "id": "api.channel.leave.direct.app_error", - "translation": "Cannot leave a direct message channel" - }, - { - "id": "api.channel.leave.left", - "translation": "%v has left the channel." - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.join_leave.error", - "translation": "Failed to post join/leave message %v" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.removed", - "translation": "%s removed the channel header (was: %s)" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.retrieve_user.error", - "translation": "Failed to retrieve user while trying to save update channel header message %v" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.updated_from", - "translation": "%s updated the channel header from: %s to: %s" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.updated_to", - "translation": "%s updated the channel header to: %s" - }, - { - "id": "api.channel.post_user_add_remove_message_and_forget.error", - "translation": "Failed to post join/leave message %v" - }, - { - "id": "api.channel.remove_member.permissions.app_error", - "translation": "You do not have the appropriate permissions " - }, - { - "id": "api.channel.remove_member.unable.app_error", - "translation": "Unable to remove user." - }, - { - "id": "api.channel.remove_user_from_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.update_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.update_channel.permission.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.channel.update_channel.tried.app_error", - "translation": "Tried to perform an invalid update of the default channel {{.Channel}}" - }, - { - "id": "api.command.check_command.start.app_error", - "translation": "Command must start with /" - }, - { - "id": "api.command.echo_command.create.error", - "translation": "Unable to create /echo post, err=%v" - }, - { - "id": "api.command.echo_command.description", - "translation": "Echo back text from your account, /echo \"message\" [delay in seconds]" - }, - { - "id": "api.command.echo_command.high_volume.app_error", - "translation": "High volume of echo request, cannot process request" - }, - { - "id": "api.command.echo_command.under.app_error", - "translation": "Delays must be under 10000 seconds" - }, - { - "id": "api.command.init.debug", - "translation": "Initializing command api routes" - }, - { - "id": "api.command.load_test_channels_command.channel.description", - "translation": "Add a specified number of random channels to current team " - }, - { - "id": "api.command.load_test_channels_command.fuzz.description", - "translation": "Add a specified number of random channels with fuzz text to current team " - }, - { - "id": "api.command.load_test_command.description", - "translation": "Debug Load Testing" - }, - { - "id": "api.command.load_test_posts_command.fuzz.description", - "translation": "Add some random posts with fuzz text to current channel " - }, - { - "id": "api.command.load_test_posts_command.posts.description", - "translation": "Add some random posts to current channel " - }, - { - "id": "api.command.load_test_setup_command.create.error", - "translation": "Failed to create testing environment" - }, - { - "id": "api.command.load_test_setup_command.created.info", - "translation": "Team Created: %v" - }, - { - "id": "api.command.load_test_setup_command.description", - "translation": "Creates a testing environment in current team. [teams] [fuzz] " - }, - { - "id": "api.command.load_test_setup_command.login.info", - "translation": "\t User to login: %v, %v" - }, - { - "id": "api.command.load_test_url_command.create.error", - "translation": "Unable to create post, err=%v" - }, - { - "id": "api.command.load_test_url_command.description", - "translation": "Add a post containing the text from a given url to current channel " - }, - { - "id": "api.command.load_test_url_command.file.app_error", - "translation": "Unable to get file" - }, - { - "id": "api.command.load_test_url_command.reading.app_error", - "translation": "Encountered error reading file" - }, - { - "id": "api.command.load_test_url_command.url.app_error", - "translation": "Command must contain a url" - }, - { - "id": "api.command.load_test_users_command.fuzz.description", - "translation": "Add a specified number of random users with fuzz text to current team " - }, - { - "id": "api.command.load_test_users_command.users.description", - "translation": "Add a specified number of random users to current team " - }, - { - "id": "api.command.logout_command.description", - "translation": "Logout" - }, - { - "id": "api.command.me_command.create.error", - "translation": "Unable to create /me post post, err=%v" - }, - { - "id": "api.command.me_command.description", - "translation": "Do an action, /me [message]" - }, - { - "id": "api.command.no_implemented.app_error", - "translation": "Command not implemented" - }, - { - "id": "api.command.shrug_command.create.error", - "translation": "Unable to create /shrug post post, err=%v" - }, - { - "id": "api.command.shrug_command.description", - "translation": "Adds ¯\\_(ツ)_/¯ to your message, /shrug [message]" - }, - { - "id": "api.commmand.join_command.description", - "translation": "Join the open channel" - }, - { - "id": "api.context.404.app_error", - "translation": "Sorry, we could not find the page." - }, - { - "id": "api.context.invalid_param.app_error", - "translation": "Invalid {{.Name}} parameter" - }, - { - "id": "api.context.invalid_team_url.debug", - "translation": "TeamURL accessed when not valid. Team URL should not be used in api functions or those that are team independent" - }, - { - "id": "api.context.invalid_token.error", - "translation": "Invalid session token=%v, err=%v" - }, - { - "id": "api.context.last_activity_at.error", - "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" - }, - { - "id": "api.context.log.error", - "translation": "%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]" - }, - { - "id": "api.context.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.context.session_expired.app_error", - "translation": "Invalid or expired session, please login again." - }, - { - "id": "api.context.system_permissions.app_error", - "translation": "You do not have the appropriate permissions (system)" - }, - { - "id": "api.context.token_provided.app_error", - "translation": "Session is not OAuth but token was provided in the query string" - }, - { - "id": "api.context.unknown.app_error", - "translation": "An unknown error has occured. Please contact support." - }, - { - "id": "api.export.json.app_error", - "translation": "Unable to convert to json" - }, - { - "id": "api.export.open.app_error", - "translation": "Unable to open file" - }, - { - "id": "api.export.open_dir.app_error", - "translation": "Unable to open directory" - }, - { - "id": "api.export.open_file.app_error", - "translation": "Unable to open file for export" - }, - { - "id": "api.export.options.create.app_error", - "translation": "Unable to create options file" - }, - { - "id": "api.export.options.write.app_error", - "translation": "Unable to write to options file" - }, - { - "id": "api.export.read_dir.app_error", - "translation": "Unable to read directory" - }, - { - "id": "api.export.s3.app_error", - "translation": "S3 is not supported for local storage export." - }, - { - "id": "api.export.write_file.app_error", - "translation": "Unable to write to export file" - }, - { - "id": "api.file.file_upload.exceeds", - "translation": "File exceeds max image size." - }, - { - "id": "api.file.get_export.retrieve.app_error", - "translation": "Unable to retrieve exported file. Please re-export" - }, - { - "id": "api.file.get_export.team_admin.app_error", - "translation": "Only a team admin can retrieve exported data." - }, - { - "id": "api.file.get_file.not_found.app_error", - "translation": "Could not find file." - }, - { - "id": "api.file.get_file.public_expired.app_error", - "translation": "The public link has expired" - }, - { - "id": "api.file.get_file.public_invalid.app_error", - "translation": "The public link does not appear to be valid" - }, - { - "id": "api.file.get_public_link.disabled.app_error", - "translation": "Public links have been disabled" - }, - { - "id": "api.file.handle_images_forget.decode.error", - "translation": "Unable to decode image channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.encode_jpeg.error", - "translation": "Unable to encode image as jpeg channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.encode_preview.error", - "translation": "Unable to encode image as preview jpg channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.upload_preview.error", - "translation": "Unable to upload preview channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.upload_thumb.error", - "translation": "Unable to upload thumbnail channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.init.debug", - "translation": "Initializing file api routes" - }, - { - "id": "api.file.open_file_write_stream.configured.app_error", - "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." - }, - { - "id": "api.file.open_file_write_stream.creating_dir.app_error", - "translation": "Encountered an error creating the directory for the new file" - }, - { - "id": "api.file.open_file_write_stream.local_server.app_error", - "translation": "Encountered an error writing to local server storage" - }, - { - "id": "api.file.open_file_write_stream.s3.app_error", - "translation": "S3 is not supported." - }, - { - "id": "api.file.read_file.configured.app_error", - "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." - }, - { - "id": "api.file.read_file.get.app_error", - "translation": "Unable to get file from S3" - }, - { - "id": "api.file.read_file.reading_local.app_error", - "translation": "Encountered an error reading from local server storage" - }, - { - "id": "api.file.upload_file.image.app_error", - "translation": "Unable to upload image file." - }, - { - "id": "api.file.upload_file.large_image.app_error", - "translation": "Unable to upload image file. File is too large." - }, - { - "id": "api.file.upload_file.storage.app_error", - "translation": "Unable to upload file. Image storage is not configured." - }, - { - "id": "api.file.upload_file.too_large.app_error", - "translation": "Unable to upload file. File is too large." - }, - { - "id": "api.file.write_file.configured.app_error", - "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." - }, - { - "id": "api.file.write_file.s3.app_error", - "translation": "Encountered an error writing to S3" - }, - { - "id": "api.file.write_file_locally.create_dir.app_error", - "translation": "Encountered an error creating the directory for the new file" - }, - { - "id": "api.file.write_file_locally.writing.app_error", - "translation": "Encountered an error writing to local server storage" - }, - { - "id": "api.import.import_post.saving.debug", - "translation": "Error saving post. user=%v, message=%v" - }, - { - "id": "api.import.import_user.joining_default.error", - "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" - }, - { - "id": "api.import.import_user.saving.error", - "translation": "Error saving user. err=%v" - }, - { - "id": "api.import.import_user.set_email.error", - "translation": "Failed to set email verified err=%v" - }, - { - "id": "api.license.add_license.array.app_error", - "translation": "Empty array under 'license' in request" - }, - { - "id": "api.license.add_license.expired.app_error", - "translation": "License is either expired or has not yet started." - }, - { - "id": "api.license.add_license.invalid.app_error", - "translation": "Invalid license file." - }, - { - "id": "api.license.add_license.no_file.app_error", - "translation": "No file under 'license' in request" - }, - { - "id": "api.license.add_license.open.app_error", - "translation": "Could not open license file" - }, - { - "id": "api.license.add_license.save.app_error", - "translation": "License did not save properly." - }, - { - "id": "api.license.init.debug", - "translation": "Initializing license api routes" - }, - { - "id": "api.license.remove_license.remove.app_error", - "translation": "License did not remove properly." - }, - { - "id": "api.oauth.allow_oauth.bad_client.app_error", - "translation": "invalid_request: Bad client_id" - }, - { - "id": "api.oauth.allow_oauth.bad_redirect.app_error", - "translation": "invalid_request: Missing or bad redirect_uri" - }, - { - "id": "api.oauth.allow_oauth.bad_response.app_error", - "translation": "invalid_request: Bad response_type" - }, - { - "id": "api.oauth.allow_oauth.database.app_error", - "translation": "server_error: Error accessing the database" - }, - { - "id": "api.oauth.allow_oauth.redirect_callback.app_error", - "translation": "invalid_request: Supplied redirect_uri did not match registered callback_url" - }, - { - "id": "api.oauth.allow_oauth.turn_off.app_error", - "translation": "The system admin has turned off OAuth service providing." - }, - { - "id": "api.oauth.get_auth_data.find.error", - "translation": "Couldn't find auth code for code=%s" - }, - { - "id": "api.oauth.init.debug", - "translation": "Initializing oauth api routes" - }, - { - "id": "api.oauth.register_oauth_app.turn_off.app_error", - "translation": "The system admin has turned off OAuth service providing." - }, - { - "id": "api.oauth.revoke_access_token.del_code.app_error", - "translation": "Error deleting authorization code from DB" - }, - { - "id": "api.oauth.revoke_access_token.del_session.app_error", - "translation": "Error deleting session from DB" - }, - { - "id": "api.oauth.revoke_access_token.del_token.app_error", - "translation": "Error deleting access token from DB" - }, - { - "id": "api.oauth.revoke_access_token.get.app_error", - "translation": "Error getting access token from DB before deletion" - }, - { - "id": "api.post.create_post.bad_filename.error", - "translation": "Bad filename discarded, filename=%v" - }, - { - "id": "api.post.create_post.channel_root_id.app_error", - "translation": "Invalid ChannelId for RootId parameter" - }, - { - "id": "api.post.create_post.last_viewed.error", - "translation": "Encountered error updating last viewed, channel_id=%s, user_id=%s, err=%v" - }, - { - "id": "api.post.create_post.parent_id.app_error", - "translation": "Invalid ParentId parameter" - }, - { - "id": "api.post.create_post.root_id.app_error", - "translation": "Invalid RootId parameter" - }, - { - "id": "api.post.create_webhook_post.creating.app_error", - "translation": "Error creating post" - }, - { - "id": "api.post.delete_post.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.post.get_post.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.post.handle_post_events_and_forget.channel.error", - "translation": "Encountered error getting channel, channel_id=%s, err=%v" - }, - { - "id": "api.post.handle_post_events_and_forget.team.error", - "translation": "Encountered error getting team, team_id=%s, err=%v" - }, - { - "id": "api.post.handle_post_events_and_forget.user.error", - "translation": "Encountered error getting user, user_id=%s, err=%v" - }, - { - "id": "api.post.handle_webhook_events_and_forget.create_post.error", - "translation": "Failed to create response post, err=%v" - }, - { - "id": "api.post.handle_webhook_events_and_forget.event_post.error", - "translation": "Event POST failed, err=%s" - }, - { - "id": "api.post.handle_webhook_events_and_forget.getting.error", - "translation": "Encountered error getting webhooks by team, err=%v" - }, - { - "id": "api.post.init.debug", - "translation": "Initializing post api routes" - }, - { - "id": "api.post.make_direct_channel_visible.get_2_members.error", - "translation": "Failed to get 2 members for a direct channel channel_id=%v" - }, - { - "id": "api.post.make_direct_channel_visible.get_members.error", - "translation": "Failed to get channel members channel_id=%v err=%v" - }, - { - "id": "api.post.make_direct_channel_visible.save_pref.error", - "translation": "Failed to save direct channel preference user_id=%v other_user_id=%v err=%v" - }, - { - "id": "api.post.make_direct_channel_visible.update_pref.error", - "translation": "Failed to update direct channel preference user_id=%v other_user_id=%v err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.members.error", - "translation": "Failed to get channel members channel_id=%v err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.mention_body", - "translation": "You have one new mention." - }, - { - "id": "api.post.send_notifications_and_forget.mention_subject", - "translation": "New Mention" - }, - { - "id": "api.post.send_notifications_and_forget.message_body", - "translation": "You have one new message." - }, - { - "id": "api.post.send_notifications_and_forget.message_subject", - "translation": "New Direct Message" - }, - { - "id": "api.post.send_notifications_and_forget.push_mention", - "translation": " mentioned you in " - }, - { - "id": "api.post.send_notifications_and_forget.push_message", - "translation": " sent you a direct message" - }, - { - "id": "api.post.send_notifications_and_forget.push_notification.debug", - "translation": "Sending push notification to %v wi msg of '%v'" - }, - { - "id": "api.post.send_notifications_and_forget.push_notification.error", - "translation": "Failed to send push notificationid=%v, err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.retrive_profiles.error", - "translation": "Failed to retrieve user profiles team_id=%v, err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.send.error", - "translation": "Failed to send mention email successfully email=%v err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.sent", - "translation": "{{.Prefix}} {{.Filenames}} sent" - }, - { - "id": "api.post.send_notifications_and_forget.sessions.error", - "translation": "Failed to retrieve sessions in notifications id=%v, err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.user_id.error", - "translation": "Post user_id not returned by GetProfiles user_id=%v" - }, - { - "id": "api.post.update_mention_count_and_forget.update_error", - "translation": "Failed to update mention count for user_id=%v on channel_id=%v err=%v" - }, - { - "id": "api.post.update_post.find.app_error", - "translation": "We couldn't find the existing post or comment to update." - }, - { - "id": "api.post.update_post.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.post.update_post.permissions_details.app_error", - "translation": "Already delted id={{.PostId}}" - }, - { - "id": "api.post_get_post_by_id.get.app_error", - "translation": "Unable to get post" - }, - { - "id": "api.preference.init.debug", - "translation": "Initializing preference api routes" - }, - { - "id": "api.preference.save_preferences.decode.app_error", - "translation": "Unable to decode preferences from request" - }, - { - "id": "api.preference.save_preferences.set.app_error", - "translation": "Unable to set preferences for other user" - }, - { - "id": "api.preference.save_preferences.set_details.app_error", - "translation": "session.user_id={{.SessionUserId}}, preference.user_id={{.PreferenceUserId}}" - }, - { - "id": "api.server.new_server.init.info", - "translation": "Server is initializing..." - }, - { - "id": "api.server.start_server.listening.info", - "translation": "Server is listening on %v" - }, - { - "id": "api.server.start_server.rate.info", - "translation": "RateLimiter is enabled" - }, - { - "id": "api.server.start_server.rate.warn", - "translation": "RateLimitSettings not configured properly using VaryByHeader and disabling VaryByRemoteAddr" - }, - { - "id": "api.server.start_server.starting.critical", - "translation": "Error starting server, err:%v" - }, - { - "id": "api.server.start_server.starting.info", - "translation": "Starting Server..." - }, - { - "id": "api.server.start_server.starting.panic", - "translation": "Error starting server " - }, - { - "id": "api.server.stop_server.stopped.info", - "translation": "Server stopped" - }, - { - "id": "api.server.stop_server.stopping.info", - "translation": "Stopping Server..." - }, - { - "id": "api.slackimport.slack_add_channels.added", - "translation": "\r\n Channels Added \r\n" - }, - { - "id": "api.slackimport.slack_add_channels.import_failed", - "translation": "Failed to import: {{.DisplayName}}\r\n" - }, - { - "id": "api.slackimport.slack_add_channels.import_failed.debug", - "translation": "Failed to import: %s" - }, - { - "id": "api.slackimport.slack_add_channels.merge", - "translation": "Merged with existing channel: {{.DisplayName}}\r\n" - }, - { - "id": "api.slackimport.slack_add_posts.bot.warn", - "translation": "Slack bot posts are not imported yet" - }, - { - "id": "api.slackimport.slack_add_posts.msg_no_usr.debug", - "translation": "Message without user" - }, - { - "id": "api.slackimport.slack_add_posts.unsupported.warn", - "translation": "Unsupported post type: %v, %v" - }, - { - "id": "api.slackimport.slack_add_posts.user_no_exists.debug", - "translation": "User: %v does not exist!" - }, - { - "id": "api.slackimport.slack_add_posts.without_user.debug", - "translation": "Message without user" - }, - { - "id": "api.slackimport.slack_add_users.created", - "translation": "\r\n Users Created\r\n" - }, - { - "id": "api.slackimport.slack_add_users.email_pwd", - "translation": "Email, Password: {{.Email}}, {{.Password}}\r\n" - }, - { - "id": "api.slackimport.slack_add_users.unable_import", - "translation": "Unable to import user: {{.Username}}\r\n" - }, - { - "id": "api.slackimport.slack_convert_timestamp.bad.warn", - "translation": "Bad timestamp detected" - }, - { - "id": "api.slackimport.slack_import.log", - "translation": "Mattermost Slack Import Log\r\n" - }, - { - "id": "api.slackimport.slack_import.note1", - "translation": "- Some posts may not have been imported because they where not supported by this importer.\r\n" - }, - { - "id": "api.slackimport.slack_import.note2", - "translation": "- Slack bot posts are currently not supported.\r\n" - }, - { - "id": "api.slackimport.slack_import.notes", - "translation": "\r\n Notes \r\n" - }, - { - "id": "api.slackimport.slack_import.open.app_error", - "translation": "Unable to open: {{.Filename}}" - }, - { - "id": "api.slackimport.slack_import.zip.app_error", - "translation": "Unable to open zip file" - }, - { - "id": "api.team.create_team.email_disabled.app_error", - "translation": "Team sign-up with email is disabled." - }, - { - "id": "api.team.create_team_from_signup.email_disabled.app_error", - "translation": "Team sign-up with email is disabled." - }, - { - "id": "api.team.create_team_from_signup.expired_link.app_error", - "translation": "The signup link has expired" - }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "The signup link does not appear to be valid" - }, - { - "id": "api.team.create_team_from_signup.unavailable.app_error", - "translation": "This URL is unavailable. Please try another." - }, - { - "id": "api.team.email_teams.sending.error", - "translation": "An error occured while sending an email in emailTeams err=%v" - }, - { - "id": "api.team.export_team.admin.app_error", - "translation": "Only a team admin can export data." - }, - { - "id": "api.team.import_team.admin.app_error", - "translation": "Only a team admin can import data." - }, - { - "id": "api.team.import_team.array.app_error", - "translation": "Empty array under 'file' in request" - }, - { - "id": "api.team.import_team.integer.app_error", - "translation": "Filesize not an integer" - }, - { - "id": "api.team.import_team.no_file.app_error", - "translation": "No file under 'file' in request" - }, - { - "id": "api.team.import_team.open.app_error", - "translation": "Could not open file" - }, - { - "id": "api.team.import_team.parse.app_error", - "translation": "Could not parse multipart form" - }, - { - "id": "api.team.import_team.unavailable.app_error", - "translation": "Filesize unavilable" - }, - { - "id": "api.team.init.debug", - "translation": "Initializing team api routes" - }, - { - "id": "api.team.invite_members.admin", - "translation": "administrator" - }, - { - "id": "api.team.invite_members.already.app_error", - "translation": "This person is already on your team" - }, - { - "id": "api.team.invite_members.member", - "translation": "member" - }, - { - "id": "api.team.invite_members.no_one.app_error", - "translation": "No one to invite." - }, - { - "id": "api.team.invite_members.send.error", - "translation": "Failed to send invite email successfully err=%v" - }, - { - "id": "api.team.invite_members.sending.info", - "translation": "sending invitation to %v %v" - }, - { - "id": "api.team.is_team_creation_allowed.disabled.app_error", - "translation": "Team creation has been disabled. Please ask your systems administrator for details." - }, - { - "id": "api.team.is_team_creation_allowed.domain.app_error", - "translation": "Email must be from a specific domain (e.g. @example.com). Please ask your systems administrator for details." - }, - { - "id": "api.team.permanent_delete_team.attempting.warn", - "translation": "Attempting to permanently delete team %v id=%v" - }, - { - "id": "api.team.permanent_delete_team.deleted.warn", - "translation": "Permanently deleted team %v id=%v" - }, - { - "id": "api.team.signup_team.email_disabled.app_error", - "translation": "Team sign-up with email is disabled." - }, - { - "id": "api.team.update_team.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.user.add_direct_channels_and_forget.failed.error", - "translation": "Failed to add direct channel preferences for user user_id=%s, team_id=%s, err=%v" - }, - { - "id": "api.user.authorize_oauth_user.bad_response.app_error", - "translation": "Bad response from token request" - }, - { - "id": "api.user.authorize_oauth_user.bad_token.app_error", - "translation": "Bad token type" - }, - { - "id": "api.user.authorize_oauth_user.invalid_state.app_error", - "translation": "Invalid state" - }, - { - "id": "api.user.authorize_oauth_user.invalid_state_team.app_error", - "translation": "Invalid state; missing team name" - }, - { - "id": "api.user.authorize_oauth_user.missing.app_error", - "translation": "Missing access token" - }, - { - "id": "api.user.authorize_oauth_user.service.app_error", - "translation": "Token request to {{.Service}} failed" - }, - { - "id": "api.user.authorize_oauth_user.token_failed.app_error", - "translation": "Token request failed" - }, - { - "id": "api.user.authorize_oauth_user.unsupported.app_error", - "translation": "Unsupported OAuth service provider" - }, - { - "id": "api.user.check_user_login_attempts.too_many.app_error", - "translation": "Your account is locked because of too many failed password attempts. Please reset your password." - }, - { - "id": "api.user.check_user_password.invalid.app_error", - "translation": "Login failed because of invalid password" - }, - { - "id": "api.user.complete_switch_with_oauth.blank_email.app_error", - "translation": "Blank email" - }, - { - "id": "api.user.complete_switch_with_oauth.parse.app_error", - "translation": "Could not parse auth data out of {{.Service}} user object" - }, - { - "id": "api.user.complete_switch_with_oauth.unavailable.app_error", - "translation": "{{.Service}} oauth not available on this server" - }, - { - "id": "api.user.create_oauth_user.already_attached.app_error", - "translation": "Team {{.DisplayName}} already has a user with the email address attached to your {{.Service}} account" - }, - { - "id": "api.user.create_oauth_user.already_used.app_error", - "translation": "This {{.Service}} account has already been used to sign up for team {{.DisplayName}}" - }, - { - "id": "api.user.create_oauth_user.create.app_error", - "translation": "Could not create user out of {{.Service}} user object" - }, - { - "id": "api.user.create_oauth_user.not_available.app_error", - "translation": "{{.Service}} oauth not avlailable on this server" - }, - { - "id": "api.user.create_profile_image.default_font.app_error", - "translation": "Could not create default profile image font" - }, - { - "id": "api.user.create_profile_image.encode.app_error", - "translation": "Could not encode default profile image" - }, - { - "id": "api.user.create_profile_image.initial.app_error", - "translation": "Could not add user initial to default profile picture" - }, - { - "id": "api.user.create_user.accepted_domain.app_error", - "translation": "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email." - }, - { - "id": "api.user.create_user.joining.error", - "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" - }, - { - "id": "api.user.create_user.save.error", - "translation": "Couldn't save the user err=%v" - }, - { - "id": "api.user.create_user.signup_email_disabled.app_error", - "translation": "User sign-up with email is disabled." - }, - { - "id": "api.user.create_user.signup_link_expired.app_error", - "translation": "The signup link has expired" - }, - { - "id": "api.user.create_user.signup_link_invalid.app_error", - "translation": "The signup link does not appear to be valid" - }, - { - "id": "api.user.create_user.team_name.app_error", - "translation": "Invalid team name" - }, - { - "id": "api.user.create_user.tutorial.error", - "translation": "Encountered error saving tutorial preference, err=%v" - }, - { - "id": "api.user.create_user.verified.error", - "translation": "Failed to set email verified err=%v" - }, - { - "id": "api.user.get_authorization_code.unsupported.app_error", - "translation": "Unsupported OAuth service provider" - }, - { - "id": "api.user.get_me.getting.error", - "translation": "Error in getting users profile for id=%v forcing logout" - }, - { - "id": "api.user.init.debug", - "translation": "Initializing user api routes" - }, - { - "id": "api.user.login.blank_pwd.app_error", - "translation": "Password field must not be blank" - }, - { - "id": "api.user.login.inactive.app_error", - "translation": "Login failed because your account has been set to inactive. Please contact an administrator." - }, - { - "id": "api.user.login.not_provided.app_error", - "translation": "Either user id or team name and user email must be provided" - }, - { - "id": "api.user.login.not_verified.app_error", - "translation": "Login failed because email address has not been verified" - }, - { - "id": "api.user.login.revoking.app_error", - "translation": "Revoking sessionId=%v for userId=%v re-login with same device Id" - }, - { - "id": "api.user.login_by_email.sign_in.app_error", - "translation": "Please sign in using {{.AuthService}}" - }, - { - "id": "api.user.login_by_oauth.not_available.app_error", - "translation": "{{.Service}} oauth not avlailable on this server" - }, - { - "id": "api.user.login_by_oauth.parse.app_error", - "translation": "Could not parse auth data out of {{.Service}} user object" - }, - { - "id": "api.user.login_ldap.blank_pwd.app_error", - "translation": "Password field must not be blank" - }, - { - "id": "api.user.login_ldap.disabled.app_error", - "translation": "LDAP not enabled on this server" - }, - { - "id": "api.user.login_ldap.need_id.app_error", - "translation": "Need an ID" - }, - { - "id": "api.user.login_ldap.not_available.app_error", - "translation": "LDAP not available on this server" - }, - { - "id": "api.user.permanent_delete_user.attempting.warn", - "translation": "Attempting to permanently delete account %v id=%v" - }, - { - "id": "api.user.permanent_delete_user.deleted.warn", - "translation": "Permanently deleted account %v id=%v" - }, - { - "id": "api.user.permanent_delete_user.system_admin.warn", - "translation": "You are deleting %v that is a system administrator. You may need to set another account as the system administrator using the command line tools." - }, - { - "id": "api.user.reset_password.invalid_link.app_error", - "translation": "The reset password link does not appear to be valid" - }, - { - "id": "api.user.reset_password.link_expired.app_error", - "translation": "The reset link has expired" - }, - { - "id": "api.user.reset_password.sso.app_error", - "translation": "Cannot reset password for SSO accounts" - }, - { - "id": "api.user.reset_password.wrong_team.app_error", - "translation": "Trying to reset password for user on wrong team." - }, - { - "id": "api.user.send_email_change_email_and_forget.error", - "translation": "Failed to send email change notification email successfully err=%v" - }, - { - "id": "api.user.send_email_change_verify_email_and_forget.error", - "translation": "Failed to send email change verification email successfully err=%v" - }, - { - "id": "api.user.send_password_change_email_and_forget.error", - "translation": "Failed to send update password email successfully err=%v" - }, - { - "id": "api.user.send_password_reset.find.app_error", - "translation": "We couldn’t find an account with that address." - }, - { - "id": "api.user.send_password_reset.send.app_error", - "translation": "Failed to send password reset email successfully" - }, - { - "id": "api.user.send_password_reset.sso.app_error", - "translation": "Cannot reset password for SSO accounts" - }, - { - "id": "api.user.send_sign_in_change_email_and_forget.error", - "translation": "Failed to send update password email successfully err=%v" - }, - { - "id": "api.user.send_verify_email_and_forget.failed.error", - "translation": "Failed to send verification email successfully err=%v" - }, - { - "id": "api.user.send_welcome_email_and_forget.failed.error", - "translation": "Failed to send welcome email successfully err=%v" - }, - { - "id": "api.user.switch_to_email.context.app_error", - "translation": "Update password failed because context user_id did not match provided user's id" - }, - { - "id": "api.user.update_active.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.user.update_password.context.app_error", - "translation": "Update password failed because context user_id did not match props user_id" - }, - { - "id": "api.user.update_password.failed.app_error", - "translation": "Update password failed" - }, - { - "id": "api.user.update_password.incorrect.app_error", - "translation": "The \"Current Password\" you entered is incorrect. Please check that Caps Lock is off and try again." - }, - { - "id": "api.user.update_password.menu", - "translation": "using the settings menu" - }, - { - "id": "api.user.update_password.oauth.app_error", - "translation": "Update password failed because the user is logged in through an OAuth service" - }, - { - "id": "api.user.update_password.valid_account.app_error", - "translation": "Update password failed because we couldn't find a valid account" - }, - { - "id": "api.user.update_roles.one_admin.app_error", - "translation": "There must be at least one active admin" - }, - { - "id": "api.user.update_roles.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "The system admin role can only by modified by another system admin" - }, - { - "id": "api.user.update_roles.system_admin_set.app_error", - "translation": "The system admin role can only be set by another system admin" - }, - { - "id": "api.user.upload_profile_user.array.app_error", - "translation": "Empty array under 'image' in request" - }, - { - "id": "api.user.upload_profile_user.decode.app_error", - "translation": "Could not decode profile image" - }, - { - "id": "api.user.upload_profile_user.decode_config.app_error", - "translation": "Could not decode profile image config." - }, - { - "id": "api.user.upload_profile_user.encode.app_error", - "translation": "Could not encode profile image" - }, - { - "id": "api.user.upload_profile_user.no_file.app_error", - "translation": "No file under 'image' in request" - }, - { - "id": "api.user.upload_profile_user.open.app_error", - "translation": "Could not open image file" - }, - { - "id": "api.user.upload_profile_user.parse.app_error", - "translation": "Could not parse multipart form" - }, - { - "id": "api.user.upload_profile_user.storage.app_error", - "translation": "Unable to upload file. Image storage is not configured." - }, - { - "id": "api.user.upload_profile_user.too_large.app_error", - "translation": "Unable to upload profile image. File is too large." - }, - { - "id": "mattermost.current_version", - "translation": "Current version is %v (%v/%v/%v)" - }, - { - "id": "utils.i18n.loaded", - "translation": "Loaded system translations for '%v' from '%v'" - } + { + "id": "api.admin.file_read_error", + "translation": "Error reading log file" + }, + { + "id": "api.admin.init.debug", + "translation": "Initializing admin api routes" + }, + { + "id": "api.admin.test_email.body", + "translation": "


      It appears your Mattermost email is setup correctly!" + }, + { + "id": "api.admin.test_email.subject", + "translation": "Mattermost - Testing Email Settings" + }, + { + "id": "api.api.init.parsing_templates.debug", + "translation": "Parsing server templates at %v" + }, + { + "id": "api.api.init.parsing_templates.error", + "translation": "Failed to parse server templates %v" + }, + { + "id": "api.api.render.error", + "translation": "Error rendering template %v err=%v" + }, + { + "id": "api.channel.add_member.added", + "translation": "%v added to the channel by %v" + }, + { + "id": "api.channel.add_member.find_channel.app_error", + "translation": "Failed to find channel" + }, + { + "id": "api.channel.add_member.find_user.app_error", + "translation": "Failed to find user to be added" + }, + { + "id": "api.channel.add_member.user_adding.app_error", + "translation": "Failed to find user doing the adding" + }, + { + "id": "api.channel.add_user.to.channel.failed.app_error", + "translation": "Failed to add user to channel" + }, + { + "id": "api.channel.add_user_to_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.add_user_to_channel.type.app_error", + "translation": "Can not add user to this channel type" + }, + { + "id": "api.channel.create_channel.direct_channel.app_error", + "translation": "Must use createDirectChannel api service for direct message channel creation" + }, + { + "id": "api.channel.create_channel.invalid_character.app_error", + "translation": "Invalid character '__' in channel name for non-direct channel" + }, + { + "id": "api.channel.create_default_channels.off_topic", + "translation": "Off-Topic" + }, + { + "id": "api.channel.create_default_channels.town_square", + "translation": "Town Square" + }, + { + "id": "api.channel.create_direct_channel.invalid_user.app_error", + "translation": "Invalid other user id " + }, + { + "id": "api.channel.delete_channel.archived", + "translation": "%v has archived the channel." + }, + { + "id": "api.channel.delete_channel.cannot.app_error", + "translation": "Cannot delete the default channel {{.Channel}}" + }, + { + "id": "api.channel.delete_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.delete_channel.failed_post.error", + "translation": "Failed to post archive message %v" + }, + { + "id": "api.channel.delete_channel.failed_send.app_error", + "translation": "Failed to send archive message" + }, + { + "id": "api.channel.delete_channel.incoming_webhook.error", + "translation": "Encountered error deleting incoming webhook, id=%v" + }, + { + "id": "api.channel.delete_channel.outgoing_webhook.error", + "translation": "Encountered error deleting outgoing webhook, id=%v" + }, + { + "id": "api.channel.delete_channel.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.channel.get_channel_counts.app_error", + "translation": "Unable to get channel counts from the database" + }, + { + "id": "api.channel.get_channel_extra_info.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.get_channel_extra_info.member_limit.app_error", + "translation": "Failed to parse member limit" + }, + { + "id": "api.channel.get_channels.error", + "translation": "Error in getting users profile for id=%v forcing logout" + }, + { + "id": "api.channel.init.debug", + "translation": "Initializing channel api routes" + }, + { + "id": "api.channel.join_channel.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.channel.join_channel.post_and_forget", + "translation": "%v has joined the channel." + }, + { + "id": "api.channel.leave.default.app_error", + "translation": "Cannot leave the default channel {{.Channel}}" + }, + { + "id": "api.channel.leave.direct.app_error", + "translation": "Cannot leave a direct message channel" + }, + { + "id": "api.channel.leave.left", + "translation": "%v has left the channel." + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.join_leave.error", + "translation": "Failed to post join/leave message %v" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.removed", + "translation": "%s removed the channel header (was: %s)" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.retrieve_user.error", + "translation": "Failed to retrieve user while trying to save update channel header message %v" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.updated_from", + "translation": "%s updated the channel header from: %s to: %s" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.updated_to", + "translation": "%s updated the channel header to: %s" + }, + { + "id": "api.channel.post_user_add_remove_message_and_forget.error", + "translation": "Failed to post join/leave message %v" + }, + { + "id": "api.channel.remove_member.permissions.app_error", + "translation": "You do not have the appropriate permissions " + }, + { + "id": "api.channel.remove_member.unable.app_error", + "translation": "Unable to remove user." + }, + { + "id": "api.channel.remove_user_from_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.update_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.update_channel.permission.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.channel.update_channel.tried.app_error", + "translation": "Tried to perform an invalid update of the default channel {{.Channel}}" + }, + { + "id": "api.command.check_command.start.app_error", + "translation": "Command must start with /" + }, + { + "id": "api.command.echo_command.create.error", + "translation": "Unable to create /echo post, err=%v" + }, + { + "id": "api.command.echo_command.description", + "translation": "Echo back text from your account, /echo \"message\" [delay in seconds]" + }, + { + "id": "api.command.echo_command.high_volume.app_error", + "translation": "High volume of echo request, cannot process request" + }, + { + "id": "api.command.echo_command.under.app_error", + "translation": "Delays must be under 10000 seconds" + }, + { + "id": "api.command.init.debug", + "translation": "Initializing command api routes" + }, + { + "id": "api.command.load_test_channels_command.channel.description", + "translation": "Add a specified number of random channels to current team " + }, + { + "id": "api.command.load_test_channels_command.fuzz.description", + "translation": "Add a specified number of random channels with fuzz text to current team " + }, + { + "id": "api.command.load_test_command.description", + "translation": "Debug Load Testing" + }, + { + "id": "api.command.load_test_posts_command.fuzz.description", + "translation": "Add some random posts with fuzz text to current channel " + }, + { + "id": "api.command.load_test_posts_command.posts.description", + "translation": "Add some random posts to current channel " + }, + { + "id": "api.command.load_test_setup_command.create.error", + "translation": "Failed to create testing environment" + }, + { + "id": "api.command.load_test_setup_command.created.info", + "translation": "Team Created: %v" + }, + { + "id": "api.command.load_test_setup_command.description", + "translation": "Creates a testing environment in current team. [teams] [fuzz] " + }, + { + "id": "api.command.load_test_setup_command.login.info", + "translation": "\t User to login: %v, %v" + }, + { + "id": "api.command.load_test_url_command.create.error", + "translation": "Unable to create post, err=%v" + }, + { + "id": "api.command.load_test_url_command.description", + "translation": "Add a post containing the text from a given url to current channel " + }, + { + "id": "api.command.load_test_url_command.file.app_error", + "translation": "Unable to get file" + }, + { + "id": "api.command.load_test_url_command.reading.app_error", + "translation": "Encountered error reading file" + }, + { + "id": "api.command.load_test_url_command.url.app_error", + "translation": "Command must contain a url" + }, + { + "id": "api.command.load_test_users_command.fuzz.description", + "translation": "Add a specified number of random users with fuzz text to current team " + }, + { + "id": "api.command.load_test_users_command.users.description", + "translation": "Add a specified number of random users to current team " + }, + { + "id": "api.command.logout_command.description", + "translation": "Logout" + }, + { + "id": "api.command.me_command.create.error", + "translation": "Unable to create /me post post, err=%v" + }, + { + "id": "api.command.me_command.description", + "translation": "Do an action, /me [message]" + }, + { + "id": "api.command.no_implemented.app_error", + "translation": "Command not implemented" + }, + { + "id": "api.command.shrug_command.create.error", + "translation": "Unable to create /shrug post post, err=%v" + }, + { + "id": "api.command.shrug_command.description", + "translation": "Adds ¯\\_(ツ)_/¯ to your message, /shrug [message]" + }, + { + "id": "api.commmand.join_command.description", + "translation": "Join the open channel" + }, + { + "id": "api.context.404.app_error", + "translation": "Sorry, we could not find the page." + }, + { + "id": "api.context.invalid_param.app_error", + "translation": "Invalid {{.Name}} parameter" + }, + { + "id": "api.context.invalid_team_url.debug", + "translation": "TeamURL accessed when not valid. Team URL should not be used in api functions or those that are team independent" + }, + { + "id": "api.context.invalid_token.error", + "translation": "Invalid session token=%v, err=%v" + }, + { + "id": "api.context.last_activity_at.error", + "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" + }, + { + "id": "api.context.log.error", + "translation": "%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]" + }, + { + "id": "api.context.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.context.session_expired.app_error", + "translation": "Invalid or expired session, please login again." + }, + { + "id": "api.context.system_permissions.app_error", + "translation": "You do not have the appropriate permissions (system)" + }, + { + "id": "api.context.token_provided.app_error", + "translation": "Session is not OAuth but token was provided in the query string" + }, + { + "id": "api.context.unknown.app_error", + "translation": "An unknown error has occured. Please contact support." + }, + { + "id": "api.export.json.app_error", + "translation": "Unable to convert to json" + }, + { + "id": "api.export.open.app_error", + "translation": "Unable to open file" + }, + { + "id": "api.export.open_dir.app_error", + "translation": "Unable to open directory" + }, + { + "id": "api.export.open_file.app_error", + "translation": "Unable to open file for export" + }, + { + "id": "api.export.options.create.app_error", + "translation": "Unable to create options file" + }, + { + "id": "api.export.options.write.app_error", + "translation": "Unable to write to options file" + }, + { + "id": "api.export.read_dir.app_error", + "translation": "Unable to read directory" + }, + { + "id": "api.export.s3.app_error", + "translation": "S3 is not supported for local storage export." + }, + { + "id": "api.export.write_file.app_error", + "translation": "Unable to write to export file" + }, + { + "id": "api.file.file_upload.exceeds", + "translation": "File exceeds max image size." + }, + { + "id": "api.file.get_export.retrieve.app_error", + "translation": "Unable to retrieve exported file. Please re-export" + }, + { + "id": "api.file.get_export.team_admin.app_error", + "translation": "Only a team admin can retrieve exported data." + }, + { + "id": "api.file.get_file.not_found.app_error", + "translation": "Could not find file." + }, + { + "id": "api.file.get_file.public_expired.app_error", + "translation": "The public link has expired" + }, + { + "id": "api.file.get_file.public_invalid.app_error", + "translation": "The public link does not appear to be valid" + }, + { + "id": "api.file.get_public_link.disabled.app_error", + "translation": "Public links have been disabled" + }, + { + "id": "api.file.handle_images_forget.decode.error", + "translation": "Unable to decode image channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.encode_jpeg.error", + "translation": "Unable to encode image as jpeg channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.encode_preview.error", + "translation": "Unable to encode image as preview jpg channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.upload_preview.error", + "translation": "Unable to upload preview channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.upload_thumb.error", + "translation": "Unable to upload thumbnail channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.init.debug", + "translation": "Initializing file api routes" + }, + { + "id": "api.file.open_file_write_stream.configured.app_error", + "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." + }, + { + "id": "api.file.open_file_write_stream.creating_dir.app_error", + "translation": "Encountered an error creating the directory for the new file" + }, + { + "id": "api.file.open_file_write_stream.local_server.app_error", + "translation": "Encountered an error writing to local server storage" + }, + { + "id": "api.file.open_file_write_stream.s3.app_error", + "translation": "S3 is not supported." + }, + { + "id": "api.file.read_file.configured.app_error", + "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." + }, + { + "id": "api.file.read_file.get.app_error", + "translation": "Unable to get file from S3" + }, + { + "id": "api.file.read_file.reading_local.app_error", + "translation": "Encountered an error reading from local server storage" + }, + { + "id": "api.file.upload_file.image.app_error", + "translation": "Unable to upload image file." + }, + { + "id": "api.file.upload_file.large_image.app_error", + "translation": "Unable to upload image file. File is too large." + }, + { + "id": "api.file.upload_file.storage.app_error", + "translation": "Unable to upload file. Image storage is not configured." + }, + { + "id": "api.file.upload_file.too_large.app_error", + "translation": "Unable to upload file. File is too large." + }, + { + "id": "api.file.write_file.configured.app_error", + "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." + }, + { + "id": "api.file.write_file.s3.app_error", + "translation": "Encountered an error writing to S3" + }, + { + "id": "api.file.write_file_locally.create_dir.app_error", + "translation": "Encountered an error creating the directory for the new file" + }, + { + "id": "api.file.write_file_locally.writing.app_error", + "translation": "Encountered an error writing to local server storage" + }, + { + "id": "api.import.import_post.saving.debug", + "translation": "Error saving post. user=%v, message=%v" + }, + { + "id": "api.import.import_user.joining_default.error", + "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" + }, + { + "id": "api.import.import_user.saving.error", + "translation": "Error saving user. err=%v" + }, + { + "id": "api.import.import_user.set_email.error", + "translation": "Failed to set email verified err=%v" + }, + { + "id": "api.license.add_license.array.app_error", + "translation": "Empty array under 'license' in request" + }, + { + "id": "api.license.add_license.expired.app_error", + "translation": "License is either expired or has not yet started." + }, + { + "id": "api.license.add_license.invalid.app_error", + "translation": "Invalid license file." + }, + { + "id": "api.license.add_license.no_file.app_error", + "translation": "No file under 'license' in request" + }, + { + "id": "api.license.add_license.open.app_error", + "translation": "Could not open license file" + }, + { + "id": "api.license.add_license.save.app_error", + "translation": "License did not save properly." + }, + { + "id": "api.license.init.debug", + "translation": "Initializing license api routes" + }, + { + "id": "api.license.remove_license.remove.app_error", + "translation": "License did not remove properly." + }, + { + "id": "api.oauth.allow_oauth.bad_client.app_error", + "translation": "invalid_request: Bad client_id" + }, + { + "id": "api.oauth.allow_oauth.bad_redirect.app_error", + "translation": "invalid_request: Missing or bad redirect_uri" + }, + { + "id": "api.oauth.allow_oauth.bad_response.app_error", + "translation": "invalid_request: Bad response_type" + }, + { + "id": "api.oauth.allow_oauth.database.app_error", + "translation": "server_error: Error accessing the database" + }, + { + "id": "api.oauth.allow_oauth.redirect_callback.app_error", + "translation": "invalid_request: Supplied redirect_uri did not match registered callback_url" + }, + { + "id": "api.oauth.allow_oauth.turn_off.app_error", + "translation": "The system admin has turned off OAuth service providing." + }, + { + "id": "api.oauth.get_auth_data.find.error", + "translation": "Couldn't find auth code for code=%s" + }, + { + "id": "api.oauth.init.debug", + "translation": "Initializing oauth api routes" + }, + { + "id": "api.oauth.register_oauth_app.turn_off.app_error", + "translation": "The system admin has turned off OAuth service providing." + }, + { + "id": "api.oauth.revoke_access_token.del_code.app_error", + "translation": "Error deleting authorization code from DB" + }, + { + "id": "api.oauth.revoke_access_token.del_session.app_error", + "translation": "Error deleting session from DB" + }, + { + "id": "api.oauth.revoke_access_token.del_token.app_error", + "translation": "Error deleting access token from DB" + }, + { + "id": "api.oauth.revoke_access_token.get.app_error", + "translation": "Error getting access token from DB before deletion" + }, + { + "id": "api.post.create_post.bad_filename.error", + "translation": "Bad filename discarded, filename=%v" + }, + { + "id": "api.post.create_post.channel_root_id.app_error", + "translation": "Invalid ChannelId for RootId parameter" + }, + { + "id": "api.post.create_post.last_viewed.error", + "translation": "Encountered error updating last viewed, channel_id=%s, user_id=%s, err=%v" + }, + { + "id": "api.post.create_post.parent_id.app_error", + "translation": "Invalid ParentId parameter" + }, + { + "id": "api.post.create_post.root_id.app_error", + "translation": "Invalid RootId parameter" + }, + { + "id": "api.post.create_webhook_post.creating.app_error", + "translation": "Error creating post" + }, + { + "id": "api.post.delete_post.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.post.get_post.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.post.handle_post_events_and_forget.channel.error", + "translation": "Encountered error getting channel, channel_id=%s, err=%v" + }, + { + "id": "api.post.handle_post_events_and_forget.team.error", + "translation": "Encountered error getting team, team_id=%s, err=%v" + }, + { + "id": "api.post.handle_post_events_and_forget.user.error", + "translation": "Encountered error getting user, user_id=%s, err=%v" + }, + { + "id": "api.post.handle_webhook_events_and_forget.create_post.error", + "translation": "Failed to create response post, err=%v" + }, + { + "id": "api.post.handle_webhook_events_and_forget.event_post.error", + "translation": "Event POST failed, err=%s" + }, + { + "id": "api.post.handle_webhook_events_and_forget.getting.error", + "translation": "Encountered error getting webhooks by team, err=%v" + }, + { + "id": "api.post.init.debug", + "translation": "Initializing post api routes" + }, + { + "id": "api.post.make_direct_channel_visible.get_2_members.error", + "translation": "Failed to get 2 members for a direct channel channel_id=%v" + }, + { + "id": "api.post.make_direct_channel_visible.get_members.error", + "translation": "Failed to get channel members channel_id=%v err=%v" + }, + { + "id": "api.post.make_direct_channel_visible.save_pref.error", + "translation": "Failed to save direct channel preference user_id=%v other_user_id=%v err=%v" + }, + { + "id": "api.post.make_direct_channel_visible.update_pref.error", + "translation": "Failed to update direct channel preference user_id=%v other_user_id=%v err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.members.error", + "translation": "Failed to get channel members channel_id=%v err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.mention_body", + "translation": "You have one new mention." + }, + { + "id": "api.post.send_notifications_and_forget.mention_subject", + "translation": "New Mention" + }, + { + "id": "api.post.send_notifications_and_forget.message_body", + "translation": "You have one new message." + }, + { + "id": "api.post.send_notifications_and_forget.message_subject", + "translation": "New Direct Message" + }, + { + "id": "api.post.send_notifications_and_forget.push_mention", + "translation": " mentioned you in " + }, + { + "id": "api.post.send_notifications_and_forget.push_message", + "translation": " sent you a direct message" + }, + { + "id": "api.post.send_notifications_and_forget.push_notification.debug", + "translation": "Sending push notification to %v wi msg of '%v'" + }, + { + "id": "api.post.send_notifications_and_forget.push_notification.error", + "translation": "Failed to send push notificationid=%v, err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.retrive_profiles.error", + "translation": "Failed to retrieve user profiles team_id=%v, err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.send.error", + "translation": "Failed to send mention email successfully email=%v err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.sent", + "translation": "{{.Prefix}} {{.Filenames}} sent" + }, + { + "id": "api.post.send_notifications_and_forget.sessions.error", + "translation": "Failed to retrieve sessions in notifications id=%v, err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.user_id.error", + "translation": "Post user_id not returned by GetProfiles user_id=%v" + }, + { + "id": "api.post.update_mention_count_and_forget.update_error", + "translation": "Failed to update mention count for user_id=%v on channel_id=%v err=%v" + }, + { + "id": "api.post.update_post.find.app_error", + "translation": "We couldn't find the existing post or comment to update." + }, + { + "id": "api.post.update_post.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.post.update_post.permissions_details.app_error", + "translation": "Already delted id={{.PostId}}" + }, + { + "id": "api.post_get_post_by_id.get.app_error", + "translation": "Unable to get post" + }, + { + "id": "api.preference.init.debug", + "translation": "Initializing preference api routes" + }, + { + "id": "api.preference.save_preferences.decode.app_error", + "translation": "Unable to decode preferences from request" + }, + { + "id": "api.preference.save_preferences.set.app_error", + "translation": "Unable to set preferences for other user" + }, + { + "id": "api.preference.save_preferences.set_details.app_error", + "translation": "session.user_id={{.SessionUserId}}, preference.user_id={{.PreferenceUserId}}" + }, + { + "id": "api.server.new_server.init.info", + "translation": "Server is initializing..." + }, + { + "id": "api.server.start_server.listening.info", + "translation": "Server is listening on %v" + }, + { + "id": "api.server.start_server.rate.info", + "translation": "RateLimiter is enabled" + }, + { + "id": "api.server.start_server.rate.warn", + "translation": "RateLimitSettings not configured properly using VaryByHeader and disabling VaryByRemoteAddr" + }, + { + "id": "api.server.start_server.starting.critical", + "translation": "Error starting server, err:%v" + }, + { + "id": "api.server.start_server.starting.info", + "translation": "Starting Server..." + }, + { + "id": "api.server.start_server.starting.panic", + "translation": "Error starting server " + }, + { + "id": "api.server.stop_server.stopped.info", + "translation": "Server stopped" + }, + { + "id": "api.server.stop_server.stopping.info", + "translation": "Stopping Server..." + }, + { + "id": "api.slackimport.slack_add_channels.added", + "translation": "\r\n Channels Added \r\n" + }, + { + "id": "api.slackimport.slack_add_channels.import_failed", + "translation": "Failed to import: {{.DisplayName}}\r\n" + }, + { + "id": "api.slackimport.slack_add_channels.import_failed.debug", + "translation": "Failed to import: %s" + }, + { + "id": "api.slackimport.slack_add_channels.merge", + "translation": "Merged with existing channel: {{.DisplayName}}\r\n" + }, + { + "id": "api.slackimport.slack_add_posts.bot.warn", + "translation": "Slack bot posts are not imported yet" + }, + { + "id": "api.slackimport.slack_add_posts.msg_no_usr.debug", + "translation": "Message without user" + }, + { + "id": "api.slackimport.slack_add_posts.unsupported.warn", + "translation": "Unsupported post type: %v, %v" + }, + { + "id": "api.slackimport.slack_add_posts.user_no_exists.debug", + "translation": "User: %v does not exist!" + }, + { + "id": "api.slackimport.slack_add_posts.without_user.debug", + "translation": "Message without user" + }, + { + "id": "api.slackimport.slack_add_users.created", + "translation": "\r\n Users Created\r\n" + }, + { + "id": "api.slackimport.slack_add_users.email_pwd", + "translation": "Email, Password: {{.Email}}, {{.Password}}\r\n" + }, + { + "id": "api.slackimport.slack_add_users.unable_import", + "translation": "Unable to import user: {{.Username}}\r\n" + }, + { + "id": "api.slackimport.slack_convert_timestamp.bad.warn", + "translation": "Bad timestamp detected" + }, + { + "id": "api.slackimport.slack_import.log", + "translation": "Mattermost Slack Import Log\r\n" + }, + { + "id": "api.slackimport.slack_import.note1", + "translation": "- Some posts may not have been imported because they where not supported by this importer.\r\n" + }, + { + "id": "api.slackimport.slack_import.note2", + "translation": "- Slack bot posts are currently not supported.\r\n" + }, + { + "id": "api.slackimport.slack_import.notes", + "translation": "\r\n Notes \r\n" + }, + { + "id": "api.slackimport.slack_import.open.app_error", + "translation": "Unable to open: {{.Filename}}" + }, + { + "id": "api.slackimport.slack_import.zip.app_error", + "translation": "Unable to open zip file" + }, + { + "id": "api.team.create_team.email_disabled.app_error", + "translation": "Team sign-up with email is disabled." + }, + { + "id": "api.team.create_team_from_signup.email_disabled.app_error", + "translation": "Team sign-up with email is disabled." + }, + { + "id": "api.team.create_team_from_signup.expired_link.app_error", + "translation": "The signup link has expired" + }, + { + "id": "api.team.create_team_from_signup.invalid_link.app_error", + "translation": "The signup link does not appear to be valid" + }, + { + "id": "api.team.create_team_from_signup.unavailable.app_error", + "translation": "This URL is unavailable. Please try another." + }, + { + "id": "api.team.email_teams.sending.error", + "translation": "An error occured while sending an email in emailTeams err=%v" + }, + { + "id": "api.team.export_team.admin.app_error", + "translation": "Only a team admin can export data." + }, + { + "id": "api.team.import_team.admin.app_error", + "translation": "Only a team admin can import data." + }, + { + "id": "api.team.import_team.array.app_error", + "translation": "Empty array under 'file' in request" + }, + { + "id": "api.team.import_team.integer.app_error", + "translation": "Filesize not an integer" + }, + { + "id": "api.team.import_team.no_file.app_error", + "translation": "No file under 'file' in request" + }, + { + "id": "api.team.import_team.open.app_error", + "translation": "Could not open file" + }, + { + "id": "api.team.import_team.parse.app_error", + "translation": "Could not parse multipart form" + }, + { + "id": "api.team.import_team.unavailable.app_error", + "translation": "Filesize unavilable" + }, + { + "id": "api.team.init.debug", + "translation": "Initializing team api routes" + }, + { + "id": "api.team.invite_members.admin", + "translation": "administrator" + }, + { + "id": "api.team.invite_members.already.app_error", + "translation": "This person is already on your team" + }, + { + "id": "api.team.invite_members.member", + "translation": "member" + }, + { + "id": "api.team.invite_members.no_one.app_error", + "translation": "No one to invite." + }, + { + "id": "api.team.invite_members.send.error", + "translation": "Failed to send invite email successfully err=%v" + }, + { + "id": "api.team.invite_members.sending.info", + "translation": "sending invitation to %v %v" + }, + { + "id": "api.team.is_team_creation_allowed.disabled.app_error", + "translation": "Team creation has been disabled. Please ask your systems administrator for details." + }, + { + "id": "api.team.is_team_creation_allowed.domain.app_error", + "translation": "Email must be from a specific domain (e.g. @example.com). Please ask your systems administrator for details." + }, + { + "id": "api.team.permanent_delete_team.attempting.warn", + "translation": "Attempting to permanently delete team %v id=%v" + }, + { + "id": "api.team.permanent_delete_team.deleted.warn", + "translation": "Permanently deleted team %v id=%v" + }, + { + "id": "api.team.signup_team.email_disabled.app_error", + "translation": "Team sign-up with email is disabled." + }, + { + "id": "api.team.update_team.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.user.add_direct_channels_and_forget.failed.error", + "translation": "Failed to add direct channel preferences for user user_id=%s, team_id=%s, err=%v" + }, + { + "id": "api.user.authorize_oauth_user.bad_response.app_error", + "translation": "Bad response from token request" + }, + { + "id": "api.user.authorize_oauth_user.bad_token.app_error", + "translation": "Bad token type" + }, + { + "id": "api.user.authorize_oauth_user.invalid_state.app_error", + "translation": "Invalid state" + }, + { + "id": "api.user.authorize_oauth_user.invalid_state_team.app_error", + "translation": "Invalid state; missing team name" + }, + { + "id": "api.user.authorize_oauth_user.missing.app_error", + "translation": "Missing access token" + }, + { + "id": "api.user.authorize_oauth_user.service.app_error", + "translation": "Token request to {{.Service}} failed" + }, + { + "id": "api.user.authorize_oauth_user.token_failed.app_error", + "translation": "Token request failed" + }, + { + "id": "api.user.authorize_oauth_user.unsupported.app_error", + "translation": "Unsupported OAuth service provider" + }, + { + "id": "api.user.check_user_login_attempts.too_many.app_error", + "translation": "Your account is locked because of too many failed password attempts. Please reset your password." + }, + { + "id": "api.user.check_user_password.invalid.app_error", + "translation": "Login failed because of invalid password" + }, + { + "id": "api.user.complete_switch_with_oauth.blank_email.app_error", + "translation": "Blank email" + }, + { + "id": "api.user.complete_switch_with_oauth.parse.app_error", + "translation": "Could not parse auth data out of {{.Service}} user object" + }, + { + "id": "api.user.complete_switch_with_oauth.unavailable.app_error", + "translation": "{{.Service}} oauth not available on this server" + }, + { + "id": "api.user.create_oauth_user.already_attached.app_error", + "translation": "Team {{.DisplayName}} already has a user with the email address attached to your {{.Service}} account" + }, + { + "id": "api.user.create_oauth_user.already_used.app_error", + "translation": "This {{.Service}} account has already been used to sign up for team {{.DisplayName}}" + }, + { + "id": "api.user.create_oauth_user.create.app_error", + "translation": "Could not create user out of {{.Service}} user object" + }, + { + "id": "api.user.create_oauth_user.not_available.app_error", + "translation": "{{.Service}} oauth not avlailable on this server" + }, + { + "id": "api.user.create_profile_image.default_font.app_error", + "translation": "Could not create default profile image font" + }, + { + "id": "api.user.create_profile_image.encode.app_error", + "translation": "Could not encode default profile image" + }, + { + "id": "api.user.create_profile_image.initial.app_error", + "translation": "Could not add user initial to default profile picture" + }, + { + "id": "api.user.create_user.accepted_domain.app_error", + "translation": "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email." + }, + { + "id": "api.user.create_user.joining.error", + "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" + }, + { + "id": "api.user.create_user.save.error", + "translation": "Couldn't save the user err=%v" + }, + { + "id": "api.user.create_user.signup_email_disabled.app_error", + "translation": "User sign-up with email is disabled." + }, + { + "id": "api.user.create_user.signup_link_expired.app_error", + "translation": "The signup link has expired" + }, + { + "id": "api.user.create_user.signup_link_invalid.app_error", + "translation": "The signup link does not appear to be valid" + }, + { + "id": "api.user.create_user.team_name.app_error", + "translation": "Invalid team name" + }, + { + "id": "api.user.create_user.tutorial.error", + "translation": "Encountered error saving tutorial preference, err=%v" + }, + { + "id": "api.user.create_user.verified.error", + "translation": "Failed to set email verified err=%v" + }, + { + "id": "api.user.get_authorization_code.unsupported.app_error", + "translation": "Unsupported OAuth service provider" + }, + { + "id": "api.user.get_me.getting.error", + "translation": "Error in getting users profile for id=%v forcing logout" + }, + { + "id": "api.user.init.debug", + "translation": "Initializing user api routes" + }, + { + "id": "api.user.login.blank_pwd.app_error", + "translation": "Password field must not be blank" + }, + { + "id": "api.user.login.inactive.app_error", + "translation": "Login failed because your account has been set to inactive. Please contact an administrator." + }, + { + "id": "api.user.login.not_provided.app_error", + "translation": "Either user id or team name and user email must be provided" + }, + { + "id": "api.user.login.not_verified.app_error", + "translation": "Login failed because email address has not been verified" + }, + { + "id": "api.user.login.revoking.app_error", + "translation": "Revoking sessionId=%v for userId=%v re-login with same device Id" + }, + { + "id": "api.user.login_by_email.sign_in.app_error", + "translation": "Please sign in using {{.AuthService}}" + }, + { + "id": "api.user.login_by_oauth.not_available.app_error", + "translation": "{{.Service}} oauth not avlailable on this server" + }, + { + "id": "api.user.login_by_oauth.parse.app_error", + "translation": "Could not parse auth data out of {{.Service}} user object" + }, + { + "id": "api.user.login_ldap.blank_pwd.app_error", + "translation": "Password field must not be blank" + }, + { + "id": "api.user.login_ldap.disabled.app_error", + "translation": "LDAP not enabled on this server" + }, + { + "id": "api.user.login_ldap.need_id.app_error", + "translation": "Need an ID" + }, + { + "id": "api.user.login_ldap.not_available.app_error", + "translation": "LDAP not available on this server" + }, + { + "id": "api.user.permanent_delete_user.attempting.warn", + "translation": "Attempting to permanently delete account %v id=%v" + }, + { + "id": "api.user.permanent_delete_user.deleted.warn", + "translation": "Permanently deleted account %v id=%v" + }, + { + "id": "api.user.permanent_delete_user.system_admin.warn", + "translation": "You are deleting %v that is a system administrator. You may need to set another account as the system administrator using the command line tools." + }, + { + "id": "api.user.reset_password.invalid_link.app_error", + "translation": "The reset password link does not appear to be valid" + }, + { + "id": "api.user.reset_password.link_expired.app_error", + "translation": "The reset link has expired" + }, + { + "id": "api.user.reset_password.sso.app_error", + "translation": "Cannot reset password for SSO accounts" + }, + { + "id": "api.user.reset_password.wrong_team.app_error", + "translation": "Trying to reset password for user on wrong team." + }, + { + "id": "api.user.send_email_change_email_and_forget.error", + "translation": "Failed to send email change notification email successfully err=%v" + }, + { + "id": "api.user.send_email_change_verify_email_and_forget.error", + "translation": "Failed to send email change verification email successfully err=%v" + }, + { + "id": "api.user.send_password_change_email_and_forget.error", + "translation": "Failed to send update password email successfully err=%v" + }, + { + "id": "api.user.send_password_reset.find.app_error", + "translation": "We couldn’t find an account with that address." + }, + { + "id": "api.user.send_password_reset.send.app_error", + "translation": "Failed to send password reset email successfully" + }, + { + "id": "api.user.send_password_reset.sso.app_error", + "translation": "Cannot reset password for SSO accounts" + }, + { + "id": "api.user.send_sign_in_change_email_and_forget.error", + "translation": "Failed to send update password email successfully err=%v" + }, + { + "id": "api.user.send_verify_email_and_forget.failed.error", + "translation": "Failed to send verification email successfully err=%v" + }, + { + "id": "api.user.send_welcome_email_and_forget.failed.error", + "translation": "Failed to send welcome email successfully err=%v" + }, + { + "id": "api.user.switch_to_email.context.app_error", + "translation": "Update password failed because context user_id did not match provided user's id" + }, + { + "id": "api.user.update_active.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.user.update_password.context.app_error", + "translation": "Update password failed because context user_id did not match props user_id" + }, + { + "id": "api.user.update_password.failed.app_error", + "translation": "Update password failed" + }, + { + "id": "api.user.update_password.incorrect.app_error", + "translation": "The \"Current Password\" you entered is incorrect. Please check that Caps Lock is off and try again." + }, + { + "id": "api.user.update_password.menu", + "translation": "using the settings menu" + }, + { + "id": "api.user.update_password.oauth.app_error", + "translation": "Update password failed because the user is logged in through an OAuth service" + }, + { + "id": "api.user.update_password.valid_account.app_error", + "translation": "Update password failed because we couldn't find a valid account" + }, + { + "id": "api.user.update_roles.one_admin.app_error", + "translation": "There must be at least one active admin" + }, + { + "id": "api.user.update_roles.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.user.update_roles.system_admin_mod.app_error", + "translation": "The system admin role can only by modified by another system admin" + }, + { + "id": "api.user.update_roles.system_admin_set.app_error", + "translation": "The system admin role can only be set by another system admin" + }, + { + "id": "api.user.upload_profile_user.array.app_error", + "translation": "Empty array under 'image' in request" + }, + { + "id": "api.user.upload_profile_user.decode.app_error", + "translation": "Could not decode profile image" + }, + { + "id": "api.user.upload_profile_user.decode_config.app_error", + "translation": "Could not decode profile image config." + }, + { + "id": "api.user.upload_profile_user.encode.app_error", + "translation": "Could not encode profile image" + }, + { + "id": "api.user.upload_profile_user.no_file.app_error", + "translation": "No file under 'image' in request" + }, + { + "id": "api.user.upload_profile_user.open.app_error", + "translation": "Could not open image file" + }, + { + "id": "api.user.upload_profile_user.parse.app_error", + "translation": "Could not parse multipart form" + }, + { + "id": "api.user.upload_profile_user.storage.app_error", + "translation": "Unable to upload file. Image storage is not configured." + }, + { + "id": "api.user.upload_profile_user.too_large.app_error", + "translation": "Unable to upload profile image. File is too large." + }, + { + "id": "mattermost.current_version", + "translation": "Current version is %v (%v/%v/%v)" + }, + { + "id": "utils.i18n.loaded", + "translation": "Loaded system translations for '%v' from '%v'" + }, + { + "id": "api.web_conn.new_web_conn.last_activity.error", + "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" + }, + { + "id": "api.web_conn.new_web_conn.last_ping.error", + "translation": "Failed to update LastPingAt for user_id=%v, err=%v" + }, + { + "id": "api.web_hub.start.stopping.debug", + "translation": "stopping %v connections" + }, + { + "id": "api.web_socket.init.debug", + "translation": "Initializing web socket api routes" + }, + { + "id": "api.web_socket.connect.error", + "translation": "websocket connect err: %v" + }, + { + "id": "api.web_socket.connect.upgrade.app_error", + "translation": "Failed to upgrade websocket connection" + }, + { + "id": "api.web_team_hun.start.debug", + "translation": "team hub stopping for teamId=%v" + }, + { + "id": "api.webhook.init.debug", + "translation": "Initializing webhook api routes" + }, + { + "id": "", + "translation": "Incoming webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.delete_incoming.disabled.app_errror", + "translation": "Incoming webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.delete_incoming.permissions.app_errror", + "translation": "Inappropriate permissions to delete incoming webhook" + }, + { + "id": "api.webhook.get_incoming.disabled.app_error", + "translation": "Incoming webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.create_outgoing.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.create_outgoing.triggers.app_error", + "translation": "Either trigger_words or channel_id must be set" + }, + { + "id": "api.webhook.get_outgoing.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.delete_outgoing.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.delete_outgoing.permissions.app_error", + "translation": "Inappropriate permissions to delete outcoming webhook" + }, + { + "id": "api.webhook.regen_outgoing_token.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.regen_outgoing_token.permissions.app_error", + "translation": "Inappropriate permissions to regenerate outcoming webhook token" + } ] \ No newline at end of file diff --git a/i18n/es.json b/i18n/es.json index 480f23857..a02038085 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1,4 +1,8 @@ [ + { + "id": "", + "translation": "Webhooks entrantes han sido deshabilitados por el administrador del sistema." + }, { "id": "api.admin.file_read_error", "translation": "Error leyendo el archivo de registro" @@ -1319,6 +1323,78 @@ "id": "api.user.upload_profile_user.too_large.app_error", "translation": "No se pudo actualizar la imagen del perfil. El archivo es muy grande." }, + { + "id": "api.web_conn.new_web_conn.last_activity.error", + "translation": "Falla al actualizar LastActivityAt para user_id=%v and session_id=%v, err=%v" + }, + { + "id": "api.web_conn.new_web_conn.last_ping.error", + "translation": "Failed to update LastPingAt for user_id=%v, err=%v" + }, + { + "id": "api.web_hub.start.stopping.debug", + "translation": "deteniendo todas las conexiones" + }, + { + "id": "api.web_socket.connect.error", + "translation": "conexión al websocket err: %v" + }, + { + "id": "api.web_socket.connect.upgrade.app_error", + "translation": "Falla al actualizar la conexión del websocket" + }, + { + "id": "api.web_socket.init.debug", + "translation": "Inicializando rutas del API para los web socket" + }, + { + "id": "api.web_team_hun.start.debug", + "translation": "deteniendo el hub de equipo para teamId=%v" + }, + { + "id": "api.webhook.create_outgoing.disabled.app_error", + "translation": "Webhooks de Salida han sido deshabilitados por el administrador del sistema." + }, + { + "id": "api.webhook.create_outgoing.triggers.app_error", + "translation": "Debe establecerse palabras gatilladoras o un channel_id" + }, + { + "id": "api.webhook.delete_incoming.disabled.app_errror", + "translation": "Webhooks entrantes han sido deshabilitados por el administrador del sistema." + }, + { + "id": "api.webhook.delete_incoming.permissions.app_errror", + "translation": "Permisos inapropiados para eliminar un webhook entrante" + }, + { + "id": "api.webhook.delete_outgoing.disabled.app_error", + "translation": "Webhooks de Salida han sido deshabilitados por el administrador del sistema." + }, + { + "id": "api.webhook.delete_outgoing.permissions.app_error", + "translation": "Permisos inapropiados para eliminar el webhook saliente" + }, + { + "id": "api.webhook.get_incoming.disabled.app_error", + "translation": "Webhooks entrantes han sido deshabilitados por el administrador del sistema." + }, + { + "id": "api.webhook.get_outgoing.disabled.app_error", + "translation": "Webhooks de Salida han sido deshabilitados por el administrador del sistema." + }, + { + "id": "api.webhook.init.debug", + "translation": "Inicializando rutas del API para los Webhooks" + }, + { + "id": "api.webhook.regen_outgoing_token.disabled.app_error", + "translation": "Webhooks de Salida han sido deshabilitados por el administrador del sistema." + }, + { + "id": "api.webhook.regen_outgoing_token.permissions.app_error", + "translation": "Permisos inapropiados para regenerar un token para el Webhook saliente" + }, { "id": "mattermost.current_version", "translation": "La versión actual es %v (%v/%v/%v)" -- cgit v1.2.3-1-g7c22 From 43c19981cf67c6b1b3c4f99a1a95fce82d743584 Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 23 Jan 2016 12:15:28 -0500 Subject: Added a limit to the number of suggestions when autocompleting at mentions --- web/react/components/suggestion/at_mention_provider.jsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/react/components/suggestion/at_mention_provider.jsx b/web/react/components/suggestion/at_mention_provider.jsx index 8c2893448..e502c981d 100644 --- a/web/react/components/suggestion/at_mention_provider.jsx +++ b/web/react/components/suggestion/at_mention_provider.jsx @@ -5,6 +5,8 @@ import SuggestionStore from '../../stores/suggestion_store.jsx'; import UserStore from '../../stores/user_store.jsx'; import * as Utils from '../../utils/utils.jsx'; +const MaxUserSuggestions = 40; + class AtMentionSuggestion extends React.Component { render() { const {item, isSelection, onClick} = this.props; @@ -78,6 +80,10 @@ export default class AtMentionProvider { if (user.username.startsWith(usernamePrefix)) { filtered.push(user); } + + if (filtered.length >= MaxUserSuggestions) { + break; + } } // add dummy users to represent the @all and @channel special mentions -- cgit v1.2.3-1-g7c22 From fc0b422c37f719a350b65e064cde7b506a88052e Mon Sep 17 00:00:00 2001 From: hmhealey Date: Sat, 23 Jan 2016 13:13:34 -0500 Subject: Changed GetMemberCount to stop including inactive users --- store/sql_channel_store.go | 11 ++++- store/sql_channel_store_test.go | 106 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/store/sql_channel_store.go b/store/sql_channel_store.go index 336398ae7..7400df8d2 100644 --- a/store/sql_channel_store.go +++ b/store/sql_channel_store.go @@ -582,7 +582,16 @@ func (s SqlChannelStore) GetMemberCount(channelId string) StoreChannel { go func() { result := StoreResult{} - count, err := s.GetReplica().SelectInt("SELECT count(*) FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) + count, err := s.GetReplica().SelectInt(` + SELECT + count(*) + FROM + ChannelMembers, + Users + WHERE + ChannelMembers.UserId = Users.Id + AND ChannelMembers.ChannelId = :ChannelId + AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) if err != nil { result.Err = model.NewAppError("SqlChannelStore.GetMemberCount", "We couldn't get the channel member count", "channel_id="+channelId+", "+err.Error()) } else { diff --git a/store/sql_channel_store_test.go b/store/sql_channel_store_test.go index 8b22fbb7a..a3b0c2286 100644 --- a/store/sql_channel_store_test.go +++ b/store/sql_channel_store_test.go @@ -750,3 +750,109 @@ func TestChannelStoreIncrementMentionCount(t *testing.T) { t.Fatal("failed to update") } } + +func TestGetMemberCount(t *testing.T) { + Setup() + + teamId := model.NewId() + + c1 := model.Channel{ + TeamId: teamId, + DisplayName: "Channel1", + Name: "a" + model.NewId() + "b", + Type: model.CHANNEL_OPEN, + } + Must(store.Channel().Save(&c1)) + + c2 := model.Channel{ + TeamId: teamId, + DisplayName: "Channel2", + Name: "a" + model.NewId() + "b", + Type: model.CHANNEL_OPEN, + } + Must(store.Channel().Save(&c2)) + + t.Logf("c1.Id = %v", c1.Id) + + u1 := model.User{ + TeamId: teamId, + Email: model.NewId(), + DeleteAt: 0, + } + Must(store.User().Save(&u1)) + + m1 := model.ChannelMember{ + ChannelId: c1.Id, + UserId: u1.Id, + NotifyProps: model.GetDefaultChannelNotifyProps(), + } + Must(store.Channel().SaveMember(&m1)) + + if result := <-store.Channel().GetMemberCount(c1.Id); result.Err != nil { + t.Fatal("failed to get member count: %v", result.Err) + } else if result.Data.(int64) != 1 { + t.Fatal("got incorrect member count %v", result.Data) + } + + u2 := model.User{ + TeamId: teamId, + Email: model.NewId(), + DeleteAt: 0, + } + Must(store.User().Save(&u2)) + + m2 := model.ChannelMember{ + ChannelId: c1.Id, + UserId: u2.Id, + NotifyProps: model.GetDefaultChannelNotifyProps(), + } + Must(store.Channel().SaveMember(&m2)) + + if result := <-store.Channel().GetMemberCount(c1.Id); result.Err != nil { + t.Fatal("failed to get member count: %v", result.Err) + } else if result.Data.(int64) != 2 { + t.Fatal("got incorrect member count %v", result.Data) + } + + // make sure members of other channels aren't counted + u3 := model.User{ + TeamId: teamId, + Email: model.NewId(), + DeleteAt: 0, + } + Must(store.User().Save(&u3)) + + m3 := model.ChannelMember{ + ChannelId: c2.Id, + UserId: u3.Id, + NotifyProps: model.GetDefaultChannelNotifyProps(), + } + Must(store.Channel().SaveMember(&m3)) + + if result := <-store.Channel().GetMemberCount(c1.Id); result.Err != nil { + t.Fatal("failed to get member count: %v", result.Err) + } else if result.Data.(int64) != 2 { + t.Fatal("got incorrect member count %v", result.Data) + } + + // make sure inactive users aren't counted + u4 := model.User{ + TeamId: teamId, + Email: model.NewId(), + DeleteAt: 10000, + } + Must(store.User().Save(&u4)) + + m4 := model.ChannelMember{ + ChannelId: c1.Id, + UserId: u4.Id, + NotifyProps: model.GetDefaultChannelNotifyProps(), + } + Must(store.Channel().SaveMember(&m4)) + + if result := <-store.Channel().GetMemberCount(c1.Id); result.Err != nil { + t.Fatal("failed to get member count: %v", result.Err) + } else if result.Data.(int64) != 2 { + t.Fatal("got incorrect member count %v", result.Data) + } +} -- cgit v1.2.3-1-g7c22 From 470349d105642d7a293983a8a1f8a369dc789621 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sun, 24 Jan 2016 17:10:54 -0300 Subject: PLT-7: Refactoring api to use translations (chunk 4) - Translation for api templates english and spanish --- api/api.go | 12 +- api/context.go | 7 + api/post.go | 35 +- api/team.go | 48 +- api/templates/email_change_body.html | 4 +- api/templates/email_change_subject.html | 2 +- api/templates/email_change_verify_body.html | 6 +- api/templates/email_change_verify_subject.html | 2 +- api/templates/email_footer.html | 2 +- api/templates/email_info.html | 4 +- api/templates/error.html | 4 +- api/templates/find_teams_body.html | 10 +- api/templates/find_teams_subject.html | 2 +- api/templates/invite_body.html | 8 +- api/templates/invite_subject.html | 2 +- api/templates/password_change_body.html | 4 +- api/templates/password_change_subject.html | 2 +- api/templates/post_body.html | 6 +- api/templates/post_subject.html | 2 +- api/templates/reset_body.html | 6 +- api/templates/reset_subject.html | 2 +- api/templates/signin_change_body.html | 4 +- api/templates/signin_change_subject.html | 2 +- api/templates/signup_team_body.html | 6 +- api/templates/signup_team_subject.html | 2 +- api/templates/verify_body.html | 6 +- api/templates/verify_subject.html | 2 +- api/templates/welcome_body.html | 10 +- api/templates/welcome_subject.html | 2 +- api/user.go | 121 +- config/config.json | 27 +- i18n/en.json | 3052 +++++++++++++----------- i18n/es.json | 250 +- web/web.go | 4 +- 34 files changed, 2110 insertions(+), 1548 deletions(-) diff --git a/api/api.go b/api/api.go index f537bbfdc..d202172d0 100644 --- a/api/api.go +++ b/api/api.go @@ -19,17 +19,25 @@ var ServerTemplates *template.Template type ServerTemplatePage Page -func NewServerTemplatePage(templateName string) *ServerTemplatePage { +func NewServerTemplatePage(templateName, locale string) *ServerTemplatePage { return &ServerTemplatePage{ TemplateName: templateName, Props: make(map[string]string), + Extra: make(map[string]string), + Html: make(map[string]template.HTML), ClientCfg: utils.ClientCfg, - Locale: model.DEFAULT_LOCALE, + Locale: locale, } } func (me *ServerTemplatePage) Render() string { var text bytes.Buffer + + T := utils.GetUserTranslations(me.Locale) + me.Props["Footer"] = T("api.templates.email_footer") + me.Html["EmailInfo"] = template.HTML(T("api.templates.email_info", + map[string]interface{}{"FeedbackEmail": me.ClientCfg["FeedbackEmail"], "SiteName": me.ClientCfg["SiteName"]})) + if err := ServerTemplates.ExecuteTemplate(&text, me.TemplateName, me); err != nil { l4g.Error(utils.T("api.api.render.error"), me.TemplateName, err) } diff --git a/api/context.go b/api/context.go index f47ed1c30..41a52fa0c 100644 --- a/api/context.go +++ b/api/context.go @@ -5,6 +5,7 @@ package api import ( "fmt" + "html/template" "net" "net/http" "net/url" @@ -37,6 +38,8 @@ type Context struct { type Page struct { TemplateName string Props map[string]string + Extra map[string]string + Html map[string]template.HTML ClientCfg map[string]string ClientLicense map[string]string User *model.User @@ -507,6 +510,10 @@ func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) props["SiteURL"] = GetProtocol(r) + "://" + r.Host } + T, _ := utils.GetTranslationsAndLocale(w, r) + props["Title"] = T("api.templates.error.title", map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}) + props["Link"] = T("api.templates.error.link") + w.WriteHeader(err.StatusCode) ServerTemplates.ExecuteTemplate(w, "error.html", Page{Props: props, ClientCfg: utils.ClientCfg}) } diff --git a/api/post.go b/api/post.go index bb6bcb337..d3807653d 100644 --- a/api/post.go +++ b/api/post.go @@ -10,6 +10,7 @@ import ( "github.com/mattermost/platform/model" "github.com/mattermost/platform/store" "github.com/mattermost/platform/utils" + "html/template" "net/http" "net/url" "path/filepath" @@ -593,28 +594,26 @@ func sendNotificationsAndForget(c *Context, post *model.Post, team *model.Team, channelName = channel.DisplayName } - subjectPage := NewServerTemplatePage("post_subject") - subjectPage.Props["SiteURL"] = c.GetSiteURL() - subjectPage.Props["TeamDisplayName"] = team.DisplayName - subjectPage.Props["SubjectText"] = subjectText - subjectPage.Props["Month"] = tm.Month().String()[:3] - subjectPage.Props["Day"] = fmt.Sprintf("%d", tm.Day()) - subjectPage.Props["Year"] = fmt.Sprintf("%d", tm.Year()) + month := userLocale(tm.Month().String()) + day := fmt.Sprintf("%d", tm.Day()) + year := fmt.Sprintf("%d", tm.Year()) + zone, _ := tm.Zone() - bodyPage := NewServerTemplatePage("post_body") + subjectPage := NewServerTemplatePage("post_subject", c.Locale) + subjectPage.Props["Subject"] = userLocale("api.templates.post_subject", + map[string]interface{}{"SubjectText": subjectText, "TeamDisplayName": team.DisplayName, + "Month": month[:3], "Day": day, "Year": year}) + + bodyPage := NewServerTemplatePage("post_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage.Props["Nickname"] = profileMap[id].FirstName - bodyPage.Props["TeamDisplayName"] = team.DisplayName - bodyPage.Props["ChannelName"] = channelName - bodyPage.Props["BodyText"] = bodyText - bodyPage.Props["SenderName"] = senderName - bodyPage.Props["Hour"] = fmt.Sprintf("%02d", tm.Hour()) - bodyPage.Props["Minute"] = fmt.Sprintf("%02d", tm.Minute()) - bodyPage.Props["Month"] = tm.Month().String()[:3] - bodyPage.Props["Day"] = fmt.Sprintf("%d", tm.Day()) - bodyPage.Props["TimeZone"], _ = tm.Zone() bodyPage.Props["PostMessage"] = model.ClearMentionTags(post.Message) bodyPage.Props["TeamLink"] = teamURL + "/channels/" + channel.Name + bodyPage.Props["BodyText"] = bodyText + bodyPage.Props["Button"] = userLocale("api.templates.post_body.button") + bodyPage.Html["Info"] = template.HTML(userLocale("api.templates.post_body.info", + map[string]interface{}{"ChannelName": channelName, "SenderName": senderName, + "Hour": fmt.Sprintf("%02d", tm.Hour()), "Minute": fmt.Sprintf("%02d", tm.Minute()), + "TimeZone": zone, "Month": month, "Day": day})) // attempt to fill in a message body if the post doesn't have any text if len(strings.TrimSpace(bodyPage.Props["PostMessage"])) == 0 && len(post.Filenames) > 0 { diff --git a/api/team.go b/api/team.go index 57a0e0bd2..779a6affe 100644 --- a/api/team.go +++ b/api/team.go @@ -11,6 +11,7 @@ import ( "github.com/mattermost/platform/model" "github.com/mattermost/platform/store" "github.com/mattermost/platform/utils" + "html/template" "net/http" "net/url" "strconv" @@ -57,10 +58,16 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } - subjectPage := NewServerTemplatePage("signup_team_subject") - subjectPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage := NewServerTemplatePage("signup_team_body") + subjectPage := NewServerTemplatePage("signup_team_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.signup_team_subject", + map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("signup_team_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() + bodyPage.Props["Title"] = c.T("api.templates.signup_team_body.title") + bodyPage.Props["Button"] = c.T("api.templates.signup_team_body.button") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.signup_team_body.button", + map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]})) props := make(map[string]string) props["email"] = email @@ -427,10 +434,16 @@ func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) { return } - subjectPage := NewServerTemplatePage("find_teams_subject") - subjectPage.ClientCfg["SiteURL"] = c.GetSiteURL() - bodyPage := NewServerTemplatePage("find_teams_body") - bodyPage.ClientCfg["SiteURL"] = c.GetSiteURL() + siteURL := c.GetSiteURL() + subjectPage := NewServerTemplatePage("find_teams_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.find_teams_subject", + map[string]interface{}{"SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("find_teams_body", c.Locale) + bodyPage.Props["SiteURL"] = siteURL + bodyPage.Props["Title"] = c.T("api.templates.find_teams_body.title") + bodyPage.Props["Found"] = c.T("api.templates.find_teams_body.found") + bodyPage.Props["NotFound"] = c.T("api.templates.find_teams_body.not_found") if result := <-Srv.Store.Team().GetTeamsForEmail(email); result.Err != nil { c.Err = result.Err @@ -442,7 +455,7 @@ func emailTeams(c *Context, w http.ResponseWriter, r *http.Request) { for _, team := range teams { props[team.Name] = c.GetTeamURLFromTeam(team) } - bodyPage.Props = props + bodyPage.Extra = props if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.team.email_teams.sending.error"), err) @@ -511,16 +524,19 @@ func InviteMembers(c *Context, team *model.Team, user *model.User, invites []str senderRole = c.T("api.team.invite_members.member") } - subjectPage := NewServerTemplatePage("invite_subject") - subjectPage.Props["SenderName"] = sender - subjectPage.Props["TeamDisplayName"] = team.DisplayName + subjectPage := NewServerTemplatePage("invite_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.invite_subject", + map[string]interface{}{"SenderName": sender, "TeamDisplayName": team.DisplayName, "SiteName": utils.ClientCfg["SiteName"]}) - bodyPage := NewServerTemplatePage("invite_body") + bodyPage := NewServerTemplatePage("invite_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage.Props["TeamURL"] = c.GetTeamURL() - bodyPage.Props["TeamDisplayName"] = team.DisplayName - bodyPage.Props["SenderName"] = sender - bodyPage.Props["SenderStatus"] = senderRole + bodyPage.Props["Title"] = c.T("api.templates.invite_body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.invite_body.info", + map[string]interface{}{"SenderStatus": senderRole, "SenderName": sender, "TeamDisplayName": team.DisplayName})) + bodyPage.Props["Button"] = c.T("api.templates.invite_body.button") + bodyPage.Html["ExtraInfo"] = template.HTML(c.T("api.templates.invite_body.extra_info", + map[string]interface{}{"TeamDisplayName": team.DisplayName, "TeamURL": c.GetTeamURL()})) + props := make(map[string]string) props["email"] = invite props["id"] = team.Id diff --git a/api/templates/email_change_body.html b/api/templates/email_change_body.html index 7349aee6f..4f28584c4 100644 --- a/api/templates/email_change_body.html +++ b/api/templates/email_change_body.html @@ -17,8 +17,8 @@
      diff --git a/api/templates/email_change_subject.html b/api/templates/email_change_subject.html index 4ff8026f1..afabc2191 100644 --- a/api/templates/email_change_subject.html +++ b/api/templates/email_change_subject.html @@ -1 +1 @@ -{{define "email_change_subject"}}[{{.ClientCfg.SiteName}}] Your email address has changed for {{.Props.TeamDisplayName}}{{end}} +{{define "email_change_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.Subject}}{{end}} diff --git a/api/templates/email_change_verify_body.html b/api/templates/email_change_verify_body.html index 9d2c559b3..0d0c0aaba 100644 --- a/api/templates/email_change_verify_body.html +++ b/api/templates/email_change_verify_body.html @@ -17,10 +17,10 @@
      -

      You updated your email

      -

      You email address for {{.Props.TeamDisplayName}} has been changed to {{.Props.NewEmail}}.
      If you did not make this change, please contact the system administrator.

      +

      {{.Props.Title}}

      +

      {{.Props.Info}}

      diff --git a/api/templates/email_change_verify_subject.html b/api/templates/email_change_verify_subject.html index 744aaccfc..4fc4f4846 100644 --- a/api/templates/email_change_verify_subject.html +++ b/api/templates/email_change_verify_subject.html @@ -1 +1 @@ -{{define "email_change_verify_subject"}}[{{.ClientCfg.SiteName}}] Verify new email address for {{.Props.TeamDisplayName}}{{end}} +{{define "email_change_verify_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.Subject}}{{end}} diff --git a/api/templates/email_footer.html b/api/templates/email_footer.html index e3ff9c584..6dc7fa483 100644 --- a/api/templates/email_footer.html +++ b/api/templates/email_footer.html @@ -6,7 +6,7 @@

      (c) 2015 Mattermost, Inc. 855 El Camino Real, 13A-168, Palo Alto, CA, 94301.
      - To change your notification preferences, log in to your team site and go to Account Settings > Notifications. + {{.Props.Footer}}

      diff --git a/api/templates/email_info.html b/api/templates/email_info.html index 48725d144..0a34f18a0 100644 --- a/api/templates/email_info.html +++ b/api/templates/email_info.html @@ -1,9 +1,7 @@ {{define "email_info"}} {{end}} diff --git a/api/templates/error.html b/api/templates/error.html index 9fb2da1ba..2b6211be2 100644 --- a/api/templates/error.html +++ b/api/templates/error.html @@ -22,9 +22,9 @@
      -

      {{ .ClientCfg.SiteName }} needs your help:

      +

      {{.Props.Title}}

      {{ .Props.Message }}

      - Go back to team site + {{.Props.Link}}
      diff --git a/api/templates/find_teams_body.html b/api/templates/find_teams_body.html index 0b52af033..1324091aa 100644 --- a/api/templates/find_teams_body.html +++ b/api/templates/find_teams_body.html @@ -17,14 +17,14 @@
      -

      You updated your email

      -

      To finish updating your email address for {{.Props.TeamDisplayName}}, please click the link below to confirm this is the right address.

      +

      {{.Props.Title}}

      +

      {{.Props.Info}}

      - Verify Email + {{.Props.VerifyButton}}

      - Any questions at all, mail us any time: {{.ClientCfg.FeedbackEmail}}.
      - Best wishes,
      - The {{.ClientCfg.SiteName}} Team
      + {{.Html.EmailInfo}}
      diff --git a/api/templates/find_teams_subject.html b/api/templates/find_teams_subject.html index f3a1437b3..ebc339562 100644 --- a/api/templates/find_teams_subject.html +++ b/api/templates/find_teams_subject.html @@ -1 +1 @@ -{{define "find_teams_subject"}}Your {{ .ClientCfg.SiteName }} Teams{{end}} +{{define "find_teams_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/invite_body.html b/api/templates/invite_body.html index a81d0c3d5..2b6bde6d3 100644 --- a/api/templates/invite_body.html +++ b/api/templates/invite_body.html @@ -17,13 +17,13 @@
      -

      Finding teams

      -

      {{ if .Props }} - Your request to find teams associated with your email found the following:
      - {{range $index, $element := .Props}} +

      {{.Props.Title}}

      +

      {{ if .Extra }} + {{.Props.Found}}
      + {{range $index, $element := .Extra}} {{ $index }}
      {{ end }} {{ else }} - We could not find any teams for the given email. + {{.Props.NotFound}} {{ end }}

      diff --git a/api/templates/invite_subject.html b/api/templates/invite_subject.html index 10f68969f..504915d50 100644 --- a/api/templates/invite_subject.html +++ b/api/templates/invite_subject.html @@ -1 +1 @@ -{{define "invite_subject"}}{{ .Props.SenderName }} invited you to join {{ .Props.TeamDisplayName }} Team on {{.ClientCfg.SiteName}}{{end}} +{{define "invite_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/password_change_body.html b/api/templates/password_change_body.html index 6199a3423..2c4ba10ca 100644 --- a/api/templates/password_change_body.html +++ b/api/templates/password_change_body.html @@ -17,8 +17,8 @@
      -

      You've been invited

      -

      The team {{.Props.SenderStatus}} {{.Props.SenderName}}, has invited you to join {{.Props.TeamDisplayName}}.

      +

      {{.Props.Title}}

      +

      {{.Html.Info}}

      - Join Team + {{.Props.Button}}


      -

      Mattermost lets you share messages and files from your PC or phone, with instant search and archiving. After you’ve joined {{.Props.TeamDisplayName}}, you can sign-in to your new team and access these features anytime from the web address:

      {{.Props.TeamURL}}

      +

      {{.Html.ExtraInfo}}

      diff --git a/api/templates/password_change_subject.html b/api/templates/password_change_subject.html index 0cbf052c1..897f1210d 100644 --- a/api/templates/password_change_subject.html +++ b/api/templates/password_change_subject.html @@ -1 +1 @@ -{{define "password_change_subject"}}Your password has been updated for {{.Props.TeamDisplayName}} on {{ .ClientCfg.SiteName }}{{end}} +{{define "password_change_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/post_body.html b/api/templates/post_body.html index 468d5e205..54f34d1dd 100644 --- a/api/templates/post_body.html +++ b/api/templates/post_body.html @@ -17,10 +17,10 @@
      -

      You updated your password

      -

      Your password has been updated for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} by {{.Props.Method}}.
      If this change wasn't initiated by you, please contact your system administrator.

      +

      {{.Props.Title}}

      +

      {{.Html.Info}}

      diff --git a/api/templates/post_subject.html b/api/templates/post_subject.html index f53353d85..60daaa432 100644 --- a/api/templates/post_subject.html +++ b/api/templates/post_subject.html @@ -1 +1 @@ -{{define "post_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.TeamDisplayName}} Team Notifications for {{.Props.Month}} {{.Props.Day}}, {{.Props.Year}}{{end}} +{{define "post_subject"}}[{{.ClientCfg.SiteName}}] {{.Props.Subject}}{{end}} diff --git a/api/templates/reset_body.html b/api/templates/reset_body.html index a608c804a..69cd44957 100644 --- a/api/templates/reset_body.html +++ b/api/templates/reset_body.html @@ -17,10 +17,10 @@
      -

      You were mentioned

      -

      CHANNEL: {{.Props.ChannelName}}
      {{.Props.SenderName}} - {{.Props.Hour}}:{{.Props.Minute}} {{.Props.TimeZone}}, {{.Props.Month}} {{.Props.Day}}

      {{.Props.PostMessage}}

      +

      {{.Props.BodyText}}

      +

      {{.Html.Info}}

      {{.Props.PostMessage}}

      - Go To Channel + {{.Props.Button}}

      diff --git a/api/templates/reset_subject.html b/api/templates/reset_subject.html index 87ad7bc38..a2852d332 100644 --- a/api/templates/reset_subject.html +++ b/api/templates/reset_subject.html @@ -1 +1 @@ -{{define "reset_subject"}}Reset your password{{end}} +{{define "reset_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/signin_change_body.html b/api/templates/signin_change_body.html index 5b96df944..af8577f0f 100644 --- a/api/templates/signin_change_body.html +++ b/api/templates/signin_change_body.html @@ -17,8 +17,8 @@
      -

      You requested a password reset

      -

      To change your password, click "Reset Password" below.
      If you did not mean to reset your password, please ignore this email and your password will remain the same.

      +

      {{.Props.Title}}

      +

      {{.Html.Info}}

      - Reset Password + {{.Props.Button}}

      diff --git a/api/templates/signin_change_subject.html b/api/templates/signin_change_subject.html index b1d644a28..606dc4df3 100644 --- a/api/templates/signin_change_subject.html +++ b/api/templates/signin_change_subject.html @@ -1 +1 @@ -{{define "signin_change_subject"}}You updated your sign-in method for {{.Props.TeamDisplayName}} on {{ .ClientCfg.SiteName }}{{end}} +{{define "signin_change_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/signup_team_body.html b/api/templates/signup_team_body.html index 2f384ac43..683a9891e 100644 --- a/api/templates/signup_team_body.html +++ b/api/templates/signup_team_body.html @@ -17,11 +17,11 @@
      -

      You updated your sign-in method

      -

      You updated your sign-in method for {{.Props.TeamDisplayName}} on {{ .Props.TeamURL }} to {{.Props.Method}}.
      If this change wasn't initiated by you, please contact your system administrator.

      +

      {{.Props.Title}}

      +

      {{.Html.Info}}

      diff --git a/api/templates/signup_team_subject.html b/api/templates/signup_team_subject.html index 4fc5b3d72..413a5c8c1 100644 --- a/api/templates/signup_team_subject.html +++ b/api/templates/signup_team_subject.html @@ -1 +1 @@ -{{define "signup_team_subject"}}{{ .ClientCfg.SiteName }} Team Setup{{end}} \ No newline at end of file +{{define "signup_team_subject"}}{{.Props.Subject}}{{end}} \ No newline at end of file diff --git a/api/templates/verify_body.html b/api/templates/verify_body.html index c42b2a372..2b0d25f94 100644 --- a/api/templates/verify_body.html +++ b/api/templates/verify_body.html @@ -17,10 +17,10 @@
      -

      Thanks for creating a team!

      +

      {{.Props.Title}}

      - Set up your team + {{.Props.Button}}

      - {{ .ClientCfg.SiteName }} is one place for all your team communication, searchable and available anywhere.
      You'll get more out of {{ .ClientCfg.SiteName }} when your team is in constant communication--let's get them on board.

      + {{.Html.Info}}

      diff --git a/api/templates/verify_subject.html b/api/templates/verify_subject.html index 9a3a11282..ad7fc2aaa 100644 --- a/api/templates/verify_subject.html +++ b/api/templates/verify_subject.html @@ -1 +1 @@ -{{define "verify_subject"}}[{{ .Props.TeamDisplayName }} {{ .ClientCfg.SiteName }}] Email Verification{{end}} +{{define "verify_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/templates/welcome_body.html b/api/templates/welcome_body.html index 71d838b08..b5ca9beb3 100644 --- a/api/templates/welcome_body.html +++ b/api/templates/welcome_body.html @@ -18,19 +18,19 @@ {{if .Props.VerifyUrl }} {{end}}
      -

      You've joined the {{ .Props.TeamDisplayName }} team

      -

      Please verify your email address by clicking below.

      +

      {{.Props.Title}}

      +

      {{.Props.Info}}

      - Verify Email + {{.Props.Button}}

      -

      You've joined the {{ .Props.TeamDisplayName }} team

      -

      Please verify your email address by clicking below.

      +

      {{.Props.Title}}

      +

      {{.Props.Info}}

      - Verify Email + {{.Props.Button}}

      -

      You can sign-in to your new team from the web address:

      +

      {{.Props.Info2}}

      {{.Props.TeamURL}} -

      Mattermost lets you share messages and files from your PC or phone, with instant search and archiving.

      +

      {{.Props.Info3}}

      diff --git a/api/templates/welcome_subject.html b/api/templates/welcome_subject.html index c3b70ef20..95189b900 100644 --- a/api/templates/welcome_subject.html +++ b/api/templates/welcome_subject.html @@ -1 +1 @@ -{{define "welcome_subject"}}You joined {{ .Props.TeamDisplayName }}{{end}} +{{define "welcome_subject"}}{{.Props.Subject}}{{end}} diff --git a/api/user.go b/api/user.go index 76ed66112..473f0da54 100644 --- a/api/user.go +++ b/api/user.go @@ -17,6 +17,7 @@ import ( "github.com/mattermost/platform/utils" "github.com/mssola/user_agent" "hash/fnv" + "html/template" "image" "image/color" "image/draw" @@ -134,7 +135,7 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) { } if sendWelcomeEmail { - sendWelcomeEmailAndForget(ruser.Id, ruser.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team), ruser.EmailVerified) + sendWelcomeEmailAndForget(c, ruser.Id, ruser.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team), ruser.EmailVerified) } w.Write([]byte(ruser.ToJson())) @@ -308,13 +309,19 @@ func CreateOAuthUser(c *Context, w http.ResponseWriter, r *http.Request, service return ruser } -func sendWelcomeEmailAndForget(userId, email, teamName, teamDisplayName, siteURL, teamURL string, verified bool) { +func sendWelcomeEmailAndForget(c *Context, userId, email, teamName, teamDisplayName, siteURL, teamURL string, verified bool) { go func() { - subjectPage := NewServerTemplatePage("welcome_subject") - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("welcome_body") + subjectPage := NewServerTemplatePage("welcome_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.welcome_subject", map[string]interface{}{"TeamDisplayName": teamDisplayName}) + + bodyPage := NewServerTemplatePage("welcome_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL + bodyPage.Props["Title"] = c.T("api.templates.welcome_body.title", map[string]interface{}{"TeamDisplayName": teamDisplayName}) + bodyPage.Props["Info"] = c.T("api.templates.welcome_body.info") + bodyPage.Props["Button"] = c.T("api.templates.welcome_body.button") + bodyPage.Props["Info2"] = c.T("api.templates.welcome_body.info2") + bodyPage.Props["Info3"] = c.T("api.templates.welcome_body.info3") bodyPage.Props["TeamURL"] = teamURL if !verified { @@ -367,18 +374,21 @@ func addDirectChannelsAndForget(user *model.User) { }() } -func SendVerifyEmailAndForget(userId, userEmail, teamName, teamDisplayName, siteURL, teamURL string) { +func SendVerifyEmailAndForget(c *Context, userId, userEmail, teamName, teamDisplayName, siteURL, teamURL string) { go func() { link := fmt.Sprintf("%s/verify_email?uid=%s&hid=%s&teamname=%s&email=%s", siteURL, userId, model.HashPassword(userId), teamName, userEmail) - subjectPage := NewServerTemplatePage("verify_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("verify_body") + subjectPage := NewServerTemplatePage("verify_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.verify_subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("verify_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName + bodyPage.Props["Title"] = c.T("api.templates.verify_body.title", map[string]interface{}{"TeamDisplayName": teamDisplayName}) + bodyPage.Props["Info"] = c.T("api.templates.verify_body.info") bodyPage.Props["VerifyUrl"] = link + bodyPage.Props["Button"] = c.T("api.templates.verify_body.button") if err := utils.SendMail(userEmail, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_verify_email_and_forget.failed.error"), err) @@ -1141,10 +1151,10 @@ func updateUser(c *Context, w http.ResponseWriter, r *http.Request) { l4g.Error(tresult.Err.Message) } else { team := tresult.Data.(*model.Team) - sendEmailChangeEmailAndForget(rusers[1].Email, rusers[0].Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL()) + sendEmailChangeEmailAndForget(c, rusers[1].Email, rusers[0].Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL()) if utils.Cfg.EmailSettings.RequireEmailVerification { - SendEmailChangeVerifyEmailAndForget(rusers[0].Id, rusers[0].Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) + SendEmailChangeVerifyEmailAndForget(c, rusers[0].Id, rusers[0].Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) } } } @@ -1224,7 +1234,7 @@ func updatePassword(c *Context, w http.ResponseWriter, r *http.Request) { l4g.Error(tresult.Err.Message) } else { team := tresult.Data.(*model.Team) - sendPasswordChangeEmailAndForget(user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), c.T("api.user.update_password.menu")) + sendPasswordChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), c.T("api.user.update_password.menu")) } data := make(map[string]string) @@ -1526,11 +1536,15 @@ func sendPasswordReset(c *Context, w http.ResponseWriter, r *http.Request) { link := fmt.Sprintf("%s/reset_password?d=%s&h=%s", c.GetTeamURLFromTeam(team), url.QueryEscape(data), url.QueryEscape(hash)) - subjectPage := NewServerTemplatePage("reset_subject") - subjectPage.Props["SiteURL"] = c.GetSiteURL() - bodyPage := NewServerTemplatePage("reset_body") + subjectPage := NewServerTemplatePage("reset_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.reset_subject") + + bodyPage := NewServerTemplatePage("reset_body", c.Locale) bodyPage.Props["SiteURL"] = c.GetSiteURL() + bodyPage.Props["Title"] = c.T("api.templates.reset_body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.reset_body.info")) bodyPage.Props["ResetUrl"] = link + bodyPage.Props["Button"] = c.T("api.templates.reset_body.button") if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { c.Err = model.NewLocAppError("sendPasswordReset", "api.user.send_password_reset.send.app_error", nil, "err="+err.Message) @@ -1632,23 +1646,24 @@ func resetPassword(c *Context, w http.ResponseWriter, r *http.Request) { c.LogAuditWithUserId(userId, "success") } - sendPasswordChangeEmailAndForget(user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), "using a reset password link") + sendPasswordChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetTeamURLFromTeam(team), c.GetSiteURL(), c.T("api.user.reset_password.method")) props["new_password"] = "" w.Write([]byte(model.MapToJson(props))) } -func sendPasswordChangeEmailAndForget(email, teamDisplayName, teamURL, siteURL, method string) { +func sendPasswordChangeEmailAndForget(c *Context, email, teamDisplayName, teamURL, siteURL, method string) { go func() { - subjectPage := NewServerTemplatePage("password_change_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("password_change_body") + subjectPage := NewServerTemplatePage("password_change_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.password_change_subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("password_change_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage.Props["TeamURL"] = teamURL - bodyPage.Props["Method"] = method + bodyPage.Props["Title"] = c.T("api.templates.password_change_body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.password_change_body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "TeamURL": teamURL, "Method": method})) if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_password_change_email_and_forget.error"), err) @@ -1657,17 +1672,18 @@ func sendPasswordChangeEmailAndForget(email, teamDisplayName, teamURL, siteURL, }() } -func sendEmailChangeEmailAndForget(oldEmail, newEmail, teamDisplayName, teamURL, siteURL string) { +func sendEmailChangeEmailAndForget(c *Context, oldEmail, newEmail, teamDisplayName, teamURL, siteURL string) { go func() { - subjectPage := NewServerTemplatePage("email_change_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("email_change_body") + subjectPage := NewServerTemplatePage("email_change_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.email_change_body", + map[string]interface{}{"TeamDisplayName": teamDisplayName}) + + bodyPage := NewServerTemplatePage("email_change_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage.Props["TeamURL"] = teamURL - bodyPage.Props["NewEmail"] = newEmail + bodyPage.Props["Title"] = c.T("api.templates.email_change_body.title") + bodyPage.Props["Info"] = c.T("api.templates.email_change_body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "NewEmail": newEmail}) if err := utils.SendMail(oldEmail, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_email_change_email_and_forget.error"), err) @@ -1676,18 +1692,22 @@ func sendEmailChangeEmailAndForget(oldEmail, newEmail, teamDisplayName, teamURL, }() } -func SendEmailChangeVerifyEmailAndForget(userId, newUserEmail, teamName, teamDisplayName, siteURL, teamURL string) { +func SendEmailChangeVerifyEmailAndForget(c *Context, userId, newUserEmail, teamName, teamDisplayName, siteURL, teamURL string) { go func() { link := fmt.Sprintf("%s/verify_email?uid=%s&hid=%s&teamname=%s&email=%s", siteURL, userId, model.HashPassword(userId), teamName, newUserEmail) - subjectPage := NewServerTemplatePage("email_change_verify_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("email_change_verify_body") + subjectPage := NewServerTemplatePage("email_change_verify_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.email_change_verify_subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName}) + + bodyPage := NewServerTemplatePage("email_change_verify_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName + bodyPage.Props["Title"] = c.T("api.templates.email_change_verify_body.title") + bodyPage.Props["Info"] = c.T("api.templates.email_change_verify_body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName}) bodyPage.Props["VerifyUrl"] = link + bodyPage.Props["VerifyButton"] = c.T("api.templates.email_change_verify_body.button") if err := utils.SendMail(newUserEmail, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_email_change_verify_email_and_forget.error"), err) @@ -2028,7 +2048,7 @@ func CompleteSwitchWithOAuth(c *Context, w http.ResponseWriter, r *http.Request, return } - sendSignInChangeEmailAndForget(user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), strings.Title(service)+" SSO") + sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), strings.Title(service)+" SSO") } func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) { @@ -2085,7 +2105,7 @@ func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) { return } - sendSignInChangeEmailAndForget(user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), "email and password") + sendSignInChangeEmailAndForget(c, user.Email, team.DisplayName, c.GetSiteURL()+"/"+team.Name, c.GetSiteURL(), c.T("api.templates.signin_change_email.body.method_email")) RevokeAllSession(c, c.Session.UserId) if c.Err != nil { @@ -2099,17 +2119,18 @@ func switchToEmail(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(m))) } -func sendSignInChangeEmailAndForget(email, teamDisplayName, teamURL, siteURL, method string) { +func sendSignInChangeEmailAndForget(c *Context, email, teamDisplayName, teamURL, siteURL, method string) { go func() { - subjectPage := NewServerTemplatePage("signin_change_subject") - subjectPage.Props["SiteURL"] = siteURL - subjectPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage := NewServerTemplatePage("signin_change_body") + subjectPage := NewServerTemplatePage("signin_change_subject", c.Locale) + subjectPage.Props["Subject"] = c.T("api.templates.singin_change_email.subject", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "SiteName": utils.ClientCfg["SiteName"]}) + + bodyPage := NewServerTemplatePage("signin_change_body", c.Locale) bodyPage.Props["SiteURL"] = siteURL - bodyPage.Props["TeamDisplayName"] = teamDisplayName - bodyPage.Props["TeamURL"] = teamURL - bodyPage.Props["Method"] = method + bodyPage.Props["Title"] = c.T("api.templates.signin_change_email.body.title") + bodyPage.Html["Info"] = template.HTML(c.T("api.templates.singin_change_email.body.info", + map[string]interface{}{"TeamDisplayName": teamDisplayName, "TeamURL": teamURL, "Method": method})) if err := utils.SendMail(email, subjectPage.Render(), bodyPage.Render()); err != nil { l4g.Error(utils.T("api.user.send_sign_in_change_email_and_forget.error"), err) diff --git a/config/config.json b/config/config.json index 076f795cc..c620262a9 100644 --- a/config/config.json +++ b/config/config.json @@ -15,7 +15,9 @@ "SessionLengthWebInDays": 30, "SessionLengthMobileInDays": 30, "SessionLengthSSOInDays": 30, - "SessionCacheInMinutes": 10 + "SessionCacheInMinutes": 10, + "WebsocketSecurePort": 443, + "WebsocketPort": 80 }, "TeamSettings": { "SiteName": "Mattermost", @@ -107,5 +109,28 @@ "AuthEndpoint": "", "TokenEndpoint": "", "UserApiEndpoint": "" + }, + "GoogleSettings": { + "Enable": false, + "Secret": "", + "Id": "", + "Scope": "", + "AuthEndpoint": "", + "TokenEndpoint": "", + "UserApiEndpoint": "" + }, + "LdapSettings": { + "Enable": false, + "LdapServer": null, + "LdapPort": 389, + "BaseDN": null, + "BindUsername": null, + "BindPassword": null, + "FirstNameAttribute": null, + "LastNameAttribute": null, + "EmailAttribute": null, + "UsernameAttribute": null, + "IdAttribute": null, + "QueryTimeout": 60 } } \ No newline at end of file diff --git a/i18n/en.json b/i18n/en.json index 554840075..48f6a99a5 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,1406 +1,1650 @@ [ - { - "id": "api.admin.file_read_error", - "translation": "Error reading log file" - }, - { - "id": "api.admin.init.debug", - "translation": "Initializing admin api routes" - }, - { - "id": "api.admin.test_email.body", - "translation": "


      It appears your Mattermost email is setup correctly!" - }, - { - "id": "api.admin.test_email.subject", - "translation": "Mattermost - Testing Email Settings" - }, - { - "id": "api.api.init.parsing_templates.debug", - "translation": "Parsing server templates at %v" - }, - { - "id": "api.api.init.parsing_templates.error", - "translation": "Failed to parse server templates %v" - }, - { - "id": "api.api.render.error", - "translation": "Error rendering template %v err=%v" - }, - { - "id": "api.channel.add_member.added", - "translation": "%v added to the channel by %v" - }, - { - "id": "api.channel.add_member.find_channel.app_error", - "translation": "Failed to find channel" - }, - { - "id": "api.channel.add_member.find_user.app_error", - "translation": "Failed to find user to be added" - }, - { - "id": "api.channel.add_member.user_adding.app_error", - "translation": "Failed to find user doing the adding" - }, - { - "id": "api.channel.add_user.to.channel.failed.app_error", - "translation": "Failed to add user to channel" - }, - { - "id": "api.channel.add_user_to_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.add_user_to_channel.type.app_error", - "translation": "Can not add user to this channel type" - }, - { - "id": "api.channel.create_channel.direct_channel.app_error", - "translation": "Must use createDirectChannel api service for direct message channel creation" - }, - { - "id": "api.channel.create_channel.invalid_character.app_error", - "translation": "Invalid character '__' in channel name for non-direct channel" - }, - { - "id": "api.channel.create_default_channels.off_topic", - "translation": "Off-Topic" - }, - { - "id": "api.channel.create_default_channels.town_square", - "translation": "Town Square" - }, - { - "id": "api.channel.create_direct_channel.invalid_user.app_error", - "translation": "Invalid other user id " - }, - { - "id": "api.channel.delete_channel.archived", - "translation": "%v has archived the channel." - }, - { - "id": "api.channel.delete_channel.cannot.app_error", - "translation": "Cannot delete the default channel {{.Channel}}" - }, - { - "id": "api.channel.delete_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.delete_channel.failed_post.error", - "translation": "Failed to post archive message %v" - }, - { - "id": "api.channel.delete_channel.failed_send.app_error", - "translation": "Failed to send archive message" - }, - { - "id": "api.channel.delete_channel.incoming_webhook.error", - "translation": "Encountered error deleting incoming webhook, id=%v" - }, - { - "id": "api.channel.delete_channel.outgoing_webhook.error", - "translation": "Encountered error deleting outgoing webhook, id=%v" - }, - { - "id": "api.channel.delete_channel.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.channel.get_channel_counts.app_error", - "translation": "Unable to get channel counts from the database" - }, - { - "id": "api.channel.get_channel_extra_info.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.get_channel_extra_info.member_limit.app_error", - "translation": "Failed to parse member limit" - }, - { - "id": "api.channel.get_channels.error", - "translation": "Error in getting users profile for id=%v forcing logout" - }, - { - "id": "api.channel.init.debug", - "translation": "Initializing channel api routes" - }, - { - "id": "api.channel.join_channel.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.channel.join_channel.post_and_forget", - "translation": "%v has joined the channel." - }, - { - "id": "api.channel.leave.default.app_error", - "translation": "Cannot leave the default channel {{.Channel}}" - }, - { - "id": "api.channel.leave.direct.app_error", - "translation": "Cannot leave a direct message channel" - }, - { - "id": "api.channel.leave.left", - "translation": "%v has left the channel." - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.join_leave.error", - "translation": "Failed to post join/leave message %v" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.removed", - "translation": "%s removed the channel header (was: %s)" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.retrieve_user.error", - "translation": "Failed to retrieve user while trying to save update channel header message %v" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.updated_from", - "translation": "%s updated the channel header from: %s to: %s" - }, - { - "id": "api.channel.post_update_channel_header_message_and_forget.updated_to", - "translation": "%s updated the channel header to: %s" - }, - { - "id": "api.channel.post_user_add_remove_message_and_forget.error", - "translation": "Failed to post join/leave message %v" - }, - { - "id": "api.channel.remove_member.permissions.app_error", - "translation": "You do not have the appropriate permissions " - }, - { - "id": "api.channel.remove_member.unable.app_error", - "translation": "Unable to remove user." - }, - { - "id": "api.channel.remove_user_from_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.update_channel.deleted.app_error", - "translation": "The channel has been archived or deleted" - }, - { - "id": "api.channel.update_channel.permission.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.channel.update_channel.tried.app_error", - "translation": "Tried to perform an invalid update of the default channel {{.Channel}}" - }, - { - "id": "api.command.check_command.start.app_error", - "translation": "Command must start with /" - }, - { - "id": "api.command.echo_command.create.error", - "translation": "Unable to create /echo post, err=%v" - }, - { - "id": "api.command.echo_command.description", - "translation": "Echo back text from your account, /echo \"message\" [delay in seconds]" - }, - { - "id": "api.command.echo_command.high_volume.app_error", - "translation": "High volume of echo request, cannot process request" - }, - { - "id": "api.command.echo_command.under.app_error", - "translation": "Delays must be under 10000 seconds" - }, - { - "id": "api.command.init.debug", - "translation": "Initializing command api routes" - }, - { - "id": "api.command.load_test_channels_command.channel.description", - "translation": "Add a specified number of random channels to current team " - }, - { - "id": "api.command.load_test_channels_command.fuzz.description", - "translation": "Add a specified number of random channels with fuzz text to current team " - }, - { - "id": "api.command.load_test_command.description", - "translation": "Debug Load Testing" - }, - { - "id": "api.command.load_test_posts_command.fuzz.description", - "translation": "Add some random posts with fuzz text to current channel " - }, - { - "id": "api.command.load_test_posts_command.posts.description", - "translation": "Add some random posts to current channel " - }, - { - "id": "api.command.load_test_setup_command.create.error", - "translation": "Failed to create testing environment" - }, - { - "id": "api.command.load_test_setup_command.created.info", - "translation": "Team Created: %v" - }, - { - "id": "api.command.load_test_setup_command.description", - "translation": "Creates a testing environment in current team. [teams] [fuzz] " - }, - { - "id": "api.command.load_test_setup_command.login.info", - "translation": "\t User to login: %v, %v" - }, - { - "id": "api.command.load_test_url_command.create.error", - "translation": "Unable to create post, err=%v" - }, - { - "id": "api.command.load_test_url_command.description", - "translation": "Add a post containing the text from a given url to current channel " - }, - { - "id": "api.command.load_test_url_command.file.app_error", - "translation": "Unable to get file" - }, - { - "id": "api.command.load_test_url_command.reading.app_error", - "translation": "Encountered error reading file" - }, - { - "id": "api.command.load_test_url_command.url.app_error", - "translation": "Command must contain a url" - }, - { - "id": "api.command.load_test_users_command.fuzz.description", - "translation": "Add a specified number of random users with fuzz text to current team " - }, - { - "id": "api.command.load_test_users_command.users.description", - "translation": "Add a specified number of random users to current team " - }, - { - "id": "api.command.logout_command.description", - "translation": "Logout" - }, - { - "id": "api.command.me_command.create.error", - "translation": "Unable to create /me post post, err=%v" - }, - { - "id": "api.command.me_command.description", - "translation": "Do an action, /me [message]" - }, - { - "id": "api.command.no_implemented.app_error", - "translation": "Command not implemented" - }, - { - "id": "api.command.shrug_command.create.error", - "translation": "Unable to create /shrug post post, err=%v" - }, - { - "id": "api.command.shrug_command.description", - "translation": "Adds ¯\\_(ツ)_/¯ to your message, /shrug [message]" - }, - { - "id": "api.commmand.join_command.description", - "translation": "Join the open channel" - }, - { - "id": "api.context.404.app_error", - "translation": "Sorry, we could not find the page." - }, - { - "id": "api.context.invalid_param.app_error", - "translation": "Invalid {{.Name}} parameter" - }, - { - "id": "api.context.invalid_team_url.debug", - "translation": "TeamURL accessed when not valid. Team URL should not be used in api functions or those that are team independent" - }, - { - "id": "api.context.invalid_token.error", - "translation": "Invalid session token=%v, err=%v" - }, - { - "id": "api.context.last_activity_at.error", - "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" - }, - { - "id": "api.context.log.error", - "translation": "%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]" - }, - { - "id": "api.context.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.context.session_expired.app_error", - "translation": "Invalid or expired session, please login again." - }, - { - "id": "api.context.system_permissions.app_error", - "translation": "You do not have the appropriate permissions (system)" - }, - { - "id": "api.context.token_provided.app_error", - "translation": "Session is not OAuth but token was provided in the query string" - }, - { - "id": "api.context.unknown.app_error", - "translation": "An unknown error has occured. Please contact support." - }, - { - "id": "api.export.json.app_error", - "translation": "Unable to convert to json" - }, - { - "id": "api.export.open.app_error", - "translation": "Unable to open file" - }, - { - "id": "api.export.open_dir.app_error", - "translation": "Unable to open directory" - }, - { - "id": "api.export.open_file.app_error", - "translation": "Unable to open file for export" - }, - { - "id": "api.export.options.create.app_error", - "translation": "Unable to create options file" - }, - { - "id": "api.export.options.write.app_error", - "translation": "Unable to write to options file" - }, - { - "id": "api.export.read_dir.app_error", - "translation": "Unable to read directory" - }, - { - "id": "api.export.s3.app_error", - "translation": "S3 is not supported for local storage export." - }, - { - "id": "api.export.write_file.app_error", - "translation": "Unable to write to export file" - }, - { - "id": "api.file.file_upload.exceeds", - "translation": "File exceeds max image size." - }, - { - "id": "api.file.get_export.retrieve.app_error", - "translation": "Unable to retrieve exported file. Please re-export" - }, - { - "id": "api.file.get_export.team_admin.app_error", - "translation": "Only a team admin can retrieve exported data." - }, - { - "id": "api.file.get_file.not_found.app_error", - "translation": "Could not find file." - }, - { - "id": "api.file.get_file.public_expired.app_error", - "translation": "The public link has expired" - }, - { - "id": "api.file.get_file.public_invalid.app_error", - "translation": "The public link does not appear to be valid" - }, - { - "id": "api.file.get_public_link.disabled.app_error", - "translation": "Public links have been disabled" - }, - { - "id": "api.file.handle_images_forget.decode.error", - "translation": "Unable to decode image channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.encode_jpeg.error", - "translation": "Unable to encode image as jpeg channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.encode_preview.error", - "translation": "Unable to encode image as preview jpg channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.upload_preview.error", - "translation": "Unable to upload preview channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.handle_images_forget.upload_thumb.error", - "translation": "Unable to upload thumbnail channelId=%v userId=%v filename=%v err=%v" - }, - { - "id": "api.file.init.debug", - "translation": "Initializing file api routes" - }, - { - "id": "api.file.open_file_write_stream.configured.app_error", - "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." - }, - { - "id": "api.file.open_file_write_stream.creating_dir.app_error", - "translation": "Encountered an error creating the directory for the new file" - }, - { - "id": "api.file.open_file_write_stream.local_server.app_error", - "translation": "Encountered an error writing to local server storage" - }, - { - "id": "api.file.open_file_write_stream.s3.app_error", - "translation": "S3 is not supported." - }, - { - "id": "api.file.read_file.configured.app_error", - "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." - }, - { - "id": "api.file.read_file.get.app_error", - "translation": "Unable to get file from S3" - }, - { - "id": "api.file.read_file.reading_local.app_error", - "translation": "Encountered an error reading from local server storage" - }, - { - "id": "api.file.upload_file.image.app_error", - "translation": "Unable to upload image file." - }, - { - "id": "api.file.upload_file.large_image.app_error", - "translation": "Unable to upload image file. File is too large." - }, - { - "id": "api.file.upload_file.storage.app_error", - "translation": "Unable to upload file. Image storage is not configured." - }, - { - "id": "api.file.upload_file.too_large.app_error", - "translation": "Unable to upload file. File is too large." - }, - { - "id": "api.file.write_file.configured.app_error", - "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." - }, - { - "id": "api.file.write_file.s3.app_error", - "translation": "Encountered an error writing to S3" - }, - { - "id": "api.file.write_file_locally.create_dir.app_error", - "translation": "Encountered an error creating the directory for the new file" - }, - { - "id": "api.file.write_file_locally.writing.app_error", - "translation": "Encountered an error writing to local server storage" - }, - { - "id": "api.import.import_post.saving.debug", - "translation": "Error saving post. user=%v, message=%v" - }, - { - "id": "api.import.import_user.joining_default.error", - "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" - }, - { - "id": "api.import.import_user.saving.error", - "translation": "Error saving user. err=%v" - }, - { - "id": "api.import.import_user.set_email.error", - "translation": "Failed to set email verified err=%v" - }, - { - "id": "api.license.add_license.array.app_error", - "translation": "Empty array under 'license' in request" - }, - { - "id": "api.license.add_license.expired.app_error", - "translation": "License is either expired or has not yet started." - }, - { - "id": "api.license.add_license.invalid.app_error", - "translation": "Invalid license file." - }, - { - "id": "api.license.add_license.no_file.app_error", - "translation": "No file under 'license' in request" - }, - { - "id": "api.license.add_license.open.app_error", - "translation": "Could not open license file" - }, - { - "id": "api.license.add_license.save.app_error", - "translation": "License did not save properly." - }, - { - "id": "api.license.init.debug", - "translation": "Initializing license api routes" - }, - { - "id": "api.license.remove_license.remove.app_error", - "translation": "License did not remove properly." - }, - { - "id": "api.oauth.allow_oauth.bad_client.app_error", - "translation": "invalid_request: Bad client_id" - }, - { - "id": "api.oauth.allow_oauth.bad_redirect.app_error", - "translation": "invalid_request: Missing or bad redirect_uri" - }, - { - "id": "api.oauth.allow_oauth.bad_response.app_error", - "translation": "invalid_request: Bad response_type" - }, - { - "id": "api.oauth.allow_oauth.database.app_error", - "translation": "server_error: Error accessing the database" - }, - { - "id": "api.oauth.allow_oauth.redirect_callback.app_error", - "translation": "invalid_request: Supplied redirect_uri did not match registered callback_url" - }, - { - "id": "api.oauth.allow_oauth.turn_off.app_error", - "translation": "The system admin has turned off OAuth service providing." - }, - { - "id": "api.oauth.get_auth_data.find.error", - "translation": "Couldn't find auth code for code=%s" - }, - { - "id": "api.oauth.init.debug", - "translation": "Initializing oauth api routes" - }, - { - "id": "api.oauth.register_oauth_app.turn_off.app_error", - "translation": "The system admin has turned off OAuth service providing." - }, - { - "id": "api.oauth.revoke_access_token.del_code.app_error", - "translation": "Error deleting authorization code from DB" - }, - { - "id": "api.oauth.revoke_access_token.del_session.app_error", - "translation": "Error deleting session from DB" - }, - { - "id": "api.oauth.revoke_access_token.del_token.app_error", - "translation": "Error deleting access token from DB" - }, - { - "id": "api.oauth.revoke_access_token.get.app_error", - "translation": "Error getting access token from DB before deletion" - }, - { - "id": "api.post.create_post.bad_filename.error", - "translation": "Bad filename discarded, filename=%v" - }, - { - "id": "api.post.create_post.channel_root_id.app_error", - "translation": "Invalid ChannelId for RootId parameter" - }, - { - "id": "api.post.create_post.last_viewed.error", - "translation": "Encountered error updating last viewed, channel_id=%s, user_id=%s, err=%v" - }, - { - "id": "api.post.create_post.parent_id.app_error", - "translation": "Invalid ParentId parameter" - }, - { - "id": "api.post.create_post.root_id.app_error", - "translation": "Invalid RootId parameter" - }, - { - "id": "api.post.create_webhook_post.creating.app_error", - "translation": "Error creating post" - }, - { - "id": "api.post.delete_post.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.post.get_post.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.post.handle_post_events_and_forget.channel.error", - "translation": "Encountered error getting channel, channel_id=%s, err=%v" - }, - { - "id": "api.post.handle_post_events_and_forget.team.error", - "translation": "Encountered error getting team, team_id=%s, err=%v" - }, - { - "id": "api.post.handle_post_events_and_forget.user.error", - "translation": "Encountered error getting user, user_id=%s, err=%v" - }, - { - "id": "api.post.handle_webhook_events_and_forget.create_post.error", - "translation": "Failed to create response post, err=%v" - }, - { - "id": "api.post.handle_webhook_events_and_forget.event_post.error", - "translation": "Event POST failed, err=%s" - }, - { - "id": "api.post.handle_webhook_events_and_forget.getting.error", - "translation": "Encountered error getting webhooks by team, err=%v" - }, - { - "id": "api.post.init.debug", - "translation": "Initializing post api routes" - }, - { - "id": "api.post.make_direct_channel_visible.get_2_members.error", - "translation": "Failed to get 2 members for a direct channel channel_id=%v" - }, - { - "id": "api.post.make_direct_channel_visible.get_members.error", - "translation": "Failed to get channel members channel_id=%v err=%v" - }, - { - "id": "api.post.make_direct_channel_visible.save_pref.error", - "translation": "Failed to save direct channel preference user_id=%v other_user_id=%v err=%v" - }, - { - "id": "api.post.make_direct_channel_visible.update_pref.error", - "translation": "Failed to update direct channel preference user_id=%v other_user_id=%v err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.members.error", - "translation": "Failed to get channel members channel_id=%v err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.mention_body", - "translation": "You have one new mention." - }, - { - "id": "api.post.send_notifications_and_forget.mention_subject", - "translation": "New Mention" - }, - { - "id": "api.post.send_notifications_and_forget.message_body", - "translation": "You have one new message." - }, - { - "id": "api.post.send_notifications_and_forget.message_subject", - "translation": "New Direct Message" - }, - { - "id": "api.post.send_notifications_and_forget.push_mention", - "translation": " mentioned you in " - }, - { - "id": "api.post.send_notifications_and_forget.push_message", - "translation": " sent you a direct message" - }, - { - "id": "api.post.send_notifications_and_forget.push_notification.debug", - "translation": "Sending push notification to %v wi msg of '%v'" - }, - { - "id": "api.post.send_notifications_and_forget.push_notification.error", - "translation": "Failed to send push notificationid=%v, err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.retrive_profiles.error", - "translation": "Failed to retrieve user profiles team_id=%v, err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.send.error", - "translation": "Failed to send mention email successfully email=%v err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.sent", - "translation": "{{.Prefix}} {{.Filenames}} sent" - }, - { - "id": "api.post.send_notifications_and_forget.sessions.error", - "translation": "Failed to retrieve sessions in notifications id=%v, err=%v" - }, - { - "id": "api.post.send_notifications_and_forget.user_id.error", - "translation": "Post user_id not returned by GetProfiles user_id=%v" - }, - { - "id": "api.post.update_mention_count_and_forget.update_error", - "translation": "Failed to update mention count for user_id=%v on channel_id=%v err=%v" - }, - { - "id": "api.post.update_post.find.app_error", - "translation": "We couldn't find the existing post or comment to update." - }, - { - "id": "api.post.update_post.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.post.update_post.permissions_details.app_error", - "translation": "Already delted id={{.PostId}}" - }, - { - "id": "api.post_get_post_by_id.get.app_error", - "translation": "Unable to get post" - }, - { - "id": "api.preference.init.debug", - "translation": "Initializing preference api routes" - }, - { - "id": "api.preference.save_preferences.decode.app_error", - "translation": "Unable to decode preferences from request" - }, - { - "id": "api.preference.save_preferences.set.app_error", - "translation": "Unable to set preferences for other user" - }, - { - "id": "api.preference.save_preferences.set_details.app_error", - "translation": "session.user_id={{.SessionUserId}}, preference.user_id={{.PreferenceUserId}}" - }, - { - "id": "api.server.new_server.init.info", - "translation": "Server is initializing..." - }, - { - "id": "api.server.start_server.listening.info", - "translation": "Server is listening on %v" - }, - { - "id": "api.server.start_server.rate.info", - "translation": "RateLimiter is enabled" - }, - { - "id": "api.server.start_server.rate.warn", - "translation": "RateLimitSettings not configured properly using VaryByHeader and disabling VaryByRemoteAddr" - }, - { - "id": "api.server.start_server.starting.critical", - "translation": "Error starting server, err:%v" - }, - { - "id": "api.server.start_server.starting.info", - "translation": "Starting Server..." - }, - { - "id": "api.server.start_server.starting.panic", - "translation": "Error starting server " - }, - { - "id": "api.server.stop_server.stopped.info", - "translation": "Server stopped" - }, - { - "id": "api.server.stop_server.stopping.info", - "translation": "Stopping Server..." - }, - { - "id": "api.slackimport.slack_add_channels.added", - "translation": "\r\n Channels Added \r\n" - }, - { - "id": "api.slackimport.slack_add_channels.import_failed", - "translation": "Failed to import: {{.DisplayName}}\r\n" - }, - { - "id": "api.slackimport.slack_add_channels.import_failed.debug", - "translation": "Failed to import: %s" - }, - { - "id": "api.slackimport.slack_add_channels.merge", - "translation": "Merged with existing channel: {{.DisplayName}}\r\n" - }, - { - "id": "api.slackimport.slack_add_posts.bot.warn", - "translation": "Slack bot posts are not imported yet" - }, - { - "id": "api.slackimport.slack_add_posts.msg_no_usr.debug", - "translation": "Message without user" - }, - { - "id": "api.slackimport.slack_add_posts.unsupported.warn", - "translation": "Unsupported post type: %v, %v" - }, - { - "id": "api.slackimport.slack_add_posts.user_no_exists.debug", - "translation": "User: %v does not exist!" - }, - { - "id": "api.slackimport.slack_add_posts.without_user.debug", - "translation": "Message without user" - }, - { - "id": "api.slackimport.slack_add_users.created", - "translation": "\r\n Users Created\r\n" - }, - { - "id": "api.slackimport.slack_add_users.email_pwd", - "translation": "Email, Password: {{.Email}}, {{.Password}}\r\n" - }, - { - "id": "api.slackimport.slack_add_users.unable_import", - "translation": "Unable to import user: {{.Username}}\r\n" - }, - { - "id": "api.slackimport.slack_convert_timestamp.bad.warn", - "translation": "Bad timestamp detected" - }, - { - "id": "api.slackimport.slack_import.log", - "translation": "Mattermost Slack Import Log\r\n" - }, - { - "id": "api.slackimport.slack_import.note1", - "translation": "- Some posts may not have been imported because they where not supported by this importer.\r\n" - }, - { - "id": "api.slackimport.slack_import.note2", - "translation": "- Slack bot posts are currently not supported.\r\n" - }, - { - "id": "api.slackimport.slack_import.notes", - "translation": "\r\n Notes \r\n" - }, - { - "id": "api.slackimport.slack_import.open.app_error", - "translation": "Unable to open: {{.Filename}}" - }, - { - "id": "api.slackimport.slack_import.zip.app_error", - "translation": "Unable to open zip file" - }, - { - "id": "api.team.create_team.email_disabled.app_error", - "translation": "Team sign-up with email is disabled." - }, - { - "id": "api.team.create_team_from_signup.email_disabled.app_error", - "translation": "Team sign-up with email is disabled." - }, - { - "id": "api.team.create_team_from_signup.expired_link.app_error", - "translation": "The signup link has expired" - }, - { - "id": "api.team.create_team_from_signup.invalid_link.app_error", - "translation": "The signup link does not appear to be valid" - }, - { - "id": "api.team.create_team_from_signup.unavailable.app_error", - "translation": "This URL is unavailable. Please try another." - }, - { - "id": "api.team.email_teams.sending.error", - "translation": "An error occured while sending an email in emailTeams err=%v" - }, - { - "id": "api.team.export_team.admin.app_error", - "translation": "Only a team admin can export data." - }, - { - "id": "api.team.import_team.admin.app_error", - "translation": "Only a team admin can import data." - }, - { - "id": "api.team.import_team.array.app_error", - "translation": "Empty array under 'file' in request" - }, - { - "id": "api.team.import_team.integer.app_error", - "translation": "Filesize not an integer" - }, - { - "id": "api.team.import_team.no_file.app_error", - "translation": "No file under 'file' in request" - }, - { - "id": "api.team.import_team.open.app_error", - "translation": "Could not open file" - }, - { - "id": "api.team.import_team.parse.app_error", - "translation": "Could not parse multipart form" - }, - { - "id": "api.team.import_team.unavailable.app_error", - "translation": "Filesize unavilable" - }, - { - "id": "api.team.init.debug", - "translation": "Initializing team api routes" - }, - { - "id": "api.team.invite_members.admin", - "translation": "administrator" - }, - { - "id": "api.team.invite_members.already.app_error", - "translation": "This person is already on your team" - }, - { - "id": "api.team.invite_members.member", - "translation": "member" - }, - { - "id": "api.team.invite_members.no_one.app_error", - "translation": "No one to invite." - }, - { - "id": "api.team.invite_members.send.error", - "translation": "Failed to send invite email successfully err=%v" - }, - { - "id": "api.team.invite_members.sending.info", - "translation": "sending invitation to %v %v" - }, - { - "id": "api.team.is_team_creation_allowed.disabled.app_error", - "translation": "Team creation has been disabled. Please ask your systems administrator for details." - }, - { - "id": "api.team.is_team_creation_allowed.domain.app_error", - "translation": "Email must be from a specific domain (e.g. @example.com). Please ask your systems administrator for details." - }, - { - "id": "api.team.permanent_delete_team.attempting.warn", - "translation": "Attempting to permanently delete team %v id=%v" - }, - { - "id": "api.team.permanent_delete_team.deleted.warn", - "translation": "Permanently deleted team %v id=%v" - }, - { - "id": "api.team.signup_team.email_disabled.app_error", - "translation": "Team sign-up with email is disabled." - }, - { - "id": "api.team.update_team.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.user.add_direct_channels_and_forget.failed.error", - "translation": "Failed to add direct channel preferences for user user_id=%s, team_id=%s, err=%v" - }, - { - "id": "api.user.authorize_oauth_user.bad_response.app_error", - "translation": "Bad response from token request" - }, - { - "id": "api.user.authorize_oauth_user.bad_token.app_error", - "translation": "Bad token type" - }, - { - "id": "api.user.authorize_oauth_user.invalid_state.app_error", - "translation": "Invalid state" - }, - { - "id": "api.user.authorize_oauth_user.invalid_state_team.app_error", - "translation": "Invalid state; missing team name" - }, - { - "id": "api.user.authorize_oauth_user.missing.app_error", - "translation": "Missing access token" - }, - { - "id": "api.user.authorize_oauth_user.service.app_error", - "translation": "Token request to {{.Service}} failed" - }, - { - "id": "api.user.authorize_oauth_user.token_failed.app_error", - "translation": "Token request failed" - }, - { - "id": "api.user.authorize_oauth_user.unsupported.app_error", - "translation": "Unsupported OAuth service provider" - }, - { - "id": "api.user.check_user_login_attempts.too_many.app_error", - "translation": "Your account is locked because of too many failed password attempts. Please reset your password." - }, - { - "id": "api.user.check_user_password.invalid.app_error", - "translation": "Login failed because of invalid password" - }, - { - "id": "api.user.complete_switch_with_oauth.blank_email.app_error", - "translation": "Blank email" - }, - { - "id": "api.user.complete_switch_with_oauth.parse.app_error", - "translation": "Could not parse auth data out of {{.Service}} user object" - }, - { - "id": "api.user.complete_switch_with_oauth.unavailable.app_error", - "translation": "{{.Service}} oauth not available on this server" - }, - { - "id": "api.user.create_oauth_user.already_attached.app_error", - "translation": "Team {{.DisplayName}} already has a user with the email address attached to your {{.Service}} account" - }, - { - "id": "api.user.create_oauth_user.already_used.app_error", - "translation": "This {{.Service}} account has already been used to sign up for team {{.DisplayName}}" - }, - { - "id": "api.user.create_oauth_user.create.app_error", - "translation": "Could not create user out of {{.Service}} user object" - }, - { - "id": "api.user.create_oauth_user.not_available.app_error", - "translation": "{{.Service}} oauth not avlailable on this server" - }, - { - "id": "api.user.create_profile_image.default_font.app_error", - "translation": "Could not create default profile image font" - }, - { - "id": "api.user.create_profile_image.encode.app_error", - "translation": "Could not encode default profile image" - }, - { - "id": "api.user.create_profile_image.initial.app_error", - "translation": "Could not add user initial to default profile picture" - }, - { - "id": "api.user.create_user.accepted_domain.app_error", - "translation": "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email." - }, - { - "id": "api.user.create_user.joining.error", - "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" - }, - { - "id": "api.user.create_user.save.error", - "translation": "Couldn't save the user err=%v" - }, - { - "id": "api.user.create_user.signup_email_disabled.app_error", - "translation": "User sign-up with email is disabled." - }, - { - "id": "api.user.create_user.signup_link_expired.app_error", - "translation": "The signup link has expired" - }, - { - "id": "api.user.create_user.signup_link_invalid.app_error", - "translation": "The signup link does not appear to be valid" - }, - { - "id": "api.user.create_user.team_name.app_error", - "translation": "Invalid team name" - }, - { - "id": "api.user.create_user.tutorial.error", - "translation": "Encountered error saving tutorial preference, err=%v" - }, - { - "id": "api.user.create_user.verified.error", - "translation": "Failed to set email verified err=%v" - }, - { - "id": "api.user.get_authorization_code.unsupported.app_error", - "translation": "Unsupported OAuth service provider" - }, - { - "id": "api.user.get_me.getting.error", - "translation": "Error in getting users profile for id=%v forcing logout" - }, - { - "id": "api.user.init.debug", - "translation": "Initializing user api routes" - }, - { - "id": "api.user.login.blank_pwd.app_error", - "translation": "Password field must not be blank" - }, - { - "id": "api.user.login.inactive.app_error", - "translation": "Login failed because your account has been set to inactive. Please contact an administrator." - }, - { - "id": "api.user.login.not_provided.app_error", - "translation": "Either user id or team name and user email must be provided" - }, - { - "id": "api.user.login.not_verified.app_error", - "translation": "Login failed because email address has not been verified" - }, - { - "id": "api.user.login.revoking.app_error", - "translation": "Revoking sessionId=%v for userId=%v re-login with same device Id" - }, - { - "id": "api.user.login_by_email.sign_in.app_error", - "translation": "Please sign in using {{.AuthService}}" - }, - { - "id": "api.user.login_by_oauth.not_available.app_error", - "translation": "{{.Service}} oauth not avlailable on this server" - }, - { - "id": "api.user.login_by_oauth.parse.app_error", - "translation": "Could not parse auth data out of {{.Service}} user object" - }, - { - "id": "api.user.login_ldap.blank_pwd.app_error", - "translation": "Password field must not be blank" - }, - { - "id": "api.user.login_ldap.disabled.app_error", - "translation": "LDAP not enabled on this server" - }, - { - "id": "api.user.login_ldap.need_id.app_error", - "translation": "Need an ID" - }, - { - "id": "api.user.login_ldap.not_available.app_error", - "translation": "LDAP not available on this server" - }, - { - "id": "api.user.permanent_delete_user.attempting.warn", - "translation": "Attempting to permanently delete account %v id=%v" - }, - { - "id": "api.user.permanent_delete_user.deleted.warn", - "translation": "Permanently deleted account %v id=%v" - }, - { - "id": "api.user.permanent_delete_user.system_admin.warn", - "translation": "You are deleting %v that is a system administrator. You may need to set another account as the system administrator using the command line tools." - }, - { - "id": "api.user.reset_password.invalid_link.app_error", - "translation": "The reset password link does not appear to be valid" - }, - { - "id": "api.user.reset_password.link_expired.app_error", - "translation": "The reset link has expired" - }, - { - "id": "api.user.reset_password.sso.app_error", - "translation": "Cannot reset password for SSO accounts" - }, - { - "id": "api.user.reset_password.wrong_team.app_error", - "translation": "Trying to reset password for user on wrong team." - }, - { - "id": "api.user.send_email_change_email_and_forget.error", - "translation": "Failed to send email change notification email successfully err=%v" - }, - { - "id": "api.user.send_email_change_verify_email_and_forget.error", - "translation": "Failed to send email change verification email successfully err=%v" - }, - { - "id": "api.user.send_password_change_email_and_forget.error", - "translation": "Failed to send update password email successfully err=%v" - }, - { - "id": "api.user.send_password_reset.find.app_error", - "translation": "We couldn’t find an account with that address." - }, - { - "id": "api.user.send_password_reset.send.app_error", - "translation": "Failed to send password reset email successfully" - }, - { - "id": "api.user.send_password_reset.sso.app_error", - "translation": "Cannot reset password for SSO accounts" - }, - { - "id": "api.user.send_sign_in_change_email_and_forget.error", - "translation": "Failed to send update password email successfully err=%v" - }, - { - "id": "api.user.send_verify_email_and_forget.failed.error", - "translation": "Failed to send verification email successfully err=%v" - }, - { - "id": "api.user.send_welcome_email_and_forget.failed.error", - "translation": "Failed to send welcome email successfully err=%v" - }, - { - "id": "api.user.switch_to_email.context.app_error", - "translation": "Update password failed because context user_id did not match provided user's id" - }, - { - "id": "api.user.update_active.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.user.update_password.context.app_error", - "translation": "Update password failed because context user_id did not match props user_id" - }, - { - "id": "api.user.update_password.failed.app_error", - "translation": "Update password failed" - }, - { - "id": "api.user.update_password.incorrect.app_error", - "translation": "The \"Current Password\" you entered is incorrect. Please check that Caps Lock is off and try again." - }, - { - "id": "api.user.update_password.menu", - "translation": "using the settings menu" - }, - { - "id": "api.user.update_password.oauth.app_error", - "translation": "Update password failed because the user is logged in through an OAuth service" - }, - { - "id": "api.user.update_password.valid_account.app_error", - "translation": "Update password failed because we couldn't find a valid account" - }, - { - "id": "api.user.update_roles.one_admin.app_error", - "translation": "There must be at least one active admin" - }, - { - "id": "api.user.update_roles.permissions.app_error", - "translation": "You do not have the appropriate permissions" - }, - { - "id": "api.user.update_roles.system_admin_mod.app_error", - "translation": "The system admin role can only by modified by another system admin" - }, - { - "id": "api.user.update_roles.system_admin_set.app_error", - "translation": "The system admin role can only be set by another system admin" - }, - { - "id": "api.user.upload_profile_user.array.app_error", - "translation": "Empty array under 'image' in request" - }, - { - "id": "api.user.upload_profile_user.decode.app_error", - "translation": "Could not decode profile image" - }, - { - "id": "api.user.upload_profile_user.decode_config.app_error", - "translation": "Could not decode profile image config." - }, - { - "id": "api.user.upload_profile_user.encode.app_error", - "translation": "Could not encode profile image" - }, - { - "id": "api.user.upload_profile_user.no_file.app_error", - "translation": "No file under 'image' in request" - }, - { - "id": "api.user.upload_profile_user.open.app_error", - "translation": "Could not open image file" - }, - { - "id": "api.user.upload_profile_user.parse.app_error", - "translation": "Could not parse multipart form" - }, - { - "id": "api.user.upload_profile_user.storage.app_error", - "translation": "Unable to upload file. Image storage is not configured." - }, - { - "id": "api.user.upload_profile_user.too_large.app_error", - "translation": "Unable to upload profile image. File is too large." - }, - { - "id": "mattermost.current_version", - "translation": "Current version is %v (%v/%v/%v)" - }, - { - "id": "utils.i18n.loaded", - "translation": "Loaded system translations for '%v' from '%v'" - }, - { - "id": "api.web_conn.new_web_conn.last_activity.error", - "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" - }, - { - "id": "api.web_conn.new_web_conn.last_ping.error", - "translation": "Failed to update LastPingAt for user_id=%v, err=%v" - }, - { - "id": "api.web_hub.start.stopping.debug", - "translation": "stopping %v connections" - }, - { - "id": "api.web_socket.init.debug", - "translation": "Initializing web socket api routes" - }, - { - "id": "api.web_socket.connect.error", - "translation": "websocket connect err: %v" - }, - { - "id": "api.web_socket.connect.upgrade.app_error", - "translation": "Failed to upgrade websocket connection" - }, - { - "id": "api.web_team_hun.start.debug", - "translation": "team hub stopping for teamId=%v" - }, - { - "id": "api.webhook.init.debug", - "translation": "Initializing webhook api routes" - }, - { - "id": "", - "translation": "Incoming webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.delete_incoming.disabled.app_errror", - "translation": "Incoming webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.delete_incoming.permissions.app_errror", - "translation": "Inappropriate permissions to delete incoming webhook" - }, - { - "id": "api.webhook.get_incoming.disabled.app_error", - "translation": "Incoming webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.create_outgoing.disabled.app_error", - "translation": "Outgoing webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.create_outgoing.triggers.app_error", - "translation": "Either trigger_words or channel_id must be set" - }, - { - "id": "api.webhook.get_outgoing.disabled.app_error", - "translation": "Outgoing webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.delete_outgoing.disabled.app_error", - "translation": "Outgoing webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.delete_outgoing.permissions.app_error", - "translation": "Inappropriate permissions to delete outcoming webhook" - }, - { - "id": "api.webhook.regen_outgoing_token.disabled.app_error", - "translation": "Outgoing webhooks have been disabled by the system admin." - }, - { - "id": "api.webhook.regen_outgoing_token.permissions.app_error", - "translation": "Inappropriate permissions to regenerate outcoming webhook token" - } + { + "id": "April", + "translation": "April" + }, + { + "id": "August", + "translation": "August" + }, + { + "id": "December", + "translation": "December" + }, + { + "id": "February", + "translation": "February" + }, + { + "id": "January", + "translation": "January" + }, + { + "id": "July", + "translation": "July" + }, + { + "id": "June", + "translation": "June" + }, + { + "id": "March", + "translation": "March" + }, + { + "id": "May", + "translation": "May" + }, + { + "id": "November", + "translation": "November" + }, + { + "id": "October", + "translation": "October" + }, + { + "id": "September", + "translation": "September" + }, + { + "id": "api.admin.file_read_error", + "translation": "Error reading log file" + }, + { + "id": "api.admin.init.debug", + "translation": "Initializing admin api routes" + }, + { + "id": "api.admin.test_email.body", + "translation": "


      It appears your Mattermost email is setup correctly!" + }, + { + "id": "api.admin.test_email.subject", + "translation": "Mattermost - Testing Email Settings" + }, + { + "id": "api.api.init.parsing_templates.debug", + "translation": "Parsing server templates at %v" + }, + { + "id": "api.api.init.parsing_templates.error", + "translation": "Failed to parse server templates %v" + }, + { + "id": "api.api.render.error", + "translation": "Error rendering template %v err=%v" + }, + { + "id": "api.channel.add_member.added", + "translation": "%v added to the channel by %v" + }, + { + "id": "api.channel.add_member.find_channel.app_error", + "translation": "Failed to find channel" + }, + { + "id": "api.channel.add_member.find_user.app_error", + "translation": "Failed to find user to be added" + }, + { + "id": "api.channel.add_member.user_adding.app_error", + "translation": "Failed to find user doing the adding" + }, + { + "id": "api.channel.add_user.to.channel.failed.app_error", + "translation": "Failed to add user to channel" + }, + { + "id": "api.channel.add_user_to_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.add_user_to_channel.type.app_error", + "translation": "Can not add user to this channel type" + }, + { + "id": "api.channel.create_channel.direct_channel.app_error", + "translation": "Must use createDirectChannel api service for direct message channel creation" + }, + { + "id": "api.channel.create_channel.invalid_character.app_error", + "translation": "Invalid character '__' in channel name for non-direct channel" + }, + { + "id": "api.channel.create_default_channels.off_topic", + "translation": "Off-Topic" + }, + { + "id": "api.channel.create_default_channels.town_square", + "translation": "Town Square" + }, + { + "id": "api.channel.create_direct_channel.invalid_user.app_error", + "translation": "Invalid other user id " + }, + { + "id": "api.channel.delete_channel.archived", + "translation": "%v has archived the channel." + }, + { + "id": "api.channel.delete_channel.cannot.app_error", + "translation": "Cannot delete the default channel {{.Channel}}" + }, + { + "id": "api.channel.delete_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.delete_channel.failed_post.error", + "translation": "Failed to post archive message %v" + }, + { + "id": "api.channel.delete_channel.failed_send.app_error", + "translation": "Failed to send archive message" + }, + { + "id": "api.channel.delete_channel.incoming_webhook.error", + "translation": "Encountered error deleting incoming webhook, id=%v" + }, + { + "id": "api.channel.delete_channel.outgoing_webhook.error", + "translation": "Encountered error deleting outgoing webhook, id=%v" + }, + { + "id": "api.channel.delete_channel.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.channel.get_channel_counts.app_error", + "translation": "Unable to get channel counts from the database" + }, + { + "id": "api.channel.get_channel_extra_info.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.get_channel_extra_info.member_limit.app_error", + "translation": "Failed to parse member limit" + }, + { + "id": "api.channel.get_channels.error", + "translation": "Error in getting users profile for id=%v forcing logout" + }, + { + "id": "api.channel.init.debug", + "translation": "Initializing channel api routes" + }, + { + "id": "api.channel.join_channel.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.channel.join_channel.post_and_forget", + "translation": "%v has joined the channel." + }, + { + "id": "api.channel.leave.default.app_error", + "translation": "Cannot leave the default channel {{.Channel}}" + }, + { + "id": "api.channel.leave.direct.app_error", + "translation": "Cannot leave a direct message channel" + }, + { + "id": "api.channel.leave.left", + "translation": "%v has left the channel." + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.join_leave.error", + "translation": "Failed to post join/leave message %v" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.removed", + "translation": "%s removed the channel header (was: %s)" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.retrieve_user.error", + "translation": "Failed to retrieve user while trying to save update channel header message %v" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.updated_from", + "translation": "%s updated the channel header from: %s to: %s" + }, + { + "id": "api.channel.post_update_channel_header_message_and_forget.updated_to", + "translation": "%s updated the channel header to: %s" + }, + { + "id": "api.channel.post_user_add_remove_message_and_forget.error", + "translation": "Failed to post join/leave message %v" + }, + { + "id": "api.channel.remove_member.permissions.app_error", + "translation": "You do not have the appropriate permissions " + }, + { + "id": "api.channel.remove_member.unable.app_error", + "translation": "Unable to remove user." + }, + { + "id": "api.channel.remove_user_from_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.update_channel.deleted.app_error", + "translation": "The channel has been archived or deleted" + }, + { + "id": "api.channel.update_channel.permission.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.channel.update_channel.tried.app_error", + "translation": "Tried to perform an invalid update of the default channel {{.Channel}}" + }, + { + "id": "api.command.check_command.start.app_error", + "translation": "Command must start with /" + }, + { + "id": "api.command.echo_command.create.error", + "translation": "Unable to create /echo post, err=%v" + }, + { + "id": "api.command.echo_command.description", + "translation": "Echo back text from your account, /echo \"message\" [delay in seconds]" + }, + { + "id": "api.command.echo_command.high_volume.app_error", + "translation": "High volume of echo request, cannot process request" + }, + { + "id": "api.command.echo_command.under.app_error", + "translation": "Delays must be under 10000 seconds" + }, + { + "id": "api.command.init.debug", + "translation": "Initializing command api routes" + }, + { + "id": "api.command.load_test_channels_command.channel.description", + "translation": "Add a specified number of random channels to current team " + }, + { + "id": "api.command.load_test_channels_command.fuzz.description", + "translation": "Add a specified number of random channels with fuzz text to current team " + }, + { + "id": "api.command.load_test_command.description", + "translation": "Debug Load Testing" + }, + { + "id": "api.command.load_test_posts_command.fuzz.description", + "translation": "Add some random posts with fuzz text to current channel " + }, + { + "id": "api.command.load_test_posts_command.posts.description", + "translation": "Add some random posts to current channel " + }, + { + "id": "api.command.load_test_setup_command.create.error", + "translation": "Failed to create testing environment" + }, + { + "id": "api.command.load_test_setup_command.created.info", + "translation": "Team Created: %v" + }, + { + "id": "api.command.load_test_setup_command.description", + "translation": "Creates a testing environment in current team. [teams] [fuzz] " + }, + { + "id": "api.command.load_test_setup_command.login.info", + "translation": "\t User to login: %v, %v" + }, + { + "id": "api.command.load_test_url_command.create.error", + "translation": "Unable to create post, err=%v" + }, + { + "id": "api.command.load_test_url_command.description", + "translation": "Add a post containing the text from a given url to current channel " + }, + { + "id": "api.command.load_test_url_command.file.app_error", + "translation": "Unable to get file" + }, + { + "id": "api.command.load_test_url_command.reading.app_error", + "translation": "Encountered error reading file" + }, + { + "id": "api.command.load_test_url_command.url.app_error", + "translation": "Command must contain a url" + }, + { + "id": "api.command.load_test_users_command.fuzz.description", + "translation": "Add a specified number of random users with fuzz text to current team " + }, + { + "id": "api.command.load_test_users_command.users.description", + "translation": "Add a specified number of random users to current team " + }, + { + "id": "api.command.logout_command.description", + "translation": "Logout" + }, + { + "id": "api.command.me_command.create.error", + "translation": "Unable to create /me post post, err=%v" + }, + { + "id": "api.command.me_command.description", + "translation": "Do an action, /me [message]" + }, + { + "id": "api.command.no_implemented.app_error", + "translation": "Command not implemented" + }, + { + "id": "api.command.shrug_command.create.error", + "translation": "Unable to create /shrug post post, err=%v" + }, + { + "id": "api.command.shrug_command.description", + "translation": "Adds ¯\\_(ツ)_/¯ to your message, /shrug [message]" + }, + { + "id": "api.commmand.join_command.description", + "translation": "Join the open channel" + }, + { + "id": "api.context.404.app_error", + "translation": "Sorry, we could not find the page." + }, + { + "id": "api.context.invalid_param.app_error", + "translation": "Invalid {{.Name}} parameter" + }, + { + "id": "api.context.invalid_team_url.debug", + "translation": "TeamURL accessed when not valid. Team URL should not be used in api functions or those that are team independent" + }, + { + "id": "api.context.invalid_token.error", + "translation": "Invalid session token=%v, err=%v" + }, + { + "id": "api.context.last_activity_at.error", + "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" + }, + { + "id": "api.context.log.error", + "translation": "%v:%v code=%v rid=%v uid=%v ip=%v %v [details: %v]" + }, + { + "id": "api.context.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.context.session_expired.app_error", + "translation": "Invalid or expired session, please login again." + }, + { + "id": "api.context.system_permissions.app_error", + "translation": "You do not have the appropriate permissions (system)" + }, + { + "id": "api.context.token_provided.app_error", + "translation": "Session is not OAuth but token was provided in the query string" + }, + { + "id": "api.context.unknown.app_error", + "translation": "An unknown error has occured. Please contact support." + }, + { + "id": "api.export.json.app_error", + "translation": "Unable to convert to json" + }, + { + "id": "api.export.open.app_error", + "translation": "Unable to open file" + }, + { + "id": "api.export.open_dir.app_error", + "translation": "Unable to open directory" + }, + { + "id": "api.export.open_file.app_error", + "translation": "Unable to open file for export" + }, + { + "id": "api.export.options.create.app_error", + "translation": "Unable to create options file" + }, + { + "id": "api.export.options.write.app_error", + "translation": "Unable to write to options file" + }, + { + "id": "api.export.read_dir.app_error", + "translation": "Unable to read directory" + }, + { + "id": "api.export.s3.app_error", + "translation": "S3 is not supported for local storage export." + }, + { + "id": "api.export.write_file.app_error", + "translation": "Unable to write to export file" + }, + { + "id": "api.file.file_upload.exceeds", + "translation": "File exceeds max image size." + }, + { + "id": "api.file.get_export.retrieve.app_error", + "translation": "Unable to retrieve exported file. Please re-export" + }, + { + "id": "api.file.get_export.team_admin.app_error", + "translation": "Only a team admin can retrieve exported data." + }, + { + "id": "api.file.get_file.not_found.app_error", + "translation": "Could not find file." + }, + { + "id": "api.file.get_file.public_expired.app_error", + "translation": "The public link has expired" + }, + { + "id": "api.file.get_file.public_invalid.app_error", + "translation": "The public link does not appear to be valid" + }, + { + "id": "api.file.get_public_link.disabled.app_error", + "translation": "Public links have been disabled" + }, + { + "id": "api.file.handle_images_forget.decode.error", + "translation": "Unable to decode image channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.encode_jpeg.error", + "translation": "Unable to encode image as jpeg channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.encode_preview.error", + "translation": "Unable to encode image as preview jpg channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.upload_preview.error", + "translation": "Unable to upload preview channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.handle_images_forget.upload_thumb.error", + "translation": "Unable to upload thumbnail channelId=%v userId=%v filename=%v err=%v" + }, + { + "id": "api.file.init.debug", + "translation": "Initializing file api routes" + }, + { + "id": "api.file.open_file_write_stream.configured.app_error", + "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." + }, + { + "id": "api.file.open_file_write_stream.creating_dir.app_error", + "translation": "Encountered an error creating the directory for the new file" + }, + { + "id": "api.file.open_file_write_stream.local_server.app_error", + "translation": "Encountered an error writing to local server storage" + }, + { + "id": "api.file.open_file_write_stream.s3.app_error", + "translation": "S3 is not supported." + }, + { + "id": "api.file.read_file.configured.app_error", + "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." + }, + { + "id": "api.file.read_file.get.app_error", + "translation": "Unable to get file from S3" + }, + { + "id": "api.file.read_file.reading_local.app_error", + "translation": "Encountered an error reading from local server storage" + }, + { + "id": "api.file.upload_file.image.app_error", + "translation": "Unable to upload image file." + }, + { + "id": "api.file.upload_file.large_image.app_error", + "translation": "Unable to upload image file. File is too large." + }, + { + "id": "api.file.upload_file.storage.app_error", + "translation": "Unable to upload file. Image storage is not configured." + }, + { + "id": "api.file.upload_file.too_large.app_error", + "translation": "Unable to upload file. File is too large." + }, + { + "id": "api.file.write_file.configured.app_error", + "translation": "File storage not configured properly. Please configure for either S3 or local server file storage." + }, + { + "id": "api.file.write_file.s3.app_error", + "translation": "Encountered an error writing to S3" + }, + { + "id": "api.file.write_file_locally.create_dir.app_error", + "translation": "Encountered an error creating the directory for the new file" + }, + { + "id": "api.file.write_file_locally.writing.app_error", + "translation": "Encountered an error writing to local server storage" + }, + { + "id": "api.import.import_post.saving.debug", + "translation": "Error saving post. user=%v, message=%v" + }, + { + "id": "api.import.import_user.joining_default.error", + "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" + }, + { + "id": "api.import.import_user.saving.error", + "translation": "Error saving user. err=%v" + }, + { + "id": "api.import.import_user.set_email.error", + "translation": "Failed to set email verified err=%v" + }, + { + "id": "api.license.add_license.array.app_error", + "translation": "Empty array under 'license' in request" + }, + { + "id": "api.license.add_license.expired.app_error", + "translation": "License is either expired or has not yet started." + }, + { + "id": "api.license.add_license.invalid.app_error", + "translation": "Invalid license file." + }, + { + "id": "api.license.add_license.no_file.app_error", + "translation": "No file under 'license' in request" + }, + { + "id": "api.license.add_license.open.app_error", + "translation": "Could not open license file" + }, + { + "id": "api.license.add_license.save.app_error", + "translation": "License did not save properly." + }, + { + "id": "api.license.init.debug", + "translation": "Initializing license api routes" + }, + { + "id": "api.license.remove_license.remove.app_error", + "translation": "License did not remove properly." + }, + { + "id": "api.oauth.allow_oauth.bad_client.app_error", + "translation": "invalid_request: Bad client_id" + }, + { + "id": "api.oauth.allow_oauth.bad_redirect.app_error", + "translation": "invalid_request: Missing or bad redirect_uri" + }, + { + "id": "api.oauth.allow_oauth.bad_response.app_error", + "translation": "invalid_request: Bad response_type" + }, + { + "id": "api.oauth.allow_oauth.database.app_error", + "translation": "server_error: Error accessing the database" + }, + { + "id": "api.oauth.allow_oauth.redirect_callback.app_error", + "translation": "invalid_request: Supplied redirect_uri did not match registered callback_url" + }, + { + "id": "api.oauth.allow_oauth.turn_off.app_error", + "translation": "The system admin has turned off OAuth service providing." + }, + { + "id": "api.oauth.get_auth_data.find.error", + "translation": "Couldn't find auth code for code=%s" + }, + { + "id": "api.oauth.init.debug", + "translation": "Initializing oauth api routes" + }, + { + "id": "api.oauth.register_oauth_app.turn_off.app_error", + "translation": "The system admin has turned off OAuth service providing." + }, + { + "id": "api.oauth.revoke_access_token.del_code.app_error", + "translation": "Error deleting authorization code from DB" + }, + { + "id": "api.oauth.revoke_access_token.del_session.app_error", + "translation": "Error deleting session from DB" + }, + { + "id": "api.oauth.revoke_access_token.del_token.app_error", + "translation": "Error deleting access token from DB" + }, + { + "id": "api.oauth.revoke_access_token.get.app_error", + "translation": "Error getting access token from DB before deletion" + }, + { + "id": "api.post.create_post.bad_filename.error", + "translation": "Bad filename discarded, filename=%v" + }, + { + "id": "api.post.create_post.channel_root_id.app_error", + "translation": "Invalid ChannelId for RootId parameter" + }, + { + "id": "api.post.create_post.last_viewed.error", + "translation": "Encountered error updating last viewed, channel_id=%s, user_id=%s, err=%v" + }, + { + "id": "api.post.create_post.parent_id.app_error", + "translation": "Invalid ParentId parameter" + }, + { + "id": "api.post.create_post.root_id.app_error", + "translation": "Invalid RootId parameter" + }, + { + "id": "api.post.create_webhook_post.creating.app_error", + "translation": "Error creating post" + }, + { + "id": "api.post.delete_post.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.post.get_post.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.post.handle_post_events_and_forget.channel.error", + "translation": "Encountered error getting channel, channel_id=%s, err=%v" + }, + { + "id": "api.post.handle_post_events_and_forget.team.error", + "translation": "Encountered error getting team, team_id=%s, err=%v" + }, + { + "id": "api.post.handle_post_events_and_forget.user.error", + "translation": "Encountered error getting user, user_id=%s, err=%v" + }, + { + "id": "api.post.handle_webhook_events_and_forget.create_post.error", + "translation": "Failed to create response post, err=%v" + }, + { + "id": "api.post.handle_webhook_events_and_forget.event_post.error", + "translation": "Event POST failed, err=%s" + }, + { + "id": "api.post.handle_webhook_events_and_forget.getting.error", + "translation": "Encountered error getting webhooks by team, err=%v" + }, + { + "id": "api.post.init.debug", + "translation": "Initializing post api routes" + }, + { + "id": "api.post.make_direct_channel_visible.get_2_members.error", + "translation": "Failed to get 2 members for a direct channel channel_id=%v" + }, + { + "id": "api.post.make_direct_channel_visible.get_members.error", + "translation": "Failed to get channel members channel_id=%v err=%v" + }, + { + "id": "api.post.make_direct_channel_visible.save_pref.error", + "translation": "Failed to save direct channel preference user_id=%v other_user_id=%v err=%v" + }, + { + "id": "api.post.make_direct_channel_visible.update_pref.error", + "translation": "Failed to update direct channel preference user_id=%v other_user_id=%v err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.members.error", + "translation": "Failed to get channel members channel_id=%v err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.mention_body", + "translation": "You have one new mention." + }, + { + "id": "api.post.send_notifications_and_forget.mention_subject", + "translation": "New Mention" + }, + { + "id": "api.post.send_notifications_and_forget.message_body", + "translation": "You have one new message." + }, + { + "id": "api.post.send_notifications_and_forget.message_subject", + "translation": "New Direct Message" + }, + { + "id": "api.post.send_notifications_and_forget.push_mention", + "translation": " mentioned you in " + }, + { + "id": "api.post.send_notifications_and_forget.push_message", + "translation": " sent you a direct message" + }, + { + "id": "api.post.send_notifications_and_forget.push_notification.debug", + "translation": "Sending push notification to %v wi msg of '%v'" + }, + { + "id": "api.post.send_notifications_and_forget.push_notification.error", + "translation": "Failed to send push notificationid=%v, err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.retrive_profiles.error", + "translation": "Failed to retrieve user profiles team_id=%v, err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.send.error", + "translation": "Failed to send mention email successfully email=%v err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.sent", + "translation": "{{.Prefix}} {{.Filenames}} sent" + }, + { + "id": "api.post.send_notifications_and_forget.sessions.error", + "translation": "Failed to retrieve sessions in notifications id=%v, err=%v" + }, + { + "id": "api.post.send_notifications_and_forget.user_id.error", + "translation": "Post user_id not returned by GetProfiles user_id=%v" + }, + { + "id": "api.post.update_mention_count_and_forget.update_error", + "translation": "Failed to update mention count for user_id=%v on channel_id=%v err=%v" + }, + { + "id": "api.post.update_post.find.app_error", + "translation": "We couldn't find the existing post or comment to update." + }, + { + "id": "api.post.update_post.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.post.update_post.permissions_details.app_error", + "translation": "Already delted id={{.PostId}}" + }, + { + "id": "api.post_get_post_by_id.get.app_error", + "translation": "Unable to get post" + }, + { + "id": "api.preference.init.debug", + "translation": "Initializing preference api routes" + }, + { + "id": "api.preference.save_preferences.decode.app_error", + "translation": "Unable to decode preferences from request" + }, + { + "id": "api.preference.save_preferences.set.app_error", + "translation": "Unable to set preferences for other user" + }, + { + "id": "api.preference.save_preferences.set_details.app_error", + "translation": "session.user_id={{.SessionUserId}}, preference.user_id={{.PreferenceUserId}}" + }, + { + "id": "api.server.new_server.init.info", + "translation": "Server is initializing..." + }, + { + "id": "api.server.start_server.listening.info", + "translation": "Server is listening on %v" + }, + { + "id": "api.server.start_server.rate.info", + "translation": "RateLimiter is enabled" + }, + { + "id": "api.server.start_server.rate.warn", + "translation": "RateLimitSettings not configured properly using VaryByHeader and disabling VaryByRemoteAddr" + }, + { + "id": "api.server.start_server.starting.critical", + "translation": "Error starting server, err:%v" + }, + { + "id": "api.server.start_server.starting.info", + "translation": "Starting Server..." + }, + { + "id": "api.server.start_server.starting.panic", + "translation": "Error starting server " + }, + { + "id": "api.server.stop_server.stopped.info", + "translation": "Server stopped" + }, + { + "id": "api.server.stop_server.stopping.info", + "translation": "Stopping Server..." + }, + { + "id": "api.slackimport.slack_add_channels.added", + "translation": "\r\n Channels Added \r\n" + }, + { + "id": "api.slackimport.slack_add_channels.import_failed", + "translation": "Failed to import: {{.DisplayName}}\r\n" + }, + { + "id": "api.slackimport.slack_add_channels.import_failed.debug", + "translation": "Failed to import: %s" + }, + { + "id": "api.slackimport.slack_add_channels.merge", + "translation": "Merged with existing channel: {{.DisplayName}}\r\n" + }, + { + "id": "api.slackimport.slack_add_posts.bot.warn", + "translation": "Slack bot posts are not imported yet" + }, + { + "id": "api.slackimport.slack_add_posts.msg_no_usr.debug", + "translation": "Message without user" + }, + { + "id": "api.slackimport.slack_add_posts.unsupported.warn", + "translation": "Unsupported post type: %v, %v" + }, + { + "id": "api.slackimport.slack_add_posts.user_no_exists.debug", + "translation": "User: %v does not exist!" + }, + { + "id": "api.slackimport.slack_add_posts.without_user.debug", + "translation": "Message without user" + }, + { + "id": "api.slackimport.slack_add_users.created", + "translation": "\r\n Users Created\r\n" + }, + { + "id": "api.slackimport.slack_add_users.email_pwd", + "translation": "Email, Password: {{.Email}}, {{.Password}}\r\n" + }, + { + "id": "api.slackimport.slack_add_users.unable_import", + "translation": "Unable to import user: {{.Username}}\r\n" + }, + { + "id": "api.slackimport.slack_convert_timestamp.bad.warn", + "translation": "Bad timestamp detected" + }, + { + "id": "api.slackimport.slack_import.log", + "translation": "Mattermost Slack Import Log\r\n" + }, + { + "id": "api.slackimport.slack_import.note1", + "translation": "- Some posts may not have been imported because they where not supported by this importer.\r\n" + }, + { + "id": "api.slackimport.slack_import.note2", + "translation": "- Slack bot posts are currently not supported.\r\n" + }, + { + "id": "api.slackimport.slack_import.notes", + "translation": "\r\n Notes \r\n" + }, + { + "id": "api.slackimport.slack_import.open.app_error", + "translation": "Unable to open: {{.Filename}}" + }, + { + "id": "api.slackimport.slack_import.zip.app_error", + "translation": "Unable to open zip file" + }, + { + "id": "api.team.create_team.email_disabled.app_error", + "translation": "Team sign-up with email is disabled." + }, + { + "id": "api.team.create_team_from_signup.email_disabled.app_error", + "translation": "Team sign-up with email is disabled." + }, + { + "id": "api.team.create_team_from_signup.expired_link.app_error", + "translation": "The signup link has expired" + }, + { + "id": "api.team.create_team_from_signup.invalid_link.app_error", + "translation": "The signup link does not appear to be valid" + }, + { + "id": "api.team.create_team_from_signup.unavailable.app_error", + "translation": "This URL is unavailable. Please try another." + }, + { + "id": "api.team.email_teams.sending.error", + "translation": "An error occured while sending an email in emailTeams err=%v" + }, + { + "id": "api.team.export_team.admin.app_error", + "translation": "Only a team admin can export data." + }, + { + "id": "api.team.import_team.admin.app_error", + "translation": "Only a team admin can import data." + }, + { + "id": "api.team.import_team.array.app_error", + "translation": "Empty array under 'file' in request" + }, + { + "id": "api.team.import_team.integer.app_error", + "translation": "Filesize not an integer" + }, + { + "id": "api.team.import_team.no_file.app_error", + "translation": "No file under 'file' in request" + }, + { + "id": "api.team.import_team.open.app_error", + "translation": "Could not open file" + }, + { + "id": "api.team.import_team.parse.app_error", + "translation": "Could not parse multipart form" + }, + { + "id": "api.team.import_team.unavailable.app_error", + "translation": "Filesize unavilable" + }, + { + "id": "api.team.init.debug", + "translation": "Initializing team api routes" + }, + { + "id": "api.team.invite_members.admin", + "translation": "administrator" + }, + { + "id": "api.team.invite_members.already.app_error", + "translation": "This person is already on your team" + }, + { + "id": "api.team.invite_members.member", + "translation": "member" + }, + { + "id": "api.team.invite_members.no_one.app_error", + "translation": "No one to invite." + }, + { + "id": "api.team.invite_members.send.error", + "translation": "Failed to send invite email successfully err=%v" + }, + { + "id": "api.team.invite_members.sending.info", + "translation": "sending invitation to %v %v" + }, + { + "id": "api.team.is_team_creation_allowed.disabled.app_error", + "translation": "Team creation has been disabled. Please ask your systems administrator for details." + }, + { + "id": "api.team.is_team_creation_allowed.domain.app_error", + "translation": "Email must be from a specific domain (e.g. @example.com). Please ask your systems administrator for details." + }, + { + "id": "api.team.permanent_delete_team.attempting.warn", + "translation": "Attempting to permanently delete team %v id=%v" + }, + { + "id": "api.team.permanent_delete_team.deleted.warn", + "translation": "Permanently deleted team %v id=%v" + }, + { + "id": "api.team.signup_team.email_disabled.app_error", + "translation": "Team sign-up with email is disabled." + }, + { + "id": "api.team.update_team.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.templates.email_change_body.info", + "translation": "You email address for {{.TeamDisplayName}} has been changed to {{.NewEmail}}.
      If you did not make this change, please contact the system administrator." + }, + { + "id": "api.templates.email_change_body.title", + "translation": "You updated your email" + }, + { + "id": "api.templates.email_change_subject", + "translation": "Your email address has changed for {{.TeamDisplayName}}" + }, + { + "id": "api.templates.email_change_verify_body.button", + "translation": "Verify Email" + }, + { + "id": "api.templates.email_change_verify_body.info", + "translation": "To finish updating your email address for {{.TeamDisplayName}}, please click the link below to confirm this is the right address." + }, + { + "id": "api.templates.email_change_verify_body.title", + "translation": "You updated your email" + }, + { + "id": "api.templates.email_change_verify_subject", + "translation": "Verify new email address for {{.TeamDisplayName}}" + }, + { + "id": "api.templates.email_footer", + "translation": "To change your notification preferences, log in to your team site and go to Account Settings > Notifications." + }, + { + "id": "api.templates.email_info", + "translation": "Any questions at all, mail us any time: {{.FeedbackEmail}}.
      Best wishes,
      The {{.SiteName}} Team
      " + }, + { + "id": "api.templates.error.link", + "translation": "Go back to team site" + }, + { + "id": "api.templates.error.title", + "translation": "{{ .SiteName }} needs your help:" + }, + { + "id": "api.templates.find_teams_body.found", + "translation": "Your request to find teams associated with your email found the following:" + }, + { + "id": "api.templates.find_teams_body.not_found", + "translation": "We could not find any teams for the given email." + }, + { + "id": "api.templates.find_teams_body.title", + "translation": "Finding teams" + }, + { + "id": "api.templates.find_teams_subject", + "translation": "Your {{ .SiteName }} Teams" + }, + { + "id": "api.templates.invite_body.button", + "translation": "Join Team" + }, + { + "id": "api.templates.invite_body.extra_info", + "translation": "Mattermost lets you share messages and files from your PC or phone, with instant search and archiving. After you’ve joined {{.TeamDisplayName}}, you can sign-in to your new team and access these features anytime from the web address:

      {{.TeamURL}}" + }, + { + "id": "api.templates.invite_body.info", + "translation": "The team {{.SenderStatus}} {{.SenderName}}, has invited you to join {{.TeamDisplayName}}." + }, + { + "id": "api.templates.invite_body.title", + "translation": "You've been invited" + }, + { + "id": "api.templates.invite_subject", + "translation": "{{ .SenderName }} invited you to join {{ .TeamDisplayName }} Team on {{.SiteName}}" + }, + { + "id": "api.templates.password_change_body.info", + "translation": "Your password has been updated for {{.TeamDisplayName}} on {{ .TeamURL }} by {{.Method}}.
      If this change wasn't initiated by you, please contact your system administrator." + }, + { + "id": "api.templates.password_change_body.title", + "translation": "You updated your password" + }, + { + "id": "api.templates.password_change_subject", + "translation": "Your password has been updated for {{.TeamDisplayName}} on {{ .SiteName }}" + }, + { + "id": "api.templates.post_body.button", + "translation": "Go To Channel" + }, + { + "id": "api.templates.post_body.info", + "translation": "CHANNEL: {{.ChannelName}}
      {{.SenderName}} - {{.Hour}}:{{.Minute}} {{.TimeZone}}, {{.Month}} {{.Day}}" + }, + { + "id": "api.templates.post_subject", + "translation": "{{.SubjectText}} on {{.TeamDisplayName}} at {{.Month}} {{.Day}}, {{.Year}}" + }, + { + "id": "api.templates.reset_body.button", + "translation": "Reset Password" + }, + { + "id": "api.templates.reset_body.info", + "translation": "To change your password, click \"Reset Password\" below.
      If you did not mean to reset your password, please ignore this email and your password will remain the same." + }, + { + "id": "api.templates.reset_body.title", + "translation": "You requested a password reset" + }, + { + "id": "api.templates.reset_subject", + "translation": "Reset your password" + }, + { + "id": "api.templates.signin_change_email.body.method_email", + "translation": "email and password" + }, + { + "id": "api.templates.signin_change_email.body.title", + "translation": "You updated your sign-in method" + }, + { + "id": "api.templates.signup_team_body.button", + "translation": "Set up your team" + }, + { + "id": "api.templates.signup_team_body.info", + "translation": "{{ .SiteName }} is one place for all your team communication, searchable and available anywhere.
      You'll get more out of {{ .SiteName }} when your team is in constant communication--let's get them on board." + }, + { + "id": "api.templates.signup_team_body.title", + "translation": "Thanks for creating a team!" + }, + { + "id": "api.templates.signup_team_subject", + "translation": "{{ .SiteName }} Team Setup" + }, + { + "id": "api.templates.singin_change_email.body.info", + "translation": "You updated your sign-in method for {{.TeamDisplayName}} on {{ .TeamURL }} to {{.Method}}.
      If this change wasn't initiated by you, please contact your system administrator." + }, + { + "id": "api.templates.singin_change_email.subject", + "translation": "You updated your sign-in method for {{.TeamDisplayName}} on {{ .SiteName }}" + }, + { + "id": "api.templates.verify_body.button", + "translation": "Verify Email" + }, + { + "id": "api.templates.verify_body.info", + "translation": "Please verify your email address by clicking below." + }, + { + "id": "api.templates.verify_body.title", + "translation": "You've joined the {{ .TeamDisplayName }} team" + }, + { + "id": "api.templates.verify_subject", + "translation": "[{{ .TeamDisplayName }} {{ .SiteName }}] Email Verification" + }, + { + "id": "api.templates.welcome_body.button", + "translation": "Verify Email" + }, + { + "id": "api.templates.welcome_body.info", + "translation": "Please verify your email address by clicking below." + }, + { + "id": "api.templates.welcome_body.info2", + "translation": "You can sign-in to your new team from the web address:" + }, + { + "id": "api.templates.welcome_body.info3", + "translation": "Mattermost lets you share messages and files from your PC or phone, with instant search and archiving." + }, + { + "id": "api.templates.welcome_body.title", + "translation": "You've joined the {{ .TeamDisplayName }} team" + }, + { + "id": "api.templates.welcome_subject", + "translation": "You joined {{ .TeamDisplayName }}" + }, + { + "id": "api.user.add_direct_channels_and_forget.failed.error", + "translation": "Failed to add direct channel preferences for user user_id=%s, team_id=%s, err=%v" + }, + { + "id": "api.user.authorize_oauth_user.bad_response.app_error", + "translation": "Bad response from token request" + }, + { + "id": "api.user.authorize_oauth_user.bad_token.app_error", + "translation": "Bad token type" + }, + { + "id": "api.user.authorize_oauth_user.invalid_state.app_error", + "translation": "Invalid state" + }, + { + "id": "api.user.authorize_oauth_user.invalid_state_team.app_error", + "translation": "Invalid state; missing team name" + }, + { + "id": "api.user.authorize_oauth_user.missing.app_error", + "translation": "Missing access token" + }, + { + "id": "api.user.authorize_oauth_user.service.app_error", + "translation": "Token request to {{.Service}} failed" + }, + { + "id": "api.user.authorize_oauth_user.token_failed.app_error", + "translation": "Token request failed" + }, + { + "id": "api.user.authorize_oauth_user.unsupported.app_error", + "translation": "Unsupported OAuth service provider" + }, + { + "id": "api.user.check_user_login_attempts.too_many.app_error", + "translation": "Your account is locked because of too many failed password attempts. Please reset your password." + }, + { + "id": "api.user.check_user_password.invalid.app_error", + "translation": "Login failed because of invalid password" + }, + { + "id": "api.user.complete_switch_with_oauth.blank_email.app_error", + "translation": "Blank email" + }, + { + "id": "api.user.complete_switch_with_oauth.parse.app_error", + "translation": "Could not parse auth data out of {{.Service}} user object" + }, + { + "id": "api.user.complete_switch_with_oauth.unavailable.app_error", + "translation": "{{.Service}} oauth not available on this server" + }, + { + "id": "api.user.create_oauth_user.already_attached.app_error", + "translation": "Team {{.DisplayName}} already has a user with the email address attached to your {{.Service}} account" + }, + { + "id": "api.user.create_oauth_user.already_used.app_error", + "translation": "This {{.Service}} account has already been used to sign up for team {{.DisplayName}}" + }, + { + "id": "api.user.create_oauth_user.create.app_error", + "translation": "Could not create user out of {{.Service}} user object" + }, + { + "id": "api.user.create_oauth_user.not_available.app_error", + "translation": "{{.Service}} oauth not avlailable on this server" + }, + { + "id": "api.user.create_profile_image.default_font.app_error", + "translation": "Could not create default profile image font" + }, + { + "id": "api.user.create_profile_image.encode.app_error", + "translation": "Could not encode default profile image" + }, + { + "id": "api.user.create_profile_image.initial.app_error", + "translation": "Could not add user initial to default profile picture" + }, + { + "id": "api.user.create_user.accepted_domain.app_error", + "translation": "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email." + }, + { + "id": "api.user.create_user.joining.error", + "translation": "Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v" + }, + { + "id": "api.user.create_user.save.error", + "translation": "Couldn't save the user err=%v" + }, + { + "id": "api.user.create_user.signup_email_disabled.app_error", + "translation": "User sign-up with email is disabled." + }, + { + "id": "api.user.create_user.signup_link_expired.app_error", + "translation": "The signup link has expired" + }, + { + "id": "api.user.create_user.signup_link_invalid.app_error", + "translation": "The signup link does not appear to be valid" + }, + { + "id": "api.user.create_user.team_name.app_error", + "translation": "Invalid team name" + }, + { + "id": "api.user.create_user.tutorial.error", + "translation": "Encountered error saving tutorial preference, err=%v" + }, + { + "id": "api.user.create_user.verified.error", + "translation": "Failed to set email verified err=%v" + }, + { + "id": "api.user.get_authorization_code.unsupported.app_error", + "translation": "Unsupported OAuth service provider" + }, + { + "id": "api.user.get_me.getting.error", + "translation": "Error in getting users profile for id=%v forcing logout" + }, + { + "id": "api.user.init.debug", + "translation": "Initializing user api routes" + }, + { + "id": "api.user.login.blank_pwd.app_error", + "translation": "Password field must not be blank" + }, + { + "id": "api.user.login.inactive.app_error", + "translation": "Login failed because your account has been set to inactive. Please contact an administrator." + }, + { + "id": "api.user.login.not_provided.app_error", + "translation": "Either user id or team name and user email must be provided" + }, + { + "id": "api.user.login.not_verified.app_error", + "translation": "Login failed because email address has not been verified" + }, + { + "id": "api.user.login.revoking.app_error", + "translation": "Revoking sessionId=%v for userId=%v re-login with same device Id" + }, + { + "id": "api.user.login_by_email.sign_in.app_error", + "translation": "Please sign in using {{.AuthService}}" + }, + { + "id": "api.user.login_by_oauth.not_available.app_error", + "translation": "{{.Service}} oauth not avlailable on this server" + }, + { + "id": "api.user.login_by_oauth.parse.app_error", + "translation": "Could not parse auth data out of {{.Service}} user object" + }, + { + "id": "api.user.login_ldap.blank_pwd.app_error", + "translation": "Password field must not be blank" + }, + { + "id": "api.user.login_ldap.disabled.app_error", + "translation": "LDAP not enabled on this server" + }, + { + "id": "api.user.login_ldap.need_id.app_error", + "translation": "Need an ID" + }, + { + "id": "api.user.login_ldap.not_available.app_error", + "translation": "LDAP not available on this server" + }, + { + "id": "api.user.permanent_delete_user.attempting.warn", + "translation": "Attempting to permanently delete account %v id=%v" + }, + { + "id": "api.user.permanent_delete_user.deleted.warn", + "translation": "Permanently deleted account %v id=%v" + }, + { + "id": "api.user.permanent_delete_user.system_admin.warn", + "translation": "You are deleting %v that is a system administrator. You may need to set another account as the system administrator using the command line tools." + }, + { + "id": "api.user.reset_password.invalid_link.app_error", + "translation": "The reset password link does not appear to be valid" + }, + { + "id": "api.user.reset_password.link_expired.app_error", + "translation": "The reset link has expired" + }, + { + "id": "api.user.reset_password.method", + "translation": "using a reset password link" + }, + { + "id": "api.user.reset_password.sso.app_error", + "translation": "Cannot reset password for SSO accounts" + }, + { + "id": "api.user.reset_password.wrong_team.app_error", + "translation": "Trying to reset password for user on wrong team." + }, + { + "id": "api.user.send_email_change_email_and_forget.error", + "translation": "Failed to send email change notification email successfully err=%v" + }, + { + "id": "api.user.send_email_change_verify_email_and_forget.error", + "translation": "Failed to send email change verification email successfully err=%v" + }, + { + "id": "api.user.send_password_change_email_and_forget.error", + "translation": "Failed to send update password email successfully err=%v" + }, + { + "id": "api.user.send_password_reset.find.app_error", + "translation": "We couldn’t find an account with that address." + }, + { + "id": "api.user.send_password_reset.send.app_error", + "translation": "Failed to send password reset email successfully" + }, + { + "id": "api.user.send_password_reset.sso.app_error", + "translation": "Cannot reset password for SSO accounts" + }, + { + "id": "api.user.send_sign_in_change_email_and_forget.error", + "translation": "Failed to send update password email successfully err=%v" + }, + { + "id": "api.user.send_verify_email_and_forget.failed.error", + "translation": "Failed to send verification email successfully err=%v" + }, + { + "id": "api.user.send_welcome_email_and_forget.failed.error", + "translation": "Failed to send welcome email successfully err=%v" + }, + { + "id": "api.user.switch_to_email.context.app_error", + "translation": "Update password failed because context user_id did not match provided user's id" + }, + { + "id": "api.user.update_active.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.user.update_password.context.app_error", + "translation": "Update password failed because context user_id did not match props user_id" + }, + { + "id": "api.user.update_password.failed.app_error", + "translation": "Update password failed" + }, + { + "id": "api.user.update_password.incorrect.app_error", + "translation": "The \"Current Password\" you entered is incorrect. Please check that Caps Lock is off and try again." + }, + { + "id": "api.user.update_password.menu", + "translation": "using the settings menu" + }, + { + "id": "api.user.update_password.oauth.app_error", + "translation": "Update password failed because the user is logged in through an OAuth service" + }, + { + "id": "api.user.update_password.valid_account.app_error", + "translation": "Update password failed because we couldn't find a valid account" + }, + { + "id": "api.user.update_roles.one_admin.app_error", + "translation": "There must be at least one active admin" + }, + { + "id": "api.user.update_roles.permissions.app_error", + "translation": "You do not have the appropriate permissions" + }, + { + "id": "api.user.update_roles.system_admin_mod.app_error", + "translation": "The system admin role can only by modified by another system admin" + }, + { + "id": "api.user.update_roles.system_admin_set.app_error", + "translation": "The system admin role can only be set by another system admin" + }, + { + "id": "api.user.upload_profile_user.array.app_error", + "translation": "Empty array under 'image' in request" + }, + { + "id": "api.user.upload_profile_user.decode.app_error", + "translation": "Could not decode profile image" + }, + { + "id": "api.user.upload_profile_user.decode_config.app_error", + "translation": "Could not decode profile image config." + }, + { + "id": "api.user.upload_profile_user.encode.app_error", + "translation": "Could not encode profile image" + }, + { + "id": "api.user.upload_profile_user.no_file.app_error", + "translation": "No file under 'image' in request" + }, + { + "id": "api.user.upload_profile_user.open.app_error", + "translation": "Could not open image file" + }, + { + "id": "api.user.upload_profile_user.parse.app_error", + "translation": "Could not parse multipart form" + }, + { + "id": "api.user.upload_profile_user.storage.app_error", + "translation": "Unable to upload file. Image storage is not configured." + }, + { + "id": "api.user.upload_profile_user.too_large.app_error", + "translation": "Unable to upload profile image. File is too large." + }, + { + "id": "api.web_conn.new_web_conn.last_activity.error", + "translation": "Failed to update LastActivityAt for user_id=%v and session_id=%v, err=%v" + }, + { + "id": "api.web_conn.new_web_conn.last_ping.error", + "translation": "Failed to update LastPingAt for user_id=%v, err=%v" + }, + { + "id": "api.web_hub.start.stopping.debug", + "translation": "stopping %v connections" + }, + { + "id": "api.web_socket.connect.error", + "translation": "websocket connect err: %v" + }, + { + "id": "api.web_socket.connect.upgrade.app_error", + "translation": "Failed to upgrade websocket connection" + }, + { + "id": "api.web_socket.init.debug", + "translation": "Initializing web socket api routes" + }, + { + "id": "api.web_team_hun.start.debug", + "translation": "team hub stopping for teamId=%v" + }, + { + "id": "api.webhook.create_incoming.disabled.app_errror", + "translation": "Incoming webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.create_outgoing.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.create_outgoing.triggers.app_error", + "translation": "Either trigger_words or channel_id must be set" + }, + { + "id": "api.webhook.delete_incoming.disabled.app_errror", + "translation": "Incoming webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.delete_incoming.permissions.app_errror", + "translation": "Inappropriate permissions to delete incoming webhook" + }, + { + "id": "api.webhook.delete_outgoing.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.delete_outgoing.permissions.app_error", + "translation": "Inappropriate permissions to delete outcoming webhook" + }, + { + "id": "api.webhook.get_incoming.disabled.app_error", + "translation": "Incoming webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.get_outgoing.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.init.debug", + "translation": "Initializing webhook api routes" + }, + { + "id": "api.webhook.regen_outgoing_token.disabled.app_error", + "translation": "Outgoing webhooks have been disabled by the system admin." + }, + { + "id": "api.webhook.regen_outgoing_token.permissions.app_error", + "translation": "Inappropriate permissions to regenerate outcoming webhook token" + }, + { + "id": "mattermost.current_version", + "translation": "Current version is %v (%v/%v/%v)" + }, + { + "id": "utils.i18n.loaded", + "translation": "Loaded system translations for '%v' from '%v'" + } ] \ No newline at end of file diff --git a/i18n/es.json b/i18n/es.json index a02038085..48f70c89f 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -1,7 +1,51 @@ [ { - "id": "", - "translation": "Webhooks entrantes han sido deshabilitados por el administrador del sistema." + "id": "April", + "translation": "Abril" + }, + { + "id": "August", + "translation": "Agosto" + }, + { + "id": "December", + "translation": "Diciembre" + }, + { + "id": "February", + "translation": "Febrero" + }, + { + "id": "January", + "translation": "Enero" + }, + { + "id": "July", + "translation": "Julio" + }, + { + "id": "June", + "translation": "Junio" + }, + { + "id": "March", + "translation": "Marzo" + }, + { + "id": "May", + "translation": "Mayo" + }, + { + "id": "November", + "translation": "Noviembre" + }, + { + "id": "October", + "translation": "Octubre" + }, + { + "id": "September", + "translation": "Septiembre" }, { "id": "api.admin.file_read_error", @@ -995,6 +1039,198 @@ "id": "api.team.update_team.permissions.app_error", "translation": "No tienes los permisos apropiados" }, + { + "id": "api.templates.email_change_body.info", + "translation": "Tu dirección de correo electrónico para {{.TeamDisplayName}} ha sido cambiada por {{.NewEmail}}.
      Si este cambio no fue realizado por ti, por favor contacta un administrador de sistema." + }, + { + "id": "api.templates.email_change_body.title", + "translation": "Haz actualizado tu correo electrónico" + }, + { + "id": "api.templates.email_change_subject", + "translation": "Tu dirección de correo para {{.TeamDisplayName}} ha cambiado" + }, + { + "id": "api.templates.email_change_verify_body.button", + "translation": "Confirmar Correo" + }, + { + "id": "api.templates.email_change_verify_body.info", + "translation": "Para terminar de actualizar tu dirección de correo para {{.TeamDisplayName}}, por favor pincha en botón de abajo para confirmar que está es la dirección correcta." + }, + { + "id": "api.templates.email_change_verify_body.title", + "translation": "Haz actualizado tu correo electrónico" + }, + { + "id": "api.templates.email_change_verify_subject", + "translation": "Verificación de la nueva dirección de correo electrónico para {{.TeamDisplayName}}" + }, + { + "id": "api.templates.email_footer", + "translation": "Para cambiar tus preferencias de notificaciones, inicia sesión en tu equipo y dirigete a Configurar Cuenta > Notificaciones." + }, + { + "id": "api.templates.email_info", + "translation": "Si tienes alguna pregunta, escribenos en cualquier momento a: {{.FeedbackEmail}}.
      Los mejores deseos,
      El Equipo {{.SiteName}}
      " + }, + { + "id": "api.templates.error.link", + "translation": "Volver al sitio del equipo" + }, + { + "id": "api.templates.error.title", + "translation": "Necesitamos de tu ayuda en {{ .SiteName }}:" + }, + { + "id": "api.templates.find_teams_body.found", + "translation": "Haz solicitado encontrar los equipos a los que tienes asociado tu correo electrónico y encontramos los siguientes:" + }, + { + "id": "api.templates.find_teams_body.not_found", + "translation": "No hemos podido encontrar ningún equipo asociado al correo electrónico suministrado." + }, + { + "id": "api.templates.find_teams_body.title", + "translation": "Tus Equipos" + }, + { + "id": "api.templates.find_teams_subject", + "translation": "Tus equipos de {{ .SiteName }}" + }, + { + "id": "api.templates.invite_body.button", + "translation": "Unirme al Equipo" + }, + { + "id": "api.templates.invite_body.extra_info", + "translation": "Mattermost te permite compartir mensajes y archivos de tu Computador o teléfono, incluyendo busquedas instantáneas. Una vez que te hayas unido a {{.TeamDisplayName}}, Podrás iniciar sesión en tu nuevo equipo y utilizar todas las características en cualquier momento desde la dirección web:

      {{.TeamURL}}" + }, + { + "id": "api.templates.invite_body.info", + "translation": "{{.SenderName}} {{.SenderStatus}} del equipo {{.TeamDisplayName}}, te ha invitado a unirte." + }, + { + "id": "api.templates.invite_body.title", + "translation": "Haz sido invitado" + }, + { + "id": "api.templates.invite_subject", + "translation": "{{ .SenderName }} te ha invitado a unirte al equipo {{ .TeamDisplayName }} en {{.SiteName}}" + }, + { + "id": "api.templates.password_change_body.info", + "translation": "Tu contraseña ha sido cambiada para {{.TeamDisplayName}} en {{ .TeamURL }} por el método de {{.Method}}.
      Si este cambio no fue realizado por ti, por favor contacta a un administrador del sistema." + }, + { + "id": "api.templates.password_change_body.title", + "translation": "Haz cambiado tu contraseña" + }, + { + "id": "api.templates.password_change_subject", + "translation": "Tu contraseña ha sido cambiada para {{.TeamDisplayName}} en {{ .SiteName }}" + }, + { + "id": "api.templates.post_body.button", + "translation": "Ir al Canal" + }, + { + "id": "api.templates.post_body.info", + "translation": "Canal: {{.ChannelName}}
      {{.SenderName}} - {{.Day}} {{.Month}}, {{.Hour}}:{{.Minute}} {{.TimeZone}}" + }, + { + "id": "api.templates.post_subject", + "translation": "{{.SubjectText}} en {{.TeamDisplayName}} el {{.Day}} {{.Month}}, {{.Year}}" + }, + { + "id": "api.templates.reset_body.button", + "translation": "Restablecer Contraseña" + }, + { + "id": "api.templates.reset_body.info", + "translation": "Para cambiar tu contraseña, pincha el botón \"Restablecer Contraseña\" que se encuentra abajo.
      Si no fue tu intención restablecer tu contraseña, por favor ignora este correo y tu contraseña seguirá siendo la misma." + }, + { + "id": "api.templates.reset_body.title", + "translation": "Haz solicitado restablecer tu contraseña" + }, + { + "id": "api.templates.reset_subject", + "translation": "Restablece tu contraseña" + }, + { + "id": "api.templates.signin_change_email.body.method_email", + "translation": "correo electrónico y contraseña" + }, + { + "id": "api.templates.signin_change_email.body.title", + "translation": "Haz actualizado el método con el que inicias sesión" + }, + { + "id": "api.templates.signup_team_body.button", + "translation": "Configura tu equipo" + }, + { + "id": "api.templates.signup_team_body.info", + "translation": "{{ .SiteName }} es el lugar para todas las comunicaciones de tu equipo, con capacidades de búsqueda y disponible desde cualquier parte.
      Podrás aprovechar al máximo {{ .SiteName }} cuando tu equipo esté en constante comunicación--Traigamoslos a bordo." + }, + { + "id": "api.templates.signup_team_body.title", + "translation": "¡Gracias por haber creado un equipo!" + }, + { + "id": "api.templates.signup_team_subject", + "translation": "Configuración del equipo en {{ .SiteName }}" + }, + { + "id": "api.templates.singin_change_email.body.info", + "translation": "Haz actualizado el método con el que inicias sesión en {{.TeamURL}} para el equipo {{.TeamDisplayName}} por {{.Method}}.
      Si este cambio no fue realizado por ti, por favor contacta a un administrador del sistema." + }, + { + "id": "api.templates.singin_change_email.subject", + "translation": "Cambio del método de inicio de sesión para {{.TeamDisplayName}} en {{ .SiteName }}" + }, + { + "id": "api.templates.verify_body.button", + "translation": "Confirmar Correo" + }, + { + "id": "api.templates.verify_body.info", + "translation": "Por favor verifica tu correo electrónico al pinchar el botón de abajo." + }, + { + "id": "api.templates.verify_body.title", + "translation": "Te haz unido al equipo {{ .TeamDisplayName }}" + }, + { + "id": "api.templates.verify_subject", + "translation": "[{{ .TeamDisplayName }} {{ .SiteName }}] Correo de Verificación" + }, + { + "id": "api.templates.welcome_body.button", + "translation": "Confirmar Correo" + }, + { + "id": "api.templates.welcome_body.info", + "translation": "Por favor verifica tu correo electrónico al pinchar el botón de abajo." + }, + { + "id": "api.templates.welcome_body.info2", + "translation": "Puedes iniciar sesión en tu nuevo equipo desde la dirección web:" + }, + { + "id": "api.templates.welcome_body.info3", + "translation": "Mattermost te permite compartir mensajes y archivos desde un computador o teléfono desde donde te encuentres." + }, + { + "id": "api.templates.welcome_body.title", + "translation": "Te haz unido al equipo {{ .TeamDisplayName }}" + }, + { + "id": "api.templates.welcome_subject", + "translation": "Te haz unido a {{ .TeamDisplayName }}" + }, { "id": "api.user.add_direct_channels_and_forget.failed.error", "translation": "Falla al agragar las preferencias del canal directo para el usuario user_id=%s, team_id=%s, err=%v" @@ -1195,6 +1431,10 @@ "id": "api.user.reset_password.link_expired.app_error", "translation": "El enlace para restablecer la contraseña ha expirado" }, + { + "id": "api.user.reset_password.method", + "translation": "utilizando el enlace para restablecer contraseña" + }, { "id": "api.user.reset_password.sso.app_error", "translation": "No se puede restablecer la contraseña para cuentas SSO" @@ -1329,7 +1569,7 @@ }, { "id": "api.web_conn.new_web_conn.last_ping.error", - "translation": "Failed to update LastPingAt for user_id=%v, err=%v" + "translation": "Falla al actualizar LastPingAt para el user_id=%v, err=%v" }, { "id": "api.web_hub.start.stopping.debug", @@ -1351,6 +1591,10 @@ "id": "api.web_team_hun.start.debug", "translation": "deteniendo el hub de equipo para teamId=%v" }, + { + "id": "api.webhook.create_incoming.disabled.app_errror", + "translation": "Webhooks entrantes han sido deshabilitados por el administrador del sistema." + }, { "id": "api.webhook.create_outgoing.disabled.app_error", "translation": "Webhooks de Salida han sido deshabilitados por el administrador del sistema." diff --git a/web/web.go b/web/web.go index f73860b67..48755f94f 100644 --- a/web/web.go +++ b/web/web.go @@ -565,9 +565,9 @@ func verifyEmail(c *api.Context, w http.ResponseWriter, r *http.Request) { user := result.Data.(*model.User) if user.LastActivityAt > 0 { - api.SendEmailChangeVerifyEmailAndForget(user.Id, user.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) + api.SendEmailChangeVerifyEmailAndForget(c, user.Id, user.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) } else { - api.SendVerifyEmailAndForget(user.Id, user.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) + api.SendVerifyEmailAndForget(c, user.Id, user.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) } newAddress := strings.Replace(r.URL.String(), "&resend=true", "&resend_success=true", -1) -- cgit v1.2.3-1-g7c22 From e428269b1a7d75a17f5b94c21e624be8c8cb35ba Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sun, 24 Jan 2016 17:19:40 -0300 Subject: Remove enterprise configs --- config/config.json | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/config/config.json b/config/config.json index c620262a9..d83eea0e1 100644 --- a/config/config.json +++ b/config/config.json @@ -109,28 +109,5 @@ "AuthEndpoint": "", "TokenEndpoint": "", "UserApiEndpoint": "" - }, - "GoogleSettings": { - "Enable": false, - "Secret": "", - "Id": "", - "Scope": "", - "AuthEndpoint": "", - "TokenEndpoint": "", - "UserApiEndpoint": "" - }, - "LdapSettings": { - "Enable": false, - "LdapServer": null, - "LdapPort": 389, - "BaseDN": null, - "BindUsername": null, - "BindPassword": null, - "FirstNameAttribute": null, - "LastNameAttribute": null, - "EmailAttribute": null, - "UsernameAttribute": null, - "IdAttribute": null, - "QueryTimeout": 60 } } \ No newline at end of file -- cgit v1.2.3-1-g7c22 From e880835fbbeea4c26fc9a94b1b0a92f7692b0b82 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Sun, 24 Jan 2016 23:34:18 -0300 Subject: Revert config.json --- config/config.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config/config.json b/config/config.json index d83eea0e1..076f795cc 100644 --- a/config/config.json +++ b/config/config.json @@ -15,9 +15,7 @@ "SessionLengthWebInDays": 30, "SessionLengthMobileInDays": 30, "SessionLengthSSOInDays": 30, - "SessionCacheInMinutes": 10, - "WebsocketSecurePort": 443, - "WebsocketPort": 80 + "SessionCacheInMinutes": 10 }, "TeamSettings": { "SiteName": "Mattermost", -- cgit v1.2.3-1-g7c22 From 056fdec301de69e235313c0e27aadf8c769f8082 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Sun, 24 Jan 2016 20:48:31 -0600 Subject: PLT-7 client side infra for loc --- web/react/pages/authorize.jsx | 75 ++++++++++++++++++++++++++------ web/react/pages/claim_account.jsx | 71 +++++++++++++++++++++++++----- web/react/pages/docs.jsx | 64 +++++++++++++++++++++++---- web/react/pages/password_reset.jsx | 71 +++++++++++++++++++++++++----- web/react/pages/signup_team.jsx | 63 ++++++++++++++++++++++++--- web/react/pages/signup_team_complete.jsx | 67 ++++++++++++++++++++++++---- web/react/pages/signup_user_complete.jsx | 73 ++++++++++++++++++++++++++----- web/react/pages/verify.jsx | 65 ++++++++++++++++++++++++--- 8 files changed, 473 insertions(+), 76 deletions(-) diff --git a/web/react/pages/authorize.jsx b/web/react/pages/authorize.jsx index 71f17d007..7474332ce 100644 --- a/web/react/pages/authorize.jsx +++ b/web/react/pages/authorize.jsx @@ -2,20 +2,69 @@ // See License.txt for license information. import Authorize from '../components/authorize.jsx'; +import * as Client from '../utils/client.jsx'; -function setupAuthorizePage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setup_authorize_page = function setup(props) { ReactDOM.render( - , + , document.getElementById('authorize') ); -} - -global.window.setup_authorize_page = setupAuthorizePage; +}; diff --git a/web/react/pages/claim_account.jsx b/web/react/pages/claim_account.jsx index bca203d96..7c6af73ca 100644 --- a/web/react/pages/claim_account.jsx +++ b/web/react/pages/claim_account.jsx @@ -2,18 +2,67 @@ // See License.txt for license information. import ClaimAccount from '../components/claim/claim_account.jsx'; +import * as Client from '../utils/client.jsx'; -function setupClaimAccountPage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setup_claim_account_page = function setup(props) { ReactDOM.render( - , + , document.getElementById('claim') ); -} - -global.window.setup_claim_account_page = setupClaimAccountPage; +}; \ No newline at end of file diff --git a/web/react/pages/docs.jsx b/web/react/pages/docs.jsx index 74d9c2d19..2f5d4db55 100644 --- a/web/react/pages/docs.jsx +++ b/web/react/pages/docs.jsx @@ -2,15 +2,63 @@ // See License.txt for license information. import Docs from '../components/docs.jsx'; +import * as Client from '../utils/client.jsx'; -function setupDocumentationPage(props) { - ReactDOM.render( - , - document.getElementById('docs') - ); +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } } global.window.mm_user = global.window.mm_user || {}; -global.window.setup_documentation_page = setupDocumentationPage; + +global.window.setup_documentation_page = function setup(props) { + ReactDOM.render( + , + document.getElementById('docs') + ); +}; diff --git a/web/react/pages/password_reset.jsx b/web/react/pages/password_reset.jsx index 4a6f1dcb0..23bbf2691 100644 --- a/web/react/pages/password_reset.jsx +++ b/web/react/pages/password_reset.jsx @@ -2,18 +2,67 @@ // See License.txt for license information. import PasswordReset from '../components/password_reset.jsx'; +import * as Client from '../utils/client.jsx'; -function setupPasswordResetPage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setup_password_reset_page = function setup(props) { ReactDOM.render( - , + , document.getElementById('reset') ); -} - -global.window.setup_password_reset_page = setupPasswordResetPage; +}; diff --git a/web/react/pages/signup_team.jsx b/web/react/pages/signup_team.jsx index 08ea45000..8f4f86a7c 100644 --- a/web/react/pages/signup_team.jsx +++ b/web/react/pages/signup_team.jsx @@ -2,8 +2,60 @@ // See License.txt for license information. import SignupTeam from '../components/signup_team.jsx'; +import * as Client from '../utils/client.jsx'; -function setupSignupTeamPage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired, + teams: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setup_signup_team_page = function setup(props) { var teams = []; for (var prop in props) { @@ -15,9 +67,10 @@ function setupSignupTeamPage(props) { } ReactDOM.render( - , + , document.getElementById('signup-team') ); -} - -global.window.setup_signup_team_page = setupSignupTeamPage; +}; \ No newline at end of file diff --git a/web/react/pages/signup_team_complete.jsx b/web/react/pages/signup_team_complete.jsx index d5ed144a1..1bee4e598 100644 --- a/web/react/pages/signup_team_complete.jsx +++ b/web/react/pages/signup_team_complete.jsx @@ -2,16 +2,65 @@ // See License.txt for license information. import SignupTeamComplete from '../components/signup_team_complete.jsx'; +import * as Client from '../utils/client.jsx'; -function setupSignupTeamCompletePage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setup_signup_team_complete_page = function setup(props) { ReactDOM.render( - , + , document.getElementById('signup-team-complete') ); -} - -global.window.setup_signup_team_complete_page = setupSignupTeamCompletePage; +}; \ No newline at end of file diff --git a/web/react/pages/signup_user_complete.jsx b/web/react/pages/signup_user_complete.jsx index de2c48443..6c761c1ee 100644 --- a/web/react/pages/signup_user_complete.jsx +++ b/web/react/pages/signup_user_complete.jsx @@ -2,19 +2,68 @@ // See License.txt for license information. import SignupUserComplete from '../components/signup_user_complete.jsx'; +import * as Client from '../utils/client.jsx'; -function setupSignupUserCompletePage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setup_signup_user_complete_page = function setup(props) { ReactDOM.render( - , + , document.getElementById('signup-user-complete') ); -} - -global.window.setup_signup_user_complete_page = setupSignupUserCompletePage; +}; \ No newline at end of file diff --git a/web/react/pages/verify.jsx b/web/react/pages/verify.jsx index d4ce4844d..2fc619e58 100644 --- a/web/react/pages/verify.jsx +++ b/web/react/pages/verify.jsx @@ -2,15 +2,66 @@ // See License.txt for license information. import EmailVerify from '../components/email_verify.jsx'; +import * as Client from '../utils/client.jsx'; -global.window.setupVerifyPage = function setupVerifyPage(props) { +var IntlProvider = ReactIntl.IntlProvider; + +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } + + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + + + + ); + } +} + +global.window.setupVerifyPage = function setup(props) { ReactDOM.render( - , + , document.getElementById('verify') ); }; -- cgit v1.2.3-1-g7c22 From 6d30f3b14c3f446224daf562df9e63f29583794b Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Sun, 24 Jan 2016 21:13:30 -0600 Subject: PLT-7 client infra for loc --- web/react/pages/admin_console.jsx | 77 ++++++++++++++++++++++++++++++--------- web/templates/admin_console.html | 6 +-- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/web/react/pages/admin_console.jsx b/web/react/pages/admin_console.jsx index cbd2bd80d..3f4c39934 100644 --- a/web/react/pages/admin_console.jsx +++ b/web/react/pages/admin_console.jsx @@ -4,25 +4,68 @@ import ErrorBar from '../components/error_bar.jsx'; import SelectTeamModal from '../components/admin_console/select_team_modal.jsx'; import AdminController from '../components/admin_console/admin_controller.jsx'; +import * as Client from '../utils/client.jsx'; -export function setupAdminConsolePage(props) { - ReactDOM.render( - , - document.getElementById('admin_controller') - ); +var IntlProvider = ReactIntl.IntlProvider; - ReactDOM.render( - , - document.getElementById('select_team_modal') - ); +class Root extends React.Component { + constructor() { + super(); + this.state = { + translations: null, + loaded: false + }; + } - ReactDOM.render( - , - document.getElementById('error_bar') - ); + static propTypes() { + return { + map: React.PropTypes.object.isRequired + }; + } + + componentWillMount() { + Client.getTranslations( + this.props.map.Locale, + (data) => { + this.setState({ + translations: data, + loaded: true + }); + }, + () => { + this.setState({ + loaded: true + }); + } + ); + } + + render() { + if (!this.state.loaded) { + return
      ; + } + + return ( + +
      + + + +
      +
      + ); + } } -global.window.setup_admin_console_page = setupAdminConsolePage; +global.window.setup_admin_console_page = function setup(props) { + ReactDOM.render( + , + document.getElementById('admin_controller') + ); +}; diff --git a/web/templates/admin_console.html b/web/templates/admin_console.html index 0e37a4660..08c90493e 100644 --- a/web/templates/admin_console.html +++ b/web/templates/admin_console.html @@ -6,11 +6,7 @@ -
      - -
      - -
      +