Tab bar item localization

Hi,

Code Block
tabBarItem.title = "LevelsVC-TabBarItem".localize()

with tabBarItem.title i'm able to localize title when it is in viewDidLoad or viewWillappear but the localization will only happen when the tab becomes actives, otherwise it will show default value.

How could I localize, programmatically, the item title without the need to make it active?
Answered by OOPer in 675439022

Here is an example. LevelsViewController is a view controller that is displayed when tapping a tab bar item.

UITabBarController collects tabBarItems of the content view controllers just after they are initialized.
It is too late in viewDidLoad or viewWillAppear.

Try something like this:
Code Block
override func awakeFromNib() {
super.awakeFromNib()
tabBarItem.title = "LevelsVC-TabBarItem".localize()
}

Or
Code Block
required init?(coder: NSCoder) {
super.init(coder: coder)
tabBarItem.title = "LevelsVC-TabBarItem"//.localize()
}

In this scenario, you have no need to subclass UITabBarController.
Did you declare the translation in a localisation file Main.strings ?
If so, localisation will be automatic when view loads.
I haven't created a Main.strings.
Is there anyway to translate those tab bar title without Main.strings?
It is so easy to do it with the basic mechanisms, why do differently ?

I don't see how you manage your localisation in your app.
  • what is localise() func ?

  • in which class do you do this ?

with tabBarItem.title i'm able to localize title when it is in viewDidLoad or viewWillappear


The extension of string is like so:


Code Block
extension String {
  func localize() -> String {
    return NSLocalizedString(
      self,
      tableName: "Localizable",
      bundle: .main,
      value: self,
      comment: self)
  }
   
  public func localize(with arguments: [CVarArg]) -> String {
    return String(format: self.localize(), locale: nil, arguments: arguments)
  }
}

Most of my localisation is in Localizable.strings and hoped I could localize from there.
But as you said, I might as well create Main.strings files and do the localization in there for those titles. I wanted to avoid creating other files, but it really isn't a problem in the end.

Where do you call Localise ?
Please show the complete context.
Code Block
class LevelsViewController: UIViewController {
 override func viewDidLoad() {
    super.viewDidLoad()
tabBarItem.title = "LevelsVC-TabBarItem".localize()
}
}

Here is an example. LevelsViewController is a view controller that is displayed when tapping a tab bar item.
So you do this in the "child" VC (LevelsViewController for instance).
Which is loaded only when you access to it.

If you don't want to do it the simple way, you should:
  • subclass UITabBarController: MyTabBarController

  • create IBOutlet for the tabBar

  • in viewDidLoad, change the titles of the tabBarItems with localiee()

set the class of the TabBarController to MyTabBarController in Identity Inspector.
Accepted Answer

Here is an example. LevelsViewController is a view controller that is displayed when tapping a tab bar item.

UITabBarController collects tabBarItems of the content view controllers just after they are initialized.
It is too late in viewDidLoad or viewWillAppear.

Try something like this:
Code Block
override func awakeFromNib() {
super.awakeFromNib()
tabBarItem.title = "LevelsVC-TabBarItem".localize()
}

Or
Code Block
required init?(coder: NSCoder) {
super.init(coder: coder)
tabBarItem.title = "LevelsVC-TabBarItem"//.localize()
}

In this scenario, you have no need to subclass UITabBarController.
Answers from the titans.
Thank you for both your answers.

I went ahead with awakeFromNib().
Just 2 quick tips for best practices to have great localization in all languages.



1st, it’s not recommended to use a wrapper method for localization.

The comment should be a helpful description of the string: e.g. “Tab bar title to show levels”, so that localizers know where the string is in UI, if it’s actionable, what's the context… It's super important for many languages.

Also, you could remove most of the arguments. Table name is Localizable by default so can be omitted. Bundle is .main by default too. Lastly, Value is optional and should be a user-presentable fallback value.

So it could be:

Code Block
tabBarItem.title = NSLocalizedString("Levels", comment: "Tab bar title to show levels") // or:
tabBarItem.title = NSLocalizedString("LevelsVC-TabBarItem", value: "Levels", comment: "Tab bar title to show levels")


Moreover, strings called from wrappers are not automatically created/updated using Xcode's Export/Import Localizations in the Product menu. (Unless you declare them in the build setting Localized String Macro Names). So you'd have to create and maintain your Localizable.strings file yourself.



2nd, String(format:) should not be used for localization. It doesn't support plurals with Stringsdict, different numbers in Arabic and Hindi, and text isolation in bi-directional text. The following is preferred:
Code Block
label.text = .localizedStringWithFormat(NSLocalizedString("%d items", comment: "Total number of levels"), number)

2 titans, and now a god :) This forum is underrated.

Thanks for your suggestions Developer Tools Engineer.
You are very right, I got myself into maintaining my own Localizable.strings file with commenting each line in there. Fortunately the project is not too big, but for the next one, I will certainly do it the right way from the start.
Tab bar item localization
 
 
Q