diff --git a/Riot.xcodeproj/project.pbxproj b/Riot.xcodeproj/project.pbxproj index 8764ae962..ac5bd0b55 100644 --- a/Riot.xcodeproj/project.pbxproj +++ b/Riot.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 3205ED851E97725E003D65FA /* DirectoryServerTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3205ED831E97725E003D65FA /* DirectoryServerTableViewCell.xib */; }; 321082B21F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 321082B01F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.m */; }; 321082B31F0E9F41002E0091 /* RoomMembershipCollapsedBubbleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 321082B11F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.xib */; }; + 32185B311F20FA2B00752141 /* LanguagePickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32185B301F20FA2B00752141 /* LanguagePickerViewController.m */; }; 322806A01F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3228069E1F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.m */; }; 322806A11F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3228069F1F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.xib */; }; 32471CDC1F1373A100BDF50A /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 32471CDA1F1373A100BDF50A /* RoomMembershipCollapsedWithPaginationTitleBubbleCell.m */; }; @@ -499,6 +500,8 @@ 321082AF1F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMembershipCollapsedBubbleCell.h; sourceTree = ""; }; 321082B01F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMembershipCollapsedBubbleCell.m; sourceTree = ""; }; 321082B11F0E9F40002E0091 /* RoomMembershipCollapsedBubbleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomMembershipCollapsedBubbleCell.xib; sourceTree = ""; }; + 32185B2F1F20FA2B00752141 /* LanguagePickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LanguagePickerViewController.h; sourceTree = ""; }; + 32185B301F20FA2B00752141 /* LanguagePickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LanguagePickerViewController.m; sourceTree = ""; }; 3228069D1F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoomMembershipExpandedBubbleCell.h; sourceTree = ""; }; 3228069E1F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoomMembershipExpandedBubbleCell.m; sourceTree = ""; }; 3228069F1F0F64C4008C53D7 /* RoomMembershipExpandedBubbleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RoomMembershipExpandedBubbleCell.xib; sourceTree = ""; }; @@ -1599,6 +1602,8 @@ F083BC2F1E7009EC00A9B29C /* HomeMessagesSearchViewController.m */, F083BC301E7009EC00A9B29C /* HomeViewController.h */, F083BC311E7009EC00A9B29C /* HomeViewController.m */, + 32185B2F1F20FA2B00752141 /* LanguagePickerViewController.h */, + 32185B301F20FA2B00752141 /* LanguagePickerViewController.m */, F083BC321E7009EC00A9B29C /* MediaAlbumContentViewController.h */, F083BC331E7009EC00A9B29C /* MediaAlbumContentViewController.m */, F083BC341E7009EC00A9B29C /* MediaAlbumContentViewController.xib */, @@ -2565,6 +2570,7 @@ F083BE7E1E7009ED00A9B29C /* InviteRecentTableViewCell.m in Sources */, F083BE3C1E7009ED00A9B29C /* RoomIncomingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */, F083BE211E7009ED00A9B29C /* RoomSearchViewController.m in Sources */, + 32185B311F20FA2B00752141 /* LanguagePickerViewController.m in Sources */, F083BE3E1E7009ED00A9B29C /* RoomIncomingEncryptedAttachmentWithPaginationTitleBubbleCell.m in Sources */, F083BE071E7009ED00A9B29C /* AttachmentsViewController.m in Sources */, F083BE051E7009ED00A9B29C /* RiotDesignValues.m in Sources */, diff --git a/Riot/AppDelegate.m b/Riot/AppDelegate.m index ee993eec6..5a033cba6 100644 --- a/Riot/AppDelegate.m +++ b/Riot/AppDelegate.m @@ -291,7 +291,12 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN NSLog(@"MatrixSDK version: %@", MatrixSDKVersion); NSLog(@"Build: %@\n", build); NSLog(@"------------------------------\n"); - + + // Set up runtime language and fallback + NSString *langage = [[NSUserDefaults standardUserDefaults] objectForKey:@"appLanguage"];; + [NSBundle mxk_setLanguage:langage]; + [NSBundle mxk_setFallbackLanguage:@"en"]; + // Define the navigation bar text color [[UINavigationBar appearance] setTintColor:kRiotColorGreen]; diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index c137f8e6c..aedca653b 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -329,6 +329,7 @@ //"settings_join_leave_rooms" = "When people join or leave rooms"; //"settings_call_invitations" = "Call invitations"; +"settings_ui_language" = "Language"; "settings_ui_light_theme" = "Light theme"; "settings_ui_dark_theme" = "Dark theme"; diff --git a/Riot/ViewController/BugReportViewController.m b/Riot/ViewController/BugReportViewController.m index b9087d541..fb38f491e 100644 --- a/Riot/ViewController/BugReportViewController.m +++ b/Riot/ViewController/BugReportViewController.m @@ -237,7 +237,8 @@ } userInfo[@"locale"] = [NSLocale preferredLanguages][0]; - userInfo[@"app_language"] = [[NSBundle mainBundle] preferredLocalizations][0]; + userInfo[@"default_app_language"] = [[NSBundle mainBundle] preferredLocalizations][0]; // The language chosen by the OS + userInfo[@"app_language"] = [NSBundle mxk_language] ? [NSBundle mxk_language] : userInfo[@"default_app_language"]; // The language chosen by the user bugReportRestClient.others = userInfo; diff --git a/Riot/ViewController/LanguagePickerViewController.h b/Riot/ViewController/LanguagePickerViewController.h new file mode 100644 index 000000000..0e65d0494 --- /dev/null +++ b/Riot/ViewController/LanguagePickerViewController.h @@ -0,0 +1,21 @@ +/* + Copyright 2017 Vector Creations Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +@interface LanguagePickerViewController : MXKLanguagePickerViewController + +@end diff --git a/Riot/ViewController/LanguagePickerViewController.m b/Riot/ViewController/LanguagePickerViewController.m new file mode 100644 index 000000000..dfa4ec293 --- /dev/null +++ b/Riot/ViewController/LanguagePickerViewController.m @@ -0,0 +1,54 @@ +/* + Copyright 2017 Vector Creations Ltd + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "LanguagePickerViewController.h" + +#import "AppDelegate.h" + +@implementation LanguagePickerViewController + +- (void)finalizeInit +{ + [super finalizeInit]; + + // Setup `MXKViewControllerHandling` properties + self.defaultBarTintColor = kRiotNavBarTintColor; + self.enableBarTintColorStatusChange = NO; + self.rageShakeManager = [RageShakeManager sharedManager]; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + // Hide line separators of empty cells + self.tableView.tableFooterView = [[UIView alloc] init]; +} + +- (void)viewWillAppear:(BOOL)animated +{ + [super viewWillAppear:animated]; + + // Screen tracking (via Google Analytics) + id tracker = [[GAI sharedInstance] defaultTracker]; + if (tracker) + { + [tracker set:kGAIScreenName value:@"CountryPicker"]; + [tracker send:[[GAIDictionaryBuilder createScreenView] build]]; + } +} + +@end diff --git a/Riot/ViewController/SettingsViewController.h b/Riot/ViewController/SettingsViewController.h index f4c06b888..6713cb94d 100644 --- a/Riot/ViewController/SettingsViewController.h +++ b/Riot/ViewController/SettingsViewController.h @@ -21,7 +21,7 @@ #import "MediaPickerViewController.h" #import "TableViewCellWithCheckBoxes.h" -@interface SettingsViewController : MXKTableViewController +@interface SettingsViewController : MXKTableViewController @end diff --git a/Riot/ViewController/SettingsViewController.m b/Riot/ViewController/SettingsViewController.m index a1f8da2d5..72ac1313f 100644 --- a/Riot/ViewController/SettingsViewController.m +++ b/Riot/ViewController/SettingsViewController.m @@ -29,6 +29,7 @@ #import "BugReportViewController.h" #import "CountryPickerViewController.h" +#import "LanguagePickerViewController.h" #import "TableViewCellWithPhoneNumberTextField.h" #import "NBPhoneNumberUtil.h" @@ -71,7 +72,8 @@ enum enum { - USER_INTERFACE_THEME_INDEX = 0, + USER_INTERFACE_LANGUAGE_INDEX = 0, + USER_INTERFACE_THEME_INDEX, USER_INTERFACE_COUNT }; @@ -1565,7 +1567,26 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } else if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX) { - if (row == USER_INTERFACE_THEME_INDEX) + if (row == USER_INTERFACE_LANGUAGE_INDEX) + { + cell = [tableView dequeueReusableCellWithIdentifier:kSettingsViewControllerPhoneBookCountryCellId]; + if (!cell) + { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kSettingsViewControllerPhoneBookCountryCellId]; + } + + NSString *language = [NSBundle mxk_language]; + NSString *languageDescription = language ? [MXKLanguagePickerViewController languageDescription:language] : [MXKLanguagePickerViewController languageDescription:[MXKLanguagePickerViewController defaultLanguage]]; + + cell.textLabel.textColor = kRiotTextColorBlack; + + cell.textLabel.text = NSLocalizedStringFromTable(@"settings_ui_language", @"Vector", nil); + cell.detailTextLabel.text = languageDescription; + + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + cell.selectionStyle = UITableViewCellSelectionStyleDefault; + } + else if (row == USER_INTERFACE_THEME_INDEX) { uiThemeCell = [tableView dequeueReusableCellWithIdentifier:[TableViewCellWithCheckBoxes defaultReuseIdentifier] forIndexPath:indexPath]; @@ -2057,7 +2078,18 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); NSInteger section = indexPath.section; NSInteger row = indexPath.row; - if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX) + if (section == SETTINGS_SECTION_USER_INTERFACE_INDEX) + { + if (row == USER_INTERFACE_LANGUAGE_INDEX) + { + // Display the language picker + LanguagePickerViewController *languagePickerViewController = [LanguagePickerViewController languagePickerViewController]; + languagePickerViewController.selectedLanguage = [NSBundle mxk_language]; + languagePickerViewController.delegate = self; + [self pushViewController:languagePickerViewController]; + } + } + else if (section == SETTINGS_SECTION_IGNORED_USERS_INDEX) { MXSession* session = [[AppDelegate theDelegate].mxSessions objectAtIndex:0]; @@ -3481,6 +3513,30 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); [countryPickerViewController withdrawViewControllerAnimated:YES completion:nil]; } +#pragma mark - MXKCountryPickerViewControllerDelegate + +- (void)languagePickerViewController:(MXKLanguagePickerViewController *)languagePickerViewController didSelectLangugage:(NSString *)language +{ + [languagePickerViewController withdrawViewControllerAnimated:YES completion:nil]; + + if (![language isEqualToString:[NSBundle mxk_language]] + || (language == nil && [NSBundle mxk_language])) + { + [NSBundle mxk_setLanguage:language]; + + // Store user settings + [[NSUserDefaults standardUserDefaults] setObject:language forKey:@"appLanguage"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + // Do a full sync to recompute matrix data (rooms data sources and summaries) + [self startActivityIndicator]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ + + [[AppDelegate theDelegate] reloadMatrixSessions:NO]; + }); + } +} + #pragma mark - TableViewCellWithCheckBoxesDelegate - (void)tableViewCellWithCheckBoxes:(TableViewCellWithCheckBoxes *)tableViewCellWithCheckBoxes didTapOnCheckBoxAtIndex:(NSUInteger)index