How change app language in real time? - ios

I am working on an app which runs in 2 languages, English and Persian (farsi). So user can select his desired language and app is displayed in that language. What should I do?

Depends on what are your trying to achieve, there is an approach that might be useful to your case, which is:
Declare a global variable which should represents the key of the current used language in the app, call it appLanguageKey String -for example-:
var appLanguageKey = "english"
Create a datastore for storing both languages desired caption for each term, it might looks like (contains):
term_key term_english term_farsi
greeting_key Hello Hoi
bye_key Bye Doei
For now, you could get the desired value if you tried to do:
desiredTerm = "select term_\(appLanguageKey) where term_key = 'greeting_key'"
Consider it as pseudo-code, the condition should be similar to it.
By implementing such a function that returns a string (I will assume that it is: getDesiredCaption(_ termKey: String) -> String in the following code snippet), you will be able to automatically set the desired caption for any UI component, just call it in viewWillAppear method the view controller:
override func viewWillAppear(_ animated: Bool) {
.
.
.
label.text = getDesiredCaption("greeting_key")
// Since that 'appLanguageKey' global viriable is "english",
// the output should be "Hello"
.
.
.
}
All you have to do for changing the language of the app is to change the value of appLanguageKey to "farsi".
For another approach which related to the Internationalization and Localization, you might want to check this answer, it should affect the app to let its navigation to be from right to left.
Hope this helped.

First you should use realm, magical records or an API to store what the user picks. Then you could create your own type of localizeable string handeler, by having an array with 2 dictionaries 1 with english and 1 with persian that all the texts in your application will read from just as you do with a normal localizeable.

Related

How to get te text of a textfield from inside a function?

I want to make an app that has 2 textfields, 4 buttons and a Text view. 1 button that clears the content of the first textfield and another button that inputs the current time rounded to the nearest 4 and the Text view to display the total time in minutes. Same with the other textfield. It's an app to calculate the total time spent on something in minutes.
I also want to limit the amount of possible insertable characters to 5 as a time has a maximum of 5 characters as in "15:00". I have been able to make an observable object:
class TextFieldManager: ObservableObject {
let characterLimit = 5
#Published var userInput = "" {
didSet {
// Limit the max length of the field
if userInput.count > characterLimit {
userInput = String(userInput.prefix(characterLimit))
} else if userInput.count >= 4 {
// call the setTotalTime func or something to set totalTime
}
}
}
}
which works really well.
I am also able to clear the textfield and set the current time rounded to the nearest 5, but i am unable to limit the characters to 5 AND have the buttons do something at the same time.
So right now it's either being able to:
- Limit characters to a maximum of 5
OR being able to:
clear textfield with a button
input time now rounded to nearest 5 into textfield with a button.
If i go with the observable object method, when i have this above the body block of my ContentView:
#ObservedObject var startTimeManager = TextFieldManager()
#ObservedObject var endTimeManager = TextFieldManager()
and this inside the body for the textfields:
TextField("hh:mm", text: $startTimeManager.userInput)
TextField("hh:mm", text: $endTimeManager.userInput)
and the TextFieldManager class as shown above, than now i don't know how to get the value of the Textfield anymore.
If inside the input the current time button i try to set the time by doing
$startTimeManager.userInput = "whatever the current time is"
i get an error saying that i can't change the value of a binding<String> type something something. Likewise i also can't clear the textfield in the same way.
Also i would like to call a function inside this part:
} else if userInput.count >= characterLimit {
// call the setTotalTime func or something to set totalTime
}
I have a Functions.swift file where both the TextFieldManager class is and my function that i want to call, but if i try to call a function inside here, it says that the function doesn't exist? And inside the function i again would like to have access to the textfield values at the time of the call, but i don't know how to read the value of the textfields from inside the function.
I hope i am making sense and that someone is able to help me, or point me in the right direction. I made the same app for android (android studio), windows (python3) and Mac (python3), but this iphone and Xcode thing really doesn't want to work. I have watched a bunch of tutorial videos and guides, but none are trying to do what i am trying to do. Like i said i can get either to work, but never together and in both cases i am unable to somehow access the textfield values inside the function. I feel like i should be so close, but something is not coming together for me in my head.
Also while i'm at it, in Python 3 to catch all errors and let them pass silently i can do:
Try:
break_my_stuff = int("Break my stuff)"
ignore_some_more_stuff = int("ignore some more stuff)"
etc.
etc.
except Exception:
# catch silently and do nothing
pass
Is there something similar in swift, because
do {
breakMyStuff = whatever might make something break in swift
ignoreSomeMoreStuff = whatever might make something break in swift
etc.
etc.
} catch {
// do nothing and pass silently
}
doesn't work because it needs something to try and i wasn't able to try a complete section like i can with Python.
If inside the input the current time button i try to set the time by doing
$startTimeManager.userInput = "whatever the current time is"
you don't need binding in this case, just assign property in regular way
self.startTimeManager.userInput = "whatever the current time is"

ios application Localization

How can I set ios application supported languages?
e.g I use NSDate to get current day. If the device language is other than my supported languages NSDateFormatter returns "day" in device's language but I want to get in English if I don't support that language.
I know there is a way to get day in specific language using NSLocal but I don't want to do that way because I need to convert other strings as well.
The Apple documentation covers this pretty clearly. I know all you need is the word "day", but the following will help you include any word for any language if you do as follows:
1) You need to place all of the words (Strings) in your application into a single .swift file. Each word should be returned in a function that converts this string into the localized string per the device's NSLocal set in the device settings:
struct Localization {
static let all: String = {
return getLocalized("All")
}()
static let allMedia: String = {
return getLocalized("All Media")
}()
static let back: String = {
return getLocalized("Back")
}()
// ...and do this for each string
}
2) This file should also contain a static function that will convert the string:
static func getLocalized(_ string: String) -> String {
return NSLocalizedString(string, comment: "")
}
Here, the NSLocalizedString( method will do all of the heavy lifting for you. If will look into the .XLIFF file (we will get to that) in your project and grab the correct string per the device NSLocale. This method also includes a "comment" to tell the language translator what to do with the "string" parameter you passed along with it.
3) Reviewing all of the strings that you placed in your .swift file, you need to include each of those into an .XLIFF file. This is the file that a language expert will need to go over and include the proper translated word per string in the .XLIFF. As I stated before, this is the file that once included inside your project, the NSLocalizedString( method will search this file and grab the correct translated string for you.
And that's it!

how do you iterate through elements in UI testing in Swift/iOS?

I understand how I could, for example look at one element in a table, but what's the correct way to simply iterate through all the elements, however many are found, to for example tap on them?
let indexFromTheQuery = tables.staticTexts.elementBoundByIndex(2)
Okay I succeeded in figuring out the simple syntax. I have just started working with Swift and so it took me sleeping on it to think of the answer.
This code works:
var elementLabels = [String]()
for i in 0..<tables.staticTexts.count {
elementLabels.append (tables.staticTexts.elementBoundByIndex(i).label)
}
print (elementLabels)
My guess is the answer is there is no way to do so.
The reason is because of my experience with one of the critical iOS components while making a number of UI tests: UIDatePicker.
If you record a test where you get the page up and then you spin the picker, you will notice that the commands are all non-specific and are screen related. In the case of the picker, however, community requests resulted in the addition of a method for doing tests: How to select a picker view item in an iOS UI test in Xcode?.
Maybe you can add a helper method to whatever controller contains this table. Also, keep in mind that you can easily add methods without polluting the class interface by defining them as extensions that are in test scope only.
For Xcode 11.2.1, SwiftUI and swift 5 based app, the following code works for testing a list, each element in this case appears as a button in the test code. The table is set up like this (for each row) :
NavigationLink(destination: TopicDetail(name: "Topic name", longDesc: "A description")) {
TopicRow(thisTopic: top).accessibility(identifier: "newTopicRow_\(top.name!)")
}
Then I catch the members of the table by getting the buttons into an array:
let myTable = app.tables.matching(identifier: "newTopicTable")
var elementLabels = [String]()
for i in 0..<myTable.buttons.count {
elementLabels.append (tablesQuery.buttons.element(boundBy: i).label)
}
print (elementLabels)
Finally, I deleted each member of the table by selecting the detail view where I have a delete button, again with
.accessibility(identifier: "deleteTopic"
I wanted to delete all members of the table:
for topicLabel in elementLabels {
let myButton = app.buttons[topicLabel]
myButton.firstMatch.tap()
app.buttons["deleteTopic"].tap()
}

Objective-C iOS parse string according to the definition

I want create an iOS app for my school.
This App will show Week schledule and when I tap on Cell with Subject, it will show me detail info about subject...
My problem:
Our teachers use shotcuts for their names, but I want show their full name... I created the file "ucitele.h" with definitions of their names, but I don't know, how to use it 😕.
This is how that file looks:
//
// ucitele.h
//
#define Li #"RNDr. Dan---vá"
#define He #"Mgr. Ja---hl"
#define Sm #"Ing. Mich---rek"
#define Ks #"Mgr. Svat---á"
I get the shortcut of Teacher from previous view from "self.ucitel" and I maybe want compare the contents of the "self.ucitel" with definitions and set the "ucitelFull" string from the definitions? I don't know how to say it 😕.
when the content of the self.ucitel will be #"Sm", than I want parse "ucitelFull" as #"Ing. Mich---rek"
Answers in Objective-C only please
Okay, sounds like your trying to map a short identifier to a full name:
-(NSString*)fullNameFromShortName:(NSString*)short {
NSDictionary * names = #{#"Li" : #"RNDr. Dan---vá",
#"He" : #"Mgr. Ja---hl", ... };
return [names objectForKey:short];
}
Use like:
self.ucitelFull = [self fullNameFromShortName:self.ucitel];
This is a dictionary that has the short name as a key and the full name as the value.
Some further suggestions:
try using lowercase keys and comparing lowercaseString's, incase the user doesn't enter the value with the correct case.
You can move the dictionary definition into a json file and read it from your bundle, to eliminate the hardcoding

TAction.SecondaryShortCuts is language specific. How to set it correctly?

I just used the SecondaryShortCuts-Feature of Delphi's TAction. But Shortcuts are defined by Strings, like "F5" or "Shift+F5". Now the problem: On my German Windows the action doesn't fire, because the key "Shift" is called "Umsch" in German!
Does it mean the SecondaryShortCuts-Property is completely useless at design time, because nobody can create applications which work internationally with that?
I could set the key at runtime by translating the VK_SHIFT into the correct name. I tried it via GetKeyNameText but this didn't worked because it gave the long form "Umschalt" not "Umsch". Anybody know the function to get the short version of the key name?
You could try this: Generate the shortcut text from a shortcut:
var
s: TShortCut;
begin
s := ShortCut(Ord('A'), [ssShift]);
Action1.SecondaryShortCuts.Add(ShortCutToText(s));
By the way, these values are determined by the following constants. Have you translated those? And if so, do you need to?:
SmkcShift = 'Shift+';
SmkcCtrl = 'Ctrl+';
SmkcAlt = 'Alt+';

Resources