Reputation: 39283
I have a class that implements the "Take photo / Choose from library" that we all know and love. It is here https://github.com/fulldecent/FDTake This is included in my other projects via git submodule and that works fine.
Now I need to translate the text in that class to Chinese so it is "拍照 / 选照片" or something like that. Is there a good way to put translations in there so everyone can use them?
Upvotes: 1
Views: 2472
Reputation: 3042
Localization is typically handled by the NSLocalizedString(<#key#>, <#comment#>)
macro. In the source your replace all hard coded string with the macro. For example:
[self.buttonTitles addObject:@"Hi"]; // hard coded greeting
with
[self.theLabel setText:(NSLocalizedString(@"theKey", @"Hi"))];
Then genstrings
(from inside a Terminal) is used to scan the implementations file (*.m) and to write its output to the language project folder (here: en.lproj)
$ genstrings -o en.lproj/ *.m
In the directory en.lproj/
a file called Localizable.strings
. Its contents will be:
/* Hi */
"theKey" = "theKey";
The comment /* Hi */
is taken from our source code. The string Hi
should be displayed to the (English speaking) user. So we need to edit the string on the right hand side of the equals sign and make it the greeting, = "theKey"
has to become = "Hi"
:
/* Hi */
"theKey" = "Hi!";
All this is fine if there are only a few strings or when there is no intend to ever modify the strings. The moment gestrings is run again it will overwrite the modifications and you effectively lose the work done in Localizable.strings
.
An idea could be to write the output of genstrings to a different location. But then you will have to manually merge the changes. Once the Localizable.strings
file grows it becomes a nightmare trying to keep source code and Localizable.strings
in sync. So lets try to avoid that.
A big help comes from using NSLocalizedStringWithDefaultValue(<#key#>, <#tbl#>, <#bundle#>, <#val#>, <#comment#>)
. This macro will allow to set a default value in the Localizable.strings
file and in addition, it will make the need for the initial edit of the value field go away.
Putting it together:
[self.theLabel setText:NSLocalizedStringWithDefaultValue(@"theKey2", @"Localizable", [NSBundle mainBundle], @"Hi!", @"informal greeting"))];
After running the genstrings
command as used above there is now a small different in Localizable.strings
/* informal greeting */
"theKey2" = "Hi!";
Apart from the comment now telling the translator that we want an informal greeting, the “Hi!”
is already present in the value filed. There is no need to go to the Localizable.strings file, search for the correct line, modify the field form “theKey” to “Hi!”. genstrings
did that for us based on the default value supplied with NSLocalizedStringWithDefaultValue.
Add the file Localizable.strings
to the xcode project.
After changing the source code, for a new language from inside the Xcode first add a localization to Localizable.strings
. Xcode will generate a copy of Localizable.strings
under a subfolder based on the original Localizable.strings
.
I personally don't speak Chinese, but German. So if to add German localization my translation would go under de.lproj/Localizable.strings
, italian under it.lproj/
and so on.
Edit the new Localizable.strings
as needed:
(German)
/* informal greeting */
"theKey2" = "Hallo!";
(Italian)
/* informal greeting */
"theKey2" = "Ciao!";
and then build and run.
********* begin edit
The above considers a "standard" xcode project. You are asking about cereateing a module, therefore allowing your code to become an addition to a project. I suggest you create a bundle with the localizations. When somebody will include your code into their project the localizations remain separate. Full documentation about bundles is here.
A project that uses bundles for localizations is QuincyKit (there probably are more, that one was the first that came to mind)
So when placing the localization into a bundle other than the mainBundle
the [NSBundle mainBundle]
in the line below has to change
[self.theLabel setText:NSLocalizedStringWithDefaultValue(@"theKey2", @"Localizable", [NSBundle mainBundle], @"Hi!", @"informal greeting"))];
Instead of getting the strings from the mainBundle, obtain a reference to your own module. The docs suggest:
NSBundle* myBundle = [NSBundle bundleForClass:[self class]];
So the line becomes:
[self.theLabel setText:NSLocalizedStringWithDefaultValue(@"theKey2", @"Localizable", myBundle, @"Hi!", @"informal greeting"))];
********* end edit
PS: : my original text can be seen here
Upvotes: 5
Reputation: 15400
I think a bundle (as Olaf suggests) would work great, but another way with less overhead to ensure that your localizable string resources don't interfere with another project in the same solution (causing a weird problem to people reusing your component in another localized project) is to change your localizable.strings
file name to a unique file name. This means that where you used NSLocalizedString
you now need to use its variant NSLocalizedStringFromTable
(Apple documentation), where tableName is the same name as your strings file (without the .strings extension). You can define your own macro so that's it's just a straight replacement of NSLocalizedString
with, say FDTakeLocalizedString
.
A file name collision is much less likely to happen with XIBs files or storyboards than for the localizable.strings
file. But in both cases, if you use a prefixed naming convention (say FDTake.strings and FDTake-Main.xib), it will eliminate the risk and can only help.
Upvotes: 1