Is it possible to have multiple components that have their separate localizations in an app?
For example I want to localize strings in my app but also use ShareKit which is localized itself (so my bundle will contain 2 Localizable.strings in different locations).
So, ShareKit contains folders like en.lproj and de.lproj that contain Localizable.strings files and I want to create the same for the rest of my project but keep them separate.
I have tried just keeping them separate and that resulted in the strings of my app not being used. Any ideas?
There is a way to do this that is quite simple.
There are several macros for localizing, one of which is NSLocalizedStringFromTable(). This takes three parameters:
The string to localize
The table name, which is just a file name
The comment, just like in NSLocalizedString()
If you use a table name then you can have another strings file, i.e. if I do NSLocalizedStringFromTable(#"name", #"MyStrings", #"whatever"); then put my strings in MyStrings.strings it will use that.
See Matt Gallagher's post about this.
every file/resource can be localizable, also the IB .xib files or images jpg/png,
you just need to select a file in your project, open info, go in the "general" tab/section and press the "make file localizable"...
then you can add any language you want, xCode will create a new file duplicating the first one and will put it in the right folder...
luca
It is not possible to do what you are asking. You can have multiple Localizable.strings files, but only one per language in their respective .lproj folders.
I understand that you do not want to edit the ShareKit Localizable.strings files because that would be a pain when updating but I think you need to look at how much work it would actually take. Depending on how many languages you need to support it may be less work to localize your own strings and add them to the bottom of the ShareKit Localizable.strings files than to implement your own localization scheme.
BTW, to detect what language the device is currently set to you can use:
NSArray *preferedLocalizations = [[NSBundle mainBundle] preferredLocalizations];
This gives you an array of two letter language code strings. The item at index 0 is the currently selected language. This could be helpful if you need to make logic decisions based on the language.
oh ok, I don't know ShareKit, but i guess you cannot edit its text files and just add your new words to that files, isn't it?
then you may consider to create your own "dictionary" file and try to localize it, then read it and put it in a NSDictionary where you can read the single words/value...
you can insert a record in your file "myDict.plist" with key "greeting" of type String with value "ciao" for the italian one and "hallo" in the english one
NSString *bundle = [[ NSBundle mainBundle] pathForResource:#"myDict" ofType:#"plist"];
NSMutableDictionary *savedStock = [[NSMutableDictionary alloc] initWithContentsOfFile:bundle];
NSString *greetingsTranslatedInTheGoodLanguage = [savedStock objectForKey:#"greeting"];
// just to try what you have read:
NSLog (#"translated by your own dictionary: %#", greetingsTranslatedInTheGoodLanguage);
[savedStock release];
luca
ps
read the comments too...
Related
I develop a Swift 5 framework that runs on iOS 12 and above for iPhone and iPad.
I added French localization in addition to English, but the project info tab shows there's no localized files for both languages as shown on the image below:
When I run Xcode Editor|Export for localization I get the bundled files (including the fr.xliff file). I’ve edited fr.xliff with Xcode to translate some strings, and imported it back. But nothing changed in the app.
Btw, I can’t see any of the *.strings files in the project files hierarchy, which sounds weird.
[Update]
So I manually added Localizable.Strings file, and added English and French.
When I import xliff files, the Localizable.strings files remains empty. No apparent issue pops up.
When I put the key=value list in the string file, the NSLocalizedString() does not return the right localised version of the string (it always return the key).
Help appreciated.
Found what's wrong: I had to use the full (extended) version of NSLocalizedString() in order to make the function call get the translation from my framework Localizable.strings files (rather than the client application), as follows:
NSLocalizedString("Continue", tableName: tableName, bundle: bundle, comment: "Continue in the button title of UIAladdinOnboardingViewController")
Where:
tableName: a let global that hold the name of my localisable string file (in my case "Aladdin.Localizable"). I did this to avoid potential collision of .strings files (as my framework name is Aladdin);
bundle: a let global in my the framework name space to designates the framework model bundle to pick the string from. I defined it like this: let bundle = Bundle(for: ExtendedAppDelegate.self) where ExtendedAppDelegate is one of my framework custom class.
Side note of importance:
Btw, don’t put your interpolating string as the key parameter of the NSLocalizedString call, otherwise it’s gonna be interpolated at runtime, leading to an interpolated string that won't exist in your string file.
Don’t do that:
let s = NSLocalizedString("{Start your \(introductoryPeriod) free trial.}", tableName: tableName, bundle: bundle, comment: "in price display")
Do this:
let s = String(format: NSLocalizedString("{Start your %# free trial.}", tableName: tableName, bundle: bundle, comment: "{Start your \\(introductoryPeriod) free trial.}"), introductoryPeriod)
With the corresponding Aladdin.Localizable.strings (en):
/* {Start your \(introductoryPeriod) free trial.} (in price display) */
"{Start your %# free trial.}" = "{Start your %# free trial.}";
To generate the strings:
I used the gestrings from the terminal as follows:
$genstrings -o en.lproj/ *.swift
$genstrings -o fr.lproj/ *.swift
And so on for every target languages you have.
Finally, do the translation straight in the string files.
in Localization you can Localize your string directly from Storyboard.
after adding your language..click on Main.storyboard -> go to identity and type...
you can see your localize languages string...Image of your Main.strings -> select them select all Languages..
after that you can see main.strings(French) and main.strings(English) in your Navigation panel...
change your strings on prefer languages like...
Image of how to change your strings in English
Image of how to change your strings in French
now, change Your Simulator Language from Edit schema -> Run -> Your language(French or English).
it's working..
Is there a method I can use in a program to access and modify ripped music CD-MP3 file(s) header text?
There is a method available in the MusicMatch jukeboks music player, but with 2000 files ripper from 50 CD's, the job is quite formidable and the tool "supertagging' is cumbersome to use.
What I see for me is more like the visual representation of Excel, where I would have just the three fields Artist name, Song title and Album name. displayed.
The Artist field would have the option of repeating the top field down for all the song titles, Album would always be repeted for all song titles.
Song titles wil of course have to be entered for each item.
In the ripped files, every file has the fields track#, artist, album + some of less importance.
Just let me know if I am at the wrong forum for my search. I just don't know anywhere else that I might go.
For programming I might use Visual Foxpro and/or assembler. I haven't used C since early 1980's.
If you really want to develop it yourself, at least use an ID3 library, don't write the functionality yourself!
A good one is at http://id3lib.sourceforge.net/. I haven't tried it recently, but I'm sure you can call it from VFP somehow.
If you just want something that is better for tagging a shed-load of files, look at MediaMonkey.
If you want to work solely in VFP then you should use the VFP low-level utilities
FOPEN()
FCHSIZE( )
FCLOSE( )
FCREATE( )
FEOF( )
FFLUSH( )
FGETS( )
FPUTS( )
FREAD( )
FSEEK( )
FWRITE( )
These are pretty well documented within the VFP Help system and there are numerous examples on the web.
With them you can get the 'raw' data from the MP3 file, identify what you are looking for, change it, and write it back again.
The downside is that specific 'fields' (e.g. Artist name, Song title and Album name, etc.) will not be readily recognized. You would need to write code to identify these and then identify where the values reside.
Good Luck
So Im importing a text file that contains a list of character sets. These sets have a meaning they refer to a status of an object. For example TOMTOM100 means Delivery announced. Ones i import he text file the status is presented in 0-5 labels(depends on how many status updates are available).
At first i wanted to do this with a if statement but quickly realized that it would be to much.
if ((trackTraceStatusone.text = #"TOMTOM100"))
{
trackTraceStatusone.text = #"Delivery announced.";
}
Is there a way to create some kind of translator that automatically translates the status in a readable format?
TOMTOM100 > Delivery announced
TOMTOM101 > Delivery Scanned
and so on.
Sounds like a job for NSLocalizedStringFromTable() or the corresponding NSBundle method -localizedStringForKey:value:table:. This will let you load the string from a .strings file in your bundle, which will look something like this:
"TOMTOM100" = "Delivery Announced";
"TOMTOM101" = "Delivery Scanned";
This will also make it easy to provide different strings for different languages. For more information, see the String Resources section of the Resource Programming Guide.
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?
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!";
So far so good
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.
Doing the translations
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
Bundle it up
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
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.
I created a project without checking "use CoreData". The Project name is "glossary"
Now I changed my mind and so for I added an data model usinng Add->New File->Resource->Data Model->gave it the name Glossary->didn`t select any class->Finish.
The next step was to design my Data Model.
Then I added the needed Code to my AppDelegate.
For all Steps i was following this Tutorial:
https://developer.apple.com/library/ios/#documentation/DataManagement/Conceptual/iPhoneCoreData01/Introduction/Introduction.html%23//apple_ref/doc/uid/TP40008305-CH1-SW1
My problem now is located in this line:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"glossary" withExtension:#"momd"]
modelURL is always nill
Creating an extra NSBundle Ref and calling mainBundle shows me that this is working, however i don`t know if it is really the right path.
Doing the same Steps on an project with selected "use CoreData" while creating works great.
Has anybody an idea?
It has to do with model versioning. You want to add a versioned model (item in Xcode project tree will have .xcdatamodeld extension) and then your code will run smoothly.
In Xcode 4 when you add a new Core Data file it is versioned by default. Even if you added Core Data support after project creation.
If you don't plan to have model versions, just use .mom in your code.
I'm not 100 % sure, but URLForResource does work for files only and momd is directory.
URLForResource documentation: The method first looks for a matching resource file in the nonlocalized resource directory of the specified bundle. (In Mac OS X, this directory is typically called Resources but in iOS, it is the main bundle directory.) If a matching resource file is not found, it then looks in the top level of any available language-specific “.lproj” directories. (The search order for the language-specific directories corresponds to the user’s preferences.) It does not recurse through other subdirectories at any of these locations. For more details see Bundles and Localization.