diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 4201c4827..e971e6215 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4047,5 +4047,7 @@ "addChatToSpaceDesc": "Adding a chat to a space will make the chat appear within the space for students and give them access.", "addSpaceToSpaceDesc": "Adding a space to another space will make the child space appear within the parent space for students and give them access.", "spaceAnalytics": "Space Analytics", - "changeAnalyticsLanguage": "Change Analytics Language" + "changeAnalyticsLanguage": "Change Analytics Language", + "suggestToSpace": "Suggest this space", + "suggestToSpaceDesc": "Suggested spaces will appear in the chat lists for their parent spaces" } \ No newline at end of file diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index 61a9489b6..6ea029a6f 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -441,9 +441,7 @@ class Choreographer { } LanguageModel? get l2Lang { - return pangeaController.languageController.activeL2Model( - roomID: roomId, - ); + return pangeaController.languageController.activeL2Model(); } String? get l2LangCode => l2Lang?.langCode; diff --git a/lib/pangea/controllers/language_controller.dart b/lib/pangea/controllers/language_controller.dart index d070ac914..c906e6b4e 100644 --- a/lib/pangea/controllers/language_controller.dart +++ b/lib/pangea/controllers/language_controller.dart @@ -101,7 +101,7 @@ class LanguageController { // return activeL1 != null ? PangeaLanguage.byLangCode(activeL1) : null; } - LanguageModel? activeL2Model({String? roomID}) { + LanguageModel? activeL2Model() { return userL2; // final activeL2 = activeL2Code(roomID: roomID); // final model = activeL2 != null ? PangeaLanguage.byLangCode(activeL2) : null; diff --git a/lib/pangea/controllers/my_analytics_controller.dart b/lib/pangea/controllers/my_analytics_controller.dart index f00e601a8..f96f4096a 100644 --- a/lib/pangea/controllers/my_analytics_controller.dart +++ b/lib/pangea/controllers/my_analytics_controller.dart @@ -6,8 +6,10 @@ import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/controllers/base_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; -import 'package:fluffychat/pangea/models/analytics/analytics_event.dart'; -import 'package:fluffychat/pangea/models/analytics/analytics_model.dart'; +import 'package:fluffychat/pangea/models/analytics/constructs_event.dart'; +import 'package:fluffychat/pangea/models/analytics/constructs_model.dart'; +import 'package:fluffychat/pangea/models/analytics/summary_analytics_event.dart'; +import 'package:fluffychat/pangea/models/analytics/summary_analytics_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/foundation.dart'; import 'package:matrix/matrix.dart'; @@ -170,6 +172,12 @@ class MyAnalyticsController extends BaseController { } Future _updateAnalytics() async { + // if the user's l2 is not sent, don't send analytics + final String? userL2 = _pangeaController.languageController.activeL2Code(); + if (userL2 == null) { + return; + } + // top level analytics sending function. Send analytics // for each type of analytics event // to each of the applicable analytics rooms @@ -180,115 +188,118 @@ class MyAnalyticsController extends BaseController { await setStudentChats(); await setStudentSpaces(); - // get all the analytics rooms that the user has - // and create any missing analytics rooms (if the user is studying - // in a class but doesn't have an analytics room for that class's L2) - final List analyticsRooms = - _pangeaController.matrixState.client.allMyAnalyticsRooms; - analyticsRooms.addAll(await createMissingAnalyticsRooms()); + // get the last updated time for each analytics room + // and the least recent update, which will be used to determine + // how far to go back in the chat history to get messages + final Map lastUpdatedMap = await _pangeaController + .matrixState.client + .allAnalyticsRoomsLastUpdated(); + final List lastUpdates = lastUpdatedMap.values + .where((lastUpdate) => lastUpdate != null) + .cast() + .toList(); + lastUpdates.sort((a, b) => a.compareTo(b)); + final DateTime? leastRecentUpdate = + lastUpdates.isNotEmpty ? lastUpdates.first : null; - // finally, send an analytics event for each analytics room and - // each type of analytics event - for (final Room analyticsRoom in analyticsRooms) { - for (final String type in AnalyticsEvent.analyticsEventTypes) { - await sendAnalyticsEvent(analyticsRoom, type); - } + // for each chat the user is studying in, get all the messages + // since the least recent update analytics update, and sort them + // by their langCodes + final Map> langCodeToMsgs = + await getLangCodesToMsgs( + userL2, + leastRecentUpdate, + ); + + final List langCodes = langCodeToMsgs.keys.toList(); + for (final String langCode in langCodes) { + // for each of the langs that the user has sent message in, get + // the corresponding analytics room (or create it) + final Room analyticsRoom = await _pangeaController.matrixState.client + .getMyAnalyticsRoom(langCode); + + // if there is no analytics room for this langCode, then user hadn't sent + // message in this language at the time of the last analytics update + // so fallback to the least recent update time + final DateTime? lastUpdated = + lastUpdatedMap[analyticsRoom.id] ?? leastRecentUpdate; + + // get the corresponding list of recent messages for this langCode + final List recentMsgs = + langCodeToMsgs[langCode] ?? []; + + // finally, send the analytics events to the analytics room + await sendAnalyticsEvents( + analyticsRoom, + recentMsgs, + lastUpdated, + ); } } - Future sendAnalyticsEvent( - Room analyticsRoom, - String type, + Future>> getLangCodesToMsgs( + String userL2, + DateTime? since, ) async { - // given an analytics room for a language and a type of analytics event - // gathers all the relevant data and sends it to the analytics room - - // get the language code for the analytics room - final String? langCode = analyticsRoom.madeForLang; - if (langCode == null) { - ErrorHandler.logError( - e: "no lang code found for analytics room: ${analyticsRoom.id}", - s: StackTrace.current, - ); - return; - } - - // get the last time an analytics event of this type was sent to this room - final DateTime? lastUpdated = await analyticsRoom.analyticsLastUpdated( - type, - _pangeaController.matrixState.client.userID!, - ); - - // each type of analytics event has a format for storing per-message data - // for SummaryAnalytics events, this is RecentMessageRecord - // for Construct events, this is OneConstructUse - // analyticsContent is a list of these formatted data - final List analyticsContent = []; - + // get a map of langCodes to messages for each chat the user is studying in + final Map> langCodeToMsgs = {}; for (final Room chat in _studentChats) { - // for each chat the student studies in, check if the langCode - // matches the langCode of the analytics room - // TODO gabby - replace this - final String? chatLangCode = - _pangeaController.languageController.activeL2Code(); - if (chatLangCode != langCode) continue; - - // get messages the logged in user has sent in all chats - // since the last analytics event was sent List? recentMsgs; try { recentMsgs = await chat.myMessageEventsInChat( - since: lastUpdated, + since: since, ); } catch (err) { debugPrint("failed to fetch messages for chat ${chat.id}"); continue; } - if (lastUpdated != null) { - recentMsgs.removeWhere( - (msg) => msg.event.originServerTs.isBefore(lastUpdated), - ); + // sort those messages by their langCode + // langCode is hopefully based on the original sent rep, but if that + // is null, it will be based on the user's current l2 + for (final msg in recentMsgs) { + final String msgLangCode = msg.originalSent?.langCode ?? userL2; + langCodeToMsgs[msgLangCode] ??= []; + langCodeToMsgs[msgLangCode]!.add(msg); } + } + return langCodeToMsgs; + } - // then format that data into analytics data and add the formatted - // data to the list of analyticsContent - analyticsContent.addAll( - AnalyticsModel.formatAnalyticsContent(recentMsgs, type), + Future sendAnalyticsEvents( + Room analyticsRoom, + List recentMsgs, + DateTime? lastUpdated, + ) async { + // remove messages that were sent before the last update + if (recentMsgs.isEmpty) return; + if (lastUpdated != null) { + recentMsgs.removeWhere( + (msg) => msg.event.originServerTs.isBefore(lastUpdated), ); } - // send the analytics data to the analytics room - // if there is no data to send, don't send an event, - // unless no events have been sent yet. In that case, send an event - // with no data to indicate that the the system checked for data - // and found none, so the system doesn't repeatedly check for data - if (analyticsContent.isEmpty && lastUpdated != null) return; - await AnalyticsEvent.sendEvent( - analyticsRoom, - type, - analyticsContent, - ); - } + // format the analytics data + final List summaryContent = + SummaryAnalyticsModel.formatSummaryContent(recentMsgs); + final List constructContent = + ConstructAnalyticsModel.formatConstructsContent(recentMsgs); - // on the off chance that the user is in a class but doesn't have an analytics - // room for the target language of that class, create the analytics room(s) - Future> createMissingAnalyticsRooms() async { - List targetLangs = []; - final String? userL2 = _pangeaController.languageController.activeL2Code(); - if (userL2 != null) targetLangs.add(userL2); - // TODO gabby - replace this - final List spaceL2s = studentSpaces - .map( - (space) => _pangeaController.languageController.activeL2Code(), - ) - .toList(); - targetLangs.addAll(spaceL2s.where((l2) => l2 != null).cast()); - targetLangs = targetLangs.toSet().toList(); - for (final String langCode in targetLangs) { - await _pangeaController.matrixState.client.getMyAnalyticsRoom(langCode); + // if there's new content to be sent, or if lastUpdated hasn't been + // set yet for this room, send the analytics events + if (summaryContent.isNotEmpty || lastUpdated == null) { + await SummaryAnalyticsEvent.sendSummaryAnalyticsEvent( + analyticsRoom, + summaryContent, + ); + } + + if (constructContent.isNotEmpty) { + await ConstructAnalyticsEvent.sendConstructsEvent( + analyticsRoom, + constructContent, + ); } - return _pangeaController.matrixState.client.allMyAnalyticsRooms; } List _studentChats = []; diff --git a/lib/pangea/extensions/client_extension/client_analytics_extension.dart b/lib/pangea/extensions/client_extension/client_analytics_extension.dart index d2423131f..9956359a0 100644 --- a/lib/pangea/extensions/client_extension/client_analytics_extension.dart +++ b/lib/pangea/extensions/client_extension/client_analytics_extension.dart @@ -153,4 +153,17 @@ extension AnalyticsClientExtension on Client { await _joinInvitedAnalyticsRooms(); await _joinAnalyticsRoomsInAllSpaces(); } + + Future> _allAnalyticsRoomsLastUpdated() async { + // get the last updated time for each analytics room + final Map lastUpdatedMap = {}; + for (final analyticsRoom in allMyAnalyticsRooms) { + final DateTime? lastUpdated = await analyticsRoom.analyticsLastUpdated( + PangeaEventTypes.summaryAnalytics, + userID!, + ); + lastUpdatedMap[analyticsRoom.id] = lastUpdated; + } + return lastUpdatedMap; + } } diff --git a/lib/pangea/extensions/client_extension/client_extension.dart b/lib/pangea/extensions/client_extension/client_extension.dart index 498081a8c..779f8ee0a 100644 --- a/lib/pangea/extensions/client_extension/client_extension.dart +++ b/lib/pangea/extensions/client_extension/client_extension.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/constants/class_default_values.dart'; import 'package:fluffychat/pangea/constants/model_keys.dart'; +import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/constants/pangea_room_types.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/space_model.dart'; @@ -43,6 +44,9 @@ extension PangeaClient on Client { Future migrateAnalyticsRooms() async => await _migrateAnalyticsRooms(); + Future> allAnalyticsRoomsLastUpdated() async => + await _allAnalyticsRoomsLastUpdated(); + // spaces Future> get spacesImTeaching async => await _spacesImTeaching; diff --git a/lib/pangea/widgets/class/add_space_toggles.dart b/lib/pangea/widgets/class/add_space_toggles.dart index 08fac33d9..abbef7746 100644 --- a/lib/pangea/widgets/class/add_space_toggles.dart +++ b/lib/pangea/widgets/class/add_space_toggles.dart @@ -229,13 +229,21 @@ class AddToSpaceState extends State { ? Column( children: [ SwitchListTile.adaptive( - title: Text(L10n.of(context)!.suggestToChat), + title: Text( + widget.spaceMode || (room?.isSpace ?? false) + ? L10n.of(context)!.suggestToSpace + : L10n.of(context)!.suggestToChat, + ), secondary: Icon( isSuggested ? Icons.visibility_outlined : Icons.visibility_off_outlined, ), - subtitle: Text(L10n.of(context)!.suggestToChatDesc), + subtitle: Text( + widget.spaceMode || (room?.isSpace ?? false) + ? L10n.of(context)!.suggestToSpaceDesc + : L10n.of(context)!.suggestToChatDesc, + ), activeColor: AppConfig.activeToggleColor, value: isSuggested, onChanged: (bool add) => setSuggested(add), diff --git a/lib/pangea/widgets/igc/word_data_card.dart b/lib/pangea/widgets/igc/word_data_card.dart index eae1c2b8d..5a785c795 100644 --- a/lib/pangea/widgets/igc/word_data_card.dart +++ b/lib/pangea/widgets/igc/word_data_card.dart @@ -62,8 +62,7 @@ class WordDataCardController extends State { void initState() { if (!mounted) return; activeL1 = controller.languageController.activeL1Model()!; - activeL2 = - controller.languageController.activeL2Model(roomID: widget.room.id)!; + activeL2 = controller.languageController.activeL2Model()!; if (activeL1 == null || activeL2 == null) { wordNetError = noLanguages; definitionError = noLanguages; diff --git a/needed-translations.txt b/needed-translations.txt index 928fa5052..a2d9d0330 100644 --- a/needed-translations.txt +++ b/needed-translations.txt @@ -852,7 +852,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "be": [ @@ -2341,7 +2343,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "bn": [ @@ -3826,7 +3830,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "bo": [ @@ -5315,7 +5321,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ca": [ @@ -6206,7 +6214,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "cs": [ @@ -7179,7 +7189,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "de": [ @@ -8035,7 +8047,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "el": [ @@ -9475,7 +9489,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "eo": [ @@ -10613,11 +10629,15 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "es": [ - "searchIn" + "searchIn", + "suggestToSpace", + "suggestToSpaceDesc" ], "et": [ @@ -11473,7 +11493,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "eu": [ @@ -12331,7 +12353,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "fa": [ @@ -13326,7 +13350,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "fi": [ @@ -14285,7 +14311,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "fil": [ @@ -15600,7 +15628,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "fr": [ @@ -16594,7 +16624,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ga": [ @@ -17717,7 +17749,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "gl": [ @@ -18573,7 +18607,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "he": [ @@ -19815,7 +19851,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "hi": [ @@ -21297,7 +21335,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "hr": [ @@ -22232,7 +22272,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "hu": [ @@ -23104,7 +23146,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ia": [ @@ -24579,7 +24623,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "id": [ @@ -25441,7 +25487,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ie": [ @@ -26687,7 +26735,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "it": [ @@ -27600,7 +27650,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ja": [ @@ -28624,7 +28676,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ka": [ @@ -29967,7 +30021,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ko": [ @@ -30825,7 +30881,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "lt": [ @@ -31849,7 +31907,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "lv": [ @@ -32713,7 +32773,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "nb": [ @@ -33901,7 +33963,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "nl": [ @@ -34853,7 +34917,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "pl": [ @@ -35814,7 +35880,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "pt": [ @@ -37281,7 +37349,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "pt_BR": [ @@ -38143,7 +38213,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "pt_PT": [ @@ -39332,7 +39404,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ro": [ @@ -40328,7 +40402,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ru": [ @@ -41190,7 +41266,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "sk": [ @@ -42445,7 +42523,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "sl": [ @@ -43830,7 +43910,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "sr": [ @@ -44989,7 +45071,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "sv": [ @@ -45882,7 +45966,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "ta": [ @@ -47368,7 +47454,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "th": [ @@ -48808,7 +48896,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "tr": [ @@ -49664,7 +49754,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "uk": [ @@ -50557,7 +50649,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "vi": [ @@ -51898,7 +51992,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "zh": [ @@ -52754,7 +52850,9 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ], "zh_Hant": [ @@ -53891,6 +53989,8 @@ "addChatToSpaceDesc", "addSpaceToSpaceDesc", "spaceAnalytics", - "changeAnalyticsLanguage" + "changeAnalyticsLanguage", + "suggestToSpace", + "suggestToSpaceDesc" ] }