Good practices for multiple language data in Core Data
i need a multilingual coredata db in my iphone app. I could create different database for each language but i hope that in iphone sdk exist an automatically way to m开发者_如何学JAVAanage data in different language core data like for resources and string.
Someone have some hints?
I've done something similar to Shortseller, but without the use of categories.
InternationalBook
and LocalizedBook
are both custom managed objects with a one-to-many relationship (one international book to many localised books).
In the implementation of InternationalBook
, I've added a custom accessor for title
:
- (NSString *)title {
[self willAccessValueForKey:@"title"];
NSString *locTitle = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"locale==%@", [DataManager localeString]];
NSSet *localizedSet = [self.localizedBook filteredSetUsingPredicate:predicate];
if ([localizedSet count] > 0) {
locTitle = [[localizedSet valueForKey:@"localizedTitle"] anyObject];
}
[self didAccessValueForKey:@"title"];
return locTitle;
}
[DataManager localeString]
is a class method which returns the user's language and country code: en_US
, fr_FR
, etc. See documentation on NSLocale
for details.
See the "Custom Attribute and To-One Relationship Accessor Methods" section of the Core Data Programming Guide for an explanation of willAccessValueForKey:
and didAccessValueForKey:
.
When populating the data, I grab a string representing the user's current locale ([DataManager localeString]
), and store that along the with localised book title in a new LocalizedBook
object. Each LocalizedBook
instance is added to an NSMutableSet
, which represents the one-to-many relationship.
NSMutableSet *bookLocalizations = [internationalBook mutableSetValueForKey:@"localizedBook"]; // internationalBook is an instance of InternationalBook
// set the values for locale and localizedTitle
LocalizedBook *localizedBook = (LocalizedBook *)[NSEntityDescription insertnNewObjectEntityForName:@"LocalizedBook" inManagedObjectContext:self.bookMOC];
localizedBook.locale = [DataManager localeString];
localizedBook.localizedTitle = theLocalizedTitle; // assume theLocalizedTitle has been defined.
[bookLocalizations addObject:localizedBook];
[bookLocalizations setValue:localizedBook forKey:@"localizedBook"];
Since the localised titles are being stored in the LocalizedBook
managed object, you can make the title
attribute a transient, but if you do that you can't use title
in a predicate.
The nice thing about this approach is that the implementation of the to-many relationship is transparent to any consumers. You simply request internationalBook.title
and the custom accessor returns the appropriate value based on the user's locale behind the scenes.
I have generated model classes for the core data entities.
Then I defined category helper classes with functions to set and get the multilanguage properties (e.g. name).
So I have a Product (with e.g. code and price) and a ProductLanguage (with language and name properties) Entity.
I never directly access ProductLanguage, but always use the name function defined on the the Product model (via category). This has worked well for me sofar.
Like Gordon, I use quite similar code, but not written files generated by model. I use this code in my .m file where I want to show the data.
As I start from Apple template, I put this code exactly in
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
of my TableViewController.m
P.S: Just to understand, I use these prefixes: tbl_ for tables (entities), rel_ for relationships, fld_ for fields (attributes).
Hope this helps.
NSSet *sourceSet = [NSSet setWithArray:[[tbl_MainTable rel_Localization]allObjects]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"fld_Locale == %@", [[NSLocale preferredLanguages] objectAtIndex:0]];
NSSet *filteredSet = [sourceSet filteredSetUsingPredicate:predicate];
//NSLog(@"%@", filteredSet); NSLog(@"%@", [[filteredSet valueForKey:@"fld_Name"] anyObject]);
if ([filteredSet count] > 0)
{
[cell.detailTextLabel setText:[[filteredSet valueForKey:@"fld_Name"] anyObject]];
}
精彩评论