Swift + Strings Organization and Good Practices
A good method to organize strings with different purposes on you iOS projects.
When we are starting a new project is very common to be asking your self about how your project is organized. You are always trying to figure out if you are using the best architecture, best folder hierarchy…(well, it always happens to me at least).
One of the things that I used to ask my self often was if I used to organize strings with different purposes inside my projects properly.
“Should I create one constant for each string inside the class where this string will be used?”
“Should I create one class/struct where all the string constants will be available inside the app?”
And many other options…
…At this point you might be trying to understand why I wrote “strings with different purposes”…so let me explain it better.
Every text used inside an app are stored in a string variable or constant, but not all the strings from a app are used at the same moment or at the same View. Other strings might be use internally, or must be read by the VoiceOver when you are working with accessibility.
Would be a wise choise to organize these strings in order to help you to find each one easily over your project right?
After trying many solutions I finally decided the method I liked more…LocalizableStrings
“But why, how?”, you might be thinking…well, there are two simple reasons, which are:
- Organization - Using LocalizableStrings you will keep your code clean;
- Scalability - While your app grows, you will be thankful for keeping your strings in a single place;
“All right, all right, but finally how do I do this?”
Straight to the point…
Imagine that you are working in a project that implements accessibility features, and you have a few labels inside a ViewController that must be read by the VoiceOver properly, but the text that will be read must be different from the one presented by the label.
“I would point different string variables for each purpose inside de Controller”
Oh really? what if I tell you that there is a better approach to achieve such thing…
To solve the problem of the previous example you must create two LocalizableString tables somewhere on your project, name it (imagine that you are working in a login feature):
- LoginStrings.strings (Give it a good name)
- LoginAccessibilityStrings.strings (Awful name isn’t it?)
Good, next step is to move all the strings you just created to the respective string table, see:
Good, now we need to create the code that will represent the interface between every string table on the project with your code.
To achieve this you need to create a few swift files:
- LoginStrings.swift
- LoginAccessibilityStrings.swift
- FeatureKind.swift
LoginStrings and LoginAccessibilityStrings are enums that will hold cases for each item on the string tables.
You may notice that both enums have a function called localized, this function is responsible for returning the localized string from a given case if it exists on the string table.
We also have the enum FeatureKind, that will be used to point out which string table should be used, see the code bellow:
I believe that at this point your code must be popping error:
Yeah, I know.
This is happening because this implementation still need some piece, so please we need to create a new swift file called String+Localizable.swift, wewill implement a extension function also called localized:
As you may notice, this function is responsible for receive a string and return the respective localized matching in a string table.
“Oh man, this harder than I thought”
No this is not, you still have to do a small update on your ViewController, it should look like this:
Now we are done, you may run you app and everything should be fine.
After all this code the point is, now your project owns specific locations for each string purpose on your app, as your project evolves any new developer will easily understand where to place or find strings, and the code keeps a single and uniform string handler system.
See the full sample at: https://github.com/pericles-jr/SampleLocalizedStrings