├── .ruby-version ├── .gitignore ├── Gemfile ├── LocalizationHelperDemo ├── LocalizationHelperDemo │ ├── ar.lproj │ │ ├── LaunchScreen.strings │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── he-IL.lproj │ │ ├── LaunchScreen.strings │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── ur.lproj │ │ ├── LaunchScreen.strings │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── agq-CM.lproj │ │ ├── LaunchScreen.strings │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── ckb-IQ.lproj │ │ ├── LaunchScreen.strings │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── ckb-IR.lproj │ │ ├── LaunchScreen.strings │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── globe.imageset │ │ │ ├── png-transparent-community-world-internationalization-translation-service-paises-glass-service-innovation.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── arrow-right.png │ ├── en.lproj │ │ ├── Localizable.strings │ │ └── Main.strings │ ├── Base.lproj │ │ ├── Localizable.strings │ │ ├── LaunchScreen.storyboard │ │ ├── LaunchScreen (1).storyboard │ │ └── Main.storyboard │ ├── AppDelegate.swift │ ├── Info.plist │ ├── StackViewTestViewController.swift │ ├── InformationTextView.xib │ └── ViewController.swift └── LocalizationHelperDemo.xcodeproj │ ├── xcuserdata │ ├── moathaliwat.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── LocalizationHelperDemo.xcscheme │ └── moath.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ ├── deya.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ └── dhamza.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj ├── molhWithMultipleScenese ├── molhWithMultipleScenese │ ├── ar.lproj │ │ ├── LaunchScreen.strings │ │ ├── Main.strings │ │ └── Localizable.strings │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── en.lproj │ │ └── Localizable.strings │ ├── ViewController.swift │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── AppDelegate.swift │ ├── Info.plist │ └── SceneDelegate.swift └── molhWithMultipleScenese.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ └── xcschemes │ │ └── molhWithMultipleScenese.xcscheme │ └── project.pbxproj ├── Tests ├── LinuxMain.swift └── MOLHTests │ ├── XCTestManifests.swift │ └── MOLHTests.swift ├── MOLH.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings ├── MOLH_Info.plist ├── MOLHTests_Info.plist ├── xcshareddata │ └── xcschemes │ │ └── MOLH-Package.xcscheme └── project.pbxproj ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── Sources └── MOLH │ ├── MOLHFont.swift │ ├── MOLHSizable.swift │ ├── MOLHFontLocalizableViews.swift │ ├── MOLHLanguage.swift │ └── MOLH.swift ├── MOLH.podspec ├── LICENSE ├── Package.swift ├── Gemfile.lock ├── README.md └── post.md /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.4.5 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "cocoapods" 4 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ar.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/he-IL.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ur.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/ar.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/agq-CM.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ckb-IQ.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ckb-IR.lproj/LaunchScreen.strings: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import MOLHTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += MOLHTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoathOthman/MOLH/HEAD/LocalizationHelperDemo/LocalizationHelperDemo/arrow-right.png -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/ar.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UILabel"; text = "Label"; ObjectID = "w3U-9c-GpQ"; */ 3 | "w3U-9c-GpQ.text" = "Label"; 4 | -------------------------------------------------------------------------------- /MOLH.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/MOLHTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(MOLHTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/xcuserdata/moathaliwat.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please"; 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ur.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please urdu"; 9 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | molhWithMultipleScenese 4 | 5 | Created by Moath_Othman on 4/25/20. 6 | Copyright © 2020 moath. All rights reserved. 7 | */ 8 | "localize me please" = "localize me please"; 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/agq-CM.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please cameroon"; 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ckb-IQ.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please sorani"; 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ckb-IR.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please sorani"; 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/he-IL.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please hebrew"; 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.xcworkspace/xcuserdata/deya.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoathOthman/MOLH/HEAD/LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.xcworkspace/xcuserdata/deya.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.xcworkspace/xcuserdata/dhamza.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoathOthman/MOLH/HEAD/LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.xcworkspace/xcuserdata/dhamza.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /MOLH.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MOLH.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Assets.xcassets/globe.imageset/png-transparent-community-world-internationalization-translation-service-paises-glass-service-innovation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoathOthman/MOLH/HEAD/LocalizationHelperDemo/LocalizationHelperDemo/Assets.xcassets/globe.imageset/png-transparent-community-world-internationalization-translation-service-paises-glass-service-innovation.png -------------------------------------------------------------------------------- /Tests/MOLHTests/MOLHTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import MOLH 3 | 4 | final class MOLHTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | } 10 | 11 | static var allTests = [ 12 | ("testExample", testExample), 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ar.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "لوكالايز مي"; 9 | "stack_view_label_1" = " باعالربيStack view label one content somhow a bit longer than usual to accomodate 2 lines"; 10 | "stack_view_label_2" = "بيStack view label two"; 11 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Base.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Localization102 4 | 5 | Created by Moath_Othman on 3/6/16. 6 | Copyright © 2016 Moath_Othman. All rights reserved. 7 | */ 8 | "localize_me_please" = "localize me please base"; 9 | "stack_view_label_1" = "Stack view label one content somhow a bit longer than usual to accomodate 2 lines"; 10 | "stack_view_label_2" = "Stack view label two"; 11 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/ar.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | molhWithMultipleScenese 4 | 5 | Created by Moath_Othman on 4/25/20. 6 | Copyright © 2020 moath. All rights reserved. 7 | */ 8 | /* 9 | Localizable.strings 10 | Localization102 11 | 12 | Created by Moath_Othman on 3/6/16. 13 | Copyright © 2016 Moath_Othman. All rights reserved. 14 | */ 15 | "localize me please" = "arabic localizartion"; 16 | -------------------------------------------------------------------------------- /Sources/MOLH/MOLHFont.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MOLHFont.swift 3 | // Demo 4 | // 5 | // Created by Moath_Othman on 1/27/17. 6 | // Copyright © 2017 Moath. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public class MOLHFont { 13 | public static let shared = MOLHFont() 14 | /// Font for arabic language this variable and public 15 | public var arabic: UIFont = UIFont.systemFont(ofSize: 12) 16 | public var english: UIFont = UIFont.systemFont(ofSize: 12) 17 | } 18 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Assets.xcassets/globe.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "png-transparent-community-world-internationalization-translation-service-paises-glass-service-innovation.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/xcuserdata/moath.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | LocalizationHelperDemo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | EC5B8FE71EE0ECA4003BE809 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /MOLH.xcodeproj/MOLH_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | FMWK 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /MOLH.xcodeproj/MOLHTests_Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /MOLH.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | 4 | 5 | s.name = "MOLH" 6 | s.version = "1.4.3" 7 | s.summary = "Localization helper for iOS apps mainly focusing on the LTR/RTL issue Edit" 8 | 9 | s.description = <<-DESC 10 | Localization helper for iOS apps mainly focusing on the LTR/RTL issue Edit 11 | DESC 12 | 13 | s.homepage = "https://github.com/MoathOthman/MOLH" 14 | 15 | s.license = { :type => "MIT", :file => "LICENSE" } 16 | 17 | 18 | s.author = { "moath othman" => "myopenworld@outlook.com" } 19 | 20 | s.social_media_url = "http://twitter.com/dark_torch" 21 | 22 | s.platform = :ios, "9.0" 23 | 24 | 25 | s.source = { :git => "https://github.com/MoathOthman/MOLH.git", :tag => "v"+s.version.to_s } 26 | 27 | 28 | s.source_files = "Sources/MOLH/*.swift" 29 | 30 | 31 | s.requires_arc = true 32 | 33 | s.swift_version = '5.0' 34 | end 35 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // molhWithMultipleScenese 4 | // 5 | // Created by Moath_Othman on 4/25/20. 6 | // Copyright © 2020 moath. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | @IBOutlet weak var programmaticallylocalizedLabel: UILabel! 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | 18 | self.programmaticallylocalizedLabel.text = NSLocalizedString("localize me please", comment: "Localize me Label in the main scene") 19 | // Do any additional setup after loading the view. 20 | } 21 | @IBAction func switchTheLanguage(_ sender: UIButton) { 22 | MOLH.setLanguageTo(MOLHLanguage.currentAppleLanguage() == "en" ? "ar" : "en") 23 | MOLH.reset(transition: .transitionCrossDissolve) 24 | } 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/agq-CM.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "Hello "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "CAMERA"; 10 | 11 | /* Class = "UITextField"; placeholder = "TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "CAMERON Case"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "CAMERON Second View"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "CAMERON "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ur.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "Hello "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "Main View"; 10 | 11 | /* Class = "UITextField"; placeholder = "TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "TextField Case"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "Go to Second View"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "Second "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ckb-IQ.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "Hello "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "Main View"; 10 | 11 | /* Class = "UITextField"; placeholder = "TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "TextField Case"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "Go to Second View"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "Second "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ckb-IR.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "Hello "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "Main View"; 10 | 11 | /* Class = "UITextField"; placeholder = "TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "TextField Case"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "Go to Second View"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "Second "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/he-IL.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "Hello "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "Main View"; 10 | 11 | /* Class = "UITextField"; placeholder = "TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "TextField Case"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "Go to Second View"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "Second "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/en.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "Hello "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "Main View"; 10 | 11 | /* Class = "UITextField"; placeholder = "Centered TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "TextField Case"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "Go to Second View"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "Second "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ar.lproj/Main.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "UIButton"; normalTitle = "Switch Language"; ObjectID = "Cje-ky-EQg"; */ 3 | "Cje-ky-EQg.normalTitle" = "Switch Language"; 4 | 5 | /* Class = "UILabel"; text = "Hello "; ObjectID = "XqB-5F-EF1"; */ 6 | "XqB-5F-EF1.text" = "مرحبا "; 7 | 8 | /* Class = "UINavigationItem"; title = "Main View"; ObjectID = "eV5-Ly-eMc"; */ 9 | "eV5-Ly-eMc.title" = "الصفحة الرئيسية"; 10 | 11 | /* Class = "UITextField"; placeholder = "Centered TextField Case"; ObjectID = "fiM-aM-EMW"; */ 12 | "fiM-aM-EMW.placeholder" = "حقل بيانات"; 13 | 14 | /* Class = "UIButton"; normalTitle = "Go to Second View"; ObjectID = "jMW-hU-lgc"; */ 15 | "jMW-hU-lgc.normalTitle" = "اذهب الى الصفحة التالية"; 16 | 17 | /* Class = "UIViewController"; title = "Second "; ObjectID = "oPo-J9-SrU"; */ 18 | "oPo-J9-SrU.title" = "الثاني "; 19 | 20 | /* Class = "UILabel"; text = "Label"; ObjectID = "qa0-jT-D1A"; */ 21 | "qa0-jT-D1A.text" = "Label"; 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Moath othman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "MOLH", 8 | platforms: [ 9 | .iOS(.v10) 10 | ], 11 | products: [ 12 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 13 | .library( 14 | name: "MOLH", 15 | targets: ["MOLH"]), 16 | ], 17 | dependencies: [ 18 | // Dependencies declare other packages that this package depends on. 19 | // .package(url: /* package url */, from: "1.0.0"), 20 | ], 21 | targets: [ 22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 24 | .target( 25 | name: "MOLH", 26 | dependencies: []), 27 | .testTarget( 28 | name: "MOLHTests", 29 | dependencies: ["MOLH"]), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // LocalizationHelperDemo 4 | // 5 | // Created by Moath_Othman on 6/2/17. 6 | // Copyright © 2017 Moath. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate, MOLHResetable { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | MOLHFont.shared.arabic = UIFont(name: "Courier", size: 13)! 19 | MOLHLanguage.setDefaultLanguage("ar") 20 | MOLH.shared.activate(true) 21 | 22 | MOLH.shared.specialKeyWords = ["Cancel","Done"] 23 | reset() 24 | return true 25 | } 26 | 27 | func reset() { 28 | let rootViewController: UIWindow = ((UIApplication.shared.delegate?.window)!)! 29 | let story = UIStoryboard(name: "Main", bundle: nil) 30 | rootViewController.rootViewController = story.instantiateViewController(withIdentifier: "rootnav") 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Sources/MOLH/MOLHSizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MOLHSizable.swift 3 | // Demo 4 | // 5 | // Created by Moath_Othman on 2/5/17. 6 | // Copyright © 2017 Moath. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public enum DeviceWidthtype { 13 | case fouror3 14 | case four7 15 | case five5 16 | 17 | static var type: DeviceWidthtype { 18 | let width = UIScreen.main.bounds.width 19 | if width >= 414 { 20 | return .five5 21 | } else if width >= 375 { 22 | return .four7 23 | } else { 24 | return .fouror3 25 | } 26 | } 27 | } 28 | 29 | 30 | open class MOLHSizableLayoutConstraint: NSLayoutConstraint { 31 | var fourDeduction: CGFloat = 0.0 32 | var fourSevenDeduction: CGFloat = 0.0 33 | open override var constant: CGFloat { 34 | get { 35 | let c = super.constant 36 | var sizedConstant = c 37 | switch DeviceWidthtype.type { 38 | case .fouror3: 39 | sizedConstant -= c * self.fourDeduction 40 | break 41 | case .four7: 42 | sizedConstant -= c * self.fourSevenDeduction 43 | break 44 | case .five5: 45 | break 46 | } 47 | return sizedConstant 48 | } 49 | set { 50 | super.constant = newValue 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Base.lproj/LaunchScreen (1).storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // molhWithMultipleScenese 4 | // 5 | // Created by Moath_Othman on 4/25/20. 6 | // Copyright © 2020 moath. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate, MOLHResetable { 13 | var window: UIWindow? 14 | 15 | 16 | func reset() { 17 | let stry = UIStoryboard(name: "Main", bundle: nil) 18 | window?.rootViewController = stry.instantiateInitialViewController() 19 | } 20 | 21 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 22 | 23 | MOLHFont.shared.arabic = UIFont(name: "Courier", size: 13)! 24 | MOLHLanguage.setDefaultLanguage("ar") 25 | MOLH.shared.activate(true) 26 | MOLH.shared.specialKeyWords = ["Cancel","Done"] 27 | 28 | // Override point for customization after application launch. 29 | return true 30 | } 31 | 32 | // MARK: UISceneSession Lifecycle 33 | 34 | @available(iOS 13.0, *) 35 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 36 | // Called when a new scene session is being created. 37 | // Use this method to select a configuration to create the new scene with. 38 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 39 | } 40 | 41 | @available(iOS 13.0, *) 42 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 43 | // Called when the user discards a scene session. 44 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 45 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 46 | } 47 | 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.1) 5 | activesupport (4.2.11.1) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | algoliasearch (1.27.1) 11 | httpclient (~> 2.8, >= 2.8.3) 12 | json (>= 1.5.1) 13 | atomos (0.1.3) 14 | claide (1.0.3) 15 | cocoapods (1.8.4) 16 | activesupport (>= 4.0.2, < 5) 17 | claide (>= 1.0.2, < 2.0) 18 | cocoapods-core (= 1.8.4) 19 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 20 | cocoapods-downloader (>= 1.2.2, < 2.0) 21 | cocoapods-plugins (>= 1.0.0, < 2.0) 22 | cocoapods-search (>= 1.0.0, < 2.0) 23 | cocoapods-stats (>= 1.0.0, < 2.0) 24 | cocoapods-trunk (>= 1.4.0, < 2.0) 25 | cocoapods-try (>= 1.1.0, < 2.0) 26 | colored2 (~> 3.1) 27 | escape (~> 0.0.4) 28 | fourflusher (>= 2.3.0, < 3.0) 29 | gh_inspector (~> 1.0) 30 | molinillo (~> 0.6.6) 31 | nap (~> 1.0) 32 | ruby-macho (~> 1.4) 33 | xcodeproj (>= 1.11.1, < 2.0) 34 | cocoapods-core (1.8.4) 35 | activesupport (>= 4.0.2, < 6) 36 | algoliasearch (~> 1.0) 37 | concurrent-ruby (~> 1.1) 38 | fuzzy_match (~> 2.0.4) 39 | nap (~> 1.0) 40 | cocoapods-deintegrate (1.0.4) 41 | cocoapods-downloader (1.3.0) 42 | cocoapods-plugins (1.0.0) 43 | nap 44 | cocoapods-search (1.0.0) 45 | cocoapods-stats (1.1.0) 46 | cocoapods-trunk (1.4.1) 47 | nap (>= 0.8, < 2.0) 48 | netrc (~> 0.11) 49 | cocoapods-try (1.1.0) 50 | colored2 (3.1.2) 51 | concurrent-ruby (1.1.5) 52 | escape (0.0.4) 53 | fourflusher (2.3.1) 54 | fuzzy_match (2.0.4) 55 | gh_inspector (1.1.3) 56 | httpclient (2.8.3) 57 | i18n (0.9.5) 58 | concurrent-ruby (~> 1.0) 59 | json (2.3.1) 60 | minitest (5.13.0) 61 | molinillo (0.6.6) 62 | nanaimo (0.2.6) 63 | nap (1.1.0) 64 | netrc (0.11.0) 65 | ruby-macho (1.4.0) 66 | thread_safe (0.3.6) 67 | tzinfo (1.2.5) 68 | thread_safe (~> 0.1) 69 | xcodeproj (1.13.0) 70 | CFPropertyList (>= 2.3.3, < 4.0) 71 | atomos (~> 0.1.3) 72 | claide (>= 1.0.2, < 2.0) 73 | colored2 (~> 3.1) 74 | nanaimo (~> 0.2.6) 75 | 76 | PLATFORMS 77 | ruby 78 | 79 | DEPENDENCIES 80 | cocoapods 81 | 82 | BUNDLED WITH 83 | 1.17.3 84 | -------------------------------------------------------------------------------- /Sources/MOLH/MOLHFontLocalizableViews.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MOLHFontLocalizableViews.swift 3 | // Demo 4 | // 5 | // Created by Moath_Othman on 1/27/17. 6 | // Copyright © 2017 Moath. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public protocol MOLHFontable { 13 | func updateFont() 14 | } 15 | 16 | extension UIButton: MOLHFontable { 17 | public func updateFont() { 18 | if MOLHLanguage.isArabic() { 19 | titleLabel?.font = UIFont(name: MOLHFont.shared.arabic.fontName, size: titleLabel?.font.pointSize ?? 0) 20 | } 21 | } 22 | } 23 | 24 | extension UILabel: MOLHFontable { 25 | public func updateFont() { 26 | if MOLHLanguage.isArabic() && !MOLHLanguage.hasEnglishText(text: self.text ?? "") { 27 | self.font = UIFont(name: MOLHFont.shared.arabic.fontName, size: font.pointSize) 28 | } 29 | } 30 | } 31 | 32 | 33 | extension UITextField: MOLHFontable { 34 | public func updateFont() { 35 | if MOLHLanguage.isArabic() && !MOLHLanguage.hasEnglishText(text: self.text ?? "") { 36 | font = UIFont(name: MOLHFont.shared.arabic.fontName, size: font?.pointSize ?? 0) 37 | } 38 | } 39 | } 40 | 41 | extension UITextView: MOLHFontable { 42 | public func updateFont() { 43 | if MOLHLanguage.isArabic() && !MOLHLanguage.hasEnglishText(text: self.text) { 44 | font = UIFont(name: MOLHFont.shared.arabic.fontName, size: font?.pointSize ?? 0) 45 | } 46 | } 47 | } 48 | 49 | open class MOLHFontLocalizableButton: UIButton { 50 | override open func awakeFromNib() { 51 | super.awakeFromNib() 52 | updateFont() 53 | } 54 | } 55 | 56 | open class MOLHFontLocalizableLabel: UILabel { 57 | override open func awakeFromNib() { 58 | super.awakeFromNib() 59 | } 60 | override open var text: String? { 61 | didSet { 62 | updateFont() 63 | } 64 | } 65 | } 66 | 67 | open class MOLHFontLocalizableTextField: UITextField { 68 | override open func awakeFromNib() { 69 | super.awakeFromNib() 70 | } 71 | override open var text: String? { 72 | didSet { 73 | updateFont() 74 | } 75 | } 76 | } 77 | 78 | open class MOLHFontLocalizableTextView: UITextView { 79 | override open func awakeFromNib() { 80 | super.awakeFromNib() 81 | } 82 | override open var text: String? { 83 | didSet { 84 | updateFont() 85 | } 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MOLH 2 | Localization helper for iOS apps mainly focusing on the LTR/RTL issue 3 | 4 | # Install 5 | Add `pod 'MOLH'` to your podfile. (check https://cocoapods.org/ for more info about cocoapods) 6 | 7 | You can install it through Swift package manager as well. 8 | 9 | # How To Use 10 | `import MOLH` 11 | 12 | ### Start 13 | When you start the app 14 | 15 | `MOLH.shared.activate(true)` 16 | 17 | **Make sure this method is called only once and not on every reset** 18 | 19 | or 20 | 21 | `MOLH.shared.activate(false)` to not use swizzling and use subclassing from MOLH* UI classes. 22 | 23 | ### To reset the language 24 | 25 | ``` 26 | MOLH.setLanguageTo(MOLHLanguage.currentAppleLanguage() == "en" ? "ar" : "en") 27 | MOLH.reset() 28 | ``` 29 | 30 | ### Set default 31 | Before *.activate* set 32 | 33 | `MOLHLanguage.setDefaultLanguage("ar")` 34 | 35 | ### using without swizzling (prefered) 36 | you can choose to not use swizzling `MOLH.shared.activate(false)` , in that case you subclass MOLH-UI Subclasses , like `MOLHTextField` , this will give you more controlability as you can by-pass the *tag* requirement by using `forceSwitchingRegardlessOfTag` and set it to true. 37 | 38 | ## Images 39 | To make sure an image is flipped when switching to RTL or to LTR, you can use `flipIfNeeded()` function on image or `UIImage().imageFlippedForRightToLeftLayoutDirection()` 40 | 41 | ### Fonts 42 | Its better to have the app fonts in one place in your app, e.g. a **FontManager**. and there you can decide which font to use based on the chosen language, this would be the eaiser way. 43 | 44 | ### Other Frameworks and bundles 45 | Some controls such as ActionSheetDatePicker have locale property so you can set them appropriately e.g. 46 | 47 | `actionSheetDatePicker?.locale = Locale(identifier: MOLHLanguage.currentLocaleIdentifier())` 48 | 49 | ## Common Issues 50 | ### Collection view content are flipped in a non readable way 51 | use this line to solve it 52 | `collectionView.semanticContentAttribute = .unspecified` 53 | Thanks to [didats](https://github.com/didats) 54 | 55 | you may check [this post](https://medium.com/@dark_torch/working-with-localization-in-swift-part-2-e7c8a660eb2a). 56 | 57 | ### uilabel/uitextfield are not reflecting 58 | make sure to set the tag and make sure the .activate method is only called once and not on every reset 59 | 60 | # Author 61 | * Twitter : [dark_torch](https://twitter.com/dark_torch) 62 | * Website: https://moathothman.com 63 | * Check my app PuzzPic http://apple.co/2a6Ow8W 64 | 65 | # Support the library 66 | If you enjoy MOLH and I want to say thank you, you can (buy me a coffee)[https://www.buymeacoffee.com/moathothman] 67 | -------------------------------------------------------------------------------- /MOLH.xcodeproj/xcshareddata/xcschemes/MOLH-Package.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 63 | 64 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // molhWithMultipleScenese 4 | // 5 | // Created by Moath_Othman on 4/25/20. 6 | // Copyright © 2020 moath. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | @available(iOS 13.0, *) 13 | class SceneDelegate: UIResponder, UIWindowSceneDelegate, MOLHResetable { 14 | 15 | var window: UIWindow? 16 | 17 | func reset() { 18 | let stry = UIStoryboard(name: "Main", bundle: nil) 19 | window?.rootViewController = stry.instantiateInitialViewController() 20 | } 21 | 22 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 23 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 24 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 25 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 26 | guard let _ = (scene as? UIWindowScene) else { return } 27 | 28 | } 29 | 30 | func sceneDidDisconnect(_ scene: UIScene) { 31 | // Called as the scene is being released by the system. 32 | // This occurs shortly after the scene enters the background, or when its session is discarded. 33 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 34 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 35 | } 36 | 37 | func sceneDidBecomeActive(_ scene: UIScene) { 38 | // Called when the scene has moved from an inactive state to an active state. 39 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 40 | } 41 | 42 | func sceneWillResignActive(_ scene: UIScene) { 43 | // Called when the scene will move from an active state to an inactive state. 44 | // This may occur due to temporary interruptions (ex. an incoming phone call). 45 | } 46 | 47 | func sceneWillEnterForeground(_ scene: UIScene) { 48 | // Called as the scene transitions from the background to the foreground. 49 | // Use this method to undo the changes made on entering the background. 50 | } 51 | 52 | func sceneDidEnterBackground(_ scene: UIScene) { 53 | // Called as the scene transitions from the foreground to the background. 54 | // Use this method to save data, release shared resources, and store enough scene-specific state information 55 | // to restore the scene back to its current state. 56 | } 57 | 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese.xcodeproj/xcshareddata/xcschemes/molhWithMultipleScenese.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/xcuserdata/moathaliwat.xcuserdatad/xcschemes/LocalizationHelperDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/StackViewTestViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackViewTestViewController.swift 3 | // LocalizationHelperDemo 4 | // 5 | // Created by Moath_Othman on 5/3/22. 6 | // Copyright © 2022 Moath. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class StackViewTestViewController: UIViewController { 12 | 13 | @IBOutlet var label2: UILabel! 14 | @IBOutlet var label1: UILabel! 15 | private let noContentTextView = InformationTextView() 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | label1.text = NSLocalizedString("stack_view_label_1", comment: "") 21 | label2.text = NSLocalizedString("stack_view_label_2", comment: "") 22 | } 23 | 24 | override func viewDidAppear(_ animated: Bool) { 25 | super.viewDidAppear(animated) 26 | // showNoContentView() 27 | } 28 | 29 | func showNoContentView() { 30 | noContentTextView.configure(text: "LocalizeLocalizeLocalize LocalizeLocalizeLocalize LocalizeLocalize Localize.no_apps_linked_disclaimer()") 31 | view.addSubview(noContentTextView) 32 | 33 | noContentTextView.translatesAutoresizingMaskIntoConstraints = false 34 | NSLayoutConstraint.activate([ 35 | noContentTextView.topAnchor.constraint(equalTo: view.topAnchor, constant: 50), 36 | noContentTextView.leadingAnchor.constraint(equalTo: view.leadingAnchor), 37 | noContentTextView.heightAnchor.constraint(equalToConstant: 150), 38 | noContentTextView.trailingAnchor.constraint(equalTo: view.trailingAnchor) 39 | ]) 40 | } 41 | 42 | func hideNoContentView() { 43 | noContentTextView.removeFromSuperview() 44 | } 45 | } 46 | 47 | @IBDesignable 48 | final class InformationTextView: NibBasedView { 49 | 50 | @IBOutlet private var textLabel: UILabel! 51 | 52 | func configure(text: String) { 53 | self.textLabel.text = text 54 | setup() 55 | } 56 | 57 | override func awakeFromNib() { 58 | super.awakeFromNib() 59 | setup() 60 | } 61 | 62 | func setup() { 63 | textLabel.numberOfLines = 0 64 | textLabel.lineBreakMode = .byWordWrapping 65 | textLabel.tag = -1 66 | backgroundColor = .clear 67 | 68 | textLabel.text = "Verhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad terhoi wlog io sad te " 69 | } 70 | 71 | } 72 | 73 | 74 | class NibBasedView: UIView { 75 | 76 | @IBOutlet private var contentView: UIView! 77 | 78 | override init(frame: CGRect) { 79 | super.init(frame: frame) 80 | loadNib() 81 | } 82 | 83 | required init?(coder aDecoder: NSCoder) { 84 | super.init(coder: aDecoder) 85 | if subviews.isEmpty { 86 | loadNib() 87 | } 88 | } 89 | 90 | private func loadNib() { 91 | let ttt = type(of: self) 92 | let classString = String(describing: ttt) 93 | let bundle = Bundle(for: ttt) 94 | 95 | if UINib(nibName: classString, bundle: bundle).instantiate( 96 | withOwner: self, 97 | options: nil).first as? UIView != nil { 98 | 99 | addSubview(contentView) 100 | contentView.translatesAutoresizingMaskIntoConstraints = false 101 | NSLayoutConstraint.activate([ 102 | contentView.topAnchor.constraint(equalTo: topAnchor), 103 | contentView.leadingAnchor.constraint(equalTo: leadingAnchor), 104 | contentView.bottomAnchor.constraint(equalTo: bottomAnchor), 105 | contentView.trailingAnchor.constraint(equalTo: trailingAnchor) 106 | ]) 107 | } 108 | 109 | style() 110 | } 111 | 112 | func style() { 113 | contentView.backgroundColor = .clear 114 | backgroundColor = .clear 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /post.md: -------------------------------------------------------------------------------- 1 | Working with localization in swift part 2 2 | Last year i write a post about localization covering some issues like switching language and right-to-left / left-to-right dilemma. 3 | 4 | In this post am going to introduce a small library to do the heavy lifting for you. 5 | 6 | The goals 7 | The main goals are 8 | 9 | Switching the language without a restart. 10 | Switching layout direction and semantics based on the language RTL/LTR. 11 | Avoid duplication (nibs,stories) 12 | Simplicity (for real!!) 13 | LocalizationHelper (MOLH) 14 | LocalizationHelper is a small library to help you with the daunting issues that comes when you are dealing with more than one language where some of them are RTL languages and another's are LTR languages. 15 | 16 | You can download the repository from here , which has a demo app within it. 17 | 18 | to install MOLH through Pods add 19 | 20 | pod 'MOLH' 21 | to your podfile. (check https://cocoapods.org/ for more info about cocoapods) 22 | 23 | How to use 24 | 25 | in the Appdelegate `didFinishLaunchingWithOptions` method add 26 | 27 | MOLH.shared.activate(true) 28 | ‘True’ to use swizzling, leaving most of the work on MOLH, otherwise you have to do some extra work. We will go through that. 29 | 30 | Enable localization 31 | 32 | Add Localizable.strings file 33 | Project -> YOUR_PROJECT_NAME -> localization -> hit the plus language and add YOUR_LANGUAGE in our demo we add Arabic as its an RTL language. 34 | Lastly add some text in the strings files in this format 35 | ` “TextToLocalize” = “itsLocalization”; 36 | 37 | You may add localization for storyboard and/or xibs , but I don’t advise that , it will become hard later to modify them. so it’s better to stick with the strings file. 38 | Take effect 39 | The kind of views that are affected by MOLH are UIControl, UILabel, UITextField,UITextView,UIImageView,UIButton. These views are affected by the RTL/LTR e.g. textAlignment , control alignment and UIImage direction. 40 | 41 | If you are not using swizzling then use the appropriate subclass from MOLH e.g. MOLHLabel. 42 | 43 | The most important factor for a view here is the tag . 44 | 45 | If it's less than zero MOLH will consider that it wishes to adapt the natural direction and it will be affected. By default all views have zero tag and hence not affected, so it’s an opt-in feature. 46 | 47 | For the autolayout flipping you don’t need to do anything. Though, to opt-out, then from attribute inspector click on one of the items and uncheck “Respect language direction” . 48 | 49 | Custom Views 50 | For your custom views and custom layout you may need to check for the language manually and there you can use 51 | 52 | MOLHLanguage.isRTL() 53 | function. 54 | 55 | e.g. 56 | 57 | if MOLHLanguage.isRTL() { 58 | titleLabel?.font = UIFont.appSettingNotSelectedFontArabi() 59 | } 60 | Change the language 61 | You probably have somewhere in your app a change language button/cell/… 62 | 63 | in that function call you need to call setLanguage “accept with locale like en-us” and reset. e.g. 64 | 65 | MOLH.setLanguageTo(MOLHLanguage.currentAppleLanguage() == “en” ? “ar” : “en”) 66 | MOLH.reset() 67 | back to Appdelegate.swift , add conformance to MOLHResetable, and implement the reset function. It’s better IMO to handle reloading viewcontrollers in somewhere close to the Appdelegate. 68 | 69 | Other Frameworks and bundles 70 | MOLH currently affects the app bundle only, and since other frameworks may have UI elements with their localization bundled with them, MOLH can’t access them and reload them. 71 | 72 | Some controls such as ActionSheetDatePicker have locale property so you can set them appropriately e.g. 73 | 74 | actionSheetDatePicker?.locale = Locale(identifier: MOLHLanguage.currentLocaleIdentifier()) 75 | others don’t, and in that case you need to handle their localization yourself and simply tell MOLH that those words will be handled by the app bundle. you can do that using specialKeyWords 76 | 77 | MOLH.shared.specialKeyWords = [“Cancel”,”Done”] 78 | where cancel and done are strings used by another bundle and you are providing localizations for them in your Localizable.string. 79 | 80 | Fonts 81 | it’s possible using MOLHFont to specify an arabic font e.g. 82 | 83 | MOLHFont.shared.arabic = R.font.winSoftProMedium(size: 18)! 84 | and there is a method you can use on UIButton,UITextField,UILabel,UITextView called updatefont(), that you can call to change the font into arabic if needed , currently MOLH support specifing arabic font, since I haven’t used another languages tbh :/. 85 | 86 | or you may inherit from MOLHFont. 87 | 88 | Finale 89 | MOLH helped me in a couple of a production apps , I hope it does for you too:). Its far from complete solution and contribution is very welcome. 90 | Happy Coding. 91 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/InformationTextView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Sources/MOLH/MOLHLanguage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // L102Language.swift 3 | // Localization102 4 | // 5 | // Created by Moath_Othman on 2/24/16. 6 | // Copyright © 2016 Moath_Othman. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /// constants 12 | private let APPLE_LANGUAGE_KEY = "AppleLanguages" 13 | private let MOLHFirstTimeLanguage = "plhfirsttimelanguage" 14 | /** 15 | **MOLHLanguage** is responsible for getting and setting the language. 16 | - fetch current language without locale 17 | - get current language with locale 18 | - set current language 19 | - set default language 20 | - check if current language is RTL 21 | - check if current language is Arabic 22 | - check if a text has english chars 23 | 24 | @auther Moath Othman 25 | */ 26 | open class MOLHLanguage { 27 | public static let shared = MOLHLanguage() 28 | 29 | /// get current Apple language 30 | public class func currentAppleLanguage() -> String { 31 | let current = preferredLanguage.first! 32 | if let hyphenIndex = current.firstIndex(of: "-") { 33 | return String(current[.. String { 44 | let current = preferredLanguage.first! 45 | return current 46 | } 47 | 48 | /// set @lang to be the first in AppleLanguages list, note this method does not switch the language currently, u still need to restart the app, use MOLH.setLanguageTo instead 49 | public class func setAppleLanguageTo(_ lang: String) { 50 | let userDefaults = UserDefaults.standard 51 | userDefaults.set([lang,currentAppleLanguage()], forKey: APPLE_LANGUAGE_KEY) 52 | userDefaults.synchronize() 53 | } 54 | 55 | /** 56 | Set the default language 57 | 58 | @param language string 59 | 60 | @return void 61 | */ 62 | public class func setDefaultLanguage(_ language: String) { 63 | if !UserDefaults.standard.bool(forKey: MOLHFirstTimeLanguage) { 64 | MOLH.setLanguageTo(language) 65 | UserDefaults.standard.set(true, forKey: MOLHFirstTimeLanguage) 66 | } 67 | } 68 | 69 | /** 70 | **Check if the current language is Arabic** 71 | @description see if the prefix of the language is ar 72 | 73 | @return is arabic boolean 74 | */ 75 | public class func isArabic() -> Bool { 76 | return currentAppleLanguage() == "ar" 77 | } 78 | 79 | /** 80 | **Check the current Layout direction is right to left** 81 | 82 | @return boolean 83 | */ 84 | @available(*, deprecated, message: "Use isRTLLanguage") 85 | public static func isRTL() -> Bool { 86 | return isRTLLanguage() 87 | } 88 | 89 | /** 90 | Check if the text is english text 91 | 92 | @param text to be checked 93 | 94 | @return true of it has english text 95 | */ 96 | public static func hasEnglishText(text: String) -> Bool { 97 | return text.rangeOfCharacter(from: CharacterSet(charactersIn: "1234567890poiuytrewqasdfghjklmnbvcxz")) != nil 98 | } 99 | 100 | /** 101 | Check if the current language is a right to left language 102 | 103 | @return true if its a right to left language 104 | */ 105 | public static func isRTLLanguage() -> Bool { 106 | return !RTLLanguages.filter{$0 == currentLocaleIdentifier() || $0 == currentAppleLanguage()}.isEmpty 107 | } 108 | 109 | /** 110 | Check if the current language is a right to left language 111 | 112 | @param language to be tested 113 | 114 | @return true if its a right to left language 115 | */ 116 | public static func isRTLLanguage(language: String) -> Bool { 117 | return !RTLLanguages.filter{language == $0}.isEmpty 118 | } 119 | 120 | private static let RTLLanguages = ["ar", 121 | "fa", 122 | "he", 123 | "ckb-IQ", 124 | "ckb-IR", 125 | "ur", 126 | "ckb", 127 | "ku"] 128 | 129 | private static var preferredLanguage: [String] { 130 | let userDefaults = UserDefaults.standard 131 | let langArray = userDefaults.object(forKey: APPLE_LANGUAGE_KEY) 132 | return langArray as? [String] ?? [] 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // LocalizationHelperDemo 4 | // 5 | // Created by Moath_Othman on 6/2/17. 6 | // Copyright © 2017 Moath. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | @IBOutlet weak var programmaticallylocalizedLabel: UILabel! 13 | @IBOutlet var labelWithFont: MOLHFontLocalizableLabel! 14 | @IBOutlet var textField: TextView! 15 | @IBOutlet var arrowImage: UIImageView! { 16 | didSet { 17 | arrowImage.image = arrowImage.image?.flipIfNeeded() 18 | } 19 | } 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | // textField.forceSwitchingRegardlessOfTag = true 24 | self.programmaticallylocalizedLabel.text = NSLocalizedString("localize_me_please", comment: "Localize me Label in the main scene") 25 | 26 | self.labelWithFont.updateFont() 27 | 28 | let identifiers : NSArray = NSLocale.availableLocaleIdentifiers as NSArray 29 | let locale = NSLocale(localeIdentifier: "en_US") 30 | let list = NSMutableString() 31 | for identifier in identifiers { 32 | let name = locale.displayName(forKey: NSLocale.Key.identifier, value: identifier)! 33 | list.append("\(identifier)\t\(name)\n") 34 | } 35 | if #available(iOS 13.0, *) { 36 | labelWithFont.isUserInteractionEnabled = true 37 | let interaction = UIContextMenuInteraction(delegate: self) 38 | labelWithFont.addInteraction(interaction) 39 | 40 | } else { 41 | // Fallback on earlier versions 42 | } 43 | self.programmaticallylocalizedLabel.text = Locale.current.identifier 44 | // let view = UIView() 45 | // view.frame = CGRect(origin: .zero, size: CGSize(width: 100, height: 400)) 46 | // view.backgroundColor = .red 47 | // print("current local", Locale.current.identifier) 48 | // textField.inputView = view 49 | NotificationCenter.default.addObserver(self, selector: #selector(inputModeDidChange), name: UITextInputMode.currentInputModeDidChangeNotification, object: nil) 50 | } 51 | 52 | @objc func inputModeDidChange(_ notification: Notification) { 53 | 54 | // if let language = self.textInputMode?.primaryLanguage, MOLHLanguage.isRTLLanguage(language: language) { 55 | // textField.textAlignment = .right 56 | // } else { 57 | // textField.textAlignment = .left 58 | // } 59 | } 60 | 61 | @IBAction func switchTheLanguage(_ sender: UIButton) { 62 | MOLH.setLanguageTo(MOLHLanguage.currentAppleLanguage() == "en" ? "ar" : "en") 63 | MOLH.reset(transition: .transitionCrossDissolve, duration: 0.25) 64 | } 65 | 66 | @IBAction func didEnd(_ sender: UITextField) { 67 | sender.resignFirstResponder() 68 | } 69 | 70 | @IBAction func end(_ sender: UITextField) { 71 | sender.resignFirstResponder() 72 | } 73 | 74 | 75 | 76 | 77 | // override var textInputMode: UITextInputMode?{ 78 | // print("Total number of keyboards. : \(UITextInputMode.activeInputModes.count)") 79 | // 80 | // for keyboardInputModes in UITextInputMode.activeInputModes { 81 | // if let language = keyboardInputModes.primaryLanguage { 82 | // if language == "ar" { 83 | // print("success") 84 | // return keyboardInputModes; 85 | // } 86 | // } 87 | // } 88 | // 89 | // print("failed") 90 | // return super.textInputMode; 91 | // } 92 | } 93 | 94 | //extension UIResponder { 95 | // open var textInputMode: UITextInputMode? { 96 | // CustomTextInput() 97 | // } 98 | //} 99 | 100 | class CustomTextInput: UITextInputMode { 101 | override var primaryLanguage: String? { 102 | return "fr" 103 | } 104 | } 105 | 106 | extension UIViewController { 107 | @objc open override var textInputMode: UITextInputMode? { 108 | CustomTextInput() 109 | } 110 | } 111 | 112 | final class TextView: MOLHTextField { 113 | // private var preferredTextInputModePrimaryLanguage: String? = "en" 114 | // 115 | // /** 116 | // Use given primary language for the preferred text input mode when next time text view becomes first responder. 117 | // - Parameters: 118 | // - primaryLanguage: `String` represents a primary language for the preferred text input mode. Use `"emoji"` to use Emoji keyboard. 119 | // */ 120 | // func usePreferredTextInputModePrimaryLanguage(_ primaryLanguage: String) { 121 | // preferredTextInputModePrimaryLanguage = primaryLanguage 122 | // } 123 | // 124 | // /** 125 | // # UIKit Bug Workaround 126 | // - Confirmed on iOS 13.0 to iOS 13.3. 127 | // - Fixed on iOS 13.4. 128 | // `textInputMode` override is completely ignored on these version of iOS 13 due to bug in `-[UIKeyboardImpl recomputeActiveInputModesWithExtensions:allowNonLinguisticInputModes:]`, 129 | // which has a flipped condition check, which doesn't always call `-[UIKeyboardImpl setInputMode:userInitiated:]`. 130 | // To workaround this behavior, return non `nil` identifier from `textInputContextIdentifier` to call `-[UIKeyboardImpl setInputMode:userInitiated:]` from 131 | // `-[UIKeyboardInputModeController _trackInputModeIfNecessary:]` and bypass `-[UIKeyboardImpl recomputeActiveInputModesWithExtensions:allowNonLinguisticInputModes:]` call. 132 | // Also need to clean up text input context identifier once it’s used for the bug workaround. 133 | // - See also: 134 | // - `becomeFirstResponder()` 135 | // - `textInputContextIdentifier` 136 | // - `textInputMode` 137 | // */ 138 | // private let shouldWorkaroundTextInputModeBug: Bool = { 139 | // // iOS 13.0 to iOS 13.3 140 | // if #available(iOS 13.0, *) { 141 | // if #available(iOS 13.4, *) { 142 | // return false 143 | // } else { 144 | // return true 145 | // } 146 | // } 147 | // return false 148 | // }() 149 | // 150 | // private let preferredTextInputModeContextIdentifier = ".preferredTextInputModeContextIdentifier" 151 | // 152 | // override func becomeFirstResponder() -> Bool { 153 | // let result = super.becomeFirstResponder() 154 | // if result { 155 | // if shouldWorkaroundTextInputModeBug { 156 | // UIResponder.clearTextInputContextIdentifier(preferredTextInputModeContextIdentifier) 157 | // } 158 | // preferredTextInputModePrimaryLanguage = "en" 159 | // } 160 | // return result 161 | // } 162 | // 163 | // override var textInputContextIdentifier: String? { 164 | // if shouldWorkaroundTextInputModeBug, preferredTextInputModePrimaryLanguage != nil { 165 | // return preferredTextInputModeContextIdentifier 166 | // } 167 | // 168 | // return super.textInputContextIdentifier 169 | // } 170 | // 171 | // override var textInputMode: UITextInputMode? { 172 | // if 173 | // let inputMode = UITextInputMode.activeInputModes.first(where: { $0.primaryLanguage?.contains("en") ?? false }) { 174 | // return inputMode 175 | // } 176 | // 177 | // return super.textInputMode 178 | // } 179 | } 180 | 181 | extension ViewController: UIContextMenuInteractionDelegate { 182 | @available(iOS 13.0, *) 183 | func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? { 184 | 185 | let identifier = "\(location.debugDescription)" as NSString 186 | 187 | let info = UIAction( 188 | title: "ارابيم", 189 | image: UIImage(systemName: "info.circle")) { _ in 190 | } 191 | let mute = UIAction( 192 | title: "L10n.mute", 193 | image: UIImage(systemName: "speaker.slash")) { _ in 194 | //self.showAlert("Error", message: "Implement mute action", handler: nil) 195 | } 196 | 197 | let delete = UIAction( 198 | title: "زيايل", 199 | image: UIImage(systemName: "trash")) { _ in 200 | 201 | } 202 | 203 | let audioCall = UIAction( 204 | title: "نمستي رخه", 205 | image: UIImage(systemName: "phone")) { _ in 206 | } 207 | 208 | let videoCall = UIAction( 209 | title: "L10n.videoCall", 210 | image: UIImage(systemName: "video")) { _ in 211 | } 212 | 213 | _ = UIAction( 214 | title: "L10n.exitGroup", 215 | image: UIImage(systemName: "person.3")) { _ in 216 | } 217 | 218 | var menu = UIMenu() 219 | 220 | menu = UIMenu(title: "", children: [info, mute, delete, audioCall, videoCall]) 221 | 222 | 223 | return UIContextMenuConfiguration( 224 | identifier: identifier, 225 | previewProvider: nil) { _ in 226 | return menu 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /molhWithMultipleScenese/molhWithMultipleScenese.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | ECC09DC224544C5500A7ED48 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09DC124544C5500A7ED48 /* AppDelegate.swift */; }; 11 | ECC09DC424544C5500A7ED48 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09DC324544C5500A7ED48 /* SceneDelegate.swift */; }; 12 | ECC09DC624544C5500A7ED48 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09DC524544C5500A7ED48 /* ViewController.swift */; }; 13 | ECC09DC924544C5500A7ED48 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ECC09DC724544C5500A7ED48 /* Main.storyboard */; }; 14 | ECC09DCB24544C5800A7ED48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ECC09DCA24544C5800A7ED48 /* Assets.xcassets */; }; 15 | ECC09DCE24544C5800A7ED48 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ECC09DCC24544C5800A7ED48 /* LaunchScreen.storyboard */; }; 16 | ECC09E132454876600A7ED48 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = ECC09E152454876600A7ED48 /* Localizable.strings */; }; 17 | ECC09E1D2454B26900A7ED48 /* MOLHLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09E182454B26900A7ED48 /* MOLHLanguage.swift */; }; 18 | ECC09E1E2454B26900A7ED48 /* MOLH.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09E192454B26900A7ED48 /* MOLH.swift */; }; 19 | ECC09E1F2454B26900A7ED48 /* MOLHSizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09E1A2454B26900A7ED48 /* MOLHSizable.swift */; }; 20 | ECC09E202454B26900A7ED48 /* MOLHFontLocalizableViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09E1B2454B26900A7ED48 /* MOLHFontLocalizableViews.swift */; }; 21 | ECC09E212454B26900A7ED48 /* MOLHFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC09E1C2454B26900A7ED48 /* MOLHFont.swift */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | ECC09DBE24544C5500A7ED48 /* molhWithMultipleScenese.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = molhWithMultipleScenese.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | ECC09DC124544C5500A7ED48 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | ECC09DC324544C5500A7ED48 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 28 | ECC09DC524544C5500A7ED48 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 29 | ECC09DC824544C5500A7ED48 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | ECC09DCA24544C5800A7ED48 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | ECC09DCD24544C5800A7ED48 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | ECC09DCF24544C5800A7ED48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | ECC09DEB2454867E00A7ED48 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main.strings; sourceTree = ""; }; 34 | ECC09DEC2454867E00A7ED48 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = ""; }; 35 | ECC09E142454876600A7ED48 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 36 | ECC09E162454876A00A7ED48 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; 37 | ECC09E182454B26900A7ED48 /* MOLHLanguage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOLHLanguage.swift; sourceTree = ""; }; 38 | ECC09E192454B26900A7ED48 /* MOLH.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOLH.swift; sourceTree = ""; }; 39 | ECC09E1A2454B26900A7ED48 /* MOLHSizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOLHSizable.swift; sourceTree = ""; }; 40 | ECC09E1B2454B26900A7ED48 /* MOLHFontLocalizableViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOLHFontLocalizableViews.swift; sourceTree = ""; }; 41 | ECC09E1C2454B26900A7ED48 /* MOLHFont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOLHFont.swift; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | ECC09DBB24544C5500A7ED48 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXFrameworksBuildPhase section */ 53 | 54 | /* Begin PBXGroup section */ 55 | ECC09DB524544C5500A7ED48 = { 56 | isa = PBXGroup; 57 | children = ( 58 | ECC09DC024544C5500A7ED48 /* molhWithMultipleScenese */, 59 | ECC09DBF24544C5500A7ED48 /* Products */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | ECC09DBF24544C5500A7ED48 /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | ECC09DBE24544C5500A7ED48 /* molhWithMultipleScenese.app */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | ECC09DC024544C5500A7ED48 /* molhWithMultipleScenese */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | ECC09DC124544C5500A7ED48 /* AppDelegate.swift */, 75 | ECC09DC324544C5500A7ED48 /* SceneDelegate.swift */, 76 | ECC09DC524544C5500A7ED48 /* ViewController.swift */, 77 | ECC09E172454B26900A7ED48 /* MOLH */, 78 | ECC09E152454876600A7ED48 /* Localizable.strings */, 79 | ECC09DC724544C5500A7ED48 /* Main.storyboard */, 80 | ECC09DCA24544C5800A7ED48 /* Assets.xcassets */, 81 | ECC09DCC24544C5800A7ED48 /* LaunchScreen.storyboard */, 82 | ECC09DCF24544C5800A7ED48 /* Info.plist */, 83 | ); 84 | path = molhWithMultipleScenese; 85 | sourceTree = ""; 86 | }; 87 | ECC09E172454B26900A7ED48 /* MOLH */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | ECC09E182454B26900A7ED48 /* MOLHLanguage.swift */, 91 | ECC09E192454B26900A7ED48 /* MOLH.swift */, 92 | ECC09E1A2454B26900A7ED48 /* MOLHSizable.swift */, 93 | ECC09E1B2454B26900A7ED48 /* MOLHFontLocalizableViews.swift */, 94 | ECC09E1C2454B26900A7ED48 /* MOLHFont.swift */, 95 | ); 96 | name = MOLH; 97 | path = ../../Sources/MOLH; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXNativeTarget section */ 103 | ECC09DBD24544C5500A7ED48 /* molhWithMultipleScenese */ = { 104 | isa = PBXNativeTarget; 105 | buildConfigurationList = ECC09DD224544C5800A7ED48 /* Build configuration list for PBXNativeTarget "molhWithMultipleScenese" */; 106 | buildPhases = ( 107 | ECC09DBA24544C5500A7ED48 /* Sources */, 108 | ECC09DBB24544C5500A7ED48 /* Frameworks */, 109 | ECC09DBC24544C5500A7ED48 /* Resources */, 110 | ); 111 | buildRules = ( 112 | ); 113 | dependencies = ( 114 | ); 115 | name = molhWithMultipleScenese; 116 | productName = molhWithMultipleScenese; 117 | productReference = ECC09DBE24544C5500A7ED48 /* molhWithMultipleScenese.app */; 118 | productType = "com.apple.product-type.application"; 119 | }; 120 | /* End PBXNativeTarget section */ 121 | 122 | /* Begin PBXProject section */ 123 | ECC09DB624544C5500A7ED48 /* Project object */ = { 124 | isa = PBXProject; 125 | attributes = { 126 | LastSwiftUpdateCheck = 1140; 127 | LastUpgradeCheck = 1140; 128 | ORGANIZATIONNAME = moath; 129 | TargetAttributes = { 130 | ECC09DBD24544C5500A7ED48 = { 131 | CreatedOnToolsVersion = 11.4.1; 132 | }; 133 | }; 134 | }; 135 | buildConfigurationList = ECC09DB924544C5500A7ED48 /* Build configuration list for PBXProject "molhWithMultipleScenese" */; 136 | compatibilityVersion = "Xcode 9.3"; 137 | developmentRegion = en; 138 | hasScannedForEncodings = 0; 139 | knownRegions = ( 140 | en, 141 | Base, 142 | ar, 143 | ur, 144 | "ckb-IR", 145 | "agq-CM", 146 | "ckb-IQ", 147 | "he-IL", 148 | ); 149 | mainGroup = ECC09DB524544C5500A7ED48; 150 | productRefGroup = ECC09DBF24544C5500A7ED48 /* Products */; 151 | projectDirPath = ""; 152 | projectRoot = ""; 153 | targets = ( 154 | ECC09DBD24544C5500A7ED48 /* molhWithMultipleScenese */, 155 | ); 156 | }; 157 | /* End PBXProject section */ 158 | 159 | /* Begin PBXResourcesBuildPhase section */ 160 | ECC09DBC24544C5500A7ED48 /* Resources */ = { 161 | isa = PBXResourcesBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | ECC09DCE24544C5800A7ED48 /* LaunchScreen.storyboard in Resources */, 165 | ECC09E132454876600A7ED48 /* Localizable.strings in Resources */, 166 | ECC09DCB24544C5800A7ED48 /* Assets.xcassets in Resources */, 167 | ECC09DC924544C5500A7ED48 /* Main.storyboard in Resources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXResourcesBuildPhase section */ 172 | 173 | /* Begin PBXSourcesBuildPhase section */ 174 | ECC09DBA24544C5500A7ED48 /* Sources */ = { 175 | isa = PBXSourcesBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | ECC09E212454B26900A7ED48 /* MOLHFont.swift in Sources */, 179 | ECC09E1F2454B26900A7ED48 /* MOLHSizable.swift in Sources */, 180 | ECC09DC624544C5500A7ED48 /* ViewController.swift in Sources */, 181 | ECC09E1E2454B26900A7ED48 /* MOLH.swift in Sources */, 182 | ECC09E1D2454B26900A7ED48 /* MOLHLanguage.swift in Sources */, 183 | ECC09DC224544C5500A7ED48 /* AppDelegate.swift in Sources */, 184 | ECC09E202454B26900A7ED48 /* MOLHFontLocalizableViews.swift in Sources */, 185 | ECC09DC424544C5500A7ED48 /* SceneDelegate.swift in Sources */, 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | /* End PBXSourcesBuildPhase section */ 190 | 191 | /* Begin PBXVariantGroup section */ 192 | ECC09DC724544C5500A7ED48 /* Main.storyboard */ = { 193 | isa = PBXVariantGroup; 194 | children = ( 195 | ECC09DC824544C5500A7ED48 /* Base */, 196 | ECC09DEB2454867E00A7ED48 /* ar */, 197 | ); 198 | name = Main.storyboard; 199 | sourceTree = ""; 200 | }; 201 | ECC09DCC24544C5800A7ED48 /* LaunchScreen.storyboard */ = { 202 | isa = PBXVariantGroup; 203 | children = ( 204 | ECC09DCD24544C5800A7ED48 /* Base */, 205 | ECC09DEC2454867E00A7ED48 /* ar */, 206 | ); 207 | name = LaunchScreen.storyboard; 208 | sourceTree = ""; 209 | }; 210 | ECC09E152454876600A7ED48 /* Localizable.strings */ = { 211 | isa = PBXVariantGroup; 212 | children = ( 213 | ECC09E142454876600A7ED48 /* en */, 214 | ECC09E162454876A00A7ED48 /* ar */, 215 | ); 216 | name = Localizable.strings; 217 | sourceTree = ""; 218 | }; 219 | /* End PBXVariantGroup section */ 220 | 221 | /* Begin XCBuildConfiguration section */ 222 | ECC09DD024544C5800A7ED48 /* Debug */ = { 223 | isa = XCBuildConfiguration; 224 | buildSettings = { 225 | ALWAYS_SEARCH_USER_PATHS = NO; 226 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 227 | CLANG_ANALYZER_NONNULL = YES; 228 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_ENABLE_OBJC_WEAK = YES; 234 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 235 | CLANG_WARN_BOOL_CONVERSION = YES; 236 | CLANG_WARN_COMMA = YES; 237 | CLANG_WARN_CONSTANT_CONVERSION = YES; 238 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 239 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 240 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 241 | CLANG_WARN_EMPTY_BODY = YES; 242 | CLANG_WARN_ENUM_CONVERSION = YES; 243 | CLANG_WARN_INFINITE_RECURSION = YES; 244 | CLANG_WARN_INT_CONVERSION = YES; 245 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 246 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 247 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 248 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 249 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 250 | CLANG_WARN_STRICT_PROTOTYPES = YES; 251 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 252 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 253 | CLANG_WARN_UNREACHABLE_CODE = YES; 254 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 255 | COPY_PHASE_STRIP = NO; 256 | DEBUG_INFORMATION_FORMAT = dwarf; 257 | ENABLE_STRICT_OBJC_MSGSEND = YES; 258 | ENABLE_TESTABILITY = YES; 259 | GCC_C_LANGUAGE_STANDARD = gnu11; 260 | GCC_DYNAMIC_NO_PIC = NO; 261 | GCC_NO_COMMON_BLOCKS = YES; 262 | GCC_OPTIMIZATION_LEVEL = 0; 263 | GCC_PREPROCESSOR_DEFINITIONS = ( 264 | "DEBUG=1", 265 | "$(inherited)", 266 | ); 267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 268 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 269 | GCC_WARN_UNDECLARED_SELECTOR = YES; 270 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 271 | GCC_WARN_UNUSED_FUNCTION = YES; 272 | GCC_WARN_UNUSED_VARIABLE = YES; 273 | IPHONEOS_DEPLOYMENT_TARGET = 13.4; 274 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 275 | MTL_FAST_MATH = YES; 276 | ONLY_ACTIVE_ARCH = YES; 277 | SDKROOT = iphoneos; 278 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 279 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 280 | }; 281 | name = Debug; 282 | }; 283 | ECC09DD124544C5800A7ED48 /* Release */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ALWAYS_SEARCH_USER_PATHS = NO; 287 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 288 | CLANG_ANALYZER_NONNULL = YES; 289 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 290 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 291 | CLANG_CXX_LIBRARY = "libc++"; 292 | CLANG_ENABLE_MODULES = YES; 293 | CLANG_ENABLE_OBJC_ARC = YES; 294 | CLANG_ENABLE_OBJC_WEAK = YES; 295 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 296 | CLANG_WARN_BOOL_CONVERSION = YES; 297 | CLANG_WARN_COMMA = YES; 298 | CLANG_WARN_CONSTANT_CONVERSION = YES; 299 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 300 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 301 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 302 | CLANG_WARN_EMPTY_BODY = YES; 303 | CLANG_WARN_ENUM_CONVERSION = YES; 304 | CLANG_WARN_INFINITE_RECURSION = YES; 305 | CLANG_WARN_INT_CONVERSION = YES; 306 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 307 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 308 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 309 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 310 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 311 | CLANG_WARN_STRICT_PROTOTYPES = YES; 312 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 313 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 314 | CLANG_WARN_UNREACHABLE_CODE = YES; 315 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 316 | COPY_PHASE_STRIP = NO; 317 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 318 | ENABLE_NS_ASSERTIONS = NO; 319 | ENABLE_STRICT_OBJC_MSGSEND = YES; 320 | GCC_C_LANGUAGE_STANDARD = gnu11; 321 | GCC_NO_COMMON_BLOCKS = YES; 322 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 323 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 324 | GCC_WARN_UNDECLARED_SELECTOR = YES; 325 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 326 | GCC_WARN_UNUSED_FUNCTION = YES; 327 | GCC_WARN_UNUSED_VARIABLE = YES; 328 | IPHONEOS_DEPLOYMENT_TARGET = 13.4; 329 | MTL_ENABLE_DEBUG_INFO = NO; 330 | MTL_FAST_MATH = YES; 331 | SDKROOT = iphoneos; 332 | SWIFT_COMPILATION_MODE = wholemodule; 333 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 334 | VALIDATE_PRODUCT = YES; 335 | }; 336 | name = Release; 337 | }; 338 | ECC09DD324544C5800A7ED48 /* Debug */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 342 | CODE_SIGN_STYLE = Automatic; 343 | DEVELOPMENT_TEAM = 698J8YQ47A; 344 | INFOPLIST_FILE = molhWithMultipleScenese/Info.plist; 345 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 346 | LD_RUNPATH_SEARCH_PATHS = ( 347 | "$(inherited)", 348 | "@executable_path/Frameworks", 349 | ); 350 | PRODUCT_BUNDLE_IDENTIFIER = com.moath.molhWithMultipleScenese; 351 | PRODUCT_NAME = "$(TARGET_NAME)"; 352 | SWIFT_VERSION = 5.0; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | ECC09DD424544C5800A7ED48 /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | CODE_SIGN_STYLE = Automatic; 362 | DEVELOPMENT_TEAM = 698J8YQ47A; 363 | INFOPLIST_FILE = molhWithMultipleScenese/Info.plist; 364 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 365 | LD_RUNPATH_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "@executable_path/Frameworks", 368 | ); 369 | PRODUCT_BUNDLE_IDENTIFIER = com.moath.molhWithMultipleScenese; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | SWIFT_VERSION = 5.0; 372 | TARGETED_DEVICE_FAMILY = "1,2"; 373 | }; 374 | name = Release; 375 | }; 376 | /* End XCBuildConfiguration section */ 377 | 378 | /* Begin XCConfigurationList section */ 379 | ECC09DB924544C5500A7ED48 /* Build configuration list for PBXProject "molhWithMultipleScenese" */ = { 380 | isa = XCConfigurationList; 381 | buildConfigurations = ( 382 | ECC09DD024544C5800A7ED48 /* Debug */, 383 | ECC09DD124544C5800A7ED48 /* Release */, 384 | ); 385 | defaultConfigurationIsVisible = 0; 386 | defaultConfigurationName = Release; 387 | }; 388 | ECC09DD224544C5800A7ED48 /* Build configuration list for PBXNativeTarget "molhWithMultipleScenese" */ = { 389 | isa = XCConfigurationList; 390 | buildConfigurations = ( 391 | ECC09DD324544C5800A7ED48 /* Debug */, 392 | ECC09DD424544C5800A7ED48 /* Release */, 393 | ); 394 | defaultConfigurationIsVisible = 0; 395 | defaultConfigurationName = Release; 396 | }; 397 | /* End XCConfigurationList section */ 398 | }; 399 | rootObject = ECC09DB624544C5500A7ED48 /* Project object */; 400 | } 401 | -------------------------------------------------------------------------------- /Sources/MOLH/MOLH.swift: -------------------------------------------------------------------------------- 1 | // Moath Othman 2 | // MIT license 3 | 4 | import Foundation 5 | import UIKit 6 | 7 | protocol LayoutSwizzlable: NSObjectProtocol { 8 | func handleSwitching(forceSwitchingRegardlessOfTag: Bool) 9 | } 10 | 11 | protocol Taggable: NSObjectProtocol { 12 | var tag: Int {get set} 13 | } 14 | 15 | protocol TextAlignmented: NSObjectProtocol { 16 | var textAlignment: NSTextAlignment {get set} 17 | } 18 | 19 | extension LayoutSwizzlable where Self: TextAlignmented & Taggable { 20 | func handleSwitching(forceSwitchingRegardlessOfTag: Bool) { 21 | if self.tag < MOLH.shared.maximumLocalizableTag + 1 || forceSwitchingRegardlessOfTag , textAlignment != .center { 22 | if MOLHLanguage.isRTLLanguage() { 23 | if self.textAlignment == .right { return } 24 | self.textAlignment = .right 25 | } else { 26 | if self.textAlignment == .left { return } 27 | self.textAlignment = .left 28 | } 29 | } 30 | } 31 | } 32 | 33 | /// the type of text view , field , label 34 | typealias TextViewType = Taggable & LayoutSwizzlable & TextAlignmented 35 | 36 | /// Localize function 37 | public protocol MOLHLocalizable { 38 | func localize() 39 | } 40 | 41 | /// reset bundles 42 | public protocol MOLHResetable { 43 | func reset() 44 | } 45 | 46 | @available(iOS 13.0, *) 47 | public protocol MOLHSceneResetable { 48 | func reset(scene: UIScene) 49 | } 50 | 51 | open class MOLHViewController : UIViewController { 52 | open override func viewDidLoad() { 53 | super.viewDidLoad() 54 | if self is MOLHLocalizable { 55 | (self as! MOLHLocalizable).localize() 56 | } 57 | } 58 | } 59 | 60 | open class MOLHTableViewController : UITableViewController { 61 | open override func viewDidLoad() { 62 | super.viewDidLoad() 63 | if self is MOLHLocalizable { 64 | (self as! MOLHLocalizable).localize() 65 | } 66 | } 67 | } 68 | 69 | open class MOLHView : UIView { 70 | open override func layoutSubviews() { 71 | super.layoutSubviews() 72 | 73 | if self is MOLHLocalizable { 74 | (self as! MOLHLocalizable).localize() 75 | } 76 | 77 | if self is MOLHFontable { 78 | (self as! MOLHFontable).updateFont() 79 | } 80 | } 81 | } 82 | 83 | open class MOLH { 84 | fileprivate struct Shared { 85 | static let shared = MOLH() 86 | } 87 | 88 | /// which bundle to fallback to if the current language has no bundle 89 | open var fallbackLocale = "Base" 90 | 91 | /// Prevent MOLH() 92 | fileprivate init() {} 93 | 94 | /// shared Instance , MOLH should be accessed through this shared 95 | public static let shared = Shared.shared 96 | 97 | /** 98 | @description 99 | * set the maximum tag where a UIView subclass Deemed Localizable 100 | * if view Tag property is bigger than this number the view will not be flipped 101 | */ 102 | open var maximumLocalizableTag: Int = -1 { 103 | didSet { 104 | assert(maximumLocalizableTag <= -1, "Tag should be less than or equal -1 , since 0 will corrupt UIKit-Made UIs e.g. UIAlertView/Share...") 105 | } 106 | } 107 | 108 | /** 109 | @description 110 | * set special keywords "Keys" that handled by external frameworks to be localized locally 111 | */ 112 | public var specialKeyWords: [String] = [] 113 | 114 | /** 115 | Activate Localization Helper 116 | 117 | **@param** swizzleExtensions Bool if you want to use run time swizzle with all Views like uilabel, default is false... 118 | 119 | **@note** swizzling extension could lead to issues if you are swizzling your UIViews **layoutSubviews** method from another place 120 | */ 121 | open func activate(_ swizzleExtensions: Bool = false) { 122 | swizzle(class: Bundle.self, sel: #selector(Bundle.localizedString(forKey:value:table:)), override: #selector(Bundle.specialLocalizedStringForKey(_:value:table:))) 123 | swizzle(class:UIApplication.self, sel: #selector(getter: UIApplication.userInterfaceLayoutDirection), override: #selector(getter: UIApplication.cstm_userInterfaceLayoutDirection)) 124 | 125 | if swizzleExtensions { 126 | swizzle(class:UIViewController.self, sel: #selector(UIViewController.viewDidLayoutSubviews), override: #selector(UIViewController.mirroringviewDidLoad)) 127 | swizzle(class:UIControl.self, sel: #selector(UIControl.awakeFromNib), override: #selector(UIControl.cstmlayoutSubviews)) 128 | swizzle(class:UITextField.self, sel: #selector(UITextField.layoutSubviews), override: #selector(UITextField.cstmlayoutSubviews)) 129 | swizzle(class:UITextView.self, sel: #selector(UITextView.layoutSubviews), override: #selector(UITextView.cstmlayoutSubviews)) 130 | swizzle(class:UILabel.self, sel: #selector(UILabel.layoutSubviews), override: #selector(UILabel.cstmlayoutSubviews)) 131 | } 132 | } 133 | 134 | /// Set Language , Language parameter string identify the language e.x. en, ar,fr ... 135 | open class func setLanguageTo(_ language: String) { 136 | MOLHLanguage.setAppleLanguageTo(language) 137 | if MOLHLanguage.isRTLLanguage() { 138 | UIView.appearance().semanticContentAttribute = .forceRightToLeft 139 | UIButton.appearance().semanticContentAttribute = .forceRightToLeft 140 | UITextView.appearance().semanticContentAttribute = .forceRightToLeft 141 | UITextField.appearance().semanticContentAttribute = .forceRightToLeft 142 | UINavigationBar.appearance().semanticContentAttribute = .forceRightToLeft 143 | UITabBar.appearance().semanticContentAttribute = .forceRightToLeft 144 | UISearchBar.appearance().semanticContentAttribute = .forceRightToLeft 145 | UILabel.appearance().semanticContentAttribute = .forceRightToLeft 146 | } else { 147 | UIView.appearance().semanticContentAttribute = .forceLeftToRight 148 | UIButton.appearance().semanticContentAttribute = .forceLeftToRight 149 | UITextView.appearance().semanticContentAttribute = .forceLeftToRight 150 | UITextField.appearance().semanticContentAttribute = .forceLeftToRight 151 | UINavigationBar.appearance().semanticContentAttribute = .forceLeftToRight 152 | UITabBar.appearance().semanticContentAttribute = .forceLeftToRight 153 | UISearchBar.appearance().semanticContentAttribute = .forceLeftToRight 154 | UILabel.appearance().semanticContentAttribute = .forceLeftToRight 155 | } 156 | } 157 | 158 | /** 159 | reset app which will perform transition and call reset on appdelegate if it's MOLHResetable 160 | */ 161 | open class func reset(duration: Float = 0.5) { 162 | var transition = UIView.AnimationOptions.transitionFlipFromRight 163 | if !MOLHLanguage.isRTLLanguage() { 164 | transition = .transitionFlipFromLeft 165 | } 166 | reset(transition: transition, duration: duration) 167 | } 168 | 169 | open class func reset(transition: UIView.AnimationOptions, duration: Float = 0.5) { 170 | 171 | func resetWhenNoScenesAvailable() { 172 | if let delegate = UIApplication.shared.delegate { 173 | if delegate is MOLHResetable { 174 | (delegate as!MOLHResetable).reset() 175 | } 176 | UIView.transition(with: ((delegate.window)!)!, duration: TimeInterval(duration), options: transition, animations: {}) 177 | } 178 | } 179 | 180 | if #available(iOS 13.0, *) { 181 | if let window = UIApplication.shared.delegate?.window, window != nil { 182 | resetWhenNoScenesAvailable() 183 | } else { 184 | for scene in UIApplication.shared.connectedScenes { 185 | (scene.delegate as? MOLHSceneResetable)?.reset(scene: scene) 186 | } 187 | } 188 | } else { 189 | resetWhenNoScenesAvailable() 190 | } 191 | } 192 | } 193 | 194 | extension UIApplication { 195 | @objc var cstm_userInterfaceLayoutDirection : UIUserInterfaceLayoutDirection { 196 | get { 197 | var direction = UIUserInterfaceLayoutDirection.leftToRight 198 | if MOLHLanguage.isRTLLanguage() { 199 | direction = .rightToLeft 200 | } 201 | return direction 202 | } 203 | } 204 | } 205 | 206 | extension Bundle { 207 | @objc func specialLocalizedStringForKey(_ key: String, value: String?, table tableName: String?) -> String { 208 | // check if its the main bundle then if the bundle of the current language is available 209 | // then try without locale 210 | // if not go back to base 211 | let translate = { (tableName: String?) -> String in 212 | let currentLanguage = MOLHLanguage.currentLocaleIdentifier() // with locale 213 | let languageWithoutLocale = MOLHLanguage.currentAppleLanguage() // without locale 214 | var bundle = Bundle(); 215 | // normal case where the lang with locale working 216 | if let _path = Bundle.main.path(forResource: currentLanguage, ofType: "lproj") { 217 | bundle = Bundle(path: _path)! 218 | } // en case when its working wihout locale 219 | else if let _path = Bundle.main.path(forResource: languageWithoutLocale, ofType: "lproj") { 220 | bundle = Bundle(path: _path)! 221 | } // current locale not exist , so we fallback 222 | else if let _path = Bundle.main.path(forResource: MOLH.shared.fallbackLocale, ofType: "lproj") { 223 | bundle = Bundle(path: _path)! 224 | } 225 | return (bundle.specialLocalizedStringForKey(key, value: value, table: tableName)) 226 | } 227 | // normal case 228 | if self == Bundle.main { 229 | return translate(tableName) 230 | } // case when the external frameworks has no locale proberty so you have to handle switching yourself 231 | else if MOLH.shared.specialKeyWords.contains(key) { 232 | return translate("Localizable") 233 | } // let the bundle handle the locale 234 | else { 235 | return (self.specialLocalizedStringForKey(key, value: value, table: tableName)) 236 | } 237 | } 238 | } 239 | 240 | extension UIImage { 241 | public func flippedImage() -> UIImage?{ 242 | if let _cgImag = self.cgImage { 243 | let flippedimg = UIImage(cgImage: _cgImag, scale:self.scale , orientation: UIImage.Orientation.upMirrored) 244 | return flippedimg 245 | } 246 | return nil 247 | } 248 | 249 | public func flipIfNeeded() -> UIImage? { 250 | if MOLHLanguage.isRTLLanguage() { 251 | return self.flippedImage() 252 | } 253 | return self 254 | } 255 | } 256 | 257 | extension UIViewController { 258 | 259 | @objc func mirroringviewDidLoad() { 260 | mirroringviewDidLoad() 261 | if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft { 262 | loopThroughSubViewAndFlipTheImageIfItsNeeded(self.view.subviews) 263 | } 264 | // Do any additional setup after loading the view. 265 | } 266 | 267 | /** 268 | Loop through subviews recursivley ,finding any image , uibutton image,uislider image that needs to be flipped 269 | , meaning its tagged less than maximumLocalizableTag and flip it 270 | 271 | @param the view subviews to start with. 272 | 273 | @note note that we suppose that the original is left to right image by default , an image is only flipped if the 274 | currentLanguage is right to left 275 | 276 | @return nothing 277 | */ 278 | func loopThroughSubViewAndFlipTheImageIfItsNeeded(_ subviews: [UIView]) { 279 | 280 | if subviews.count > 0 && MOLHLanguage.isRTLLanguage() { 281 | for subView in subviews where subView.tag <= MOLH.shared.maximumLocalizableTag { 282 | // Flip UIImageView 283 | if subView.isKind(of: UIImageView.self) { 284 | let toRightArrow = subView as! UIImageView 285 | toRightArrow.image = toRightArrow.image?.flipIfNeeded() 286 | } 287 | // Flip UISlider thumb image 288 | if subView.isKind(of: UISlider.self) { 289 | let toRightArrow = subView as! UISlider 290 | let _img = toRightArrow.thumbImage(for: UIControl.State()) 291 | let flipped = _img?.flipIfNeeded() 292 | toRightArrow.setThumbImage(flipped, for: UIControl.State()) 293 | toRightArrow.setThumbImage(flipped, for: .selected) 294 | toRightArrow.setThumbImage(flipped, for: .highlighted) 295 | } 296 | // Flip UIButton image 297 | if subView.isKind(of: UIButton.self) { 298 | let _subView = subView as! UIButton 299 | var image = _subView.image(for: UIControl.State()) 300 | image = image?.flippedImage() 301 | _subView.setImage(image, for: UIControl.State()) 302 | _subView.setImage(image, for: UIControl.State.selected) 303 | _subView.setImage(image, for: UIControl.State.highlighted) 304 | } 305 | 306 | loopThroughSubViewAndFlipTheImageIfItsNeeded(subView.subviews) 307 | } 308 | } 309 | } 310 | 311 | } 312 | 313 | // MARK : - Extensions 314 | extension UIControl { 315 | internal func handleControlSwitching(forceSwitchingRegardlessOfTag: Bool) { 316 | if self.tag < MOLH.shared.maximumLocalizableTag + 1 || forceSwitchingRegardlessOfTag { 317 | if MOLHLanguage.isRTLLanguage() { 318 | if self.contentHorizontalAlignment == .right { return } 319 | self.contentHorizontalAlignment = .right 320 | } else { 321 | if self.contentHorizontalAlignment == .left { return } 322 | self.contentHorizontalAlignment = .left 323 | } 324 | } 325 | } 326 | 327 | @objc public func cstmlayoutSubviews() { 328 | self.cstmlayoutSubviews() 329 | handleControlSwitching(forceSwitchingRegardlessOfTag: false) 330 | } 331 | } 332 | 333 | extension UITextField: TextViewType { 334 | public override func cstmlayoutSubviews() { 335 | self.cstmlayoutSubviews() 336 | handleSwitching(forceSwitchingRegardlessOfTag: false) 337 | handleControlSwitching(forceSwitchingRegardlessOfTag: false) 338 | } 339 | } 340 | 341 | extension UITextView: TextViewType { 342 | @objc public func cstmlayoutSubviews() { 343 | self.cstmlayoutSubviews() 344 | handleSwitching(forceSwitchingRegardlessOfTag: false) 345 | } 346 | } 347 | 348 | extension UILabel: TextViewType { 349 | @objc public func cstmlayoutSubviews() { 350 | self.cstmlayoutSubviews() 351 | handleSwitching(forceSwitchingRegardlessOfTag: false) 352 | } 353 | } 354 | 355 | 356 | // MARK: - SubClasses 357 | /** 358 | `MOLHControl is a UIControl Subclass` 359 | 360 | Any UIControl that wants to be localizable should be subclass of this class 361 | @auther Moath Othman 362 | */ 363 | open class MOLHControl: UIControl { 364 | open var forceSwitchingRegardlessOfTag: Bool = false { 365 | didSet { 366 | handleControlSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 367 | } 368 | } 369 | override open func layoutSubviews() { 370 | super.layoutSubviews() 371 | handleControlSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 372 | } 373 | } 374 | /** 375 | MOLHLabel is a UILabel Subclass 376 | Any Label that wants to be localizable should be subclass of this class§ 377 | @auther Moath Othman 378 | */ 379 | open class MOLHLabel: UILabel { 380 | open var forceSwitchingRegardlessOfTag: Bool = false { 381 | didSet { 382 | handleSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 383 | } 384 | } 385 | override open func layoutSubviews() { 386 | super.layoutSubviews() 387 | handleSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 388 | } 389 | } 390 | /** 391 | MOLHTextView is a UITextView Subclass 392 | Any TextView that wants to be localizable should be subclass of this class§ 393 | @auther Moath Othman 394 | */ 395 | open class MOLHTextView: UITextView { 396 | open var forceSwitchingRegardlessOfTag: Bool = false { 397 | didSet { 398 | handleSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 399 | } 400 | } 401 | override open func layoutSubviews() { 402 | super.layoutSubviews() 403 | handleSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 404 | } 405 | } 406 | /** 407 | MOLHTextField is a UITextField Subclass 408 | Any TextField that wants to be localizable should be subclass of this class§ 409 | @auther Moath Othman 410 | */ 411 | open class MOLHTextField: UITextField { 412 | open var forceSwitchingRegardlessOfTag: Bool = false { 413 | didSet { 414 | setupForLocalization() 415 | } 416 | } 417 | 418 | public override init(frame: CGRect) { 419 | super.init(frame: frame) 420 | setupForLocalization() 421 | } 422 | 423 | public required init?(coder aDecoder: NSCoder) { 424 | super.init(coder: aDecoder) 425 | setupForLocalization() 426 | } 427 | 428 | func setupForLocalization() { 429 | handleControlSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 430 | handleSwitching(forceSwitchingRegardlessOfTag: forceSwitchingRegardlessOfTag) 431 | } 432 | } 433 | 434 | // MARK: - Utility 435 | /// Exchange the implementation of two methods for the same Class override will replace sel 436 | private func swizzle(class cls: AnyClass, sel: Selector, override: Selector) { 437 | guard let origMethod: Method = class_getInstanceMethod(cls, sel) else { return } 438 | guard let overrideMethod: Method = class_getInstanceMethod(cls, override) else { return } 439 | if (class_addMethod(cls, sel, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) { 440 | class_replaceMethod(cls, override, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)) 441 | } else { 442 | method_exchangeImplementations(origMethod, overrideMethod); 443 | } 444 | } 445 | 446 | -------------------------------------------------------------------------------- /MOLH.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = "1"; 4 | objectVersion = "46"; 5 | objects = { 6 | "MOLH::MOLH" = { 7 | isa = "PBXNativeTarget"; 8 | buildConfigurationList = "OBJ_27"; 9 | buildPhases = ( 10 | "OBJ_30", 11 | "OBJ_36" 12 | ); 13 | dependencies = ( 14 | ); 15 | name = "MOLH"; 16 | productName = "MOLH"; 17 | productReference = "MOLH::MOLH::Product"; 18 | productType = "com.apple.product-type.framework"; 19 | }; 20 | "MOLH::MOLH::Product" = { 21 | isa = "PBXFileReference"; 22 | path = "MOLH.framework"; 23 | sourceTree = "BUILT_PRODUCTS_DIR"; 24 | }; 25 | "MOLH::MOLHPackageTests::ProductTarget" = { 26 | isa = "PBXAggregateTarget"; 27 | buildConfigurationList = "OBJ_44"; 28 | buildPhases = ( 29 | ); 30 | dependencies = ( 31 | "OBJ_47" 32 | ); 33 | name = "MOLHPackageTests"; 34 | productName = "MOLHPackageTests"; 35 | }; 36 | "MOLH::MOLHTests" = { 37 | isa = "PBXNativeTarget"; 38 | buildConfigurationList = "OBJ_49"; 39 | buildPhases = ( 40 | "OBJ_52", 41 | "OBJ_55" 42 | ); 43 | dependencies = ( 44 | "OBJ_57" 45 | ); 46 | name = "MOLHTests"; 47 | productName = "MOLHTests"; 48 | productReference = "MOLH::MOLHTests::Product"; 49 | productType = "com.apple.product-type.bundle.unit-test"; 50 | }; 51 | "MOLH::MOLHTests::Product" = { 52 | isa = "PBXFileReference"; 53 | path = "MOLHTests.xctest"; 54 | sourceTree = "BUILT_PRODUCTS_DIR"; 55 | }; 56 | "MOLH::SwiftPMPackageDescription" = { 57 | isa = "PBXNativeTarget"; 58 | buildConfigurationList = "OBJ_38"; 59 | buildPhases = ( 60 | "OBJ_41" 61 | ); 62 | dependencies = ( 63 | ); 64 | name = "MOLHPackageDescription"; 65 | productName = "MOLHPackageDescription"; 66 | productType = "com.apple.product-type.framework"; 67 | }; 68 | "OBJ_1" = { 69 | isa = "PBXProject"; 70 | attributes = { 71 | LastSwiftMigration = "9999"; 72 | LastUpgradeCheck = "9999"; 73 | }; 74 | buildConfigurationList = "OBJ_2"; 75 | compatibilityVersion = "Xcode 3.2"; 76 | developmentRegion = "en"; 77 | hasScannedForEncodings = "0"; 78 | knownRegions = ( 79 | "en" 80 | ); 81 | mainGroup = "OBJ_5"; 82 | productRefGroup = "OBJ_18"; 83 | projectDirPath = "."; 84 | targets = ( 85 | "MOLH::MOLH", 86 | "MOLH::SwiftPMPackageDescription", 87 | "MOLH::MOLHPackageTests::ProductTarget", 88 | "MOLH::MOLHTests" 89 | ); 90 | }; 91 | "OBJ_10" = { 92 | isa = "PBXFileReference"; 93 | path = "MOLHFont.swift"; 94 | sourceTree = ""; 95 | }; 96 | "OBJ_11" = { 97 | isa = "PBXFileReference"; 98 | path = "MOLHFontLocalizableViews.swift"; 99 | sourceTree = ""; 100 | }; 101 | "OBJ_12" = { 102 | isa = "PBXFileReference"; 103 | path = "MOLHLanguage.swift"; 104 | sourceTree = ""; 105 | }; 106 | "OBJ_13" = { 107 | isa = "PBXFileReference"; 108 | path = "MOLHSizable.swift"; 109 | sourceTree = ""; 110 | }; 111 | "OBJ_14" = { 112 | isa = "PBXGroup"; 113 | children = ( 114 | "OBJ_15" 115 | ); 116 | name = "Tests"; 117 | path = ""; 118 | sourceTree = "SOURCE_ROOT"; 119 | }; 120 | "OBJ_15" = { 121 | isa = "PBXGroup"; 122 | children = ( 123 | "OBJ_16", 124 | "OBJ_17" 125 | ); 126 | name = "MOLHTests"; 127 | path = "Tests/MOLHTests"; 128 | sourceTree = "SOURCE_ROOT"; 129 | }; 130 | "OBJ_16" = { 131 | isa = "PBXFileReference"; 132 | path = "MOLHTests.swift"; 133 | sourceTree = ""; 134 | }; 135 | "OBJ_17" = { 136 | isa = "PBXFileReference"; 137 | path = "XCTestManifests.swift"; 138 | sourceTree = ""; 139 | }; 140 | "OBJ_18" = { 141 | isa = "PBXGroup"; 142 | children = ( 143 | "MOLH::MOLHTests::Product", 144 | "MOLH::MOLH::Product" 145 | ); 146 | name = "Products"; 147 | path = ""; 148 | sourceTree = "BUILT_PRODUCTS_DIR"; 149 | }; 150 | "OBJ_2" = { 151 | isa = "XCConfigurationList"; 152 | buildConfigurations = ( 153 | "OBJ_3", 154 | "OBJ_4" 155 | ); 156 | defaultConfigurationIsVisible = "0"; 157 | defaultConfigurationName = "Release"; 158 | }; 159 | "OBJ_21" = { 160 | isa = "PBXFileReference"; 161 | path = "LocalizationHelperDemo"; 162 | sourceTree = "SOURCE_ROOT"; 163 | }; 164 | "OBJ_22" = { 165 | isa = "PBXFileReference"; 166 | path = "LICENSE"; 167 | sourceTree = ""; 168 | }; 169 | "OBJ_23" = { 170 | isa = "PBXFileReference"; 171 | path = "MOLH.podspec"; 172 | sourceTree = ""; 173 | }; 174 | "OBJ_24" = { 175 | isa = "PBXFileReference"; 176 | path = "README.md"; 177 | sourceTree = ""; 178 | }; 179 | "OBJ_25" = { 180 | isa = "PBXFileReference"; 181 | path = "post.md"; 182 | sourceTree = ""; 183 | }; 184 | "OBJ_27" = { 185 | isa = "XCConfigurationList"; 186 | buildConfigurations = ( 187 | "OBJ_28", 188 | "OBJ_29" 189 | ); 190 | defaultConfigurationIsVisible = "0"; 191 | defaultConfigurationName = "Release"; 192 | }; 193 | "OBJ_28" = { 194 | isa = "XCBuildConfiguration"; 195 | buildSettings = { 196 | ENABLE_TESTABILITY = "YES"; 197 | FRAMEWORK_SEARCH_PATHS = ( 198 | "$(inherited)", 199 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 200 | ); 201 | HEADER_SEARCH_PATHS = ( 202 | "$(inherited)" 203 | ); 204 | INFOPLIST_FILE = "MOLH.xcodeproj/MOLH_Info.plist"; 205 | IPHONEOS_DEPLOYMENT_TARGET = "10.0"; 206 | LD_RUNPATH_SEARCH_PATHS = ( 207 | "$(inherited)", 208 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" 209 | ); 210 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 211 | OTHER_CFLAGS = ( 212 | "$(inherited)" 213 | ); 214 | OTHER_LDFLAGS = ( 215 | "$(inherited)" 216 | ); 217 | OTHER_SWIFT_FLAGS = ( 218 | "$(inherited)" 219 | ); 220 | PRODUCT_BUNDLE_IDENTIFIER = "MOLH"; 221 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 222 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 223 | SKIP_INSTALL = "YES"; 224 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 225 | "$(inherited)" 226 | ); 227 | SWIFT_VERSION = "5.0"; 228 | TARGET_NAME = "MOLH"; 229 | TVOS_DEPLOYMENT_TARGET = "9.0"; 230 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 231 | }; 232 | name = "Debug"; 233 | }; 234 | "OBJ_29" = { 235 | isa = "XCBuildConfiguration"; 236 | buildSettings = { 237 | ENABLE_TESTABILITY = "YES"; 238 | FRAMEWORK_SEARCH_PATHS = ( 239 | "$(inherited)", 240 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 241 | ); 242 | HEADER_SEARCH_PATHS = ( 243 | "$(inherited)" 244 | ); 245 | INFOPLIST_FILE = "MOLH.xcodeproj/MOLH_Info.plist"; 246 | IPHONEOS_DEPLOYMENT_TARGET = "10.0"; 247 | LD_RUNPATH_SEARCH_PATHS = ( 248 | "$(inherited)", 249 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx" 250 | ); 251 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 252 | OTHER_CFLAGS = ( 253 | "$(inherited)" 254 | ); 255 | OTHER_LDFLAGS = ( 256 | "$(inherited)" 257 | ); 258 | OTHER_SWIFT_FLAGS = ( 259 | "$(inherited)" 260 | ); 261 | PRODUCT_BUNDLE_IDENTIFIER = "MOLH"; 262 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; 263 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 264 | SKIP_INSTALL = "YES"; 265 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 266 | "$(inherited)" 267 | ); 268 | SWIFT_VERSION = "5.0"; 269 | TARGET_NAME = "MOLH"; 270 | TVOS_DEPLOYMENT_TARGET = "9.0"; 271 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 272 | }; 273 | name = "Release"; 274 | }; 275 | "OBJ_3" = { 276 | isa = "XCBuildConfiguration"; 277 | buildSettings = { 278 | CLANG_ENABLE_OBJC_ARC = "YES"; 279 | COMBINE_HIDPI_IMAGES = "YES"; 280 | COPY_PHASE_STRIP = "NO"; 281 | DEBUG_INFORMATION_FORMAT = "dwarf"; 282 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 283 | ENABLE_NS_ASSERTIONS = "YES"; 284 | GCC_OPTIMIZATION_LEVEL = "0"; 285 | GCC_PREPROCESSOR_DEFINITIONS = ( 286 | "$(inherited)", 287 | "SWIFT_PACKAGE=1", 288 | "DEBUG=1" 289 | ); 290 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 291 | ONLY_ACTIVE_ARCH = "YES"; 292 | OTHER_SWIFT_FLAGS = ( 293 | "$(inherited)", 294 | "-DXcode" 295 | ); 296 | PRODUCT_NAME = "$(TARGET_NAME)"; 297 | SDKROOT = "macosx"; 298 | SUPPORTED_PLATFORMS = ( 299 | "macosx", 300 | "iphoneos", 301 | "iphonesimulator", 302 | "appletvos", 303 | "appletvsimulator", 304 | "watchos", 305 | "watchsimulator" 306 | ); 307 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 308 | "$(inherited)", 309 | "SWIFT_PACKAGE", 310 | "DEBUG" 311 | ); 312 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 313 | USE_HEADERMAP = "NO"; 314 | }; 315 | name = "Debug"; 316 | }; 317 | "OBJ_30" = { 318 | isa = "PBXSourcesBuildPhase"; 319 | files = ( 320 | "OBJ_31", 321 | "OBJ_32", 322 | "OBJ_33", 323 | "OBJ_34", 324 | "OBJ_35" 325 | ); 326 | }; 327 | "OBJ_31" = { 328 | isa = "PBXBuildFile"; 329 | fileRef = "OBJ_9"; 330 | }; 331 | "OBJ_32" = { 332 | isa = "PBXBuildFile"; 333 | fileRef = "OBJ_10"; 334 | }; 335 | "OBJ_33" = { 336 | isa = "PBXBuildFile"; 337 | fileRef = "OBJ_11"; 338 | }; 339 | "OBJ_34" = { 340 | isa = "PBXBuildFile"; 341 | fileRef = "OBJ_12"; 342 | }; 343 | "OBJ_35" = { 344 | isa = "PBXBuildFile"; 345 | fileRef = "OBJ_13"; 346 | }; 347 | "OBJ_36" = { 348 | isa = "PBXFrameworksBuildPhase"; 349 | files = ( 350 | ); 351 | }; 352 | "OBJ_38" = { 353 | isa = "XCConfigurationList"; 354 | buildConfigurations = ( 355 | "OBJ_39", 356 | "OBJ_40" 357 | ); 358 | defaultConfigurationIsVisible = "0"; 359 | defaultConfigurationName = "Release"; 360 | }; 361 | "OBJ_39" = { 362 | isa = "XCBuildConfiguration"; 363 | buildSettings = { 364 | LD = "/usr/bin/true"; 365 | OTHER_SWIFT_FLAGS = ( 366 | "-swift-version", 367 | "5", 368 | "-I", 369 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", 370 | "-target", 371 | "x86_64-apple-macosx10.10", 372 | "-sdk", 373 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk", 374 | "-package-description-version", 375 | "5.1" 376 | ); 377 | SWIFT_VERSION = "5.0"; 378 | }; 379 | name = "Debug"; 380 | }; 381 | "OBJ_4" = { 382 | isa = "XCBuildConfiguration"; 383 | buildSettings = { 384 | CLANG_ENABLE_OBJC_ARC = "YES"; 385 | COMBINE_HIDPI_IMAGES = "YES"; 386 | COPY_PHASE_STRIP = "YES"; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 389 | GCC_OPTIMIZATION_LEVEL = "s"; 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "$(inherited)", 392 | "SWIFT_PACKAGE=1" 393 | ); 394 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 395 | OTHER_SWIFT_FLAGS = ( 396 | "$(inherited)", 397 | "-DXcode" 398 | ); 399 | PRODUCT_NAME = "$(TARGET_NAME)"; 400 | SDKROOT = "macosx"; 401 | SUPPORTED_PLATFORMS = ( 402 | "macosx", 403 | "iphoneos", 404 | "iphonesimulator", 405 | "appletvos", 406 | "appletvsimulator", 407 | "watchos", 408 | "watchsimulator" 409 | ); 410 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 411 | "$(inherited)", 412 | "SWIFT_PACKAGE" 413 | ); 414 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 415 | USE_HEADERMAP = "NO"; 416 | }; 417 | name = "Release"; 418 | }; 419 | "OBJ_40" = { 420 | isa = "XCBuildConfiguration"; 421 | buildSettings = { 422 | LD = "/usr/bin/true"; 423 | OTHER_SWIFT_FLAGS = ( 424 | "-swift-version", 425 | "5", 426 | "-I", 427 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2", 428 | "-target", 429 | "x86_64-apple-macosx10.10", 430 | "-sdk", 431 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk", 432 | "-package-description-version", 433 | "5.1" 434 | ); 435 | SWIFT_VERSION = "5.0"; 436 | }; 437 | name = "Release"; 438 | }; 439 | "OBJ_41" = { 440 | isa = "PBXSourcesBuildPhase"; 441 | files = ( 442 | "OBJ_42" 443 | ); 444 | }; 445 | "OBJ_42" = { 446 | isa = "PBXBuildFile"; 447 | fileRef = "OBJ_6"; 448 | }; 449 | "OBJ_44" = { 450 | isa = "XCConfigurationList"; 451 | buildConfigurations = ( 452 | "OBJ_45", 453 | "OBJ_46" 454 | ); 455 | defaultConfigurationIsVisible = "0"; 456 | defaultConfigurationName = "Release"; 457 | }; 458 | "OBJ_45" = { 459 | isa = "XCBuildConfiguration"; 460 | buildSettings = { 461 | }; 462 | name = "Debug"; 463 | }; 464 | "OBJ_46" = { 465 | isa = "XCBuildConfiguration"; 466 | buildSettings = { 467 | }; 468 | name = "Release"; 469 | }; 470 | "OBJ_47" = { 471 | isa = "PBXTargetDependency"; 472 | target = "MOLH::MOLHTests"; 473 | }; 474 | "OBJ_49" = { 475 | isa = "XCConfigurationList"; 476 | buildConfigurations = ( 477 | "OBJ_50", 478 | "OBJ_51" 479 | ); 480 | defaultConfigurationIsVisible = "0"; 481 | defaultConfigurationName = "Release"; 482 | }; 483 | "OBJ_5" = { 484 | isa = "PBXGroup"; 485 | children = ( 486 | "OBJ_6", 487 | "OBJ_7", 488 | "OBJ_14", 489 | "OBJ_18", 490 | "OBJ_21", 491 | "OBJ_22", 492 | "OBJ_23", 493 | "OBJ_24", 494 | "OBJ_25" 495 | ); 496 | path = ""; 497 | sourceTree = ""; 498 | }; 499 | "OBJ_50" = { 500 | isa = "XCBuildConfiguration"; 501 | buildSettings = { 502 | CLANG_ENABLE_MODULES = "YES"; 503 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; 504 | FRAMEWORK_SEARCH_PATHS = ( 505 | "$(inherited)", 506 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 507 | ); 508 | HEADER_SEARCH_PATHS = ( 509 | "$(inherited)" 510 | ); 511 | INFOPLIST_FILE = "MOLH.xcodeproj/MOLHTests_Info.plist"; 512 | IPHONEOS_DEPLOYMENT_TARGET = "10.0"; 513 | LD_RUNPATH_SEARCH_PATHS = ( 514 | "$(inherited)", 515 | "@loader_path/../Frameworks", 516 | "@loader_path/Frameworks" 517 | ); 518 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 519 | OTHER_CFLAGS = ( 520 | "$(inherited)" 521 | ); 522 | OTHER_LDFLAGS = ( 523 | "$(inherited)" 524 | ); 525 | OTHER_SWIFT_FLAGS = ( 526 | "$(inherited)" 527 | ); 528 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 529 | "$(inherited)" 530 | ); 531 | SWIFT_VERSION = "5.0"; 532 | TARGET_NAME = "MOLHTests"; 533 | TVOS_DEPLOYMENT_TARGET = "9.0"; 534 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 535 | }; 536 | name = "Debug"; 537 | }; 538 | "OBJ_51" = { 539 | isa = "XCBuildConfiguration"; 540 | buildSettings = { 541 | CLANG_ENABLE_MODULES = "YES"; 542 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES"; 543 | FRAMEWORK_SEARCH_PATHS = ( 544 | "$(inherited)", 545 | "$(PLATFORM_DIR)/Developer/Library/Frameworks" 546 | ); 547 | HEADER_SEARCH_PATHS = ( 548 | "$(inherited)" 549 | ); 550 | INFOPLIST_FILE = "MOLH.xcodeproj/MOLHTests_Info.plist"; 551 | IPHONEOS_DEPLOYMENT_TARGET = "10.0"; 552 | LD_RUNPATH_SEARCH_PATHS = ( 553 | "$(inherited)", 554 | "@loader_path/../Frameworks", 555 | "@loader_path/Frameworks" 556 | ); 557 | MACOSX_DEPLOYMENT_TARGET = "10.10"; 558 | OTHER_CFLAGS = ( 559 | "$(inherited)" 560 | ); 561 | OTHER_LDFLAGS = ( 562 | "$(inherited)" 563 | ); 564 | OTHER_SWIFT_FLAGS = ( 565 | "$(inherited)" 566 | ); 567 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( 568 | "$(inherited)" 569 | ); 570 | SWIFT_VERSION = "5.0"; 571 | TARGET_NAME = "MOLHTests"; 572 | TVOS_DEPLOYMENT_TARGET = "9.0"; 573 | WATCHOS_DEPLOYMENT_TARGET = "2.0"; 574 | }; 575 | name = "Release"; 576 | }; 577 | "OBJ_52" = { 578 | isa = "PBXSourcesBuildPhase"; 579 | files = ( 580 | "OBJ_53", 581 | "OBJ_54" 582 | ); 583 | }; 584 | "OBJ_53" = { 585 | isa = "PBXBuildFile"; 586 | fileRef = "OBJ_16"; 587 | }; 588 | "OBJ_54" = { 589 | isa = "PBXBuildFile"; 590 | fileRef = "OBJ_17"; 591 | }; 592 | "OBJ_55" = { 593 | isa = "PBXFrameworksBuildPhase"; 594 | files = ( 595 | "OBJ_56" 596 | ); 597 | }; 598 | "OBJ_56" = { 599 | isa = "PBXBuildFile"; 600 | fileRef = "MOLH::MOLH::Product"; 601 | }; 602 | "OBJ_57" = { 603 | isa = "PBXTargetDependency"; 604 | target = "MOLH::MOLH"; 605 | }; 606 | "OBJ_6" = { 607 | isa = "PBXFileReference"; 608 | explicitFileType = "sourcecode.swift"; 609 | path = "Package.swift"; 610 | sourceTree = ""; 611 | }; 612 | "OBJ_7" = { 613 | isa = "PBXGroup"; 614 | children = ( 615 | "OBJ_8" 616 | ); 617 | name = "Sources"; 618 | path = ""; 619 | sourceTree = "SOURCE_ROOT"; 620 | }; 621 | "OBJ_8" = { 622 | isa = "PBXGroup"; 623 | children = ( 624 | "OBJ_9", 625 | "OBJ_10", 626 | "OBJ_11", 627 | "OBJ_12", 628 | "OBJ_13" 629 | ); 630 | name = "MOLH"; 631 | path = "Sources/MOLH"; 632 | sourceTree = "SOURCE_ROOT"; 633 | }; 634 | "OBJ_9" = { 635 | isa = "PBXFileReference"; 636 | path = "MOLH.swift"; 637 | sourceTree = ""; 638 | }; 639 | }; 640 | rootObject = "OBJ_1"; 641 | } 642 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | EC07B15428491341009C9FCE /* InformationTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = EC07B15328491341009C9FCE /* InformationTextView.xib */; }; 11 | EC15335321F39E440048AB78 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC15335521F39E440048AB78 /* Main.storyboard */; }; 12 | EC1F34662821477F00C0286B /* StackViewTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC1F34652821477F00C0286B /* StackViewTestViewController.swift */; }; 13 | EC48F76D238186500095E588 /* MOLHFontLocalizableViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC48F768238186500095E588 /* MOLHFontLocalizableViews.swift */; }; 14 | EC48F76E238186500095E588 /* MOLHFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC48F769238186500095E588 /* MOLHFont.swift */; }; 15 | EC48F76F238186500095E588 /* MOLH.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC48F76A238186500095E588 /* MOLH.swift */; }; 16 | EC48F770238186500095E588 /* MOLHSizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC48F76B238186500095E588 /* MOLHSizable.swift */; }; 17 | EC48F771238186500095E588 /* MOLHLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC48F76C238186500095E588 /* MOLHLanguage.swift */; }; 18 | EC5B8FEC1EE0ECA4003BE809 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC5B8FEB1EE0ECA4003BE809 /* AppDelegate.swift */; }; 19 | EC5B8FEE1EE0ECA4003BE809 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC5B8FED1EE0ECA4003BE809 /* ViewController.swift */; }; 20 | EC5B8FF31EE0ECA4003BE809 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC5B8FF21EE0ECA4003BE809 /* Assets.xcassets */; }; 21 | EC5B8FF61EE0ECA4003BE809 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EC5B8FF41EE0ECA4003BE809 /* LaunchScreen.storyboard */; }; 22 | ECE2F0C321FB72AD009D506D /* MOLH.podspec in Resources */ = {isa = PBXBuildFile; fileRef = ECE2F0C221FB72AC009D506D /* MOLH.podspec */; }; 23 | ECE534921EE2237300EBB394 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = ECE534941EE2237300EBB394 /* Localizable.strings */; }; 24 | ECE534981EE226F300EBB394 /* arrow-right.png in Resources */ = {isa = PBXBuildFile; fileRef = ECE534971EE226F300EBB394 /* arrow-right.png */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | EC07B15328491341009C9FCE /* InformationTextView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InformationTextView.xib; sourceTree = ""; }; 29 | EC15335821F39E790048AB78 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | EC15335A21F39E7C0048AB78 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = ""; }; 31 | EC15335B21F39E810048AB78 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main.strings; sourceTree = ""; }; 32 | EC1F34652821477F00C0286B /* StackViewTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackViewTestViewController.swift; sourceTree = ""; }; 33 | EC3E86B9226F1AB200EDE6EE /* agq-CM */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "agq-CM"; path = "agq-CM.lproj/Main.strings"; sourceTree = ""; }; 34 | EC3E86BA226F1AB200EDE6EE /* agq-CM */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "agq-CM"; path = "agq-CM.lproj/LaunchScreen.strings"; sourceTree = ""; }; 35 | EC3E86BB226F1AB200EDE6EE /* agq-CM */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "agq-CM"; path = "agq-CM.lproj/Localizable.strings"; sourceTree = ""; }; 36 | EC48F768238186500095E588 /* MOLHFontLocalizableViews.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MOLHFontLocalizableViews.swift; path = ../Sources/MOLH/MOLHFontLocalizableViews.swift; sourceTree = ""; }; 37 | EC48F769238186500095E588 /* MOLHFont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MOLHFont.swift; path = ../Sources/MOLH/MOLHFont.swift; sourceTree = ""; }; 38 | EC48F76A238186500095E588 /* MOLH.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MOLH.swift; path = ../Sources/MOLH/MOLH.swift; sourceTree = ""; }; 39 | EC48F76B238186500095E588 /* MOLHSizable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MOLHSizable.swift; path = ../Sources/MOLH/MOLHSizable.swift; sourceTree = ""; }; 40 | EC48F76C238186500095E588 /* MOLHLanguage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MOLHLanguage.swift; path = ../Sources/MOLH/MOLHLanguage.swift; sourceTree = ""; }; 41 | EC5B8FE81EE0ECA4003BE809 /* LocalizationHelperDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LocalizationHelperDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | EC5B8FEB1EE0ECA4003BE809 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 43 | EC5B8FED1EE0ECA4003BE809 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 44 | EC5B8FF21EE0ECA4003BE809 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | EC5B8FF51EE0ECA4003BE809 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | EC5B8FF71EE0ECA4003BE809 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | ECB7A11D22C6740500E90F40 /* he-IL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "he-IL"; path = "he-IL.lproj/Main.strings"; sourceTree = ""; }; 48 | ECB7A11E22C6740500E90F40 /* he-IL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "he-IL"; path = "he-IL.lproj/LaunchScreen.strings"; sourceTree = ""; }; 49 | ECB7A11F22C6740500E90F40 /* he-IL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "he-IL"; path = "he-IL.lproj/Localizable.strings"; sourceTree = ""; }; 50 | ECB7A12022C6742300E90F40 /* ur */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ur; path = ur.lproj/Main.strings; sourceTree = ""; }; 51 | ECB7A12122C6742300E90F40 /* ur */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ur; path = ur.lproj/LaunchScreen.strings; sourceTree = ""; }; 52 | ECB7A12222C6742300E90F40 /* ur */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ur; path = ur.lproj/Localizable.strings; sourceTree = ""; }; 53 | ECB7A12322C6746B00E90F40 /* ckb-IQ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ckb-IQ"; path = "ckb-IQ.lproj/Main.strings"; sourceTree = ""; }; 54 | ECB7A12422C6746B00E90F40 /* ckb-IQ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ckb-IQ"; path = "ckb-IQ.lproj/LaunchScreen.strings"; sourceTree = ""; }; 55 | ECB7A12522C6746B00E90F40 /* ckb-IQ */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ckb-IQ"; path = "ckb-IQ.lproj/Localizable.strings"; sourceTree = ""; }; 56 | ECB7A12622C6747700E90F40 /* ckb-IR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ckb-IR"; path = "ckb-IR.lproj/Main.strings"; sourceTree = ""; }; 57 | ECB7A12722C6747700E90F40 /* ckb-IR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ckb-IR"; path = "ckb-IR.lproj/LaunchScreen.strings"; sourceTree = ""; }; 58 | ECB7A12822C6747700E90F40 /* ckb-IR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ckb-IR"; path = "ckb-IR.lproj/Localizable.strings"; sourceTree = ""; }; 59 | ECE2F0C221FB72AC009D506D /* MOLH.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = MOLH.podspec; path = ../../MOLH.podspec; sourceTree = ""; }; 60 | ECE534911EE2236800EBB394 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/LaunchScreen.strings; sourceTree = ""; }; 61 | ECE534931EE2237300EBB394 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; 62 | ECE534951EE2237500EBB394 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 63 | ECE534961EE2237600EBB394 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = ""; }; 64 | ECE534971EE226F300EBB394 /* arrow-right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "arrow-right.png"; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | EC5B8FE51EE0ECA4003BE809 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | EC5B8FDF1EE0ECA4003BE809 = { 79 | isa = PBXGroup; 80 | children = ( 81 | EC5B8FEA1EE0ECA4003BE809 /* LocalizationHelperDemo */, 82 | EC5B8FE91EE0ECA4003BE809 /* Products */, 83 | ); 84 | sourceTree = ""; 85 | }; 86 | EC5B8FE91EE0ECA4003BE809 /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | EC5B8FE81EE0ECA4003BE809 /* LocalizationHelperDemo.app */, 90 | ); 91 | name = Products; 92 | sourceTree = ""; 93 | }; 94 | EC5B8FEA1EE0ECA4003BE809 /* LocalizationHelperDemo */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | EC9594B71F29EC63006984E0 /* MOLH */, 98 | EC5B8FEB1EE0ECA4003BE809 /* AppDelegate.swift */, 99 | EC5B8FED1EE0ECA4003BE809 /* ViewController.swift */, 100 | EC07B15328491341009C9FCE /* InformationTextView.xib */, 101 | EC1F34652821477F00C0286B /* StackViewTestViewController.swift */, 102 | ECE2F0C221FB72AC009D506D /* MOLH.podspec */, 103 | ECE534941EE2237300EBB394 /* Localizable.strings */, 104 | EC15335521F39E440048AB78 /* Main.storyboard */, 105 | EC5B8FF21EE0ECA4003BE809 /* Assets.xcassets */, 106 | EC5B8FF41EE0ECA4003BE809 /* LaunchScreen.storyboard */, 107 | ECE534971EE226F300EBB394 /* arrow-right.png */, 108 | EC5B8FF71EE0ECA4003BE809 /* Info.plist */, 109 | ); 110 | path = LocalizationHelperDemo; 111 | sourceTree = ""; 112 | }; 113 | EC9594B71F29EC63006984E0 /* MOLH */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | EC48F76A238186500095E588 /* MOLH.swift */, 117 | EC48F769238186500095E588 /* MOLHFont.swift */, 118 | EC48F768238186500095E588 /* MOLHFontLocalizableViews.swift */, 119 | EC48F76C238186500095E588 /* MOLHLanguage.swift */, 120 | EC48F76B238186500095E588 /* MOLHSizable.swift */, 121 | ); 122 | name = MOLH; 123 | path = ../../MOLH; 124 | sourceTree = ""; 125 | }; 126 | /* End PBXGroup section */ 127 | 128 | /* Begin PBXNativeTarget section */ 129 | EC5B8FE71EE0ECA4003BE809 /* LocalizationHelperDemo */ = { 130 | isa = PBXNativeTarget; 131 | buildConfigurationList = EC5B8FFA1EE0ECA4003BE809 /* Build configuration list for PBXNativeTarget "LocalizationHelperDemo" */; 132 | buildPhases = ( 133 | EC5B8FE41EE0ECA4003BE809 /* Sources */, 134 | EC5B8FE51EE0ECA4003BE809 /* Frameworks */, 135 | EC5B8FE61EE0ECA4003BE809 /* Resources */, 136 | ); 137 | buildRules = ( 138 | ); 139 | dependencies = ( 140 | ); 141 | name = LocalizationHelperDemo; 142 | productName = LocalizationHelperDemo; 143 | productReference = EC5B8FE81EE0ECA4003BE809 /* LocalizationHelperDemo.app */; 144 | productType = "com.apple.product-type.application"; 145 | }; 146 | /* End PBXNativeTarget section */ 147 | 148 | /* Begin PBXProject section */ 149 | EC5B8FE01EE0ECA4003BE809 /* Project object */ = { 150 | isa = PBXProject; 151 | attributes = { 152 | LastSwiftUpdateCheck = 0830; 153 | LastUpgradeCheck = 0930; 154 | ORGANIZATIONNAME = Moath; 155 | TargetAttributes = { 156 | EC5B8FE71EE0ECA4003BE809 = { 157 | CreatedOnToolsVersion = 8.3.2; 158 | DevelopmentTeam = 5YP97VN386; 159 | LastSwiftMigration = 1000; 160 | ProvisioningStyle = Automatic; 161 | }; 162 | }; 163 | }; 164 | buildConfigurationList = EC5B8FE31EE0ECA4003BE809 /* Build configuration list for PBXProject "LocalizationHelperDemo" */; 165 | compatibilityVersion = "Xcode 3.2"; 166 | developmentRegion = English; 167 | hasScannedForEncodings = 0; 168 | knownRegions = ( 169 | English, 170 | en, 171 | Base, 172 | ar, 173 | "agq-CM", 174 | "he-IL", 175 | ur, 176 | "ckb-IQ", 177 | "ckb-IR", 178 | ); 179 | mainGroup = EC5B8FDF1EE0ECA4003BE809; 180 | productRefGroup = EC5B8FE91EE0ECA4003BE809 /* Products */; 181 | projectDirPath = ""; 182 | projectRoot = ""; 183 | targets = ( 184 | EC5B8FE71EE0ECA4003BE809 /* LocalizationHelperDemo */, 185 | ); 186 | }; 187 | /* End PBXProject section */ 188 | 189 | /* Begin PBXResourcesBuildPhase section */ 190 | EC5B8FE61EE0ECA4003BE809 /* Resources */ = { 191 | isa = PBXResourcesBuildPhase; 192 | buildActionMask = 2147483647; 193 | files = ( 194 | ECE2F0C321FB72AD009D506D /* MOLH.podspec in Resources */, 195 | EC15335321F39E440048AB78 /* Main.storyboard in Resources */, 196 | ECE534921EE2237300EBB394 /* Localizable.strings in Resources */, 197 | EC5B8FF61EE0ECA4003BE809 /* LaunchScreen.storyboard in Resources */, 198 | ECE534981EE226F300EBB394 /* arrow-right.png in Resources */, 199 | EC5B8FF31EE0ECA4003BE809 /* Assets.xcassets in Resources */, 200 | EC07B15428491341009C9FCE /* InformationTextView.xib in Resources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | /* End PBXResourcesBuildPhase section */ 205 | 206 | /* Begin PBXSourcesBuildPhase section */ 207 | EC5B8FE41EE0ECA4003BE809 /* Sources */ = { 208 | isa = PBXSourcesBuildPhase; 209 | buildActionMask = 2147483647; 210 | files = ( 211 | EC48F770238186500095E588 /* MOLHSizable.swift in Sources */, 212 | EC48F76E238186500095E588 /* MOLHFont.swift in Sources */, 213 | EC48F76F238186500095E588 /* MOLH.swift in Sources */, 214 | EC5B8FEE1EE0ECA4003BE809 /* ViewController.swift in Sources */, 215 | EC1F34662821477F00C0286B /* StackViewTestViewController.swift in Sources */, 216 | EC48F76D238186500095E588 /* MOLHFontLocalizableViews.swift in Sources */, 217 | EC48F771238186500095E588 /* MOLHLanguage.swift in Sources */, 218 | EC5B8FEC1EE0ECA4003BE809 /* AppDelegate.swift in Sources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXSourcesBuildPhase section */ 223 | 224 | /* Begin PBXVariantGroup section */ 225 | EC15335521F39E440048AB78 /* Main.storyboard */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | EC15335821F39E790048AB78 /* Base */, 229 | EC15335A21F39E7C0048AB78 /* en */, 230 | EC15335B21F39E810048AB78 /* ar */, 231 | EC3E86B9226F1AB200EDE6EE /* agq-CM */, 232 | ECB7A11D22C6740500E90F40 /* he-IL */, 233 | ECB7A12022C6742300E90F40 /* ur */, 234 | ECB7A12322C6746B00E90F40 /* ckb-IQ */, 235 | ECB7A12622C6747700E90F40 /* ckb-IR */, 236 | ); 237 | name = Main.storyboard; 238 | sourceTree = ""; 239 | }; 240 | EC5B8FF41EE0ECA4003BE809 /* LaunchScreen.storyboard */ = { 241 | isa = PBXVariantGroup; 242 | children = ( 243 | EC5B8FF51EE0ECA4003BE809 /* Base */, 244 | ECE534911EE2236800EBB394 /* ar */, 245 | EC3E86BA226F1AB200EDE6EE /* agq-CM */, 246 | ECB7A11E22C6740500E90F40 /* he-IL */, 247 | ECB7A12122C6742300E90F40 /* ur */, 248 | ECB7A12422C6746B00E90F40 /* ckb-IQ */, 249 | ECB7A12722C6747700E90F40 /* ckb-IR */, 250 | ); 251 | name = LaunchScreen.storyboard; 252 | sourceTree = ""; 253 | }; 254 | ECE534941EE2237300EBB394 /* Localizable.strings */ = { 255 | isa = PBXVariantGroup; 256 | children = ( 257 | ECE534931EE2237300EBB394 /* Base */, 258 | ECE534951EE2237500EBB394 /* en */, 259 | ECE534961EE2237600EBB394 /* ar */, 260 | EC3E86BB226F1AB200EDE6EE /* agq-CM */, 261 | ECB7A11F22C6740500E90F40 /* he-IL */, 262 | ECB7A12222C6742300E90F40 /* ur */, 263 | ECB7A12522C6746B00E90F40 /* ckb-IQ */, 264 | ECB7A12822C6747700E90F40 /* ckb-IR */, 265 | ); 266 | name = Localizable.strings; 267 | sourceTree = ""; 268 | }; 269 | /* End PBXVariantGroup section */ 270 | 271 | /* Begin XCBuildConfiguration section */ 272 | EC5B8FF81EE0ECA4003BE809 /* Debug */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 277 | CLANG_ANALYZER_NONNULL = YES; 278 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 280 | CLANG_CXX_LIBRARY = "libc++"; 281 | CLANG_ENABLE_MODULES = YES; 282 | CLANG_ENABLE_OBJC_ARC = YES; 283 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 284 | CLANG_WARN_BOOL_CONVERSION = YES; 285 | CLANG_WARN_COMMA = YES; 286 | CLANG_WARN_CONSTANT_CONVERSION = YES; 287 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 288 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 289 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 296 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 297 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 298 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 299 | CLANG_WARN_STRICT_PROTOTYPES = YES; 300 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 301 | CLANG_WARN_UNREACHABLE_CODE = YES; 302 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 303 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 304 | COPY_PHASE_STRIP = NO; 305 | DEBUG_INFORMATION_FORMAT = dwarf; 306 | ENABLE_STRICT_OBJC_MSGSEND = YES; 307 | ENABLE_TESTABILITY = YES; 308 | GCC_C_LANGUAGE_STANDARD = gnu99; 309 | GCC_DYNAMIC_NO_PIC = NO; 310 | GCC_NO_COMMON_BLOCKS = YES; 311 | GCC_OPTIMIZATION_LEVEL = 0; 312 | GCC_PREPROCESSOR_DEFINITIONS = ( 313 | "DEBUG=1", 314 | "$(inherited)", 315 | ); 316 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 317 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 318 | GCC_WARN_UNDECLARED_SELECTOR = YES; 319 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 320 | GCC_WARN_UNUSED_FUNCTION = YES; 321 | GCC_WARN_UNUSED_VARIABLE = YES; 322 | IPHONEOS_DEPLOYMENT_TARGET = 9; 323 | MTL_ENABLE_DEBUG_INFO = YES; 324 | ONLY_ACTIVE_ARCH = YES; 325 | SDKROOT = iphoneos; 326 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 327 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 328 | }; 329 | name = Debug; 330 | }; 331 | EC5B8FF91EE0ECA4003BE809 /* Release */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 336 | CLANG_ANALYZER_NONNULL = YES; 337 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 339 | CLANG_CXX_LIBRARY = "libc++"; 340 | CLANG_ENABLE_MODULES = YES; 341 | CLANG_ENABLE_OBJC_ARC = YES; 342 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 343 | CLANG_WARN_BOOL_CONVERSION = YES; 344 | CLANG_WARN_COMMA = YES; 345 | CLANG_WARN_CONSTANT_CONVERSION = YES; 346 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 347 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 348 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 349 | CLANG_WARN_EMPTY_BODY = YES; 350 | CLANG_WARN_ENUM_CONVERSION = YES; 351 | CLANG_WARN_INFINITE_RECURSION = YES; 352 | CLANG_WARN_INT_CONVERSION = YES; 353 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 354 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 355 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 356 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 357 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 358 | CLANG_WARN_STRICT_PROTOTYPES = YES; 359 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 360 | CLANG_WARN_UNREACHABLE_CODE = YES; 361 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 362 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 363 | COPY_PHASE_STRIP = NO; 364 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 365 | ENABLE_NS_ASSERTIONS = NO; 366 | ENABLE_STRICT_OBJC_MSGSEND = YES; 367 | GCC_C_LANGUAGE_STANDARD = gnu99; 368 | GCC_NO_COMMON_BLOCKS = YES; 369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 371 | GCC_WARN_UNDECLARED_SELECTOR = YES; 372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 373 | GCC_WARN_UNUSED_FUNCTION = YES; 374 | GCC_WARN_UNUSED_VARIABLE = YES; 375 | IPHONEOS_DEPLOYMENT_TARGET = 9; 376 | MTL_ENABLE_DEBUG_INFO = NO; 377 | SDKROOT = iphoneos; 378 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 379 | VALIDATE_PRODUCT = YES; 380 | }; 381 | name = Release; 382 | }; 383 | EC5B8FFB1EE0ECA4003BE809 /* Debug */ = { 384 | isa = XCBuildConfiguration; 385 | buildSettings = { 386 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 387 | DEVELOPMENT_TEAM = 5YP97VN386; 388 | INFOPLIST_FILE = LocalizationHelperDemo/Info.plist; 389 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 391 | PRODUCT_BUNDLE_IDENTIFIER = com.whitetorch.LocalizationHelperDemo; 392 | PRODUCT_NAME = "$(TARGET_NAME)"; 393 | SWIFT_VERSION = 5.0; 394 | }; 395 | name = Debug; 396 | }; 397 | EC5B8FFC1EE0ECA4003BE809 /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | DEVELOPMENT_TEAM = 5YP97VN386; 402 | INFOPLIST_FILE = LocalizationHelperDemo/Info.plist; 403 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 404 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 405 | PRODUCT_BUNDLE_IDENTIFIER = com.whitetorch.LocalizationHelperDemo; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | SWIFT_VERSION = 5.0; 408 | }; 409 | name = Release; 410 | }; 411 | /* End XCBuildConfiguration section */ 412 | 413 | /* Begin XCConfigurationList section */ 414 | EC5B8FE31EE0ECA4003BE809 /* Build configuration list for PBXProject "LocalizationHelperDemo" */ = { 415 | isa = XCConfigurationList; 416 | buildConfigurations = ( 417 | EC5B8FF81EE0ECA4003BE809 /* Debug */, 418 | EC5B8FF91EE0ECA4003BE809 /* Release */, 419 | ); 420 | defaultConfigurationIsVisible = 0; 421 | defaultConfigurationName = Release; 422 | }; 423 | EC5B8FFA1EE0ECA4003BE809 /* Build configuration list for PBXNativeTarget "LocalizationHelperDemo" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | EC5B8FFB1EE0ECA4003BE809 /* Debug */, 427 | EC5B8FFC1EE0ECA4003BE809 /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | /* End XCConfigurationList section */ 433 | }; 434 | rootObject = EC5B8FE01EE0ECA4003BE809 /* Project object */; 435 | } 436 | -------------------------------------------------------------------------------- /LocalizationHelperDemo/LocalizationHelperDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 71 | 77 | 78 | 79 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 215 | 216 | 217 | 218 | 219 | 220 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | --------------------------------------------------------------------------------