2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "WEStringTableManager.h"
23 #include "WEStringTable.h"
24 #include "WEResourceManager.h"
27 @implementation WEStringTableManager
29 static NSNull *null = nil;
30 static BOOL debugOn = NO;
33 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
35 if (null == nil) null = [[NSNull null] retain];
37 if ((debugOn = [ud boolForKey:@"WEStringTableManagerDebugEnabled"]))
38 NSLog(@"Note: WEStringTableManager debugging is enabled.");
42 if ((self = [super init])) {
43 if ([WOApplication isCachingEnabled]) {
44 // TODO: find proper capacities
46 [[NSMutableDictionary alloc] initWithCapacity:16];
47 self->compLabelCache =
48 [[NSMutableDictionary alloc] initWithCapacity:512];
51 [self logWithFormat:@"Note: label caching is disabled (slow!)."];
57 [self->compLabelCache release];
58 [self->nameToTable release];
64 - (NGBundleManager *)bundleManager {
65 static NGBundleManager *bm = nil; // THREAD
66 if (bm == nil) bm = [[NGBundleManager defaultBundleManager] retain];
72 + (NSString *)findResourceDirectoryNamed:(NSString *)_name
73 fhsName:(NSString *)_fhs
75 static NSDictionary *env = nil;
80 if (env == nil) env = [[[NSProcessInfo processInfo] environment] retain];
81 fm = [NSFileManager defaultManager];
83 /* look in GNUstep pathes */
85 tmp = [[WEResourceManager rootPathesInGNUstep] objectEnumerator];
86 while ((path = [tmp nextObject]) != nil) {
87 path = [path stringByAppendingPathComponent:_name];
89 if ([fm fileExistsAtPath:path])
93 /* look in FHS pathes */
95 tmp = [[WEResourceManager rootPathesInFHS] objectEnumerator];
96 while ((path = [tmp nextObject])) {
97 path = [path stringByAppendingPathComponent:_fhs];
98 if ([fm fileExistsAtPath:path])
106 - (NSString *)labelForKey:(NSString *)_key component:(WOComponent *)_component{
115 if ([_key length] == 0)
117 if (_component == nil)
120 if (null == nil) null = [[NSNull null] retain];
122 cname = [_component name];
123 langs = [(WOSession *)[_component session] languages];
128 /* cache cachekeys here ;-) */
129 cacheKey = [NSArray arrayWithObjects:_key, cname, langs, nil];
132 if ((value = [self->compLabelCache objectForKey:cacheKey]) != nil) {
133 if (value == null) value = nil;
139 app = [WOApplication application];
141 bm = [NGBundleManager defaultBundleManager];
142 bundle = [bm bundleProvidingResource:cname ofType:@"WOComponents"];
144 bundle = [NGBundle bundleForClass:[_component class]];
146 /* look in BundleName.strings */
148 value = [self stringForKey:_key
149 inTableNamed:[bundle bundleName]
155 /* look in App.strings */
156 value = [self stringForKey:_key
163 /* no string found, use key as string */
168 NSAssert(value, @"missing value ..");
171 [self->compLabelCache setObject:value forKey:cacheKey];
173 NSLog(@"%s: label cache size now: %i", __PRETTY_FUNCTION__,
174 [self->compLabelCache count]);
179 - (NSString *)_cachedStringForKey:(NSString *)_key
180 inTableNamed:(NSString *)_tableName
181 withDefaultValue:(NSString *)_default
182 languages:(NSArray *)_languages
184 if (_tableName == nil) _tableName = @"default";
186 /* look into string cache */
188 if ([_languages count] > 0) {
194 language = [_languages objectAtIndex:0];
196 r = [language rangeOfString:@"_"];
198 language = [language substringToIndex:r.location];
200 tname = [language stringByAppendingString:@"+++"];
201 tname = [tname stringByAppendingString:_tableName];
203 if ((table = [self->nameToTable objectForKey:tname])) {
206 @"resolved label %@ table %@ in lang %@ (languages=%@)",
207 _key, _tableName, language,
208 [_languages componentsJoinedByString:@","]];
210 return [table stringForKey:_key withDefaultValue:_default];
213 else if ([_languages count] == 0) {
216 NSLog(@"WARNING: called %s without languages array %@ !",
217 __PRETTY_FUNCTION__, _languages);
219 if ((table = [self->nameToTable objectForKey:_tableName]))
220 return [table stringForKey:_key withDefaultValue:_default];
226 - (NSString *)_bundleStringForKey:(NSString *)_key
227 inTableNamed:(NSString *)_tableName
228 withDefaultValue:(NSString *)_default
229 languages:(NSArray *)_languages
236 if (_tableName == nil) _tableName = @"default";
238 bundle = [[self bundleManager]
239 bundleProvidingResource:_tableName
244 e = [_languages objectEnumerator];
245 while ((language = [e nextObject])) {
249 r = [language rangeOfString:@"_"];
251 language = [language substringToIndex:r.location];
253 ls = [NSArray arrayWithObject:language];
255 path = [bundle pathForResource:_tableName
262 tname = [language stringByAppendingString:@"+++"];
263 tname = [tname stringByAppendingString:_tableName];
265 table = [WEStringTable stringTableWithPath:path];
266 [self->nameToTable setObject:table forKey:tname];
268 return [table stringForKey:_key withDefaultValue:_default];
272 path = [bundle pathForResource:_tableName
277 WEStringTable *table;
279 table = [WEStringTable stringTableWithPath:path];
281 [self->nameToTable setObject:table forKey:_tableName];
283 return [table stringForKey:_key withDefaultValue:_default];
286 NSLog(@"WARNING: missing string table %@ in bundle %@",
287 _tableName, [bundle bundlePath]);
292 + (NSString *)gsTranslationsSubpath {
295 p = [[WOApplication application] gsTranslationsDirectoryName];
299 p = [@"Resources/" stringByAppendingString:p];
302 + (NSString *)fhsTranslationsSubpath {
305 p = [[WOApplication application] shareTranslationsDirectoryName];
309 p = [@"share/" stringByAppendingString:p];
310 return [p stringByAppendingString:@"/translations/"];
313 + (NSArray *)availableTranslations {
314 static NSArray *ltranslations = nil;
315 NSMutableSet *translations;
319 NSArray *translationPathes;
321 if (ltranslations != nil)
322 return ltranslations;
324 // TODO: use lists ..., or maybe NGResourceLocator
325 path = [self findResourceDirectoryNamed:[self gsTranslationsSubpath]
326 fhsName:[self fhsTranslationsSubpath]];
330 translationPathes = [NSArray arrayWithObject:path];
331 translations = [NSMutableSet setWithCapacity:16];
332 fm = [NSFileManager defaultManager];
334 e = [translationPathes objectEnumerator];
335 while ((path = [e nextObject]) != nil) {
339 dl = [[fm directoryContentsAtPath:path] objectEnumerator];
340 while ((l = [dl nextObject]) != nil) {
341 if (![l hasSuffix:@".lproj"])
343 if ([l hasPrefix:@"."])
346 l = [l stringByDeletingPathExtension];
347 [translations addObject:l];
351 ltranslations = [[translations allObjects] copy];
352 if ([ltranslations count] > 0) {
353 NSLog(@"Note: located translations: %@",
354 [ltranslations componentsJoinedByString:@", "]);
357 NSLog(@"Note: located no additional translations.");
358 return ltranslations;
361 - (NSString *)_resourceStringForKey:(NSString *)_key
362 inTableNamed:(NSString *)_tableName
363 withDefaultValue:(NSString *)_default
364 languages:(NSArray *)_languages
366 NSString *rpath, *path;
371 if (_tableName == nil) _tableName = @"default";
373 fm = [NSFileManager defaultManager];
374 // TODO: should be NGResourceLocator method?
375 rpath = [[self class] findResourceDirectoryNamed:
376 [[self class] gsTranslationsSubpath]
378 [[self class] fhsTranslationsSubpath]];
380 [self logWithFormat:@"missing translations directory ..."];
384 /* look into language projects .. */
386 e = [_languages objectEnumerator];
387 while ((language = [e nextObject]) != nil) {
388 WEStringTable *table;
393 r = [language rangeOfString:@"_"];
395 language = [language substringToIndex:r.location];
397 ls = [NSArray arrayWithObject:language];
399 path = [_tableName stringByAppendingPathExtension:@"strings"];
400 path = [[language stringByAppendingPathExtension:@"lproj"]
401 stringByAppendingPathComponent:path];
402 path = [rpath stringByAppendingPathComponent:path];
404 if (![fm fileExistsAtPath:path])
407 tname = [language stringByAppendingString:@"+++"];
408 tname = [tname stringByAppendingString:_tableName];
410 table = [WEStringTable stringTableWithPath:path];
411 [self->nameToTable setObject:table forKey:tname];
413 return [table stringForKey:_key withDefaultValue:_default];
416 /* look into resource dir */
418 path = [_tableName stringByAppendingPathExtension:@"strings"];
419 path = [rpath stringByAppendingPathComponent:path];
421 if ([fm fileExistsAtPath:path]) {
422 WEStringTable *table;
424 table = [WEStringTable stringTableWithPath:path];
425 if (self->nameToTable == nil)
426 self->nameToTable = [[NSMutableDictionary alloc] initWithCapacity:16];
428 [self->nameToTable setObject:table forKey:_tableName];
430 return [table stringForKey:_key withDefaultValue:_default];
434 NSLog(@"WARNING: missing string table %@ in %@", _tableName, path);
439 - (NSString *)stringForKey:(NSString *)_key
440 inTableNamed:(NSString *)_tableName
441 withDefaultValue:(NSString *)_default
442 languages:(NSArray *)_languages
446 if (_tableName == nil) _tableName = @"default";
448 /* look into string cache */
450 s = [self _cachedStringForKey:_key
451 inTableNamed:_tableName
452 withDefaultValue:_default
453 languages:_languages];
454 if (s != nil) return s;
456 if (self->nameToTable == nil)
457 self->nameToTable = [[NSMutableDictionary alloc] initWithCapacity:16];
459 /* search for string */
461 s = [self _resourceStringForKey:_key
462 inTableNamed:_tableName
464 languages:_languages];
465 if (s != nil) return s;
467 s = [self _bundleStringForKey:_key
468 inTableNamed:_tableName
470 languages:_languages];
471 if (s != nil) return s;
478 - (BOOL)isDebuggingEnabled {
482 @end /* WEStringTableManager */
484 @implementation WOApplication(WEStringTableManager)
486 - (NSString *)shareTranslationsDirectoryName {
487 return [[self name] lowercaseString];
489 - (NSString *)gsTranslationsDirectoryName {
493 @end /* WOApplication(WEStringTableManager) */