diff --git a/README.md b/README.md index 20a7b90..86078f5 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Localize-Swift is a simple framework that improves i18n and localization in Swif - Keep the Localizable.strings file your app already uses. - Allow your users to change the app's language without changing their device language. -- Use .localized() instead of NSLocalizedString(key,comment) - a more Swifty syntax. +- Use .localized instead of NSLocalizedString(key,comment) - a more Swifty syntax. - Generate your strings with a new genstrings swift/python script that recognises .localized(). ## Usage @@ -24,9 +24,9 @@ If CocoaPods - import Localize_Swift ``` -Add `.localized()` following any `String` object you want translated: +Add `.localized` following any `String` object you want translated: ```swift -textLabel.text = "Hello World".localized() +textLabel.text = "Hello World".localized ``` To get an array of available localizations: diff --git a/Sources/Localize.swift b/Sources/Localize.swift index 278240f..68e267b 100644 --- a/Sources/Localize.swift +++ b/Sources/Localize.swift @@ -28,7 +28,7 @@ Swift 1.x friendly localization syntax, replaces NSLocalizedString - Returns: The localized string. */ public func Localized(_ string: String) -> String { - return string.localized() + return string.localized } /** @@ -37,7 +37,7 @@ public func Localized(_ string: String) -> String { - Returns: The formatted localized string with arguments. */ public func Localized(_ string: String, arguments: CVarArg...) -> String { - return String(format: string.localized(), arguments: arguments) + return String(format: string.localized, arguments: arguments) } /** @@ -55,10 +55,10 @@ public func LocalizedPlural(_ string: String, argument: CVarArg) -> String { public extension String { /** - Swift 2 friendly localization syntax, replaces NSLocalizedString + Swift 3 friendly localization syntax, replaces NSLocalizedString - Returns: The localized string. */ - func localized() -> String { + var localized: String { return localized(using: nil, in: .main) } @@ -67,7 +67,7 @@ public extension String { - Returns: The formatted localized string with arguments. */ func localizedFormat(_ arguments: CVarArg...) -> String { - return String(format: localized(), arguments: arguments) + return String(format: localized, arguments: arguments) } /** @@ -78,7 +78,7 @@ public extension String { - returns: Pluralized localized string. */ func localizedPlural(_ argument: CVarArg) -> String { - return NSString.localizedStringWithFormat(localized() as NSString, argument) as String + return NSString.localizedStringWithFormat(localized as NSString, argument) as String } } @@ -105,11 +105,11 @@ open class Localize: NSObject { Current language - Returns: The current language. String. */ - open class func currentLanguage() -> String { + open class var currentLanguage: String { if let currentLanguage = UserDefaults.standard.object(forKey: LCLCurrentLanguageKey) as? String { return currentLanguage } - return defaultLanguage() + return defaultLanguage } /** @@ -117,8 +117,8 @@ open class Localize: NSObject { - Parameter language: Desired language. */ open class func setCurrentLanguage(_ language: String) { - let selectedLanguage = availableLanguages().contains(language) ? language : defaultLanguage() - if (selectedLanguage != currentLanguage()){ + let selectedLanguage = availableLanguages().contains(language) ? language : defaultLanguage + if (selectedLanguage != currentLanguage){ UserDefaults.standard.set(selectedLanguage, forKey: LCLCurrentLanguageKey) UserDefaults.standard.synchronize() NotificationCenter.default.post(name: Notification.Name(rawValue: LCLLanguageChangeNotification), object: nil) @@ -129,7 +129,7 @@ open class Localize: NSObject { Default language - Returns: The app's default language. String. */ - open class func defaultLanguage() -> String { + open class var defaultLanguage: String { var defaultLanguage: String = String() guard let preferredLanguage = Bundle.main.preferredLocalizations.first else { return LCLDefaultLanguage @@ -148,7 +148,7 @@ open class Localize: NSObject { Resets the current language to the default */ open class func resetCurrentLanguageToDefault() { - setCurrentLanguage(self.defaultLanguage()) + setCurrentLanguage(defaultLanguage) } /** @@ -157,11 +157,10 @@ open class Localize: NSObject { - Returns: The localized string. */ open class func displayNameForLanguage(_ language: String) -> String { - let locale : NSLocale = NSLocale(localeIdentifier: currentLanguage()) + let locale : NSLocale = NSLocale(localeIdentifier: currentLanguage) if let displayName = locale.displayName(forKey: NSLocale.Key.identifier, value: language) { return displayName } return String() } } - diff --git a/Sources/String+LocalizedBundleTableName.swift b/Sources/String+LocalizedBundleTableName.swift index 9cdd2f1..6df4e6d 100644 --- a/Sources/String+LocalizedBundleTableName.swift +++ b/Sources/String+LocalizedBundleTableName.swift @@ -24,7 +24,7 @@ public extension String { */ func localized(using tableName: String?, in bundle: Bundle?) -> String { let bundle: Bundle = bundle ?? .main - if let path = bundle.path(forResource: Localize.currentLanguage(), ofType: "lproj"), + if let path = bundle.path(forResource: Localize.currentLanguage, ofType: "lproj"), let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: tableName) } diff --git a/examples/LanguageSwitch/Sample.xcodeproj/project.pbxproj b/examples/LanguageSwitch/Sample.xcodeproj/project.pbxproj index d19bb3d..203fad5 100644 --- a/examples/LanguageSwitch/Sample.xcodeproj/project.pbxproj +++ b/examples/LanguageSwitch/Sample.xcodeproj/project.pbxproj @@ -7,10 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 23C6BB55DB6C55D75A0D1A00 /* Pods_SampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B823A35026E31B4C36949480 /* Pods_SampleTests.framework */; }; + 24C04082F27EE9AD23319C27 /* Pods_Sample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 333B3261F84DF59D1EBBD7A4 /* Pods_Sample.framework */; }; 3426FF931BB6AEE200E8E1BB /* SampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3426FF921BB6AEE200E8E1BB /* SampleTests.swift */; }; 3426FF9B1BB6AF5D00E8E1BB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 34346D2F1B72983C0063FED4 /* Localizable.strings */; }; - 342B3BE21DDAEA4600F6D25D /* Localize_Swift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 342B3BD31DDAEA2D00F6D25D /* Localize_Swift.framework */; }; - 342B3BE31DDAEA4600F6D25D /* Localize_Swift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 342B3BD31DDAEA2D00F6D25D /* Localize_Swift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 342B3BE21DDAEA4600F6D25D /* ReferenceProxy in Frameworks */ = {isa = PBXBuildFile; fileRef = 342B3BD31DDAEA2D00F6D25D /* Localize_Swift.framework */; }; + 342B3BE31DDAEA4600F6D25D /* ReferenceProxy in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 342B3BD31DDAEA2D00F6D25D /* Localize_Swift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 34346D031B7294470063FED4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34346D021B7294470063FED4 /* AppDelegate.swift */; }; 34346D051B7294470063FED4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34346D041B7294470063FED4 /* ViewController.swift */; }; 34346D081B7294470063FED4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 34346D061B7294470063FED4 /* Main.storyboard */; }; @@ -80,7 +82,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 342B3BE31DDAEA4600F6D25D /* Localize_Swift.framework in Embed Frameworks */, + 342B3BE31DDAEA4600F6D25D /* ReferenceProxy in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -88,7 +90,10 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1ED10F461C321990E109AB86 /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = ""; }; 20D57BE01DC0AF00001BA2F9 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; + 2572FB4DB392CD69E2011330 /* Pods-SampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.debug.xcconfig"; sourceTree = ""; }; + 2755A28A03A471EAF4C3254E /* Pods-SampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests.release.xcconfig"; sourceTree = ""; }; 333B3261F84DF59D1EBBD7A4 /* Pods_Sample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Sample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3426FF901BB6AEE200E8E1BB /* SampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3426FF921BB6AEE200E8E1BB /* SampleTests.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = SampleTests.swift; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; @@ -118,6 +123,7 @@ 68A520161DA6DA8900F43D9E /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ButtonTitles.strings"; sourceTree = ""; }; 68A520171DA6DA9600F43D9E /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/ButtonTitles.strings; sourceTree = ""; }; B823A35026E31B4C36949480 /* Pods_SampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E0FF4D520D33F72523E754C7 /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -125,6 +131,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 23C6BB55DB6C55D75A0D1A00 /* Pods_SampleTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -132,13 +139,25 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 342B3BE21DDAEA4600F6D25D /* Localize_Swift.framework in Frameworks */, + 342B3BE21DDAEA4600F6D25D /* ReferenceProxy in Frameworks */, + 24C04082F27EE9AD23319C27 /* Pods_Sample.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0C3D951F4768042DCA2145AA /* Pods */ = { + isa = PBXGroup; + children = ( + 1ED10F461C321990E109AB86 /* Pods-Sample.debug.xcconfig */, + E0FF4D520D33F72523E754C7 /* Pods-Sample.release.xcconfig */, + 2572FB4DB392CD69E2011330 /* Pods-SampleTests.debug.xcconfig */, + 2755A28A03A471EAF4C3254E /* Pods-SampleTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; 1296D3EDC6FA72EB325EB960 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -177,6 +196,7 @@ 3426FF911BB6AEE200E8E1BB /* SampleTests */, 34346CFE1B7294470063FED4 /* Products */, 1296D3EDC6FA72EB325EB960 /* Frameworks */, + 0C3D951F4768042DCA2145AA /* Pods */, ); sourceTree = ""; }; @@ -227,9 +247,12 @@ isa = PBXNativeTarget; buildConfigurationList = 3426FF971BB6AEE200E8E1BB /* Build configuration list for PBXNativeTarget "SampleTests" */; buildPhases = ( + 68DE43F9E45469F5E391C1CF /* [CP] Check Pods Manifest.lock */, 3426FF8C1BB6AEE200E8E1BB /* Sources */, 3426FF8D1BB6AEE200E8E1BB /* Frameworks */, 3426FF8E1BB6AEE200E8E1BB /* Resources */, + 2C0AA57AAB19CAE7359CB4A8 /* [CP] Embed Pods Frameworks */, + 3425353165902F14FFA98BEF /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -245,10 +268,13 @@ isa = PBXNativeTarget; buildConfigurationList = 34346D1C1B7294470063FED4 /* Build configuration list for PBXNativeTarget "Sample" */; buildPhases = ( + 7CCE71DC308431E5F1D49AFC /* [CP] Check Pods Manifest.lock */, 34346CF91B7294470063FED4 /* Sources */, 34346CFA1B7294470063FED4 /* Frameworks */, 34346CFB1B7294470063FED4 /* Resources */, 342B3BE61DDAEA4700F6D25D /* Embed Frameworks */, + 4FD870030708728702B50385 /* [CP] Embed Pods Frameworks */, + 5230A75D966B418897D3572C /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -376,6 +402,99 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 2C0AA57AAB19CAE7359CB4A8 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3425353165902F14FFA98BEF /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SampleTests/Pods-SampleTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 4FD870030708728702B50385 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 5230A75D966B418897D3572C /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 68DE43F9E45469F5E391C1CF /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 7CCE71DC308431E5F1D49AFC /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 3426FF8C1BB6AEE200E8E1BB /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -462,6 +581,7 @@ /* Begin XCBuildConfiguration section */ 3426FF981BB6AEE200E8E1BB /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 2572FB4DB392CD69E2011330 /* Pods-SampleTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; DEBUG_INFORMATION_FORMAT = dwarf; @@ -478,6 +598,7 @@ }; 3426FF991BB6AEE200E8E1BB /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 2755A28A03A471EAF4C3254E /* Pods-SampleTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -582,6 +703,7 @@ }; 34346D1D1B7294470063FED4 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 1ED10F461C321990E109AB86 /* Pods-Sample.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; @@ -596,6 +718,7 @@ }; 34346D1E1B7294470063FED4 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E0FF4D520D33F72523E754C7 /* Pods-Sample.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; diff --git a/examples/LanguageSwitch/Sample/ViewController.swift b/examples/LanguageSwitch/Sample/ViewController.swift index cfe0ad8..f719ebe 100644 --- a/examples/LanguageSwitch/Sample/ViewController.swift +++ b/examples/LanguageSwitch/Sample/ViewController.swift @@ -41,7 +41,7 @@ class ViewController: UIViewController { // MARK: Localized Text func setText(){ - textLabel.text = "Hello world".localized(); + textLabel.text = "Hello world".localized; changeButton.setTitle("Change".localized(using: "ButtonTitles"), for: UIControlState.normal) resetButton.setTitle("Reset".localized(using: "ButtonTitles"), for: UIControlState.normal) } diff --git a/examples/LanguageSwitch/SampleTests/SampleTests.swift b/examples/LanguageSwitch/SampleTests/SampleTests.swift index 2a4735a..6484932 100644 --- a/examples/LanguageSwitch/SampleTests/SampleTests.swift +++ b/examples/LanguageSwitch/SampleTests/SampleTests.swift @@ -26,30 +26,30 @@ class SampleTests: XCTestCase { func testSwift2Syntax() { let testString = "Hello world"; Localize.setCurrentLanguage("fr") - let translatedString = testString.localized() + let translatedString = testString.localized XCTAssertEqual(translatedString, "Bonjour le monde") } func testMultipleLanguageSwitching() { let testString = "Hello world"; Localize.setCurrentLanguage("es") - XCTAssertEqual(testString.localized(), "Hola mundo") + XCTAssertEqual(testString.localized, "Hola mundo") Localize.setCurrentLanguage("de") - XCTAssertEqual(testString.localized(), "Hallo Welt") + XCTAssertEqual(testString.localized, "Hallo Welt") Localize.resetCurrentLanguageToDefault() - XCTAssertEqual(testString.localized(), "Hello world") + XCTAssertEqual(testString.localized, "Hello world") } func testFalseLanguage() { let testString = "Hello world"; Localize.setCurrentLanguage("xxx") - XCTAssertEqual(testString.localized(), "Hello world") + XCTAssertEqual(testString.localized, "Hello world") } func testFalseString() { let testString = "Non translated string"; Localize.setCurrentLanguage("fr") - XCTAssertEqual(testString.localized(), "Non translated string") + XCTAssertEqual(testString.localized, "Non translated string") } func testTableName() {