├── .gitignore ├── CONTRIBUTE.md ├── LICENSE.md ├── Localizations.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── Localizations.xcscheme └── xcuserdata │ └── tipoli.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── Localizations ├── ATBasicAnimator.swift ├── ATReplacingSegue.swift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon_128x128.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256.png │ │ ├── icon_32x32.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512-1.png │ │ ├── icon_512x512.png │ │ └── icon_512x512@2x.png ├── Choose Project │ ├── ChooseProjectController+Parser.swift │ └── ChooseProjectViewController.swift ├── ErrorCenter.swift ├── Info.plist ├── Main.storyboard ├── MainWindowController.swift ├── Models │ ├── File.swift │ ├── Region.swift │ ├── Translation.swift │ └── XcodeProject.swift ├── Project Details │ ├── DetailViewController.swift │ ├── FileCellView.swift │ ├── FileDataSource.swift │ ├── RegionCellView.swift │ ├── TranslationCellView.swift │ └── TranslationDataSource.swift ├── Project Info │ └── ProjectInfoViewController.swift ├── Save │ ├── ATStatusView.swift │ ├── ChangeStepCellView.swift │ ├── ChangeTableViewDataSource.swift │ └── SaveViewController.swift └── xcode-project_Icon.icns ├── LocalizationsTests ├── Info.plist └── LocalizationsTests.swift ├── LocalizationsUITests ├── Info.plist └── LocalizationsUITests.swift ├── README.md ├── Screenshots ├── localization-0.1-4.png └── localization-0.1-5.png └── TestProjects └── LocalizedSampleApp ├── LocalizedSampleApp.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── LocalizedSampleApp ├── AppDelegate.swift ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── DetailViewController.swift ├── Info.plist └── MasterViewController.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | 65 | *.xcuserstate 66 | -------------------------------------------------------------------------------- /CONTRIBUTE.md: -------------------------------------------------------------------------------- 1 | # Contribute 2 | 3 | I'm glad to see you want to help. Here are some of the ways you ca do that. 4 | 5 | ## Test Projects 6 | I am always in need for test projects. Projects with existing, partial string files and new, edited, deleted localizations. 7 | 8 | To submit one, fork this repo, add your test project to the TestProjects folder and submit a PR with your expected results 9 | 10 | ## App Testing 11 | 12 | Whenever you test Localizations and find a bug, a need for an improvement of anything else, please file them into the issues! That greatly helps me keep track of the roadmap. 13 | 14 | ## Bug Fixing/Feature adding 15 | If you want to fix a bug or add a new feature, please follow this process: 16 | 17 | - File the bug or feature request into the issues if not already, 18 | - Fix/implement, 19 | - Add (Xcode) Unit Tests and/or UI Tests, 20 | - File a PR to merge into **pr\_landing\_strip** with reference to the issue and _describe the intention behind the PR_. 21 | 22 | **In any cases, make sure your code has been tested thorougly** 23 | 24 | 25 | # Thanks 26 | I really appreciate all contributions, I made this tool because many in my surrounding needed it and I hope Localizations will belong to all of us. -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Arnaud Thiercelin 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. -------------------------------------------------------------------------------- /Localizations.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 892A66411CA5DAC600190F1F /* ErrorCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A66401CA5DAC600190F1F /* ErrorCenter.swift */; }; 11 | 892C2B711C78282100CB7E7D /* xcode-project_Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 892C2B701C78282100CB7E7D /* xcode-project_Icon.icns */; }; 12 | 892C2B731C782B1C00CB7E7D /* RegionCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892C2B721C782B1C00CB7E7D /* RegionCellView.swift */; }; 13 | 892C2B751C782BA100CB7E7D /* Region.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892C2B741C782BA100CB7E7D /* Region.swift */; }; 14 | 8939527E1C82224A00D35895 /* SaveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8939527C1C82224A00D35895 /* SaveViewController.swift */; }; 15 | 893952811C82228F00D35895 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 893952801C82228F00D35895 /* Main.storyboard */; }; 16 | 893952BA1C82290000D35895 /* MainWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893952B91C82290000D35895 /* MainWindowController.swift */; }; 17 | 893952C01C822B4500D35895 /* ProjectInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893952BF1C822B4500D35895 /* ProjectInfoViewController.swift */; }; 18 | 893952C21C82377800D35895 /* ATReplacingSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893952C11C82377800D35895 /* ATReplacingSegue.swift */; }; 19 | 893952C41C83D47C00D35895 /* ChangeStepCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893952C31C83D47C00D35895 /* ChangeStepCellView.swift */; }; 20 | 893952C61C83D50000D35895 /* ATStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893952C51C83D50000D35895 /* ATStatusView.swift */; }; 21 | 893952C81C83EED900D35895 /* ChangeTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893952C71C83EED900D35895 /* ChangeTableViewDataSource.swift */; }; 22 | 8939530B1C8C7EF600D35895 /* XcodeProject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8939530A1C8C7EF600D35895 /* XcodeProject.swift */; }; 23 | 893BB5351C66BD6700F26792 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893BB5331C66BD6700F26792 /* DetailViewController.swift */; }; 24 | 893BB5421C679C0E00F26792 /* ATBasicAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893BB5411C679C0E00F26792 /* ATBasicAnimator.swift */; }; 25 | 893BB5441C67C38C00F26792 /* FileDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893BB5431C67C38C00F26792 /* FileDataSource.swift */; }; 26 | 893BB5461C67C3D900F26792 /* TranslationDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893BB5451C67C3D900F26792 /* TranslationDataSource.swift */; }; 27 | 893BB5481C67C93C00F26792 /* FileCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893BB5471C67C93C00F26792 /* FileCellView.swift */; }; 28 | 893BB54A1C67C94A00F26792 /* TranslationCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 893BB5491C67C94A00F26792 /* TranslationCellView.swift */; }; 29 | 89A294181C714E41003B76D6 /* ChooseProjectController+Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89A294171C714E41003B76D6 /* ChooseProjectController+Parser.swift */; }; 30 | 89F0716B1C5AE60500E75780 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F0716A1C5AE60500E75780 /* AppDelegate.swift */; }; 31 | 89F0716D1C5AE60500E75780 /* ChooseProjectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F0716C1C5AE60500E75780 /* ChooseProjectViewController.swift */; }; 32 | 89F0716F1C5AE60500E75780 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 89F0716E1C5AE60500E75780 /* Assets.xcassets */; }; 33 | 89F0717D1C5AE60500E75780 /* LocalizationsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F0717C1C5AE60500E75780 /* LocalizationsTests.swift */; }; 34 | 89F071881C5AE60500E75780 /* LocalizationsUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F071871C5AE60500E75780 /* LocalizationsUITests.swift */; }; 35 | 89F071A21C62EA2F00E75780 /* Translation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F071A11C62EA2F00E75780 /* Translation.swift */; }; 36 | 89F071A41C64246600E75780 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F071A31C64246600E75780 /* File.swift */; }; 37 | /* End PBXBuildFile section */ 38 | 39 | /* Begin PBXContainerItemProxy section */ 40 | 89F071791C5AE60500E75780 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = 89F0715F1C5AE60500E75780 /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = 89F071661C5AE60500E75780; 45 | remoteInfo = Localizations; 46 | }; 47 | 89F071841C5AE60500E75780 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = 89F0715F1C5AE60500E75780 /* Project object */; 50 | proxyType = 1; 51 | remoteGlobalIDString = 89F071661C5AE60500E75780; 52 | remoteInfo = Localizations; 53 | }; 54 | /* End PBXContainerItemProxy section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | 892A66401CA5DAC600190F1F /* ErrorCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorCenter.swift; sourceTree = ""; }; 58 | 892C2B701C78282100CB7E7D /* xcode-project_Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = "xcode-project_Icon.icns"; sourceTree = ""; }; 59 | 892C2B721C782B1C00CB7E7D /* RegionCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegionCellView.swift; sourceTree = ""; }; 60 | 892C2B741C782BA100CB7E7D /* Region.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Region.swift; sourceTree = ""; }; 61 | 8939527C1C82224A00D35895 /* SaveViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SaveViewController.swift; sourceTree = ""; }; 62 | 893952801C82228F00D35895 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 63 | 893952B91C82290000D35895 /* MainWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowController.swift; sourceTree = ""; }; 64 | 893952BF1C822B4500D35895 /* ProjectInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProjectInfoViewController.swift; sourceTree = ""; }; 65 | 893952C11C82377800D35895 /* ATReplacingSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ATReplacingSegue.swift; sourceTree = ""; }; 66 | 893952C31C83D47C00D35895 /* ChangeStepCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeStepCellView.swift; sourceTree = ""; }; 67 | 893952C51C83D50000D35895 /* ATStatusView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ATStatusView.swift; sourceTree = ""; }; 68 | 893952C71C83EED900D35895 /* ChangeTableViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeTableViewDataSource.swift; sourceTree = ""; }; 69 | 8939530A1C8C7EF600D35895 /* XcodeProject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XcodeProject.swift; sourceTree = ""; }; 70 | 893BB5331C66BD6700F26792 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 71 | 893BB5411C679C0E00F26792 /* ATBasicAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ATBasicAnimator.swift; sourceTree = ""; }; 72 | 893BB5431C67C38C00F26792 /* FileDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileDataSource.swift; sourceTree = ""; }; 73 | 893BB5451C67C3D900F26792 /* TranslationDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationDataSource.swift; sourceTree = ""; }; 74 | 893BB5471C67C93C00F26792 /* FileCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileCellView.swift; sourceTree = ""; }; 75 | 893BB5491C67C94A00F26792 /* TranslationCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationCellView.swift; sourceTree = ""; }; 76 | 89A294111C68441F003B76D6 /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; }; 77 | 89A294121C68441F003B76D6 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 78 | 89A294171C714E41003B76D6 /* ChooseProjectController+Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ChooseProjectController+Parser.swift"; sourceTree = ""; }; 79 | 89F071671C5AE60500E75780 /* Localizations.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Localizations.app; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 89F0716A1C5AE60500E75780 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 81 | 89F0716C1C5AE60500E75780 /* ChooseProjectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChooseProjectViewController.swift; sourceTree = ""; }; 82 | 89F0716E1C5AE60500E75780 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 83 | 89F071731C5AE60500E75780 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84 | 89F071781C5AE60500E75780 /* LocalizationsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LocalizationsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 89F0717C1C5AE60500E75780 /* LocalizationsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationsTests.swift; sourceTree = ""; }; 86 | 89F0717E1C5AE60500E75780 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 87 | 89F071831C5AE60500E75780 /* LocalizationsUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LocalizationsUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | 89F071871C5AE60500E75780 /* LocalizationsUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationsUITests.swift; sourceTree = ""; }; 89 | 89F071891C5AE60500E75780 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 90 | 89F071A11C62EA2F00E75780 /* Translation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Translation.swift; sourceTree = ""; }; 91 | 89F071A31C64246600E75780 /* File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; 92 | /* End PBXFileReference section */ 93 | 94 | /* Begin PBXFrameworksBuildPhase section */ 95 | 89F071641C5AE60500E75780 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | 89F071751C5AE60500E75780 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | ); 107 | runOnlyForDeploymentPostprocessing = 0; 108 | }; 109 | 89F071801C5AE60500E75780 /* Frameworks */ = { 110 | isa = PBXFrameworksBuildPhase; 111 | buildActionMask = 2147483647; 112 | files = ( 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | /* End PBXFrameworksBuildPhase section */ 117 | 118 | /* Begin PBXGroup section */ 119 | 892A663F1CA5DAB200190F1F /* Centers */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 892A66401CA5DAC600190F1F /* ErrorCenter.swift */, 123 | ); 124 | name = Centers; 125 | sourceTree = ""; 126 | }; 127 | 892C2B761C796E9B00CB7E7D /* Cell Views */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 892C2B721C782B1C00CB7E7D /* RegionCellView.swift */, 131 | 893BB5471C67C93C00F26792 /* FileCellView.swift */, 132 | 893BB5491C67C94A00F26792 /* TranslationCellView.swift */, 133 | ); 134 | name = "Cell Views"; 135 | sourceTree = ""; 136 | }; 137 | 893952771C820AA400D35895 /* Save */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 8939527C1C82224A00D35895 /* SaveViewController.swift */, 141 | 893952C31C83D47C00D35895 /* ChangeStepCellView.swift */, 142 | 893952C71C83EED900D35895 /* ChangeTableViewDataSource.swift */, 143 | 893952C51C83D50000D35895 /* ATStatusView.swift */, 144 | ); 145 | path = Save; 146 | sourceTree = ""; 147 | }; 148 | 893952BB1C82290B00D35895 /* Choose Project */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 89F0716C1C5AE60500E75780 /* ChooseProjectViewController.swift */, 152 | 89A294171C714E41003B76D6 /* ChooseProjectController+Parser.swift */, 153 | ); 154 | path = "Choose Project"; 155 | sourceTree = ""; 156 | }; 157 | 893952BC1C822AFB00D35895 /* Project Info */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 893952BF1C822B4500D35895 /* ProjectInfoViewController.swift */, 161 | ); 162 | path = "Project Info"; 163 | sourceTree = ""; 164 | }; 165 | 893BB5311C66BD4400F26792 /* MainWindow */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 893952B91C82290000D35895 /* MainWindowController.swift */, 169 | 893952BB1C82290B00D35895 /* Choose Project */, 170 | 893BB5321C66BD4D00F26792 /* Project Details */, 171 | 893952771C820AA400D35895 /* Save */, 172 | 893952BC1C822AFB00D35895 /* Project Info */, 173 | ); 174 | name = MainWindow; 175 | sourceTree = ""; 176 | }; 177 | 893BB5321C66BD4D00F26792 /* Project Details */ = { 178 | isa = PBXGroup; 179 | children = ( 180 | 893BB5331C66BD6700F26792 /* DetailViewController.swift */, 181 | 893BB5431C67C38C00F26792 /* FileDataSource.swift */, 182 | 893BB5451C67C3D900F26792 /* TranslationDataSource.swift */, 183 | 892C2B761C796E9B00CB7E7D /* Cell Views */, 184 | ); 185 | path = "Project Details"; 186 | sourceTree = ""; 187 | }; 188 | 89F0715E1C5AE60500E75780 = { 189 | isa = PBXGroup; 190 | children = ( 191 | 89A294111C68441F003B76D6 /* LICENSE.md */, 192 | 89A294121C68441F003B76D6 /* README.md */, 193 | 89F071691C5AE60500E75780 /* Localizations */, 194 | 89F0717B1C5AE60500E75780 /* LocalizationsTests */, 195 | 89F071861C5AE60500E75780 /* LocalizationsUITests */, 196 | 89F071681C5AE60500E75780 /* Products */, 197 | ); 198 | sourceTree = ""; 199 | }; 200 | 89F071681C5AE60500E75780 /* Products */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | 89F071671C5AE60500E75780 /* Localizations.app */, 204 | 89F071781C5AE60500E75780 /* LocalizationsTests.xctest */, 205 | 89F071831C5AE60500E75780 /* LocalizationsUITests.xctest */, 206 | ); 207 | name = Products; 208 | sourceTree = ""; 209 | }; 210 | 89F071691C5AE60500E75780 /* Localizations */ = { 211 | isa = PBXGroup; 212 | children = ( 213 | 892C2B701C78282100CB7E7D /* xcode-project_Icon.icns */, 214 | 89F0716A1C5AE60500E75780 /* AppDelegate.swift */, 215 | 893952801C82228F00D35895 /* Main.storyboard */, 216 | 893BB5311C66BD4400F26792 /* MainWindow */, 217 | 89F071A01C62EA0F00E75780 /* Models */, 218 | 892A663F1CA5DAB200190F1F /* Centers */, 219 | 893BB5411C679C0E00F26792 /* ATBasicAnimator.swift */, 220 | 893952C11C82377800D35895 /* ATReplacingSegue.swift */, 221 | 89F0716E1C5AE60500E75780 /* Assets.xcassets */, 222 | 89F071731C5AE60500E75780 /* Info.plist */, 223 | ); 224 | path = Localizations; 225 | sourceTree = ""; 226 | }; 227 | 89F0717B1C5AE60500E75780 /* LocalizationsTests */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | 89F0717C1C5AE60500E75780 /* LocalizationsTests.swift */, 231 | 89F0717E1C5AE60500E75780 /* Info.plist */, 232 | ); 233 | path = LocalizationsTests; 234 | sourceTree = ""; 235 | }; 236 | 89F071861C5AE60500E75780 /* LocalizationsUITests */ = { 237 | isa = PBXGroup; 238 | children = ( 239 | 89F071871C5AE60500E75780 /* LocalizationsUITests.swift */, 240 | 89F071891C5AE60500E75780 /* Info.plist */, 241 | ); 242 | path = LocalizationsUITests; 243 | sourceTree = ""; 244 | }; 245 | 89F071A01C62EA0F00E75780 /* Models */ = { 246 | isa = PBXGroup; 247 | children = ( 248 | 892C2B741C782BA100CB7E7D /* Region.swift */, 249 | 89F071A31C64246600E75780 /* File.swift */, 250 | 89F071A11C62EA2F00E75780 /* Translation.swift */, 251 | 8939530A1C8C7EF600D35895 /* XcodeProject.swift */, 252 | ); 253 | path = Models; 254 | sourceTree = ""; 255 | }; 256 | /* End PBXGroup section */ 257 | 258 | /* Begin PBXNativeTarget section */ 259 | 89F071661C5AE60500E75780 /* Localizations */ = { 260 | isa = PBXNativeTarget; 261 | buildConfigurationList = 89F0718C1C5AE60500E75780 /* Build configuration list for PBXNativeTarget "Localizations" */; 262 | buildPhases = ( 263 | 89F071631C5AE60500E75780 /* Sources */, 264 | 89F071641C5AE60500E75780 /* Frameworks */, 265 | 89F071651C5AE60500E75780 /* Resources */, 266 | 89F0719D1C5D0E4300E75780 /* Additional Warnings */, 267 | ); 268 | buildRules = ( 269 | ); 270 | dependencies = ( 271 | ); 272 | name = Localizations; 273 | productName = Localizations; 274 | productReference = 89F071671C5AE60500E75780 /* Localizations.app */; 275 | productType = "com.apple.product-type.application"; 276 | }; 277 | 89F071771C5AE60500E75780 /* LocalizationsTests */ = { 278 | isa = PBXNativeTarget; 279 | buildConfigurationList = 89F0718F1C5AE60500E75780 /* Build configuration list for PBXNativeTarget "LocalizationsTests" */; 280 | buildPhases = ( 281 | 89F071741C5AE60500E75780 /* Sources */, 282 | 89F071751C5AE60500E75780 /* Frameworks */, 283 | 89F071761C5AE60500E75780 /* Resources */, 284 | ); 285 | buildRules = ( 286 | ); 287 | dependencies = ( 288 | 89F0717A1C5AE60500E75780 /* PBXTargetDependency */, 289 | ); 290 | name = LocalizationsTests; 291 | productName = LocalizationsTests; 292 | productReference = 89F071781C5AE60500E75780 /* LocalizationsTests.xctest */; 293 | productType = "com.apple.product-type.bundle.unit-test"; 294 | }; 295 | 89F071821C5AE60500E75780 /* LocalizationsUITests */ = { 296 | isa = PBXNativeTarget; 297 | buildConfigurationList = 89F071921C5AE60500E75780 /* Build configuration list for PBXNativeTarget "LocalizationsUITests" */; 298 | buildPhases = ( 299 | 89F0717F1C5AE60500E75780 /* Sources */, 300 | 89F071801C5AE60500E75780 /* Frameworks */, 301 | 89F071811C5AE60500E75780 /* Resources */, 302 | ); 303 | buildRules = ( 304 | ); 305 | dependencies = ( 306 | 89F071851C5AE60500E75780 /* PBXTargetDependency */, 307 | ); 308 | name = LocalizationsUITests; 309 | productName = LocalizationsUITests; 310 | productReference = 89F071831C5AE60500E75780 /* LocalizationsUITests.xctest */; 311 | productType = "com.apple.product-type.bundle.ui-testing"; 312 | }; 313 | /* End PBXNativeTarget section */ 314 | 315 | /* Begin PBXProject section */ 316 | 89F0715F1C5AE60500E75780 /* Project object */ = { 317 | isa = PBXProject; 318 | attributes = { 319 | LastSwiftUpdateCheck = 0720; 320 | LastUpgradeCheck = 0830; 321 | ORGANIZATIONNAME = "Arnaud Thiercelin"; 322 | TargetAttributes = { 323 | 89F071661C5AE60500E75780 = { 324 | CreatedOnToolsVersion = 7.2; 325 | LastSwiftMigration = 0800; 326 | }; 327 | 89F071771C5AE60500E75780 = { 328 | CreatedOnToolsVersion = 7.2; 329 | LastSwiftMigration = 0800; 330 | TestTargetID = 89F071661C5AE60500E75780; 331 | }; 332 | 89F071821C5AE60500E75780 = { 333 | CreatedOnToolsVersion = 7.2; 334 | LastSwiftMigration = 0800; 335 | TestTargetID = 89F071661C5AE60500E75780; 336 | }; 337 | }; 338 | }; 339 | buildConfigurationList = 89F071621C5AE60500E75780 /* Build configuration list for PBXProject "Localizations" */; 340 | compatibilityVersion = "Xcode 3.2"; 341 | developmentRegion = English; 342 | hasScannedForEncodings = 0; 343 | knownRegions = ( 344 | en, 345 | Base, 346 | ); 347 | mainGroup = 89F0715E1C5AE60500E75780; 348 | productRefGroup = 89F071681C5AE60500E75780 /* Products */; 349 | projectDirPath = ""; 350 | projectRoot = ""; 351 | targets = ( 352 | 89F071661C5AE60500E75780 /* Localizations */, 353 | 89F071771C5AE60500E75780 /* LocalizationsTests */, 354 | 89F071821C5AE60500E75780 /* LocalizationsUITests */, 355 | ); 356 | }; 357 | /* End PBXProject section */ 358 | 359 | /* Begin PBXResourcesBuildPhase section */ 360 | 89F071651C5AE60500E75780 /* Resources */ = { 361 | isa = PBXResourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 892C2B711C78282100CB7E7D /* xcode-project_Icon.icns in Resources */, 365 | 893952811C82228F00D35895 /* Main.storyboard in Resources */, 366 | 89F0716F1C5AE60500E75780 /* Assets.xcassets in Resources */, 367 | ); 368 | runOnlyForDeploymentPostprocessing = 0; 369 | }; 370 | 89F071761C5AE60500E75780 /* Resources */ = { 371 | isa = PBXResourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | ); 375 | runOnlyForDeploymentPostprocessing = 0; 376 | }; 377 | 89F071811C5AE60500E75780 /* Resources */ = { 378 | isa = PBXResourcesBuildPhase; 379 | buildActionMask = 2147483647; 380 | files = ( 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | /* End PBXResourcesBuildPhase section */ 385 | 386 | /* Begin PBXShellScriptBuildPhase section */ 387 | 89F0719D1C5D0E4300E75780 /* Additional Warnings */ = { 388 | isa = PBXShellScriptBuildPhase; 389 | buildActionMask = 2147483647; 390 | files = ( 391 | ); 392 | inputPaths = ( 393 | ); 394 | name = "Additional Warnings"; 395 | outputPaths = ( 396 | ); 397 | runOnlyForDeploymentPostprocessing = 0; 398 | shellPath = /bin/sh; 399 | shellScript = "KEYWORDS=\"TODO:|FIXME:|\\?\\?\\?:|\\!\\!\\!:\"\nfind \"${SRCROOT}\" \\( -name \"*.h\" -or -name \"*.m\" -or -name \"*.swift\" \\) -print0 | xargs -0 egrep --with-filename --line-number --only-matching \"($KEYWORDS).*\\$\" | perl -p -e \"s/($KEYWORDS)/ warning: \\$1/\""; 400 | }; 401 | /* End PBXShellScriptBuildPhase section */ 402 | 403 | /* Begin PBXSourcesBuildPhase section */ 404 | 89F071631C5AE60500E75780 /* Sources */ = { 405 | isa = PBXSourcesBuildPhase; 406 | buildActionMask = 2147483647; 407 | files = ( 408 | 893BB5461C67C3D900F26792 /* TranslationDataSource.swift in Sources */, 409 | 893BB5421C679C0E00F26792 /* ATBasicAnimator.swift in Sources */, 410 | 893952C81C83EED900D35895 /* ChangeTableViewDataSource.swift in Sources */, 411 | 892C2B731C782B1C00CB7E7D /* RegionCellView.swift in Sources */, 412 | 893BB54A1C67C94A00F26792 /* TranslationCellView.swift in Sources */, 413 | 893952C41C83D47C00D35895 /* ChangeStepCellView.swift in Sources */, 414 | 893BB5481C67C93C00F26792 /* FileCellView.swift in Sources */, 415 | 892A66411CA5DAC600190F1F /* ErrorCenter.swift in Sources */, 416 | 89F0716D1C5AE60500E75780 /* ChooseProjectViewController.swift in Sources */, 417 | 893952BA1C82290000D35895 /* MainWindowController.swift in Sources */, 418 | 89F071A41C64246600E75780 /* File.swift in Sources */, 419 | 893952C01C822B4500D35895 /* ProjectInfoViewController.swift in Sources */, 420 | 893BB5441C67C38C00F26792 /* FileDataSource.swift in Sources */, 421 | 893BB5351C66BD6700F26792 /* DetailViewController.swift in Sources */, 422 | 892C2B751C782BA100CB7E7D /* Region.swift in Sources */, 423 | 8939527E1C82224A00D35895 /* SaveViewController.swift in Sources */, 424 | 893952C21C82377800D35895 /* ATReplacingSegue.swift in Sources */, 425 | 89A294181C714E41003B76D6 /* ChooseProjectController+Parser.swift in Sources */, 426 | 89F0716B1C5AE60500E75780 /* AppDelegate.swift in Sources */, 427 | 89F071A21C62EA2F00E75780 /* Translation.swift in Sources */, 428 | 8939530B1C8C7EF600D35895 /* XcodeProject.swift in Sources */, 429 | 893952C61C83D50000D35895 /* ATStatusView.swift in Sources */, 430 | ); 431 | runOnlyForDeploymentPostprocessing = 0; 432 | }; 433 | 89F071741C5AE60500E75780 /* Sources */ = { 434 | isa = PBXSourcesBuildPhase; 435 | buildActionMask = 2147483647; 436 | files = ( 437 | 89F0717D1C5AE60500E75780 /* LocalizationsTests.swift in Sources */, 438 | ); 439 | runOnlyForDeploymentPostprocessing = 0; 440 | }; 441 | 89F0717F1C5AE60500E75780 /* Sources */ = { 442 | isa = PBXSourcesBuildPhase; 443 | buildActionMask = 2147483647; 444 | files = ( 445 | 89F071881C5AE60500E75780 /* LocalizationsUITests.swift in Sources */, 446 | ); 447 | runOnlyForDeploymentPostprocessing = 0; 448 | }; 449 | /* End PBXSourcesBuildPhase section */ 450 | 451 | /* Begin PBXTargetDependency section */ 452 | 89F0717A1C5AE60500E75780 /* PBXTargetDependency */ = { 453 | isa = PBXTargetDependency; 454 | target = 89F071661C5AE60500E75780 /* Localizations */; 455 | targetProxy = 89F071791C5AE60500E75780 /* PBXContainerItemProxy */; 456 | }; 457 | 89F071851C5AE60500E75780 /* PBXTargetDependency */ = { 458 | isa = PBXTargetDependency; 459 | target = 89F071661C5AE60500E75780 /* Localizations */; 460 | targetProxy = 89F071841C5AE60500E75780 /* PBXContainerItemProxy */; 461 | }; 462 | /* End PBXTargetDependency section */ 463 | 464 | /* Begin XCBuildConfiguration section */ 465 | 89F0718A1C5AE60500E75780 /* Debug */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ALWAYS_SEARCH_USER_PATHS = NO; 469 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 470 | CLANG_CXX_LIBRARY = "libc++"; 471 | CLANG_ENABLE_MODULES = YES; 472 | CLANG_ENABLE_OBJC_ARC = YES; 473 | CLANG_WARN_BOOL_CONVERSION = YES; 474 | CLANG_WARN_CONSTANT_CONVERSION = YES; 475 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 476 | CLANG_WARN_EMPTY_BODY = YES; 477 | CLANG_WARN_ENUM_CONVERSION = YES; 478 | CLANG_WARN_INFINITE_RECURSION = YES; 479 | CLANG_WARN_INT_CONVERSION = YES; 480 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 481 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 482 | CLANG_WARN_UNREACHABLE_CODE = YES; 483 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 484 | CODE_SIGN_IDENTITY = "-"; 485 | COPY_PHASE_STRIP = NO; 486 | DEBUG_INFORMATION_FORMAT = dwarf; 487 | ENABLE_STRICT_OBJC_MSGSEND = YES; 488 | ENABLE_TESTABILITY = YES; 489 | GCC_C_LANGUAGE_STANDARD = gnu99; 490 | GCC_DYNAMIC_NO_PIC = NO; 491 | GCC_NO_COMMON_BLOCKS = YES; 492 | GCC_OPTIMIZATION_LEVEL = 0; 493 | GCC_PREPROCESSOR_DEFINITIONS = ( 494 | "DEBUG=1", 495 | "$(inherited)", 496 | ); 497 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 498 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 499 | GCC_WARN_UNDECLARED_SELECTOR = YES; 500 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 501 | GCC_WARN_UNUSED_FUNCTION = YES; 502 | GCC_WARN_UNUSED_VARIABLE = YES; 503 | MACOSX_DEPLOYMENT_TARGET = 10.11; 504 | MTL_ENABLE_DEBUG_INFO = YES; 505 | ONLY_ACTIVE_ARCH = YES; 506 | SDKROOT = macosx; 507 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 508 | }; 509 | name = Debug; 510 | }; 511 | 89F0718B1C5AE60500E75780 /* Release */ = { 512 | isa = XCBuildConfiguration; 513 | buildSettings = { 514 | ALWAYS_SEARCH_USER_PATHS = NO; 515 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 516 | CLANG_CXX_LIBRARY = "libc++"; 517 | CLANG_ENABLE_MODULES = YES; 518 | CLANG_ENABLE_OBJC_ARC = YES; 519 | CLANG_WARN_BOOL_CONVERSION = YES; 520 | CLANG_WARN_CONSTANT_CONVERSION = YES; 521 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 522 | CLANG_WARN_EMPTY_BODY = YES; 523 | CLANG_WARN_ENUM_CONVERSION = YES; 524 | CLANG_WARN_INFINITE_RECURSION = YES; 525 | CLANG_WARN_INT_CONVERSION = YES; 526 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 527 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 528 | CLANG_WARN_UNREACHABLE_CODE = YES; 529 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 530 | CODE_SIGN_IDENTITY = "-"; 531 | COPY_PHASE_STRIP = NO; 532 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 533 | ENABLE_NS_ASSERTIONS = NO; 534 | ENABLE_STRICT_OBJC_MSGSEND = YES; 535 | GCC_C_LANGUAGE_STANDARD = gnu99; 536 | GCC_NO_COMMON_BLOCKS = YES; 537 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 538 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 539 | GCC_WARN_UNDECLARED_SELECTOR = YES; 540 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 541 | GCC_WARN_UNUSED_FUNCTION = YES; 542 | GCC_WARN_UNUSED_VARIABLE = YES; 543 | MACOSX_DEPLOYMENT_TARGET = 10.11; 544 | MTL_ENABLE_DEBUG_INFO = NO; 545 | SDKROOT = macosx; 546 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 547 | }; 548 | name = Release; 549 | }; 550 | 89F0718D1C5AE60500E75780 /* Debug */ = { 551 | isa = XCBuildConfiguration; 552 | buildSettings = { 553 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 554 | COMBINE_HIDPI_IMAGES = YES; 555 | INFOPLIST_FILE = Localizations/Info.plist; 556 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 557 | PRODUCT_BUNDLE_IDENTIFIER = com.arnaudthiercelin.Localizations; 558 | PRODUCT_NAME = "$(TARGET_NAME)"; 559 | SWIFT_VERSION = 3.0; 560 | }; 561 | name = Debug; 562 | }; 563 | 89F0718E1C5AE60500E75780 /* Release */ = { 564 | isa = XCBuildConfiguration; 565 | buildSettings = { 566 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 567 | COMBINE_HIDPI_IMAGES = YES; 568 | INFOPLIST_FILE = Localizations/Info.plist; 569 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 570 | PRODUCT_BUNDLE_IDENTIFIER = com.arnaudthiercelin.Localizations; 571 | PRODUCT_NAME = "$(TARGET_NAME)"; 572 | SWIFT_VERSION = 3.0; 573 | }; 574 | name = Release; 575 | }; 576 | 89F071901C5AE60500E75780 /* Debug */ = { 577 | isa = XCBuildConfiguration; 578 | buildSettings = { 579 | BUNDLE_LOADER = "$(TEST_HOST)"; 580 | COMBINE_HIDPI_IMAGES = YES; 581 | INFOPLIST_FILE = LocalizationsTests/Info.plist; 582 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 583 | PRODUCT_BUNDLE_IDENTIFIER = com.arnaudthiercelin.LocalizationsTests; 584 | PRODUCT_NAME = "$(TARGET_NAME)"; 585 | SWIFT_VERSION = 3.0; 586 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Localizations.app/Contents/MacOS/Localizations"; 587 | }; 588 | name = Debug; 589 | }; 590 | 89F071911C5AE60500E75780 /* Release */ = { 591 | isa = XCBuildConfiguration; 592 | buildSettings = { 593 | BUNDLE_LOADER = "$(TEST_HOST)"; 594 | COMBINE_HIDPI_IMAGES = YES; 595 | INFOPLIST_FILE = LocalizationsTests/Info.plist; 596 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 597 | PRODUCT_BUNDLE_IDENTIFIER = com.arnaudthiercelin.LocalizationsTests; 598 | PRODUCT_NAME = "$(TARGET_NAME)"; 599 | SWIFT_VERSION = 3.0; 600 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Localizations.app/Contents/MacOS/Localizations"; 601 | }; 602 | name = Release; 603 | }; 604 | 89F071931C5AE60500E75780 /* Debug */ = { 605 | isa = XCBuildConfiguration; 606 | buildSettings = { 607 | COMBINE_HIDPI_IMAGES = YES; 608 | INFOPLIST_FILE = LocalizationsUITests/Info.plist; 609 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 610 | PRODUCT_BUNDLE_IDENTIFIER = com.arnaudthiercelin.LocalizationsUITests; 611 | PRODUCT_NAME = "$(TARGET_NAME)"; 612 | SWIFT_VERSION = 3.0; 613 | TEST_TARGET_NAME = Localizations; 614 | USES_XCTRUNNER = YES; 615 | }; 616 | name = Debug; 617 | }; 618 | 89F071941C5AE60500E75780 /* Release */ = { 619 | isa = XCBuildConfiguration; 620 | buildSettings = { 621 | COMBINE_HIDPI_IMAGES = YES; 622 | INFOPLIST_FILE = LocalizationsUITests/Info.plist; 623 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 624 | PRODUCT_BUNDLE_IDENTIFIER = com.arnaudthiercelin.LocalizationsUITests; 625 | PRODUCT_NAME = "$(TARGET_NAME)"; 626 | SWIFT_VERSION = 3.0; 627 | TEST_TARGET_NAME = Localizations; 628 | USES_XCTRUNNER = YES; 629 | }; 630 | name = Release; 631 | }; 632 | /* End XCBuildConfiguration section */ 633 | 634 | /* Begin XCConfigurationList section */ 635 | 89F071621C5AE60500E75780 /* Build configuration list for PBXProject "Localizations" */ = { 636 | isa = XCConfigurationList; 637 | buildConfigurations = ( 638 | 89F0718A1C5AE60500E75780 /* Debug */, 639 | 89F0718B1C5AE60500E75780 /* Release */, 640 | ); 641 | defaultConfigurationIsVisible = 0; 642 | defaultConfigurationName = Release; 643 | }; 644 | 89F0718C1C5AE60500E75780 /* Build configuration list for PBXNativeTarget "Localizations" */ = { 645 | isa = XCConfigurationList; 646 | buildConfigurations = ( 647 | 89F0718D1C5AE60500E75780 /* Debug */, 648 | 89F0718E1C5AE60500E75780 /* Release */, 649 | ); 650 | defaultConfigurationIsVisible = 0; 651 | defaultConfigurationName = Release; 652 | }; 653 | 89F0718F1C5AE60500E75780 /* Build configuration list for PBXNativeTarget "LocalizationsTests" */ = { 654 | isa = XCConfigurationList; 655 | buildConfigurations = ( 656 | 89F071901C5AE60500E75780 /* Debug */, 657 | 89F071911C5AE60500E75780 /* Release */, 658 | ); 659 | defaultConfigurationIsVisible = 0; 660 | defaultConfigurationName = Release; 661 | }; 662 | 89F071921C5AE60500E75780 /* Build configuration list for PBXNativeTarget "LocalizationsUITests" */ = { 663 | isa = XCConfigurationList; 664 | buildConfigurations = ( 665 | 89F071931C5AE60500E75780 /* Debug */, 666 | 89F071941C5AE60500E75780 /* Release */, 667 | ); 668 | defaultConfigurationIsVisible = 0; 669 | defaultConfigurationName = Release; 670 | }; 671 | /* End XCConfigurationList section */ 672 | }; 673 | rootObject = 89F0715F1C5AE60500E75780 /* Project object */; 674 | } 675 | -------------------------------------------------------------------------------- /Localizations.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Localizations.xcodeproj/xcshareddata/xcschemes/Localizations.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Localizations.xcodeproj/xcuserdata/tipoli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Localizations.xcodeproj/xcuserdata/tipoli.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Localizations.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 89F071661C5AE60500E75780 16 | 17 | primary 18 | 19 | 20 | 89F071771C5AE60500E75780 21 | 22 | primary 23 | 24 | 25 | 89F071821C5AE60500E75780 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Localizations/ATBasicAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ATBasicAnimator.swift 3 | // Localizations 4 | // 5 | // Created by Arnaud Thiercelin on 2/7/16. 6 | // Copyright © 2016 Arnaud Thiercelin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 9 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 10 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 12 | // subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial 15 | // portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 18 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 21 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | import Cocoa 24 | 25 | class ATBasicAnimator: NSObject, NSViewControllerPresentationAnimator { 26 | 27 | func addSubviewAsFullSize(containingView: NSView, subView: NSView) { 28 | subView.translatesAutoresizingMaskIntoConstraints = false 29 | 30 | containingView.addSubview(subView) 31 | let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|", 32 | options: .directionLeadingToTrailing, 33 | metrics: nil, 34 | views: ["view" : subView]) 35 | let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[view]-0-|", 36 | options: .directionLeadingToTrailing, 37 | metrics: nil, 38 | views: ["view" : subView]) 39 | containingView.addConstraints(horizontalConstraints) 40 | containingView.addConstraints(verticalConstraints) 41 | } 42 | 43 | func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) { 44 | let fromView = fromViewController.view 45 | let view = viewController.view 46 | 47 | self.addSubviewAsFullSize(containingView: fromView, subView: view) 48 | } 49 | 50 | func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) { 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Localizations/ATReplacingSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ATReplacingSegue.swift 3 | // Localizations 4 | // 5 | // Created by Arnaud Thiercelin on 2/27/16. 6 | // Copyright © 2016 Arnaud Thiercelin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 9 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 10 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 12 | // subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial 15 | // portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 18 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 21 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | import Cocoa 24 | 25 | /** 26 | This Segue only works with NSViewControllers. 27 | If provided with other classes, it defaults to super behavior. 28 | It adds destination's view to source's view as a full size subview. 29 | */ 30 | class ATReplacingSegue: NSStoryboardSegue { 31 | 32 | override func perform() { 33 | if self.sourceController is NSViewController && 34 | self.destinationController is NSViewController { 35 | let sourceViewController = self.sourceController as! NSViewController 36 | let destinationViewController = self.destinationController as! NSViewController 37 | 38 | sourceViewController.view.addSubview(destinationViewController.view) 39 | destinationViewController.view.translatesAutoresizingMaskIntoConstraints = false 40 | let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview" : destinationViewController.view]) 41 | let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[subview]-0-|", options: .directionLeadingToTrailing, metrics: nil, views: ["subview" : destinationViewController.view]) 42 | sourceViewController.view.addConstraints(horizontalConstraints) 43 | sourceViewController.view.addConstraints(verticalConstraints) 44 | } else { 45 | super.perform() 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Localizations/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Localizations 4 | // 5 | // Created by Arnaud Thiercelin on 1/28/16. 6 | // Copyright © 2016 Arnaud Thiercelin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 9 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 10 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 12 | // subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial 15 | // portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 18 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 21 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | import Cocoa 24 | 25 | @NSApplicationMain 26 | class AppDelegate: NSObject, NSApplicationDelegate { 27 | 28 | var errorCenter = ErrorCenter() 29 | 30 | @IBOutlet var newMenuItem: NSMenuItem! 31 | @IBOutlet var saveMenuItem: NSMenuItem! 32 | 33 | var chooseProjectViewController: ChooseProjectViewController? 34 | var detailViewController: DetailViewController? 35 | 36 | func applicationDidFinishLaunching(aNotification: NSNotification) { 37 | self.errorCenter.appDelegate = self 38 | } 39 | 40 | func applicationWillTerminate(aNotification: NSNotification) { 41 | // Insert code here to tear down your application 42 | } 43 | 44 | @IBAction func new(sender: AnyObject) { 45 | self.chooseProjectViewController?.startFresh() 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_512x512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512-1.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_512x512-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_512x512-1.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /Localizations/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/e7711bbear/Localizations/a95bedc86040846c0ae04af5ef4794283d28a2fd/Localizations/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /Localizations/Choose Project/ChooseProjectController+Parser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChooseProjectViewController+Parser.swift 3 | // Localizations 4 | // 5 | // Created by Arnaud Thiercelin on 2/14/16. 6 | // Copyright © 2016 Arnaud Thiercelin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 9 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 10 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 12 | // subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial 15 | // portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 18 | // NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 21 | // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | import Foundation 24 | 25 | extension ChooseProjectViewController { 26 | 27 | func parseTranslations(rawContent: String) -> [Translation] { 28 | let lines = rawContent.components(separatedBy: "\n") 29 | var translations = [Translation]() 30 | var comments = "" 31 | 32 | for line in lines { 33 | if line.characters.count == 0 { 34 | continue 35 | } 36 | if line.characters.first != "\"" { // Comment line or blank lines 37 | comments.append(line) 38 | comments.append("\n") 39 | } else { // line with key 40 | let translation = self.splitStringLine(line: line) 41 | 42 | translation.comments = comments 43 | translations.append(translation) 44 | comments = "" 45 | } 46 | } 47 | return translations 48 | } 49 | 50 | func splitStringLine(line: String) -> Translation { 51 | var foundFirstQuote = false 52 | var foundSecondQuote = false 53 | var foundThirdQuote = false 54 | let foundLastQuote = false 55 | var ignoreNextCharacter = false 56 | 57 | var key = "" 58 | var value = "" 59 | 60 | for index in 0.. Void in 159 | 160 | // Find the xcode pbxproj. 161 | self.findPbxproj(startPath: self.rootDirectory!.path as NSString) 162 | 163 | // Browsing the existing files 164 | self.findStringFiles(startPath: self.rootDirectory!.path as NSString) 165 | self.sortFoundStringFiles() 166 | 167 | // Get fresh generation of files 168 | self.generateFreshFilesUsingGenstrings() 169 | self.generateFreshFilesWithIBTool() 170 | self.produceFreshListOfStringFiles() 171 | 172 | self.compareAndCombine() 173 | // show detail ui 174 | DispatchQueue.main.async(execute: { [unowned self] () -> Void in 175 | self.stopProgression() 176 | self.performSegue(withIdentifier: "detailsSegue", sender: nil) 177 | self.appDelegate.newMenuItem.isEnabled = true 178 | self.appDelegate.saveMenuItem.isEnabled = true 179 | }) 180 | }) 181 | // } catch { 182 | // // TODO: Implement error here if and when this app is sandboxed 183 | // } 184 | } 185 | } 186 | 187 | // MARK: - Methods collecting existing localization data from .string files. 188 | 189 | func findPbxproj(startPath: NSString) { 190 | let fileManager = FileManager.default 191 | 192 | do { 193 | let content = try fileManager.contentsOfDirectory(atPath: startPath as String) 194 | 195 | for element in content { 196 | let elementPath = startPath.appendingPathComponent(element) 197 | var isDirectory: ObjCBool = false 198 | 199 | fileManager.fileExists(atPath: elementPath, isDirectory: &isDirectory) 200 | if isDirectory.boolValue { 201 | // Skipping Directories that can't be open 202 | if !fileManager.isExecutableFile(atPath: elementPath) { 203 | continue 204 | } 205 | 206 | // Skipping Hidden Folders 207 | let dotRange = element.range(of: ".") 208 | if dotRange != nil && dotRange!.lowerBound == element.startIndex { 209 | continue 210 | } 211 | 212 | // We open the folder and continue the process. 213 | self.findPbxproj(startPath: elementPath as NSString) 214 | } 215 | else // files - we are only interested in localizations files. 216 | { 217 | let stringsRange = element.range(of: ".pbxproj") 218 | 219 | if stringsRange != nil { 220 | if self.xcodeProject.pbxprojPath == "" { 221 | self.xcodeProject.pbxprojPath = elementPath 222 | self.readPbxproj() 223 | } else { 224 | NSLog("Error: Found multiple pbxproj - \(elementPath)") 225 | //TODO: Implement critical error here as we have multiple xcode project under the folder. 226 | // We could offer to choose manually or crash directly. 227 | } 228 | } 229 | } 230 | } 231 | } catch { 232 | // TODO: error handling 233 | } 234 | } 235 | 236 | func readPbxproj() { 237 | self.xcodeProject.knownRegions.removeAll() 238 | self.xcodeProject.devRegion = "" 239 | 240 | do { 241 | self.xcodeProject.pbxprojContent = try NSString(contentsOfFile: self.xcodeProject.pbxprojPath as String, encoding: String.Encoding.utf8.rawValue) as String 242 | } catch { 243 | do { 244 | self.xcodeProject.pbxprojContent = try NSString(contentsOfFile: self.xcodeProject.pbxprojPath as String, encoding: String.Encoding.utf16.rawValue) as String 245 | } catch { 246 | //TODO: Eventually retry with even more encoding. 247 | } 248 | } 249 | 250 | guard self.xcodeProject.pbxprojContent != "" else { 251 | NSLog("Can't proceed with reading the pbxproj file (\(self.xcodeProject.pbxprojPath)), because it's empty.") 252 | return 253 | } 254 | let lines = self.xcodeProject.pbxprojContent.components(separatedBy: "\n") 255 | 256 | for line in lines { 257 | if line.characters.count == 0 { 258 | continue 259 | } 260 | 261 | if self.xcodeProject.devRegion == "" { 262 | let devRegionRange = line.range(of: "developmentRegion") 263 | 264 | if devRegionRange != nil { 265 | let foundDevRegion = self.parseDevRegion(line: line) 266 | 267 | if foundDevRegion != nil { 268 | self.xcodeProject.devRegion = foundDevRegion! 269 | } else { 270 | // TODO: Recovery here 271 | } 272 | } 273 | } 274 | if self.xcodeProject.knownRegions.count == 0 { 275 | let knownRegionRange = line.range(of: "knownRegions") 276 | 277 | if knownRegionRange != nil { 278 | let startingIndex = lines.index(of: line) 279 | 280 | let foundRegions = self.parseKnownRegions(lines: lines, startingIndex: startingIndex!) 281 | 282 | // TODO: Eventually add here a test on the qty returned. 283 | self.xcodeProject.knownRegions.append(contentsOf: foundRegions) 284 | } 285 | } 286 | } 287 | } 288 | 289 | func parseDevRegion(line: String) -> String? { 290 | let lineParts = line.components(separatedBy: "=") 291 | var cleanedString = lineParts[1].replacingOccurrences(of: " ", with: "") 292 | cleanedString = cleanedString.replacingOccurrences(of: ";", with: "") 293 | 294 | return cleanedString 295 | } 296 | 297 | func parseKnownRegions(lines: [String], startingIndex: Int) -> [String] { 298 | var foundRegions = [String]() 299 | 300 | for index in startingIndex+1..