From 22fb297b6920bf1c1cea0d66e9a1952c3e766d14 Mon Sep 17 00:00:00 2001 From: Henry Fox Date: Fri, 15 Dec 2017 21:39:22 -0800 Subject: [PATCH] Fix NSLocalizedString and Add Localization Tests (#2824) * Fix NSLocalizedString and add new tests * Address CR Feedback. * Forgot to change to StringByAppendingPath * Nevermind. ASSERT_OBJCEQ does indeed work. * Address feedback. * Address feedback. --- .../PlugIn.subproj/CFBundle_Locale.c | 63 ++++++++++++++ .../Foundation.WindowsOnly.UnitTests.vcxproj | 3 +- ...tion.WindowsOnly.UnitTests.vcxproj.filters | 3 +- .../Base.lproj/Localizable.strings | 11 +++ .../WOCCatalog-WinStore10/WOCCatalog.vcxproj | 30 +++++-- .../WOCCatalog.vcxproj.filters | 27 +++++- .../de.lproj/Localizable.strings | 11 +++ .../es_MX.lproj/Localizable.strings | 11 +++ .../zh-Hant-TW.lproj/Localizable.strings | 11 +++ .../zh.lproj/Localizable.strings | 11 +++ .../WOCCatalog/LocalizationViewController.h | 21 +++++ .../WOCCatalog/LocalizationViewController.m | 82 +++++++++++++++++++ .../WOCCatalog/MainViewController.m | 6 +- .../WindowsOnly/BundleInternalTests.mm | 77 +++++++++++++++++ 14 files changed, 357 insertions(+), 10 deletions(-) create mode 100644 samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings create mode 100644 samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings create mode 100644 samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings create mode 100644 samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings create mode 100644 samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings create mode 100644 samples/WOCCatalog/WOCCatalog/LocalizationViewController.h create mode 100644 samples/WOCCatalog/WOCCatalog/LocalizationViewController.m create mode 100644 tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm diff --git a/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c b/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c index 6ca3a0d0c3..546673b52c 100644 --- a/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c +++ b/Frameworks/CoreFoundation/PlugIn.subproj/CFBundle_Locale.c @@ -531,6 +531,10 @@ CF_PRIVATE CFArrayRef _CFBundleCopyUserLanguages() { static CFArrayRef _CFBundleUserLanguages = NULL; static dispatch_once_t once = 0; dispatch_once(&once, ^{ +// WINOBJC: __CFAppleLanguages does not exist on Windows +#if DEPLOYMENT_TARGET_WINDOWS + _CFBundleUserLanguages = CFLocaleCopyPreferredLanguages(); +#else CFArrayRef preferencesArray = NULL; if (__CFAppleLanguages) { CFDataRef data; @@ -555,6 +559,7 @@ CF_PRIVATE CFArrayRef _CFBundleCopyUserLanguages() { _CFBundleUserLanguages = NULL; } if (preferencesArray) CFRelease(preferencesArray); +#endif }); if (_CFBundleUserLanguages) { @@ -663,8 +668,66 @@ static CFStringRef _CFBundleCopyLanguageFoundInLocalizations(CFArrayRef localiza return NULL; } +// WINOBJC: Helper functions for workaround in _CFBundleCreateMutableArrayOfFallbackLanguages +static CFStringRef _copyStringTruncated(CFStringRef localization, CFRange cutoff) { + return CFStringCreateWithSubstring(NULL, localization, CFRangeMake(0, cutoff.location)); +} + +static CFStringRef _copyStringWithUnderscores(CFStringRef localization) { + CFMutableStringRef underscoredString = CFStringCreateMutableCopy(NULL, 0, localization); + CFStringFindAndReplace(underscoredString, CFSTR("-"), CFSTR("_"), CFRangeMake(0, CFStringGetLength(underscoredString)), 0); + return underscoredString; +} + // Given a list of localizations (e.g., provided as argument to API, or present as .lproj directories), return a mutable array of localizations in preferred order. Returns NULL if nothing is found. static CFMutableArrayRef _CFBundleCreateMutableArrayOfFallbackLanguages(CFArrayRef availableLocalizations, CFArrayRef preferredLocalizations) { +// WINOBJC: The API that performs the work described below does not exist in our 3rd party libraries. ualoc_ is an Apple ICU addition. +#if DEPLOYMENT_TARGET_WINDOWS + // Here we need to intersect the preferred languages with the available localizations + // We know the user languages are in preferred order, add to this list in this order + // Prefer the full language locale, attempt to convert any hyphens to underscores as + // Windows language settings are retrieved with hyphens while underscores are commonly used for localization. + // Finally, attempt to truncate any underscores from the language to find a base localization. + // For example, an english locale will appear as "en-US" and a German locale will appear as "de-DE". + // A localization for "en-US" may be set up as "en-US", "en_US", or even just "en". + + CFMutableArrayRef resultArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + + for (CFIndex i = 0, preferredCount = CFArrayGetCount(preferredLocalizations); i < preferredCount; i++) { + CFStringRef preferredLocalization = (CFStringRef)CFArrayGetValueAtIndex(preferredLocalizations, i); + for (CFIndex j = 0, availableCount = CFArrayGetCount(availableLocalizations); j < availableCount; j++) { + CFStringRef availableLocalization = (CFStringRef)CFArrayGetValueAtIndex(availableLocalizations, j); + if(CFStringCompare(preferredLocalization, availableLocalization, 0) == kCFCompareEqualTo) { + CFArrayAppendValue(resultArray, preferredLocalization); + } + CFRange hyphenation; + if (CFStringFindWithOptions(preferredLocalization, CFSTR("-"), CFRangeMake(0, CFStringGetLength(preferredLocalization)), kCFCompareCaseInsensitive, &hyphenation) == true) { + CFStringRef underscoreNotationLocalization = _copyStringWithUnderscores(preferredLocalization); + if (CFStringCompare(underscoreNotationLocalization, availableLocalization, 0) == kCFCompareEqualTo) { + CFArrayAppendValue(resultArray, underscoreNotationLocalization); + } + + CFStringRef truncatedLocalization = _copyStringTruncated(underscoreNotationLocalization, hyphenation); + if (CFStringCompare(truncatedLocalization, availableLocalization, 0) == kCFCompareEqualTo) { + CFArrayAppendValue(resultArray, truncatedLocalization); + } + + CFRelease(underscoreNotationLocalization); + CFRelease(truncatedLocalization); + } else if (CFStringFindWithOptions(preferredLocalization, CFSTR("_"), CFRangeMake(0, CFStringGetLength(preferredLocalization)), kCFCompareCaseInsensitive, &hyphenation) == true) { + CFStringRef truncatedLocalization = _copyStringTruncated(preferredLocalization, hyphenation); + if (CFStringCompare(truncatedLocalization, availableLocalization, 0) == kCFCompareEqualTo) { + CFArrayAppendValue(resultArray, truncatedLocalization); + } + CFRelease(truncatedLocalization); + } + } + } + if (CFArrayGetCount(resultArray) > 0) { + return resultArray; + } + return NULL; +#endif // stringPointers must be the length of list char * (^makeBuffer)(CFArrayRef, char **) = ^(CFArrayRef list, char *stringPointers[]) { #if !__HAS_APPLE_ICU__ diff --git a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj index 3841c533be..377163b715 100644 --- a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj +++ b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj @@ -237,10 +237,11 @@ + - + \ No newline at end of file diff --git a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters index a1a6943b2e..3e01426aff 100644 --- a/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters +++ b/build/Tests/UnitTests/Foundation.WindowsOnly/Foundation.WindowsOnly.UnitTests.vcxproj.filters @@ -27,5 +27,6 @@ + - + \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings new file mode 100644 index 0000000000..2fe0fcfe5a --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/Base.lproj/Localizable.strings @@ -0,0 +1,11 @@ +"a" = "z"; +"b" = "y"; +"c" = "x"; +"d" = "w"; +"e" = "v"; +"f" = "u"; +"g" = "t"; +"h" = "s"; +"i" = "r"; +"j" = "q"; +"Hello World" = "English: Hello World"; \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj index 29f397cd22..d7622a3a4d 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj @@ -1,4 +1,4 @@ - + @@ -212,6 +212,7 @@ + @@ -248,6 +249,7 @@ + @@ -274,6 +276,26 @@ WOCCatalog-Debug-xcvars.txt WOCCatalog-Release-xcvars.txt + + Document + Base.lproj + + + Document + de.lproj + + + Document + zh.lproj + + + Document + zh-Hant-TW.lproj + + + Document + es_MX.lproj + @@ -303,7 +325,6 @@ - uap10.0 @@ -316,6 +337,5 @@ - - - + + \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters index c4f5fe296f..344291f793 100644 --- a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/WOCCatalog.vcxproj.filters @@ -1,4 +1,4 @@ - + @@ -99,6 +99,9 @@ WOCCatalog + + WOCCatalog + WOCCatalog @@ -207,6 +210,9 @@ WOCCatalog + + WOCCatalog + WOCCatalog @@ -332,4 +338,21 @@ WOCCatalog - + + + + + + + + + + + WOCCatalog + + + + + + + \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings new file mode 100644 index 0000000000..07ae7d03e6 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/de.lproj/Localizable.strings @@ -0,0 +1,11 @@ +"a" = "1"; +"b" = "2"; +"c" = "3"; +"d" = "4"; +"e" = "5"; +"f" = "6"; +"g" = "7"; +"h" = "8"; +"i" = "9"; +"j" = "10"; +"Hello World" = "German: Hallo Welt"; \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings new file mode 100644 index 0000000000..014451d3e7 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/es_MX.lproj/Localizable.strings @@ -0,0 +1,11 @@ +"a" = "z"; +"b" = "x"; +"c" = "c"; +"d" = "v"; +"e" = "b"; +"f" = "n"; +"g" = "m"; +"h" = ","; +"i" = "."; +"j" = "/"; +"Hello World" = "Spanish _: Hola Mundo"; \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings new file mode 100644 index 0000000000..4978c25d48 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh-Hant-TW.lproj/Localizable.strings @@ -0,0 +1,11 @@ +"a" = "q"; +"b" = "w"; +"c" = "e"; +"d" = "r"; +"e" = "t"; +"f" = "y"; +"g" = "u"; +"h" = "i"; +"i" = "o"; +"j" = "p"; +"Hello World" = "zh-Hant-TW: 世界您好"; \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings new file mode 100644 index 0000000000..5a8405fe6f --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog.vsimporter/WOCCatalog-WinStore10/zh.lproj/Localizable.strings @@ -0,0 +1,11 @@ +"a" = "a"; +"b" = "s"; +"c" = "d"; +"d" = "f"; +"e" = "g"; +"f" = "h"; +"g" = "j"; +"h" = "k"; +"i" = "l"; +"j" = ";"; +"Hello World" = "zh-Hans-CN truncated: 世界您好"; \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog/LocalizationViewController.h b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.h new file mode 100644 index 0000000000..1e9b1143b5 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.h @@ -0,0 +1,21 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import + +@interface LocalizationViewController : UITableViewController +@end \ No newline at end of file diff --git a/samples/WOCCatalog/WOCCatalog/LocalizationViewController.m b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.m new file mode 100644 index 0000000000..209a3c3e29 --- /dev/null +++ b/samples/WOCCatalog/WOCCatalog/LocalizationViewController.m @@ -0,0 +1,82 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import "LocalizationViewController.h" + +static const CGFloat c_originX = 5; +static const CGFloat c_originY = 8; +static const CGFloat c_width = 260; +static const CGFloat c_height = 50; + +@implementation LocalizationViewController { +@private + UITableViewCell* _cell; + UITextField* _copyTextField; + UILabel* _pasteTextLabel; +} +- (void)viewDidLoad { + [super viewDidLoad]; + self.tableView.allowsSelection = YES; +} + +- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { + return 2; +} + +- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { + return 70; +} + +- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { + _cell = [tableView dequeueReusableCellWithIdentifier:@"MenuCell"]; + if (nil == _cell) { + _cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MenuCell"]; + _cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + CGRect frame = CGRectMake(c_originX, c_originY, c_width, c_height); + + if (indexPath.row == 0) { + _copyTextField = [[UITextField alloc] initWithFrame:frame]; + _copyTextField.textColor = [UIColor blackColor]; + _copyTextField.font = [UIFont systemFontOfSize:17.0]; + _copyTextField.text = @"Hello World"; + [_copyTextField addTarget:self action:@selector(onCopyTextChanged:) forControlEvents:UIControlEventEditingChanged]; + + _cell.accessoryView = _copyTextField; + _cell.textLabel.text = @"Enter Text"; + } else if (indexPath.row == 1) { + _pasteTextLabel = [[UILabel alloc] initWithFrame:frame]; + _pasteTextLabel.textColor = [UIColor blackColor]; + _pasteTextLabel.font = [UIFont systemFontOfSize:17.0]; + _pasteTextLabel.textAlignment = NSTextAlignmentLeft; + _pasteTextLabel.text = NSLocalizedString(_copyTextField.text, nil); + _cell.accessoryView = _pasteTextLabel; + _cell.textLabel.text = @"Localized Text"; + } + return _cell; +} + +- (void)viewDidLayoutSubviews { + [(UIScrollView*)self.view setContentSize:[self.view.subviews[0] bounds].size]; +} + +- (void)onCopyTextChanged:(UITextField*)textField { + _pasteTextLabel.text = NSLocalizedString(textField.text, nil); + [[self tableView] setNeedsLayout]; +} + +@end diff --git a/samples/WOCCatalog/WOCCatalog/MainViewController.m b/samples/WOCCatalog/WOCCatalog/MainViewController.m index 781ac814ad..ed371d655e 100644 --- a/samples/WOCCatalog/WOCCatalog/MainViewController.m +++ b/samples/WOCCatalog/WOCCatalog/MainViewController.m @@ -44,6 +44,7 @@ #import "GeocodingViewController.h" #import "CoreLocationViewController.h" #import "GesturesViewController.h" +#import "LocalizationViewController.h" #ifdef WINOBJC #import "XamlViewController.h" @@ -138,12 +139,15 @@ - (void)viewDidLoad { // Accelerate 2 [self addMenuItemViewController:[[AccelerateViewController2 alloc] init] andTitle:@"Accelerate 2"]; - + // Shadow [self addMenuItemViewController:[[ShadowViewController alloc] init] andTitle:@"Shadow"]; // UIPasteboard [self addMenuItemViewController:[[UIPasteboardViewController alloc] init] andTitle:@"Copy And Paste"]; + + // Localization + [self addMenuItemViewController:[[LocalizationViewController alloc] init] andTitle:@"Localization"]; } - (void)didReceiveMemoryWarning { diff --git a/tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm b/tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm new file mode 100644 index 0000000000..bbe9c2e026 --- /dev/null +++ b/tests/UnitTests/Foundation/WindowsOnly/BundleInternalTests.mm @@ -0,0 +1,77 @@ +//****************************************************************************** +// +// Copyright (c) Microsoft. All rights reserved. +// +// This code is licensed under the MIT License (MIT). +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +//****************************************************************************** + +#import +#import +#import + +class NSBundleLocalization : public ::testing::Test { +public: + explicit NSBundleLocalization() : ::testing::Test() { + } + +protected: + virtual void SetUp() { + NSString* _subDirectory = @"en.lproj"; + NSString* localizationResourceName = @"Localizable.strings"; + // Create a unique test directory + _playground = [@"./tmp_TestFoundation" stringByAppendingPathComponent:[NSUUID UUID].UUIDString]; + _bundlePath = [_playground stringByAppendingPathComponent:@"MyBundle.bundle"]; + NSError* error = nil; + + NSString* localizationPath = [NSString stringWithFormat:@"%@/%@", _bundlePath.get(), _subDirectory]; + [[NSFileManager defaultManager] createDirectoryAtPath:localizationPath + withIntermediateDirectories:true + attributes:nil + error:&error]; + ASSERT_EQ(nil, error); + + // Full path to the file name + NSString* filepath = [NSString stringWithFormat:@"%@/%@", localizationPath, localizationResourceName]; + [[NSFileManager defaultManager] createFileAtPath:filepath contents:nil attributes:nil]; + + // As translated by Bing translate using unicode escapes to properly write to file + NSString* localization = @"\"Hello World\" = \"Hallo Welt\";\n\"Coding\" = \"\u7f16\u7801\";"; + [localization writeToFile:filepath atomically:YES encoding:NSUnicodeStringEncoding error:&error]; + } + + virtual void TearDown() { + NSError* error; + [[NSFileManager defaultManager] removeItemAtPath:_playground error:&error]; + if (error) { + // Oh well, temporary directories in taef are cleaned up automatically anyway + } + } + + StrongId _playground; + StrongId _bundlePath; +}; + +TEST_F(NSBundleLocalization, LocalizedString) { + if (!_playground) { + ASSERT_TRUE_MSG(false, @"Unable to create bundle resources"); + } + + NSBundle* bundle = [NSBundle bundleWithPath:_bundlePath]; + ASSERT_OBJCNE(bundle, nil); + + NSString* helloWorld = @"Hello World"; + NSString* coding = @"Coding"; + NSString* helloWorldInGerman = NSLocalizedStringFromTableInBundle(helloWorld, nil, bundle, nil); + NSString* codingInChinese = NSLocalizedStringFromTableInBundle(coding, nil, bundle, nil); + ASSERT_OBJCEQ(@"Hallo Welt", helloWorldInGerman); + ASSERT_OBJCEQ(@"编码", codingInChinese); +} \ No newline at end of file