diff --git a/AppKit/Cib/CPCib.j b/AppKit/Cib/CPCib.j index 12c9611af..64ec7d981 100644 --- a/AppKit/Cib/CPCib.j +++ b/AppKit/Cib/CPCib.j @@ -32,6 +32,7 @@ @import "_CPCibObjectData.j" @import "_CPCibProxyObject.j" @import "_CPCibWindowTemplate.j" +@import "_CPLocalizableString.j" CPCibOwner = @"CPCibOwner"; CPCibTopLevelObjects = @"CPCibTopLevelObjects"; @@ -46,10 +47,11 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; @implementation CPCib : CPObject { - CPData _data; - CPBundle _bundle; - BOOL _awakenCustomResources; + BOOL _awakenCustomResources @accessors(property=_awakenCustomResources); + CPBundle _bundle; + CPData _data; + CPString _cibName; id _loadDelegate; } @@ -59,6 +61,8 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; if (self) { + _cibName = [aURL lastPathComponent]; + _data = [CPURLConnection sendSynchronousRequest:[CPURLRequest requestWithURL:aURL] returningResponse:nil]; if (!_data) @@ -76,6 +80,8 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; if (self) { + _cibName = [aURL lastPathComponent]; + [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:aURL] delegate:self]; _awakenCustomResources = YES; @@ -92,7 +98,9 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; aName = [aName stringByAppendingString:@".cib"]; // If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later. - self = [self initWithContentsOfURL:[aBundle || [CPBundle mainBundle] pathForResource:aName]]; + var bundle = aBundle || [CPBundle mainBundle]; + + self = [self initWithContentsOfURL:[bundle _cibPathForResource:aName]]; if (self) _bundle = aBundle; @@ -106,7 +114,9 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; aName = [aName stringByAppendingString:@".cib"]; // If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later. - self = [self initWithContentsOfURL:[aBundle || [CPBundle mainBundle] pathForResource:aName] loadDelegate:aLoadDelegate]; + var bundle = aBundle || [CPBundle mainBundle]; + + self = [self initWithContentsOfURL:[bundle _cibPathForResource:aName] loadDelegate:aLoadDelegate]; if (self) _bundle = aBundle; @@ -114,16 +124,6 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; return self; } -- (void)_setAwakenCustomResources:(BOOL)shouldAwakenCustomResources -{ - _awakenCustomResources = shouldAwakenCustomResources; -} - -- (BOOL)_awakenCustomResources -{ - return _awakenCustomResources; -} - - (BOOL)instantiateCibWithExternalNameTable:(CPDictionary)anExternalNameTable { var bundle = _bundle, @@ -132,7 +132,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey"; if (!bundle && owner) bundle = [CPBundle bundleForClass:[owner class]]; - var unarchiver = [[_CPCibKeyedUnarchiver alloc] initForReadingWithData:_data bundle:bundle awakenCustomResources:_awakenCustomResources], + var unarchiver = [[_CPCibKeyedUnarchiver alloc] initForReadingWithData:_data bundle:bundle awakenCustomResources:_awakenCustomResources cibName:_cibName], replacementClasses = [anExternalNameTable objectForKey:CPCibReplacementClasses]; if (replacementClasses) @@ -226,4 +226,4 @@ var CPCibDataFileKey = @"CPCibDataFileKey", [aCoder encodeObject:[_data base64] forKey:CPCibDataFileKey]; } -@end +@end \ No newline at end of file diff --git a/AppKit/Cib/CPCibLoading.j b/AppKit/Cib/CPCibLoading.j index 91ae95ed3..fa5bd6956 100644 --- a/AppKit/Cib/CPCibLoading.j +++ b/AppKit/Cib/CPCibLoading.j @@ -26,7 +26,11 @@ @import "CPCib.j" -var CPCibOwner = @"CPCibOwner"; +var CPCibOwner = @"CPCibOwner", + CPBundleDefaultLanguage = @"CPBundleDefaultLanguage", + CPBundleTypeOfLocalization = @"CPBundleTypeOfLocalization", + CPBundleBaseLocalizationType = @"CPBundleBaseLocalizationType", + CPBundleInterfaceBuilderLocalizationType = @"CPBundleInterfaceBuilderLocalizationType"; @implementation CPObject (CPCibLoading) @@ -45,14 +49,7 @@ var CPCibOwner = @"CPCibOwner"; + (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner { - if (![aName hasSuffix:@".cib"]) - aName = [aName stringByAppendingString:@".cib"]; - - // Path is based solely on anOwner: - var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle], - path = [bundle pathForResource:aName]; - - return [self loadCibFile:path externalNameTable:@{ CPCibOwner: anOwner }]; + return [self loadCibNamed:aName owner:anOwner loadDelegate:nil]; } - (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable @@ -76,7 +73,7 @@ var CPCibOwner = @"CPCibOwner"; // Path is based solely on anOwner: var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle], - path = [bundle pathForResource:aName]; + path = [bundle _cibPathForResource:aName]; return [self loadCibFile:path externalNameTable:@{ CPCibOwner: anOwner } loadDelegate:aDelegate]; } @@ -91,6 +88,19 @@ var CPCibOwner = @"CPCibOwner"; externalNameTable:aNameTable]]); } +- (CPString)_cibPathForResource:(CPString)aName +{ + var defaultBundleLanguage = [self objectForInfoDictionaryKey:CPBundleDefaultLanguage], + typeOfLocalization = [self objectForInfoDictionaryKey:CPBundleTypeOfLocalization]; + + if (defaultBundleLanguage && (!typeOfLocalization || typeOfLocalization == CPBundleBaseLocalizationType)) + aName = @"Base.lproj/" + aName; + else if (defaultBundleLanguage && typeOfLocalization == CPBundleInterfaceBuilderLocalizationType) + aName = _bundle.loadedLanguage() + ".lproj/" + aName; + + return [self pathForResource:aName]; +} + @end @implementation _CPCibLoadDelegate : CPObject diff --git a/AppKit/Cib/_CPCibKeyedUnarchiver.j b/AppKit/Cib/_CPCibKeyedUnarchiver.j index bdb88d1a0..e68c63ce2 100644 --- a/AppKit/Cib/_CPCibKeyedUnarchiver.j +++ b/AppKit/Cib/_CPCibKeyedUnarchiver.j @@ -21,16 +21,22 @@ */ @import - +@import @implementation _CPCibKeyedUnarchiver : CPKeyedUnarchiver { - CPBundle _bundle; - BOOL _awakenCustomResources; - CPDictionary _externalObjectsForProxyIdentifiers; + BOOL _awakenCustomResources @accessors(getter=awakenCustomResources); + CPBundle _bundle @accessors(getter=bundle); + CPDictionary _externalObjectsForProxyIdentifiers @accessors(setter=setExternalObjectsForProxyIdentifiers:); + CPString _cibName @accessors(getter=cibName); } - (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources +{ + return [self initForReadingWithData:data bundle:aBundle awakenCustomResources:shouldAwakenCustomResources cibName:@""]; +} + +- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources cibName:(CPString)aCibName { self = [super initForReadingWithData:data]; @@ -38,6 +44,7 @@ { _bundle = aBundle; _awakenCustomResources = shouldAwakenCustomResources; + _cibName = aCibName; [self setDelegate:self]; } @@ -45,21 +52,6 @@ return self; } -- (CPBundle)bundle -{ - return _bundle; -} - -- (BOOL)awakenCustomResources -{ - return _awakenCustomResources; -} - -- (void)setExternalObjectsForProxyIdentifiers:(CPDictionary)externalObjectsForProxyIdentifiers -{ - _externalObjectsForProxyIdentifiers = externalObjectsForProxyIdentifiers; -} - - (id)externalObjectForProxyIdentifier:(CPString)anIdentifier { return [_externalObjectsForProxyIdentifiers objectForKey:anIdentifier]; diff --git a/AppKit/Cib/_CPLocalizableString.j b/AppKit/Cib/_CPLocalizableString.j new file mode 100644 index 000000000..dca7608bb --- /dev/null +++ b/AppKit/Cib/_CPLocalizableString.j @@ -0,0 +1,62 @@ +/* + * _CPLocalizableString.j + * AppKit + * + * Created by Alexandre Wilhelm. + * Copyright 2015, Cappuccino Project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import +@import + +@implementation _CPLocalizableString : CPObject +{ + CPString _dev @accessors(property=dev); + CPString _key @accessors(property=key); + CPString _value @accessors(property=value); +} + +@end + + +var CPLocalizableStringDev = @"CPLocalizableStringDev", + CPLocalizableStringKey = @"CPLocalizableStringKey", + CPLocalizableStringValue = @"CPLocalizableStringValue"; + +@implementation _CPLocalizableString (CPCoding) + +- (id)initWithCoder:(CPCoder)aCoder +{ + [self init]; + + _dev = [aCoder decodeObjectForKey:CPLocalizableStringDev]; + _key = [aCoder decodeObjectForKey:CPLocalizableStringKey]; + _value = [aCoder decodeObjectForKey:CPLocalizableStringValue]; + + var tableName = [[aCoder cibName] stringByTrimmingCharactersInSet:[CPCharacterSet characterSetWithCharactersInString:@".cib"]]; + + return [[aCoder bundle] localizedStringForKey:_key value:_value table:tableName]; +} + +- (void)encodeWithCoder:(CPCoder)aCoder +{ + [aCoder encodeObject:_dev forKey:CPLocalizableStringDev]; + [aCoder encodeObject:_key forKey:CPLocalizableStringKey]; + [aCoder encodeObject:_value forKey:CPLocalizableStringValue]; +} + +@end \ No newline at end of file diff --git a/Foundation/CPBundle.j b/Foundation/CPBundle.j index 817ba6717..069e0e6eb 100644 --- a/Foundation/CPBundle.j +++ b/Foundation/CPBundle.j @@ -25,8 +25,18 @@ @import "CPNotificationCenter.j" @import "CPObject.j" +@global CFBundleCopyBundleLocalizations +@global CFBundleCopyLocalizedString + CPBundleDidLoadNotification = @"CPBundleDidLoadNotification"; +@protocol CPBundleDelegate + +@required +- (void)bundleDidFinishLoading:(CPBundle)aBundle; + +@end + /*! @class CPBundle @ingroup foundation @@ -37,8 +47,8 @@ var CPBundlesForURLStrings = { }; @implementation CPBundle : CPObject { - CFBundle _bundle; - id _delegate; + CFBundle _bundle; + id _delegate; } + (CPBundle)bundleWithURL:(CPURL)aURL @@ -94,6 +104,7 @@ var CPBundlesForURLStrings = { }; if (self) { _bundle = new CFBundle(aURL); + CPBundlesForURLStrings[URLString] = self; } @@ -154,6 +165,21 @@ var CPBundlesForURLStrings = { }; return _bundle.pathForResource(aFilename); } +- (CPString)pathForResource:(CPString)aFilename ofType:(CPString)extension +{ + return _bundle.pathForResource(aFilename, extension); +} + +- (CPString)pathForResource:(CPString)aFilename ofType:(CPString)extension inDirectory:(CPString)subpath +{ + return _bundle.pathForResource(aFilename, extension, subpath); +} + +- (CPString)pathForResource:(CPString)aFilename ofType:(CPString)extension inDirectory:(CPString)subpath forLocalization:(CPString)localizationName +{ + return _bundle.pathForResource(aFilename, extension, subpath, localizationName); +} + - (CPDictionary)infoDictionary { return _bundle.infoDictionary(); @@ -164,7 +190,7 @@ var CPBundlesForURLStrings = { }; return _bundle.valueForInfoDictionaryKey(aKey); } -- (void)loadWithDelegate:(id)aDelegate +- (void)loadWithDelegate:(id )aDelegate { _delegate = aDelegate; @@ -212,4 +238,33 @@ var CPBundlesForURLStrings = { }; return [super description] + "(" + [self bundlePath] + ")"; } + +#pragma mark - +#pragma mark Localization + +- (CPArray)localizations +{ + return CFBundleCopyBundleLocalizations(_bundle); +} + +- (CPString)localizedStringForKey:(CPString)aKey value:(CPString)aValue table:(CPString)aTable +{ + return CFBundleCopyLocalizedString(_bundle, aKey, aValue, aTable); +} + @end + +function CPLocalizedString(key, comment) +{ + return CFCopyLocalizedString(key, comment); +} + +function CPLocalizedStringFromTable(key, table, comment) +{ + return CFCopyLocalizedStringFromTable(key, table, comment); +} + +function CPCopyLocalizedStringFromTableInBundle(key, table, bundle, comment) +{ + return CFCopyLocalizedStringFromTableInBundle(key, table, bundle._bundle, comment); +} \ No newline at end of file diff --git a/Objective-J/CFBundle.js b/Objective-J/CFBundle.js index db3f77190..995b60904 100644 --- a/Objective-J/CFBundle.js +++ b/Objective-J/CFBundle.js @@ -20,20 +20,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -var CFBundleUnloaded = 0, - CFBundleLoading = 1 << 0, - CFBundleLoadingInfoPlist = 1 << 1, - CFBundleLoadingExecutable = 1 << 2, - CFBundleLoadingSpritedImages = 1 << 3, - CFBundleLoaded = 1 << 4; +var CFBundleUnloaded = 0, + CFBundleLoading = 1 << 0, + CFBundleLoadingInfoPlist = 1 << 1, + CFBundleLoadingExecutable = 1 << 2, + CFBundleLoadingSpritedImages = 1 << 3, + CFBundleLoadingLocalizableStrings = 1 << 4, + CFBundleLoaded = 1 << 5; var CFBundlesForURLStrings = { }, CFBundlesForClasses = { }, CFBundlesWithIdentifiers = { }, - CFCacheBuster = new Date().getTime(), - CFTotalBytesLoaded = 0, + CFCacheBuster = new Date().getTime(), + CFTotalBytesLoaded = 0, CPApplicationSizeInBytes = 0; +var CPBundleDefaultBrowserLanguage = "CPBundleDefaultBrowserLanguage", + CPBundleDefaultLanguage = "CPBundleDefaultLanguage"; + GLOBAL(CFBundle) = function(/*CFURL|String*/ aURL) { aURL = makeAbsoluteURL(aURL).asDirectoryPathURL(); @@ -58,6 +62,9 @@ GLOBAL(CFBundle) = function(/*CFURL|String*/ aURL) this._infoDictionary = new CFDictionary(); this._eventDispatcher = new EventDispatcher(this); + + this._localizableStrings = []; + this._loadedLanguage = NULL; } DISPLAY_NAME(CFBundle); @@ -145,11 +152,14 @@ CFBundle.prototype.resourcesDirectoryURL = function() DISPLAY_NAME(CFBundle.prototype.resourcesDirectoryURL); -CFBundle.prototype.resourceURL = function(/*String*/ aResourceName, /*String*/ aType, /*String*/ aSubDirectory) +CFBundle.prototype.resourceURL = function(/*String*/ aResourceName, /*String*/ aType, /*String*/ aSubDirectory, /*String*/ localizationName) { if (aType) aResourceName = aResourceName + "." + aType; + if (localizationName) + aResourceName = localizationName + aResourceName; + if (aSubDirectory) aResourceName = aSubDirectory + "/" + aResourceName; @@ -194,6 +204,11 @@ CFBundle.prototype.infoDictionary = function() DISPLAY_NAME(CFBundle.prototype.infoDictionary); +CFBundle.prototype.loadedLanguage = function() +{ + return this._loadedLanguage; +}; + CFBundle.prototype.valueForInfoDictionaryKey = function(/*String*/ aKey) { return this._infoDictionary.valueForKey(aKey); @@ -318,6 +333,7 @@ CFBundle.prototype.load = function(/*BOOL*/ shouldExecute) if (self === CFBundle.mainBundle() && self.valueForInfoDictionaryKey("CPApplicationSize")) CPApplicationSizeInBytes = self.valueForInfoDictionaryKey("CPApplicationSize").valueForKey("executable") || 0; + loadLanguageForBundle(self); loadExecutableAndResources(self, shouldExecute); } @@ -354,6 +370,7 @@ function loadExecutableAndResources(/*Bundle*/ aBundle, /*BOOL*/ shouldExecute) loadExecutableForBundle(aBundle, success, failure, progress); loadSpritedImagesForBundle(aBundle, success, failure, progress); + loadLocalizableStringsForBundle(aBundle, success, failure, progress); if (aBundle._loadStatus === CFBundleLoading) return success(); @@ -490,6 +507,120 @@ function loadSpritedImagesForBundle(/*Bundle*/ aBundle, success, failure, progre }, failure, progress); } +function loadLocalizableStringsForBundle(/*Bundle*/ aBundle, success, failure, progress) +{ + var language = aBundle._loadedLanguage; + + if (!language) + return; + + var localizableStrings = aBundle.valueForInfoDictionaryKey("CPBundleLocalizableStrings"); + + if (!localizableStrings) + return; + + var self = aBundle, + length = localizableStrings.length, + languagePathURL = new CFURL(language + ".lproj/", self.resourcesDirectoryURL()), + fileSuccessed = 0; + + for (var i = 0; i < length; i++) + { + var localizableString = localizableStrings[i]; + + function onsuccess(/*Event*/ anEvent) + { + var contentFile = anEvent.request.responseText(), + tableName = new CFURL(anEvent.request._URL).lastPathComponent(); + + try + { + loadLocalizableContentForFileInBundle(self, contentFile, tableName); + + if (++fileSuccessed == length) + { + aBundle._loadStatus &= ~CFBundleLoadingLocalizableStrings; + success(); + } + } + catch(e) + { + failure(new Error("Error when parsing the localizable file " + tableName)); + } + } + + aBundle._loadStatus |= CFBundleLoadingLocalizableStrings; + new FileRequest(new CFURL(localizableString, languagePathURL), onsuccess, failure, progress); + } +} + +function loadLocalizableContentForFileInBundle(bundle, contentFile, tableName) +{ + var values = {}, + lines = contentFile.split("\n"), + currentContext; + + bundle._localizableStrings[tableName] = values; + + for (var i = 0; i < lines.length; i++) + { + var line = lines[i]; + + // Context + if (line[0] == "/") + { + currentContext = line.substring(2, line.length - 2).trim(); + continue; + } + + // Key + if (line[0] == "\"") + { + var split = line.split("\"") + + // Here we add twice the translated value, once with the context and once without + // This will help in term of rapidity when asking the value of the key + + var key = split[1]; + + if (!(key in values)) + values[key] = split[3]; + + key += currentContext; + + if (!(key in values)) + values[key] = split[3]; + + continue; + } + } +} + +function loadLanguageForBundle(aBundle) +{ + if (aBundle._loadedLanguage) + return; + + var defaultLanguage = aBundle.valueForInfoDictionaryKey(CPBundleDefaultLanguage); + + if (defaultLanguage != CPBundleDefaultBrowserLanguage && defaultLanguage) + { + aBundle._loadedLanguage = defaultLanguage; + return; + } + + if (typeof navigator == "undefined") + return; + + // userLanguage is an IE only property. + var language = (typeof navigator.language !== "undefined") ? navigator.language : navigator.userLanguage; + + if (!language) + return; + + aBundle._loadedLanguage = language.substring(0, 2); +} + var CFBundleSpriteSupportListeners = [], CFBundleSupportedSpriteType = -1, CFBundleNoSpriteType = 0, @@ -734,7 +865,53 @@ CFBundle.prototype.path = function() return this.bundlePath.apply(this, arguments); }; -CFBundle.prototype.pathForResource = function(aResource) +CFBundle.prototype.pathForResource = function(aResource, aType, aSubDirectory, localizationName) { - return this.resourceURL(aResource).absoluteString(); + return this.resourceURL(aResource, aType, aSubDirectory, localizationName).absoluteString(); }; + +GLOBAL(CFBundleCopyLocalizedString) = function (/*Bundle*/ bundle, key, value, tableName) +{ + return CFCopyLocalizedStringWithDefaultValue(key, tableName, bundle, value, ""); +} + +GLOBAL(CFBundleCopyBundleLocalizations) = function (/*Bundle*/ aBundle) +{ + return [this._loadedLanguage]; +} + +GLOBAL(CFCopyLocalizedString) = function (key, comment) +{ + return CFCopyLocalizedStringFromTable(key, "Localizable", comment); +} + +GLOBAL(CFCopyLocalizedStringFromTable) = function (key, tableName, comment) +{ + return CFCopyLocalizedStringFromTableInBundle(key, tableName, CFBundleGetMainBundle(), comment); +} + +GLOBAL(CFCopyLocalizedStringFromTableInBundle) = function (key, tableName, bundle, comment) +{ + return CFCopyLocalizedStringWithDefaultValue(key, tableName, bundle, null, comment); +} + +GLOBAL(CFCopyLocalizedStringWithDefaultValue) = function (key, tableName, bundle, value, comment) +{ + var string; + + if (!tableName) + tableName = "Localizable"; + + tableName += ".strings"; + + var localizableString = bundle._localizableStrings[tableName]; + + string = localizableString ? localizableString[key + comment] : null; + + return string || (value || key); +} + +GLOBAL(CFBundleGetMainBundle) = function () +{ + return CFBundle.mainBundle(); +} diff --git a/Tests/Foundation/BundleTest/Info.plist b/Tests/Foundation/BundleTest/Info.plist new file mode 100644 index 000000000..6a2f0fe2d --- /dev/null +++ b/Tests/Foundation/BundleTest/Info.plist @@ -0,0 +1,16 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + BundleTest + CPBundleLocalizableStrings + + Localizable.strings + + CPBundleDefaultLanguage + fr + + diff --git a/Tests/Foundation/BundleTest/Resources/fr.lproj/Localizable.strings b/Tests/Foundation/BundleTest/Resources/fr.lproj/Localizable.strings new file mode 100644 index 000000000..1c16f3ac7 --- /dev/null +++ b/Tests/Foundation/BundleTest/Resources/fr.lproj/Localizable.strings @@ -0,0 +1,5 @@ +/* My first context. */ +"Label from file" = "Label traduit de fr.lproj du premier context"; + +/* My second context. */ +"Label from file" = "Label traduit de fr.lproj du second context"; \ No newline at end of file diff --git a/Tests/Foundation/CPBundleTest.j b/Tests/Foundation/CPBundleTest.j new file mode 100644 index 000000000..f301175fc --- /dev/null +++ b/Tests/Foundation/CPBundleTest.j @@ -0,0 +1,69 @@ +@import + +@implementation CPBundleTest : OJTestCase +{ + +} + ++ (void)setUp +{ + +} + ++ (void)tearDown +{ + +} + +- (void)setUp +{ + +} + +- (void)tearDown +{ + +} + +- (void)testCreationMainBundle +{ + var bundle = [CPBundle mainBundle]; +} + +- (void)testLoadingBundle +{ + var bundle = [CPBundle bundleWithPath:@"Tests/Foundation/BundleTest"]; + [bundle loadWithDelegate:self]; + + [self assert:[bundle objectForInfoDictionaryKey:"CPBundleDefaultLanguage"] equals:"fr"]; + [self assert:[bundle objectForInfoDictionaryKey:"CPBundleLocalizableStrings"] equals:["Localizable.strings"]]; +} + +- (void)testLocalization +{ + var bundle = [CPBundle bundleWithPath:@"Tests/Foundation/BundleTest"]; + [bundle loadWithDelegate:self]; + + [self assert:[bundle localizedStringForKey:"Label from file" value:"" table:"Localizable"] equals:"Label traduit de fr.lproj du premier context"]; + [self assert:[bundle localizedStringForKey:"Wrong key" value:"Default value" table:"Localizable"] equals:"Default value"]; + [self assert:[bundle localizedStringForKey:"Wrong key" value:"" table:"Localizable"] equals:"Wrong key"]; + + [self assert:CPCopyLocalizedStringFromTableInBundle("Label from file", "Localizable", bundle, "My first context.") equals:"Label traduit de fr.lproj du premier context"]; + [self assert:CPCopyLocalizedStringFromTableInBundle("Label from file", "", bundle, "My first context.") equals:"Label traduit de fr.lproj du premier context"]; + [self assert:CPCopyLocalizedStringFromTableInBundle("Label from file", "Localizable", bundle, "") equals:"Label traduit de fr.lproj du premier context"]; + [self assert:CPCopyLocalizedStringFromTableInBundle("Wrong key", "Localizable", bundle, "") equals:"Wrong key"]; + [self assert:CPCopyLocalizedStringFromTableInBundle("Wrong key", "coucou", bundle, "") equals:"Wrong key"]; + + [self assert:CPCopyLocalizedStringFromTableInBundle("Label from file", "Localizable", bundle, "My second context.") equals:"Label traduit de fr.lproj du second context"]; +} + +@end + +@implementation CPBundleTest (CPBundleTestBundleDelegate) + +- (void)bundleDidFinishLoading:(CPBundle)aBundle +{ + +} + +@end \ No newline at end of file diff --git a/Tests/Manual/CPLocalizationTest/AppController.j b/Tests/Manual/CPLocalizationTest/AppController.j new file mode 100644 index 000000000..1d4141578 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/AppController.j @@ -0,0 +1,53 @@ +/* + * AppController.j + * CPLocalizationTest + * + * Created by You on April 20, 2015. + * Copyright 2015, Your Company All rights reserved. + */ + +@import +@import + + +@implementation AppController : CPObject +{ + @outlet CPWindow theWindow; +} + +- (void)applicationDidFinishLaunching:(CPNotification)aNotification +{ + // This is called when the application is done loading. +} + +- (void)awakeFromCib +{ + var label = [CPTextField labelWithTitle:CPLocalizedString(@"Label from file", @"") + " -> Label title from en.lproj from first context"]; + [label setFrameOrigin:CGPointMake(20, 10)]; + [[theWindow contentView] addSubview:label]; + + var label2 = [CPTextField labelWithTitle:CPLocalizedString(@"Label from file", @"My second context.") + " -> Label title from en.lproj from second context"]; + [label2 setFrameOrigin:CGPointMake(20, 30)]; + [[theWindow contentView] addSubview:label2]; + + var label3 = [CPTextField labelWithTitle:CPLocalizedString(@"Label from file", @"My first context.") + " -> Label title from en.lproj from first context"]; + [label3 setFrameOrigin:CGPointMake(20, 50)]; + [[theWindow contentView] addSubview:label3]; + + var label4 = [CPTextField labelWithTitle:CPLocalizedStringFromTable(@"Label from file", @"SecondLocalizable", @"My first context.") + " -> Label title from first context from en.lproj from SecondLocalizable"]; + [label4 setFrameOrigin:CGPointMake(20, 70)]; + [[theWindow contentView] addSubview:label4]; + + var label5 = [CPTextField labelWithTitle:CPLocalizedString(@"Wrong key", @"") + " -> Wrong key"]; + [label5 setFrameOrigin:CGPointMake(20, 90)]; + [[theWindow contentView] addSubview:label5]; + + // This is called when the cib is done loading. + // You can implement this method on any object instantiated from a Cib. + // It's a useful hook for setting up current UI values, and other things. + + // In this case, we want the window from Cib to become our full browser window + [theWindow setFullPlatformWindow:YES]; +} + +@end diff --git a/Tests/Manual/CPLocalizationTest/Info.plist b/Tests/Manual/CPLocalizationTest/Info.plist new file mode 100644 index 000000000..5b71bb727 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Info.plist @@ -0,0 +1,24 @@ + + + + + Main cib file base name + MainMenu.cib + CPBundleName + CPLocalizationTest + CPBundleVersion + 1.0 + CPHumanReadableCopyright + Copyright © 2015, Your Company All rights reserved. + CPBundleLocalizableStrings + + Localizable.strings + SecondLocalizable.strings + MainMenu.strings + + CPBundleTypeOfLocalization + CPBundleBaseLocalizationType + CPBundleDefaultLanguage + en + + diff --git a/Tests/Manual/CPLocalizationTest/Jakefile b/Tests/Manual/CPLocalizationTest/Jakefile new file mode 100644 index 000000000..991dcebdc --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Jakefile @@ -0,0 +1,184 @@ +/* + * Jakefile + * CPLocalizationTest + * + * Created by You on April 20, 2015. + * Copyright 2015, Your Company All rights reserved. + */ + +var ENV = require("system").env, + FILE = require("file"), + JAKE = require("jake"), + task = JAKE.task, + FileList = JAKE.FileList, + app = require("cappuccino/jake").app, + configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug", + OS = require("os"), + projectName = "CPLocalizationTest"; + +app (projectName, function(task) +{ + ENV["OBJJ_INCLUDE_PATHS"] = "Frameworks"; + + if (configuration === "Debug") + ENV["OBJJ_INCLUDE_PATHS"] = FILE.join(ENV["OBJJ_INCLUDE_PATHS"], configuration); + + task.setBuildIntermediatesPath(FILE.join("Build", "CPLocalizationTest.build", configuration)); + task.setBuildPath(FILE.join("Build", configuration)); + + task.setProductName("CPLocalizationTest"); + task.setIdentifier("com.yourcompany.CPLocalizationTest"); + task.setVersion("1.0"); + task.setAuthor("Your Company"); + task.setEmail("feedback @nospam@ yourcompany.com"); + task.setSummary("CPLocalizationTest"); + task.setSources(new FileList("**/*.j").exclude(FILE.join("Build", "**")).exclude(FILE.join("Frameworks", "Source", "**"))); + task.setResources(new FileList("Resources/**")); + task.setIndexFilePath("index.html"); + task.setInfoPlistPath("Info.plist"); + + if (configuration === "Debug") + task.setCompilerFlags("-DDEBUG -g"); + else + task.setCompilerFlags("-O"); +}); + +task ("default", [projectName], function() +{ + printResults(configuration); +}); + +task ("build", ["default"], function() +{ + updateApplicationSize(); +}); + +task ("debug", function() +{ + configuration = ENV["CONFIGURATION"] = "Debug"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("release", function() +{ + configuration = ENV["CONFIGURATION"] = "Release"; + JAKE.subjake(["."], "build", ENV); +}); + +task ("run", ["debug"], function() +{ + OS.system(["open", FILE.join("Build", "Debug", projectName, "index.html")]); +}); + +task ("run-release", ["release"], function() +{ + OS.system(["open", FILE.join("Build", "Release", projectName, "index.html")]); +}); + +task ("deploy", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Deployment", projectName)); + OS.system(["press", "-f", FILE.join("Build", "Release", projectName), FILE.join("Build", "Deployment", projectName)]); + printResults("Deployment") +}); + +task ("desktop", ["release"], function() +{ + FILE.mkdirs(FILE.join("Build", "Desktop", projectName)); + require("cappuccino/nativehost").buildNativeHost(FILE.join("Build", "Release", projectName), FILE.join("Build", "Desktop", projectName, "CPLocalizationTest.app")); + printResults("Desktop") +}); + +task ("run-desktop", ["desktop"], function() +{ + OS.system([FILE.join("Build", "Desktop", projectName, "CPLocalizationTest.app", "Contents", "MacOS", "NativeHost"), "-i"]); +}); + +function printResults(configuration) +{ + print("----------------------------"); + print(configuration+" app built at path: "+FILE.join("Build", configuration, projectName)); + print("----------------------------"); +} + +function updateApplicationSize() +{ + print("Calculating application file sizes..."); + + var contents = FILE.read(FILE.join("Build", configuration, projectName, "Info.plist"), { charset:"UTF-8" }), + format = CFPropertyList.sniffedFormatOfString(contents), + plist = CFPropertyList.propertyListFromString(contents), + totalBytes = {executable:0, data:0, mhtml:0}; + + // Get the size of all framework executables and sprite data + var frameworksDir = "Frameworks"; + + if (configuration === "Debug") + frameworksDir = FILE.join(frameworksDir, "Debug"); + + var frameworks = FILE.list(frameworksDir); + + frameworks.forEach(function(framework) + { + if (framework !== "Source") + addBundleFileSizes(FILE.join(frameworksDir, framework), totalBytes); + }); + + // Read in the default theme name, and attempt to get its size + var themeName = plist.valueForKey("CPDefaultTheme") || "Aristo2", + themePath = nil; + + if (themeName === "Aristo" || themeName === "Aristo2") + themePath = FILE.join(frameworksDir, "AppKit", "Resources", themeName + ".blend"); + else + themePath = FILE.join("Frameworks", "Resources", themeName + ".blend"); + + if (FILE.isDirectory(themePath)) + addBundleFileSizes(themePath, totalBytes); + + // Add sizes for the app + addBundleFileSizes(FILE.join("Build", configuration, projectName), totalBytes); + + print("Executables: " + totalBytes.executable + ", sprite data: " + totalBytes.data + ", total: " + (totalBytes.executable + totalBytes.data)); + + var dict = new CFMutableDictionary(); + + dict.setValueForKey("executable", totalBytes.executable); + dict.setValueForKey("data", totalBytes.data); + dict.setValueForKey("mhtml", totalBytes.mhtml); + + plist.setValueForKey("CPApplicationSize", dict); + + FILE.write(FILE.join("Build", configuration, projectName, "Info.plist"), CFPropertyList.stringFromPropertyList(plist, format), { charset:"UTF-8" }); +} + +function addBundleFileSizes(bundlePath, totalBytes) +{ + var bundleName = FILE.basename(bundlePath), + environment = bundleName === "Foundation" ? "Objj" : "Browser", + bundlePath = FILE.join(bundlePath, environment + ".environment"); + + if (FILE.isDirectory(bundlePath)) + { + var filename = bundleName + ".sj", + filePath = new FILE.Path(FILE.join(bundlePath, filename)); + + if (filePath.exists()) + totalBytes.executable += filePath.size(); + + filePath = new FILE.Path(FILE.join(bundlePath, "dataURLs.txt")); + + if (filePath.exists()) + totalBytes.data += filePath.size(); + + filePath = new FILE.Path(FILE.join(bundlePath, "MHTMLData.txt")); + + if (filePath.exists()) + totalBytes.mhtml += filePath.size(); + + filePath = new FILE.Path(FILE.join(bundlePath, "MHTMLPaths.txt")); + + if (filePath.exists()) + totalBytes.mhtml += filePath.size(); + } +} diff --git a/Tests/Manual/CPLocalizationTest/Resources/Base.lproj/MainMenu.cib b/Tests/Manual/CPLocalizationTest/Resources/Base.lproj/MainMenu.cib new file mode 100644 index 000000000..2a05f4f95 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Resources/Base.lproj/MainMenu.cib @@ -0,0 +1 @@ +280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;0E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;0E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;4E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;1;0E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;1;6E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;1;7E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;1;8E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;1;9E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;11E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;13E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;15E;D;K;6;CP$UIDd;2;16E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;19E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;1;0E;D;K;6;CP$UIDd;2;24E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;11E;D;K;6;CP$UIDd;2;19E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;11E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;25E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;12E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;26E;E;D;K;10;$classnameS;20;CPCibOutletConnectorK;8;$classesA;S;20;CPCibOutletConnectorS;14;CPCibConnectorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;11E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;24E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;27E;E;D;K;6;$classD;K;6;CP$UIDd;2;14E;K;24;_CPCibConnectorSourceKeyD;K;6;CP$UIDd;2;24E;K;29;_CPCibConnectorDestinationKeyD;K;6;CP$UIDd;2;19E;K;23;_CPCibConnectorLabelKeyD;K;6;CP$UIDd;2;28E;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;25E;E;D;K;10;$classnameS;20;_CPCibWindowTemplateK;8;$classesA;S;20;_CPCibWindowTemplateS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;18E;K;30;_CPCibWindowTemplateMaxSizeKeyD;K;6;CP$UIDd;2;29E;K;32;_CPCibWindowTemplateViewClassKeyD;K;6;CP$UIDd;1;0E;K;34;_CPCibWindowTemplateWindowClassKeyD;K;6;CP$UIDd;2;30E;K;30;_CPCibWindowTemplateWTFlagsKeyD;K;6;CP$UIDd;2;31E;K;33;_CPCibWindowTemplateWindowRectKeyD;K;6;CP$UIDd;2;32E;K;33;_CPCibWindowTemplateScreenRectKeyD;K;6;CP$UIDd;2;33E;K;30;_CPCibWindowTempatStyleMaskKeyD;K;6;CP$UIDd;2;34E;K;34;_CPCibWindowTemplateWindowTitleKeyD;K;6;CP$UIDd;2;36E;K;33;_CPCibWindowTemplateWindowViewKeyD;K;6;CP$UIDd;2;21E;E;D;K;10;$classnameS;6;CPViewK;8;$classesA;S;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;37E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;38E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;38E;K;17;CPViewSubviewsKeyD;K;6;CP$UIDd;2;39E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;1;0E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;40E;K;14;CPViewScaleKeyD;K;6;CP$UIDd;2;41E;K;18;CPViewSizeScaleKeyD;K;6;CP$UIDd;2;41E;K;17;CPViewIsScaledKeyD;K;6;CP$UIDd;2;42E;E;D;K;10;$classnameS;11;CPTextFieldK;8;$classesA;S;11;CPTextFieldS;9;CPControlS;6;CPViewS;11;CPResponderS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;22E;K;27;CPResponderNextResponderKeyD;K;6;CP$UIDd;2;21E;K;18;CPResponderMenuKeyD;K;6;CP$UIDd;1;0E;K;12;CPViewTagKeyD;K;6;CP$UIDd;2;37E;K;14;CPViewFrameKeyD;K;6;CP$UIDd;2;43E;K;15;CPViewBoundsKeyD;K;6;CP$UIDd;2;44E;K;18;CPViewSuperviewKeyD;K;6;CP$UIDd;2;21E;K;22;CPViewAutoresizingMaskD;K;6;CP$UIDd;2;45E;K;19;CPViewThemeClassKeyD;K;6;CP$UIDd;2;46E;K;19;CPViewThemeStateKeyD;K;6;CP$UIDd;2;47E;K;11;$aalignmentD;K;6;CP$UIDd;2;48E;K;17;$aline-break-modeD;K;6;CP$UIDd;2;49E;K;6;$afontD;K;6;CP$UIDd;2;51E;K;14;CPViewScaleKeyD;K;6;CP$UIDd;2;41E;K;18;CPViewSizeScaleKeyD;K;6;CP$UIDd;2;41E;K;17;CPViewIsScaledKeyD;K;6;CP$UIDd;2;42E;K;35;CPControlSendsActionOnEndEditingKeyD;K;6;CP$UIDd;2;52E;K;17;CPControlValueKeyD;K;6;CP$UIDd;2;53E;K;24;CPControlSendActionOnKeyD;K;6;CP$UIDd;2;48E;K;23;CPControlControlSizeKeyD;K;6;CP$UIDd;2;37E;K;24;CPTextFieldIsEditableKeyD;K;6;CP$UIDd;2;42E;K;26;CPTextFieldIsSelectableKeyD;K;6;CP$UIDd;2;42E;K;29;CPTextFieldDrawsBackgroundKeyD;K;6;CP$UIDd;2;42E;K;29;CPTextFieldBackgroundColorKeyD;K;6;CP$UIDd;2;55E;K;27;CPTextFieldLineBreakModeKeyD;K;6;CP$UIDd;2;49E;K;23;CPTextFieldAlignmentKeyD;K;6;CP$UIDd;2;48E;K;31;CPTextFieldPlaceholderStringKeyD;K;6;CP$UIDd;1;0E;K;29;CPTextFieldUsesSingleLineModeD;K;6;CP$UIDd;2;42E;K;16;CPTextFieldWrapsD;K;6;CP$UIDd;2;42E;K;18;CPTextFieldScrollsD;K;6;CP$UIDd;2;52E;E;D;K;6;$classD;K;6;CP$UIDd;2;10E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;56E;E;S;13;CPApplicationD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;19E;E;E;S;8;delegateS;9;theWindowS;32;{10000000000000, 10000000000000}S;8;CPWindowd;10;1879048192S;24;{{335, 127}, {480, 360}}S;21;{{0, 0}, {1440, 877}}d;1;7D;K;10;$classnameS;20;_CPLocalizableStringK;8;$classesA;S;20;_CPLocalizableStringS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;35E;K;22;CPLocalizableStringDevD;K;6;CP$UIDd;2;57E;K;22;CPLocalizableStringKeyD;K;6;CP$UIDd;2;58E;K;24;CPLocalizableStringValueD;K;6;CP$UIDd;2;57E;E;d;1;0S;20;{{0, 0}, {480, 360}}D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;23E;E;E;S;6;normalS;6;{1, 1}F;S;22;{{20, 166}, {364, 17}}S;19;{{0, 0}, {364, 17}}d;2;36S;9;textfieldS;18;controlSizeRegulard;1;4d;1;2D;K;10;$classnameS;6;CPFontK;8;$classesA;S;6;CPFontS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;50E;K;13;CPFontNameKeyD;K;6;CP$UIDd;2;59E;K;13;CPFontSizeKeyD;K;6;CP$UIDd;2;60E;K;15;CPFontIsBoldKeyD;K;6;CP$UIDd;2;42E;K;17;CPFontIsItalicKeyD;K;6;CP$UIDd;2;42E;K;17;CPFontIsSystemKeyD;K;6;CP$UIDd;2;42E;E;T;D;K;6;$classD;K;6;CP$UIDd;2;35E;K;22;CPLocalizableStringDevD;K;6;CP$UIDd;2;61E;K;22;CPLocalizableStringKeyD;K;6;CP$UIDd;2;62E;K;24;CPLocalizableStringValueD;K;6;CP$UIDd;2;61E;E;D;K;10;$classnameS;7;CPColorK;8;$classesA;S;7;CPColorS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;54E;K;20;CPColorComponentsKeyD;K;6;CP$UIDd;2;63E;E;S;13;AppControllerS;6;WindowS;9;371.titleS;29;.Helvetica Neue DeskInterfaced;2;13S;29;Label not translated from xibS;9;461.titleD;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;64E;D;K;6;CP$UIDd;2;65E;E;E;f;18;0.6862745098039216d;1;1E;K;9;$archiverS;15;CPKeyedArchiverK;8;$versionS;6;100000E; \ No newline at end of file diff --git a/Tests/Manual/CPLocalizationTest/Resources/Base.lproj/MainMenu.xib b/Tests/Manual/CPLocalizationTest/Resources/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..574a3dbb2 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Resources/Base.lproj/MainMenu.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/Manual/CPLocalizationTest/Resources/en.lproj/Localizable.strings b/Tests/Manual/CPLocalizationTest/Resources/en.lproj/Localizable.strings new file mode 100644 index 000000000..c5ebdefa5 Binary files /dev/null and b/Tests/Manual/CPLocalizationTest/Resources/en.lproj/Localizable.strings differ diff --git a/Tests/Manual/CPLocalizationTest/Resources/en.lproj/MainMenu.strings b/Tests/Manual/CPLocalizationTest/Resources/en.lproj/MainMenu.strings new file mode 100644 index 000000000..99058cdd2 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Resources/en.lproj/MainMenu.strings @@ -0,0 +1,186 @@ + +/* Class = "NSMenuItem"; title = "Bring All to Front"; ObjectID = "5"; */ +"5.title" = "Bring All to Front"; + +/* Class = "NSMenuItem"; title = "Window"; ObjectID = "19"; */ +"19.title" = "Window"; + +/* Class = "NSMenuItem"; title = "Minimize"; ObjectID = "23"; */ +"23.title" = "Minimize"; + +/* Class = "NSMenu"; title = "Window"; ObjectID = "24"; */ +"24.title" = "Window"; + +/* Class = "NSMenu"; title = "AMainMenu"; ObjectID = "29"; */ +"29.title" = "AMainMenu"; + +/* Class = "NSMenuItem"; title = "NewApplication"; ObjectID = "56"; */ +"56.title" = "NewApplication"; + +/* Class = "NSMenu"; title = "NewApplication"; ObjectID = "57"; */ +"57.title" = "NewApplication"; + +/* Class = "NSMenuItem"; title = "About NewApplication"; ObjectID = "58"; */ +"58.title" = "About NewApplication"; + +/* Class = "NSMenuItem"; title = "Open…"; ObjectID = "72"; */ +"72.title" = "Open…"; + +/* Class = "NSMenuItem"; title = "Close"; ObjectID = "73"; */ +"73.title" = "Close"; + +/* Class = "NSMenuItem"; title = "Save"; ObjectID = "75"; */ +"75.title" = "Save"; + +/* Class = "NSMenuItem"; title = "Save As…"; ObjectID = "80"; */ +"80.title" = "Save As…"; + +/* Class = "NSMenu"; title = "File"; ObjectID = "81"; */ +"81.title" = "File"; + +/* Class = "NSMenuItem"; title = "New"; ObjectID = "82"; */ +"82.title" = "New"; + +/* Class = "NSMenuItem"; title = "File"; ObjectID = "83"; */ +"83.title" = "File"; + +/* Class = "NSMenuItem"; title = "Help"; ObjectID = "103"; */ +"103.title" = "Help"; + +/* Class = "NSMenu"; title = "Help"; ObjectID = "106"; */ +"106.title" = "Help"; + +/* Class = "NSMenuItem"; title = "NewApplication Help"; ObjectID = "111"; */ +"111.title" = "NewApplication Help"; + +/* Class = "NSMenuItem"; title = "Revert to Saved"; ObjectID = "112"; */ +"112.title" = "Revert to Saved"; + +/* Class = "NSMenuItem"; title = "Open Recent"; ObjectID = "124"; */ +"124.title" = "Open Recent"; + +/* Class = "NSMenu"; title = "Open Recent"; ObjectID = "125"; */ +"125.title" = "Open Recent"; + +/* Class = "NSMenuItem"; title = "Clear Menu"; ObjectID = "126"; */ +"126.title" = "Clear Menu"; + +/* Class = "NSMenuItem"; title = "Preferences…"; ObjectID = "129"; */ +"129.title" = "Preferences…"; + +/* Class = "NSMenuItem"; title = "Quit NewApplication"; ObjectID = "136"; */ +"136.title" = "Quit NewApplication"; + +/* Class = "NSMenuItem"; title = "Stop Speaking"; ObjectID = "195"; */ +"195.title" = "Stop Speaking"; + +/* Class = "NSMenuItem"; title = "Start Speaking"; ObjectID = "196"; */ +"196.title" = "Start Speaking"; + +/* Class = "NSMenuItem"; title = "Copy"; ObjectID = "197"; */ +"197.title" = "Copy"; + +/* Class = "NSMenuItem"; title = "Select All"; ObjectID = "198"; */ +"198.title" = "Select All"; + +/* Class = "NSMenuItem"; title = "Cut"; ObjectID = "199"; */ +"199.title" = "Cut"; + +/* Class = "NSMenu"; title = "Spelling and Grammar"; ObjectID = "200"; */ +"200.title" = "Spelling and Grammar"; + +/* Class = "NSMenuItem"; title = "Check Spelling"; ObjectID = "201"; */ +"201.title" = "Check Spelling"; + +/* Class = "NSMenuItem"; title = "Delete"; ObjectID = "202"; */ +"202.title" = "Delete"; + +/* Class = "NSMenuItem"; title = "Paste"; ObjectID = "203"; */ +"203.title" = "Paste"; + +/* Class = "NSMenuItem"; title = "Show Spelling…"; ObjectID = "204"; */ +"204.title" = "Show Spelling…"; + +/* Class = "NSMenu"; title = "Edit"; ObjectID = "205"; */ +"205.title" = "Edit"; + +/* Class = "NSMenuItem"; title = "Undo"; ObjectID = "207"; */ +"207.title" = "Undo"; + +/* Class = "NSMenuItem"; title = "Find Next"; ObjectID = "208"; */ +"208.title" = "Find Next"; + +/* Class = "NSMenuItem"; title = "Find…"; ObjectID = "209"; */ +"209.title" = "Find…"; + +/* Class = "NSMenuItem"; title = "Jump to Selection"; ObjectID = "210"; */ +"210.title" = "Jump to Selection"; + +/* Class = "NSMenuItem"; title = "Speech"; ObjectID = "211"; */ +"211.title" = "Speech"; + +/* Class = "NSMenu"; title = "Speech"; ObjectID = "212"; */ +"212.title" = "Speech"; + +/* Class = "NSMenuItem"; title = "Find Previous"; ObjectID = "213"; */ +"213.title" = "Find Previous"; + +/* Class = "NSMenuItem"; title = "Redo"; ObjectID = "215"; */ +"215.title" = "Redo"; + +/* Class = "NSMenuItem"; title = "Spelling and Grammar"; ObjectID = "216"; */ +"216.title" = "Spelling and Grammar"; + +/* Class = "NSMenuItem"; title = "Edit"; ObjectID = "217"; */ +"217.title" = "Edit"; + +/* Class = "NSMenuItem"; title = "Find"; ObjectID = "218"; */ +"218.title" = "Find"; + +/* Class = "NSMenuItem"; title = "Check Spelling While Typing"; ObjectID = "219"; */ +"219.title" = "Check Spelling While Typing"; + +/* Class = "NSMenu"; title = "Find"; ObjectID = "220"; */ +"220.title" = "Find"; + +/* Class = "NSMenuItem"; title = "Use Selection for Find"; ObjectID = "221"; */ +"221.title" = "Use Selection for Find"; + +/* Class = "NSMenuItem"; title = "Zoom"; ObjectID = "239"; */ +"239.title" = "Zoom"; + +/* Class = "NSMenuItem"; title = "View"; ObjectID = "295"; */ +"295.title" = "View"; + +/* Class = "NSMenu"; title = "View"; ObjectID = "296"; */ +"296.title" = "View"; + +/* Class = "NSMenuItem"; title = "Show Toolbar"; ObjectID = "297"; */ +"297.title" = "Show Toolbar"; + +/* Class = "NSMenuItem"; title = "Customize Toolbar…"; ObjectID = "298"; */ +"298.title" = "Customize Toolbar…"; + +/* Class = "NSMenuItem"; title = "Check Grammar With Spelling"; ObjectID = "346"; */ +"346.title" = "Check Grammar With Spelling"; + +/* Class = "NSMenuItem"; title = "Substitutions"; ObjectID = "348"; */ +"348.title" = "Substitutions"; + +/* Class = "NSMenu"; title = "Substitutions"; ObjectID = "349"; */ +"349.title" = "Substitutions"; + +/* Class = "NSMenuItem"; title = "Smart Copy/Paste"; ObjectID = "350"; */ +"350.title" = "Smart Copy/Paste"; + +/* Class = "NSMenuItem"; title = "Smart Quotes"; ObjectID = "351"; */ +"351.title" = "Smart Quotes"; + +/* Class = "NSMenuItem"; title = "Smart Links"; ObjectID = "354"; */ +"354.title" = "Smart Links"; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "371"; */ +"371.title" = "Window"; + +/* Class = "NSTextFieldCell"; title = "Label not translated from xib"; ObjectID = "461"; */ +"461.title" = "Label translated from xib in english"; diff --git a/Tests/Manual/CPLocalizationTest/Resources/en.lproj/SecondLocalizable.strings b/Tests/Manual/CPLocalizationTest/Resources/en.lproj/SecondLocalizable.strings new file mode 100644 index 000000000..c70c542d4 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Resources/en.lproj/SecondLocalizable.strings @@ -0,0 +1,2 @@ +/* My first context. */ +"Label from file" = "Label title from en.lproj from first context from SecondLocalizable"; diff --git a/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/Localizable.strings b/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/Localizable.strings new file mode 100644 index 000000000..f200b3f07 Binary files /dev/null and b/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/Localizable.strings differ diff --git a/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/MainMenu.strings b/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/MainMenu.strings new file mode 100644 index 000000000..8ae402c02 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/MainMenu.strings @@ -0,0 +1,186 @@ + +/* Class = "NSMenuItem"; title = "Bring All to Front"; ObjectID = "5"; */ +"5.title" = "Bring All to Front"; + +/* Class = "NSMenuItem"; title = "Window"; ObjectID = "19"; */ +"19.title" = "Window"; + +/* Class = "NSMenuItem"; title = "Minimize"; ObjectID = "23"; */ +"23.title" = "Minimize"; + +/* Class = "NSMenu"; title = "Window"; ObjectID = "24"; */ +"24.title" = "Window"; + +/* Class = "NSMenu"; title = "AMainMenu"; ObjectID = "29"; */ +"29.title" = "AMainMenu"; + +/* Class = "NSMenuItem"; title = "NewApplication"; ObjectID = "56"; */ +"56.title" = "NewApplication"; + +/* Class = "NSMenu"; title = "NewApplication"; ObjectID = "57"; */ +"57.title" = "NewApplication"; + +/* Class = "NSMenuItem"; title = "About NewApplication"; ObjectID = "58"; */ +"58.title" = "About NewApplication"; + +/* Class = "NSMenuItem"; title = "Open…"; ObjectID = "72"; */ +"72.title" = "Open…"; + +/* Class = "NSMenuItem"; title = "Close"; ObjectID = "73"; */ +"73.title" = "Close"; + +/* Class = "NSMenuItem"; title = "Save"; ObjectID = "75"; */ +"75.title" = "Save"; + +/* Class = "NSMenuItem"; title = "Save As…"; ObjectID = "80"; */ +"80.title" = "Save As…"; + +/* Class = "NSMenu"; title = "File"; ObjectID = "81"; */ +"81.title" = "File"; + +/* Class = "NSMenuItem"; title = "New"; ObjectID = "82"; */ +"82.title" = "New"; + +/* Class = "NSMenuItem"; title = "File"; ObjectID = "83"; */ +"83.title" = "File"; + +/* Class = "NSMenuItem"; title = "Help"; ObjectID = "103"; */ +"103.title" = "Help"; + +/* Class = "NSMenu"; title = "Help"; ObjectID = "106"; */ +"106.title" = "Help"; + +/* Class = "NSMenuItem"; title = "NewApplication Help"; ObjectID = "111"; */ +"111.title" = "NewApplication Help"; + +/* Class = "NSMenuItem"; title = "Revert to Saved"; ObjectID = "112"; */ +"112.title" = "Revert to Saved"; + +/* Class = "NSMenuItem"; title = "Open Recent"; ObjectID = "124"; */ +"124.title" = "Open Recent"; + +/* Class = "NSMenu"; title = "Open Recent"; ObjectID = "125"; */ +"125.title" = "Open Recent"; + +/* Class = "NSMenuItem"; title = "Clear Menu"; ObjectID = "126"; */ +"126.title" = "Clear Menu"; + +/* Class = "NSMenuItem"; title = "Preferences…"; ObjectID = "129"; */ +"129.title" = "Preferences…"; + +/* Class = "NSMenuItem"; title = "Quit NewApplication"; ObjectID = "136"; */ +"136.title" = "Quit NewApplication"; + +/* Class = "NSMenuItem"; title = "Stop Speaking"; ObjectID = "195"; */ +"195.title" = "Stop Speaking"; + +/* Class = "NSMenuItem"; title = "Start Speaking"; ObjectID = "196"; */ +"196.title" = "Start Speaking"; + +/* Class = "NSMenuItem"; title = "Copy"; ObjectID = "197"; */ +"197.title" = "Copy"; + +/* Class = "NSMenuItem"; title = "Select All"; ObjectID = "198"; */ +"198.title" = "Select All"; + +/* Class = "NSMenuItem"; title = "Cut"; ObjectID = "199"; */ +"199.title" = "Cut"; + +/* Class = "NSMenu"; title = "Spelling and Grammar"; ObjectID = "200"; */ +"200.title" = "Spelling and Grammar"; + +/* Class = "NSMenuItem"; title = "Check Spelling"; ObjectID = "201"; */ +"201.title" = "Check Spelling"; + +/* Class = "NSMenuItem"; title = "Delete"; ObjectID = "202"; */ +"202.title" = "Delete"; + +/* Class = "NSMenuItem"; title = "Paste"; ObjectID = "203"; */ +"203.title" = "Paste"; + +/* Class = "NSMenuItem"; title = "Show Spelling…"; ObjectID = "204"; */ +"204.title" = "Show Spelling…"; + +/* Class = "NSMenu"; title = "Edit"; ObjectID = "205"; */ +"205.title" = "Edit"; + +/* Class = "NSMenuItem"; title = "Undo"; ObjectID = "207"; */ +"207.title" = "Undo"; + +/* Class = "NSMenuItem"; title = "Find Next"; ObjectID = "208"; */ +"208.title" = "Find Next"; + +/* Class = "NSMenuItem"; title = "Find…"; ObjectID = "209"; */ +"209.title" = "Find…"; + +/* Class = "NSMenuItem"; title = "Jump to Selection"; ObjectID = "210"; */ +"210.title" = "Jump to Selection"; + +/* Class = "NSMenuItem"; title = "Speech"; ObjectID = "211"; */ +"211.title" = "Speech"; + +/* Class = "NSMenu"; title = "Speech"; ObjectID = "212"; */ +"212.title" = "Speech"; + +/* Class = "NSMenuItem"; title = "Find Previous"; ObjectID = "213"; */ +"213.title" = "Find Previous"; + +/* Class = "NSMenuItem"; title = "Redo"; ObjectID = "215"; */ +"215.title" = "Redo"; + +/* Class = "NSMenuItem"; title = "Spelling and Grammar"; ObjectID = "216"; */ +"216.title" = "Spelling and Grammar"; + +/* Class = "NSMenuItem"; title = "Edit"; ObjectID = "217"; */ +"217.title" = "Edit"; + +/* Class = "NSMenuItem"; title = "Find"; ObjectID = "218"; */ +"218.title" = "Find"; + +/* Class = "NSMenuItem"; title = "Check Spelling While Typing"; ObjectID = "219"; */ +"219.title" = "Check Spelling While Typing"; + +/* Class = "NSMenu"; title = "Find"; ObjectID = "220"; */ +"220.title" = "Find"; + +/* Class = "NSMenuItem"; title = "Use Selection for Find"; ObjectID = "221"; */ +"221.title" = "Use Selection for Find"; + +/* Class = "NSMenuItem"; title = "Zoom"; ObjectID = "239"; */ +"239.title" = "Zoom"; + +/* Class = "NSMenuItem"; title = "View"; ObjectID = "295"; */ +"295.title" = "View"; + +/* Class = "NSMenu"; title = "View"; ObjectID = "296"; */ +"296.title" = "View"; + +/* Class = "NSMenuItem"; title = "Show Toolbar"; ObjectID = "297"; */ +"297.title" = "Show Toolbar"; + +/* Class = "NSMenuItem"; title = "Customize Toolbar…"; ObjectID = "298"; */ +"298.title" = "Customize Toolbar…"; + +/* Class = "NSMenuItem"; title = "Check Grammar With Spelling"; ObjectID = "346"; */ +"346.title" = "Check Grammar With Spelling"; + +/* Class = "NSMenuItem"; title = "Substitutions"; ObjectID = "348"; */ +"348.title" = "Substitutions"; + +/* Class = "NSMenu"; title = "Substitutions"; ObjectID = "349"; */ +"349.title" = "Substitutions"; + +/* Class = "NSMenuItem"; title = "Smart Copy/Paste"; ObjectID = "350"; */ +"350.title" = "Smart Copy/Paste"; + +/* Class = "NSMenuItem"; title = "Smart Quotes"; ObjectID = "351"; */ +"351.title" = "Smart Quotes"; + +/* Class = "NSMenuItem"; title = "Smart Links"; ObjectID = "354"; */ +"354.title" = "Smart Links"; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "371"; */ +"371.title" = "Window"; + +/* Class = "NSTextFieldCell"; title = "Label not translated from xib"; ObjectID = "461"; */ +"461.title" = "Label traduit du xib en français"; \ No newline at end of file diff --git a/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/SecondLocalizable.strings b/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/SecondLocalizable.strings new file mode 100644 index 000000000..6de1256c8 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/Resources/fr.lproj/SecondLocalizable.strings @@ -0,0 +1,2 @@ +/* My first context. */ +"Label from file" = "Label traduit de en.lproj du premier context de SecondLocalizable"; diff --git a/Tests/Manual/CPLocalizationTest/index-debug.html b/Tests/Manual/CPLocalizationTest/index-debug.html new file mode 100644 index 000000000..13c385d7e --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/index-debug.html @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + CPLocalizationTest + + + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Tests/Manual/CPLocalizationTest/index.html b/Tests/Manual/CPLocalizationTest/index.html new file mode 100644 index 000000000..e80f2fe83 --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/index.html @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + CPLocalizationTest + + + + + + + + + + + + +
+
+
+ +
+
+ +
+ + diff --git a/Tests/Manual/CPLocalizationTest/main.j b/Tests/Manual/CPLocalizationTest/main.j new file mode 100644 index 000000000..c0df1910e --- /dev/null +++ b/Tests/Manual/CPLocalizationTest/main.j @@ -0,0 +1,18 @@ +/* + * AppController.j + * CPLocalizationTest + * + * Created by You on April 20, 2015. + * Copyright 2015, Your Company All rights reserved. + */ + +@import +@import + +@import "AppController.j" + + +function main(args, namedArgs) +{ + CPApplicationMain(args, namedArgs); +} diff --git a/Tools/nib2cib/NSAppKit.j b/Tools/nib2cib/NSAppKit.j index a45eac2e5..812a94d5a 100644 --- a/Tools/nib2cib/NSAppKit.j +++ b/Tools/nib2cib/NSAppKit.j @@ -46,6 +46,7 @@ @import "NSImageView.j" @import "NSLayoutConstraint.j" @import "NSLevelIndicator.j" +@import "NSLocalizableString.j" @import "NSMatrix.j" @import "NSMenu.j" @import "NSMenuItem.j" diff --git a/Tools/nib2cib/NSLocalizableString.j b/Tools/nib2cib/NSLocalizableString.j new file mode 100644 index 000000000..2b2149f0a --- /dev/null +++ b/Tools/nib2cib/NSLocalizableString.j @@ -0,0 +1,60 @@ +/* + * NSLocalizableString.j + * AppKit + * + * Created by Alexandre Wilhelm. + * Copyright 2015, Cappuccino Project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@import + +@implementation _CPLocalizableString (CPCoding) + +- (id)NS_initWithCoder:(CPCoder)aCoder +{ + self = [self init]; + + if (self) + { + _dev = [aCoder decodeObjectForKey:@"NSDev"]; + _key = [aCoder decodeObjectForKey:@"NSKey"]; + _value = [aCoder decodeObjectForKey:@"NS.string"]; + } + + return self; +} + +@end + + +@implementation NSLocalizableString : _CPLocalizableString +{ + +} + +- (id)initWithCoder:(CPCoder)aCoder +{ + return [self NS_initWithCoder:aCoder]; +} + +- (Class)classForKeyedArchiver +{ + return [_CPLocalizableString class]; +} + + +@end \ No newline at end of file