Changing app language on the fly in iOS - swift

I am new to iOS and I know this is a very frequently asked question, but I have found no appropriate answer for my query.
I have added text to controls on the app like this
let productDescriptionCell = tableView.dequeueReusableCellWithIdentifier("textDescriptionCell") as! TextDescriptionCell
productDescriptionCell.labelForCell.text = "Description"
productDescriptionCell.labelForCell.sizeToFit()
productDescriptionCell.labelForCell.adjustsFontSizeToFitWidth = true
like the 'Description' text above.
I want to have a button in my app, which lets the user change the language on the fly. I have found the following code as the most relevant but this requires an app restart.
userDefaults.setObject(["\(cc)"], forKey: "AppleLanguages")
userDefaults.synchronize()
In addition, I have text hard coded in my storyboard controllers, I want those localized as well. How can I achieve this?
Thai and English are the languages I need localization for
productTitleCell.textFieldForCell.placeholder = SpecProvider.spec.localizedTuv(createLocalizedString("en", tuvEnglish: "Enter Title", tuvThai: "ป้อนชื่อ"))
func localizedTuv(localizedString: LocalizedString) -> String {
var locale = LocaleSelectionService.sharedInstance.getCachedLocale()
if locale.isEmpty {
locale = ""
}
switch(locale) {
case "en": return localizedString.getTuvEnglish()
case "th": return localizedString.getTuvThai()
default: return localizedString.getTuvEnglish()
}
}
I have tried the above code, but this could get very tedious. Please help, I am really stuck!

You have to create string files, and add the labels for every language you want to support. Once this is done you can use NSLocalizedString for the text used in your ViewController.
Here's a tutorial http://www.raywenderlich.com/64401/internationalization-tutorial-for-ios-2014

Related

Shortcut/Action on Siri Watch Face with independent WatchOS app

I'm relatively new to making apps, and even newer to independent watch apps. As training, I'm making a watch app that I can use to log my water intake throughout the day. I've created a new intent definition file (see image 1) on which I've checked the marks for all the target memberships (the app, the WatchKit app, and the WatchKit extension). Furthermore, the target membership class is a public intent for the WatchKit extension.
When logging my water I execute the following code:
let intent = INManager.intent(drink: item)
INManager.donateShortcuts(withIntent: intent)
and my IntentManager looks like this:
import Foundation
import Intents
class IntentManager {
func intent(drink: Drink) -> LogDrinkIntent {
let intent = LogDrinkIntent()
intent.uuid = drink.id.uuidString
intent.name = drink.name
intent.emoji = drink.emoji
return intent
}
func donateShortcuts(withIntent intent:INIntent) {
var relevantShortcuts: [INRelevantShortcut] = []
if let relevantShortcut = defaultRelevantShortcut(withIntent: intent) {
relevantShortcuts.append(relevantShortcut)
}
INRelevantShortcutStore.default.setRelevantShortcuts(relevantShortcuts) { (error) in
if let error = error {
print("Failed to set relevant shortcuts: \(error))")
} else {
print("Relevant shortcuts set.")
}
}
}
private func defaultRelevantShortcut(withIntent intent: INIntent) -> INRelevantShortcut? {
if let shortcut = INShortcut(intent: intent) {
let relevantShortcut = INRelevantShortcut(shortcut: shortcut)
relevantShortcut.shortcutRole = .action
let template = INDefaultCardTemplate(title: "Log Drink")
relevantShortcut.watchTemplate = template
print("Returning relevant shortcut.")
return relevantShortcut
}
return nil
}
}
When logging a drink the confirmation Returning relevant shortcut. and Relevant shortcuts set. are printed. However, the Siri watch face doesn't update to include a link to my action. I got the code for the IntentManager from this Medium article.
I really appreciate your time and help. I've had a hard time trying to find any details about this functionality and Apple's documentation is imo inferior. Thank you! If you need more details or such, feel free to ask.
Image 1
Let's saddle the horse from behind: Generally speaking, you want to make use of Soup Chef. Now you can categorize Siri suggestions into two sub-groups, being donated shortcuts and relevant shortcuts.
In your specific example of a "water intake" logging app, you should work with donating the INIntent to INIteraction. The reason for that is quite simple: Your suggestion is due to an action a user has committed within your application, not based upon plainly relevance, thus your passage about INRelevantShortcutStore isn't necessary and/or should be replaced with INInteraction.
To re-phrase myself: The issue is that you parse INRelevantShortcutStore as a donation, see here:
func donateShortcuts(withIntent intent:INIntent) {
var relevantShortcuts: [INRelevantShortcut] = []
if let relevantShortcut = defaultRelevantShortcut(withIntent: intent) {
relevantShortcuts.append(relevantShortcut)
}
INRelevantShortcutStore.default.setRelevantShortcuts(relevantShortcuts) { (error) in
if let error = error {
print("Failed to set relevant shortcuts: \(error))")
} else {
print("Relevant shortcuts set.")
}
}
}
... as explained above, that is not the correct usage for INIntent in your specific example.
I highly suggest to read through Soup Chef in general as well as specifically donating shortcuts to Siri (what you want to do!). The documentation is very detailed and explanative!

Different voices in Text to Speech iOS app

I have a Text to Speech App and all is good, but I was looking for a voice.
In Settings/Accessibility/Voice Over/Speech/Voice there is a list of voices. I wanted to select one of those, for example "Susan (Enhanced)". How would I go about doing that?
I am new to Text to Speech and AVSpeechSynthesizer so I was hoping for some advice how to select that voice?
When I try it in General/Settings it sounds good, but when I select, what I thought was that voice it in my App, it sounds different. This happens with all of the voices I tried.
Here is the code I used to speak the text:
for voice in AVSpeechSynthesisVoice.speechVoices()
{
print("\(voice.name)")
if voice.name == "Susan (Enhanced)" {
self.voiceToUse = voice
}
}
let textToSpeak = self.tvTextToSpeak.text
if (!textToSpeak!.isEmpty)
{
let speechSynthesizer = AVSpeechSynthesizer()
let speechUtterance: AVSpeechUtterance = AVSpeechUtterance(string: textToSpeak!)
speechUtterance.voice = self.voiceToUse
speechSynthesizer.speak(speechUtterance)
}
So if I use the same text as the example in the iOS settings it sounds different in my App, why?
Is it something I need to do?
Are those voices special?
Does it have to do with the utterance, I have not set that.
Thanks for any clarification.

Swift UITest - No match found for textField with accessibility identifier

Trying to create a UITest for entering an email address/password into text fields and then hitting a login button. Using Xcode.
I watch the UITest navigate to the proper page, but it does not detect the text fields. I made sure that both text fields have the "Accessibility" box checked, and I've given them identifiers.
I'm getting this error:
UI Testing Failure - No matches found for text field
func testExample() {
let app = XCUIApplication()
//Test login page
app.buttons["loginButton"].tap()
//Here it navigates to the desired page
let emailField = app.textFields["email"]
emailField.tap()
emailField.typeText("xxx.xx.edu")
let passwordField = app.textFields["password"]
passwordField.tap()
passwordField.typeText("xxx")
app.buttons["loginButton"].tap()
// let loginAlert = app.alerts["alertVC"]
// XCTAssertEqual(loginAlert.title, "Error")
}
The accessibility indicators are "email" and "password" respectively. Logging in works fine when I run the simulator myself.
EDIT: Apparently there are no text fields at all (count = 0) even though I see them and use them on the page...
Image of storyboard with text fields:
If UITextFiled set SecureTextEntry true, you should use:
let passwordField = app.secureTextFields["password"]
I was having the same problem and I solved by unchecking the "accessibility enabled" box for the "views" of ViewControllers

Localization the Navigation Bar Title in swift

I write navigation bar title in Attributes inspector. I would like to translate that title when I switch to other language.
self.navigationItem.title = NSLocalizedString("Login", comment: "")
I write it in override func viewDidLoad().
I took navigation item Object ID "S3Z-Mr-Qda" and translate it in Main.strings file.
/* Class = "UINavigationItem"; text = "Package History"; ObjectID = "S3Z-Mr-Qda"; */
"S3Z-Mr-Qda.text" = "Login";
However, it does not change at all and how to implement it in swift?
You can actually provide a translation to the title using that method.
The only thing that you did wrong was setting the property "text". As you can see in the code version, a navigationItem has a title property instead of text.
This would work:
"S3Z-Mr-Qda.title" = "Login";
I think you should put your translation inside a generic
Localizable.strings file instead of the storyboard translation file.
Then use your same code to load the title text:
self.navigationItem.title = NSLocalizedString("Login", comment: "")
Take a look at the official doc in order to create this kind of file:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html

AppleWatch Speech-to-Text functionality not working

I am trying to implement Speech-to-text feature for watchkit app.
I referred this question which has sample code.
Following is the code I tried:
self.presentTextInputControllerWithSuggestions(["Start it", "Stop it"], allowedInputMode: .Plain, completion: { (selectedAnswers) -> Void in
if selectedAnswers.count > 0 {
if let spokenReply = selectedAnswers[0] as? String {
self.label.setText("\(spokenReply)")
}
}
})
label is a label to display text I speak.
When I run it, it shows the screen where you are supposed to speak (Siri kind of screen) and you have two options on top: ‘Cancel', and ‘Done'. Once I am done speaking, I tap on ‘Done’ but screen doesn’t go away or shows me initial screen, I always have to tap on ‘Cancel’ to go back, and I don’t get any speech data in form of text. I checked it and seems like selectedAnswers is always an empty array, unless I tap on the "Start it"/"Stop it" options.
Can anyone help me with this? I want to show the spoken message on label. I have code inside awakeWithContext method in InterfaceController.swift file, am I supposed to put it somewhere else?
I am using iPhone with iOS 9 beta 2 and watchOS 2 beta on AppleWatch.
Thanks!
You can ask for user input and give him suggestion (see Swift example bellow).
self.presentTextInputControllerWithSuggestions(["suggestion 1", "suggestion 2"] allowedInputMode: .Plain, completion: { (answers) -> Void in
if answers && answers.count > 0 {
if let answer = answers[0] as? String {
println("\answer")
}
}
})
If suggestion is nil it goes directly to dictation. It is not working on the simulator but it is on real watch.
Your approach is correct but something is wrong with your SIRI , try changing the language.
It should work like these.