📜 ⬆️ ⬇️

Localization of applications for OS X



When developing an application, its localization has a certain value, since it directly affects the number of users and, accordingly, the success of the product. We know the statistics on the number of Internet users for different languages, and the conclusion is that by making a translation for a group of certain specific languages, you can significantly expand the audience of users of your program.

Our team is working on the ICQ project and Mail.Ru Agent (hello Dima, Vova, Lesha) under OS X, and localizing the product at different stages of development was carried out differently, for each of the approaches revealed their strengths and weaknesses. Some experience I want to share.

1. Localization through Interface Builder

The easiest way to do localization is through standard Interface Builder (IB) tools. At the same time, new languages ​​can be added in the project settings MyTestProject> Info> Localizations. Also here, already existing interface files can be processed automatically (a command of the type genstrings -o en.lproj *.m ).
')
When creating a new file with a user interface, just click on the Localize button in the Utilities window. The interface is generally friendly and understandable. To get strings from xib, if you want to localize not via IB, but manually, it makes sense to use a console command like this:

 ibtool --export-strings-file SomeViewController.utf16-strings.tmp \ SomeViewController.xib && iconv -f utf-16 -t utf-8 \ SomeViewController.utf16-strings.tmp > SomeViewController.strings && \ rm SomeViewController.utf16-strings.tmp 

The output will be something like:

 $ cat SomeViewController.strings /* Class = "NSTextFieldCell"; title = "   "; ObjectID = "4"; */ "4.title" = "   "; /* Class = "NSTextFieldCell"; title = "  "; ObjectID = "9"; */ "9.title" = "  "; /* Class = "NSTextFieldCell"; title = " "; ObjectID = "15"; */ "15.title" = " "; /* Class = "NSTextFieldCell"; title = ""; ObjectID = "23"; */ "23.title" = ""; 

The resulting translation can be corrected manually in any editor or any automation can be applied, after which the new SomeViewController.strings strings file can be returned to xib as follows:

 iconv -f utf-8 -t utf-16 SomeViewController.strings > \ SomeViewController.utf16-strings.tmp && ibtool --strings-file SomeViewController.utf16-strings.tmp \ SomeViewController.xib --write SomeViewController-updated.xib && \ rm SomeViewController.utf16-strings.tmp 

The advantage here is simplicity and clarity, visual control of the “layout” for each language. The disadvantages include problems with merge in git, the fact that with a large number of supported languages, changes in localization need to be done via IB, which is not always convenient. Alternatively, you can still use scripts, such as the one above, keep the translation in xibs and translate everything automatically, but in our case, practice has shown that it is better not to complicate the system and not to use extra add-ins.

2. Software localization through NSLocalizedString

This approach eliminates the shortcomings of the previous one and consists in the fact that the interface element outlet is programmatically NSLocalizedStrings headers by the NSLocalizedStrings function:

 self.startButton.stringValue = NSLocalizedString(@“StartCaption”, @“Start button in menu”); self.pauseButton.stringValue = NSLocalizedString(@“PauseCaption”, @“Pause button in menu”); 

Here, the first argument of the function is the key by which the corresponding localized string is searched for in the corresponding Localizable.strings file.



Examples of localization file content:

 Localizable.strings (Russian): “StartCaption” = “!”; “PauseCaption” = “!”; Localizable.strings (Engligh): “StartCaption” = “Start!”; “PauseCaption” = “Pause!”; 

It is worth noting that if the key is not in Localizable.strings , then NSLocalizedStrings will return its value itself. There is a temptation to use its value as a key, we did it for some time - here is a beautiful clear key, and it’s not scary to forget to write down the value, but in fact it became clear that, first, it is more inconvenient that the key value may be needed put down the key in the base language, different from the key itself, and it turns out ugly, and, secondly, it is still more convenient to control the correctness of localization using the key that pops out to the GUI. The second argument of NSLocalizedStrings is a comment that does not play a special role, it is mainly used in the generation of string files based on existing code to clarify exactly what the string refers to. You can get the actual file with strings for translation using the following script:

 #!/bin/bash export LANG=C LC_CTYPE=C LC_ALL=C for file in `find . -name "*.m"` do genstrings -a $file done cat Localizable.strings | sort -u | sed '/\/\\*/d' > actual.strings 

Along with NSLocalizedString you can immediately use the [NSBundle localizedStringForKey:value:table:] method, which actually twitches (for the main bundle and with nil as a table) - it makes sense to use it when working with libraries, when you want to load strings from a custom .strings file (then specify its name as a table). The language used is determined based on the values ​​of the AppleLanguages key from NSUserDefaults .

If the translation lengths for different languages ​​are very different, and the interface floats, then along with the software alignment based on the size of the control

 NSSize myButtonSize = [self.myButton.stringValue sizeWithAttributes:[NSDictionary dictionaryWithObject:self.myButton.font forKey:NSFontAttributeName]]; 

you can, and it's generally more convenient, use Auto Layout:





Here it is necessary to affix, as when changing the text of the control, to change its geometry automatically, and to align the buttons following it. Great.

3. Dynamic localization

Now applied in our project. It is rather a modification of the previous version, the bottom line is that the language changes dynamically through the program settings, and a notification is sent that we go around localized interfaces, where our NSLocalizedString analog is NSLocalizedString localizedStringForKey based on [NSBundle localizedStringForKey:value:table:] , which at runtime, it takes from the application resources the required line value in the language selected in the program settings. Of the nuances worth noting that

In general, for each approach has its own scope. Localization via IB, for example, is better to use for applications where not very many languages ​​are supported, a large number of text elements, and for different localizations the interface geometry is different. Software localization is best done for projects where, on the contrary, many languages ​​and line lengths for different localizations are not very different. In some cases, you can get stuck and make a dynamic localization, here is a plus in that you can additionally switch the language elegantly on the fly, and the user will be happy. Do not forget the Auto Layout. I hope someone will find something useful for themselves in this information. Thanks for attention!

Source: https://habr.com/ru/post/241217/


All Articles