Rewrite in Swift
This commit is contained in:
Родитель
abe80a46f9
Коммит
50c26a2c9a
|
@ -21,8 +21,7 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
OBJ_32 /* LocalizedStringKit.m in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* LocalizedStringKit.m */; };
|
||||
OBJ_34 /* LocalizedStringKit.h in Headers */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* LocalizedStringKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DD90F1BF25A47E1C006C2ED8 /* LocalizedStringKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD90F1BE25A47E1C006C2ED8 /* LocalizedStringKit.swift */; };
|
||||
OBJ_41 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
|
||||
OBJ_52 /* LocalizedStringKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* LocalizedStringKitTests.swift */; };
|
||||
OBJ_53 /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* XCTestManifests.swift */; };
|
||||
|
@ -47,14 +46,13 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
DD90F1BE25A47E1C006C2ED8 /* LocalizedStringKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedStringKit.swift; sourceTree = "<group>"; };
|
||||
"LocalizedStringKit::LocalizedStringKit::Product" /* LocalizedStringKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LocalizedStringKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
"LocalizedStringKit::LocalizedStringKitTests::Product" /* LocalizedStringKitTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = LocalizedStringKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
OBJ_11 /* LocalizedStringKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalizedStringKit.h; sourceTree = "<group>"; };
|
||||
OBJ_14 /* LocalizedStringKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedStringKitTests.swift; sourceTree = "<group>"; };
|
||||
"LocalizedStringKit::LocalizedStringKitTests::Product" /* LocalizedStringKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = LocalizedStringKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
OBJ_14 /* LocalizedStringKitTests.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = LocalizedStringKitTests.swift; sourceTree = "<group>"; tabWidth = 2; };
|
||||
OBJ_15 /* XCTestManifests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestManifests.swift; sourceTree = "<group>"; };
|
||||
OBJ_25 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
|
||||
OBJ_9 /* LocalizedStringKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalizedStringKit.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -76,14 +74,6 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
OBJ_10 /* include */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_11 /* LocalizedStringKit.h */,
|
||||
);
|
||||
path = include;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
OBJ_12 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -133,8 +123,7 @@
|
|||
OBJ_8 /* LocalizedStringKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
OBJ_9 /* LocalizedStringKit.m */,
|
||||
OBJ_10 /* include */,
|
||||
DD90F1BE25A47E1C006C2ED8 /* LocalizedStringKit.swift */,
|
||||
);
|
||||
name = LocalizedStringKit;
|
||||
path = Sources/LocalizedStringKit;
|
||||
|
@ -147,7 +136,6 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
OBJ_34 /* LocalizedStringKit.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -210,6 +198,11 @@
|
|||
attributes = {
|
||||
LastSwiftMigration = 9999;
|
||||
LastUpgradeCheck = 9999;
|
||||
TargetAttributes = {
|
||||
"LocalizedStringKit::LocalizedStringKit" = {
|
||||
LastSwiftMigration = 1220;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "LocalizedStringKit" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
|
@ -236,7 +229,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 0;
|
||||
files = (
|
||||
OBJ_32 /* LocalizedStringKit.m in Sources */,
|
||||
DD90F1BF25A47E1C006C2ED8 /* LocalizedStringKit.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -289,9 +282,9 @@
|
|||
"$(SRCROOT)/Sources/LocalizedStringKit/include",
|
||||
);
|
||||
INFOPLIST_FILE = LocalizedStringKit.xcodeproj/LocalizedStringKit_Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
|
@ -300,9 +293,11 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGET_NAME = LocalizedStringKit;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -351,9 +346,9 @@
|
|||
"$(SRCROOT)/Sources/LocalizedStringKit/include",
|
||||
);
|
||||
INFOPLIST_FILE = LocalizedStringKit.xcodeproj/LocalizedStringKit_Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
|
@ -362,9 +357,10 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGET_NAME = LocalizedStringKit;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -429,6 +425,7 @@
|
|||
OBJ_49 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -440,23 +437,24 @@
|
|||
"$(SRCROOT)/Sources/LocalizedStringKit/include",
|
||||
);
|
||||
INFOPLIST_FILE = LocalizedStringKit.xcodeproj/LocalizedStringKitTests_Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGET_NAME = LocalizedStringKitTests;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
OBJ_50 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -468,17 +466,17 @@
|
|||
"$(SRCROOT)/Sources/LocalizedStringKit/include",
|
||||
);
|
||||
INFOPLIST_FILE = LocalizedStringKit.xcodeproj/LocalizedStringKitTests_Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
OTHER_CFLAGS = "$(inherited)";
|
||||
OTHER_LDFLAGS = "$(inherited)";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGET_NAME = LocalizedStringKitTests;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
|
|
@ -1,180 +0,0 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
@import CommonCrypto;
|
||||
|
||||
#import "LocalizedStringKit.h"
|
||||
|
||||
@interface LocalizedStringKit : NSObject
|
||||
|
||||
@end
|
||||
|
||||
@implementation LocalizedStringKit
|
||||
|
||||
static NSMutableDictionary *bundleMap = nil;
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
NSString *_Nonnull LSKPrimaryBundleName = @"LocalizedStringKit.bundle";
|
||||
|
||||
NSURL *_Nullable LSKAlternateBundleSearchPath = nil;
|
||||
|
||||
NSString *Localized(NSString *_Nonnull value, NSString *_Nonnull comment) {
|
||||
return [LocalizedStringKit localizeWithValue:value comment:comment keyExtension:nil bundleName:nil];
|
||||
}
|
||||
|
||||
NSString *LocalizedWithBundle(NSString *_Nonnull value, NSString *_Nonnull comment, NSString *_Nonnull bundleName) {
|
||||
return [LocalizedStringKit localizeWithValue:value comment:comment keyExtension:nil bundleName:bundleName];
|
||||
}
|
||||
|
||||
NSString *LocalizedWithKeyExtension(NSString *_Nonnull value, NSString *_Nonnull comment, NSString *_Nonnull keyExtension) {
|
||||
return [LocalizedStringKit localizeWithValue:value comment:comment keyExtension:keyExtension bundleName:nil];
|
||||
}
|
||||
|
||||
NSString *LocalizedWithKeyExtensionAndBundle(NSString *_Nonnull value, NSString *_Nonnull comment, NSString *_Nonnull keyExtension, NSString *_Nullable bundleName) {
|
||||
return [LocalizedStringKit localizeWithValue:value comment:comment keyExtension:keyExtension bundleName:bundleName];
|
||||
}
|
||||
|
||||
__attribute__((annotate("returns_localized_nsstring")))
|
||||
NSString *LocalizationUnnecessary(NSString *value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
NSBundle * _Nullable getLocalizedStringKitBundle(NSString *_Nullable bundleName) {
|
||||
return [LocalizedStringKit getLocalizedStringKitBundle:bundleName];
|
||||
}
|
||||
|
||||
#pragma mark - Private / Static
|
||||
|
||||
+ (NSString *)localizeWithValue:(NSString *_Nonnull)value comment:(NSString *_Nonnull)comment keyExtension:(NSString *_Nullable)keyExtension bundleName:(NSString *_Nullable)bundleName
|
||||
{
|
||||
// Key
|
||||
NSString *key = [self keyWithValue:value keyExtension:keyExtension];
|
||||
|
||||
// Table: This does not change between bundles
|
||||
NSString *table = @"LocalizedStringKit";
|
||||
|
||||
// Bundle Map: [bundleName String: NSBundle]
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
bundleMap = [[NSMutableDictionary alloc] init];
|
||||
});
|
||||
|
||||
if (bundleName == nil)
|
||||
{
|
||||
// Default to primary strings bundle
|
||||
bundleName = @"LocalizedStringKit.bundle";
|
||||
}
|
||||
|
||||
NSBundle *bundle = [bundleMap objectForKey:bundleName];
|
||||
|
||||
if (bundle == nil)
|
||||
{
|
||||
// Load and cache bundle
|
||||
bundle = [LocalizedStringKit getLocalizedStringKitBundle:bundleName];
|
||||
if (bundle == nil)
|
||||
{
|
||||
[bundleMap setObject:[NSNull null] forKey:bundleName];
|
||||
// Unable to load `LocalizedStringKit` bundle
|
||||
return value;
|
||||
}
|
||||
[bundleMap setObject:bundle forKey:bundleName];
|
||||
}
|
||||
|
||||
if ([bundle isKindOfClass:[NSNull class]]) {
|
||||
// Resolved NSNull for bundle
|
||||
return value;
|
||||
}
|
||||
|
||||
// Forward to `NSLocalizedString`
|
||||
return NSLocalizedStringWithDefaultValue(key, table, bundle, value, comment);
|
||||
}
|
||||
|
||||
+ (NSString *)keyWithValue:(NSString *_Nonnull)value keyExtension:(NSString *)keyExtension
|
||||
{
|
||||
// Generate the `key` which is equal to the `MD5(<value>)` or `MD5(<value>:<keyExtension>)`. This logic must stay in sync with `localize.py`.
|
||||
NSString *hashInput = value;
|
||||
|
||||
if (keyExtension.length > 0)
|
||||
{
|
||||
hashInput = [hashInput stringByAppendingFormat:@":%@", keyExtension];
|
||||
}
|
||||
|
||||
const char *inputCharacterArray = [hashInput UTF8String];
|
||||
unsigned char outputCharacterArray[CC_MD5_DIGEST_LENGTH];
|
||||
|
||||
CC_MD5(inputCharacterArray, (CC_LONG)strlen(inputCharacterArray), outputCharacterArray);
|
||||
|
||||
NSMutableString *key = [[NSMutableString alloc] init];
|
||||
|
||||
for (NSInteger idx = 0; idx < CC_MD5_DIGEST_LENGTH; idx++) {
|
||||
[key appendFormat:@"%02x", outputCharacterArray[idx]];
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
+ (NSBundle *_Nullable)getLocalizedStringKitBundle:(NSString *_Nullable)bundleName
|
||||
{
|
||||
// Search Paths
|
||||
NSURL *searchPath = [[NSBundle mainBundle] bundleURL];
|
||||
|
||||
// Determine target bundleName
|
||||
if (bundleName == nil) {
|
||||
// Defaults to primary bundle if bundleName not specified
|
||||
bundleName = LSKPrimaryBundleName;
|
||||
}
|
||||
else if (![bundleName hasSuffix:@".bundle"])
|
||||
{
|
||||
// Append suffix
|
||||
bundleName = [bundleName stringByAppendingFormat:@".bundle"];
|
||||
}
|
||||
|
||||
// Alternate path check, if url specified
|
||||
if (LSKAlternateBundleSearchPath != nil) {
|
||||
NSURL *alternateBundleURL = [LSKAlternateBundleSearchPath URLByAppendingPathComponent:bundleName];
|
||||
NSBundle *bundle = [NSBundle bundleWithURL:alternateBundleURL];
|
||||
if (bundle) {
|
||||
return bundle;
|
||||
}
|
||||
}
|
||||
|
||||
// Primary searchPath check
|
||||
while(YES)
|
||||
{
|
||||
NSURL *bundleURL = [searchPath URLByAppendingPathComponent:bundleName];
|
||||
NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];
|
||||
|
||||
if (bundle != nil)
|
||||
{
|
||||
if ([bundle.bundleURL.lastPathComponent isEqualToString:bundleName]) {
|
||||
return bundle;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NSURL *newPath = [[searchPath URLByAppendingPathComponent:@".."] absoluteURL];
|
||||
if ([newPath isEqual:searchPath])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
searchPath = newPath;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
void LSKSetPrimaryBundleName(NSString *_Nonnull bundleName) {
|
||||
LSKPrimaryBundleName = bundleName;
|
||||
}
|
||||
|
||||
void LSKSetAlternateBundleSearchPath(NSURL *_Nonnull url) {
|
||||
LSKAlternateBundleSearchPath = url;
|
||||
[bundleMap removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
|
||||
|
||||
public func Localized(_ value: String, _ comment: String, keyExtension: String? = nil, bundleName: String? = nil) -> String {
|
||||
return Localizer.localize(value, comment, keyExtension: keyExtension, bundleName: bundleName)
|
||||
}
|
||||
|
||||
/// Soft deprecated. Use `Localized(value, comment, keyExtension: keyExtension)` instead
|
||||
public func LocalizedWithKeyExtension(_ value: String, _ comment: String, _ keyExtension: String) -> String {
|
||||
return Localizer.localize(value, comment, keyExtension: keyExtension, bundleName: nil)
|
||||
}
|
||||
|
||||
/// Soft deprecated. Use `Localized(value, comment, bundleName: bundleName)` instead
|
||||
public func LocalizedWithBundle(_ value: String, _ comment: String, _ bundleName: String) -> String {
|
||||
return Localizer.localize(value, comment, keyExtension: nil, bundleName: bundleName)
|
||||
}
|
||||
|
||||
/// Soft deprecated. Use `Localized(value, comment, keyExtension: keyExtension, bundleName: bundleName)` instead
|
||||
public func LocalizedWithKeyExtensionAndBundle(_ value: String, _ comment: String, _ keyExtension: String, _ bundleName: String) -> String {
|
||||
return Localizer.localize(value, comment, keyExtension: keyExtension, bundleName: bundleName)
|
||||
}
|
||||
|
||||
public class Localizer {
|
||||
|
||||
private static var bundleMap = [String: Bundle]()
|
||||
private static var missingBundles: Set<String> = Set()
|
||||
public static var primaryBundleName = "LocalizedStringKit.bundle"
|
||||
public static var alternateBundleSearchPath: URL? {
|
||||
didSet {
|
||||
bundleMap.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
static func md5(string: String) -> String? {
|
||||
guard let data = string.data(using: .utf8) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let digest = Insecure.MD5.hash(data: data)
|
||||
|
||||
return digest.map { String(format: "%02hhx", $0) }.joined()
|
||||
}
|
||||
|
||||
static func key(_ value: String, keyExtension: String?) -> String? {
|
||||
// Generate the `key` which is equal to the `MD5(<value>)` or `MD5(<value>:<keyExtension>)`. This logic must stay in sync with `localize.py`.
|
||||
var hashInput = value
|
||||
|
||||
if let ke = keyExtension, ke.isEmpty {
|
||||
hashInput = hashInput.appendingFormat(":%@", ke)
|
||||
}
|
||||
|
||||
return md5(string: hashInput)
|
||||
}
|
||||
|
||||
static func getBundle(_ bundleName: String?) -> Bundle? {
|
||||
// Search Paths
|
||||
var searchPath = Bundle.main.bundleURL
|
||||
|
||||
// Determine target bundleName
|
||||
var bundleName = bundleName ?? primaryBundleName
|
||||
|
||||
// Append suffix
|
||||
if !bundleName.hasSuffix(".bundle") {
|
||||
bundleName += ".bundle"
|
||||
}
|
||||
|
||||
// Alternate path check, if url specified
|
||||
if let alernateSearchPath = alternateBundleSearchPath,
|
||||
let bundle = Bundle(url: alernateSearchPath.appendingPathComponent(bundleName)) {
|
||||
return bundle
|
||||
}
|
||||
|
||||
// Primary searchPath check
|
||||
while true {
|
||||
let bundleURL = searchPath.appendingPathComponent(bundleName)
|
||||
if let bundle = Bundle(url: bundleURL) {
|
||||
if bundle.bundleURL.lastPathComponent == bundleName {
|
||||
return bundle
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let newPath = searchPath.appendingPathComponent("..").absoluteURL
|
||||
if newPath == searchPath {
|
||||
break
|
||||
}
|
||||
|
||||
searchPath = newPath
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@objc static func localize(_ value: String, _ comment: String, keyExtension: String?, bundleName: String?) -> String {
|
||||
let bundleName = bundleName ?? "LocalizedStringKit.bundle"
|
||||
let table = "LocalizedStringKit" // This does not change between bundles
|
||||
|
||||
guard let key = self.key(value, keyExtension: keyExtension) else {
|
||||
return value
|
||||
}
|
||||
|
||||
if let cachedBundle = bundleMap[bundleName] {
|
||||
return NSLocalizedString(key, tableName: table, bundle: cachedBundle, value: value, comment: comment)
|
||||
}
|
||||
|
||||
// We can't find it, so don't bother searching again
|
||||
guard !missingBundles.contains(bundleName) else {
|
||||
return value
|
||||
}
|
||||
|
||||
// Bundle wasn't cached so fetch and cache
|
||||
guard let bundle = getBundle(bundleName) else {
|
||||
missingBundles.insert(bundleName)
|
||||
return value
|
||||
}
|
||||
|
||||
bundleMap[bundleName] = bundle
|
||||
|
||||
// Forward to `NSLocalizedString`
|
||||
return NSLocalizedString(key, tableName: table, bundle: bundle, value: value, comment: comment)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
//! Project version number for LocalizedStringKit.
|
||||
FOUNDATION_EXPORT double LocalizedStringKitVersionNumber;
|
||||
|
||||
//! Project version string for LocalizedStringKit.
|
||||
FOUNDATION_EXPORT const unsigned char LocalizedStringKitVersionString[];
|
||||
|
||||
/// The name to be used for the primary strings bundle
|
||||
/// Example:
|
||||
/// "Localizable" (do not include the extension suffix)
|
||||
FOUNDATION_EXPORT NSString *_Nonnull LSKPrimaryBundleName;
|
||||
|
||||
/// URL for alternate string bundle search (the root from where search will begin)
|
||||
FOUNDATION_EXPORT NSURL *_Nullable LSKAlternateBundleSearchPath;
|
||||
|
||||
/// Primary localization function used to localize strings (excluding bundleName)
|
||||
///
|
||||
/// @param value: The English string
|
||||
/// @param comment: String to give context where the value string is used
|
||||
///
|
||||
/// Examples
|
||||
/// Localized("Cancel", "Action sheet action title")
|
||||
NSString *Localized(NSString *_Nonnull value, NSString *_Nonnull comment);
|
||||
|
||||
/// Primary localization function used to localize strings
|
||||
///
|
||||
/// @param value: The English string
|
||||
/// @param comment: String to give context where the value string is used
|
||||
/// @param bundleName: String to provide additional classification of the value string. Can be used to segment groups of strings in multiple bundles.
|
||||
///
|
||||
/// Examples
|
||||
/// Localized("Cancel", "Action sheet action title", nil)
|
||||
/// Localized("Cancel", "Action sheet action title", "primary")
|
||||
/// Localized("Cancel", "Action sheet action title", "primary")
|
||||
NSString *LocalizedWithBundle(NSString *_Nonnull value, NSString *_Nonnull comment, NSString *_Nonnull bundleName);
|
||||
|
||||
/// Additional localization function used to localize strings
|
||||
///
|
||||
/// @param value: The English string
|
||||
/// @param comment: String to give context where the value string is used
|
||||
/// @param keyExtension: String to be used to provide additional differentiation between contexts. The `keyExtension` is included when generating the string `key` so two calls with the same `value` but different `keyExtension` values will result in two different strings in the localization dictionary
|
||||
///
|
||||
/// Ex: `LocalizedWithKeyExtension("Archive", "Button title", "Verb")
|
||||
/// Ex: `LocalizedWithKeyExtension("Archive", "Folder title", "Noun")
|
||||
NSString *LocalizedWithKeyExtension(NSString *_Nonnull value, NSString *_Nonnull scomment, NSString *_Nonnull keyExtension);
|
||||
|
||||
/// Additional localization function used to localize strings
|
||||
///
|
||||
/// @param value: The English string
|
||||
/// @param comment: String to give context where the value string is used
|
||||
/// @param keyExtension: String to be used to provide additional differentiation between contexts. The `keyExtension` is included when generating the string `key` so two calls with the same `value` but different `keyExtension` values will result in two different strings in the localization dictionary
|
||||
/// @param bundleName: Optional string to provide additional classification of the string. Can be used to segment groups of strings in multiple bundles.
|
||||
///
|
||||
/// Ex: `LocalizedWithKeyExtensionAndBundle("Archive", "Button title", "Verb", "primary")
|
||||
/// Ex: `LocalizedWithKeyExtensionAndBundle("Archive", "Folder title", "Noun", "primary")
|
||||
NSString *LocalizedWithKeyExtensionAndBundle(NSString *_Nonnull value, NSString *_Nonnull scomment, NSString *_Nonnull keyExtension, NSString *_Nullable bundleName);
|
||||
|
||||
/// Marks a string as not needing localization (to avoid false positives from
|
||||
/// the static analyzer
|
||||
NSString *LocalizationUnnecessary(NSString *value);
|
||||
|
||||
/// Load the bundle which contains the localized strings
|
||||
///
|
||||
/// @param bundleName: Optional bundleName to find related bundle for strings. bundleNames can be used to segment localized string bundles. If nil, default bundle will be returned.
|
||||
NSBundle * _Nullable LSKLocalizedStringKitBundle(NSString *_Nullable bundleName);
|
||||
|
||||
/// Set the primary bundle name
|
||||
///
|
||||
/// @param bundleName: Nonnull bundle name to set as a String
|
||||
void LSKSetPrimaryBundleName(NSString *_Nonnull bundleName);
|
||||
|
||||
/// Set the alternate bundle search path
|
||||
///
|
||||
/// @param url: URL to search
|
||||
void LSKSetAlternateBundleSearchPath(NSURL *_Nonnull url);
|
||||
|
||||
/// Get a strings bundle
|
||||
///
|
||||
/// @param bundleName: Name of bundle to search for
|
||||
NSBundle * _Nullable getLocalizedStringKitBundle(NSString *_Nullable bundleName);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -20,13 +20,11 @@ final class LocalizedStringKitTests: XCTestCase {
|
|||
if Locale.current.languageCode == "en" {
|
||||
XCTAssertEqual(Localized("Done", "Done"), "Done")
|
||||
XCTAssertEqual(Localized("Not a Localized String", "Done"), "Not a Localized String")
|
||||
XCTAssertEqual(LocalizationUnnecessary("Not Needed"), "Not Needed")
|
||||
}
|
||||
else {
|
||||
XCTFail("Please add other development language localization tests")
|
||||
XCTAssertEqual(Localized("Done", "Done"), "Done")
|
||||
XCTAssertEqual(LocalizedWithBundle("Not a Localized String", "Done", "primary"), "Not a Localized String")
|
||||
XCTAssertEqual(LocalizationUnnecessary("Not Needed"), "Not Needed")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,19 +54,19 @@ final class LocalizedStringKitTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testGetLocalizedStringKitBundle() {
|
||||
XCTAssertNil(getLocalizedStringKitBundle("unknown_bundle"))
|
||||
XCTAssertNil(LocalizedStringKit.getBundle("unknown_bundle"))
|
||||
}
|
||||
|
||||
func testPrimaryBundleName() {
|
||||
XCTAssertEqual(LSKPrimaryBundleName, "LocalizedStringKit.bundle")
|
||||
LSKSetPrimaryBundleName("Other.bundle")
|
||||
XCTAssertEqual(LSKPrimaryBundleName, "Other.bundle")
|
||||
XCTAssertEqual(LocalizedStringKit.primaryBundleName, "LocalizedStringKit.bundle")
|
||||
LocalizedStringKit.primaryBundleName = "Other.bundle"
|
||||
XCTAssertEqual(LocalizedStringKit.primaryBundleName, "Other.bundle")
|
||||
}
|
||||
|
||||
func testAlternateBundleSearchPath() {
|
||||
XCTAssertNil(LSKAlternateBundleSearchPath)
|
||||
LSKAlternateBundleSearchPath = NSURL(string: "file://path")
|
||||
XCTAssertEqual(LSKAlternateBundleSearchPath, NSURL(string: "file://path"))
|
||||
XCTAssertNil(LocalizedStringKit.alternateBundleSearchPath)
|
||||
LocalizedStringKit.alternateBundleSearchPath = URL(string: "file://path")
|
||||
XCTAssertEqual(LocalizedStringKit.alternateBundleSearchPath, URL(string: "file://path"))
|
||||
}
|
||||
|
||||
// TODO: LocalizedStringKit statically binds the Locale bundle so we cannot swap locale at runtime, if we need to
|
||||
|
|
Загрузка…
Ссылка в новой задаче