IOS Localization: Best Practices

What are your best localization practices for iOS? I have worked a lot with Localization, but it seems that it is not efficient and scalable enough. There must be some better way. This is my current approach:

Using .strings + NSLocalizedString Files

  • It works well. Especially when you break a line file into smaller pieces. But if it is for many small files. It can be tiring to add another language.

Using .stringsdict for zeros, one, many, etc. lines

  • This also works well. The disadvantage is that for one word "code" is enough.

Using .strings files for storyboard

  • This is the hardest part. Creating a .string file from a storyboard is not difficult in itself. But for some reason it is impossible to update the lines? So. if you add more lines to the storyboard file, it is impossible to get new lines to old lines without regeneration. This means that all your old translations will be lost.
  • I read and tested FileMerge. (Works fine, but seems to be a long way).
  • I read and tested some python scripts. (Do not work at all)

I tried to create an xliff file from Xcode but did not get it to work. It always cannot export a file.

Error msg: Failed to read the line file. /..../Localizable.strings/. Data could not be read because it is not in the correct format.

So .. How do you deal with Localizedstrings in iOS? Special. What are your approaches to localizing storyboard files? I saw people setting all localized lines in code. But for this purpose an unnecessary step arises to create a large number of IBOutlets .

+5
source share
3 answers

What I did is quite a mission initially, but ultimately it's worth putting all your translations into an excel file and then saving your Excel document as csv. Then I wrote a small parser that spits out the csv file into a string file format. Good for line alignment if you also have an Android project.

+1
source

Use the XLIFF export / import function available with Xcode 6. This is a universal file format known by most translation tools, and Xcode will make sure everything is in sync for you. There are also sessions from WWDC 2014 that describe this in detail.

Make sure that your storyboards are in Base.lproj (this is the default value for new projects) and that you use automatic layout with localization-friendly restrictions (which is necessary for proper layout settings for translations of different lengths),

+1
source

.strings and .stringsdict really work well. I don’t like any approaches to broadcasting the storyboard, they are too fragile, and it sucks that you need to finish the whole cycle again just because you added / removed / or changed something in the storyboard.

I have good results with the following approach:

  • Use .strings localization .strings for captions / subtitles / placeholders / texts in your storyboard objects.
  • Define a helper function in the base class of the UIViewController (or category) that goes through your user interface and sets localizations on supported widgets using your keys in the storyboard.

I am calling a helper function in viewDidLoad . Here is an example:

 static void translateLocalizableStringsInView( UIView* v ) { NSBundle* mainBundle = [NSBundle mainBundle]; UIView* view = v; if ( [view isKindOfClass:UILabel.class] ) { UILabel* label = (UILabel*)view; if ( label.text.length ) { NSString* localizedString = [mainBundle localizedStringForKey:label.text value:nil table:nil]; if ( localizedString.length ) { label.text = localizedString; } } } else if ( [view isKindOfClass:UITextField.class] ) { UITextField* textField = (UITextField*)view; if ( textField.text.length ) { NSString* localizedString = [mainBundle localizedStringForKey:textField.text value:nil table:nil]; if ( localizedString.length ) { textField.text = localizedString; } } if ( textField.placeholder.length ) { NSString* localizedString = [mainBundle localizedStringForKey:textField.placeholder value:nil table:nil]; if ( localizedString.length ) { textField.placeholder = localizedString; } } } else if ( [view isKindOfClass:UIButton.class] ) { UIButton* button = (UIButton*)view; NSString* title = [button titleForState:UIControlStateNormal]; if ( title.length ) { NSString* localizedString = [mainBundle localizedStringForKey:title value:nil table:nil]; if ( localizedString.length ) { [button setTitle:localizedString forState:UIControlStateNormal]; } } } else if ( [view isKindOfClass:UISegmentedControl.class] ) { UISegmentedControl* sc = (UISegmentedControl*)view; for ( NSUInteger i = 0; i < sc.numberOfSegments; ++i ) { NSString* title = [sc titleForSegmentAtIndex:i]; if ( title.length ) { NSString* localizedString = [mainBundle localizedStringForKey:title value:nil table:nil]; if ( localizedString.length ) { [sc setTitle:localizedString forSegmentAtIndex:i]; } } } } } @implementation UIViewController (LocalizableStrings) -(void)LT_translateLocalizableStringsInView { [self.view LT_iterateThroughAllSubviewsRecursively:YES usingBlock:^(UIView * _Nonnull view, BOOL * _Nonnull stop) { translateLocalizableStringsInView( view ); }]; if ( self.navigationItem.titleView ) { translateLocalizableStringsInView( self.navigationItem.titleView ); } } 
+1
source

All Articles